diff --git a/driver/cl_options.cpp b/driver/cl_options.cpp index c101cf199c..0ad7323078 100644 --- a/driver/cl_options.cpp +++ b/driver/cl_options.cpp @@ -751,7 +751,7 @@ cl::opt cl::desc("Warn for stack size bigger than the given number"), cl::value_desc("threshold")); -#if LDC_LLVM_SUPPORTED_TARGET_SPIRV || LDC_LLVM_SUPPORTED_TARGET_NVPTX +#if LDC_LLVM_SUPPORTED_TARGET_SPIRV || LDC_LLVM_SUPPORTED_TARGET_NVPTX || LDC_LLVM_SUPPORTED_TARGET_AArch64 cl::list dcomputeTargets("mdcompute-targets", cl::CommaSeparated, cl::desc("Generates code for the specified DCompute target" diff --git a/driver/cl_options.h b/driver/cl_options.h index 481b83adcc..d9d8d6445f 100644 --- a/driver/cl_options.h +++ b/driver/cl_options.h @@ -140,7 +140,7 @@ extern cl::opt saveOptimizationRecord; extern cl::opt fWarnStackSize; -#if LDC_LLVM_SUPPORTED_TARGET_SPIRV || LDC_LLVM_SUPPORTED_TARGET_NVPTX +#if LDC_LLVM_SUPPORTED_TARGET_SPIRV || LDC_LLVM_SUPPORTED_TARGET_NVPTX || LDC_LLVM_SUPPORTED_TARGET_AArch64 extern cl::list dcomputeTargets; extern cl::opt dcomputeFilePrefix; #endif diff --git a/driver/dcomputecodegenerator.cpp b/driver/dcomputecodegenerator.cpp index 534757d453..1428532261 100644 --- a/driver/dcomputecodegenerator.cpp +++ b/driver/dcomputecodegenerator.cpp @@ -17,7 +17,7 @@ #include #include -#if !(LDC_LLVM_SUPPORTED_TARGET_SPIRV || LDC_LLVM_SUPPORTED_TARGET_NVPTX) +#if !(LDC_LLVM_SUPPORTED_TARGET_SPIRV || LDC_LLVM_SUPPORTED_TARGET_NVPTX || LDC_LLVM_SUPPORTED_TARGET_AArch64) DComputeCodeGenManager::DComputeCodeGenManager(llvm::LLVMContext &c) : ctx(c) {} void DComputeCodeGenManager::emit(Module *) {} @@ -43,6 +43,20 @@ DComputeCodeGenManager::createComputeTarget(const std::string &s) { #endif } + if (s.substr(0, 6) == "metal-") { +#if LDC_LLVM_SUPPORTED_TARGET_AArch64 //&& LDC_LLVM_VER >= 2100 +#define METAL_VALID_VER_INIT 400 + const std::array valid_metal_versions = {{METAL_VALID_VER_INIT}}; + const int v = atoi(s.c_str() + 6); + if (std::find(valid_metal_versions.begin(), valid_metal_versions.end(), v) != + valid_metal_versions.end()) { + return createMetalTarget(ctx, v); + } +#else + error(Loc(), "LDC was not built with Apple Metal Dcompute support!"); +#endif + } + if (s.substr(0, 5) == "cuda-") { #if LDC_LLVM_SUPPORTED_TARGET_NVPTX #define CUDA_VALID_VER_INIT 100, 110, 120, 130, 200, 210, 300, 350, 370,\ @@ -64,14 +78,18 @@ DComputeCodeGenManager::createComputeTarget(const std::string &s) { error(Loc(), "Unrecognised or invalid DCompute targets: the format is ocl-xy0 " - "for OpenCl x.y and cuda-xy0 for CUDA CC x.y." + "for OpenCl x.y and cuda-xy0 for CUDA CC x.y and metal-xy0 for Metal x.y." #if LDC_LLVM_SUPPORTED_TARGET_SPIRV " Valid version strings for OpenCl are ocl-{" XSTR(OCL_VALID_VER_INIT) "}." #endif #if LDC_LLVM_SUPPORTED_TARGET_NVPTX " Valid version strings for CUDA are cuda-{" XSTR(CUDA_VALID_VER_INIT) "}." +#endif +#if LDC_LLVM_SUPPORTED_TARGET_AArch64 + "Valid version strings for Metal are metal-{" XSTR(METAL_VALID_VER_INIT) "}" #endif ); + #undef XSTR #undef STR @@ -106,4 +124,4 @@ DComputeCodeGenManager::~DComputeCodeGenManager() { gTargetMachine = oldGTargetMachine; } -#endif // LDC_LLVM_SUPPORTED_TARGET_SPIRV || LDC_LLVM_SUPPORTED_TARGET_NVPTX +#endif // LDC_LLVM_SUPPORTED_TARGET_SPIRV || LDC_LLVM_SUPPORTED_TARGET_NVPTX || LDC_LLVM_SUPPORTED_TARGET_AArch64 diff --git a/driver/dcomputecodegenerator.h b/driver/dcomputecodegenerator.h index 21d3fd3479..379335fa9d 100644 --- a/driver/dcomputecodegenerator.h +++ b/driver/dcomputecodegenerator.h @@ -21,7 +21,7 @@ namespace llvm { class DComputeCodeGenManager { llvm::LLVMContext &ctx; - llvm::SmallVector targets; + llvm::SmallVector targets; DComputeTarget *createComputeTarget(const std::string &s); IRState *oldGIR = nullptr; llvm::TargetMachine *oldGTargetMachine = nullptr; diff --git a/driver/main.cpp b/driver/main.cpp index df3637f55c..b42f0b6113 100644 --- a/driver/main.cpp +++ b/driver/main.cpp @@ -950,7 +950,7 @@ void registerPredefinedVersions() { VersionCondition::addPredefinedGlobalIdent("all"); VersionCondition::addPredefinedGlobalIdent("D_Version2"); -#if LDC_LLVM_SUPPORTED_TARGET_SPIRV || LDC_LLVM_SUPPORTED_TARGET_NVPTX +#if LDC_LLVM_SUPPORTED_TARGET_SPIRV || LDC_LLVM_SUPPORTED_TARGET_NVPTX || LDC_LLVM_SUPPORTED_TARGET_AArch64 if (dcomputeTargets.size() != 0) { VersionCondition::addPredefinedGlobalIdent("LDC_DCompute"); } diff --git a/driver/targetmachine.cpp b/driver/targetmachine.cpp index 6f85efd660..4187f85144 100644 --- a/driver/targetmachine.cpp +++ b/driver/targetmachine.cpp @@ -653,6 +653,16 @@ ComputeBackend::Type getComputeTargetType(llvm::Module* m) { return ComputeBackend::SPIRV; else if (a == llvm::Triple::nvptx || a == llvm::Triple::nvptx64) return ComputeBackend::NVPTX; - else - return ComputeBackend::None; + + +#if LDC_LLVM_SUPPORTED_TARGET_AArch64 && LLVM_VERSION_MAJOR >= 21 + llvm::StringRef tripleString = m->getTargetTriple().str(); +#else + llvm::StringRef tripleString = m->getTargetTriple(); +#endif + + + if (tripleString.starts_with("air64")) + return ComputeBackend::METAL; + return ComputeBackend::None; } diff --git a/driver/targetmachine.h b/driver/targetmachine.h index e0c21ee140..bf5c97625e 100644 --- a/driver/targetmachine.h +++ b/driver/targetmachine.h @@ -41,7 +41,7 @@ class Module; } namespace ComputeBackend { -enum Type { None, SPIRV, NVPTX }; +enum Type { None, SPIRV, NVPTX, METAL }; } ComputeBackend::Type getComputeTargetType(llvm::Module*); diff --git a/driver/toobj.cpp b/driver/toobj.cpp index 211d8d88f4..91b176f4cd 100644 --- a/driver/toobj.cpp +++ b/driver/toobj.cpp @@ -35,10 +35,10 @@ #include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/Analysis/TargetTransformInfo.h" #include "llvm/CodeGen/TargetSubtargetInfo.h" +#include "llvm/Transforms/IPO/AlwaysInliner.h" #include "llvm/Transforms/Utils/Cloning.h" #include "llvm/IR/Module.h" #include -#include namespace llvm { namespace codegen { @@ -58,6 +58,40 @@ void runDLLImportRelocationPass(llvm::TargetMachine &Target, llvm::Module &m) { pm.run(m); } +void inlineDComputeKernelFunctions(llvm::Module *m) { + // Create a PassManager to hold and optimize the collection of passes we are + // about to build. + llvm::legacy::PassManager Passes; + + llvm::SmallPtrSet kernelFunctions; + + // Extract all the kernel functions + if (auto *kernelMetadata = m->getNamedMetadata("air.kernel")) { + for(auto *op: kernelMetadata->operands()) { + if (auto *F = llvm::mdconst::dyn_extract(op->getOperand(0))) { + kernelFunctions.insert(F); + } + } + } + + // Prepare non-kernel functions to be inlined + for(auto& F: *m) { + if (!F.isDeclaration() && !kernelFunctions.contains(&F)) { + F.addFnAttr(llvm::Attribute::AlwaysInline); + } + } + + Passes.add(llvm::createAlwaysInlinerLegacyPass()); + + Passes.run(*m); + + // Terminate upon errors during the LLVM passes. + if (global.errors || global.warnings) { + error(Loc(), "Aborting because of errors/warnings during LLVM passes"); + fatal(); + } +} + // based on llc code, University of Illinois Open Source License void codegenModule(llvm::TargetMachine &Target, llvm::Module &m, const char *filename, @@ -73,6 +107,60 @@ void codegenModule(llvm::TargetMachine &Target, llvm::Module &m, #endif } +#ifdef LDC_LLVM_SUPPORTED_TARGET_AArch64 + if (cb == ComputeBackend::METAL) { + { + // Inline non-kernel functions for Metal dcompute target + inlineDComputeKernelFunctions(&m); + + std::error_code errinfo; + llvm::ToolOutputFile out(filename, errinfo, llvm::sys::fs::OF_None); + if (errinfo) { + error(Loc(), "cannot write file '%s': %s", filename, + errinfo.message().c_str()); + fatal(); + } + + llvm::WriteBitcodeToFile(m, out.os()); + + out.keep(); + + // Terminate upon errors during the LLVM passes. + if (global.errors || global.warnings) { + error(Loc(), "Aborting because of errors/warnings during LLVM passes!"); + fatal(); + } + } + + auto xcrunpath = llvm::sys::findProgramByName("xcrun"); + if (!xcrunpath) { + error(Loc(), "xcrun not found - XCode should be installed first!"); + fatal(); + } + + llvm::SmallString<256> metallibOutPath; + llvm::sys::fs::current_path(metallibOutPath); + llvm::sys::path::append(metallibOutPath, llvm::sys::path::filename(filename)); + llvm::sys::path::replace_extension(metallibOutPath, "metallib"); + + std::vector args = { + xcrunpath.get(), "-sdk", "macosx", "metallib", filename, "-o", metallibOutPath.c_str() + }; + + std::string errorMsg; + + int status = executeToolAndWait(Loc(), args[0], args); + + if (status < 0) { + error(Loc(), "program received signal %d (%s)", -status, + strsignal(-status)); + fatal(); + } + + return; + } +#endif + std::error_code errinfo; llvm::ToolOutputFile out(filename, errinfo, llvm::sys::fs::OF_None); if (errinfo) { @@ -303,6 +391,15 @@ std::string replaceExtensionWith(const DArray &ext, } void writeModule(llvm::Module *m, const char *filename) { +// Inline non-kernel functions for Metal dcompute target +#ifdef LDC_LLVM_SUPPORTED_TARGET_AArch64 + const ComputeBackend::Type cb = getComputeTargetType(m); + + if (cb == ComputeBackend::METAL) { + inlineDComputeKernelFunctions(m); + } +#endif + const bool doLTO = opts::isUsingLTO(); const bool outputObj = shouldOutputObjectFile(); const bool assembleExternally = shouldAssembleExternally(); diff --git a/gen/abi/abi.cpp b/gen/abi/abi.cpp index 5e5a1baa20..d592ca5ffb 100644 --- a/gen/abi/abi.cpp +++ b/gen/abi/abi.cpp @@ -11,8 +11,6 @@ #include "dmd/argtypes.h" #include "dmd/expression.h" -#include "dmd/id.h" -#include "dmd/identifier.h" #include "dmd/target.h" #include "gen/abi/targets.h" #include "gen/abi/generic.h" @@ -24,7 +22,6 @@ #include "gen/tollvm.h" #include "ir/irfunction.h" #include "ir/irfuncty.h" -#include using namespace dmd; @@ -286,6 +283,13 @@ TargetABI *TargetABI::getTarget() { case llvm::Triple::wasm32: case llvm::Triple::wasm64: return getWasmTargetABI(); + + case llvm::Triple::UnknownArch: + if (global.params.targetTriple->getArchName() == "air64") { + return createMetalABI(); + } + // fallthrough + default: warning(Loc(), "unknown target ABI, falling back to generic implementation. C/C++ " diff --git a/gen/abi/metal.cpp b/gen/abi/metal.cpp new file mode 100644 index 0000000000..904f3e8808 --- /dev/null +++ b/gen/abi/metal.cpp @@ -0,0 +1,60 @@ +//===-- gen/abi-metal.cpp ---------------------------------------*- C++ -*-===// +// +// LDC – the LLVM D compiler +// +// This file is distributed under the BSD-style LDC license. See the LICENSE +// file for details. +// +//===----------------------------------------------------------------------===// + +#include "gen/abi/abi.h" +#include "gen/dcompute/druntime.h" +#include "gen/dcompute/abi-rewrites.h" +#include "ir/irfuncty.h" +#include "dmd/mtype.h" +#include + +using namespace dmd; + +struct MetalABI : TargetABI { + DComputePointerRewrite pointerRewite; + DcomputeMetalScalarRewrite metalScalarRewrite; + + auto returnInArg(TypeFunction *tf, bool needsThis) -> bool override { + return false; + } + + auto passByVal(TypeFunction *tf, Type*t) -> bool override { + return false; + } + + void rewriteFunctionType(IrFuncTy &fty) override { + for (auto arg : fty.args) { + if (!arg->byref) { + rewriteArgument(fty, *arg); + } + } + } + + void rewriteArgument(IrFuncTy &fty, IrFuncTyArg &arg) override { + TargetABI::rewriteArgument(fty, arg); + + if (arg.rewrite) { + return; + } + + Type *ty = arg.type->toBasetype(); + std::optional ptr; + + if (ty->ty == TY::Tstruct && + (ptr = toDcomputePointer(static_cast(ty)->sym))) { + pointerRewite.applyTo(arg); + } + + if (ty->isScalar()) { + metalScalarRewrite.applyTo(arg); + } + } +}; + +TargetABI* createMetalABI() { return new MetalABI(); } diff --git a/gen/abi/targets.h b/gen/abi/targets.h index 49098fe257..afc6c64fe1 100644 --- a/gen/abi/targets.h +++ b/gen/abi/targets.h @@ -40,3 +40,5 @@ TargetABI *getX86TargetABI(); TargetABI *getLoongArch64TargetABI(); TargetABI *getWasmTargetABI(); + +TargetABI* createMetalABI(); diff --git a/gen/dcompute/abi-rewrites.h b/gen/dcompute/abi-rewrites.h index 1821df81b0..ead84da287 100644 --- a/gen/dcompute/abi-rewrites.h +++ b/gen/dcompute/abi-rewrites.h @@ -32,3 +32,19 @@ struct DComputePointerRewrite : ABIRewrite { return ptr->toLLVMType(true); } }; + +struct DcomputeMetalScalarRewrite : ABIRewrite { + LLType *type(Type* t) override { + // XXX: Scalar variables are stored in the constant memory space for Metal GPU + return llvm::PointerType::get(gIR->context(), 2/*Constant Memory space*/); + } + + LLValue *getLVal(Type *dty, LLValue *v) override { + return v; + } + + LLValue *put(DValue *v, bool isLValueExp, bool) override { + auto value = DtoRVal(v); + return value; + } +}; diff --git a/gen/dcompute/target.cpp b/gen/dcompute/target.cpp index 65c6f027c2..bf67cd011e 100644 --- a/gen/dcompute/target.cpp +++ b/gen/dcompute/target.cpp @@ -7,7 +7,7 @@ // //===----------------------------------------------------------------------===// -#if LDC_LLVM_SUPPORTED_TARGET_SPIRV || LDC_LLVM_SUPPORTED_TARGET_NVPTX +#if LDC_LLVM_SUPPORTED_TARGET_SPIRV || LDC_LLVM_SUPPORTED_TARGET_NVPTX || LDC_LLVM_SUPPORTED_TARGET_AArch64 #include "dmd/dsymbol.h" #include "dmd/errors.h" diff --git a/gen/dcompute/target.h b/gen/dcompute/target.h index 6ffdbea767..24e354f951 100644 --- a/gen/dcompute/target.h +++ b/gen/dcompute/target.h @@ -27,7 +27,7 @@ class DComputeTarget { public: llvm::LLVMContext &ctx; int tversion; // OpenCL or CUDA CC version:major*100 + minor*10 - enum class ID { Host = 0, OpenCL = 1, CUDA = 2 }; + enum class ID { Host = 0, OpenCL = 1, CUDA = 2, Metal = 3 }; ID target; // ID for codegen time conditional compilation. const char *short_name; const char *binSuffix; @@ -58,6 +58,10 @@ class DComputeTarget { DComputeTarget *createCUDATarget(llvm::LLVMContext &c, int sm); #endif +#if LDC_LLVM_SUPPORTED_TARGET_AArch64 +DComputeTarget* createMetalTarget(llvm::LLVMContext &c, int version); +#endif + #if LDC_LLVM_SUPPORTED_TARGET_SPIRV DComputeTarget *createOCLTarget(llvm::LLVMContext &c, int oclver); #endif diff --git a/gen/dcompute/targetMetal.cpp b/gen/dcompute/targetMetal.cpp new file mode 100644 index 0000000000..c8312e39c3 --- /dev/null +++ b/gen/dcompute/targetMetal.cpp @@ -0,0 +1,205 @@ +//===-- gen/dcompute/targetCUDA.cpp ---------------------------------------===// +// +// LDC – the LLVM D compiler +// +// This file is distributed under the BSD-style LDC license. See the LICENSE +// file for details. +// +//===----------------------------------------------------------------------===// +#if LDC_LLVM_SUPPORTED_TARGET_AArch64 + +#include "gen/dcompute/druntime.h" +#include "gen/dcompute/target.h" +#include "gen/abi/targets.h" +#include "dmd/identifier.h" + +namespace { +class TargetMetal : public DComputeTarget { +public: + TargetMetal(llvm::LLVMContext &c, int version) + : DComputeTarget(c, version, ID::Metal, "metal", "air", createMetalABI(), + + // DCompute Order: [Private, Global, Shared, Constant, + // Generic] AIR equivalents: Private=0, Device/Global=1, + // Threadgroup/Shared=3, Constant=2 + {{0, 1, 3, 2, 0}}) { + + _ir = new IRState("dcomputeTargetMetal", ctx); + llvm::StringRef tripleString = "air64_v28-apple-macosx26.0.0"; + +#if LLVM_VERSION_MAJOR >= 21 + _ir->module.setTargetTriple(llvm::Triple(tripleString)); +#else + _ir->module.setTargetTriple(tripleString); +#endif + + llvm::StringRef dataLayout = + "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-" + "f64:64:64" + "-v16:16:16-v24:32:32-v32:32:32-v48:64:64-v64:64:64-v96:128:128-v128:" + "128:128-v192:256:256-v256:256:256-" + "v512:512:512-v1024:1024:1024-n8:16:32"; + + _ir->module.setDataLayout(dataLayout); + _ir->dcomputetarget = this; + } + + void addMetadata() override { + llvm::NamedMDNode *airVersion = + _ir->module.getOrInsertNamedMetadata("air.version"); + llvm::Metadata *major = metaInt(2); + llvm::Metadata *minor = metaInt(8); + llvm::Metadata *patch = metaInt(0); + + std::array arr = {major, minor, patch}; + airVersion->addOperand(llvm::MDTuple::get(ctx, arr)); + + llvm::NamedMDNode *airLangVersion = + _ir->module.getOrInsertNamedMetadata("air.language_version"); + + std::array langArr = { + metaString("Metal"), + metaInt(tversion / 100), + metaInt((tversion / 10) % 10), + metaInt(tversion % 10), + }; + + airLangVersion->addOperand(llvm::MDTuple::get(ctx, langArr)); + } + + void addKernelMetadata(FuncDeclaration *df, llvm::Function *llf, + StructLiteralExp *_unused_) override { + llvm::NamedMDNode *kernels = + _ir->module.getOrInsertNamedMetadata("air.kernel"); + + std::vector kernelMetadataArguments; + kernelMetadataArguments.push_back(llvm::ConstantAsMetadata::get(llf)); + + // XXX: unknown, not sure why we need this, Metal backend expects it + kernelMetadataArguments.push_back(llvm::MDNode::get(ctx, {})); + + std::vector argumentMetadata = + addArgumentMetadata(df, llf); + + kernelMetadataArguments.push_back(llvm::MDNode::get(ctx, argumentMetadata)); + + llvm::MDTuple *kernelTuple = + llvm::MDTuple::get(ctx, kernelMetadataArguments); + + kernels->addOperand(kernelTuple); + } + + auto addArgumentMetadata(FuncDeclaration *df, llvm::Function *llf) + -> std::vector { + std::vector kernelMetadataArguments; + int locationIndex = 0; + + for (auto &arg : llf->args()) { + std::vector argumentMetadata; + + argumentMetadata.push_back( + metaInt(locationIndex)); + + argumentMetadata.push_back( + metaString("air.buffer")); + argumentMetadata.push_back( + metaString("air.location_index")); + argumentMetadata.push_back( + metaInt(locationIndex)); + + // XXX: unknown, not sure why we need this, Metal backend expects it + argumentMetadata.push_back( + metaInt(1)); + + argumentMetadata.push_back( + metaString("air.read_write")); + argumentMetadata.push_back( + metaString("air.address_space")); + + if (arg.getType()->isPointerTy()) { + unsigned addressSpace = arg.getType()->getPointerAddressSpace(); + argumentMetadata.push_back( + metaInt(addressSpace)); + } else { + // XXX: 0 - generic address space + argumentMetadata.push_back(metaInt(0)); + } + + VarDeclaration *vd = (*df->parameters)[locationIndex]; + addArgumentTypeInformation(vd, argumentMetadata); + + if (!argumentMetadata.empty()) { + kernelMetadataArguments.push_back( + llvm::MDTuple::get(ctx, argumentMetadata)); + } + + locationIndex++; + } + + return kernelMetadataArguments; + } + + void addArgumentTypeInformation(VarDeclaration *vd, + std::vector &argumentMetadata) { + Type *type = nullptr; + std::optional ptr; + if (vd->type->ty == TY::Tstruct && + (ptr = toDcomputePointer(static_cast(vd->type)->sym))) { + type = ptr->type; + } else { + type = vd->type; + } + + argumentMetadata.push_back( + metaString("air.arg_type_size")); + argumentMetadata.push_back( + metaInt(dmd::size(type, vd->loc))); + + argumentMetadata.push_back( + metaString("air.arg_type_align_size")); + argumentMetadata.push_back( + metaInt(type->alignsize())); + + argumentMetadata.push_back( + metaString("air.arg_type_name")); + // TODO: check if using char needed instead of int8 as in ocl target implementation + argumentMetadata.push_back( + metaString(basicTypeToString(type))); + + argumentMetadata.push_back( + metaString("air.arg_name")); + argumentMetadata.push_back( + metaString(vd->ident->toChars())); + } + + llvm::Metadata *metaInt(int n) { + return llvm::ConstantAsMetadata::get( + llvm::ConstantInt::get(llvm::IntegerType::get(ctx, 32), n) + ); + } + + llvm::Metadata *metaString(llvm::StringRef s) { + return llvm::MDString::get(ctx, s); + } + + auto basicTypeToString(Type *t) -> std::string { + std::stringstream ss; + auto ty = t->ty; + if (ty == TY::Tint8) { + ss << "char"; + } else if (ty == TY::Tuns8) { + ss << "uchar"; + } else { + ss << t->toChars(); + } + + return ss.str(); + } +}; +} // anonymous namespace. + +DComputeTarget* createMetalTarget(llvm::LLVMContext &c, int version) { + return new TargetMetal(c, version); +}; + +#endif // LDC_LLVM_SUPPORTED_TARGET_AArch64 diff --git a/gen/target.cpp b/gen/target.cpp index 16622a9922..e6453c9aac 100644 --- a/gen/target.cpp +++ b/gen/target.cpp @@ -401,7 +401,7 @@ Expression *Target::getTargetInfo(const char *name_, Loc loc) { return IntegerExp::create(loc, static_cast(cet), Type::tint32); } -#if LDC_LLVM_SUPPORTED_TARGET_SPIRV || LDC_LLVM_SUPPORTED_TARGET_NVPTX +#if LDC_LLVM_SUPPORTED_TARGET_SPIRV || LDC_LLVM_SUPPORTED_TARGET_NVPTX || LDC_LLVM_SUPPORTED_TARGET_AArch64 if (name == "dcomputeTargets") { Expressions* exps = createExpressions(); for (auto &targ : opts::dcomputeTargets) { diff --git a/runtime/druntime/src/ldc/dcompute.d b/runtime/druntime/src/ldc/dcompute.d index 04002a43d9..ec807b5804 100644 --- a/runtime/druntime/src/ldc/dcompute.d +++ b/runtime/druntime/src/ldc/dcompute.d @@ -14,6 +14,7 @@ enum ReflectTarget : uint Host = 0, OpenCL = 1, CUDA = 2, + Metal = 3, } /** * The pseudo conditional compilation function. @@ -23,8 +24,9 @@ enum ReflectTarget : uint * arguments MUST be compiletime constants * valid values of _version are for OpenCL 100 110 120 200 210 * and for CUDA are x*100 + y*10 for x any valid values of sm x.y + * and 400 for Metal 4.0.0 * use 0 as a wildcard to match any version. - + * This is mostly used for selecting the correct intrinsic for the * given target and version, but could also be used to tailor for * performance characteristics. See dcompute.std.index for an example