[llvm] [SPIR-V] Add OpSMulExtended and OpUMulExtended builtin support (PR #187474)
Arseniy Obolenskiy via llvm-commits
llvm-commits at lists.llvm.org
Thu Mar 19 09:26:51 PDT 2026
https://github.com/aobolensk updated https://github.com/llvm/llvm-project/pull/187474
>From ec7ba1d78723fec36c12e7e87c3d25590d9729f0 Mon Sep 17 00:00:00 2001
From: Arseniy Obolenskiy <arseniy.obolenskiy at amd.com>
Date: Thu, 19 Mar 2026 11:41:49 +0100
Subject: [PATCH 1/2] [SPIR-V] Add OpSMulExtended and OpUMulExtended builtin
support
---
llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp | 50 +++++++
llvm/lib/Target/SPIRV/SPIRVBuiltins.td | 5 +
.../CodeGen/SPIRV/smulextended-builtin.ll | 125 ++++++++++++++++++
.../CodeGen/SPIRV/umulextended-builtin.ll | 125 ++++++++++++++++++
4 files changed, 305 insertions(+)
create mode 100644 llvm/test/CodeGen/SPIRV/smulextended-builtin.ll
create mode 100644 llvm/test/CodeGen/SPIRV/umulextended-builtin.ll
diff --git a/llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp b/llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp
index f9a9127446013..6abf50f59a03f 100644
--- a/llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp
@@ -1996,6 +1996,54 @@ static bool generateICarryBorrowInst(const SPIRV::IncomingCall *Call,
return true;
}
+// We expect a builtin
+// Name(ptr sret([RetType]) %result, Type %operand1, Type %operand2)
+// where %result is a pointer to where the result of the builtin execution
+// is to be stored, and generate the following instructions:
+// Res = Opcode RetType Operand1 Operand2
+// OpStore RetVariable Res
+static bool generateMulExtendedInst(const SPIRV::IncomingCall *Call,
+ MachineIRBuilder &MIRBuilder,
+ SPIRVGlobalRegistry *GR) {
+ const SPIRV::DemangledBuiltin *Builtin = Call->Builtin;
+ unsigned Opcode =
+ SPIRV::lookupNativeBuiltin(Builtin->Name, Builtin->Set)->Opcode;
+ assert((Opcode == SPIRV::OpUMulExtended || Opcode == SPIRV::OpSMulExtended) &&
+ "Expected OpUMulExtended or OpSMulExtended");
+
+ Register SRetReg = Call->Arguments[0];
+ SPIRVTypeInst PtrRetType = GR->getSPIRVTypeForVReg(SRetReg);
+ SPIRVTypeInst RetType = GR->getPointeeType(PtrRetType);
+ if (!RetType)
+ report_fatal_error("The first parameter must be a pointer");
+ if (RetType->getOpcode() != SPIRV::OpTypeStruct)
+ report_fatal_error("Expected struct type result for the extended "
+ "multiplication builtins");
+
+ SPIRVTypeInst OpType1 = GR->getSPIRVTypeForVReg(Call->Arguments[1]);
+ SPIRVTypeInst OpType2 = GR->getSPIRVTypeForVReg(Call->Arguments[2]);
+ if (!OpType1 || !OpType2 || OpType1 != OpType2)
+ report_fatal_error("Operands must have the same type");
+
+ MachineRegisterInfo *MRI = MIRBuilder.getMRI();
+ Register ResReg = MRI->createVirtualRegister(&SPIRV::iIDRegClass);
+ if (const TargetRegisterClass *DstRC =
+ MRI->getRegClassOrNull(Call->Arguments[1])) {
+ MRI->setRegClass(ResReg, DstRC);
+ MRI->setType(ResReg, MRI->getType(Call->Arguments[1]));
+ } else {
+ MRI->setType(ResReg, LLT::scalar(64));
+ }
+ GR->assignSPIRVTypeToVReg(RetType, ResReg, MIRBuilder.getMF());
+ MIRBuilder.buildInstr(Opcode)
+ .addDef(ResReg)
+ .addUse(GR->getSPIRVTypeID(RetType))
+ .addUse(Call->Arguments[1])
+ .addUse(Call->Arguments[2]);
+ MIRBuilder.buildInstr(SPIRV::OpStore).addUse(SRetReg).addUse(ResReg);
+ return true;
+}
+
static bool generateGetQueryInst(const SPIRV::IncomingCall *Call,
MachineIRBuilder &MIRBuilder,
SPIRVGlobalRegistry *GR) {
@@ -3236,6 +3284,8 @@ std::optional<bool> lowerBuiltin(const StringRef DemangledCall,
return generateWaveInst(Call.get(), MIRBuilder, GR);
case SPIRV::ICarryBorrow:
return generateICarryBorrowInst(Call.get(), MIRBuilder, GR);
+ case SPIRV::MulExtended:
+ return generateMulExtendedInst(Call.get(), MIRBuilder, GR);
case SPIRV::GetQuery:
return generateGetQueryInst(Call.get(), MIRBuilder, GR);
case SPIRV::ImageSizeQuery:
diff --git a/llvm/lib/Target/SPIRV/SPIRVBuiltins.td b/llvm/lib/Target/SPIRV/SPIRVBuiltins.td
index eb1b6c3185e7d..b30db2b9f718d 100644
--- a/llvm/lib/Target/SPIRV/SPIRVBuiltins.td
+++ b/llvm/lib/Target/SPIRV/SPIRVBuiltins.td
@@ -65,6 +65,7 @@ def CastToPtr : BuiltinGroup;
def Construct : BuiltinGroup;
def CoopMatr : BuiltinGroup;
def ICarryBorrow : BuiltinGroup;
+def MulExtended : BuiltinGroup;
def ExtendedBitOps : BuiltinGroup;
def BindlessINTEL : BuiltinGroup;
def TernaryBitwiseINTEL : BuiltinGroup;
@@ -676,6 +677,10 @@ defm : DemangledNativeBuiltin<"__spirv_ControlBarrier", OpenCL_std, Barrier, 3,
defm : DemangledNativeBuiltin<"__spirv_IAddCarry", OpenCL_std, ICarryBorrow, 3, 3, OpIAddCarryS>;
defm : DemangledNativeBuiltin<"__spirv_ISubBorrow", OpenCL_std, ICarryBorrow, 3, 3, OpISubBorrowS>;
+// MulExtended builtin records:
+defm : DemangledNativeBuiltin<"__spirv_UMulExtended", OpenCL_std, MulExtended, 3, 3, OpUMulExtended>;
+defm : DemangledNativeBuiltin<"__spirv_SMulExtended", OpenCL_std, MulExtended, 3, 3, OpSMulExtended>;
+
// cl_intel_split_work_group_barrier
defm : DemangledNativeBuiltin<"intel_work_group_barrier_arrive", OpenCL_std, Barrier, 1, 2, OpControlBarrierArriveINTEL>;
defm : DemangledNativeBuiltin<"__spirv_ControlBarrierArriveINTEL", OpenCL_std, Barrier, 3, 3, OpControlBarrierArriveINTEL>;
diff --git a/llvm/test/CodeGen/SPIRV/smulextended-builtin.ll b/llvm/test/CodeGen/SPIRV/smulextended-builtin.ll
new file mode 100644
index 0000000000000..f8c632526ee23
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/smulextended-builtin.ll
@@ -0,0 +1,125 @@
+; RUN: llc -O0 -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s --check-prefix=CHECK-SPIRV
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown %s -o - -filetype=obj | spirv-val %}
+
+%i8struct = type {i8, i8}
+%i16struct = type {i16, i16}
+%i32struct = type {i32, i32}
+%i64struct = type {i64, i64}
+%vecstruct = type {<4 x i32>, <4 x i32>}
+
+; CHECK-SPIRV-DAG: [[uchar:%[a-z0-9_]+]] = OpTypeInt 8
+; CHECK-SPIRV-DAG: [[ushort:%[a-z0-9_]+]] = OpTypeInt 16
+; CHECK-SPIRV-DAG: [[uint:%[a-z0-9_]+]] = OpTypeInt 32
+; CHECK-SPIRV-DAG: [[ulong:%[a-z0-9_]+]] = OpTypeInt 64
+; CHECK-SPIRV-DAG: [[void:%[a-z0-9_]+]] = OpTypeVoid
+; CHECK-SPIRV-DAG: [[i8struct:%[a-z0-9_]+]] = OpTypeStruct [[uchar]] [[uchar]]
+; CHECK-SPIRV-DAG: [[_ptr_Function_i8struct:%[a-z0-9_]+]] = OpTypePointer Function [[i8struct]]
+; CHECK-SPIRV-DAG: [[i16struct:%[a-z0-9_]+]] = OpTypeStruct [[ushort]] [[ushort]]
+; CHECK-SPIRV-DAG: [[_ptr_Function_i16struct:%[a-z0-9_]+]] = OpTypePointer Function [[i16struct]]
+; CHECK-SPIRV-DAG: [[i32struct:%[a-z0-9_]+]] = OpTypeStruct [[uint]] [[uint]]
+; CHECK-SPIRV-DAG: [[_ptr_Function_i32struct:%[a-z0-9_]+]] = OpTypePointer Function [[i32struct]]
+; CHECK-SPIRV-DAG: [[i64struct:%[a-z0-9_]+]] = OpTypeStruct [[ulong]] [[ulong]]
+; CHECK-SPIRV-DAG: [[_ptr_Function_i64struct:%[a-z0-9_]+]] = OpTypePointer Function [[i64struct]]
+; CHECK-SPIRV-DAG: [[v4uint:%[a-z0-9_]+]] = OpTypeVector [[uint]] 4
+; CHECK-SPIRV-DAG: [[vecstruct:%[a-z0-9_]+]] = OpTypeStruct [[v4uint]] [[v4uint]]
+; CHECK-SPIRV-DAG: [[_ptr_Function_vecstruct:%[a-z0-9_]+]] = OpTypePointer Function [[vecstruct]]
+; CHECK-SPIRV-DAG: [[_ptr_Generic_i32struct:%[a-z0-9_]+]] = OpTypePointer Generic [[i32struct]]
+
+define spir_func void @test_builtin_smulextcc(i8 %a, i8 %b) {
+ entry:
+ %0 = alloca %i8struct
+ call void @_Z20__spirv_SMulExtendedcc(ptr sret (%i8struct) %0, i8 %a, i8 %b)
+ ret void
+}
+; CHECK-SPIRV: [[a:%[a-z0-9_]+]] = OpFunctionParameter [[uchar]]
+; CHECK-SPIRV: [[b:%[a-z0-9_]+]] = OpFunctionParameter [[uchar]]
+; CHECK-SPIRV: [[entry:%[a-z0-9_]+]] = OpLabel
+; CHECK-SPIRV: [[var_11:%[a-z0-9_]+]] = OpVariable [[_ptr_Function_i8struct]] Function
+; CHECK-SPIRV: [[var_12:%[a-z0-9_]+]] = OpSMulExtended [[i8struct]] [[a]] [[b]]
+; CHECK-SPIRV: OpStore [[var_11]] [[var_12]]
+; CHECK-SPIRV: OpReturn
+; CHECK-SPIRV: OpFunctionEnd
+
+define spir_func void @test_builtin_smulextss(i16 %a, i16 %b) {
+ entry:
+ %0 = alloca %i16struct
+ call void @_Z20__spirv_SMulExtendedss(ptr sret (%i16struct) %0, i16 %a, i16 %b)
+ ret void
+}
+; CHECK-SPIRV: [[a_0:%[a-z0-9_]+]] = OpFunctionParameter [[ushort]]
+; CHECK-SPIRV: [[b_0:%[a-z0-9_]+]] = OpFunctionParameter [[ushort]]
+; CHECK-SPIRV: [[entry_0:%[a-z0-9_]+]] = OpLabel
+; CHECK-SPIRV: [[var_21:%[a-z0-9_]+]] = OpVariable [[_ptr_Function_i16struct]] Function
+; CHECK-SPIRV: [[var_22:%[a-z0-9_]+]] = OpSMulExtended [[i16struct]] [[a_0]] [[b_0]]
+; CHECK-SPIRV: OpStore [[var_21]] [[var_22]]
+; CHECK-SPIRV: OpReturn
+; CHECK-SPIRV: OpFunctionEnd
+
+define spir_func void @test_builtin_smulextii(i32 %a, i32 %b) {
+ entry:
+ %0 = alloca %i32struct
+ call void @_Z20__spirv_SMulExtendedii(ptr sret (%i32struct) %0, i32 %a, i32 %b)
+ ret void
+}
+; CHECK-SPIRV: [[a_1:%[a-z0-9_]+]] = OpFunctionParameter [[uint]]
+; CHECK-SPIRV: [[b_1:%[a-z0-9_]+]] = OpFunctionParameter [[uint]]
+; CHECK-SPIRV: [[entry_1:%[a-z0-9_]+]] = OpLabel
+; CHECK-SPIRV: [[var_31:%[a-z0-9_]+]] = OpVariable [[_ptr_Function_i32struct]] Function
+; CHECK-SPIRV: [[var_32:%[a-z0-9_]+]] = OpSMulExtended [[i32struct]] [[a_1]] [[b_1]]
+; CHECK-SPIRV: OpStore [[var_31]] [[var_32]]
+; CHECK-SPIRV: OpReturn
+; CHECK-SPIRV: OpFunctionEnd
+
+define spir_func void @test_builtin_smulextll(i64 %a, i64 %b) {
+ entry:
+ %0 = alloca %i64struct
+ call void @_Z20__spirv_SMulExtendedll(ptr sret (%i64struct) %0, i64 %a, i64 %b)
+ ret void
+}
+; CHECK-SPIRV: [[a_2:%[a-z0-9_]+]] = OpFunctionParameter [[ulong]]
+; CHECK-SPIRV: [[b_2:%[a-z0-9_]+]] = OpFunctionParameter [[ulong]]
+; CHECK-SPIRV: [[entry_2:%[a-z0-9_]+]] = OpLabel
+; CHECK-SPIRV: [[var_41:%[a-z0-9_]+]] = OpVariable [[_ptr_Function_i64struct]] Function
+; CHECK-SPIRV: [[var_42:%[a-z0-9_]+]] = OpSMulExtended [[i64struct]] [[a_2]] [[b_2]]
+; CHECK-SPIRV: OpStore [[var_41]] [[var_42]]
+; CHECK-SPIRV: OpReturn
+; CHECK-SPIRV: OpFunctionEnd
+
+define spir_func void @test_builtin_smulextDv4_xS_(<4 x i32> %a, <4 x i32> %b) {
+ entry:
+ %0 = alloca %vecstruct
+ call void @_Z20__spirv_SMulExtendedDv4_iS_(ptr sret (%vecstruct) %0, <4 x i32> %a, <4 x i32> %b)
+ ret void
+}
+; CHECK-SPIRV: [[a_3:%[a-z0-9_]+]] = OpFunctionParameter [[v4uint]]
+; CHECK-SPIRV: [[b_3:%[a-z0-9_]+]] = OpFunctionParameter [[v4uint]]
+; CHECK-SPIRV: [[entry_3:%[a-z0-9_]+]] = OpLabel
+; CHECK-SPIRV: [[var_51:%[a-z0-9_]+]] = OpVariable [[_ptr_Function_vecstruct]] Function
+; CHECK-SPIRV: [[var_52:%[a-z0-9_]+]] = OpSMulExtended [[vecstruct]] [[a_3]] [[b_3]]
+; CHECK-SPIRV: OpStore [[var_51]] [[var_52]]
+; CHECK-SPIRV: OpReturn
+; CHECK-SPIRV: OpFunctionEnd
+
+%struct.anon = type { i32, i32 }
+
+define spir_func void @test_builtin_smulext_anon(i32 %a, i32 %b) {
+ entry:
+ %0 = alloca %struct.anon
+ %1 = addrspacecast ptr %0 to ptr addrspace(4)
+ call spir_func void @_Z20__spirv_SMulExtendedIiiE4anonIT_T0_ES1_S2_(ptr addrspace(4) sret(%struct.anon) align 4 %1, i32 %a, i32 %b)
+ ret void
+}
+; CHECK-SPIRV: [[a_4:%[a-z0-9_]+]] = OpFunctionParameter [[uint]]
+; CHECK-SPIRV: [[b_4:%[a-z0-9_]+]] = OpFunctionParameter [[uint]]
+; CHECK-SPIRV: [[entry_4:%[a-z0-9_]+]] = OpLabel
+; CHECK-SPIRV: [[var_59:%[a-z0-9_]+]] = OpVariable [[_ptr_Function_i32struct]] Function
+; CHECK-SPIRV: [[var_61:%[a-z0-9_]+]] = OpPtrCastToGeneric [[_ptr_Generic_i32struct]] [[var_59]]
+; CHECK-SPIRV: [[var_62:%[a-z0-9_]+]] = OpSMulExtended [[i32struct]] [[a_4]] [[b_4]]
+; CHECK-SPIRV: OpStore [[var_61]] [[var_62]]
+
+declare void @_Z20__spirv_SMulExtendedIiiE4anonIT_T0_ES1_S2_(ptr addrspace(4) sret(%struct.anon) align 4, i32, i32)
+declare void @_Z20__spirv_SMulExtendedcc(ptr sret(%i8struct), i8, i8)
+declare void @_Z20__spirv_SMulExtendedss(ptr sret(%i16struct), i16, i16)
+declare void @_Z20__spirv_SMulExtendedii(ptr sret(%i32struct), i32, i32)
+declare void @_Z20__spirv_SMulExtendedll(ptr sret(%i64struct), i64, i64)
+declare void @_Z20__spirv_SMulExtendedDv4_iS_(ptr sret (%vecstruct), <4 x i32>, <4 x i32>)
diff --git a/llvm/test/CodeGen/SPIRV/umulextended-builtin.ll b/llvm/test/CodeGen/SPIRV/umulextended-builtin.ll
new file mode 100644
index 0000000000000..1f7980b2e5c47
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/umulextended-builtin.ll
@@ -0,0 +1,125 @@
+; RUN: llc -O0 -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s --check-prefix=CHECK-SPIRV
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown %s -o - -filetype=obj | spirv-val %}
+
+%i8struct = type {i8, i8}
+%i16struct = type {i16, i16}
+%i32struct = type {i32, i32}
+%i64struct = type {i64, i64}
+%vecstruct = type {<4 x i32>, <4 x i32>}
+
+; CHECK-SPIRV-DAG: [[uchar:%[a-z0-9_]+]] = OpTypeInt 8
+; CHECK-SPIRV-DAG: [[ushort:%[a-z0-9_]+]] = OpTypeInt 16
+; CHECK-SPIRV-DAG: [[uint:%[a-z0-9_]+]] = OpTypeInt 32
+; CHECK-SPIRV-DAG: [[ulong:%[a-z0-9_]+]] = OpTypeInt 64
+; CHECK-SPIRV-DAG: [[void:%[a-z0-9_]+]] = OpTypeVoid
+; CHECK-SPIRV-DAG: [[i8struct:%[a-z0-9_]+]] = OpTypeStruct [[uchar]] [[uchar]]
+; CHECK-SPIRV-DAG: [[_ptr_Function_i8struct:%[a-z0-9_]+]] = OpTypePointer Function [[i8struct]]
+; CHECK-SPIRV-DAG: [[i16struct:%[a-z0-9_]+]] = OpTypeStruct [[ushort]] [[ushort]]
+; CHECK-SPIRV-DAG: [[_ptr_Function_i16struct:%[a-z0-9_]+]] = OpTypePointer Function [[i16struct]]
+; CHECK-SPIRV-DAG: [[i32struct:%[a-z0-9_]+]] = OpTypeStruct [[uint]] [[uint]]
+; CHECK-SPIRV-DAG: [[_ptr_Function_i32struct:%[a-z0-9_]+]] = OpTypePointer Function [[i32struct]]
+; CHECK-SPIRV-DAG: [[i64struct:%[a-z0-9_]+]] = OpTypeStruct [[ulong]] [[ulong]]
+; CHECK-SPIRV-DAG: [[_ptr_Function_i64struct:%[a-z0-9_]+]] = OpTypePointer Function [[i64struct]]
+; CHECK-SPIRV-DAG: [[v4uint:%[a-z0-9_]+]] = OpTypeVector [[uint]] 4
+; CHECK-SPIRV-DAG: [[vecstruct:%[a-z0-9_]+]] = OpTypeStruct [[v4uint]] [[v4uint]]
+; CHECK-SPIRV-DAG: [[_ptr_Function_vecstruct:%[a-z0-9_]+]] = OpTypePointer Function [[vecstruct]]
+; CHECK-SPIRV-DAG: [[_ptr_Generic_i32struct:%[a-z0-9_]+]] = OpTypePointer Generic [[i32struct]]
+
+define spir_func void @test_builtin_umulextcc(i8 %a, i8 %b) {
+ entry:
+ %0 = alloca %i8struct
+ call void @_Z20__spirv_UMulExtendedcc(ptr sret (%i8struct) %0, i8 %a, i8 %b)
+ ret void
+}
+; CHECK-SPIRV: [[a:%[a-z0-9_]+]] = OpFunctionParameter [[uchar]]
+; CHECK-SPIRV: [[b:%[a-z0-9_]+]] = OpFunctionParameter [[uchar]]
+; CHECK-SPIRV: [[entry:%[a-z0-9_]+]] = OpLabel
+; CHECK-SPIRV: [[var_11:%[a-z0-9_]+]] = OpVariable [[_ptr_Function_i8struct]] Function
+; CHECK-SPIRV: [[var_12:%[a-z0-9_]+]] = OpUMulExtended [[i8struct]] [[a]] [[b]]
+; CHECK-SPIRV: OpStore [[var_11]] [[var_12]]
+; CHECK-SPIRV: OpReturn
+; CHECK-SPIRV: OpFunctionEnd
+
+define spir_func void @test_builtin_umulextss(i16 %a, i16 %b) {
+ entry:
+ %0 = alloca %i16struct
+ call void @_Z20__spirv_UMulExtendedss(ptr sret (%i16struct) %0, i16 %a, i16 %b)
+ ret void
+}
+; CHECK-SPIRV: [[a_0:%[a-z0-9_]+]] = OpFunctionParameter [[ushort]]
+; CHECK-SPIRV: [[b_0:%[a-z0-9_]+]] = OpFunctionParameter [[ushort]]
+; CHECK-SPIRV: [[entry_0:%[a-z0-9_]+]] = OpLabel
+; CHECK-SPIRV: [[var_21:%[a-z0-9_]+]] = OpVariable [[_ptr_Function_i16struct]] Function
+; CHECK-SPIRV: [[var_22:%[a-z0-9_]+]] = OpUMulExtended [[i16struct]] [[a_0]] [[b_0]]
+; CHECK-SPIRV: OpStore [[var_21]] [[var_22]]
+; CHECK-SPIRV: OpReturn
+; CHECK-SPIRV: OpFunctionEnd
+
+define spir_func void @test_builtin_umulextii(i32 %a, i32 %b) {
+ entry:
+ %0 = alloca %i32struct
+ call void @_Z20__spirv_UMulExtendedii(ptr sret (%i32struct) %0, i32 %a, i32 %b)
+ ret void
+}
+; CHECK-SPIRV: [[a_1:%[a-z0-9_]+]] = OpFunctionParameter [[uint]]
+; CHECK-SPIRV: [[b_1:%[a-z0-9_]+]] = OpFunctionParameter [[uint]]
+; CHECK-SPIRV: [[entry_1:%[a-z0-9_]+]] = OpLabel
+; CHECK-SPIRV: [[var_31:%[a-z0-9_]+]] = OpVariable [[_ptr_Function_i32struct]] Function
+; CHECK-SPIRV: [[var_32:%[a-z0-9_]+]] = OpUMulExtended [[i32struct]] [[a_1]] [[b_1]]
+; CHECK-SPIRV: OpStore [[var_31]] [[var_32]]
+; CHECK-SPIRV: OpReturn
+; CHECK-SPIRV: OpFunctionEnd
+
+define spir_func void @test_builtin_umulextll(i64 %a, i64 %b) {
+ entry:
+ %0 = alloca %i64struct
+ call void @_Z20__spirv_UMulExtendedll(ptr sret (%i64struct) %0, i64 %a, i64 %b)
+ ret void
+}
+; CHECK-SPIRV: [[a_2:%[a-z0-9_]+]] = OpFunctionParameter [[ulong]]
+; CHECK-SPIRV: [[b_2:%[a-z0-9_]+]] = OpFunctionParameter [[ulong]]
+; CHECK-SPIRV: [[entry_2:%[a-z0-9_]+]] = OpLabel
+; CHECK-SPIRV: [[var_41:%[a-z0-9_]+]] = OpVariable [[_ptr_Function_i64struct]] Function
+; CHECK-SPIRV: [[var_42:%[a-z0-9_]+]] = OpUMulExtended [[i64struct]] [[a_2]] [[b_2]]
+; CHECK-SPIRV: OpStore [[var_41]] [[var_42]]
+; CHECK-SPIRV: OpReturn
+; CHECK-SPIRV: OpFunctionEnd
+
+define spir_func void @test_builtin_umulextDv4_xS_(<4 x i32> %a, <4 x i32> %b) {
+ entry:
+ %0 = alloca %vecstruct
+ call void @_Z20__spirv_UMulExtendedDv4_iS_(ptr sret (%vecstruct) %0, <4 x i32> %a, <4 x i32> %b)
+ ret void
+}
+; CHECK-SPIRV: [[a_3:%[a-z0-9_]+]] = OpFunctionParameter [[v4uint]]
+; CHECK-SPIRV: [[b_3:%[a-z0-9_]+]] = OpFunctionParameter [[v4uint]]
+; CHECK-SPIRV: [[entry_3:%[a-z0-9_]+]] = OpLabel
+; CHECK-SPIRV: [[var_51:%[a-z0-9_]+]] = OpVariable [[_ptr_Function_vecstruct]] Function
+; CHECK-SPIRV: [[var_52:%[a-z0-9_]+]] = OpUMulExtended [[vecstruct]] [[a_3]] [[b_3]]
+; CHECK-SPIRV: OpStore [[var_51]] [[var_52]]
+; CHECK-SPIRV: OpReturn
+; CHECK-SPIRV: OpFunctionEnd
+
+%struct.anon = type { i32, i32 }
+
+define spir_func void @test_builtin_umulext_anon(i32 %a, i32 %b) {
+ entry:
+ %0 = alloca %struct.anon
+ %1 = addrspacecast ptr %0 to ptr addrspace(4)
+ call spir_func void @_Z20__spirv_UMulExtendedIiiE4anonIT_T0_ES1_S2_(ptr addrspace(4) sret(%struct.anon) align 4 %1, i32 %a, i32 %b)
+ ret void
+}
+; CHECK-SPIRV: [[a_4:%[a-z0-9_]+]] = OpFunctionParameter [[uint]]
+; CHECK-SPIRV: [[b_4:%[a-z0-9_]+]] = OpFunctionParameter [[uint]]
+; CHECK-SPIRV: [[entry_4:%[a-z0-9_]+]] = OpLabel
+; CHECK-SPIRV: [[var_59:%[a-z0-9_]+]] = OpVariable [[_ptr_Function_i32struct]] Function
+; CHECK-SPIRV: [[var_61:%[a-z0-9_]+]] = OpPtrCastToGeneric [[_ptr_Generic_i32struct]] [[var_59]]
+; CHECK-SPIRV: [[var_62:%[a-z0-9_]+]] = OpUMulExtended [[i32struct]] [[a_4]] [[b_4]]
+; CHECK-SPIRV: OpStore [[var_61]] [[var_62]]
+
+declare void @_Z20__spirv_UMulExtendedIiiE4anonIT_T0_ES1_S2_(ptr addrspace(4) sret(%struct.anon) align 4, i32, i32)
+declare void @_Z20__spirv_UMulExtendedcc(ptr sret(%i8struct), i8, i8)
+declare void @_Z20__spirv_UMulExtendedss(ptr sret(%i16struct), i16, i16)
+declare void @_Z20__spirv_UMulExtendedii(ptr sret(%i32struct), i32, i32)
+declare void @_Z20__spirv_UMulExtendedll(ptr sret(%i64struct), i64, i64)
+declare void @_Z20__spirv_UMulExtendedDv4_iS_(ptr sret (%vecstruct), <4 x i32>, <4 x i32>)
>From f5bec4eef93fea51a0b81d6e64736c6869e05613 Mon Sep 17 00:00:00 2001
From: Arseniy Obolenskiy <arseniy.obolenskiy at amd.com>
Date: Thu, 19 Mar 2026 17:26:19 +0100
Subject: [PATCH 2/2] Address review comments
---
llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp | 31 ++--
llvm/lib/Target/SPIRV/SPIRVBuiltins.td | 4 +-
.../CodeGen/SPIRV/smulextended-builtin.ll | 145 +++++++-----------
.../CodeGen/SPIRV/umulextended-builtin.ll | 145 +++++++-----------
4 files changed, 129 insertions(+), 196 deletions(-)
diff --git a/llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp b/llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp
index 6abf50f59a03f..0f00cfed326b4 100644
--- a/llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp
@@ -1997,11 +1997,10 @@ static bool generateICarryBorrowInst(const SPIRV::IncomingCall *Call,
}
// We expect a builtin
-// Name(ptr sret([RetType]) %result, Type %operand1, Type %operand2)
-// where %result is a pointer to where the result of the builtin execution
-// is to be stored, and generate the following instructions:
+// RetType Name(Type %operand1, Type %operand2)
+// where RetType is a struct with two members of the same type as the operands,
+// and generate the following instruction:
// Res = Opcode RetType Operand1 Operand2
-// OpStore RetVariable Res
static bool generateMulExtendedInst(const SPIRV::IncomingCall *Call,
MachineIRBuilder &MIRBuilder,
SPIRVGlobalRegistry *GR) {
@@ -2011,36 +2010,28 @@ static bool generateMulExtendedInst(const SPIRV::IncomingCall *Call,
assert((Opcode == SPIRV::OpUMulExtended || Opcode == SPIRV::OpSMulExtended) &&
"Expected OpUMulExtended or OpSMulExtended");
- Register SRetReg = Call->Arguments[0];
- SPIRVTypeInst PtrRetType = GR->getSPIRVTypeForVReg(SRetReg);
- SPIRVTypeInst RetType = GR->getPointeeType(PtrRetType);
- if (!RetType)
- report_fatal_error("The first parameter must be a pointer");
- if (RetType->getOpcode() != SPIRV::OpTypeStruct)
+ SPIRVTypeInst RetType = Call->ReturnType;
+ if (!RetType || RetType->getOpcode() != SPIRV::OpTypeStruct)
report_fatal_error("Expected struct type result for the extended "
"multiplication builtins");
- SPIRVTypeInst OpType1 = GR->getSPIRVTypeForVReg(Call->Arguments[1]);
- SPIRVTypeInst OpType2 = GR->getSPIRVTypeForVReg(Call->Arguments[2]);
+ SPIRVTypeInst OpType1 = GR->getSPIRVTypeForVReg(Call->Arguments[0]);
+ SPIRVTypeInst OpType2 = GR->getSPIRVTypeForVReg(Call->Arguments[1]);
if (!OpType1 || !OpType2 || OpType1 != OpType2)
report_fatal_error("Operands must have the same type");
MachineRegisterInfo *MRI = MIRBuilder.getMRI();
- Register ResReg = MRI->createVirtualRegister(&SPIRV::iIDRegClass);
+ Register ResReg = Call->ReturnRegister;
if (const TargetRegisterClass *DstRC =
- MRI->getRegClassOrNull(Call->Arguments[1])) {
+ MRI->getRegClassOrNull(Call->Arguments[0])) {
MRI->setRegClass(ResReg, DstRC);
- MRI->setType(ResReg, MRI->getType(Call->Arguments[1]));
- } else {
- MRI->setType(ResReg, LLT::scalar(64));
}
GR->assignSPIRVTypeToVReg(RetType, ResReg, MIRBuilder.getMF());
MIRBuilder.buildInstr(Opcode)
.addDef(ResReg)
.addUse(GR->getSPIRVTypeID(RetType))
- .addUse(Call->Arguments[1])
- .addUse(Call->Arguments[2]);
- MIRBuilder.buildInstr(SPIRV::OpStore).addUse(SRetReg).addUse(ResReg);
+ .addUse(Call->Arguments[0])
+ .addUse(Call->Arguments[1]);
return true;
}
diff --git a/llvm/lib/Target/SPIRV/SPIRVBuiltins.td b/llvm/lib/Target/SPIRV/SPIRVBuiltins.td
index b30db2b9f718d..20fc3ff5bd29a 100644
--- a/llvm/lib/Target/SPIRV/SPIRVBuiltins.td
+++ b/llvm/lib/Target/SPIRV/SPIRVBuiltins.td
@@ -678,8 +678,8 @@ defm : DemangledNativeBuiltin<"__spirv_IAddCarry", OpenCL_std, ICarryBorrow, 3,
defm : DemangledNativeBuiltin<"__spirv_ISubBorrow", OpenCL_std, ICarryBorrow, 3, 3, OpISubBorrowS>;
// MulExtended builtin records:
-defm : DemangledNativeBuiltin<"__spirv_UMulExtended", OpenCL_std, MulExtended, 3, 3, OpUMulExtended>;
-defm : DemangledNativeBuiltin<"__spirv_SMulExtended", OpenCL_std, MulExtended, 3, 3, OpSMulExtended>;
+defm : DemangledNativeBuiltin<"__spirv_UMulExtended", OpenCL_std, MulExtended, 2, 2, OpUMulExtended>;
+defm : DemangledNativeBuiltin<"__spirv_SMulExtended", OpenCL_std, MulExtended, 2, 2, OpSMulExtended>;
// cl_intel_split_work_group_barrier
defm : DemangledNativeBuiltin<"intel_work_group_barrier_arrive", OpenCL_std, Barrier, 1, 2, OpControlBarrierArriveINTEL>;
diff --git a/llvm/test/CodeGen/SPIRV/smulextended-builtin.ll b/llvm/test/CodeGen/SPIRV/smulextended-builtin.ll
index f8c632526ee23..87ab7154b54fe 100644
--- a/llvm/test/CodeGen/SPIRV/smulextended-builtin.ll
+++ b/llvm/test/CodeGen/SPIRV/smulextended-builtin.ll
@@ -11,115 +11,86 @@
; CHECK-SPIRV-DAG: [[ushort:%[a-z0-9_]+]] = OpTypeInt 16
; CHECK-SPIRV-DAG: [[uint:%[a-z0-9_]+]] = OpTypeInt 32
; CHECK-SPIRV-DAG: [[ulong:%[a-z0-9_]+]] = OpTypeInt 64
-; CHECK-SPIRV-DAG: [[void:%[a-z0-9_]+]] = OpTypeVoid
; CHECK-SPIRV-DAG: [[i8struct:%[a-z0-9_]+]] = OpTypeStruct [[uchar]] [[uchar]]
-; CHECK-SPIRV-DAG: [[_ptr_Function_i8struct:%[a-z0-9_]+]] = OpTypePointer Function [[i8struct]]
; CHECK-SPIRV-DAG: [[i16struct:%[a-z0-9_]+]] = OpTypeStruct [[ushort]] [[ushort]]
-; CHECK-SPIRV-DAG: [[_ptr_Function_i16struct:%[a-z0-9_]+]] = OpTypePointer Function [[i16struct]]
; CHECK-SPIRV-DAG: [[i32struct:%[a-z0-9_]+]] = OpTypeStruct [[uint]] [[uint]]
-; CHECK-SPIRV-DAG: [[_ptr_Function_i32struct:%[a-z0-9_]+]] = OpTypePointer Function [[i32struct]]
; CHECK-SPIRV-DAG: [[i64struct:%[a-z0-9_]+]] = OpTypeStruct [[ulong]] [[ulong]]
-; CHECK-SPIRV-DAG: [[_ptr_Function_i64struct:%[a-z0-9_]+]] = OpTypePointer Function [[i64struct]]
; CHECK-SPIRV-DAG: [[v4uint:%[a-z0-9_]+]] = OpTypeVector [[uint]] 4
; CHECK-SPIRV-DAG: [[vecstruct:%[a-z0-9_]+]] = OpTypeStruct [[v4uint]] [[v4uint]]
-; CHECK-SPIRV-DAG: [[_ptr_Function_vecstruct:%[a-z0-9_]+]] = OpTypePointer Function [[vecstruct]]
-; CHECK-SPIRV-DAG: [[_ptr_Generic_i32struct:%[a-z0-9_]+]] = OpTypePointer Generic [[i32struct]]
-define spir_func void @test_builtin_smulextcc(i8 %a, i8 %b) {
+define spir_func %i8struct @test_builtin_smulextcc(i8 %a, i8 %b) {
entry:
- %0 = alloca %i8struct
- call void @_Z20__spirv_SMulExtendedcc(ptr sret (%i8struct) %0, i8 %a, i8 %b)
- ret void
+ %0 = call %i8struct @_Z20__spirv_SMulExtendedcc(i8 %a, i8 %b)
+ ret %i8struct %0
}
-; CHECK-SPIRV: [[a:%[a-z0-9_]+]] = OpFunctionParameter [[uchar]]
-; CHECK-SPIRV: [[b:%[a-z0-9_]+]] = OpFunctionParameter [[uchar]]
-; CHECK-SPIRV: [[entry:%[a-z0-9_]+]] = OpLabel
-; CHECK-SPIRV: [[var_11:%[a-z0-9_]+]] = OpVariable [[_ptr_Function_i8struct]] Function
-; CHECK-SPIRV: [[var_12:%[a-z0-9_]+]] = OpSMulExtended [[i8struct]] [[a]] [[b]]
-; CHECK-SPIRV: OpStore [[var_11]] [[var_12]]
-; CHECK-SPIRV: OpReturn
-; CHECK-SPIRV: OpFunctionEnd
+; CHECK-SPIRV: [[a:%[a-z0-9_]+]] = OpFunctionParameter [[uchar]]
+; CHECK-SPIRV-NEXT: [[b:%[a-z0-9_]+]] = OpFunctionParameter [[uchar]]
+; CHECK-SPIRV-NEXT: [[entry:%[a-z0-9_]+]] = OpLabel
+; CHECK-SPIRV-NEXT: [[res:%[a-z0-9_]+]] = OpSMulExtended [[i8struct]] [[a]] [[b]]
+; CHECK-SPIRV-NEXT: OpReturnValue [[res]]
+; CHECK-SPIRV-NEXT: OpFunctionEnd
-define spir_func void @test_builtin_smulextss(i16 %a, i16 %b) {
+define spir_func %i16struct @test_builtin_smulextss(i16 %a, i16 %b) {
entry:
- %0 = alloca %i16struct
- call void @_Z20__spirv_SMulExtendedss(ptr sret (%i16struct) %0, i16 %a, i16 %b)
- ret void
+ %0 = call %i16struct @_Z20__spirv_SMulExtendedss(i16 %a, i16 %b)
+ ret %i16struct %0
}
-; CHECK-SPIRV: [[a_0:%[a-z0-9_]+]] = OpFunctionParameter [[ushort]]
-; CHECK-SPIRV: [[b_0:%[a-z0-9_]+]] = OpFunctionParameter [[ushort]]
-; CHECK-SPIRV: [[entry_0:%[a-z0-9_]+]] = OpLabel
-; CHECK-SPIRV: [[var_21:%[a-z0-9_]+]] = OpVariable [[_ptr_Function_i16struct]] Function
-; CHECK-SPIRV: [[var_22:%[a-z0-9_]+]] = OpSMulExtended [[i16struct]] [[a_0]] [[b_0]]
-; CHECK-SPIRV: OpStore [[var_21]] [[var_22]]
-; CHECK-SPIRV: OpReturn
-; CHECK-SPIRV: OpFunctionEnd
+; CHECK-SPIRV: [[a_0:%[a-z0-9_]+]] = OpFunctionParameter [[ushort]]
+; CHECK-SPIRV-NEXT: [[b_0:%[a-z0-9_]+]] = OpFunctionParameter [[ushort]]
+; CHECK-SPIRV-NEXT: [[entry_0:%[a-z0-9_]+]] = OpLabel
+; CHECK-SPIRV-NEXT: [[res_0:%[a-z0-9_]+]] = OpSMulExtended [[i16struct]] [[a_0]] [[b_0]]
+; CHECK-SPIRV-NEXT: OpReturnValue [[res_0]]
+; CHECK-SPIRV-NEXT: OpFunctionEnd
-define spir_func void @test_builtin_smulextii(i32 %a, i32 %b) {
+define spir_func %i32struct @test_builtin_smulextii(i32 %a, i32 %b) {
entry:
- %0 = alloca %i32struct
- call void @_Z20__spirv_SMulExtendedii(ptr sret (%i32struct) %0, i32 %a, i32 %b)
- ret void
+ %0 = call %i32struct @_Z20__spirv_SMulExtendedii(i32 %a, i32 %b)
+ ret %i32struct %0
}
-; CHECK-SPIRV: [[a_1:%[a-z0-9_]+]] = OpFunctionParameter [[uint]]
-; CHECK-SPIRV: [[b_1:%[a-z0-9_]+]] = OpFunctionParameter [[uint]]
-; CHECK-SPIRV: [[entry_1:%[a-z0-9_]+]] = OpLabel
-; CHECK-SPIRV: [[var_31:%[a-z0-9_]+]] = OpVariable [[_ptr_Function_i32struct]] Function
-; CHECK-SPIRV: [[var_32:%[a-z0-9_]+]] = OpSMulExtended [[i32struct]] [[a_1]] [[b_1]]
-; CHECK-SPIRV: OpStore [[var_31]] [[var_32]]
-; CHECK-SPIRV: OpReturn
-; CHECK-SPIRV: OpFunctionEnd
+; CHECK-SPIRV: [[a_1:%[a-z0-9_]+]] = OpFunctionParameter [[uint]]
+; CHECK-SPIRV-NEXT: [[b_1:%[a-z0-9_]+]] = OpFunctionParameter [[uint]]
+; CHECK-SPIRV-NEXT: [[entry_1:%[a-z0-9_]+]] = OpLabel
+; CHECK-SPIRV-NEXT: [[res_1:%[a-z0-9_]+]] = OpSMulExtended [[i32struct]] [[a_1]] [[b_1]]
+; CHECK-SPIRV-NEXT: OpReturnValue [[res_1]]
+; CHECK-SPIRV-NEXT: OpFunctionEnd
-define spir_func void @test_builtin_smulextll(i64 %a, i64 %b) {
+define spir_func %i64struct @test_builtin_smulextll(i64 %a, i64 %b) {
entry:
- %0 = alloca %i64struct
- call void @_Z20__spirv_SMulExtendedll(ptr sret (%i64struct) %0, i64 %a, i64 %b)
- ret void
+ %0 = call %i64struct @_Z20__spirv_SMulExtendedll(i64 %a, i64 %b)
+ ret %i64struct %0
}
-; CHECK-SPIRV: [[a_2:%[a-z0-9_]+]] = OpFunctionParameter [[ulong]]
-; CHECK-SPIRV: [[b_2:%[a-z0-9_]+]] = OpFunctionParameter [[ulong]]
-; CHECK-SPIRV: [[entry_2:%[a-z0-9_]+]] = OpLabel
-; CHECK-SPIRV: [[var_41:%[a-z0-9_]+]] = OpVariable [[_ptr_Function_i64struct]] Function
-; CHECK-SPIRV: [[var_42:%[a-z0-9_]+]] = OpSMulExtended [[i64struct]] [[a_2]] [[b_2]]
-; CHECK-SPIRV: OpStore [[var_41]] [[var_42]]
-; CHECK-SPIRV: OpReturn
-; CHECK-SPIRV: OpFunctionEnd
+; CHECK-SPIRV: [[a_2:%[a-z0-9_]+]] = OpFunctionParameter [[ulong]]
+; CHECK-SPIRV-NEXT: [[b_2:%[a-z0-9_]+]] = OpFunctionParameter [[ulong]]
+; CHECK-SPIRV-NEXT: [[entry_2:%[a-z0-9_]+]] = OpLabel
+; CHECK-SPIRV-NEXT: [[res_2:%[a-z0-9_]+]] = OpSMulExtended [[i64struct]] [[a_2]] [[b_2]]
+; CHECK-SPIRV-NEXT: OpReturnValue [[res_2]]
+; CHECK-SPIRV-NEXT: OpFunctionEnd
-define spir_func void @test_builtin_smulextDv4_xS_(<4 x i32> %a, <4 x i32> %b) {
+define spir_func %vecstruct @test_builtin_smulextDv4_xS_(<4 x i32> %a, <4 x i32> %b) {
entry:
- %0 = alloca %vecstruct
- call void @_Z20__spirv_SMulExtendedDv4_iS_(ptr sret (%vecstruct) %0, <4 x i32> %a, <4 x i32> %b)
- ret void
+ %0 = call %vecstruct @_Z20__spirv_SMulExtendedDv4_iS_(<4 x i32> %a, <4 x i32> %b)
+ ret %vecstruct %0
}
-; CHECK-SPIRV: [[a_3:%[a-z0-9_]+]] = OpFunctionParameter [[v4uint]]
-; CHECK-SPIRV: [[b_3:%[a-z0-9_]+]] = OpFunctionParameter [[v4uint]]
-; CHECK-SPIRV: [[entry_3:%[a-z0-9_]+]] = OpLabel
-; CHECK-SPIRV: [[var_51:%[a-z0-9_]+]] = OpVariable [[_ptr_Function_vecstruct]] Function
-; CHECK-SPIRV: [[var_52:%[a-z0-9_]+]] = OpSMulExtended [[vecstruct]] [[a_3]] [[b_3]]
-; CHECK-SPIRV: OpStore [[var_51]] [[var_52]]
-; CHECK-SPIRV: OpReturn
-; CHECK-SPIRV: OpFunctionEnd
+; CHECK-SPIRV: [[a_3:%[a-z0-9_]+]] = OpFunctionParameter [[v4uint]]
+; CHECK-SPIRV-NEXT: [[b_3:%[a-z0-9_]+]] = OpFunctionParameter [[v4uint]]
+; CHECK-SPIRV-NEXT: [[entry_3:%[a-z0-9_]+]] = OpLabel
+; CHECK-SPIRV-NEXT: [[res_3:%[a-z0-9_]+]] = OpSMulExtended [[vecstruct]] [[a_3]] [[b_3]]
+; CHECK-SPIRV-NEXT: OpReturnValue [[res_3]]
+; CHECK-SPIRV-NEXT: OpFunctionEnd
-%struct.anon = type { i32, i32 }
-
-define spir_func void @test_builtin_smulext_anon(i32 %a, i32 %b) {
+define spir_func %i32struct @test_builtin_smulext_same_arg(i32 %a) {
entry:
- %0 = alloca %struct.anon
- %1 = addrspacecast ptr %0 to ptr addrspace(4)
- call spir_func void @_Z20__spirv_SMulExtendedIiiE4anonIT_T0_ES1_S2_(ptr addrspace(4) sret(%struct.anon) align 4 %1, i32 %a, i32 %b)
- ret void
+ %0 = call %i32struct @_Z20__spirv_SMulExtendedii(i32 %a, i32 %a)
+ ret %i32struct %0
}
-; CHECK-SPIRV: [[a_4:%[a-z0-9_]+]] = OpFunctionParameter [[uint]]
-; CHECK-SPIRV: [[b_4:%[a-z0-9_]+]] = OpFunctionParameter [[uint]]
-; CHECK-SPIRV: [[entry_4:%[a-z0-9_]+]] = OpLabel
-; CHECK-SPIRV: [[var_59:%[a-z0-9_]+]] = OpVariable [[_ptr_Function_i32struct]] Function
-; CHECK-SPIRV: [[var_61:%[a-z0-9_]+]] = OpPtrCastToGeneric [[_ptr_Generic_i32struct]] [[var_59]]
-; CHECK-SPIRV: [[var_62:%[a-z0-9_]+]] = OpSMulExtended [[i32struct]] [[a_4]] [[b_4]]
-; CHECK-SPIRV: OpStore [[var_61]] [[var_62]]
+; CHECK-SPIRV: [[a_4:%[a-z0-9_]+]] = OpFunctionParameter [[uint]]
+; CHECK-SPIRV-NEXT: [[entry_4:%[a-z0-9_]+]] = OpLabel
+; CHECK-SPIRV-NEXT: [[res_4:%[a-z0-9_]+]] = OpSMulExtended [[i32struct]] [[a_4]] [[a_4]]
+; CHECK-SPIRV-NEXT: OpReturnValue [[res_4]]
+; CHECK-SPIRV-NEXT: OpFunctionEnd
-declare void @_Z20__spirv_SMulExtendedIiiE4anonIT_T0_ES1_S2_(ptr addrspace(4) sret(%struct.anon) align 4, i32, i32)
-declare void @_Z20__spirv_SMulExtendedcc(ptr sret(%i8struct), i8, i8)
-declare void @_Z20__spirv_SMulExtendedss(ptr sret(%i16struct), i16, i16)
-declare void @_Z20__spirv_SMulExtendedii(ptr sret(%i32struct), i32, i32)
-declare void @_Z20__spirv_SMulExtendedll(ptr sret(%i64struct), i64, i64)
-declare void @_Z20__spirv_SMulExtendedDv4_iS_(ptr sret (%vecstruct), <4 x i32>, <4 x i32>)
+declare %i8struct @_Z20__spirv_SMulExtendedcc(i8, i8)
+declare %i16struct @_Z20__spirv_SMulExtendedss(i16, i16)
+declare %i32struct @_Z20__spirv_SMulExtendedii(i32, i32)
+declare %i64struct @_Z20__spirv_SMulExtendedll(i64, i64)
+declare %vecstruct @_Z20__spirv_SMulExtendedDv4_iS_(<4 x i32>, <4 x i32>)
diff --git a/llvm/test/CodeGen/SPIRV/umulextended-builtin.ll b/llvm/test/CodeGen/SPIRV/umulextended-builtin.ll
index 1f7980b2e5c47..aaa1e07c32650 100644
--- a/llvm/test/CodeGen/SPIRV/umulextended-builtin.ll
+++ b/llvm/test/CodeGen/SPIRV/umulextended-builtin.ll
@@ -11,115 +11,86 @@
; CHECK-SPIRV-DAG: [[ushort:%[a-z0-9_]+]] = OpTypeInt 16
; CHECK-SPIRV-DAG: [[uint:%[a-z0-9_]+]] = OpTypeInt 32
; CHECK-SPIRV-DAG: [[ulong:%[a-z0-9_]+]] = OpTypeInt 64
-; CHECK-SPIRV-DAG: [[void:%[a-z0-9_]+]] = OpTypeVoid
; CHECK-SPIRV-DAG: [[i8struct:%[a-z0-9_]+]] = OpTypeStruct [[uchar]] [[uchar]]
-; CHECK-SPIRV-DAG: [[_ptr_Function_i8struct:%[a-z0-9_]+]] = OpTypePointer Function [[i8struct]]
; CHECK-SPIRV-DAG: [[i16struct:%[a-z0-9_]+]] = OpTypeStruct [[ushort]] [[ushort]]
-; CHECK-SPIRV-DAG: [[_ptr_Function_i16struct:%[a-z0-9_]+]] = OpTypePointer Function [[i16struct]]
; CHECK-SPIRV-DAG: [[i32struct:%[a-z0-9_]+]] = OpTypeStruct [[uint]] [[uint]]
-; CHECK-SPIRV-DAG: [[_ptr_Function_i32struct:%[a-z0-9_]+]] = OpTypePointer Function [[i32struct]]
; CHECK-SPIRV-DAG: [[i64struct:%[a-z0-9_]+]] = OpTypeStruct [[ulong]] [[ulong]]
-; CHECK-SPIRV-DAG: [[_ptr_Function_i64struct:%[a-z0-9_]+]] = OpTypePointer Function [[i64struct]]
; CHECK-SPIRV-DAG: [[v4uint:%[a-z0-9_]+]] = OpTypeVector [[uint]] 4
; CHECK-SPIRV-DAG: [[vecstruct:%[a-z0-9_]+]] = OpTypeStruct [[v4uint]] [[v4uint]]
-; CHECK-SPIRV-DAG: [[_ptr_Function_vecstruct:%[a-z0-9_]+]] = OpTypePointer Function [[vecstruct]]
-; CHECK-SPIRV-DAG: [[_ptr_Generic_i32struct:%[a-z0-9_]+]] = OpTypePointer Generic [[i32struct]]
-define spir_func void @test_builtin_umulextcc(i8 %a, i8 %b) {
+define spir_func %i8struct @test_builtin_umulextcc(i8 %a, i8 %b) {
entry:
- %0 = alloca %i8struct
- call void @_Z20__spirv_UMulExtendedcc(ptr sret (%i8struct) %0, i8 %a, i8 %b)
- ret void
+ %0 = call %i8struct @_Z20__spirv_UMulExtendedcc(i8 %a, i8 %b)
+ ret %i8struct %0
}
-; CHECK-SPIRV: [[a:%[a-z0-9_]+]] = OpFunctionParameter [[uchar]]
-; CHECK-SPIRV: [[b:%[a-z0-9_]+]] = OpFunctionParameter [[uchar]]
-; CHECK-SPIRV: [[entry:%[a-z0-9_]+]] = OpLabel
-; CHECK-SPIRV: [[var_11:%[a-z0-9_]+]] = OpVariable [[_ptr_Function_i8struct]] Function
-; CHECK-SPIRV: [[var_12:%[a-z0-9_]+]] = OpUMulExtended [[i8struct]] [[a]] [[b]]
-; CHECK-SPIRV: OpStore [[var_11]] [[var_12]]
-; CHECK-SPIRV: OpReturn
-; CHECK-SPIRV: OpFunctionEnd
+; CHECK-SPIRV: [[a:%[a-z0-9_]+]] = OpFunctionParameter [[uchar]]
+; CHECK-SPIRV-NEXT: [[b:%[a-z0-9_]+]] = OpFunctionParameter [[uchar]]
+; CHECK-SPIRV-NEXT: [[entry:%[a-z0-9_]+]] = OpLabel
+; CHECK-SPIRV-NEXT: [[res:%[a-z0-9_]+]] = OpUMulExtended [[i8struct]] [[a]] [[b]]
+; CHECK-SPIRV-NEXT: OpReturnValue [[res]]
+; CHECK-SPIRV-NEXT: OpFunctionEnd
-define spir_func void @test_builtin_umulextss(i16 %a, i16 %b) {
+define spir_func %i16struct @test_builtin_umulextss(i16 %a, i16 %b) {
entry:
- %0 = alloca %i16struct
- call void @_Z20__spirv_UMulExtendedss(ptr sret (%i16struct) %0, i16 %a, i16 %b)
- ret void
+ %0 = call %i16struct @_Z20__spirv_UMulExtendedss(i16 %a, i16 %b)
+ ret %i16struct %0
}
-; CHECK-SPIRV: [[a_0:%[a-z0-9_]+]] = OpFunctionParameter [[ushort]]
-; CHECK-SPIRV: [[b_0:%[a-z0-9_]+]] = OpFunctionParameter [[ushort]]
-; CHECK-SPIRV: [[entry_0:%[a-z0-9_]+]] = OpLabel
-; CHECK-SPIRV: [[var_21:%[a-z0-9_]+]] = OpVariable [[_ptr_Function_i16struct]] Function
-; CHECK-SPIRV: [[var_22:%[a-z0-9_]+]] = OpUMulExtended [[i16struct]] [[a_0]] [[b_0]]
-; CHECK-SPIRV: OpStore [[var_21]] [[var_22]]
-; CHECK-SPIRV: OpReturn
-; CHECK-SPIRV: OpFunctionEnd
+; CHECK-SPIRV: [[a_0:%[a-z0-9_]+]] = OpFunctionParameter [[ushort]]
+; CHECK-SPIRV-NEXT: [[b_0:%[a-z0-9_]+]] = OpFunctionParameter [[ushort]]
+; CHECK-SPIRV-NEXT: [[entry_0:%[a-z0-9_]+]] = OpLabel
+; CHECK-SPIRV-NEXT: [[res_0:%[a-z0-9_]+]] = OpUMulExtended [[i16struct]] [[a_0]] [[b_0]]
+; CHECK-SPIRV-NEXT: OpReturnValue [[res_0]]
+; CHECK-SPIRV-NEXT: OpFunctionEnd
-define spir_func void @test_builtin_umulextii(i32 %a, i32 %b) {
+define spir_func %i32struct @test_builtin_umulextii(i32 %a, i32 %b) {
entry:
- %0 = alloca %i32struct
- call void @_Z20__spirv_UMulExtendedii(ptr sret (%i32struct) %0, i32 %a, i32 %b)
- ret void
+ %0 = call %i32struct @_Z20__spirv_UMulExtendedii(i32 %a, i32 %b)
+ ret %i32struct %0
}
-; CHECK-SPIRV: [[a_1:%[a-z0-9_]+]] = OpFunctionParameter [[uint]]
-; CHECK-SPIRV: [[b_1:%[a-z0-9_]+]] = OpFunctionParameter [[uint]]
-; CHECK-SPIRV: [[entry_1:%[a-z0-9_]+]] = OpLabel
-; CHECK-SPIRV: [[var_31:%[a-z0-9_]+]] = OpVariable [[_ptr_Function_i32struct]] Function
-; CHECK-SPIRV: [[var_32:%[a-z0-9_]+]] = OpUMulExtended [[i32struct]] [[a_1]] [[b_1]]
-; CHECK-SPIRV: OpStore [[var_31]] [[var_32]]
-; CHECK-SPIRV: OpReturn
-; CHECK-SPIRV: OpFunctionEnd
+; CHECK-SPIRV: [[a_1:%[a-z0-9_]+]] = OpFunctionParameter [[uint]]
+; CHECK-SPIRV-NEXT: [[b_1:%[a-z0-9_]+]] = OpFunctionParameter [[uint]]
+; CHECK-SPIRV-NEXT: [[entry_1:%[a-z0-9_]+]] = OpLabel
+; CHECK-SPIRV-NEXT: [[res_1:%[a-z0-9_]+]] = OpUMulExtended [[i32struct]] [[a_1]] [[b_1]]
+; CHECK-SPIRV-NEXT: OpReturnValue [[res_1]]
+; CHECK-SPIRV-NEXT: OpFunctionEnd
-define spir_func void @test_builtin_umulextll(i64 %a, i64 %b) {
+define spir_func %i64struct @test_builtin_umulextll(i64 %a, i64 %b) {
entry:
- %0 = alloca %i64struct
- call void @_Z20__spirv_UMulExtendedll(ptr sret (%i64struct) %0, i64 %a, i64 %b)
- ret void
+ %0 = call %i64struct @_Z20__spirv_UMulExtendedll(i64 %a, i64 %b)
+ ret %i64struct %0
}
-; CHECK-SPIRV: [[a_2:%[a-z0-9_]+]] = OpFunctionParameter [[ulong]]
-; CHECK-SPIRV: [[b_2:%[a-z0-9_]+]] = OpFunctionParameter [[ulong]]
-; CHECK-SPIRV: [[entry_2:%[a-z0-9_]+]] = OpLabel
-; CHECK-SPIRV: [[var_41:%[a-z0-9_]+]] = OpVariable [[_ptr_Function_i64struct]] Function
-; CHECK-SPIRV: [[var_42:%[a-z0-9_]+]] = OpUMulExtended [[i64struct]] [[a_2]] [[b_2]]
-; CHECK-SPIRV: OpStore [[var_41]] [[var_42]]
-; CHECK-SPIRV: OpReturn
-; CHECK-SPIRV: OpFunctionEnd
+; CHECK-SPIRV: [[a_2:%[a-z0-9_]+]] = OpFunctionParameter [[ulong]]
+; CHECK-SPIRV-NEXT: [[b_2:%[a-z0-9_]+]] = OpFunctionParameter [[ulong]]
+; CHECK-SPIRV-NEXT: [[entry_2:%[a-z0-9_]+]] = OpLabel
+; CHECK-SPIRV-NEXT: [[res_2:%[a-z0-9_]+]] = OpUMulExtended [[i64struct]] [[a_2]] [[b_2]]
+; CHECK-SPIRV-NEXT: OpReturnValue [[res_2]]
+; CHECK-SPIRV-NEXT: OpFunctionEnd
-define spir_func void @test_builtin_umulextDv4_xS_(<4 x i32> %a, <4 x i32> %b) {
+define spir_func %vecstruct @test_builtin_umulextDv4_xS_(<4 x i32> %a, <4 x i32> %b) {
entry:
- %0 = alloca %vecstruct
- call void @_Z20__spirv_UMulExtendedDv4_iS_(ptr sret (%vecstruct) %0, <4 x i32> %a, <4 x i32> %b)
- ret void
+ %0 = call %vecstruct @_Z20__spirv_UMulExtendedDv4_iS_(<4 x i32> %a, <4 x i32> %b)
+ ret %vecstruct %0
}
-; CHECK-SPIRV: [[a_3:%[a-z0-9_]+]] = OpFunctionParameter [[v4uint]]
-; CHECK-SPIRV: [[b_3:%[a-z0-9_]+]] = OpFunctionParameter [[v4uint]]
-; CHECK-SPIRV: [[entry_3:%[a-z0-9_]+]] = OpLabel
-; CHECK-SPIRV: [[var_51:%[a-z0-9_]+]] = OpVariable [[_ptr_Function_vecstruct]] Function
-; CHECK-SPIRV: [[var_52:%[a-z0-9_]+]] = OpUMulExtended [[vecstruct]] [[a_3]] [[b_3]]
-; CHECK-SPIRV: OpStore [[var_51]] [[var_52]]
-; CHECK-SPIRV: OpReturn
-; CHECK-SPIRV: OpFunctionEnd
+; CHECK-SPIRV: [[a_3:%[a-z0-9_]+]] = OpFunctionParameter [[v4uint]]
+; CHECK-SPIRV-NEXT: [[b_3:%[a-z0-9_]+]] = OpFunctionParameter [[v4uint]]
+; CHECK-SPIRV-NEXT: [[entry_3:%[a-z0-9_]+]] = OpLabel
+; CHECK-SPIRV-NEXT: [[res_3:%[a-z0-9_]+]] = OpUMulExtended [[vecstruct]] [[a_3]] [[b_3]]
+; CHECK-SPIRV-NEXT: OpReturnValue [[res_3]]
+; CHECK-SPIRV-NEXT: OpFunctionEnd
-%struct.anon = type { i32, i32 }
-
-define spir_func void @test_builtin_umulext_anon(i32 %a, i32 %b) {
+define spir_func %i32struct @test_builtin_umulext_same_arg(i32 %a) {
entry:
- %0 = alloca %struct.anon
- %1 = addrspacecast ptr %0 to ptr addrspace(4)
- call spir_func void @_Z20__spirv_UMulExtendedIiiE4anonIT_T0_ES1_S2_(ptr addrspace(4) sret(%struct.anon) align 4 %1, i32 %a, i32 %b)
- ret void
+ %0 = call %i32struct @_Z20__spirv_UMulExtendedii(i32 %a, i32 %a)
+ ret %i32struct %0
}
-; CHECK-SPIRV: [[a_4:%[a-z0-9_]+]] = OpFunctionParameter [[uint]]
-; CHECK-SPIRV: [[b_4:%[a-z0-9_]+]] = OpFunctionParameter [[uint]]
-; CHECK-SPIRV: [[entry_4:%[a-z0-9_]+]] = OpLabel
-; CHECK-SPIRV: [[var_59:%[a-z0-9_]+]] = OpVariable [[_ptr_Function_i32struct]] Function
-; CHECK-SPIRV: [[var_61:%[a-z0-9_]+]] = OpPtrCastToGeneric [[_ptr_Generic_i32struct]] [[var_59]]
-; CHECK-SPIRV: [[var_62:%[a-z0-9_]+]] = OpUMulExtended [[i32struct]] [[a_4]] [[b_4]]
-; CHECK-SPIRV: OpStore [[var_61]] [[var_62]]
+; CHECK-SPIRV: [[a_4:%[a-z0-9_]+]] = OpFunctionParameter [[uint]]
+; CHECK-SPIRV-NEXT: [[entry_4:%[a-z0-9_]+]] = OpLabel
+; CHECK-SPIRV-NEXT: [[res_4:%[a-z0-9_]+]] = OpUMulExtended [[i32struct]] [[a_4]] [[a_4]]
+; CHECK-SPIRV-NEXT: OpReturnValue [[res_4]]
+; CHECK-SPIRV-NEXT: OpFunctionEnd
-declare void @_Z20__spirv_UMulExtendedIiiE4anonIT_T0_ES1_S2_(ptr addrspace(4) sret(%struct.anon) align 4, i32, i32)
-declare void @_Z20__spirv_UMulExtendedcc(ptr sret(%i8struct), i8, i8)
-declare void @_Z20__spirv_UMulExtendedss(ptr sret(%i16struct), i16, i16)
-declare void @_Z20__spirv_UMulExtendedii(ptr sret(%i32struct), i32, i32)
-declare void @_Z20__spirv_UMulExtendedll(ptr sret(%i64struct), i64, i64)
-declare void @_Z20__spirv_UMulExtendedDv4_iS_(ptr sret (%vecstruct), <4 x i32>, <4 x i32>)
+declare %i8struct @_Z20__spirv_UMulExtendedcc(i8, i8)
+declare %i16struct @_Z20__spirv_UMulExtendedss(i16, i16)
+declare %i32struct @_Z20__spirv_UMulExtendedii(i32, i32)
+declare %i64struct @_Z20__spirv_UMulExtendedll(i64, i64)
+declare %vecstruct @_Z20__spirv_UMulExtendedDv4_iS_(<4 x i32>, <4 x i32>)
More information about the llvm-commits
mailing list