summaryrefslogtreecommitdiffstats
path: root/source/slang/emit.cpp
diff options
context:
space:
mode:
authorTim Foley <tfoleyNV@users.noreply.github.com>2017-12-18 15:14:59 -0800
committerGitHub <noreply@github.com>2017-12-18 15:14:59 -0800
commit393e25fd2e2b8c5ff82ff4c6b14a9d7152d37a5e (patch)
treea3b0617e7ce5a5bfcf43454893f6c2962b7ec382 /source/slang/emit.cpp
parent46b68ed41daecfaf1761e299cf040156e0f65ac0 (diff)
Work on getting rewriter + IR playing nice together. (#314)
* Work on getting rewriter + IR playing nice together. There are a few different changes here, with the goal of improving the interaction between the "rewriter" code generation approach and the new IR and type legalization code. The main changes are: - Add a new pass that occurs before the AST legalization pass, which walks the (used) AST declarations and tries to discover (1) which declarations need to be specialized/lowered via the IR, and (2) which declarations need to be included in the resulting AST module. - AST-based legalization now uses the generated list when in "rewriter" mode, so that we should be working around issues that users were seeing with types not getting emitted. - TODO: we still need an equivalent fixup in the case of non-"rewriter" emit, so this may still be a problem for `.slang` files. - IR type legalization now precedes AST legalization, so that we can record information on how any IR global values got legalized (e.g., if they got split). Then AST legalization includes logic to reconstruct suitable tuple expressions to reference a split global. - When emitting using IR + AST, we walk all of the declarations that we decided belonged to the IR, but which were subsequently referenced in the AST, to make sure they get output (this would include `struct` types that are declared in a file compiled via IR, but never used in IR-based code). The rewriter+IR use case still doesn't *quite* work, but the logic for walking the AST in a pre-pass ends up being needed/useful to fix some pure rewriter bugs, so I'm getting this checked in sooner rather than later. * Fixup: walk arguments to generic declaration reference The gotcha here is that the code for walking the AST would walk a line of code like: SomeType a; and know to traverse the declaration of `SomeType`, but if it saw a line of code like: ParameterBlock<SomeType> b; it would traverse the declaration of `ParameterBlock`, but fail to visit that of `SomeType`.
Diffstat (limited to 'source/slang/emit.cpp')
-rw-r--r--source/slang/emit.cpp111
1 files changed, 78 insertions, 33 deletions
diff --git a/source/slang/emit.cpp b/source/slang/emit.cpp
index bf7ad0c3a..ce17c8d03 100644
--- a/source/slang/emit.cpp
+++ b/source/slang/emit.cpp
@@ -100,7 +100,7 @@ struct SharedEmitContext
Dictionary<IRValue*, UInt> mapIRValueToID;
Dictionary<Decl*, UInt> mapDeclToID;
- HashSet<Decl*> irDeclsVisited;
+ HashSet<String> irDeclsVisited;
Dictionary<IRBlock*, IRBlock*> irMapContinueTargetToLoopHead;
@@ -2415,7 +2415,8 @@ struct EmitVisitor
}
else
{
- emit(memberExpr->declRef.GetName());
+ EmitDeclRef(memberExpr->declRef);
+// emit(memberExpr->declRef.GetName());
}
if(needClose) Emit(")");
@@ -2453,7 +2454,8 @@ struct EmitVisitor
}
else
{
- emit(memberExpr->declRef.GetName());
+ EmitDeclRef(memberExpr->declRef);
+// emit(memberExpr->declRef.GetName());
}
if(needClose) Emit(")");
@@ -6892,15 +6894,11 @@ emitDeclImpl(decl, nullptr);
EmitContext* ctx,
DeclRef<StructDecl> declRef)
{
- // TODO: Eventually need to deal with the case where
- // we have user-defined generic types.
- //
- auto decl = declRef.getDecl();
-
- if(ctx->shared->irDeclsVisited.Contains(decl))
+ auto mangledName = getMangledName(declRef);
+ if(ctx->shared->irDeclsVisited.Contains(mangledName))
return;
- ctx->shared->irDeclsVisited.Add(decl);
+ ctx->shared->irDeclsVisited.Add(mangledName);
// First emit any types used by fields of this type
for( auto ff : GetFields(declRef) )
@@ -6935,6 +6933,25 @@ emitDeclImpl(decl, nullptr);
Emit("};\n");
}
+ void emitIRUsedDeclRef(
+ EmitContext* ctx,
+ DeclRef<Decl> declRef)
+ {
+ auto decl = declRef.getDecl();
+
+ if(decl->HasModifier<BuiltinTypeModifier>()
+ || decl->HasModifier<MagicTypeModifier>())
+ {
+ return;
+ }
+
+ if( auto structDeclRef = declRef.As<StructDecl>() )
+ {
+ //
+ ensureStructDecl(ctx, structDeclRef);
+ }
+ }
+
// A type is going to be used by the IR, so
// make sure that we have emitted whatever
// it needs.
@@ -6970,19 +6987,7 @@ emitDeclImpl(decl, nullptr);
else if( auto declRefType = type->As<DeclRefType>() )
{
auto declRef = declRefType->declRef;
- auto decl = declRef.getDecl();
-
- if(decl->HasModifier<BuiltinTypeModifier>()
- || decl->HasModifier<MagicTypeModifier>())
- {
- return;
- }
-
- if( auto structDeclRef = declRef.As<StructDecl>() )
- {
- //
- ensureStructDecl(ctx, structDeclRef);
- }
+ emitIRUsedDeclRef(ctx, declRef);
}
else
{}
@@ -7249,13 +7254,21 @@ String emitEntryPoint(
// boilerplate at the start of the ouput for GLSL (e.g., what
// version we require).
+ List<Decl*> astDecls;
+ findDeclsUsedByASTEntryPoint(
+ entryPoint,
+ target,
+ nullptr,
+ astDecls);
+
auto lowered = lowerEntryPoint(
entryPoint,
programLayout,
target,
&sharedContext.extensionUsageTracker,
nullptr,
- &typeLegalizationContext);
+ &typeLegalizationContext,
+ astDecls);
sharedContext.program = lowered.program;
// Note that we emit the main body code of the program *before*
@@ -7287,25 +7300,23 @@ String emitEntryPoint(
typeLegalizationContext.irModule = irModule;
- LoweredEntryPoint lowered;
+ List<Decl*> astDecls;
if(translationUnit->compileFlags & SLANG_COMPILE_FLAG_NO_CHECKING)
{
// We are in case (2b), where the main module is in unchecked
// HLSL/GLSL that we need to "rewrite," and any library code
// is in Slang that will need to be cross-compiled via the IR.
- // Initially, we will apply the AST-to-AST pass to legalize
- // the user's code, much like we would for any other target.
- // Along the way, this pass will discover any IR declarations
- // that we use, and try to emit code for them into our IR module.
+ // We first need to walk the AST part of the code to look
+ // for any places where it references declarations that
+ // are implemented in the IR, so that we can be sure to
+ // generate suitable IR code for them.
- lowered = lowerEntryPoint(
+ findDeclsUsedByASTEntryPoint(
entryPoint,
- programLayout,
target,
- &sharedContext.extensionUsageTracker,
irSpecializationState,
- &typeLegalizationContext);
+ astDecls);
}
else
{
@@ -7358,6 +7369,33 @@ String emitEntryPoint(
fprintf(stderr, "###\n");
#endif
+ LoweredEntryPoint lowered;
+ if(translationUnit->compileFlags & SLANG_COMPILE_FLAG_NO_CHECKING)
+ {
+ // In the (2b) case, once we have legalized the IR code,
+ // we now need to go in and legalize the AST code.
+ // This order is important because when referring to a variable
+ // that is defined in the IR, we need to legalize it first (which
+ // might split it into many decls) before we can legalize an AST
+ // expression that references that decl (which will also need
+ // to get split).
+ //
+ // We don't have to worry about references in the other direction;
+ // we don't allow the user to define something in unchecked AST
+ // code and then use it from the IR shader library.
+
+ lowered = lowerEntryPoint(
+ entryPoint,
+ programLayout,
+ target,
+ &sharedContext.extensionUsageTracker,
+ irSpecializationState,
+ &typeLegalizationContext,
+ astDecls);
+ }
+
+ // When emitting IR-based declarations, we wnat to
+ // track which decls have already been lowered.
sharedContext.irDeclSetForAST = &lowered.irDecls;
// After all of the required optimization and legalization
@@ -7372,6 +7410,13 @@ String emitEntryPoint(
// that we need to output, we'll do it now.
if (translationUnit->compileFlags & SLANG_COMPILE_FLAG_NO_CHECKING)
{
+ // First make sure that we've emitted any types that were declared
+ // in the IR, but then subsequently only used by the AST
+ for( auto decl : lowered.irDecls )
+ {
+ visitor.emitIRUsedDeclRef(&context, makeDeclRef(decl));
+ }
+
visitor.EmitDeclsInContainer(lowered.program);
}