diff options
Diffstat (limited to 'source/slang/lower.cpp')
| -rw-r--r-- | source/slang/lower.cpp | 234 |
1 files changed, 231 insertions, 3 deletions
diff --git a/source/slang/lower.cpp b/source/slang/lower.cpp index b90573495..0bb047791 100644 --- a/source/slang/lower.cpp +++ b/source/slang/lower.cpp @@ -194,8 +194,17 @@ public: struct SharedLoweringContext { ProgramLayout* programLayout; + + // The target we are going to generate code for. + // + // We may need to specialize how constructs get lowered based + // on the capabilities of the target language. CodeGenTarget target; + // A set of words reserved by the target + Dictionary<String, String> reservedWords; + + RefPtr<ProgramSyntaxNode> loweredProgram; Dictionary<Decl*, RefPtr<Decl>> loweredDecls; @@ -238,6 +247,165 @@ struct LoweringVisitor CodeGenTarget getTarget() { return shared->target; } + bool isReservedWord(String const& name) + { + return shared->reservedWords.TryGetValue(name) != nullptr; + } + + void registerReservedWord( + String const& name) + { + shared->reservedWords.Add(name, name); + } + + void registerReservedWords() + { + #define WORD(NAME) registerReservedWord(#NAME) + + switch (shared->target) + { + case CodeGenTarget::GLSL: + WORD(attribute); + WORD(const); + WORD(uniform); + WORD(varying); + WORD(buffer); + + WORD(shared); + WORD(coherent); + WORD(volatile); + WORD(restrict); + WORD(readonly); + WORD(writeonly); + WORD(atomic_unit); + WORD(layout); + WORD(centroid); + WORD(flat); + WORD(smooth); + WORD(noperspective); + WORD(patch); + WORD(sample); + WORD(break); + WORD(continue); + WORD(do); + WORD(for); + WORD(while); + WORD(switch); + WORD(case); + WORD(default); + WORD(if); + WORD(else); + WORD(subroutine); + WORD(in); + WORD(out); + WORD(inout); + WORD(float); + WORD(double); + WORD(int); + WORD(void); + WORD(bool); + WORD(true); + WORD(false); + WORD(invariant); + WORD(precise); + WORD(discard); + WORD(return); + + WORD(lowp); + WORD(mediump); + WORD(highp); + WORD(precision); + WORD(struct); + WORD(uint); + + WORD(common); + WORD(partition); + WORD(active); + WORD(asm); + WORD(class); + WORD(union); + WORD(enum); + WORD(typedef); + WORD(template); + WORD(this); + WORD(resource); + + WORD(goto); + WORD(inline); + WORD(noinline); + WORD(public); + WORD(static); + WORD(extern); + WORD(external); + WORD(interface); + WORD(long); + WORD(short); + WORD(half); + WORD(fixed); + WORD(unsigned); + WORD(superp); + WORD(input); + WORD(output); + WORD(filter); + WORD(sizeof); + WORD(cast); + WORD(namespace); + WORD(using); + + #define CASE(NAME) \ + WORD(NAME ## 2); WORD(NAME ## 3); WORD(NAME ## 4) + + CASE(mat); + CASE(dmat); + CASE(mat2x); + CASE(mat3x); + CASE(mat4x); + CASE(dmat2x); + CASE(dmat3x); + CASE(dmat4x); + CASE(vec); + CASE(ivec); + CASE(bvec); + CASE(dvec); + CASE(uvec); + CASE(hvec); + CASE(fvec); + + #undef CASE + + #define CASE(NAME) \ + WORD(NAME ## 1D); \ + WORD(NAME ## 2D); \ + WORD(NAME ## 3D); \ + WORD(NAME ## Cube); \ + WORD(NAME ## 1DArray); \ + WORD(NAME ## 2DArray); \ + WORD(NAME ## 3DArray); \ + WORD(NAME ## CubeArray);\ + WORD(NAME ## 2DMS); \ + WORD(NAME ## 2DMSArray) \ + /* end */ + + #define CASE2(NAME) \ + CASE(NAME); \ + CASE(i ## NAME); \ + CASE(u ## NAME) \ + /* end */ + + CASE2(sampler); + CASE2(image); + CASE2(texture); + + #undef CASE2 + #undef CASE + break; + + default: + break; + } + } + + // // Values // @@ -451,6 +619,7 @@ struct LoweringVisitor lowerExprCommon(loweredExpr, expr); loweredExpr->BaseExpression = loweredBase; loweredExpr->declRef = loweredDeclRef; + loweredExpr->name = expr->name; return loweredExpr; } @@ -732,10 +901,10 @@ struct LoweringVisitor addStmt(loweredStmt); } - - void visitForStatementSyntaxNode(ForStatementSyntaxNode* stmt) + void lowerForStmtCommon( + RefPtr<ForStatementSyntaxNode> loweredStmt, + ForStatementSyntaxNode* stmt) { - RefPtr<ForStatementSyntaxNode> loweredStmt = new ForStatementSyntaxNode(); lowerScopeStmtFields(loweredStmt, stmt); LoweringVisitor subVisitor = pushScope(loweredStmt, stmt); @@ -748,6 +917,16 @@ struct LoweringVisitor addStmt(loweredStmt); } + void visitForStatementSyntaxNode(ForStatementSyntaxNode* stmt) + { + lowerForStmtCommon(new ForStatementSyntaxNode(), stmt); + } + + void visitUnscopedForStmt(UnscopedForStmt* stmt) + { + lowerForStmtCommon(new UnscopedForStmt(), stmt); + } + void visitWhileStatementSyntaxNode(WhileStatementSyntaxNode* stmt) { RefPtr<WhileStatementSyntaxNode> loweredStmt = new WhileStatementSyntaxNode(); @@ -964,6 +1143,43 @@ struct LoweringVisitor shared->mapLoweredDeclToOriginal.Add(loweredDecl, decl); } + // If the name of the declarations collides with a reserved word + // for the code generation target, then rename it to avoid the conflict + // + // Note that this does *not* implement any kind of comprehensive renaming + // to, e.g., avoid conflicts between user-defined and library functions. + void ensureDeclHasAValidName(Decl* decl) + { + // By default, we would like to emit a name in the generated + // code exactly as it appeared in the original program. + // When that isn't possible, we'd like to emit a name as + // close to the original as possible (to ensure that existing + // debugging tools still work reasonably well). + // + // One reason why a name might not be allowed as-is is that + // it could collide with a reserved word in the target language. + // Another reason is that it might not follow a naming convention + // imposed by the target (e.g., in GLSL names starting with + // `gl_` or containing `__` are reserved). + // + // Given a name that should not be allowed, we want to + // change it to a name that *is* allowed. e.g., by adding + // `_` to the end of a reserved word. + // + // The next problem this creates is that the modified name + // could not collide with an existing use of the same + // (valid) name. + // + // For now we are going to solve this problem in a simple + // and ad hoc fashion, but longer term we'll want to do + // something sytematic. + + if (isReservedWord(decl->getName())) + { + decl->Name.Content.append("_"); + } + } + void lowerDeclCommon( Decl* loweredDecl, Decl* decl) @@ -973,6 +1189,9 @@ struct LoweringVisitor loweredDecl->Position = decl->Position; loweredDecl->Name = decl->getNameToken(); + // Deal with renaming - we shouldn't allow decls with names that are reserved words + ensureDeclHasAValidName(loweredDecl); + // Lower modifiers as needed // HACK: just doing a shallow copy of modifiers, which will @@ -1314,6 +1533,8 @@ struct LoweringVisitor globalVarDecl->Name.Content = info.name; globalVarDecl->Type.type = type; + ensureDeclHasAValidName(globalVarDecl); + addMember(shared->loweredProgram, globalVarDecl); // Add the layout information @@ -1515,6 +1736,8 @@ struct LoweringVisitor localVarDecl->Name.Content = paramDecl->getName(); localVarDecl->Type = lowerType(paramDecl->Type); + ensureDeclHasAValidName(localVarDecl); + subVisitor.addDecl(localVarDecl); EntryPointParamPair paramPair; @@ -1549,6 +1772,8 @@ struct LoweringVisitor resultVarDecl->Name.Content = "_main_result"; resultVarDecl->Type = TypeExp(loweredEntryPointFunc->ReturnType); + ensureDeclHasAValidName(resultVarDecl); + subVisitor.addDecl(resultVarDecl); } @@ -1793,6 +2018,9 @@ LoweredEntryPoint lowerEntryPoint( visitor.shared = &sharedContext; visitor.parentDecl = loweredProgram; + // TODO: this should only need to take the shared context + visitor.registerReservedWords(); + // We need to register the lowered program as the lowered version // of the existing translation unit declaration. |
