From beae3a9d219dac1e4e3da9c357b25d06370388f3 Mon Sep 17 00:00:00 2001 From: Yong He Date: Fri, 19 Apr 2024 21:02:32 -0700 Subject: Add metal downstream compiler + metallib target. (#3990) * Add metal downstream compiler + metallib target. * Add more comments. * Add missing override. --- source/compiler-core/slang-artifact-desc-util.cpp | 7 +- .../slang-downstream-compiler-util.cpp | 2 + source/compiler-core/slang-gcc-compiler-util.cpp | 11 ++- source/compiler-core/slang-metal-compiler.cpp | 80 ++++++++++++++++++++++ source/compiler-core/slang-metal-compiler.h | 18 +++++ source/core/slang-type-text-util.cpp | 5 +- source/slang/slang-capabilities.capdef | 10 ++- source/slang/slang-compiler.cpp | 10 +++ source/slang/slang-compiler.h | 2 + source/slang/slang-emit-c-like.cpp | 2 + source/slang/slang-ir-link.cpp | 2 + source/slang/slang-options.cpp | 3 + source/slang/slang-profile-defs.h | 8 ++- source/slang/slang-type-layout.cpp | 4 ++ source/slang/slang.cpp | 14 +++- 15 files changed, 172 insertions(+), 6 deletions(-) create mode 100644 source/compiler-core/slang-metal-compiler.cpp create mode 100644 source/compiler-core/slang-metal-compiler.h (limited to 'source') diff --git a/source/compiler-core/slang-artifact-desc-util.cpp b/source/compiler-core/slang-artifact-desc-util.cpp index 2646555bc..7e3f61915 100644 --- a/source/compiler-core/slang-artifact-desc-util.cpp +++ b/source/compiler-core/slang-artifact-desc-util.cpp @@ -287,6 +287,8 @@ SLANG_HIERARCHICAL_ENUM(ArtifactStyle, SLANG_ARTIFACT_STYLE, SLANG_ARTIFACT_STYL case SLANG_OBJECT_CODE: return Desc::make(Kind::ObjectCode, Payload::HostCPU, Style::Kernel, 0); case SLANG_HOST_HOST_CALLABLE: return Desc::make(Kind::HostCallable, Payload::HostCPU, Style::Host, 0); case SLANG_METAL: return Desc::make(Kind::Source, Payload::Metal, Style::Kernel, 0); + case SLANG_METAL_LIB: return Desc::make(Kind::Executable, Payload::MetalAIR, Style::Kernel, 0); + case SLANG_METAL_LIB_ASM: return Desc::make(Kind::Assembly, Payload::MetalAIR, Style::Kernel, 0); default: break; } @@ -328,6 +330,7 @@ SLANG_HIERARCHICAL_ENUM(ArtifactStyle, SLANG_ARTIFACT_STYLE, SLANG_ARTIFACT_STYL case Payload::C: return SLANG_C_SOURCE; case Payload::Cpp: return (desc.style == Style::Host) ? SLANG_HOST_CPP_SOURCE : SLANG_CPP_SOURCE; case Payload::CUDA: return SLANG_CUDA_SOURCE; + case Payload::Metal: return SLANG_METAL; default: break; } break; @@ -340,6 +343,7 @@ SLANG_HIERARCHICAL_ENUM(ArtifactStyle, SLANG_ARTIFACT_STYLE, SLANG_ARTIFACT_STYL case Payload::DXIL: return SLANG_DXIL_ASM; case Payload::DXBC: return SLANG_DXBC_ASM; case Payload::PTX: return SLANG_PTX; + case Payload::MetalAIR: return SLANG_METAL_LIB_ASM; default: break; } } @@ -367,6 +371,7 @@ SLANG_HIERARCHICAL_ENUM(ArtifactStyle, SLANG_ARTIFACT_STYLE, SLANG_ARTIFACT_STYL case Payload::DXIL: return SLANG_DXIL; case Payload::DXBC: return SLANG_DXBC; case Payload::PTX: return SLANG_PTX; + case Payload::MetalAIR: return SLANG_METAL_LIB_ASM; default: break; } } @@ -638,7 +643,7 @@ static UnownedStringSlice _getPayloadExtension(ArtifactPayload payload) case Payload::SlangIR: return toSlice("slang-ir"); - case Payload::MetalAIR: return toSlice("air"); + case Payload::MetalAIR: return toSlice("metallib"); case Payload::PdbDebugInfo: return toSlice("pdb"); case Payload::SourceMap: return toSlice("map"); diff --git a/source/compiler-core/slang-downstream-compiler-util.cpp b/source/compiler-core/slang-downstream-compiler-util.cpp index 52bf03acc..70ecb8ad7 100644 --- a/source/compiler-core/slang-downstream-compiler-util.cpp +++ b/source/compiler-core/slang-downstream-compiler-util.cpp @@ -23,6 +23,7 @@ #include "slang-dxc-compiler.h" #include "slang-glslang-compiler.h" #include "slang-llvm-compiler.h" +#include "slang-metal-compiler.h" namespace Slang { @@ -330,6 +331,7 @@ DownstreamCompilerMatchVersion DownstreamCompilerUtil::getCompiledVersion() outFuncs[int(SLANG_PASS_THROUGH_SPIRV_OPT)] = &SpirvOptDownstreamCompilerUtil::locateCompilers; outFuncs[int(SLANG_PASS_THROUGH_LLVM)] = &LLVMDownstreamCompilerUtil::locateCompilers; outFuncs[int(SLANG_PASS_THROUGH_SPIRV_DIS)] = &SpirvDisDownstreamCompilerUtil::locateCompilers; + outFuncs[int(SLANG_PASS_THROUGH_METAL)] = &MetalDownstreamCompilerUtil::locateCompilers; } static String _getParentPath(const String& path) diff --git a/source/compiler-core/slang-gcc-compiler-util.cpp b/source/compiler-core/slang-gcc-compiler-util.cpp index 79aefc71d..2bcdfcbfa 100644 --- a/source/compiler-core/slang-gcc-compiler-util.cpp +++ b/source/compiler-core/slang-gcc-compiler-util.cpp @@ -107,12 +107,15 @@ SlangResult GCCDownstreamCompilerUtil::calcVersion(const ExecutableLocation& exe UnownedStringSlice::fromLiteral("clang version"), UnownedStringSlice::fromLiteral("gcc version"), UnownedStringSlice::fromLiteral("Apple LLVM version"), + UnownedStringSlice::fromLiteral("Apple metal version"), + }; const SlangPassThrough types[] = { SLANG_PASS_THROUGH_CLANG, SLANG_PASS_THROUGH_GCC, SLANG_PASS_THROUGH_CLANG, + SLANG_PASS_THROUGH_METAL, }; SLANG_COMPILE_TIME_ASSERT(SLANG_COUNT_OF(prefixes) == SLANG_COUNT_OF(types)); @@ -262,8 +265,9 @@ static SlangResult _parseGCCFamilyLine(SliceAllocator& allocator, const UnownedS const auto split1 = split[1].trim(); const auto text = split[2].trim(); - // Check for special handling for clang (Can be Clang or clang apparently) + // Check for special handling for clang or metal if (split0.startsWith(UnownedStringSlice::fromLiteral("clang")) || + split0.startsWith(UnownedStringSlice::fromLiteral("metal")) || split0.startsWith(UnownedStringSlice::fromLiteral("Clang")) || split0 == UnownedStringSlice::fromLiteral("g++") || split0 == UnownedStringSlice::fromLiteral("gcc")) @@ -469,6 +473,11 @@ static SlangResult _parseGCCFamilyLine(SliceAllocator& allocator, const UnownedS // C++17 since we share headers with slang itself (which uses c++17) cmdLine.addArg("-std=c++17"); } + + if (targetDesc.payload == ArtifactDesc::Payload::MetalAIR) + { + cmdLine.addArg("-std=macos-metal2.3"); + } // Our generated code very often casts between dissimilar types with the // knowledge that they have the same representation. This is strictly diff --git a/source/compiler-core/slang-metal-compiler.cpp b/source/compiler-core/slang-metal-compiler.cpp new file mode 100644 index 000000000..04bcf0f57 --- /dev/null +++ b/source/compiler-core/slang-metal-compiler.cpp @@ -0,0 +1,80 @@ +#include "slang-metal-compiler.h" +#include "slang-gcc-compiler-util.h" +#include "slang-artifact-desc-util.h" +#include "slang-artifact-util.h" +#include "slang-artifact-representation.h" + +namespace Slang +{ + + class MetalDownstreamCompiler : public DownstreamCompilerBase + { + public: + // Because the metal compiler shares the same commandline interface with clang, + // we will use GccDownstreamCompilerUtil, which implements both gcc and clang, + // to create the inner compiler and wrap it here. + // + ComPtr cppCompiler; + String executablePath; + + MetalDownstreamCompiler(ComPtr& innerCompiler, String path) + : DownstreamCompilerBase(innerCompiler->getDesc()) + , cppCompiler(innerCompiler) + , executablePath(path) + { + } + + virtual SLANG_NO_THROW bool SLANG_MCALL isFileBased() override { return true; } + + virtual SLANG_NO_THROW SlangResult SLANG_MCALL compile(const CompileOptions& options, IArtifact** outArtifact) + { + // All compile requests should be routed directly to the inner compiler. + return cppCompiler->compile(options, outArtifact); + } + + virtual SLANG_NO_THROW bool SLANG_MCALL canConvert(const ArtifactDesc& from, const ArtifactDesc& to) override + { + // Report that we can convert Metal IR to disassembly. + return ArtifactDescUtil::isDisassembly(from, to) && from.payload == ArtifactPayload::MetalAIR; + } + + virtual SLANG_NO_THROW SlangResult SLANG_MCALL convert(IArtifact* from, const ArtifactDesc& to, IArtifact** outArtifact) override + { + // Use metal-objdump to disassemble the Metal IR. + + ExecutableLocation exeLocation(executablePath, "metal-objdump"); + CommandLine cmdLine; + cmdLine.setExecutableLocation(exeLocation); + cmdLine.addArg("--disassemble"); + ComPtr srcFile; + SLANG_RETURN_ON_FAIL(from->requireFile(IArtifact::Keep::No, srcFile.writeRef())); + cmdLine.addArg(String(srcFile->getPath())); + + ExecuteResult exeRes; + SLANG_RETURN_ON_FAIL(ProcessUtil::execute(cmdLine, exeRes)); + auto artifact = ArtifactUtil::createArtifact(to); + artifact->addRepresentationUnknown(StringBlob::create(exeRes.standardOutput)); + *outArtifact = artifact.detach(); + return SLANG_OK; + } + }; + + static SlangResult locateMetalCompiler(const String& path, DownstreamCompilerSet* set) + { + ComPtr innerCppCompiler; + ExecutableLocation exeLocation(path, "metal"); + SLANG_RETURN_ON_FAIL(GCCDownstreamCompilerUtil::createCompiler(exeLocation, innerCppCompiler)); + + ComPtr compiler = ComPtr( + new MetalDownstreamCompiler(innerCppCompiler, path)); + set->addCompiler(compiler); + return SLANG_OK; + } + + SlangResult MetalDownstreamCompilerUtil::locateCompilers(const String& path, ISlangSharedLibraryLoader* loader, DownstreamCompilerSet* set) + { + SLANG_UNUSED(loader); + return locateMetalCompiler(path, set); + } + +} diff --git a/source/compiler-core/slang-metal-compiler.h b/source/compiler-core/slang-metal-compiler.h new file mode 100644 index 000000000..7a14e5fa9 --- /dev/null +++ b/source/compiler-core/slang-metal-compiler.h @@ -0,0 +1,18 @@ +#ifndef SLANG_METAL_COMPILER_UTIL_H +#define SLANG_METAL_COMPILER_UTIL_H + +#include "slang-downstream-compiler-util.h" + +#include "../core/slang-platform.h" + +namespace Slang +{ + + struct MetalDownstreamCompilerUtil + { + static SlangResult locateCompilers(const String& path, ISlangSharedLibraryLoader* loader, DownstreamCompilerSet* set); + }; + +} + +#endif diff --git a/source/core/slang-type-text-util.cpp b/source/core/slang-type-text-util.cpp index 7e1ffc439..f2f408b28 100644 --- a/source/core/slang-type-text-util.cpp +++ b/source/core/slang-type-text-util.cpp @@ -61,7 +61,9 @@ static const TypeTextUtil::CompileTargetInfo s_compileTargetInfos[] = { SLANG_SHADER_HOST_CALLABLE, "", "host-callable,callable", "Host callable" }, { SLANG_OBJECT_CODE, "obj,o", "object-code", "Object code" }, { SLANG_HOST_HOST_CALLABLE, "", "host-host-callable", "Host callable for host execution" }, - { SLANG_METAL, "metal", "metal", "Metal shader source"}, + { SLANG_METAL, "metal", "metal", "Metal shader source" }, + { SLANG_METAL_LIB, "metallib", "metallib", "Metal Library Bytecode" }, + { SLANG_METAL_LIB_ASM, "metallib-asm" "metallib-asm", "Metal Library Bytecode assembly" }, }; static const NamesDescriptionValue s_languageInfos[] = @@ -88,6 +90,7 @@ static const NamesDescriptionValue s_compilerInfos[] = { SLANG_PASS_THROUGH_NVRTC, "nvrtc", "NVRTC CUDA compiler" }, { SLANG_PASS_THROUGH_LLVM, "llvm", "LLVM/Clang `slang-llvm`" }, { SLANG_PASS_THROUGH_SPIRV_OPT, "spirv-opt", "spirv-tools SPIRV optimizer" }, + { SLANG_PASS_THROUGH_METAL, "metal", "Metal shader compiler" }, }; static const NamesDescriptionValue s_archiveTypeInfos[] = diff --git a/source/slang/slang-capabilities.capdef b/source/slang/slang-capabilities.capdef index 4e31948a2..fe11be4b2 100644 --- a/source/slang/slang-capabilities.capdef +++ b/source/slang/slang-capabilities.capdef @@ -95,6 +95,10 @@ def glsl_spirv_1_4 : glsl_spirv_1_3; def glsl_spirv_1_5 : glsl_spirv_1_4; def glsl_spirv_1_6 : glsl_spirv_1_5; +def metallib_2_3 : metal; +def metallib_2_4 : metallib_2_3; + + abstract stage; def vertex : stage; def fragment : stage; @@ -572,6 +576,10 @@ alias DX_6_5 = sm_6_5; alias DX_6_6 = sm_6_6; alias DX_6_7 = sm_6_7; + +alias METAL_2_3 = metallib_2_3; +alias METAL_2_4 = metallib_2_4; + alias sm_2_0_GLSL_140 = sm_4_0 | glsl | spirv_1_0 | cuda | cpp; alias sm_2_0_GLSL_400 = sm_4_0 | glsl | spirv_1_0 | cuda | cpp; alias appendstructuredbuffer = sm_5_0 + raytracing_stages_compute_fragment; @@ -679,4 +687,4 @@ alias all = _sm_6_7 + hlsl_nvapi + _GL_NV_ray_tracing_motion_blur + _GL_NV_shader_texture_footprint | spirv_1_5 + sm_6_7 + ser + shaderclock + texturefootprint + fragmentshaderinterlock + spvGroupNonUniformPartitionedNV - + spvRayTracingMotionBlurNV + spvRayTracingMotionBlurNV; \ No newline at end of file + + spvRayTracingMotionBlurNV + spvRayTracingMotionBlurNV; diff --git a/source/slang/slang-compiler.cpp b/source/slang/slang-compiler.cpp index 04536c81a..851e3115b 100644 --- a/source/slang/slang-compiler.cpp +++ b/source/slang/slang-compiler.cpp @@ -530,6 +530,11 @@ namespace Slang { return PassThroughMode::Glslang; } + case CodeGenTarget::MetalLib: + case CodeGenTarget::MetalLibAssembly: + { + return PassThroughMode::MetalC; + } case CodeGenTarget::ShaderHostCallable: case CodeGenTarget::ShaderSharedLibrary: case CodeGenTarget::HostExecutable: @@ -957,6 +962,7 @@ namespace Slang case CodeGenTarget::DXBytecode: return CodeGenTarget::HLSL; case CodeGenTarget::DXIL: return CodeGenTarget::HLSL; case CodeGenTarget::SPIRV: return CodeGenTarget::GLSL; + case CodeGenTarget::MetalLib: return CodeGenTarget::Metal; default: break; } return CodeGenTarget::Unknown; @@ -1546,6 +1552,7 @@ namespace Slang case CodeGenTarget::SPIRVAssembly: case CodeGenTarget::DXBytecodeAssembly: case CodeGenTarget::DXILAssembly: + case CodeGenTarget::MetalLibAssembly: { // First compile to an intermediate target for the corresponding binary format. const CodeGenTarget intermediateTarget = _getIntermediateTarget(target); @@ -1573,6 +1580,7 @@ namespace Slang [[fallthrough]]; case CodeGenTarget::DXIL: case CodeGenTarget::DXBytecode: + case CodeGenTarget::MetalLib: case CodeGenTarget::PTX: case CodeGenTarget::ShaderHostCallable: case CodeGenTarget::ShaderSharedLibrary: @@ -1602,6 +1610,8 @@ namespace Slang case CodeGenTarget::SPIRV: case CodeGenTarget::DXIL: case CodeGenTarget::DXBytecode: + case CodeGenTarget::MetalLib: + case CodeGenTarget::MetalLibAssembly: case CodeGenTarget::PTX: case CodeGenTarget::HostHostCallable: case CodeGenTarget::ShaderHostCallable: diff --git a/source/slang/slang-compiler.h b/source/slang/slang-compiler.h index 7f7903f8b..266c503ae 100755 --- a/source/slang/slang-compiler.h +++ b/source/slang/slang-compiler.h @@ -93,6 +93,8 @@ namespace Slang ObjectCode = SLANG_OBJECT_CODE, HostHostCallable = SLANG_HOST_HOST_CALLABLE, Metal = SLANG_METAL, + MetalLib = SLANG_METAL_LIB, + MetalLibAssembly = SLANG_METAL_LIB_ASM, CountOf = SLANG_TARGET_COUNT_OF, }; diff --git a/source/slang/slang-emit-c-like.cpp b/source/slang/slang-emit-c-like.cpp index 1926cbdcb..38708ae5e 100644 --- a/source/slang/slang-emit-c-like.cpp +++ b/source/slang/slang-emit-c-like.cpp @@ -74,6 +74,8 @@ struct CLikeSourceEmitter::ComputeEmitActionsContext case CodeGenTarget::DXBytecodeAssembly: case CodeGenTarget::DXIL: case CodeGenTarget::DXILAssembly: + case CodeGenTarget::MetalLib: + case CodeGenTarget::MetalLibAssembly: { return SourceLanguage::Unknown; } diff --git a/source/slang/slang-ir-link.cpp b/source/slang/slang-ir-link.cpp index 86e255705..4871062d4 100644 --- a/source/slang/slang-ir-link.cpp +++ b/source/slang/slang-ir-link.cpp @@ -1468,6 +1468,8 @@ static bool doesTargetAllowUnresolvedFuncSymbol(TargetRequest* req) { case CodeGenTarget::HLSL: case CodeGenTarget::Metal: + case CodeGenTarget::MetalLib: + case CodeGenTarget::MetalLibAssembly: case CodeGenTarget::DXIL: case CodeGenTarget::DXILAssembly: case CodeGenTarget::HostCPPSource: diff --git a/source/slang/slang-options.cpp b/source/slang/slang-options.cpp index 896388db0..13a11f10b 100644 --- a/source/slang/slang-options.cpp +++ b/source/slang/slang-options.cpp @@ -2816,6 +2816,9 @@ SlangResult OptionsParser::_parse( case CodeGenTarget::ShaderSharedLibrary: case CodeGenTarget::PyTorchCppBinding: case CodeGenTarget::DXIL: + case CodeGenTarget::MetalLib: + case CodeGenTarget::MetalLibAssembly: + case CodeGenTarget::Metal: rawOutput.isWholeProgram = true; break; case CodeGenTarget::SPIRV: diff --git a/source/slang/slang-profile-defs.h b/source/slang/slang-profile-defs.h index 9a9c128a5..826555d1b 100644 --- a/source/slang/slang-profile-defs.h +++ b/source/slang/slang-profile-defs.h @@ -49,7 +49,7 @@ LANGUAGE(SPIRV, spirv) LANGUAGE(SPIRV_GL, spirv_gl) LANGUAGE(C, c) LANGUAGE(CPP, cpp) - +LANGUAGE(METAL, metal) LANGUAGE_ALIAS(GLSL, glsl_gl) LANGUAGE_ALIAS(SPIRV, spirv_vk) @@ -86,6 +86,7 @@ PROFILE_STAGE_ALIAS(Fragment, fragment, Pixel) PROFILE_FAMILY(DX) PROFILE_FAMILY(GLSL) +PROFILE_FAMILY(METAL) // Profile versions PROFILE_VERSION(DX_4_0, DX) @@ -111,6 +112,9 @@ PROFILE_VERSION(GLSL_440, GLSL) PROFILE_VERSION(GLSL_450, GLSL) PROFILE_VERSION(GLSL_460, GLSL) +PROFILE_VERSION(METAL_2_3, METAL) +PROFILE_VERSION(METAL_2_4, METAL) + // Specific profiles PROFILE(DX_Compute_4_0, cs_4_0, Compute, DX_4_0) @@ -229,6 +233,8 @@ PROFILE_ALIAS(DX_None_6_5, DX_Lib_6_5, sm_6_5) PROFILE_ALIAS(DX_None_6_6, DX_Lib_6_6, sm_6_6) PROFILE_ALIAS(DX_None_6_7, DX_Lib_6_7, sm_6_7) +PROFILE(METAL_LIB_2_3, metallib_2_3, Unknown, METAL_2_3) +PROFILE(METAL_LIB_2_4, metallib_2_4, Unknown, METAL_2_4) // Define all the GLSL profiles diff --git a/source/slang/slang-type-layout.cpp b/source/slang/slang-type-layout.cpp index a350226c8..00f365ac3 100644 --- a/source/slang/slang-type-layout.cpp +++ b/source/slang/slang-type-layout.cpp @@ -1550,6 +1550,8 @@ LayoutRulesFamilyImpl* getDefaultLayoutRulesFamilyForTarget(TargetRequest* targe case CodeGenTarget::CPPSource: case CodeGenTarget::CSource: case CodeGenTarget::Metal: + case CodeGenTarget::MetalLib: + case CodeGenTarget::MetalLibAssembly: { // For now lets use some fairly simple CPU binding rules @@ -1820,6 +1822,8 @@ SourceLanguage getIntermediateSourceLanguageForTarget(TargetProgram* targetProgr return SourceLanguage::HLSL; } case CodeGenTarget::Metal: + case CodeGenTarget::MetalLib: + case CodeGenTarget::MetalLibAssembly: { return SourceLanguage::Metal; } diff --git a/source/slang/slang.cpp b/source/slang/slang.cpp index 437f0cd63..971d6056f 100644 --- a/source/slang/slang.cpp +++ b/source/slang/slang.cpp @@ -257,11 +257,13 @@ void Session::_initCodeGenTransitionMap() map.addTransition(CodeGenTarget::HLSL, CodeGenTarget::DXBytecode, PassThroughMode::Fxc); map.addTransition(CodeGenTarget::HLSL, CodeGenTarget::DXIL, PassThroughMode::Dxc); map.addTransition(CodeGenTarget::GLSL, CodeGenTarget::SPIRV, PassThroughMode::Glslang); - + map.addTransition(CodeGenTarget::Metal, CodeGenTarget::MetalLib, PassThroughMode::MetalC); // To assembly map.addTransition(CodeGenTarget::SPIRV, CodeGenTarget::SPIRVAssembly, PassThroughMode::Glslang); map.addTransition(CodeGenTarget::DXIL, CodeGenTarget::DXILAssembly, PassThroughMode::Dxc); map.addTransition(CodeGenTarget::DXBytecode, CodeGenTarget::DXBytecodeAssembly, PassThroughMode::Fxc); + map.addTransition(CodeGenTarget::MetalLib, CodeGenTarget::MetalLibAssembly, PassThroughMode::MetalC); + } void Session::addBuiltins( @@ -930,6 +932,14 @@ Profile getEffectiveProfile(EntryPoint* entryPoint, TargetRequest* target) targetProfile.setVersion(ProfileVersion::DX_5_1); } break; + case CodeGenTarget::Metal: + case CodeGenTarget::MetalLib: + case CodeGenTarget::MetalLibAssembly: + if (targetProfile.getFamily() != ProfileFamily::METAL) + { + targetProfile.setVersion(ProfileVersion::METAL_2_3); + } + break; } auto entryPointProfileVersion = entryPointProfile.getVersion(); @@ -1710,6 +1720,8 @@ CapabilitySet TargetRequest::getTargetCaps() break; case CodeGenTarget::Metal: + case CodeGenTarget::MetalLib: + case CodeGenTarget::MetalLibAssembly: atoms.add(CapabilityName::metal); break; -- cgit v1.2.3