summaryrefslogtreecommitdiffstats
path: root/source
diff options
context:
space:
mode:
authorTim Foley <tfoley@nvidia.com>2017-07-08 17:21:37 -0700
committerTim Foley <tfoley@nvidia.com>2017-07-08 18:22:26 -0700
commita40b6679931f672a911070fcc7eeb41c52e8b8fd (patch)
tree0797d803e737ed96c54a58d485b2c803be4184c9 /source
parent6233f9b35f1901ca33c53ce37f9b1517e91e1d79 (diff)
Differentiate HLSL `for` loops in AST
HLSL has the bad scoping behavior for `for` loops, and we need to respect that. But, we need to have correct scoping for GLSL, and we'd like it for Slang. We also need to ensure that `for` loops written in a "correct" language get the correct behavior when emitted as HLSL. There was already code to handle this in the emit pass, but it was unfortunately using an `isRewrite` flag to try to tell if the HLSL behavior was wanted. This doesn't work when the code being emitted might come from a mix of languages. This change adds a distinct `UnscopedForStmt` syntax node type, and uses that when parsing HLSL input (bot not for other languages). We make sure to preserve this node type through lowering, and then specialize our emit logic on this case. With this, there are no more remaining uses of `isRewrite` in the emit logic, which is good because it didn't mean what I needed it to mean any more (since we now emit only a single module, that was merged during lowering).
Diffstat (limited to 'source')
-rw-r--r--source/slang/emit.cpp17
-rw-r--r--source/slang/lower.cpp16
-rw-r--r--source/slang/parser.cpp33
-rw-r--r--source/slang/stmt-defs.h5
4 files changed, 48 insertions, 23 deletions
diff --git a/source/slang/emit.cpp b/source/slang/emit.cpp
index a8c0083c1..24b0dd717 100644
--- a/source/slang/emit.cpp
+++ b/source/slang/emit.cpp
@@ -57,10 +57,6 @@ struct EmitContext
{
// The shared context that is in effect
SharedEmitContext* shared;
-
- // Are we in "rewrite" mode, where we are trying to reproduce the input
- // code as closely as posible?
- bool isRewrite;
};
//
@@ -2196,12 +2192,10 @@ struct EmitVisitor
// The one wrinkle is that HLSL implements the
// bad approach to scoping a `for` loop variable,
// so we need to avoid those outer `{...}` when
- // we are generating HLSL via "rewrite" (that is,
- // without our semantic checks).
+ // we are emitting code that was written in HLSL.
//
bool brokenScoping = false;
- if (context->shared->target == CodeGenTarget::HLSL
- && context->isRewrite)
+ if (forStmt.As<UnscopedForStmt>())
{
brokenScoping = true;
}
@@ -3406,10 +3400,6 @@ struct EmitVisitor
}
};
-bool isRewriteRequest(
- SourceLanguage sourceLanguage,
- CodeGenTarget target);
-
String emitEntryPoint(
EntryPointRequest* entryPoint,
ProgramLayout* programLayout,
@@ -3465,9 +3455,6 @@ String emitEntryPoint(
EmitContext context;
context.shared = &sharedContext;
- context.isRewrite = isRewriteRequest(
- translationUnit->sourceLanguage,
- target);
EmitVisitor visitor(&context);
diff --git a/source/slang/lower.cpp b/source/slang/lower.cpp
index c154c96c8..8a4b7a4b1 100644
--- a/source/slang/lower.cpp
+++ b/source/slang/lower.cpp
@@ -723,10 +723,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);
@@ -739,6 +739,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();
diff --git a/source/slang/parser.cpp b/source/slang/parser.cpp
index 0efc8cd77..199275a2d 100644
--- a/source/slang/parser.cpp
+++ b/source/slang/parser.cpp
@@ -2673,12 +2673,32 @@ namespace Slang
RefPtr<ForStatementSyntaxNode> Parser::ParseForStatement()
{
RefPtr<ScopeDecl> scopeDecl = new ScopeDecl();
- RefPtr<ForStatementSyntaxNode> stmt = new ForStatementSyntaxNode();
+
+ // HLSL implements the bad approach to scoping a `for` loop
+ // variable, and we want to respect that, but *only* when
+ // parsing HLSL code.
+ //
+
+ bool brokenScoping = translationUnit->sourceLanguage == SourceLanguage::HLSL;
+
+ // We will create a distinct syntax node class for the unscoped
+ // case, just so that we can correctly handle it in downstream
+ // logic.
+ //
+ RefPtr<ForStatementSyntaxNode> stmt;
+ if (brokenScoping)
+ {
+ stmt = new UnscopedForStmt();
+ }
+ else
+ {
+ stmt = new ForStatementSyntaxNode();
+ }
+
stmt->scopeDecl = scopeDecl;
- // Note(tfoley): HLSL implements `for` with incorrect scoping.
- // We need an option to turn on this behavior in a kind of "legacy" mode
-// PushScope(scopeDecl.Ptr());
+ if(!brokenScoping)
+ PushScope(scopeDecl.Ptr());
FillPosition(stmt.Ptr());
ReadToken("for");
ReadToken(TokenType::LParent);
@@ -2704,7 +2724,10 @@ namespace Slang
stmt->SideEffectExpression = ParseExpression();
ReadToken(TokenType::RParent);
stmt->Statement = ParseStatement();
-// PopScope();
+
+ if (!brokenScoping)
+ PopScope();
+
return stmt;
}
diff --git a/source/slang/stmt-defs.h b/source/slang/stmt-defs.h
index 165ffea83..15826abc4 100644
--- a/source/slang/stmt-defs.h
+++ b/source/slang/stmt-defs.h
@@ -66,6 +66,7 @@ SIMPLE_SYNTAX_CLASS(DefaultStmt, CaseStmtBase)
ABSTRACT_SYNTAX_CLASS(LoopStmt, BreakableStmt)
END_SYNTAX_CLASS()
+// A `for` statement
SYNTAX_CLASS(ForStatementSyntaxNode, LoopStmt)
SYNTAX_FIELD(RefPtr<StatementSyntaxNode>, InitialStatement)
SYNTAX_FIELD(RefPtr<ExpressionSyntaxNode>, SideEffectExpression)
@@ -73,6 +74,10 @@ SYNTAX_CLASS(ForStatementSyntaxNode, LoopStmt)
SYNTAX_FIELD(RefPtr<StatementSyntaxNode>, Statement)
END_SYNTAX_CLASS()
+// A `for` statement in a language that doesn't restrict the scope
+// of the loop variable to the body.
+SYNTAX_CLASS(UnscopedForStmt, ForStatementSyntaxNode);
+END_SYNTAX_CLASS()
SYNTAX_CLASS(WhileStatementSyntaxNode, LoopStmt)
SYNTAX_FIELD(RefPtr<ExpressionSyntaxNode>, Predicate)