[llvm] b8435e3 - [SPIR-V] Emit spv_undef intrinsic for aggregate undef operands

Michal Paszkowski via llvm-commits llvm-commits at lists.llvm.org
Tue Feb 21 12:47:30 PST 2023


Author: Michal Paszkowski
Date: 2023-02-21T21:17:33+01:00
New Revision: b8435e392cc82639c3c5e9adff078063ac76c27d

URL: https://github.com/llvm/llvm-project/commit/b8435e392cc82639c3c5e9adff078063ac76c27d
DIFF: https://github.com/llvm/llvm-project/commit/b8435e392cc82639c3c5e9adff078063ac76c27d.diff

LOG: [SPIR-V] Emit spv_undef intrinsic for aggregate undef operands

This change adds a new spv_undef intrinsic which is emitted in place of
aggregate undef operands and later selected to single OpUndef SPIR-V
instruction. The behavior matches that of Khronos SPIR-V Translator and
should support nested aggregates.

Differential Revision: https://reviews.llvm.org/D143107

Added: 
    llvm/test/CodeGen/SPIRV/instructions/undef-nested-composite-store.ll
    llvm/test/CodeGen/SPIRV/instructions/undef-simple-composite-store.ll

Modified: 
    llvm/include/llvm/IR/IntrinsicsSPIRV.td
    llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp
    llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/IR/IntrinsicsSPIRV.td b/llvm/include/llvm/IR/IntrinsicsSPIRV.td
index bf90aa0c0402..2b8602f430df 100644
--- a/llvm/include/llvm/IR/IntrinsicsSPIRV.td
+++ b/llvm/include/llvm/IR/IntrinsicsSPIRV.td
@@ -31,4 +31,5 @@ let TargetPrefix = "spv" in {
   def int_spv_cmpxchg : Intrinsic<[llvm_i32_ty], [llvm_any_ty, llvm_vararg_ty]>;
   def int_spv_unreachable : Intrinsic<[], []>;
   def int_spv_alloca : Intrinsic<[llvm_any_ty], []>;
+  def int_spv_undef : Intrinsic<[llvm_i32_ty], []>;
 }

diff  --git a/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp b/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp
index f91b6ea5cb14..4e8afbe2e77e 100644
--- a/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp
@@ -56,6 +56,7 @@ class SPIRVEmitIntrinsics
   DenseMap<Instruction *, Constant *> AggrConsts;
   DenseSet<Instruction *> AggrStores;
   void preprocessCompositeConstants();
+  void preprocessUndefs();
   CallInst *buildIntrWithMD(Intrinsic::ID IntrID, ArrayRef<Type *> Types,
                             Value *Arg, Value *Arg2) {
     ConstantAsMetadata *CM = ValueAsMetadata::getConstant(Arg);
@@ -151,6 +152,29 @@ void SPIRVEmitIntrinsics::replaceMemInstrUses(Instruction *Old,
   Old->eraseFromParent();
 }
 
+void SPIRVEmitIntrinsics::preprocessUndefs() {
+  std::queue<Instruction *> Worklist;
+  for (auto &I : instructions(F))
+    Worklist.push(&I);
+
+  while (!Worklist.empty()) {
+    Instruction *I = Worklist.front();
+    Worklist.pop();
+
+    for (auto &Op : I->operands()) {
+      auto *AggrUndef = dyn_cast<UndefValue>(Op);
+      if (!AggrUndef || !Op->getType()->isAggregateType())
+        continue;
+
+      IRB->SetInsertPoint(I);
+      auto *IntrUndef = IRB->CreateIntrinsic(Intrinsic::spv_undef, {}, {});
+      Worklist.push(IntrUndef);
+      I->replaceUsesOfWith(Op, IntrUndef);
+      AggrConsts[IntrUndef] = AggrUndef;
+    }
+  }
+}
+
 void SPIRVEmitIntrinsics::preprocessCompositeConstants() {
   std::queue<Instruction *> Worklist;
   for (auto &I : instructions(F))
@@ -369,7 +393,8 @@ void SPIRVEmitIntrinsics::insertAssignTypeIntrs(Instruction *I) {
     setInsertPointSkippingPhis(*IRB, I->getNextNode());
     Type *TypeToAssign = Ty;
     if (auto *II = dyn_cast<IntrinsicInst>(I)) {
-      if (II->getIntrinsicID() == Intrinsic::spv_const_composite) {
+      if (II->getIntrinsicID() == Intrinsic::spv_const_composite ||
+          II->getIntrinsicID() == Intrinsic::spv_undef) {
         auto t = AggrConsts.find(II);
         assert(t != AggrConsts.end());
         TypeToAssign = t->second->getType();
@@ -453,6 +478,7 @@ bool SPIRVEmitIntrinsics::runOnFunction(Function &Func) {
   for (auto &GV : Func.getParent()->globals())
     processGlobalValue(GV);
 
+  preprocessUndefs();
   preprocessCompositeConstants();
   SmallVector<Instruction *> Worklist;
   for (auto &I : instructions(Func))

diff  --git a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
index 5ebec6b8fa13..f48b7032ba4f 100644
--- a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
@@ -1316,25 +1316,18 @@ bool SPIRVInstructionSelector::selectIntrinsic(Register ResVReg,
   switch (I.getIntrinsicID()) {
   case Intrinsic::spv_load:
     return selectLoad(ResVReg, ResType, I);
-    break;
   case Intrinsic::spv_store:
     return selectStore(I);
-    break;
   case Intrinsic::spv_extractv:
     return selectExtractVal(ResVReg, ResType, I);
-    break;
   case Intrinsic::spv_insertv:
     return selectInsertVal(ResVReg, ResType, I);
-    break;
   case Intrinsic::spv_extractelt:
     return selectExtractElt(ResVReg, ResType, I);
-    break;
   case Intrinsic::spv_insertelt:
     return selectInsertElt(ResVReg, ResType, I);
-    break;
   case Intrinsic::spv_gep:
     return selectGEP(ResVReg, ResType, I);
-    break;
   case Intrinsic::spv_unref_global:
   case Intrinsic::spv_init_global: {
     MachineInstr *MI = MRI->getVRegDef(I.getOperand(1).getReg());
@@ -1343,7 +1336,13 @@ bool SPIRVInstructionSelector::selectIntrinsic(Register ResVReg,
                              : nullptr;
     assert(MI);
     return selectGlobalValue(MI->getOperand(0).getReg(), *MI, Init);
-  } break;
+  }
+  case Intrinsic::spv_undef: {
+    auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpUndef))
+                   .addDef(ResVReg)
+                   .addUse(GR.getSPIRVTypeID(ResType));
+    return MIB.constrainAllUses(TII, TRI, RBI);
+  }
   case Intrinsic::spv_const_composite: {
     // If no values are attached, the composite is null constant.
     bool IsNull = I.getNumExplicitDefs() + 1 == I.getNumExplicitOperands();
@@ -1360,7 +1359,7 @@ bool SPIRVInstructionSelector::selectIntrinsic(Register ResVReg,
       }
     }
     return MIB.constrainAllUses(TII, TRI, RBI);
-  } break;
+  }
   case Intrinsic::spv_assign_name: {
     auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpName));
     MIB.addUse(I.getOperand(I.getNumExplicitDefs() + 1).getReg());
@@ -1369,7 +1368,7 @@ bool SPIRVInstructionSelector::selectIntrinsic(Register ResVReg,
       MIB.addImm(I.getOperand(i).getImm());
     }
     return MIB.constrainAllUses(TII, TRI, RBI);
-  } break;
+  }
   case Intrinsic::spv_switch: {
     auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpSwitch));
     for (unsigned i = 1; i < I.getNumExplicitOperands(); ++i) {
@@ -1383,16 +1382,14 @@ bool SPIRVInstructionSelector::selectIntrinsic(Register ResVReg,
         llvm_unreachable("Unexpected OpSwitch operand");
     }
     return MIB.constrainAllUses(TII, TRI, RBI);
-  } break;
+  }
   case Intrinsic::spv_cmpxchg:
     return selectAtomicCmpXchg(ResVReg, ResType, I);
-    break;
   case Intrinsic::spv_unreachable:
     BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpUnreachable));
     break;
   case Intrinsic::spv_alloca:
     return selectFrameIndex(ResVReg, ResType, I);
-    break;
   default:
     llvm_unreachable("Intrinsic selection not implemented");
   }

diff  --git a/llvm/test/CodeGen/SPIRV/instructions/undef-nested-composite-store.ll b/llvm/test/CodeGen/SPIRV/instructions/undef-nested-composite-store.ll
new file mode 100644
index 000000000000..9fa94b848463
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/instructions/undef-nested-composite-store.ll
@@ -0,0 +1,29 @@
+; RUN: llc -O0 -mtriple=spirv32-unknown-unknown %s -o - | FileCheck %s
+
+; CHECK-DAG: %[[#I32:]] = OpTypeInt 32
+; CHECK-DAG: %[[#I16:]] = OpTypeInt 16
+; CHECK-DAG: %[[#STRUCT:]] = OpTypeStruct %[[#I32]] %[[#I16]]
+; CHECK-DAG: %[[#NESTED_STRUCT:]] = OpTypeStruct %[[#STRUCT]] %[[#I16]]
+; CHECK-DAG: %[[#UNDEF:]] = OpUndef %[[#NESTED_STRUCT]]
+
+; CHECK: %[[#]] = OpFunction %[[#]] None %[[#]]
+; CHECK-NEXT: %[[#PTR:]] = OpFunctionParameter %[[#]]
+; CHECK-NEXT: %[[#]] = OpLabel
+; CHECK-NEXT: OpStore %[[#PTR]] %[[#UNDEF]] Aligned 4
+; CHECK-NEXT: OpReturn
+; CHECK-NEXT: OpFunctionEnd
+
+%struct = type {
+  i32,
+  i16
+}
+
+%nested_struct = type {
+  %struct,
+  i16
+}
+
+define void @foo(ptr %ptr) {
+  store %nested_struct undef, ptr %ptr
+  ret void
+}

diff  --git a/llvm/test/CodeGen/SPIRV/instructions/undef-simple-composite-store.ll b/llvm/test/CodeGen/SPIRV/instructions/undef-simple-composite-store.ll
new file mode 100644
index 000000000000..6a274732417d
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/instructions/undef-simple-composite-store.ll
@@ -0,0 +1,18 @@
+; RUN: llc -O0 -mtriple=spirv32-unknown-unknown %s -o - | FileCheck %s
+
+; CHECK-DAG: %[[#I32:]] = OpTypeInt 32
+; CHECK-DAG: %[[#I16:]] = OpTypeInt 16
+; CHECK-DAG: %[[#STRUCT:]] = OpTypeStruct %[[#I32]] %[[#I16]]
+; CHECK-DAG: %[[#UNDEF:]] = OpUndef %[[#STRUCT]]
+
+; CHECK: %[[#]] = OpFunction %[[#]] None %[[#]]
+; CHECK-NEXT: %[[#PTR:]] = OpFunctionParameter %[[#]]
+; CHECK-NEXT: %[[#]] = OpLabel
+; CHECK-NEXT: OpStore %[[#PTR]] %[[#UNDEF]] Aligned 4
+; CHECK-NEXT: OpReturn
+; CHECK-NEXT: OpFunctionEnd
+
+define void @foo(ptr %ptr) {
+  store { i32, i16 } undef, ptr %ptr
+  ret void
+}


        


More information about the llvm-commits mailing list