summaryrefslogtreecommitdiff
path: root/source/slang/slang-compiler-tu.cpp
blob: b007e7b71d49c2c36bafcf46159aa9402de7f90f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
// slang-compiler-tu.cpp: Compiles translation units to target language
// and emit precompiled blobs into IR

#include "../core/slang-basic.h"
#include "slang-compiler.h"
#include "slang-ir-insts.h"
#include "slang-capability.h"

namespace Slang
{
    SLANG_NO_THROW SlangResult SLANG_MCALL Module::precompileForTargets(
        DiagnosticSink* sink,
        EndToEndCompileRequest* endToEndReq,
        TargetRequest* targetReq)
    {
        auto module = getIRModule();
        Slang::Session* session = endToEndReq->getSession();
        Slang::ASTBuilder* astBuilder = session->getGlobalASTBuilder();
        Slang::Linkage* builtinLinkage = session->getBuiltinLinkage();
        Slang::Linkage linkage(session, astBuilder, builtinLinkage);

        CapabilityName precompileRequirement = CapabilityName::Invalid;
        switch (targetReq->getTarget())
        {
        case CodeGenTarget::DXIL:
            linkage.addTarget(Slang::CodeGenTarget::DXIL);
            precompileRequirement = CapabilityName::dxil_lib;
            break;
        default:
            assert(!"Unhandled target");
            break;
        }
        SLANG_ASSERT(precompileRequirement != CapabilityName::Invalid);

        // Ensure precompilation capability requirements are met.
        auto targetCaps = targetReq->getTargetCaps();
        auto precompileRequirementsCapabilitySet = CapabilitySet(precompileRequirement);
        if (targetCaps.atLeastOneSetImpliedInOther(precompileRequirementsCapabilitySet) == CapabilitySet::ImpliesReturnFlags::NotImplied)
        {
            // If `RestrictiveCapabilityCheck` is true we will error, else we will warn.
            // error ...: dxil libraries require $0, entry point compiled with $1.
            // warn ...: dxil libraries require $0, entry point compiled with $1, implicitly upgrading capabilities.
            maybeDiagnoseWarningOrError(
                                sink,
                                targetReq->getOptionSet(),
                                DiagnosticCategory::Capability,
                                SourceLoc(),
                                Diagnostics::incompatibleWithPrecompileLib,
                                Diagnostics::incompatibleWithPrecompileLibRestrictive,
                                precompileRequirementsCapabilitySet,
                                targetCaps);

            // add precompile requirements to the cooked targetCaps
            targetCaps.join(precompileRequirementsCapabilitySet);
            if (targetCaps.isInvalid())
            {
                sink->diagnose(SourceLoc(), Diagnostics::unknownCapability, targetCaps);
                return SLANG_FAIL;
            }
            else
            {
                targetReq->setTargetCaps(targetCaps);
            }
        }

        List<RefPtr<ComponentType>> allComponentTypes;
        allComponentTypes.add(this); // Add Module as a component type

        for (auto entryPoint : this->getEntryPoints())
        {
            allComponentTypes.add(entryPoint); // Add the entry point as a component type
        }

        auto composite = CompositeComponentType::create(
            &linkage,
            allComponentTypes);

        TargetProgram tp(composite, targetReq);
        tp.getOrCreateLayout(sink);
        Slang::Index const entryPointCount = m_entryPoints.getCount();

        CodeGenContext::EntryPointIndices entryPointIndices;

        entryPointIndices.setCount(entryPointCount);
        for (Index i = 0; i < entryPointCount; i++)
            entryPointIndices[i] = i;
        CodeGenContext::Shared sharedCodeGenContext(&tp, entryPointIndices, sink, endToEndReq);
        CodeGenContext codeGenContext(&sharedCodeGenContext);

        ComPtr<IArtifact> outArtifact;
        SlangResult res = codeGenContext.emitTranslationUnit(outArtifact);
        if (res != SLANG_OK)
        {
            return res;
        }

        ISlangBlob* blob;
        outArtifact->loadBlob(ArtifactKeep::Yes, &blob);

        auto builder = IRBuilder(module);
        builder.setInsertInto(module);

        switch (targetReq->getTarget())
        {
        case CodeGenTarget::DXIL:
            builder.emitEmbeddedDXIL(blob);
            break;
        default:
            assert(!"Unhandled target");
            break;
        }

        return SLANG_OK;
    }
}