moved SkSL FunctionCall data into IRNode

Change-Id: Iefa82eccbba518cbd741b4415ea6340c66eabd9d
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/321465
Reviewed-by: John Stiles <johnstiles@google.com>
Commit-Queue: Ethan Nicholas <ethannicholas@google.com>
This commit is contained in:
Ethan Nicholas 2020-10-05 15:51:52 -04:00 committed by Skia Commit-Bot
parent 7a7bec371a
commit 0dec9927af
17 changed files with 288 additions and 228 deletions

View File

@ -65,10 +65,10 @@ namespace SkSL {
namespace {
static bool is_sample_call_to_fp(const FunctionCall& fc, const Variable& fp) {
const FunctionDeclaration& f = fc.fFunction;
return f.fBuiltin && f.name() == "sample" && fc.fArguments.size() >= 1 &&
fc.fArguments[0]->is<VariableReference>() &&
fc.fArguments[0]->as<VariableReference>().fVariable == &fp;
const FunctionDeclaration& f = fc.function();
return f.fBuiltin && f.name() == "sample" && fc.arguments().size() >= 1 &&
fc.arguments()[0]->is<VariableReference>() &&
fc.arguments()[0]->as<VariableReference>().fVariable == &fp;
}
// Visitor that determines the merged SampleUsage for a given child 'fp' in the program.
@ -94,7 +94,7 @@ protected:
const FunctionCall& fc = e.as<FunctionCall>();
if (is_sample_call_to_fp(fc, fFP)) {
// Determine the type of call at this site, and merge it with the accumulated state
const Expression* lastArg = fc.fArguments.back().get();
const Expression* lastArg = fc.arguments().back().get();
if (lastArg->type() == *fContext.fFloat2_Type) {
fUsage.merge(SampleUsage::Explicit());
@ -389,7 +389,7 @@ bool TProgramVisitor<PROG, EXPR, STMT, ELEM>::visitExpression(EXPR e) {
case Expression::Kind::kFunctionCall: {
auto& c = e.template as<FunctionCall>();
for (auto& arg : c.fArguments) {
for (auto& arg : c.arguments()) {
if (this->visitExpression(*arg)) { return true; }
}
return false;

View File

@ -1032,15 +1032,15 @@ static bool is_generic_type(const Type* type, const Type* generic) {
}
void ByteCodeGenerator::writeIntrinsicCall(const FunctionCall& c) {
auto found = fIntrinsics.find(c.fFunction.name());
auto found = fIntrinsics.find(c.function().name());
if (found == fIntrinsics.end()) {
fErrors.error(c.fOffset, String::printf("Unsupported intrinsic: '%s'",
String(c.fFunction.name()).c_str()));
String(c.function().name()).c_str()));
return;
}
Intrinsic intrin = found->second;
const auto& args = c.fArguments;
const auto& args = c.arguments();
const size_t nargs = args.size();
SkASSERT(nargs >= 1);
@ -1242,7 +1242,7 @@ void ByteCodeGenerator::writeFunctionCall(const FunctionCall& f) {
// before they're defined. This is an easy-to-understand rule that prevents recursion.
int idx = -1;
for (size_t i = 0; i < fFunctions.size(); ++i) {
if (f.fFunction.matches(fFunctions[i]->fDeclaration)) {
if (f.function().matches(fFunctions[i]->fDeclaration)) {
idx = i;
break;
}
@ -1266,11 +1266,11 @@ void ByteCodeGenerator::writeFunctionCall(const FunctionCall& f) {
this->write(ByteCodeInstruction::kReserve, returnCount);
}
int argCount = f.fArguments.size();
int argCount = f.arguments().size();
std::vector<std::unique_ptr<LValue>> lvalues;
for (int i = 0; i < argCount; ++i) {
const auto& param = f.fFunction.fParameters[i];
const auto& arg = f.fArguments[i];
const auto& param = f.function().fParameters[i];
const auto& arg = f.arguments()[i];
if (param->fModifiers.fFlags & Modifiers::kOut_Flag) {
lvalues.emplace_back(this->getLValue(*arg));
lvalues.back()->load();
@ -1302,8 +1302,8 @@ void ByteCodeGenerator::writeFunctionCall(const FunctionCall& f) {
};
for (int i = argCount - 1; i >= 0; --i) {
const auto& param = f.fFunction.fParameters[i];
const auto& arg = f.fArguments[i];
const auto& param = f.function().fParameters[i];
const auto& arg = f.arguments()[i];
if (param->fModifiers.fFlags & Modifiers::kOut_Flag) {
pop();
lvalues.back()->store(true);

View File

@ -221,7 +221,7 @@ bool BasicBlock::tryRemoveExpression(std::vector<BasicBlock::Node>::iterator* it
}
case Expression::Kind::kFunctionCall: {
FunctionCall& f = expr->as<FunctionCall>();
for (auto& arg : f.fArguments) {
for (auto& arg : f.arguments()) {
if (!this->tryRemoveExpressionBefore(iter, arg.get())) {
return false;
}
@ -368,7 +368,7 @@ void CFGGenerator::addExpression(CFG& cfg, std::unique_ptr<Expression>* e, bool
}
case Expression::Kind::kFunctionCall: {
FunctionCall& c = e->get()->as<FunctionCall>();
for (auto& arg : c.fArguments) {
for (auto& arg : c.arguments()) {
this->addExpression(cfg, &arg, constantPropagate);
}
cfg.currentBlock().fNodes.push_back(BasicBlock::MakeExpression(e, constantPropagate));

View File

@ -431,33 +431,35 @@ int CPPCodeGenerator::getChildFPIndex(const Variable& var) const {
}
void CPPCodeGenerator::writeFunctionCall(const FunctionCall& c) {
if (c.fFunction.fBuiltin && c.fFunction.name() == "sample" &&
c.fArguments[0]->type().typeKind() != Type::TypeKind::kSampler) {
const FunctionDeclaration& function = c.function();
const std::vector<std::unique_ptr<Expression>>& arguments = c.arguments();
if (function.fBuiltin && function.name() == "sample" &&
arguments[0]->type().typeKind() != Type::TypeKind::kSampler) {
// Validity checks that are detected by function definition in sksl_fp.inc
SkASSERT(c.fArguments.size() >= 1 && c.fArguments.size() <= 3);
SkASSERT("fragmentProcessor" == c.fArguments[0]->type().name() ||
"fragmentProcessor?" == c.fArguments[0]->type().name());
SkASSERT(arguments.size() >= 1 && arguments.size() <= 3);
SkASSERT("fragmentProcessor" == arguments[0]->type().name() ||
"fragmentProcessor?" == arguments[0]->type().name());
// Actually fail during compilation if arguments with valid types are
// provided that are not variable references, since sample() is a
// special function that impacts code emission.
if (!c.fArguments[0]->is<VariableReference>()) {
fErrors.error(c.fArguments[0]->fOffset,
if (!arguments[0]->is<VariableReference>()) {
fErrors.error(arguments[0]->fOffset,
"sample()'s fragmentProcessor argument must be a variable reference\n");
return;
}
const Variable& child = *c.fArguments[0]->as<VariableReference>().fVariable;
const Variable& child = *arguments[0]->as<VariableReference>().fVariable;
// Start a new extra emit code section so that the emitted child processor can depend on
// sksl variables defined in earlier sksl code.
this->newExtraEmitCodeBlock();
String inputColor;
if (c.fArguments.size() > 1 && c.fArguments[1]->type().name() == "half4") {
if (arguments.size() > 1 && arguments[1]->type().name() == "half4") {
// Use the invokeChild() variant that accepts an input color, so convert the 2nd
// argument's expression into C++ code that produces sksl stored in an SkString.
String inputColorName = "_input" + to_string(c.fOffset);
addExtraEmitCodeLine(convertSKSLExpressionToCPP(*c.fArguments[1], inputColorName));
addExtraEmitCodeLine(convertSKSLExpressionToCPP(*arguments[1], inputColorName));
// invokeChild() needs a char* and a pre-pended comma
inputColor = ", " + inputColorName + ".c_str()";
@ -465,19 +467,19 @@ void CPPCodeGenerator::writeFunctionCall(const FunctionCall& c) {
String inputCoord;
String invokeFunction = "invokeChild";
if (c.fArguments.back()->type().name() == "float2") {
if (arguments.back()->type().name() == "float2") {
// Invoking child with explicit coordinates at this call site
inputCoord = "_coords" + to_string(c.fOffset);
addExtraEmitCodeLine(convertSKSLExpressionToCPP(*c.fArguments.back(), inputCoord));
addExtraEmitCodeLine(convertSKSLExpressionToCPP(*arguments.back(), inputCoord));
inputCoord.append(".c_str()");
} else if (c.fArguments.back()->type().name() == "float3x3") {
} else if (arguments.back()->type().name() == "float3x3") {
// Invoking child with a matrix, sampling relative to the input coords.
invokeFunction = "invokeChildWithMatrix";
SampleUsage usage = Analysis::GetSampleUsage(fProgram, child);
if (!usage.hasUniformMatrix()) {
inputCoord = "_matrix" + to_string(c.fOffset);
addExtraEmitCodeLine(convertSKSLExpressionToCPP(*c.fArguments.back(), inputCoord));
addExtraEmitCodeLine(convertSKSLExpressionToCPP(*arguments.back(), inputCoord));
inputCoord.append(".c_str()");
}
// else pass in the empty string to rely on invokeChildWithMatrix's automatic uniform
@ -497,26 +499,26 @@ void CPPCodeGenerator::writeFunctionCall(const FunctionCall& c) {
fFormatArgs.push_back(childName + ".c_str()");
return;
}
if (c.fFunction.fBuiltin) {
if (function.fBuiltin) {
INHERITED::writeFunctionCall(c);
} else {
this->write("%s");
fFormatArgs.push_back((String(c.fFunction.name()) + "_name.c_str()").c_str());
fFormatArgs.push_back((String(function.name()) + "_name.c_str()").c_str());
this->write("(");
const char* separator = "";
for (const auto& arg : c.fArguments) {
for (const auto& arg : arguments) {
this->write(separator);
separator = ", ";
this->writeExpression(*arg, kSequence_Precedence);
}
this->write(")");
}
if (c.fFunction.fBuiltin && c.fFunction.name() == "sample") {
if (function.fBuiltin && function.name() == "sample") {
this->write(".%s");
SkASSERT(c.fArguments.size() >= 1);
SkASSERT(c.fArguments[0]->is<VariableReference>());
SkASSERT(arguments.size() >= 1);
SkASSERT(arguments[0]->is<VariableReference>());
String sampler =
this->getSamplerHandle(*c.fArguments[0]->as<VariableReference>().fVariable);
this->getSamplerHandle(*arguments[0]->as<VariableReference>().fVariable);
fFormatArgs.push_back("fragBuilder->getProgramBuilder()->samplerSwizzle(" + sampler +
").asString().c_str()");
}

View File

@ -495,10 +495,10 @@ void Compiler::addDefinitions(const BasicBlock::Node& node,
}
case Expression::Kind::kFunctionCall: {
const FunctionCall& c = expr->as<FunctionCall>();
for (size_t i = 0; i < c.fFunction.fParameters.size(); ++i) {
if (c.fFunction.fParameters[i]->fModifiers.fFlags & Modifiers::kOut_Flag) {
for (size_t i = 0; i < c.function().fParameters.size(); ++i) {
if (c.function().fParameters[i]->fModifiers.fFlags & Modifiers::kOut_Flag) {
this->addDefinition(
c.fArguments[i].get(),
c.arguments()[i].get(),
(std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
definitions);
}

View File

@ -306,9 +306,9 @@ void Dehydrator::write(const Expression* e) {
const FunctionCall& f = e->as<FunctionCall>();
this->writeU8(Rehydrator::kFunctionCall_Command);
this->write(f.type());
this->writeId(&f.fFunction);
this->writeU8(f.fArguments.size());
for (const auto& a : f.fArguments) {
this->writeId(&f.function());
this->writeU8(f.arguments().size());
for (const auto& a : f.arguments()) {
this->write(a.get());
}
break;

View File

@ -242,7 +242,7 @@ static bool is_abs(Expression& expr) {
if (expr.kind() != Expression::Kind::kFunctionCall) {
return false;
}
return expr.as<FunctionCall>().fFunction.name() == "abs";
return expr.as<FunctionCall>().function().name() == "abs";
}
// turns min(abs(x), y) into ((tmpVar1 = abs(x)) < (tmpVar2 = y) ? tmpVar1 : tmpVar2) to avoid a
@ -454,6 +454,8 @@ std::unordered_map<StringFragment, GLSLCodeGenerator::FunctionClass>*
GLSLCodeGenerator::fFunctionClasses = nullptr;
void GLSLCodeGenerator::writeFunctionCall(const FunctionCall& c) {
const FunctionDeclaration& function = c.function();
const std::vector<std::unique_ptr<Expression>>& arguments = c.arguments();
#ifdef SKSL_STANDALONE
if (!fFunctionClasses) {
#else
@ -480,8 +482,8 @@ void GLSLCodeGenerator::writeFunctionCall(const FunctionCall& c) {
#ifndef SKSL_STANDALONE
);
#endif
const auto found = c.fFunction.fBuiltin ? fFunctionClasses->find(c.fFunction.name()) :
fFunctionClasses->end();
const auto found = function.fBuiltin ? fFunctionClasses->find(function.name()) :
fFunctionClasses->end();
bool isTextureFunctionWithBias = false;
bool nameWritten = false;
if (found != fFunctionClasses->end()) {
@ -489,9 +491,10 @@ void GLSLCodeGenerator::writeFunctionCall(const FunctionCall& c) {
case FunctionClass::kAbs: {
if (!fProgram.fSettings.fCaps->emulateAbsIntFunction())
break;
SkASSERT(c.fArguments.size() == 1);
if (c.fArguments[0]->type() != *fContext.fInt_Type)
break;
SkASSERT(arguments.size() == 1);
if (arguments[0]->type() != *fContext.fInt_Type) {
break;
}
// abs(int) on Intel OSX is incorrect, so emulate it:
String name = "_absemulation";
this->write(name);
@ -508,12 +511,12 @@ void GLSLCodeGenerator::writeFunctionCall(const FunctionCall& c) {
}
case FunctionClass::kAtan:
if (fProgram.fSettings.fCaps->mustForceNegatedAtanParamToFloat() &&
c.fArguments.size() == 2 &&
c.fArguments[1]->kind() == Expression::Kind::kPrefix) {
const PrefixExpression& p = (PrefixExpression&) *c.fArguments[1];
arguments.size() == 2 &&
arguments[1]->kind() == Expression::Kind::kPrefix) {
const PrefixExpression& p = (PrefixExpression&) *arguments[1];
if (p.fOperator == Token::Kind::TK_MINUS) {
this->write("atan(");
this->writeExpression(*c.fArguments[0], kSequence_Precedence);
this->writeExpression(*arguments[0], kSequence_Precedence);
this->write(", -1.0 * ");
this->writeExpression(*p.fOperand, kMultiplicative_Precedence);
this->write(")");
@ -539,60 +542,60 @@ void GLSLCodeGenerator::writeFunctionCall(const FunctionCall& c) {
break;
case FunctionClass::kDeterminant:
if (fProgram.fSettings.fCaps->generation() < k150_GrGLSLGeneration) {
SkASSERT(c.fArguments.size() == 1);
this->writeDeterminantHack(*c.fArguments[0]);
SkASSERT(arguments.size() == 1);
this->writeDeterminantHack(*arguments[0]);
return;
}
break;
case FunctionClass::kFMA:
if (!fProgram.fSettings.fCaps->builtinFMASupport()) {
SkASSERT(c.fArguments.size() == 3);
SkASSERT(arguments.size() == 3);
this->write("((");
this->writeExpression(*c.fArguments[0], kSequence_Precedence);
this->writeExpression(*arguments[0], kSequence_Precedence);
this->write(") * (");
this->writeExpression(*c.fArguments[1], kSequence_Precedence);
this->writeExpression(*arguments[1], kSequence_Precedence);
this->write(") + (");
this->writeExpression(*c.fArguments[2], kSequence_Precedence);
this->writeExpression(*arguments[2], kSequence_Precedence);
this->write("))");
return;
}
break;
case FunctionClass::kFract:
if (!fProgram.fSettings.fCaps->canUseFractForNegativeValues()) {
SkASSERT(c.fArguments.size() == 1);
SkASSERT(arguments.size() == 1);
this->write("(0.5 - sign(");
this->writeExpression(*c.fArguments[0], kSequence_Precedence);
this->writeExpression(*arguments[0], kSequence_Precedence);
this->write(") * (0.5 - fract(abs(");
this->writeExpression(*c.fArguments[0], kSequence_Precedence);
this->writeExpression(*arguments[0], kSequence_Precedence);
this->write("))))");
return;
}
break;
case FunctionClass::kInverse:
if (fProgram.fSettings.fCaps->generation() < k140_GrGLSLGeneration) {
SkASSERT(c.fArguments.size() == 1);
this->writeInverseHack(*c.fArguments[0]);
SkASSERT(arguments.size() == 1);
this->writeInverseHack(*arguments[0]);
return;
}
break;
case FunctionClass::kInverseSqrt:
if (fProgram.fSettings.fCaps->generation() < k130_GrGLSLGeneration) {
SkASSERT(c.fArguments.size() == 1);
this->writeInverseSqrtHack(*c.fArguments[0]);
SkASSERT(arguments.size() == 1);
this->writeInverseSqrtHack(*arguments[0]);
return;
}
break;
case FunctionClass::kMin:
if (!fProgram.fSettings.fCaps->canUseMinAndAbsTogether()) {
SkASSERT(c.fArguments.size() == 2);
if (is_abs(*c.fArguments[0])) {
this->writeMinAbsHack(*c.fArguments[0], *c.fArguments[1]);
SkASSERT(arguments.size() == 2);
if (is_abs(*arguments[0])) {
this->writeMinAbsHack(*arguments[0], *arguments[1]);
return;
}
if (is_abs(*c.fArguments[1])) {
if (is_abs(*arguments[1])) {
// note that this violates the GLSL left-to-right evaluation semantics.
// I doubt it will ever end up mattering, but it's worth calling out.
this->writeMinAbsHack(*c.fArguments[1], *c.fArguments[0]);
this->writeMinAbsHack(*arguments[1], *arguments[0]);
return;
}
}
@ -607,22 +610,22 @@ void GLSLCodeGenerator::writeFunctionCall(const FunctionCall& c) {
// Change pow(x, y) into exp2(y * log2(x))
this->write("exp2(");
this->writeExpression(*c.fArguments[1], kMultiplicative_Precedence);
this->writeExpression(*arguments[1], kMultiplicative_Precedence);
this->write(" * log2(");
this->writeExpression(*c.fArguments[0], kSequence_Precedence);
this->writeExpression(*arguments[0], kSequence_Precedence);
this->write("))");
return;
case FunctionClass::kSaturate:
SkASSERT(c.fArguments.size() == 1);
SkASSERT(arguments.size() == 1);
this->write("clamp(");
this->writeExpression(*c.fArguments[0], kSequence_Precedence);
this->writeExpression(*arguments[0], kSequence_Precedence);
this->write(", 0.0, 1.0)");
return;
case FunctionClass::kTexture: {
const char* dim = "";
bool proj = false;
const Type& arg0Type = c.fArguments[0]->type();
const Type& arg1Type = c.fArguments[1]->type();
const Type& arg0Type = arguments[0]->type();
const Type& arg1Type = arguments[1]->type();
switch (arg0Type.dimensions()) {
case SpvDim1D:
dim = "1D";
@ -692,19 +695,19 @@ void GLSLCodeGenerator::writeFunctionCall(const FunctionCall& c) {
}
case FunctionClass::kTranspose:
if (fProgram.fSettings.fCaps->generation() < k130_GrGLSLGeneration) {
SkASSERT(c.fArguments.size() == 1);
this->writeTransposeHack(*c.fArguments[0]);
SkASSERT(arguments.size() == 1);
this->writeTransposeHack(*arguments[0]);
return;
}
break;
}
}
if (!nameWritten) {
this->write(c.fFunction.name());
this->write(function.name());
}
this->write("(");
const char* separator = "";
for (const auto& arg : c.fArguments) {
for (const auto& arg : arguments) {
this->write(separator);
separator = ", ";
this->writeExpression(*arg, kSequence_Precedence);

View File

@ -246,7 +246,7 @@ std::unique_ptr<Statement> IRGenerator::convertSingleStatement(const ASTNode& st
Expression& expr = *result->as<ExpressionStatement>().expression();
if (expr.kind() == Expression::Kind::kFunctionCall) {
FunctionCall& fc = expr.as<FunctionCall>();
if (fc.fFunction.fBuiltin && fc.fFunction.name() == "EmitVertex") {
if (fc.function().fBuiltin && fc.function().name() == "EmitVertex") {
std::vector<std::unique_ptr<Statement>> statements;
statements.push_back(getNormalizeSkPositionCode());
statements.push_back(std::move(result));
@ -2116,11 +2116,11 @@ std::unique_ptr<Expression> IRGenerator::call(int offset,
}
}
auto funcCall = std::make_unique<FunctionCall>(offset, returnType, function,
auto funcCall = std::make_unique<FunctionCall>(offset, returnType, &function,
std::move(arguments));
if (fCanInline &&
fInliner->isSafeToInline(funcCall->fFunction.fDefinition) &&
!fInliner->isLargeFunction(funcCall->fFunction.fDefinition)) {
fInliner->isSafeToInline(funcCall->function().fDefinition) &&
!fInliner->isLargeFunction(funcCall->function().fDefinition)) {
Inliner::InlinedCall inlinedCall = fInliner->inlineCall(funcCall.get(), fSymbolTable.get(),
fCurrentFunction);
if (inlinedCall.fInlinedBody) {

View File

@ -172,7 +172,7 @@ static bool contains_recursive_call(const FunctionDeclaration& funcDecl) {
}
bool visitExpression(const Expression& expr) override {
if (expr.is<FunctionCall>() && expr.as<FunctionCall>().fFunction.matches(*fFuncDecl)) {
if (expr.is<FunctionCall>() && expr.as<FunctionCall>().function().matches(*fFuncDecl)) {
return true;
}
return INHERITED::visitExpression(expr);
@ -382,8 +382,8 @@ std::unique_ptr<Expression> Inliner::inlineExpression(int offset,
}
case Expression::Kind::kFunctionCall: {
const FunctionCall& funcCall = expression.as<FunctionCall>();
return std::make_unique<FunctionCall>(offset, &funcCall.type(), funcCall.fFunction,
argList(funcCall.fArguments));
return std::make_unique<FunctionCall>(offset, &funcCall.type(), &funcCall.function(),
argList(funcCall.arguments()));
}
case Expression::Kind::kFunctionReference:
return expression.clone();
@ -595,11 +595,11 @@ Inliner::InlinedCall Inliner::inlineCall(FunctionCall* call,
SkASSERT(fSettings);
SkASSERT(fContext);
SkASSERT(call);
SkASSERT(this->isSafeToInline(call->fFunction.fDefinition));
SkASSERT(this->isSafeToInline(call->function().fDefinition));
std::vector<std::unique_ptr<Expression>>& arguments = call->fArguments;
std::vector<std::unique_ptr<Expression>>& arguments = call->arguments();
const int offset = call->fOffset;
const FunctionDefinition& function = *call->fFunction.fDefinition;
const FunctionDefinition& function = *call->function().fDefinition;
const bool hasEarlyReturn = has_early_return(function);
InlinedCall inlinedCall;
@ -615,7 +615,7 @@ Inliner::InlinedCall Inliner::inlineCall(FunctionCall* call,
arguments.size() + // Function arguments (copy out-params back)
1); // Inlined code (Block or do-while loop)
inlinedBody.children().push_back(std::make_unique<InlineMarker>(call->fFunction));
inlinedBody.children().push_back(std::make_unique<InlineMarker>(call->function()));
auto makeInlineVar =
[&](const String& baseName, const Type* type, Modifiers modifiers,
@ -1028,7 +1028,7 @@ public:
}
case Expression::Kind::kFunctionCall: {
FunctionCall& funcCallExpr = (*expr)->as<FunctionCall>();
for (std::unique_ptr<Expression>& arg : funcCallExpr.fArguments) {
for (std::unique_ptr<Expression>& arg : funcCallExpr.arguments()) {
this->visitExpression(&arg);
}
this->addInlineCandidate(expr);
@ -1080,7 +1080,8 @@ public:
};
bool Inliner::candidateCanBeInlined(const InlineCandidate& candidate, InlinabilityCache* cache) {
const FunctionDeclaration& funcDecl = (*candidate.fCandidateExpr)->as<FunctionCall>().fFunction;
const FunctionDeclaration& funcDecl =
(*candidate.fCandidateExpr)->as<FunctionCall>().function();
auto [iter, wasInserted] = cache->insert({&funcDecl, false});
if (wasInserted) {
@ -1097,7 +1098,8 @@ bool Inliner::isLargeFunction(const FunctionDefinition* functionDef) {
}
bool Inliner::isLargeFunction(const InlineCandidate& candidate, LargeFunctionCache* cache) {
const FunctionDeclaration& funcDecl = (*candidate.fCandidateExpr)->as<FunctionCall>().fFunction;
const FunctionDeclaration& funcDecl =
(*candidate.fCandidateExpr)->as<FunctionCall>().function();
auto [iter, wasInserted] = cache->insert({&funcDecl, false});
if (wasInserted) {
@ -1143,7 +1145,7 @@ bool Inliner::analyze(Program& program) {
bool madeChanges = false;
for (const InlineCandidate& candidate : candidateList.fCandidates) {
FunctionCall& funcCall = (*candidate.fCandidateExpr)->as<FunctionCall>();
const FunctionDeclaration* funcDecl = &funcCall.fFunction;
const FunctionDeclaration* funcDecl = &funcCall.function();
// If the function is large, not marked `inline`, and is called more than once, it's a bad
// idea to inline it.

View File

@ -172,7 +172,7 @@ void MetalCodeGenerator::writeExpression(const Expression& expr, Precedence pare
}
void MetalCodeGenerator::writeIntrinsicCall(const FunctionCall& c) {
auto i = fIntrinsicMap.find(c.fFunction.name());
auto i = fIntrinsicMap.find(c.function().name());
SkASSERT(i != fIntrinsicMap.end());
Intrinsic intrinsic = i->second;
int32_t intrinsicId = intrinsic.second;
@ -181,7 +181,7 @@ void MetalCodeGenerator::writeIntrinsicCall(const FunctionCall& c) {
return this->writeSpecialIntrinsic(c, (SpecialIntrinsic) intrinsicId);
break;
case kMetal_IntrinsicKind:
this->writeExpression(*c.fArguments[0], kSequence_Precedence);
this->writeExpression(*c.arguments()[0], kSequence_Precedence);
switch ((MetalIntrinsic) intrinsicId) {
case kEqual_MetalIntrinsic:
this->write(" == ");
@ -204,7 +204,7 @@ void MetalCodeGenerator::writeIntrinsicCall(const FunctionCall& c) {
default:
ABORT("unsupported metal intrinsic kind");
}
this->writeExpression(*c.fArguments[1], kSequence_Precedence);
this->writeExpression(*c.arguments()[1], kSequence_Precedence);
break;
default:
ABORT("unsupported intrinsic kind");
@ -212,22 +212,24 @@ void MetalCodeGenerator::writeIntrinsicCall(const FunctionCall& c) {
}
void MetalCodeGenerator::writeFunctionCall(const FunctionCall& c) {
const auto& entry = fIntrinsicMap.find(c.fFunction.name());
const FunctionDeclaration& function = c.function();
const std::vector<std::unique_ptr<Expression>>& arguments = c.arguments();
const auto& entry = fIntrinsicMap.find(function.name());
if (entry != fIntrinsicMap.end()) {
this->writeIntrinsicCall(c);
return;
}
const StringFragment& name = c.fFunction.name();
if (c.fFunction.fBuiltin && name == "atan" && 2 == c.fArguments.size()) {
const StringFragment& name = function.name();
if (function.fBuiltin && name == "atan" && arguments.size() == 2) {
this->write("atan2");
} else if (c.fFunction.fBuiltin && name == "inversesqrt") {
} else if (function.fBuiltin && name == "inversesqrt") {
this->write("rsqrt");
} else if (c.fFunction.fBuiltin && name == "inverse") {
SkASSERT(c.fArguments.size() == 1);
this->writeInverseHack(*c.fArguments[0]);
} else if (c.fFunction.fBuiltin && name == "dFdx") {
} else if (function.fBuiltin && name == "inverse") {
SkASSERT(arguments.size() == 1);
this->writeInverseHack(*arguments[0]);
} else if (function.fBuiltin && name == "dFdx") {
this->write("dfdx");
} else if (c.fFunction.fBuiltin && name == "dFdy") {
} else if (function.fBuiltin && name == "dFdy") {
// Flipping Y also negates the Y derivatives.
this->write((fProgram.fSettings.fFlipY) ? "-dfdy" : "dfdy");
} else {
@ -235,35 +237,35 @@ void MetalCodeGenerator::writeFunctionCall(const FunctionCall& c) {
}
this->write("(");
const char* separator = "";
if (this->requirements(c.fFunction) & kInputs_Requirement) {
if (this->requirements(function) & kInputs_Requirement) {
this->write("_in");
separator = ", ";
}
if (this->requirements(c.fFunction) & kOutputs_Requirement) {
if (this->requirements(function) & kOutputs_Requirement) {
this->write(separator);
this->write("_out");
separator = ", ";
}
if (this->requirements(c.fFunction) & kUniforms_Requirement) {
if (this->requirements(function) & kUniforms_Requirement) {
this->write(separator);
this->write("_uniforms");
separator = ", ";
}
if (this->requirements(c.fFunction) & kGlobals_Requirement) {
if (this->requirements(function) & kGlobals_Requirement) {
this->write(separator);
this->write("_globals");
separator = ", ";
}
if (this->requirements(c.fFunction) & kFragCoord_Requirement) {
if (this->requirements(function) & kFragCoord_Requirement) {
this->write(separator);
this->write("_fragCoord");
separator = ", ";
}
for (size_t i = 0; i < c.fArguments.size(); ++i) {
const Expression& arg = *c.fArguments[i];
for (size_t i = 0; i < arguments.size(); ++i) {
const Expression& arg = *arguments[i];
this->write(separator);
separator = ", ";
if (c.fFunction.fParameters[i]->fModifiers.fFlags & Modifiers::kOut_Flag) {
if (function.fParameters[i]->fModifiers.fFlags & Modifiers::kOut_Flag) {
this->write("&");
}
this->writeExpression(arg, kSequence_Precedence);
@ -353,24 +355,25 @@ void MetalCodeGenerator::writeInverseHack(const Expression& mat) {
}
void MetalCodeGenerator::writeSpecialIntrinsic(const FunctionCall & c, SpecialIntrinsic kind) {
const std::vector<std::unique_ptr<Expression>>& arguments = c.arguments();
switch (kind) {
case kTexture_SpecialIntrinsic: {
this->writeExpression(*c.fArguments[0], kSequence_Precedence);
this->writeExpression(*arguments[0], kSequence_Precedence);
this->write(".sample(");
this->writeExpression(*c.fArguments[0], kSequence_Precedence);
this->writeExpression(*arguments[0], kSequence_Precedence);
this->write(SAMPLER_SUFFIX);
this->write(", ");
const Type& arg1Type = c.fArguments[1]->type();
const Type& arg1Type = arguments[1]->type();
if (arg1Type == *fContext.fFloat3_Type) {
// have to store the vector in a temp variable to avoid double evaluating it
String tmpVar = "tmpCoord" + to_string(fVarCount++);
this->fFunctionHeader += " " + this->typeName(arg1Type) + " " + tmpVar + ";\n";
this->write("(" + tmpVar + " = ");
this->writeExpression(*c.fArguments[1], kSequence_Precedence);
this->writeExpression(*arguments[1], kSequence_Precedence);
this->write(", " + tmpVar + ".xy / " + tmpVar + ".z))");
} else {
SkASSERT(arg1Type == *fContext.fFloat2_Type);
this->writeExpression(*c.fArguments[1], kSequence_Precedence);
this->writeExpression(*arguments[1], kSequence_Precedence);
this->write(")");
}
break;
@ -379,12 +382,12 @@ void MetalCodeGenerator::writeSpecialIntrinsic(const FunctionCall & c, SpecialIn
// fmod(x, y) in metal calculates x - y * trunc(x / y) instead of x - y * floor(x / y)
String tmpX = "tmpX" + to_string(fVarCount++);
String tmpY = "tmpY" + to_string(fVarCount++);
this->fFunctionHeader += " " + this->typeName(c.fArguments[0]->type()) +
this->fFunctionHeader += " " + this->typeName(arguments[0]->type()) +
" " + tmpX + ", " + tmpY + ";\n";
this->write("(" + tmpX + " = ");
this->writeExpression(*c.fArguments[0], kSequence_Precedence);
this->writeExpression(*arguments[0], kSequence_Precedence);
this->write(", " + tmpY + " = ");
this->writeExpression(*c.fArguments[1], kSequence_Precedence);
this->writeExpression(*arguments[1], kSequence_Precedence);
this->write(", " + tmpX + " - " + tmpY + " * floor(" + tmpX + " / " + tmpY + "))");
break;
}
@ -1713,8 +1716,8 @@ MetalCodeGenerator::Requirements MetalCodeGenerator::requirements(const Expressi
switch (e->kind()) {
case Expression::Kind::kFunctionCall: {
const FunctionCall& f = e->as<FunctionCall>();
Requirements result = this->requirements(f.fFunction);
for (const auto& arg : f.fArguments) {
Requirements result = this->requirements(f.function());
for (const auto& arg : f.arguments()) {
result |= this->requirements(arg.get());
}
return result;

View File

@ -33,13 +33,15 @@ String PipelineStageCodeGenerator::getTypeName(const Type& type) {
}
void PipelineStageCodeGenerator::writeFunctionCall(const FunctionCall& c) {
if (c.fFunction.fBuiltin && c.fFunction.name() == "sample" &&
c.fArguments[0]->type().typeKind() != Type::TypeKind::kSampler) {
SkASSERT(c.fArguments.size() <= 2);
SkDEBUGCODE(const Type& arg0Type = c.fArguments[0]->type());
const FunctionDeclaration& function = c.function();
const std::vector<std::unique_ptr<Expression>>& arguments = c.arguments();
if (function.fBuiltin && function.name() == "sample" &&
arguments[0]->type().typeKind() != Type::TypeKind::kSampler) {
SkASSERT(arguments.size() <= 2);
SkDEBUGCODE(const Type& arg0Type = arguments[0]->type());
SkASSERT("fragmentProcessor" == arg0Type.name() ||
"fragmentProcessor?" == arg0Type.name());
SkASSERT(c.fArguments[0]->is<VariableReference>());
SkASSERT(arguments[0]->is<VariableReference>());
int index = 0;
bool found = false;
for (const auto& p : fProgram) {
@ -47,7 +49,7 @@ void PipelineStageCodeGenerator::writeFunctionCall(const FunctionCall& c) {
const VarDeclarations& decls = p.as<VarDeclarations>();
for (const std::unique_ptr<Statement>& raw : decls.fVars) {
VarDeclaration& decl = raw->as<VarDeclaration>();
if (decl.fVar == c.fArguments[0]->as<VariableReference>().fVariable) {
if (decl.fVar == arguments[0]->as<VariableReference>().fVariable) {
found = true;
} else if (decl.fVar->type() == *fContext.fFragmentProcessor_Type) {
++index;
@ -61,29 +63,29 @@ void PipelineStageCodeGenerator::writeFunctionCall(const FunctionCall& c) {
SkASSERT(found);
size_t childCallIndex = fArgs->fFormatArgs.size();
this->write(Compiler::kFormatArgPlaceholderStr);
bool matrixCall = c.fArguments.size() == 2 &&
c.fArguments[1]->type().typeKind() == Type::TypeKind::kMatrix;
bool matrixCall = arguments.size() == 2 &&
arguments[1]->type().typeKind() == Type::TypeKind::kMatrix;
fArgs->fFormatArgs.push_back(Compiler::FormatArg(
matrixCall ? Compiler::FormatArg::Kind::kChildProcessorWithMatrix
: Compiler::FormatArg::Kind::kChildProcessor,
index));
if (c.fArguments.size() > 1) {
if (arguments.size() > 1) {
OutputStream* oldOut = fOut;
StringStream buffer;
fOut = &buffer;
this->writeExpression(*c.fArguments[1], kSequence_Precedence);
this->writeExpression(*arguments[1], kSequence_Precedence);
fOut = oldOut;
fArgs->fFormatArgs[childCallIndex].fCoords = buffer.str();
}
return;
}
if (c.fFunction.fBuiltin) {
if (function.fBuiltin) {
INHERITED::writeFunctionCall(c);
} else {
int index = 0;
for (const ProgramElement& e : fProgram) {
if (e.kind() == ProgramElement::Kind::kFunction) {
if (&e.as<FunctionDefinition>().fDeclaration == &c.fFunction) {
if (&e.as<FunctionDefinition>().fDeclaration == &function) {
break;
}
++index;
@ -94,7 +96,7 @@ void PipelineStageCodeGenerator::writeFunctionCall(const FunctionCall& c) {
Compiler::FormatArg(Compiler::FormatArg::Kind::kFunctionName, index));
this->write("(");
const char* separator = "";
for (const std::unique_ptr<Expression>& arg : c.fArguments) {
for (const std::unique_ptr<Expression>& arg : arguments) {
this->write(separator);
separator = ", ";
this->writeExpression(*arg, kSequence_Precedence);

View File

@ -509,7 +509,7 @@ std::unique_ptr<Expression> Rehydrator::expression() {
for (int i = 0; i < argCount; ++i) {
args.push_back(this->expression());
}
return std::make_unique<FunctionCall>(-1, type, *f, std::move(args));
return std::make_unique<FunctionCall>(-1, type, f, std::move(args));
}
case Rehydrator::kIndex_Command: {
std::unique_ptr<Expression> base = this->expression();

View File

@ -691,11 +691,13 @@ SpvId SPIRVCodeGenerator::writeExpression(const Expression& expr, OutputStream&
}
SpvId SPIRVCodeGenerator::writeIntrinsicCall(const FunctionCall& c, OutputStream& out) {
auto intrinsic = fIntrinsicMap.find(c.fFunction.name());
const FunctionDeclaration& function = c.function();
const std::vector<std::unique_ptr<Expression>>& arguments = c.arguments();
auto intrinsic = fIntrinsicMap.find(function.name());
SkASSERT(intrinsic != fIntrinsicMap.end());
int32_t intrinsicId;
if (c.fArguments.size() > 0) {
const Type& type = c.fArguments[0]->type();
if (arguments.size() > 0) {
const Type& type = arguments[0]->type();
if (std::get<0>(intrinsic->second) == kSpecial_IntrinsicKind || is_float(fContext, type)) {
intrinsicId = std::get<1>(intrinsic->second);
} else if (is_signed(fContext, type)) {
@ -713,32 +715,32 @@ SpvId SPIRVCodeGenerator::writeIntrinsicCall(const FunctionCall& c, OutputStream
switch (std::get<0>(intrinsic->second)) {
case kGLSL_STD_450_IntrinsicKind: {
SpvId result = this->nextId();
std::vector<SpvId> arguments;
for (size_t i = 0; i < c.fArguments.size(); i++) {
if (c.fFunction.fParameters[i]->fModifiers.fFlags & Modifiers::kOut_Flag) {
arguments.push_back(this->getLValue(*c.fArguments[i], out)->getPointer());
std::vector<SpvId> argumentIds;
for (size_t i = 0; i < arguments.size(); i++) {
if (function.fParameters[i]->fModifiers.fFlags & Modifiers::kOut_Flag) {
argumentIds.push_back(this->getLValue(*arguments[i], out)->getPointer());
} else {
arguments.push_back(this->writeExpression(*c.fArguments[i], out));
argumentIds.push_back(this->writeExpression(*arguments[i], out));
}
}
this->writeOpCode(SpvOpExtInst, 5 + (int32_t) arguments.size(), out);
this->writeOpCode(SpvOpExtInst, 5 + (int32_t) argumentIds.size(), out);
this->writeWord(this->getType(c.type()), out);
this->writeWord(result, out);
this->writeWord(fGLSLExtendedInstructions, out);
this->writeWord(intrinsicId, out);
for (SpvId id : arguments) {
for (SpvId id : argumentIds) {
this->writeWord(id, out);
}
return result;
}
case kSPIRV_IntrinsicKind: {
SpvId result = this->nextId();
std::vector<SpvId> arguments;
for (size_t i = 0; i < c.fArguments.size(); i++) {
if (c.fFunction.fParameters[i]->fModifiers.fFlags & Modifiers::kOut_Flag) {
arguments.push_back(this->getLValue(*c.fArguments[i], out)->getPointer());
std::vector<SpvId> argumentIds;
for (size_t i = 0; i < arguments.size(); i++) {
if (function.fParameters[i]->fModifiers.fFlags & Modifiers::kOut_Flag) {
argumentIds.push_back(this->getLValue(*arguments[i], out)->getPointer());
} else {
arguments.push_back(this->writeExpression(*c.fArguments[i], out));
argumentIds.push_back(this->writeExpression(*arguments[i], out));
}
}
if (c.type() != *fContext.fVoid_Type) {
@ -748,7 +750,7 @@ SpvId SPIRVCodeGenerator::writeIntrinsicCall(const FunctionCall& c, OutputStream
} else {
this->writeOpCode((SpvOp_) intrinsicId, 1 + (int32_t) arguments.size(), out);
}
for (SpvId id : arguments) {
for (SpvId id : argumentIds) {
this->writeWord(id, out);
}
return result;
@ -820,28 +822,29 @@ void SPIRVCodeGenerator::writeGLSLExtendedInstruction(const Type& type, SpvId id
SpvId SPIRVCodeGenerator::writeSpecialIntrinsic(const FunctionCall& c, SpecialIntrinsic kind,
OutputStream& out) {
const std::vector<std::unique_ptr<Expression>>& arguments = c.arguments();
SpvId result = this->nextId();
const Type& callType = c.type();
switch (kind) {
case kAtan_SpecialIntrinsic: {
std::vector<SpvId> arguments;
for (size_t i = 0; i < c.fArguments.size(); i++) {
arguments.push_back(this->writeExpression(*c.fArguments[i], out));
std::vector<SpvId> argumentIds;
for (const std::unique_ptr<Expression>& arg : arguments) {
argumentIds.push_back(this->writeExpression(*arg, out));
}
this->writeOpCode(SpvOpExtInst, 5 + (int32_t) arguments.size(), out);
this->writeOpCode(SpvOpExtInst, 5 + (int32_t) argumentIds.size(), out);
this->writeWord(this->getType(callType), out);
this->writeWord(result, out);
this->writeWord(fGLSLExtendedInstructions, out);
this->writeWord(arguments.size() == 2 ? GLSLstd450Atan2 : GLSLstd450Atan, out);
for (SpvId id : arguments) {
this->writeWord(argumentIds.size() == 2 ? GLSLstd450Atan2 : GLSLstd450Atan, out);
for (SpvId id : argumentIds) {
this->writeWord(id, out);
}
break;
}
case kSampledImage_SpecialIntrinsic: {
SkASSERT(2 == c.fArguments.size());
SpvId img = this->writeExpression(*c.fArguments[0], out);
SpvId sampler = this->writeExpression(*c.fArguments[1], out);
SkASSERT(arguments.size() == 2);
SpvId img = this->writeExpression(*arguments[0], out);
SpvId sampler = this->writeExpression(*arguments[1], out);
this->writeInstruction(SpvOpSampledImage,
this->getType(callType),
result,
@ -851,13 +854,13 @@ SpvId SPIRVCodeGenerator::writeSpecialIntrinsic(const FunctionCall& c, SpecialIn
break;
}
case kSubpassLoad_SpecialIntrinsic: {
SpvId img = this->writeExpression(*c.fArguments[0], out);
SpvId img = this->writeExpression(*arguments[0], out);
std::vector<std::unique_ptr<Expression>> args;
args.emplace_back(new IntLiteral(fContext, -1, 0));
args.emplace_back(new IntLiteral(fContext, -1, 0));
Constructor ctor(-1, fContext.fInt2_Type.get(), std::move(args));
SpvId coords = this->writeConstantVector(ctor);
if (1 == c.fArguments.size()) {
if (arguments.size() == 1) {
this->writeInstruction(SpvOpImageRead,
this->getType(callType),
result,
@ -865,8 +868,8 @@ SpvId SPIRVCodeGenerator::writeSpecialIntrinsic(const FunctionCall& c, SpecialIn
coords,
out);
} else {
SkASSERT(2 == c.fArguments.size());
SpvId sample = this->writeExpression(*c.fArguments[1], out);
SkASSERT(arguments.size() == 2);
SpvId sample = this->writeExpression(*arguments[1], out);
this->writeInstruction(SpvOpImageRead,
this->getType(callType),
result,
@ -880,8 +883,8 @@ SpvId SPIRVCodeGenerator::writeSpecialIntrinsic(const FunctionCall& c, SpecialIn
}
case kTexture_SpecialIntrinsic: {
SpvOp_ op = SpvOpImageSampleImplicitLod;
const Type& arg1Type = c.fArguments[1]->type();
switch (c.fArguments[0]->type().dimensions()) {
const Type& arg1Type = arguments[1]->type();
switch (arguments[0]->type().dimensions()) {
case SpvDim1D:
if (arg1Type == *fContext.fFloat2_Type) {
op = SpvOpImageSampleProjImplicitLod;
@ -910,15 +913,15 @@ SpvId SPIRVCodeGenerator::writeSpecialIntrinsic(const FunctionCall& c, SpecialIn
break;
}
SpvId type = this->getType(callType);
SpvId sampler = this->writeExpression(*c.fArguments[0], out);
SpvId uv = this->writeExpression(*c.fArguments[1], out);
if (c.fArguments.size() == 3) {
SpvId sampler = this->writeExpression(*arguments[0], out);
SpvId uv = this->writeExpression(*arguments[1], out);
if (arguments.size() == 3) {
this->writeInstruction(op, type, result, sampler, uv,
SpvImageOperandsBiasMask,
this->writeExpression(*c.fArguments[2], out),
this->writeExpression(*arguments[2], out),
out);
} else {
SkASSERT(c.fArguments.size() == 2);
SkASSERT(arguments.size() == 2);
if (fProgram.fSettings.fSharpenTextures) {
FloatLiteral lodBias(fContext, -1, -0.5);
this->writeInstruction(op, type, result, sampler, uv,
@ -933,9 +936,9 @@ SpvId SPIRVCodeGenerator::writeSpecialIntrinsic(const FunctionCall& c, SpecialIn
break;
}
case kMod_SpecialIntrinsic: {
std::vector<SpvId> args = this->vectorize(c.fArguments, out);
std::vector<SpvId> args = this->vectorize(arguments, out);
SkASSERT(args.size() == 2);
const Type& operandType = c.fArguments[0]->type();
const Type& operandType = arguments[0]->type();
SpvOp_ op;
if (is_float(fContext, operandType)) {
op = SpvOpFMod;
@ -955,7 +958,7 @@ SpvId SPIRVCodeGenerator::writeSpecialIntrinsic(const FunctionCall& c, SpecialIn
break;
}
case kDFdy_SpecialIntrinsic: {
SpvId fn = this->writeExpression(*c.fArguments[0], out);
SpvId fn = this->writeExpression(*arguments[0], out);
this->writeOpCode(SpvOpDPdy, 4, out);
this->writeWord(this->getType(callType), out);
this->writeWord(result, out);
@ -971,37 +974,37 @@ SpvId SPIRVCodeGenerator::writeSpecialIntrinsic(const FunctionCall& c, SpecialIn
break;
}
case kClamp_SpecialIntrinsic: {
std::vector<SpvId> args = this->vectorize(c.fArguments, out);
std::vector<SpvId> args = this->vectorize(arguments, out);
SkASSERT(args.size() == 3);
this->writeGLSLExtendedInstruction(callType, result, GLSLstd450FClamp, GLSLstd450SClamp,
GLSLstd450UClamp, args, out);
break;
}
case kMax_SpecialIntrinsic: {
std::vector<SpvId> args = this->vectorize(c.fArguments, out);
std::vector<SpvId> args = this->vectorize(arguments, out);
SkASSERT(args.size() == 2);
this->writeGLSLExtendedInstruction(callType, result, GLSLstd450FMax, GLSLstd450SMax,
GLSLstd450UMax, args, out);
break;
}
case kMin_SpecialIntrinsic: {
std::vector<SpvId> args = this->vectorize(c.fArguments, out);
std::vector<SpvId> args = this->vectorize(arguments, out);
SkASSERT(args.size() == 2);
this->writeGLSLExtendedInstruction(callType, result, GLSLstd450FMin, GLSLstd450SMin,
GLSLstd450UMin, args, out);
break;
}
case kMix_SpecialIntrinsic: {
std::vector<SpvId> args = this->vectorize(c.fArguments, out);
std::vector<SpvId> args = this->vectorize(arguments, out);
SkASSERT(args.size() == 3);
this->writeGLSLExtendedInstruction(callType, result, GLSLstd450FMix, SpvOpUndef,
SpvOpUndef, args, out);
break;
}
case kSaturate_SpecialIntrinsic: {
SkASSERT(c.fArguments.size() == 1);
SkASSERT(arguments.size() == 1);
std::vector<std::unique_ptr<Expression>> finalArgs;
finalArgs.push_back(c.fArguments[0]->clone());
finalArgs.push_back(arguments[0]->clone());
finalArgs.emplace_back(new FloatLiteral(fContext, -1, 0));
finalArgs.emplace_back(new FloatLiteral(fContext, -1, 1));
std::vector<SpvId> spvArgs = this->vectorize(finalArgs, out);
@ -1014,24 +1017,26 @@ SpvId SPIRVCodeGenerator::writeSpecialIntrinsic(const FunctionCall& c, SpecialIn
}
SpvId SPIRVCodeGenerator::writeFunctionCall(const FunctionCall& c, OutputStream& out) {
const auto& entry = fFunctionMap.find(&c.fFunction);
const FunctionDeclaration& function = c.function();
const std::vector<std::unique_ptr<Expression>>& arguments = c.arguments();
const auto& entry = fFunctionMap.find(&function);
if (entry == fFunctionMap.end()) {
return this->writeIntrinsicCall(c, out);
}
// stores (variable, type, lvalue) pairs to extract and save after the function call is complete
std::vector<std::tuple<SpvId, const Type*, std::unique_ptr<LValue>>> lvalues;
std::vector<SpvId> arguments;
for (size_t i = 0; i < c.fArguments.size(); i++) {
std::vector<SpvId> argumentIds;
for (size_t i = 0; i < arguments.size(); i++) {
// id of temporary variable that we will use to hold this argument, or 0 if it is being
// passed directly
SpvId tmpVar;
// if we need a temporary var to store this argument, this is the value to store in the var
SpvId tmpValueId;
if (is_out(*c.fFunction.fParameters[i])) {
std::unique_ptr<LValue> lv = this->getLValue(*c.fArguments[i], out);
if (is_out(*function.fParameters[i])) {
std::unique_ptr<LValue> lv = this->getLValue(*arguments[i], out);
SpvId ptr = lv->getPointer();
if (ptr) {
arguments.push_back(ptr);
argumentIds.push_back(ptr);
continue;
} else {
// lvalue cannot simply be read and written via a pointer (e.g. a swizzle). Need to
@ -1039,28 +1044,28 @@ SpvId SPIRVCodeGenerator::writeFunctionCall(const FunctionCall& c, OutputStream&
// update the lvalue.
tmpValueId = lv->load(out);
tmpVar = this->nextId();
lvalues.push_back(std::make_tuple(tmpVar, &c.fArguments[i]->type(), std::move(lv)));
lvalues.push_back(std::make_tuple(tmpVar, &arguments[i]->type(), std::move(lv)));
}
} else {
// see getFunctionType for an explanation of why we're always using pointer parameters
tmpValueId = this->writeExpression(*c.fArguments[i], out);
tmpValueId = this->writeExpression(*arguments[i], out);
tmpVar = this->nextId();
}
this->writeInstruction(SpvOpVariable,
this->getPointerType(c.fArguments[i]->type(),
this->getPointerType(arguments[i]->type(),
SpvStorageClassFunction),
tmpVar,
SpvStorageClassFunction,
fVariableBuffer);
this->writeInstruction(SpvOpStore, tmpVar, tmpValueId, out);
arguments.push_back(tmpVar);
argumentIds.push_back(tmpVar);
}
SpvId result = this->nextId();
this->writeOpCode(SpvOpFunctionCall, 4 + (int32_t) c.fArguments.size(), out);
this->writeOpCode(SpvOpFunctionCall, 4 + (int32_t) arguments.size(), out);
this->writeWord(this->getType(c.type()), out);
this->writeWord(result, out);
this->writeWord(entry->second, out);
for (SpvId id : arguments) {
for (SpvId id : argumentIds) {
this->writeWord(id, out);
}
// now that the call is complete, we may need to update some lvalues with the new values of out

View File

@ -61,19 +61,21 @@ struct Expression : public IRNode {
: INHERITED(offset, (int) Kind::kBoolLiteral, data) {
}
Expression(int offset, const IntLiteralData& data)
: INHERITED(offset, (int) Kind::kIntLiteral, data) {
}
Expression(int offset, FloatLiteralData data)
: INHERITED(offset, (int) Kind::kFloatLiteral, data) {
}
Expression(int offset, Kind kind, ExternalValueData data)
Expression(int offset, Kind kind, const ExternalValueData& data)
: INHERITED(offset, (int) kind, data) {
SkASSERT(kind >= Kind::kFirst && kind <= Kind::kLast);
}
Expression(int offset, const FloatLiteralData& data)
: INHERITED(offset, (int) Kind::kFloatLiteral, data) {}
Expression(int offset, const FunctionCallData& data)
: INHERITED(offset, (int) Kind::kFunctionCall, data) {}
Expression(int offset, const IntLiteralData& data)
: INHERITED(offset, (int) Kind::kIntLiteral, data) {
}
Expression(int offset, Kind kind, const Type* type)
: INHERITED(offset, (int) kind, type) {
SkASSERT(kind >= Kind::kFirst && kind <= Kind::kLast);

View File

@ -19,24 +19,35 @@ namespace SkSL {
struct FunctionCall : public Expression {
static constexpr Kind kExpressionKind = Kind::kFunctionCall;
FunctionCall(int offset, const Type* type, const FunctionDeclaration& function,
FunctionCall(int offset, const Type* type, const FunctionDeclaration* function,
std::vector<std::unique_ptr<Expression>> arguments)
: INHERITED(offset, kExpressionKind, type)
, fFunction(std::move(function))
, fArguments(std::move(arguments)) {
++fFunction.fCallCount;
: INHERITED(offset, FunctionCallData{type, function}) {
fExpressionChildren = std::move(arguments);
++this->function().fCallCount;
}
~FunctionCall() override {
--fFunction.fCallCount;
--this->function().fCallCount;
}
const FunctionDeclaration& function() const {
return *this->functionCallData().fFunction;
}
std::vector<std::unique_ptr<Expression>>& arguments() {
return fExpressionChildren;
}
const std::vector<std::unique_ptr<Expression>>& arguments() const {
return fExpressionChildren;
}
bool hasProperty(Property property) const override {
if (property == Property::kSideEffects && (fFunction.fModifiers.fFlags &
if (property == Property::kSideEffects && (this->function().fModifiers.fFlags &
Modifiers::kHasSideEffects_Flag)) {
return true;
}
for (const auto& arg : fArguments) {
for (const auto& arg : this->arguments()) {
if (arg->hasProperty(property)) {
return true;
}
@ -46,28 +57,25 @@ struct FunctionCall : public Expression {
std::unique_ptr<Expression> clone() const override {
std::vector<std::unique_ptr<Expression>> cloned;
for (const auto& arg : fArguments) {
for (const auto& arg : this->arguments()) {
cloned.push_back(arg->clone());
}
return std::unique_ptr<Expression>(new FunctionCall(fOffset, &this->type(), fFunction,
std::move(cloned)));
return std::unique_ptr<Expression>(new FunctionCall(fOffset, &this->type(),
&this->function(), std::move(cloned)));
}
String description() const override {
String result = String(fFunction.name()) + "(";
String result = String(this->function().name()) + "(";
String separator;
for (size_t i = 0; i < fArguments.size(); i++) {
for (size_t i = 0; i < this->arguments().size(); i++) {
result += separator;
result += fArguments[i]->description();
result += this->arguments()[i]->description();
separator = ", ";
}
result += ")";
return result;
}
const FunctionDeclaration& fFunction;
std::vector<std::unique_ptr<Expression>> fArguments;
using INHERITED = Expression;
};

View File

@ -38,12 +38,17 @@ IRNode::IRNode(int offset, int kind, const FieldData& data)
, fKind(kind)
, fData(data) {}
IRNode::IRNode(int offset, int kind, const IntLiteralData& data)
IRNode::IRNode(int offset, int kind, const FloatLiteralData& data)
: fOffset(offset)
, fKind(kind)
, fData(data) {}
IRNode::IRNode(int offset, int kind, const FloatLiteralData& data)
IRNode::IRNode(int offset, int kind, const FunctionCallData& data)
: fOffset(offset)
, fKind(kind)
, fData(data) {}
IRNode::IRNode(int offset, int kind, const IntLiteralData& data)
: fOffset(offset)
, fKind(kind)
, fData(data) {}

View File

@ -19,6 +19,7 @@ namespace SkSL {
struct Expression;
class ExternalValue;
struct FunctionDeclaration;
struct Statement;
class SymbolTable;
class Type;
@ -56,12 +57,14 @@ public:
return *this->boolLiteralData().fType;
case NodeData::Kind::kExternalValue:
return *this->externalValueData().fType;
case NodeData::Kind::kIntLiteral:
return *this->intLiteralData().fType;
case NodeData::Kind::kField:
return *this->fieldData().fType;
case NodeData::Kind::kFloatLiteral:
return *this->floatLiteralData().fType;
case NodeData::Kind::kFunctionCall:
return *this->functionCallData().fType;
case NodeData::Kind::kIntLiteral:
return *this->intLiteralData().fType;
case NodeData::Kind::kSymbol:
return *this->symbolData().fType;
case NodeData::Kind::kType:
@ -114,6 +117,11 @@ protected:
std::shared_ptr<SymbolTable> fSymbolTable;
};
struct FunctionCallData {
const Type* fType;
const FunctionDeclaration* fFunction;
};
struct IntLiteralData {
const Type* fType;
int64_t fValue;
@ -138,6 +146,7 @@ protected:
kField,
kFloatLiteral,
kForStatement,
kFunctionCall,
kIntLiteral,
kString,
kSymbol,
@ -154,6 +163,7 @@ protected:
FieldData fField;
FloatLiteralData fFloatLiteral;
ForStatementData fForStatement;
FunctionCallData fFunctionCall;
IntLiteralData fIntLiteral;
String fString;
SymbolData fSymbol;
@ -200,6 +210,11 @@ protected:
*(new(&fContents) ForStatementData) = data;
}
NodeData(const FunctionCallData& data)
: fKind(Kind::kFunctionCall) {
*(new(&fContents) FunctionCallData) = data;
}
NodeData(IntLiteralData data)
: fKind(Kind::kIntLiteral) {
*(new(&fContents) IntLiteralData) = data;
@ -254,6 +269,9 @@ protected:
case Kind::kForStatement:
*(new(&fContents) ForStatementData) = other.fContents.fForStatement;
break;
case Kind::kFunctionCall:
*(new(&fContents) FunctionCallData) = other.fContents.fFunctionCall;
break;
case Kind::kIntLiteral:
*(new(&fContents) IntLiteralData) = other.fContents.fIntLiteral;
break;
@ -301,6 +319,9 @@ protected:
case Kind::kForStatement:
fContents.fForStatement.~ForStatementData();
break;
case Kind::kFunctionCall:
fContents.fFunctionCall.~FunctionCallData();
break;
case Kind::kIntLiteral:
fContents.fIntLiteral.~IntLiteralData();
break;
@ -334,6 +355,8 @@ protected:
IRNode(int offset, int kind, const ForStatementData& data);
IRNode(int offset, int kind, const FunctionCallData& data);
IRNode(int offset, int kind, const IntLiteralData& data);
IRNode(int offset, int kind, const String& data);
@ -425,6 +448,11 @@ protected:
return fData.fContents.fForStatement;
}
const FunctionCallData& functionCallData() const {
SkASSERT(fData.fKind == NodeData::Kind::kFunctionCall);
return fData.fContents.fFunctionCall;
}
const IntLiteralData& intLiteralData() const {
SkASSERT(fData.fKind == NodeData::Kind::kIntLiteral);
return fData.fContents.fIntLiteral;