[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