moved SkSL Variable data into IRNode

Change-Id: I53af66c1b65971c204ac7c515e0d0e39481b015d
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/323097
Reviewed-by: Brian Osman <brianosman@google.com>
Commit-Queue: Ethan Nicholas <ethannicholas@google.com>
This commit is contained in:
Ethan Nicholas 2020-10-07 16:42:04 -04:00 committed by Skia Commit-Bot
parent 54c1b3dd43
commit 041fd0ad7d
39 changed files with 597 additions and 375 deletions

View File

@ -160,7 +160,7 @@ SkRuntimeEffect::EffectResult SkRuntimeEffect::Make(SkString sksl) {
const SkSL::Type& varType = var.type();
// Varyings (only used in conjunction with drawVertices)
if (var.fModifiers.fFlags & SkSL::Modifiers::kVarying_Flag) {
if (var.modifiers().fFlags & SkSL::Modifiers::kVarying_Flag) {
varyings.push_back({var.name(),
varType.typeKind() == SkSL::Type::TypeKind::kVector
? varType.columns()
@ -172,7 +172,7 @@ SkRuntimeEffect::EffectResult SkRuntimeEffect::Make(SkString sksl) {
sampleUsages.push_back(SkSL::Analysis::GetSampleUsage(*program, var));
}
// 'uniform' variables
else if (var.fModifiers.fFlags & SkSL::Modifiers::kUniform_Flag) {
else if (var.modifiers().fFlags & SkSL::Modifiers::kUniform_Flag) {
Uniform uni;
uni.fName = var.name();
uni.fFlags = 0;
@ -189,7 +189,7 @@ SkRuntimeEffect::EffectResult SkRuntimeEffect::Make(SkString sksl) {
RETURN_FAILURE("Invalid uniform type: '%s'", type->displayName().c_str());
}
const SkSL::StringFragment& marker(var.fModifiers.fLayout.fMarker);
const SkSL::StringFragment& marker(var.modifiers().fLayout.fMarker);
if (marker.fLength) {
uni.fFlags |= Uniform::kMarker_Flag;
allowColorFilter = false;
@ -199,7 +199,7 @@ SkRuntimeEffect::EffectResult SkRuntimeEffect::Make(SkString sksl) {
}
}
if (var.fModifiers.fLayout.fFlags & SkSL::Layout::Flag::kSRGBUnpremul_Flag) {
if (var.modifiers().fLayout.fFlags & SkSL::Layout::Flag::kSRGBUnpremul_Flag) {
uni.fFlags |= Uniform::kSRGBUnpremul_Flag;
}

View File

@ -139,7 +139,7 @@ public:
bool visitExpression(const Expression& e) override {
if (e.is<VariableReference>()) {
const VariableReference& var = e.as<VariableReference>();
return var.fVariable->fModifiers.fLayout.fBuiltin == fBuiltin;
return var.fVariable->modifiers().fLayout.fBuiltin == fBuiltin;
}
return INHERITED::visitExpression(e);
}
@ -240,8 +240,8 @@ public:
case Expression::Kind::kVariableReference: {
VariableReference& varRef = expr.as<VariableReference>();
const Variable* var = varRef.fVariable;
if (var->fModifiers.fFlags & (Modifiers::kConst_Flag | Modifiers::kUniform_Flag |
Modifiers::kVarying_Flag)) {
if (var->modifiers().fFlags & (Modifiers::kConst_Flag | Modifiers::kUniform_Flag |
Modifiers::kVarying_Flag)) {
fErrors->error(expr.fOffset,
"cannot modify immutable variable '" + var->name() + "'");
} else if (fAssignableVar) {

View File

@ -21,7 +21,7 @@ struct FunctionDefinition;
struct Program;
struct ProgramElement;
struct Statement;
struct Variable;
class Variable;
struct VariableReference;
/**

View File

@ -117,11 +117,11 @@ int ByteCodeGenerator::SlotCount(const Type& type) {
}
static inline bool is_uniform(const SkSL::Variable& var) {
return var.fModifiers.fFlags & Modifiers::kUniform_Flag;
return var.modifiers().fFlags & Modifiers::kUniform_Flag;
}
static inline bool is_in(const SkSL::Variable& var) {
return var.fModifiers.fFlags & Modifiers::kIn_Flag;
return var.modifiers().fFlags & Modifiers::kIn_Flag;
}
void ByteCodeGenerator::gatherUniforms(const Type& type, const String& name) {
@ -165,7 +165,7 @@ bool ByteCodeGenerator::generateCode() {
if (declVar->type() == *fContext.fFragmentProcessor_Type) {
fOutput->fChildFPCount++;
}
if (declVar->fModifiers.fLayout.fBuiltin >= 0 || is_in(*declVar)) {
if (declVar->modifiers().fLayout.fBuiltin >= 0 || is_in(*declVar)) {
continue;
}
if (is_uniform(*declVar)) {
@ -218,8 +218,8 @@ std::unique_ptr<ByteCodeFunction> ByteCodeGenerator::writeFunction(const Functio
static int expression_as_builtin(const Expression& e) {
if (e.is<VariableReference>()) {
const Variable& var(*e.as<VariableReference>().fVariable);
if (var.fStorage == Variable::kGlobal_Storage) {
return var.fModifiers.fLayout.fBuiltin;
if (var.storage() == Variable::kGlobal_Storage) {
return var.modifiers().fLayout.fBuiltin;
}
}
return -1;
@ -423,7 +423,7 @@ int ByteCodeGenerator::StackUsage(ByteCodeInstruction inst, int count_) {
ByteCodeGenerator::Location ByteCodeGenerator::getLocation(const Variable& var) {
// given that we seldom have more than a couple of variables, linear search is probably the most
// efficient way to handle lookups
switch (var.fStorage) {
switch (var.storage()) {
case Variable::kLocal_Storage: {
for (int i = fLocals.size() - 1; i >= 0; --i) {
if (fLocals[i] == &var) {
@ -486,7 +486,7 @@ ByteCodeGenerator::Location ByteCodeGenerator::getLocation(const Variable& var)
if (e.is<GlobalVarDeclaration>()) {
const GlobalVarDeclaration& decl = e.as<GlobalVarDeclaration>();
const Variable* declVar = decl.fDecl->fVar;
if (declVar->fModifiers.fLayout.fBuiltin >= 0 || is_in(*declVar)) {
if (declVar->modifiers().fLayout.fBuiltin >= 0 || is_in(*declVar)) {
continue;
}
if (isUniform != is_uniform(*declVar)) {
@ -1265,7 +1265,7 @@ void ByteCodeGenerator::writeFunctionCall(const FunctionCall& f) {
for (int i = 0; i < argCount; ++i) {
const auto& param = f.function().fParameters[i];
const auto& arg = f.arguments()[i];
if (param->fModifiers.fFlags & Modifiers::kOut_Flag) {
if (param->modifiers().fFlags & Modifiers::kOut_Flag) {
lvalues.emplace_back(this->getLValue(*arg));
lvalues.back()->load();
} else {
@ -1298,7 +1298,7 @@ void ByteCodeGenerator::writeFunctionCall(const FunctionCall& f) {
for (int i = argCount - 1; i >= 0; --i) {
const auto& param = f.function().fParameters[i];
const auto& arg = f.arguments()[i];
if (param->fModifiers.fFlags & Modifiers::kOut_Flag) {
if (param->modifiers().fFlags & Modifiers::kOut_Flag) {
pop();
lvalues.back()->store(true);
lvalues.pop_back();
@ -1834,7 +1834,7 @@ ByteCodeFunction::ByteCodeFunction(const FunctionDeclaration* declaration)
fParameterCount = 0;
for (const auto& p : declaration->fParameters) {
int slots = ByteCodeGenerator::SlotCount(p->type());
fParameters.push_back({ slots, (bool)(p->fModifiers.fFlags & Modifiers::kOut_Flag) });
fParameters.push_back({ slots, (bool)(p->modifiers().fFlags & Modifiers::kOut_Flag) });
fParameterCount += slots;
}
}

View File

@ -20,8 +20,8 @@
namespace SkSL {
static bool needs_uniform_var(const Variable& var) {
return (var.fModifiers.fFlags & Modifiers::kUniform_Flag) &&
var.type().typeKind() != Type::TypeKind::kSampler;
return (var.modifiers().fFlags & Modifiers::kUniform_Flag) &&
var.type().typeKind() != Type::TypeKind::kSampler;
}
CPPCodeGenerator::CPPCodeGenerator(const Context* context, const Program* program,
@ -128,22 +128,24 @@ static String default_value(const Type& type) {
}
static String default_value(const Variable& var) {
if (var.fModifiers.fLayout.fCType == SkSL::Layout::CType::kSkPMColor4f) {
if (var.modifiers().fLayout.fCType == SkSL::Layout::CType::kSkPMColor4f) {
return "{SK_FloatNaN, SK_FloatNaN, SK_FloatNaN, SK_FloatNaN}";
}
return default_value(var.type());
}
static bool is_private(const Variable& var) {
return !(var.fModifiers.fFlags & Modifiers::kUniform_Flag) &&
!(var.fModifiers.fFlags & Modifiers::kIn_Flag) &&
var.fStorage == Variable::kGlobal_Storage &&
var.fModifiers.fLayout.fBuiltin == -1;
const Modifiers& modifiers = var.modifiers();
return !(modifiers.fFlags & Modifiers::kUniform_Flag) &&
!(modifiers.fFlags & Modifiers::kIn_Flag) &&
var.storage() == Variable::kGlobal_Storage &&
modifiers.fLayout.fBuiltin == -1;
}
static bool is_uniform_in(const Variable& var) {
return (var.fModifiers.fFlags & Modifiers::kUniform_Flag) &&
(var.fModifiers.fFlags & Modifiers::kIn_Flag) &&
const Modifiers& modifiers = var.modifiers();
return (modifiers.fFlags & Modifiers::kUniform_Flag) &&
(modifiers.fFlags & Modifiers::kIn_Flag) &&
var.type().typeKind() != Type::TypeKind::kSampler;
}
@ -260,7 +262,7 @@ void CPPCodeGenerator::writeRuntimeValue(const Type& type, const Layout& layout,
void CPPCodeGenerator::writeVarInitializer(const Variable& var, const Expression& value) {
if (is_private(var)) {
this->writeRuntimeValue(var.type(), var.fModifiers.fLayout, var.name());
this->writeRuntimeValue(var.type(), var.modifiers().fLayout, var.name());
} else {
this->writeExpression(value, kTopLevel_Precedence);
}
@ -312,7 +314,7 @@ void CPPCodeGenerator::writeVariableReference(const VariableReference& ref) {
this->write(ref.fVariable->name());
return;
}
switch (ref.fVariable->fModifiers.fLayout.fBuiltin) {
switch (ref.fVariable->modifiers().fLayout.fBuiltin) {
case SK_OUTCOLOR_BUILTIN:
this->write("%s");
fFormatArgs.push_back(String("args.fOutputColor"));
@ -336,13 +338,13 @@ void CPPCodeGenerator::writeVariableReference(const VariableReference& ref) {
this->getSamplerHandle(*ref.fVariable) + ")");
return;
}
if (ref.fVariable->fModifiers.fFlags & Modifiers::kUniform_Flag) {
if (ref.fVariable->modifiers().fFlags & Modifiers::kUniform_Flag) {
this->write("%s");
String name = ref.fVariable->name();
String var = String::printf("args.fUniformHandler->getUniformCStr(%sVar)",
HCodeGenerator::FieldName(name.c_str()).c_str());
String code;
if (ref.fVariable->fModifiers.fLayout.fWhen.fLength) {
if (ref.fVariable->modifiers().fLayout.fWhen.fLength) {
code = String::printf("%sVar.isValid() ? %s : \"%s\"",
HCodeGenerator::FieldName(name.c_str()).c_str(),
var.c_str(),
@ -353,7 +355,7 @@ void CPPCodeGenerator::writeVariableReference(const VariableReference& ref) {
fFormatArgs.push_back(code);
} else if (SectionAndParameterHelper::IsParameter(*ref.fVariable)) {
String name(ref.fVariable->name());
this->writeRuntimeValue(ref.fVariable->type(), ref.fVariable->fModifiers.fLayout,
this->writeRuntimeValue(ref.fVariable->type(), ref.fVariable->modifiers().fLayout,
String::printf("_outer.%s", name.c_str()).c_str());
} else {
this->write(ref.fVariable->name());
@ -657,8 +659,8 @@ void CPPCodeGenerator::writeProgramElement(const ProgramElement& p) {
case ProgramElement::Kind::kGlobalVar: {
const GlobalVarDeclaration& decl = p.as<GlobalVarDeclaration>();
const Variable& var = *decl.fDecl->fVar;
if (var.fModifiers.fFlags & (Modifiers::kIn_Flag | Modifiers::kUniform_Flag) ||
-1 != var.fModifiers.fLayout.fBuiltin) {
if (var.modifiers().fFlags & (Modifiers::kIn_Flag | Modifiers::kUniform_Flag) ||
-1 != var.modifiers().fLayout.fBuiltin) {
return;
}
break;
@ -673,8 +675,8 @@ void CPPCodeGenerator::addUniform(const Variable& var) {
if (!needs_uniform_var(var)) {
return;
}
if (var.fModifiers.fLayout.fWhen.fLength) {
this->writef(" if (%s) {\n ", String(var.fModifiers.fLayout.fWhen).c_str());
if (var.modifiers().fLayout.fWhen.fLength) {
this->writef(" if (%s) {\n ", String(var.modifiers().fLayout.fWhen).c_str());
}
String name(var.name());
if (var.type().typeKind() != Type::TypeKind::kArray) {
@ -691,7 +693,7 @@ void CPPCodeGenerator::addUniform(const Variable& var) {
name.c_str(),
var.type().columns());
}
if (var.fModifiers.fLayout.fWhen.fLength) {
if (var.modifiers().fLayout.fWhen.fLength) {
this->write(" }\n");
}
}
@ -711,11 +713,11 @@ void CPPCodeGenerator::writePrivateVars() {
}
this->writef("%s %s = %s;\n",
HCodeGenerator::FieldType(fContext, decl.fVar->type(),
decl.fVar->fModifiers.fLayout)
decl.fVar->modifiers().fLayout)
.c_str(),
String(decl.fVar->name()).c_str(),
default_value(*decl.fVar).c_str());
} else if (decl.fVar->fModifiers.fLayout.fFlags & Layout::kTracked_Flag) {
} else if (decl.fVar->modifiers().fLayout.fFlags & Layout::kTracked_Flag) {
// An auto-tracked uniform in variable, so add a field to hold onto the prior
// state. Note that tracked variables must be uniform in's and that is validated
// before writePrivateVars() is called.
@ -1010,8 +1012,8 @@ void CPPCodeGenerator::writeSetData(std::vector<const Variable*>& uniforms) {
const char* name = nameString.c_str();
// Switches for setData behavior in the generated code
bool conditionalUniform = u->fModifiers.fLayout.fWhen != "";
bool isTracked = u->fModifiers.fLayout.fFlags & Layout::kTracked_Flag;
bool conditionalUniform = u->modifiers().fLayout.fWhen != "";
bool isTracked = u->modifiers().fLayout.fFlags & Layout::kTracked_Flag;
bool needsValueDeclaration = isTracked || !mapper->canInlineUniformValue();
String uniformName = HCodeGenerator::FieldName(name) + "Var";
@ -1029,7 +1031,7 @@ void CPPCodeGenerator::writeSetData(std::vector<const Variable*>& uniforms) {
valueVar.appendf("%sValue", name);
// Use AccessType since that will match the return type of _outer's public API.
String valueType = HCodeGenerator::AccessType(fContext, u->type(),
u->fModifiers.fLayout);
u->modifiers().fLayout);
this->writef("%s%s %s = _outer.%s;\n",
indent.c_str(), valueType.c_str(), valueVar.c_str(), name);
} else {
@ -1189,7 +1191,7 @@ void CPPCodeGenerator::writeDumpInfo() {
// Add this field onto the format string and argument list.
String fieldName = HCodeGenerator::FieldName(String(param->name()).c_str());
String runtimeValue = this->formatRuntimeValue(param->type(),
param->fModifiers.fLayout,
param->modifiers().fLayout,
param->name(),
&argumentList);
formatString.appendf("%s%s=%s",
@ -1245,16 +1247,16 @@ void CPPCodeGenerator::writeGetKey() {
const Type& varType = var.type();
String nameString(var.name());
const char* name = nameString.c_str();
if (var.fModifiers.fLayout.fKey != Layout::kNo_Key &&
(var.fModifiers.fFlags & Modifiers::kUniform_Flag)) {
if (var.modifiers().fLayout.fKey != Layout::kNo_Key &&
(var.modifiers().fFlags & Modifiers::kUniform_Flag)) {
fErrors.error(var.fOffset, "layout(key) may not be specified on uniforms");
}
switch (var.fModifiers.fLayout.fKey) {
switch (var.modifiers().fLayout.fKey) {
case Layout::kKey_Key:
if (is_private(var)) {
this->writef("%s %s =",
HCodeGenerator::FieldType(fContext, varType,
var.fModifiers.fLayout).c_str(),
var.modifiers().fLayout).c_str(),
String(var.name()).c_str());
if (decl.fValue) {
fCPPMode = true;
@ -1265,8 +1267,8 @@ void CPPCodeGenerator::writeGetKey() {
}
this->write(";\n");
}
if (var.fModifiers.fLayout.fWhen.fLength) {
this->writef("if (%s) {", String(var.fModifiers.fLayout.fWhen).c_str());
if (var.modifiers().fLayout.fWhen.fLength) {
this->writef("if (%s) {", String(var.modifiers().fLayout.fWhen).c_str());
}
if (varType == *fContext.fHalf4_Type) {
this->writef(" uint16_t red = SkFloatToHalf(%s.fR);\n",
@ -1291,7 +1293,7 @@ void CPPCodeGenerator::writeGetKey() {
ABORT("NOT YET IMPLEMENTED: automatic key handling for %s\n",
varType.displayName().c_str());
}
if (var.fModifiers.fLayout.fWhen.fLength) {
if (var.modifiers().fLayout.fWhen.fLength) {
this->write("}");
}
break;
@ -1315,7 +1317,7 @@ bool CPPCodeGenerator::generateCode() {
for (const auto& p : fProgram) {
if (p.is<GlobalVarDeclaration>()) {
const VarDeclaration& decl = *p.as<GlobalVarDeclaration>().fDecl;
if ((decl.fVar->fModifiers.fFlags & Modifiers::kUniform_Flag) &&
if ((decl.fVar->modifiers().fFlags & Modifiers::kUniform_Flag) &&
decl.fVar->type().typeKind() != Type::TypeKind::kSampler) {
uniforms.push_back(decl.fVar);
}
@ -1330,7 +1332,7 @@ bool CPPCodeGenerator::generateCode() {
+ "'s type is not supported for use as a 'uniform in'");
return false;
}
if (decl.fVar->fModifiers.fLayout.fFlags & Layout::kTracked_Flag) {
if (decl.fVar->modifiers().fLayout.fFlags & Layout::kTracked_Flag) {
if (!mapper->supportsTracking()) {
fErrors.error(decl.fOffset, String(decl.fVar->name())
+ "'s type does not support state tracking");
@ -1340,7 +1342,7 @@ bool CPPCodeGenerator::generateCode() {
} else {
// If it's not a uniform_in, it's an error to be tracked
if (decl.fVar->fModifiers.fLayout.fFlags & Layout::kTracked_Flag) {
if (decl.fVar->modifiers().fLayout.fFlags & Layout::kTracked_Flag) {
fErrors.error(decl.fOffset, "Non-'in uniforms' cannot be tracked");
return false;
}
@ -1369,7 +1371,7 @@ bool CPPCodeGenerator::generateCode() {
this->writeSetData(uniforms);
this->writePrivateVars();
for (const auto& u : uniforms) {
if (needs_uniform_var(*u) && !(u->fModifiers.fFlags & Modifiers::kIn_Flag)) {
if (needs_uniform_var(*u) && !(u->modifiers().fFlags & Modifiers::kIn_Flag)) {
this->writef(" UniformHandle %sVar;\n",
HCodeGenerator::FieldName(String(u->name()).c_str()).c_str());
}

View File

@ -50,7 +50,7 @@ public:
const Layout& layout);
static const UniformCTypeMapper* Get(const Context& context, const Variable& variable) {
return Get(context, variable.type(), variable.fModifiers.fLayout);
return Get(context, variable.type(), variable.modifiers().fLayout);
}
// The C++ type name that this mapper applies to

View File

@ -250,8 +250,9 @@ Compiler::Compiler(Flags flags)
// treat it as builtin (ie, no need to clone it into the Program).
StringFragment skCapsName("sk_Caps");
fRootSymbolTable->add(skCapsName,
std::make_unique<Variable>(/*offset=*/-1, Modifiers(), skCapsName,
fContext->fSkCaps_Type.get(),
std::make_unique<Variable>(/*offset=*/-1,
fIRGenerator->fModifiers->handle(Modifiers()),
skCapsName, fContext->fSkCaps_Type.get(),
/*builtin=*/false, Variable::kGlobal_Storage));
fIRGenerator->fIntrinsics = nullptr;
@ -266,22 +267,28 @@ Compiler::Compiler(Flags flags)
&fragElements, &fFragmentSymbolTable);
#else
{
Rehydrator rehydrator(fContext.get(), fRootSymbolTable, this, SKSL_INCLUDE_sksl_gpu,
Rehydrator rehydrator(&fIRGenerator->fContext, fIRGenerator->fModifiers.get(),
fRootSymbolTable, this, SKSL_INCLUDE_sksl_gpu,
SKSL_INCLUDE_sksl_gpu_LENGTH);
fGpuSymbolTable = rehydrator.symbolTable();
gpuElements = rehydrator.elements();
fModifiers.push_back(fIRGenerator->releaseModifiers());
}
{
Rehydrator rehydrator(fContext.get(), fGpuSymbolTable, this, SKSL_INCLUDE_sksl_vert,
Rehydrator rehydrator(&fIRGenerator->fContext, fIRGenerator->fModifiers.get(),
fGpuSymbolTable, this, SKSL_INCLUDE_sksl_vert,
SKSL_INCLUDE_sksl_vert_LENGTH);
fVertexSymbolTable = rehydrator.symbolTable();
fVertexInclude = rehydrator.elements();
fModifiers.push_back(fIRGenerator->releaseModifiers());
}
{
Rehydrator rehydrator(fContext.get(), fGpuSymbolTable, this, SKSL_INCLUDE_sksl_frag,
Rehydrator rehydrator(&fIRGenerator->fContext, fIRGenerator->fModifiers.get(),
fGpuSymbolTable, this, SKSL_INCLUDE_sksl_frag,
SKSL_INCLUDE_sksl_frag_LENGTH);
fFragmentSymbolTable = rehydrator.symbolTable();
fragElements = rehydrator.elements();
fModifiers.push_back(fIRGenerator->releaseModifiers());
}
#endif
// Call counts are used to track dead-stripping and inlinability within the program being
@ -308,10 +315,12 @@ void Compiler::loadGeometryIntrinsics() {
}
#if !SKSL_STANDALONE
{
Rehydrator rehydrator(fContext.get(), fGpuSymbolTable, this, SKSL_INCLUDE_sksl_geom,
SKSL_INCLUDE_sksl_geom_LENGTH);
Rehydrator rehydrator(&fIRGenerator->fContext, fIRGenerator->fModifiers.get(),
fGpuSymbolTable, this, SKSL_INCLUDE_sksl_geom,
SKSL_INCLUDE_sksl_geom_LENGTH);
fGeometrySymbolTable = rehydrator.symbolTable();
fGeometryInclude = rehydrator.elements();
fModifiers.push_back(fIRGenerator->releaseModifiers());
}
#else
this->processIncludeFile(Program::kGeometry_Kind, SKSL_GEOM_INCLUDE, fGpuSymbolTable,
@ -327,7 +336,8 @@ void Compiler::loadFPIntrinsics() {
std::vector<std::unique_ptr<ProgramElement>> fpElements;
#if !SKSL_STANDALONE
{
Rehydrator rehydrator(fContext.get(), fGpuSymbolTable, this, SKSL_INCLUDE_sksl_fp,
Rehydrator rehydrator(&fIRGenerator->fContext, fIRGenerator->fModifiers.get(),
fGpuSymbolTable, this, SKSL_INCLUDE_sksl_fp,
SKSL_INCLUDE_sksl_fp_LENGTH);
fFPSymbolTable = rehydrator.symbolTable();
fpElements = rehydrator.elements();
@ -347,11 +357,12 @@ void Compiler::loadPipelineIntrinsics() {
std::vector<std::unique_ptr<ProgramElement>> pipelineIntrinics;
#if !SKSL_STANDALONE
{
Rehydrator rehydrator(fContext.get(), fGpuSymbolTable, this,
SKSL_INCLUDE_sksl_pipeline,
Rehydrator rehydrator(&fIRGenerator->fContext, fIRGenerator->fModifiers.get(),
fGpuSymbolTable, this, SKSL_INCLUDE_sksl_pipeline,
SKSL_INCLUDE_sksl_pipeline_LENGTH);
fPipelineSymbolTable = rehydrator.symbolTable();
pipelineIntrinics = rehydrator.elements();
fModifiers.push_back(fIRGenerator->releaseModifiers());
}
#else
this->processIncludeFile(Program::kPipelineStage_Kind, SKSL_PIPELINE_INCLUDE,
@ -368,11 +379,12 @@ void Compiler::loadInterpreterIntrinsics() {
std::vector<std::unique_ptr<ProgramElement>> interpElements;
#if !SKSL_STANDALONE
{
Rehydrator rehydrator(fContext.get(), fRootSymbolTable, this,
SKSL_INCLUDE_sksl_interp,
Rehydrator rehydrator(&fIRGenerator->fContext, fIRGenerator->fModifiers.get(),
fRootSymbolTable, this, SKSL_INCLUDE_sksl_interp,
SKSL_INCLUDE_sksl_interp_LENGTH);
fInterpreterSymbolTable = rehydrator.symbolTable();
interpElements = rehydrator.elements();
fModifiers.push_back(fIRGenerator->releaseModifiers());
}
#else
this->processIncludeFile(Program::kGeneric_Kind, SKSL_INTERP_INCLUDE,
@ -414,6 +426,7 @@ void Compiler::processIncludeFile(Program::Kind kind, const char* path,
#ifdef SK_DEBUG
fSource = nullptr;
#endif
fModifiers.push_back(fIRGenerator->releaseModifiers());
fIRGenerator->finish();
}
@ -423,7 +436,7 @@ void Compiler::addDefinition(const Expression* lvalue, std::unique_ptr<Expressio
switch (lvalue->kind()) {
case Expression::Kind::kVariableReference: {
const Variable& var = *lvalue->as<VariableReference>().fVariable;
if (var.fStorage == Variable::kLocal_Storage) {
if (var.storage() == Variable::kLocal_Storage) {
(*definitions)[&var] = expr;
}
break;
@ -492,7 +505,7 @@ 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]->fModifiers.fFlags & Modifiers::kOut_Flag) {
if (c.function().fParameters[i]->modifiers().fFlags & Modifiers::kOut_Flag) {
this->addDefinition(
c.arguments()[i].get(),
(std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
@ -905,7 +918,7 @@ void Compiler::simplifyExpression(DefinitionMap& definitions,
const Variable* var = ref.fVariable;
if (ref.refKind() != VariableReference::kWrite_RefKind &&
ref.refKind() != VariableReference::kPointer_RefKind &&
var->fStorage == Variable::kLocal_Storage && !definitions[var] &&
var->storage() == Variable::kLocal_Storage && !definitions[var] &&
(*undefinedVariables).find(var) == (*undefinedVariables).end()) {
(*undefinedVariables).insert(var);
this->error(expr->fOffset,
@ -1572,7 +1585,7 @@ std::unique_ptr<Program> Compiler::convertProgram(
fErrorText = "";
fErrorCount = 0;
fInliner.reset(context(), settings);
fInliner.reset(&fIRGenerator->fContext, fIRGenerator->fModifiers.get(), &settings);
std::vector<std::unique_ptr<ProgramElement>>* inherited;
std::vector<std::unique_ptr<ProgramElement>> elements;
switch (kind) {
@ -1627,6 +1640,7 @@ std::unique_ptr<Program> Compiler::convertProgram(
fContext,
inherited,
std::move(elements),
fIRGenerator->releaseModifiers(),
fIRGenerator->fSymbolTable,
fIRGenerator->fInputs);
fIRGenerator->finish();
@ -1696,6 +1710,7 @@ bool Compiler::optimize(Program& program) {
break;
}
}
program.finish();
return fErrorCount == 0;
}
@ -1705,7 +1720,8 @@ bool Compiler::toSPIRV(Program& program, OutputStream& out) {
#ifdef SK_ENABLE_SPIRV_VALIDATION
StringStream buffer;
fSource = program.fSource.get();
SPIRVCodeGenerator cg(fContext.get(), &program, this, &buffer);
SPIRVCodeGenerator cg(&fIRGenerator->fContext, fIRGenerator->fModifiers.get(), &program, this,
&buffer);
bool result = cg.generateCode();
fSource = nullptr;
if (result) {
@ -1723,7 +1739,8 @@ bool Compiler::toSPIRV(Program& program, OutputStream& out) {
}
#else
fSource = program.fSource.get();
SPIRVCodeGenerator cg(fContext.get(), &program, this, &out);
SPIRVCodeGenerator cg(&fIRGenerator->fContext, fIRGenerator->fModifiers.get(), &program, this,
&out);
bool result = cg.generateCode();
fSource = nullptr;
#endif

View File

@ -252,6 +252,9 @@ private:
std::shared_ptr<SymbolTable> fFPSymbolTable;
std::unique_ptr<IRIntrinsicMap> fFPIntrinsics;
// holds ModifiersPools belonging to the core includes for lifetime purposes
std::vector<std::unique_ptr<ModifiersPool>> fModifiers;
Inliner fInliner;
std::unique_ptr<IRGenerator> fIRGenerator;
int fFlags;

View File

@ -216,10 +216,10 @@ void Dehydrator::write(const Symbol& s) {
const Variable& v = s.as<Variable>();
this->writeU8(Rehydrator::kVariable_Command);
this->writeId(&v);
this->write(v.fModifiers);
this->write(v.modifiers());
this->write(v.name());
this->write(v.type());
this->writeU8(v.fStorage);
this->writeU8(v.storage());
break;
}
case Symbol::Kind::kField: {
@ -519,8 +519,8 @@ void Dehydrator::write(const ProgramElement& e) {
for (const std::unique_ptr<const Symbol>& s : en.symbols()->fOwnedSymbols) {
SkASSERT(s->kind() == Symbol::Kind::kVariable);
Variable& v = (Variable&) *s;
SkASSERT(v.fInitialValue);
const IntLiteral& i = v.fInitialValue->as<IntLiteral>();
SkASSERT(v.initialValue());
const IntLiteral& i = v.initialValue()->as<IntLiteral>();
this->writeS32(i.value());
}
break;

View File

@ -785,7 +785,7 @@ void GLSLCodeGenerator::writeFragCoord() {
}
void GLSLCodeGenerator::writeVariableReference(const VariableReference& ref) {
switch (ref.fVariable->fModifiers.fLayout.fBuiltin) {
switch (ref.fVariable->modifiers().fLayout.fBuiltin) {
case SK_FRAGCOLOR_BUILTIN:
if (fProgram.fSettings.fCaps->mustDeclareFragmentShaderOutput()) {
this->write("sk_FragColor");
@ -1050,7 +1050,7 @@ void GLSLCodeGenerator::writeFunction(const FunctionDefinition& f) {
for (const auto& param : f.fDeclaration.fParameters) {
this->write(separator);
separator = ", ";
this->writeModifiers(param->fModifiers, false);
this->writeModifiers(param->modifiers(), false);
std::vector<int> sizes;
const Type* type = &param->type();
while (type->typeKind() == Type::TypeKind::kArray) {
@ -1177,7 +1177,7 @@ void GLSLCodeGenerator::writeInterfaceBlock(const InterfaceBlock& intf) {
if (intf.fTypeName == "sk_PerVertex") {
return;
}
this->writeModifiers(intf.fVariable.fModifiers, true);
this->writeModifiers(intf.fVariable.modifiers(), true);
this->writeLine(intf.fTypeName + " {");
fIndentation++;
const Type* structType = &intf.fVariable.type();
@ -1245,7 +1245,7 @@ void GLSLCodeGenerator::writeTypePrecision(const Type& type) {
}
void GLSLCodeGenerator::writeVarDeclaration(const VarDeclaration& var, bool global) {
this->writeModifiers(var.fVar->fModifiers, global);
this->writeModifiers(var.fVar->modifiers(), global);
this->writeTypePrecision(var.fBaseType);
this->writeType(var.fBaseType);
this->write(" ");
@ -1487,14 +1487,14 @@ void GLSLCodeGenerator::writeProgramElement(const ProgramElement& e) {
break;
case ProgramElement::Kind::kGlobalVar: {
const VarDeclaration& decl = *e.as<GlobalVarDeclaration>().fDecl;
int builtin = decl.fVar->fModifiers.fLayout.fBuiltin;
int builtin = decl.fVar->modifiers().fLayout.fBuiltin;
if (builtin == -1) {
// normal var
this->writeVarDeclaration(decl, true);
this->writeLine();
} else if (builtin == SK_FRAGCOLOR_BUILTIN &&
fProgram.fSettings.fCaps->mustDeclareFragmentShaderOutput() &&
decl.fVar->fWriteCount) {
decl.fVar->writeCount()) {
if (fProgram.fSettings.fFragColorIsInOut) {
this->write("inout ");
} else {

View File

@ -190,7 +190,7 @@ void HCodeGenerator::writeMake() {
separator = "";
for (const auto& param : fSectionAndParameterHelper.getParameters()) {
this->writef("%s%s %s", separator, ParameterType(fContext, param->type(),
param->fModifiers.fLayout).c_str(),
param->modifiers().fLayout).c_str(),
String(param->name()).c_str());
separator = ", ";
}
@ -234,7 +234,7 @@ void HCodeGenerator::writeConstructor() {
const char* separator = "";
for (const auto& param : fSectionAndParameterHelper.getParameters()) {
this->writef("%s%s %s", separator, ParameterType(fContext, param->type(),
param->fModifiers.fLayout).c_str(),
param->modifiers().fLayout).c_str(),
String(param->name()).c_str());
separator = ", ";
}
@ -287,7 +287,7 @@ void HCodeGenerator::writeConstructor() {
std::string perspExpression;
if (usage.hasUniformMatrix()) {
for (const Variable* p : fSectionAndParameterHelper.getParameters()) {
if ((p->fModifiers.fFlags & Modifiers::kIn_Flag) &&
if ((p->modifiers().fFlags & Modifiers::kIn_Flag) &&
usage.fExpression == String(p->name())) {
perspExpression = usage.fExpression + ".hasPerspective()";
break;
@ -315,7 +315,7 @@ void HCodeGenerator::writeFields() {
// Don't need to write any fields, FPs are held as children
} else {
this->writef(" %s %s;\n", FieldType(fContext, param->type(),
param->fModifiers.fLayout).c_str(),
param->modifiers().fLayout).c_str(),
name.c_str());
}
}

View File

@ -127,7 +127,8 @@ IRGenerator::IRGenerator(const Context* context, Inliner* inliner,
, fSymbolTable(symbolTable)
, fLoopLevel(0)
, fSwitchLevel(0)
, fErrors(errorReporter) {
, fErrors(errorReporter)
, fModifiers(new ModifiersPool()) {
SkASSERT(fInliner);
}
@ -211,6 +212,14 @@ std::unique_ptr<Extension> IRGenerator::convertExtension(int offset, StringFragm
void IRGenerator::finish() {
this->popSymbolTable();
fSettings = nullptr;
// releaseModifiers should have been called before now
SkASSERT(fModifiers->empty());
}
std::unique_ptr<ModifiersPool> IRGenerator::releaseModifiers() {
std::unique_ptr<ModifiersPool> result = std::move(fModifiers);
fModifiers = std::make_unique<ModifiersPool>();
return result;
}
std::unique_ptr<Statement> IRGenerator::convertSingleStatement(const ASTNode& statement) {
@ -444,8 +453,8 @@ std::vector<std::unique_ptr<Statement>> IRGenerator::convertVarDeclarations(
sizes.push_back(nullptr);
}
}
auto var = std::make_unique<Variable>(varDecl.fOffset, modifiers, varData.fName, type,
fIsBuiltinCode, storage);
auto var = std::make_unique<Variable>(varDecl.fOffset, fModifiers->handle(modifiers),
varData.fName, type, fIsBuiltinCode, storage);
if (var->name() == Compiler::RTADJUST_NAME) {
SkASSERT(!fRTAdjust);
SkASSERT(var->type() == *fContext.fFloat4_Type);
@ -461,17 +470,16 @@ std::vector<std::unique_ptr<Statement>> IRGenerator::convertVarDeclarations(
if (!value) {
return {};
}
var->fWriteCount = 1;
var->fInitialValue = value.get();
var->setInitialValue(value.get());
}
const Symbol* symbol = (*fSymbolTable)[var->name()];
Symbol* symbol = (*fSymbolTable)[var->name()];
if (symbol && storage == Variable::kGlobal_Storage && var->name() == "sk_FragColor") {
// Already defined, ignore.
} else if (symbol && storage == Variable::kGlobal_Storage &&
symbol->kind() == Symbol::Kind::kVariable &&
symbol->as<Variable>().fModifiers.fLayout.fBuiltin >= 0) {
symbol->as<Variable>().modifiers().fLayout.fBuiltin >= 0) {
// Already defined, just update the modifiers.
symbol->as<Variable>().fModifiers = var->fModifiers;
symbol->as<Variable>().setModifiersHandle(var->modifiersHandle());
} else {
varDecls.emplace_back(std::make_unique<VarDeclaration>(
var.get(), baseType, std::move(sizes), std::move(value)));
@ -500,9 +508,11 @@ std::unique_ptr<ModifiersDeclaration> IRGenerator::convertModifiersDeclaration(c
fInvocations = modifiers.fLayout.fInvocations;
if (fSettings->fCaps && !fSettings->fCaps->gsInvocationsSupport()) {
modifiers.fLayout.fInvocations = -1;
const Variable& invocationId = (*fSymbolTable)["sk_InvocationID"]->as<Variable>();
invocationId.fModifiers.fFlags = 0;
invocationId.fModifiers.fLayout.fBuiltin = -1;
Variable& invocationId = (*fSymbolTable)["sk_InvocationID"]->as<Variable>();
Modifiers modifiers = invocationId.modifiers();
modifiers.fFlags = 0;
modifiers.fLayout.fBuiltin = -1;
invocationId.setModifiersHandle(fModifiers->handle(modifiers));
if (modifiers.fLayout.description() == "") {
return nullptr;
}
@ -768,7 +778,7 @@ std::unique_ptr<Block> IRGenerator::applyInvocationIDWorkaround(std::unique_ptr<
"_invoke", std::make_unique<FunctionDeclaration>(/*offset=*/-1,
invokeModifiers,
"_invoke",
std::vector<const Variable*>(),
std::vector<Variable*>(),
*fContext.fVoid_Type,
/*builtin=*/false));
fProgramElements->push_back(std::make_unique<FunctionDefinition>(/*offset=*/-1,
@ -930,7 +940,7 @@ void IRGenerator::convertFunction(const ASTNode& f) {
const ASTNode::FunctionData& funcData = f.getFunctionData();
this->checkModifiers(f.fOffset, funcData.fModifiers, Modifiers::kHasSideEffects_Flag |
Modifiers::kInline_Flag);
std::vector<const Variable*> parameters;
std::vector<Variable*> parameters;
for (size_t i = 0; i < funcData.fParameterCount; ++i) {
const ASTNode& param = *(iter++);
SkASSERT(param.fKind == ASTNode::Kind::kParameter);
@ -956,15 +966,16 @@ void IRGenerator::convertFunction(const ASTNode& f) {
return;
}
StringFragment name = pd.fName;
const Variable* var = fSymbolTable->takeOwnershipOfSymbol(
std::make_unique<Variable>(param.fOffset, pd.fModifiers, name, type,
fIsBuiltinCode, Variable::kParameter_Storage));
Variable* var = fSymbolTable->takeOwnershipOfSymbol(
std::make_unique<Variable>(param.fOffset, fModifiers->handle(pd.fModifiers),
name, type, fIsBuiltinCode,
Variable::kParameter_Storage));
parameters.push_back(var);
}
auto paramIsCoords = [&](int idx) {
return parameters[idx]->type() == *fContext.fFloat2_Type &&
parameters[idx]->fModifiers.fFlags == 0;
parameters[idx]->modifiers().fFlags == 0;
};
if (funcData.fName == "main") {
@ -1036,7 +1047,7 @@ void IRGenerator::convertFunction(const ASTNode& f) {
}
decl = other;
for (size_t i = 0; i < parameters.size(); i++) {
if (parameters[i]->fModifiers != other->fParameters[i]->fModifiers) {
if (parameters[i]->modifiers() != other->fParameters[i]->modifiers()) {
fErrors.error(f.fOffset, "modifiers on parameter " +
to_string((uint64_t) i + 1) +
" differ between declaration and definition");
@ -1077,7 +1088,9 @@ void IRGenerator::convertFunction(const ASTNode& f) {
fKind == Program::kFragmentProcessor_Kind)) {
if (parameters.size() == 1) {
SkASSERT(paramIsCoords(0));
parameters[0]->fModifiers.fLayout.fBuiltin = SK_MAIN_COORDS_BUILTIN;
Modifiers m = parameters[0]->modifiers();
m.fLayout.fBuiltin = SK_MAIN_COORDS_BUILTIN;
parameters[0]->setModifiersHandle(fModifiers->handle(m));
}
}
for (size_t i = 0; i < parameters.size(); i++) {
@ -1140,7 +1153,7 @@ std::unique_ptr<InterfaceBlock> IRGenerator::convertInterfaceBlock(const ASTNode
SkASSERT(vd.fVar->type() == *fContext.fFloat4_Type);
fRTAdjustFieldIndex = fields.size();
}
fields.push_back(Type::Field(vd.fVar->fModifiers, vd.fVar->name(),
fields.push_back(Type::Field(vd.fVar->modifiers(), vd.fVar->name(),
&vd.fVar->type()));
if (vd.fValue) {
fErrors.error(decl->fOffset,
@ -1186,9 +1199,9 @@ std::unique_ptr<InterfaceBlock> IRGenerator::convertInterfaceBlock(const ASTNode
sizes.push_back(nullptr);
}
}
const Variable* var = old->takeOwnershipOfSymbol(
Variable* var = old->takeOwnershipOfSymbol(
std::make_unique<Variable>(intf.fOffset,
id.fModifiers,
fModifiers->handle(id.fModifiers),
id.fInstanceName.fLength ? id.fInstanceName : id.fTypeName,
type,
fIsBuiltinCode,
@ -1218,9 +1231,8 @@ bool IRGenerator::getConstantInt(const Expression& value, int64_t* out) {
return true;
case Expression::Kind::kVariableReference: {
const Variable& var = *value.as<VariableReference>().fVariable;
return (var.fModifiers.fFlags & Modifiers::kConst_Flag) &&
var.fInitialValue &&
this->getConstantInt(*var.fInitialValue, out);
return (var.modifiers().fFlags & Modifiers::kConst_Flag) &&
var.initialValue() && this->getConstantInt(*var.initialValue(), out);
}
default:
return false;
@ -1262,8 +1274,9 @@ void IRGenerator::convertEnum(const ASTNode& e) {
++currentValue;
fSymbolTable->add(
child.getString(),
std::make_unique<Variable>(e.fOffset, modifiers, child.getString(), type,
fIsBuiltinCode, Variable::kGlobal_Storage, value.get()));
std::make_unique<Variable>(e.fOffset, fModifiers->handle(modifiers),
child.getString(), type, fIsBuiltinCode,
Variable::kGlobal_Storage, value.get()));
fSymbolTable->takeOwnershipOfIRNode(std::move(value));
}
// Now we orphanize the Enum's symbol table, so that future lookups in it are strict
@ -1376,7 +1389,8 @@ std::unique_ptr<Expression> IRGenerator::convertIdentifier(const ASTNode& identi
}
case Symbol::Kind::kVariable: {
const Variable* var = &result->as<Variable>();
switch (var->fModifiers.fLayout.fBuiltin) {
const Modifiers& modifiers = var->modifiers();
switch (modifiers.fLayout.fBuiltin) {
case SK_WIDTH_BUILTIN:
fInputs.fRTWidth = true;
break;
@ -1394,10 +1408,10 @@ std::unique_ptr<Expression> IRGenerator::convertIdentifier(const ASTNode& identi
#endif
}
if (fKind == Program::kFragmentProcessor_Kind &&
(var->fModifiers.fFlags & Modifiers::kIn_Flag) &&
!(var->fModifiers.fFlags & Modifiers::kUniform_Flag) &&
!var->fModifiers.fLayout.fKey &&
var->fModifiers.fLayout.fBuiltin == -1 &&
(modifiers.fFlags & Modifiers::kIn_Flag) &&
!(modifiers.fFlags & Modifiers::kUniform_Flag) &&
!modifiers.fLayout.fKey &&
modifiers.fLayout.fBuiltin == -1 &&
var->type().nonnullable() != *fContext.fFragmentProcessor_Type &&
var->type().typeKind() != Type::TypeKind::kSampler) {
bool valid = false;
@ -1454,7 +1468,6 @@ std::unique_ptr<Section> IRGenerator::convertSection(const ASTNode& s) {
section.fText);
}
std::unique_ptr<Expression> IRGenerator::coerce(std::unique_ptr<Expression> expr,
const Type& type) {
if (!expr) {
@ -2109,7 +2122,7 @@ std::unique_ptr<Expression> IRGenerator::call(int offset,
if (!arguments[i]) {
return nullptr;
}
const Modifiers& paramModifiers = function.fParameters[i]->fModifiers;
const Modifiers& paramModifiers = function.fParameters[i]->modifiers();
if (paramModifiers.fFlags & Modifiers::kOut_Flag) {
if (!this->setRefKind(*arguments[i], paramModifiers.fFlags & Modifiers::kIn_Flag
? VariableReference::kReadWrite_RefKind
@ -2697,9 +2710,9 @@ std::unique_ptr<Expression> IRGenerator::convertTypeField(int offset, const Type
ASTNode(&fFile->fNodes, offset, ASTNode::Kind::kIdentifier, field));
if (result) {
const Variable& v = *result->as<VariableReference>().fVariable;
SkASSERT(v.fInitialValue);
SkASSERT(v.initialValue());
result = std::make_unique<IntLiteral>(
offset, v.fInitialValue->as<IntLiteral>().value(), &type);
offset, v.initialValue()->as<IntLiteral>().value(), &type);
} else {
fErrors.error(offset,
"type '" + type.name() + "' does not have a member named '" + field +
@ -2860,8 +2873,8 @@ void IRGenerator::cloneBuiltinVariables() {
// so we're pointing at a Program-owned expression.
const Variable* clonedVar =
fGenerator->fSymbolTable->takeOwnershipOfSymbol(std::make_unique<Variable>(
sharedVar->fOffset, sharedVar->fModifiers, sharedVar->name(),
&sharedVar->type(), /*builtin=*/false, sharedVar->fStorage,
sharedVar->fOffset, sharedVar->modifiersHandle(), sharedVar->name(),
&sharedVar->type(), /*builtin=*/false, sharedVar->storage(),
varDecl.fValue.get()));
// Go back and update the VarDeclaration to point at the cloned Variable.
@ -2877,7 +2890,7 @@ void IRGenerator::cloneBuiltinVariables() {
bool visitExpression(Expression& e) override {
// Look for references to builtin variables.
if (e.is<VariableReference>() && e.as<VariableReference>().fVariable->fBuiltin) {
if (e.is<VariableReference>() && e.as<VariableReference>().fVariable->isBuiltin()) {
const Variable* sharedVar = e.as<VariableReference>().fVariable;
this->cloneVariable(sharedVar->name());

View File

@ -123,6 +123,11 @@ private:
*/
void finish();
/**
* Relinquishes ownership of the Modifiers that have been collected so far and returns them.
*/
std::unique_ptr<ModifiersPool> releaseModifiers();
void pushSymbolTable();
void popSymbolTable();
@ -224,6 +229,7 @@ private:
bool fCanInline = true;
// true if we are currently processing one of the built-in SkSL include files
bool fIsBuiltinCode;
std::unique_ptr<ModifiersPool> fModifiers;
friend class AutoSymbolTable;
friend class AutoLoopLevel;

View File

@ -301,9 +301,11 @@ void Inliner::ensureScopedBlocks(Statement* inlinedBody, Statement* parentStmt)
}
}
void Inliner::reset(const Context& context, const Program::Settings& settings) {
fContext = &context;
fSettings = &settings;
void Inliner::reset(const Context* context, ModifiersPool* modifiers,
const Program::Settings* settings) {
fContext = context;
fModifiers = modifiers;
fSettings = settings;
fInlineVarCounter = 0;
}
@ -550,11 +552,11 @@ std::unique_ptr<Statement> Inliner::inlineStatement(int offset,
const Type* typePtr = copy_if_needed(&old->type(), *symbolTableForStatement);
const Variable* clone = symbolTableForStatement->takeOwnershipOfSymbol(
std::make_unique<Variable>(offset,
old->fModifiers,
old->modifiersHandle(),
namePtr->c_str(),
typePtr,
isBuiltinCode,
old->fStorage,
old->storage(),
initialValue.get()));
(*varMap)[old] = std::make_unique<VariableReference>(offset, clone);
return std::make_unique<VarDeclaration>(clone, baseTypePtr, std::move(sizes),
@ -628,9 +630,10 @@ Inliner::InlinedCall Inliner::inlineCall(FunctionCall* call,
StringFragment nameFrag{namePtr->c_str(), namePtr->length()};
// Add our new variable to the symbol table.
auto newVar = std::make_unique<Variable>(/*offset=*/-1, Modifiers(), nameFrag, type,
caller->fBuiltin, Variable::kLocal_Storage,
initialValue->get());
auto newVar = std::make_unique<Variable>(/*offset=*/-1,
fModifiers->handle(Modifiers()),
nameFrag, type, caller->fBuiltin,
Variable::kLocal_Storage, initialValue->get());
const Variable* variableSymbol = symbolTableForCall->add(nameFrag, std::move(newVar));
// Prepare the variable declaration (taking extra care with `out` params to not clobber any
@ -667,7 +670,7 @@ Inliner::InlinedCall Inliner::inlineCall(FunctionCall* call,
std::vector<int> argsToCopyBack;
for (int i = 0; i < (int) arguments.size(); ++i) {
const Variable* param = function.fDeclaration.fParameters[i];
bool isOutParam = param->fModifiers.fFlags & Modifiers::kOut_Flag;
bool isOutParam = param->modifiers().fFlags & Modifiers::kOut_Flag;
// If this argument can be inlined trivially (e.g. a swizzle, or a constant array index)...
if (is_trivial_argument(*arguments[i])) {
@ -684,7 +687,7 @@ Inliner::InlinedCall Inliner::inlineCall(FunctionCall* call,
}
varMap[param] = makeInlineVar(String(param->name()), &arguments[i]->type(),
param->fModifiers, &arguments[i]);
param->modifiers(), &arguments[i]);
}
const Block& body = function.fBody->as<Block>();
@ -730,7 +733,8 @@ Inliner::InlinedCall Inliner::inlineCall(FunctionCall* call,
} else {
// It's a void function, so it doesn't actually result in anything, but we have to return
// something non-null as a standin.
inlinedCall.fReplacementExpr = std::make_unique<BoolLiteral>(*fContext, offset,
inlinedCall.fReplacementExpr = std::make_unique<BoolLiteral>(*fContext,
offset,
/*value=*/false);
}

View File

@ -23,9 +23,10 @@ struct FunctionCall;
struct FunctionDefinition;
struct InlineCandidate;
struct InlineCandidateList;
class ModifiersPool;
struct Statement;
class SymbolTable;
struct Variable;
class Variable;
/**
* Converts a FunctionCall in the IR to a set of statements to be injected ahead of the function
@ -37,7 +38,7 @@ class Inliner {
public:
Inliner() {}
void reset(const Context&, const Program::Settings&);
void reset(const Context*, ModifiersPool* modifiers, const Program::Settings*);
/**
* Processes the passed-in FunctionCall expression. The FunctionCall expression should be
@ -87,6 +88,7 @@ private:
bool isLargeFunction(const InlineCandidate& candidate, LargeFunctionCache* cache);
const Context* fContext = nullptr;
ModifiersPool* fModifiers = nullptr;
const Program::Settings* fSettings = nullptr;
int fInlineVarCounter = 0;
};

View File

@ -265,7 +265,7 @@ void MetalCodeGenerator::writeFunctionCall(const FunctionCall& c) {
const Expression& arg = *arguments[i];
this->write(separator);
separator = ", ";
if (function.fParameters[i]->fModifiers.fFlags & Modifiers::kOut_Flag) {
if (function.fParameters[i]->modifiers().fFlags & Modifiers::kOut_Flag) {
this->write("&");
}
this->writeExpression(arg, kSequence_Precedence);
@ -680,7 +680,7 @@ void MetalCodeGenerator::writeFragCoord() {
}
void MetalCodeGenerator::writeVariableReference(const VariableReference& ref) {
switch (ref.fVariable->fModifiers.fLayout.fBuiltin) {
switch (ref.fVariable->modifiers().fLayout.fBuiltin) {
case SK_FRAGCOLOR_BUILTIN:
this->write("_out->sk_FragColor");
break;
@ -699,12 +699,12 @@ void MetalCodeGenerator::writeVariableReference(const VariableReference& ref) {
this->write(fProgram.fSettings.fFlipY ? "_frontFacing" : "(!_frontFacing)");
break;
default:
if (Variable::kGlobal_Storage == ref.fVariable->fStorage) {
if (ref.fVariable->fModifiers.fFlags & Modifiers::kIn_Flag) {
if (Variable::kGlobal_Storage == ref.fVariable->storage()) {
if (ref.fVariable->modifiers().fFlags & Modifiers::kIn_Flag) {
this->write("_in.");
} else if (ref.fVariable->fModifiers.fFlags & Modifiers::kOut_Flag) {
} else if (ref.fVariable->modifiers().fFlags & Modifiers::kOut_Flag) {
this->write("_out->");
} else if (ref.fVariable->fModifiers.fFlags & Modifiers::kUniform_Flag &&
} else if (ref.fVariable->modifiers().fFlags & Modifiers::kUniform_Flag &&
ref.fVariable->type().typeKind() != Type::TypeKind::kSampler) {
this->write("_uniforms.");
} else {
@ -836,8 +836,8 @@ void MetalCodeGenerator::writeBinaryExpression(const BinaryExpression& b,
this->write("(");
}
if (Compiler::IsAssignment(op) && left.is<VariableReference>() &&
left.as<VariableReference>().fVariable->fStorage == Variable::kParameter_Storage &&
left.as<VariableReference>().fVariable->fModifiers.fFlags & Modifiers::kOut_Flag) {
left.as<VariableReference>().fVariable->storage() == Variable::kParameter_Storage &&
left.as<VariableReference>().fVariable->modifiers().fFlags & Modifiers::kOut_Flag) {
// writing to an out parameter. Since we have to turn those into pointers, we have to
// dereference it here.
this->write("*");
@ -955,7 +955,7 @@ void MetalCodeGenerator::writeFunction(const FunctionDefinition& f) {
const GlobalVarDeclaration& decls = e.as<GlobalVarDeclaration>();
const VarDeclaration& var = *decls.fDecl;
if (var.fVar->type().typeKind() == Type::TypeKind::kSampler) {
if (var.fVar->fModifiers.fLayout.fBinding < 0) {
if (var.fVar->modifiers().fLayout.fBinding < 0) {
fErrors.error(decls.fOffset,
"Metal samplers must have 'layout(binding=...)'");
return;
@ -968,13 +968,13 @@ void MetalCodeGenerator::writeFunction(const FunctionDefinition& f) {
this->write(", texture2d<float> ");
this->writeName(var.fVar->name());
this->write("[[texture(");
this->write(to_string(var.fVar->fModifiers.fLayout.fBinding));
this->write(to_string(var.fVar->modifiers().fLayout.fBinding));
this->write(")]]");
this->write(", sampler ");
this->writeName(var.fVar->name());
this->write(SAMPLER_SUFFIX);
this->write("[[sampler(");
this->write(to_string(var.fVar->fModifiers.fLayout.fBinding));
this->write(to_string(var.fVar->modifiers().fLayout.fBinding));
this->write(")]]");
}
} else if (e.kind() == ProgramElement::Kind::kInterfaceBlock) {
@ -987,7 +987,7 @@ void MetalCodeGenerator::writeFunction(const FunctionDefinition& f) {
this->write("& " );
this->write(fInterfaceBlockNameMap[&intf]);
this->write(" [[buffer(");
this->write(to_string(intf.fVariable.fModifiers.fLayout.fBinding));
this->write(to_string(intf.fVariable.modifiers().fLayout.fBinding));
this->write(")]]");
}
}
@ -1036,7 +1036,7 @@ void MetalCodeGenerator::writeFunction(const FunctionDefinition& f) {
for (const auto& param : f.fDeclaration.fParameters) {
this->write(separator);
separator = ", ";
this->writeModifiers(param->fModifiers, false);
this->writeModifiers(param->modifiers(), false);
std::vector<int> sizes;
const Type* type = &param->type();
while (type->typeKind() == Type::TypeKind::kArray) {
@ -1044,7 +1044,7 @@ void MetalCodeGenerator::writeFunction(const FunctionDefinition& f) {
type = &type->componentType();
}
this->writeType(*type);
if (param->fModifiers.fFlags & Modifiers::kOut_Flag) {
if (param->modifiers().fFlags & Modifiers::kOut_Flag) {
this->write("*");
}
this->write(" ");
@ -1113,7 +1113,7 @@ void MetalCodeGenerator::writeInterfaceBlock(const InterfaceBlock& intf) {
if ("sk_PerVertex" == intf.fTypeName) {
return;
}
this->writeModifiers(intf.fVariable.fModifiers, true);
this->writeModifiers(intf.fVariable.modifiers(), true);
this->write("struct ");
this->writeLine(intf.fTypeName + " {");
const Type* structType = &intf.fVariable.type();
@ -1215,10 +1215,10 @@ void MetalCodeGenerator::writeName(const String& name) {
}
void MetalCodeGenerator::writeVarDeclaration(const VarDeclaration& var, bool global) {
if (global && !(var.fVar->fModifiers.fFlags & Modifiers::kConst_Flag)) {
if (global && !(var.fVar->modifiers().fFlags & Modifiers::kConst_Flag)) {
return;
}
this->writeModifiers(var.fVar->fModifiers, global);
this->writeModifiers(var.fVar->modifiers(), global);
this->writeType(var.fBaseType);
this->write(" ");
this->writeName(var.fVar->name());
@ -1393,15 +1393,15 @@ void MetalCodeGenerator::writeUniformStruct() {
if (e.is<GlobalVarDeclaration>()) {
const GlobalVarDeclaration& decls = e.as<GlobalVarDeclaration>();
const Variable& var = *decls.fDecl->fVar;
if (var.fModifiers.fFlags & Modifiers::kUniform_Flag &&
if (var.modifiers().fFlags & Modifiers::kUniform_Flag &&
var.type().typeKind() != Type::TypeKind::kSampler) {
if (-1 == fUniformBuffer) {
this->write("struct Uniforms {\n");
fUniformBuffer = var.fModifiers.fLayout.fSet;
fUniformBuffer = var.modifiers().fLayout.fSet;
if (-1 == fUniformBuffer) {
fErrors.error(decls.fOffset, "Metal uniforms must have 'layout(set=...)'");
}
} else if (var.fModifiers.fLayout.fSet != fUniformBuffer) {
} else if (var.modifiers().fLayout.fSet != fUniformBuffer) {
if (-1 == fUniformBuffer) {
fErrors.error(decls.fOffset, "Metal backend requires all uniforms to have "
"the same 'layout(set=...)'");
@ -1426,19 +1426,19 @@ void MetalCodeGenerator::writeInputStruct() {
if (e.is<GlobalVarDeclaration>()) {
const GlobalVarDeclaration& decls = e.as<GlobalVarDeclaration>();
const Variable& var = *decls.fDecl->fVar;
if (var.fModifiers.fFlags & Modifiers::kIn_Flag &&
-1 == var.fModifiers.fLayout.fBuiltin) {
if (var.modifiers().fFlags & Modifiers::kIn_Flag &&
-1 == var.modifiers().fLayout.fBuiltin) {
this->write(" ");
this->writeType(var.type());
this->write(" ");
this->writeName(var.name());
if (-1 != var.fModifiers.fLayout.fLocation) {
if (-1 != var.modifiers().fLayout.fLocation) {
if (fProgram.fKind == Program::kVertex_Kind) {
this->write(" [[attribute(" +
to_string(var.fModifiers.fLayout.fLocation) + ")]]");
to_string(var.modifiers().fLayout.fLocation) + ")]]");
} else if (fProgram.fKind == Program::kFragment_Kind) {
this->write(" [[user(locn" +
to_string(var.fModifiers.fLayout.fLocation) + ")]]");
to_string(var.modifiers().fLayout.fLocation) + ")]]");
}
}
this->write(";\n");
@ -1459,19 +1459,19 @@ void MetalCodeGenerator::writeOutputStruct() {
if (e.is<GlobalVarDeclaration>()) {
const GlobalVarDeclaration& decls = e.as<GlobalVarDeclaration>();
const Variable& var = *decls.fDecl->fVar;
if (var.fModifiers.fFlags & Modifiers::kOut_Flag &&
-1 == var.fModifiers.fLayout.fBuiltin) {
if (var.modifiers().fFlags & Modifiers::kOut_Flag &&
-1 == var.modifiers().fLayout.fBuiltin) {
this->write(" ");
this->writeType(var.type());
this->write(" ");
this->writeName(var.name());
if (fProgram.fKind == Program::kVertex_Kind) {
this->write(" [[user(locn" +
to_string(var.fModifiers.fLayout.fLocation) + ")]]");
to_string(var.modifiers().fLayout.fLocation) + ")]]");
} else if (fProgram.fKind == Program::kFragment_Kind) {
this->write(" [[color(" +
to_string(var.fModifiers.fLayout.fLocation) +")");
int colorIndex = var.fModifiers.fLayout.fIndex;
to_string(var.modifiers().fLayout.fLocation) +")");
int colorIndex = var.modifiers().fLayout.fIndex;
if (colorIndex) {
this->write(", index(" + to_string(colorIndex) + ")");
}
@ -1514,7 +1514,7 @@ void MetalCodeGenerator::visitGlobalStruct(GlobalStructVisitor* visitor) {
const GlobalVarDeclaration& decls = element.as<GlobalVarDeclaration>();
const VarDeclaration& decl = *decls.fDecl;
const Variable& var = *decl.fVar;
if ((!var.fModifiers.fFlags && -1 == var.fModifiers.fLayout.fBuiltin) ||
if ((!var.modifiers().fFlags && -1 == var.modifiers().fLayout.fBuiltin) ||
var.type().typeKind() == Type::TypeKind::kSampler) {
if (var.type().typeKind() == Type::TypeKind::kSampler) {
// Samplers are represented as a "texture/sampler" duo in the global struct.
@ -1638,7 +1638,7 @@ void MetalCodeGenerator::writeProgramElement(const ProgramElement& e) {
break;
case ProgramElement::Kind::kGlobalVar: {
const VarDeclaration& decl = *e.as<GlobalVarDeclaration>().fDecl;
int builtin = decl.fVar->fModifiers.fLayout.fBuiltin;
int builtin = decl.fVar->modifiers().fLayout.fBuiltin;
if (-1 == builtin) {
// normal var
this->writeVarDeclaration(decl, true);
@ -1716,15 +1716,16 @@ MetalCodeGenerator::Requirements MetalCodeGenerator::requirements(const Expressi
}
case Expression::Kind::kVariableReference: {
const VariableReference& v = e->as<VariableReference>();
const Modifiers& modifiers = v.fVariable->modifiers();
Requirements result = kNo_Requirements;
if (v.fVariable->fModifiers.fLayout.fBuiltin == SK_FRAGCOORD_BUILTIN) {
if (modifiers.fLayout.fBuiltin == SK_FRAGCOORD_BUILTIN) {
result = kGlobals_Requirement | kFragCoord_Requirement;
} else if (Variable::kGlobal_Storage == v.fVariable->fStorage) {
if (v.fVariable->fModifiers.fFlags & Modifiers::kIn_Flag) {
} else if (Variable::kGlobal_Storage == v.fVariable->storage()) {
if (modifiers.fFlags & Modifiers::kIn_Flag) {
result = kInputs_Requirement;
} else if (v.fVariable->fModifiers.fFlags & Modifiers::kOut_Flag) {
} else if (modifiers.fFlags & Modifiers::kOut_Flag) {
result = kOutputs_Requirement;
} else if (v.fVariable->fModifiers.fFlags & Modifiers::kUniform_Flag &&
} else if (modifiers.fFlags & Modifiers::kUniform_Flag &&
v.fVariable->type().typeKind() != Type::TypeKind::kSampler) {
result = kUniforms_Requirement;
} else {

View File

@ -0,0 +1,73 @@
/*
* Copyright 2020 Google LLC.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SKSL_MODIFIERSPOOL
#define SKSL_MODIFIERSPOOL
#include <unordered_map>
namespace SkSL {
struct Modifiers;
/**
* Stores a pool of Modifiers objects. Modifiers is fairly heavy, so to reduce IRNode's size we only
* store a handle to the Modifiers inside of the node and keep the object itself in a ModifiersPool.
*/
class ModifiersPool {
public:
class Handle {
public:
Handle() = default;
Handle(const ModifiersPool* pool, int index)
: fPool(pool)
, fIndex(index) {}
const Modifiers* operator->() const {
return &fPool->fModifiers[fIndex];
}
const Modifiers& operator*() const {
return fPool->fModifiers[fIndex];
}
private:
const ModifiersPool* fPool;
int fIndex;
};
bool empty() {
return fModifiers.empty();
}
Handle handle(const Modifiers& modifiers) {
SkASSERT(fModifiers.size() == fModifiersMap.size());
int index;
auto found = fModifiersMap.find(modifiers);
if (found != fModifiersMap.end()) {
index = found->second;
} else {
index = fModifiers.size();
fModifiers.push_back(modifiers);
fModifiersMap.insert({modifiers, index});
}
return Handle(this, index);
}
void finish() {
fModifiersMap.clear();
}
private:
std::vector<Modifiers> fModifiers;
std::unordered_map<Modifiers, int> fModifiersMap;
};
} // namespace SkSL
#endif

View File

@ -107,7 +107,7 @@ void PipelineStageCodeGenerator::writeIntLiteral(const IntLiteral& i) {
}
void PipelineStageCodeGenerator::writeVariableReference(const VariableReference& ref) {
switch (ref.fVariable->fModifiers.fLayout.fBuiltin) {
switch (ref.fVariable->modifiers().fLayout.fBuiltin) {
case SK_OUTCOLOR_BUILTIN:
this->write(Compiler::kFormatArgPlaceholderStr);
fArgs->fFormatArgs.push_back(Compiler::FormatArg(Compiler::FormatArg::Kind::kOutput));
@ -130,7 +130,7 @@ void PipelineStageCodeGenerator::writeVariableReference(const VariableReference&
found = true;
break;
}
if (var.fModifiers.fFlags & flag) {
if (var.modifiers().fFlags & flag) {
++index;
}
}
@ -139,12 +139,12 @@ void PipelineStageCodeGenerator::writeVariableReference(const VariableReference&
return index;
};
if (ref.fVariable->fModifiers.fFlags & Modifiers::kUniform_Flag) {
if (ref.fVariable->modifiers().fFlags & Modifiers::kUniform_Flag) {
this->write(Compiler::kFormatArgPlaceholderStr);
fArgs->fFormatArgs.push_back(
Compiler::FormatArg(Compiler::FormatArg::Kind::kUniform,
varIndexByFlag(Modifiers::kUniform_Flag)));
} else if (ref.fVariable->fModifiers.fFlags & Modifiers::kVarying_Flag) {
} else if (ref.fVariable->modifiers().fFlags & Modifiers::kVarying_Flag) {
this->write("_vtx_attr_");
this->write(to_string(varIndexByFlag(Modifiers::kVarying_Flag)));
} else {
@ -214,9 +214,9 @@ void PipelineStageCodeGenerator::writeProgramElement(const ProgramElement& p) {
}
if (p.is<GlobalVarDeclaration>()) {
const Variable& var = *p.as<GlobalVarDeclaration>().fDecl->fVar;
if (var.fModifiers.fFlags &
if (var.modifiers().fFlags &
(Modifiers::kIn_Flag | Modifiers::kUniform_Flag | Modifiers::kVarying_Flag) ||
-1 != var.fModifiers.fLayout.fBuiltin) {
var.modifiers().fLayout.fBuiltin == -1) {
return;
}
}

View File

@ -126,7 +126,7 @@ Modifiers Rehydrator::modifiers() {
}
}
const Symbol* Rehydrator::symbol() {
Symbol* Rehydrator::symbol() {
int kind = this->readU8();
switch (kind) {
case kArrayType_Command: {
@ -139,7 +139,7 @@ const Symbol* Rehydrator::symbol() {
} else {
name += "[" + to_string(count) + "]";
}
const Type* result = fSymbolTable->takeOwnershipOfSymbol(
Type* result = fSymbolTable->takeOwnershipOfSymbol(
std::make_unique<Type>(name, Type::TypeKind::kArray, *componentType, count));
this->addSymbol(id, result);
return result;
@ -147,7 +147,7 @@ const Symbol* Rehydrator::symbol() {
case kEnumType_Command: {
uint16_t id = this->readU16();
StringFragment name = this->readString();
const Type* result = fSymbolTable->takeOwnershipOfSymbol(
Type* result = fSymbolTable->takeOwnershipOfSymbol(
std::make_unique<Type>(name, Type::TypeKind::kEnum));
this->addSymbol(id, result);
return result;
@ -157,13 +157,13 @@ const Symbol* Rehydrator::symbol() {
Modifiers modifiers = this->modifiers();
StringFragment name = this->readString();
int parameterCount = this->readU8();
std::vector<const Variable*> parameters;
std::vector<Variable*> parameters;
parameters.reserve(parameterCount);
for (int i = 0; i < parameterCount; ++i) {
parameters.push_back(this->symbolRef<Variable>(Symbol::Kind::kVariable));
}
const Type* returnType = this->type();
const FunctionDeclaration* result =
FunctionDeclaration* result =
fSymbolTable->takeOwnershipOfSymbol(std::make_unique<FunctionDeclaration>(
/*offset=*/-1, modifiers, name, std::move(parameters), *returnType,
/*builtin=*/true));
@ -173,14 +173,14 @@ const Symbol* Rehydrator::symbol() {
case kField_Command: {
const Variable* owner = this->symbolRef<Variable>(Symbol::Kind::kVariable);
uint8_t index = this->readU8();
const Field* result = fSymbolTable->takeOwnershipOfSymbol(
Field* result = fSymbolTable->takeOwnershipOfSymbol(
std::make_unique<Field>(/*offset=*/-1, owner, index));
return result;
}
case kNullableType_Command: {
uint16_t id = this->readU16();
const Type* base = this->type();
const Type* result = fSymbolTable->takeOwnershipOfSymbol(
Type* result = fSymbolTable->takeOwnershipOfSymbol(
std::make_unique<Type>(base->name() + "?", Type::TypeKind::kNullable, *base));
this->addSymbol(id, result);
return result;
@ -197,7 +197,7 @@ const Symbol* Rehydrator::symbol() {
const Type* type = this->type();
fields.emplace_back(m, fieldName, type);
}
const Type* result = fSymbolTable->takeOwnershipOfSymbol(
Type* result = fSymbolTable->takeOwnershipOfSymbol(
std::make_unique<Type>(/*offset=*/-1, name, std::move(fields)));
this->addSymbol(id, result);
return result;
@ -210,8 +210,8 @@ const Symbol* Rehydrator::symbol() {
case kSymbolAlias_Command: {
uint16_t id = this->readU16();
StringFragment name = this->readString();
const Symbol* origSymbol = this->symbol();
const SymbolAlias* symbolAlias = fSymbolTable->takeOwnershipOfSymbol(
Symbol* origSymbol = this->symbol();
SymbolAlias* symbolAlias = fSymbolTable->takeOwnershipOfSymbol(
std::make_unique<SymbolAlias>(/*offset=*/-1, name, origSymbol));
this->addSymbol(id, symbolAlias);
return symbolAlias;
@ -219,7 +219,7 @@ const Symbol* Rehydrator::symbol() {
case kSystemType_Command: {
uint16_t id = this->readU16();
StringFragment name = this->readString();
const Symbol* result = (*fSymbolTable)[name];
Symbol* result = (*fSymbolTable)[name];
SkASSERT(result && result->kind() == Symbol::Kind::kType);
this->addSymbol(id, result);
return result;
@ -234,18 +234,18 @@ const Symbol* Rehydrator::symbol() {
SkASSERT(f && f->kind() == Symbol::Kind::kFunctionDeclaration);
functions.push_back((const FunctionDeclaration*) f);
}
const UnresolvedFunction* result = fSymbolTable->takeOwnershipOfSymbol(
UnresolvedFunction* result = fSymbolTable->takeOwnershipOfSymbol(
std::make_unique<UnresolvedFunction>(std::move(functions)));
this->addSymbol(id, result);
return result;
}
case kVariable_Command: {
uint16_t id = this->readU16();
Modifiers m = this->modifiers();
ModifiersPool::Handle m = fModifiers.handle(this->modifiers());
StringFragment name = this->readString();
const Type* type = this->type();
Variable::Storage storage = (Variable::Storage) this->readU8();
const Variable* result = fSymbolTable->takeOwnershipOfSymbol(std::make_unique<Variable>(
Variable* result = fSymbolTable->takeOwnershipOfSymbol(std::make_unique<Variable>(
/*offset=*/-1, m, name, type, /*builtin=*/true, storage));
this->addSymbol(id, result);
return result;
@ -285,9 +285,8 @@ std::unique_ptr<ProgramElement> Rehydrator::element() {
SkASSERT(s->kind() == Symbol::Kind::kVariable);
Variable& v = (Variable&) *s;
int value = this->readS32();
v.fInitialValue = symbols->takeOwnershipOfIRNode(
std::make_unique<IntLiteral>(fContext, /*offset=*/-1, value));
v.fWriteCount = 1;
v.setInitialValue(symbols->takeOwnershipOfIRNode(
std::make_unique<IntLiteral>(fContext, /*offset=*/-1, value)));
}
return std::unique_ptr<ProgramElement>(new Enum(-1, typeName, std::move(symbols)));
}
@ -429,9 +428,7 @@ std::unique_ptr<Statement> Rehydrator::statement() {
}
std::unique_ptr<Expression> value = this->expression();
if (value) {
var->fInitialValue = value.get();
SkASSERT(var->fWriteCount == 0);
++var->fWriteCount;
var->setInitialValue(value.get());
}
return std::unique_ptr<Statement>(
new VarDeclaration(var, baseType, std::move(sizes), std::move(value)));
@ -567,7 +564,7 @@ std::shared_ptr<SymbolTable> Rehydrator::symbolTable(bool inherit) {
std::shared_ptr<SymbolTable> result = inherit ? std::make_shared<SymbolTable>(fSymbolTable)
: std::make_shared<SymbolTable>(fErrors);
fSymbolTable = result;
std::vector<const Symbol*> ownedSymbols;
std::vector<Symbol*> ownedSymbols;
ownedSymbols.reserve(ownedCount);
for (int i = 0; i < ownedCount; ++i) {
ownedSymbols.push_back(this->symbol());

View File

@ -20,6 +20,7 @@ namespace SkSL {
class Context;
class ErrorReporter;
struct Expression;
class IRGenerator;
struct ProgramElement;
struct Statement;
class SymbolTable;
@ -144,9 +145,11 @@ public:
};
// src must remain in memory as long as the objects created from it do
Rehydrator(Context* context, std::shared_ptr<SymbolTable> symbolTable,
ErrorReporter* errorReporter, const uint8_t* src, size_t length)
Rehydrator(const Context* context, ModifiersPool* modifiers,
std::shared_ptr<SymbolTable> symbolTable, ErrorReporter* errorReporter,
const uint8_t* src, size_t length)
: fContext(*context)
, fModifiers(*modifiers)
, fErrors(errorReporter)
, fSymbolTable(std::move(symbolTable))
, fStart(src)
@ -200,7 +203,7 @@ private:
return StringFragment(chars, length);
}
void addSymbol(int id, const Symbol* symbol) {
void addSymbol(int id, Symbol* symbol) {
while ((size_t) id >= fSymbols.size()) {
fSymbols.push_back(nullptr);
}
@ -218,7 +221,7 @@ private:
Modifiers modifiers();
const Symbol* symbol();
Symbol* symbol();
std::unique_ptr<ProgramElement> element();
@ -228,10 +231,11 @@ private:
const Type* type();
Context& fContext;
const Context& fContext;
ModifiersPool& fModifiers;
ErrorReporter* fErrors;
std::shared_ptr<SymbolTable> fSymbolTable;
std::vector<const Symbol*> fSymbols;
std::vector<Symbol*> fSymbols;
const uint8_t* fStart;
const uint8_t* fIP;

View File

@ -179,7 +179,7 @@ static bool is_bool(const Context& context, const Type& type) {
}
static bool is_out(const Variable& var) {
return (var.fModifiers.fFlags & Modifiers::kOut_Flag) != 0;
return (var.modifiers().fFlags & Modifiers::kOut_Flag) != 0;
}
void SPIRVCodeGenerator::writeOpCode(SpvOp_ opCode, int length, OutputStream& out) {
@ -717,7 +717,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]->fModifiers.fFlags & Modifiers::kOut_Flag) {
if (function.fParameters[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 +737,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]->fModifiers.fFlags & Modifiers::kOut_Flag) {
if (function.fParameters[i]->modifiers().fFlags & Modifiers::kOut_Flag) {
argumentIds.push_back(this->getLValue(*arguments[i], out)->getPointer());
} else {
argumentIds.push_back(this->writeExpression(*arguments[i], out));
@ -1564,10 +1564,10 @@ SpvStorageClass_ get_storage_class(const Expression& expr) {
switch (expr.kind()) {
case Expression::Kind::kVariableReference: {
const Variable& var = *expr.as<VariableReference>().fVariable;
if (var.fStorage != Variable::kGlobal_Storage) {
if (var.storage() != Variable::kGlobal_Storage) {
return SpvStorageClassFunction;
}
SpvStorageClass_ result = get_storage_class(var.fModifiers);
SpvStorageClass_ result = get_storage_class(var.modifiers());
if (result == SpvStorageClassFunction) {
result = SpvStorageClassPrivate;
}
@ -1727,7 +1727,7 @@ std::unique_ptr<SPIRVCodeGenerator::LValue> SPIRVCodeGenerator::getLValue(const
case Expression::Kind::kVariableReference: {
SpvId typeId;
const Variable& var = *expr.as<VariableReference>().fVariable;
if (var.fModifiers.fLayout.fBuiltin == SK_IN_BUILTIN) {
if (var.modifiers().fLayout.fBuiltin == SK_IN_BUILTIN) {
typeId = this->getType(Type("sk_in", Type::TypeKind::kArray,
var.type().componentType(), fSkInCount));
} else {
@ -1838,7 +1838,7 @@ SpvId SPIRVCodeGenerator::writeVariableReference(const VariableReference& ref, O
SpvId var = entry->second;
this->writeInstruction(SpvOpLoad, this->getType(ref.fVariable->type()), result, var, out);
this->writePrecisionModifier(ref.fVariable->type(), result);
if (ref.fVariable->fModifiers.fLayout.fBuiltin == SK_FRAGCOORD_BUILTIN &&
if (ref.fVariable->modifiers().fLayout.fBuiltin == SK_FRAGCOORD_BUILTIN &&
(fProgram.fSettings.fFlipY || fProgram.fSettings.fInverseW)) {
// The x component never changes, so just grab it
SpvId xId = this->nextId();
@ -1875,9 +1875,10 @@ SpvId SPIRVCodeGenerator::writeVariableReference(const VariableReference& ref, O
Layout layout(0, -1, -1, binding, -1, set, -1, -1, Layout::Format::kUnspecified,
Layout::kUnspecified_Primitive, -1, -1, "", "", Layout::kNo_Key,
Layout::CType::kDefault);
Modifiers modifiers(layout, Modifiers::kUniform_Flag);
const Variable* intfVar = fSynthetics.takeOwnershipOfSymbol(
std::make_unique<Variable>(/*offset=*/-1,
Modifiers(layout, Modifiers::kUniform_Flag),
fModifiers.handle(modifiers),
name,
&intfStruct,
/*builtin=*/false,
@ -1946,7 +1947,7 @@ SpvId SPIRVCodeGenerator::writeVariableReference(const VariableReference& ref, O
return adjusted;
}
if (ref.fVariable->fModifiers.fLayout.fBuiltin == SK_CLOCKWISE_BUILTIN &&
if (ref.fVariable->modifiers().fLayout.fBuiltin == SK_CLOCKWISE_BUILTIN &&
!fProgram.fSettings.fFlipY) {
// FrontFacing in Vulkan is defined in terms of a top-down render target. In skia, we use
// the default convention of "counter-clockwise face is front".
@ -2692,8 +2693,8 @@ static void update_sk_in_count(const Modifiers& m, int* outSkInCount) {
}
SpvId SPIRVCodeGenerator::writeInterfaceBlock(const InterfaceBlock& intf, bool appendRTHeight) {
bool isBuffer = (0 != (intf.fVariable.fModifiers.fFlags & Modifiers::kBuffer_Flag));
bool pushConstant = (0 != (intf.fVariable.fModifiers.fLayout.fFlags &
bool isBuffer = (0 != (intf.fVariable.modifiers().fFlags & Modifiers::kBuffer_Flag));
bool pushConstant = (0 != (intf.fVariable.modifiers().fLayout.fFlags &
Layout::kPushConstant_Flag));
MemoryLayout memoryLayout = (pushConstant || isBuffer) ?
MemoryLayout(MemoryLayout::k430_Standard) :
@ -2710,7 +2711,8 @@ SpvId SPIRVCodeGenerator::writeInterfaceBlock(const InterfaceBlock& intf, bool a
type = new Type(type->fOffset, type->name(), fields);
}
SpvId typeId;
if (intf.fVariable.fModifiers.fLayout.fBuiltin == SK_IN_BUILTIN) {
Modifiers intfModifiers = intf.fVariable.modifiers();
if (intfModifiers.fLayout.fBuiltin == SK_IN_BUILTIN) {
for (const auto& e : fProgram) {
if (e.kind() == ProgramElement::Kind::kModifiers) {
const Modifiers& m = ((ModifiersDeclaration&) e).fModifiers;
@ -2724,17 +2726,17 @@ SpvId SPIRVCodeGenerator::writeInterfaceBlock(const InterfaceBlock& intf, bool a
} else {
typeId = this->getType(*type, memoryLayout);
}
if (intf.fVariable.fModifiers.fFlags & Modifiers::kBuffer_Flag) {
if (intfModifiers.fFlags & Modifiers::kBuffer_Flag) {
this->writeInstruction(SpvOpDecorate, typeId, SpvDecorationBufferBlock, fDecorationBuffer);
} else if (intf.fVariable.fModifiers.fLayout.fBuiltin == -1) {
} else if (intfModifiers.fLayout.fBuiltin == -1) {
this->writeInstruction(SpvOpDecorate, typeId, SpvDecorationBlock, fDecorationBuffer);
}
SpvStorageClass_ storageClass = get_storage_class(intf.fVariable.fModifiers);
SpvStorageClass_ storageClass = get_storage_class(intfModifiers);
SpvId ptrType = this->nextId();
this->writeInstruction(SpvOpTypePointer, ptrType, storageClass, typeId, fConstantBuffer);
this->writeInstruction(SpvOpVariable, ptrType, result, storageClass, fConstantBuffer);
Layout layout = intf.fVariable.fModifiers.fLayout;
if (intf.fVariable.fModifiers.fFlags & Modifiers::kUniform_Flag && layout.fSet == -1) {
Layout layout = intfModifiers.fLayout;
if (intfModifiers.fFlags & Modifiers::kUniform_Flag && layout.fSet == -1) {
layout.fSet = 0;
}
this->writeLayout(layout, result);
@ -2756,19 +2758,19 @@ void SPIRVCodeGenerator::writePrecisionModifier(Precision precision, SpvId id) {
}
bool is_dead(const Variable& var) {
if (var.fReadCount || var.fWriteCount) {
if (var.readCount() || var.writeCount()) {
return false;
}
// not entirely sure what the rules are for when it's safe to elide interface variables, but it
// causes various problems to elide some of them even when dead. But it also causes problems
// *not* to elide sk_SampleMask when it's not being used.
if (!(var.fModifiers.fFlags & (Modifiers::kIn_Flag |
Modifiers::kOut_Flag |
Modifiers::kUniform_Flag |
Modifiers::kBuffer_Flag))) {
if (!(var.modifiers().fFlags & (Modifiers::kIn_Flag |
Modifiers::kOut_Flag |
Modifiers::kUniform_Flag |
Modifiers::kBuffer_Flag))) {
return true;
}
return var.fModifiers.fLayout.fBuiltin == SK_SAMPLEMASK_BUILTIN;
return var.modifiers().fLayout.fBuiltin == SK_SAMPLEMASK_BUILTIN;
}
#define BUILTIN_IGNORE 9999
@ -2777,15 +2779,15 @@ void SPIRVCodeGenerator::writeGlobalVar(Program::Kind kind, const VarDeclaration
const Variable* var = varDecl.fVar;
// These haven't been implemented in our SPIR-V generator yet and we only currently use them
// in the OpenGL backend.
SkASSERT(!(var->fModifiers.fFlags & (Modifiers::kReadOnly_Flag |
Modifiers::kWriteOnly_Flag |
Modifiers::kCoherent_Flag |
Modifiers::kVolatile_Flag |
Modifiers::kRestrict_Flag)));
if (var->fModifiers.fLayout.fBuiltin == BUILTIN_IGNORE) {
SkASSERT(!(var->modifiers().fFlags & (Modifiers::kReadOnly_Flag |
Modifiers::kWriteOnly_Flag |
Modifiers::kCoherent_Flag |
Modifiers::kVolatile_Flag |
Modifiers::kRestrict_Flag)));
if (var->modifiers().fLayout.fBuiltin == BUILTIN_IGNORE) {
return;
}
if (var->fModifiers.fLayout.fBuiltin == SK_FRAGCOLOR_BUILTIN &&
if (var->modifiers().fLayout.fBuiltin == SK_FRAGCOLOR_BUILTIN &&
kind != Program::kFragment_Kind) {
SkASSERT(!fProgram.fSettings.fFragColorIsInOut);
return;
@ -2795,11 +2797,11 @@ void SPIRVCodeGenerator::writeGlobalVar(Program::Kind kind, const VarDeclaration
}
const Type& type = var->type();
SpvStorageClass_ storageClass;
if (var->fModifiers.fFlags & Modifiers::kIn_Flag) {
if (var->modifiers().fFlags & Modifiers::kIn_Flag) {
storageClass = SpvStorageClassInput;
} else if (var->fModifiers.fFlags & Modifiers::kOut_Flag) {
} else if (var->modifiers().fFlags & Modifiers::kOut_Flag) {
storageClass = SpvStorageClassOutput;
} else if (var->fModifiers.fFlags & Modifiers::kUniform_Flag) {
} else if (var->modifiers().fFlags & Modifiers::kUniform_Flag) {
if (type.typeKind() == Type::TypeKind::kSampler ||
type.typeKind() == Type::TypeKind::kSeparateSampler ||
type.typeKind() == Type::TypeKind::kTexture) {
@ -2813,7 +2815,7 @@ void SPIRVCodeGenerator::writeGlobalVar(Program::Kind kind, const VarDeclaration
SpvId id = this->nextId();
fVariableMap[var] = id;
SpvId typeId;
if (var->fModifiers.fLayout.fBuiltin == SK_IN_BUILTIN) {
if (var->modifiers().fLayout.fBuiltin == SK_IN_BUILTIN) {
typeId = this->getPointerType(
Type("sk_in", Type::TypeKind::kArray, type.componentType(), fSkInCount),
storageClass);
@ -2830,11 +2832,11 @@ void SPIRVCodeGenerator::writeGlobalVar(Program::Kind kind, const VarDeclaration
this->writeInstruction(SpvOpStore, id, value, fGlobalInitializersBuffer);
fCurrentBlock = 0;
}
this->writeLayout(var->fModifiers.fLayout, id);
if (var->fModifiers.fFlags & Modifiers::kFlat_Flag) {
this->writeLayout(var->modifiers().fLayout, id);
if (var->modifiers().fFlags & Modifiers::kFlat_Flag) {
this->writeInstruction(SpvOpDecorate, id, SpvDecorationFlat, fDecorationBuffer);
}
if (var->fModifiers.fFlags & Modifiers::kNoPerspective_Flag) {
if (var->modifiers().fFlags & Modifiers::kNoPerspective_Flag) {
this->writeInstruction(SpvOpDecorate, id, SpvDecorationNoPerspective,
fDecorationBuffer);
}
@ -2844,11 +2846,11 @@ void SPIRVCodeGenerator::writeVarDeclaration(const VarDeclaration& varDecl, Outp
const Variable* var = varDecl.fVar;
// These haven't been implemented in our SPIR-V generator yet and we only currently use them
// in the OpenGL backend.
SkASSERT(!(var->fModifiers.fFlags & (Modifiers::kReadOnly_Flag |
Modifiers::kWriteOnly_Flag |
Modifiers::kCoherent_Flag |
Modifiers::kVolatile_Flag |
Modifiers::kRestrict_Flag)));
SkASSERT(!(var->modifiers().fFlags & (Modifiers::kReadOnly_Flag |
Modifiers::kWriteOnly_Flag |
Modifiers::kCoherent_Flag |
Modifiers::kVolatile_Flag |
Modifiers::kRestrict_Flag)));
SpvId id = this->nextId();
fVariableMap[var] = id;
SpvId type = this->getPointerType(var->type(), SpvStorageClassFunction);
@ -3192,14 +3194,15 @@ void SPIRVCodeGenerator::writeInstructions(const Program& program, OutputStream&
for (const auto& e : program) {
if (e.kind() == ProgramElement::Kind::kInterfaceBlock) {
InterfaceBlock& intf = (InterfaceBlock&) e;
if (SK_IN_BUILTIN == intf.fVariable.fModifiers.fLayout.fBuiltin) {
const Modifiers& modifiers = intf.fVariable.modifiers();
if (SK_IN_BUILTIN == modifiers.fLayout.fBuiltin) {
SkASSERT(skInSize != -1);
intf.fSizes.emplace_back(new IntLiteral(fContext, -1, skInSize));
}
SpvId id = this->writeInterfaceBlock(intf);
if (((intf.fVariable.fModifiers.fFlags & Modifiers::kIn_Flag) ||
(intf.fVariable.fModifiers.fFlags & Modifiers::kOut_Flag)) &&
intf.fVariable.fModifiers.fLayout.fBuiltin == -1 &&
if (((modifiers.fFlags & Modifiers::kIn_Flag) ||
(modifiers.fFlags & Modifiers::kOut_Flag)) &&
modifiers.fLayout.fBuiltin == -1 &&
!is_dead(intf.fVariable)) {
interfaceVars.insert(id);
}
@ -3227,9 +3230,9 @@ void SPIRVCodeGenerator::writeInstructions(const Program& program, OutputStream&
}
for (auto entry : fVariableMap) {
const Variable* var = entry.first;
if (var->fStorage == Variable::kGlobal_Storage &&
((var->fModifiers.fFlags & Modifiers::kIn_Flag) ||
(var->fModifiers.fFlags & Modifiers::kOut_Flag)) && !is_dead(*var)) {
if (var->storage() == Variable::kGlobal_Storage &&
((var->modifiers().fFlags & Modifiers::kIn_Flag) ||
(var->modifiers().fFlags & Modifiers::kOut_Flag)) && !is_dead(*var)) {
interfaceVars.insert(entry.second);
}
}

View File

@ -104,10 +104,11 @@ public:
virtual void store(SpvId value, OutputStream& out) = 0;
};
SPIRVCodeGenerator(const Context* context, const Program* program, ErrorReporter* errors,
OutputStream* out)
SPIRVCodeGenerator(const Context* context, ModifiersPool* modifiers,
const Program* program, ErrorReporter* errors, OutputStream* out)
: INHERITED(program, errors, out)
, fContext(*context)
, fModifiers(*modifiers)
, fDefaultLayout(MemoryLayout::k140_Standard)
, fCapabilities(0)
, fIdCount(1)
@ -366,6 +367,7 @@ private:
void writeGeometryShaderExecutionMode(SpvId entryPoint, OutputStream& out);
const Context& fContext;
ModifiersPool& fModifiers;
const MemoryLayout fDefaultLayout;
uint64_t fCapabilities;

View File

@ -63,8 +63,8 @@ public:
}
static bool IsParameter(const Variable& var) {
return (var.fModifiers.fFlags & Modifiers::kIn_Flag) &&
-1 == var.fModifiers.fLayout.fBuiltin;
return (var.modifiers().fFlags & Modifiers::kIn_Flag) &&
-1 == var.modifiers().fLayout.fBuiltin;
}
static bool IsSupportedSection(const char* name) {

View File

@ -55,7 +55,7 @@ public:
std::sort(sortedSymbols.begin(), sortedSymbols.end(),
[](const Symbol* a, const Symbol* b) { return a->name() < b->name(); });
for (const auto& s : sortedSymbols) {
const Expression& initialValue = *s->as<Variable>().fInitialValue;
const Expression& initialValue = *s->as<Variable>().initialValue();
result += separator + " " + s->name() + " = " +
to_string(initialValue.as<IntLiteral>().value());
separator = ",\n";

View File

@ -18,7 +18,7 @@ namespace SkSL {
struct Expression;
class IRGenerator;
struct Variable;
class Variable;
using DefinitionMap = TinyUnorderedMap<const Variable*, std::unique_ptr<Expression>*>;

View File

@ -28,7 +28,7 @@ struct FunctionDeclaration : public Symbol {
static constexpr Kind kSymbolKind = Kind::kFunctionDeclaration;
FunctionDeclaration(int offset, Modifiers modifiers, StringFragment name,
std::vector<const Variable*> parameters, const Type& returnType,
std::vector<Variable*> parameters, const Type& returnType,
bool builtin)
: INHERITED(offset, kSymbolKind, std::move(name))
, fDefinition(nullptr)
@ -118,7 +118,7 @@ struct FunctionDeclaration : public Symbol {
mutable FunctionDefinition* fDefinition;
bool fBuiltin;
Modifiers fModifiers;
const std::vector<const Variable*> fParameters;
const std::vector<Variable*> fParameters;
const Type& fReturnType;
mutable std::atomic<int> fCallCount = 0;

View File

@ -83,15 +83,10 @@ IRNode::IRNode(int offset, int kind, const TypeTokenData& data)
, fKind(kind)
, fData(data) {}
IRNode::IRNode(const IRNode& other)
: fOffset(other.fOffset)
, fKind(other.fKind)
, fData(other.fData) {
// For now, we can't use a default copy constructor because of the std::unique_ptr children.
// Since we never copy nodes containing children, it's easiest just to assert we don't have any
// than bother with cloning them.
SkASSERT(other.fExpressionChildren.empty());
}
IRNode::IRNode(int offset, int kind, const VariableData& data)
: fOffset(offset)
, fKind(kind)
, fData(data) {}
IRNode::~IRNode() {}

View File

@ -10,6 +10,7 @@
#include "src/sksl/SkSLASTNode.h"
#include "src/sksl/SkSLLexer.h"
#include "src/sksl/SkSLModifiersPool.h"
#include "src/sksl/SkSLString.h"
#include <algorithm>
@ -24,7 +25,7 @@ struct Statement;
class Symbol;
class SymbolTable;
class Type;
struct Variable;
class Variable;
/**
* Represents a node in the intermediate representation (IR) tree. The IR is a fully-resolved
@ -72,6 +73,8 @@ public:
return *this->typeData();
case NodeData::Kind::kTypeToken:
return *this->typeTokenData().fType;
case NodeData::Kind::kVariable:
return *this->variableData().fType;
default:
SkUNREACHABLE;
}
@ -135,7 +138,7 @@ protected:
struct SymbolAliasData {
StringFragment fName;
const Symbol* fOrigSymbol;
Symbol* fOrigSymbol;
};
struct TypeTokenData {
@ -143,6 +146,21 @@ protected:
Token::Kind fToken;
};
struct VariableData {
StringFragment fName;
const Type* fType;
const Expression* fInitialValue = nullptr;
ModifiersPool::Handle fModifiersHandle;
// Tracks how many sites read from the variable. If this is zero for a non-out variable (or
// becomes zero during optimization), the variable is dead and may be eliminated.
mutable int16_t fReadCount;
// Tracks how many sites write to the variable. If this is zero, the variable is dead and
// may be eliminated.
mutable int16_t fWriteCount;
/*Variable::Storage*/int8_t fStorage;
bool fBuiltin;
};
struct NodeData {
enum class Kind {
kBlock,
@ -159,6 +177,7 @@ protected:
kSymbolAlias,
kType,
kTypeToken,
kVariable,
} fKind = Kind::kType;
// it doesn't really matter what kind we default to, as long as it's a POD type
@ -177,6 +196,7 @@ protected:
SymbolAliasData fSymbolAlias;
const Type* fType;
TypeTokenData fTypeToken;
VariableData fVariable;
Contents() {}
@ -253,6 +273,11 @@ protected:
*(new(&fContents) TypeTokenData) = data;
}
NodeData(const VariableData& data)
: fKind(Kind::kVariable) {
*(new(&fContents) VariableData) = data;
}
NodeData(const NodeData& other) {
*this = other;
}
@ -303,6 +328,9 @@ protected:
case Kind::kTypeToken:
*(new(&fContents) TypeTokenData) = other.fContents.fTypeToken;
break;
case Kind::kVariable:
*(new(&fContents) VariableData) = other.fContents.fVariable;
break;
}
return *this;
}
@ -355,6 +383,9 @@ protected:
case Kind::kTypeToken:
fContents.fTypeToken.~TypeTokenData();
break;
case Kind::kVariable:
fContents.fVariable.~VariableData();
break;
}
}
};
@ -388,7 +419,7 @@ protected:
IRNode(int offset, int kind, const TypeTokenData& data);
IRNode(const IRNode& other);
IRNode(int offset, int kind, const VariableData& data);
Expression& expressionChild(int index) const {
SkASSERT(index >= 0 && index < (int) fExpressionChildren.size());
@ -509,6 +540,16 @@ protected:
return fData.fContents.fTypeToken;
}
VariableData& variableData() {
SkASSERT(fData.fKind == NodeData::Kind::kVariable);
return fData.fContents.fVariable;
}
const VariableData& variableData() const {
SkASSERT(fData.fKind == NodeData::Kind::kVariable);
return fData.fContents.fVariable;
}
int fKind;
NodeData fData;

View File

@ -49,7 +49,7 @@ struct InterfaceBlock : public ProgramElement {
}
String description() const override {
String result = fVariable.fModifiers.description() + fTypeName + " {\n";
String result = fVariable.modifiers().description() + fTypeName + " {\n";
const Type* structType = &fVariable.type();
while (structType->typeKind() == Type::TypeKind::kArray) {
structType = &structType->componentType();

View File

@ -10,6 +10,8 @@
#include "src/sksl/ir/SkSLLayout.h"
#include <vector>
namespace SkSL {
/**
@ -116,6 +118,17 @@ struct Modifiers {
int fFlags;
};
} // namespace SkSL
} // namespace SkSL
namespace std {
template <>
struct hash<SkSL::Modifiers> {
size_t operator()(const SkSL::Modifiers& key) const {
return key.fFlags ^ (key.fLayout.fFlags << 8) ^ ((unsigned) key.fLayout.fBuiltin << 16);
}
};
} // namespace std
#endif

View File

@ -250,6 +250,7 @@ struct Program {
std::shared_ptr<Context> context,
std::vector<std::unique_ptr<ProgramElement>>* inheritedElements,
std::vector<std::unique_ptr<ProgramElement>> elements,
std::unique_ptr<ModifiersPool> modifiers,
std::shared_ptr<SymbolTable> symbols,
Inputs inputs)
: fKind(kind)
@ -259,7 +260,8 @@ struct Program {
, fSymbols(symbols)
, fInputs(inputs)
, fInheritedElements(inheritedElements)
, fElements(std::move(elements)) {}
, fElements(std::move(elements))
, fModifiers(std::move(modifiers)) {}
iterator begin() {
if (fInheritedElements) {
@ -293,6 +295,10 @@ struct Program {
return const_iterator(fElements.end(), fElements.end(), fElements.end(), fElements.end());
}
void finish() {
fModifiers->finish();
}
Kind fKind;
std::unique_ptr<String> fSource;
Settings fSettings;
@ -305,6 +311,7 @@ struct Program {
private:
std::vector<std::unique_ptr<ProgramElement>>* fInheritedElements;
std::vector<std::unique_ptr<ProgramElement>> fElements;
std::unique_ptr<ModifiersPool> fModifiers;
friend class Compiler;
};

View File

@ -42,7 +42,9 @@ public:
Symbol(int offset, const SymbolAliasData& data)
: INHERITED(offset, (int) Kind::kSymbolAlias, data) {}
Symbol(const Symbol&) = default;
Symbol(int offset, const VariableData& data)
: INHERITED(offset, (int) Kind::kVariable, data) {}
Symbol& operator=(const Symbol&) = default;
~Symbol() override {}

View File

@ -19,14 +19,14 @@ class SymbolAlias : public Symbol {
public:
static constexpr Kind kSymbolKind = Kind::kSymbolAlias;
SymbolAlias(int offset, StringFragment name, const Symbol* origSymbol)
SymbolAlias(int offset, StringFragment name, Symbol* origSymbol)
: INHERITED(offset, SymbolAliasData{name, origSymbol}) {}
StringFragment name() const override {
return this->symbolAliasData().fName;
}
const Symbol* origSymbol() const {
Symbol* origSymbol() const {
return this->symbolAliasData().fOrigSymbol;
}

View File

@ -23,8 +23,8 @@ std::vector<const FunctionDeclaration*> SymbolTable::GetFunctions(const Symbol&
}
}
const Symbol* SymbolTable::operator[](StringFragment name) {
const auto& entry = fSymbols.find(name);
Symbol* SymbolTable::operator[](StringFragment name) {
auto entry = fSymbols.find(name);
if (entry == fSymbols.end()) {
if (fParent) {
return (*fParent)[name];
@ -59,7 +59,7 @@ const Symbol* SymbolTable::operator[](StringFragment name) {
}
}
}
const Symbol* symbol = entry->second;
Symbol* symbol = entry->second;
while (symbol && symbol->is<SymbolAlias>()) {
symbol = symbol->as<SymbolAlias>().origSymbol();
}
@ -72,14 +72,14 @@ const String* SymbolTable::takeOwnershipOfString(std::unique_ptr<String> n) {
return result;
}
void SymbolTable::addAlias(StringFragment name, const Symbol* symbol) {
void SymbolTable::addAlias(StringFragment name, Symbol* symbol) {
this->add(name, std::make_unique<SymbolAlias>(symbol->fOffset, name, symbol));
}
void SymbolTable::addWithoutOwnership(StringFragment name, const Symbol* symbol) {
void SymbolTable::addWithoutOwnership(StringFragment name, Symbol* symbol) {
SkASSERT(symbol->name() == name);
const Symbol*& refInSymbolTable = fSymbols[name];
Symbol*& refInSymbolTable = fSymbols[name];
if (refInSymbolTable == nullptr) {
refInSymbolTable = symbol;
return;
@ -106,11 +106,11 @@ void SymbolTable::addWithoutOwnership(StringFragment name, const Symbol* symbol)
}
}
std::unordered_map<StringFragment, const Symbol*>::iterator SymbolTable::begin() {
std::unordered_map<StringFragment, Symbol*>::iterator SymbolTable::begin() {
return fSymbols.begin();
}
std::unordered_map<StringFragment, const Symbol*>::iterator SymbolTable::end() {
std::unordered_map<StringFragment, Symbol*>::iterator SymbolTable::end() {
return fSymbols.end();
}

View File

@ -31,38 +31,38 @@ public:
: fParent(parent)
, fErrorReporter(parent->fErrorReporter) {}
const Symbol* operator[](StringFragment name);
Symbol* operator[](StringFragment name);
void addAlias(StringFragment name, const Symbol* symbol);
void addWithoutOwnership(StringFragment name, const Symbol* symbol);
void addAlias(StringFragment name, Symbol* symbol);
void addWithoutOwnership(StringFragment name, Symbol* symbol);
template <typename T>
const T* add(StringFragment name, std::unique_ptr<T> symbol) {
const T* ptr = symbol.get();
T* ptr = symbol.get();
this->addWithoutOwnership(name, ptr);
this->takeOwnershipOfSymbol(std::move(symbol));
return ptr;
}
template <typename T>
const T* takeOwnershipOfSymbol(std::unique_ptr<T> symbol) {
const T* ptr = symbol.get();
T* takeOwnershipOfSymbol(std::unique_ptr<T> symbol) {
T* ptr = symbol.get();
fOwnedSymbols.push_back(std::move(symbol));
return ptr;
}
template <typename T>
const T* takeOwnershipOfIRNode(std::unique_ptr<T> node) {
const T* ptr = node.get();
T* takeOwnershipOfIRNode(std::unique_ptr<T> node) {
T* ptr = node.get();
fOwnedNodes.push_back(std::move(node));
return ptr;
}
const String* takeOwnershipOfString(std::unique_ptr<String> n);
std::unordered_map<StringFragment, const Symbol*>::iterator begin();
std::unordered_map<StringFragment, Symbol*>::iterator begin();
std::unordered_map<StringFragment, const Symbol*>::iterator end();
std::unordered_map<StringFragment, Symbol*>::iterator end();
std::shared_ptr<SymbolTable> fParent;
@ -75,7 +75,7 @@ private:
std::vector<std::unique_ptr<String>> fOwnedStrings;
std::unordered_map<StringFragment, const Symbol*> fSymbols;
std::unordered_map<StringFragment, Symbol*> fSymbols;
ErrorReporter& fErrorReporter;

View File

@ -47,8 +47,8 @@ struct VarDeclaration : public Statement {
}
String description() const override {
String result =
fVar->fModifiers.description() + fBaseType.description() + " " + fVar->name();
String result = fVar->modifiers().description() + fBaseType.description() + " " +
fVar->name();
for (const auto& size : fSizes) {
if (size) {
result += "[" + size->description() + "]";

View File

@ -12,6 +12,7 @@
#include "src/sksl/ir/SkSLModifiers.h"
#include "src/sksl/ir/SkSLSymbol.h"
#include "src/sksl/ir/SkSLType.h"
#include "src/sksl/ir/SkSLVariableReference.h"
namespace SkSL {
@ -22,7 +23,8 @@ struct Expression;
* variable itself (the storage location), which is shared between all VariableReferences which
* read or write that storage location.
*/
struct Variable : public Symbol {
class Variable : public Symbol {
public:
static constexpr Kind kSymbolKind = Kind::kVariable;
enum Storage {
@ -32,53 +34,102 @@ struct Variable : public Symbol {
kParameter_Storage
};
Variable(int offset, Modifiers modifiers, StringFragment name, const Type* type,
Variable(int offset, ModifiersPool::Handle modifiers, StringFragment name, const Type* type,
bool builtin, Storage storage, Expression* initialValue = nullptr)
: INHERITED(offset, kSymbolKind, name, type)
, fModifiers(modifiers)
, fStorage(storage)
, fInitialValue(initialValue)
, fBuiltin(builtin)
, fReadCount(0)
, fWriteCount(initialValue ? 1 : 0) {}
: INHERITED(offset, VariableData{name, type, initialValue, modifiers, /*readCount=*/0,
/*writeCount=*/(int16_t) (initialValue ? 1 : 0),
(int8_t) storage, builtin}) {}
~Variable() override {
// can't destroy a variable while there are remaining references to it
if (fInitialValue) {
--fWriteCount;
if (this->initialValue()) {
--this->variableData().fWriteCount;
}
SkASSERT(!fReadCount && !fWriteCount);
SkASSERT(!this->variableData().fReadCount && !this->variableData().fWriteCount);
}
const Modifiers& modifiers() const {
return *this->variableData().fModifiersHandle;
}
const ModifiersPool::Handle& modifiersHandle() const {
return this->variableData().fModifiersHandle;
}
void setModifiersHandle(const ModifiersPool::Handle& handle) {
this->variableData().fModifiersHandle = handle;
}
bool isBuiltin() const {
return this->variableData().fBuiltin;
}
Storage storage() const {
return (Storage) this->variableData().fStorage;
}
const Expression* initialValue() const {
return this->variableData().fInitialValue;
}
void setInitialValue(const Expression* initialValue) {
SkASSERT(!this->initialValue());
SkASSERT(this->variableData().fWriteCount == 0);
this->variableData().fInitialValue = initialValue;
++this->variableData().fWriteCount;
}
int readCount() const {
return this->variableData().fReadCount;
}
int writeCount() const {
return this->variableData().fWriteCount;
}
StringFragment name() const override {
return this->variableData().fName;
}
String description() const override {
return fModifiers.description() + this->type().name() + " " + this->name();
return this->modifiers().description() + this->type().name() + " " + this->name();
}
bool dead() const {
if ((fStorage != kLocal_Storage && fReadCount) ||
(fModifiers.fFlags & (Modifiers::kIn_Flag | Modifiers::kOut_Flag |
const VariableData& data = this->variableData();
const Modifiers& modifiers = this->modifiers();
if ((data.fStorage != kLocal_Storage && this->variableData().fReadCount) ||
(modifiers.fFlags & (Modifiers::kIn_Flag | Modifiers::kOut_Flag |
Modifiers::kUniform_Flag | Modifiers::kVarying_Flag))) {
return false;
}
return !fWriteCount ||
(!fReadCount && !(fModifiers.fFlags & (Modifiers::kPLS_Flag |
Modifiers::kPLSOut_Flag)));
return !data.fWriteCount ||
(!data.fReadCount && !(modifiers.fFlags & (Modifiers::kPLS_Flag |
Modifiers::kPLSOut_Flag)));
}
mutable Modifiers fModifiers;
const Storage fStorage;
private:
void referenceCreated(VariableReference::RefKind refKind) const {
if (refKind != VariableReference::kRead_RefKind) {
++this->variableData().fWriteCount;
}
if (refKind != VariableReference::kWrite_RefKind) {
++this->variableData().fReadCount;
}
}
const Expression* fInitialValue = nullptr;
bool fBuiltin;
// Tracks how many sites read from the variable. If this is zero for a non-out variable (or
// becomes zero during optimization), the variable is dead and may be eliminated.
mutable int fReadCount;
// Tracks how many sites write to the variable. If this is zero, the variable is dead and may be
// eliminated.
mutable int fWriteCount;
void referenceDestroyed(VariableReference::RefKind refKind) const {
if (refKind != VariableReference::kRead_RefKind) {
--this->variableData().fWriteCount;
}
if (refKind != VariableReference::kWrite_RefKind) {
--this->variableData().fReadCount;
}
}
using INHERITED = Symbol;
friend struct VariableReference;
};
} // namespace SkSL

View File

@ -19,41 +19,41 @@ VariableReference::VariableReference(int offset, const Variable* variable, RefKi
, fVariable(variable)
, fRefKind(refKind) {
SkASSERT(fVariable);
this->incrementRefs();
fVariable->referenceCreated(fRefKind);
}
VariableReference::~VariableReference() {
this->decrementRefs();
fVariable->referenceDestroyed(fRefKind);
}
void VariableReference::incrementRefs() const {
if (fRefKind != kRead_RefKind) {
fVariable->fWriteCount++;
}
if (fRefKind != kWrite_RefKind) {
fVariable->fReadCount++;
bool VariableReference::hasProperty(Property property) const {
switch (property) {
case Property::kSideEffects: return false;
case Property::kContainsRTAdjust: return fVariable->name() == "sk_RTAdjust";
default:
SkASSERT(false);
return false;
}
}
void VariableReference::decrementRefs() const {
if (fRefKind != kRead_RefKind) {
fVariable->fWriteCount--;
}
if (fRefKind != kWrite_RefKind) {
fVariable->fReadCount--;
}
bool VariableReference::isConstantOrUniform() const {
return (fVariable->modifiers().fFlags & Modifiers::kUniform_Flag) != 0;
}
String VariableReference::description() const {
return fVariable->name();
}
void VariableReference::setRefKind(RefKind refKind) {
this->decrementRefs();
fVariable->referenceDestroyed(fRefKind);
fRefKind = refKind;
this->incrementRefs();
fVariable->referenceCreated(fRefKind);
}
void VariableReference::setVariable(const Variable* variable) {
this->decrementRefs();
fVariable->referenceDestroyed(fRefKind);
fVariable = variable;
this->incrementRefs();
fVariable->referenceCreated(fRefKind);
}
std::unique_ptr<Expression> VariableReference::constantPropagate(const IRGenerator& irGenerator,
@ -61,10 +61,11 @@ std::unique_ptr<Expression> VariableReference::constantPropagate(const IRGenerat
if (fRefKind != kRead_RefKind) {
return nullptr;
}
if ((fVariable->fModifiers.fFlags & Modifiers::kConst_Flag) && fVariable->fInitialValue &&
fVariable->fInitialValue->isCompileTimeConstant() &&
const Expression* initialValue = fVariable->initialValue();
if ((fVariable->modifiers().fFlags & Modifiers::kConst_Flag) && initialValue &&
initialValue->isCompileTimeConstant() &&
this->type().typeKind() != Type::TypeKind::kArray) {
return fVariable->fInitialValue->clone();
return initialValue->clone();
}
auto exprIter = definitions.find(fVariable);
if (exprIter != definitions.end() && exprIter->second &&

View File

@ -9,11 +9,11 @@
#define SKSL_VARIABLEREFERENCE
#include "src/sksl/ir/SkSLExpression.h"
#include "src/sksl/ir/SkSLVariable.h"
namespace SkSL {
class IRGenerator;
class Variable;
/**
* A reference to a variable, through which it can be read or written. In the statement:
@ -48,27 +48,15 @@ struct VariableReference : public Expression {
void setRefKind(RefKind refKind);
void setVariable(const Variable* variable);
bool hasProperty(Property property) const override {
switch (property) {
case Property::kSideEffects: return false;
case Property::kContainsRTAdjust: return fVariable->name() == "sk_RTAdjust";
default:
SkASSERT(false);
return false;
}
}
bool hasProperty(Property property) const override;
bool isConstantOrUniform() const override {
return (fVariable->fModifiers.fFlags & Modifiers::kUniform_Flag) != 0;
}
bool isConstantOrUniform() const override;
std::unique_ptr<Expression> clone() const override {
return std::unique_ptr<Expression>(new VariableReference(fOffset, fVariable, fRefKind));
}
String description() const override {
return fVariable->name();
}
String description() const override;
std::unique_ptr<Expression> constantPropagate(const IRGenerator& irGenerator,
const DefinitionMap& definitions) override;
@ -77,9 +65,6 @@ struct VariableReference : public Expression {
RefKind fRefKind;
private:
void incrementRefs() const;
void decrementRefs() const;
using INHERITED = Expression;
};