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:
parent
7a7bec371a
commit
0dec9927af
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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));
|
||||
|
@ -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()");
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
@ -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) {}
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user