diff options
| author | Tim Foley <tfoley@nvidia.com> | 2017-07-18 14:51:12 -0700 |
|---|---|---|
| committer | Tim Foley <tfoley@nvidia.com> | 2017-07-18 14:51:12 -0700 |
| commit | 2476c035ec15d3ee22239ebd1fe10e6e8c1e01e3 (patch) | |
| tree | 30e1bf209e232d7f8d6723959db68b2c0cb015dd /source | |
| parent | 3d313d963f29f6ca6a8d12bd5c403a70c49aca2a (diff) | |
Add a compile-time loop construct to Slang
The basic syntax is:
$for(i in Range(0,99))
{
/* stuff goes here */
}
Note that the exact form is very restrictive. All that you are allowed to change is `i`, `0`, `99` or `/* stuff goes here */`.
As a tiny bit of syntax sugar, the following should work:
$for(i in Range(99))
{
/* stuff goes here */
}
Note that the range given is half-open (C++ iterator `[begin,end)` style).
Both the beginning and end of the range must be compile-time constant expressions that Slang knows how to constant-fold.
The implementation will basically generate code for `/* stuff goes here */` N times, once for each value in the half-open range.
Each time, the variable `i` will be replaced with a different compile-time-constant expression.
While I was working on a test case for this, I also found that our build of glslang had an issue with resource limits, so I fixed that.
Clients will need to build a new glslang to use the fix.
Diffstat (limited to 'source')
| -rw-r--r-- | source/slang/check.cpp | 42 | ||||
| -rw-r--r-- | source/slang/lower.cpp | 35 | ||||
| -rw-r--r-- | source/slang/parser.cpp | 65 | ||||
| -rw-r--r-- | source/slang/slang-stdlib.cpp | 2 | ||||
| -rw-r--r-- | source/slang/stmt-defs.h | 10 |
5 files changed, 153 insertions, 1 deletions
diff --git a/source/slang/check.cpp b/source/slang/check.cpp index 1c1c6d5d3..26d28d495 100644 --- a/source/slang/check.cpp +++ b/source/slang/check.cpp @@ -1735,6 +1735,48 @@ namespace Slang PopOuterStmt(stmt); } + + RefPtr<ExpressionSyntaxNode> checkExpressionAndExpectIntegerConstant(RefPtr<ExpressionSyntaxNode> expr, RefPtr<IntVal>* outIntVal) + { + expr = CheckExpr(expr); + auto intVal = CheckIntegerConstantExpression(expr); + if (outIntVal) + *outIntVal = intVal; + return expr; + } + + void visitCompileTimeForStmt(CompileTimeForStmt* stmt) + { + PushOuterStmt(stmt); + + stmt->varDecl->Type.type = ExpressionType::GetInt(); + addModifier(stmt->varDecl, new ConstModifier()); + + RefPtr<IntVal> rangeBeginVal; + RefPtr<IntVal> rangeEndVal; + + if (stmt->rangeBeginExpr) + { + stmt->rangeBeginExpr = checkExpressionAndExpectIntegerConstant(stmt->rangeBeginExpr, &rangeBeginVal); + } + else + { + RefPtr<ConstantIntVal> rangeBeginConst = new ConstantIntVal(); + rangeBeginConst->value = 0; + rangeBeginVal = rangeBeginConst; + } + + stmt->rangeEndExpr = checkExpressionAndExpectIntegerConstant(stmt->rangeEndExpr, &rangeEndVal); + + stmt->rangeBeginVal = rangeBeginVal; + stmt->rangeEndVal = rangeEndVal; + + checkStmt(stmt->body); + + + PopOuterStmt(stmt); + } + void visitSwitchStmt(SwitchStmt* stmt) { PushOuterStmt(stmt); diff --git a/source/slang/lower.cpp b/source/slang/lower.cpp index bbbfe724b..127ef75ca 100644 --- a/source/slang/lower.cpp +++ b/source/slang/lower.cpp @@ -1628,6 +1628,41 @@ struct LoweringVisitor lowerForStmtCommon(new UnscopedForStmt(), stmt); } + void visitCompileTimeForStmt(CompileTimeForStmt* stmt) + { + // We can either lower this here, so that emit logic doesn't have to deal with it, + // or else just translate it and then let emit deal with it. + // + // The right answer is really to lower it here, I guess. + + auto rangeBeginVal = GetIntVal(stmt->rangeBeginVal); + auto rangeEndVal = GetIntVal(stmt->rangeEndVal); + + if (rangeBeginVal >= rangeEndVal) + return; + + auto varDecl = stmt->varDecl; + + auto varType = lowerType(varDecl->Type); + + for (IntegerLiteralValue ii = rangeBeginVal; ii < rangeEndVal; ++ii) + { + RefPtr<ConstantExpressionSyntaxNode> constExpr = new ConstantExpressionSyntaxNode(); + constExpr->Type.type = varType.type; + constExpr->ConstType = ConstantExpressionSyntaxNode::ConstantType::Int; + constExpr->integerValue = ii; + + RefPtr<VaryingTupleVarDecl> loweredVarDecl = new VaryingTupleVarDecl(); + loweredVarDecl->Position = varDecl->Position; + loweredVarDecl->Type = varType; + loweredVarDecl->Expr = constExpr; + + shared->loweredDecls[varDecl] = loweredVarDecl; + + lowerStmtImpl(stmt->body); + } + } + void visitWhileStatementSyntaxNode(WhileStatementSyntaxNode* stmt) { RefPtr<WhileStatementSyntaxNode> loweredStmt = new WhileStatementSyntaxNode(); diff --git a/source/slang/parser.cpp b/source/slang/parser.cpp index 1ad0c6b94..b821555a9 100644 --- a/source/slang/parser.cpp +++ b/source/slang/parser.cpp @@ -2555,6 +2555,67 @@ namespace Slang return isTypeName(parser, name); } + RefPtr<StatementSyntaxNode> parseCompileTimeForStmt( + Parser* parser) + { + RefPtr<ScopeDecl> scopeDecl = new ScopeDecl(); + RefPtr<CompileTimeForStmt> stmt = new CompileTimeForStmt(); + stmt->scopeDecl = scopeDecl; + + + parser->ReadToken("for"); + parser->ReadToken(TokenType::LParent); + + Token varNameToken = parser->ReadToken(TokenType::Identifier); + RefPtr<Variable> varDecl = new Variable(); + varDecl->Name = varNameToken; + varDecl->Position = varNameToken.Position; + + stmt->varDecl = varDecl; + + parser->ReadToken("in"); + parser->ReadToken("Range"); + parser->ReadToken(TokenType::LParent); + + RefPtr<ExpressionSyntaxNode> rangeBeginExpr; + RefPtr<ExpressionSyntaxNode> rangeEndExpr = parser->ParseArgExpr(); + if (AdvanceIf(parser, TokenType::Comma)) + { + rangeBeginExpr = rangeEndExpr; + rangeEndExpr = parser->ParseArgExpr(); + } + + stmt->rangeBeginExpr = rangeBeginExpr; + stmt->rangeEndExpr = rangeEndExpr; + + parser->ReadToken(TokenType::RParent); + parser->ReadToken(TokenType::RParent); + + parser->PushScope(scopeDecl); + AddMember(parser->currentScope, varDecl); + + stmt->body = parser->ParseStatement(); + + parser->PopScope(); + + return stmt; + } + + RefPtr<StatementSyntaxNode> parseCompileTimeStmt( + Parser* parser) + { + parser->ReadToken(TokenType::Dollar); + if (parser->LookAheadToken("for")) + { + return parseCompileTimeForStmt(parser); + } + else + { + Unexpected(parser); + return nullptr; + } + } + RefPtr<StatementSyntaxNode> Parser::ParseStatement() { auto modifiers = ParseModifiers(this); @@ -2591,6 +2652,10 @@ namespace Slang statement = ParseCaseStmt(this); else if (LookAheadToken("default")) statement = ParseDefaultStmt(this); + else if (LookAheadToken(TokenType::Dollar)) + { + statement = parseCompileTimeStmt(this); + } else if (LookAheadToken(TokenType::Identifier)) { // We might be looking at a local declaration, or an diff --git a/source/slang/slang-stdlib.cpp b/source/slang/slang-stdlib.cpp index 3062112c6..b26fc8a8e 100644 --- a/source/slang/slang-stdlib.cpp +++ b/source/slang/slang-stdlib.cpp @@ -1603,7 +1603,7 @@ namespace Slang if( baseShape != TextureType::ShapeCube ) { - sb << "__intrinsic(glsl, \"textureOffset($p, $1)\")\n"; + sb << "__intrinsic(glsl, \"textureOffset($p, $1, $2)\")\n"; sb << "__intrinsic\n"; sb << "T Sample(SamplerState s, "; sb << "float" << kBaseTextureTypes[tt].coordCount + isArray << " location, "; diff --git a/source/slang/stmt-defs.h b/source/slang/stmt-defs.h index 9dea40fbf..80e3cd60d 100644 --- a/source/slang/stmt-defs.h +++ b/source/slang/stmt-defs.h @@ -96,6 +96,16 @@ SYNTAX_CLASS(DoWhileStatementSyntaxNode, LoopStmt) SYNTAX_FIELD(RefPtr<ExpressionSyntaxNode>, Predicate) END_SYNTAX_CLASS() +// A compile-time, range-based `for` loop, which will not appear in the output code +SYNTAX_CLASS(CompileTimeForStmt, ScopeStmt) + SYNTAX_FIELD(RefPtr<Variable>, varDecl) + SYNTAX_FIELD(RefPtr<ExpressionSyntaxNode>, rangeBeginExpr) + SYNTAX_FIELD(RefPtr<ExpressionSyntaxNode>, rangeEndExpr) + SYNTAX_FIELD(RefPtr<StatementSyntaxNode>, body) + SYNTAX_FIELD(RefPtr<IntVal>, rangeBeginVal) + SYNTAX_FIELD(RefPtr<IntVal>, rangeEndVal) +END_SYNTAX_CLASS() + // The case of child statements that do control flow relative // to their parent statement. ABSTRACT_SYNTAX_CLASS(JumpStmt, ChildStmt) |
