[llvm] [SPIR-V] Allow intrinsics with aggregate return type to reach GlobalISel (PR #108893)

Vyacheslav Levytskyy via llvm-commits llvm-commits at lists.llvm.org
Mon Sep 16 15:17:55 PDT 2024


https://github.com/VyacheslavLevytskyy created https://github.com/llvm/llvm-project/pull/108893

Two main goals of this PR are:
* to support "Arithmetic with Overflow" intrinsics, including the special case when those intrinsics are being generated by the CodeGenPrepare pass during translations with optimization;
* to redirect intrinsics with aggregate return type to be lowered via GlobalISel operations instead of SPIRV-specific unfolding/lowering (see https://github.com/llvm/llvm-project/pull/95012).

This PR continues a series of PRs aimed to identify and fix flaws in code emission, to improve pass rates for the mode with expensive checks set on (see https://github.com/llvm/llvm-project/pull/101732, https://github.com/llvm/llvm-project/pull/104104, https://github.com/llvm/llvm-project/pull/106966), having in mind the ultimate goal of proceeding towards the non-experimental status of SPIR-V Backend.



>From bb1ad757c940f3d5194bbd9fd32bcd54aa5f6374 Mon Sep 17 00:00:00 2001
From: "Levytskyy, Vyacheslav" <vyacheslav.levytskyy at intel.com>
Date: Mon, 16 Sep 2024 15:00:55 -0700
Subject: [PATCH] allow intrinsics with aggregate return type to reach
 GlobalISel

---
 llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp | 48 ++++++++++++++++++-
 llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp  |  3 +-
 llvm/lib/Target/SPIRV/SPIRVPreLegalizer.cpp   |  8 +++-
 .../Target/SPIRV/SPIRVPrepareFunctions.cpp    | 19 ++++++++
 4 files changed, 74 insertions(+), 4 deletions(-)

diff --git a/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp b/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp
index 4175f766ac69ad..0af656729c946f 100644
--- a/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp
@@ -188,6 +188,40 @@ bool isConvergenceIntrinsic(const Instruction *I) {
          II->getIntrinsicID() == Intrinsic::experimental_convergence_loop ||
          II->getIntrinsicID() == Intrinsic::experimental_convergence_anchor;
 }
+
+bool isInternalNonVoidIntrinsic(const Value *I) {
+  if (const auto *II = dyn_cast<IntrinsicInst>(I))
+    switch (II->getIntrinsicID()) {
+    case Intrinsic::spv_cmpxchg:
+    case Intrinsic::spv_const_composite:
+    case Intrinsic::spv_track_constant:
+    case Intrinsic::spv_load:
+    case Intrinsic::spv_extractv:
+    case Intrinsic::spv_insertv:
+    case Intrinsic::spv_extractelt:
+    case Intrinsic::spv_insertelt:
+    case Intrinsic::spv_bitcast:
+    case Intrinsic::spv_ptrcast:
+    case Intrinsic::spv_alloca:
+    case Intrinsic::spv_alloca_array:
+    case Intrinsic::spv_undef:
+      return true;
+    }
+  return false;
+}
+
+bool allowEmitFakeUse(const Value *Arg) {
+  if (isInternalNonVoidIntrinsic(Arg))
+    return false;
+  if (dyn_cast<AtomicCmpXchgInst>(Arg) || dyn_cast<InsertValueInst>(Arg) ||
+      dyn_cast<UndefValue>(Arg))
+    return false;
+  if (const auto *LI = dyn_cast<LoadInst>(Arg))
+    if (LI->getType()->isAggregateType())
+      return false;
+  return true;
+}
+
 } // namespace
 
 char SPIRVEmitIntrinsics::ID = 0;
@@ -283,8 +317,16 @@ static inline Type *reconstructType(SPIRVGlobalRegistry *GR, Value *Op) {
 void SPIRVEmitIntrinsics::buildAssignType(IRBuilder<> &B, Type *Ty,
                                           Value *Arg) {
   Value *OfType = PoisonValue::get(Ty);
-  CallInst *AssignCI = buildIntrWithMD(Intrinsic::spv_assign_type,
-                                       {Arg->getType()}, OfType, Arg, {}, B);
+  CallInst *AssignCI = nullptr;
+  if (Ty->isAggregateType() && allowEmitFakeUse(Arg)) {
+    AssignCI = B.CreateIntrinsic(Intrinsic::fake_use, {}, {Arg});
+    AssignCI->setMetadata(
+        "spirv.__BE.assign_type",
+        MDNode::get(Arg->getContext(), ValueAsMetadata::getConstant(OfType)));
+  } else {
+    AssignCI = buildIntrWithMD(Intrinsic::spv_assign_type, {Arg->getType()},
+                               OfType, Arg, {}, B);
+  }
   GR->addAssignPtrTypeInstr(Arg, AssignCI);
 }
 
@@ -1270,6 +1312,8 @@ Instruction *SPIRVEmitIntrinsics::visitInsertValueInst(InsertValueInst &I) {
 }
 
 Instruction *SPIRVEmitIntrinsics::visitExtractValueInst(ExtractValueInst &I) {
+  if (I.getAggregateOperand()->getType()->isAggregateType())
+    return &I;
   IRBuilder<> B(I.getParent());
   B.SetInsertPoint(&I);
   SmallVector<Value *> Args;
diff --git a/llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp b/llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp
index 9fe4d8a16bc32a..189b84369d1c33 100644
--- a/llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp
@@ -287,7 +287,8 @@ SPIRVLegalizerInfo::SPIRVLegalizerInfo(const SPIRVSubtarget &ST) {
   // TODO: add proper legalization rules.
   getActionDefinitionsBuilder(G_ATOMIC_CMPXCHG).alwaysLegal();
 
-  getActionDefinitionsBuilder({G_UADDO, G_USUBO, G_SMULO, G_UMULO})
+  getActionDefinitionsBuilder(
+      {G_UADDO, G_SADDO, G_USUBO, G_SSUBO, G_SMULO, G_UMULO})
       .alwaysLegal();
 
   // FP conversions.
diff --git a/llvm/lib/Target/SPIRV/SPIRVPreLegalizer.cpp b/llvm/lib/Target/SPIRV/SPIRVPreLegalizer.cpp
index df1b75bc1cb9eb..53a266722da21d 100644
--- a/llvm/lib/Target/SPIRV/SPIRVPreLegalizer.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVPreLegalizer.cpp
@@ -376,7 +376,13 @@ Register insertAssignInstr(Register Reg, Type *Ty, SPIRVType *SpvType,
       .addUse(NewReg)
       .addUse(GR->getSPIRVTypeID(SpvType))
       .setMIFlags(Flags);
-  Def->getOperand(0).setReg(NewReg);
+  for (unsigned I = 0, E = Def->getNumExplicitDefs(); I != E; ++I) {
+    MachineOperand &MO = Def->getOperand(I);
+    if (MO.isReg() && MO.isDef() && MO.getReg() == Reg) {
+      MO.setReg(NewReg);
+      break;
+    }
+  }
   return NewReg;
 }
 
diff --git a/llvm/lib/Target/SPIRV/SPIRVPrepareFunctions.cpp b/llvm/lib/Target/SPIRV/SPIRVPrepareFunctions.cpp
index 29b8f8fac98e82..e755af2ff20158 100644
--- a/llvm/lib/Target/SPIRV/SPIRVPrepareFunctions.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVPrepareFunctions.cpp
@@ -478,6 +478,24 @@ bool SPIRVPrepareFunctions::substituteIntrinsicCalls(Function *F) {
 // noted in 'spv.cloned_funcs' metadata for later restoration.
 Function *
 SPIRVPrepareFunctions::removeAggregateTypesFromSignature(Function *F) {
+  if (F->isIntrinsic())
+    // Allow intrinsics with aggregate return type to reach GlobalISel
+    switch (F->getIntrinsicID()) {
+    // Standard C/C++ Library Intrinsics
+    case Intrinsic::frexp:
+      // Vector Reduction Intrinsics
+    case Intrinsic::vector_interleave2:
+    case Intrinsic::vector_deinterleave2:
+    // Arithmetic with Overflow Intrinsics
+    case Intrinsic::smul_with_overflow:
+    case Intrinsic::umul_with_overflow:
+    case Intrinsic::sadd_with_overflow:
+    case Intrinsic::uadd_with_overflow:
+    case Intrinsic::ssub_with_overflow:
+    case Intrinsic::usub_with_overflow:
+      return F;
+    }
+
   IRBuilder<> B(F->getContext());
 
   bool IsRetAggr = F->getReturnType()->isAggregateType();
@@ -561,6 +579,7 @@ bool SPIRVPrepareFunctions::runOnModule(Module &M) {
       Changed = true;
     }
   }
+
   return Changed;
 }
 



More information about the llvm-commits mailing list