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.cpp510
1 files changed, 0 insertions, 510 deletions
diff --git a/source/slang/emit.cpp b/source/slang/emit.cpp
deleted file mode 100644
index d90415d89..000000000
--- a/source/slang/emit.cpp
+++ /dev/null
@@ -1,510 +0,0 @@
-// emit.cpp
-#include "emit.h"
-
-#include "../core/slang-writer.h"
-#include "ir-bind-existentials.h"
-#include "ir-dce.h"
-#include "ir-entry-point-uniforms.h"
-#include "ir-glsl-legalize.h"
-#include "ir-insts.h"
-#include "ir-link.h"
-#include "ir-restructure.h"
-#include "ir-restructure-scoping.h"
-#include "ir-specialize.h"
-#include "ir-specialize-resources.h"
-#include "ir-ssa.h"
-#include "ir-union.h"
-#include "ir-validate.h"
-#include "legalize-types.h"
-#include "lower-to-ir.h"
-#include "mangle.h"
-#include "name.h"
-#include "syntax.h"
-#include "type-layout.h"
-#include "visitor.h"
-
-#include "slang-source-stream.h"
-#include "slang-emit-context.h"
-
-#include "slang-c-like-source-emitter.h"
-
-#include <assert.h>
-
-namespace Slang {
-
-enum class BuiltInCOp
-{
- Splat, //< Splat a single value to all values of a vector or matrix type
- Init, //< Initialize with parameters (must match the type)
-};
-
-
-//
-
-
-//
-
-EntryPointLayout* findEntryPointLayout(
- ProgramLayout* programLayout,
- EntryPoint* entryPoint)
-{
- for( auto entryPointLayout : programLayout->entryPoints )
- {
- if(entryPointLayout->entryPoint->getName() != entryPoint->getName())
- continue;
-
- // TODO: We need to be careful about this check, since it relies on
- // the profile information in the layout matching that in the request.
- //
- // What we really seem to want here is some dictionary mapping the
- // `EntryPoint` directly to the `EntryPointLayout`, and maybe
- // that is precisely what we should build...
- //
- if(entryPointLayout->profile != entryPoint->getProfile())
- continue;
-
- // TODO: can't easily filter on translation unit here...
- // Ideally the `EntryPoint` should get filled in with a pointer
- // the specific function declaration that represents the entry point.
-
- return entryPointLayout.Ptr();
- }
-
- return nullptr;
-}
-
- /// Given a layout computed for a scope, get the layout to use when lookup up variables.
- ///
- /// A scope (such as the global scope of a program) groups its
- /// parameters into a pseudo-`struct` type for layout purposes,
- /// and in some cases that type will in turn be wrapped in a
- /// `ConstantBuffer` type to indicate that the parameters needed
- /// an implicit constant buffer to be allocated.
- ///
- /// This function "unwraps" the type layout to find the structure
- /// type layout that must be stored inside.
- ///
-StructTypeLayout* getScopeStructLayout(
- ScopeLayout* scopeLayout)
-{
- auto scopeTypeLayout = scopeLayout->parametersLayout->typeLayout;
-
- if( auto constantBufferTypeLayout = as<ParameterGroupTypeLayout>(scopeTypeLayout) )
- {
- scopeTypeLayout = constantBufferTypeLayout->offsetElementTypeLayout;
- }
-
- if( auto structTypeLayout = as<StructTypeLayout>(scopeTypeLayout) )
- {
- return structTypeLayout;
- }
-
- SLANG_UNEXPECTED("uhandled global-scope binding layout");
- return nullptr;
-}
-
- /// Given a layout computed for a program, get the layout to use when lookup up variables.
- ///
- /// This is just an alias of `getScopeStructLayout`.
- ///
-StructTypeLayout* getGlobalStructLayout(
- ProgramLayout* programLayout)
-{
- return getScopeStructLayout(programLayout);
-}
-
-static void dumpIR(
- BackEndCompileRequest* compileRequest,
- IRModule* irModule,
- char const* label)
-{
- DiagnosticSinkWriter writerImpl(compileRequest->getSink());
- WriterHelper writer(&writerImpl);
-
- if(label)
- {
- writer.put("### ");
- writer.put(label);
- writer.put(":\n");
- }
-
- dumpIR(irModule, writer.getWriter());
-
- if( label )
- {
- writer.put("###\n");
- }
-}
-
-static void dumpIRIfEnabled(
- BackEndCompileRequest* compileRequest,
- IRModule* irModule,
- char const* label = nullptr)
-{
- if(compileRequest->shouldDumpIR)
- {
- dumpIR(compileRequest, irModule, label);
- }
-}
-
-String emitEntryPoint(
- BackEndCompileRequest* compileRequest,
- EntryPoint* entryPoint,
- CodeGenTarget target,
- TargetRequest* targetRequest)
-{
- auto sink = compileRequest->getSink();
- auto program = compileRequest->getProgram();
- auto targetProgram = program->getTargetProgram(targetRequest);
- auto programLayout = targetProgram->getOrCreateLayout(sink);
-
-// auto translationUnit = entryPoint->getTranslationUnit();
-
- auto lineDirectiveMode = compileRequest->getLineDirectiveMode();
- // To try to make the default behavior reasonable, we will
- // always use C-style line directives (to give the user
- // good source locations on error messages from downstream
- // compilers) *unless* they requested raw GLSL as the
- // output (in which case we want to maximize compatibility
- // with downstream tools).
- if (lineDirectiveMode == LineDirectiveMode::Default && targetRequest->getTarget() == CodeGenTarget::GLSL)
- {
- lineDirectiveMode = LineDirectiveMode::GLSL;
- }
-
- SourceStream sourceStream(compileRequest->getSourceManager(), lineDirectiveMode );
-
- EmitContext emitContext;
- emitContext.compileRequest = compileRequest;
- emitContext.target = target;
- emitContext.entryPoint = entryPoint;
- emitContext.effectiveProfile = getEffectiveProfile(entryPoint, targetRequest);
- emitContext.stream = &sourceStream;
-
- if (entryPoint && programLayout)
- {
- emitContext.entryPointLayout = findEntryPointLayout(
- programLayout,
- entryPoint);
- }
-
- emitContext.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.
-
- StructTypeLayout* globalStructLayout = programLayout ? getGlobalStructLayout(programLayout) : nullptr;
- emitContext.globalStructLayout = globalStructLayout;
-
- CLikeSourceEmitter sourceEmitter(&emitContext);
-
- {
- auto session = targetRequest->getSession();
-
- // We start out by performing "linking" at the level of the IR.
- // This step will create a fresh IR module to be used for
- // code generation, and will copy in any IR definitions that
- // the desired entry point requires. Along the way it will
- // resolve references to imported/exported symbols across
- // modules, and also select between the definitions of
- // any "profile-overloaded" symbols.
- //
- auto linkedIR = linkIR(
- compileRequest,
- entryPoint,
- programLayout,
- target,
- targetRequest);
- auto irModule = linkedIR.module;
- auto irEntryPoint = linkedIR.entryPoint;
-
-#if 0
- dumpIRIfEnabled(compileRequest, irModule, "LINKED");
-#endif
-
- validateIRModuleIfEnabled(compileRequest, irModule);
-
- // 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.
- dumpIRIfEnabled(compileRequest, irModule);
-
- // When there are top-level existential-type parameters
- // to the shader, we need to take the side-band information
- // on how the existential "slots" were bound to concrete
- // types, and use it to introduce additional explicit
- // shader parameters for those slots, to be wired up to
- // use sites.
- //
- bindExistentialSlots(irModule, sink);
-#if 0
- dumpIRIfEnabled(compileRequest, irModule, "EXISTENTIALS BOUND");
-#endif
- validateIRModuleIfEnabled(compileRequest, irModule);
-
-
-
-
-
- // Now that we've linked the IR code, any layout/binding
- // information has been attached to shader parameters
- // and entry points. Now we are safe to make transformations
- // that might move code without worrying about losing
- // the connection between a parameter and its layout.
- //
- // An easy transformation of this kind is to take uniform
- // parameters of a shader entry point and move them into
- // the global scope instead.
- //
- moveEntryPointUniformParamsToGlobalScope(irModule);
-#if 0
- dumpIRIfEnabled(compileRequest, irModule, "ENTRY POINT UNIFORMS MOVED");
-#endif
- validateIRModuleIfEnabled(compileRequest, irModule);
-
- // Desguar any union types, since these will be illegal on
- // various targets.
- //
- desugarUnionTypes(irModule);
-#if 0
- dumpIRIfEnabled(compileRequest, irModule, "UNIONS DESUGARED");
-#endif
- validateIRModuleIfEnabled(compileRequest, irModule);
-
- // Next, we need to ensure that the code we emit for
- // the target doesn't contain any operations that would
- // be illegal on the target platform. For example,
- // none of our target supports generics, or interfaces,
- // so we need to specialize those away.
- //
- // Simplification of existential-based and generics-based
- // code may each open up opportunities for the other, so
- // the relevant specialization transformations are handled in a
- // single pass that looks for all simplification opportunities.
- //
- // TODO: We also need to extend this pass so that it will "expose"
- // existential values that are nested inside of other types,
- // so that the simplifications can be applied.
- //
- // TODO: This pass is *also* likely to be the place where we
- // perform specialization of functions based on parameter
- // values that need to be compile-time constants.
- //
- specializeModule(irModule);
-
- // Debugging code for IR transformations...
-#if 0
- dumpIRIfEnabled(compileRequest, irModule, "SPECIALIZED");
-#endif
- validateIRModuleIfEnabled(compileRequest, irModule);
-
-
- // Specialization can introduce dead code that could trip
- // up downstream passes like type legalization, so we
- // will run a DCE pass to clean up after the specialization.
- //
- // TODO: Are there other cleanup optimizations we should
- // apply at this point?
- //
- eliminateDeadCode(compileRequest, irModule);
-#if 0
- dumpIRIfEnabled(compileRequest, irModule, "AFTER DCE");
-#endif
- validateIRModuleIfEnabled(compileRequest, irModule);
-
- // The Slang language allows interfaces to be used like
- // ordinary types (including placing them in constant
- // buffers and entry-point parameter lists), but then
- // getting them to lay out in a reasonable way requires
- // us to treat fields/variables with interface type
- // *as if* they were pointers to heap-allocated "objects."
- //
- // Specialization will have replaced fields/variables
- // with interface types like `IFoo` with fields/variables
- // with pointer-like types like `ExistentialBox<SomeType>`.
- //
- // We need to legalize these pointer-like types away,
- // which involves two main changes:
- //
- // 1. Any `ExistentialBox<...>` fields need to be moved
- // out of their enclosing `struct` type, so that the layout
- // of the enclosing type is computed as if the field had
- // zero size.
- //
- // 2. Once an `ExistentialBox<X>` has been floated out
- // of its parent and landed somwhere permanent (e.g., either
- // a dedicated variable, or a field of constant buffer),
- // we need to replace it with just an `X`, after which we
- // will have (more) legal shader code.
- //
- legalizeExistentialTypeLayout(
- irModule,
- sink);
- eliminateDeadCode(compileRequest, irModule);
-
-#if 0
- dumpIRIfEnabled(compileRequest, irModule, "EXISTENTIALS LEGALIZED");
-#endif
- validateIRModuleIfEnabled(compileRequest, irModule);
-
- // Many of our target languages and/or downstream compilers
- // don't support `struct` types that have resource-type fields.
- // In order to work around this limitation, we will rewrite the
- // IR so that any structure types with resource-type fields get
- // split into a "tuple" that comprises the ordinary fields (still
- // bundles up as a `struct`) and one element for each resource-type
- // field (recursively).
- //
- // What used to be individual variables/parameters/arguments/etc.
- // then become multiple variables/parameters/arguments/etc.
- //
- legalizeResourceTypes(
- irModule,
- sink);
- eliminateDeadCode(compileRequest, irModule);
-
- // Debugging output of legalization
-#if 0
- dumpIRIfEnabled(compileRequest, irModule, "LEGALIZED");
-#endif
- validateIRModuleIfEnabled(compileRequest, irModule);
-
- // Once specialization and type legalization have been performed,
- // we should perform some of our basic optimization steps again,
- // to see if we can clean up any temporaries created by legalization.
- // (e.g., things that used to be aggregated might now be split up,
- // so that we can work with the individual fields).
- constructSSA(irModule);
-
-#if 0
- dumpIRIfEnabled(compileRequest, irModule, "AFTER SSA");
-#endif
- validateIRModuleIfEnabled(compileRequest, irModule);
-
- // After type legalization and subsequent SSA cleanup we expect
- // that any resource types passed to functions are exposed
- // as their own top-level parameters (which might have
- // resource or array-of-...-resource types).
- //
- // Many of our targets place restrictions on how certain
- // resource types can be used, so that having them as
- // function parameters is invalid. To clean this up,
- // we will try to specialize called functions based
- // on the actual resources that are being passed to them
- // at specific call sites.
- //
- // Because the legalization may depend on what target
- // we are compiling for (certain things might be okay
- // for D3D targets that are not okay for Vulkan), we
- // pass down the target request along with the IR.
- //
- specializeResourceParameters(compileRequest, targetRequest, irModule);
-
-#if 0
- dumpIRIfEnabled(compileRequest, irModule, "AFTER RESOURCE SPECIALIZATION");
-#endif
- validateIRModuleIfEnabled(compileRequest, irModule);
-
-
- // For GLSL only, we will need to perform "legalization" of
- // the entry point and any entry-point parameters.
- //
- // TODO: We should consider moving this legalization work
- // as late as possible, so that it doesn't affect how other
- // optimization passes need to work.
- //
- switch (target)
- {
- case CodeGenTarget::GLSL:
- {
- legalizeEntryPointForGLSL(
- session,
- irModule,
- irEntryPoint,
- compileRequest->getSink(),
- &emitContext.extensionUsageTracker);
-
-#if 0
- dumpIRIfEnabled(compileRequest, irModule, "GLSL LEGALIZED");
-#endif
- validateIRModuleIfEnabled(compileRequest, irModule);
- }
- break;
-
- default:
- break;
- }
-
- // The resource-based specialization pass above
- // may create specialized versions of functions, but
- // it does not try to completely eliminate the original
- // functions, so there might still be invalid code in
- // our IR module.
- //
- // To clean up the code, we will apply a fairly general
- // dead-code-elimination (DCE) pass that only retains
- // whatever code is "live."
- //
- eliminateDeadCode(compileRequest, irModule);
-#if 0
- dumpIRIfEnabled(compileRequest, irModule, "AFTER DCE");
-#endif
- validateIRModuleIfEnabled(compileRequest, irModule);
-
- // 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?
- sourceEmitter.emitIRModule(irModule);
- }
-
- // Deal with cases where a particular stage requires certain GLSL versions
- // and/or extensions.
- switch( entryPoint->getStage() )
- {
- default:
- break;
-
- case Stage::AnyHit:
- case Stage::Callable:
- case Stage::ClosestHit:
- case Stage::Intersection:
- case Stage::Miss:
- case Stage::RayGeneration:
- if( target == CodeGenTarget::GLSL )
- {
- emitContext.extensionUsageTracker.requireGLSLExtension("GL_NV_ray_tracing");
- emitContext.extensionUsageTracker.requireGLSLVersion(ProfileVersion::GLSL_460);
- }
- break;
- }
-
- String code = sourceStream.getContent();
- sourceStream.clearContent();
-
- // Now that we've emitted the code for all the declarations in the file,
- // it is time to stitch together the final output.
-
- // There may be global-scope modifiers that we should emit now
- sourceEmitter.emitGLSLPreprocessorDirectives();
-
- sourceEmitter.emitLayoutDirectives(targetRequest);
-
- String prefix = sourceStream.getContent();
-
- StringBuilder finalResultBuilder;
- finalResultBuilder << prefix;
-
- finalResultBuilder << emitContext.extensionUsageTracker.getGLSLExtensionRequireLines();
-
- finalResultBuilder << code;
-
- String finalResult = finalResultBuilder.ProduceString();
-
- return finalResult;
-}
-
-} // namespace Slang