diff options
Diffstat (limited to 'source/slang/emit.cpp')
| -rw-r--r-- | source/slang/emit.cpp | 183 |
1 files changed, 160 insertions, 23 deletions
diff --git a/source/slang/emit.cpp b/source/slang/emit.cpp index 71ee31e5e..c8f3f06cb 100644 --- a/source/slang/emit.cpp +++ b/source/slang/emit.cpp @@ -2,6 +2,7 @@ #include "emit.h" #include "lower.h" +#include "lower-to-ir.h" #include "name.h" #include "syntax.h" #include "type-layout.h" @@ -47,6 +48,9 @@ struct SharedEmitContext // The entry point we are being asked to compile EntryPointRequest* entryPoint; + // The layout for the entry point + EntryPointLayout* entryPointLayout; + // The target language we want to generate code for CodeGenTarget target; @@ -519,7 +523,7 @@ struct EmitVisitor emitRawText("\n#line "); char buffer[16]; - sprintf(buffer, "%d", sourceLocation.line); + sprintf(buffer, "%llu", (unsigned long long)sourceLocation.line); emitRawText(buffer); emitRawText(" "); @@ -679,7 +683,7 @@ struct EmitVisitor // and how we do. if(sourceLocation.column > context->shared->loc.column) { - int delta = sourceLocation.column - context->shared->loc.column; + Slang::Int delta = sourceLocation.column - context->shared->loc.column; for( int ii = 0; ii < delta; ++ii ) { emitRawText(" "); @@ -2282,8 +2286,32 @@ struct EmitVisitor emitName(expr->lookupResult2.getName()); } + void setSampleRateFlag() + { + context->shared->entryPointLayout->flags |= EntryPointLayout::Flag::usesAnySampleRateInput; + } + + void doSampleRateInputCheck(VarDeclBase* decl) + { + if (decl->HasModifier<HLSLSampleModifier>()) + { + setSampleRateFlag(); + } + } + + void doSampleRateInputCheck(Name* name) + { + auto text = getText(name); + if (text == "gl_SampleID") + { + setSampleRateFlag(); + } + } + void visitVarExpr(VarExpr* varExpr, ExprEmitArg const& arg) { + doSampleRateInputCheck(varExpr->name); + auto prec = kEOp_Atomic; auto outerPrec = arg.outerPrec; bool needClose = MaybeEmitParens(outerPrec, kEOp_Atomic); @@ -2484,6 +2512,11 @@ struct EmitVisitor Emit("{\n"); for( auto& token : stmt->tokens ) { + if (token.type == TokenType::Identifier) + { + doSampleRateInputCheck(token.getName()); + } + emitTokenWithLocation(token); } Emit("}\n"); @@ -3559,6 +3592,15 @@ struct EmitVisitor void visitVarDeclBase(RefPtr<VarDeclBase> decl, DeclEmitArg const& arg) { + // Global variable? Check if it is a sample-rate input. + if (dynamic_cast<ModuleDecl*>(decl->ParentDecl)) + { + if (decl->HasModifier<InModifier>()) + { + doSampleRateInputCheck(decl); + } + } + // Skip fields that have been tuple-ified and don't contribute // any fields of "ordinary" type. if (auto tupleFieldMod = decl->FindModifier<TupleFieldModifier>()) @@ -3756,7 +3798,7 @@ struct EmitVisitor void EmitDecl(RefPtr<Decl> decl) { - emitDeclImpl(decl, nullptr); +emitDeclImpl(decl, nullptr); } void EmitDeclUsingLayout(RefPtr<Decl> decl, RefPtr<VarLayout> layout) @@ -3770,9 +3812,9 @@ struct EmitVisitor { EmitDecl(decl); } - else if(auto declGroup = declBase.As<DeclGroup>()) + else if( auto declGroup = declBase.As<DeclGroup>() ) { - for(auto d : declGroup->decls) + for( auto d : declGroup->decls ) EmitDecl(d); } else @@ -3782,6 +3824,29 @@ struct EmitVisitor } }; + +EntryPointLayout* findEntryPointLayout( + ProgramLayout* programLayout, + EntryPointRequest* entryPointRequest) +{ + for( auto entryPointLayout : programLayout->entryPoints ) + { + if(entryPointLayout->entryPoint->getName() != entryPointRequest->name) + continue; + + if(entryPointLayout->profile != entryPointRequest->profile) + continue; + + // TODO: can't easily filter on translation unit here... + // Ideally the `EntryPointRequest` should get filled in with a pointer + // the specific function declaration that represents the entry point. + + return entryPointLayout.Ptr(); + } + + return nullptr; +} + String emitEntryPoint( EntryPointRequest* entryPoint, ProgramLayout* programLayout, @@ -3794,6 +3859,13 @@ String emitEntryPoint( sharedContext.finalTarget = entryPoint->compileRequest->Target; sharedContext.entryPoint = entryPoint; + if (entryPoint) + { + sharedContext.entryPointLayout = findEntryPointLayout( + programLayout, + entryPoint); + } + sharedContext.programLayout = programLayout; // Layout information for the global scope is either an ordinary @@ -3805,7 +3877,7 @@ String emitEntryPoint( { globalStructLayout = gs.Ptr(); } - else if(auto globalConstantBufferLayout = globalScopeLayout.As<ParameterBlockTypeLayout>()) + 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 @@ -3837,32 +3909,97 @@ String emitEntryPoint( } sharedContext.globalStructLayout = globalStructLayout; + auto translationUnitSyntax = translationUnit->SyntaxNode.Ptr(); + EmitContext context; context.shared = &sharedContext; EmitVisitor visitor(&context); - auto translationUnitSyntax = translationUnit->SyntaxNode.Ptr(); - - // 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. + // 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: + // + // 1. "Full rewriter" mode, where the user provides HLSL/GLSL, and + // doesn't make use of any Slang code via `import`. // - // 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()); + // 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. + // + // 3. "Full" mode, where all of the input code is in Slang (and/or + // the subset of HLSL we can fully type-check). + // + // We'll try to detect the cases here: + // +#if 0 + if(!(translationUnit->compileFlags & SLANG_COMPILE_FLAG_NO_CHECKING )) + { + // This seems to be case (3), because the user is asking for full + // checking, and so we can assume we understand the code fully. + // + // In this case we want to translate to our intermediate representation + // and do optimizations/transformations there before we emit final code. + // + + auto lowered = lowerEntryPointToIR(entryPoint, programLayout, target); + + dumpIR(lowered); + + throw 99; + + } + else if(translationUnit->compileRequest->loadedModulesList.Count() != 0) +#else + if(!(translationUnit->compileFlags & SLANG_COMPILE_FLAG_NO_CHECKING ) + || translationUnit->compileRequest->loadedModulesList.Count() != 0) +#endif + { + // 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(); + // Now that we've emitted the code for all the declaratiosn in the file, + // it is time to stich together the final output. + + + // There may be global-scope modifiers that we should emit now visitor.emitGLSLPreprocessorDirectives(translationUnitSyntax); String prefix = sharedContext.sb.ProduceString(); |
