summaryrefslogtreecommitdiffstats
path: root/source/slang/emit.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'source/slang/emit.cpp')
-rw-r--r--source/slang/emit.cpp435
1 files changed, 248 insertions, 187 deletions
diff --git a/source/slang/emit.cpp b/source/slang/emit.cpp
index dc7c68aa4..71b39aabb 100644
--- a/source/slang/emit.cpp
+++ b/source/slang/emit.cpp
@@ -1,6 +1,7 @@
// emit.cpp
#include "emit.h"
+#include "lower.h"
#include "syntax.h"
#include "type-layout.h"
@@ -13,8 +14,16 @@
namespace Slang {
-struct EmitContext
+// Shared state for an entire emit session
+struct SharedEmitContext
{
+ // The target language we want to generate code for
+ CodeGenTarget target;
+
+ // A set of words reserved by the target
+ Dictionary<String, String> reservedWords;
+
+ // The string of code we've built so far
StringBuilder sb;
// Current source position for tracking purposes...
@@ -22,12 +31,6 @@ struct EmitContext
CodePosition nextSourceLocation;
bool needToUpdateSourceLocation;
- // The target language we want to generate code for
- CodeGenTarget target;
-
- // A set of words reserved by the target
- Dictionary<String, String> reservedWords;
-
// For GLSL output, we can't emit traidtional `#line` directives
// with a file path in them, so we maintain a map that associates
// each path with a unique integer, and then we output those
@@ -45,6 +48,18 @@ struct EmitContext
// TODO: This will probably change if we represent imports
// explicitly in the layout data.
StructTypeLayout* globalStructLayout;
+
+ ProgramLayout* programLayout;
+};
+
+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;
};
//
@@ -79,7 +94,7 @@ static void emitRawTextSpan(EmitContext* context, char const* textBegin, char co
// TODO(tfoley): Need to make "corelib" not use `int` for pointer-sized things...
auto len = int(textEnd - textBegin);
- context->sb.Append(textBegin, len);
+ context->shared->sb.Append(textBegin, len);
}
static void emitRawText(EmitContext* context, char const* text)
@@ -99,7 +114,7 @@ static void emitTextSpan(EmitContext* context, char const* textBegin, char const
// Update our logical position
// TODO(tfoley): Need to make "corelib" not use `int` for pointer-sized things...
auto len = int(textEnd - textBegin);
- context->loc.Col += len;
+ context->shared->loc.Col += len;
}
static void Emit(EmitContext* context, char const* textBegin, char const* textEnd)
@@ -123,8 +138,8 @@ static void Emit(EmitContext* context, char const* textBegin, char const* textEn
// At the end of a line, we need to update our tracking
// information on code positions
emitTextSpan(context, spanBegin, spanEnd);
- context->loc.Line++;
- context->loc.Col = 1;
+ context->shared->loc.Line++;
+ context->shared->loc.Col = 1;
// Start a new span for emit purposes
spanBegin = spanEnd;
@@ -144,7 +159,7 @@ static void emit(EmitContext* context, String const& text)
static bool isReservedWord(EmitContext* context, String const& name)
{
- return context->reservedWords.TryGetValue(name) != nullptr;
+ return context->shared->reservedWords.TryGetValue(name) != nullptr;
}
static void emitName(
@@ -449,7 +464,7 @@ static bool isTargetIntrinsicModifierApplicable(
// we expect.
auto const& targetName = targetToken.Content;
- switch(context->target)
+ switch(context->shared->target)
{
default:
assert(!"unexpected");
@@ -658,7 +673,7 @@ static void emitCallExpr(
case IntrinsicOp::InnerProduct_Vector_Vector:
// HLSL allows `mul()` to be used as a synonym for `dot()`,
// so we need to translate to `dot` for GLSL
- if (context->target == CodeGenTarget::GLSL)
+ if (context->shared->target == CodeGenTarget::GLSL)
{
Emit(context, "dot(");
EmitExpr(context, callExpr->Arguments[0]);
@@ -677,7 +692,7 @@ static void emitCallExpr(
//
// The other critical detail here is that the way we handle matrix
// conventions requires that the operands to the product be swapped.
- if (context->target == CodeGenTarget::GLSL)
+ if (context->shared->target == CodeGenTarget::GLSL)
{
Emit(context, "((");
EmitExpr(context, callExpr->Arguments[1]);
@@ -825,6 +840,13 @@ static void EmitExprWithPrecedence(EmitContext* context, RefPtr<ExpressionSyntax
Emit(context, " : ");
EmitExprWithPrecedence(context, selectExpr->Arguments[2], kPrecedence_Conditional);
}
+ else if (auto assignExpr = expr.As<AssignExpr>())
+ {
+ needClose = MaybeEmitParens(context, outerPrec, kPrecedence_Assign);
+ EmitExprWithPrecedence(context, assignExpr->left, kPrecedence_Assign);
+ Emit(context, " = ");
+ EmitExprWithPrecedence(context, assignExpr->right, kPrecedence_Assign);
+ }
else if (auto callExpr = expr.As<InvokeExpressionSyntaxNode>())
{
emitCallExpr(context, callExpr, outerPrec);
@@ -970,7 +992,7 @@ static void EmitExprWithPrecedence(EmitContext* context, RefPtr<ExpressionSyntax
}
else if (auto castExpr = expr.As<TypeCastExpressionSyntaxNode>())
{
- switch(context->target)
+ switch(context->shared->target)
{
case CodeGenTarget::GLSL:
// GLSL requires constructor syntax for all conversions
@@ -1227,7 +1249,7 @@ static void emitTextureType(
EmitContext* context,
RefPtr<TextureType> texType)
{
- switch(context->target)
+ switch(context->shared->target)
{
case CodeGenTarget::HLSL:
emitHLSLTextureType(context, texType);
@@ -1247,7 +1269,7 @@ static void emitTextureSamplerType(
EmitContext* context,
RefPtr<TextureSamplerType> type)
{
- switch(context->target)
+ switch(context->shared->target)
{
case CodeGenTarget::GLSL:
emitGLSLTextureSamplerType(context, type);
@@ -1263,7 +1285,7 @@ static void emitImageType(
EmitContext* context,
RefPtr<GLSLImageType> type)
{
- switch(context->target)
+ switch(context->shared->target)
{
case CodeGenTarget::HLSL:
emitHLSLTextureType(context, type);
@@ -1300,7 +1322,7 @@ static void EmitType(EmitContext* context, RefPtr<ExpressionType> type, EDeclara
}
else if (auto vecType = type->As<VectorExpressionType>())
{
- switch(context->target)
+ switch(context->shared->target)
{
case CodeGenTarget::GLSL:
case CodeGenTarget::GLSL_Vulkan:
@@ -1331,7 +1353,7 @@ static void EmitType(EmitContext* context, RefPtr<ExpressionType> type, EDeclara
}
else if (auto matType = type->As<MatrixExpressionType>())
{
- switch(context->target)
+ switch(context->shared->target)
{
case CodeGenTarget::GLSL:
case CodeGenTarget::GLSL_Vulkan:
@@ -1386,7 +1408,7 @@ static void EmitType(EmitContext* context, RefPtr<ExpressionType> type, EDeclara
}
else if (auto samplerStateType = type->As<SamplerStateType>())
{
- switch(context->target)
+ switch(context->shared->target)
{
case CodeGenTarget::HLSL:
default:
@@ -1474,7 +1496,8 @@ static void EmitType(EmitContext* context, RefPtr<ExpressionType> type)
static void EmitType(EmitContext* context, TypeExp const& typeExp, Token const& nameToken)
{
- EmitType(context, typeExp.type, typeExp.exp->Position, nameToken.Content, nameToken.Position);
+ EmitType(context, typeExp.type,
+ typeExp.exp ? typeExp.exp->Position : CodePosition(), nameToken.Content, nameToken.Position);
}
static void EmitType(EmitContext* context, TypeExp const& typeExp, String const& name)
@@ -1497,12 +1520,9 @@ static void EmitBlockStmt(EmitContext* context, RefPtr<StatementSyntaxNode> stmt
{
// TODO(tfoley): support indenting
Emit(context, "{\n");
- if( auto blockStmt = stmt.As<BlockStatementSyntaxNode>() )
+ if( auto blockStmt = stmt.As<BlockStmt>() )
{
- for (auto s : blockStmt->Statements)
- {
- EmitStmt(context, s);
- }
+ EmitStmt(context, blockStmt->body);
}
else
{
@@ -1544,7 +1564,7 @@ static void emitLineDirective(
emitRawText(context, " ");
- if(context->target == CodeGenTarget::GLSL)
+ if(context->shared->target == CodeGenTarget::GLSL)
{
auto path = sourceLocation.FileName;
@@ -1556,10 +1576,10 @@ static void emitLineDirective(
// extension and then emit a traditional line directive.
int id = 0;
- if(!context->mapGLSLSourcePathToID.TryGetValue(path, id))
+ if(!context->shared->mapGLSLSourcePathToID.TryGetValue(path, id))
{
- id = context->glslSourceIDCount++;
- context->mapGLSLSourcePathToID.Add(path, id);
+ id = context->shared->glslSourceIDCount++;
+ context->shared->mapGLSLSourcePathToID.Add(path, id);
}
sprintf(buffer, "%d", id);
@@ -1611,9 +1631,9 @@ static void emitLineDirectiveAndUpdateSourceLocation(
{
emitLineDirective(context, sourceLocation);
- context->loc.FileName = sourceLocation.FileName;
- context->loc.Line = sourceLocation.Line;
- context->loc.Col = 1;
+ context->shared->loc.FileName = sourceLocation.FileName;
+ context->shared->loc.Line = sourceLocation.Line;
+ context->shared->loc.Col = 1;
}
static void emitLineDirectiveIfNeeded(
@@ -1628,24 +1648,24 @@ static void emitLineDirectiveIfNeeded(
// a differnet file or line, *or* if the source location is
// somehow later on the line than what we want to emit,
// then we need to emit a new `#line` directive.
- if(sourceLocation.FileName != context->loc.FileName
- || sourceLocation.Line != context->loc.Line
- || sourceLocation.Col < context->loc.Col)
+ if(sourceLocation.FileName != context->shared->loc.FileName
+ || sourceLocation.Line != context->shared->loc.Line
+ || sourceLocation.Col < context->shared->loc.Col)
{
// Special case: if we are in the same file, and within a small number
// of lines of the target location, then go ahead and output newlines
// to get us caught up.
enum { kSmallLineCount = 3 };
- auto lineDiff = sourceLocation.Line - context->loc.Line;
- if(sourceLocation.FileName == context->loc.FileName
- && sourceLocation.Line > context->loc.Line
+ auto lineDiff = sourceLocation.Line - context->shared->loc.Line;
+ if(sourceLocation.FileName == context->shared->loc.FileName
+ && sourceLocation.Line > context->shared->loc.Line
&& lineDiff <= kSmallLineCount)
{
for(int ii = 0; ii < lineDiff; ++ii )
{
Emit(context, "\n");
}
- assert(sourceLocation.Line == context->loc.Line);
+ assert(sourceLocation.Line == context->shared->loc.Line);
}
else
{
@@ -1661,14 +1681,14 @@ static void emitLineDirectiveIfNeeded(
// came in as spaces or tabs, so there is necessarily going to be
// coupling between how the downstream compiler counts columns,
// and how we do.
- if(sourceLocation.Col > context->loc.Col)
+ if(sourceLocation.Col > context->shared->loc.Col)
{
- int delta = sourceLocation.Col - context->loc.Col;
+ int delta = sourceLocation.Col - context->shared->loc.Col;
for( int ii = 0; ii < delta; ++ii )
{
emitRawText(context, " ");
}
- context->loc.Col = sourceLocation.Col;
+ context->shared->loc.Col = sourceLocation.Col;
}
}
@@ -1680,22 +1700,22 @@ static void advanceToSourceLocation(
if(sourceLocation.Line <= 0)
return;
- context->needToUpdateSourceLocation = true;
- context->nextSourceLocation = sourceLocation;
+ context->shared->needToUpdateSourceLocation = true;
+ context->shared->nextSourceLocation = sourceLocation;
}
static void flushSourceLocationChange(
EmitContext* context)
{
- if(!context->needToUpdateSourceLocation)
+ if(!context->shared->needToUpdateSourceLocation)
return;
// Note: the order matters here, because trying to update
// the source location may involve outputting text that
// advances the location, and outputting text is what
// triggers this flush operation.
- context->needToUpdateSourceLocation = false;
- emitLineDirectiveIfNeeded(context, context->nextSourceLocation);
+ context->shared->needToUpdateSourceLocation = false;
+ emitLineDirectiveIfNeeded(context, context->shared->nextSourceLocation);
}
static void emitTokenWithLocation(EmitContext* context, Token const& token)
@@ -1737,11 +1757,19 @@ static void EmitStmt(EmitContext* context, RefPtr<StatementSyntaxNode> stmt)
// Try to ensure that debugging can find the right location
advanceToSourceLocation(context, stmt->Position);
- if (auto blockStmt = stmt.As<BlockStatementSyntaxNode>())
+ if (auto blockStmt = stmt.As<BlockStmt>())
{
EmitBlockStmt(context, blockStmt);
return;
}
+ else if (auto seqStmt = stmt.As<SeqStmt>())
+ {
+ for (auto ss : seqStmt->stmts)
+ {
+ EmitStmt(context, ss);
+ }
+ return;
+ }
else if( auto unparsedStmt = stmt.As<UnparsedStmt>() )
{
EmitUnparsedStmt(context, unparsedStmt);
@@ -1784,17 +1812,43 @@ static void EmitStmt(EmitContext* context, RefPtr<StatementSyntaxNode> stmt)
}
else if (auto forStmt = stmt.As<ForStatementSyntaxNode>())
{
- EmitLoopAttributes(context, forStmt);
+ // We are going to always take a `for` loop like:
+ //
+ // for(A; B; C) { D }
+ //
+ // and emit it as:
+ //
+ // { A; for(; B; C) { D } }
+ //
+ // This ensures that we are robust against any kind
+ // of statement appearing in `A`, including things
+ // that might occur due to lowering steps.
+ //
- Emit(context, "for(");
- if (auto initStmt = forStmt->InitialStatement)
+ // 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).
+ //
+ bool brokenScoping = false;
+ if (context->shared->target == CodeGenTarget::HLSL
+ && context->isRewrite)
{
- EmitStmt(context, initStmt);
+ brokenScoping = true;
}
- else
+
+ auto initStmt = forStmt->InitialStatement;
+ if(initStmt)
{
- Emit(context, ";");
+ if(!brokenScoping)
+ Emit(context, "{\n");
+ EmitStmt(context, initStmt);
}
+
+ EmitLoopAttributes(context, forStmt);
+
+ Emit(context, "for(;");
if (auto testExp = forStmt->PredicateExpression)
{
EmitExpr(context, testExp);
@@ -1806,6 +1860,13 @@ static void EmitStmt(EmitContext* context, RefPtr<StatementSyntaxNode> stmt)
}
Emit(context, ")\n");
EmitBlockStmt(context, forStmt->Statement);
+
+ if (initStmt)
+ {
+ if(!brokenScoping)
+ Emit(context, "}\n");
+ }
+
return;
}
else if (auto whileStmt = stmt.As<WhileStatementSyntaxNode>())
@@ -2085,7 +2146,7 @@ static void EmitSemantic(EmitContext* context, RefPtr<HLSLSemantic> semantic, ES
static void EmitSemantics(EmitContext* context, RefPtr<Decl> decl, ESemanticMask mask = kESemanticMask_Default )
{
// Don't emit semantics if we aren't translating down to HLSL
- switch (context->target)
+ switch (context->shared->target)
{
case CodeGenTarget::HLSL:
break;
@@ -2263,7 +2324,7 @@ static void emitHLSLRegisterSemantics(
{
if (!layout) return;
- switch( context->target )
+ switch( context->shared->target )
{
default:
return;
@@ -2278,6 +2339,25 @@ static void emitHLSLRegisterSemantics(
}
}
+static RefPtr<VarLayout> maybeFetchLayout(
+ RefPtr<Decl> decl,
+ RefPtr<VarLayout> layout)
+{
+ // If we have already found layout info, don't go searching
+ if (layout) return layout;
+
+ // Otherwise, we need to look and see if computed layout
+ // information has been attached to the declaration.
+ auto modifier = decl->FindModifier<ComputedLayoutModifier>();
+ if (!modifier) return nullptr;
+
+ auto computedLayout = modifier->layout;
+ assert(computedLayout);
+
+ auto varLayout = computedLayout.As<VarLayout>();
+ return varLayout;
+}
+
static void emitHLSLParameterBlockDecl(
EmitContext* context,
RefPtr<VarDeclBase> varDecl,
@@ -2292,6 +2372,7 @@ static void emitHLSLParameterBlockDecl(
assert(declRefType);
// We expect to always have layout information
+ layout = maybeFetchLayout(varDecl, layout);
assert(layout);
// We expect the layout to be for a structured type...
@@ -2325,13 +2406,16 @@ static void emitHLSLParameterBlockDecl(
Emit(context, "\n{\n");
if (auto structRef = declRefType->declRef.As<StructSyntaxNode>())
{
+ int fieldCounter = 0;
+
for (auto field : getMembersOfType<StructField>(structRef))
{
+ int fieldIndex = fieldCounter++;
+
EmitVarDeclCommon(context, field);
- RefPtr<VarLayout> fieldLayout;
- structTypeLayout->mapVarToLayout.TryGetValue(field.getDecl(), fieldLayout);
- assert(fieldLayout);
+ RefPtr<VarLayout> fieldLayout = structTypeLayout->fields[fieldIndex];
+ assert(fieldLayout->varDecl.GetName() == field.GetName());
// Emit explicit layout annotations for every field
for( auto rr : fieldLayout->resourceInfos )
@@ -2415,7 +2499,7 @@ emitGLSLLayoutQualifiers(
{
if(!layout) return;
- switch( context->target )
+ switch( context->shared->target )
{
default:
return;
@@ -2493,7 +2577,7 @@ static void emitGLSLParameterBlockDecl(
{
RefPtr<VarLayout> fieldLayout;
structTypeLayout->mapVarToLayout.TryGetValue(field.getDecl(), fieldLayout);
- assert(fieldLayout);
+// assert(fieldLayout);
// TODO(tfoley): We may want to emit *some* of these,
// some of the time...
@@ -2521,7 +2605,7 @@ static void emitParameterBlockDecl(
RefPtr<ParameterBlockType> parameterBlockType,
RefPtr<VarLayout> layout)
{
- switch(context->target)
+ switch(context->shared->target)
{
case CodeGenTarget::HLSL:
emitHLSLParameterBlockDecl(context, varDecl, parameterBlockType, layout);
@@ -2539,6 +2623,8 @@ static void emitParameterBlockDecl(
static void EmitVarDecl(EmitContext* context, RefPtr<VarDeclBase> decl, RefPtr<VarLayout> layout)
{
+ layout = maybeFetchLayout(decl, layout);
+
// As a special case, a variable using a parameter block type
// will be translated into a declaration using the more primitive
// language syntax.
@@ -2606,7 +2692,7 @@ static void emitGLSLPreprocessorDirectives(
EmitContext* context,
RefPtr<ProgramSyntaxNode> program)
{
- switch(context->target)
+ switch(context->shared->target)
{
// Don't emit this stuff unless we are targetting GLSL
default:
@@ -2658,78 +2744,6 @@ static void emitGLSLPreprocessorDirectives(
// TODO: handle other cases...
}
-static void EmitProgram(
- EmitContext* context,
- RefPtr<ProgramSyntaxNode> program,
- RefPtr<ProgramLayout> programLayout)
-{
- // There may be global-scope modifiers that we should emit now
- emitGLSLPreprocessorDirectives(context, program);
-
- switch(context->target)
- {
- case CodeGenTarget::GLSL:
- {
- // TODO(tfoley): Need a plan for how to enable/disable these as needed...
-// Emit(context, "#extension GL_GOOGLE_cpp_style_line_directive : require\n");
- }
- break;
-
- default:
- break;
- }
-
-
- // Layout information for the global scope is either an ordinary
- // `struct` in the common case, or a constant buffer in the case
- // where there were global-scope uniforms.
- auto globalScopeLayout = programLayout->globalScopeLayout;
- if( auto globalStructLayout = globalScopeLayout.As<StructTypeLayout>() )
- {
- context->globalStructLayout = globalStructLayout.Ptr();
-
- // The `struct` case is easy enough to handle: we just
- // emit all the declarations directly, using their layout
- // information as a guideline.
- EmitDeclsInContainerUsingLayout(context, program, globalStructLayout);
- }
- else if(auto globalConstantBufferLayout = globalScopeLayout.As<ParameterBlockTypeLayout>())
- {
- // TODO: the `cbuffer` case really needs to be emitted very
- // carefully, but that is beyond the scope of what a simple rewriter
- // can easily do (without semantic analysis, etc.).
- //
- // The crux of the problem is that we need to collect all the
- // global-scope uniforms (but not declarations that don't involve
- // uniform storage...) and put them in a single `cbuffer` declaration,
- // so that we can give it an explicit location. The fields in that
- // declaration might use various type declarations, so we'd really
- // need to emit all the type declarations first, and that involves
- // some large scale reorderings.
- //
- // For now we will punt and just emit the declarations normally,
- // and hope that the global-scope block (`$Globals`) gets auto-assigned
- // the same location that we manually asigned it.
-
- auto elementTypeLayout = globalConstantBufferLayout->elementTypeLayout;
- auto elementTypeStructLayout = elementTypeLayout.As<StructTypeLayout>();
-
- // We expect all constant buffers to contain `struct` types for now
- assert(elementTypeStructLayout);
-
- context->globalStructLayout = elementTypeStructLayout.Ptr();
-
- EmitDeclsInContainerUsingLayout(
- context,
- program,
- elementTypeStructLayout);
- }
- else
- {
- assert(!"unexpected");
- }
-}
-
static void EmitDeclImpl(EmitContext* context, RefPtr<Decl> decl, RefPtr<VarLayout> layout)
{
// Don't emit code for declarations that came from the stdlib.
@@ -2783,18 +2797,18 @@ static void EmitDeclImpl(EmitContext* context, RefPtr<Decl> decl, RefPtr<VarLayo
// We might import the same module along two different paths,
// so we need to be careful to only emit each module once
// per output.
- if(!context->modulesAlreadyEmitted.Contains(moduleDecl))
+ if(!context->shared->modulesAlreadyEmitted.Contains(moduleDecl))
{
// Add the module to our set before emitting it, just
// in case a circular reference would lead us to
// infinite recursion (but that shouldn't be allowed
// in the first place).
- context->modulesAlreadyEmitted.Add(moduleDecl);
+ context->shared->modulesAlreadyEmitted.Add(moduleDecl);
// TODO: do we need to modify the code generation environment at
// all when doing this recursive emit?
- EmitDeclsInContainerUsingLayout(context, moduleDecl, context->globalStructLayout);
+ EmitDeclsInContainerUsingLayout(context, moduleDecl, context->shared->globalStructLayout);
}
return;
@@ -2839,7 +2853,7 @@ static void registerReservedWord(
EmitContext* context,
String const& name)
{
- context->reservedWords.Add(name, name);
+ context->shared->reservedWords.Add(name, name);
}
static void registerReservedWords(
@@ -2847,7 +2861,7 @@ static void registerReservedWords(
{
#define WORD(NAME) registerReservedWord(context, #NAME)
- switch (context->target)
+ switch (context->shared->target)
{
case CodeGenTarget::GLSL:
WORD(attribute);
@@ -2990,68 +3004,115 @@ static void registerReservedWords(
}
}
-String emitProgram(
- ProgramSyntaxNode* program,
+bool isRewriteRequest(
+ SourceLanguage sourceLanguage,
+ CodeGenTarget target);
+
+String emitEntryPoint(
+ EntryPointRequest* entryPoint,
ProgramLayout* programLayout,
CodeGenTarget target)
{
- // TODO(tfoley): only emit symbols on-demand, as needed by a particular entry point
+ auto translationUnit = entryPoint->getTranslationUnit();
+
+ SharedEmitContext sharedContext;
+ sharedContext.target = target;
+
+ sharedContext.programLayout = programLayout;
+
+ // Layout information for the global scope is either an ordinary
+ // `struct` in the common case, or a constant buffer in the case
+ // where there were global-scope uniforms.
+ auto globalScopeLayout = programLayout->globalScopeLayout;
+ StructTypeLayout* globalStructLayout = nullptr;
+ if( auto globalStructLayout = globalScopeLayout.As<StructTypeLayout>() )
+ {
+ globalStructLayout = globalStructLayout.Ptr();
+ }
+ else if(auto globalConstantBufferLayout = globalScopeLayout.As<ParameterBlockTypeLayout>())
+ {
+ // TODO: the `cbuffer` case really needs to be emitted very
+ // carefully, but that is beyond the scope of what a simple rewriter
+ // can easily do (without semantic analysis, etc.).
+ //
+ // The crux of the problem is that we need to collect all the
+ // global-scope uniforms (but not declarations that don't involve
+ // uniform storage...) and put them in a single `cbuffer` declaration,
+ // so that we can give it an explicit location. The fields in that
+ // declaration might use various type declarations, so we'd really
+ // need to emit all the type declarations first, and that involves
+ // some large scale reorderings.
+ //
+ // For now we will punt and just emit the declarations normally,
+ // and hope that the global-scope block (`$Globals`) gets auto-assigned
+ // the same location that we manually asigned it.
+
+ auto elementTypeLayout = globalConstantBufferLayout->elementTypeLayout;
+ auto elementTypeStructLayout = elementTypeLayout.As<StructTypeLayout>();
+
+ // We expect all constant buffers to contain `struct` types for now
+ assert(elementTypeStructLayout);
+
+ globalStructLayout = elementTypeStructLayout.Ptr();
+ }
+ else
+ {
+ assert(!"unexpected");
+ }
+ sharedContext.globalStructLayout = globalStructLayout;
EmitContext context;
- context.target = target;
+ context.shared = &sharedContext;
+ context.isRewrite = isRewriteRequest(
+ translationUnit->sourceLanguage,
+ target);
+ // TODO: this should only need to take the shared context
registerReservedWords(&context);
- EmitProgram(&context, program, programLayout);
+ auto translationUnitSyntax = translationUnit->SyntaxNode.Ptr();
- String code = context.sb.ProduceString();
- return code;
-
-#if 0
- // HACK(tfoley): Invoke the D3D HLSL compiler on the result, to validate it
+ // There may be global-scope modifiers that we should emit now
+ emitGLSLPreprocessorDirectives(&context, translationUnitSyntax);
-#ifdef _WIN32
+ switch(target)
{
- HMODULE d3dCompiler = LoadLibraryA("d3dcompiler_47");
- assert(d3dCompiler);
-
- pD3DCompile D3DCompile_ = (pD3DCompile)GetProcAddress(d3dCompiler, "D3DCompile");
- assert(D3DCompile_);
-
- ID3DBlob* codeBlob;
- ID3DBlob* diagnosticsBlob;
- HRESULT hr = D3DCompile_(
- code.begin(),
- code.Length(),
- "slang",
- nullptr,
- nullptr,
- "main",
- "ps_5_0",
- 0,
- 0,
- &codeBlob,
- &diagnosticsBlob);
- if (codeBlob) codeBlob->Release();
- if (diagnosticsBlob)
- {
- String diagnostics = (char const*) diagnosticsBlob->GetBufferPointer();
- fprintf(stderr, "%s", diagnostics.begin());
- OutputDebugStringA(diagnostics.begin());
- diagnosticsBlob->Release();
- }
- if (FAILED(hr))
+ case CodeGenTarget::GLSL:
{
- int f = 9;
+ // TODO(tfoley): Need a plan for how to enable/disable these as needed...
+// Emit(context, "#extension GL_GOOGLE_cpp_style_line_directive : require\n");
}
+ break;
+
+ default:
+ break;
}
- #include <d3dcompiler.h>
-#endif
+ auto lowered = lowerEntryPoint(entryPoint, programLayout, target);
+
+ EmitDeclsInContainer(&context, lowered.program.Ptr());
+
+#if 0
+ if( isRewrite )
+ {
+ // In rewrite mode, we will just emit the text of the translation unit as given,
+ // and not pay attention to the specific entry point that was requested.
+ //
+ // It is a user error to request GLSL output and have an entry point name
+ // other than `main`.
+ EmitDeclsInContainerUsingLayout(&context, translationUnitSyntax, globalStructLayout);
+ }
+ else
+ {
+ // We are being asked to emit a single entry point in "full" mode.
+ emitEntryPoint(&context, entryPoint);
+ }
#endif
-}
+ String code = sharedContext.sb.ProduceString();
+ return code;
+}
} // namespace Slang