moved SkSL FunctionDeclaration data into IRNode

Change-Id: I97a59563914c4f75f8cfdc2bd5a9ae430de9bb3c
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/323881
Commit-Queue: Ethan Nicholas <ethannicholas@google.com>
Reviewed-by: Brian Osman <brianosman@google.com>
This commit is contained in:
Ethan Nicholas 2020-10-08 11:45:44 -04:00 committed by Skia Commit-Bot
parent 9eaca48f46
commit ed84b73797
19 changed files with 241 additions and 143 deletions

View File

@ -65,7 +65,7 @@ namespace {
static bool is_sample_call_to_fp(const FunctionCall& fc, const Variable& fp) {
const FunctionDeclaration& f = fc.function();
return f.fBuiltin && f.name() == "sample" && fc.arguments().size() >= 1 &&
return f.isBuiltin() && f.name() == "sample" && fc.arguments().size() >= 1 &&
fc.arguments()[0]->is<VariableReference>() &&
fc.arguments()[0]->as<VariableReference>().variable() == &fp;
}

View File

@ -17,7 +17,7 @@
namespace SkSL {
class ExternalValue;
struct FunctionDeclaration;
class FunctionDeclaration;
enum class ByteCodeInstruction : uint8_t {
// B = bool, F = float, I = int, S = signed, U = unsigned

View File

@ -204,7 +204,7 @@ std::unique_ptr<ByteCodeFunction> ByteCodeGenerator::writeFunction(const Functio
result->fLoopCount = fMaxLoopCount;
result->fStackCount = fMaxStackCount;
const Type& returnType = f.fDeclaration.fReturnType;
const Type& returnType = f.fDeclaration.returnType();
if (returnType != *fContext.fVoid_Type) {
result->fReturnCount = SlotCount(returnType);
}
@ -441,7 +441,7 @@ ByteCodeGenerator::Location ByteCodeGenerator::getLocation(const Variable& var)
}
case Variable::kParameter_Storage: {
int offset = 0;
for (const auto& p : fFunction->fDeclaration.fParameters) {
for (const auto& p : fFunction->fDeclaration.parameters()) {
if (p == &var) {
SkASSERT(offset <= 255);
return { offset, Storage::kLocal };
@ -1263,7 +1263,7 @@ void ByteCodeGenerator::writeFunctionCall(const FunctionCall& f) {
int argCount = f.arguments().size();
std::vector<std::unique_ptr<LValue>> lvalues;
for (int i = 0; i < argCount; ++i) {
const auto& param = f.function().fParameters[i];
const auto& param = f.function().parameters()[i];
const auto& arg = f.arguments()[i];
if (param->modifiers().fFlags & Modifiers::kOut_Flag) {
lvalues.emplace_back(this->getLValue(*arg));
@ -1296,7 +1296,7 @@ void ByteCodeGenerator::writeFunctionCall(const FunctionCall& f) {
};
for (int i = argCount - 1; i >= 0; --i) {
const auto& param = f.function().fParameters[i];
const auto& param = f.function().parameters()[i];
const auto& arg = f.arguments()[i];
if (param->modifiers().fFlags & Modifiers::kOut_Flag) {
pop();
@ -1832,7 +1832,7 @@ void ByteCodeGenerator::writeStatement(const Statement& s) {
ByteCodeFunction::ByteCodeFunction(const FunctionDeclaration* declaration)
: fName(declaration->name()) {
fParameterCount = 0;
for (const auto& p : declaration->fParameters) {
for (const auto& p : declaration->parameters()) {
int slots = ByteCodeGenerator::SlotCount(p->type());
fParameters.push_back({ slots, (bool)(p->modifiers().fFlags & Modifiers::kOut_Flag) });
fParameterCount += slots;

View File

@ -429,7 +429,7 @@ int CPPCodeGenerator::getChildFPIndex(const Variable& var) const {
void CPPCodeGenerator::writeFunctionCall(const FunctionCall& c) {
const FunctionDeclaration& function = c.function();
const std::vector<std::unique_ptr<Expression>>& arguments = c.arguments();
if (function.fBuiltin && function.name() == "sample" &&
if (function.isBuiltin() && function.name() == "sample" &&
arguments[0]->type().typeKind() != Type::TypeKind::kSampler) {
// Validity checks that are detected by function definition in sksl_fp.inc
SkASSERT(arguments.size() >= 1 && arguments.size() <= 3);
@ -495,7 +495,7 @@ void CPPCodeGenerator::writeFunctionCall(const FunctionCall& c) {
fFormatArgs.push_back(childName + ".c_str()");
return;
}
if (function.fBuiltin) {
if (function.isBuiltin()) {
INHERITED::writeFunctionCall(c);
} else {
this->write("%s");
@ -509,7 +509,7 @@ void CPPCodeGenerator::writeFunctionCall(const FunctionCall& c) {
}
this->write(")");
}
if (function.fBuiltin && function.name() == "sample") {
if (function.isBuiltin() && function.name() == "sample") {
this->write(".%s");
SkASSERT(arguments.size() >= 1);
SkASSERT(arguments[0]->is<VariableReference>());
@ -594,7 +594,7 @@ static const char* glsltype_string(const Context& context, const Type& type) {
void CPPCodeGenerator::writeFunction(const FunctionDefinition& f) {
const FunctionDeclaration& decl = f.fDeclaration;
if (decl.fBuiltin) {
if (decl.isBuiltin()) {
return;
}
fFunctionHeader = "";
@ -616,7 +616,7 @@ void CPPCodeGenerator::writeFunction(const FunctionDefinition& f) {
this->addExtraEmitCodeLine("SkString " + decl.name() + "_name;");
String args = "const GrShaderVar " + decl.name() + "_args[] = { ";
const char* separator = "";
for (const Variable* param : decl.fParameters) {
for (const Variable* param : decl.parameters()) {
args += String(separator) + "GrShaderVar(\"" + param->name() + "\", " +
glsltype_string(fContext, param->type()) + ")";
separator = ", ";
@ -630,9 +630,9 @@ void CPPCodeGenerator::writeFunction(const FunctionDefinition& f) {
fOut = oldOut;
String emit = "fragBuilder->emitFunction(";
emit += glsltype_string(fContext, decl.fReturnType);
emit += glsltype_string(fContext, decl.returnType());
emit += ", \"" + decl.name() + "\"";
emit += ", " + to_string((int64_t) decl.fParameters.size());
emit += ", " + to_string((int64_t) decl.parameters().size());
emit += ", " + decl.name() + "_args";
emit += ",\nR\"SkSL(" + buffer.str() + ")SkSL\"";
emit += ", &" + decl.name() + "_name);";

View File

@ -77,7 +77,7 @@ static void grab_intrinsics(std::vector<std::unique_ptr<ProgramElement>>* src,
switch (element->kind()) {
case ProgramElement::Kind::kFunction: {
const FunctionDefinition& f = element->as<FunctionDefinition>();
SkASSERT(f.fDeclaration.fBuiltin);
SkASSERT(f.fDeclaration.isBuiltin());
target->insertOrDie(f.fDeclaration.description(), std::move(element));
break;
}
@ -111,7 +111,7 @@ static void reset_call_counts(std::vector<std::unique_ptr<ProgramElement>>* src)
for (std::unique_ptr<ProgramElement>& element : *src) {
if (element->is<FunctionDefinition>()) {
const FunctionDeclaration& fnDecl = element->as<FunctionDefinition>().fDeclaration;
fnDecl.fCallCount = 0;
fnDecl.callCount() = 0;
}
}
}
@ -512,8 +512,9 @@ void Compiler::addDefinitions(const BasicBlock::Node& node,
}
case Expression::Kind::kFunctionCall: {
const FunctionCall& c = expr->as<FunctionCall>();
for (size_t i = 0; i < c.function().fParameters.size(); ++i) {
if (c.function().fParameters[i]->modifiers().fFlags & Modifiers::kOut_Flag) {
const std::vector<Variable*>& parameters = c.function().parameters();
for (size_t i = 0; i < parameters.size(); ++i) {
if (parameters[i]->modifiers().fFlags & Modifiers::kOut_Flag) {
this->addDefinition(
c.arguments()[i].get(),
(std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
@ -1572,7 +1573,7 @@ bool Compiler::scanCFG(FunctionDefinition& f) {
}
// check for missing return
if (f.fDeclaration.fReturnType != *fContext->fVoid_Type) {
if (f.fDeclaration.returnType() != *fContext->fVoid_Type) {
if (cfg.fBlocks[cfg.fExit].fIsReachable) {
this->error(f.fOffset, String("function '" + String(f.fDeclaration.name()) +
"' can exit without returning a value"));
@ -1680,7 +1681,7 @@ bool Compiler::optimize(Program& program) {
return false;
}
const auto& fn = element->as<FunctionDefinition>();
bool dead = fn.fDeclaration.fCallCount == 0 &&
bool dead = fn.fDeclaration.callCount() == 0 &&
fn.fDeclaration.name() != "main";
madeChanges |= dead;
return dead;

View File

@ -148,13 +148,13 @@ void Dehydrator::write(const Symbol& s) {
const FunctionDeclaration& f = s.as<FunctionDeclaration>();
this->writeU8(Rehydrator::kFunctionDeclaration_Command);
this->writeId(&f);
this->write(f.fModifiers);
this->write(f.modifiers());
this->write(f.name());
this->writeU8(f.fParameters.size());
for (const Variable* p : f.fParameters) {
this->writeU8(f.parameters().size());
for (const Variable* p : f.parameters()) {
this->writeU16(this->symbolId(p));
}
this->write(f.fReturnType);
this->write(f.returnType());
break;
}
case Symbol::Kind::kSymbolAlias: {

View File

@ -482,8 +482,8 @@ void GLSLCodeGenerator::writeFunctionCall(const FunctionCall& c) {
#ifndef SKSL_STANDALONE
);
#endif
const auto found = function.fBuiltin ? fFunctionClasses->find(function.name()) :
fFunctionClasses->end();
const auto found = function.isBuiltin() ? fFunctionClasses->find(function.name()) :
fFunctionClasses->end();
bool isTextureFunctionWithBias = false;
bool nameWritten = false;
if (found != fFunctionClasses->end()) {
@ -1043,11 +1043,11 @@ void GLSLCodeGenerator::writeFunction(const FunctionDefinition& f) {
// accidentally end up here.
SkASSERT(fProgramKind != Program::kPipelineStage_Kind);
this->writeTypePrecision(f.fDeclaration.fReturnType);
this->writeType(f.fDeclaration.fReturnType);
this->writeTypePrecision(f.fDeclaration.returnType());
this->writeType(f.fDeclaration.returnType());
this->write(" " + f.fDeclaration.name() + "(");
const char* separator = "";
for (const auto& param : f.fDeclaration.fParameters) {
for (const auto& param : f.fDeclaration.parameters()) {
this->write(separator);
separator = ", ";
this->writeModifiers(param->modifiers(), false);

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.function().fBuiltin && fc.function().name() == "EmitVertex") {
if (fc.function().isBuiltin() && fc.function().name() == "EmitVertex") {
std::vector<std::unique_ptr<Statement>> statements;
statements.push_back(getNormalizeSkPositionCode());
statements.push_back(std::move(result));
@ -718,20 +718,20 @@ std::unique_ptr<Statement> IRGenerator::convertReturn(const ASTNode& r) {
if (!result) {
return nullptr;
}
if (fCurrentFunction->fReturnType == *fContext.fVoid_Type) {
if (fCurrentFunction->returnType() == *fContext.fVoid_Type) {
fErrors.error(result->fOffset, "may not return a value from a void function");
return nullptr;
} else {
result = this->coerce(std::move(result), fCurrentFunction->fReturnType);
result = this->coerce(std::move(result), fCurrentFunction->returnType());
if (!result) {
return nullptr;
}
}
return std::unique_ptr<Statement>(new ReturnStatement(std::move(result)));
} else {
if (fCurrentFunction->fReturnType != *fContext.fVoid_Type) {
if (fCurrentFunction->returnType() != *fContext.fVoid_Type) {
fErrors.error(r.fOffset, "expected function to return '" +
fCurrentFunction->fReturnType.displayName() + "'");
fCurrentFunction->returnType().displayName() + "'");
}
return std::unique_ptr<Statement>(new ReturnStatement(r.fOffset));
}
@ -766,12 +766,13 @@ std::unique_ptr<Block> IRGenerator::applyInvocationIDWorkaround(std::unique_ptr<
Layout invokeLayout;
Modifiers invokeModifiers(invokeLayout, Modifiers::kHasSideEffects_Flag);
const FunctionDeclaration* invokeDecl =
fSymbolTable->add(std::make_unique<FunctionDeclaration>(/*offset=*/-1,
invokeModifiers,
"_invoke",
std::vector<Variable*>(),
*fContext.fVoid_Type,
/*builtin=*/false));
fSymbolTable->add(std::make_unique<FunctionDeclaration>(
/*offset=*/-1,
fModifiers->handle(invokeModifiers),
"_invoke",
std::vector<Variable*>(),
fContext.fVoid_Type.get(),
/*builtin=*/false));
fProgramElements->push_back(std::make_unique<FunctionDefinition>(/*offset=*/-1,
*invokeDecl,
std::move(main)));
@ -1019,18 +1020,22 @@ void IRGenerator::convertFunction(const ASTNode& f) {
}
for (const FunctionDeclaration* other : functions) {
SkASSERT(other->name() == funcData.fName);
if (parameters.size() == other->fParameters.size()) {
if (parameters.size() == other->parameters().size()) {
bool match = true;
for (size_t i = 0; i < parameters.size(); i++) {
if (parameters[i]->type() != other->fParameters[i]->type()) {
if (parameters[i]->type() != other->parameters()[i]->type()) {
match = false;
break;
}
}
if (match) {
if (*returnType != other->fReturnType) {
FunctionDeclaration newDecl(f.fOffset, funcData.fModifiers, funcData.fName,
parameters, *returnType, fIsBuiltinCode);
if (*returnType != other->returnType()) {
FunctionDeclaration newDecl(f.fOffset,
fModifiers->handle(funcData.fModifiers),
funcData.fName,
parameters,
returnType,
fIsBuiltinCode);
fErrors.error(f.fOffset, "functions '" + newDecl.description() +
"' and '" + other->description() +
"' differ only in return type");
@ -1038,14 +1043,14 @@ void IRGenerator::convertFunction(const ASTNode& f) {
}
decl = other;
for (size_t i = 0; i < parameters.size(); i++) {
if (parameters[i]->modifiers() != other->fParameters[i]->modifiers()) {
if (parameters[i]->modifiers() != other->parameters()[i]->modifiers()) {
fErrors.error(f.fOffset, "modifiers on parameter " +
to_string((uint64_t) i + 1) +
" differ between declaration and definition");
return;
}
}
if (other->fDefinition && !other->fBuiltin) {
if (other->definition() && !other->isBuiltin()) {
fErrors.error(f.fOffset, "duplicate definition of " + other->description());
}
break;
@ -1061,12 +1066,13 @@ void IRGenerator::convertFunction(const ASTNode& f) {
}
// Create a new declaration.
decl = fSymbolTable->add(std::make_unique<FunctionDeclaration>(f.fOffset,
declModifiers,
funcData.fName,
parameters,
*returnType,
fIsBuiltinCode));
decl = fSymbolTable->add(std::make_unique<FunctionDeclaration>(
f.fOffset,
fModifiers->handle(declModifiers),
funcData.fName,
parameters,
returnType,
fIsBuiltinCode));
}
if (iter != f.end()) {
// compile body
@ -1083,8 +1089,9 @@ void IRGenerator::convertFunction(const ASTNode& f) {
parameters[0]->setModifiersHandle(fModifiers->handle(m));
}
}
const std::vector<Variable*>& declParameters = decl->parameters();
for (size_t i = 0; i < parameters.size(); i++) {
fSymbolTable->addWithoutOwnership(decl->fParameters[i]);
fSymbolTable->addWithoutOwnership(declParameters[i]);
}
bool needInvocationIDWorkaround = fInvocations != -1 && funcData.fName == "main" &&
fSettings->fCaps &&
@ -1102,7 +1109,7 @@ void IRGenerator::convertFunction(const ASTNode& f) {
}
auto result = std::make_unique<FunctionDefinition>(f.fOffset, *decl, std::move(body),
std::move(fReferencedIntrinsics));
decl->fDefinition = result.get();
decl->setDefinition(result.get());
result->fSource = &f;
fProgramElements->push_back(std::move(result));
}
@ -2045,8 +2052,8 @@ void IRGenerator::copyIntrinsicIfNeeded(const FunctionDeclaration& function) {
original.fReferencedIntrinsics.end());
std::sort(intrinsics.begin(), intrinsics.end(),
[](const FunctionDeclaration* a, const FunctionDeclaration* b) {
if (a->fBuiltin != b->fBuiltin) {
return a->fBuiltin < b->fBuiltin;
if (a->isBuiltin() != b->isBuiltin()) {
return a->isBuiltin() < b->isBuiltin();
}
if (a->fOffset != b->fOffset) {
return a->fOffset < b->fOffset;
@ -2066,26 +2073,26 @@ void IRGenerator::copyIntrinsicIfNeeded(const FunctionDeclaration& function) {
std::unique_ptr<Expression> IRGenerator::call(int offset,
const FunctionDeclaration& function,
std::vector<std::unique_ptr<Expression>> arguments) {
if (function.fBuiltin) {
if (function.fDefinition) {
if (function.isBuiltin()) {
if (function.definition()) {
fReferencedIntrinsics.insert(&function);
}
if (!fIsBuiltinCode && fIntrinsics) {
this->copyIntrinsicIfNeeded(function);
}
}
if (function.fParameters.size() != arguments.size()) {
if (function.parameters().size() != arguments.size()) {
String msg = "call to '" + function.name() + "' expected " +
to_string((uint64_t) function.fParameters.size()) +
to_string((uint64_t) function.parameters().size()) +
" argument";
if (function.fParameters.size() != 1) {
if (function.parameters().size() != 1) {
msg += "s";
}
msg += ", but found " + to_string((uint64_t) arguments.size());
fErrors.error(offset, msg);
return nullptr;
}
if (fKind == Program::kPipelineStage_Kind && !function.fDefinition && !function.fBuiltin) {
if (fKind == Program::kPipelineStage_Kind && !function.definition() && !function.isBuiltin()) {
String msg = "call to undefined function '" + function.name() + "'";
fErrors.error(offset, msg);
return nullptr;
@ -2109,7 +2116,7 @@ std::unique_ptr<Expression> IRGenerator::call(int offset,
if (!arguments[i]) {
return nullptr;
}
const Modifiers& paramModifiers = function.fParameters[i]->modifiers();
const Modifiers& paramModifiers = function.parameters()[i]->modifiers();
if (paramModifiers.fFlags & Modifiers::kOut_Flag) {
if (!this->setRefKind(*arguments[i], paramModifiers.fFlags & Modifiers::kIn_Flag
? VariableReference::kReadWrite_RefKind
@ -2122,8 +2129,8 @@ std::unique_ptr<Expression> IRGenerator::call(int offset,
auto funcCall = std::make_unique<FunctionCall>(offset, returnType, &function,
std::move(arguments));
if (fCanInline &&
fInliner->isSafeToInline(funcCall->function().fDefinition) &&
!fInliner->isLargeFunction(funcCall->function().fDefinition)) {
fInliner->isSafeToInline(funcCall->function().definition()) &&
!fInliner->isLargeFunction(funcCall->function().definition())) {
Inliner::InlinedCall inlinedCall = fInliner->inlineCall(funcCall.get(), fSymbolTable.get(),
fCurrentFunction);
if (inlinedCall.fInlinedBody) {
@ -2142,7 +2149,7 @@ std::unique_ptr<Expression> IRGenerator::call(int offset,
*/
CoercionCost IRGenerator::callCost(const FunctionDeclaration& function,
const std::vector<std::unique_ptr<Expression>>& arguments) {
if (function.fParameters.size() != arguments.size()) {
if (function.parameters().size() != arguments.size()) {
return CoercionCost::Impossible();
}
std::vector<const Type*> types;

View File

@ -166,8 +166,8 @@ static bool contains_recursive_call(const FunctionDeclaration& funcDecl) {
public:
bool visit(const FunctionDeclaration& funcDecl) {
fFuncDecl = &funcDecl;
return funcDecl.fDefinition ? this->visitProgramElement(*funcDecl.fDefinition)
: false;
return funcDecl.definition() ? this->visitProgramElement(*funcDecl.definition())
: false;
}
bool visitExpression(const Expression& expr) override {
@ -587,11 +587,11 @@ Inliner::InlinedCall Inliner::inlineCall(FunctionCall* call,
SkASSERT(fSettings);
SkASSERT(fContext);
SkASSERT(call);
SkASSERT(this->isSafeToInline(call->function().fDefinition));
SkASSERT(this->isSafeToInline(call->function().definition()));
std::vector<std::unique_ptr<Expression>>& arguments = call->arguments();
const int offset = call->fOffset;
const FunctionDefinition& function = *call->function().fDefinition;
const FunctionDefinition& function = *call->function().definition();
const bool hasEarlyReturn = has_early_return(function);
InlinedCall inlinedCall;
@ -632,7 +632,7 @@ Inliner::InlinedCall Inliner::inlineCall(FunctionCall* call,
// Add our new variable to the symbol table.
const Variable* variableSymbol = symbolTableForCall->add(std::make_unique<Variable>(
/*offset=*/-1, fModifiers->handle(Modifiers()),
nameFrag, type, caller->fBuiltin,
nameFrag, type, caller->isBuiltin(),
Variable::kLocal_Storage, initialValue->get()));
// Prepare the variable declaration (taking extra care with `out` params to not clobber any
@ -656,10 +656,10 @@ Inliner::InlinedCall Inliner::inlineCall(FunctionCall* call,
// Create a variable to hold the result in the extra statements (excepting void).
std::unique_ptr<Expression> resultExpr;
if (function.fDeclaration.fReturnType != *fContext->fVoid_Type) {
if (function.fDeclaration.returnType() != *fContext->fVoid_Type) {
std::unique_ptr<Expression> noInitialValue;
resultExpr = makeInlineVar(String(function.fDeclaration.name()),
&function.fDeclaration.fReturnType,
&function.fDeclaration.returnType(),
Modifiers{}, &noInitialValue);
}
@ -668,7 +668,7 @@ Inliner::InlinedCall Inliner::inlineCall(FunctionCall* call,
VariableRewriteMap varMap;
std::vector<int> argsToCopyBack;
for (int i = 0; i < (int) arguments.size(); ++i) {
const Variable* param = function.fDeclaration.fParameters[i];
const Variable* param = function.fDeclaration.parameters()[i];
bool isOutParam = param->modifiers().fFlags & Modifiers::kOut_Flag;
// If this argument can be inlined trivially (e.g. a swizzle, or a constant array index)...
@ -695,7 +695,7 @@ Inliner::InlinedCall Inliner::inlineCall(FunctionCall* call,
for (const std::unique_ptr<Statement>& stmt : body.children()) {
inlineBlock->children().push_back(this->inlineStatement(offset, &varMap, symbolTableForCall,
resultExpr.get(), hasEarlyReturn,
*stmt, caller->fBuiltin));
*stmt, caller->isBuiltin()));
}
if (hasEarlyReturn) {
// Since we output to backends that don't have a goto statement (which would normally be
@ -714,7 +714,7 @@ Inliner::InlinedCall Inliner::inlineCall(FunctionCall* call,
// Copy back the values of `out` parameters into their real destinations.
for (int i : argsToCopyBack) {
const Variable* p = function.fDeclaration.fParameters[i];
const Variable* p = function.fDeclaration.parameters()[i];
SkASSERT(varMap.find(p) != varMap.end());
inlinedBody.children().push_back(
std::make_unique<ExpressionStatement>(std::make_unique<BinaryExpression>(
@ -1071,7 +1071,7 @@ bool Inliner::candidateCanBeInlined(const InlineCandidate& candidate, Inlinabili
auto [iter, wasInserted] = cache->insert({&funcDecl, false});
if (wasInserted) {
// Recursion is forbidden here to avoid an infinite death spiral of inlining.
iter->second = this->isSafeToInline(funcDecl.fDefinition) &&
iter->second = this->isSafeToInline(funcDecl.definition()) &&
!contains_recursive_call(funcDecl);
}
@ -1088,7 +1088,7 @@ bool Inliner::isLargeFunction(const InlineCandidate& candidate, LargeFunctionCac
auto [iter, wasInserted] = cache->insert({&funcDecl, false});
if (wasInserted) {
iter->second = this->isLargeFunction(funcDecl.fDefinition);
iter->second = this->isLargeFunction(funcDecl.definition());
}
return iter->second;
@ -1135,8 +1135,8 @@ bool Inliner::analyze(Program& program) {
// If the function is large, not marked `inline`, and is called more than once, it's a bad
// idea to inline it.
if (candidate.fIsLargeFunction &&
!(funcDecl->fModifiers.fFlags & Modifiers::kInline_Flag) &&
funcDecl->fCallCount.load() > 1) {
!(funcDecl->modifiers().fFlags & Modifiers::kInline_Flag) &&
funcDecl->callCount() > 1) {
continue;
}

View File

@ -220,16 +220,17 @@ void MetalCodeGenerator::writeFunctionCall(const FunctionCall& c) {
return;
}
const StringFragment& name = function.name();
if (function.fBuiltin && name == "atan" && arguments.size() == 2) {
bool builtin = function.isBuiltin();
if (builtin && name == "atan" && arguments.size() == 2) {
this->write("atan2");
} else if (function.fBuiltin && name == "inversesqrt") {
} else if (builtin && name == "inversesqrt") {
this->write("rsqrt");
} else if (function.fBuiltin && name == "inverse") {
} else if (builtin && name == "inverse") {
SkASSERT(arguments.size() == 1);
this->writeInverseHack(*arguments[0]);
} else if (function.fBuiltin && name == "dFdx") {
} else if (builtin && name == "dFdx") {
this->write("dfdx");
} else if (function.fBuiltin && name == "dFdy") {
} else if (builtin && name == "dFdy") {
// Flipping Y also negates the Y derivatives.
this->write((fProgram.fSettings.fFlipY) ? "-dfdy" : "dfdy");
} else {
@ -261,11 +262,12 @@ void MetalCodeGenerator::writeFunctionCall(const FunctionCall& c) {
this->write("_fragCoord");
separator = ", ";
}
const std::vector<Variable*>& parameters = function.parameters();
for (size_t i = 0; i < arguments.size(); ++i) {
const Expression& arg = *arguments[i];
this->write(separator);
separator = ", ";
if (function.fParameters[i]->modifiers().fFlags & Modifiers::kOut_Flag) {
if (parameters[i]->modifiers().fFlags & Modifiers::kOut_Flag) {
this->write("&");
}
this->writeExpression(arg, kSequence_Precedence);
@ -1004,7 +1006,7 @@ void MetalCodeGenerator::writeFunction(const FunctionDefinition& f) {
}
separator = ", ";
} else {
this->writeType(f.fDeclaration.fReturnType);
this->writeType(f.fDeclaration.returnType());
this->write(" ");
this->writeName(f.fDeclaration.name());
this->write("(");
@ -1034,7 +1036,7 @@ void MetalCodeGenerator::writeFunction(const FunctionDefinition& f) {
separator = ", ";
}
}
for (const auto& param : f.fDeclaration.fParameters) {
for (const auto& param : f.fDeclaration.parameters()) {
this->write(separator);
separator = ", ";
this->writeModifiers(param->modifiers(), false);
@ -1801,7 +1803,7 @@ MetalCodeGenerator::Requirements MetalCodeGenerator::requirements(const Statemen
}
MetalCodeGenerator::Requirements MetalCodeGenerator::requirements(const FunctionDeclaration& f) {
if (f.fBuiltin) {
if (f.isBuiltin()) {
return kNo_Requirements;
}
auto found = fRequirements.find(&f);

View File

@ -35,7 +35,7 @@ String PipelineStageCodeGenerator::getTypeName(const Type& type) {
void PipelineStageCodeGenerator::writeFunctionCall(const FunctionCall& c) {
const FunctionDeclaration& function = c.function();
const std::vector<std::unique_ptr<Expression>>& arguments = c.arguments();
if (function.fBuiltin && function.name() == "sample" &&
if (function.isBuiltin() && function.name() == "sample" &&
arguments[0]->type().typeKind() != Type::TypeKind::kSampler) {
SkASSERT(arguments.size() <= 2);
SkDEBUGCODE(const Type& arg0Type = arguments[0]->type());
@ -76,7 +76,7 @@ void PipelineStageCodeGenerator::writeFunctionCall(const FunctionCall& c) {
}
return;
}
if (function.fBuiltin) {
if (function.isBuiltin()) {
INHERITED::writeFunctionCall(c);
} else {
int index = 0;
@ -184,12 +184,12 @@ void PipelineStageCodeGenerator::writeFunction(const FunctionDefinition& f) {
} else {
const FunctionDeclaration& decl = f.fDeclaration;
Compiler::GLSLFunction result;
if (!type_to_grsltype(fContext, decl.fReturnType, &result.fReturnType)) {
if (!type_to_grsltype(fContext, decl.returnType(), &result.fReturnType)) {
fErrors.error(f.fOffset, "unsupported return type");
return;
}
result.fName = decl.name();
for (const Variable* v : decl.fParameters) {
for (const Variable* v : decl.parameters()) {
GrSLType paramSLType;
if (!type_to_grsltype(fContext, v->type(), &paramSLType)) {
fErrors.error(v->fOffset, "unsupported parameter type");

View File

@ -165,8 +165,8 @@ Symbol* Rehydrator::symbol() {
const Type* returnType = this->type();
FunctionDeclaration* result =
fSymbolTable->takeOwnershipOfSymbol(std::make_unique<FunctionDeclaration>(
/*offset=*/-1, modifiers, name, std::move(parameters), *returnType,
/*builtin=*/true));
/*offset=*/-1, fModifiers.handle(modifiers), name,
std::move(parameters), returnType, /*builtin=*/true));
this->addSymbol(id, result);
return result;
}
@ -302,7 +302,7 @@ std::unique_ptr<ProgramElement> Rehydrator::element() {
}
FunctionDefinition* result = new FunctionDefinition(-1, *decl, std::move(body),
std::move(refs));
decl->fDefinition = result;
decl->setDefinition(result);
return std::unique_ptr<ProgramElement>(result);
}
case Rehydrator::kInterfaceBlock_Command: {

View File

@ -578,21 +578,22 @@ SpvId SPIRVCodeGenerator::getImageType(const Type& type) {
}
SpvId SPIRVCodeGenerator::getFunctionType(const FunctionDeclaration& function) {
String key = to_string(this->getType(function.fReturnType)) + "(";
String key = to_string(this->getType(function.returnType())) + "(";
String separator;
for (size_t i = 0; i < function.fParameters.size(); i++) {
const std::vector<Variable*>& parameters = function.parameters();
for (size_t i = 0; i < parameters.size(); i++) {
key += separator;
separator = ", ";
key += to_string(this->getType(function.fParameters[i]->type()));
key += to_string(this->getType(parameters[i]->type()));
}
key += ")";
auto entry = fTypeMap.find(key);
if (entry == fTypeMap.end()) {
SpvId result = this->nextId();
int32_t length = 3 + (int32_t) function.fParameters.size();
SpvId returnType = this->getType(function.fReturnType);
int32_t length = 3 + (int32_t) parameters.size();
SpvId returnType = this->getType(function.returnType());
std::vector<SpvId> parameterTypes;
for (size_t i = 0; i < function.fParameters.size(); i++) {
for (size_t i = 0; i < parameters.size(); i++) {
// glslang seems to treat all function arguments as pointers whether they need to be or
// not. I was initially puzzled by this until I ran bizarre failures with certain
// patterns of function calls and control constructs, as exemplified by this minimal
@ -616,7 +617,7 @@ SpvId SPIRVCodeGenerator::getFunctionType(const FunctionDeclaration& function) {
// as glslang does, fixes it. It's entirely possible I simply missed whichever part of
// the spec makes this make sense.
// if (is_out(function->fParameters[i])) {
parameterTypes.push_back(this->getPointerType(function.fParameters[i]->type(),
parameterTypes.push_back(this->getPointerType(parameters[i]->type(),
SpvStorageClassFunction));
// } else {
// parameterTypes.push_back(this->getType(function.fParameters[i]->fType));
@ -717,7 +718,7 @@ SpvId SPIRVCodeGenerator::writeIntrinsicCall(const FunctionCall& c, OutputStream
SpvId result = this->nextId();
std::vector<SpvId> argumentIds;
for (size_t i = 0; i < arguments.size(); i++) {
if (function.fParameters[i]->modifiers().fFlags & Modifiers::kOut_Flag) {
if (function.parameters()[i]->modifiers().fFlags & Modifiers::kOut_Flag) {
argumentIds.push_back(this->getLValue(*arguments[i], out)->getPointer());
} else {
argumentIds.push_back(this->writeExpression(*arguments[i], out));
@ -737,7 +738,7 @@ SpvId SPIRVCodeGenerator::writeIntrinsicCall(const FunctionCall& c, OutputStream
SpvId result = this->nextId();
std::vector<SpvId> argumentIds;
for (size_t i = 0; i < arguments.size(); i++) {
if (function.fParameters[i]->modifiers().fFlags & Modifiers::kOut_Flag) {
if (function.parameters()[i]->modifiers().fFlags & Modifiers::kOut_Flag) {
argumentIds.push_back(this->getLValue(*arguments[i], out)->getPointer());
} else {
argumentIds.push_back(this->writeExpression(*arguments[i], out));
@ -1032,7 +1033,7 @@ SpvId SPIRVCodeGenerator::writeFunctionCall(const FunctionCall& c, OutputStream&
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(*function.fParameters[i])) {
if (is_out(*function.parameters()[i])) {
std::unique_ptr<LValue> lv = this->getLValue(*arguments[i], out);
SpvId ptr = lv->getPointer();
if (ptr) {
@ -2579,14 +2580,15 @@ SpvId SPIRVCodeGenerator::writeFloatLiteral(const FloatLiteral& f) {
SpvId SPIRVCodeGenerator::writeFunctionStart(const FunctionDeclaration& f, OutputStream& out) {
SpvId result = fFunctionMap[&f];
this->writeInstruction(SpvOpFunction, this->getType(f.fReturnType), result,
this->writeInstruction(SpvOpFunction, this->getType(f.returnType()), result,
SpvFunctionControlMaskNone, this->getFunctionType(f), out);
this->writeInstruction(SpvOpName, result, f.name(), fNameBuffer);
for (size_t i = 0; i < f.fParameters.size(); i++) {
const std::vector<Variable*>& parameters = f.parameters();
for (size_t i = 0; i < parameters.size(); i++) {
SpvId id = this->nextId();
fVariableMap[f.fParameters[i]] = id;
fVariableMap[parameters[i]] = id;
SpvId type;
type = this->getPointerType(f.fParameters[i]->type(), SpvStorageClassFunction);
type = this->getPointerType(parameters[i]->type(), SpvStorageClassFunction);
this->writeInstruction(SpvOpFunctionParameter, type, id, out);
}
return result;
@ -2604,7 +2606,7 @@ SpvId SPIRVCodeGenerator::writeFunction(const FunctionDefinition& f, OutputStrea
}
write_stringstream(bodyBuffer, out);
if (fCurrentBlock) {
if (f.fDeclaration.fReturnType == *fContext.fVoid_Type) {
if (f.fDeclaration.returnType() == *fContext.fVoid_Type) {
this->writeInstruction(SpvOpReturn, out);
} else {
this->writeInstruction(SpvOpUnreachable, out);

View File

@ -24,11 +24,11 @@ public:
std::vector<std::unique_ptr<Expression>> arguments)
: INHERITED(offset, FunctionCallData{type, function}) {
fExpressionChildren = std::move(arguments);
++this->function().fCallCount;
++this->function().callCount();
}
~FunctionCall() override {
--this->function().fCallCount;
--this->function().callCount();
}
const Type& type() const override {
@ -48,7 +48,7 @@ public:
}
bool hasProperty(Property property) const override {
if (property == Property::kSideEffects && (this->function().fModifiers.fFlags &
if (property == Property::kSideEffects && (this->function().modifiers().fFlags &
Modifiers::kHasSideEffects_Flag)) {
return true;
}

View File

@ -24,23 +24,53 @@ struct FunctionDefinition;
/**
* A function declaration (not a definition -- does not contain a body).
*/
struct FunctionDeclaration : public Symbol {
class FunctionDeclaration : public Symbol {
public:
static constexpr Kind kSymbolKind = Kind::kFunctionDeclaration;
FunctionDeclaration(int offset, Modifiers modifiers, StringFragment name,
std::vector<Variable*> parameters, const Type& returnType,
FunctionDeclaration(int offset, ModifiersPool::Handle modifiers, StringFragment name,
std::vector<Variable*> parameters, const Type* returnType,
bool builtin)
: INHERITED(offset, kSymbolKind, std::move(name))
, fDefinition(nullptr)
, fBuiltin(builtin)
, fModifiers(modifiers)
, fParameters(std::move(parameters))
, fReturnType(returnType) {}
: INHERITED(offset, FunctionDeclarationData{name, /*fDefiniition=*/nullptr, modifiers,
std::move(parameters), returnType,
/*fCallCount=*/0, builtin}) {}
const Modifiers& modifiers() const {
return *this->functionDeclarationData().fModifiersHandle;
}
StringFragment name() const override {
return this->functionDeclarationData().fName;
}
const FunctionDefinition* definition() const {
return this->functionDeclarationData().fDefinition;
}
void setDefinition(const FunctionDefinition* definition) const {
this->functionDeclarationData().fDefinition = definition;
}
const std::vector<Variable*>& parameters() const {
return this->functionDeclarationData().fParameters;
}
const Type& returnType() const {
return *this->functionDeclarationData().fReturnType;
}
bool isBuiltin() const {
return this->functionDeclarationData().fBuiltin;
}
std::atomic<int>& callCount() const {
return this->functionDeclarationData().fCallCount;
}
String description() const override {
String result = fReturnType.displayName() + " " + this->name() + "(";
String result = this->returnType().displayName() + " " + this->name() + "(";
String separator;
for (auto p : fParameters) {
for (auto p : this->parameters()) {
result += separator;
separator = ", ";
result += p->type().displayName();
@ -53,11 +83,13 @@ struct FunctionDeclaration : public Symbol {
if (this->name() != f.name()) {
return false;
}
if (fParameters.size() != f.fParameters.size()) {
const std::vector<Variable*>& parameters = this->parameters();
const std::vector<Variable*>& otherParameters = f.parameters();
if (parameters.size() != otherParameters.size()) {
return false;
}
for (size_t i = 0; i < fParameters.size(); i++) {
if (fParameters[i]->type() != f.fParameters[i]->type()) {
for (size_t i = 0; i < parameters.size(); i++) {
if (parameters[i]->type() != otherParameters[i]->type()) {
return false;
}
}
@ -82,10 +114,11 @@ struct FunctionDeclaration : public Symbol {
bool determineFinalTypes(const std::vector<std::unique_ptr<Expression>>& arguments,
std::vector<const Type*>* outParameterTypes,
const Type** outReturnType) const {
SkASSERT(arguments.size() == fParameters.size());
const std::vector<Variable*>& parameters = this->parameters();
SkASSERT(arguments.size() == parameters.size());
int genericIndex = -1;
for (size_t i = 0; i < arguments.size(); i++) {
const Type& parameterType = fParameters[i]->type();
const Type& parameterType = parameters[i]->type();
if (parameterType.typeKind() == Type::TypeKind::kGeneric) {
std::vector<const Type*> types = parameterType.coercibleTypes();
if (genericIndex == -1) {
@ -104,24 +137,19 @@ struct FunctionDeclaration : public Symbol {
outParameterTypes->push_back(&parameterType);
}
}
if (fReturnType.typeKind() == Type::TypeKind::kGeneric) {
const Type& returnType = this->returnType();
if (returnType.typeKind() == Type::TypeKind::kGeneric) {
if (genericIndex == -1) {
return false;
}
*outReturnType = fReturnType.coercibleTypes()[genericIndex];
*outReturnType = returnType.coercibleTypes()[genericIndex];
} else {
*outReturnType = &fReturnType;
*outReturnType = &returnType;
}
return true;
}
mutable FunctionDefinition* fDefinition;
bool fBuiltin;
Modifiers fModifiers;
const std::vector<Variable*> fParameters;
const Type& fReturnType;
mutable std::atomic<int> fCallCount = 0;
private:
using INHERITED = Symbol;
};

View File

@ -48,6 +48,11 @@ IRNode::IRNode(int offset, int kind, const FunctionCallData& data)
, fKind(kind)
, fData(data) {}
IRNode::IRNode(int offset, int kind, const FunctionDeclarationData& data)
: fOffset(offset)
, fKind(kind)
, fData(data) {}
IRNode::IRNode(int offset, int kind, const IfStatementData& data)
: fOffset(offset)
, fKind(kind)

View File

@ -20,7 +20,8 @@ namespace SkSL {
class Expression;
class ExternalValue;
struct FunctionDeclaration;
class FunctionDeclaration;
struct FunctionDefinition;
class Statement;
class Symbol;
class SymbolTable;
@ -100,6 +101,29 @@ protected:
const FunctionDeclaration* fFunction;
};
struct FunctionDeclarationData {
StringFragment fName;
mutable const FunctionDefinition* fDefinition;
ModifiersPool::Handle fModifiersHandle;
// FIXME after killing fExpressionChildren / fStatementChildren in favor of just fChildren,
// the parameters should move into that vector
std::vector<Variable*> fParameters;
const Type* fReturnType;
mutable std::atomic<int> fCallCount;
bool fBuiltin;
FunctionDeclarationData& operator=(const FunctionDeclarationData& other) {
fName = other.fName;
fDefinition = other.fDefinition;
fModifiersHandle = other.fModifiersHandle;
fParameters = other.fParameters;
fReturnType = other.fReturnType;
fCallCount = other.fCallCount.load();
fBuiltin = other.fBuiltin;
return *this;
}
};
struct IfStatementData {
bool fIsStatic;
};
@ -154,6 +178,7 @@ protected:
kFloatLiteral,
kForStatement,
kFunctionCall,
kFunctionDeclaration,
kIfStatement,
kIntLiteral,
kString,
@ -175,6 +200,7 @@ protected:
FloatLiteralData fFloatLiteral;
ForStatementData fForStatement;
FunctionCallData fFunctionCall;
FunctionDeclarationData fFunctionDeclaration;
IfStatementData fIfStatement;
IntLiteralData fIntLiteral;
String fString;
@ -230,6 +256,11 @@ protected:
*(new(&fContents) FunctionCallData) = data;
}
NodeData(const FunctionDeclarationData& data)
: fKind(Kind::kFunctionDeclaration) {
*(new(&fContents) FunctionDeclarationData) = data;
}
NodeData(IfStatementData data)
: fKind(Kind::kIfStatement) {
*(new(&fContents) IfStatementData) = data;
@ -307,6 +338,10 @@ protected:
case Kind::kFunctionCall:
*(new(&fContents) FunctionCallData) = other.fContents.fFunctionCall;
break;
case Kind::kFunctionDeclaration:
*(new(&fContents) FunctionDeclarationData) =
other.fContents.fFunctionDeclaration;
break;
case Kind::kIfStatement:
*(new(&fContents) IfStatementData) = other.fContents.fIfStatement;
break;
@ -372,6 +407,9 @@ protected:
case Kind::kIfStatement:
fContents.fIfStatement.~IfStatementData();
break;
case Kind::kFunctionDeclaration:
fContents.fFunctionDeclaration.~FunctionDeclarationData();
break;
case Kind::kIntLiteral:
fContents.fIntLiteral.~IntLiteralData();
break;
@ -418,6 +456,8 @@ protected:
IRNode(int offset, int kind, const IfStatementData& data);
IRNode(int offset, int kind, const FunctionDeclarationData& data);
IRNode(int offset, int kind, const IntLiteralData& data);
IRNode(int offset, int kind, const String& data);
@ -518,11 +558,21 @@ protected:
return fData.fContents.fFunctionCall;
}
FunctionDeclarationData& functionDeclarationData() {
SkASSERT(fData.fKind == NodeData::Kind::kFunctionDeclaration);
return fData.fContents.fFunctionDeclaration;
}
const IfStatementData& ifStatementData() const {
SkASSERT(fData.fKind == NodeData::Kind::kIfStatement);
return fData.fContents.fIfStatement;
}
const FunctionDeclarationData& functionDeclarationData() const {
SkASSERT(fData.fKind == NodeData::Kind::kFunctionDeclaration);
return fData.fContents.fFunctionDeclaration;
}
const IntLiteralData& intLiteralData() const {
SkASSERT(fData.fKind == NodeData::Kind::kIntLiteral);
return fData.fContents.fIntLiteral;

View File

@ -39,6 +39,9 @@ public:
Symbol(int offset, const FieldData& data)
: INHERITED(offset, (int) Kind::kField, data) {}
Symbol(int offset, const FunctionDeclarationData& data)
: INHERITED(offset, (int) Kind::kFunctionDeclaration, data) {}
Symbol(int offset, const SymbolAliasData& data)
: INHERITED(offset, (int) Kind::kSymbolAlias, data) {}

View File

@ -16,7 +16,7 @@
namespace SkSL {
struct FunctionDeclaration;
class FunctionDeclaration;
/**
* Maps identifiers to symbols. Functions, in particular, are mapped to either FunctionDeclaration