diff options
| author | Ellie Hermaszewska <ellieh@nvidia.com> | 2024-10-29 14:49:26 +0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-10-29 14:49:26 +0800 |
| commit | f65d756bff8d4c5cbc15bd0322a2ae8e6b896a21 (patch) | |
| tree | ea1d61342cd29368e19135000ec2948813096205 /source/slang/slang-compiler.cpp | |
| parent | a729c15e9dce9f5116a38afc66329ab2ca4cea54 (diff) | |
format
* format
* Minor test fixes
* enable checking cpp format in ci
Diffstat (limited to 'source/slang/slang-compiler.cpp')
| -rw-r--r-- | source/slang/slang-compiler.cpp | 4209 |
1 files changed, 2163 insertions, 2046 deletions
diff --git a/source/slang/slang-compiler.cpp b/source/slang/slang-compiler.cpp index 40e1903e5..63952db3d 100644 --- a/source/slang/slang-compiler.cpp +++ b/source/slang/slang-compiler.cpp @@ -1,1572 +1,1651 @@ // Compiler.cpp : Defines the entry point for the console application. // +#include "slang-compiler.h" + +#include "../compiler-core/slang-lexer.h" #include "../core/slang-basic.h" -#include "../core/slang-platform.h" +#include "../core/slang-castable.h" +#include "../core/slang-hex-dump-util.h" #include "../core/slang-io.h" #include "../core/slang-performance-profiler.h" -#include "../core/slang-string-util.h" -#include "../core/slang-hex-dump-util.h" +#include "../core/slang-platform.h" #include "../core/slang-riff.h" -#include "../core/slang-type-text-util.h" +#include "../core/slang-string-util.h" #include "../core/slang-type-convert-util.h" -#include "../core/slang-castable.h" - -#include "slang-check.h" +#include "../core/slang-type-text-util.h" #include "slang-check-impl.h" -#include "slang-compiler.h" - -#include "../compiler-core/slang-lexer.h" +#include "slang-check.h" // Artifact +#include "../compiler-core/slang-artifact-associated.h" +#include "../compiler-core/slang-artifact-container-util.h" #include "../compiler-core/slang-artifact-desc-util.h" -#include "../compiler-core/slang-artifact-representation-impl.h" +#include "../compiler-core/slang-artifact-diagnostic-util.h" #include "../compiler-core/slang-artifact-impl.h" +#include "../compiler-core/slang-artifact-representation-impl.h" #include "../compiler-core/slang-artifact-util.h" -#include "../compiler-core/slang-artifact-associated.h" -#include "../compiler-core/slang-artifact-diagnostic-util.h" -#include "../compiler-core/slang-artifact-container-util.h" // Artifact output #include "slang-artifact-output-util.h" - +#include "slang-emit-cuda.h" +#include "slang-glsl-extension-tracker.h" #include "slang-lower-to-ir.h" #include "slang-mangle.h" #include "slang-parameter-binding.h" #include "slang-parser.h" #include "slang-preprocessor.h" -#include "slang-type-layout.h" - -#include "slang-glsl-extension-tracker.h" -#include "slang-emit-cuda.h" - #include "slang-serialize-ast.h" #include "slang-serialize-container.h" +#include "slang-type-layout.h" namespace Slang { // !!!!!!!!!!!!!!!!!!!!!! free functions for DiagnosicSink !!!!!!!!!!!!!!!!!!!!!!!!!!!!! - bool isHeterogeneousTarget(CodeGenTarget target) - { - return ArtifactDescUtil::makeDescForCompileTarget(asExternal(target)).style == ArtifactStyle::Host; - } +bool isHeterogeneousTarget(CodeGenTarget target) +{ + return ArtifactDescUtil::makeDescForCompileTarget(asExternal(target)).style == + ArtifactStyle::Host; +} - void printDiagnosticArg(StringBuilder& sb, CodeGenTarget val) - { - UnownedStringSlice name = TypeTextUtil::getCompileTargetName(asExternal(val)); - name = name.getLength() ? name : toSlice("<unknown>"); - sb << name; - } +void printDiagnosticArg(StringBuilder& sb, CodeGenTarget val) +{ + UnownedStringSlice name = TypeTextUtil::getCompileTargetName(asExternal(val)); + name = name.getLength() ? name : toSlice("<unknown>"); + sb << name; +} - void printDiagnosticArg(StringBuilder& sb, PassThroughMode val) - { - sb << TypeTextUtil::getPassThroughName(SlangPassThrough(val)); - } +void printDiagnosticArg(StringBuilder& sb, PassThroughMode val) +{ + sb << TypeTextUtil::getPassThroughName(SlangPassThrough(val)); +} - // - // FrontEndEntryPointRequest - // +// +// FrontEndEntryPointRequest +// - FrontEndEntryPointRequest::FrontEndEntryPointRequest( - FrontEndCompileRequest* compileRequest, - int translationUnitIndex, - Name* name, - Profile profile) - : m_compileRequest(compileRequest) - , m_translationUnitIndex(translationUnitIndex) - , m_name(name) - , m_profile(profile) - {} +FrontEndEntryPointRequest::FrontEndEntryPointRequest( + FrontEndCompileRequest* compileRequest, + int translationUnitIndex, + Name* name, + Profile profile) + : m_compileRequest(compileRequest) + , m_translationUnitIndex(translationUnitIndex) + , m_name(name) + , m_profile(profile) +{ +} - TranslationUnitRequest* FrontEndEntryPointRequest::getTranslationUnit() - { - return getCompileRequest()->translationUnits[m_translationUnitIndex]; - } +TranslationUnitRequest* FrontEndEntryPointRequest::getTranslationUnit() +{ + return getCompileRequest()->translationUnits[m_translationUnitIndex]; +} - // - // EntryPoint - // +// +// EntryPoint +// - ISlangUnknown* EntryPoint::getInterface(const Guid& guid) - { - if(guid == slang::IEntryPoint::getTypeGuid()) - return static_cast<slang::IEntryPoint*>(this); +ISlangUnknown* EntryPoint::getInterface(const Guid& guid) +{ + if (guid == slang::IEntryPoint::getTypeGuid()) + return static_cast<slang::IEntryPoint*>(this); - return Super::getInterface(guid); - } + return Super::getInterface(guid); +} - RefPtr<EntryPoint> EntryPoint::create( - Linkage* linkage, - DeclRef<FuncDecl> funcDeclRef, - Profile profile) - { - RefPtr<EntryPoint> entryPoint = new EntryPoint( - linkage, - funcDeclRef.getName(), - profile, - funcDeclRef); - entryPoint->m_mangledName = getMangledName(linkage->getASTBuilder(), funcDeclRef); - return entryPoint; - } +RefPtr<EntryPoint> EntryPoint::create( + Linkage* linkage, + DeclRef<FuncDecl> funcDeclRef, + Profile profile) +{ + RefPtr<EntryPoint> entryPoint = + new EntryPoint(linkage, funcDeclRef.getName(), profile, funcDeclRef); + entryPoint->m_mangledName = getMangledName(linkage->getASTBuilder(), funcDeclRef); + return entryPoint; +} - RefPtr<EntryPoint> EntryPoint::createDummyForPassThrough( - Linkage* linkage, - Name* name, - Profile profile) - { - RefPtr<EntryPoint> entryPoint = new EntryPoint( - linkage, - name, - profile, - DeclRef<FuncDecl>()); - return entryPoint; - } +RefPtr<EntryPoint> EntryPoint::createDummyForPassThrough( + Linkage* linkage, + Name* name, + Profile profile) +{ + RefPtr<EntryPoint> entryPoint = new EntryPoint(linkage, name, profile, DeclRef<FuncDecl>()); + return entryPoint; +} - RefPtr<EntryPoint> EntryPoint::createDummyForDeserialize( - Linkage* linkage, - Name* name, - Profile profile, - String mangledName) - { - RefPtr<EntryPoint> entryPoint = new EntryPoint( - linkage, - name, - profile, - DeclRef<FuncDecl>()); - entryPoint->m_mangledName = mangledName; - return entryPoint; - } - - EntryPoint::EntryPoint( - Linkage* linkage, - Name* name, - Profile profile, - DeclRef<FuncDecl> funcDeclRef) - : ComponentType(linkage) - , m_name(name) - , m_profile(profile) - , m_funcDeclRef(funcDeclRef) - { - // Collect any specialization parameters used by the entry point - // - _collectShaderParams(); - } +RefPtr<EntryPoint> EntryPoint::createDummyForDeserialize( + Linkage* linkage, + Name* name, + Profile profile, + String mangledName) +{ + RefPtr<EntryPoint> entryPoint = new EntryPoint(linkage, name, profile, DeclRef<FuncDecl>()); + entryPoint->m_mangledName = mangledName; + return entryPoint; +} - Module* EntryPoint::getModule() - { - return Slang::getModule(getFuncDecl()); - } +EntryPoint::EntryPoint(Linkage* linkage, Name* name, Profile profile, DeclRef<FuncDecl> funcDeclRef) + : ComponentType(linkage), m_name(name), m_profile(profile), m_funcDeclRef(funcDeclRef) +{ + // Collect any specialization parameters used by the entry point + // + _collectShaderParams(); +} - Index EntryPoint::getSpecializationParamCount() - { - return m_genericSpecializationParams.getCount() + m_existentialSpecializationParams.getCount(); - } +Module* EntryPoint::getModule() +{ + return Slang::getModule(getFuncDecl()); +} - SpecializationParam const& EntryPoint::getSpecializationParam(Index index) +Index EntryPoint::getSpecializationParamCount() +{ + return m_genericSpecializationParams.getCount() + m_existentialSpecializationParams.getCount(); +} + +SpecializationParam const& EntryPoint::getSpecializationParam(Index index) +{ + auto genericParamCount = m_genericSpecializationParams.getCount(); + if (index < genericParamCount) { - auto genericParamCount = m_genericSpecializationParams.getCount(); - if(index < genericParamCount) - { - return m_genericSpecializationParams[index]; - } - else - { - return m_existentialSpecializationParams[index - genericParamCount]; - } + return m_genericSpecializationParams[index]; } - - Index EntryPoint::getRequirementCount() + else { - // The only requirement of an entry point is the module that contains it. - // - // TODO: We will eventually want to support the case of an entry - // point nested in a `struct` type, in which case there should be - // a single requirement representing that outer type (so that multiple - // entry points nested under the same type can share the storage - // for parameters at that scope). - - // Note: the defensive coding is here because the - // "dummy" entry points we create for pass-through - // compilation will not have an associated module. - // - if( const auto module = getModule() ) - { - return 1; - } - return 0; + return m_existentialSpecializationParams[index - genericParamCount]; } +} - RefPtr<ComponentType> EntryPoint::getRequirement(Index index) +Index EntryPoint::getRequirementCount() +{ + // The only requirement of an entry point is the module that contains it. + // + // TODO: We will eventually want to support the case of an entry + // point nested in a `struct` type, in which case there should be + // a single requirement representing that outer type (so that multiple + // entry points nested under the same type can share the storage + // for parameters at that scope). + + // Note: the defensive coding is here because the + // "dummy" entry points we create for pass-through + // compilation will not have an associated module. + // + if (const auto module = getModule()) { - SLANG_UNUSED(index); - SLANG_ASSERT(index == 0); - SLANG_ASSERT(getModule()); - return getModule(); + return 1; } + return 0; +} - String EntryPoint::getEntryPointMangledName(Index index) - { - SLANG_UNUSED(index); - SLANG_ASSERT(index == 0); +RefPtr<ComponentType> EntryPoint::getRequirement(Index index) +{ + SLANG_UNUSED(index); + SLANG_ASSERT(index == 0); + SLANG_ASSERT(getModule()); + return getModule(); +} - return m_mangledName; - } +String EntryPoint::getEntryPointMangledName(Index index) +{ + SLANG_UNUSED(index); + SLANG_ASSERT(index == 0); - String EntryPoint::getEntryPointNameOverride(Index index) - { - SLANG_UNUSED(index); - SLANG_ASSERT(index == 0); + return m_mangledName; +} - return m_name ? m_name->text : ""; - } +String EntryPoint::getEntryPointNameOverride(Index index) +{ + SLANG_UNUSED(index); + SLANG_ASSERT(index == 0); - void EntryPoint::acceptVisitor(ComponentTypeVisitor* visitor, SpecializationInfo* specializationInfo) - { - visitor->visitEntryPoint(this, as<EntryPointSpecializationInfo>(specializationInfo)); - } + return m_name ? m_name->text : ""; +} - void EntryPoint::buildHash(DigestBuilder<SHA1>& builder) - { - SLANG_UNUSED(builder); - } +void EntryPoint::acceptVisitor( + ComponentTypeVisitor* visitor, + SpecializationInfo* specializationInfo) +{ + visitor->visitEntryPoint(this, as<EntryPointSpecializationInfo>(specializationInfo)); +} - List<Module*> const& EntryPoint::getModuleDependencies() - { - if(auto module = getModule()) - return module->getModuleDependencies(); +void EntryPoint::buildHash(DigestBuilder<SHA1>& builder) +{ + SLANG_UNUSED(builder); +} - static List<Module*> empty; - return empty; - } +List<Module*> const& EntryPoint::getModuleDependencies() +{ + if (auto module = getModule()) + return module->getModuleDependencies(); - List<SourceFile*> const& EntryPoint::getFileDependencies() - { - if(const auto module = getModule()) - return getModule()->getFileDependencies(); - - static List<SourceFile*> empty; - return empty; - } + static List<Module*> empty; + return empty; +} - TypeConformance::TypeConformance( - Linkage* linkage, - SubtypeWitness* witness, - Int confomrmanceIdOverride, - DiagnosticSink* sink) - : ComponentType(linkage) - , m_subtypeWitness(witness) - , m_conformanceIdOverride(confomrmanceIdOverride) - { - addDepedencyFromWitness(witness); - m_irModule = generateIRForTypeConformance(this, m_conformanceIdOverride, sink); - } +List<SourceFile*> const& EntryPoint::getFileDependencies() +{ + if (const auto module = getModule()) + return getModule()->getFileDependencies(); + + static List<SourceFile*> empty; + return empty; +} - void TypeConformance::addDepedencyFromWitness(SubtypeWitness* witness) +TypeConformance::TypeConformance( + Linkage* linkage, + SubtypeWitness* witness, + Int confomrmanceIdOverride, + DiagnosticSink* sink) + : ComponentType(linkage) + , m_subtypeWitness(witness) + , m_conformanceIdOverride(confomrmanceIdOverride) +{ + addDepedencyFromWitness(witness); + m_irModule = generateIRForTypeConformance(this, m_conformanceIdOverride, sink); +} + +void TypeConformance::addDepedencyFromWitness(SubtypeWitness* witness) +{ + if (auto declaredWitness = as<DeclaredSubtypeWitness>(witness)) { - if (auto declaredWitness = as<DeclaredSubtypeWitness>(witness)) - { - auto declModule = getModule(declaredWitness->getDeclRef().getDecl()); - m_moduleDependencyList.addDependency(declModule); - m_fileDependencyList.addDependency(declModule); - if (m_requirementSet.add(declModule)) - { - m_requirements.add(declModule); - } - // TODO: handle the specialization arguments in declaredWitness->declRef.substitutions. - } - else if (auto transitiveWitness = as<TransitiveSubtypeWitness>(witness)) + auto declModule = getModule(declaredWitness->getDeclRef().getDecl()); + m_moduleDependencyList.addDependency(declModule); + m_fileDependencyList.addDependency(declModule); + if (m_requirementSet.add(declModule)) { - addDepedencyFromWitness(transitiveWitness->getMidToSup()); - addDepedencyFromWitness(transitiveWitness->getSubToMid()); + m_requirements.add(declModule); } - else if (auto conjunctionWitness = as<ConjunctionSubtypeWitness>(witness)) + // TODO: handle the specialization arguments in declaredWitness->declRef.substitutions. + } + else if (auto transitiveWitness = as<TransitiveSubtypeWitness>(witness)) + { + addDepedencyFromWitness(transitiveWitness->getMidToSup()); + addDepedencyFromWitness(transitiveWitness->getSubToMid()); + } + else if (auto conjunctionWitness = as<ConjunctionSubtypeWitness>(witness)) + { + auto componentCount = conjunctionWitness->getComponentCount(); + for (Index i = 0; i < componentCount; ++i) { - auto componentCount = conjunctionWitness->getComponentCount(); - for (Index i = 0; i < componentCount; ++i) - { - auto w = as<SubtypeWitness>(conjunctionWitness->getComponentWitness(i)); - if (w) addDepedencyFromWitness(w); - } + auto w = as<SubtypeWitness>(conjunctionWitness->getComponentWitness(i)); + if (w) + addDepedencyFromWitness(w); } } +} - ISlangUnknown* TypeConformance::getInterface(const Guid& guid) - { - if (guid == slang::ITypeConformance::getTypeGuid()) - return static_cast<slang::ITypeConformance*>(this); +ISlangUnknown* TypeConformance::getInterface(const Guid& guid) +{ + if (guid == slang::ITypeConformance::getTypeGuid()) + return static_cast<slang::ITypeConformance*>(this); - return Super::getInterface(guid); - } + return Super::getInterface(guid); +} - void TypeConformance::buildHash(DigestBuilder<SHA1>& builder) - { - //TODO: Implement some kind of hashInto for Val then replace this - auto subtypeWitness = m_subtypeWitness->toString(); +void TypeConformance::buildHash(DigestBuilder<SHA1>& builder) +{ + // TODO: Implement some kind of hashInto for Val then replace this + auto subtypeWitness = m_subtypeWitness->toString(); - builder.append(subtypeWitness); - builder.append(m_conformanceIdOverride); - } + builder.append(subtypeWitness); + builder.append(m_conformanceIdOverride); +} - List<Module*> const& TypeConformance::getModuleDependencies() - { - return m_moduleDependencyList.getModuleList(); - } +List<Module*> const& TypeConformance::getModuleDependencies() +{ + return m_moduleDependencyList.getModuleList(); +} - List<SourceFile*> const& TypeConformance::getFileDependencies() - { - return m_fileDependencyList.getFileList(); - } +List<SourceFile*> const& TypeConformance::getFileDependencies() +{ + return m_fileDependencyList.getFileList(); +} - Index TypeConformance::getRequirementCount() { return m_requirements.getCount(); } +Index TypeConformance::getRequirementCount() +{ + return m_requirements.getCount(); +} - RefPtr<ComponentType> TypeConformance::getRequirement(Index index) - { - return m_requirements[index]; - } +RefPtr<ComponentType> TypeConformance::getRequirement(Index index) +{ + return m_requirements[index]; +} - void TypeConformance::acceptVisitor( - ComponentTypeVisitor* visitor, - ComponentType::SpecializationInfo* specializationInfo) - { - SLANG_UNUSED(specializationInfo); - visitor->visitTypeConformance(this); - } +void TypeConformance::acceptVisitor( + ComponentTypeVisitor* visitor, + ComponentType::SpecializationInfo* specializationInfo) +{ + SLANG_UNUSED(specializationInfo); + visitor->visitTypeConformance(this); +} - RefPtr<ComponentType::SpecializationInfo> TypeConformance::_validateSpecializationArgsImpl( - SpecializationArg const* args, - Index argCount, - DiagnosticSink* sink) - { - SLANG_UNUSED(args); - SLANG_UNUSED(argCount); - SLANG_UNUSED(sink); - return nullptr; - } +RefPtr<ComponentType::SpecializationInfo> TypeConformance::_validateSpecializationArgsImpl( + SpecializationArg const* args, + Index argCount, + DiagnosticSink* sink) +{ + SLANG_UNUSED(args); + SLANG_UNUSED(argCount); + SLANG_UNUSED(sink); + return nullptr; +} - // +// - Profile Profile::lookUp(UnownedStringSlice const& name) - { - #define PROFILE(TAG, NAME, STAGE, VERSION) if(name == UnownedTerminatedStringSlice(#NAME)) return Profile::TAG; - #define PROFILE_ALIAS(TAG, DEF, NAME) if(name == UnownedTerminatedStringSlice(#NAME)) return Profile::TAG; - #include "slang-profile-defs.h" +Profile Profile::lookUp(UnownedStringSlice const& name) +{ +#define PROFILE(TAG, NAME, STAGE, VERSION) \ + if (name == UnownedTerminatedStringSlice(#NAME)) \ + return Profile::TAG; +#define PROFILE_ALIAS(TAG, DEF, NAME) \ + if (name == UnownedTerminatedStringSlice(#NAME)) \ + return Profile::TAG; +#include "slang-profile-defs.h" - return Profile::Unknown; - } + return Profile::Unknown; +} - Profile Profile::lookUp(char const* name) +Profile Profile::lookUp(char const* name) +{ + return lookUp(UnownedTerminatedStringSlice(name)); +} + +CapabilitySet Profile::getCapabilityName() +{ + List<CapabilityName> result; + switch (getVersion()) { - return lookUp(UnownedTerminatedStringSlice(name)); +#define PROFILE_VERSION(TAG, NAME) \ + case ProfileVersion::TAG: result.add(CapabilityName::TAG); break; +#include "slang-profile-defs.h" + default: break; } - - CapabilitySet Profile::getCapabilityName() + switch (getStage()) { - List<CapabilityName> result; - switch (getVersion()) - { - #define PROFILE_VERSION(TAG, NAME) case ProfileVersion::TAG: result.add(CapabilityName::TAG); break; - #include "slang-profile-defs.h" - default: - break; - } - switch (getStage()) - { -#define PROFILE_STAGE(TAG, NAME, VAL) case Stage::TAG: result.add(CapabilityName::NAME); break; +#define PROFILE_STAGE(TAG, NAME, VAL) \ + case Stage::TAG: result.add(CapabilityName::NAME); break; #include "slang-profile-defs.h" - default: - break; - } - - CapabilitySet resultSet = CapabilitySet(result); - for(auto i : this->additionalCapabilities) - resultSet.join(i); - return resultSet; + default: break; } - char const* Profile::getName() + CapabilitySet resultSet = CapabilitySet(result); + for (auto i : this->additionalCapabilities) + resultSet.join(i); + return resultSet; +} + +char const* Profile::getName() +{ + switch (raw) { - switch( raw ) - { - default: - return "unknown"; + default: return "unknown"; - #define PROFILE(TAG, NAME, STAGE, VERSION) case Profile::TAG: return #NAME; - #define PROFILE_ALIAS(TAG, DEF, NAME) /* empty */ - #include "slang-profile-defs.h" - } +#define PROFILE(TAG, NAME, STAGE, VERSION) \ + case Profile::TAG: return #NAME; +#define PROFILE_ALIAS(TAG, DEF, NAME) /* empty */ +#include "slang-profile-defs.h" } +} - static const StageInfo kStages[] = - { - #define PROFILE_STAGE(ID, NAME, ENUM) \ - { #NAME, Stage::ID }, +static const StageInfo kStages[] = { +#define PROFILE_STAGE(ID, NAME, ENUM) {#NAME, Stage::ID}, - #define PROFILE_STAGE_ALIAS(ID, NAME, VAL) \ - { #NAME, Stage::ID }, +#define PROFILE_STAGE_ALIAS(ID, NAME, VAL) {#NAME, Stage::ID}, - #include "slang-profile-defs.h" - }; +#include "slang-profile-defs.h" +}; - ConstArrayView<StageInfo> getStageInfos() - { - return makeConstArrayView(kStages); - } +ConstArrayView<StageInfo> getStageInfos() +{ + return makeConstArrayView(kStages); +} - Stage findStageByName(String const& name) +Stage findStageByName(String const& name) +{ + for (auto entry : kStages) { - for(auto entry : kStages) + if (name == entry.name) { - if(name == entry.name) - { - return entry.stage; - } + return entry.stage; } - - return Stage::Unknown; } - UnownedStringSlice getStageText(Stage stage) + return Stage::Unknown; +} + +UnownedStringSlice getStageText(Stage stage) +{ + for (auto entry : kStages) { - for (auto entry : kStages) + if (stage == entry.stage) { - if (stage == entry.stage) - { - return UnownedStringSlice(entry.name); - } - } - return UnownedStringSlice(); - } - - Stage getStageFromAtom(CapabilityAtom atom) - { - switch (atom) - { - case CapabilityAtom::vertex: - return Stage::Vertex; - case CapabilityAtom::hull: - return Stage::Hull; - case CapabilityAtom::domain: - return Stage::Domain; - case CapabilityAtom::geometry: - return Stage::Geometry; - case CapabilityAtom::fragment: - return Stage::Fragment; - case CapabilityAtom::compute: - return Stage::Compute; - case CapabilityAtom::_mesh: - return Stage::Mesh; - case CapabilityAtom::_amplification: - return Stage::Amplification; - case CapabilityAtom::_anyhit: - return Stage::AnyHit; - case CapabilityAtom::_closesthit: - return Stage::ClosestHit; - case CapabilityAtom::_intersection: - return Stage::Intersection; - case CapabilityAtom::_raygen: - return Stage::RayGeneration; - case CapabilityAtom::_miss: - return Stage::Miss; - case CapabilityAtom::_callable: - return Stage::Callable; - default: - SLANG_UNEXPECTED("unknown stage atom"); - UNREACHABLE_RETURN(Stage::Unknown); - } - } - - SlangResult checkExternalCompilerSupport(Session* session, PassThroughMode passThrough) - { - // Check if the type is supported on this compile - if (passThrough == PassThroughMode::None) - { - // If no pass through -> that will always work! - return SLANG_OK; + return UnownedStringSlice(entry.name); } + } + return UnownedStringSlice(); +} - return session->getOrLoadDownstreamCompiler(passThrough, nullptr) ? SLANG_OK: SLANG_E_NOT_FOUND; +Stage getStageFromAtom(CapabilityAtom atom) +{ + switch (atom) + { + case CapabilityAtom::vertex: return Stage::Vertex; + case CapabilityAtom::hull: return Stage::Hull; + case CapabilityAtom::domain: return Stage::Domain; + case CapabilityAtom::geometry: return Stage::Geometry; + case CapabilityAtom::fragment: return Stage::Fragment; + case CapabilityAtom::compute: return Stage::Compute; + case CapabilityAtom::_mesh: return Stage::Mesh; + case CapabilityAtom::_amplification: return Stage::Amplification; + case CapabilityAtom::_anyhit: return Stage::AnyHit; + case CapabilityAtom::_closesthit: return Stage::ClosestHit; + case CapabilityAtom::_intersection: return Stage::Intersection; + case CapabilityAtom::_raygen: return Stage::RayGeneration; + case CapabilityAtom::_miss: return Stage::Miss; + case CapabilityAtom::_callable: return Stage::Callable; + default: SLANG_UNEXPECTED("unknown stage atom"); UNREACHABLE_RETURN(Stage::Unknown); } +} - SourceLanguage getDefaultSourceLanguageForDownstreamCompiler(PassThroughMode compiler) +SlangResult checkExternalCompilerSupport(Session* session, PassThroughMode passThrough) +{ + // Check if the type is supported on this compile + if (passThrough == PassThroughMode::None) { - switch (compiler) + // If no pass through -> that will always work! + return SLANG_OK; + } + + return session->getOrLoadDownstreamCompiler(passThrough, nullptr) ? SLANG_OK + : SLANG_E_NOT_FOUND; +} + +SourceLanguage getDefaultSourceLanguageForDownstreamCompiler(PassThroughMode compiler) +{ + switch (compiler) + { + case PassThroughMode::None: { - case PassThroughMode::None: - { - return SourceLanguage::Unknown; - } - case PassThroughMode::Fxc: - case PassThroughMode::Dxc: - { - return SourceLanguage::HLSL; - } - case PassThroughMode::Glslang: - { - return SourceLanguage::GLSL; - } - case PassThroughMode::LLVM: - case PassThroughMode::Clang: - case PassThroughMode::VisualStudio: - case PassThroughMode::Gcc: - case PassThroughMode::GenericCCpp: - { - // These could ingest C, but we only have this function to work out a - // 'default' language to ingest. - return SourceLanguage::CPP; - } - case PassThroughMode::NVRTC: - { - return SourceLanguage::CUDA; - } - case PassThroughMode::Tint: - { - return SourceLanguage::WGSL; - } - case PassThroughMode::SpirvDis: - { - return SourceLanguage::SPIRV; - } - case PassThroughMode::MetalC: - { - return SourceLanguage::Metal; - } - default: break; + return SourceLanguage::Unknown; } - SLANG_ASSERT(!"Unknown compiler"); - return SourceLanguage::Unknown; + case PassThroughMode::Fxc: + case PassThroughMode::Dxc: + { + return SourceLanguage::HLSL; + } + case PassThroughMode::Glslang: + { + return SourceLanguage::GLSL; + } + case PassThroughMode::LLVM: + case PassThroughMode::Clang: + case PassThroughMode::VisualStudio: + case PassThroughMode::Gcc: + case PassThroughMode::GenericCCpp: + { + // These could ingest C, but we only have this function to work out a + // 'default' language to ingest. + return SourceLanguage::CPP; + } + case PassThroughMode::NVRTC: + { + return SourceLanguage::CUDA; + } + case PassThroughMode::Tint: + { + return SourceLanguage::WGSL; + } + case PassThroughMode::SpirvDis: + { + return SourceLanguage::SPIRV; + } + case PassThroughMode::MetalC: + { + return SourceLanguage::Metal; + } + default: break; } + SLANG_ASSERT(!"Unknown compiler"); + return SourceLanguage::Unknown; +} - PassThroughMode getDownstreamCompilerRequiredForTarget(CodeGenTarget target) +PassThroughMode getDownstreamCompilerRequiredForTarget(CodeGenTarget target) +{ + switch (target) { - switch (target) + // Don't *require* a downstream compiler for source output + case CodeGenTarget::GLSL: + case CodeGenTarget::HLSL: + case CodeGenTarget::CUDASource: + case CodeGenTarget::CPPSource: + case CodeGenTarget::HostCPPSource: + case CodeGenTarget::PyTorchCppBinding: + case CodeGenTarget::CSource: + case CodeGenTarget::Metal: + case CodeGenTarget::WGSL: { - // Don't *require* a downstream compiler for source output - case CodeGenTarget::GLSL: - case CodeGenTarget::HLSL: - case CodeGenTarget::CUDASource: - case CodeGenTarget::CPPSource: - case CodeGenTarget::HostCPPSource: - case CodeGenTarget::PyTorchCppBinding: - case CodeGenTarget::CSource: - case CodeGenTarget::Metal: - case CodeGenTarget::WGSL: - { - return PassThroughMode::None; - } - case CodeGenTarget::None: - { - return PassThroughMode::None; - } - case CodeGenTarget::WGSLSPIRVAssembly: - case CodeGenTarget::SPIRVAssembly: - case CodeGenTarget::SPIRV: - { - return PassThroughMode::SpirvDis; - } - case CodeGenTarget::DXBytecode: - case CodeGenTarget::DXBytecodeAssembly: - { - return PassThroughMode::Fxc; - } - case CodeGenTarget::DXIL: - case CodeGenTarget::DXILAssembly: - { - return PassThroughMode::Dxc; - } - case CodeGenTarget::MetalLib: - case CodeGenTarget::MetalLibAssembly: - { - return PassThroughMode::MetalC; - } - case CodeGenTarget::ShaderHostCallable: - case CodeGenTarget::ShaderSharedLibrary: - case CodeGenTarget::HostExecutable: - case CodeGenTarget::HostHostCallable: - case CodeGenTarget::HostSharedLibrary: - { - // We need some C/C++ compiler - return PassThroughMode::GenericCCpp; - } - case CodeGenTarget::PTX: - { - return PassThroughMode::NVRTC; - } - case CodeGenTarget::WGSLSPIRV: - { - return PassThroughMode::Tint; - } - default: break; + return PassThroughMode::None; } - - SLANG_ASSERT(!"Unhandled target"); - return PassThroughMode::None; + case CodeGenTarget::None: + { + return PassThroughMode::None; + } + case CodeGenTarget::WGSLSPIRVAssembly: + case CodeGenTarget::SPIRVAssembly: + case CodeGenTarget::SPIRV: + { + return PassThroughMode::SpirvDis; + } + case CodeGenTarget::DXBytecode: + case CodeGenTarget::DXBytecodeAssembly: + { + return PassThroughMode::Fxc; + } + case CodeGenTarget::DXIL: + case CodeGenTarget::DXILAssembly: + { + return PassThroughMode::Dxc; + } + case CodeGenTarget::MetalLib: + case CodeGenTarget::MetalLibAssembly: + { + return PassThroughMode::MetalC; + } + case CodeGenTarget::ShaderHostCallable: + case CodeGenTarget::ShaderSharedLibrary: + case CodeGenTarget::HostExecutable: + case CodeGenTarget::HostHostCallable: + case CodeGenTarget::HostSharedLibrary: + { + // We need some C/C++ compiler + return PassThroughMode::GenericCCpp; + } + case CodeGenTarget::PTX: + { + return PassThroughMode::NVRTC; + } + case CodeGenTarget::WGSLSPIRV: + { + return PassThroughMode::Tint; + } + default: break; } - EndToEndCompileRequest* CodeGenContext::isPassThroughEnabled() - { - auto endToEndReq = isEndToEndCompile(); + SLANG_ASSERT(!"Unhandled target"); + return PassThroughMode::None; +} - // If there isn't an end-to-end compile going on, - // there can be no pass-through. - // - if (!endToEndReq) - return nullptr; +EndToEndCompileRequest* CodeGenContext::isPassThroughEnabled() +{ + auto endToEndReq = isEndToEndCompile(); - // And if pass-through isn't set on that end-to-end compile, - // then we clearly areb't doing a pass-through compile. - // - if(endToEndReq->m_passThrough == PassThroughMode::None) - return nullptr; + // If there isn't an end-to-end compile going on, + // there can be no pass-through. + // + if (!endToEndReq) + return nullptr; - // If we have confirmed that pass-through compilation is going on, - // we return the end-to-end request, because it has all the - // relevant state that we need to implement pass-through mode. - // - return endToEndReq; - } + // And if pass-through isn't set on that end-to-end compile, + // then we clearly areb't doing a pass-through compile. + // + if (endToEndReq->m_passThrough == PassThroughMode::None) + return nullptr; - /// If there is a pass-through compile going on, find the translation unit for the given entry point. - /// Assumes isPassThroughEnabled has already been called - TranslationUnitRequest* getPassThroughTranslationUnit( - EndToEndCompileRequest* endToEndReq, - Int entryPointIndex) - { - SLANG_ASSERT(endToEndReq); - SLANG_ASSERT(endToEndReq->m_passThrough != PassThroughMode::None); - auto frontEndReq = endToEndReq->getFrontEndReq(); - auto entryPointReq = frontEndReq->getEntryPointReq(entryPointIndex); - auto translationUnit = entryPointReq->getTranslationUnit(); - return translationUnit; - } + // If we have confirmed that pass-through compilation is going on, + // we return the end-to-end request, because it has all the + // relevant state that we need to implement pass-through mode. + // + return endToEndReq; +} - TranslationUnitRequest* CodeGenContext::findPassThroughTranslationUnit( - Int entryPointIndex) - { - if (auto endToEndReq = isPassThroughEnabled()) - return getPassThroughTranslationUnit(endToEndReq, entryPointIndex); - return nullptr; - } +/// If there is a pass-through compile going on, find the translation unit for the given entry +/// point. Assumes isPassThroughEnabled has already been called +TranslationUnitRequest* getPassThroughTranslationUnit( + EndToEndCompileRequest* endToEndReq, + Int entryPointIndex) +{ + SLANG_ASSERT(endToEndReq); + SLANG_ASSERT(endToEndReq->m_passThrough != PassThroughMode::None); + auto frontEndReq = endToEndReq->getFrontEndReq(); + auto entryPointReq = frontEndReq->getEntryPointReq(entryPointIndex); + auto translationUnit = entryPointReq->getTranslationUnit(); + return translationUnit; +} - static void _appendCodeWithPath(const UnownedStringSlice& filePath, const UnownedStringSlice& fileContent, StringBuilder& outCodeBuilder) - { - outCodeBuilder << "#line 1 \""; - auto handler = StringEscapeUtil::getHandler(StringEscapeUtil::Style::Cpp); - handler->appendEscaped(filePath, outCodeBuilder); - outCodeBuilder << "\"\n"; - outCodeBuilder << fileContent << "\n"; - } +TranslationUnitRequest* CodeGenContext::findPassThroughTranslationUnit(Int entryPointIndex) +{ + if (auto endToEndReq = isPassThroughEnabled()) + return getPassThroughTranslationUnit(endToEndReq, entryPointIndex); + return nullptr; +} + +static void _appendCodeWithPath( + const UnownedStringSlice& filePath, + const UnownedStringSlice& fileContent, + StringBuilder& outCodeBuilder) +{ + outCodeBuilder << "#line 1 \""; + auto handler = StringEscapeUtil::getHandler(StringEscapeUtil::Style::Cpp); + handler->appendEscaped(filePath, outCodeBuilder); + outCodeBuilder << "\"\n"; + outCodeBuilder << fileContent << "\n"; +} - void trackGLSLTargetCaps( - GLSLExtensionTracker* extensionTracker, - CapabilitySet const& caps) +void trackGLSLTargetCaps(GLSLExtensionTracker* extensionTracker, CapabilitySet const& caps) +{ + for (auto& conjunctions : caps.getAtomSets()) { - for(auto& conjunctions : caps.getAtomSets() ) + for (auto atom : conjunctions) { - for (auto atom : conjunctions) + switch (asAtom(atom)) { - switch (asAtom(atom)) - { - default: - break; + default: break; - case CapabilityAtom::glsl_spirv_1_0: extensionTracker->requireSPIRVVersion(SemanticVersion(1, 0)); break; - case CapabilityAtom::glsl_spirv_1_1: extensionTracker->requireSPIRVVersion(SemanticVersion(1, 1)); break; - case CapabilityAtom::glsl_spirv_1_2: extensionTracker->requireSPIRVVersion(SemanticVersion(1, 2)); break; - case CapabilityAtom::glsl_spirv_1_3: extensionTracker->requireSPIRVVersion(SemanticVersion(1, 3)); break; - case CapabilityAtom::glsl_spirv_1_4: extensionTracker->requireSPIRVVersion(SemanticVersion(1, 4)); break; - case CapabilityAtom::glsl_spirv_1_5: extensionTracker->requireSPIRVVersion(SemanticVersion(1, 5)); break; - case CapabilityAtom::glsl_spirv_1_6: extensionTracker->requireSPIRVVersion(SemanticVersion(1, 6)); break; - } + case CapabilityAtom::glsl_spirv_1_0: + extensionTracker->requireSPIRVVersion(SemanticVersion(1, 0)); + break; + case CapabilityAtom::glsl_spirv_1_1: + extensionTracker->requireSPIRVVersion(SemanticVersion(1, 1)); + break; + case CapabilityAtom::glsl_spirv_1_2: + extensionTracker->requireSPIRVVersion(SemanticVersion(1, 2)); + break; + case CapabilityAtom::glsl_spirv_1_3: + extensionTracker->requireSPIRVVersion(SemanticVersion(1, 3)); + break; + case CapabilityAtom::glsl_spirv_1_4: + extensionTracker->requireSPIRVVersion(SemanticVersion(1, 4)); + break; + case CapabilityAtom::glsl_spirv_1_5: + extensionTracker->requireSPIRVVersion(SemanticVersion(1, 5)); + break; + case CapabilityAtom::glsl_spirv_1_6: + extensionTracker->requireSPIRVVersion(SemanticVersion(1, 6)); + break; } } } +} - SlangResult CodeGenContext::requireTranslationUnitSourceFiles() +SlangResult CodeGenContext::requireTranslationUnitSourceFiles() +{ + if (auto endToEndReq = isPassThroughEnabled()) { - if (auto endToEndReq = isPassThroughEnabled()) + for (auto entryPointIndex : getEntryPointIndices()) { - for (auto entryPointIndex : getEntryPointIndices()) - { - auto translationUnit = getPassThroughTranslationUnit(endToEndReq, entryPointIndex); - SLANG_ASSERT(translationUnit); - /// Make sure we have the source files - SLANG_RETURN_ON_FAIL(translationUnit->requireSourceFiles()); - } + auto translationUnit = getPassThroughTranslationUnit(endToEndReq, entryPointIndex); + SLANG_ASSERT(translationUnit); + /// Make sure we have the source files + SLANG_RETURN_ON_FAIL(translationUnit->requireSourceFiles()); } - - return SLANG_OK; } + return SLANG_OK; +} + #if SLANG_VC -// TODO(JS): This is a workaround +// TODO(JS): This is a workaround // In debug VS builds there is a warning on line about it being unreachable. // for (auto entryPointIndex : getEntryPointIndices()) // It's not clear how that could possibly be unreachable -# pragma warning(push) -# pragma warning(disable:4702) +#pragma warning(push) +#pragma warning(disable : 4702) #endif - SlangResult CodeGenContext::emitEntryPointsSource(ComPtr<IArtifact>& outArtifact) - { - outArtifact.setNull(); +SlangResult CodeGenContext::emitEntryPointsSource(ComPtr<IArtifact>& outArtifact) +{ + outArtifact.setNull(); - SLANG_RETURN_ON_FAIL(requireTranslationUnitSourceFiles()); + SLANG_RETURN_ON_FAIL(requireTranslationUnitSourceFiles()); - auto endToEndReq = isPassThroughEnabled(); - if(endToEndReq) + auto endToEndReq = isPassThroughEnabled(); + if (endToEndReq) + { + for (auto entryPointIndex : getEntryPointIndices()) { - for (auto entryPointIndex : getEntryPointIndices()) - { - auto translationUnit = getPassThroughTranslationUnit(endToEndReq, entryPointIndex); - SLANG_ASSERT(translationUnit); + auto translationUnit = getPassThroughTranslationUnit(endToEndReq, entryPointIndex); + SLANG_ASSERT(translationUnit); - /// Make sure we have the source files - SLANG_RETURN_ON_FAIL(translationUnit->requireSourceFiles()); + /// Make sure we have the source files + SLANG_RETURN_ON_FAIL(translationUnit->requireSourceFiles()); - // 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. + // 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; - if (getTargetFormat() == CodeGenTarget::GLSL) + StringBuilder codeBuilder; + if (getTargetFormat() == CodeGenTarget::GLSL) + { + // Special case GLSL + int translationUnitCounter = 0; + for (auto sourceFile : translationUnit->getSourceFiles()) { - // Special case GLSL - int translationUnitCounter = 0; - for (auto sourceFile : translationUnit->getSourceFiles()) + 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) { - 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->getContent() << "\n"; + codeBuilder << "#line 1 " << translationUnitIndex << "\n"; } + codeBuilder << sourceFile->getContent() << "\n"; } - else + } + else + { + for (auto sourceFile : translationUnit->getSourceFiles()) { - for (auto sourceFile : translationUnit->getSourceFiles()) - { - _appendCodeWithPath(sourceFile->getPathInfo().foundPath.getUnownedSlice(), sourceFile->getContent(), codeBuilder); - } + _appendCodeWithPath( + sourceFile->getPathInfo().foundPath.getUnownedSlice(), + sourceFile->getContent(), + codeBuilder); } + } - auto artifact = ArtifactUtil::createArtifactForCompileTarget(asExternal(getTargetFormat())); - artifact->addRepresentationUnknown(StringBlob::moveCreate(codeBuilder)); + auto artifact = + ArtifactUtil::createArtifactForCompileTarget(asExternal(getTargetFormat())); + artifact->addRepresentationUnknown(StringBlob::moveCreate(codeBuilder)); - outArtifact.swap(artifact); - return SLANG_OK; - } + outArtifact.swap(artifact); return SLANG_OK; } - else - { - return emitEntryPointsSourceFromIR(outArtifact); - } + return SLANG_OK; } + else + { + return emitEntryPointsSourceFromIR(outArtifact); + } +} #if SLANG_VC -# pragma warning(pop) +#pragma warning(pop) #endif - SlangResult CodeGenContext::emitPrecompiledDownstreamIR(ComPtr<IArtifact>& outArtifact) - { - return _emitEntryPoints(outArtifact); - } +SlangResult CodeGenContext::emitPrecompiledDownstreamIR(ComPtr<IArtifact>& outArtifact) +{ + return _emitEntryPoints(outArtifact); +} - String GetHLSLProfileName(Profile profile) +String GetHLSLProfileName(Profile profile) +{ + switch (profile.getFamily()) { - switch( profile.getFamily() ) - { - case ProfileFamily::DX: - // Profile version is a DX one, so stick with it. - break; + case ProfileFamily::DX: + // Profile version is a DX one, so stick with it. + break; - default: - // Profile is a non-DX profile family, so we need to try - // to clobber it with something to get a default. - // - // TODO: This is a huge hack... - profile.setVersion(ProfileVersion::DX_5_1); - break; - } - - char const* stagePrefix = nullptr; - switch( profile.getStage() ) - { - // Note: All of the raytracing-related stages require - // compiling for a `lib_*` profile, even when only a - // single entry point is present. - // - // We also go ahead and use this target in any case - // where we don't know the actual stage to compiel for, - // as a fallback option. - // - // TODO: We also want to use this option when compiling - // multiple entry points to a DXIL library. - // - default: - stagePrefix = "lib"; - break; + default: + // Profile is a non-DX profile family, so we need to try + // to clobber it with something to get a default. + // + // TODO: This is a huge hack... + profile.setVersion(ProfileVersion::DX_5_1); + break; + } - // The traditional rasterization pipeline and compute - // shaders all have custom profile names that identify - // both the stage and shader model, which need to be - // used when compiling a single entry point. - // - #define CASE(NAME, PREFIX) case Stage::NAME: stagePrefix = #PREFIX; break - CASE(Vertex, vs); - CASE(Hull, hs); - CASE(Domain, ds); - CASE(Geometry, gs); - CASE(Fragment, ps); - CASE(Compute, cs); + char const* stagePrefix = nullptr; + switch (profile.getStage()) + { + // Note: All of the raytracing-related stages require + // compiling for a `lib_*` profile, even when only a + // single entry point is present. + // + // We also go ahead and use this target in any case + // where we don't know the actual stage to compiel for, + // as a fallback option. + // + // TODO: We also want to use this option when compiling + // multiple entry points to a DXIL library. + // + default: + stagePrefix = "lib"; + break; + + // The traditional rasterization pipeline and compute + // shaders all have custom profile names that identify + // both the stage and shader model, which need to be + // used when compiling a single entry point. + // +#define CASE(NAME, PREFIX) \ + case Stage::NAME: stagePrefix = #PREFIX; break + CASE(Vertex, vs); + CASE(Hull, hs); + CASE(Domain, ds); + CASE(Geometry, gs); + CASE(Fragment, ps); + CASE(Compute, cs); CASE(Amplification, as); - CASE(Mesh, ms); - #undef CASE - } - - char const* versionSuffix = nullptr; - switch(profile.getVersion()) - { - #define CASE(TAG, SUFFIX) case ProfileVersion::TAG: versionSuffix = #SUFFIX; break - CASE(DX_4_0, _4_0); - CASE(DX_4_1, _4_1); - CASE(DX_5_0, _5_0); - CASE(DX_5_1, _5_1); - CASE(DX_6_0, _6_0); - CASE(DX_6_1, _6_1); - CASE(DX_6_2, _6_2); - CASE(DX_6_3, _6_3); - CASE(DX_6_4, _6_4); - CASE(DX_6_5, _6_5); - CASE(DX_6_6, _6_6); - CASE(DX_6_7, _6_7); - #undef CASE - - default: - return "unknown"; - } + CASE(Mesh, ms); +#undef CASE + } + + char const* versionSuffix = nullptr; + switch (profile.getVersion()) + { +#define CASE(TAG, SUFFIX) \ + case ProfileVersion::TAG: versionSuffix = #SUFFIX; break + CASE(DX_4_0, _4_0); + CASE(DX_4_1, _4_1); + CASE(DX_5_0, _5_0); + CASE(DX_5_1, _5_1); + CASE(DX_6_0, _6_0); + CASE(DX_6_1, _6_1); + CASE(DX_6_2, _6_2); + CASE(DX_6_3, _6_3); + CASE(DX_6_4, _6_4); + CASE(DX_6_5, _6_5); + CASE(DX_6_6, _6_6); + CASE(DX_6_7, _6_7); +#undef CASE + + default: return "unknown"; + } + + String result; + result.append(stagePrefix); + result.append(versionSuffix); + return result; +} - String result; - result.append(stagePrefix); - result.append(versionSuffix); - return result; +void reportExternalCompileError( + const char* compilerName, + Severity severity, + SlangResult res, + const UnownedStringSlice& diagnostic, + DiagnosticSink* sink) +{ + StringBuilder builder; + if (compilerName) + { + builder << compilerName << ": "; } - void reportExternalCompileError(const char* compilerName, Severity severity, SlangResult res, const UnownedStringSlice& diagnostic, DiagnosticSink* sink) + if (SLANG_FAILED(res) && res != SLANG_FAIL) { - StringBuilder builder; - if (compilerName) { - builder << compilerName << ": "; + char tmp[17]; + sprintf_s(tmp, SLANG_COUNT_OF(tmp), "0x%08x", uint32_t(res)); + builder << "Result(" << tmp << ") "; } - if (SLANG_FAILED(res) && res != SLANG_FAIL) - { - { - char tmp[17]; - sprintf_s(tmp, SLANG_COUNT_OF(tmp), "0x%08x", uint32_t(res)); - builder << "Result(" << tmp << ") "; - } - - PlatformUtil::appendResult(res, builder); - } + PlatformUtil::appendResult(res, builder); + } - if (diagnostic.getLength() > 0) + if (diagnostic.getLength() > 0) + { + builder.append(diagnostic); + if (!diagnostic.endsWith("\n")) { - builder.append(diagnostic); - if (!diagnostic.endsWith("\n")) - { - builder.append("\n"); - } + builder.append("\n"); } - - sink->diagnoseRaw(severity, builder.getUnownedSlice()); } - void reportExternalCompileError(const char* compilerName, SlangResult res, const UnownedStringSlice& diagnostic, DiagnosticSink* sink) + sink->diagnoseRaw(severity, builder.getUnownedSlice()); +} + +void reportExternalCompileError( + const char* compilerName, + SlangResult res, + const UnownedStringSlice& diagnostic, + DiagnosticSink* sink) +{ + // TODO(tfoley): need a better policy for how we translate diagnostics + // back into the Slang world (although we should always try to generate + // HLSL that doesn't produce any diagnostics...) + reportExternalCompileError( + compilerName, + SLANG_FAILED(res) ? Severity::Error : Severity::Warning, + res, + diagnostic, + sink); +} + +static String _getDisplayPath(DiagnosticSink* sink, SourceFile* sourceFile) +{ + if (sink->isFlagSet(DiagnosticSink::Flag::VerbosePath)) { - // TODO(tfoley): need a better policy for how we translate diagnostics - // back into the Slang world (although we should always try to generate - // HLSL that doesn't produce any diagnostics...) - reportExternalCompileError(compilerName, SLANG_FAILED(res) ? Severity::Error : Severity::Warning, res, diagnostic, sink); + return sourceFile->calcVerbosePath(); } - - static String _getDisplayPath(DiagnosticSink* sink, SourceFile* sourceFile) + else { - if (sink->isFlagSet(DiagnosticSink::Flag::VerbosePath)) - { - return sourceFile->calcVerbosePath(); - } - else - { - return sourceFile->getPathInfo().foundPath; - } + return sourceFile->getPathInfo().foundPath; } +} - String CodeGenContext::calcSourcePathForEntryPoints() - { - String failureMode = "slang-generated"; - if (getEntryPointCount() != 1) - return failureMode; - auto entryPointIndex = getSingleEntryPointIndex(); - auto translationUnitRequest = findPassThroughTranslationUnit(entryPointIndex); - if (!translationUnitRequest) - return failureMode; +String CodeGenContext::calcSourcePathForEntryPoints() +{ + String failureMode = "slang-generated"; + if (getEntryPointCount() != 1) + return failureMode; + auto entryPointIndex = getSingleEntryPointIndex(); + auto translationUnitRequest = findPassThroughTranslationUnit(entryPointIndex); + if (!translationUnitRequest) + return failureMode; - const auto& sourceFiles = translationUnitRequest->getSourceFiles(); + const auto& sourceFiles = translationUnitRequest->getSourceFiles(); - auto sink = getSink(); + auto sink = getSink(); - const Index numSourceFiles = sourceFiles.getCount(); + const Index numSourceFiles = sourceFiles.getCount(); - switch (numSourceFiles) + switch (numSourceFiles) + { + case 0: return "unknown"; + case 1: return _getDisplayPath(sink, sourceFiles[0]); + default: { - case 0: return "unknown"; - case 1: return _getDisplayPath(sink, sourceFiles[0]); - default: + StringBuilder builder; + builder << _getDisplayPath(sink, sourceFiles[0]); + for (int i = 1; i < numSourceFiles; ++i) { - StringBuilder builder; - builder << _getDisplayPath(sink, sourceFiles[0]); - for (int i = 1; i < numSourceFiles; ++i) - { - builder << ";" << _getDisplayPath(sink, sourceFiles[i]); - } - return builder; + builder << ";" << _getDisplayPath(sink, sourceFiles[i]); } + return builder; } } +} - // Helper function for cases where we can assume a single entry point - Int assertSingleEntryPoint(List<Int> const& entryPointIndices) { - SLANG_ASSERT(entryPointIndices.getCount() == 1); - return *entryPointIndices.begin(); - } +// Helper function for cases where we can assume a single entry point +Int assertSingleEntryPoint(List<Int> const& entryPointIndices) +{ + SLANG_ASSERT(entryPointIndices.getCount() == 1); + return *entryPointIndices.begin(); +} - // True if it's best to use 'emitted' source for complication. For a downstream compiler - // that is not file based, this is always ok. - /// - /// If the downstream compiler is file system based, we may want to just use the file that was passed to be compiled. - /// That the downstream compiler can determine if it will then save the file or not based on if it's a match - - /// and generally there will not be a match with emitted source. - /// - /// This test is only used for pass through mode. - static bool _useEmittedSource(IDownstreamCompiler* compiler, TranslationUnitRequest* translationUnit) +// True if it's best to use 'emitted' source for complication. For a downstream compiler +// that is not file based, this is always ok. +/// +/// If the downstream compiler is file system based, we may want to just use the file that was +/// passed to be compiled. That the downstream compiler can determine if it will then save the file +/// or not based on if it's a match - and generally there will not be a match with emitted source. +/// +/// This test is only used for pass through mode. +static bool _useEmittedSource( + IDownstreamCompiler* compiler, + TranslationUnitRequest* translationUnit) +{ + // We only bother if it's a file based compiler. + if (compiler->isFileBased()) { - // We only bother if it's a file based compiler. - if (compiler->isFileBased()) - { - // It can only have *one* source file as otherwise we have to combine to make a new source file anyway - return translationUnit->getSourceArtifacts().getCount() != 1; - } - return true; + // It can only have *one* source file as otherwise we have to combine to make a new source + // file anyway + return translationUnit->getSourceArtifacts().getCount() != 1; } + return true; +} - static Severity _getDiagnosticSeverity(ArtifactDiagnostic::Severity severity) +static Severity _getDiagnosticSeverity(ArtifactDiagnostic::Severity severity) +{ + switch (severity) { - switch (severity) - { - case ArtifactDiagnostic::Severity::Warning: return Severity::Warning; - case ArtifactDiagnostic::Severity::Info: return Severity::Note; - default: return Severity::Error; - } + case ArtifactDiagnostic::Severity::Warning: return Severity::Warning; + case ArtifactDiagnostic::Severity::Info: return Severity::Note; + default: return Severity::Error; } +} - static RefPtr<ExtensionTracker> _newExtensionTracker(CodeGenTarget target) +static RefPtr<ExtensionTracker> _newExtensionTracker(CodeGenTarget target) +{ + switch (target) { - switch (target) + case CodeGenTarget::PTX: + case CodeGenTarget::CUDASource: { - case CodeGenTarget::PTX: - case CodeGenTarget::CUDASource: - { - return new CUDAExtensionTracker; - } - case CodeGenTarget::SPIRV: - case CodeGenTarget::GLSL: - { - return new GLSLExtensionTracker; - } - default: return nullptr; + return new CUDAExtensionTracker; } + case CodeGenTarget::SPIRV: + case CodeGenTarget::GLSL: + { + return new GLSLExtensionTracker; + } + default: return nullptr; } +} - static CodeGenTarget _getDefaultSourceForTarget(CodeGenTarget target) +static CodeGenTarget _getDefaultSourceForTarget(CodeGenTarget target) +{ + switch (target) { - switch (target) + case CodeGenTarget::ShaderHostCallable: + case CodeGenTarget::ShaderSharedLibrary: { - case CodeGenTarget::ShaderHostCallable: - case CodeGenTarget::ShaderSharedLibrary: - { - return CodeGenTarget::CPPSource; - } - case CodeGenTarget::HostHostCallable: - case CodeGenTarget::HostExecutable: - case CodeGenTarget::HostSharedLibrary: - { - return CodeGenTarget::HostCPPSource; - } - case CodeGenTarget::PTX: return CodeGenTarget::CUDASource; - case CodeGenTarget::DXBytecode: return CodeGenTarget::HLSL; - case CodeGenTarget::DXIL: return CodeGenTarget::HLSL; - case CodeGenTarget::SPIRV: return CodeGenTarget::GLSL; - case CodeGenTarget::MetalLib: return CodeGenTarget::Metal; - case CodeGenTarget::WGSLSPIRV: return CodeGenTarget::WGSL; - default: break; + return CodeGenTarget::CPPSource; + } + case CodeGenTarget::HostHostCallable: + case CodeGenTarget::HostExecutable: + case CodeGenTarget::HostSharedLibrary: + { + return CodeGenTarget::HostCPPSource; } - return CodeGenTarget::Unknown; + case CodeGenTarget::PTX: return CodeGenTarget::CUDASource; + case CodeGenTarget::DXBytecode: return CodeGenTarget::HLSL; + case CodeGenTarget::DXIL: return CodeGenTarget::HLSL; + case CodeGenTarget::SPIRV: return CodeGenTarget::GLSL; + case CodeGenTarget::MetalLib: return CodeGenTarget::Metal; + case CodeGenTarget::WGSLSPIRV: return CodeGenTarget::WGSL; + default: break; } + return CodeGenTarget::Unknown; +} - static bool _isCPUHostTarget(CodeGenTarget target) - { - auto desc = ArtifactDescUtil::makeDescForCompileTarget(asExternal(target)); - return desc.style == ArtifactStyle::Host; - } +static bool _isCPUHostTarget(CodeGenTarget target) +{ + auto desc = ArtifactDescUtil::makeDescForCompileTarget(asExternal(target)); + return desc.style == ArtifactStyle::Host; +} - static bool _shouldSetEntryPointName(TargetProgram* targetProgram) - { - if (!isKhronosTarget(targetProgram->getTargetReq())) - return true; - if (targetProgram->getOptionSet().getBoolOption(CompilerOptionName::VulkanUseEntryPointName)) - return true; - return false; - } +static bool _shouldSetEntryPointName(TargetProgram* targetProgram) +{ + if (!isKhronosTarget(targetProgram->getTargetReq())) + return true; + if (targetProgram->getOptionSet().getBoolOption(CompilerOptionName::VulkanUseEntryPointName)) + return true; + return false; +} - SlangResult passthroughDownstreamDiagnostics(DiagnosticSink* sink, IDownstreamCompiler* compiler, IArtifact* artifact) - { - auto diagnostics = findAssociatedRepresentation<IArtifactDiagnostics>(artifact); +SlangResult passthroughDownstreamDiagnostics( + DiagnosticSink* sink, + IDownstreamCompiler* compiler, + IArtifact* artifact) +{ + auto diagnostics = findAssociatedRepresentation<IArtifactDiagnostics>(artifact); - if (!diagnostics) - return SLANG_OK; + if (!diagnostics) + return SLANG_OK; - if (diagnostics->getCount()) - { - StringBuilder compilerText; - DownstreamCompilerUtil::appendAsText(compiler->getDesc(), compilerText); + if (diagnostics->getCount()) + { + StringBuilder compilerText; + DownstreamCompilerUtil::appendAsText(compiler->getDesc(), compilerText); - StringBuilder builder; + StringBuilder builder; - auto const diagnosticCount = diagnostics->getCount(); - for (Index i = 0; i < diagnosticCount; ++i) - { - const auto& diagnostic = *diagnostics->getAt(i); + auto const diagnosticCount = diagnostics->getCount(); + for (Index i = 0; i < diagnosticCount; ++i) + { + const auto& diagnostic = *diagnostics->getAt(i); - builder.clear(); + builder.clear(); - const Severity severity = _getDiagnosticSeverity(diagnostic.severity); + const Severity severity = _getDiagnosticSeverity(diagnostic.severity); - if (diagnostic.filePath.count == 0 && diagnostic.location.line == 0 && severity == Severity::Note) + if (diagnostic.filePath.count == 0 && diagnostic.location.line == 0 && + severity == Severity::Note) + { + // If theres no filePath line number and it's info, output severity and text alone + builder << getSeverityName(severity) << " : "; + } + else + { + if (diagnostic.filePath.count) { - // If theres no filePath line number and it's info, output severity and text alone - builder << getSeverityName(severity) << " : "; + builder << asStringSlice(diagnostic.filePath); } - else - { - if (diagnostic.filePath.count) - { - builder << asStringSlice(diagnostic.filePath); - } - if (diagnostic.location.line) - { - builder << "(" << diagnostic.location.line << ")"; - } - - builder << ": "; + if (diagnostic.location.line) + { + builder << "(" << diagnostic.location.line << ")"; + } - if (diagnostic.stage == ArtifactDiagnostic::Stage::Link) - { - builder << "link "; - } + builder << ": "; - builder << getSeverityName(severity); - builder << " " << asStringSlice(diagnostic.code) << ": "; + if (diagnostic.stage == ArtifactDiagnostic::Stage::Link) + { + builder << "link "; } - builder << asStringSlice(diagnostic.text); - reportExternalCompileError(compilerText.getBuffer(), severity, SLANG_OK, builder.getUnownedSlice(), sink); + builder << getSeverityName(severity); + builder << " " << asStringSlice(diagnostic.code) << ": "; } - } - // If any errors are emitted, then we are done - if (diagnostics->hasOfAtLeastSeverity(ArtifactDiagnostic::Severity::Error)) - { - return SLANG_FAIL; + builder << asStringSlice(diagnostic.text); + reportExternalCompileError( + compilerText.getBuffer(), + severity, + SLANG_OK, + builder.getUnownedSlice(), + sink); } - - return SLANG_OK; } - SlangResult CodeGenContext::emitWithDownstreamForEntryPoints(ComPtr<IArtifact>& outArtifact) + // If any errors are emitted, then we are done + if (diagnostics->hasOfAtLeastSeverity(ArtifactDiagnostic::Severity::Error)) { - outArtifact.setNull(); + return SLANG_FAIL; + } - auto sink = getSink(); - auto session = getSession(); + return SLANG_OK; +} - CodeGenTarget sourceTarget = CodeGenTarget::None; - SourceLanguage sourceLanguage = SourceLanguage::Unknown; +SlangResult CodeGenContext::emitWithDownstreamForEntryPoints(ComPtr<IArtifact>& outArtifact) +{ + outArtifact.setNull(); - auto target = getTargetFormat(); - RefPtr<ExtensionTracker> extensionTracker = _newExtensionTracker(target); - PassThroughMode compilerType; + auto sink = getSink(); + auto session = getSession(); - SliceAllocator allocator; - - if (auto endToEndReq = isPassThroughEnabled()) - { - compilerType = endToEndReq->m_passThrough; - } - else - { - // If we are not in pass through, lookup the default compiler for the emitted source type + CodeGenTarget sourceTarget = CodeGenTarget::None; + SourceLanguage sourceLanguage = SourceLanguage::Unknown; - // Get the default source codegen type for a given target - sourceTarget = _getDefaultSourceForTarget(target); - compilerType = (PassThroughMode)session->getDownstreamCompilerForTransition((SlangCompileTarget)sourceTarget, (SlangCompileTarget)target); - // We should have a downstream compiler set at this point - if (compilerType == PassThroughMode::None) - { - auto sourceName = TypeTextUtil::getCompileTargetName(SlangCompileTarget(sourceTarget)); - auto targetName = TypeTextUtil::getCompileTargetName(SlangCompileTarget(target)); + auto target = getTargetFormat(); + RefPtr<ExtensionTracker> extensionTracker = _newExtensionTracker(target); + PassThroughMode compilerType; - sink->diagnose(SourceLoc(), Diagnostics::compilerNotDefinedForTransition, sourceName, targetName); - return SLANG_FAIL; - } - } + SliceAllocator allocator; - SLANG_ASSERT(compilerType != PassThroughMode::None); + if (auto endToEndReq = isPassThroughEnabled()) + { + compilerType = endToEndReq->m_passThrough; + } + else + { + // If we are not in pass through, lookup the default compiler for the emitted source type - // Get the required downstream compiler - IDownstreamCompiler* compiler = session->getOrLoadDownstreamCompiler(compilerType, sink); - if (!compiler) + // Get the default source codegen type for a given target + sourceTarget = _getDefaultSourceForTarget(target); + compilerType = (PassThroughMode)session->getDownstreamCompilerForTransition( + (SlangCompileTarget)sourceTarget, + (SlangCompileTarget)target); + // We should have a downstream compiler set at this point + if (compilerType == PassThroughMode::None) { - auto compilerName = TypeTextUtil::getPassThroughAsHumanText((SlangPassThrough)compilerType); - sink->diagnose(SourceLoc(), Diagnostics::passThroughCompilerNotFound, compilerName); + auto sourceName = TypeTextUtil::getCompileTargetName(SlangCompileTarget(sourceTarget)); + auto targetName = TypeTextUtil::getCompileTargetName(SlangCompileTarget(target)); + + sink->diagnose( + SourceLoc(), + Diagnostics::compilerNotDefinedForTransition, + sourceName, + targetName); return SLANG_FAIL; } + } - Dictionary<String, String> preprocessorDefinitions; - List<String> includePaths; + SLANG_ASSERT(compilerType != PassThroughMode::None); - typedef DownstreamCompileOptions CompileOptions; - CompileOptions options; + // Get the required downstream compiler + IDownstreamCompiler* compiler = session->getOrLoadDownstreamCompiler(compilerType, sink); + if (!compiler) + { + auto compilerName = TypeTextUtil::getPassThroughAsHumanText((SlangPassThrough)compilerType); + sink->diagnose(SourceLoc(), Diagnostics::passThroughCompilerNotFound, compilerName); + return SLANG_FAIL; + } + + Dictionary<String, String> preprocessorDefinitions; + List<String> includePaths; + + typedef DownstreamCompileOptions CompileOptions; + CompileOptions options; - List<DownstreamCompileOptions::CapabilityVersion> requiredCapabilityVersions; - List<String> compilerSpecificArguments; - List<ComPtr<IArtifact>> libraries; - List<String> libraryPaths; + List<DownstreamCompileOptions::CapabilityVersion> requiredCapabilityVersions; + List<String> compilerSpecificArguments; + List<ComPtr<IArtifact>> libraries; + List<String> libraryPaths; - // Set compiler specific args + // Set compiler specific args + { + auto name = TypeTextUtil::getPassThroughName((SlangPassThrough)compilerType); + List<String> downstreamArgs = getTargetProgram()->getOptionSet().getDownstreamArgs(name); + for (const auto& arg : downstreamArgs) { - auto name = TypeTextUtil::getPassThroughName((SlangPassThrough)compilerType); - List<String> downstreamArgs = getTargetProgram()->getOptionSet().getDownstreamArgs(name); - for (const auto& arg : downstreamArgs) + // We special case some kinds of args, that can be handled directly + if (arg.startsWith("-I")) { - // We special case some kinds of args, that can be handled directly - if (arg.startsWith("-I")) - { - // We handle the -I option, by just adding to the include paths - includePaths.add(arg.getUnownedSlice().tail(2)); - } - else - { - compilerSpecificArguments.add(arg); - } + // We handle the -I option, by just adding to the include paths + includePaths.add(arg.getUnownedSlice().tail(2)); + } + else + { + compilerSpecificArguments.add(arg); } } + } - ComPtr<IArtifact> sourceArtifact; + ComPtr<IArtifact> sourceArtifact; - /* This is more convoluted than the other scenarios, because when we invoke C/C++ compiler we would ideally like - to use the original file. We want to do this because we want includes relative to the source file to work, and - for that to work most easily we want to use the original file, if there is one */ - if (auto endToEndReq = isPassThroughEnabled()) + /* This is more convoluted than the other scenarios, because when we invoke C/C++ compiler we + would ideally like to use the original file. We want to do this because we want includes + relative to the source file to work, and for that to work most easily we want to use the + original file, if there is one */ + if (auto endToEndReq = isPassThroughEnabled()) + { + // If we are pass through, we may need to set extension tracker state. + if (GLSLExtensionTracker* glslTracker = as<GLSLExtensionTracker>(extensionTracker)) { - // If we are pass through, we may need to set extension tracker state. - if (GLSLExtensionTracker* glslTracker = as<GLSLExtensionTracker>(extensionTracker)) - { - trackGLSLTargetCaps(glslTracker, getTargetCaps()); - } + trackGLSLTargetCaps(glslTracker, getTargetCaps()); + } - auto translationUnit = getPassThroughTranslationUnit(endToEndReq, getSingleEntryPointIndex()); + auto translationUnit = + getPassThroughTranslationUnit(endToEndReq, getSingleEntryPointIndex()); - // We are just passing thru, so it's whatever it originally was - sourceLanguage = translationUnit->sourceLanguage; + // We are just passing thru, so it's whatever it originally was + sourceLanguage = translationUnit->sourceLanguage; - // TODO(JS): This seems like a bit of a hack - // That if a pass-through is being performed and the source language is Slang - // no downstream compiler knows how to deal with that, so probably means 'HLSL' - sourceLanguage = (sourceLanguage == SourceLanguage::Slang) ? SourceLanguage::HLSL : sourceLanguage; - sourceTarget = CodeGenTarget(TypeConvertUtil::getCompileTargetFromSourceLanguage((SlangSourceLanguage)sourceLanguage)); + // TODO(JS): This seems like a bit of a hack + // That if a pass-through is being performed and the source language is Slang + // no downstream compiler knows how to deal with that, so probably means 'HLSL' + sourceLanguage = + (sourceLanguage == SourceLanguage::Slang) ? SourceLanguage::HLSL : sourceLanguage; + sourceTarget = CodeGenTarget(TypeConvertUtil::getCompileTargetFromSourceLanguage( + (SlangSourceLanguage)sourceLanguage)); - // If it's pass through we accumulate the preprocessor definitions. - for (const auto& define : endToEndReq->getOptionSet().getArray(CompilerOptionName::MacroDefine)) - preprocessorDefinitions.add(define.stringValue, define.stringValue2); - for (const auto& define : translationUnit->preprocessorDefinitions) - preprocessorDefinitions.add(define); - - { - /* TODO(JS): Not totally clear what options should be set here. If we are using the pass through - then using say the defines/includes - all makes total sense. If we are generating C++ code from slang, then should we really be using these values -> aren't they what is - being set for the *slang* source, not for the C++ generated code. That being the case it implies that there needs to be a mechanism - (if there isn't already) to specify such information on a particular pass/pass through etc. + // If it's pass through we accumulate the preprocessor definitions. + for (const auto& define : + endToEndReq->getOptionSet().getArray(CompilerOptionName::MacroDefine)) + preprocessorDefinitions.add(define.stringValue, define.stringValue2); + for (const auto& define : translationUnit->preprocessorDefinitions) + preprocessorDefinitions.add(define); - On invoking DXC for example include paths do not appear to be set at all (even with pass-through). - */ + { + /* TODO(JS): Not totally clear what options should be set here. If we are using the pass + through - then using say the defines/includes all makes total sense. If we are + generating C++ code from slang, then should we really be using these values -> aren't + they what is being set for the *slang* source, not for the C++ generated code. That + being the case it implies that there needs to be a mechanism (if there isn't already) to + specify such information on a particular pass/pass through etc. - auto linkage = getLinkage(); + On invoking DXC for example include paths do not appear to be set at all (even with + pass-through). + */ - // Add all the search paths - - const auto searchDirectories = linkage->getSearchDirectories(); - const SearchDirectoryList* searchList = &searchDirectories; - while (searchList) + auto linkage = getLinkage(); + + // Add all the search paths + + const auto searchDirectories = linkage->getSearchDirectories(); + const SearchDirectoryList* searchList = &searchDirectories; + while (searchList) + { + for (const auto& searchDirectory : searchList->searchDirectories) { - for (const auto& searchDirectory : searchList->searchDirectories) - { - includePaths.add(searchDirectory.path); - } - searchList = searchList->parent; + includePaths.add(searchDirectory.path); } + searchList = searchList->parent; } + } - // If emitted source is required, emit and set the path - if (_useEmittedSource(compiler, translationUnit)) - { - CodeGenContext sourceCodeGenContext(this, sourceTarget, extensionTracker); - - SLANG_RETURN_ON_FAIL(sourceCodeGenContext.emitEntryPointsSource(sourceArtifact)); + // If emitted source is required, emit and set the path + if (_useEmittedSource(compiler, translationUnit)) + { + CodeGenContext sourceCodeGenContext(this, sourceTarget, extensionTracker); - // If it's not file based we can set an appropriate path name, and it doesn't matter if it doesn't - // exist on the file system. - // We set the name to the path as this will be used for downstream reporting. - auto sourcePath = calcSourcePathForEntryPoints(); - sourceArtifact->setName(sourcePath.getBuffer()); + SLANG_RETURN_ON_FAIL(sourceCodeGenContext.emitEntryPointsSource(sourceArtifact)); - sourceCodeGenContext.maybeDumpIntermediate(sourceArtifact); - } - else - { - // Special case if we have a single file, so that we pass the path, and the contents as is. - const auto& sourceArtifacts = translationUnit->getSourceArtifacts(); - SLANG_ASSERT(sourceArtifacts.getCount() == 1); + // If it's not file based we can set an appropriate path name, and it doesn't matter if + // it doesn't exist on the file system. We set the name to the path as this will be used + // for downstream reporting. + auto sourcePath = calcSourcePathForEntryPoints(); + sourceArtifact->setName(sourcePath.getBuffer()); - sourceArtifact = sourceArtifacts[0]; - SLANG_ASSERT(sourceArtifact); - } + sourceCodeGenContext.maybeDumpIntermediate(sourceArtifact); } else { - CodeGenContext sourceCodeGenContext(this, sourceTarget, extensionTracker); + // Special case if we have a single file, so that we pass the path, and the contents as + // is. + const auto& sourceArtifacts = translationUnit->getSourceArtifacts(); + SLANG_ASSERT(sourceArtifacts.getCount() == 1); - sourceCodeGenContext.removeAvailableInDownstreamIR = true; + sourceArtifact = sourceArtifacts[0]; + SLANG_ASSERT(sourceArtifact); + } + } + else + { + CodeGenContext sourceCodeGenContext(this, sourceTarget, extensionTracker); - SLANG_RETURN_ON_FAIL(sourceCodeGenContext.emitEntryPointsSource(sourceArtifact)); - sourceCodeGenContext.maybeDumpIntermediate(sourceArtifact); + sourceCodeGenContext.removeAvailableInDownstreamIR = true; - sourceLanguage = (SourceLanguage)TypeConvertUtil::getSourceLanguageFromTarget((SlangCompileTarget)sourceTarget); - } + SLANG_RETURN_ON_FAIL(sourceCodeGenContext.emitEntryPointsSource(sourceArtifact)); + sourceCodeGenContext.maybeDumpIntermediate(sourceArtifact); - if (sourceArtifact) - { - // Set the source artifacts - options.sourceArtifacts = makeSlice(sourceArtifact.readRef(), 1); - } + sourceLanguage = (SourceLanguage)TypeConvertUtil::getSourceLanguageFromTarget( + (SlangCompileTarget)sourceTarget); + } - // Add any preprocessor definitions associated with the linkage - { - // TODO(JS): This is somewhat arguable - should defines passed to Slang really be - // passed to downstream compilers? It does appear consistent with the behavior if - // there is an endToEndReq. - // - // That said it's very convenient and provides way to control aspects - // of downstream compilation. + if (sourceArtifact) + { + // Set the source artifacts + options.sourceArtifacts = makeSlice(sourceArtifact.readRef(), 1); + } - for (const auto& define : getTargetProgram()->getOptionSet().getArray(CompilerOptionName::MacroDefine)) - { - preprocessorDefinitions.addIfNotExists(define.stringValue, define.stringValue2); - } - } + // Add any preprocessor definitions associated with the linkage + { + // TODO(JS): This is somewhat arguable - should defines passed to Slang really be + // passed to downstream compilers? It does appear consistent with the behavior if + // there is an endToEndReq. + // + // That said it's very convenient and provides way to control aspects + // of downstream compilation. - - // If we have an extension tracker, we may need to set options such as SPIR-V version - // and CUDA Shader Model. - if (extensionTracker) + for (const auto& define : + getTargetProgram()->getOptionSet().getArray(CompilerOptionName::MacroDefine)) { - // Look for the version - if (auto cudaTracker = as<CUDAExtensionTracker>(extensionTracker)) - { - cudaTracker->finalize(); + preprocessorDefinitions.addIfNotExists(define.stringValue, define.stringValue2); + } + } - if (cudaTracker->m_smVersion.isSet()) - { - DownstreamCompileOptions::CapabilityVersion version; - version.kind = DownstreamCompileOptions::CapabilityVersion::Kind::CUDASM; - version.version = cudaTracker->m_smVersion; - requiredCapabilityVersions.add(version); - } + // If we have an extension tracker, we may need to set options such as SPIR-V version + // and CUDA Shader Model. + if (extensionTracker) + { + // Look for the version + if (auto cudaTracker = as<CUDAExtensionTracker>(extensionTracker)) + { + cudaTracker->finalize(); - if (cudaTracker->isBaseTypeRequired(BaseType::Half)) - { - options.flags |= CompileOptions::Flag::EnableFloat16; - } - } - else if (GLSLExtensionTracker* glslTracker = as<GLSLExtensionTracker>(extensionTracker)) + if (cudaTracker->m_smVersion.isSet()) { DownstreamCompileOptions::CapabilityVersion version; - version.kind = DownstreamCompileOptions::CapabilityVersion::Kind::SPIRV; - version.version = glslTracker->getSPIRVVersion(); + version.kind = DownstreamCompileOptions::CapabilityVersion::Kind::CUDASM; + version.version = cudaTracker->m_smVersion; requiredCapabilityVersions.add(version); } - } - // Set the file sytem and source manager, as *may* be used by downstream compiler - options.fileSystemExt = getFileSystemExt(); - options.sourceManager = getSourceManager(); - - // Set the source type - options.sourceLanguage = SlangSourceLanguage(sourceLanguage); - - switch (target) + if (cudaTracker->isBaseTypeRequired(BaseType::Half)) + { + options.flags |= CompileOptions::Flag::EnableFloat16; + } + } + else if (GLSLExtensionTracker* glslTracker = as<GLSLExtensionTracker>(extensionTracker)) { - case CodeGenTarget::ShaderHostCallable: - case CodeGenTarget::ShaderSharedLibrary: - // Disable exceptions and security checks - options.flags &= ~(CompileOptions::Flag::EnableExceptionHandling | CompileOptions::Flag::EnableSecurityChecks); - break; + DownstreamCompileOptions::CapabilityVersion version; + version.kind = DownstreamCompileOptions::CapabilityVersion::Kind::SPIRV; + version.version = glslTracker->getSPIRVVersion(); + + requiredCapabilityVersions.add(version); } + } - Profile profile; + // Set the file sytem and source manager, as *may* be used by downstream compiler + options.fileSystemExt = getFileSystemExt(); + options.sourceManager = getSourceManager(); - if (compilerType == PassThroughMode::Fxc || - compilerType == PassThroughMode::Dxc || - compilerType == PassThroughMode::Glslang) - { - const auto entryPointIndices = getEntryPointIndices(); - auto targetReq = getTargetReq(); + // Set the source type + options.sourceLanguage = SlangSourceLanguage(sourceLanguage); - const auto entryPointIndicesCount = entryPointIndices.getCount(); + switch (target) + { + case CodeGenTarget::ShaderHostCallable: + case CodeGenTarget::ShaderSharedLibrary: + // Disable exceptions and security checks + options.flags &= + ~(CompileOptions::Flag::EnableExceptionHandling | + CompileOptions::Flag::EnableSecurityChecks); + break; + } - // Whole program means - // * can have 0-N entry points - // * 'doesn't build into an executable/kernel' - // - // So in some sense it is a library - if (getTargetProgram()->getOptionSet().getBoolOption(CompilerOptionName::GenerateWholeProgram)) - { - if (compilerType == PassThroughMode::Dxc) - { - // Can support no entry points on DXC because we can build libraries - profile = Profile(getTargetProgram()->getOptionSet().getEnumOption<Profile::RawEnum>(CompilerOptionName::Profile)); - } - else - { - auto downstreamCompilerName = TypeTextUtil::getPassThroughName((SlangPassThrough)compilerType); + Profile profile; - sink->diagnose(SourceLoc(), Diagnostics::downstreamCompilerDoesntSupportWholeProgramCompilation, downstreamCompilerName); - return SLANG_FAIL; - } - } - else if (entryPointIndicesCount == 1) - { - // All support a single entry point - const Index entryPointIndex = entryPointIndices[0]; + if (compilerType == PassThroughMode::Fxc || compilerType == PassThroughMode::Dxc || + compilerType == PassThroughMode::Glslang) + { + const auto entryPointIndices = getEntryPointIndices(); + auto targetReq = getTargetReq(); - auto entryPoint = getEntryPoint(entryPointIndex); - profile = getEffectiveProfile(entryPoint, targetReq); + const auto entryPointIndicesCount = entryPointIndices.getCount(); - if (_shouldSetEntryPointName(getTargetProgram())) - { - options.entryPointName = allocator.allocate(getText(entryPoint->getName())); - auto entryPointNameOverride = getProgram()->getEntryPointNameOverride(entryPointIndex); - if (entryPointNameOverride.getLength() != 0) - { - options.entryPointName = allocator.allocate(entryPointNameOverride); - } - } + // Whole program means + // * can have 0-N entry points + // * 'doesn't build into an executable/kernel' + // + // So in some sense it is a library + if (getTargetProgram()->getOptionSet().getBoolOption( + CompilerOptionName::GenerateWholeProgram)) + { + if (compilerType == PassThroughMode::Dxc) + { + // Can support no entry points on DXC because we can build libraries + profile = + Profile(getTargetProgram()->getOptionSet().getEnumOption<Profile::RawEnum>( + CompilerOptionName::Profile)); } - else + else { - // We only support a single entry point on this target - SLANG_ASSERT(!"Can only compile with a single entry point on this target"); + auto downstreamCompilerName = + TypeTextUtil::getPassThroughName((SlangPassThrough)compilerType); + + sink->diagnose( + SourceLoc(), + Diagnostics::downstreamCompilerDoesntSupportWholeProgramCompilation, + downstreamCompilerName); return SLANG_FAIL; } - - options.stage = SlangStage(profile.getStage()); + } + else if (entryPointIndicesCount == 1) + { + // All support a single entry point + const Index entryPointIndex = entryPointIndices[0]; - if (compilerType == PassThroughMode::Dxc) + auto entryPoint = getEntryPoint(entryPointIndex); + profile = getEffectiveProfile(entryPoint, targetReq); + + if (_shouldSetEntryPointName(getTargetProgram())) { - // We will enable the flag to generate proper code for 16 - bit types - // by default, as long as the user is requesting a sufficiently - // high shader model. - // - // TODO: Need to check that this is safe to enable in all cases, - // or if it will make a shader demand hardware features that - // aren't always present. - // - // TODO: Ideally the dxc back-end should be passed some information - // on the "capabilities" that were used and/or requested in the code. - // - if (profile.getVersion() >= ProfileVersion::DX_6_2) + options.entryPointName = allocator.allocate(getText(entryPoint->getName())); + auto entryPointNameOverride = + getProgram()->getEntryPointNameOverride(entryPointIndex); + if (entryPointNameOverride.getLength() != 0) { - options.flags |= CompileOptions::Flag::EnableFloat16; + options.entryPointName = allocator.allocate(entryPointNameOverride); } - - // Set the matrix layout - options.matrixLayout = (SlangMatrixLayoutMode)getTargetProgram()->getOptionSet().getMatrixLayoutMode(); } - - // Set the profile - options.profileName = allocator.allocate(GetHLSLProfileName(profile)); } - - // If we aren't using LLVM 'host callable', we want downstream compile to produce a shared library - if (compilerType != PassThroughMode::LLVM && - ArtifactDescUtil::makeDescForCompileTarget(asExternal(target)).kind == ArtifactKind::HostCallable) + else { - target = CodeGenTarget::ShaderSharedLibrary; + // We only support a single entry point on this target + SLANG_ASSERT(!"Can only compile with a single entry point on this target"); + return SLANG_FAIL; } - if (!isPassThroughEnabled()) + options.stage = SlangStage(profile.getStage()); + + if (compilerType == PassThroughMode::Dxc) { - if (_isCPUHostTarget(target)) + // We will enable the flag to generate proper code for 16 - bit types + // by default, as long as the user is requesting a sufficiently + // high shader model. + // + // TODO: Need to check that this is safe to enable in all cases, + // or if it will make a shader demand hardware features that + // aren't always present. + // + // TODO: Ideally the dxc back-end should be passed some information + // on the "capabilities" that were used and/or requested in the code. + // + if (profile.getVersion() >= ProfileVersion::DX_6_2) { - libraryPaths.add(Path::getParentDirectory(Path::getExecutablePath())); - libraryPaths.add(Path::combine(Path::getParentDirectory(Path::getExecutablePath()), "../lib")); + options.flags |= CompileOptions::Flag::EnableFloat16; + } - // Set up the library artifact - auto artifact = Artifact::create(ArtifactDesc::make(ArtifactKind::Library, Artifact::Payload::HostCPU), toSlice("slang-rt")); + // Set the matrix layout + options.matrixLayout = + (SlangMatrixLayoutMode)getTargetProgram()->getOptionSet().getMatrixLayoutMode(); + } - ComPtr<IOSFileArtifactRepresentation> fileRep(new OSFileArtifactRepresentation(IOSFileArtifactRepresentation::Kind::NameOnly, toSlice("slang-rt"), nullptr)); - artifact->addRepresentation(fileRep); + // Set the profile + options.profileName = allocator.allocate(GetHLSLProfileName(profile)); + } - libraries.add(artifact); - } + // If we aren't using LLVM 'host callable', we want downstream compile to produce a shared + // library + if (compilerType != PassThroughMode::LLVM && + ArtifactDescUtil::makeDescForCompileTarget(asExternal(target)).kind == + ArtifactKind::HostCallable) + { + target = CodeGenTarget::ShaderSharedLibrary; + } + + if (!isPassThroughEnabled()) + { + if (_isCPUHostTarget(target)) + { + libraryPaths.add(Path::getParentDirectory(Path::getExecutablePath())); + libraryPaths.add( + Path::combine(Path::getParentDirectory(Path::getExecutablePath()), "../lib")); + + // Set up the library artifact + auto artifact = Artifact::create( + ArtifactDesc::make(ArtifactKind::Library, Artifact::Payload::HostCPU), + toSlice("slang-rt")); + + ComPtr<IOSFileArtifactRepresentation> fileRep(new OSFileArtifactRepresentation( + IOSFileArtifactRepresentation::Kind::NameOnly, + toSlice("slang-rt"), + nullptr)); + artifact->addRepresentation(fileRep); + + libraries.add(artifact); } + } - options.targetType = (SlangCompileTarget)target; + options.targetType = (SlangCompileTarget)target; - // Need to configure for the compilation + // Need to configure for the compilation + { + auto linkage = getLinkage(); + + switch (getTargetProgram()->getOptionSet().getEnumOption<OptimizationLevel>( + CompilerOptionName::Optimization)) { - auto linkage = getLinkage(); + case OptimizationLevel::None: + options.optimizationLevel = DownstreamCompileOptions::OptimizationLevel::None; + break; + case OptimizationLevel::Default: + options.optimizationLevel = DownstreamCompileOptions::OptimizationLevel::Default; + break; + case OptimizationLevel::High: + options.optimizationLevel = DownstreamCompileOptions::OptimizationLevel::High; + break; + case OptimizationLevel::Maximal: + options.optimizationLevel = DownstreamCompileOptions::OptimizationLevel::Maximal; + break; + default: SLANG_ASSERT(!"Unhandled optimization level"); break; + } - switch (getTargetProgram()->getOptionSet().getEnumOption<OptimizationLevel>(CompilerOptionName::Optimization)) - { - case OptimizationLevel::None: options.optimizationLevel = DownstreamCompileOptions::OptimizationLevel::None; break; - case OptimizationLevel::Default: options.optimizationLevel = DownstreamCompileOptions::OptimizationLevel::Default; break; - case OptimizationLevel::High: options.optimizationLevel = DownstreamCompileOptions::OptimizationLevel::High; break; - case OptimizationLevel::Maximal: options.optimizationLevel = DownstreamCompileOptions::OptimizationLevel::Maximal; break; - default: SLANG_ASSERT(!"Unhandled optimization level"); break; - } + switch (getTargetProgram()->getOptionSet().getEnumOption<DebugInfoLevel>( + CompilerOptionName::DebugInformation)) + { + case DebugInfoLevel::None: + options.debugInfoType = DownstreamCompileOptions::DebugInfoType::None; + break; + case DebugInfoLevel::Minimal: + options.debugInfoType = DownstreamCompileOptions::DebugInfoType::Minimal; + break; - switch (getTargetProgram()->getOptionSet().getEnumOption<DebugInfoLevel>(CompilerOptionName::DebugInformation)) - { - case DebugInfoLevel::None: options.debugInfoType = DownstreamCompileOptions::DebugInfoType::None; break; - case DebugInfoLevel::Minimal: options.debugInfoType = DownstreamCompileOptions::DebugInfoType::Minimal; break; - - case DebugInfoLevel::Standard: options.debugInfoType = DownstreamCompileOptions::DebugInfoType::Standard; break; - case DebugInfoLevel::Maximal: options.debugInfoType = DownstreamCompileOptions::DebugInfoType::Maximal; break; - default: SLANG_ASSERT(!"Unhandled debug level"); break; - } + case DebugInfoLevel::Standard: + options.debugInfoType = DownstreamCompileOptions::DebugInfoType::Standard; + break; + case DebugInfoLevel::Maximal: + options.debugInfoType = DownstreamCompileOptions::DebugInfoType::Maximal; + break; + default: SLANG_ASSERT(!"Unhandled debug level"); break; + } - switch (getTargetProgram()->getOptionSet().getEnumOption<FloatingPointMode>(CompilerOptionName::FloatingPointMode)) - { - case FloatingPointMode::Default: options.floatingPointMode = DownstreamCompileOptions::FloatingPointMode::Default; break; - case FloatingPointMode::Precise: options.floatingPointMode = DownstreamCompileOptions::FloatingPointMode::Precise; break; - case FloatingPointMode::Fast: options.floatingPointMode = DownstreamCompileOptions::FloatingPointMode::Fast; break; - default: SLANG_ASSERT(!"Unhandled floating point mode"); - } + switch (getTargetProgram()->getOptionSet().getEnumOption<FloatingPointMode>( + CompilerOptionName::FloatingPointMode)) + { + case FloatingPointMode::Default: + options.floatingPointMode = DownstreamCompileOptions::FloatingPointMode::Default; + break; + case FloatingPointMode::Precise: + options.floatingPointMode = DownstreamCompileOptions::FloatingPointMode::Precise; + break; + case FloatingPointMode::Fast: + options.floatingPointMode = DownstreamCompileOptions::FloatingPointMode::Fast; + break; + default: SLANG_ASSERT(!"Unhandled floating point mode"); + } + { + // We need to look at the stage of the entry point(s) we are + // being asked to compile, since this will determine the + // "pipeline" that the result should be compiled for (e.g., + // compute vs. ray tracing). + // + // TODO: This logic is kind of messy in that it assumes + // a program to be compiled will only contain kernels for + // a single pipeline type, but that invariant isn't expressed + // at all in the front-end today. It also has no error + // checking for the case where there are conflicts. + // + // HACK: Right now none of the above concerns matter + // because we always perform code generation on a single + // entry point at a time. + // + Index entryPointCount = getEntryPointCount(); + for (Index ee = 0; ee < entryPointCount; ++ee) { - // We need to look at the stage of the entry point(s) we are - // being asked to compile, since this will determine the - // "pipeline" that the result should be compiled for (e.g., - // compute vs. ray tracing). - // - // TODO: This logic is kind of messy in that it assumes - // a program to be compiled will only contain kernels for - // a single pipeline type, but that invariant isn't expressed - // at all in the front-end today. It also has no error - // checking for the case where there are conflicts. - // - // HACK: Right now none of the above concerns matter - // because we always perform code generation on a single - // entry point at a time. - // - Index entryPointCount = getEntryPointCount(); - for(Index ee = 0; ee < entryPointCount; ++ee) + auto stage = getEntryPoint(ee)->getStage(); + switch (stage) { - auto stage = getEntryPoint(ee)->getStage(); - switch(stage) - { - default: - break; - - case Stage::Compute: - options.pipelineType = DownstreamCompileOptions::PipelineType::Compute; - break; - - case Stage::Vertex: - case Stage::Hull: - case Stage::Domain: - case Stage::Geometry: - case Stage::Fragment: - options.pipelineType = DownstreamCompileOptions::PipelineType::Rasterization; - break; - - case Stage::RayGeneration: - case Stage::Intersection: - case Stage::AnyHit: - case Stage::ClosestHit: - case Stage::Miss: - case Stage::Callable: - options.pipelineType = DownstreamCompileOptions::PipelineType::RayTracing; - break; - } - } + default: break; + + case Stage::Compute: + options.pipelineType = DownstreamCompileOptions::PipelineType::Compute; + break; + + case Stage::Vertex: + case Stage::Hull: + case Stage::Domain: + case Stage::Geometry: + case Stage::Fragment: + options.pipelineType = DownstreamCompileOptions::PipelineType::Rasterization; + break; + + case Stage::RayGeneration: + case Stage::Intersection: + case Stage::AnyHit: + case Stage::ClosestHit: + case Stage::Miss: + case Stage::Callable: + options.pipelineType = DownstreamCompileOptions::PipelineType::RayTracing; + break; + } } + } - // Add all the search paths (as calculated earlier - they will only be set if this is a pass through else will be empty) - options.includePaths = allocator.allocate(includePaths); + // Add all the search paths (as calculated earlier - they will only be set if this is a pass + // through else will be empty) + options.includePaths = allocator.allocate(includePaths); - // Add the specified defines (as calculated earlier - they will only be set if this is a pass through else will be empty) - { - const auto count = preprocessorDefinitions.getCount(); - auto dst = allocator.getArena().allocateArray<DownstreamCompileOptions::Define>(count); + // Add the specified defines (as calculated earlier - they will only be set if this is a + // pass through else will be empty) + { + const auto count = preprocessorDefinitions.getCount(); + auto dst = allocator.getArena().allocateArray<DownstreamCompileOptions::Define>(count); - Index i = 0; + Index i = 0; - for(const auto& [defKey, defValue] : preprocessorDefinitions) - { - auto& define = dst[i]; - - define.nameWithSig = allocator.allocate(defKey); - define.value = allocator.allocate(defValue); + for (const auto& [defKey, defValue] : preprocessorDefinitions) + { + auto& define = dst[i]; - ++i; - } - options.defines = makeSlice(dst, count); - } + define.nameWithSig = allocator.allocate(defKey); + define.value = allocator.allocate(defValue); - // Add all of the module libraries - libraries.addRange(linkage->m_libModules.getBuffer(), linkage->m_libModules.getCount()); + ++i; + } + options.defines = makeSlice(dst, count); } - auto program = getProgram(); + // Add all of the module libraries + libraries.addRange(linkage->m_libModules.getBuffer(), linkage->m_libModules.getCount()); + } + + auto program = getProgram(); - // Load embedded precompiled libraries from IR into library artifacts - program->enumerateIRModules([&](IRModule* irModule) + // Load embedded precompiled libraries from IR into library artifacts + program->enumerateIRModules( + [&](IRModule* irModule) { for (auto globalInst : irModule->getModuleInst()->getChildren()) { @@ -1577,7 +1656,8 @@ namespace Slang if (inst->getTarget() == CodeGenTarget::DXIL) { auto slice = inst->getBlob()->getStringSlice(); - ArtifactDesc desc = ArtifactDescUtil::makeDescForCompileTarget(SLANG_DXIL); + ArtifactDesc desc = + ArtifactDescUtil::makeDescForCompileTarget(SLANG_DXIL); desc.kind = ArtifactKind::Library; auto library = ArtifactUtil::createArtifact(desc); @@ -1590,1060 +1670,1097 @@ namespace Slang } }); - options.compilerSpecificArguments = allocator.allocate(compilerSpecificArguments); - options.requiredCapabilityVersions = SliceUtil::asSlice(requiredCapabilityVersions); - options.libraries = SliceUtil::asSlice(libraries); - options.libraryPaths = allocator.allocate(libraryPaths); - - // Compile - ComPtr<IArtifact> artifact; - auto downstreamStartTime = std::chrono::high_resolution_clock::now(); - SLANG_RETURN_ON_FAIL(compiler->compile(options, artifact.writeRef())); - auto downstreamElapsedTime = - (std::chrono::high_resolution_clock::now() - downstreamStartTime).count() * 0.000000001; - getSession()->addDownstreamCompileTime(downstreamElapsedTime); - - SLANG_RETURN_ON_FAIL(passthroughDownstreamDiagnostics(getSink(), compiler, artifact)); - - // Copy over all of the information associated with the source into the output - if (sourceArtifact) - { - for (auto associatedArtifact : sourceArtifact->getAssociated()) - { - artifact->addAssociated(associatedArtifact); - } - } + options.compilerSpecificArguments = allocator.allocate(compilerSpecificArguments); + options.requiredCapabilityVersions = SliceUtil::asSlice(requiredCapabilityVersions); + options.libraries = SliceUtil::asSlice(libraries); + options.libraryPaths = allocator.allocate(libraryPaths); - // Set the artifact - outArtifact.swap(artifact); - return SLANG_OK; - } + // Compile + ComPtr<IArtifact> artifact; + auto downstreamStartTime = std::chrono::high_resolution_clock::now(); + SLANG_RETURN_ON_FAIL(compiler->compile(options, artifact.writeRef())); + auto downstreamElapsedTime = + (std::chrono::high_resolution_clock::now() - downstreamStartTime).count() * 0.000000001; + getSession()->addDownstreamCompileTime(downstreamElapsedTime); - SlangResult emitSPIRVForEntryPointsDirectly( - CodeGenContext* codeGenContext, - ComPtr<IArtifact>& outArtifact); + SLANG_RETURN_ON_FAIL(passthroughDownstreamDiagnostics(getSink(), compiler, artifact)); - static CodeGenTarget _getIntermediateTarget(CodeGenTarget target) + // Copy over all of the information associated with the source into the output + if (sourceArtifact) { - switch (target) + for (auto associatedArtifact : sourceArtifact->getAssociated()) { - case CodeGenTarget::DXBytecodeAssembly: return CodeGenTarget::DXBytecode; - case CodeGenTarget::DXILAssembly: return CodeGenTarget::DXIL; - case CodeGenTarget::SPIRVAssembly: return CodeGenTarget::SPIRV; - case CodeGenTarget::WGSLSPIRVAssembly: return CodeGenTarget::WGSLSPIRV; - default: return CodeGenTarget::None; + artifact->addAssociated(associatedArtifact); } } - /// Function to simplify the logic around emitting, and dissassembling - SlangResult CodeGenContext::_emitEntryPoints(ComPtr<IArtifact>& outArtifact) - { - auto target = getTargetFormat(); - switch (target) - { - case CodeGenTarget::SPIRVAssembly: - case CodeGenTarget::DXBytecodeAssembly: - case CodeGenTarget::DXILAssembly: - case CodeGenTarget::MetalLibAssembly: - case CodeGenTarget::WGSLSPIRVAssembly: - { - // First compile to an intermediate target for the corresponding binary format. - const CodeGenTarget intermediateTarget = _getIntermediateTarget(target); - CodeGenContext intermediateContext(this, intermediateTarget); - - ComPtr<IArtifact> intermediateArtifact; - - SLANG_RETURN_ON_FAIL(intermediateContext._emitEntryPoints(intermediateArtifact)); - intermediateContext.maybeDumpIntermediate(intermediateArtifact); + // Set the artifact + outArtifact.swap(artifact); + return SLANG_OK; +} - // Then disassemble the intermediate binary result to get the desired output - // Output the disassemble - ComPtr<IArtifact> disassemblyArtifact; - SLANG_RETURN_ON_FAIL(ArtifactOutputUtil::dissassembleWithDownstream(getSession(), intermediateArtifact, getSink(), disassemblyArtifact.writeRef())); +SlangResult emitSPIRVForEntryPointsDirectly( + CodeGenContext* codeGenContext, + ComPtr<IArtifact>& outArtifact); - outArtifact.swap(disassemblyArtifact); - return SLANG_OK; - } - case CodeGenTarget::SPIRV: - if (getTargetProgram()->getOptionSet().shouldEmitSPIRVDirectly()) - { - SLANG_RETURN_ON_FAIL(emitSPIRVForEntryPointsDirectly(this, outArtifact)); - return SLANG_OK; - } - [[fallthrough]]; - case CodeGenTarget::DXIL: - case CodeGenTarget::DXBytecode: - case CodeGenTarget::MetalLib: - case CodeGenTarget::PTX: - case CodeGenTarget::ShaderHostCallable: - case CodeGenTarget::ShaderSharedLibrary: - case CodeGenTarget::HostExecutable: - case CodeGenTarget::HostHostCallable: - case CodeGenTarget::HostSharedLibrary: - case CodeGenTarget::WGSLSPIRV: - SLANG_RETURN_ON_FAIL(emitWithDownstreamForEntryPoints(outArtifact)); - return SLANG_OK; +static CodeGenTarget _getIntermediateTarget(CodeGenTarget target) +{ + switch (target) + { + case CodeGenTarget::DXBytecodeAssembly: return CodeGenTarget::DXBytecode; + case CodeGenTarget::DXILAssembly: return CodeGenTarget::DXIL; + case CodeGenTarget::SPIRVAssembly: return CodeGenTarget::SPIRV; + case CodeGenTarget::WGSLSPIRVAssembly: return CodeGenTarget::WGSLSPIRV; + default: return CodeGenTarget::None; + } +} - default: break; +/// Function to simplify the logic around emitting, and dissassembling +SlangResult CodeGenContext::_emitEntryPoints(ComPtr<IArtifact>& outArtifact) +{ + auto target = getTargetFormat(); + switch (target) + { + case CodeGenTarget::SPIRVAssembly: + case CodeGenTarget::DXBytecodeAssembly: + case CodeGenTarget::DXILAssembly: + case CodeGenTarget::MetalLibAssembly: + case CodeGenTarget::WGSLSPIRVAssembly: + { + // First compile to an intermediate target for the corresponding binary format. + const CodeGenTarget intermediateTarget = _getIntermediateTarget(target); + CodeGenContext intermediateContext(this, intermediateTarget); + + ComPtr<IArtifact> intermediateArtifact; + + SLANG_RETURN_ON_FAIL(intermediateContext._emitEntryPoints(intermediateArtifact)); + intermediateContext.maybeDumpIntermediate(intermediateArtifact); + + // Then disassemble the intermediate binary result to get the desired output + // Output the disassemble + ComPtr<IArtifact> disassemblyArtifact; + SLANG_RETURN_ON_FAIL(ArtifactOutputUtil::dissassembleWithDownstream( + getSession(), + intermediateArtifact, + getSink(), + disassemblyArtifact.writeRef())); + + outArtifact.swap(disassemblyArtifact); + return SLANG_OK; + } + case CodeGenTarget::SPIRV: + if (getTargetProgram()->getOptionSet().shouldEmitSPIRVDirectly()) + { + SLANG_RETURN_ON_FAIL(emitSPIRVForEntryPointsDirectly(this, outArtifact)); + return SLANG_OK; } + [[fallthrough]]; + case CodeGenTarget::DXIL: + case CodeGenTarget::DXBytecode: + case CodeGenTarget::MetalLib: + case CodeGenTarget::PTX: + case CodeGenTarget::ShaderHostCallable: + case CodeGenTarget::ShaderSharedLibrary: + case CodeGenTarget::HostExecutable: + case CodeGenTarget::HostHostCallable: + case CodeGenTarget::HostSharedLibrary: + case CodeGenTarget::WGSLSPIRV: + SLANG_RETURN_ON_FAIL(emitWithDownstreamForEntryPoints(outArtifact)); + return SLANG_OK; - return SLANG_FAIL; + default: break; } - // Do emit logic for a zero or more entry points - SlangResult CodeGenContext::emitEntryPoints(ComPtr<IArtifact>& outArtifact) - { - CompileTimerRAII recordCompileTime(getSession()); - - auto target = getTargetFormat(); + return SLANG_FAIL; +} - switch (target) +// Do emit logic for a zero or more entry points +SlangResult CodeGenContext::emitEntryPoints(ComPtr<IArtifact>& outArtifact) +{ + CompileTimerRAII recordCompileTime(getSession()); + + auto target = getTargetFormat(); + + switch (target) + { + case CodeGenTarget::SPIRVAssembly: + case CodeGenTarget::DXBytecodeAssembly: + case CodeGenTarget::DXILAssembly: + case CodeGenTarget::SPIRV: + case CodeGenTarget::DXIL: + case CodeGenTarget::DXBytecode: + case CodeGenTarget::MetalLib: + case CodeGenTarget::MetalLibAssembly: + case CodeGenTarget::PTX: + case CodeGenTarget::HostHostCallable: + case CodeGenTarget::ShaderHostCallable: + case CodeGenTarget::ShaderSharedLibrary: + case CodeGenTarget::HostExecutable: + case CodeGenTarget::HostSharedLibrary: + case CodeGenTarget::WGSLSPIRVAssembly: + { + SLANG_RETURN_ON_FAIL(_emitEntryPoints(outArtifact)); + + maybeDumpIntermediate(outArtifact); + return SLANG_OK; + } + break; + case CodeGenTarget::GLSL: + case CodeGenTarget::HLSL: + case CodeGenTarget::CUDASource: + case CodeGenTarget::CPPSource: + case CodeGenTarget::HostCPPSource: + case CodeGenTarget::PyTorchCppBinding: + case CodeGenTarget::CSource: + case CodeGenTarget::Metal: + case CodeGenTarget::WGSL: { - case CodeGenTarget::SPIRVAssembly: - case CodeGenTarget::DXBytecodeAssembly: - case CodeGenTarget::DXILAssembly: - case CodeGenTarget::SPIRV: - case CodeGenTarget::DXIL: - case CodeGenTarget::DXBytecode: - case CodeGenTarget::MetalLib: - case CodeGenTarget::MetalLibAssembly: - case CodeGenTarget::PTX: - case CodeGenTarget::HostHostCallable: - case CodeGenTarget::ShaderHostCallable: - case CodeGenTarget::ShaderSharedLibrary: - case CodeGenTarget::HostExecutable: - case CodeGenTarget::HostSharedLibrary: - case CodeGenTarget::WGSLSPIRVAssembly: - { - SLANG_RETURN_ON_FAIL(_emitEntryPoints(outArtifact)); + RefPtr<ExtensionTracker> extensionTracker = _newExtensionTracker(target); - maybeDumpIntermediate(outArtifact); - return SLANG_OK; - } - break; - case CodeGenTarget::GLSL: - case CodeGenTarget::HLSL: - case CodeGenTarget::CUDASource: - case CodeGenTarget::CPPSource: - case CodeGenTarget::HostCPPSource: - case CodeGenTarget::PyTorchCppBinding: - case CodeGenTarget::CSource: - case CodeGenTarget::Metal: - case CodeGenTarget::WGSL: - { - RefPtr<ExtensionTracker> extensionTracker = _newExtensionTracker(target); - - CodeGenContext subContext(this, target, extensionTracker); + CodeGenContext subContext(this, target, extensionTracker); - ComPtr<IArtifact> sourceArtifact; + ComPtr<IArtifact> sourceArtifact; - SLANG_RETURN_ON_FAIL(subContext.emitEntryPointsSource(sourceArtifact)); - - subContext.maybeDumpIntermediate(sourceArtifact); - outArtifact = sourceArtifact; - return SLANG_OK; - } - break; + SLANG_RETURN_ON_FAIL(subContext.emitEntryPointsSource(sourceArtifact)); - case CodeGenTarget::None: - // The user requested no output + subContext.maybeDumpIntermediate(sourceArtifact); + outArtifact = sourceArtifact; return SLANG_OK; + } + break; - // Note(tfoley): We currently hit this case when compiling the core module - case CodeGenTarget::Unknown: - return SLANG_OK; + case CodeGenTarget::None: + // The user requested no output + return SLANG_OK; - default: - SLANG_UNEXPECTED("unhandled code generation target"); - break; - } - return SLANG_FAIL; + // Note(tfoley): We currently hit this case when compiling the core module + case CodeGenTarget::Unknown: return SLANG_OK; + + default: SLANG_UNEXPECTED("unhandled code generation target"); break; } + return SLANG_FAIL; +} - void EndToEndCompileRequest::writeArtifactToStandardOutput(IArtifact* artifact, DiagnosticSink* sink) +void EndToEndCompileRequest::writeArtifactToStandardOutput( + IArtifact* artifact, + DiagnosticSink* sink) +{ + // If it's host callable it's not available to write to output + if (isDerivedFrom(artifact->getDesc().kind, ArtifactKind::HostCallable)) { - // If it's host callable it's not available to write to output - if (isDerivedFrom(artifact->getDesc().kind, ArtifactKind::HostCallable)) - { - return; - } - - auto session = getSession(); - ArtifactOutputUtil::maybeConvertAndWrite(session, artifact, sink, toSlice("stdout"), getWriter(WriterChannel::StdOutput)); + return; } - String EndToEndCompileRequest::_getWholeProgramPath(TargetRequest* targetReq) + auto session = getSession(); + ArtifactOutputUtil::maybeConvertAndWrite( + session, + artifact, + sink, + toSlice("stdout"), + getWriter(WriterChannel::StdOutput)); +} + +String EndToEndCompileRequest::_getWholeProgramPath(TargetRequest* targetReq) +{ + RefPtr<EndToEndCompileRequest::TargetInfo> targetInfo; + if (m_targetInfos.tryGetValue(targetReq, targetInfo)) { - RefPtr<EndToEndCompileRequest::TargetInfo> targetInfo; - if (m_targetInfos.tryGetValue(targetReq, targetInfo)) - { - return targetInfo->wholeTargetOutputPath; - } - return String(); + return targetInfo->wholeTargetOutputPath; } + return String(); +} - String EndToEndCompileRequest::_getEntryPointPath(TargetRequest* targetReq, Index entryPointIndex) +String EndToEndCompileRequest::_getEntryPointPath(TargetRequest* targetReq, Index entryPointIndex) +{ + // It is possible that we are dynamically discovering entry + // points (using `[shader(...)]` attributes), so that there + // might be entry points added to the program that did not + // get paths specified via command-line options. + // + RefPtr<EndToEndCompileRequest::TargetInfo> targetInfo; + if (m_targetInfos.tryGetValue(targetReq, targetInfo)) { - // It is possible that we are dynamically discovering entry - // points (using `[shader(...)]` attributes), so that there - // might be entry points added to the program that did not - // get paths specified via command-line options. - // - RefPtr<EndToEndCompileRequest::TargetInfo> targetInfo; - if (m_targetInfos.tryGetValue(targetReq, targetInfo)) + String outputPath; + if (targetInfo->entryPointOutputPaths.tryGetValue(entryPointIndex, outputPath)) { - String outputPath; - if (targetInfo->entryPointOutputPaths.tryGetValue(entryPointIndex, outputPath)) - { - return outputPath; - } + return outputPath; } + } - return String(); + return String(); +} + +SlangResult EndToEndCompileRequest::_writeArtifact(const String& path, IArtifact* artifact) +{ + if (path.getLength() > 0) + { + SLANG_RETURN_ON_FAIL(ArtifactOutputUtil::writeToFile(artifact, getSink(), path)); + } + else if (m_containerFormat == ContainerFormat::None) + { + // If we aren't writing to a container and we didn't write to a file, we can output to + // standard output + writeArtifactToStandardOutput(artifact, getSink()); } + return SLANG_OK; +} - SlangResult EndToEndCompileRequest::_writeArtifact(const String& path, IArtifact* artifact) +SlangResult EndToEndCompileRequest::_maybeWriteArtifact(const String& path, IArtifact* artifact) +{ + // We don't have to do anything if there is no artifact + if (!artifact) { - if (path.getLength() > 0) - { - SLANG_RETURN_ON_FAIL(ArtifactOutputUtil::writeToFile(artifact, getSink(), path)); - } - else if (m_containerFormat == ContainerFormat::None) - { - // If we aren't writing to a container and we didn't write to a file, we can output to standard output - writeArtifactToStandardOutput(artifact, getSink()); - } return SLANG_OK; } - SlangResult EndToEndCompileRequest::_maybeWriteArtifact(const String& path, IArtifact* artifact) + // If embedding is enabled... + if (m_sourceEmbedStyle != SourceEmbedUtil::Style::None) { - // We don't have to do anything if there is no artifact - if (!artifact) - { - return SLANG_OK; - } - - // If embedding is enabled... - if (m_sourceEmbedStyle != SourceEmbedUtil::Style::None) - { - SourceEmbedUtil::Options options; + SourceEmbedUtil::Options options; - options.style = m_sourceEmbedStyle; - options.variableName = m_sourceEmbedName; - options.language = (SlangSourceLanguage)m_sourceEmbedLanguage; + options.style = m_sourceEmbedStyle; + options.variableName = m_sourceEmbedName; + options.language = (SlangSourceLanguage)m_sourceEmbedLanguage; - ComPtr<IArtifact> embeddedArtifact; - SLANG_RETURN_ON_FAIL(SourceEmbedUtil::createEmbedded(artifact, options, embeddedArtifact)); + ComPtr<IArtifact> embeddedArtifact; + SLANG_RETURN_ON_FAIL(SourceEmbedUtil::createEmbedded(artifact, options, embeddedArtifact)); - if (!embeddedArtifact) - { - return SLANG_FAIL; - } - SLANG_RETURN_ON_FAIL(_writeArtifact(SourceEmbedUtil::getPath(path, options), embeddedArtifact)); - return SLANG_OK; - } - else + if (!embeddedArtifact) { - SLANG_RETURN_ON_FAIL(_writeArtifact(path, artifact)); + return SLANG_FAIL; } - + SLANG_RETURN_ON_FAIL( + _writeArtifact(SourceEmbedUtil::getPath(path, options), embeddedArtifact)); return SLANG_OK; } - - IArtifact* TargetProgram::_createWholeProgramResult( - DiagnosticSink* sink, - EndToEndCompileRequest* endToEndReq) + else { - // We want to call `emitEntryPoints` function to generate code that contains - // all the entrypoints defined in `m_program`. - // The current logic of `emitEntryPoints` takes a list of entry-point indices to - // emit code for, so we construct such a list first. - List<Int> entryPointIndices; + SLANG_RETURN_ON_FAIL(_writeArtifact(path, artifact)); + } - m_entryPointResults.setCount(m_program->getEntryPointCount()); - entryPointIndices.setCount(m_program->getEntryPointCount()); - for (Index i = 0; i < entryPointIndices.getCount(); i++) - entryPointIndices[i] = i; - - CodeGenContext::Shared sharedCodeGenContext(this, entryPointIndices, sink, endToEndReq); - CodeGenContext codeGenContext(&sharedCodeGenContext); + return SLANG_OK; +} - if (SLANG_FAILED(codeGenContext.emitEntryPoints(m_wholeProgramResult))) - { - return nullptr; - } - - return m_wholeProgramResult; - } +IArtifact* TargetProgram::_createWholeProgramResult( + DiagnosticSink* sink, + EndToEndCompileRequest* endToEndReq) +{ + // We want to call `emitEntryPoints` function to generate code that contains + // all the entrypoints defined in `m_program`. + // The current logic of `emitEntryPoints` takes a list of entry-point indices to + // emit code for, so we construct such a list first. + List<Int> entryPointIndices; + + m_entryPointResults.setCount(m_program->getEntryPointCount()); + entryPointIndices.setCount(m_program->getEntryPointCount()); + for (Index i = 0; i < entryPointIndices.getCount(); i++) + entryPointIndices[i] = i; - IArtifact* TargetProgram::_createEntryPointResult( - Int entryPointIndex, - DiagnosticSink* sink, - EndToEndCompileRequest* endToEndReq) + CodeGenContext::Shared sharedCodeGenContext(this, entryPointIndices, sink, endToEndReq); + CodeGenContext codeGenContext(&sharedCodeGenContext); + + if (SLANG_FAILED(codeGenContext.emitEntryPoints(m_wholeProgramResult))) { - // It is possible that entry points got added to the `Program` - // *after* we created this `TargetProgram`, so there might be - // a request for an entry point that we didn't allocate space for. - // - // TODO: Change the construction logic so that a `Program` is - // constructed all at once rather than incrementally, to avoid - // this problem. - // - if(entryPointIndex >= m_entryPointResults.getCount()) - m_entryPointResults.setCount(entryPointIndex + 1); + return nullptr; + } - - CodeGenContext::EntryPointIndices entryPointIndices; - entryPointIndices.add(entryPointIndex); + return m_wholeProgramResult; +} - CodeGenContext::Shared sharedCodeGenContext(this, entryPointIndices, sink, endToEndReq); - CodeGenContext codeGenContext(&sharedCodeGenContext); +IArtifact* TargetProgram::_createEntryPointResult( + Int entryPointIndex, + DiagnosticSink* sink, + EndToEndCompileRequest* endToEndReq) +{ + // It is possible that entry points got added to the `Program` + // *after* we created this `TargetProgram`, so there might be + // a request for an entry point that we didn't allocate space for. + // + // TODO: Change the construction logic so that a `Program` is + // constructed all at once rather than incrementally, to avoid + // this problem. + // + if (entryPointIndex >= m_entryPointResults.getCount()) + m_entryPointResults.setCount(entryPointIndex + 1); - codeGenContext.emitEntryPoints(m_entryPointResults[entryPointIndex]); - return m_entryPointResults[entryPointIndex]; - } + CodeGenContext::EntryPointIndices entryPointIndices; + entryPointIndices.add(entryPointIndex); - IArtifact* TargetProgram::getOrCreateWholeProgramResult( - DiagnosticSink* sink) - { - if (m_wholeProgramResult) - return m_wholeProgramResult; + CodeGenContext::Shared sharedCodeGenContext(this, entryPointIndices, sink, endToEndReq); + CodeGenContext codeGenContext(&sharedCodeGenContext); - // If we haven't yet computed a layout for this target - // program, we need to make sure that is done before - // code generation. - // - if (!getOrCreateIRModuleForLayout(sink)) - { - return nullptr; - } + codeGenContext.emitEntryPoints(m_entryPointResults[entryPointIndex]); - return _createWholeProgramResult(sink); - } + return m_entryPointResults[entryPointIndex]; +} - IArtifact* TargetProgram::getOrCreateEntryPointResult( - Int entryPointIndex, - DiagnosticSink* sink) +IArtifact* TargetProgram::getOrCreateWholeProgramResult(DiagnosticSink* sink) +{ + if (m_wholeProgramResult) + return m_wholeProgramResult; + + // If we haven't yet computed a layout for this target + // program, we need to make sure that is done before + // code generation. + // + if (!getOrCreateIRModuleForLayout(sink)) { - if(entryPointIndex >= m_entryPointResults.getCount()) - m_entryPointResults.setCount(entryPointIndex + 1); + return nullptr; + } - if(IArtifact* artifact = m_entryPointResults[entryPointIndex]) - return artifact; + return _createWholeProgramResult(sink); +} - // If we haven't yet computed a layout for this target - // program, we need to make sure that is done before - // code generation. - // - if( !getOrCreateIRModuleForLayout(sink) ) - { - return nullptr; - } +IArtifact* TargetProgram::getOrCreateEntryPointResult(Int entryPointIndex, DiagnosticSink* sink) +{ + if (entryPointIndex >= m_entryPointResults.getCount()) + m_entryPointResults.setCount(entryPointIndex + 1); - return _createEntryPointResult( - entryPointIndex, - sink); - } + if (IArtifact* artifact = m_entryPointResults[entryPointIndex]) + return artifact; - void EndToEndCompileRequest::generateOutput( - TargetProgram* targetProgram) + // If we haven't yet computed a layout for this target + // program, we need to make sure that is done before + // code generation. + // + if (!getOrCreateIRModuleForLayout(sink)) { - auto program = targetProgram->getProgram(); - - // Generate target code any entry points that - // have been requested for compilation. - auto entryPointCount = program->getEntryPointCount(); - if (targetProgram->getOptionSet().getBoolOption(CompilerOptionName::GenerateWholeProgram)) - { - targetProgram->_createWholeProgramResult(getSink(), this); - } - else - { - for (Index ii = 0; ii < entryPointCount; ++ii) - { - targetProgram->_createEntryPointResult( - ii, - getSink(), - this); - } - } + return nullptr; } - - bool _shouldWriteSourceLocs(Linkage* linkage) + return _createEntryPointResult(entryPointIndex, sink); +} + +void EndToEndCompileRequest::generateOutput(TargetProgram* targetProgram) +{ + auto program = targetProgram->getProgram(); + + // Generate target code any entry points that + // have been requested for compilation. + auto entryPointCount = program->getEntryPointCount(); + if (targetProgram->getOptionSet().getBoolOption(CompilerOptionName::GenerateWholeProgram)) { - // If debug information or source manager are not avaiable we can't/shouldn't write out locs - if (linkage->m_optionSet.getEnumOption<DebugInfoLevel>(CompilerOptionName::DebugInformation) == DebugInfoLevel::None || - linkage->getSourceManager() == nullptr) + targetProgram->_createWholeProgramResult(getSink(), this); + } + else + { + for (Index ii = 0; ii < entryPointCount; ++ii) { - return false; + targetProgram->_createEntryPointResult(ii, getSink(), this); } - - // Otherwise we do want to write out the locs - return true; } +} - SlangResult EndToEndCompileRequest::writeContainerToStream(Stream* stream) + +bool _shouldWriteSourceLocs(Linkage* linkage) +{ + // If debug information or source manager are not avaiable we can't/shouldn't write out locs + if (linkage->m_optionSet.getEnumOption<DebugInfoLevel>(CompilerOptionName::DebugInformation) == + DebugInfoLevel::None || + linkage->getSourceManager() == nullptr) { - auto linkage = getLinkage(); + return false; + } - // Set up options - SerialContainerUtil::WriteOptions options; + // Otherwise we do want to write out the locs + return true; +} - options.compressionType = linkage->m_optionSet.getEnumOption<SerialCompressionType>(CompilerOptionName::IrCompression); +SlangResult EndToEndCompileRequest::writeContainerToStream(Stream* stream) +{ + auto linkage = getLinkage(); - // If debug information is enabled, enable writing out source locs - if (_shouldWriteSourceLocs(linkage)) - { - options.optionFlags |= SerialOptionFlag::SourceLocation; - options.sourceManager = linkage->getSourceManager(); - } + // Set up options + SerialContainerUtil::WriteOptions options; - { - RiffContainer container; - { - SerialContainerData data; - SLANG_RETURN_ON_FAIL(SerialContainerUtil::addEndToEndRequestToData(this, options, data)); - SLANG_RETURN_ON_FAIL(SerialContainerUtil::write(data, options, &container)); - } - // We now write the RiffContainer to the stream - SLANG_RETURN_ON_FAIL(RiffUtil::write(container.getRoot(), true, stream)); - } + options.compressionType = linkage->m_optionSet.getEnumOption<SerialCompressionType>( + CompilerOptionName::IrCompression); - return SLANG_OK; + // If debug information is enabled, enable writing out source locs + if (_shouldWriteSourceLocs(linkage)) + { + options.optionFlags |= SerialOptionFlag::SourceLocation; + options.sourceManager = linkage->getSourceManager(); } - static IBoxValue<SourceMap>* _getObfuscatedSourceMap(TranslationUnitRequest* translationUnit) { - if (auto module = translationUnit->getModule()) + RiffContainer container; { - if (auto irModule = module->getIRModule()) - { - return irModule->getObfuscatedSourceMap(); - } + SerialContainerData data; + SLANG_RETURN_ON_FAIL( + SerialContainerUtil::addEndToEndRequestToData(this, options, data)); + SLANG_RETURN_ON_FAIL(SerialContainerUtil::write(data, options, &container)); } - return nullptr; + // We now write the RiffContainer to the stream + SLANG_RETURN_ON_FAIL(RiffUtil::write(container.getRoot(), true, stream)); } - SlangResult EndToEndCompileRequest::maybeCreateContainer() + return SLANG_OK; +} + +static IBoxValue<SourceMap>* _getObfuscatedSourceMap(TranslationUnitRequest* translationUnit) +{ + if (auto module = translationUnit->getModule()) { - m_containerArtifact.setNull(); + if (auto irModule = module->getIRModule()) + { + return irModule->getObfuscatedSourceMap(); + } + } + return nullptr; +} - List<ComPtr<IArtifact>> artifacts; +SlangResult EndToEndCompileRequest::maybeCreateContainer() +{ + m_containerArtifact.setNull(); - auto linkage = getLinkage(); - - auto program = getSpecializedGlobalAndEntryPointsComponentType(); + List<ComPtr<IArtifact>> artifacts; - for (auto targetReq : linkage->targets) - { - auto targetProgram = program->getTargetProgram(targetReq); + auto linkage = getLinkage(); + + auto program = getSpecializedGlobalAndEntryPointsComponentType(); - if (targetProgram->getOptionSet().getBoolOption(CompilerOptionName::GenerateWholeProgram)) - { - if (auto artifact = targetProgram->getExistingWholeProgramResult()) + for (auto targetReq : linkage->targets) + { + auto targetProgram = program->getTargetProgram(targetReq); + + if (targetProgram->getOptionSet().getBoolOption(CompilerOptionName::GenerateWholeProgram)) + { + if (auto artifact = targetProgram->getExistingWholeProgramResult()) + { + if (!targetProgram->getOptionSet().getBoolOption( + CompilerOptionName::EmbedDownstreamIR)) { - if (!targetProgram->getOptionSet().getBoolOption(CompilerOptionName::EmbedDownstreamIR)) - { - artifacts.add(ComPtr<IArtifact>(artifact)); - } + artifacts.add(ComPtr<IArtifact>(artifact)); } } - else + } + else + { + Index entryPointCount = program->getEntryPointCount(); + for (Index ee = 0; ee < entryPointCount; ++ee) { - Index entryPointCount = program->getEntryPointCount(); - for (Index ee = 0; ee < entryPointCount; ++ee) + if (auto artifact = targetProgram->getExistingEntryPointResult(ee)) { - if (auto artifact = targetProgram->getExistingEntryPointResult(ee)) - { - artifacts.add(ComPtr<IArtifact>(artifact)); - } + artifacts.add(ComPtr<IArtifact>(artifact)); } } } + } - // If IR emitting is enabled, add IR to the artifacts - if (m_emitIr && (m_containerFormat == ContainerFormat::SlangModule)) + // If IR emitting is enabled, add IR to the artifacts + if (m_emitIr && (m_containerFormat == ContainerFormat::SlangModule)) + { + OwnedMemoryStream stream(FileAccess::Write); + SlangResult res = writeContainerToStream(&stream); + if (SLANG_FAILED(res)) { - OwnedMemoryStream stream(FileAccess::Write); - SlangResult res = writeContainerToStream(&stream); - if (SLANG_FAILED(res)) - { - getSink()->diagnose(SourceLoc(), Diagnostics::unableToCreateModuleContainer); - return res; - } + getSink()->diagnose(SourceLoc(), Diagnostics::unableToCreateModuleContainer); + return res; + } - // Need to turn into a blob - List<uint8_t> blobData; - stream.swapContents(blobData); + // Need to turn into a blob + List<uint8_t> blobData; + stream.swapContents(blobData); - auto containerBlob = ListBlob::moveCreate(blobData); + auto containerBlob = ListBlob::moveCreate(blobData); - auto irArtifact = Artifact::create(ArtifactDesc::make(Artifact::Kind::CompileBinary, ArtifactPayload::SlangIR, ArtifactStyle::Unknown)); - irArtifact->addRepresentationUnknown(containerBlob); - - // Add the IR artifact - artifacts.add(irArtifact); - } + auto irArtifact = Artifact::create(ArtifactDesc::make( + Artifact::Kind::CompileBinary, + ArtifactPayload::SlangIR, + ArtifactStyle::Unknown)); + irArtifact->addRepresentationUnknown(containerBlob); + + // Add the IR artifact + artifacts.add(irArtifact); + } - // If there is only one artifact we can use that as the container - if (artifacts.getCount() == 1) + // If there is only one artifact we can use that as the container + if (artifacts.getCount() == 1) + { + m_containerArtifact = artifacts[0]; + } + else + { + m_containerArtifact = ArtifactUtil::createArtifact( + ArtifactDesc::make(ArtifactKind::Container, ArtifactPayload::CompileResults)); + + for (IArtifact* childArtifact : artifacts) { - m_containerArtifact = artifacts[0]; + m_containerArtifact->addChild(childArtifact); } - else - { - m_containerArtifact = ArtifactUtil::createArtifact(ArtifactDesc::make(ArtifactKind::Container, ArtifactPayload::CompileResults)); + } - for (IArtifact* childArtifact : artifacts) - { - m_containerArtifact->addChild(childArtifact); - } - } + // Get all of the source obfuscated source maps and add those + if (m_containerArtifact) + { + auto frontEndReq = getFrontEndReq(); - // Get all of the source obfuscated source maps and add those - if (m_containerArtifact) + for (auto translationUnit : frontEndReq->translationUnits) { - auto frontEndReq = getFrontEndReq(); - - for (auto translationUnit : frontEndReq->translationUnits) + // Hmmm do I have to therefore add a map for all translation units(!) + // I guess this is okay in so far as an association can always be looked up by name + if (auto sourceMap = _getObfuscatedSourceMap(translationUnit)) { - // Hmmm do I have to therefore add a map for all translation units(!) - // I guess this is okay in so far as an association can always be looked up by name - if (auto sourceMap = _getObfuscatedSourceMap(translationUnit)) - { - auto artifactDesc = ArtifactDesc::make(ArtifactKind::Json, ArtifactPayload::SourceMap, ArtifactStyle::Obfuscated); + auto artifactDesc = ArtifactDesc::make( + ArtifactKind::Json, + ArtifactPayload::SourceMap, + ArtifactStyle::Obfuscated); - // Create the source map artifact - auto sourceMapArtifact = Artifact::create(artifactDesc, sourceMap->get().m_file.getUnownedSlice()); + // Create the source map artifact + auto sourceMapArtifact = + Artifact::create(artifactDesc, sourceMap->get().m_file.getUnownedSlice()); - // Add the repesentation - sourceMapArtifact->addRepresentation(sourceMap); + // Add the repesentation + sourceMapArtifact->addRepresentation(sourceMap); - // Associate with the container - m_containerArtifact->addAssociated(sourceMapArtifact); - } + // Associate with the container + m_containerArtifact->addAssociated(sourceMapArtifact); } } - - return SLANG_OK; - } - - CompilerOptionSet& EndToEndCompileRequest::getTargetOptionSet(TargetRequest* req) - { - return req->getOptionSet(); } - CompilerOptionSet& EndToEndCompileRequest::getTargetOptionSet(Index targetIndex) - { - return m_linkage->targets[targetIndex]->getOptionSet(); - } + return SLANG_OK; +} - SlangResult EndToEndCompileRequest::maybeWriteContainer(const String& fileName) - { - // If there is no container, or filename, don't write anything - if (fileName.getLength() == 0 || !m_containerArtifact) - { - return SLANG_OK; - } +CompilerOptionSet& EndToEndCompileRequest::getTargetOptionSet(TargetRequest* req) +{ + return req->getOptionSet(); +} - // Filter the containerArtifact into things that can be written - ComPtr<IArtifact> writeArtifact; - SLANG_RETURN_ON_FAIL(ArtifactContainerUtil::filter(m_containerArtifact, writeArtifact)); +CompilerOptionSet& EndToEndCompileRequest::getTargetOptionSet(Index targetIndex) +{ + return m_linkage->targets[targetIndex]->getOptionSet(); +} - // Only write if there is something to write - if (writeArtifact) - { - SLANG_RETURN_ON_FAIL(ArtifactContainerUtil::writeContainer(writeArtifact, fileName)); - } - +SlangResult EndToEndCompileRequest::maybeWriteContainer(const String& fileName) +{ + // If there is no container, or filename, don't write anything + if (fileName.getLength() == 0 || !m_containerArtifact) + { return SLANG_OK; } - static void _writeString(Stream& stream, const char* string) + // Filter the containerArtifact into things that can be written + ComPtr<IArtifact> writeArtifact; + SLANG_RETURN_ON_FAIL(ArtifactContainerUtil::filter(m_containerArtifact, writeArtifact)); + + // Only write if there is something to write + if (writeArtifact) { - stream.write(string, strlen(string)); + SLANG_RETURN_ON_FAIL(ArtifactContainerUtil::writeContainer(writeArtifact, fileName)); } - static void _escapeDependencyString(const char* string, StringBuilder& outBuilder) + return SLANG_OK; +} + +static void _writeString(Stream& stream, const char* string) +{ + stream.write(string, strlen(string)); +} + +static void _escapeDependencyString(const char* string, StringBuilder& outBuilder) +{ + // make has unusual escaping rules, but we only care about characters that are acceptable in a + // path + for (const char* p = string; *p; ++p) { - // make has unusual escaping rules, but we only care about characters that are acceptable in a path - for (const char* p = string; *p; ++p) + char c = *p; + switch (c) { - char c = *p; - switch(c) - { - case ' ': - case ':': - case '#': - case '[': - case ']': - case '\\': - outBuilder.appendChar('\\'); - break; - - case '$': - outBuilder.appendChar('$'); - break; - } + case ' ': + case ':': + case '#': + case '[': + case ']': + case '\\': outBuilder.appendChar('\\'); break; - outBuilder.appendChar(c); + case '$': outBuilder.appendChar('$'); break; } + + outBuilder.appendChar(c); } +} - // Writes a line to the file stream, formatted like this: - // <output-file>: <dependency-file> <dependency-file...> - static void _writeDependencyStatement(Stream& stream, EndToEndCompileRequest* compileRequest, const String& outputPath) - { - if (outputPath.getLength() == 0) - return; +// Writes a line to the file stream, formatted like this: +// <output-file>: <dependency-file> <dependency-file...> +static void _writeDependencyStatement( + Stream& stream, + EndToEndCompileRequest* compileRequest, + const String& outputPath) +{ + if (outputPath.getLength() == 0) + return; - StringBuilder builder; - _escapeDependencyString(outputPath.begin(), builder); - _writeString(stream, builder.begin()); - _writeString(stream, ": "); + StringBuilder builder; + _escapeDependencyString(outputPath.begin(), builder); + _writeString(stream, builder.begin()); + _writeString(stream, ": "); - int dependencyCount = compileRequest->getDependencyFileCount(); - for (int dependencyIndex = 0; dependencyIndex < dependencyCount; ++dependencyIndex) - { - builder.clear(); - _escapeDependencyString(compileRequest->getDependencyFilePath(dependencyIndex), builder); - _writeString(stream, builder.begin()); - _writeString(stream, (dependencyIndex + 1 < dependencyCount) ? " " : "\n"); - } + int dependencyCount = compileRequest->getDependencyFileCount(); + for (int dependencyIndex = 0; dependencyIndex < dependencyCount; ++dependencyIndex) + { + builder.clear(); + _escapeDependencyString(compileRequest->getDependencyFilePath(dependencyIndex), builder); + _writeString(stream, builder.begin()); + _writeString(stream, (dependencyIndex + 1 < dependencyCount) ? " " : "\n"); } +} - // Writes a file with dependency info, with one line in the output file per compile product. - static SlangResult _writeDependencyFile(EndToEndCompileRequest* compileRequest) - { - if (compileRequest->m_dependencyOutputPath.getLength() == 0) - return SLANG_OK; +// Writes a file with dependency info, with one line in the output file per compile product. +static SlangResult _writeDependencyFile(EndToEndCompileRequest* compileRequest) +{ + if (compileRequest->m_dependencyOutputPath.getLength() == 0) + return SLANG_OK; - FileStream stream; - SLANG_RETURN_ON_FAIL(stream.init(compileRequest->m_dependencyOutputPath, FileMode::Create, FileAccess::Write, FileShare::ReadWrite)); + FileStream stream; + SLANG_RETURN_ON_FAIL(stream.init( + compileRequest->m_dependencyOutputPath, + FileMode::Create, + FileAccess::Write, + FileShare::ReadWrite)); - auto linkage = compileRequest->getLinkage(); - auto program = compileRequest->getSpecializedGlobalAndEntryPointsComponentType(); + auto linkage = compileRequest->getLinkage(); + auto program = compileRequest->getSpecializedGlobalAndEntryPointsComponentType(); - // Iterate over all the targets and their outputs - for (const auto& targetReq : linkage->targets) + // Iterate over all the targets and their outputs + for (const auto& targetReq : linkage->targets) + { + if (compileRequest->getTargetOptionSet(targetReq).getBoolOption( + CompilerOptionName::GenerateWholeProgram)) { - if (compileRequest->getTargetOptionSet(targetReq).getBoolOption(CompilerOptionName::GenerateWholeProgram)) + RefPtr<EndToEndCompileRequest::TargetInfo> targetInfo; + if (compileRequest->m_targetInfos.tryGetValue(targetReq, targetInfo)) { - RefPtr<EndToEndCompileRequest::TargetInfo> targetInfo; - if (compileRequest->m_targetInfos.tryGetValue(targetReq, targetInfo)) - { - _writeDependencyStatement(stream, compileRequest, targetInfo->wholeTargetOutputPath); - } + _writeDependencyStatement( + stream, + compileRequest, + targetInfo->wholeTargetOutputPath); } - else + } + else + { + Index entryPointCount = program->getEntryPointCount(); + for (Index entryPointIndex = 0; entryPointIndex < entryPointCount; ++entryPointIndex) { - Index entryPointCount = program->getEntryPointCount(); - for (Index entryPointIndex = 0; entryPointIndex < entryPointCount; ++entryPointIndex) + RefPtr<EndToEndCompileRequest::TargetInfo> targetInfo; + if (compileRequest->m_targetInfos.tryGetValue(targetReq, targetInfo)) { - RefPtr<EndToEndCompileRequest::TargetInfo> targetInfo; - if (compileRequest->m_targetInfos.tryGetValue(targetReq, targetInfo)) + String outputPath; + if (targetInfo->entryPointOutputPaths.tryGetValue(entryPointIndex, outputPath)) { - String outputPath; - if (targetInfo->entryPointOutputPaths.tryGetValue(entryPointIndex, outputPath)) - { - _writeDependencyStatement(stream, compileRequest, outputPath); - } + _writeDependencyStatement(stream, compileRequest, outputPath); } } } } - - return SLANG_OK; } + return SLANG_OK; +} - void EndToEndCompileRequest::generateOutput( - ComponentType* program) + +void EndToEndCompileRequest::generateOutput(ComponentType* program) +{ + // When dynamic dispatch is disabled, the program must + // be fully specialized by now. So we check if we still + // have unspecialized generic/existential parameters, + // and report them as an error. + // + auto specializationParamCount = program->getSpecializationParamCount(); + if (getOptionSet().getBoolOption(CompilerOptionName::DisableDynamicDispatch) && + specializationParamCount != 0) { - // When dynamic dispatch is disabled, the program must - // be fully specialized by now. So we check if we still - // have unspecialized generic/existential parameters, - // and report them as an error. - // - auto specializationParamCount = program->getSpecializationParamCount(); - if (getOptionSet().getBoolOption(CompilerOptionName::DisableDynamicDispatch) && specializationParamCount != 0) + auto sink = getSink(); + + for (Index ii = 0; ii < specializationParamCount; ++ii) { - auto sink = getSink(); - - for( Index ii = 0; ii < specializationParamCount; ++ii ) + auto specializationParam = program->getSpecializationParam(ii); + if (auto decl = as<Decl>(specializationParam.object)) { - auto specializationParam = program->getSpecializationParam(ii); - if( auto decl = as<Decl>(specializationParam.object) ) - { - sink->diagnose(specializationParam.loc, Diagnostics::specializationParameterOfNameNotSpecialized, decl); - } - else if( auto type = as<Type>(specializationParam.object) ) - { - sink->diagnose(specializationParam.loc, Diagnostics::specializationParameterOfNameNotSpecialized, type); - } - else - { - sink->diagnose(specializationParam.loc, Diagnostics::specializationParameterNotSpecialized); - } + sink->diagnose( + specializationParam.loc, + Diagnostics::specializationParameterOfNameNotSpecialized, + decl); + } + else if (auto type = as<Type>(specializationParam.object)) + { + sink->diagnose( + specializationParam.loc, + Diagnostics::specializationParameterOfNameNotSpecialized, + type); + } + else + { + sink->diagnose( + specializationParam.loc, + Diagnostics::specializationParameterNotSpecialized); } - - return; } + return; + } - // Go through the code-generation targets that the user - // has specified, and generate code for each of them. - // - auto linkage = getLinkage(); - for (auto targetReq : linkage->targets) - { - if (targetReq->getOptionSet().getBoolOption(CompilerOptionName::EmbedDownstreamIR)) - continue; - auto targetProgram = program->getTargetProgram(targetReq); - generateOutput(targetProgram); - } + // Go through the code-generation targets that the user + // has specified, and generate code for each of them. + // + auto linkage = getLinkage(); + for (auto targetReq : linkage->targets) + { + if (targetReq->getOptionSet().getBoolOption(CompilerOptionName::EmbedDownstreamIR)) + continue; + + auto targetProgram = program->getTargetProgram(targetReq); + generateOutput(targetProgram); } +} - void EndToEndCompileRequest::generateOutput() - { - SLANG_PROFILE; - generateOutput(getSpecializedGlobalAndEntryPointsComponentType()); +void EndToEndCompileRequest::generateOutput() +{ + SLANG_PROFILE; + generateOutput(getSpecializedGlobalAndEntryPointsComponentType()); + + // If we are in command-line mode, we might be expected to actually + // write output to one or more files here. - // If we are in command-line mode, we might be expected to actually - // write output to one or more files here. + if (m_isCommandLineCompile && m_containerFormat == ContainerFormat::None) + { + auto linkage = getLinkage(); + auto program = getSpecializedGlobalAndEntryPointsComponentType(); - if (m_isCommandLineCompile && - m_containerFormat == ContainerFormat::None) + for (auto targetReq : linkage->targets) { - auto linkage = getLinkage(); - auto program = getSpecializedGlobalAndEntryPointsComponentType(); + auto targetProgram = program->getTargetProgram(targetReq); - for (auto targetReq : linkage->targets) + if (targetProgram->getOptionSet().getBoolOption( + CompilerOptionName::GenerateWholeProgram)) { - auto targetProgram = program->getTargetProgram(targetReq); - - if (targetProgram->getOptionSet().getBoolOption(CompilerOptionName::GenerateWholeProgram)) + if (const auto artifact = targetProgram->getExistingWholeProgramResult()) { - if (const auto artifact = targetProgram->getExistingWholeProgramResult()) - { - const auto path = _getWholeProgramPath(targetReq); + const auto path = _getWholeProgramPath(targetReq); - _maybeWriteArtifact(path, artifact); - } + _maybeWriteArtifact(path, artifact); } - else + } + else + { + Index entryPointCount = program->getEntryPointCount(); + for (Index ee = 0; ee < entryPointCount; ++ee) { - Index entryPointCount = program->getEntryPointCount(); - for (Index ee = 0; ee < entryPointCount; ++ee) - { - if (const auto artifact = targetProgram->getExistingEntryPointResult(ee)) - { - const auto path = _getEntryPointPath(targetReq, ee); + if (const auto artifact = targetProgram->getExistingEntryPointResult(ee)) + { + const auto path = _getEntryPointPath(targetReq, ee); - _maybeWriteArtifact(path, artifact); - } + _maybeWriteArtifact(path, artifact); } } } } + } - // Maybe create the container - maybeCreateContainer(); + // Maybe create the container + maybeCreateContainer(); - // If it's a command line compile we may need to write the container to a file - if (m_isCommandLineCompile) - { - // TODO(JS): - // We could write the container into a source embedded format potentially + // If it's a command line compile we may need to write the container to a file + if (m_isCommandLineCompile) + { + // TODO(JS): + // We could write the container into a source embedded format potentially - maybeWriteContainer(m_containerOutputPath); + maybeWriteContainer(m_containerOutputPath); - _writeDependencyFile(this); - } + _writeDependencyFile(this); } +} - // Debug logic for dumping intermediate outputs +// Debug logic for dumping intermediate outputs - - void CodeGenContext::_dumpIntermediateMaybeWithAssembly(IArtifact* artifact) - { - _dumpIntermediate(artifact); - ComPtr<IArtifact> assembly; - ArtifactOutputUtil::maybeDisassemble(getSession(), artifact, nullptr, assembly); +void CodeGenContext::_dumpIntermediateMaybeWithAssembly(IArtifact* artifact) +{ + _dumpIntermediate(artifact); - if (assembly) - { - _dumpIntermediate(assembly); - } - } + ComPtr<IArtifact> assembly; + ArtifactOutputUtil::maybeDisassemble(getSession(), artifact, nullptr, assembly); - void CodeGenContext::_dumpIntermediate(IArtifact* artifact) + if (assembly) { - ComPtr<ISlangBlob> blob; - if (SLANG_FAILED(artifact->loadBlob(ArtifactKeep::No, blob.writeRef()))) - { - return; - } - _dumpIntermediate(artifact->getDesc(), blob->getBufferPointer(), blob->getBufferSize()); + _dumpIntermediate(assembly); } +} - void CodeGenContext::_dumpIntermediate( - const ArtifactDesc& desc, - void const* data, - size_t size) +void CodeGenContext::_dumpIntermediate(IArtifact* artifact) +{ + ComPtr<ISlangBlob> blob; + if (SLANG_FAILED(artifact->loadBlob(ArtifactKeep::No, blob.writeRef()))) { - // Try to generate a unique ID for the file to dump, - // even in cases where there might be multiple threads - // doing compilation. - // - // This is primarily a debugging aid, so we don't - // really need/want to do anything too elaborate + return; + } + _dumpIntermediate(artifact->getDesc(), blob->getBufferPointer(), blob->getBufferSize()); +} - static std::atomic<uint32_t> counter(0); +void CodeGenContext::_dumpIntermediate(const ArtifactDesc& desc, void const* data, size_t size) +{ + // Try to generate a unique ID for the file to dump, + // even in cases where there might be multiple threads + // doing compilation. + // + // This is primarily a debugging aid, so we don't + // really need/want to do anything too elaborate - const uint32_t id = ++counter; + static std::atomic<uint32_t> counter(0); - // Just use the counter for the 'base name' - StringBuilder basename; + const uint32_t id = ++counter; - // Add the prefix - basename << getIntermediateDumpPrefix(); + // Just use the counter for the 'base name' + StringBuilder basename; - // Add the id - basename << int(id); + // Add the prefix + basename << getIntermediateDumpPrefix(); - // Work out the filename based on the desc and the basename - StringBuilder filename; - ArtifactDescUtil::calcNameForDesc(desc, basename.getUnownedSlice(), filename); + // Add the id + basename << int(id); - // If didn't produce a filename, use basename with .unknown extension - if (filename.getLength() == 0) - { - filename = basename; - filename << ".unknown"; - } - - // Write to a file - ArtifactOutputUtil::writeToFile(desc, data, size, filename); - } + // Work out the filename based on the desc and the basename + StringBuilder filename; + ArtifactDescUtil::calcNameForDesc(desc, basename.getUnownedSlice(), filename); - void CodeGenContext::maybeDumpIntermediate(IArtifact* artifact) + // If didn't produce a filename, use basename with .unknown extension + if (filename.getLength() == 0) { - if (!shouldDumpIntermediates()) - return; - - - _dumpIntermediateMaybeWithAssembly(artifact); + filename = basename; + filename << ".unknown"; } - IRDumpOptions CodeGenContext::getIRDumpOptions() - { - if (auto endToEndReq = isEndToEndCompile()) - { - return endToEndReq->getFrontEndReq()->m_irDumpOptions; - } - return IRDumpOptions(); - } + // Write to a file + ArtifactOutputUtil::writeToFile(desc, data, size, filename); +} - bool CodeGenContext::shouldValidateIR() - { - return getTargetProgram()->getOptionSet().getBoolOption(CompilerOptionName::ValidateIr); - } +void CodeGenContext::maybeDumpIntermediate(IArtifact* artifact) +{ + if (!shouldDumpIntermediates()) + return; - bool CodeGenContext::shouldSkipSPIRVValidation() - { - return getTargetProgram()->getOptionSet().getBoolOption(CompilerOptionName::SkipSPIRVValidation); - } - bool CodeGenContext::shouldDumpIR() - { - return getTargetProgram()->getOptionSet().getBoolOption(CompilerOptionName::DumpIr); - } + _dumpIntermediateMaybeWithAssembly(artifact); +} - bool CodeGenContext::shouldReportCheckpointIntermediates() +IRDumpOptions CodeGenContext::getIRDumpOptions() +{ + if (auto endToEndReq = isEndToEndCompile()) { - return getTargetProgram()->getOptionSet().getBoolOption(CompilerOptionName::ReportCheckpointIntermediates); + return endToEndReq->getFrontEndReq()->m_irDumpOptions; } + return IRDumpOptions(); +} - bool CodeGenContext::shouldDumpIntermediates() - { - return getTargetProgram()->getOptionSet().getBoolOption(CompilerOptionName::DumpIntermediates); - } +bool CodeGenContext::shouldValidateIR() +{ + return getTargetProgram()->getOptionSet().getBoolOption(CompilerOptionName::ValidateIr); +} - bool CodeGenContext::shouldTrackLiveness() - { - return getTargetProgram()->getOptionSet().getBoolOption(CompilerOptionName::TrackLiveness); - } +bool CodeGenContext::shouldSkipSPIRVValidation() +{ + return getTargetProgram()->getOptionSet().getBoolOption( + CompilerOptionName::SkipSPIRVValidation); +} - String CodeGenContext::getIntermediateDumpPrefix() - { - return getTargetProgram()->getOptionSet().getStringOption(CompilerOptionName::DumpIntermediatePrefix); - } +bool CodeGenContext::shouldDumpIR() +{ + return getTargetProgram()->getOptionSet().getBoolOption(CompilerOptionName::DumpIr); +} - bool CodeGenContext::getUseUnknownImageFormatAsDefault() - { - return getTargetProgram()->getOptionSet().getBoolOption(CompilerOptionName::DefaultImageFormatUnknown); - } +bool CodeGenContext::shouldReportCheckpointIntermediates() +{ + return getTargetProgram()->getOptionSet().getBoolOption( + CompilerOptionName::ReportCheckpointIntermediates); +} - bool CodeGenContext::isSpecializationDisabled() - { - return getTargetProgram()->getOptionSet().getBoolOption(CompilerOptionName::DisableSpecialization); - } +bool CodeGenContext::shouldDumpIntermediates() +{ + return getTargetProgram()->getOptionSet().getBoolOption(CompilerOptionName::DumpIntermediates); +} - SLANG_NO_THROW SlangResult SLANG_MCALL Module::serialize(ISlangBlob** outSerializedBlob) - { - SerialContainerUtil::WriteOptions writeOptions; - writeOptions.sourceManager = getLinkage()->getSourceManager(); - OwnedMemoryStream memoryStream(FileAccess::Write); - SLANG_RETURN_ON_FAIL(SerialContainerUtil::write(this, writeOptions, &memoryStream)); - *outSerializedBlob = RawBlob::create( - memoryStream.getContents().getBuffer(), - (size_t)memoryStream.getContents().getCount()).detach(); - return SLANG_OK; - } +bool CodeGenContext::shouldTrackLiveness() +{ + return getTargetProgram()->getOptionSet().getBoolOption(CompilerOptionName::TrackLiveness); +} - SLANG_NO_THROW SlangResult SLANG_MCALL Module::writeToFile(char const* fileName) - { - SerialContainerUtil::WriteOptions writeOptions; - writeOptions.sourceManager = getLinkage()->getSourceManager(); - FileStream fileStream; - SLANG_RETURN_ON_FAIL(fileStream.init(fileName, FileMode::Create)); - return SerialContainerUtil::write(this, writeOptions, &fileStream); - } +String CodeGenContext::getIntermediateDumpPrefix() +{ + return getTargetProgram()->getOptionSet().getStringOption( + CompilerOptionName::DumpIntermediatePrefix); +} - SLANG_NO_THROW const char* SLANG_MCALL Module::getName() - { - if (m_name) - return m_name->text.getBuffer(); - return nullptr; - } +bool CodeGenContext::getUseUnknownImageFormatAsDefault() +{ + return getTargetProgram()->getOptionSet().getBoolOption( + CompilerOptionName::DefaultImageFormatUnknown); +} - SLANG_NO_THROW const char* SLANG_MCALL Module::getFilePath() - { - if (m_pathInfo.hasFoundPath()) - return m_pathInfo.foundPath.getBuffer(); - return nullptr; - } +bool CodeGenContext::isSpecializationDisabled() +{ + return getTargetProgram()->getOptionSet().getBoolOption( + CompilerOptionName::DisableSpecialization); +} - SLANG_NO_THROW const char* SLANG_MCALL Module::getUniqueIdentity() - { - if (m_pathInfo.hasUniqueIdentity()) - return m_pathInfo.getMostUniqueIdentity().getBuffer(); - return nullptr; - } +SLANG_NO_THROW SlangResult SLANG_MCALL Module::serialize(ISlangBlob** outSerializedBlob) +{ + SerialContainerUtil::WriteOptions writeOptions; + writeOptions.sourceManager = getLinkage()->getSourceManager(); + OwnedMemoryStream memoryStream(FileAccess::Write); + SLANG_RETURN_ON_FAIL(SerialContainerUtil::write(this, writeOptions, &memoryStream)); + *outSerializedBlob = RawBlob::create( + memoryStream.getContents().getBuffer(), + (size_t)memoryStream.getContents().getCount()) + .detach(); + return SLANG_OK; +} - SLANG_NO_THROW SlangInt32 SLANG_MCALL Module::getDependencyFileCount() - { - return (SlangInt32)getFileDependencies().getCount(); - } +SLANG_NO_THROW SlangResult SLANG_MCALL Module::writeToFile(char const* fileName) +{ + SerialContainerUtil::WriteOptions writeOptions; + writeOptions.sourceManager = getLinkage()->getSourceManager(); + FileStream fileStream; + SLANG_RETURN_ON_FAIL(fileStream.init(fileName, FileMode::Create)); + return SerialContainerUtil::write(this, writeOptions, &fileStream); +} - SLANG_NO_THROW char const* SLANG_MCALL Module::getDependencyFilePath( - SlangInt32 index) - { - SourceFile* sourceFile = getFileDependencies()[index]; - return sourceFile->getPathInfo().hasFoundPath() ? sourceFile->getPathInfo().foundPath.getBuffer() : nullptr; - } +SLANG_NO_THROW const char* SLANG_MCALL Module::getName() +{ + if (m_name) + return m_name->text.getBuffer(); + return nullptr; +} - void validateEntryPoint( - EntryPoint* entryPoint, - DiagnosticSink* sink); +SLANG_NO_THROW const char* SLANG_MCALL Module::getFilePath() +{ + if (m_pathInfo.hasFoundPath()) + return m_pathInfo.foundPath.getBuffer(); + return nullptr; +} - void Module::_discoverEntryPoints(DiagnosticSink* sink, const List<RefPtr<TargetRequest>>& targets) - { - if (m_entryPoints.getCount() > 0) - return; - _discoverEntryPointsImpl(m_moduleDecl, sink, targets); - } - void Module::_discoverEntryPointsImpl(ContainerDecl* containerDecl, DiagnosticSink* sink, const List<RefPtr<TargetRequest>>& targets) +SLANG_NO_THROW const char* SLANG_MCALL Module::getUniqueIdentity() +{ + if (m_pathInfo.hasUniqueIdentity()) + return m_pathInfo.getMostUniqueIdentity().getBuffer(); + return nullptr; +} + +SLANG_NO_THROW SlangInt32 SLANG_MCALL Module::getDependencyFileCount() +{ + return (SlangInt32)getFileDependencies().getCount(); +} + +SLANG_NO_THROW char const* SLANG_MCALL Module::getDependencyFilePath(SlangInt32 index) +{ + SourceFile* sourceFile = getFileDependencies()[index]; + return sourceFile->getPathInfo().hasFoundPath() + ? sourceFile->getPathInfo().foundPath.getBuffer() + : nullptr; +} + +void validateEntryPoint(EntryPoint* entryPoint, DiagnosticSink* sink); + +void Module::_discoverEntryPoints(DiagnosticSink* sink, const List<RefPtr<TargetRequest>>& targets) +{ + if (m_entryPoints.getCount() > 0) + return; + _discoverEntryPointsImpl(m_moduleDecl, sink, targets); +} +void Module::_discoverEntryPointsImpl( + ContainerDecl* containerDecl, + DiagnosticSink* sink, + const List<RefPtr<TargetRequest>>& targets) +{ + for (auto globalDecl : containerDecl->members) { - for (auto globalDecl : containerDecl->members) + auto maybeFuncDecl = globalDecl; + if (auto genericDecl = as<GenericDecl>(maybeFuncDecl)) { - auto maybeFuncDecl = globalDecl; - if (auto genericDecl = as<GenericDecl>(maybeFuncDecl)) - { - maybeFuncDecl = genericDecl->inner; - } + maybeFuncDecl = genericDecl->inner; + } + + if (as<NamespaceDeclBase>(globalDecl) || as<FileDecl>(globalDecl) || + as<StructDecl>(globalDecl)) + { + _discoverEntryPointsImpl(as<ContainerDecl>(globalDecl), sink, targets); + continue; + } + + auto funcDecl = as<FuncDecl>(maybeFuncDecl); + if (!funcDecl) + continue; + + Profile profile; + bool resolvedStageOfProfileWithEntryPoint = resolveStageOfProfileWithEntryPoint( + profile, + getLinkage()->m_optionSet, + targets, + funcDecl, + sink); + if (!resolvedStageOfProfileWithEntryPoint) + { + // If there isn't a [shader] attribute, look for a [numthreads] attribute + // since that implicitly means a compute shader. We'll not do this when compiling for + // CUDA/Torch since [numthreads] attributes are utilized differently for those targets. + // - if (as<NamespaceDeclBase>(globalDecl) || as<FileDecl>(globalDecl) || as<StructDecl>(globalDecl)) + bool allTargetsCUDARelated = true; + for (auto target : targets) { - _discoverEntryPointsImpl(as<ContainerDecl>(globalDecl), sink, targets); - continue; + if (!isCUDATarget(target) && + target->getTarget() != CodeGenTarget::PyTorchCppBinding) + { + allTargetsCUDARelated = false; + break; + } } - auto funcDecl = as<FuncDecl>(maybeFuncDecl); - if (!funcDecl) + if (allTargetsCUDARelated && targets.getCount() > 0) continue; - Profile profile; - bool resolvedStageOfProfileWithEntryPoint = resolveStageOfProfileWithEntryPoint(profile, getLinkage()->m_optionSet, targets, funcDecl, sink); - if (!resolvedStageOfProfileWithEntryPoint) + bool canDetermineStage = false; + for (auto modifier : funcDecl->modifiers) { - // If there isn't a [shader] attribute, look for a [numthreads] attribute - // since that implicitly means a compute shader. We'll not do this when compiling for - // CUDA/Torch since [numthreads] attributes are utilized differently for those targets. - // - - bool allTargetsCUDARelated = true; - for (auto target : targets) + if (as<NumThreadsAttribute>(modifier)) { - if (!isCUDATarget(target) && - target->getTarget() != CodeGenTarget::PyTorchCppBinding) - { - allTargetsCUDARelated = false; - break; - } + if (funcDecl->findModifier<OutputTopologyAttribute>()) + profile.setStage(Stage::Mesh); + else + profile.setStage(Stage::Compute); + canDetermineStage = true; + break; } - - if (allTargetsCUDARelated && targets.getCount() > 0) - continue; - - bool canDetermineStage = false; - for (auto modifier : funcDecl->modifiers) + else if (as<PatchConstantFuncAttribute>(modifier)) { - if (as<NumThreadsAttribute>(modifier)) - { - if (funcDecl->findModifier<OutputTopologyAttribute>()) - profile.setStage(Stage::Mesh); - else - profile.setStage(Stage::Compute); - canDetermineStage = true; - break; - } - else if (as<PatchConstantFuncAttribute>(modifier)) - { - profile.setStage(Stage::Hull); - canDetermineStage = true; - break; - } + profile.setStage(Stage::Hull); + canDetermineStage = true; + break; } - if (!canDetermineStage) - continue; } + if (!canDetermineStage) + continue; + } - RefPtr<EntryPoint> entryPoint = EntryPoint::create( - getLinkage(), - makeDeclRef(funcDecl), - profile); + RefPtr<EntryPoint> entryPoint = + EntryPoint::create(getLinkage(), makeDeclRef(funcDecl), profile); - validateEntryPoint(entryPoint, sink); + validateEntryPoint(entryPoint, sink); - // Note: in the case that the user didn't explicitly - // specify entry points and we are instead compiling - // a shader "library," then we do not want to automatically - // combine the entry points into groups in the generated - // `Program`, since that would be slightly too magical. - // - // Instead, each entry point will end up in a singleton - // group, so that its entry-point parameters lay out - // independent of the others. - // - _addEntryPoint(entryPoint); - } + // Note: in the case that the user didn't explicitly + // specify entry points and we are instead compiling + // a shader "library," then we do not want to automatically + // combine the entry points into groups in the generated + // `Program`, since that would be slightly too magical. + // + // Instead, each entry point will end up in a singleton + // group, so that its entry-point parameters lay out + // independent of the others. + // + _addEntryPoint(entryPoint); } } - +} // namespace Slang |
