Skip to content

Commit beae3a9

Browse files
authored
Add metal downstream compiler + metallib target. (shader-slang#3990)
* Add metal downstream compiler + metallib target. * Add more comments. * Add missing override.
1 parent f9bcad3 commit beae3a9

21 files changed

+192
-6
lines changed

build/visual-studio/compiler-core/compiler-core.vcxproj

+2
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,7 @@
302302
<ClInclude Include="..\..\..\source\compiler-core\slang-lexer-diagnostic-defs.h" />
303303
<ClInclude Include="..\..\..\source\compiler-core\slang-lexer.h" />
304304
<ClInclude Include="..\..\..\source\compiler-core\slang-llvm-compiler.h" />
305+
<ClInclude Include="..\..\..\source\compiler-core\slang-metal-compiler.h" />
305306
<ClInclude Include="..\..\..\source\compiler-core\slang-misc-diagnostic-defs.h" />
306307
<ClInclude Include="..\..\..\source\compiler-core\slang-name-convention-util.h" />
307308
<ClInclude Include="..\..\..\source\compiler-core\slang-name.h" />
@@ -352,6 +353,7 @@
352353
<ClCompile Include="..\..\..\source\compiler-core\slang-language-server-protocol.cpp" />
353354
<ClCompile Include="..\..\..\source\compiler-core\slang-lexer.cpp" />
354355
<ClCompile Include="..\..\..\source\compiler-core\slang-llvm-compiler.cpp" />
356+
<ClCompile Include="..\..\..\source\compiler-core\slang-metal-compiler.cpp" />
355357
<ClCompile Include="..\..\..\source\compiler-core\slang-name-convention-util.cpp" />
356358
<ClCompile Include="..\..\..\source\compiler-core\slang-name.cpp" />
357359
<ClCompile Include="..\..\..\source\compiler-core\slang-nvrtc-compiler.cpp" />

build/visual-studio/compiler-core/compiler-core.vcxproj.filters

+6
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,9 @@
120120
<ClInclude Include="..\..\..\source\compiler-core\slang-llvm-compiler.h">
121121
<Filter>Header Files</Filter>
122122
</ClInclude>
123+
<ClInclude Include="..\..\..\source\compiler-core\slang-metal-compiler.h">
124+
<Filter>Header Files</Filter>
125+
</ClInclude>
123126
<ClInclude Include="..\..\..\source\compiler-core\slang-misc-diagnostic-defs.h">
124127
<Filter>Header Files</Filter>
125128
</ClInclude>
@@ -266,6 +269,9 @@
266269
<ClCompile Include="..\..\..\source\compiler-core\slang-llvm-compiler.cpp">
267270
<Filter>Source Files</Filter>
268271
</ClCompile>
272+
<ClCompile Include="..\..\..\source\compiler-core\slang-metal-compiler.cpp">
273+
<Filter>Source Files</Filter>
274+
</ClCompile>
269275
<ClCompile Include="..\..\..\source\compiler-core\slang-name-convention-util.cpp">
270276
<Filter>Source Files</Filter>
271277
</ClCompile>

slang.h

+2
Original file line numberDiff line numberDiff line change
@@ -610,6 +610,8 @@ extern "C"
610610
SLANG_HOST_HOST_CALLABLE, ///< Host callable host code (ie non kernel/shader)
611611
SLANG_CPP_PYTORCH_BINDING, ///< C++ PyTorch binding code.
612612
SLANG_METAL, ///< Metal shading language
613+
SLANG_METAL_LIB, ///< Metal library
614+
SLANG_METAL_LIB_ASM, ///< Metal library assembly
613615
SLANG_TARGET_COUNT_OF,
614616
};
615617

source/compiler-core/slang-artifact-desc-util.cpp

+6-1
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,8 @@ SLANG_HIERARCHICAL_ENUM(ArtifactStyle, SLANG_ARTIFACT_STYLE, SLANG_ARTIFACT_STYL
287287
case SLANG_OBJECT_CODE: return Desc::make(Kind::ObjectCode, Payload::HostCPU, Style::Kernel, 0);
288288
case SLANG_HOST_HOST_CALLABLE: return Desc::make(Kind::HostCallable, Payload::HostCPU, Style::Host, 0);
289289
case SLANG_METAL: return Desc::make(Kind::Source, Payload::Metal, Style::Kernel, 0);
290+
case SLANG_METAL_LIB: return Desc::make(Kind::Executable, Payload::MetalAIR, Style::Kernel, 0);
291+
case SLANG_METAL_LIB_ASM: return Desc::make(Kind::Assembly, Payload::MetalAIR, Style::Kernel, 0);
290292
default: break;
291293
}
292294

@@ -328,6 +330,7 @@ SLANG_HIERARCHICAL_ENUM(ArtifactStyle, SLANG_ARTIFACT_STYLE, SLANG_ARTIFACT_STYL
328330
case Payload::C: return SLANG_C_SOURCE;
329331
case Payload::Cpp: return (desc.style == Style::Host) ? SLANG_HOST_CPP_SOURCE : SLANG_CPP_SOURCE;
330332
case Payload::CUDA: return SLANG_CUDA_SOURCE;
333+
case Payload::Metal: return SLANG_METAL;
331334
default: break;
332335
}
333336
break;
@@ -340,6 +343,7 @@ SLANG_HIERARCHICAL_ENUM(ArtifactStyle, SLANG_ARTIFACT_STYLE, SLANG_ARTIFACT_STYL
340343
case Payload::DXIL: return SLANG_DXIL_ASM;
341344
case Payload::DXBC: return SLANG_DXBC_ASM;
342345
case Payload::PTX: return SLANG_PTX;
346+
case Payload::MetalAIR: return SLANG_METAL_LIB_ASM;
343347
default: break;
344348
}
345349
}
@@ -367,6 +371,7 @@ SLANG_HIERARCHICAL_ENUM(ArtifactStyle, SLANG_ARTIFACT_STYLE, SLANG_ARTIFACT_STYL
367371
case Payload::DXIL: return SLANG_DXIL;
368372
case Payload::DXBC: return SLANG_DXBC;
369373
case Payload::PTX: return SLANG_PTX;
374+
case Payload::MetalAIR: return SLANG_METAL_LIB_ASM;
370375
default: break;
371376
}
372377
}
@@ -638,7 +643,7 @@ static UnownedStringSlice _getPayloadExtension(ArtifactPayload payload)
638643

639644
case Payload::SlangIR: return toSlice("slang-ir");
640645

641-
case Payload::MetalAIR: return toSlice("air");
646+
case Payload::MetalAIR: return toSlice("metallib");
642647

643648
case Payload::PdbDebugInfo: return toSlice("pdb");
644649
case Payload::SourceMap: return toSlice("map");

source/compiler-core/slang-downstream-compiler-util.cpp

+2
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "slang-dxc-compiler.h"
2424
#include "slang-glslang-compiler.h"
2525
#include "slang-llvm-compiler.h"
26+
#include "slang-metal-compiler.h"
2627

2728
namespace Slang
2829
{
@@ -330,6 +331,7 @@ DownstreamCompilerMatchVersion DownstreamCompilerUtil::getCompiledVersion()
330331
outFuncs[int(SLANG_PASS_THROUGH_SPIRV_OPT)] = &SpirvOptDownstreamCompilerUtil::locateCompilers;
331332
outFuncs[int(SLANG_PASS_THROUGH_LLVM)] = &LLVMDownstreamCompilerUtil::locateCompilers;
332333
outFuncs[int(SLANG_PASS_THROUGH_SPIRV_DIS)] = &SpirvDisDownstreamCompilerUtil::locateCompilers;
334+
outFuncs[int(SLANG_PASS_THROUGH_METAL)] = &MetalDownstreamCompilerUtil::locateCompilers;
333335
}
334336

335337
static String _getParentPath(const String& path)

source/compiler-core/slang-gcc-compiler-util.cpp

+10-1
Original file line numberDiff line numberDiff line change
@@ -107,12 +107,15 @@ SlangResult GCCDownstreamCompilerUtil::calcVersion(const ExecutableLocation& exe
107107
UnownedStringSlice::fromLiteral("clang version"),
108108
UnownedStringSlice::fromLiteral("gcc version"),
109109
UnownedStringSlice::fromLiteral("Apple LLVM version"),
110+
UnownedStringSlice::fromLiteral("Apple metal version"),
111+
110112
};
111113
const SlangPassThrough types[] =
112114
{
113115
SLANG_PASS_THROUGH_CLANG,
114116
SLANG_PASS_THROUGH_GCC,
115117
SLANG_PASS_THROUGH_CLANG,
118+
SLANG_PASS_THROUGH_METAL,
116119
};
117120

118121
SLANG_COMPILE_TIME_ASSERT(SLANG_COUNT_OF(prefixes) == SLANG_COUNT_OF(types));
@@ -262,8 +265,9 @@ static SlangResult _parseGCCFamilyLine(SliceAllocator& allocator, const UnownedS
262265
const auto split1 = split[1].trim();
263266
const auto text = split[2].trim();
264267

265-
// Check for special handling for clang (Can be Clang or clang apparently)
268+
// Check for special handling for clang or metal
266269
if (split0.startsWith(UnownedStringSlice::fromLiteral("clang")) ||
270+
split0.startsWith(UnownedStringSlice::fromLiteral("metal")) ||
267271
split0.startsWith(UnownedStringSlice::fromLiteral("Clang")) ||
268272
split0 == UnownedStringSlice::fromLiteral("g++") ||
269273
split0 == UnownedStringSlice::fromLiteral("gcc"))
@@ -469,6 +473,11 @@ static SlangResult _parseGCCFamilyLine(SliceAllocator& allocator, const UnownedS
469473
// C++17 since we share headers with slang itself (which uses c++17)
470474
cmdLine.addArg("-std=c++17");
471475
}
476+
477+
if (targetDesc.payload == ArtifactDesc::Payload::MetalAIR)
478+
{
479+
cmdLine.addArg("-std=macos-metal2.3");
480+
}
472481

473482
// Our generated code very often casts between dissimilar types with the
474483
// knowledge that they have the same representation. This is strictly
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
#include "slang-metal-compiler.h"
2+
#include "slang-gcc-compiler-util.h"
3+
#include "slang-artifact-desc-util.h"
4+
#include "slang-artifact-util.h"
5+
#include "slang-artifact-representation.h"
6+
7+
namespace Slang
8+
{
9+
10+
class MetalDownstreamCompiler : public DownstreamCompilerBase
11+
{
12+
public:
13+
// Because the metal compiler shares the same commandline interface with clang,
14+
// we will use GccDownstreamCompilerUtil, which implements both gcc and clang,
15+
// to create the inner compiler and wrap it here.
16+
//
17+
ComPtr<IDownstreamCompiler> cppCompiler;
18+
String executablePath;
19+
20+
MetalDownstreamCompiler(ComPtr<IDownstreamCompiler>& innerCompiler, String path)
21+
: DownstreamCompilerBase(innerCompiler->getDesc())
22+
, cppCompiler(innerCompiler)
23+
, executablePath(path)
24+
{
25+
}
26+
27+
virtual SLANG_NO_THROW bool SLANG_MCALL isFileBased() override { return true; }
28+
29+
virtual SLANG_NO_THROW SlangResult SLANG_MCALL compile(const CompileOptions& options, IArtifact** outArtifact)
30+
{
31+
// All compile requests should be routed directly to the inner compiler.
32+
return cppCompiler->compile(options, outArtifact);
33+
}
34+
35+
virtual SLANG_NO_THROW bool SLANG_MCALL canConvert(const ArtifactDesc& from, const ArtifactDesc& to) override
36+
{
37+
// Report that we can convert Metal IR to disassembly.
38+
return ArtifactDescUtil::isDisassembly(from, to) && from.payload == ArtifactPayload::MetalAIR;
39+
}
40+
41+
virtual SLANG_NO_THROW SlangResult SLANG_MCALL convert(IArtifact* from, const ArtifactDesc& to, IArtifact** outArtifact) override
42+
{
43+
// Use metal-objdump to disassemble the Metal IR.
44+
45+
ExecutableLocation exeLocation(executablePath, "metal-objdump");
46+
CommandLine cmdLine;
47+
cmdLine.setExecutableLocation(exeLocation);
48+
cmdLine.addArg("--disassemble");
49+
ComPtr<IOSFileArtifactRepresentation> srcFile;
50+
SLANG_RETURN_ON_FAIL(from->requireFile(IArtifact::Keep::No, srcFile.writeRef()));
51+
cmdLine.addArg(String(srcFile->getPath()));
52+
53+
ExecuteResult exeRes;
54+
SLANG_RETURN_ON_FAIL(ProcessUtil::execute(cmdLine, exeRes));
55+
auto artifact = ArtifactUtil::createArtifact(to);
56+
artifact->addRepresentationUnknown(StringBlob::create(exeRes.standardOutput));
57+
*outArtifact = artifact.detach();
58+
return SLANG_OK;
59+
}
60+
};
61+
62+
static SlangResult locateMetalCompiler(const String& path, DownstreamCompilerSet* set)
63+
{
64+
ComPtr<IDownstreamCompiler> innerCppCompiler;
65+
ExecutableLocation exeLocation(path, "metal");
66+
SLANG_RETURN_ON_FAIL(GCCDownstreamCompilerUtil::createCompiler(exeLocation, innerCppCompiler));
67+
68+
ComPtr<IDownstreamCompiler> compiler = ComPtr<IDownstreamCompiler>(
69+
new MetalDownstreamCompiler(innerCppCompiler, path));
70+
set->addCompiler(compiler);
71+
return SLANG_OK;
72+
}
73+
74+
SlangResult MetalDownstreamCompilerUtil::locateCompilers(const String& path, ISlangSharedLibraryLoader* loader, DownstreamCompilerSet* set)
75+
{
76+
SLANG_UNUSED(loader);
77+
return locateMetalCompiler(path, set);
78+
}
79+
80+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#ifndef SLANG_METAL_COMPILER_UTIL_H
2+
#define SLANG_METAL_COMPILER_UTIL_H
3+
4+
#include "slang-downstream-compiler-util.h"
5+
6+
#include "../core/slang-platform.h"
7+
8+
namespace Slang
9+
{
10+
11+
struct MetalDownstreamCompilerUtil
12+
{
13+
static SlangResult locateCompilers(const String& path, ISlangSharedLibraryLoader* loader, DownstreamCompilerSet* set);
14+
};
15+
16+
}
17+
18+
#endif

source/core/slang-type-text-util.cpp

+4-1
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,9 @@ static const TypeTextUtil::CompileTargetInfo s_compileTargetInfos[] =
6161
{ SLANG_SHADER_HOST_CALLABLE, "", "host-callable,callable", "Host callable" },
6262
{ SLANG_OBJECT_CODE, "obj,o", "object-code", "Object code" },
6363
{ SLANG_HOST_HOST_CALLABLE, "", "host-host-callable", "Host callable for host execution" },
64-
{ SLANG_METAL, "metal", "metal", "Metal shader source"},
64+
{ SLANG_METAL, "metal", "metal", "Metal shader source" },
65+
{ SLANG_METAL_LIB, "metallib", "metallib", "Metal Library Bytecode" },
66+
{ SLANG_METAL_LIB_ASM, "metallib-asm" "metallib-asm", "Metal Library Bytecode assembly" },
6567
};
6668

6769
static const NamesDescriptionValue s_languageInfos[] =
@@ -88,6 +90,7 @@ static const NamesDescriptionValue s_compilerInfos[] =
8890
{ SLANG_PASS_THROUGH_NVRTC, "nvrtc", "NVRTC CUDA compiler" },
8991
{ SLANG_PASS_THROUGH_LLVM, "llvm", "LLVM/Clang `slang-llvm`" },
9092
{ SLANG_PASS_THROUGH_SPIRV_OPT, "spirv-opt", "spirv-tools SPIRV optimizer" },
93+
{ SLANG_PASS_THROUGH_METAL, "metal", "Metal shader compiler" },
9194
};
9295

9396
static const NamesDescriptionValue s_archiveTypeInfos[] =

source/slang/slang-capabilities.capdef

+9-1
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,10 @@ def glsl_spirv_1_4 : glsl_spirv_1_3;
9595
def glsl_spirv_1_5 : glsl_spirv_1_4;
9696
def glsl_spirv_1_6 : glsl_spirv_1_5;
9797

98+
def metallib_2_3 : metal;
99+
def metallib_2_4 : metallib_2_3;
100+
101+
98102
abstract stage;
99103
def vertex : stage;
100104
def fragment : stage;
@@ -572,6 +576,10 @@ alias DX_6_5 = sm_6_5;
572576
alias DX_6_6 = sm_6_6;
573577
alias DX_6_7 = sm_6_7;
574578

579+
580+
alias METAL_2_3 = metallib_2_3;
581+
alias METAL_2_4 = metallib_2_4;
582+
575583
alias sm_2_0_GLSL_140 = sm_4_0 | glsl | spirv_1_0 | cuda | cpp;
576584
alias sm_2_0_GLSL_400 = sm_4_0 | glsl | spirv_1_0 | cuda | cpp;
577585
alias appendstructuredbuffer = sm_5_0 + raytracing_stages_compute_fragment;
@@ -679,4 +687,4 @@ alias all = _sm_6_7 + hlsl_nvapi
679687
+ _GL_NV_ray_tracing_motion_blur + _GL_NV_shader_texture_footprint
680688
| spirv_1_5 + sm_6_7
681689
+ ser + shaderclock + texturefootprint + fragmentshaderinterlock + spvGroupNonUniformPartitionedNV
682-
+ spvRayTracingMotionBlurNV + spvRayTracingMotionBlurNV;
690+
+ spvRayTracingMotionBlurNV + spvRayTracingMotionBlurNV;

source/slang/slang-compiler.cpp

+10
Original file line numberDiff line numberDiff line change
@@ -530,6 +530,11 @@ namespace Slang
530530
{
531531
return PassThroughMode::Glslang;
532532
}
533+
case CodeGenTarget::MetalLib:
534+
case CodeGenTarget::MetalLibAssembly:
535+
{
536+
return PassThroughMode::MetalC;
537+
}
533538
case CodeGenTarget::ShaderHostCallable:
534539
case CodeGenTarget::ShaderSharedLibrary:
535540
case CodeGenTarget::HostExecutable:
@@ -957,6 +962,7 @@ namespace Slang
957962
case CodeGenTarget::DXBytecode: return CodeGenTarget::HLSL;
958963
case CodeGenTarget::DXIL: return CodeGenTarget::HLSL;
959964
case CodeGenTarget::SPIRV: return CodeGenTarget::GLSL;
965+
case CodeGenTarget::MetalLib: return CodeGenTarget::Metal;
960966
default: break;
961967
}
962968
return CodeGenTarget::Unknown;
@@ -1546,6 +1552,7 @@ namespace Slang
15461552
case CodeGenTarget::SPIRVAssembly:
15471553
case CodeGenTarget::DXBytecodeAssembly:
15481554
case CodeGenTarget::DXILAssembly:
1555+
case CodeGenTarget::MetalLibAssembly:
15491556
{
15501557
// First compile to an intermediate target for the corresponding binary format.
15511558
const CodeGenTarget intermediateTarget = _getIntermediateTarget(target);
@@ -1573,6 +1580,7 @@ namespace Slang
15731580
[[fallthrough]];
15741581
case CodeGenTarget::DXIL:
15751582
case CodeGenTarget::DXBytecode:
1583+
case CodeGenTarget::MetalLib:
15761584
case CodeGenTarget::PTX:
15771585
case CodeGenTarget::ShaderHostCallable:
15781586
case CodeGenTarget::ShaderSharedLibrary:
@@ -1602,6 +1610,8 @@ namespace Slang
16021610
case CodeGenTarget::SPIRV:
16031611
case CodeGenTarget::DXIL:
16041612
case CodeGenTarget::DXBytecode:
1613+
case CodeGenTarget::MetalLib:
1614+
case CodeGenTarget::MetalLibAssembly:
16051615
case CodeGenTarget::PTX:
16061616
case CodeGenTarget::HostHostCallable:
16071617
case CodeGenTarget::ShaderHostCallable:

source/slang/slang-compiler.h

+2
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,8 @@ namespace Slang
9393
ObjectCode = SLANG_OBJECT_CODE,
9494
HostHostCallable = SLANG_HOST_HOST_CALLABLE,
9595
Metal = SLANG_METAL,
96+
MetalLib = SLANG_METAL_LIB,
97+
MetalLibAssembly = SLANG_METAL_LIB_ASM,
9698
CountOf = SLANG_TARGET_COUNT_OF,
9799
};
98100

source/slang/slang-emit-c-like.cpp

+2
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,8 @@ struct CLikeSourceEmitter::ComputeEmitActionsContext
7474
case CodeGenTarget::DXBytecodeAssembly:
7575
case CodeGenTarget::DXIL:
7676
case CodeGenTarget::DXILAssembly:
77+
case CodeGenTarget::MetalLib:
78+
case CodeGenTarget::MetalLibAssembly:
7779
{
7880
return SourceLanguage::Unknown;
7981
}

source/slang/slang-ir-link.cpp

+2
Original file line numberDiff line numberDiff line change
@@ -1468,6 +1468,8 @@ static bool doesTargetAllowUnresolvedFuncSymbol(TargetRequest* req)
14681468
{
14691469
case CodeGenTarget::HLSL:
14701470
case CodeGenTarget::Metal:
1471+
case CodeGenTarget::MetalLib:
1472+
case CodeGenTarget::MetalLibAssembly:
14711473
case CodeGenTarget::DXIL:
14721474
case CodeGenTarget::DXILAssembly:
14731475
case CodeGenTarget::HostCPPSource:

source/slang/slang-options.cpp

+3
Original file line numberDiff line numberDiff line change
@@ -2816,6 +2816,9 @@ SlangResult OptionsParser::_parse(
28162816
case CodeGenTarget::ShaderSharedLibrary:
28172817
case CodeGenTarget::PyTorchCppBinding:
28182818
case CodeGenTarget::DXIL:
2819+
case CodeGenTarget::MetalLib:
2820+
case CodeGenTarget::MetalLibAssembly:
2821+
case CodeGenTarget::Metal:
28192822
rawOutput.isWholeProgram = true;
28202823
break;
28212824
case CodeGenTarget::SPIRV:

0 commit comments

Comments
 (0)