[llvm] [SPIR-V] Fix early definition of SPIR-V types during call lowering (PR #115192)

Vyacheslav Levytskyy via llvm-commits llvm-commits at lists.llvm.org
Thu Nov 7 02:53:52 PST 2024


https://github.com/VyacheslavLevytskyy updated https://github.com/llvm/llvm-project/pull/115192

>From aaf20d0c888d0bcbe351ad5a3b9570536842b98c Mon Sep 17 00:00:00 2001
From: "Levytskyy, Vyacheslav" <vyacheslav.levytskyy at intel.com>
Date: Wed, 6 Nov 2024 09:18:01 -0800
Subject: [PATCH 1/3] call lowering may not know register's type

---
 llvm/lib/Target/SPIRV/SPIRVCallLowering.cpp | 16 +++++++++++++---
 1 file changed, 13 insertions(+), 3 deletions(-)

diff --git a/llvm/lib/Target/SPIRV/SPIRVCallLowering.cpp b/llvm/lib/Target/SPIRV/SPIRVCallLowering.cpp
index 98cf598a1f031a..d914f3cf256d48 100644
--- a/llvm/lib/Target/SPIRV/SPIRVCallLowering.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVCallLowering.cpp
@@ -545,13 +545,23 @@ bool SPIRVCallLowering::lowerCall(MachineIRBuilder &MIRBuilder,
       Register ArgReg = Arg.Regs[0];
       ArgVRegs.push_back(ArgReg);
       SPIRVType *SpvType = GR->getSPIRVTypeForVReg(ArgReg);
-      if (!SpvType) {
+      // If Arg.Ty is an untyped pointer (i.e., ptr [addrspace(...)]) we should
+      // wait with setting the type for the virtual register until pre-legalizer
+      // step when we access @llvm.spv.assign.ptr.type.p...(...)'s info.
+      if (!SpvType && !isUntypedPointerTy(Arg.Ty)) {
         SpvType = GR->getOrCreateSPIRVType(Arg.Ty, MIRBuilder);
         GR->assignSPIRVTypeToVReg(SpvType, ArgReg, MF);
       }
       if (!MRI->getRegClassOrNull(ArgReg)) {
-        MRI->setRegClass(ArgReg, GR->getRegClass(SpvType));
-        MRI->setType(ArgReg, GR->getRegType(SpvType));
+        // Either we have SpvType created, or Arg.Ty is an untyped pointer and
+        // we know its virtual register's class and type.
+        MRI->setRegClass(ArgReg, SpvType ? GR->getRegClass(SpvType)
+                                         : &SPIRV::pIDRegClass);
+        MRI->setType(
+            ArgReg,
+            SpvType ? GR->getRegType(SpvType)
+                    : LLT::pointer(cast<PointerType>(Arg.Ty)->getAddressSpace(),
+                                   GR->getPointerSize()));
       }
     }
     auto instructionSet = canUseOpenCL ? SPIRV::InstructionSet::OpenCL_std

>From e919ea18e9fb2081f758c88de6f24561db435440 Mon Sep 17 00:00:00 2001
From: "Levytskyy, Vyacheslav" <vyacheslav.levytskyy at intel.com>
Date: Wed, 6 Nov 2024 10:46:13 -0800
Subject: [PATCH 2/3] ensure that correct types are applied to virtual
 registers which were used as arguments in call lowering and so caused early
 definition of SPIR-V types

---
 llvm/lib/Target/SPIRV/SPIRVCallLowering.cpp   | 27 +++++++---
 llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp |  2 +
 ...operand-types-vs-calllowering-unwrapped.ll | 50 +++++++++++++++++++
 ...phi-valid-operand-types-vs-calllowering.ll | 49 ++++++++++++++++++
 4 files changed, 121 insertions(+), 7 deletions(-)
 create mode 100644 llvm/test/CodeGen/SPIRV/pointers/phi-valid-operand-types-vs-calllowering-unwrapped.ll
 create mode 100644 llvm/test/CodeGen/SPIRV/pointers/phi-valid-operand-types-vs-calllowering.ll

diff --git a/llvm/lib/Target/SPIRV/SPIRVCallLowering.cpp b/llvm/lib/Target/SPIRV/SPIRVCallLowering.cpp
index d914f3cf256d48..8d1b82465d3df2 100644
--- a/llvm/lib/Target/SPIRV/SPIRVCallLowering.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVCallLowering.cpp
@@ -545,16 +545,29 @@ bool SPIRVCallLowering::lowerCall(MachineIRBuilder &MIRBuilder,
       Register ArgReg = Arg.Regs[0];
       ArgVRegs.push_back(ArgReg);
       SPIRVType *SpvType = GR->getSPIRVTypeForVReg(ArgReg);
-      // If Arg.Ty is an untyped pointer (i.e., ptr [addrspace(...)]) we should
-      // wait with setting the type for the virtual register until pre-legalizer
-      // step when we access @llvm.spv.assign.ptr.type.p...(...)'s info.
-      if (!SpvType && !isUntypedPointerTy(Arg.Ty)) {
-        SpvType = GR->getOrCreateSPIRVType(Arg.Ty, MIRBuilder);
-        GR->assignSPIRVTypeToVReg(SpvType, ArgReg, MF);
+      if (!SpvType) {
+        Type *ArgTy = nullptr;
+        if (auto *PtrArgTy = dyn_cast<PointerType>(Arg.Ty)) {
+          // If Arg.Ty is an untyped pointer (i.e., ptr [addrspace(...)]) and we
+          // don't have access to original value in LLVM IR or info about
+          // deduced pointee type, then we should wait with setting the type for
+          // the virtual register until pre-legalizer step when we access
+          // @llvm.spv.assign.ptr.type.p...(...)'s info.
+          if (Arg.OrigValue)
+            if (Type *ElemTy = GR->findDeducedElementType(Arg.OrigValue))
+              ArgTy = TypedPointerType::get(ElemTy, PtrArgTy->getAddressSpace());
+        } else {
+          ArgTy = Arg.Ty;
+        }
+        if (ArgTy) {
+          SpvType = GR->getOrCreateSPIRVType(ArgTy, MIRBuilder);
+          GR->assignSPIRVTypeToVReg(SpvType, ArgReg, MF);
+        }
       }
       if (!MRI->getRegClassOrNull(ArgReg)) {
         // Either we have SpvType created, or Arg.Ty is an untyped pointer and
-        // we know its virtual register's class and type.
+        // we know its virtual register's class and type even if we don't know
+        // pointee type.
         MRI->setRegClass(ArgReg, SpvType ? GR->getRegClass(SpvType)
                                          : &SPIRV::pIDRegClass);
         MRI->setType(
diff --git a/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp b/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp
index 8b7e9c48de6c75..191533a52cccd9 100644
--- a/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp
@@ -1219,6 +1219,8 @@ void SPIRVEmitIntrinsics::replacePointerOperandWithPtrCast(
   SmallVector<Value *, 2> Args = {Pointer, VMD, B.getInt32(AddressSpace)};
   auto *PtrCastI = B.CreateIntrinsic(Intrinsic::spv_ptrcast, {Types}, Args);
   I->setOperand(OperandToReplace, PtrCastI);
+  // We need to set up a pointee type for the newly created spv_ptrcast.
+  buildAssignPtr(B, ExpectedElementType, PtrCastI);
 }
 
 void SPIRVEmitIntrinsics::insertPtrCastOrAssignTypeInstr(Instruction *I,
diff --git a/llvm/test/CodeGen/SPIRV/pointers/phi-valid-operand-types-vs-calllowering-unwrapped.ll b/llvm/test/CodeGen/SPIRV/pointers/phi-valid-operand-types-vs-calllowering-unwrapped.ll
new file mode 100644
index 00000000000000..09c0a92d596ce3
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/pointers/phi-valid-operand-types-vs-calllowering-unwrapped.ll
@@ -0,0 +1,50 @@
+; The goal of the test case is to ensure that correct types are applied to virtual registers
+; which were used as arguments in call lowering and so caused early definition of SPIR-V types.
+
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown %s -o - -filetype=obj | spirv-val %}
+
+%t_id = type { %t_arr }
+%t_arr = type { [1 x i64] }
+%t_bf16 = type { i16 }
+
+define weak_odr dso_local spir_kernel void @foo(ptr addrspace(1) align 4 %_arg_ERR, ptr byval(%t_id) align 8 %_arg_ERR3) {
+entry:
+  %FloatArray.i = alloca [4 x float], align 4
+  %BF16Array.i = alloca [4 x %t_bf16], align 2
+  %0 = load i64, ptr %_arg_ERR3, align 8
+  %add.ptr.i = getelementptr inbounds i32, ptr addrspace(1) %_arg_ERR, i64 %0
+  %FloatArray.ascast.i = addrspacecast ptr %FloatArray.i to ptr addrspace(4)
+  %BF16Array.ascast.i = addrspacecast ptr %BF16Array.i to ptr addrspace(4)
+  call spir_func void @__devicelib_ConvertFToBF16INTELVec4(ptr addrspace(4) %FloatArray.ascast.i, ptr addrspace(4) %BF16Array.ascast.i)
+  br label %for.cond.i
+
+for.cond.i:                                       ; preds = %for.inc.i, %entry
+  %lsr.iv1 = phi ptr [ %scevgep2, %for.inc.i ], [ %FloatArray.i, %entry ]
+  %lsr.iv = phi ptr addrspace(4) [ %scevgep, %for.inc.i ], [ %BF16Array.ascast.i, %entry ]
+  %i.0.i = phi i32 [ 0, %entry ], [ %inc.i, %for.inc.i ]
+  %cmp.i = icmp ult i32 %i.0.i, 4
+  br i1 %cmp.i, label %for.body.i, label %exit
+
+for.body.i:                                       ; preds = %for.cond.i
+  %1 = load float, ptr %lsr.iv1, align 4
+  %call.i.i = call spir_func float @__devicelib_ConvertBF16ToFINTEL(ptr addrspace(4) align 2 dereferenceable(2) %lsr.iv)
+  %cmp5.i = fcmp une float %1, %call.i.i
+  br i1 %cmp5.i, label %if.then.i, label %for.inc.i
+
+if.then.i:                                        ; preds = %for.body.i
+  store i32 1, ptr addrspace(1) %add.ptr.i, align 4
+  br label %for.inc.i
+
+for.inc.i:                                        ; preds = %if.then.i, %for.body.i
+  %inc.i = add nuw nsw i32 %i.0.i, 1
+  %scevgep = getelementptr i8, ptr addrspace(4) %lsr.iv, i64 2
+  %scevgep2 = getelementptr i8, ptr %lsr.iv1, i64 4
+  br label %for.cond.i
+
+exit:                                             ; preds = %for.cond.i
+  ret void
+}
+
+declare void @llvm.memcpy.p0.p1.i64(ptr noalias nocapture writeonly, ptr addrspace(1) noalias nocapture readonly, i64, i1 immarg)
+declare dso_local spir_func void @__devicelib_ConvertFToBF16INTELVec4(ptr addrspace(4), ptr addrspace(4))
+declare dso_local spir_func float @__devicelib_ConvertBF16ToFINTEL(ptr addrspace(4) align 2 dereferenceable(2))
diff --git a/llvm/test/CodeGen/SPIRV/pointers/phi-valid-operand-types-vs-calllowering.ll b/llvm/test/CodeGen/SPIRV/pointers/phi-valid-operand-types-vs-calllowering.ll
new file mode 100644
index 00000000000000..a31638e0b87043
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/pointers/phi-valid-operand-types-vs-calllowering.ll
@@ -0,0 +1,49 @@
+; The goal of the test case is to ensure that correct types are applied to virtual registers
+; which were used as arguments in call lowering and so caused early definition of SPIR-V types.
+
+; RUN: %if spirv-tools %{ llc -O2 -mtriple=spirv64-unknown-unknown %s -o - -filetype=obj | spirv-val %}
+
+%t_id = type { %t_arr }
+%t_arr = type { [1 x i64] }
+%t_bf16 = type { i16 }
+
+define weak_odr dso_local spir_kernel void @foo(ptr addrspace(1) align 4 %_arg_ERR, ptr byval(%t_id) align 8 %_arg_ERR3) {
+entry:
+  %FloatArray.i = alloca [4 x float], align 4
+  %BF16Array.i = alloca [4 x %t_bf16], align 2
+  %0 = load i64, ptr %_arg_ERR3, align 8
+  %add.ptr.i = getelementptr inbounds i32, ptr addrspace(1) %_arg_ERR, i64 %0
+  %FloatArray.ascast.i = addrspacecast ptr %FloatArray.i to ptr addrspace(4)
+  %BF16Array.ascast.i = addrspacecast ptr %BF16Array.i to ptr addrspace(4)
+  call spir_func void @__devicelib_ConvertFToBF16INTELVec4(ptr addrspace(4) %FloatArray.ascast.i, ptr addrspace(4) %BF16Array.ascast.i)
+  br label %for.cond.i
+
+for.cond.i:                                       ; preds = %for.inc.i, %entry
+  %i.0.i = phi i32 [ 0, %entry ], [ %inc.i, %for.inc.i ]
+  %cmp.i = icmp ult i32 %i.0.i, 4
+  br i1 %cmp.i, label %for.body.i, label %exit
+
+for.body.i:                                       ; preds = %for.cond.i
+  %idxprom.i = zext nneg i32 %i.0.i to i64
+  %arrayidx.i = getelementptr inbounds [4 x float], ptr %FloatArray.i, i64 0, i64 %idxprom.i
+  %1 = load float, ptr %arrayidx.i, align 4
+  %arrayidx4.i = getelementptr inbounds [4 x %t_bf16], ptr addrspace(4) %BF16Array.ascast.i, i64 0, i64 %idxprom.i
+  %call.i.i = call spir_func float @__devicelib_ConvertBF16ToFINTEL(ptr addrspace(4) align 2 dereferenceable(2) %arrayidx4.i)
+  %cmp5.i = fcmp une float %1, %call.i.i
+  br i1 %cmp5.i, label %if.then.i, label %for.inc.i
+
+if.then.i:                                        ; preds = %for.body.i
+  store i32 1, ptr addrspace(1) %add.ptr.i, align 4
+  br label %for.inc.i
+
+for.inc.i:                                        ; preds = %if.then.i, %for.body.i
+  %inc.i = add nuw nsw i32 %i.0.i, 1
+  br label %for.cond.i
+
+exit: ; preds = %for.cond.i
+  ret void
+}
+
+declare void @llvm.memcpy.p0.p1.i64(ptr noalias nocapture writeonly, ptr addrspace(1) noalias nocapture readonly, i64, i1 immarg)
+declare dso_local spir_func void @__devicelib_ConvertFToBF16INTELVec4(ptr addrspace(4), ptr addrspace(4))
+declare dso_local spir_func float @__devicelib_ConvertBF16ToFINTEL(ptr addrspace(4) align 2 dereferenceable(2))

>From 570efc37187c21163bceb9636ca98b3dbb16a671 Mon Sep 17 00:00:00 2001
From: "Levytskyy, Vyacheslav" <vyacheslav.levytskyy at intel.com>
Date: Thu, 7 Nov 2024 02:53:37 -0800
Subject: [PATCH 3/3] clang-format

---
 llvm/lib/Target/SPIRV/SPIRVCallLowering.cpp | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/llvm/lib/Target/SPIRV/SPIRVCallLowering.cpp b/llvm/lib/Target/SPIRV/SPIRVCallLowering.cpp
index 8d1b82465d3df2..3c5397319aaf21 100644
--- a/llvm/lib/Target/SPIRV/SPIRVCallLowering.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVCallLowering.cpp
@@ -555,7 +555,8 @@ bool SPIRVCallLowering::lowerCall(MachineIRBuilder &MIRBuilder,
           // @llvm.spv.assign.ptr.type.p...(...)'s info.
           if (Arg.OrigValue)
             if (Type *ElemTy = GR->findDeducedElementType(Arg.OrigValue))
-              ArgTy = TypedPointerType::get(ElemTy, PtrArgTy->getAddressSpace());
+              ArgTy =
+                  TypedPointerType::get(ElemTy, PtrArgTy->getAddressSpace());
         } else {
           ArgTy = Arg.Ty;
         }



More information about the llvm-commits mailing list