From 3e0abe10c53e08cc1ebf16662d8d58cd7245f70f Mon Sep 17 00:00:00 2001 From: Alex Voicu Date: Thu, 15 May 2025 23:27:42 +0100 Subject: [PATCH 1/5] Add pass which forwards unimplemented math builtins / libcalls to the HIPSTDPAR runtime component. --- .../llvm/Transforms/HipStdPar/HipStdPar.h | 7 + llvm/lib/Passes/PassRegistry.def | 1 + .../lib/Target/AMDGPU/AMDGPUTargetMachine.cpp | 8 +- llvm/lib/Transforms/HipStdPar/HipStdPar.cpp | 117 +++++++++ llvm/test/Transforms/HipStdPar/math-fixup.ll | 240 ++++++++++++++++++ 5 files changed, 371 insertions(+), 2 deletions(-) create mode 100644 llvm/test/Transforms/HipStdPar/math-fixup.ll diff --git a/llvm/include/llvm/Transforms/HipStdPar/HipStdPar.h b/llvm/include/llvm/Transforms/HipStdPar/HipStdPar.h index 5ff38bdf04812..27195051ed7eb 100644 --- a/llvm/include/llvm/Transforms/HipStdPar/HipStdPar.h +++ b/llvm/include/llvm/Transforms/HipStdPar/HipStdPar.h @@ -40,6 +40,13 @@ class HipStdParAllocationInterpositionPass static bool isRequired() { return true; } }; +class HipStdParMathFixupPass : public PassInfoMixin { +public: + PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM); + + static bool isRequired() { return true; } +}; + } // namespace llvm #endif // LLVM_TRANSFORMS_HIPSTDPAR_HIPSTDPAR_H diff --git a/llvm/lib/Passes/PassRegistry.def b/llvm/lib/Passes/PassRegistry.def index 94dabe290213d..3acdbf4d49fde 100644 --- a/llvm/lib/Passes/PassRegistry.def +++ b/llvm/lib/Passes/PassRegistry.def @@ -80,6 +80,7 @@ MODULE_PASS("global-merge-func", GlobalMergeFuncPass()) MODULE_PASS("globalopt", GlobalOptPass()) MODULE_PASS("globalsplit", GlobalSplitPass()) MODULE_PASS("hipstdpar-interpose-alloc", HipStdParAllocationInterpositionPass()) +MODULE_PASS("hipstdpar-math-fixup", HipStdParMathFixupPass()) MODULE_PASS("hipstdpar-select-accelerator-code", HipStdParAcceleratorCodeSelectionPass()) MODULE_PASS("hotcoldsplit", HotColdSplittingPass()) diff --git a/llvm/lib/Target/AMDGPU/AMDGPUTargetMachine.cpp b/llvm/lib/Target/AMDGPU/AMDGPUTargetMachine.cpp index ccb251b730f16..c3f8cee1e1783 100644 --- a/llvm/lib/Target/AMDGPU/AMDGPUTargetMachine.cpp +++ b/llvm/lib/Target/AMDGPU/AMDGPUTargetMachine.cpp @@ -819,8 +819,10 @@ void AMDGPUTargetMachine::registerPassBuilderCallbacks(PassBuilder &PB) { // When we are not using -fgpu-rdc, we can run accelerator code // selection relatively early, but still after linking to prevent // eager removal of potentially reachable symbols. - if (EnableHipStdPar) + if (EnableHipStdPar) { + PM.addPass(HipStdParMathFixupPass()); PM.addPass(HipStdParAcceleratorCodeSelectionPass()); + } PM.addPass(AMDGPUPrintfRuntimeBindingPass()); } @@ -899,8 +901,10 @@ void AMDGPUTargetMachine::registerPassBuilderCallbacks(PassBuilder &PB) { // selection after linking to prevent, otherwise we end up removing // potentially reachable symbols that were exported as external in other // modules. - if (EnableHipStdPar) + if (EnableHipStdPar) { + PM.addPass(HipStdParMathFixupPass()); PM.addPass(HipStdParAcceleratorCodeSelectionPass()); + } // We want to support the -lto-partitions=N option as "best effort". // For that, we need to lower LDS earlier in the pipeline before the // module is partitioned for codegen. diff --git a/llvm/lib/Transforms/HipStdPar/HipStdPar.cpp b/llvm/lib/Transforms/HipStdPar/HipStdPar.cpp index 5a87cf8c83d79..815878089c69e 100644 --- a/llvm/lib/Transforms/HipStdPar/HipStdPar.cpp +++ b/llvm/lib/Transforms/HipStdPar/HipStdPar.cpp @@ -37,6 +37,16 @@ // memory that ends up in one of the runtime equivalents, since this can // happen if e.g. a library that was compiled without interposition returns // an allocation that can be validly passed to `free`. +// +// 3. MathFixup (required): Some accelerators might have an incomplete +// implementation for the intrinsics used to implement some of the math +// functions in / their corresponding libcall lowerings. Since this +// can vary quite significantly between accelerators, we replace calls to a +// set of intrinsics / lib functions known to be problematic with calls to a +// HIPSTDPAR specific forwarding layer, which gives an uniform interface for +// accelerators to implement in their own runtime components. This pass +// should run before AcceleratorCodeSelection so as to prevent the spurious +// removal of the HIPSTDPAR specific forwarding functions. //===----------------------------------------------------------------------===// #include "llvm/Transforms/HipStdPar/HipStdPar.h" @@ -48,6 +58,7 @@ #include "llvm/Analysis/OptimizationRemarkEmitter.h" #include "llvm/IR/Constants.h" #include "llvm/IR/Function.h" +#include "llvm/IR/Intrinsics.h" #include "llvm/IR/Module.h" #include "llvm/Transforms/Utils/ModuleUtils.h" @@ -321,3 +332,109 @@ HipStdParAllocationInterpositionPass::run(Module &M, ModuleAnalysisManager&) { return PreservedAnalyses::none(); } + +static constexpr std::pair MathLibToHipStdPar[]{ + {"acosh", "__hipstdpar_acosh_f64"}, + {"acoshf", "__hipstdpar_acosh_f32"}, + {"asinh", "__hipstdpar_asinh_f64"}, + {"asinhf", "__hipstdpar_asinh_f32"}, + {"atanh", "__hipstdpar_atanh_f64"}, + {"atanhf", "__hipstdpar_atanh_f32"}, + {"cbrt", "__hipstdpar_cbrt_f64"}, + {"cbrtf", "__hipstdpar_cbrt_f32"}, + {"erf", "__hipstdpar_erf_f64"}, + {"erff", "__hipstdpar_erf_f32"}, + {"erfc", "__hipstdpar_erfc_f64"}, + {"erfcf", "__hipstdpar_erfc_f32"}, + {"fdim", "__hipstdpar_fdim_f64"}, + {"fdimf", "__hipstdpar_fdim_f32"}, + {"expm1", "__hipstdpar_expm1_f64"}, + {"expm1f", "__hipstdpar_expm1_f32"}, + {"hypot", "__hipstdpar_hypot_f64"}, + {"hypotf", "__hipstdpar_hypot_f32"}, + {"ilogb", "__hipstdpar_ilogb_f64"}, + {"ilogbf", "__hipstdpar_ilogb_f32"}, + {"lgamma", "__hipstdpar_lgamma_f64"}, + {"lgammaf", "__hipstdpar_lgamma_f32"}, + {"log1p", "__hipstdpar_log1p_f64"}, + {"log1pf", "__hipstdpar_log1p_f32"}, + {"logb", "__hipstdpar_logb_f64"}, + {"logbf", "__hipstdpar_logb_f32"}, + {"nextafter", "__hipstdpar_nextafter_f64"}, + {"nextafterf", "__hipstdpar_nextafter_f32"}, + {"nexttoward", "__hipstdpar_nexttoward_f64"}, + {"nexttowardf", "__hipstdpar_nexttoward_f32"}, + {"remainder", "__hipstdpar_remainder_f64"}, + {"remainderf", "__hipstdpar_remainder_f32"}, + {"remquo", "__hipstdpar_remquo_f64"}, + {"remquof", "__hipstdpar_remquo_f32"}, + {"scalbln", "__hipstdpar_scalbln_f64"}, + {"scalblnf", "__hipstdpar_scalbln_f32"}, + {"scalbn", "__hipstdpar_scalbn_f64"}, + {"scalbnf", "__hipstdpar_scalbn_f32"}, + {"tgamma", "__hipstdpar_tgamma_f64"}, + {"tgammaf", "__hipstdpar_tgamma_f32"}}; + +PreservedAnalyses HipStdParMathFixupPass::run(Module &M, + ModuleAnalysisManager &) { + if (M.empty()) + return PreservedAnalyses::all(); + + SmallVector> ToReplace; + for (auto &&F : M) { + if (!F.hasName()) + continue; + + auto N = F.getName().str(); + auto ID = F.getIntrinsicID(); + + switch (ID) { + case Intrinsic::not_intrinsic: { + auto It = find_if(MathLibToHipStdPar, + [&](auto &&M) { return M.first == N; }); + if (It == std::cend(MathLibToHipStdPar)) + continue; + ToReplace.emplace_back(&F, It->second); + break; + } + case Intrinsic::acos: + case Intrinsic::asin: + case Intrinsic::atan: + case Intrinsic::atan2: + case Intrinsic::cosh: + case Intrinsic::modf: + case Intrinsic::sinh: + case Intrinsic::tan: + case Intrinsic::tanh: + break; + default: { + if (F.getReturnType()->isDoubleTy()) { + switch (ID) { + case Intrinsic::cos: + case Intrinsic::exp: + case Intrinsic::exp2: + case Intrinsic::log: + case Intrinsic::log10: + case Intrinsic::log2: + case Intrinsic::pow: + case Intrinsic::sin: + break; + default: + continue; + } + break; + } + continue; + } + } + + llvm::replace(N, '.', '_'); + N.replace(0, sizeof("llvm"), "__hipstdpar_"); + ToReplace.emplace_back(&F, std::move(N)); + } + for (auto &&F : ToReplace) + F.first->replaceAllUsesWith(M.getOrInsertFunction( + F.second, F.first->getFunctionType()).getCallee()); + + return PreservedAnalyses::none(); +} \ No newline at end of file diff --git a/llvm/test/Transforms/HipStdPar/math-fixup.ll b/llvm/test/Transforms/HipStdPar/math-fixup.ll new file mode 100644 index 0000000000000..e0e2ca79c0843 --- /dev/null +++ b/llvm/test/Transforms/HipStdPar/math-fixup.ll @@ -0,0 +1,240 @@ +; RUN: opt -S -passes=hipstdpar-math-fixup %s | FileCheck %s + +define void @foo(double noundef %dbl, float noundef %flt, i32 noundef %quo) #0 { +; CHECK-LABEL: define void @foo( +; CHECK-SAME: double noundef [[DBL:%.*]], float noundef [[FLT:%.*]], i32 noundef [[QUO:%.*]]) #[[ATTR0:[0-9]+]] { +; CHECK-NEXT: [[ENTRY:.*:]] +; CHECK-NEXT: [[QUO_ADDR:%.*]] = alloca i32, align 4 +; CHECK-NEXT: store i32 [[QUO]], ptr [[QUO_ADDR]], align 4 +entry: + %quo.addr = alloca i32, align 4 + store i32 %quo, ptr %quo.addr, align 4 + ; CHECK-NEXT: [[TMP0:%.*]] = tail call contract double @llvm.fabs.f64(double [[DBL]]) + %0 = tail call contract double @llvm.fabs.f64(double %dbl) + ; CHECK-NEXT: [[TMP1:%.*]] = tail call contract float @llvm.fabs.f32(float [[FLT]]) + %1 = tail call contract float @llvm.fabs.f32(float %flt) + ; CHECK-NEXT: [[CALL:%.*]] = tail call contract double @__hipstdpar_remainder_f64(double noundef [[TMP0]], double noundef [[TMP0]]) #[[ATTR4:[0-9]+]] + %call = tail call contract double @remainder(double noundef %0, double noundef %0) #4 + ; CHECK-NEXT: [[CALL1:%.*]] = tail call contract float @__hipstdpar_remainder_f32(float noundef [[TMP1]], float noundef [[TMP1]]) #[[ATTR4]] + %call1 = tail call contract float @remainderf(float noundef %1, float noundef %1) #4 + ; CHECK-NEXT: [[CALL2:%.*]] = call contract double @__hipstdpar_remquo_f64(double noundef [[CALL]], double noundef [[CALL]], ptr noundef nonnull [[QUO_ADDR]]) #[[ATTR3:[0-9]+]] + %call2 = call contract double @remquo(double noundef %call, double noundef %call, ptr noundef nonnull %quo.addr) #5 + ; CHECK-NEXT: [[CALL3:%.*]] = call contract float @__hipstdpar_remquo_f32(float noundef [[CALL1]], float noundef [[CALL1]], ptr noundef nonnull [[QUO_ADDR]]) #[[ATTR3]] + %call3 = call contract float @remquof(float noundef %call1, float noundef %call1, ptr noundef nonnull %quo.addr) #5 + ; CHECK-NEXT: [[TMP2:%.*]] = call contract double @llvm.fma.f64(double [[CALL2]], double [[CALL2]], double [[CALL2]]) + %2 = call contract double @llvm.fma.f64(double %call2, double %call2, double %call2) + ; CHECK-NEXT: [[TMP3:%.*]] = call contract float @llvm.fma.f32(float [[CALL3]], float [[CALL3]], float [[CALL3]]) + %3 = call contract float @llvm.fma.f32(float %call3, float %call3, float %call3) + ; CHECK-NEXT: [[CALL4:%.*]] = call contract double @__hipstdpar_fdim_f64(double noundef [[TMP2]], double noundef [[TMP2]]) #[[ATTR4]] + %call4 = call contract double @fdim(double noundef %2, double noundef %2) #4 + ; CHECK-NEXT: [[CALL5:%.*]] = call contract float @__hipstdpar_fdim_f32(float noundef [[TMP3]], float noundef [[TMP3]]) #[[ATTR4]] + %call5 = call contract float @fdimf(float noundef %3, float noundef %3) #4 + ; CHECK-NEXT: [[TMP4:%.*]] = call contract double @__hipstdpar_exp_f64(double [[CALL4]]) + %4 = call contract double @llvm.exp.f64(double %call4) + ; CHECK-NEXT: [[TMP5:%.*]] = call contract float @llvm.exp.f32(float [[CALL5]]) + %5 = call contract float @llvm.exp.f32(float %call5) + ; CHECK-NEXT: [[TMP6:%.*]] = call contract double @__hipstdpar_exp2_f64(double [[TMP4]]) + %6 = call contract double @llvm.exp2.f64(double %4) + ; CHECK-NEXT: [[TMP7:%.*]] = call contract float @llvm.exp2.f32(float [[TMP5]]) + %7 = call contract float @llvm.exp2.f32(float %5) + ; CHECK-NEXT: [[CALL6:%.*]] = call contract double @__hipstdpar_expm1_f64(double noundef [[TMP6]]) #[[ATTR4]] + %call6 = call contract double @expm1(double noundef %6) #4 + ; CHECK-NEXT: [[CALL7:%.*]] = call contract float @__hipstdpar_expm1_f32(float noundef [[TMP7]]) #[[ATTR4]] + %call7 = call contract float @expm1f(float noundef %7) #4 + ; CHECK-NEXT: [[TMP8:%.*]] = call contract double @__hipstdpar_log_f64(double [[CALL6]]) + %8 = call contract double @llvm.log.f64(double %call6) + ; CHECK-NEXT: [[TMP9:%.*]] = call contract float @llvm.log.f32(float [[CALL7]]) + %9 = call contract float @llvm.log.f32(float %call7) + ; CHECK-NEXT: [[TMP10:%.*]] = call contract double @__hipstdpar_log10_f64(double [[TMP8]]) + %10 = call contract double @llvm.log10.f64(double %8) + ; CHECK-NEXT: [[TMP11:%.*]] = call contract float @llvm.log10.f32(float [[TMP9]]) + %11 = call contract float @llvm.log10.f32(float %9) + ; CHECK-NEXT: [[TMP12:%.*]] = call contract double @__hipstdpar_log2_f64(double [[TMP10]]) + %12 = call contract double @llvm.log2.f64(double %10) + ; CHECK-NEXT: [[TMP13:%.*]] = call contract float @llvm.log2.f32(float [[TMP11]]) + %13 = call contract float @llvm.log2.f32(float %11) + ; CHECK-NEXT: [[CALL8:%.*]] = call contract double @__hipstdpar_log1p_f64(double noundef [[TMP12]]) #[[ATTR4]] + %call8 = call contract double @log1p(double noundef %12) #4 + ; CHECK-NEXT: [[CALL9:%.*]] = call contract float @__hipstdpar_log1p_f32(float noundef [[TMP13]]) #[[ATTR4]] + %call9 = call contract float @log1pf(float noundef %13) #4 + ; CHECK-NEXT: [[TMP14:%.*]] = call contract float @llvm.pow.f32(float [[CALL9]], float [[CALL9]]) + %14 = call contract float @llvm.pow.f32(float %call9, float %call9) + ; CHECK-NEXT: [[TMP15:%.*]] = call contract double @llvm.sqrt.f64(double [[CALL8]]) + %15 = call contract double @llvm.sqrt.f64(double %call8) + ; CHECK-NEXT: [[TMP16:%.*]] = call contract float @llvm.sqrt.f32(float [[TMP14]]) + %16 = call contract float @llvm.sqrt.f32(float %14) + ; CHECK-NEXT: [[CALL10:%.*]] = call contract double @__hipstdpar_cbrt_f64(double noundef [[TMP15]]) #[[ATTR4]] + %call10 = call contract double @cbrt(double noundef %15) #4 + ; CHECK-NEXT: [[CALL11:%.*]] = call contract float @__hipstdpar_cbrt_f32(float noundef [[TMP16]]) #[[ATTR4]] + %call11 = call contract float @cbrtf(float noundef %16) #4 + ; CHECK-NEXT: [[CALL12:%.*]] = call contract double @__hipstdpar_hypot_f64(double noundef [[CALL10]], double noundef [[CALL10]]) #[[ATTR4]] + %call12 = call contract double @hypot(double noundef %call10, double noundef %call10) #4 + ; CHECK-NEXT: [[CALL13:%.*]] = call contract float @__hipstdpar_hypot_f32(float noundef [[CALL11]], float noundef [[CALL11]]) #[[ATTR4]] + %call13 = call contract float @hypotf(float noundef %call11, float noundef %call11) #4 + ; CHECK-NEXT: [[TMP17:%.*]] = call contract float @llvm.sin.f32(float [[CALL13]]) + %17 = call contract float @llvm.sin.f32(float %call13) + ; CHECK-NEXT: [[TMP18:%.*]] = call contract float @llvm.cos.f32(float [[TMP17]]) + %18 = call contract float @llvm.cos.f32(float %17) + ; CHECK-NEXT: [[TMP19:%.*]] = call contract double @__hipstdpar_tan_f64(double [[CALL12]]) + %19 = call contract double @llvm.tan.f64(double %call12) + ; CHECK-NEXT: [[TMP20:%.*]] = call contract double @__hipstdpar_asin_f64(double [[TMP19]]) + %20 = call contract double @llvm.asin.f64(double %19) + ; CHECK-NEXT: [[TMP21:%.*]] = call contract double @__hipstdpar_acos_f64(double [[TMP20]]) + %21 = call contract double @llvm.acos.f64(double %20) + ; CHECK-NEXT: [[TMP22:%.*]] = call contract double @__hipstdpar_atan_f64(double [[TMP21]]) + %22 = call contract double @llvm.atan.f64(double %21) + ; CHECK-NEXT: [[TMP23:%.*]] = call contract double @__hipstdpar_atan2_f64(double [[TMP22]], double [[TMP22]]) + %23 = call contract double @llvm.atan2.f64(double %22, double %22) + ; CHECK-NEXT: [[TMP24:%.*]] = call contract double @__hipstdpar_sinh_f64(double [[TMP23]]) + %24 = call contract double @llvm.sinh.f64(double %23) + ; CHECK-NEXT: [[TMP25:%.*]] = call contract double @__hipstdpar_cosh_f64(double [[TMP24]]) + %25 = call contract double @llvm.cosh.f64(double %24) + ; CHECK-NEXT: [[TMP26:%.*]] = call contract double @__hipstdpar_tanh_f64(double [[TMP25]]) + %26 = call contract double @llvm.tanh.f64(double %25) + ; CHECK-NEXT: [[CALL14:%.*]] = call contract double @__hipstdpar_asinh_f64(double noundef [[TMP26]]) #[[ATTR4]] + %call14 = call contract double @asinh(double noundef %26) #4 + ; CHECK-NEXT: [[CALL15:%.*]] = call contract float @__hipstdpar_asinh_f32(float noundef [[TMP18]]) #[[ATTR4]] + %call15 = call contract float @asinhf(float noundef %18) #4 + ; CHECK-NEXT: [[CALL16:%.*]] = call contract double @__hipstdpar_acosh_f64(double noundef [[CALL14]]) #[[ATTR4]] + %call16 = call contract double @acosh(double noundef %call14) #4 + ; CHECK-NEXT: [[CALL17:%.*]] = call contract float @__hipstdpar_acosh_f32(float noundef [[CALL15]]) #[[ATTR4]] + %call17 = call contract float @acoshf(float noundef %call15) #4 + ; CHECK-NEXT: [[CALL18:%.*]] = call contract double @__hipstdpar_atanh_f64(double noundef [[CALL16]]) #[[ATTR4]] + %call18 = call contract double @atanh(double noundef %call16) #4 + ; CHECK-NEXT: [[CALL19:%.*]] = call contract float @__hipstdpar_atanh_f32(float noundef [[CALL17]]) #[[ATTR4]] + %call19 = call contract float @atanhf(float noundef %call17) #4 + ; CHECK-NEXT: [[CALL20:%.*]] = call contract double @__hipstdpar_erf_f64(double noundef [[CALL18]]) #[[ATTR4]] + %call20 = call contract double @erf(double noundef %call18) #4 + ; CHECK-NEXT: [[CALL21:%.*]] = call contract float @__hipstdpar_erf_f32(float noundef [[CALL19]]) #[[ATTR4]] + %call21 = call contract float @erff(float noundef %call19) #4 + ; CHECK-NEXT: [[CALL22:%.*]] = call contract double @__hipstdpar_erfc_f64(double noundef [[CALL20]]) #[[ATTR4]] + %call22 = call contract double @erfc(double noundef %call20) #4 + ; CHECK-NEXT: [[CALL23:%.*]] = call contract float @__hipstdpar_erfc_f32(float noundef [[CALL21]]) #[[ATTR4]] + %call23 = call contract float @erfcf(float noundef %call21) #4 + ; CHECK-NEXT: [[CALL24:%.*]] = call contract double @__hipstdpar_tgamma_f64(double noundef [[CALL22]]) #[[ATTR4]] + %call24 = call contract double @tgamma(double noundef %call22) #4 + ; CHECK-NEXT: [[CALL25:%.*]] = call contract float @__hipstdpar_tgamma_f32(float noundef [[CALL23]]) #[[ATTR4]] + %call25 = call contract float @tgammaf(float noundef %call23) #4 + ; CHECK-NEXT: [[CALL26:%.*]] = call contract double @__hipstdpar_lgamma_f64(double noundef [[CALL24]]) #[[ATTR3]] + %call26 = call contract double @lgamma(double noundef %call24) #5 + ; CHECK-NEXT: [[CALL27:%.*]] = call contract float @__hipstdpar_lgamma_f32(float noundef [[CALL25]]) #[[ATTR3]] + %call27 = call contract float @lgammaf(float noundef %call25) #5 + ret void +} + +declare double @llvm.fabs.f64(double) #1 + +declare float @llvm.fabs.f32(float) #1 + +declare hidden double @remainder(double noundef, double noundef) local_unnamed_addr #2 + +declare hidden float @remainderf(float noundef, float noundef) local_unnamed_addr #2 + +declare hidden double @remquo(double noundef, double noundef, ptr noundef) local_unnamed_addr #3 + +declare hidden float @remquof(float noundef, float noundef, ptr noundef) local_unnamed_addr #3 + +declare double @llvm.fma.f64(double, double, double) #1 + +declare float @llvm.fma.f32(float, float, float) #1 + +declare hidden double @fdim(double noundef, double noundef) local_unnamed_addr #2 + +declare hidden float @fdimf(float noundef, float noundef) local_unnamed_addr #2 + +declare double @llvm.exp.f64(double) #1 + +declare float @llvm.exp.f32(float) #1 + +declare double @llvm.exp2.f64(double) #1 + +declare float @llvm.exp2.f32(float) #1 + +declare hidden double @expm1(double noundef) local_unnamed_addr #2 + +declare hidden float @expm1f(float noundef) local_unnamed_addr #2 + +declare double @llvm.log.f64(double) #1 + +declare float @llvm.log.f32(float) #1 + +declare double @llvm.log10.f64(double) #1 + +declare float @llvm.log10.f32(float) #1 + +declare double @llvm.log2.f64(double) #1 + +declare float @llvm.log2.f32(float) #1 + +declare hidden double @log1p(double noundef) local_unnamed_addr #2 + +declare hidden float @log1pf(float noundef) local_unnamed_addr #2 + +declare float @llvm.pow.f32(float, float) #1 + +declare double @llvm.sqrt.f64(double) #1 + +declare float @llvm.sqrt.f32(float) #1 + +declare hidden double @cbrt(double noundef) local_unnamed_addr #2 + +declare hidden float @cbrtf(float noundef) local_unnamed_addr #2 + +declare hidden double @hypot(double noundef, double noundef) local_unnamed_addr #2 + +declare hidden float @hypotf(float noundef, float noundef) local_unnamed_addr #2 + +declare float @llvm.sin.f32(float) #1 + +declare float @llvm.cos.f32(float) #1 + +declare double @llvm.tan.f64(double) #1 + +declare double @llvm.asin.f64(double) #1 + +declare double @llvm.acos.f64(double) #1 + +declare double @llvm.atan.f64(double) #1 + +declare double @llvm.atan2.f64(double, double) #1 + +declare double @llvm.sinh.f64(double) #1 + +declare double @llvm.cosh.f64(double) #1 + +declare double @llvm.tanh.f64(double) #1 + +declare hidden double @asinh(double noundef) local_unnamed_addr #2 + +declare hidden float @asinhf(float noundef) local_unnamed_addr #2 + +declare hidden double @acosh(double noundef) local_unnamed_addr #2 + +declare hidden float @acoshf(float noundef) local_unnamed_addr #2 + +declare hidden double @atanh(double noundef) local_unnamed_addr #2 + +declare hidden float @atanhf(float noundef) local_unnamed_addr #2 + +declare hidden double @erf(double noundef) local_unnamed_addr #2 + +declare hidden float @erff(float noundef) local_unnamed_addr #2 + +declare hidden double @erfc(double noundef) local_unnamed_addr #2 + +declare hidden float @erfcf(float noundef) local_unnamed_addr #2 + +declare hidden double @tgamma(double noundef) local_unnamed_addr #2 + +declare hidden float @tgammaf(float noundef) local_unnamed_addr #2 + +declare hidden double @lgamma(double noundef) local_unnamed_addr #3 + +declare hidden float @lgammaf(float noundef) local_unnamed_addr #3 + +attributes #0 = { convergent mustprogress norecurse nounwind } +attributes #1 = { mustprogress nocallback nofree nosync nounwind speculatable willreturn memory(none) } +attributes #2 = { convergent mustprogress nofree nounwind willreturn memory(none) } +attributes #3 = { convergent nounwind } +attributes #4 = { convergent nounwind willreturn memory(none) } +attributes #5 = { convergent nounwind } From 2e9bc217e0ee463cc5b064b3c7a050c2f47fadbd Mon Sep 17 00:00:00 2001 From: Alex Voicu Date: Fri, 31 Oct 2025 03:53:05 +0200 Subject: [PATCH 2/5] Add AMDGCN flavoured SPIR-V specific bits to the BE: generator number, enable all extensions and non semantic debug info generation. --- llvm/lib/MC/SPIRVObjectWriter.cpp | 7 +++++-- llvm/lib/Target/SPIRV/SPIRVSubtarget.cpp | 10 ++++++++-- llvm/lib/Target/SPIRV/SPIRVTargetMachine.cpp | 3 ++- .../CodeGen/SPIRV/debug-info/debug-type-pointer.ll | 4 +++- llvm/test/CodeGen/SPIRV/extensions/SPV_EXT_optnone.ll | 2 ++ .../CodeGen/SPIRV/extensions/enable-all-extensions.ll | 1 + .../SPIRV/physical-layout/generator-magic-number.ll | 2 ++ .../CodeGen/SPIRV/physical-layout/spirv-version.ll | 2 ++ 8 files changed, 25 insertions(+), 6 deletions(-) diff --git a/llvm/lib/MC/SPIRVObjectWriter.cpp b/llvm/lib/MC/SPIRVObjectWriter.cpp index 5e3713778286f..82089e566668a 100644 --- a/llvm/lib/MC/SPIRVObjectWriter.cpp +++ b/llvm/lib/MC/SPIRVObjectWriter.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "llvm/MC/MCAssembler.h" +#include "llvm/MC/MCContext.h" #include "llvm/MC/MCSPIRVObjectWriter.h" #include "llvm/MC/MCSection.h" #include "llvm/MC/MCValue.h" @@ -17,8 +18,10 @@ using namespace llvm; void SPIRVObjectWriter::writeHeader(const MCAssembler &Asm) { constexpr uint32_t MagicNumber = 0x07230203; constexpr uint32_t GeneratorID = 43; - constexpr uint32_t GeneratorMagicNumber = - (GeneratorID << 16) | (LLVM_VERSION_MAJOR); + const uint32_t GeneratorMagicNumber = + Asm.getContext().getTargetTriple().getVendor() == Triple::AMD + ? UINT16_MAX + : ((GeneratorID << 16) | (LLVM_VERSION_MAJOR)); constexpr uint32_t Schema = 0; W.write(MagicNumber); diff --git a/llvm/lib/Target/SPIRV/SPIRVSubtarget.cpp b/llvm/lib/Target/SPIRV/SPIRVSubtarget.cpp index ba09692fec515..89f075d0839d8 100644 --- a/llvm/lib/Target/SPIRV/SPIRVSubtarget.cpp +++ b/llvm/lib/Target/SPIRV/SPIRVSubtarget.cpp @@ -71,7 +71,10 @@ SPIRVSubtarget::SPIRVSubtarget(const Triple &TT, const std::string &CPU, break; case Triple::SPIRVSubArch_v14: default: - SPIRVVersion = VersionTuple(1, 4); + if (TT.getVendor() == Triple::AMD) + SPIRVVersion = VersionTuple(1, 6); + else + SPIRVVersion = VersionTuple(1, 4); break; case Triple::SPIRVSubArch_v15: SPIRVVersion = VersionTuple(1, 5); @@ -85,7 +88,8 @@ SPIRVSubtarget::SPIRVSubtarget(const Triple &TT, const std::string &CPU, // Set the environment based on the target triple. if (TargetTriple.getOS() == Triple::Vulkan) Env = Shader; - else if (TargetTriple.getEnvironment() == Triple::OpenCL) + else if (TargetTriple.getEnvironment() == Triple::OpenCL || + TargetTriple.getVendor() == Triple::AMD) Env = Kernel; else Env = Unknown; @@ -93,6 +97,8 @@ SPIRVSubtarget::SPIRVSubtarget(const Triple &TT, const std::string &CPU, // Set the default extensions based on the target triple. if (TargetTriple.getVendor() == Triple::Intel) Extensions.insert(SPIRV::Extension::SPV_INTEL_function_pointers); + if (TargetTriple.getVendor() == Triple::AMD) + Extensions = SPIRVExtensionsParser::getValidExtensions(TargetTriple); // The order of initialization is important. initAvailableExtensions(Extensions); diff --git a/llvm/lib/Target/SPIRV/SPIRVTargetMachine.cpp b/llvm/lib/Target/SPIRV/SPIRVTargetMachine.cpp index 7dd0b95cd9763..9fd436f974fa3 100644 --- a/llvm/lib/Target/SPIRV/SPIRVTargetMachine.cpp +++ b/llvm/lib/Target/SPIRV/SPIRVTargetMachine.cpp @@ -244,7 +244,8 @@ static cl::opt SPVEnableNonSemanticDI( cl::Optional, cl::init(false)); void SPIRVPassConfig::addPreEmitPass() { - if (SPVEnableNonSemanticDI) { + if (SPVEnableNonSemanticDI || + getSPIRVTargetMachine().getTargetTriple().getVendor() == Triple::AMD) { addPass(createSPIRVEmitNonSemanticDIPass(&getTM())); } } diff --git a/llvm/test/CodeGen/SPIRV/debug-info/debug-type-pointer.ll b/llvm/test/CodeGen/SPIRV/debug-info/debug-type-pointer.ll index ec4884ff643cb..3e0d0cc4cd8e2 100644 --- a/llvm/test/CodeGen/SPIRV/debug-info/debug-type-pointer.ll +++ b/llvm/test/CodeGen/SPIRV/debug-info/debug-type-pointer.ll @@ -1,7 +1,9 @@ ; RUN: llc --verify-machineinstrs --spv-emit-nonsemantic-debug-info --spirv-ext=+SPV_KHR_non_semantic_info --print-after=spirv-nonsemantic-debug-info -O0 -mtriple=spirv64-unknown-unknown %s -o - 2>&1 | FileCheck %s --check-prefix=CHECK-MIR +; RUN: llc --verify-machineinstrs --print-after=spirv-nonsemantic-debug-info -O0 -mtriple=spirv64-amd-amdhsa %s -o - 2>&1 | FileCheck %s --check-prefix=CHECK-MIR ; RUN: llc --verify-machineinstrs --spv-emit-nonsemantic-debug-info --spirv-ext=+SPV_KHR_non_semantic_info -O0 -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s --check-prefix=CHECK-SPIRV +; RUN: llc --verify-machineinstrs -O0 -mtriple=spirv64-amd-amdhsa %s -o - | FileCheck %s --check-prefix=CHECK-SPIRV ; RUN: llc --verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown --spirv-ext=+SPV_KHR_non_semantic_info %s -o - | FileCheck %s --check-prefix=CHECK-OPTION -; TODO(#109287): When type is void * the spirv-val raises an error when DebugInfoNone is set as Base Type argument of DebugTypePointer. +; TODO(#109287): When type is void * the spirv-val raises an error when DebugInfoNone is set as Base Type argument of DebugTypePointer. ; DISABLED: %if spirv-tools %{ llc --verify-machineinstrs --spv-emit-nonsemantic-debug-info --spirv-ext=+SPV_KHR_non_semantic_info -O0 -mtriple=spirv64-unknown-unknown %s -o - -filetype=obj | spirv-val %} ; CHECK-MIR-DAG: [[i32type:%[0-9]+\:type]] = OpTypeInt 32, 0 diff --git a/llvm/test/CodeGen/SPIRV/extensions/SPV_EXT_optnone.ll b/llvm/test/CodeGen/SPIRV/extensions/SPV_EXT_optnone.ll index b1a555a52f40d..6b4e35e997124 100644 --- a/llvm/test/CodeGen/SPIRV/extensions/SPV_EXT_optnone.ll +++ b/llvm/test/CodeGen/SPIRV/extensions/SPV_EXT_optnone.ll @@ -7,6 +7,8 @@ ; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown --spirv-ext=+SPV_EXT_optnone,+SPV_INTEL_optnone %s -o - | FileCheck %s --check-prefixes=CHECK-TWO-EXTENSIONS ; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown --spirv-ext=all %s -o - | FileCheck %s --check-prefixes=CHECK-ALL-EXTENSIONS +; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv64-amd-amdhsa %s -o - | FileCheck %s --check-prefixes=CHECK-ALL-EXTENSIONS + ; CHECK-EXTENSION: OpCapability OptNoneEXT ; CHECK-EXTENSION: OpExtension "SPV_EXT_optnone" ; CHECK-NO-EXTENSION-NOT: OpCapability OptNoneINTEL diff --git a/llvm/test/CodeGen/SPIRV/extensions/enable-all-extensions.ll b/llvm/test/CodeGen/SPIRV/extensions/enable-all-extensions.ll index f745794e11de1..15905dd1894e2 100644 --- a/llvm/test/CodeGen/SPIRV/extensions/enable-all-extensions.ll +++ b/llvm/test/CodeGen/SPIRV/extensions/enable-all-extensions.ll @@ -1,4 +1,5 @@ ; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv32-unknown-unknown --spirv-ext=all %s -o - | FileCheck %s +; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv64-amd-amdhsa %s -o - | FileCheck %s define i6 @getConstantI6() { ret i6 2 diff --git a/llvm/test/CodeGen/SPIRV/physical-layout/generator-magic-number.ll b/llvm/test/CodeGen/SPIRV/physical-layout/generator-magic-number.ll index afffd9e69b454..11e7d006c5ecf 100644 --- a/llvm/test/CodeGen/SPIRV/physical-layout/generator-magic-number.ll +++ b/llvm/test/CodeGen/SPIRV/physical-layout/generator-magic-number.ll @@ -1,4 +1,6 @@ ; REQUIRES: spirv-tools ; RUN: llc -O0 -mtriple=spirv-unknown-unknown %s -o - --filetype=obj | spirv-dis | FileCheck %s +; RUN: llc -O0 -mtriple=spirv64-amd-amdhsa %s -o - --filetype=obj | spirv-dis | FileCheck --check-prefix=AMDGCNSPIRV %s ; CHECK: Generator: {{.*}}{{43|LLVM SPIR-V Backend}}{{.*}} +; AMDGCNSPIRV: Generator: {{.*}}{{65535|LLVM SPIR-V Backend}}{{.*}} diff --git a/llvm/test/CodeGen/SPIRV/physical-layout/spirv-version.ll b/llvm/test/CodeGen/SPIRV/physical-layout/spirv-version.ll index 686c1e97257ad..49ee9931d1126 100644 --- a/llvm/test/CodeGen/SPIRV/physical-layout/spirv-version.ll +++ b/llvm/test/CodeGen/SPIRV/physical-layout/spirv-version.ll @@ -6,6 +6,7 @@ ; RUN: llc -O0 -mtriple=spirv64v1.4-unknown-unknown %s -o - --filetype=obj | spirv-dis | FileCheck %s --check-prefix=CHECK-SPIRV14 ; RUN: llc -O0 -mtriple=spirv64v1.5-unknown-unknown %s -o - --filetype=obj | spirv-dis | FileCheck %s --check-prefix=CHECK-SPIRV15 ; RUN: llc -O0 -mtriple=spirv64v1.6-unknown-unknown %s -o - --filetype=obj | spirv-dis | FileCheck %s --check-prefix=CHECK-SPIRV16 +; RUN: llc -O0 -mtriple=spirv64-amd-amdhsa %s -o - --filetype=obj | spirv-dis | FileCheck %s --check-prefix=AMDGCNSPIRV ; CHECK-SPIRV10: Version: 1.0 ; CHECK-SPIRV11: Version: 1.1 @@ -14,3 +15,4 @@ ; CHECK-SPIRV14: Version: 1.4 ; CHECK-SPIRV15: Version: 1.5 ; CHECK-SPIRV16: Version: 1.6 +; AMDGCNSPIRV: Version: 1.6 From 00ffdaa5451fabbb1e2d340d043ec7d2327bd0a6 Mon Sep 17 00:00:00 2001 From: Alex Voicu Date: Fri, 31 Oct 2025 11:33:53 +0200 Subject: [PATCH 3/5] Fix formatting. --- llvm/lib/MC/SPIRVObjectWriter.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/llvm/lib/MC/SPIRVObjectWriter.cpp b/llvm/lib/MC/SPIRVObjectWriter.cpp index 82089e566668a..d693ea33d8d7b 100644 --- a/llvm/lib/MC/SPIRVObjectWriter.cpp +++ b/llvm/lib/MC/SPIRVObjectWriter.cpp @@ -20,8 +20,8 @@ void SPIRVObjectWriter::writeHeader(const MCAssembler &Asm) { constexpr uint32_t GeneratorID = 43; const uint32_t GeneratorMagicNumber = Asm.getContext().getTargetTriple().getVendor() == Triple::AMD - ? UINT16_MAX - : ((GeneratorID << 16) | (LLVM_VERSION_MAJOR)); + ? UINT16_MAX + : ((GeneratorID << 16) | (LLVM_VERSION_MAJOR)); constexpr uint32_t Schema = 0; W.write(MagicNumber); From acd6bb05011b8a67d603c6a95890309143d97a8a Mon Sep 17 00:00:00 2001 From: Alex Voicu Date: Fri, 31 Oct 2025 16:09:24 +0200 Subject: [PATCH 4/5] Fix bug. --- llvm/lib/Target/SPIRV/SPIRVSubtarget.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/llvm/lib/Target/SPIRV/SPIRVSubtarget.cpp b/llvm/lib/Target/SPIRV/SPIRVSubtarget.cpp index 89f075d0839d8..5f25457ea71b9 100644 --- a/llvm/lib/Target/SPIRV/SPIRVSubtarget.cpp +++ b/llvm/lib/Target/SPIRV/SPIRVSubtarget.cpp @@ -70,6 +70,8 @@ SPIRVSubtarget::SPIRVSubtarget(const Triple &TT, const std::string &CPU, SPIRVVersion = VersionTuple(1, 3); break; case Triple::SPIRVSubArch_v14: + SPIRVVersion = VersionTuple(1, 4); + break; default: if (TT.getVendor() == Triple::AMD) SPIRVVersion = VersionTuple(1, 6); From 94cad95fab3292f4e3f2c6a76c2728388f54c5c1 Mon Sep 17 00:00:00 2001 From: Alex Voicu Date: Fri, 31 Oct 2025 16:18:33 +0200 Subject: [PATCH 5/5] Reformat switch for readability. --- llvm/lib/Target/SPIRV/SPIRVSubtarget.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/llvm/lib/Target/SPIRV/SPIRVSubtarget.cpp b/llvm/lib/Target/SPIRV/SPIRVSubtarget.cpp index 5f25457ea71b9..ad6c9cd421b7c 100644 --- a/llvm/lib/Target/SPIRV/SPIRVSubtarget.cpp +++ b/llvm/lib/Target/SPIRV/SPIRVSubtarget.cpp @@ -72,18 +72,17 @@ SPIRVSubtarget::SPIRVSubtarget(const Triple &TT, const std::string &CPU, case Triple::SPIRVSubArch_v14: SPIRVVersion = VersionTuple(1, 4); break; - default: - if (TT.getVendor() == Triple::AMD) - SPIRVVersion = VersionTuple(1, 6); - else - SPIRVVersion = VersionTuple(1, 4); - break; case Triple::SPIRVSubArch_v15: SPIRVVersion = VersionTuple(1, 5); break; case Triple::SPIRVSubArch_v16: SPIRVVersion = VersionTuple(1, 6); break; + default: + if (TT.getVendor() == Triple::AMD) + SPIRVVersion = VersionTuple(1, 6); + else + SPIRVVersion = VersionTuple(1, 4); } OpenCLVersion = VersionTuple(2, 2);