From c0933bf40cee4ed34a14c6b70cab9950194ad6d3 Mon Sep 17 00:00:00 2001 From: Alex Voicu Date: Tue, 9 Dec 2025 21:44:27 +0000 Subject: [PATCH 1/4] i128 is legal in IR / MIR, even though it might yield a module which requires extensions. --- llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp | 17 +++++++++-------- llvm/lib/Target/SPIRV/SPIRVPreLegalizer.cpp | 4 ++-- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp b/llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp index 2078bfee2e767..73e813ef53094 100644 --- a/llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp +++ b/llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp @@ -115,18 +115,19 @@ SPIRVLegalizerInfo::SPIRVLegalizerInfo(const SPIRVSubtarget &ST) { v4s1, v4s8, v4s16, v4s32, v4s64}; auto allScalarsAndVectors = { - s1, s8, s16, s32, s64, v2s1, v2s8, v2s16, v2s32, v2s64, - v3s1, v3s8, v3s16, v3s32, v3s64, v4s1, v4s8, v4s16, v4s32, v4s64, - v8s1, v8s8, v8s16, v8s32, v8s64, v16s1, v16s8, v16s16, v16s32, v16s64}; + s1, s8, s16, s32, s64, s128, v2s1, v2s8, v2s16, v2s32, + v2s64, v3s1, v3s8, v3s16, v3s32, v3s64, v4s1, v4s8, v4s16, v4s32, + v4s64, v8s1, v8s8, v8s16, v8s32, v8s64, v16s1, v16s8, v16s16, v16s32, + v16s64}; - auto allIntScalarsAndVectors = {s8, s16, s32, s64, v2s8, v2s16, - v2s32, v2s64, v3s8, v3s16, v3s32, v3s64, - v4s8, v4s16, v4s32, v4s64, v8s8, v8s16, - v8s32, v8s64, v16s8, v16s16, v16s32, v16s64}; + auto allIntScalarsAndVectors = { + s8, s16, s32, s64, s128, v2s8, v2s16, v2s32, v2s64, v3s8, + v3s16, v3s32, v3s64, v4s8, v4s16, v4s32, v4s64, v8s8, v8s16, v8s32, + v8s64, v16s8, v16s16, v16s32, v16s64}; auto allBoolScalarsAndVectors = {s1, v2s1, v3s1, v4s1, v8s1, v16s1}; - auto allIntScalars = {s8, s16, s32, s64}; + auto allIntScalars = {s8, s16, s32, s64, s128}; auto allFloatScalarsAndF16Vector2AndVector4s = {s16, s32, s64, v2s16, v4s16}; diff --git a/llvm/lib/Target/SPIRV/SPIRVPreLegalizer.cpp b/llvm/lib/Target/SPIRV/SPIRVPreLegalizer.cpp index acc726717743d..9ddbeee92ffb6 100644 --- a/llvm/lib/Target/SPIRV/SPIRVPreLegalizer.cpp +++ b/llvm/lib/Target/SPIRV/SPIRVPreLegalizer.cpp @@ -388,11 +388,11 @@ static SPIRVType *propagateSPIRVType(MachineInstr *MI, SPIRVGlobalRegistry *GR, // To support current approach and limitations wrt. bit width here we widen a // scalar register with a bit width greater than 1 to valid sizes and cap it to -// 64 width. +// 128 width. static unsigned widenBitWidthToNextPow2(unsigned BitWidth) { if (BitWidth == 1) return 1; // No need to widen 1-bit values - return std::min(std::max(1u << Log2_32_Ceil(BitWidth), 8u), 64u); + return std::min(std::max(1u << Log2_32_Ceil(BitWidth), 8u), 128u); } static void widenScalarType(Register Reg, MachineRegisterInfo &MRI) { From 82dbfe9ac050698e040cfacf5bc1ea4125901518 Mon Sep 17 00:00:00 2001 From: Alex Voicu Date: Tue, 9 Dec 2025 21:54:01 +0000 Subject: [PATCH 2/4] Fix formatting. --- llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp b/llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp index 73e813ef53094..30703ee40be06 100644 --- a/llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp +++ b/llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp @@ -115,15 +115,15 @@ SPIRVLegalizerInfo::SPIRVLegalizerInfo(const SPIRVSubtarget &ST) { v4s1, v4s8, v4s16, v4s32, v4s64}; auto allScalarsAndVectors = { - s1, s8, s16, s32, s64, s128, v2s1, v2s8, v2s16, v2s32, - v2s64, v3s1, v3s8, v3s16, v3s32, v3s64, v4s1, v4s8, v4s16, v4s32, - v4s64, v8s1, v8s8, v8s16, v8s32, v8s64, v16s1, v16s8, v16s16, v16s32, - v16s64}; + s1, s8, s16, s32, s64, s128, v2s1, v2s8, + v2s16, v2s32, v2s64, v3s1, v3s8, v3s16, v3s32, v3s64, + v4s1, v4s8, v4s16, v4s32, v4s64, v8s1, v8s8, v8s16, + v8s32, v8s64, v16s1, v16s8, v16s16, v16s32, v16s64}; auto allIntScalarsAndVectors = { - s8, s16, s32, s64, s128, v2s8, v2s16, v2s32, v2s64, v3s8, - v3s16, v3s32, v3s64, v4s8, v4s16, v4s32, v4s64, v8s8, v8s16, v8s32, - v8s64, v16s8, v16s16, v16s32, v16s64}; + s8, s16, s32, s64, s128, v2s8, v2s16, v2s32, v2s64, + v3s8, v3s16, v3s32, v3s64, v4s8, v4s16, v4s32, v4s64, v8s8, + v8s16, v8s32, v8s64, v16s8, v16s16, v16s32, v16s64}; auto allBoolScalarsAndVectors = {s1, v2s1, v3s1, v4s1, v8s1, v16s1}; From 97d5cc2eaa4db8027ecb6f038b356231c745c0a8 Mon Sep 17 00:00:00 2001 From: Alex Voicu Date: Mon, 15 Dec 2025 17:59:30 +0000 Subject: [PATCH 3/4] Handle storing of aggregates via `spv_store`. --- llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp | 13 ++++++++ .../Target/SPIRV/SPIRVInstructionSelector.cpp | 10 +++++++ .../SPIRV/instructions/nested-composites.ll | 30 +++++++++++++++++++ 3 files changed, 53 insertions(+) diff --git a/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp b/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp index 9b34ff90abe69..73dcec062d3f0 100644 --- a/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp +++ b/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp @@ -2021,6 +2021,19 @@ Instruction *SPIRVEmitIntrinsics::visitStoreInst(StoreInst &I) { MachineMemOperand::Flags Flags = TLI->getStoreMemOperandFlags(I, CurrF->getDataLayout()); auto *PtrOp = I.getPointerOperand(); + + if (I.getValueOperand()->getType()->isAggregateType()) { + // It is possible that what used to be an ExtractValueInst has been replaced + // with a call to the spv_extractv intrinsic, and that said call hasn't + // had its return type replaced with i32 during the dedicated pass (because + // it was emitted later); we have to handle this here, because IRTranslator + // cannot deal with multi-register types at the moment. + CallBase *CB = dyn_cast(I.getValueOperand()); + assert(CB && CB->getIntrinsicID() == Intrinsic::spv_extractv && + "Unexpected argument of aggregate type, should be spv_extractv!"); + CB->mutateType(B.getInt32Ty()); + } + auto *NewI = B.CreateIntrinsic( Intrinsic::spv_store, {I.getValueOperand()->getType(), PtrOp->getType()}, {I.getValueOperand(), PtrOp, B.getInt16(Flags), diff --git a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp index 2e4563795e8f0..dd2e3f1951850 100644 --- a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp +++ b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp @@ -3297,6 +3297,16 @@ bool SPIRVInstructionSelector::selectInsertVal(Register ResVReg, bool SPIRVInstructionSelector::selectExtractVal(Register ResVReg, const SPIRVType *ResType, MachineInstr &I) const { + Type *MaybeResTy = nullptr; + StringRef ResName; + if (GR.findValueAttrs(&I, MaybeResTy, ResName) && + MaybeResTy != GR.getTypeForSPIRVType(ResType)) { + assert(!MaybeResTy || MaybeResTy->isAggregateType() && + "Expected aggregate type for extractv instruction"); + ResType = GR.getOrCreateSPIRVType(MaybeResTy, I, + SPIRV::AccessQualifier::ReadWrite, false); + GR.assignSPIRVTypeToVReg(ResType, ResVReg, *I.getMF()); + } MachineBasicBlock &BB = *I.getParent(); auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpCompositeExtract)) .addDef(ResVReg) diff --git a/llvm/test/CodeGen/SPIRV/instructions/nested-composites.ll b/llvm/test/CodeGen/SPIRV/instructions/nested-composites.ll index 88e992f183452..7b49002766a26 100644 --- a/llvm/test/CodeGen/SPIRV/instructions/nested-composites.ll +++ b/llvm/test/CodeGen/SPIRV/instructions/nested-composites.ll @@ -1,13 +1,19 @@ ; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv32-unknown-unknown %s -o - | FileCheck %s +; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s +; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv32-unknown-unknown %s -o - -filetype=obj | spirv-val %} +; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown %s -o - -filetype=obj | spirv-val %} ; CHECK-DAG: OpName [[FOOBAR:%.+]] "foobar" ; CHECK-DAG: OpName [[PRODUCER:%.+]] "producer" ; CHECK-DAG: OpName [[CONSUMER:%.+]] "consumer" +; CHECK-DAG: OpName [[SNEAKY:%.+]] "sneaky" +; CHECK-DAG: OpName [[ARR_RET:%.+]] "arr_ret" ; CHECK-NOT: DAG-FENCE %ty1 = type {i16, i32} %ty2 = type {%ty1, i64} +%ty3 = type {ptr addrspace(4), ptr addrspace(4), [8 x i8]} ; CHECK-DAG: [[I16:%.+]] = OpTypeInt 16 ; CHECK-DAG: [[I32:%.+]] = OpTypeInt 32 @@ -18,6 +24,12 @@ ; CHECK-DAG: [[UNDEF_I64:%.+]] = OpUndef [[I64]] ; CHECK-DAG: [[UNDEF_TY2:%.+]] = OpUndef [[TY2]] ; CHECK-DAG: [[CST_42:%.+]] = OpConstant [[I32]] 42 +; CHECK-DAG: [[I8:%.+]] = OpTypeInt 8 0 +; CHECK-DAG: [[PTR:%.+]] = OpTypePointer Generic [[I8]] +; CHECK-DAG: [[CST_8:%.+]] = OpConstant [[I32]] 8 +; CHECK-DAG: [[ARR:%.+]] = OpTypeArray [[I8]] [[CST_8]] +; CHECK-DAG: [[TY3:%.+]] = OpTypeStruct [[PTR]] [[PTR]] [[ARR]] +; CHECK-DAG: [[PTR_ARR:%.+]] = OpTypePointer Generic [[ARR]] ; CHECK-NOT: DAG-FENCE @@ -62,3 +74,21 @@ define i32 @consumer(%ty2 %agg) { ; CHECK: [[RET:%.+]] = OpCompositeExtract [[I32]] [[AGG]] 0 1 ; CHECK: OpReturnValue [[RET]] ; CHECK: OpFunctionEnd + +declare %ty3 @arr_ret() + +define void @sneaky(ptr addrspace(4) %p, [8 x i8] %a) { + %1 = call spir_func %ty3 @arr_ret() + %2 = getelementptr inbounds nuw %ty3, ptr addrspace(4) %p, i32 0, i32 2 + %3 = extractvalue %ty3 %1, 2 + store [8 x i8] %3, ptr addrspace(4) %2, align 8 + ret void +} + +; CHECK: [[SNEAKY]] = OpFunction +; CHECK: [[PTR_AGG:%.+]] = OpFunctionParameter +; CHECK: [[A:%.+]] = OpFunctionParameter [[ARR]] +; CHECK: [[AGG_RET:%.+]] = OpFunctionCall [[TY3]] +; CHECK: [[GEP:%.+]] = OpInBoundsPtrAccessChain [[PTR_ARR]] [[PTR_AGG]] +; CHECK: [[EXTRACTV:%.+]] = OpCompositeExtract [[ARR]] [[AGG_RET]] 2 +; CHECK: OpStore [[GEP]] [[EXTRACTV]] From f837bb69c73c38dc2c628fe1e83b87526bd8d4d8 Mon Sep 17 00:00:00 2001 From: Alex Voicu Date: Mon, 15 Dec 2025 18:46:39 +0000 Subject: [PATCH 4/4] Fix formatting. --- llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp index dd2e3f1951850..77c4678bb2210 100644 --- a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp +++ b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp @@ -3301,8 +3301,9 @@ bool SPIRVInstructionSelector::selectExtractVal(Register ResVReg, StringRef ResName; if (GR.findValueAttrs(&I, MaybeResTy, ResName) && MaybeResTy != GR.getTypeForSPIRVType(ResType)) { - assert(!MaybeResTy || MaybeResTy->isAggregateType() && - "Expected aggregate type for extractv instruction"); + assert(!MaybeResTy || + MaybeResTy->isAggregateType() && + "Expected aggregate type for extractv instruction"); ResType = GR.getOrCreateSPIRVType(MaybeResTy, I, SPIRV::AccessQualifier::ReadWrite, false); GR.assignSPIRVTypeToVReg(ResType, ResVReg, *I.getMF());