AMDGPU/SI: Implement AMDGPUTargetTransformInfo::isSourceOfDivergence()
authorTom Stellard <thomas.stellard@amd.com>
Tue, 15 Dec 2015 18:04:38 +0000 (18:04 +0000)
committerTom Stellard <thomas.stellard@amd.com>
Tue, 15 Dec 2015 18:04:38 +0000 (18:04 +0000)
Reviewers: arsenm

Subscribers: arsenm, llvm-commits

Differential Revision: http://reviews.llvm.org/D15476

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@255661 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Target/AMDGPU/AMDGPUTargetTransformInfo.cpp
lib/Target/AMDGPU/AMDGPUTargetTransformInfo.h

index 4afcc60984fc7c84ae2c47868cd375f2bfc4178c..c7ea412ce22a05a6085b640f54b33a94b9dddf51 100644 (file)
@@ -91,3 +91,80 @@ int AMDGPUTTIImpl::getVectorInstrCost(unsigned Opcode, Type *ValTy,
     return BaseT::getVectorInstrCost(Opcode, ValTy, Index);
   }
 }
     return BaseT::getVectorInstrCost(Opcode, ValTy, Index);
   }
 }
+
+static bool isIntrinsicSourceOfDivergence(const TargetIntrinsicInfo *TII,
+                                          const IntrinsicInst *I) {
+  switch (I->getIntrinsicID()) {
+  default:
+    return false;
+  case Intrinsic::not_intrinsic:
+    // This means we have an intrinsic that isn't defined in
+    // IntrinsicsAMDGPU.td
+    break;
+
+  case Intrinsic::amdgcn_interp_p1:
+  case Intrinsic::amdgcn_interp_p2:
+  case Intrinsic::amdgcn_mbcnt_hi:
+  case Intrinsic::amdgcn_mbcnt_lo:
+  case Intrinsic::r600_read_tidig_x:
+  case Intrinsic::r600_read_tidig_y:
+  case Intrinsic::r600_read_tidig_z:
+    return true;
+  }
+
+  StringRef Name = I->getCalledFunction()->getName();
+  switch (TII->lookupName((const char *)Name.bytes_begin(), Name.size())) {
+  default:
+    return false;
+  case AMDGPUIntrinsic::SI_tid:
+  case AMDGPUIntrinsic::SI_fs_interp:
+    return true;
+  }
+}
+
+static bool isArgPassedInSGPR(const Argument *A) {
+  const Function *F = A->getParent();
+  unsigned ShaderType = AMDGPU::getShaderType(*F);
+
+  // Arguments to compute shaders are never a source of divergence.
+  if (ShaderType == ShaderType::COMPUTE)
+    return true;
+
+  // For non-compute shaders, the inreg attribute is used to mark inputs,
+  // which pre-loaded into SGPRs.
+  if (F->getAttributes().hasAttribute(A->getArgNo(), Attribute::InReg))
+    return true;
+
+  // For non-compute shaders, 32-bit values are pre-loaded into vgprs, all
+  // other value types use SGPRS.
+  return !A->getType()->isIntegerTy(32) && !A->getType()->isFloatTy();
+}
+
+///
+/// \returns true if the result of the value could potentially be
+/// different across workitems in a wavefront.
+bool AMDGPUTTIImpl::isSourceOfDivergence(const Value *V) const {
+
+  if (const Argument *A = dyn_cast<Argument>(V))
+    return !isArgPassedInSGPR(A);
+
+  // Loads from the private address space are divergent, because threads
+  // can execute the load instruction with the same inputs and get different
+  // results.
+  //
+  // All other loads are not divergent, because if threads issue loads with the
+  // same arguments, they will always get the same result.
+  if (const LoadInst *Load = dyn_cast<LoadInst>(V))
+    return Load->getPointerAddressSpace() == AMDGPUAS::PRIVATE_ADDRESS;
+
+  if (const IntrinsicInst *Intrinsic = dyn_cast<IntrinsicInst>(V)) {
+    const TargetMachine &TM = getTLI()->getTargetMachine();
+    return isIntrinsicSourceOfDivergence(TM.getIntrinsicInfo(), Intrinsic);
+  }
+
+  // Assume all function calls are a source of divergence.
+  if (isa<CallInst>(V) || isa<InvokeInst>(V))
+    return true;
+
+  return false;
+}
index 5a94a0ba4706048dd1073f32bd729f30cfa3c868..2a9727141b3d3001349d0691503e5b6518f16b41 100644 (file)
@@ -62,6 +62,7 @@ public:
   unsigned getMaxInterleaveFactor(unsigned VF);
 
   int getVectorInstrCost(unsigned Opcode, Type *ValTy, unsigned Index);
   unsigned getMaxInterleaveFactor(unsigned VF);
 
   int getVectorInstrCost(unsigned Opcode, Type *ValTy, unsigned Index);
+  bool isSourceOfDivergence(const Value *V) const;
 };
 
 } // end namespace llvm
 };
 
 } // end namespace llvm