diff options
| author | Tim Foley <tfoley@nvidia.com> | 2017-06-20 08:11:27 -0700 |
|---|---|---|
| committer | Tim Foley <tfoley@nvidia.com> | 2017-06-20 11:54:35 -0700 |
| commit | 327f2b7ec50a7480b458d6d3ba8e2ca7fcdb8498 (patch) | |
| tree | e62d8f184bf04df0906fcc6c8a04803febe35376 | |
| parent | 40617db15d87ece6e7cc88da23f747f8f827c69a (diff) | |
Overhaul handling of entry points and translation units.
The main user-visible change here is that instead of `spAddTranslationUnitEntryPoint` we have `spAddEntryPoint`, to reflect that the list of entry points is "global" to a compile request.
As a result, `spGetEntryPointSource` now only needs the entry point index, and not the translation unit index.
There are a bunch more behind-the-scenes changes, though, reflecting a streamlining of the concepts related to compilation into a smaller number of classes.
Now there is:
- `Session` (unchanged) to manage the lifetimes of shared stuff like the stdlib
- `CompileRequest` (merges in `CompileOptions`) to handle all the lifetime related to a single invocation of the compiler
- `TranslationUnitRequest` (merges `TranslationUnitOptions`, `CompileUnit`) to represent a single translation unit ("module") that the user is trying to compile. This is a single file for HLSL/GLSL, but can be multiple files for Slang.
- `EntryPointRequest` (merges `EntryPointOption` and a bit of `EntryPointResult`) to track a single entry point that the user is asking to compile (that entry point always comes from a single translation unit)
A lot of functions used to take some combination of these and end up with really long signatures.
I've given most of the objects "parent" pointers so that they can get back to all the context they need, so most functions don't need as many parameters.
It may eventually be important to tease these apart again, in particular:
- The code-generation side of things (the `*Result` types) might need to be pulled out in case we want to codegen multiple times from the same AST
- Similarly, the layout stuff may also need to be pulled out, in case we want to lay things out multiple times with different rules.
| -rw-r--r-- | examples/hello/hello.cpp | 4 | ||||
| -rw-r--r-- | slang.h | 3 | ||||
| -rw-r--r-- | source/slang/check.cpp | 29 | ||||
| -rw-r--r-- | source/slang/compiled-program.h | 36 | ||||
| -rw-r--r-- | source/slang/compiler.cpp | 227 | ||||
| -rw-r--r-- | source/slang/compiler.h | 172 | ||||
| -rw-r--r-- | source/slang/options.cpp | 2 | ||||
| -rw-r--r-- | source/slang/parameter-binding.cpp | 40 | ||||
| -rw-r--r-- | source/slang/parameter-binding.h | 6 | ||||
| -rw-r--r-- | source/slang/parser.cpp | 22 | ||||
| -rw-r--r-- | source/slang/parser.h | 4 | ||||
| -rw-r--r-- | source/slang/preprocessor.h | 2 | ||||
| -rw-r--r-- | source/slang/slang.cpp | 769 | ||||
| -rw-r--r-- | source/slang/syntax-visitors.h | 12 | ||||
| -rw-r--r-- | source/slangc/main.cpp | 37 | ||||
| -rw-r--r-- | tools/render-test/render-d3d11.cpp | 4 | ||||
| -rw-r--r-- | tools/render-test/slang-support.cpp | 8 |
17 files changed, 676 insertions, 701 deletions
diff --git a/examples/hello/hello.cpp b/examples/hello/hello.cpp index c9121b790..8e48b3c13 100644 --- a/examples/hello/hello.cpp +++ b/examples/hello/hello.cpp @@ -100,8 +100,8 @@ HRESULT initialize( ID3D11Device* dxDevice ) char const* vertexProfileName = "vs_4_0"; char const* fragmentProfileName = "ps_4_0"; - spAddTranslationUnitEntryPoint(slangRequest, translationUnitIndex, vertexEntryPointName, spFindProfile(slangSession, vertexProfileName)); - spAddTranslationUnitEntryPoint(slangRequest, translationUnitIndex, fragmentEntryPointName, spFindProfile(slangSession, fragmentProfileName)); + spAddEntryPoint(slangRequest, translationUnitIndex, vertexEntryPointName, spFindProfile(slangSession, vertexProfileName)); + spAddEntryPoint(slangRequest, translationUnitIndex, fragmentEntryPointName, spFindProfile(slangSession, fragmentProfileName)); int compileErr = spCompile(slangRequest); if(auto diagnostics = spGetDiagnosticOutput(slangRequest)) @@ -281,7 +281,7 @@ extern "C" /** Add an entry point in a particular translation unit */ - SLANG_API int spAddTranslationUnitEntryPoint( + SLANG_API int spAddEntryPoint( SlangCompileRequest* request, int translationUnitIndex, char const* name, @@ -337,7 +337,6 @@ extern "C" */ SLANG_API char const* spGetEntryPointSource( SlangCompileRequest* request, - int translationUnitIndex, int entryPointIndex); diff --git a/source/slang/check.cpp b/source/slang/check.cpp index f79df0c40..128afcefe 100644 --- a/source/slang/check.cpp +++ b/source/slang/check.cpp @@ -46,27 +46,25 @@ namespace Slang { ProgramSyntaxNode * program = nullptr; FunctionSyntaxNode * function = nullptr; - CompileOptions const* options = nullptr; - TranslationUnitOptions const* translationUnitOptions = nullptr; + CompileRequest* request = nullptr; + TranslationUnitRequest* translationUnit = nullptr; // lexical outer statements List<StatementSyntaxNode*> outerStmts; public: SemanticsVisitor( DiagnosticSink * pErr, - CompileOptions const& options, - TranslationUnitOptions const& translationUnitOptions, - CompileRequest* request) + CompileRequest* request, + TranslationUnitRequest* translationUnit) : SyntaxVisitor(pErr) - , options(&options) - , translationUnitOptions(&translationUnitOptions) , request(request) + , translationUnit(translationUnit) { } - CompileOptions const& getOptions() { return *options; } - TranslationUnitOptions const& getTranslationUnitOptions() { return *translationUnitOptions; } + CompileRequest* getCompileRequest() { return request; } + TranslationUnitRequest* getTranslationUnit() { return translationUnit; } public: // Translate Types @@ -969,7 +967,7 @@ namespace Slang // expressions without a type, and we need to ignore them. if( !fromExpr->Type.type ) { - if(getTranslationUnitOptions().compileFlags & SLANG_COMPILE_FLAG_NO_CHECKING ) + if(getTranslationUnit()->compileFlags & SLANG_COMPILE_FLAG_NO_CHECKING ) return fromExpr; } @@ -981,7 +979,7 @@ namespace Slang fromExpr.Ptr(), nullptr)) { - if(!(getTranslationUnitOptions().compileFlags & SLANG_COMPILE_FLAG_NO_CHECKING)) + if(!(getTranslationUnit()->compileFlags & SLANG_COMPILE_FLAG_NO_CHECKING)) { getSink()->diagnose(fromExpr->Position, Diagnostics::typeMismatch, toType, fromExpr->Type); } @@ -4967,12 +4965,11 @@ namespace Slang }; SyntaxVisitor* CreateSemanticsVisitor( - DiagnosticSink* err, - CompileOptions const& options, - TranslationUnitOptions const& translationUnitOptions, - CompileRequest* request) + DiagnosticSink* err, + CompileRequest* request, + TranslationUnitRequest* translationUnit) { - return new SemanticsVisitor(err, options, translationUnitOptions, request); + return new SemanticsVisitor(err, request, translationUnit); } // diff --git a/source/slang/compiled-program.h b/source/slang/compiled-program.h index 1766127b2..7f5b674a0 100644 --- a/source/slang/compiled-program.h +++ b/source/slang/compiled-program.h @@ -8,42 +8,6 @@ namespace Slang { - void IndentString(StringBuilder & sb, String src); - - struct EntryPointResult - { - String outputSource; - }; - - struct TranslationUnitResult - { - String outputSource; - List<EntryPointResult> entryPoints; - }; - - class CompileResult - { - public: - DiagnosticSink* mSink = nullptr; - - // Per-translation-unit results - List<TranslationUnitResult> translationUnits; - - CompileResult() - {} - ~CompileResult() - { - } - DiagnosticSink * GetErrorWriter() - { - return mSink; - } - int GetErrorCount() - { - return mSink->GetErrorCount(); - } - }; - } #endif
\ No newline at end of file diff --git a/source/slang/compiler.cpp b/source/slang/compiler.cpp index 6db04b900..9132624f9 100644 --- a/source/slang/compiler.cpp +++ b/source/slang/compiler.cpp @@ -32,6 +32,14 @@ namespace Slang { + + // EntryPointRequest + + TranslationUnitRequest* EntryPointRequest::getTranslationUnit() + { + return compileRequest->translationUnits[translationUnitIndex].Ptr(); + } + // Profile Profile::LookUp(char const* name) @@ -47,34 +55,91 @@ namespace Slang // - String EmitHLSL(ExtraContext& context) + String emitHLSLForTranslationUnit( + TranslationUnitRequest* translationUnit) { - if (context.getOptions().passThrough != PassThroughMode::None) + auto compileRequest = translationUnit->compileRequest; + if (compileRequest->passThrough != PassThroughMode::None) { - return context.sourceText; + // Generate a string that includes the content of + // the source file(s), along with a line directive + // to ensure that we get reasonable messages + // from the downstream compiler when in pass-through + // mode. + + StringBuilder codeBuilder; + for(auto sourceFile : translationUnit->sourceFiles) + { + codeBuilder << "#line 1 \""; + for(auto c : sourceFile->path) + { + char buffer[] = { c, 0 }; + switch(c) + { + default: + codeBuilder << buffer; + break; + + case '\\': + codeBuilder << "\\\\"; + } + } + codeBuilder << "\"\n"; + codeBuilder << sourceFile->content << "\n"; + } + + return codeBuilder.ProduceString(); } else { - // TODO(tfoley): probably need a way to customize the emit logic... return emitProgram( - context.programSyntax.Ptr(), - context.programLayout, + translationUnit->SyntaxNode.Ptr(), + compileRequest->layout.Ptr(), CodeGenTarget::HLSL); } } - String emitGLSLForEntryPoint(ExtraContext& context, EntryPointOption const& /*entryPoint*/) + String emitGLSLForEntryPoint( + EntryPointRequest* entryPoint) { - if (context.getOptions().passThrough != PassThroughMode::None) + auto compileRequest = entryPoint->compileRequest; + auto translationUnit = entryPoint->getTranslationUnit(); + + if (compileRequest->passThrough != PassThroughMode::None) { - return context.sourceText; + // Generate a string that includes the content of + // the source file(s), along with a line directive + // to ensure that we get reasonable messages + // from the downstream compiler when in pass-through + // mode. + + StringBuilder codeBuilder; + int translationUnitCounter = 0; + for(auto sourceFile : translationUnit->sourceFiles) + { + int translationUnitIndex = translationUnitCounter++; + + // We want to output `#line` directives, but we need + // to skip this for the first file, since otherwise + // some GLSL implementations will get tripped up by + // not having the `#version` directive be the first + // thing in the file. + if(translationUnitIndex != 0) + { + codeBuilder << "#line 1 " << translationUnitIndex << "\n"; + } + codeBuilder << sourceFile->content << "\n"; + } + + return codeBuilder.ProduceString(); } else { - // TODO(tfoley): probably need a way to customize the emit logic... + // TODO(tfoley): need to pass along the entry point + // so that we properly emit it as the `main` function. return emitProgram( - context.programSyntax.Ptr(), - context.programLayout, + translationUnit->SyntaxNode.Ptr(), + compileRequest->layout.Ptr(), CodeGenTarget::GLSL); } } @@ -103,8 +168,7 @@ namespace Slang } List<uint8_t> EmitDXBytecodeForEntryPoint( - ExtraContext& context, - EntryPointOption const& entryPoint) + EntryPointRequest* entryPoint) { static pD3DCompile D3DCompile_ = nullptr; if (!D3DCompile_) @@ -122,38 +186,20 @@ namespace Slang // // To work around that, we prepend a custom `#line` directive. - String rawHlslCode = EmitHLSL(context); + auto translationUnit = entryPoint->getTranslationUnit(); - StringBuilder hlslCodeBuilder; - hlslCodeBuilder << "#line 1 \""; - for(auto c : context.sourcePath) - { - char buffer[] = { c, 0 }; - switch(c) - { - default: - hlslCodeBuilder << buffer; - break; - - case '\\': - hlslCodeBuilder << "\\\\"; - } - } - hlslCodeBuilder << "\"\n"; - hlslCodeBuilder << rawHlslCode; - - auto hlslCode = hlslCodeBuilder.ProduceString(); + auto hlslCode = emitHLSLForTranslationUnit(translationUnit); ID3DBlob* codeBlob; ID3DBlob* diagnosticsBlob; HRESULT hr = D3DCompile_( hlslCode.begin(), hlslCode.Length(), - context.sourcePath.begin(), + "slang", nullptr, nullptr, - entryPoint.name.begin(), - GetHLSLProfileName(entryPoint.profile), + entryPoint->name.begin(), + GetHLSLProfileName(entryPoint->profile), 0, 0, &codeBlob, @@ -181,6 +227,7 @@ namespace Slang return data; } +#if 0 List<uint8_t> EmitDXBytecode( ExtraContext& context) { @@ -200,10 +247,10 @@ namespace Slang return EmitDXBytecodeForEntryPoint(context, context.getTranslationUnitOptions().entryPoints[0]); } +#endif String EmitDXBytecodeAssemblyForEntryPoint( - ExtraContext& context, - EntryPointOption const& entryPoint) + EntryPointRequest* entryPoint) { static pD3DDisassemble D3DDisassemble_ = nullptr; if (!D3DDisassemble_) @@ -215,7 +262,7 @@ namespace Slang assert(D3DDisassemble_); } - List<uint8_t> dxbc = EmitDXBytecodeForEntryPoint(context, entryPoint); + List<uint8_t> dxbc = EmitDXBytecodeForEntryPoint(entryPoint); if (!dxbc.Count()) { return ""; @@ -242,7 +289,7 @@ namespace Slang return result; } - +#if 0 String EmitDXBytecodeAssembly( ExtraContext& context) { @@ -260,6 +307,7 @@ namespace Slang } return sb.ProduceString(); } +#endif HMODULE getGLSLCompilerDLL() @@ -273,10 +321,9 @@ namespace Slang String emitSPIRVAssemblyForEntryPoint( - ExtraContext& context, - EntryPointOption const& entryPoint) + EntryPointRequest* entryPoint) { - String rawGLSL = emitGLSLForEntryPoint(context, entryPoint); + String rawGLSL = emitGLSLForEntryPoint(entryPoint); static glslang_CompileFunc glslang_compile = nullptr; if (!glslang_compile) @@ -297,9 +344,9 @@ namespace Slang }; glslang_CompileRequest request; - request.sourcePath = context.sourcePath.begin(); + request.sourcePath = "slang"; request.sourceText = rawGLSL.begin(); - request.slangStage = (SlangStage) entryPoint.profile.GetStage(); + request.slangStage = (SlangStage) entryPoint->profile.GetStage(); request.diagnosticFunc = outputFunc; request.diagnosticUserData = &diagnosticBuilder; @@ -323,6 +370,7 @@ namespace Slang } #endif +#if 0 String emitSPIRVAssembly( ExtraContext& context) { @@ -340,24 +388,28 @@ namespace Slang } return sb.ProduceString(); } +#endif // Do emit logic for a single entry point - EntryPointResult emitEntryPoint(ExtraContext& context, EntryPointOption& entryPoint) + EntryPointResult emitEntryPoint( + EntryPointRequest* entryPoint) { EntryPointResult result; - switch (context.getOptions().Target) + auto compileRequest = entryPoint->compileRequest; + + switch (compileRequest->Target) { case CodeGenTarget::GLSL: { - String code = emitGLSLForEntryPoint(context, entryPoint); + String code = emitGLSLForEntryPoint(entryPoint); result.outputSource = code; } break; case CodeGenTarget::DXBytecode: { - auto code = EmitDXBytecodeForEntryPoint(context, entryPoint); + auto code = EmitDXBytecodeForEntryPoint(entryPoint); // TODO(tfoley): Need to figure out an appropriate interface // for returning binary code, in addition to source. @@ -396,14 +448,14 @@ namespace Slang case CodeGenTarget::DXBytecodeAssembly: { - String code = EmitDXBytecodeAssemblyForEntryPoint(context, entryPoint); + String code = EmitDXBytecodeAssemblyForEntryPoint(entryPoint); result.outputSource = code; } break; case CodeGenTarget::SPIRVAssembly: { - String code = emitSPIRVAssemblyForEntryPoint(context, entryPoint); + String code = emitSPIRVAssemblyForEntryPoint(entryPoint); result.outputSource = code; } break; @@ -421,26 +473,28 @@ namespace Slang } - TranslationUnitResult emitTranslationUnitEntryPoints(ExtraContext& context) + TranslationUnitResult emitTranslationUnitEntryPoints( + TranslationUnitRequest* translationUnit) { TranslationUnitResult result; - for (auto& entryPoint : context.getTranslationUnitOptions().entryPoints) + for (auto& entryPoint : translationUnit->entryPoints) { - EntryPointResult entryPointResult = emitEntryPoint(context, entryPoint); + EntryPointResult entryPointResult = emitEntryPoint(entryPoint.Ptr()); - result.entryPoints.Add(entryPointResult); + entryPoint->result = entryPointResult; } // The result for the translation unit will just be the concatenation // of the results for each entry point. This doesn't actually make // much sense, but it is good enough for now. + // + // TODO: Replace this with a packaged JSON and/or binary format. StringBuilder sb; - for (auto& entryPointResult : result.entryPoints) + for (auto& entryPoint : translationUnit->entryPoints) { - sb << entryPointResult.outputSource; + sb << entryPoint->result.outputSource; } - result.outputSource = sb.ProduceString(); return result; @@ -448,26 +502,29 @@ namespace Slang // Do emit logic for an entire translation unit, which might // have zero or more entry points - TranslationUnitResult emitTranslationUnit(ExtraContext& context) + TranslationUnitResult emitTranslationUnit( + TranslationUnitRequest* translationUnit) { + auto compileRequest = translationUnit->compileRequest; + // Most of our code generation targets will require us // to proceed through one entry point at a time, but // in some cases we can emit an entire translation unit // in one go. - switch (context.getOptions().Target) + switch (compileRequest->Target) { default: // The default behavior is going to loop over all the entry // points, and then collect an aggregate result. - return emitTranslationUnitEntryPoints(context); + return emitTranslationUnitEntryPoints(translationUnit); case CodeGenTarget::HLSL: // When targetting HLSL, we can emit the entire translation unit // as a single HLSL program, and include all the entry points. { - String hlsl = EmitHLSL(context); + String hlsl = emitHLSLForTranslationUnit(translationUnit); TranslationUnitResult result; result.outputSource = hlsl; @@ -475,13 +532,12 @@ namespace Slang // Because the user might ask for per-entry-point source, // we will just attach the same string as the result for // each entry point. - for( auto& entryPoint : context.getTranslationUnitOptions().entryPoints ) + for( auto& entryPoint : translationUnit->entryPoints ) { - (void)entryPoint; - EntryPointResult entryPointResult; entryPointResult.outputSource = hlsl; - result.entryPoints.Add(entryPointResult); + + entryPoint->result = entryPointResult; } return result; @@ -490,36 +546,31 @@ namespace Slang } } +#if 0 TranslationUnitResult generateOutput(ExtraContext& context) { TranslationUnitResult result = emitTranslationUnit(context); return result; } +#endif void generateOutput( - ExtraContext& context, - CollectionOfTranslationUnits* collectionOfTranslationUnits) + CompileRequest* compileRequest) { - switch (context.getOptions().Target) + switch (compileRequest->Target) { default: // For most targets, we will do things per-translation-unit - for( auto translationUnit : collectionOfTranslationUnits->translationUnits ) + for( auto translationUnit : compileRequest->translationUnits ) { - ExtraContext innerContext = context; - innerContext.translationUnitOptions = &translationUnit.options; - innerContext.programSyntax = translationUnit.SyntaxNode; - innerContext.sourcePath = "slang"; // don't have this any more! - innerContext.sourceText = ""; - - TranslationUnitResult translationUnitResult = generateOutput(innerContext); - context.compileResult->translationUnits.Add(translationUnitResult); + TranslationUnitResult translationUnitResult = emitTranslationUnit(translationUnit.Ptr()); + translationUnit->result = translationUnitResult; } break; case CodeGenTarget::ReflectionJSON: { - String reflectionJSON = emitReflectionJSON(context.programLayout); + String reflectionJSON = emitReflectionJSON(compileRequest->layout.Ptr()); // HACK(tfoley): just print it out since that is what people probably expect. // TODO: need a way to control where output gets routed across all possible targets. @@ -528,20 +579,4 @@ namespace Slang break; } } - - TranslationUnitResult passThrough( - String const& sourceText, - String const& sourcePath, - const CompileOptions & options, - TranslationUnitOptions const& translationUnitOptions) - { - ExtraContext extra; - extra.options = &options; - extra.translationUnitOptions = &translationUnitOptions; - extra.sourcePath = sourcePath; - extra.sourceText = sourceText; - - return generateOutput(extra); - } - } diff --git a/source/slang/compiler.h b/source/slang/compiler.h index 39c91e21b..36fc5f42f 100644 --- a/source/slang/compiler.h +++ b/source/slang/compiler.h @@ -14,7 +14,7 @@ namespace Slang { struct IncludeHandler; - struct CompileRequest; + class CompileRequest; enum class CompilerMode { @@ -48,11 +48,42 @@ namespace Slang ReflectionJSON = SLANG_REFLECTION_JSON, }; + class CompileRequest; + class TranslationUnitRequest; + + // Result of compiling an entry point + struct EntryPointResult + { + String outputSource; + }; + // Describes an entry point that we've been requested to compile - struct EntryPointOption + class EntryPointRequest : public RefObject { + public: + // The parent compile request + CompileRequest* compileRequest = nullptr; + + // The name of the entry point function (e.g., `main`) String name; + + // The profile that the entry point will be compiled for + // (this is a combination of the target state, and also + // a feature level that sets capabilities) Profile profile; + + // The index of the translation unit (within the parent + // compile request) that the entry point function is + // supposed to be defined in. + int translationUnitIndex; + + // The resulting output for the enry point + // + // TODO: low-level code generation should be a distinct step + EntryPointResult result; + + // The translation unit that this entry point came from + TranslationUnitRequest* getTranslationUnit(); }; enum class PassThroughMode : SlangPassThrough @@ -74,27 +105,49 @@ namespace Slang String content; }; - // Options for a single translation unit being requested by the user - class TranslationUnitOptions + // Result of compiling a translation unit + struct TranslationUnitResult + { + String outputSource; + }; + + // A single translation unit requested to be compiled. + // + class TranslationUnitRequest : public RefObject { public: - SourceLanguage sourceLanguage = SourceLanguage::Unknown; + // The parent compile request + CompileRequest* compileRequest = nullptr; - // All entry points we've been asked to compile for this translation unit - List<EntryPointOption> entryPoints; + // The language in which the source file(s) + // are assumed to be written + SourceLanguage sourceLanguage = SourceLanguage::Unknown; // The source file(s) that will be compiled to form this translation unit + // + // Usually, for HLSL or GLSL there will be only one file. List<RefPtr<SourceFile> > sourceFiles; + // The entry points associated with this translation unit + List<RefPtr<EntryPointRequest> > entryPoints; + // Preprocessor definitions to use for this translation unit only // (whereas the ones on `CompileOptions` will be shared) Dictionary<String, String> preprocessorDefinitions; // Compile flags for this translation unit SlangCompileFlags compileFlags = 0; - }; + // The parsed syntax for the translation unit + RefPtr<ProgramSyntaxNode> SyntaxNode; + // The resulting output for the translation unit + // + // TODO: low-level code generation should be a distinct step + TranslationUnitResult result; + }; + + // A directory to be searched when looking for files (e.g., `#include`) struct SearchDirectory { enum Kind @@ -114,9 +167,14 @@ namespace Slang Kind kind; }; - class CompileOptions + class Session; + + class CompileRequest : public RefObject { public: + // Pointer to parent session + Session* mSession; + // What target language are we compiling to? CodeGenTarget Target = CodeGenTarget::Unknown; @@ -127,7 +185,11 @@ namespace Slang Dictionary<String, String> preprocessorDefinitions; // Translation units we are being asked to compile - List<TranslationUnitOptions> translationUnits; + List<RefPtr<TranslationUnitRequest> > translationUnits; + + // Entry points we've been asked to compile (each + // assocaited with a translation unit). + List<RefPtr<EntryPointRequest> > entryPoints; // The code generation profile we've been asked to use. Profile profile; @@ -137,53 +199,73 @@ namespace Slang // Compile flags to be shared by all translation units SlangCompileFlags compileFlags = 0; - }; - // This is the representation of a given translation unit - class CompileUnit - { - public: - TranslationUnitOptions options; - RefPtr<ProgramSyntaxNode> SyntaxNode; - }; + // Output stuff + DiagnosticSink mSink; + String mDiagnosticOutput; - // TODO: pick an appropriate name for this... - class CollectionOfTranslationUnits : public RefObject - { - public: - List<CompileUnit> translationUnits; + // Files that compilation depended on + List<String> mDependencyFilePaths; - // TODO: this is more output-oriented, but maybe okay to have here... + // The resulting reflection layout information RefPtr<ProgramLayout> layout; - }; - // Context information for code generation - struct ExtraContext - { - CompileOptions const* options = nullptr; - TranslationUnitOptions const* translationUnitOptions = nullptr; + // Modules that have been dynamically loaded via `import` + Dictionary<String, RefPtr<ProgramSyntaxNode>> loadedModules; + + + CompileRequest(Session* session) + : mSession(session) + {} - CompileResult* compileResult = nullptr; + ~CompileRequest() + {} - RefPtr<ProgramSyntaxNode> programSyntax; - ProgramLayout* programLayout; + void parseTranslationUnit( + TranslationUnitRequest* translationUnit); - String sourceText; - String sourcePath; + void CompileRequest::checkTranslationUnit( + TranslationUnitRequest* translationUnit); - CompileOptions const& getOptions() { return *options; } - TranslationUnitOptions const& getTranslationUnitOptions() { return *translationUnitOptions; } - }; + void checkAllTranslationUnits(); + + int executeActionsInner(); + int executeActions(); + + int addTranslationUnit(SourceLanguage language, String const& name); + + void addTranslationUnitSourceString( + int translationUnitIndex, + String const& path, + String const& source); - TranslationUnitResult passThrough( - String const& sourceText, - String const& sourcePath, - const CompileOptions & options, - TranslationUnitOptions const& translationUnitOptions); + void addTranslationUnitSourceFile( + int translationUnitIndex, + String const& path); + + int addEntryPoint( + int translationUnitIndex, + String const& name, + Profile profile); + + RefPtr<ProgramSyntaxNode> loadModule( + String const& name, + String const& path, + String const& source, + CodePosition const& loc); + + String autoImportModule( + String const& path, + String const& source, + CodePosition const& loc); + + RefPtr<ProgramSyntaxNode> findOrImportModule( + String const& name, + CodePosition const& loc); + }; void generateOutput( - ExtraContext& context, - CollectionOfTranslationUnits* collectionOfTranslationUnits); + CompileRequest* compileRequest); } #endif
\ No newline at end of file diff --git a/source/slang/options.cpp b/source/slang/options.cpp index b3f0629c6..81b893d66 100644 --- a/source/slang/options.cpp +++ b/source/slang/options.cpp @@ -520,7 +520,7 @@ struct OptionsParser // Now place all those entry points where they belong for( auto& entryPoint : rawEntryPoints ) { - spAddTranslationUnitEntryPoint( + spAddEntryPoint( compileRequest, entryPoint.translationUnitIndex, entryPoint.name.begin(), diff --git a/source/slang/parameter-binding.cpp b/source/slang/parameter-binding.cpp index 0756eb68c..70cb4e7ba 100644 --- a/source/slang/parameter-binding.cpp +++ b/source/slang/parameter-binding.cpp @@ -941,7 +941,7 @@ static void processEntryPointParameter( static void collectEntryPointParameters( ParameterBindingContext* context, - EntryPointOption const& entryPoint, + EntryPointRequest* entryPoint, ProgramSyntaxNode* translationUnitSyntax) { // First, look for the entry point with the specified name @@ -950,7 +950,7 @@ static void collectEntryPointParameters( buildMemberDictionary(translationUnitSyntax); Decl* entryPointDecl; - if( !translationUnitSyntax->memberDictionary.TryGetValue(entryPoint.name, entryPointDecl) ) + if( !translationUnitSyntax->memberDictionary.TryGetValue(entryPoint->name, entryPointDecl) ) { // No such entry point! return; @@ -970,7 +970,7 @@ static void collectEntryPointParameters( // Create the layout object here auto entryPointLayout = new EntryPointLayout(); - entryPointLayout->profile = entryPoint.profile; + entryPointLayout->profile = entryPoint->profile; entryPointLayout->entryPoint = entryPointFuncDecl; @@ -1043,18 +1043,18 @@ static void collectEntryPointParameters( // inputs and outputs). static Stage inferStageForTranslationUnit( - CompileUnit const& translationUnit) + TranslationUnitRequest* translationUnit) { // In the specific case where we are compiling GLSL input, // and have only a single entry point, use the stage // of the entry point. // // TODO: can we generalize this at all? - if( translationUnit.options.sourceLanguage == SourceLanguage::GLSL ) + if( translationUnit->sourceLanguage == SourceLanguage::GLSL ) { - if( translationUnit.options.entryPoints.Count() == 1 ) + if( translationUnit->entryPoints.Count() == 1 ) { - return translationUnit.options.entryPoints[0].profile.GetStage(); + return translationUnit->entryPoints[0]->profile.GetStage(); } } @@ -1063,36 +1063,36 @@ inferStageForTranslationUnit( static void collectParameters( ParameterBindingContext* inContext, - CollectionOfTranslationUnits* program) + CompileRequest* request) { ParameterBindingContext contextData = *inContext; auto context = &contextData; - for( auto& translationUnit : program->translationUnits ) + for( auto& translationUnit : request->translationUnits ) { - context->stage = inferStageForTranslationUnit(translationUnit); + context->stage = inferStageForTranslationUnit(translationUnit.Ptr()); // First look at global-scope parameters - collectGlobalScopeParameters(context, translationUnit.SyntaxNode.Ptr()); + collectGlobalScopeParameters(context, translationUnit->SyntaxNode.Ptr()); // Next consider parameters for entry points - for( auto& entryPoint : translationUnit.options.entryPoints ) + for( auto& entryPoint : translationUnit->entryPoints ) { - context->stage = entryPoint.profile.GetStage(); - collectEntryPointParameters(context, entryPoint, translationUnit.SyntaxNode.Ptr()); + context->stage = entryPoint->profile.GetStage(); + collectEntryPointParameters(context, entryPoint.Ptr(), translationUnit->SyntaxNode.Ptr()); } } } -void GenerateParameterBindings( - CollectionOfTranslationUnits* program) +void generateParameterBindings( + CompileRequest* request) { // TODO: infer a language or set of language rules to use based on the // source files and entry points given auto language = SourceLanguage::Unknown; - for( auto& translationUnit : program->translationUnits ) + for( auto& translationUnit : request->translationUnits ) { - auto translationUnitLanguage = translationUnit.options.sourceLanguage; + auto translationUnitLanguage = translationUnit->sourceLanguage; if( language == SourceLanguage::Unknown ) { language = translationUnitLanguage; @@ -1129,7 +1129,7 @@ void GenerateParameterBindings( context.layoutRules = sharedContext.defaultLayoutRules; // Walk through AST to discover all the parameters - collectParameters(&context, program); + collectParameters(&context, request); // Now walk through the parameters to generate initial binding information for( auto& parameter : sharedContext.parameters ) @@ -1245,7 +1245,7 @@ void GenerateParameterBindings( // We now have a bunch of layout information, which we should // record into a suitable object that represents the program programLayout->globalScopeLayout = globalScopeLayout; - program->layout = programLayout; + request->layout = programLayout; } } diff --git a/source/slang/parameter-binding.h b/source/slang/parameter-binding.h index 2fff08090..66c8053d3 100644 --- a/source/slang/parameter-binding.h +++ b/source/slang/parameter-binding.h @@ -8,7 +8,7 @@ namespace Slang { -class CollectionOfTranslationUnits; +class CompileRequest; // The parameter-binding interface is responsible for assigning // binding locations/registers to every parameter of a shader @@ -23,8 +23,8 @@ class CollectionOfTranslationUnits; // and attach that information to the syntax nodes // of the program. -void GenerateParameterBindings( - CollectionOfTranslationUnits* program); +void generateParameterBindings( + CompileRequest* compileRequest); } diff --git a/source/slang/parser.cpp b/source/slang/parser.cpp index 75398a40d..5e06aa877 100644 --- a/source/slang/parser.cpp +++ b/source/slang/parser.cpp @@ -32,8 +32,7 @@ namespace Slang class Parser { public: - CompileOptions const& options; - TranslationUnitOptions const& translationUnitOptions; + TranslationUnitRequest* translationUnit; int anonymousCounter = 0; @@ -67,15 +66,11 @@ namespace Slang currentScope = currentScope->parent; } Parser( - CompileOptions const& options, - TranslationUnitOptions const& translationUnitOptions, TokenSpan const& _tokens, DiagnosticSink * sink, String _fileName, RefPtr<Scope> const& outerScope) - : options(options) - , translationUnitOptions(translationUnitOptions) - , tokenReader(_tokens) + : tokenReader(_tokens) , sink(sink) , fileName(_fileName) , outerScope(outerScope) @@ -2500,7 +2495,7 @@ parser->ReadToken(TokenType::Comma); RefPtr<StatementSyntaxNode> Parser::ParseBlockStatement() { - if( translationUnitOptions.compileFlags & SLANG_COMPILE_FLAG_NO_CHECKING ) + if( translationUnit->compileFlags & SLANG_COMPILE_FLAG_NO_CHECKING ) { // We have been asked to parse the input, but not attempt to understand it. @@ -3157,15 +3152,16 @@ parser->ReadToken(TokenType::Comma); // Parse a source file into an existing translation unit void parseSourceFile( - ProgramSyntaxNode* translationUnitSyntax, - CompileOptions const& options, - TranslationUnitOptions const& translationUnitOptions, + TranslationUnitRequest* translationUnit, TokenSpan const& tokens, DiagnosticSink* sink, String const& fileName, RefPtr<Scope> const& outerScope) { - Parser parser(options, translationUnitOptions, tokens, sink, fileName, outerScope); - return parser.parseSourceFile(translationUnitSyntax); + Parser parser(tokens, sink, fileName, outerScope); + + parser.translationUnit = translationUnit; + + return parser.parseSourceFile(translationUnit->SyntaxNode.Ptr()); } } diff --git a/source/slang/parser.h b/source/slang/parser.h index d74a3f5a8..8dfef4c12 100644 --- a/source/slang/parser.h +++ b/source/slang/parser.h @@ -9,9 +9,7 @@ namespace Slang { // Parse a source file into an existing translation unit void parseSourceFile( - ProgramSyntaxNode* translationUnitSyntax, - CompileOptions const& options, - TranslationUnitOptions const& translationUnitOptions, + TranslationUnitRequest* translationUnit, TokenSpan const& tokens, DiagnosticSink* sink, String const& fileName, diff --git a/source/slang/preprocessor.h b/source/slang/preprocessor.h index f16bc3929..0c7848bb4 100644 --- a/source/slang/preprocessor.h +++ b/source/slang/preprocessor.h @@ -7,7 +7,7 @@ namespace Slang { -struct CompileRequest; +class CompileRequest; class DiagnosticSink; class ProgramSyntaxNode; diff --git a/source/slang/slang.cpp b/source/slang/slang.cpp index d86825766..37d72cadc 100644 --- a/source/slang/slang.cpp +++ b/source/slang/slang.cpp @@ -79,66 +79,50 @@ public: ExpressionType::Finalize(); } - CompileUnit createPredefUnit() - { - CompileUnit translationUnit; - - - RefPtr<ProgramSyntaxNode> translationUnitSyntax = new ProgramSyntaxNode(); - - TranslationUnitOptions translationUnitOptions; - translationUnit.options = translationUnitOptions; - translationUnit.SyntaxNode = translationUnitSyntax; - - return translationUnit; - } - void addBuiltinSource( RefPtr<Scope> const& scope, String const& path, String const& source); }; -struct CompileRequest +struct IncludeHandlerImpl : IncludeHandler { - // Pointer to parent session - Session* mSession; - - // Input options - CompileOptions Options; - - // Output stuff - DiagnosticSink mSink; - String mDiagnosticOutput; - - RefPtr<CollectionOfTranslationUnits> mCollectionOfTranslationUnits; - - RefPtr<ProgramLayout> mReflectionData; + CompileRequest* request; - CompileResult mResult; + virtual IncludeResult TryToFindIncludeFile( + String const& pathToInclude, + String const& pathIncludedFrom, + String* outFoundPath, + String* outFoundSource) override + { + String path = Path::Combine(Path::GetDirectoryName(pathIncludedFrom), pathToInclude); + if (File::Exists(path)) + { + *outFoundPath = path; + *outFoundSource = File::ReadAllText(path); - List<String> mDependencyFilePaths; + request->mDependencyFilePaths.Add(path); - CompileRequest(Session* session) - : mSession(session) - {} + // HACK(tfoley): We might have found the file in the same directory, + // but what if this is also inside an auto-import path? + for (auto & dir : request->searchDirectories) + { + // Only consider auto-import paths + if(dir.kind != SearchDirectory::Kind::AutoImport) + continue; - ~CompileRequest() - {} + String otherPath = Path::Combine(dir.path, pathToInclude); - struct IncludeHandlerImpl : IncludeHandler - { - CompileRequest* request; + if(otherPath == path) + return IncludeResult::FoundAutoImportFile; + } - List<SearchDirectory> searchDirs; + return IncludeResult::FoundIncludeFile; + } - virtual IncludeResult TryToFindIncludeFile( - String const& pathToInclude, - String const& pathIncludedFrom, - String* outFoundPath, - String* outFoundSource) override + for (auto & dir : request->searchDirectories) { - String path = Path::Combine(Path::GetDirectoryName(pathIncludedFrom), pathToInclude); + path = Path::Combine(dir.path, pathToInclude); if (File::Exists(path)) { *outFoundPath = path; @@ -146,464 +130,381 @@ struct CompileRequest request->mDependencyFilePaths.Add(path); - // HACK(tfoley): We might have found the file in the same directory, - // but what if this is also inside an auto-import path? - for (auto & dir : searchDirs) - { - // Only consider auto-import paths - if(dir.kind != SearchDirectory::Kind::AutoImport) - continue; - - String otherPath = Path::Combine(dir.path, pathToInclude); - - if(otherPath == path) - return IncludeResult::FoundAutoImportFile; - } - - return IncludeResult::FoundIncludeFile; - } - - for (auto & dir : searchDirs) - { - path = Path::Combine(dir.path, pathToInclude); - if (File::Exists(path)) + switch( dir.kind ) { - *outFoundPath = path; - *outFoundSource = File::ReadAllText(path); - - request->mDependencyFilePaths.Add(path); + case SearchDirectory::Kind::Default: + return IncludeResult::FoundIncludeFile; - switch( dir.kind ) - { - case SearchDirectory::Kind::Default: - return IncludeResult::FoundIncludeFile; - - case SearchDirectory::Kind::AutoImport: - return IncludeResult::FoundAutoImportFile; - } + case SearchDirectory::Kind::AutoImport: + return IncludeResult::FoundAutoImportFile; } } - return IncludeResult::NotFound; - } - }; - - - CompileUnit parseTranslationUnit( - TranslationUnitOptions const& translationUnitOptions, - CompileOptions& options) - { - IncludeHandlerImpl includeHandler; - includeHandler.request = this; - - CompileUnit translationUnit; - - RefPtr<Scope> languageScope; - switch (translationUnitOptions.sourceLanguage) - { - case SourceLanguage::HLSL: - languageScope = mSession->hlslLanguageScope; - break; - - case SourceLanguage::GLSL: - languageScope = mSession->glslLanguageScope; - break; - - case SourceLanguage::Slang: - default: - languageScope = mSession->slangLanguageScope; - break; - } - - Dictionary<String, String> preprocessorDefinitions; - for(auto& def : options.preprocessorDefinitions) - preprocessorDefinitions.Add(def.Key, def.Value); - for(auto& def : translationUnitOptions.preprocessorDefinitions) - preprocessorDefinitions.Add(def.Key, def.Value); - - RefPtr<ProgramSyntaxNode> translationUnitSyntax = new ProgramSyntaxNode(); - - for (auto sourceFile : translationUnitOptions.sourceFiles) - { - auto sourceFilePath = sourceFile->path; - - auto searchDirs = options.searchDirectories; - searchDirs.Reverse(); - searchDirs.Add(SearchDirectory(Path::GetDirectoryName(sourceFilePath), SearchDirectory::Kind::Default)); - searchDirs.Reverse(); - includeHandler.searchDirs = searchDirs; - - String source = sourceFile->content; - - auto tokens = preprocessSource( - source, - sourceFilePath, - mResult.GetErrorWriter(), - &includeHandler, - preprocessorDefinitions, - translationUnitSyntax.Ptr(), - this); - - parseSourceFile( - translationUnitSyntax.Ptr(), - options, - translationUnitOptions, - tokens, - mResult.GetErrorWriter(), - sourceFilePath, - languageScope); } + return IncludeResult::NotFound; + } +}; - translationUnit.options = translationUnitOptions; - translationUnit.SyntaxNode = translationUnitSyntax; - return translationUnit; - } +void CompileRequest::parseTranslationUnit( + TranslationUnitRequest* translationUnit) +{ + IncludeHandlerImpl includeHandler; + includeHandler.request = this; - CompileUnit parseTranslationUnit( - TranslationUnitOptions const& translationUnitOptions) + RefPtr<Scope> languageScope; + switch (translationUnit->sourceLanguage) { - return parseTranslationUnit(translationUnitOptions, Options); + case SourceLanguage::HLSL: + languageScope = mSession->hlslLanguageScope; + break; + + case SourceLanguage::GLSL: + languageScope = mSession->glslLanguageScope; + break; + + case SourceLanguage::Slang: + default: + languageScope = mSession->slangLanguageScope; + break; } - void checkTranslationUnit( - CompileUnit& translationUnit, - RefPtr<SyntaxVisitor> visitor) - { - visitor->setSourceLanguage(translationUnit.options.sourceLanguage); - translationUnit.SyntaxNode->Accept(visitor.Ptr()); - } + Dictionary<String, String> combinedPreprocessorDefinitions; + for(auto& def : preprocessorDefinitions) + combinedPreprocessorDefinitions.Add(def.Key, def.Value); + for(auto& def : translationUnit->preprocessorDefinitions) + combinedPreprocessorDefinitions.Add(def.Key, def.Value); + + RefPtr<ProgramSyntaxNode> translationUnitSyntax = new ProgramSyntaxNode(); + translationUnit->SyntaxNode = translationUnitSyntax; - void checkTranslationUnit( - CompileUnit& translationUnit, - CompileOptions& options) + for (auto sourceFile : translationUnit->sourceFiles) { - RefPtr<SyntaxVisitor> visitor = CreateSemanticsVisitor( - mResult.GetErrorWriter(), - options, - translationUnit.options, + auto sourceFilePath = sourceFile->path; + String source = sourceFile->content; + + auto tokens = preprocessSource( + source, + sourceFilePath, + &mSink, + &includeHandler, + combinedPreprocessorDefinitions, + translationUnitSyntax.Ptr(), this); - checkTranslationUnit(translationUnit, visitor); + parseSourceFile( + translationUnit, + tokens, + &mSink, + sourceFilePath, + languageScope); } +} + +void CompileRequest::checkTranslationUnit( + TranslationUnitRequest* translationUnit) +{ + RefPtr<SyntaxVisitor> visitor = CreateSemanticsVisitor( + &mSink, + this, + translationUnit); - void checkCollectionOfTranslationUnits( - RefPtr<CollectionOfTranslationUnits> collectionOfTranslationUnits) + visitor->setSourceLanguage(translationUnit->sourceLanguage); + translationUnit->SyntaxNode->Accept(visitor.Ptr()); +} + +void CompileRequest::checkAllTranslationUnits() +{ + for( auto& translationUnit : translationUnits ) { - for( auto& translationUnit : collectionOfTranslationUnits->translationUnits ) - { - checkTranslationUnit(translationUnit, Options); - } + checkTranslationUnit(translationUnit.Ptr()); } +} - void generateOutputForCollectionOfTranslationUnits( - RefPtr<CollectionOfTranslationUnits> collectionOfTranslationUnits) +int CompileRequest::executeActionsInner() +{ + // Do some cleanup on settings specified by user. + // In particular, we want to propagate flags from the overall request down to + // each translation unit. + for( auto& translationUnit : translationUnits ) { - // Do binding generation, and then reflection (globally) - // before we move on to any code-generation activites. - GenerateParameterBindings(collectionOfTranslationUnits.Ptr()); - - - // HACK(tfoley): for right now I just want to pretty-print an AST - // into another language, so the whole compiler back-end is just - // getting in the way. - // - // I'm going to bypass it for now and see what I can do: - - ExtraContext extra; - extra.options = &Options; - extra.programLayout = collectionOfTranslationUnits->layout.Ptr(); - extra.compileResult = &mResult; + translationUnit->compileFlags |= compileFlags; - generateOutput(extra, collectionOfTranslationUnits.Ptr()); + // However, the "no checking" flag shouldn't be applied to + // any translation unit that is native Slang code. + if( translationUnit->sourceLanguage == SourceLanguage::Slang ) + { + translationUnit->compileFlags &= ~SLANG_COMPILE_FLAG_NO_CHECKING; + } } - int executeCompilerDriverActions() +#if 0 + // If we are being asked to do pass-through, then we need to do that here... + if (passThrough != PassThroughMode::None) { - // Do some cleanup on settings specified by user. - // In particular, we want to propagate flags from the overall request down to - // each translation unit. - for( auto& translationUnitOptions : Options.translationUnits ) + for (auto& translationUnitOptions : Options.translationUnits) { - translationUnitOptions.compileFlags |= Options.compileFlags; - - // However, the "no checking" flag shouldn't be applied to - // any translation unit that is native Slang code. - if( translationUnitOptions.sourceLanguage == SourceLanguage::Slang ) + switch (translationUnitOptions.sourceLanguage) { - translationUnitOptions.compileFlags &= SLANG_COMPILE_FLAG_NO_CHECKING; + // We can pass-through code written in a native shading language + case SourceLanguage::GLSL: + case SourceLanguage::HLSL: + break; + + // All other translation units need to be skipped + default: + continue; } - } - // If we are being asked to do pass-through, then we need to do that here... - if (Options.passThrough != PassThroughMode::None) - { - for (auto& translationUnitOptions : Options.translationUnits) - { - switch (translationUnitOptions.sourceLanguage) - { - // We can pass-through code written in a native shading language - case SourceLanguage::GLSL: - case SourceLanguage::HLSL: - break; - - // All other translation units need to be skipped - default: - continue; - } - - auto sourceFile = translationUnitOptions.sourceFiles[0]; - auto sourceFilePath = sourceFile->path; - String source = sourceFile->content; + auto sourceFile = translationUnitOptions.sourceFiles[0]; + auto sourceFilePath = sourceFile->path; + String source = sourceFile->content; - auto translationUnitResult = passThrough( - source, - sourceFilePath, - Options, - translationUnitOptions); + auto translationUnitResult = passThrough( + source, + sourceFilePath, + Options, + translationUnitOptions); - mResult.translationUnits.Add(translationUnitResult); - } - return 0; + mResult.translationUnits.Add(translationUnitResult); } + return 0; + } +#endif - // TODO: load the stdlib - - mCollectionOfTranslationUnits = new CollectionOfTranslationUnits(); - + // We only do parsing and semantic checking if we *aren't* doing + // a pass-through compilation. + // + // Note that we *do* perform output generation as normal in pass-through mode. + if( passThrough == PassThroughMode::None ) + { // Parse everything from the input files requested - // - // TODO: this may trigger the loading and/or compilation of additional modules. - for (auto& translationUnitOptions : Options.translationUnits) + for (auto& translationUnit : translationUnits) { - auto translationUnit = parseTranslationUnit(translationUnitOptions); - mCollectionOfTranslationUnits->translationUnits.Add(translationUnit); + parseTranslationUnit(translationUnit.Ptr()); } - if (mResult.GetErrorCount() != 0) + if (mSink.GetErrorCount() != 0) return 1; // Perform semantic checking on the whole collection - checkCollectionOfTranslationUnits(mCollectionOfTranslationUnits); - if (mResult.GetErrorCount() != 0) + checkAllTranslationUnits(); + if (mSink.GetErrorCount() != 0) return 1; - // Generate output code, in whatever format was requested - generateOutputForCollectionOfTranslationUnits(mCollectionOfTranslationUnits); - if (mResult.GetErrorCount() != 0) + // Now do shader parameter binding generation, which + // needs to be performed globally. + generateParameterBindings(this); + if (mSink.GetErrorCount() != 0) return 1; + } - // Extract the reflection layout information so that users - // can easily query it. - mReflectionData = mCollectionOfTranslationUnits->layout; + // Generate output code, in whatever format was requested + generateOutput(this); + if (mSink.GetErrorCount() != 0) + return 1; - return 0; - } + return 0; +} - // Act as expected of the API-based compiler - int executeAPIActions() - { - mResult.mSink = &mSink; +// Act as expected of the API-based compiler +int CompileRequest::executeActions() +{ + int err = executeActionsInner(); - int err = executeCompilerDriverActions(); + mDiagnosticOutput = mSink.outputBuffer.ProduceString(); - mDiagnosticOutput = mSink.outputBuffer.ProduceString(); + return err; +} - if (mSink.GetErrorCount() != 0) - return mSink.GetErrorCount(); +int CompileRequest::addTranslationUnit(SourceLanguage language, String const& name) +{ + int result = translationUnits.Count(); - return err; - } + RefPtr<TranslationUnitRequest> translationUnit = new TranslationUnitRequest(); + translationUnit->compileRequest = this; + translationUnit->sourceLanguage = SourceLanguage(language); - int addTranslationUnit(SourceLanguage language, String const& name) - { - int result = Options.translationUnits.Count(); + translationUnits.Add(translationUnit); - TranslationUnitOptions translationUnit; - translationUnit.sourceLanguage = SourceLanguage(language); + return result; +} - Options.translationUnits.Add(translationUnit); +void CompileRequest::addTranslationUnitSourceString( + int translationUnitIndex, + String const& path, + String const& source) +{ + RefPtr<SourceFile> sourceFile = new SourceFile(); + sourceFile->path = path; + sourceFile->content = source; - return result; - } + translationUnits[translationUnitIndex]->sourceFiles.Add(sourceFile); +} - void addTranslationUnitSourceString( - int translationUnitIndex, - String const& path, - String const& source) +void CompileRequest::addTranslationUnitSourceFile( + int translationUnitIndex, + String const& path) +{ + String source; + try { - RefPtr<SourceFile> sourceFile = new SourceFile(); - sourceFile->path = path; - sourceFile->content = source; - - Options.translationUnits[translationUnitIndex].sourceFiles.Add(sourceFile); + source = File::ReadAllText(path); } - - void addTranslationUnitSourceFile( - int translationUnitIndex, - String const& path) + catch (...) { - String source; - try - { - source = File::ReadAllText(path); - } - catch (...) - { - // Emit a diagnostic! - mSink.diagnose( - CodePosition(0, 0, 0, path), - Diagnostics::cannotOpenFile, - path); - return; - } + // Emit a diagnostic! + mSink.diagnose( + CodePosition(0, 0, 0, path), + Diagnostics::cannotOpenFile, + path); + return; + } - addTranslationUnitSourceString( - translationUnitIndex, - path, - source); + addTranslationUnitSourceString( + translationUnitIndex, + path, + source); - mDependencyFilePaths.Add(path); - } + mDependencyFilePaths.Add(path); +} - int addTranslationUnitEntryPoint( - int translationUnitIndex, - String const& name, - Profile profile) - { - EntryPointOption entryPoint; - entryPoint.name = name; - entryPoint.profile = profile; +int CompileRequest::addEntryPoint( + int translationUnitIndex, + String const& name, + Profile profile) +{ + RefPtr<EntryPointRequest> entryPoint = new EntryPointRequest(); + entryPoint->compileRequest = this; + entryPoint->name = name; + entryPoint->profile = profile; + entryPoint->translationUnitIndex = translationUnitIndex; - // TODO: realistically want this to be global across all TUs... - int result = Options.translationUnits[translationUnitIndex].entryPoints.Count(); + auto translationUnit = translationUnits[translationUnitIndex].Ptr(); + translationUnit->entryPoints.Add(entryPoint); - Options.translationUnits[translationUnitIndex].entryPoints.Add(entryPoint); - return result; - } + int result = entryPoints.Count(); + entryPoints.Add(entryPoint); + return result; +} - Dictionary<String, RefPtr<ProgramSyntaxNode>> loadedModules; +RefPtr<ProgramSyntaxNode> CompileRequest::loadModule( + String const& name, + String const& path, + String const& source, + CodePosition const& loc) +{ + RefPtr<TranslationUnitRequest> translationUnit = new TranslationUnitRequest(); + translationUnit->compileRequest = this; - RefPtr<ProgramSyntaxNode> loadModule( - String const& name, - String const& path, - String const& source, - CodePosition const& loc) - { - // now we need to try compiling it, etc. + // We don't want to use the same options that the user specified + // for loading modules on-demand. In particular, we always want + // semantic checking to be enabled. + // + // TODO: decide which options, if any, should be inherited. - // We don't want to use the same options that the user specified - // for loading modules on-demand. In particular, we always want - // semantic checking to be enabled. - CompileOptions moduleOptions; - moduleOptions.searchDirectories = Options.searchDirectories; - moduleOptions.profile = Options.profile; + RefPtr<SourceFile> sourceFile = new SourceFile(); + sourceFile->path = path; + sourceFile->content = source; - RefPtr<SourceFile> sourceFile = new SourceFile(); - sourceFile->path = path; - sourceFile->content = source; + translationUnit->sourceFiles.Add(sourceFile); - TranslationUnitOptions translationUnitOptions; - translationUnitOptions.sourceFiles.Add(sourceFile); + parseTranslationUnit(translationUnit.Ptr()); - CompileUnit translationUnit = parseTranslationUnit(translationUnitOptions, moduleOptions); + // TODO: handle errors - // TODO: handle errors + checkTranslationUnit(translationUnit.Ptr()); - checkTranslationUnit(translationUnit, moduleOptions); + // Skip code generation - // Skip code generation + // - // + RefPtr<ProgramSyntaxNode> moduleDecl = translationUnit->SyntaxNode; - RefPtr<ProgramSyntaxNode> moduleDecl = translationUnit.SyntaxNode; + loadedModules.Add(name, moduleDecl); - loadedModules.Add(name, moduleDecl); + return moduleDecl; - return moduleDecl; +} - } +String CompileRequest::autoImportModule( + String const& path, + String const& source, + CodePosition const& loc) +{ + // TODO: may want to have some kind of canonicalization step here + String name = path; - String autoImportModule( - String const& path, - String const& source, - CodePosition const& loc) - { - // TODO: may want to have some kind of canonicalization step here - String name = path; + // Have we already loaded a module matching this name? + if (loadedModules.TryGetValue(name)) + return name; + + loadModule(name, path, source, loc); - // Have we already loaded a module matching this name? - if (loadedModules.TryGetValue(name)) - return name; + return name; +} - loadModule(name, path, source, loc); +RefPtr<ProgramSyntaxNode> CompileRequest::findOrImportModule( + String const& name, + CodePosition const& loc) +{ + // Have we already loaded a module matching this name? + // If so, return it. + RefPtr<ProgramSyntaxNode> moduleDecl; + if (loadedModules.TryGetValue(name, moduleDecl)) + return moduleDecl; - return name; - } + // Derive a file name for the module, by taking the given + // identifier, replacing all occurences of `_` with `-`, + // and then appending `.slang`. + // + // For example, `foo_bar` becomes `foo-bar.slang`. - RefPtr<ProgramSyntaxNode> findOrImportModule( - String const& name, - CodePosition const& loc) + StringBuilder sb; + for (auto c : name) { - // Have we already loaded a module matching this name? - // If so, return it. - RefPtr<ProgramSyntaxNode> moduleDecl; - if (loadedModules.TryGetValue(name, moduleDecl)) - return moduleDecl; - - // Derive a file name for the module, by taking the given - // identifier, replacing all occurences of `_` with `-`, - // and then appending `.slang`. - // - // For example, `foo_bar` becomes `foo-bar.slang`. + if (c == '_') + c = '-'; - StringBuilder sb; - for (auto c : name) - { - if (c == '_') - c = '-'; - - sb.Append(c); - } - sb.Append(".slang"); + sb.Append(c); + } + sb.Append(".slang"); - String fileName = sb.ProduceString(); + String fileName = sb.ProduceString(); - // Next, try to find the file of the given name, - // using our ordinary include-handling logic. + // Next, try to find the file of the given name, + // using our ordinary include-handling logic. - IncludeHandlerImpl includeHandler; - includeHandler.request = this; + IncludeHandlerImpl includeHandler; + includeHandler.request = this; - String pathIncludedFrom = loc.FileName; + String pathIncludedFrom = loc.FileName; - String foundPath; - String foundSource; - IncludeResult includeResult = includeHandler.TryToFindIncludeFile(fileName, pathIncludedFrom, &foundPath, &foundSource); - switch( includeResult ) + String foundPath; + String foundSource; + IncludeResult includeResult = includeHandler.TryToFindIncludeFile(fileName, pathIncludedFrom, &foundPath, &foundSource); + switch( includeResult ) + { + case IncludeResult::NotFound: + case IncludeResult::Error: { - case IncludeResult::NotFound: - case IncludeResult::Error: - { - this->mSink.diagnose(loc, Diagnostics::cannotFindFile, fileName); - - loadedModules[name] = nullptr; - return nullptr; - } - break; + this->mSink.diagnose(loc, Diagnostics::cannotFindFile, fileName); - default: - break; + loadedModules[name] = nullptr; + return nullptr; } + break; - // We've found a file that we can load for the given module, so - // go ahead and perform the module-load action - return loadModule( - name, - foundPath, - foundSource, - loc); + default: + break; } -}; + // We've found a file that we can load for the given module, so + // go ahead and perform the module-load action + return loadModule( + name, + foundPath, + foundSource, + loc); +} RefPtr<ProgramSyntaxNode> findOrImportModule( CompileRequest* request, @@ -627,29 +528,29 @@ void Session::addBuiltinSource( String const& path, String const& source) { - CompileRequest compileRequest(this); + RefPtr<CompileRequest> compileRequest = new CompileRequest(this); - auto translationUnitIndex = compileRequest.addTranslationUnit(SourceLanguage::Slang, path); + auto translationUnitIndex = compileRequest->addTranslationUnit(SourceLanguage::Slang, path); - compileRequest.addTranslationUnitSourceString( + compileRequest->addTranslationUnitSourceString( translationUnitIndex, path, source); - int err = compileRequest.executeAPIActions(); + int err = compileRequest->executeActions(); if (err) { - fprintf(stderr, "%s", compileRequest.mDiagnosticOutput.Buffer()); + fprintf(stderr, "%s", compileRequest->mDiagnosticOutput.Buffer()); #ifdef _WIN32 - OutputDebugStringA(compileRequest.mDiagnosticOutput.Buffer()); + OutputDebugStringA(compileRequest->mDiagnosticOutput.Buffer()); #endif assert(!"error in stdlib"); } // Extract the AST for the code we just parsed - auto syntax = compileRequest.mCollectionOfTranslationUnits->translationUnits[translationUnitIndex].SyntaxNode; + auto syntax = compileRequest->translationUnits[translationUnitIndex]->SyntaxNode; // HACK(tfoley): mark all declarations in the "stdlib" so // that we can detect them later (e.g., so we don't emit them) @@ -739,21 +640,21 @@ SLANG_API void spSetCompileFlags( SlangCompileRequest* request, SlangCompileFlags flags) { - REQ(request)->Options.compileFlags = flags; + REQ(request)->compileFlags = flags; } SLANG_API void spSetCodeGenTarget( SlangCompileRequest* request, int target) { - REQ(request)->Options.Target = (Slang::CodeGenTarget)target; + REQ(request)->Target = (Slang::CodeGenTarget)target; } SLANG_API void spSetPassThrough( SlangCompileRequest* request, SlangPassThrough passThrough) { - REQ(request)->Options.passThrough = Slang::PassThroughMode(passThrough); + REQ(request)->passThrough = Slang::PassThroughMode(passThrough); } SLANG_API void spSetDiagnosticCallback( @@ -772,14 +673,14 @@ SLANG_API void spAddSearchPath( SlangCompileRequest* request, const char* path) { - REQ(request)->Options.searchDirectories.Add(Slang::SearchDirectory(path, Slang::SearchDirectory::Kind::Default)); + REQ(request)->searchDirectories.Add(Slang::SearchDirectory(path, Slang::SearchDirectory::Kind::Default)); } SLANG_API void spAddAutoImportPath( SlangCompileRequest* request, const char* path) { - REQ(request)->Options.searchDirectories.Add(Slang::SearchDirectory(path, Slang::SearchDirectory::Kind::AutoImport)); + REQ(request)->searchDirectories.Add(Slang::SearchDirectory(path, Slang::SearchDirectory::Kind::AutoImport)); } SLANG_API void spAddPreprocessorDefine( @@ -787,7 +688,7 @@ SLANG_API void spAddPreprocessorDefine( const char* key, const char* value) { - REQ(request)->Options.preprocessorDefinitions[key] = value; + REQ(request)->preprocessorDefinitions[key] = value; } SLANG_API char const* spGetDiagnosticOutput( @@ -820,7 +721,7 @@ SLANG_API void spTranslationUnit_addPreprocessorDefine( { auto req = REQ(request); - req->Options.translationUnits[translationUnitIndex].preprocessorDefinitions[key] = value; + req->translationUnits[translationUnitIndex]->preprocessorDefinitions[key] = value; } @@ -833,7 +734,7 @@ SLANG_API void spAddTranslationUnitSourceFile( auto req = REQ(request); if(!path) return; if(translationUnitIndex < 0) return; - if(translationUnitIndex >= req->Options.translationUnits.Count()) return; + if(translationUnitIndex >= req->translationUnits.Count()) return; req->addTranslationUnitSourceFile( translationUnitIndex, @@ -851,7 +752,7 @@ SLANG_API void spAddTranslationUnitSourceString( auto req = REQ(request); if(!source) return; if(translationUnitIndex < 0) return; - if(translationUnitIndex >= req->Options.translationUnits.Count()) return; + if(translationUnitIndex >= req->translationUnits.Count()) return; if(!path) path = ""; @@ -869,7 +770,7 @@ SLANG_API SlangProfileID spFindProfile( return Slang::Profile::LookUp(name).raw; } -SLANG_API int spAddTranslationUnitEntryPoint( +SLANG_API int spAddEntryPoint( SlangCompileRequest* request, int translationUnitIndex, char const* name, @@ -879,10 +780,9 @@ SLANG_API int spAddTranslationUnitEntryPoint( auto req = REQ(request); if(!name) return -1; if(translationUnitIndex < 0) return -1; - if(translationUnitIndex >= req->Options.translationUnits.Count()) return -1; + if(translationUnitIndex >= req->translationUnits.Count()) return -1; - - return req->addTranslationUnitEntryPoint( + return req->addEntryPoint( translationUnitIndex, name, Slang::Profile(Slang::Profile::RawVal(profile))); @@ -895,7 +795,7 @@ SLANG_API int spCompile( { auto req = REQ(request); - int anyErrors = req->executeAPIActions(); + int anyErrors = req->executeActions(); return anyErrors; } @@ -925,7 +825,7 @@ spGetTranslationUnitCount( SlangCompileRequest* request) { auto req = REQ(request); - return req->mResult.translationUnits.Count(); + return req->translationUnits.Count(); } // Get the output code associated with a specific translation unit @@ -934,16 +834,15 @@ SLANG_API char const* spGetTranslationUnitSource( int translationUnitIndex) { auto req = REQ(request); - return req->mResult.translationUnits[translationUnitIndex].outputSource.Buffer(); + return req->translationUnits[translationUnitIndex]->result.outputSource.Buffer(); } SLANG_API char const* spGetEntryPointSource( SlangCompileRequest* request, - int translationUnitIndex, int entryPointIndex) { auto req = REQ(request); - return req->mResult.translationUnits[translationUnitIndex].entryPoints[entryPointIndex].outputSource.Buffer(); + return req->entryPoints[entryPointIndex]->result.outputSource.Buffer(); } @@ -955,7 +854,7 @@ SLANG_API SlangReflection* spGetReflection( if( !request ) return 0; auto req = REQ(request); - return (SlangReflection*) req->mReflectionData.Ptr(); + return (SlangReflection*) req->layout.Ptr(); } diff --git a/source/slang/syntax-visitors.h b/source/slang/syntax-visitors.h index dbcbf2781..5d712b671 100644 --- a/source/slang/syntax-visitors.h +++ b/source/slang/syntax-visitors.h @@ -7,18 +7,16 @@ namespace Slang { - class CompileOptions; - struct CompileRequest; + class CompileRequest; class ShaderCompiler; class ShaderLinkInfo; class ShaderSymbol; - class TranslationUnitOptions; + class TranslationUnitRequest; SyntaxVisitor* CreateSemanticsVisitor( - DiagnosticSink* err, - CompileOptions const& options, - TranslationUnitOptions const& translationUnitOptions, - CompileRequest* request); + DiagnosticSink* err, + CompileRequest* request, + TranslationUnitRequest* translationUnit); // Look for a module that matches the given name: // either one we've loaded already, or one we diff --git a/source/slangc/main.cpp b/source/slangc/main.cpp index 06f004531..4a783a17c 100644 --- a/source/slangc/main.cpp +++ b/source/slangc/main.cpp @@ -12,7 +12,7 @@ using namespace Slang; static void diagnosticCallback( char const* message, - void* userData) + void* /*userData*/) { fputs(message, stderr); fflush(stderr); @@ -89,29 +89,36 @@ int MAIN(int argc, char** argv) } #endif -#ifdef _MSC_VER - _CrtDumpMemoryLeaks(); -#endif return 0; } #ifdef _WIN32 int wmain(int argc, wchar_t** argv) { - // Conver the wide-character Unicode arguments to UTF-8, - // since that is what Slang expects on the API side. + int result = 0; - List<String> args; - for(int ii = 0; ii < argc; ++ii) - { - args.Add(String::FromWString(argv[ii])); - } - List<char const*> argBuffers; - for(int ii = 0; ii < argc; ++ii) { - argBuffers.Add(args[ii].Buffer()); + // Conver the wide-character Unicode arguments to UTF-8, + // since that is what Slang expects on the API side. + + List<String> args; + for(int ii = 0; ii < argc; ++ii) + { + args.Add(String::FromWString(argv[ii])); + } + List<char const*> argBuffers; + for(int ii = 0; ii < argc; ++ii) + { + argBuffers.Add(args[ii].Buffer()); + } + + result = MAIN(argc, (char**) &argBuffers[0]); } - return MAIN(argc, (char**) &argBuffers[0]); +#ifdef _MSC_VER + _CrtDumpMemoryLeaks(); +#endif + + return result; } #endif diff --git a/tools/render-test/render-d3d11.cpp b/tools/render-test/render-d3d11.cpp index 4f1071905..19795d685 100644 --- a/tools/render-test/render-d3d11.cpp +++ b/tools/render-test/render-d3d11.cpp @@ -113,8 +113,8 @@ HRESULT initializeSlang(ID3D11Device* dxDevice, char const* sourceText) spAddTranslationUnitSourceString(slangRequest, translationUnitIndex, gOptions.sourcePath, sourceText); - spAddTranslationUnitEntryPoint(slangRequest, translationUnitIndex, vertexEntryPointName, spFindProfile(slangSession, vertexProfileName)); - spAddTranslationUnitEntryPoint(slangRequest, translationUnitIndex, fragmentEntryPointName, spFindProfile(slangSession, fragmentProfileName)); + spAddEntryPoint(slangRequest, translationUnitIndex, vertexEntryPointName, spFindProfile(slangSession, vertexProfileName)); + spAddEntryPoint(slangRequest, translationUnitIndex, fragmentEntryPointName, spFindProfile(slangSession, fragmentProfileName)); int compileErr = spCompile(slangRequest); if(auto diagnostics = spGetDiagnosticOutput(slangRequest)) diff --git a/tools/render-test/slang-support.cpp b/tools/render-test/slang-support.cpp index 8db62ebef..d87f693eb 100644 --- a/tools/render-test/slang-support.cpp +++ b/tools/render-test/slang-support.cpp @@ -73,8 +73,8 @@ struct SlangShaderCompilerWrapper : public ShaderCompiler spSetCompileFlags(slangRequest, SLANG_COMPILE_FLAG_NO_CHECKING); } - int vertexEntryPoint = spAddTranslationUnitEntryPoint(slangRequest, vertexTranslationUnit, request.vertexShader.name, spFindProfile(slangSession, request.vertexShader.profile)); - int fragmentEntryPoint = spAddTranslationUnitEntryPoint(slangRequest, fragmentTranslationUnit, request.fragmentShader.name, spFindProfile(slangSession, request.fragmentShader.profile)); + int vertexEntryPoint = spAddEntryPoint(slangRequest, vertexTranslationUnit, request.vertexShader.name, spFindProfile(slangSession, request.vertexShader.profile)); + int fragmentEntryPoint = spAddEntryPoint(slangRequest, fragmentTranslationUnit, request.fragmentShader.name, spFindProfile(slangSession, request.fragmentShader.profile)); int compileErr = spCompile(slangRequest); if(auto diagnostics = spGetDiagnosticOutput(slangRequest)) @@ -97,8 +97,8 @@ struct SlangShaderCompilerWrapper : public ShaderCompiler innerRequest.source.text = translatedCode; } - char const* vertexCode = spGetEntryPointSource(slangRequest, vertexTranslationUnit, vertexEntryPoint); - char const* fragmentCode = spGetEntryPointSource(slangRequest, fragmentTranslationUnit, fragmentEntryPoint); + char const* vertexCode = spGetEntryPointSource(slangRequest, vertexEntryPoint); + char const* fragmentCode = spGetEntryPointSource(slangRequest, fragmentEntryPoint); innerRequest.vertexShader.source.text = vertexCode; innerRequest.fragmentShader.source.text = fragmentCode; |
