[llvm] 583450f - AMDGPU: Fix DivergenceAnalysis for llvm.read_register

Matt Arsenault via llvm-commits llvm-commits at lists.llvm.org
Mon Nov 7 10:42:42 PST 2022


Author: Matt Arsenault
Date: 2022-11-07T10:42:35-08:00
New Revision: 583450fa0988d1ac088d36ec840cec4f84e013c4

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

LOG: AMDGPU: Fix DivergenceAnalysis for llvm.read_register

This was treating all calls as uniform by default, which
is wrong if used to read a VGPR.

Added: 
    llvm/test/Analysis/DivergenceAnalysis/AMDGPU/read_register.ll

Modified: 
    llvm/lib/Target/AMDGPU/AMDGPUTargetTransformInfo.cpp
    llvm/lib/Target/AMDGPU/AMDGPUTargetTransformInfo.h

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Target/AMDGPU/AMDGPUTargetTransformInfo.cpp b/llvm/lib/Target/AMDGPU/AMDGPUTargetTransformInfo.cpp
index f3310a6ec368..483c7037acf3 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPUTargetTransformInfo.cpp
+++ b/llvm/lib/Target/AMDGPU/AMDGPUTargetTransformInfo.cpp
@@ -857,6 +857,27 @@ bool GCNTTIImpl::useGPUDivergenceAnalysis() const {
   return !UseLegacyDA;
 }
 
+bool GCNTTIImpl::isReadRegisterSourceOfDivergence(
+    const IntrinsicInst *ReadReg) const {
+  Metadata *MD =
+      cast<MetadataAsValue>(ReadReg->getArgOperand(0))->getMetadata();
+  StringRef RegName =
+      cast<MDString>(cast<MDNode>(MD)->getOperand(0))->getString();
+
+  // Special case registers that look like VCC.
+  MVT VT = MVT::getVT(ReadReg->getType());
+  if (VT == MVT::i1)
+    return true;
+
+  // Special case scalar registers that start with 'v'.
+  if (RegName.startswith("vcc") || RegName.empty())
+    return false;
+
+  // VGPR or AGPR is divergent. There aren't any specially named vector
+  // registers.
+  return RegName[0] == 'v' || RegName[0] == 'a';
+}
+
 /// \returns true if the result of the value could potentially be
 /// 
diff erent across workitems in a wavefront.
 bool GCNTTIImpl::isSourceOfDivergence(const Value *V) const {
@@ -880,8 +901,12 @@ bool GCNTTIImpl::isSourceOfDivergence(const Value *V) const {
   if (isa<AtomicRMWInst>(V) || isa<AtomicCmpXchgInst>(V))
     return true;
 
-  if (const IntrinsicInst *Intrinsic = dyn_cast<IntrinsicInst>(V))
+  if (const IntrinsicInst *Intrinsic = dyn_cast<IntrinsicInst>(V)) {
+    if (Intrinsic->getIntrinsicID() == Intrinsic::read_register)
+      return isReadRegisterSourceOfDivergence(Intrinsic);
+
     return AMDGPU::isIntrinsicSourceOfDivergence(Intrinsic->getIntrinsicID());
+  }
 
   // Assume all function calls are a source of divergence.
   if (const CallInst *CI = dyn_cast<CallInst>(V)) {

diff  --git a/llvm/lib/Target/AMDGPU/AMDGPUTargetTransformInfo.h b/llvm/lib/Target/AMDGPU/AMDGPUTargetTransformInfo.h
index 4ee785f83ba2..fb54cfd09da3 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPUTargetTransformInfo.h
+++ b/llvm/lib/Target/AMDGPU/AMDGPUTargetTransformInfo.h
@@ -162,6 +162,8 @@ class GCNTTIImpl final : public BasicTTIImplBase<GCNTTIImpl> {
   using BaseT::getVectorInstrCost;
   InstructionCost getVectorInstrCost(unsigned Opcode, Type *ValTy,
                                      unsigned Index);
+
+  bool isReadRegisterSourceOfDivergence(const IntrinsicInst *ReadReg) const;
   bool isSourceOfDivergence(const Value *V) const;
   bool isAlwaysUniform(const Value *V) const;
 

diff  --git a/llvm/test/Analysis/DivergenceAnalysis/AMDGPU/read_register.ll b/llvm/test/Analysis/DivergenceAnalysis/AMDGPU/read_register.ll
new file mode 100644
index 000000000000..91e5d588710a
--- /dev/null
+++ b/llvm/test/Analysis/DivergenceAnalysis/AMDGPU/read_register.ll
@@ -0,0 +1,142 @@
+; RUN: opt -mtriple amdgcn-unknown-amdhsa -mcpu=gfx90a -passes='print<divergence>' -disable-output %s 2>&1 | FileCheck %s
+
+; CHECK-LABEL: Divergence Analysis' for function 'read_register_exec':
+; CHECK-NOT: DIVERGENT
+define i64 @read_register_exec() {
+  %reg = call i64 @llvm.read_register.i64(metadata !0)
+  ret i64 %reg
+}
+
+; CHECK-LABEL: Divergence Analysis' for function 'read_register_m0':
+; CHECK-NOT: DIVERGENT
+define i32 @read_register_m0() {
+  %reg = call i32 @llvm.read_register.i32(metadata !1)
+  ret i32 %reg
+}
+
+; CHECK-LABEL: Divergence Analysis' for function 'read_register_s17':
+; CHECK-NOT: DIVERGENT
+define i32 @read_register_s17() {
+  %reg = call i32 @llvm.read_register.i32(metadata !2)
+  ret i32 %reg
+}
+
+; CHECK-LABEL: Divergence Analysis' for function 'read_register_s17_i17':
+; CHECK-NOT: DIVERGENT
+define i17 @read_register_s17_i17() {
+  %reg = call i17 @llvm.read_register.i17(metadata !2)
+  ret i17 %reg
+}
+
+; CHECK-LABEL: Divergence Analysis' for function 'read_register_v0':
+; CHECK: DIVERGENT
+define i32 @read_register_v0() {
+  %reg = call i32 @llvm.read_register.i32(metadata !3)
+  ret i32 %reg
+}
+
+; CHECK-LABEL: Divergence Analysis' for function 'read_register_v0_v1':
+; CHECK: DIVERGENT
+define i64 @read_register_v0_v1() {
+  %reg = call i64 @llvm.read_register.i64(metadata !4)
+  ret i64 %reg
+}
+
+; CHECK-LABEL: Divergence Analysis' for function 'read_register_a0':
+; CHECK: DIVERGENT
+define i32 @read_register_a0() {
+  %reg = call i32 @llvm.read_register.i32(metadata !5)
+  ret i32 %reg
+}
+
+; CHECK-LABEL: Divergence Analysis' for function 'read_register_a0_a1':
+; CHECK: DIVERGENT
+define i64 @read_register_a0_a1() {
+  %reg = call i64 @llvm.read_register.i64(metadata !6)
+  ret i64 %reg
+}
+
+; CHECK-LABEL: Divergence Analysis' for function 'read_register_vcc_i64':
+; CHECK-NOT: DIVERGENT
+define i64 @read_register_vcc_i64() {
+  %reg = call i64 @llvm.read_register.i64(metadata !7)
+  ret i64 %reg
+}
+
+; CHECK-LABEL: Divergence Analysis' for function 'read_register_vcc_i1':
+; CHECK: DIVERGENT
+define i1 @read_register_vcc_i1() {
+  %reg = call i1 @llvm.read_register.i1(metadata !7)
+  ret i1 %reg
+}
+
+; CHECK-LABEL: Divergence Analysis' for function 'read_register_invalid_reg':
+; CHECK-NOT: DIVERGENT
+define i64 @read_register_invalid_reg() {
+  %reg = call i64 @llvm.read_register.i64(metadata !8)
+  ret i64 %reg
+}
+
+; CHECK-LABEL: Divergence Analysis' for function 'read_register_flat_scratch':
+; CHECK-NOT: DIVERGENT
+define i32 @read_register_flat_scratch() {
+  %reg = call i32 @llvm.read_register.i32(metadata !9)
+  ret i32 %reg
+}
+
+; CHECK-LABEL: Divergence Analysis' for function 'read_register_vcc_lo_i32':
+; CHECK-NOT: DIVERGENT
+define i32 @read_register_vcc_lo_i32() {
+  %reg = call i32 @llvm.read_register.i32(metadata !10)
+  ret i32 %reg
+}
+
+; CHECK-LABEL: Divergence Analysis' for function 'read_register_vcc_hi_i32':
+; CHECK-NOT: DIVERGENT
+define i32 @read_register_vcc_hi_i32() {
+  %reg = call i32 @llvm.read_register.i32(metadata !11)
+  ret i32 %reg
+}
+
+; CHECK-LABEL: Divergence Analysis' for function 'read_register_exec_lo_i32':
+; CHECK-NOT: DIVERGENT
+define i32 @read_register_exec_lo_i32() {
+  %reg = call i32 @llvm.read_register.i32(metadata !12)
+  ret i32 %reg
+}
+
+; CHECK-LABEL: Divergence Analysis' for function 'read_register_exec_hi_i32':
+; CHECK-NOT: DIVERGENT
+define i32 @read_register_exec_hi_i32() {
+  %reg = call i32 @llvm.read_register.i32(metadata !13)
+  ret i32 %reg
+}
+
+; FIXME: Why does the verifier allow this?
+; CHECK-LABEL: Divergence Analysis' for function 'read_register_empty_str_i32':
+; CHECK-NOT: DIVERGENT
+define i32 @read_register_empty_str_i32() {
+  %reg = call i32 @llvm.read_register.i32(metadata !14)
+  ret i32 %reg
+}
+
+declare i64 @llvm.read_register.i64(metadata)
+declare i32 @llvm.read_register.i32(metadata)
+declare i17 @llvm.read_register.i17(metadata)
+declare i1 @llvm.read_register.i1(metadata)
+
+!0 = !{!"exec"}
+!1 = !{!"m0"}
+!2 = !{!"s17"}
+!3 = !{!"v0"}
+!4 = !{!"v[0:1]"}
+!5 = !{!"a0"}
+!6 = !{!"a[0:1]"}
+!7 = !{!"vcc"}
+!8 = !{!"not a register"}
+!9 = !{!"flat_scratch"}
+!10 = !{!"vcc_lo"}
+!11 = !{!"vcc_hi"}
+!12 = !{!"exec_lo"}
+!13 = !{!"exec_hi"}
+!14 = !{!""}


        


More information about the llvm-commits mailing list