[clang] [llvm] [SPIRV] Add size optimisation for AMDGCN flavoured SPIR-V (PR #228188)
Alex Voicu via cfe-commits
cfe-commits at lists.llvm.org
Thu Oct 15 09:50:22 PDT 2026
https://github.com/AlexVlx updated https://github.com/llvm/llvm-project/pull/228188
>From 3e0abe10c53e08cc1ebf16662d8d58cd7245f70f Mon Sep 17 00:00:00 2001
From: Alex Voicu <alexandru.voicu at amd.com>
Date: Thu, 15 May 2025 23:27:42 +0100
Subject: [PATCH 01/15] 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 5ff38bdf04812b..27195051ed7eb9 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<HipStdParMathFixupPass> {
+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 94dabe290213dc..3acdbf4d49fdec 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 ccb251b730f169..c3f8cee1e17832 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 5a87cf8c83d790..815878089c69ec 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 <cmath> / 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<StringLiteral, StringLiteral> 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<std::pair<Function *, std::string>> 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 00000000000000..e0e2ca79c08435
--- /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 d2998eac9f2a7a26edf69b54e850d6c81a5998d7 Mon Sep 17 00:00:00 2001
From: Alex Voicu <alexandru.voicu at amd.com>
Date: Thu, 1 Oct 2026 19:05:14 +0100
Subject: [PATCH 02/15] Add safe-ish size optimization for AMDGCN flavoured
SPIR-V.
---
clang/lib/CodeGen/BackendUtil.cpp | 45 +++++++++++++++++++
.../CodeGen/amdgcnspirv-size-optimization.c | 45 +++++++++++++++++++
2 files changed, 90 insertions(+)
create mode 100644 clang/test/CodeGen/amdgcnspirv-size-optimization.c
diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp
index c754c75aa59de5..6f7e5c76965441 100644
--- a/clang/lib/CodeGen/BackendUtil.cpp
+++ b/clang/lib/CodeGen/BackendUtil.cpp
@@ -66,9 +66,14 @@
#include "llvm/TargetParser/SubtargetFeature.h"
#include "llvm/TargetParser/Triple.h"
#include "llvm/Transforms/HipStdPar/HipStdPar.h"
+#include "llvm/Transforms/IPO/DeadArgumentElimination.h"
#include "llvm/Transforms/IPO/EmbedBitcodePass.h"
+#include "llvm/Transforms/IPO/FunctionAttrs.h"
+#include "llvm/Transforms/IPO/ForceFunctionAttrs.h"
+#include "llvm/Transforms/IPO/GlobalOpt.h"
#include "llvm/Transforms/IPO/InferFunctionAttrs.h"
#include "llvm/Transforms/IPO/LowerTypeTests.h"
+#include "llvm/Transforms/IPO/SCCP.h"
#include "llvm/Transforms/IPO/ThinLTOBitcodeWriter.h"
#include "llvm/Transforms/InstCombine/InstCombine.h"
#include "llvm/Transforms/Instrumentation/AddressSanitizer.h"
@@ -95,9 +100,13 @@
#include "llvm/Transforms/Scalar/EarlyCSE.h"
#include "llvm/Transforms/Scalar/GVN.h"
#include "llvm/Transforms/Scalar/JumpThreading.h"
+#include "llvm/Transforms/Scalar/LowerExpectIntrinsic.h"
+#include "llvm/Transforms/Scalar/SimplifyCFG.h"
+#include "llvm/Transforms/Scalar/SROA.h"
#include "llvm/Transforms/Utils/AssignGUID.h"
#include "llvm/Transforms/Utils/Debugify.h"
#include "llvm/Transforms/Utils/DynamicDebugging.h"
+#include "llvm/Transforms/Utils/Mem2Reg.h"
#include "llvm/Transforms/Utils/ModuleUtils.h"
#include <limits>
#include <memory>
@@ -800,6 +809,38 @@ void addLowerAllowCheckPass(const CodeGenOptions &CodeGenOpts,
}
}
+static void addAMDGCNSPIRVSizeOptimizationPasses(ModulePassManager &MPM) {
+ // For AMDGCN flavoured SPIR-V we want to preserve the pristine Clang input
+ // by default, to minimise the risk of SPIR-V target specific transforms
+ // being disruptive for the AMDGPU BE. However, this can yield very large
+ // binaries. Thus, for higher optimisation levels we turn on a minimal set
+ // of size reducing passes. The pass collection here is derived from that
+ // proposed in Jain et al. "An analysis of executable size reduction by LLVM
+ // passes" (https://doi.org/10.1007/s40012-019-00248-5), more specifically
+ // the GF and G0 groups.
+
+ // GF: -lower-expect -simplifycfg -sroa -early-cse
+ MPM.addPass(createModuleToFunctionPassAdaptor(LowerExpectIntrinsicPass()));
+ MPM.addPass(createModuleToFunctionPassAdaptor(SimplifyCFGPass()));
+ MPM.addPass(createModuleToFunctionPassAdaptor(
+ SROAPass(SROAOptions::PreserveCFG)));
+ MPM.addPass(createModuleToFunctionPassAdaptor(EarlyCSEPass()));
+
+ // G0: -forceattrs -inferattrs -ipsccp -globalopt -mem2reg -deadargelim
+ // -instcombine -simplifycfg -prune-eh (PostOrderFunctionAttrs in NewPM)
+ // -inline(disabled) -functionattrs (disabled)
+ MPM.addPass(ForceFunctionAttrsPass());
+ MPM.addPass(InferFunctionAttrsPass());
+ MPM.addPass(IPSCCPPass());
+ MPM.addPass(GlobalOptPass());
+ MPM.addPass(createModuleToFunctionPassAdaptor(PromotePass()));
+ MPM.addPass(DeadArgumentEliminationPass());
+ MPM.addPass(createModuleToFunctionPassAdaptor(InstCombinePass()));
+ MPM.addPass(createModuleToFunctionPassAdaptor(SimplifyCFGPass()));
+ MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(
+ PostOrderFunctionAttrsPass()));
+}
+
void EmitAssemblyHelper::RunOptimizationPipeline(
BackendAction Action, std::unique_ptr<raw_pwrite_stream> &OS,
std::unique_ptr<llvm::ToolOutputFile> &ThinLinkOS, BackendConsumer *BC) {
@@ -1116,6 +1157,10 @@ void EmitAssemblyHelper::RunOptimizationPipeline(
} else {
MPM.addPass(PB.buildPerModuleDefaultPipeline(Level));
}
+ } else if (TargetTriple.isSPIRV() &&
+ TargetTriple.getVendor() == llvm::Triple::VendorType::AMD &&
+ mapToLevel(CodeGenOpts) > OptimizationLevel::O1) {
+ addAMDGCNSPIRVSizeOptimizationPasses(MPM);
}
// Link against bitcodes supplied via the -mlink-builtin-bitcode option
diff --git a/clang/test/CodeGen/amdgcnspirv-size-optimization.c b/clang/test/CodeGen/amdgcnspirv-size-optimization.c
new file mode 100644
index 00000000000000..93385ec800e0fe
--- /dev/null
+++ b/clang/test/CodeGen/amdgcnspirv-size-optimization.c
@@ -0,0 +1,45 @@
+
+// RUN: %clang_cc1 -O0 -triple spirv64-amd-amdhsa -disable-llvm-passes -emit-llvm-bc -o /dev/null -fdebug-pass-manager %s 2>&1 | FileCheck %s --check-prefix=O0
+// RUN: %clang_cc1 -O1 -triple spirv64-amd-amdhsa -disable-llvm-passes -emit-llvm-bc -o /dev/null -fdebug-pass-manager %s 2>&1 | FileCheck %s --check-prefix=O1
+// RUN: %clang_cc1 -O2 -triple spirv64-amd-amdhsa -disable-llvm-passes -emit-llvm-bc -o /dev/null -fdebug-pass-manager %s 2>&1 | FileCheck %s --check-prefix=O2
+
+// O0-NOT: Running pass: LowerExpectIntrinsic
+// O0-NOT: Running pass: SimplifyCFG
+// O0-NOT: Running pass: SROA
+// O0-NOT: Running pass: EarlyCSE
+// O0-NOT: Running pass: ForceFunctionAttrs
+// O0-NOT: Running pass: InferFunctionAttrs
+// O0-NOT: Running pass: IPSCCP
+// O0-NOT: Running pass: GlobalOpt
+// O0-NOT: Running pass: Promote
+// O0-NOT: Running pass: DeadArgumentElimination
+// O0-NOT: Running pass: InstCombine
+// O0-NOT: Running pass: PostOrderFunctionAttrs
+
+// O1-NOT: Running pass: LowerExpectIntrinsic
+// O1-NOT: Running pass: SimplifyCFG
+// O1-NOT: Running pass: SROA
+// O1-NOT: Running pass: EarlyCSE
+// O1-NOT: Running pass: ForceFunctionAttrs
+// O1-NOT: Running pass: InferFunctionAttrs
+// O1-NOT: Running pass: IPSCCP
+// O1-NOT: Running pass: GlobalOpt
+// O1-NOT: Running pass: Promote
+// O1-NOT: Running pass: DeadArgumentElimination
+// O1-NOT: Running pass: InstCombine
+// O1-NOT: Running pass: PostOrderFunctionAttrs
+
+// O2-DAG: Running pass: LowerExpectIntrinsic
+// O2-DAG: Running pass: SimplifyCFG
+// O2-DAG: Running pass: SROA
+// O2-DAG: Running pass: EarlyCSE
+// O2-DAG: Running pass: ForceFunctionAttrs
+// O2-DAG: Running pass: InferFunctionAttrs
+// O2-DAG: Running pass: IPSCCP
+// O2-DAG: Running pass: GlobalOpt
+// O2-DAG: Running pass: Promote
+// O2-DAG: Running pass: DeadArgumentElimination
+// O2-DAG: Running pass: InstCombine
+// O2-DAG: Running pass: PostOrderFunctionAttrs
+
+void foo() {}
>From 86fc7fa0632f0487be03b82affd51875fdadd66b Mon Sep 17 00:00:00 2001
From: Alex Voicu <alexandru.voicu at amd.com>
Date: Fri, 2 Oct 2026 12:52:51 +0100
Subject: [PATCH 03/15] Fix formatting.
---
clang/lib/CodeGen/BackendUtil.cpp | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp
index 6f7e5c76965441..ee4e4be696de9b 100644
--- a/clang/lib/CodeGen/BackendUtil.cpp
+++ b/clang/lib/CodeGen/BackendUtil.cpp
@@ -68,8 +68,8 @@
#include "llvm/Transforms/HipStdPar/HipStdPar.h"
#include "llvm/Transforms/IPO/DeadArgumentElimination.h"
#include "llvm/Transforms/IPO/EmbedBitcodePass.h"
-#include "llvm/Transforms/IPO/FunctionAttrs.h"
#include "llvm/Transforms/IPO/ForceFunctionAttrs.h"
+#include "llvm/Transforms/IPO/FunctionAttrs.h"
#include "llvm/Transforms/IPO/GlobalOpt.h"
#include "llvm/Transforms/IPO/InferFunctionAttrs.h"
#include "llvm/Transforms/IPO/LowerTypeTests.h"
@@ -101,8 +101,8 @@
#include "llvm/Transforms/Scalar/GVN.h"
#include "llvm/Transforms/Scalar/JumpThreading.h"
#include "llvm/Transforms/Scalar/LowerExpectIntrinsic.h"
-#include "llvm/Transforms/Scalar/SimplifyCFG.h"
#include "llvm/Transforms/Scalar/SROA.h"
+#include "llvm/Transforms/Scalar/SimplifyCFG.h"
#include "llvm/Transforms/Utils/AssignGUID.h"
#include "llvm/Transforms/Utils/Debugify.h"
#include "llvm/Transforms/Utils/DynamicDebugging.h"
@@ -822,8 +822,8 @@ static void addAMDGCNSPIRVSizeOptimizationPasses(ModulePassManager &MPM) {
// GF: -lower-expect -simplifycfg -sroa -early-cse
MPM.addPass(createModuleToFunctionPassAdaptor(LowerExpectIntrinsicPass()));
MPM.addPass(createModuleToFunctionPassAdaptor(SimplifyCFGPass()));
- MPM.addPass(createModuleToFunctionPassAdaptor(
- SROAPass(SROAOptions::PreserveCFG)));
+ MPM.addPass(
+ createModuleToFunctionPassAdaptor(SROAPass(SROAOptions::PreserveCFG)));
MPM.addPass(createModuleToFunctionPassAdaptor(EarlyCSEPass()));
// G0: -forceattrs -inferattrs -ipsccp -globalopt -mem2reg -deadargelim
@@ -837,8 +837,8 @@ static void addAMDGCNSPIRVSizeOptimizationPasses(ModulePassManager &MPM) {
MPM.addPass(DeadArgumentEliminationPass());
MPM.addPass(createModuleToFunctionPassAdaptor(InstCombinePass()));
MPM.addPass(createModuleToFunctionPassAdaptor(SimplifyCFGPass()));
- MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(
- PostOrderFunctionAttrsPass()));
+ MPM.addPass(
+ createModuleToPostOrderCGSCCPassAdaptor(PostOrderFunctionAttrsPass()));
}
void EmitAssemblyHelper::RunOptimizationPipeline(
>From 15d5013fa6a6012ed4f318ec2b8ac6628a2282a8 Mon Sep 17 00:00:00 2001
From: Alex Voicu <alexandru.voicu at amd.com>
Date: Sun, 4 Oct 2026 12:22:55 +0100
Subject: [PATCH 04/15] Update test.
---
.../CodeGen/amdgcnspirv-size-optimization.c | 44 +++++++------------
1 file changed, 17 insertions(+), 27 deletions(-)
diff --git a/clang/test/CodeGen/amdgcnspirv-size-optimization.c b/clang/test/CodeGen/amdgcnspirv-size-optimization.c
index 93385ec800e0fe..cf512d3a4d7af9 100644
--- a/clang/test/CodeGen/amdgcnspirv-size-optimization.c
+++ b/clang/test/CodeGen/amdgcnspirv-size-optimization.c
@@ -1,7 +1,10 @@
// RUN: %clang_cc1 -O0 -triple spirv64-amd-amdhsa -disable-llvm-passes -emit-llvm-bc -o /dev/null -fdebug-pass-manager %s 2>&1 | FileCheck %s --check-prefix=O0
-// RUN: %clang_cc1 -O1 -triple spirv64-amd-amdhsa -disable-llvm-passes -emit-llvm-bc -o /dev/null -fdebug-pass-manager %s 2>&1 | FileCheck %s --check-prefix=O1
-// RUN: %clang_cc1 -O2 -triple spirv64-amd-amdhsa -disable-llvm-passes -emit-llvm-bc -o /dev/null -fdebug-pass-manager %s 2>&1 | FileCheck %s --check-prefix=O2
+// RUN: %clang_cc1 -O1 -triple spirv64-amd-amdhsa -disable-llvm-passes -emit-llvm-bc -o /dev/null -fdebug-pass-manager %s 2>&1 | FileCheck %s --check-prefix=O0
+// RUN: %clang_cc1 -Og -triple spirv64-amd-amdhsa -disable-llvm-passes -emit-llvm-bc -o /dev/null -fdebug-pass-manager %s 2>&1 | FileCheck %s --check-prefix=O0
+// RUN: %clang_cc1 -O2 -triple spirv64-amd-amdhsa -disable-llvm-passes -emit-llvm-bc -o /dev/null -fdebug-pass-manager %s 2>&1 | FileCheck %s --check-prefix=O
+// RUN: %clang_cc1 -Os -triple spirv64-amd-amdhsa -disable-llvm-passes -emit-llvm-bc -o /dev/null -fdebug-pass-manager %s 2>&1 | FileCheck %s --check-prefix=O
+// RUN: %clang_cc1 -Oz -triple spirv64-amd-amdhsa -disable-llvm-passes -emit-llvm-bc -o /dev/null -fdebug-pass-manager %s 2>&1 | FileCheck %s --check-prefix=O
// O0-NOT: Running pass: LowerExpectIntrinsic
// O0-NOT: Running pass: SimplifyCFG
@@ -16,30 +19,17 @@
// O0-NOT: Running pass: InstCombine
// O0-NOT: Running pass: PostOrderFunctionAttrs
-// O1-NOT: Running pass: LowerExpectIntrinsic
-// O1-NOT: Running pass: SimplifyCFG
-// O1-NOT: Running pass: SROA
-// O1-NOT: Running pass: EarlyCSE
-// O1-NOT: Running pass: ForceFunctionAttrs
-// O1-NOT: Running pass: InferFunctionAttrs
-// O1-NOT: Running pass: IPSCCP
-// O1-NOT: Running pass: GlobalOpt
-// O1-NOT: Running pass: Promote
-// O1-NOT: Running pass: DeadArgumentElimination
-// O1-NOT: Running pass: InstCombine
-// O1-NOT: Running pass: PostOrderFunctionAttrs
-
-// O2-DAG: Running pass: LowerExpectIntrinsic
-// O2-DAG: Running pass: SimplifyCFG
-// O2-DAG: Running pass: SROA
-// O2-DAG: Running pass: EarlyCSE
-// O2-DAG: Running pass: ForceFunctionAttrs
-// O2-DAG: Running pass: InferFunctionAttrs
-// O2-DAG: Running pass: IPSCCP
-// O2-DAG: Running pass: GlobalOpt
-// O2-DAG: Running pass: Promote
-// O2-DAG: Running pass: DeadArgumentElimination
-// O2-DAG: Running pass: InstCombine
-// O2-DAG: Running pass: PostOrderFunctionAttrs
+// O-DAG: Running pass: LowerExpectIntrinsic
+// O-DAG: Running pass: SimplifyCFG
+// O-DAG: Running pass: SROA
+// O-DAG: Running pass: EarlyCSE
+// O-DAG: Running pass: ForceFunctionAttrs
+// O-DAG: Running pass: InferFunctionAttrs
+// O-DAG: Running pass: IPSCCP
+// O-DAG: Running pass: GlobalOpt
+// O-DAG: Running pass: Promote
+// O-DAG: Running pass: DeadArgumentElimination
+// O-DAG: Running pass: InstCombine
+// O-DAG: Running pass: PostOrderFunctionAttrs
void foo() {}
>From 2230231bfa7ce820fe2eaae24333827b5f09f265 Mon Sep 17 00:00:00 2001
From: Alex Voicu <alexandru.voicu at amd.com>
Date: Mon, 12 Oct 2026 19:39:43 +0100
Subject: [PATCH 05/15] Guard size optimizations via flag.
---
clang/include/clang/Basic/CodeGenOptions.def | 1 +
clang/include/clang/Options/Options.td | 7 +++++++
clang/lib/CodeGen/BackendUtil.cpp | 8 +++++---
3 files changed, 13 insertions(+), 3 deletions(-)
diff --git a/clang/include/clang/Basic/CodeGenOptions.def b/clang/include/clang/Basic/CodeGenOptions.def
index 10d9a4e3a6a82c..bb86ae58f7c2f3 100644
--- a/clang/include/clang/Basic/CodeGenOptions.def
+++ b/clang/include/clang/Basic/CodeGenOptions.def
@@ -205,6 +205,7 @@ CODEGENOPT(OpenCLCorrectlyRoundedDivSqrt, 1, 0, Benign) ///< -cl-fp32-correctly-
CODEGENOPT(HIPCorrectlyRoundedDivSqrt, 1, 1, Benign) ///< -fno-hip-fp32-correctly-rounded-divide-sqrt
CODEGENOPT(DisableBlockSignatureString, 1, 0, Benign) ///< Set when -fdisable-block-signature-string is enabled.
CODEGENOPT(HIPSaveKernelArgName, 1, 0, Benign) ///< Set when -fhip-kernel-arg-name is enabled.
+CODEGENOPT(AMDGCNSPIRVSizeOptimization, 1, 0, Benign) ///< Set when fenable-spirv-size-optimization is enabled.
CODEGENOPT(UniqueInternalLinkageNames, 1, 0, Benign) ///< Internal Linkage symbols get unique names.
CODEGENOPT(SplitMachineFunctions, 1, 0, Benign) ///< Split machine functions using profile information.
CODEGENOPT(PartitionStaticDataSections, 1, 0, Benign) /// < Partition static data sections using profile information.
diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td
index 60ae84cb0af5c7..a0f5706749e08e 100644
--- a/clang/include/clang/Options/Options.td
+++ b/clang/include/clang/Options/Options.td
@@ -1580,6 +1580,13 @@ def no_use_spirv_backend
Group<hip_Group>,
Flags<[HelpHidden]>,
HelpText<"Do not use the SPIRV backend for compilation ">;
+def fenable_spirv_size_optimization
+ : Flag<["-"], "fenable-spirv-size-optimization">,
+ MarshallingInfoFlag<CodeGenOpts<"AMDGCNSPIRVSizeOptimization">>,
+ Visibility<[ClangOption, CC1Option]>,
+ Group<hip_Group>,
+ Flags<[HelpHidden]>,
+ HelpText<"Enable size reducing optimizations for AMDGCNSPIRV">;
}
// Clang specific/exclusive options for OpenACC.
diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp
index ee4e4be696de9b..a9924f2619de61 100644
--- a/clang/lib/CodeGen/BackendUtil.cpp
+++ b/clang/lib/CodeGen/BackendUtil.cpp
@@ -1157,9 +1157,11 @@ void EmitAssemblyHelper::RunOptimizationPipeline(
} else {
MPM.addPass(PB.buildPerModuleDefaultPipeline(Level));
}
- } else if (TargetTriple.isSPIRV() &&
- TargetTriple.getVendor() == llvm::Triple::VendorType::AMD &&
- mapToLevel(CodeGenOpts) > OptimizationLevel::O1) {
+ } else if (mapToLevel(CodeGenOpts) > OptimizationLevel::O0 &&
+ CodeGenOpts.AMDGCNSPIRVSizeOptimization) {
+ assert(TargetTriple.isSPIRV() &&
+ TargetTriple.getVendor() == llvm::Triple::VendorType::AMD &&
+ "Invalid target triple!");
addAMDGCNSPIRVSizeOptimizationPasses(MPM);
}
>From 35e3959fc73d47221cb452fc616e3ee97ca171dd Mon Sep 17 00:00:00 2001
From: Alex Voicu <alexandru.voicu at amd.com>
Date: Mon, 12 Oct 2026 19:40:17 +0100
Subject: [PATCH 06/15] Update test.
---
clang/test/CodeGen/amdgcnspirv-size-optimization.c | 14 +++++++++++---
1 file changed, 11 insertions(+), 3 deletions(-)
diff --git a/clang/test/CodeGen/amdgcnspirv-size-optimization.c b/clang/test/CodeGen/amdgcnspirv-size-optimization.c
index cf512d3a4d7af9..f052c0c740358f 100644
--- a/clang/test/CodeGen/amdgcnspirv-size-optimization.c
+++ b/clang/test/CodeGen/amdgcnspirv-size-optimization.c
@@ -1,10 +1,18 @@
// RUN: %clang_cc1 -O0 -triple spirv64-amd-amdhsa -disable-llvm-passes -emit-llvm-bc -o /dev/null -fdebug-pass-manager %s 2>&1 | FileCheck %s --check-prefix=O0
+// RUN: %clang_cc1 -O0 -triple spirv64-amd-amdhsa -disable-llvm-passes -emit-llvm-bc -fenable-spirv-size-optimization -o /dev/null -fdebug-pass-manager %s 2>&1 | FileCheck %s --check-prefix=O0
// RUN: %clang_cc1 -O1 -triple spirv64-amd-amdhsa -disable-llvm-passes -emit-llvm-bc -o /dev/null -fdebug-pass-manager %s 2>&1 | FileCheck %s --check-prefix=O0
+// RUN: %clang_cc1 -O2 -triple spirv64-amd-amdhsa -disable-llvm-passes -emit-llvm-bc -o /dev/null -fdebug-pass-manager %s 2>&1 | FileCheck %s --check-prefix=O0
+// RUN: %clang_cc1 -O3 -triple spirv64-amd-amdhsa -disable-llvm-passes -emit-llvm-bc -o /dev/null -fdebug-pass-manager %s 2>&1 | FileCheck %s --check-prefix=O0
// RUN: %clang_cc1 -Og -triple spirv64-amd-amdhsa -disable-llvm-passes -emit-llvm-bc -o /dev/null -fdebug-pass-manager %s 2>&1 | FileCheck %s --check-prefix=O0
-// RUN: %clang_cc1 -O2 -triple spirv64-amd-amdhsa -disable-llvm-passes -emit-llvm-bc -o /dev/null -fdebug-pass-manager %s 2>&1 | FileCheck %s --check-prefix=O
-// RUN: %clang_cc1 -Os -triple spirv64-amd-amdhsa -disable-llvm-passes -emit-llvm-bc -o /dev/null -fdebug-pass-manager %s 2>&1 | FileCheck %s --check-prefix=O
-// RUN: %clang_cc1 -Oz -triple spirv64-amd-amdhsa -disable-llvm-passes -emit-llvm-bc -o /dev/null -fdebug-pass-manager %s 2>&1 | FileCheck %s --check-prefix=O
+// RUN: %clang_cc1 -Os -triple spirv64-amd-amdhsa -disable-llvm-passes -emit-llvm-bc -o /dev/null -fdebug-pass-manager %s 2>&1 | FileCheck %s --check-prefix=O0
+// RUN: %clang_cc1 -Oz -triple spirv64-amd-amdhsa -disable-llvm-passes -emit-llvm-bc -o /dev/null -fdebug-pass-manager %s 2>&1 | FileCheck %s --check-prefix=O0
+// RUN: %clang_cc1 -O1 -triple spirv64-amd-amdhsa -disable-llvm-passes -emit-llvm-bc -fenable-spirv-size-optimization -o /dev/null -fdebug-pass-manager %s 2>&1 | FileCheck %s --check-prefix=O
+// RUN: %clang_cc1 -O2 -triple spirv64-amd-amdhsa -disable-llvm-passes -emit-llvm-bc -fenable-spirv-size-optimization -o /dev/null -fdebug-pass-manager %s 2>&1 | FileCheck %s --check-prefix=O
+// RUN: %clang_cc1 -O3 -triple spirv64-amd-amdhsa -disable-llvm-passes -emit-llvm-bc -fenable-spirv-size-optimization -o /dev/null -fdebug-pass-manager %s 2>&1 | FileCheck %s --check-prefix=O
+// RUN: %clang_cc1 -Og -triple spirv64-amd-amdhsa -disable-llvm-passes -emit-llvm-bc -fenable-spirv-size-optimization -o /dev/null -fdebug-pass-manager %s 2>&1 | FileCheck %s --check-prefix=O
+// RUN: %clang_cc1 -Os -triple spirv64-amd-amdhsa -disable-llvm-passes -emit-llvm-bc -fenable-spirv-size-optimization -o /dev/null -fdebug-pass-manager %s 2>&1 | FileCheck %s --check-prefix=O
+// RUN: %clang_cc1 -Oz -triple spirv64-amd-amdhsa -disable-llvm-passes -emit-llvm-bc -fenable-spirv-size-optimization -o /dev/null -fdebug-pass-manager %s 2>&1 | FileCheck %s --check-prefix=O
// O0-NOT: Running pass: LowerExpectIntrinsic
// O0-NOT: Running pass: SimplifyCFG
>From b5c7ff151009a5d60f04b347b3082017ce98d58d Mon Sep 17 00:00:00 2001
From: Alex Voicu <alexandru.voicu at amd.com>
Date: Tue, 13 Oct 2026 10:54:58 +0100
Subject: [PATCH 07/15] Add missing Clang side handling.
---
clang/lib/Driver/ToolChains/Clang.cpp | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index fb6effb65d71f7..35fc112fce400d 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -7480,6 +7480,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
Args.AddLastArg(CmdArgs, options::OPT_hipstdpar_interpose_alloc);
Args.addOptInFlag(CmdArgs, options::OPT_fhip_kernel_arg_name,
options::OPT_fno_hip_kernel_arg_name);
+ Args.addLastArg(CmdArgs, options::OPT_fenable_spirv_size_optimization);
}
if ((IsCuda || IsHIP || IsSYCL) && IsRDCMode)
@@ -9845,7 +9846,8 @@ void LinkerWrapper::ConstructJob(Compilation &C, const JobAction &JA,
OPT_fno_sanitize_trap_EQ,
OPT_fslp_vectorize,
OPT_fno_slp_vectorize,
- OPT_hipstdpar};
+ OPT_hipstdpar,
+ OPT_fenable_spirv_size_optimization};
const llvm::DenseSet<unsigned> LinkerOptions{OPT_mllvm, OPT_Zlinker_input};
// Suppress verbose output for HIP non-RDC fat binaries because it confuses
// CMake implicit linker argument parsing.
>From bb147f89c06ba2673677a8339d9d25f51b6afed8 Mon Sep 17 00:00:00 2001
From: Alex Voicu <alexandru.voicu at amd.com>
Date: Tue, 13 Oct 2026 18:13:08 +0100
Subject: [PATCH 08/15] Correctly constrain to AMDGCNSPIRV.
---
clang/lib/Driver/ToolChains/Clang.cpp | 2 ++
1 file changed, 2 insertions(+)
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index 35fc112fce400d..dcc9d0502a1b44 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -7480,6 +7480,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
Args.AddLastArg(CmdArgs, options::OPT_hipstdpar_interpose_alloc);
Args.addOptInFlag(CmdArgs, options::OPT_fhip_kernel_arg_name,
options::OPT_fno_hip_kernel_arg_name);
+ if (TC.getTriple().isSPIRV() &&
+ TC.getTriple().getVendor() == llvm::Triple::VendorType::AMD)
Args.addLastArg(CmdArgs, options::OPT_fenable_spirv_size_optimization);
}
>From bc402094dfc0479c8ec512a65e077750081fb524 Mon Sep 17 00:00:00 2001
From: Alex Voicu <alexandru.voicu at amd.com>
Date: Wed, 14 Oct 2026 22:22:57 +0100
Subject: [PATCH 09/15] Use a hard error instead of an `assert`.
---
clang/lib/CodeGen/BackendUtil.cpp | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp
index e22e8da04a6ee5..306946d10dda61 100644
--- a/clang/lib/CodeGen/BackendUtil.cpp
+++ b/clang/lib/CodeGen/BackendUtil.cpp
@@ -1156,9 +1156,10 @@ void EmitAssemblyHelper::RunOptimizationPipeline(
}
} else if (mapToLevel(CodeGenOpts) > OptimizationLevel::O0 &&
CodeGenOpts.AMDGCNSPIRVSizeOptimization) {
- assert(TargetTriple.isSPIRV() &&
- TargetTriple.getVendor() == llvm::Triple::VendorType::AMD &&
- "Invalid target triple!");
+ if (!TargetTriple.isSPIRV() ||
+ (TargetTriple.getVendor() != llvm::Triple::VendorType::AMD))
+ Diags.Report(diag::err_opt_not_valid_on_target)
+ << "fenable-spirv-size-optimization";
addAMDGCNSPIRVSizeOptimizationPasses(MPM);
}
>From 7b56e65f9b034be72db0c5ff6396ca16236f68f9 Mon Sep 17 00:00:00 2001
From: Alex Voicu <alexandru.voicu at amd.com>
Date: Wed, 14 Oct 2026 22:23:44 +0100
Subject: [PATCH 10/15] Apply suggestion.
---
clang/include/clang/Basic/CodeGenOptions.def | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/include/clang/Basic/CodeGenOptions.def b/clang/include/clang/Basic/CodeGenOptions.def
index bb86ae58f7c2f3..1bd9afc684c3ab 100644
--- a/clang/include/clang/Basic/CodeGenOptions.def
+++ b/clang/include/clang/Basic/CodeGenOptions.def
@@ -205,7 +205,7 @@ CODEGENOPT(OpenCLCorrectlyRoundedDivSqrt, 1, 0, Benign) ///< -cl-fp32-correctly-
CODEGENOPT(HIPCorrectlyRoundedDivSqrt, 1, 1, Benign) ///< -fno-hip-fp32-correctly-rounded-divide-sqrt
CODEGENOPT(DisableBlockSignatureString, 1, 0, Benign) ///< Set when -fdisable-block-signature-string is enabled.
CODEGENOPT(HIPSaveKernelArgName, 1, 0, Benign) ///< Set when -fhip-kernel-arg-name is enabled.
-CODEGENOPT(AMDGCNSPIRVSizeOptimization, 1, 0, Benign) ///< Set when fenable-spirv-size-optimization is enabled.
+CODEGENOPT(AMDGCNSPIRVSizeOptimization, 1, 0, Benign) ///< Set when -fenable-spirv-size-optimization is enabled.
CODEGENOPT(UniqueInternalLinkageNames, 1, 0, Benign) ///< Internal Linkage symbols get unique names.
CODEGENOPT(SplitMachineFunctions, 1, 0, Benign) ///< Split machine functions using profile information.
CODEGENOPT(PartitionStaticDataSections, 1, 0, Benign) /// < Partition static data sections using profile information.
>From 2169eabb6762d74d715674ef780ae917f6a7dda8 Mon Sep 17 00:00:00 2001
From: Alex Voicu <alexandru.voicu at amd.com>
Date: Wed, 14 Oct 2026 22:39:50 +0100
Subject: [PATCH 11/15] Check BC as well.
---
clang/test/CodeGen/amdgcnspirv-size-optimization.c | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/clang/test/CodeGen/amdgcnspirv-size-optimization.c b/clang/test/CodeGen/amdgcnspirv-size-optimization.c
index f052c0c740358f..864337c01d3d29 100644
--- a/clang/test/CodeGen/amdgcnspirv-size-optimization.c
+++ b/clang/test/CodeGen/amdgcnspirv-size-optimization.c
@@ -13,6 +13,8 @@
// RUN: %clang_cc1 -Og -triple spirv64-amd-amdhsa -disable-llvm-passes -emit-llvm-bc -fenable-spirv-size-optimization -o /dev/null -fdebug-pass-manager %s 2>&1 | FileCheck %s --check-prefix=O
// RUN: %clang_cc1 -Os -triple spirv64-amd-amdhsa -disable-llvm-passes -emit-llvm-bc -fenable-spirv-size-optimization -o /dev/null -fdebug-pass-manager %s 2>&1 | FileCheck %s --check-prefix=O
// RUN: %clang_cc1 -Oz -triple spirv64-amd-amdhsa -disable-llvm-passes -emit-llvm-bc -fenable-spirv-size-optimization -o /dev/null -fdebug-pass-manager %s 2>&1 | FileCheck %s --check-prefix=O
+// RUN: %clang_cc1 -Oz -triple spirv64-amd-amdhsa -disable-llvm-passes -emit-llvm -o - %s | FileCheck %s --check-prefix=O0-BC
+// RUN: %clang_cc1 -Oz -triple spirv64-amd-amdhsa -disable-llvm-passes -emit-llvm -fenable-spirv-size-optimization -o - %s | FileCheck %s --check-prefix=O-BC
// O0-NOT: Running pass: LowerExpectIntrinsic
// O0-NOT: Running pass: SimplifyCFG
@@ -40,4 +42,9 @@
// O-DAG: Running pass: InstCombine
// O-DAG: Running pass: PostOrderFunctionAttrs
-void foo() {}
+// O0-BC: alloca
+// O-BC-NOT: alloca
+int foo(int x) {
+ int y = x;
+ return y;
+}
>From fa78c92c2b61e2fa05c1c91691f7999613a9db32 Mon Sep 17 00:00:00 2001
From: Alex Voicu <alexandru.voicu at amd.com>
Date: Wed, 14 Oct 2026 22:59:56 +0100
Subject: [PATCH 12/15] Add Clang side test.
---
clang/test/Driver/hip-options.hip | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/clang/test/Driver/hip-options.hip b/clang/test/Driver/hip-options.hip
index a53c1a61abefab..d6b77a0822d06a 100644
--- a/clang/test/Driver/hip-options.hip
+++ b/clang/test/Driver/hip-options.hip
@@ -286,3 +286,8 @@
// NO-COV-NOT: --device-compiler=amdgcn-amd-amdhsa=-fprofile-instr-generate
// NO-COV-NOT: --device-compiler=amdgcn-amd-amdhsa=-fcoverage-mapping
+// Check that AMDGCNSPIRV size optimization is forwarded to -cc1
+// RUN: %clang -### -nogpuinc -nogpulib -fenable-spirv-size-optimization \
+// RUN: --offload-arch=amdgcnspirv %s 2>&1 | FileCheck -check-prefix=AMDGCNSPIRV-SIZE-OPT %s
+// AMDGCNSPIRV-SIZE-OPT: "-cc1"{{.*}} "-triple" "spirv64-amd-amdhsa" {{.*}} "-fenable-spirv-size-optimization"
+
>From a460c19411dd0d60ac1fce3091102086c862a4be Mon Sep 17 00:00:00 2001
From: Alex Voicu <alexandru.voicu at amd.com>
Date: Wed, 14 Oct 2026 23:04:08 +0100
Subject: [PATCH 13/15] Fix formatting.
---
clang/lib/Driver/ToolChains/Clang.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index dcc9d0502a1b44..cf00632a935ba2 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -7482,7 +7482,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
options::OPT_fno_hip_kernel_arg_name);
if (TC.getTriple().isSPIRV() &&
TC.getTriple().getVendor() == llvm::Triple::VendorType::AMD)
- Args.addLastArg(CmdArgs, options::OPT_fenable_spirv_size_optimization);
+ Args.addLastArg(CmdArgs, options::OPT_fenable_spirv_size_optimization);
}
if ((IsCuda || IsHIP || IsSYCL) && IsRDCMode)
>From 18aa0a2ab0dc1fb2cfd852b161cab9f0c0caa01d Mon Sep 17 00:00:00 2001
From: Alex Voicu <alexandru.voicu at amd.com>
Date: Thu, 15 Oct 2026 17:45:18 +0100
Subject: [PATCH 14/15] Test for error state as well.
---
clang/test/CodeGen/amdgcnspirv-size-optimization.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/clang/test/CodeGen/amdgcnspirv-size-optimization.c b/clang/test/CodeGen/amdgcnspirv-size-optimization.c
index 864337c01d3d29..38428cef345d08 100644
--- a/clang/test/CodeGen/amdgcnspirv-size-optimization.c
+++ b/clang/test/CodeGen/amdgcnspirv-size-optimization.c
@@ -15,6 +15,7 @@
// RUN: %clang_cc1 -Oz -triple spirv64-amd-amdhsa -disable-llvm-passes -emit-llvm-bc -fenable-spirv-size-optimization -o /dev/null -fdebug-pass-manager %s 2>&1 | FileCheck %s --check-prefix=O
// RUN: %clang_cc1 -Oz -triple spirv64-amd-amdhsa -disable-llvm-passes -emit-llvm -o - %s | FileCheck %s --check-prefix=O0-BC
// RUN: %clang_cc1 -Oz -triple spirv64-amd-amdhsa -disable-llvm-passes -emit-llvm -fenable-spirv-size-optimization -o - %s | FileCheck %s --check-prefix=O-BC
+// RUN: not %clang_cc1 -Oz -triple spirv64-unknown-unknown -disable-llvm-passes -emit-llvm -fenable-spirv-size-optimization %s 2>&1 | FileCheck %s --check-prefix=ERR
// O0-NOT: Running pass: LowerExpectIntrinsic
// O0-NOT: Running pass: SimplifyCFG
@@ -48,3 +49,5 @@ int foo(int x) {
int y = x;
return y;
}
+
+// ERR: error: option 'fenable-spirv-size-optimization' cannot be specified on this target
>From f832e020e79207772103fd96fa214c247d6ad9fa Mon Sep 17 00:00:00 2001
From: Alex Voicu <alexandru.voicu at amd.com>
Date: Thu, 15 Oct 2026 17:49:58 +0100
Subject: [PATCH 15/15] Return immediately after erroring out.
---
clang/lib/CodeGen/BackendUtil.cpp | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp
index 306946d10dda61..599c0dab717fb5 100644
--- a/clang/lib/CodeGen/BackendUtil.cpp
+++ b/clang/lib/CodeGen/BackendUtil.cpp
@@ -1157,9 +1157,11 @@ void EmitAssemblyHelper::RunOptimizationPipeline(
} else if (mapToLevel(CodeGenOpts) > OptimizationLevel::O0 &&
CodeGenOpts.AMDGCNSPIRVSizeOptimization) {
if (!TargetTriple.isSPIRV() ||
- (TargetTriple.getVendor() != llvm::Triple::VendorType::AMD))
+ (TargetTriple.getVendor() != llvm::Triple::VendorType::AMD)) {
Diags.Report(diag::err_opt_not_valid_on_target)
<< "fenable-spirv-size-optimization";
+ return;
+ }
addAMDGCNSPIRVSizeOptimizationPasses(MPM);
}
More information about the cfe-commits
mailing list