[llvm] [SPIR-V] Add lowering for G_FEXP10 (PR #182466)
via llvm-commits
llvm-commits at lists.llvm.org
Fri Feb 20 08:06:44 PST 2026
https://github.com/idubinov updated https://github.com/llvm/llvm-project/pull/182466
>From 66f73e0a3a7a7e9c8cdb426ca76c75710e917128 Mon Sep 17 00:00:00 2001
From: idubinov <igor.dubinov at amd.com>
Date: Fri, 20 Feb 2026 03:53:47 -0600
Subject: [PATCH 1/4] Add exp10 support
---
.../Target/SPIRV/SPIRVInstructionSelector.cpp | 106 ++++++++++++++++
llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp | 1 +
.../SPIRV/llvm-intrinsics/exp10-glsl.ll | 120 ++++++++++++++++++
.../SPIRV/llvm-intrinsics/exp10-opencl.ll | 108 ++++++++++++++++
4 files changed, 335 insertions(+)
create mode 100644 llvm/test/CodeGen/SPIRV/llvm-intrinsics/exp10-glsl.ll
create mode 100644 llvm/test/CodeGen/SPIRV/llvm-intrinsics/exp10-opencl.ll
diff --git a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
index 1ea8036a2a698..3531e084e0122 100644
--- a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
@@ -324,6 +324,19 @@ class SPIRVInstructionSelector : public InstructionSelector {
bool selectExtInstForLRound(Register ResVReg, SPIRVTypeInst ResType,
MachineInstr &I,
const ExtInstList &ExtInsts) const;
+ bool selectExtInstWithSrcs(Register ResVReg, SPIRVTypeInst RestType,
+ MachineInstr &I, std::vector<Register> SrcRegs,
+ GL::GLSLExtInst GLInst) const;
+ bool selectExtInstWithSrcs(Register ResVReg, SPIRVTypeInst ResType,
+ MachineInstr &I, std::vector<Register> SrcRegs,
+ CL::OpenCLExtInst CLInst) const;
+ bool selectExtInstWithSrcs(Register ResVReg, SPIRVTypeInst ResType,
+ MachineInstr &I, std::vector<Register> SrcRegs,
+ CL::OpenCLExtInst CLInst,
+ GL::GLSLExtInst GLInst) const;
+ bool selectExtInstWithSrcs(Register ResVReg, SPIRVTypeInst ResType,
+ MachineInstr &I, std::vector<Register> SrcRegs,
+ const ExtInstList &ExtInsts) const;
bool selectLog10(Register ResVReg, SPIRVTypeInst ResType,
MachineInstr &I) const;
@@ -375,6 +388,8 @@ class SPIRVInstructionSelector : public InstructionSelector {
MachineInstr &I) const;
bool selectSincos(Register ResVReg, SPIRVTypeInst ResType,
MachineInstr &I) const;
+ bool selectExp10(Register ResVReg, SPIRVTypeInst ResType,
+ MachineInstr &I) const;
bool selectDerivativeInst(Register ResVReg, SPIRVTypeInst ResType,
MachineInstr &I, const unsigned DPdOpCode) const;
// Utilities
@@ -1024,6 +1039,9 @@ bool SPIRVInstructionSelector::spvSelect(Register ResVReg,
return selectExtInst(ResVReg, ResType, I, CL::exp, GL::Exp);
case TargetOpcode::G_FEXP2:
return selectExtInst(ResVReg, ResType, I, CL::exp2, GL::Exp2);
+ case TargetOpcode::G_FEXP10:
+ return selectExp10(ResVReg, ResType, I);
+
case TargetOpcode::G_FMODF:
return selectModf(ResVReg, ResType, I);
case TargetOpcode::G_FSINCOS:
@@ -1370,6 +1388,54 @@ bool SPIRVInstructionSelector::selectExtInst(Register ResVReg,
}
return false;
}
+
+bool SPIRVInstructionSelector::selectExtInstWithSrcs(
+ Register ResVReg, SPIRVTypeInst ResType, MachineInstr &I,
+ std::vector<Register> SrcRegs, GL::GLSLExtInst GLInst) const {
+ ExtInstList ExtInsts = {{SPIRV::InstructionSet::GLSL_std_450, GLInst}};
+ return selectExtInstWithSrcs(ResVReg, ResType, I, SrcRegs, ExtInsts);
+}
+
+bool SPIRVInstructionSelector::selectExtInstWithSrcs(
+ Register ResVReg, SPIRVTypeInst ResType, MachineInstr &I,
+ std::vector<Register> SrcRegs, CL::OpenCLExtInst CLInst) const {
+ ExtInstList ExtInsts = {{SPIRV::InstructionSet::OpenCL_std, CLInst}};
+ return selectExtInstWithSrcs(ResVReg, ResType, I, SrcRegs, ExtInsts);
+}
+
+bool SPIRVInstructionSelector::selectExtInstWithSrcs(
+ Register ResVReg, SPIRVTypeInst ResType, MachineInstr &I,
+ std::vector<Register> SrcRegs, CL::OpenCLExtInst CLInst,
+ GL::GLSLExtInst GLInst) const {
+ ExtInstList ExtInsts = {{SPIRV::InstructionSet::OpenCL_std, CLInst},
+ {SPIRV::InstructionSet::GLSL_std_450, GLInst}};
+ return selectExtInstWithSrcs(ResVReg, ResType, I, SrcRegs, ExtInsts);
+}
+
+bool SPIRVInstructionSelector::selectExtInstWithSrcs(
+ Register ResVReg, SPIRVTypeInst ResType, MachineInstr &I,
+ std::vector<Register> SrcRegs, const ExtInstList &Insts) const {
+ for (const auto &Ex : Insts) {
+ SPIRV::InstructionSet::InstructionSet Set = Ex.first;
+ if (STI.canUseExtInstSet(Set)) {
+ uint32_t Opcode = Ex.second;
+ MachineBasicBlock &BB = *I.getParent();
+ auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpExtInst))
+ .addDef(ResVReg)
+ .addUse(GR.getSPIRVTypeID(ResType))
+ .addImm(static_cast<uint32_t>(Set))
+ .addImm(Opcode)
+ .setMIFlags(I.getFlags());
+ for (Register SReg : SrcRegs) {
+ MIB.addUse(SReg);
+ }
+ MIB.constrainAllUses(TII, TRI, RBI);
+ return true;
+ }
+ }
+ return false;
+}
+
bool SPIRVInstructionSelector::selectExtInstForLRound(
Register ResVReg, SPIRVTypeInst ResType, MachineInstr &I,
CL::OpenCLExtInst CLInst, GL::GLSLExtInst GLInst) const {
@@ -3218,6 +3284,46 @@ bool SPIRVInstructionSelector::selectFCmp(Register ResVReg,
return selectCmp(ResVReg, ResType, CmpOp, I);
}
+bool SPIRVInstructionSelector::selectExp10(Register ResVReg,
+ SPIRVTypeInst ResType,
+ MachineInstr &I) const {
+
+ if (STI.canUseExtInstSet(SPIRV::InstructionSet::OpenCL_std)) {
+ return selectExtInst(ResVReg, ResType, I, CL::exp10);
+ } else if (STI.canUseExtInstSet(SPIRV::InstructionSet::GLSL_std_450)) {
+ /// There is no exp10 in GLSL. Use exp10(x) = exp2(x * log2(10)) instead
+ /// log2(10) ~= 3.3219280948874
+
+ if (ResType->getOpcode() != SPIRV::OpTypeVector &&
+ ResType->getOpcode() != SPIRV::OpTypeFloat)
+ return false;
+
+ MachineIRBuilder MIRBuilder(I);
+
+ SPIRVTypeInst SpirvScalarType = ResType->getOpcode() == SPIRV::OpTypeVector
+ ? SPIRVTypeInst(GR.getSPIRVTypeForVReg(
+ ResType->getOperand(1).getReg()))
+ : ResType;
+
+ Register ConstReg = GR.buildConstantFP(APFloat(3.3219280948874f),
+ MIRBuilder, SpirvScalarType);
+ Register ArgReg = MRI->createVirtualRegister(GR.getRegClass(ResType));
+ auto Opcode = ResType->getOpcode() == SPIRV::OpTypeVector
+ ? SPIRV::OpVectorTimesScalar
+ : SPIRV::OpFMulS;
+
+ if (!selectOpWithSrcs(
+ ArgReg, ResType, I,
+ std::vector<Register>({ConstReg, I.getOperand(1).getReg()}),
+ Opcode))
+ return false;
+ return selectExtInstWithSrcs(
+ ResVReg, ResType, I, std::vector<Register>({ArgReg}), GL::Exp2);
+ }
+
+ return false;
+}
+
Register SPIRVInstructionSelector::buildZerosVal(SPIRVTypeInst ResType,
MachineInstr &I) const {
// OpenCL uses nulls for Zero. In HLSL we don't use null constants.
diff --git a/llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp b/llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp
index d8f197443c6ab..93e82750c4f32 100644
--- a/llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp
@@ -445,6 +445,7 @@ SPIRVLegalizerInfo::SPIRVLegalizerInfo(const SPIRVSubtarget &ST) {
G_FMODF,
G_FSINCOS,
G_FEXP2,
+ G_FEXP10,
G_FLOG,
G_FLOG2,
G_FLOG10,
diff --git a/llvm/test/CodeGen/SPIRV/llvm-intrinsics/exp10-glsl.ll b/llvm/test/CodeGen/SPIRV/llvm-intrinsics/exp10-glsl.ll
new file mode 100644
index 0000000000000..9662df6b5bbf9
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/llvm-intrinsics/exp10-glsl.ll
@@ -0,0 +1,120 @@
+; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv-unknown-vulkan1.3-compute %s -o - | FileCheck %s
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-vulkan1.3-compute %s -o - -filetype=obj | spirv-val %}
+
+; Test if llvm.exp10 is lowered to opencl::exp10 with the result correctly
+;reused by the original llvm.exp10 user.
+
+
+; CHECK-DAG: %[[#ExtInstId:]] = OpExtInstImport "GLSL.std.450"
+; CHECK-DAG: %[[#F16Ty:]] = OpTypeFloat 16
+; CHECK-DAG: %[[#F32Ty:]] = OpTypeFloat 32
+; CHECK-DAG: %[[#F64Ty:]] = OpTypeFloat 64
+; CHECK-DAG: %[[#Vec2_16Ty:]] = OpTypeVector %[[#F16Ty]] 2
+; CHECK-DAG: %[[#Vec2_32Ty:]] = OpTypeVector %[[#F32Ty]] 2
+; CHECK-DAG: %[[#Vec2_64Ty:]] = OpTypeVector %[[#F64Ty]] 2
+; CHECK-DAG: %[[#Vec4_16Ty:]] = OpTypeVector %[[#F16Ty]] 4
+; CHECK-DAG: %[[#Vec4_32Ty:]] = OpTypeVector %[[#F32Ty]] 4
+; CHECK-DAG: %[[#Vec4_64Ty:]] = OpTypeVector %[[#F64Ty]] 4
+; CHECK-DAG: %[[#Constant_s16:]] = OpConstant %[[#F16Ty:]] 3.3219280242919922
+; CHECK-DAG: %[[#Constant_s32:]] = OpConstant %[[#F32Ty:]] 3.3219280242919922
+; CHECK-DAG: %[[#Constant_s64:]] = OpConstant %[[#F64Ty:]] 3.3219280242919922
+
+; CHECK-LABEL: Begin function test_exp10_f16_scalar
+; CHECK: %[[#s16_arg:]] = OpFunctionParameter %[[#F16Ty]]
+; CHECK: %[[#s16_mul:]] = OpFMul %[[#F16Ty]] %[[#Constant_s16]] %[[#s16_arg]]
+; CHECK: %[[#s16_ret:]] = OpExtInst %[[#F16Ty]] %[[#ExtInstId]] Exp2 %[[#s16_mul]]
+; CHECK: OpReturnValue %[[#s16_ret]]
+; CHECK-LABEL: OpFunctionEnd
+define half @test_exp10_f16_scalar(half %x) {
+ %res = call half @llvm.exp10.f16(half %x)
+ ret half %res
+}
+
+; CHECK-LABEL: Begin function test_exp10_f32_scalar
+; CHECK: %[[#s32_arg:]] = OpFunctionParameter %[[#F32Ty]]
+; CHECK: %[[#s32_mul:]] = OpFMul %[[#F32Ty]] %[[#Constant_s32]] %[[#s32_arg]]
+; CHECK: %[[#s32_ret:]] = OpExtInst %[[#F32Ty]] %[[#ExtInstId]] Exp2 %[[#s32_mul]]
+; CHECK: OpReturnValue %[[#s32_ret]]
+; CHECK-LABEL: OpFunctionEnd
+define float @test_exp10_f32_scalar(float %x) {
+ %res = call float @llvm.exp10.f32(float %x)
+ ret float %res
+}
+
+; CHECK-LABEL: Begin function test_exp10_f64_scalar
+; CHECK: %[[#s64_arg:]] = OpFunctionParameter %[[#F64Ty]]
+; CHECK: %[[#s64_mul:]] = OpFMul %[[#F64Ty]] %[[#Constant_s64]] %[[#s64_arg]]
+; CHECK: %[[#s64_ret:]] = OpExtInst %[[#F64Ty]] %[[#ExtInstId]] Exp2 %[[#s64_mul]]
+; CHECK: OpReturnValue %[[#s64_ret]]
+; CHECK-LABEL: OpFunctionEnd
+define double @test_exp10_f64_scalar(double %x) {
+ %res = call double @llvm.exp10.f64(double %x)
+ ret double %res
+}
+
+; CHECK-LABEL: Begin function test_exp10_f16_vec2
+; CHECK: %[[#v2_16_arg:]] = OpFunctionParameter %[[#Vec2_16Ty]]
+; CHECK: %[[#v2_16_mul:]] = OpVectorTimesScalar %[[#Vec2_16Ty]] %[[#Constant_s16]] %[[#v2_16_arg]]
+; CHECK: %[[#v2_16_ret:]] = OpExtInst %[[#Vec2_16Ty]] %[[#ExtInstId]] Exp2 %[[#v2_16_mul]]
+; CHECK: OpReturnValue %[[#v2_16_ret]]
+; CHECK-LABEL: OpFunctionEnd
+define <2 x half> @test_exp10_f16_vec2(<2 x half> %x) {
+ %res = call <2 x half> @llvm.exp10.f16(<2 x half> %x)
+ ret <2 x half> %res
+}
+
+; CHECK-LABEL: Begin function test_exp10_f32_vec2
+; CHECK: %[[#v2_32_arg:]] = OpFunctionParameter %[[#Vec2_32Ty]]
+; CHECK: %[[#v2_32_mul:]] = OpVectorTimesScalar %[[#Vec2_32Ty]] %[[#Constant_s32]] %[[#v2_32_arg]]
+; CHECK: %[[#v2_32_ret:]] = OpExtInst %[[#Vec2_32Ty]] %[[#ExtInstId]] Exp2 %[[#v2_32_mul]]
+; CHECK: OpReturnValue %[[#v2_32_ret]]
+; CHECK-LABEL: OpFunctionEnd
+define <2 x float> @test_exp10_f32_vec2(<2 x float> %x) {
+ %res = call <2 x float> @llvm.exp10.f32(<2 x float> %x)
+ ret <2 x float> %res
+}
+
+; CHECK-LABEL: Begin function test_exp10_f64_vec2
+; CHECK: %[[#v2_64_arg:]] = OpFunctionParameter %[[#Vec2_64Ty]]
+; CHECK: %[[#v2_64_mul:]] = OpVectorTimesScalar %[[#Vec2_64Ty]] %[[#Constant_s64]] %[[#v2_64_arg]]
+; CHECK: %[[#v2_64_ret:]] = OpExtInst %[[#Vec2_64Ty]] %[[#ExtInstId]] Exp2 %[[#v2_64_mul]]
+; CHECK: OpReturnValue %[[#v2_64_ret]]
+; CHECK-LABEL: OpFunctionEnd
+define <2 x double> @test_exp10_f64_vec2(<2 x double> %x) {
+ %res = call <2 x double> @llvm.exp10.f64(<2 x double> %x)
+ ret <2 x double> %res
+}
+
+
+; CHECK-LABEL: Begin function test_exp10_f16_vec4
+; CHECK: %[[#v4_16_arg:]] = OpFunctionParameter %[[#Vec4_16Ty]]
+; CHECK: %[[#v4_16_mul:]] = OpVectorTimesScalar %[[#Vec4_16Ty]] %[[#Constant_s16]] %[[#v4_16_arg]]
+; CHECK: %[[#v4_16_ret:]] = OpExtInst %[[#Vec4_16Ty]] %[[#ExtInstId]] Exp2 %[[#v4_16_mul]]
+; CHECK: OpReturnValue %[[#v4_16_ret]]
+; CHECK-LABEL: OpFunctionEnd
+define <4 x half> @test_exp10_f16_vec4(<4 x half> %x) {
+ %res = call <4 x half> @llvm.exp10.f16(<4 x half> %x)
+ ret <4 x half> %res
+}
+
+; CHECK-LABEL: Begin function test_exp10_f32_vec4
+; CHECK: %[[#v4_32_arg:]] = OpFunctionParameter %[[#Vec4_32Ty]]
+; CHECK: %[[#v4_32_mul:]] = OpVectorTimesScalar %[[#Vec4_32Ty]] %[[#Constant_s32]] %[[#v4_32_arg]]
+; CHECK: %[[#v4_32_ret:]] = OpExtInst %[[#Vec4_32Ty]] %[[#ExtInstId]] Exp2 %[[#v4_32_mul]]
+; CHECK: OpReturnValue %[[#v4_32_ret]]
+; CHECK-LABEL: OpFunctionEnd
+define <4 x float> @test_exp10_f32_vec4(<4 x float> %x) {
+ %res = call <4 x float> @llvm.exp10.f32(<4 x float> %x)
+ ret <4 x float> %res
+}
+
+; CHECK-LABEL: Begin function test_exp10_f64_vec4
+; CHECK: %[[#v4_64_arg:]] = OpFunctionParameter %[[#Vec4_64Ty]]
+; CHECK: %[[#v4_64_mul:]] = OpVectorTimesScalar %[[#Vec4_64Ty]] %[[#Constant_s64]] %[[#v4_64_arg]]
+; CHECK: %[[#v4_64_ret:]] = OpExtInst %[[#Vec4_64Ty]] %[[#ExtInstId]] Exp2 %[[#v4_64_mul]]
+; CHECK: OpReturnValue %[[#v4_64_ret]]
+; CHECK-LABEL: OpFunctionEnd
+define <4 x double> @test_exp10_f64_vec4(<4 x double> %x) {
+ %res = call <4 x double> @llvm.exp10.f64(<4 x double> %x)
+ ret <4 x double> %res
+}
diff --git a/llvm/test/CodeGen/SPIRV/llvm-intrinsics/exp10-opencl.ll b/llvm/test/CodeGen/SPIRV/llvm-intrinsics/exp10-opencl.ll
new file mode 100644
index 0000000000000..dd4340b85ab0d
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/llvm-intrinsics/exp10-opencl.ll
@@ -0,0 +1,108 @@
+; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown %s -o - -filetype=obj | spirv-val %}
+
+; Test if llvm.exp10 is lowered to opencl::exp10 with the result correctly
+;reused by the original llvm.exp10 user.
+
+
+; CHECK-DAG: %[[#ExtInstId:]] = OpExtInstImport "OpenCL.std"
+; CHECK-DAG: %[[#F16Ty:]] = OpTypeFloat 16
+; CHECK-DAG: %[[#F32Ty:]] = OpTypeFloat 32
+; CHECK-DAG: %[[#F64Ty:]] = OpTypeFloat 64
+; CHECK-DAG: %[[#Vec2_16Ty:]] = OpTypeVector %[[#F16Ty]] 2
+; CHECK-DAG: %[[#Vec2_32Ty:]] = OpTypeVector %[[#F32Ty]] 2
+; CHECK-DAG: %[[#Vec2_64Ty:]] = OpTypeVector %[[#F64Ty]] 2
+; CHECK-DAG: %[[#Vec16_16Ty:]] = OpTypeVector %[[#F16Ty]] 16
+; CHECK-DAG: %[[#Vec16_32y:]] = OpTypeVector %[[#F32Ty]] 16
+; CHECK-DAG: %[[#Vec16_64Ty:]] = OpTypeVector %[[#F64Ty]] 16
+
+; CHECK-LABEL: Begin function test_exp10_f16_scalar
+; CHECK: %[[#s16_arg:]] = OpFunctionParameter %[[#F16Ty]]
+; CHECK: %[[#s16_ret:]] = OpExtInst %[[#F16Ty]] %[[#ExtInstId]] exp10 %[[#s16_arg]]
+; CHECK: OpReturnValue %[[#s16_ret]]
+; CHECK-LABEL: OpFunctionEnd
+define half @test_exp10_f16_scalar(half %x) {
+ %res = call half @llvm.exp10.f16(half %x)
+ ret half %res
+}
+
+; CHECK-LABEL: Begin function test_exp10_f32_scalar
+; CHECK: %[[#s32_arg:]] = OpFunctionParameter %[[#F32Ty]]
+; CHECK: %[[#s32_ret:]] = OpExtInst %[[#F32Ty]] %[[#ExtInstId]] exp10 %[[#s32_arg]]
+; CHECK: OpReturnValue %[[#s32_ret]]
+; CHECK-LABEL: OpFunctionEnd
+define float @test_exp10_f32_scalar(float %x) {
+ %res = call float @llvm.exp10.f32(float %x)
+ ret float %res
+}
+
+; CHECK-LABEL: Begin function test_exp10_f64_scalar
+; CHECK: %[[#s64_arg:]] = OpFunctionParameter %[[#F64Ty]]
+; CHECK: %[[#s64_ret:]] = OpExtInst %[[#F64Ty]] %[[#ExtInstId]] exp10 %[[#s64_arg]]
+; CHECK: OpReturnValue %[[#s64_ret]]
+; CHECK-LABEL: OpFunctionEnd
+define double @test_exp10_f64_scalar(double %x) {
+ %res = call double @llvm.exp10.f64(double %x)
+ ret double %res
+}
+
+; CHECK-LABEL: Begin function test_exp10_f16_vec2
+; CHECK: %[[#v2_16_arg:]] = OpFunctionParameter %[[#Vec2_16Ty]]
+; CHECK: %[[#v2_16_ret:]] = OpExtInst %[[#Vec2_16Ty]] %[[#ExtInstId]] exp10 %[[#v2_16_arg]]
+; CHECK: OpReturnValue %[[#v2_16_ret]]
+; CHECK-LABEL: OpFunctionEnd
+define <2 x half> @test_exp10_f16_vec2(<2 x half> %x) {
+ %res = call <2 x half> @llvm.exp10.v2f16(<2 x half> %x)
+ ret <2 x half> %res
+}
+
+; CHECK-LABEL: Begin function test_exp10_f32_vec2
+; CHECK: %[[#v2_32_arg:]] = OpFunctionParameter %[[#Vec2_32Ty]]
+; CHECK: %[[#v2_32_ret:]] = OpExtInst %[[#Vec2_32Ty]] %[[#ExtInstId]] exp10 %[[#v2_32_arg]]
+; CHECK: OpReturnValue %[[#v2_32_ret]]
+; CHECK-LABEL: OpFunctionEnd
+define <2 x float> @test_exp10_f32_vec2(<2 x float> %x) {
+ %res = call <2 x float> @llvm.exp10.v2f32(<2 x float> %x)
+ ret <2 x float> %res
+}
+
+; CHECK-LABEL: Begin function test_exp10_f64_vec2
+; CHECK: %[[#v2_64_arg:]] = OpFunctionParameter %[[#Vec2_64Ty]]
+; CHECK: %[[#v2_64_ret:]] = OpExtInst %[[#Vec2_64Ty]] %[[#ExtInstId]] exp10 %[[#v2_64_arg]]
+; CHECK: OpReturnValue %[[#v2_64_ret]]
+; CHECK-LABEL: OpFunctionEnd
+define <2 x double> @test_exp10_f64_vec2(<2 x double> %x) {
+ %res = call <2 x double> @llvm.exp10.v2f64(<2 x double> %x)
+ ret <2 x double> %res
+}
+
+
+; CHECK-LABEL: Begin function test_exp10_f16_vec16
+; CHECK: %[[#v16_16_arg:]] = OpFunctionParameter %[[#Vec16_16Ty]]
+; CHECK: %[[#v16_16_ret:]] = OpExtInst %[[#Vec16_16Ty]] %[[#ExtInstId]] exp10 %[[#v16_16_arg]]
+; CHECK: OpReturnValue %[[#v16_16_ret]]
+; CHECK-LABEL: OpFunctionEnd
+define <16 x half> @test_exp10_f16_vec16(<16 x half> %x) {
+ %res = call <16 x half> @llvm.exp10.v16f16(<16 x half> %x)
+ ret <16 x half> %res
+}
+
+; CHECK-LABEL: Begin function test_exp10_f32_vec16
+; CHECK: %[[#v16_32_arg:]] = OpFunctionParameter %[[#Vec16_32y]]
+; CHECK: %[[#v16_32_ret:]] = OpExtInst %[[#Vec16_32y]] %[[#ExtInstId]] exp10 %[[#v16_32_arg]]
+; CHECK: OpReturnValue %[[#v16_32_ret]]
+; CHECK-LABEL: OpFunctionEnd
+define <16 x float> @test_exp10_f32_vec16(<16 x float> %x) {
+ %res = call <16 x float> @llvm.exp10.v16f32(<16 x float> %x)
+ ret <16 x float> %res
+}
+
+; CHECK-LABEL: Begin function test_exp10_f64_vec16
+; CHECK: %[[#v16_64_arg:]] = OpFunctionParameter %[[#Vec16_64Ty]]
+; CHECK: %[[#v16_64_ret:]] = OpExtInst %[[#Vec16_64Ty]] %[[#ExtInstId]] exp10 %[[#v16_64_arg]]
+; CHECK: OpReturnValue %[[#v16_64_ret]]
+; CHECK-LABEL: OpFunctionEnd
+define <16 x double> @test_exp10_f64_vec16(<16 x double> %x) {
+ %res = call <16 x double> @llvm.exp10.v16f64(<16 x double> %x)
+ ret <16 x double> %res
+}
>From 255af7df1594ecb91d441131d60c87fb879087b0 Mon Sep 17 00:00:00 2001
From: idubinov <igor.dubinov at amd.com>
Date: Fri, 20 Feb 2026 04:10:19 -0600
Subject: [PATCH 2/4] code format
---
llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp | 4 ++--
llvm/test/CodeGen/SPIRV/llvm-intrinsics/exp10-glsl.ll | 4 ++--
llvm/test/CodeGen/SPIRV/llvm-intrinsics/exp10-opencl.ll | 2 +-
3 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
index 3531e084e0122..0262f8ee13f9b 100644
--- a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
@@ -3317,8 +3317,8 @@ bool SPIRVInstructionSelector::selectExp10(Register ResVReg,
std::vector<Register>({ConstReg, I.getOperand(1).getReg()}),
Opcode))
return false;
- return selectExtInstWithSrcs(
- ResVReg, ResType, I, std::vector<Register>({ArgReg}), GL::Exp2);
+ return selectExtInstWithSrcs(ResVReg, ResType, I,
+ std::vector<Register>({ArgReg}), GL::Exp2);
}
return false;
diff --git a/llvm/test/CodeGen/SPIRV/llvm-intrinsics/exp10-glsl.ll b/llvm/test/CodeGen/SPIRV/llvm-intrinsics/exp10-glsl.ll
index 9662df6b5bbf9..07042a39ee662 100644
--- a/llvm/test/CodeGen/SPIRV/llvm-intrinsics/exp10-glsl.ll
+++ b/llvm/test/CodeGen/SPIRV/llvm-intrinsics/exp10-glsl.ll
@@ -1,8 +1,8 @@
; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv-unknown-vulkan1.3-compute %s -o - | FileCheck %s
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-vulkan1.3-compute %s -o - -filetype=obj | spirv-val %}
-; Test if llvm.exp10 is lowered to opencl::exp10 with the result correctly
-;reused by the original llvm.exp10 user.
+; Test if llvm.exp10 is lowered with the result correctly reused by the
+; original llvm.exp10 user.
; CHECK-DAG: %[[#ExtInstId:]] = OpExtInstImport "GLSL.std.450"
diff --git a/llvm/test/CodeGen/SPIRV/llvm-intrinsics/exp10-opencl.ll b/llvm/test/CodeGen/SPIRV/llvm-intrinsics/exp10-opencl.ll
index dd4340b85ab0d..f98179546b245 100644
--- a/llvm/test/CodeGen/SPIRV/llvm-intrinsics/exp10-opencl.ll
+++ b/llvm/test/CodeGen/SPIRV/llvm-intrinsics/exp10-opencl.ll
@@ -2,7 +2,7 @@
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown %s -o - -filetype=obj | spirv-val %}
; Test if llvm.exp10 is lowered to opencl::exp10 with the result correctly
-;reused by the original llvm.exp10 user.
+; reused by the original llvm.exp10 user.
; CHECK-DAG: %[[#ExtInstId:]] = OpExtInstImport "OpenCL.std"
>From 424b1d0f2aff7902fb06ab5c51e87944d2338962 Mon Sep 17 00:00:00 2001
From: idubinov <igor.dubinov at amd.com>
Date: Fri, 20 Feb 2026 09:48:13 -0600
Subject: [PATCH 3/4] Address review comments
---
.../Target/SPIRV/SPIRVInstructionSelector.cpp | 163 +++++++-----------
1 file changed, 63 insertions(+), 100 deletions(-)
diff --git a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
index 0262f8ee13f9b..51b5888590dcf 100644
--- a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
@@ -143,7 +143,7 @@ class SPIRVInstructionSelector : public InstructionSelector {
const MachineInstr *Init = nullptr) const;
bool selectOpWithSrcs(Register ResVReg, SPIRVTypeInst ResType,
- MachineInstr &I, std::vector<Register> SrcRegs,
+ MachineInstr &I, ArrayRef<Register> SrcRegs,
unsigned Opcode) const;
bool selectUnOp(Register ResVReg, SPIRVTypeInst ResType, MachineInstr &I,
@@ -324,18 +324,9 @@ class SPIRVInstructionSelector : public InstructionSelector {
bool selectExtInstForLRound(Register ResVReg, SPIRVTypeInst ResType,
MachineInstr &I,
const ExtInstList &ExtInsts) const;
- bool selectExtInstWithSrcs(Register ResVReg, SPIRVTypeInst RestType,
- MachineInstr &I, std::vector<Register> SrcRegs,
- GL::GLSLExtInst GLInst) const;
- bool selectExtInstWithSrcs(Register ResVReg, SPIRVTypeInst ResType,
- MachineInstr &I, std::vector<Register> SrcRegs,
- CL::OpenCLExtInst CLInst) const;
- bool selectExtInstWithSrcs(Register ResVReg, SPIRVTypeInst ResType,
- MachineInstr &I, std::vector<Register> SrcRegs,
- CL::OpenCLExtInst CLInst,
- GL::GLSLExtInst GLInst) const;
+
bool selectExtInstWithSrcs(Register ResVReg, SPIRVTypeInst ResType,
- MachineInstr &I, std::vector<Register> SrcRegs,
+ MachineInstr &I, ArrayRef<Register> SrcRegs,
const ExtInstList &ExtInsts) const;
bool selectLog10(Register ResVReg, SPIRVTypeInst ResType,
@@ -1363,75 +1354,48 @@ bool SPIRVInstructionSelector::selectExtInst(Register ResVReg,
MachineInstr &I,
const ExtInstList &Insts) const {
- for (const auto &Ex : Insts) {
- SPIRV::InstructionSet::InstructionSet Set = Ex.first;
- uint32_t Opcode = Ex.second;
- if (STI.canUseExtInstSet(Set)) {
- MachineBasicBlock &BB = *I.getParent();
- auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpExtInst))
- .addDef(ResVReg)
- .addUse(GR.getSPIRVTypeID(ResType))
- .addImm(static_cast<uint32_t>(Set))
- .addImm(Opcode)
- .setMIFlags(I.getFlags());
- const unsigned NumOps = I.getNumOperands();
- unsigned Index = 1;
- if (Index < NumOps &&
- I.getOperand(Index).getType() ==
- MachineOperand::MachineOperandType::MO_IntrinsicID)
- Index = 2;
- for (; Index < NumOps; ++Index)
- MIB.add(I.getOperand(Index));
- MIB.constrainAllUses(TII, TRI, RBI);
- return true;
- }
+ for (const auto &[InstructionSet, Opcode] : Insts) {
+ if (!STI.canUseExtInstSet(InstructionSet))
+ continue;
+ MachineBasicBlock &BB = *I.getParent();
+ auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpExtInst))
+ .addDef(ResVReg)
+ .addUse(GR.getSPIRVTypeID(ResType))
+ .addImm(static_cast<uint32_t>(InstructionSet))
+ .addImm(Opcode)
+ .setMIFlags(I.getFlags());
+ const unsigned NumOps = I.getNumOperands();
+ unsigned Index = 1;
+ if (Index < NumOps &&
+ I.getOperand(Index).getType() ==
+ MachineOperand::MachineOperandType::MO_IntrinsicID)
+ Index = 2;
+ for (; Index < NumOps; ++Index)
+ MIB.add(I.getOperand(Index));
+ MIB.constrainAllUses(TII, TRI, RBI);
+ return true;
}
return false;
}
bool SPIRVInstructionSelector::selectExtInstWithSrcs(
Register ResVReg, SPIRVTypeInst ResType, MachineInstr &I,
- std::vector<Register> SrcRegs, GL::GLSLExtInst GLInst) const {
- ExtInstList ExtInsts = {{SPIRV::InstructionSet::GLSL_std_450, GLInst}};
- return selectExtInstWithSrcs(ResVReg, ResType, I, SrcRegs, ExtInsts);
-}
-
-bool SPIRVInstructionSelector::selectExtInstWithSrcs(
- Register ResVReg, SPIRVTypeInst ResType, MachineInstr &I,
- std::vector<Register> SrcRegs, CL::OpenCLExtInst CLInst) const {
- ExtInstList ExtInsts = {{SPIRV::InstructionSet::OpenCL_std, CLInst}};
- return selectExtInstWithSrcs(ResVReg, ResType, I, SrcRegs, ExtInsts);
-}
-
-bool SPIRVInstructionSelector::selectExtInstWithSrcs(
- Register ResVReg, SPIRVTypeInst ResType, MachineInstr &I,
- std::vector<Register> SrcRegs, CL::OpenCLExtInst CLInst,
- GL::GLSLExtInst GLInst) const {
- ExtInstList ExtInsts = {{SPIRV::InstructionSet::OpenCL_std, CLInst},
- {SPIRV::InstructionSet::GLSL_std_450, GLInst}};
- return selectExtInstWithSrcs(ResVReg, ResType, I, SrcRegs, ExtInsts);
-}
-
-bool SPIRVInstructionSelector::selectExtInstWithSrcs(
- Register ResVReg, SPIRVTypeInst ResType, MachineInstr &I,
- std::vector<Register> SrcRegs, const ExtInstList &Insts) const {
- for (const auto &Ex : Insts) {
- SPIRV::InstructionSet::InstructionSet Set = Ex.first;
- if (STI.canUseExtInstSet(Set)) {
- uint32_t Opcode = Ex.second;
- MachineBasicBlock &BB = *I.getParent();
- auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpExtInst))
- .addDef(ResVReg)
- .addUse(GR.getSPIRVTypeID(ResType))
- .addImm(static_cast<uint32_t>(Set))
- .addImm(Opcode)
- .setMIFlags(I.getFlags());
- for (Register SReg : SrcRegs) {
- MIB.addUse(SReg);
- }
- MIB.constrainAllUses(TII, TRI, RBI);
- return true;
+ ArrayRef<Register> SrcRegs, const ExtInstList &Insts) const {
+ for (const auto &[InstructionSet, Opcode] : Insts) {
+ if (!STI.canUseExtInstSet(InstructionSet))
+ continue;
+ MachineBasicBlock &BB = *I.getParent();
+ auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpExtInst))
+ .addDef(ResVReg)
+ .addUse(GR.getSPIRVTypeID(ResType))
+ .addImm(static_cast<uint32_t>(InstructionSet))
+ .addImm(Opcode)
+ .setMIFlags(I.getFlags());
+ for (Register SReg : SrcRegs) {
+ MIB.addUse(SReg);
}
+ MIB.constrainAllUses(TII, TRI, RBI);
+ return true;
}
return false;
}
@@ -1447,27 +1411,25 @@ bool SPIRVInstructionSelector::selectExtInstForLRound(
bool SPIRVInstructionSelector::selectExtInstForLRound(
Register ResVReg, SPIRVTypeInst ResType, MachineInstr &I,
const ExtInstList &Insts) const {
- for (const auto &Ex : Insts) {
- SPIRV::InstructionSet::InstructionSet Set = Ex.first;
- uint32_t Opcode = Ex.second;
- if (STI.canUseExtInstSet(Set)) {
- MachineBasicBlock &BB = *I.getParent();
- auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpExtInst))
- .addDef(ResVReg)
- .addUse(GR.getSPIRVTypeID(ResType))
- .addImm(static_cast<uint32_t>(Set))
- .addImm(Opcode);
- const unsigned NumOps = I.getNumOperands();
- unsigned Index = 1;
- if (Index < NumOps &&
- I.getOperand(Index).getType() ==
- MachineOperand::MachineOperandType::MO_IntrinsicID)
- Index = 2;
- for (; Index < NumOps; ++Index)
- MIB.add(I.getOperand(Index));
- MIB.constrainAllUses(TII, TRI, RBI);
- return true;
- }
+ for (const auto &[InstructionSet, Opcode] : Insts) {
+ if (!STI.canUseExtInstSet(InstructionSet))
+ continue;
+ MachineBasicBlock &BB = *I.getParent();
+ auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpExtInst))
+ .addDef(ResVReg)
+ .addUse(GR.getSPIRVTypeID(ResType))
+ .addImm(static_cast<uint32_t>(InstructionSet))
+ .addImm(Opcode);
+ const unsigned NumOps = I.getNumOperands();
+ unsigned Index = 1;
+ if (Index < NumOps &&
+ I.getOperand(Index).getType() ==
+ MachineOperand::MachineOperandType::MO_IntrinsicID)
+ Index = 2;
+ for (; Index < NumOps; ++Index)
+ MIB.add(I.getOperand(Index));
+ MIB.constrainAllUses(TII, TRI, RBI);
+ return true;
}
return false;
}
@@ -1575,7 +1537,7 @@ bool SPIRVInstructionSelector::selectSincos(Register ResVReg,
bool SPIRVInstructionSelector::selectOpWithSrcs(Register ResVReg,
SPIRVTypeInst ResType,
MachineInstr &I,
- std::vector<Register> Srcs,
+ ArrayRef<Register> Srcs,
unsigned Opcode) const {
auto MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(Opcode))
.addDef(ResVReg)
@@ -3287,10 +3249,10 @@ bool SPIRVInstructionSelector::selectFCmp(Register ResVReg,
bool SPIRVInstructionSelector::selectExp10(Register ResVReg,
SPIRVTypeInst ResType,
MachineInstr &I) const {
-
if (STI.canUseExtInstSet(SPIRV::InstructionSet::OpenCL_std)) {
return selectExtInst(ResVReg, ResType, I, CL::exp10);
- } else if (STI.canUseExtInstSet(SPIRV::InstructionSet::GLSL_std_450)) {
+ }
+ if (STI.canUseExtInstSet(SPIRV::InstructionSet::GLSL_std_450)) {
/// There is no exp10 in GLSL. Use exp10(x) = exp2(x * log2(10)) instead
/// log2(10) ~= 3.3219280948874
@@ -3314,11 +3276,12 @@ bool SPIRVInstructionSelector::selectExp10(Register ResVReg,
if (!selectOpWithSrcs(
ArgReg, ResType, I,
- std::vector<Register>({ConstReg, I.getOperand(1).getReg()}),
+ {ConstReg, I.getOperand(1).getReg()},
Opcode))
return false;
return selectExtInstWithSrcs(ResVReg, ResType, I,
- std::vector<Register>({ArgReg}), GL::Exp2);
+ std::vector<Register>({ArgReg}),
+ {{SPIRV::InstructionSet::GLSL_std_450,GL::Exp2}});
}
return false;
>From 012e87adb1237c8c0961154eb5085e9f38a9d11e Mon Sep 17 00:00:00 2001
From: idubinov <igor.dubinov at amd.com>
Date: Fri, 20 Feb 2026 10:04:54 -0600
Subject: [PATCH 4/4] code format
---
.../Target/SPIRV/SPIRVInstructionSelector.cpp | 40 +++++++++----------
1 file changed, 19 insertions(+), 21 deletions(-)
diff --git a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
index 51b5888590dcf..acd4483077d40 100644
--- a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
@@ -1359,11 +1359,11 @@ bool SPIRVInstructionSelector::selectExtInst(Register ResVReg,
continue;
MachineBasicBlock &BB = *I.getParent();
auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpExtInst))
- .addDef(ResVReg)
- .addUse(GR.getSPIRVTypeID(ResType))
- .addImm(static_cast<uint32_t>(InstructionSet))
- .addImm(Opcode)
- .setMIFlags(I.getFlags());
+ .addDef(ResVReg)
+ .addUse(GR.getSPIRVTypeID(ResType))
+ .addImm(static_cast<uint32_t>(InstructionSet))
+ .addImm(Opcode)
+ .setMIFlags(I.getFlags());
const unsigned NumOps = I.getNumOperands();
unsigned Index = 1;
if (Index < NumOps &&
@@ -1386,11 +1386,11 @@ bool SPIRVInstructionSelector::selectExtInstWithSrcs(
continue;
MachineBasicBlock &BB = *I.getParent();
auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpExtInst))
- .addDef(ResVReg)
- .addUse(GR.getSPIRVTypeID(ResType))
- .addImm(static_cast<uint32_t>(InstructionSet))
- .addImm(Opcode)
- .setMIFlags(I.getFlags());
+ .addDef(ResVReg)
+ .addUse(GR.getSPIRVTypeID(ResType))
+ .addImm(static_cast<uint32_t>(InstructionSet))
+ .addImm(Opcode)
+ .setMIFlags(I.getFlags());
for (Register SReg : SrcRegs) {
MIB.addUse(SReg);
}
@@ -1416,10 +1416,10 @@ bool SPIRVInstructionSelector::selectExtInstForLRound(
continue;
MachineBasicBlock &BB = *I.getParent();
auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpExtInst))
- .addDef(ResVReg)
- .addUse(GR.getSPIRVTypeID(ResType))
- .addImm(static_cast<uint32_t>(InstructionSet))
- .addImm(Opcode);
+ .addDef(ResVReg)
+ .addUse(GR.getSPIRVTypeID(ResType))
+ .addImm(static_cast<uint32_t>(InstructionSet))
+ .addImm(Opcode);
const unsigned NumOps = I.getNumOperands();
unsigned Index = 1;
if (Index < NumOps &&
@@ -3274,14 +3274,12 @@ bool SPIRVInstructionSelector::selectExp10(Register ResVReg,
? SPIRV::OpVectorTimesScalar
: SPIRV::OpFMulS;
- if (!selectOpWithSrcs(
- ArgReg, ResType, I,
- {ConstReg, I.getOperand(1).getReg()},
- Opcode))
+ if (!selectOpWithSrcs(ArgReg, ResType, I,
+ {ConstReg, I.getOperand(1).getReg()}, Opcode))
return false;
- return selectExtInstWithSrcs(ResVReg, ResType, I,
- std::vector<Register>({ArgReg}),
- {{SPIRV::InstructionSet::GLSL_std_450,GL::Exp2}});
+ return selectExtInstWithSrcs(
+ ResVReg, ResType, I, std::vector<Register>({ArgReg}),
+ {{SPIRV::InstructionSet::GLSL_std_450, GL::Exp2}});
}
return false;
More information about the llvm-commits
mailing list