[llvm] [SPIR-V] Emit SPIR-V bitcasts between source/expected pointer type (PR #69621)

Michal Paszkowski via llvm-commits llvm-commits at lists.llvm.org
Thu Jan 4 10:41:15 PST 2024


https://github.com/michalpaszkowski updated https://github.com/llvm/llvm-project/pull/69621

>From 4de7110138dc8e4b3c44dfec6e1b6587095422f9 Mon Sep 17 00:00:00 2001
From: Michal Paszkowski <michal.paszkowski at outlook.com>
Date: Thu, 19 Oct 2023 10:58:05 -0700
Subject: [PATCH] [SPIR-V] Emit SPIR-V bitcasts between source/expected pointer
 type

This patch introduces a new spv_ptrcast intrinsic for tracking exptected
pointer types. The change fixes multiple OpenCL CTS regressions due
the switch to opaque pointers (e.g. basic/hiloeo).
---
 llvm/include/llvm/IR/IntrinsicsSPIRV.td       |   1 +
 llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp | 123 +++++++++++++++++-
 llvm/lib/Target/SPIRV/SPIRVPreLegalizer.cpp   |  32 ++++-
 .../CodeGen/SPIRV/AtomicCompareExchange.ll    |  31 ++---
 .../SPIRV/function/alloca-load-store.ll       |  22 ++--
 .../undef-nested-composite-store.ll           |   3 +-
 .../undef-simple-composite-store.ll           |   3 +-
 .../CodeGen/SPIRV/llvm-intrinsics/memset.ll   |   4 +-
 llvm/test/CodeGen/SPIRV/opaque_pointers.ll    |  20 +--
 .../SPIRV/opencl/basic/get_global_offset.ll   |   8 +-
 .../SPIRV/pointers/two-bitcast-users.ll       |  19 +++
 .../SPIRV/pointers/two-subsequent-bitcasts.ll |  17 +++
 llvm/test/CodeGen/SPIRV/sitofp-with-bool.ll   |  15 ++-
 .../OpPhi_ArgumentsPlaceholders.ll            |   1 +
 .../CodeGen/SPIRV/transcoding/spec_const.ll   |   1 +
 .../spirv-private-array-initialization.ll     |   6 +-
 llvm/test/CodeGen/SPIRV/uitofp-with-bool.ll   |   4 +-
 17 files changed, 243 insertions(+), 67 deletions(-)
 create mode 100644 llvm/test/CodeGen/SPIRV/pointers/two-bitcast-users.ll
 create mode 100644 llvm/test/CodeGen/SPIRV/pointers/two-subsequent-bitcasts.ll

diff --git a/llvm/include/llvm/IR/IntrinsicsSPIRV.td b/llvm/include/llvm/IR/IntrinsicsSPIRV.td
index 736be8ca3212bf..ea0074d22a4419 100644
--- a/llvm/include/llvm/IR/IntrinsicsSPIRV.td
+++ b/llvm/include/llvm/IR/IntrinsicsSPIRV.td
@@ -28,6 +28,7 @@ let TargetPrefix = "spv" in {
   def int_spv_insertelt : Intrinsic<[llvm_any_ty], [llvm_any_ty, llvm_any_ty, llvm_anyint_ty]>;
   def int_spv_const_composite : Intrinsic<[llvm_i32_ty], [llvm_vararg_ty]>;
   def int_spv_bitcast : Intrinsic<[llvm_any_ty], [llvm_any_ty]>;
+  def int_spv_ptrcast : Intrinsic<[llvm_any_ty], [llvm_any_ty, llvm_metadata_ty, llvm_i32_ty], [ImmArg<ArgIndex<2>>]>;
   def int_spv_switch : Intrinsic<[], [llvm_any_ty, llvm_vararg_ty]>;
   def int_spv_cmpxchg : Intrinsic<[llvm_i32_ty], [llvm_any_ty, llvm_vararg_ty]>;
   def int_spv_unreachable : Intrinsic<[], []>;
diff --git a/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp b/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp
index 660c574daf38f7..6e08b2a4aac53e 100644
--- a/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp
@@ -74,6 +74,7 @@ class SPIRVEmitIntrinsics
   void processInstrAfterVisit(Instruction *I);
   void insertAssignPtrTypeIntrs(Instruction *I);
   void insertAssignTypeIntrs(Instruction *I);
+  void insertPtrCastInstr(Instruction *I);
   void processGlobalValue(GlobalVariable &GV);
 
 public:
@@ -255,7 +256,19 @@ Instruction *SPIRVEmitIntrinsics::visitGetElementPtrInst(GetElementPtrInst &I) {
 }
 
 Instruction *SPIRVEmitIntrinsics::visitBitCastInst(BitCastInst &I) {
-  SmallVector<Type *, 2> Types = {I.getType(), I.getOperand(0)->getType()};
+  Value *Source = I.getOperand(0);
+
+  // SPIR-V, contrary to LLVM 17+ IR, supports bitcasts between pointers of
+  // varying element types. In case of IR coming from older versions of LLVM
+  // such bitcasts do not provide sufficient information, should be just skipped
+  // here, and handled in insertPtrCastInstr.
+  if (I.getType()->isPointerTy()) {
+    I.replaceAllUsesWith(Source);
+    I.eraseFromParent();
+    return nullptr;
+  }
+
+  SmallVector<Type *, 2> Types = {I.getType(), Source->getType()};
   SmallVector<Value *> Args(I.op_begin(), I.op_end());
   auto *NewI = IRB->CreateIntrinsic(Intrinsic::spv_bitcast, {Types}, {Args});
   std::string InstName = I.hasName() ? I.getName().str() : "";
@@ -265,6 +278,109 @@ Instruction *SPIRVEmitIntrinsics::visitBitCastInst(BitCastInst &I) {
   return NewI;
 }
 
+void SPIRVEmitIntrinsics::insertPtrCastInstr(Instruction *I) {
+  Value *Pointer;
+  Type *ExpectedElementType;
+  unsigned OperandToReplace;
+  if (StoreInst *SI = dyn_cast<StoreInst>(I)) {
+    Pointer = SI->getPointerOperand();
+    ExpectedElementType = SI->getValueOperand()->getType();
+    OperandToReplace = 1;
+  } else if (LoadInst *LI = dyn_cast<LoadInst>(I)) {
+    Pointer = LI->getPointerOperand();
+    ExpectedElementType = LI->getType();
+    OperandToReplace = 0;
+  } else if (GetElementPtrInst *GEPI = dyn_cast<GetElementPtrInst>(I)) {
+    Pointer = GEPI->getPointerOperand();
+    ExpectedElementType = GEPI->getSourceElementType();
+    OperandToReplace = 0;
+  } else {
+    return;
+  }
+
+  // If Pointer is the result of nop BitCastInst (ptr -> ptr), use the source
+  // pointer instead. The BitCastInst should be later removed when visited.
+  while (BitCastInst *BC = dyn_cast<BitCastInst>(Pointer))
+    Pointer = BC->getOperand(0);
+
+  // Do not emit spv_ptrcast if Pointer is a GlobalValue of expected type.
+  GlobalValue *GV = dyn_cast<GlobalValue>(Pointer);
+  if (GV && GV->getValueType() == ExpectedElementType)
+    return;
+
+  // Do not emit spv_ptrcast if Pointer is a result of alloca with expected
+  // type.
+  AllocaInst *A = dyn_cast<AllocaInst>(Pointer);
+  if (A && A->getAllocatedType() == ExpectedElementType)
+    return;
+
+  if (dyn_cast<GetElementPtrInst>(Pointer))
+    return;
+
+  setInsertPointSkippingPhis(*IRB, I);
+  Constant *ExpectedElementTypeConst =
+      Constant::getNullValue(ExpectedElementType);
+  ConstantAsMetadata *CM =
+      ValueAsMetadata::getConstant(ExpectedElementTypeConst);
+  MDTuple *TyMD = MDNode::get(F->getContext(), CM);
+  MetadataAsValue *VMD = MetadataAsValue::get(F->getContext(), TyMD);
+  unsigned AddressSpace = Pointer->getType()->getPointerAddressSpace();
+  bool FirstPtrCastOrAssignPtrType = true;
+
+  // Do not emit new spv_ptrcast if equivalent one already exists or when
+  // spv_assign_ptr_type already targets this pointer with the same element
+  // type.
+  for (auto User : Pointer->users()) {
+    auto *II = dyn_cast<IntrinsicInst>(User);
+    if (!II ||
+        (II->getIntrinsicID() != Intrinsic::spv_assign_ptr_type &&
+         II->getIntrinsicID() != Intrinsic::spv_ptrcast) ||
+        II->getOperand(0) != Pointer)
+      continue;
+
+    // There is some spv_ptrcast/spv_assign_ptr_type already targeting this
+    // pointer.
+    FirstPtrCastOrAssignPtrType = false;
+    if (II->getOperand(1) != VMD ||
+        dyn_cast<ConstantInt>(II->getOperand(2))->getSExtValue() !=
+            AddressSpace)
+      continue;
+
+    // The spv_ptrcast/spv_assign_ptr_type targeting this pointer is of the same
+    // element type and address space.
+    if (II->getIntrinsicID() != Intrinsic::spv_ptrcast)
+      return;
+
+    // This must be a spv_ptrcast, do not emit new if this one has the same BB
+    // as I. Otherwise, search for other spv_ptrcast/spv_assign_ptr_type.
+    if (II->getParent() != I->getParent())
+      continue;
+
+    I->setOperand(OperandToReplace, II);
+    return;
+  }
+
+  // Do not emit spv_ptrcast if it would cast to the default pointer element
+  // type (i8) of the same address space.
+  if (ExpectedElementType->isIntegerTy(8))
+    return;
+
+  // If this would be the first spv_ptrcast and there is no spv_assign_ptr_type
+  // for this pointer before, do not emit spv_ptrcast but emit
+  // spv_assign_ptr_type instead.
+  if (FirstPtrCastOrAssignPtrType && isa<Instruction>(Pointer)) {
+    buildIntrWithMD(Intrinsic::spv_assign_ptr_type, {Pointer->getType()},
+                    ExpectedElementTypeConst, Pointer,
+                    {IRB->getInt32(AddressSpace)});
+  } else {
+    SmallVector<Type *, 2> Types = {Pointer->getType(), Pointer->getType()};
+    SmallVector<Value *, 2> Args = {Pointer, VMD, IRB->getInt32(AddressSpace)};
+    auto *PtrCastI =
+        IRB->CreateIntrinsic(Intrinsic::spv_ptrcast, {Types}, Args);
+    I->setOperand(OperandToReplace, PtrCastI);
+  }
+}
+
 Instruction *SPIRVEmitIntrinsics::visitInsertElementInst(InsertElementInst &I) {
   SmallVector<Type *, 4> Types = {I.getType(), I.getOperand(0)->getType(),
                                   I.getOperand(1)->getType(),
@@ -522,13 +638,18 @@ bool SPIRVEmitIntrinsics::runOnFunction(Function &Func) {
   for (auto &I : Worklist) {
     insertAssignPtrTypeIntrs(I);
     insertAssignTypeIntrs(I);
+    insertPtrCastInstr(I);
   }
 
   for (auto *I : Worklist) {
     TrackConstants = true;
     if (!I->getType()->isVoidTy() || isa<StoreInst>(I))
       IRB->SetInsertPoint(I->getNextNode());
+    // Visitors return either the original/newly created instruction for further
+    // processing, nullptr otherwise.
     I = visit(*I);
+    if (!I)
+      continue;
     processInstrAfterVisit(I);
   }
   return true;
diff --git a/llvm/lib/Target/SPIRV/SPIRVPreLegalizer.cpp b/llvm/lib/Target/SPIRV/SPIRVPreLegalizer.cpp
index 1bfce70fedc0ec..9ec38a458d0a1d 100644
--- a/llvm/lib/Target/SPIRV/SPIRVPreLegalizer.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVPreLegalizer.cpp
@@ -125,12 +125,32 @@ static void insertBitcasts(MachineFunction &MF, SPIRVGlobalRegistry *GR,
   SmallVector<MachineInstr *, 10> ToErase;
   for (MachineBasicBlock &MBB : MF) {
     for (MachineInstr &MI : MBB) {
-      if (!isSpvIntrinsic(MI, Intrinsic::spv_bitcast))
-        continue;
-      assert(MI.getOperand(2).isReg());
-      MIB.setInsertPt(*MI.getParent(), MI);
-      MIB.buildBitcast(MI.getOperand(0).getReg(), MI.getOperand(2).getReg());
-      ToErase.push_back(&MI);
+      if (isSpvIntrinsic(MI, Intrinsic::spv_bitcast)) {
+        assert(MI.getOperand(2).isReg());
+        MIB.setInsertPt(*MI.getParent(), MI);
+        MIB.buildBitcast(MI.getOperand(0).getReg(), MI.getOperand(2).getReg());
+        ToErase.push_back(&MI);
+      } else if (isSpvIntrinsic(MI, Intrinsic::spv_ptrcast)) {
+        assert(MI.getOperand(2).isReg());
+        MIB.setInsertPt(*MI.getParent(), MI);
+        Register Def = MI.getOperand(0).getReg();
+        Register Source = MI.getOperand(2).getReg();
+        SPIRVType *BaseTy = GR->getOrCreateSPIRVType(
+            getMDOperandAsType(MI.getOperand(3).getMetadata(), 0), MIB);
+        SPIRVType *AssignedPtrType = GR->getOrCreateSPIRVPointerType(
+            BaseTy, MI, *MF.getSubtarget<SPIRVSubtarget>().getInstrInfo(),
+            addressSpaceToStorageClass(MI.getOperand(4).getImm()));
+
+        // If the bitcast would be redundant, replace all uses with the source
+        // register.
+        if (GR->getSPIRVTypeForVReg(Source) == AssignedPtrType) {
+          MIB.getMRI()->replaceRegWith(Def, Source);
+        } else {
+          GR->assignSPIRVTypeToVReg(AssignedPtrType, Def, MF);
+          MIB.buildBitcast(Def, Source);
+        }
+        ToErase.push_back(&MI);
+      }
     }
   }
   for (MachineInstr *MI : ToErase)
diff --git a/llvm/test/CodeGen/SPIRV/AtomicCompareExchange.ll b/llvm/test/CodeGen/SPIRV/AtomicCompareExchange.ll
index 8d12414c66a8f8..323afec7f35f87 100644
--- a/llvm/test/CodeGen/SPIRV/AtomicCompareExchange.ll
+++ b/llvm/test/CodeGen/SPIRV/AtomicCompareExchange.ll
@@ -10,47 +10,40 @@
 ; CHECK-SPIRV-DAG:  %[[#Struct:]] = OpTypeStruct %[[#Int]] %[[#Bool]]
 ; CHECK-SPIRV-DAG:  %[[#UndefStruct:]] = OpUndef %[[#Struct]]
 
-; CHECK-SPIRV:      %[[#Pointer:]] = OpFunctionParameter %[[#]]
-; CHECK-SPIRV:      %[[#Value_ptr:]] = OpFunctionParameter %[[#]]
-; CHECK-SPIRV:      %[[#Comparator:]] = OpFunctionParameter %[[#]]
-
-; CHECK-SPIRV:      %[[#Value:]] = OpLoad %[[#Int]] %[[#Value_ptr]]
-; CHECK-SPIRV:      %[[#Res:]] = OpAtomicCompareExchange %[[#Int]] %[[#Pointer]] %[[#MemScope_Device]]
-; CHECK-SPIRV-SAME: %[[#MemSemEqual_SeqCst]] %[[#MemSemUnequal_Acquire]] %[[#Value]] %[[#Comparator]]
+; CHECK-SPIRV:      %[[#Value:]] = OpLoad %[[#Int]] %[[#Value_ptr:]]
+; CHECK-SPIRV:      %[[#Res:]] = OpAtomicCompareExchange %[[#Int]] %[[#Pointer:]] %[[#MemScope_Device]]
+; CHECK-SPIRV-SAME: %[[#MemSemEqual_SeqCst]] %[[#MemSemUnequal_Acquire]] %[[#Value]] %[[#Comparator:]]
 ; CHECK-SPIRV:      %[[#Success:]] = OpIEqual %[[#]] %[[#Res]] %[[#Comparator]]
 ; CHECK-SPIRV:      %[[#Composite_0:]] = OpCompositeInsert %[[#Struct]] %[[#Res]] %[[#UndefStruct]] 0
 ; CHECK-SPIRV:      %[[#Composite_1:]] = OpCompositeInsert %[[#Struct]] %[[#Success]] %[[#Composite_0]] 1
 ; CHECK-SPIRV:      %[[#]] = OpCompositeExtract %[[#Bool]] %[[#Composite_1]] 1
 
-define dso_local spir_func void @test(i32* %ptr, i32* %value_ptr, i32 %comparator) local_unnamed_addr {
+define dso_local spir_func void @test(ptr %ptr, ptr %value_ptr, i32 %comparator) local_unnamed_addr {
 entry:
-  %0 = load i32, i32* %value_ptr, align 4
-  %1 = cmpxchg i32* %ptr, i32 %comparator, i32 %0 seq_cst acquire
+  %0 = load i32, ptr %value_ptr, align 4
+  %1 = cmpxchg ptr %ptr, i32 %comparator, i32 %0 seq_cst acquire
   %2 = extractvalue { i32, i1 } %1, 1
   br i1 %2, label %cmpxchg.continue, label %cmpxchg.store_expected
 
 cmpxchg.store_expected:                           ; preds = %entry
   %3 = extractvalue { i32, i1 } %1, 0
-  store i32 %3, i32* %value_ptr, align 4
+  store i32 %3, ptr %value_ptr, align 4
   br label %cmpxchg.continue
 
 cmpxchg.continue:                                 ; preds = %cmpxchg.store_expected, %entry
   ret void
 }
 
-; CHECK-SPIRV:      %[[#Ptr:]] = OpFunctionParameter %[[#]]
-; CHECK-SPIRV:      %[[#Store_ptr:]] = OpFunctionParameter %[[#]]
-
-; CHECK-SPIRV:      %[[#Res_1:]] = OpAtomicCompareExchange %[[#Int]] %[[#Ptr]] %[[#MemScope_Device]]
+; CHECK-SPIRV:      %[[#Res_1:]] = OpAtomicCompareExchange %[[#Int]] %[[#Ptr:]] %[[#MemScope_Device]]
 ; CHECK-SPIRV-SAME: %[[#MemSemEqual_SeqCst]] %[[#MemSemUnequal_Acquire]] %[[#Constant_456]] %[[#Constant_128]]
 ; CHECK-SPIRV:      %[[#Success_1:]] = OpIEqual %[[#]] %[[#Res_1]] %[[#Constant_128]]
 ; CHECK-SPIRV:      %[[#Composite:]] = OpCompositeInsert %[[#Struct]] %[[#Res_1]] %[[#UndefStruct]] 0
 ; CHECK-SPIRV:      %[[#Composite_1:]] = OpCompositeInsert %[[#Struct]] %[[#Success_1]] %[[#Composite]] 1
-; CHECK-SPIRV:      OpStore %[[#Store_ptr]] %[[#Composite_1]]
+; CHECK-SPIRV:      OpStore %[[#Store_ptr:]] %[[#Composite_1]]
 
-define dso_local spir_func void @test2(i32* %ptr, {i32, i1}* %store_ptr) local_unnamed_addr {
+define dso_local spir_func void @test2(ptr %ptr, ptr %store_ptr) local_unnamed_addr {
 entry:
-  %0 = cmpxchg i32* %ptr, i32 128, i32 456 seq_cst acquire
-  store { i32, i1 } %0, { i32, i1 }* %store_ptr, align 4
+  %0 = cmpxchg ptr %ptr, i32 128, i32 456 seq_cst acquire
+  store { i32, i1 } %0, ptr %store_ptr, align 4
   ret void
 }
diff --git a/llvm/test/CodeGen/SPIRV/function/alloca-load-store.ll b/llvm/test/CodeGen/SPIRV/function/alloca-load-store.ll
index 5e76eb11de633d..c64a708b28ebe4 100644
--- a/llvm/test/CodeGen/SPIRV/function/alloca-load-store.ll
+++ b/llvm/test/CodeGen/SPIRV/function/alloca-load-store.ll
@@ -1,17 +1,16 @@
 ; RUN: llc -O0 -mtriple=spirv32-unknown-unknown %s -o - | FileCheck %s
 
-target triple = "spirv32-unknown-unknown"
-
 ; CHECK-DAG: OpName %[[#BAR:]] "bar"
 ; CHECK-DAG: OpName %[[#FOO:]] "foo"
 ; CHECK-DAG: OpName %[[#GOO:]] "goo"
 
 ; CHECK-DAG: %[[#CHAR:]] = OpTypeInt 8
 ; CHECK-DAG: %[[#INT:]] = OpTypeInt 32
-; CHECK-DAG: %[[#STACK_PTR:]] = OpTypePointer Function %[[#INT]]
-; CHECK-DAG: %[[#GLOBAL_PTR:]] = OpTypePointer CrossWorkgroup %[[#CHAR]]
+; CHECK-DAG: %[[#STACK_PTR_INT:]] = OpTypePointer Function %[[#INT]]
+; CHECK-DAG: %[[#GLOBAL_PTR_INT:]] = OpTypePointer CrossWorkgroup %[[#INT]]
+; CHECK-DAG: %[[#GLOBAL_PTR_CHAR:]] = OpTypePointer CrossWorkgroup %[[#CHAR]]
 ; CHECK-DAG: %[[#FN1:]] = OpTypeFunction %[[#INT]] %[[#INT]]
-; CHECK-DAG: %[[#FN2:]] = OpTypeFunction %[[#INT]] %[[#INT]] %[[#GLOBAL_PTR]]
+; CHECK-DAG: %[[#FN2:]] = OpTypeFunction %[[#INT]] %[[#INT]] %[[#GLOBAL_PTR_CHAR]]
 
 define i32 @bar(i32 %a) {
   %p = alloca i32
@@ -23,7 +22,7 @@ define i32 @bar(i32 %a) {
 ; CHECK: %[[#BAR]] = OpFunction %[[#INT]] None %[[#FN1]]
 ; CHECK: %[[#A:]] = OpFunctionParameter %[[#INT]]
 ; CHECK: OpLabel
-; CHECK: %[[#P:]] = OpVariable %[[#STACK_PTR]] Function
+; CHECK: %[[#P:]] = OpVariable %[[#STACK_PTR_INT]] Function
 ; CHECK: OpStore %[[#P]] %[[#A]]
 ; CHECK: %[[#B:]] = OpLoad %[[#INT]] %[[#P]]
 ; CHECK: OpReturnValue %[[#B]]
@@ -40,7 +39,7 @@ define i32 @foo(i32 %a) {
 ; CHECK: %[[#FOO]] = OpFunction %[[#INT]] None %[[#FN1]]
 ; CHECK: %[[#A:]] = OpFunctionParameter %[[#INT]]
 ; CHECK: OpLabel
-; CHECK: %[[#P:]] = OpVariable %[[#STACK_PTR]] Function
+; CHECK: %[[#P:]] = OpVariable %[[#STACK_PTR_INT]] Function
 ; CHECK: OpStore %[[#P]] %[[#A]] Volatile
 ; CHECK: %[[#B:]] = OpLoad %[[#INT]] %[[#P]] Volatile
 ; CHECK: OpReturnValue %[[#B]]
@@ -48,7 +47,7 @@ define i32 @foo(i32 %a) {
 
 
 ;; Test load and store in global address space.
-define i32 @goo(i32 %a, i32 addrspace(1)* %p) {
+define i32 @goo(i32 %a, ptr addrspace(1) %p) {
   store i32 %a, i32 addrspace(1)* %p
   %b = load i32, i32 addrspace(1)* %p
   ret i32 %b
@@ -56,9 +55,10 @@ define i32 @goo(i32 %a, i32 addrspace(1)* %p) {
 
 ; CHECK: %[[#GOO]] = OpFunction %[[#INT]] None %[[#FN2]]
 ; CHECK: %[[#A:]] = OpFunctionParameter %[[#INT]]
-; CHECK: %[[#P:]] = OpFunctionParameter %[[#GLOBAL_PTR]]
+; CHECK: %[[#P:]] = OpFunctionParameter %[[#GLOBAL_PTR_CHAR]]
 ; CHECK: OpLabel
-; CHECK: OpStore %[[#P]] %[[#A]]
-; CHECK: %[[#B:]] = OpLoad %[[#INT]] %[[#P]]
+; CHECK: %[[#C:]] = OpBitcast %[[#GLOBAL_PTR_INT]] %[[#P]]
+; CHECK: OpStore %[[#C]] %[[#A]]
+; CHECK: %[[#B:]] = OpLoad %[[#INT]] %[[#C]]
 ; CHECK: OpReturnValue %[[#B]]
 ; CHECK: OpFunctionEnd
diff --git a/llvm/test/CodeGen/SPIRV/instructions/undef-nested-composite-store.ll b/llvm/test/CodeGen/SPIRV/instructions/undef-nested-composite-store.ll
index 9fa94b8484631c..5fa4a7a93ee0b9 100644
--- a/llvm/test/CodeGen/SPIRV/instructions/undef-nested-composite-store.ll
+++ b/llvm/test/CodeGen/SPIRV/instructions/undef-nested-composite-store.ll
@@ -9,7 +9,8 @@
 ; CHECK: %[[#]] = OpFunction %[[#]] None %[[#]]
 ; CHECK-NEXT: %[[#PTR:]] = OpFunctionParameter %[[#]]
 ; CHECK-NEXT: %[[#]] = OpLabel
-; CHECK-NEXT: OpStore %[[#PTR]] %[[#UNDEF]] Aligned 4
+; CHECK-NEXT: %[[#BC:]] = OpBitcast %[[#]] %[[#PTR]]
+; CHECK-NEXT: OpStore %[[#BC]] %[[#UNDEF]] Aligned 4
 ; CHECK-NEXT: OpReturn
 ; CHECK-NEXT: OpFunctionEnd
 
diff --git a/llvm/test/CodeGen/SPIRV/instructions/undef-simple-composite-store.ll b/llvm/test/CodeGen/SPIRV/instructions/undef-simple-composite-store.ll
index 6a274732417d4d..24dad10382ada9 100644
--- a/llvm/test/CodeGen/SPIRV/instructions/undef-simple-composite-store.ll
+++ b/llvm/test/CodeGen/SPIRV/instructions/undef-simple-composite-store.ll
@@ -8,7 +8,8 @@
 ; CHECK: %[[#]] = OpFunction %[[#]] None %[[#]]
 ; CHECK-NEXT: %[[#PTR:]] = OpFunctionParameter %[[#]]
 ; CHECK-NEXT: %[[#]] = OpLabel
-; CHECK-NEXT: OpStore %[[#PTR]] %[[#UNDEF]] Aligned 4
+; CHECK-NEXT: %[[#BC:]] = OpBitcast %[[#]] %[[#PTR]]
+; CHECK-NEXT: OpStore %[[#BC]] %[[#UNDEF]] Aligned 4
 ; CHECK-NEXT: OpReturn
 ; CHECK-NEXT: OpFunctionEnd
 
diff --git a/llvm/test/CodeGen/SPIRV/llvm-intrinsics/memset.ll b/llvm/test/CodeGen/SPIRV/llvm-intrinsics/memset.ll
index 3d7d9fbf907598..e7a986980f250e 100644
--- a/llvm/test/CodeGen/SPIRV/llvm-intrinsics/memset.ll
+++ b/llvm/test/CodeGen/SPIRV/llvm-intrinsics/memset.ll
@@ -25,9 +25,7 @@
 ; CHECK: %[[#VarNull:]] = OpVariable %[[#]] UniformConstant %[[#ConstNull]]
 
 ; CHECK-DAG: %[[#Int8PtrConst:]] = OpTypePointer UniformConstant %[[#Int8]]
-; CHECK: %[[#Target:]] = OpBitcast %[[#Int8Ptr]] %[[#]]
-; CHECK: %[[#Source:]] = OpBitcast %[[#Int8PtrConst]] %[[#VarNull]]
-; CHECK: OpCopyMemorySized %[[#Target]] %[[#Source]] %[[#Const12]] Aligned 4
+; CHECK: OpCopyMemorySized %[[#Target:]] %[[#Source:]] %[[#Const12]] Aligned 4
 
 ; CHECK: %[[#SourceComp:]] = OpBitcast %[[#Int8PtrConst]] %[[#VarComp]]
 ; CHECK: OpCopyMemorySized %[[#]] %[[#SourceComp]] %[[#Const4]] Aligned 4
diff --git a/llvm/test/CodeGen/SPIRV/opaque_pointers.ll b/llvm/test/CodeGen/SPIRV/opaque_pointers.ll
index aaddea1372721b..30c9d8dc774e24 100644
--- a/llvm/test/CodeGen/SPIRV/opaque_pointers.ll
+++ b/llvm/test/CodeGen/SPIRV/opaque_pointers.ll
@@ -1,19 +1,23 @@
 ; RUN: llc -O0 -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s --check-prefix=CHECK
 
 ; CHECK-DAG: %[[#Int8Ty:]] = OpTypeInt 8 0
-; CHECK-DAG: %[[#PtrTy:]] = OpTypePointer Function %[[#Int8Ty]]
-; CHECK-DAG: %[[#Int64Ty:]] = OpTypeInt 64 0
-; CHECK-DAG: %[[#FTy:]] = OpTypeFunction %[[#Int64Ty]] %[[#PtrTy]]
+; CHECK-DAG: %[[#PtrInt8Ty:]] = OpTypePointer Function %[[#Int8Ty]]
 ; CHECK-DAG: %[[#Int32Ty:]] = OpTypeInt 32 0
+; CHECK-DAG: %[[#PtrInt32Ty:]] = OpTypePointer Function %[[#Int32Ty]]
+; CHECK-DAG: %[[#Int64Ty:]] = OpTypeInt 64 0
+; CHECK-DAG: %[[#PtrInt64Ty:]] = OpTypePointer Function %[[#Int64Ty]]
+; CHECK-DAG: %[[#FTy:]] = OpTypeFunction %[[#Int64Ty]] %[[#PtrInt8Ty]]
 ; CHECK-DAG: %[[#Const:]] = OpConstant %[[#Int32Ty]] 0
 ; CHECK: OpFunction %[[#Int64Ty]] None %[[#FTy]]
-; CHECK: %[[#Parm:]] = OpFunctionParameter %[[#PtrTy]]
-; CHECK: OpStore %[[#Parm]] %[[#Const]] Aligned 4
-; CHECK: %[[#Res:]] = OpLoad %[[#Int64Ty]] %[[#Parm]] Aligned 8
+; CHECK: %[[#Parm:]] = OpFunctionParameter %[[#PtrInt8Ty]]
+; CHECK-DAG: %[[#Bitcast1:]] = OpBitcast %[[#PtrInt32Ty]] %[[#Parm]]
+; CHECK: OpStore %[[#Bitcast1]] %[[#Const]] Aligned 4
+; CHECK-DAG: %[[#Bitcast2:]] = OpBitcast %[[#PtrInt64Ty]] %[[#Parm]]
+; CHECK: %[[#Res:]] = OpLoad %[[#Int64Ty]] %[[#Bitcast2]] Aligned 4
 ; CHECK: OpReturnValue %[[#Res]]
 
 define i64 @test(ptr %p) {
-  store i32 0, ptr %p
-  %v = load i64, ptr %p
+  store i32 0, ptr %p, align 4
+  %v = load i64, ptr %p, align 4
   ret i64 %v
 }
diff --git a/llvm/test/CodeGen/SPIRV/opencl/basic/get_global_offset.ll b/llvm/test/CodeGen/SPIRV/opencl/basic/get_global_offset.ll
index 127804671cee47..43d6238360f6fc 100644
--- a/llvm/test/CodeGen/SPIRV/opencl/basic/get_global_offset.ll
+++ b/llvm/test/CodeGen/SPIRV/opencl/basic/get_global_offset.ll
@@ -1,10 +1,7 @@
 ; RUN: llc -O0 -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s
 
 ; CHECK: OpEntryPoint Kernel %[[#test_func:]] "test"
-; CHECK: OpName %[[#outOffsets:]] "outOffsets"
-; CHECK: OpName %[[#test_func]] "test"
-; CHECK: OpName %[[#f2_decl:]] "BuiltInGlobalOffset"
-; CHECK: OpDecorate %[[#f2_decl]] LinkageAttributes "BuiltInGlobalOffset" Import
+; CHECK: OpDecorate %[[#f2_decl:]] LinkageAttributes "BuiltInGlobalOffset" Import
 ; CHECK: %[[#int_ty:]] = OpTypeInt 8 0
 ; CHECK: %[[#void_ty:]] = OpTypeVoid
 ; CHECK: %[[#iptr_ty:]] = OpTypePointer CrossWorkgroup  %[[#int_ty]]
@@ -26,14 +23,13 @@
 ; CHECK-NOT: %[[#vec_ty]] = OpFunction
 ; CHECK-NOT: %[[#func2_ty]] = OpFunction
 ; CHECK-NOT: %[[#f2_decl]] = OpFunction
-; CHECK: %[[#outOffsets]] = OpFunctionParameter %[[#iptr_ty]]
 
 define spir_kernel void @test(i32 addrspace(1)* %outOffsets) {
 entry:
   %0 = call spir_func <3 x i64> @BuiltInGlobalOffset() #1
   %call = extractelement <3 x i64> %0, i32 0
   %conv = trunc i64 %call to i32
-; CHECK: %[[#i1:]] = OpInBoundsPtrAccessChain %[[#i32ptr_ty]] %[[#outOffsets]]
+; CHECK: %[[#i1:]] = OpInBoundsPtrAccessChain %[[#i32ptr_ty]] %[[#outOffsets:]]
 ; CHECK: OpStore %[[#i1:]] %[[#]] Aligned 4
   %arrayidx = getelementptr inbounds i32, i32 addrspace(1)* %outOffsets, i64 0
   store i32 %conv, i32 addrspace(1)* %arrayidx, align 4
diff --git a/llvm/test/CodeGen/SPIRV/pointers/two-bitcast-users.ll b/llvm/test/CodeGen/SPIRV/pointers/two-bitcast-users.ll
new file mode 100644
index 00000000000000..f4ea710fa04317
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/pointers/two-bitcast-users.ll
@@ -0,0 +1,19 @@
+; RUN: llc -O0 -mtriple=spirv32-unknown-unknown %s -o - | FileCheck %s
+
+; CHECK-DAG: %[[#CHAR:]] = OpTypeInt 8
+; CHECK-DAG: %[[#INT:]] = OpTypeInt 32
+; CHECK-DAG: %[[#GLOBAL_PTR_INT:]] = OpTypePointer CrossWorkgroup %[[#INT]]
+; CHECK-DAG: %[[#GLOBAL_PTR_CHAR:]] = OpTypePointer CrossWorkgroup %[[#CHAR]]
+
+define i32 @foo(i32 %a, ptr addrspace(1) %p) {
+  store i32 %a, i32 addrspace(1)* %p
+  %b = load i32, i32 addrspace(1)* %p
+  ret i32 %b
+}
+
+; CHECK: %[[#A:]] = OpFunctionParameter %[[#INT]]
+; CHECK: %[[#P:]] = OpFunctionParameter %[[#GLOBAL_PTR_CHAR]]
+; CHECK: %[[#C:]] = OpBitcast %[[#GLOBAL_PTR_INT]] %[[#P]]
+; CHECK: OpStore %[[#C]] %[[#A]]
+; CHECK: %[[#B:]] = OpLoad %[[#INT]] %[[#C]]
+; CHECK-NOT: %[[#B:]] = OpLoad %[[#INT]] %[[#P]]
diff --git a/llvm/test/CodeGen/SPIRV/pointers/two-subsequent-bitcasts.ll b/llvm/test/CodeGen/SPIRV/pointers/two-subsequent-bitcasts.ll
new file mode 100644
index 00000000000000..8998329ea64fe2
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/pointers/two-subsequent-bitcasts.ll
@@ -0,0 +1,17 @@
+; RUN: llc -O0 -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s
+
+; CHECK-DAG: %[[#float:]] = OpTypeFloat 32
+; CHECK-DAG: %[[#pointer:]] = OpTypePointer CrossWorkgroup %[[#float]]
+; CHECK: %[[#A:]] = OpFunctionParameter %[[#]]
+
+define void @foo(float addrspace(1)* %A, i32 %B) {
+  %cmp = icmp sgt i32 %B, 0
+  %conv = uitofp i1 %cmp to float
+; CHECK: %[[#utof_res:]] = OpConvertUToF %[[#float]] %[[#]]
+; CHECK: %[[#bitcast:]] = OpBitcast %[[#pointer]] %[[#A]]
+; CHECK: OpStore %[[#bitcast]] %[[#utof_res]]
+  %BC1 = bitcast float addrspace(1)* %A to i32 addrspace(1)*
+  %BC2 = bitcast i32 addrspace(1)* %BC1 to float addrspace(1)*
+  store float %conv, float addrspace(1)* %BC2, align 4;
+  ret void
+}
diff --git a/llvm/test/CodeGen/SPIRV/sitofp-with-bool.ll b/llvm/test/CodeGen/SPIRV/sitofp-with-bool.ll
index 4dda0aadced49b..06f27e2cb1f906 100644
--- a/llvm/test/CodeGen/SPIRV/sitofp-with-bool.ll
+++ b/llvm/test/CodeGen/SPIRV/sitofp-with-bool.ll
@@ -1,9 +1,11 @@
 ; RUN: llc -O0 -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s
 
-; CHECK: %[[#int_32:]] = OpTypeInt 32 0
-; CHECK: %[[#bool:]] = OpTypeBool
-; CHECK: %[[#zero:]] = OpConstant %[[#int_32]] 0
-; CHECK: %[[#one:]] = OpConstant %[[#int_32]] 1
+; CHECK-DAG: %[[#int_32:]] = OpTypeInt 32 0
+; CHECK-DAG: %[[#float:]] = OpTypeFloat 32
+; CHECK-DAG: %[[#bool:]] = OpTypeBool
+; CHECK-DAG: %[[#zero:]] = OpConstant %[[#int_32]] 0
+; CHECK-DAG: %[[#one:]] = OpConstant %[[#int_32]] 1
+; CHECK-DAG: %[[#ptr:]] = OpTypePointer CrossWorkgroup %[[#float]]
 
 ; CHECK: OpFunction
 ; CHECK: %[[#A:]] = OpFunctionParameter %[[#]]
@@ -11,9 +13,10 @@
 ; CHECK: %[[#cmp_res:]] = OpSGreaterThan %[[#bool]] %[[#B]] %[[#zero]]
 ; CHECK: %[[#select_res:]] = OpSelect %[[#int_32]] %[[#cmp_res]] %[[#one]] %[[#zero]]
 ; CHECK: %[[#stof_res:]] = OpConvertSToF %[[#]] %[[#select_res]]
-; CHECK: OpStore %[[#A]] %[[#stof_res]]
+; CHECK: %[[#bitcast:]] = OpBitcast %[[#ptr]] %[[#A]]
+; CHECK: OpStore %[[#bitcast]] %[[#stof_res]]
 
-define dso_local spir_kernel void @K(float addrspace(1)* nocapture %A, i32 %B) local_unnamed_addr {
+define dso_local spir_kernel void @K(ptr addrspace(1) nocapture %A, i32 %B) local_unnamed_addr {
 entry:
   %cmp = icmp sgt i32 %B, 0
   %conv = sitofp i1 %cmp to float
diff --git a/llvm/test/CodeGen/SPIRV/transcoding/OpPhi_ArgumentsPlaceholders.ll b/llvm/test/CodeGen/SPIRV/transcoding/OpPhi_ArgumentsPlaceholders.ll
index 9252e264cec8e3..c98fef3631e04b 100644
--- a/llvm/test/CodeGen/SPIRV/transcoding/OpPhi_ArgumentsPlaceholders.ll
+++ b/llvm/test/CodeGen/SPIRV/transcoding/OpPhi_ArgumentsPlaceholders.ll
@@ -13,6 +13,7 @@
 ;; }
 
 ; RUN: llc -O0 -mtriple=spirv32-unknown-unknown %s -o - | FileCheck %s --check-prefix=CHECK-SPIRV
+; XFAIL: *
 
 %struct.Node = type { %struct.Node.0 addrspace(1)* }
 %struct.Node.0 = type opaque
diff --git a/llvm/test/CodeGen/SPIRV/transcoding/spec_const.ll b/llvm/test/CodeGen/SPIRV/transcoding/spec_const.ll
index 9fd74608852411..c47dccb35e14d5 100644
--- a/llvm/test/CodeGen/SPIRV/transcoding/spec_const.ll
+++ b/llvm/test/CodeGen/SPIRV/transcoding/spec_const.ll
@@ -1,4 +1,5 @@
 ; RUN: llc -O0 -mtriple=spirv32-unknown-unknown %s -o - | FileCheck %s --check-prefix=CHECK-SPIRV
+; XFAIL: *
 
 ; CHECK-SPIRV-NOT: OpCapability Matrix
 ; CHECK-SPIRV-NOT: OpCapability Shader
diff --git a/llvm/test/CodeGen/SPIRV/transcoding/spirv-private-array-initialization.ll b/llvm/test/CodeGen/SPIRV/transcoding/spirv-private-array-initialization.ll
index 3c45fdd0481dcc..a07af76c223240 100644
--- a/llvm/test/CodeGen/SPIRV/transcoding/spirv-private-array-initialization.ll
+++ b/llvm/test/CodeGen/SPIRV/transcoding/spirv-private-array-initialization.ll
@@ -19,10 +19,8 @@
 
 ; CHECK-SPIRV:     %[[#arr:]] = OpVariable %[[#i32x3_ptr]] Function
 ; CHECK-SPIRV:     %[[#arr2:]] = OpVariable %[[#i32x3_ptr]] Function
-; CHECK-SPIRV:     %[[#arr_i8_ptr:]] = OpBitcast %[[#i8_ptr]] %[[#arr]]
-; CHECK-SPIRV:     OpCopyMemorySized %[[#arr_i8_ptr]] %[[#test_arr]] %[[#twelve]] Aligned 4
-; CHECK-SPIRV:     %[[#arr2_i8_ptr:]] = OpBitcast %[[#i8_ptr]] %[[#arr2]]
-; CHECK-SPIRV:     OpCopyMemorySized %[[#arr2_i8_ptr]] %[[#test_arr2]] %[[#twelve]] Aligned 4
+; CHECK-SPIRV:     OpCopyMemorySized %[[#arr]] %[[#test_arr]] %[[#twelve]] Aligned 4
+; CHECK-SPIRV:     OpCopyMemorySized %[[#arr2]] %[[#test_arr2]] %[[#twelve]] Aligned 4
 
 
 @__const.test.arr = private unnamed_addr addrspace(2) constant [3 x i32] [i32 1, i32 2, i32 3], align 4
diff --git a/llvm/test/CodeGen/SPIRV/uitofp-with-bool.ll b/llvm/test/CodeGen/SPIRV/uitofp-with-bool.ll
index 2fe0dc91e7b4ca..8a3c2853d99149 100644
--- a/llvm/test/CodeGen/SPIRV/uitofp-with-bool.ll
+++ b/llvm/test/CodeGen/SPIRV/uitofp-with-bool.ll
@@ -66,6 +66,7 @@
 ; SPV-DAG: %[[#ones_16:]] = OpConstantComposite %[[#vec_16]] %[[#one_16]] %[[#one_16]]
 ; SPV-DAG: %[[#ones_32:]] = OpConstantComposite %[[#vec_32]] %[[#one_32]] %[[#one_32]]
 ; SPV-DAG: %[[#ones_64:]] = OpConstantComposite %[[#vec_64]] %[[#one_64]] %[[#one_64]]
+; SPV-DAG: %[[#pointer:]] = OpTypePointer CrossWorkgroup %[[#float]]
 
 ; SPV-DAG: OpFunction
 ; SPV-DAG: %[[#A:]] = OpFunctionParameter %[[#]]
@@ -81,7 +82,8 @@ entry:
 ; SPV-DAG: %[[#select_res:]] = OpSelect %[[#int_32]] %[[#cmp_res]] %[[#one_32]] %[[#zero_32]]
 ; SPV-DAG: %[[#utof_res:]] = OpConvertUToF %[[#float]] %[[#select_res]]
   %conv = uitofp i1 %cmp to float
-; SPV-DAG: OpStore %[[#A]] %[[#utof_res]]
+; SPV-DAG: %[[#bitcast:]] = OpBitcast %[[#pointer]] %[[#A]]
+; SPV-DAG: OpStore %[[#bitcast]] %[[#utof_res]]
   store float %conv, float addrspace(1)* %A, align 4;
 
 ; SPV-DAG: %[[#s1]] = OpSelect %[[#int_8]] %[[#i1s]] %[[#mone_8]] %[[#zero_8]]



More information about the llvm-commits mailing list