summaryrefslogtreecommitdiff
path: root/source/slang/emit.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'source/slang/emit.cpp')
-rw-r--r--source/slang/emit.cpp217
1 files changed, 147 insertions, 70 deletions
diff --git a/source/slang/emit.cpp b/source/slang/emit.cpp
index d6f1f8e1a..4a084c714 100644
--- a/source/slang/emit.cpp
+++ b/source/slang/emit.cpp
@@ -102,6 +102,9 @@ struct SharedEmitContext
Dictionary<IRBlock*, IRBlock*> irMapContinueTargetToLoopHead;
HashSet<String> irTupleTypes;
+
+ // Map used to tell AST lowering what decls are represented by IR.
+ HashSet<Decl*>* irDeclSetForAST = nullptr;
};
struct EmitContext
@@ -2942,6 +2945,19 @@ struct EmitVisitor
void EmitDeclRef(DeclRef<Decl> declRef)
{
+ // Are we emitting an AST in a context where some declarations
+ // are actually stored as IR code?
+ if(auto irDeclSet = context->shared->irDeclSetForAST)
+ {
+ Decl* decl = declRef.getDecl();
+ if(irDeclSet->Contains(decl))
+ {
+ emit(getMangledName(declRef));
+ return;
+ }
+ }
+
+
// TODO: need to qualify a declaration name based on parent scopes/declarations
// Emit the name for the declaration itself
@@ -6870,55 +6886,142 @@ String emitEntryPoint(
// Depending on how the compiler was invoked, we may need to perform
// some amount of preocessing on the code before we can emit it.
//
- // For our purposes, there are basically three different "modes" we
- // care about:
+ // We try to partition the cases we need to handle into a few broad
+ // categories, each of which is reflected as a different code path
+ // below:
+ //
+ // 1. "Full rewriter" mode, where the user provides HLSL/GLSL, opts
+ // out of semantic checking, and doesn't make use of any Slang
+ // code via `import`.
+ //
+ // 2. "Partial rewriter" modes, where the user starts with HLSL/GLSL
+ // and opts out of checking for that code, but also imports some
+ // Slang code which may need cross-compilation. They may also
+ // need us to rewrite the AST for some of their HLSL/GLSL function
+ // bodies to make things work. This actually has two main sub-modes:
//
- // 1. "Full rewriter" mode, where the user provides HLSL/GLSL, and
- // doesn't make use of any Slang code via `import`.
+ // a) "Without IR." If the user doesn't opt into using the IR, then
+ // the imported Slang code gets translated to the target languge
+ // via the same AST-to-AST pass that legalized the user's code. This
+ // mode will eventually go away, but it is the main one used right now.
//
- // 2. "Partial rewriter" mode, where the user starts with HLSL/GLSL,
- // but also imports some Slang code, and may need us to rewrite
- // their HLSL/GLSL function bodies to make things work.
+ // b) "With IR." If the user opts into using the IR, then we need to
+ // apply the AST-to-AST pass to their HLSL/GLSL code, but *also* use
+ // the IR to compile everything else.
//
- // 3. "Full" mode, where all of the input code is in Slang (and/or
- // the subset of HLSL we can fully type-check).
+ // 3. "Full IR" mode, where we can assume all the input code is in Slang
+ // (or the subset of HLSL we understand) that has undergone full
+ // semantic checking, and the user has opted into using the IR.
//
- // We'll try to detect the cases here:
+ // We'll try to detect the cases here, starting with case (1):
//
- if((translationUnit->compileRequest->compileFlags & SLANG_COMPILE_FLAG_USE_IR)
- && !(translationUnit->compileFlags & SLANG_COMPILE_FLAG_NO_CHECKING ))
+ if ((translationUnit->compileFlags & SLANG_COMPILE_FLAG_NO_CHECKING)
+ && translationUnit->compileRequest->loadedModulesList.Count() == 0)
{
- // This seems to be case (3), because the user is asking for full
- // checking, and so we can assume we understand the code fully.
+ // The user has opted out of semantic checking for their own code
+ // (in the "main" module), and also hasn't `import`ed any Slang
+ // modules that would require cross-compilation.
//
- // The IR code for the module should already have been generated,
- // so that we "just" need to specialize it as needed for the
- // specific target and entry point in use.
+ // Our goal in this mode is to print out the AST we parsed and
+ // hopefully reproduce something as close to the original as possible.
//
- // The first pass is to extract the IR code of the entry point,
- // and any other symbols it references. At the same time,
- // we go ahead and select the target-specific version of
- // any such functions if they are available. We also go
- // ahead and apply the layout information (from `programLayout`)
- // to the IR code (which previously had no layout).
+ // The only deviation we *want* from the original code is that we will
+ // add new parameter binding annotations.
+
+ sharedContext.program = translationUnitSyntax;
+ visitor.EmitDeclsInContainerUsingLayout(
+ translationUnitSyntax,
+ globalStructLayout);
+ }
+ //
+ // Next we will check for case (2a):
+ else if (!(translationUnit->compileRequest->compileFlags & SLANG_COMPILE_FLAG_USE_IR))
+ {
+ // This case means the user has opted out of using the IR (so we can't use the
+ // cases below), but they either turned on semantic checking *or* imported some
+ // Slang code, so they can't use the case above.
//
- // Note: it is important that we extract a *copy* of all the
- // relevant IR, so that transformations we make for one
- // entry point (or target) don't mess up the IR used for other
- // entry points (targets).
+ // Note: This case should go away completely once the IR is able to be relied
+ // upon for all cross-compilation scenarios.
+
+ // We will apply our AST-to-AST legalization pass before we emit
+ // any code, and we will emit code for the AST that comes out
+ // of this pass instead of the original.
+
+ // We perform legalization of the program before emitting *anything*,
+ // because the lowering process might change how we emit some
+ // boilerplate at the start of the ouput for GLSL (e.g., what
+ // version we require).
+
+ auto lowered = lowerEntryPoint(
+ entryPoint,
+ programLayout,
+ target,
+ &sharedContext.extensionUsageTracker,
+ nullptr);
+ sharedContext.program = lowered.program;
+
+ // Note that we emit the main body code of the program *before*
+ // we emit any leading preprocessor directives for GLSL.
+ // This is to give the emit logic a change to make last-minute
+ // adjustments like changing the required GLSL version.
//
- auto lowered = specializeIRForEntryPoint(
+ // TODO: All such adjustments would be better handled during
+ // lowering, but that requires having a semantic rather than
+ // textual format for the HLSL->GLSL mapping.
+ visitor.EmitDeclsInContainer(lowered.program.Ptr());
+ }
+ //
+ // The remaining cases all require the use of our IR, and so there
+ // are certain steps that need to be shared.
+ else
+ {
+ // We are going to create a fresh IR module that we will use to
+ // clone any code needed by the user's entry point.
+ IRSpecializationState* irSpecializationState = createIRSpecializationState(
entryPoint,
programLayout,
- target,
+ target,
targetRequest);
+ IRModule* irModule = getIRModule(irSpecializationState);
+
+ LoweredEntryPoint lowered;
+ 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.
+
+ lowered = lowerEntryPoint(
+ entryPoint,
+ programLayout,
+ target,
+ &sharedContext.extensionUsageTracker,
+ irSpecializationState);
+ }
+ else
+ {
+ // We are in case (3), where all of the code is in Slang, and
+ // has already been lowered to IR as part of the front-end
+ // compilation work. We thus start by cloning any code needed
+ // by the entry point over to our fresh IR module.
+
+ specializeIRForEntryPoint(
+ irSpecializationState,
+ entryPoint);
+ }
// If the user specified the flag that they want us to dump
// IR, then do it here, for the target-specific, but
// un-specialized IR.
if (translationUnit->compileRequest->shouldDumpIR)
{
- dumpIR(lowered);
+ dumpIR(irModule);
}
// Next, we need to ensure that the code we emit for
@@ -6927,7 +7030,7 @@ String emitEntryPoint(
// none of our target supports generics, or interfaces,
// so we need to specialize those away.
//
- specializeGenerics(lowered);
+ specializeGenerics(irModule);
// Debugging code for IR transformations...
#if 0
@@ -6941,7 +7044,7 @@ String emitEntryPoint(
// we need to ensure that the code only uses types
// that are legal on the chosen target.
//
- legalizeTypes(lowered);
+ legalizeTypes(irModule);
// Debugging output of legalization
#if 0
@@ -6950,50 +7053,24 @@ String emitEntryPoint(
fprintf(stderr, "###\n");
#endif
+ // After all of the required optimization and legalization
+ // passes have been performed, we can emit target code from
+ // the IR module.
+ //
// TODO: do we want to emit directly from IR, or translate the
// IR back into AST for emission?
+ visitor.emitIRModule(&context, irModule);
- visitor.emitIRModule(&context, lowered);
+ // If we are in case (2b) and the user *also* has AST-based code
+ // that we need to output, we'll do it now.
+ if (translationUnit->compileFlags & SLANG_COMPILE_FLAG_NO_CHECKING)
+ {
+ sharedContext.irDeclSetForAST = &lowered.irDecls;
+ visitor.EmitDeclsInContainer(lowered.program);
+ }
// TODO: need to clean up the IR module here
}
- else if(!(translationUnit->compileFlags & SLANG_COMPILE_FLAG_NO_CHECKING ) ||
- translationUnit->compileRequest->loadedModulesList.Count() != 0)
- {
- // The user has `import`ed some Slang modules, and so we are in case (2)
- //
- // We need to apply a "rewriting" pass to the code the user wrote,
- // and then emit the result.
-
- // We perform lowering of the program before emitting *anything*,
- // because the lowering process might change how we emit some
- // boilerplate at the start of the ouput for GLSL (e.g., what
- // version we require).
- auto lowered = lowerEntryPoint(entryPoint, programLayout, target, &sharedContext.extensionUsageTracker);
- sharedContext.program = lowered.program;
-
- // Note that we emit the main body code of the program *before*
- // we emit any leading preprocessor directives for GLSL.
- // This is to give the emit logic a change to make last-minute
- // adjustments like changing the required GLSL version.
- //
- // TODO: All such adjustments would be better handled during
- // lowering, but that requires having a semantic rather than
- // textual format for the HLSL->GLSL mapping.
- visitor.EmitDeclsInContainer(lowered.program.Ptr());
- }
- else
- {
- // We are in case (1).
- //
- // We should be able to just emit the AST we parsed right back out,
- // along with whatever annotations we added along the way.
-
- sharedContext.program = translationUnitSyntax;
- visitor.EmitDeclsInContainerUsingLayout(
- translationUnitSyntax,
- globalStructLayout);
- }
String code = sharedContext.sb.ProduceString();
sharedContext.sb.Clear();