Skip to content

[NVPTX] Add TTI support for folding isspacep in InferAS #114486

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged

Conversation

AlexMaclean
Copy link
Member

This change enables constant folding of '@llvm.nvvm.isspacep.*' intrinsics if the address space can be propagated in InferAdressSpace.

@llvmbot
Copy link
Member

llvmbot commented Oct 31, 2024

@llvm/pr-subscribers-backend-nvptx

Author: Alex MacLean (AlexMaclean)

Changes

This change enables constant folding of '@<!-- -->llvm.nvvm.isspacep.*' intrinsics if the address space can be propagated in InferAdressSpace.


Full diff: https://github.com/llvm/llvm-project/pull/114486.diff

3 Files Affected:

  • (modified) llvm/lib/Target/NVPTX/NVPTXTargetTransformInfo.cpp (+59-24)
  • (modified) llvm/lib/Target/NVPTX/NVPTXTargetTransformInfo.h (+6)
  • (added) llvm/test/Transforms/InferAddressSpaces/NVPTX/isspacep.ll (+144)
diff --git a/llvm/lib/Target/NVPTX/NVPTXTargetTransformInfo.cpp b/llvm/lib/Target/NVPTX/NVPTXTargetTransformInfo.cpp
index 3507573df1869f..5df211726882ec 100644
--- a/llvm/lib/Target/NVPTX/NVPTXTargetTransformInfo.cpp
+++ b/llvm/lib/Target/NVPTX/NVPTXTargetTransformInfo.cpp
@@ -416,33 +416,34 @@ static Instruction *convertNvvmIntrinsicToLlvm(InstCombiner &IC,
   llvm_unreachable("All SpecialCase enumerators should be handled in switch.");
 }
 
+  // Returns true/false when we know the answer, nullopt otherwise.
+static std::optional<bool> evaluateIsSpace(Intrinsic::ID IID, unsigned AS) {
+  if (AS == NVPTXAS::ADDRESS_SPACE_GENERIC ||
+      AS == NVPTXAS::ADDRESS_SPACE_PARAM)
+    return std::nullopt; // Got to check at run-time.
+  switch (IID) {
+  case Intrinsic::nvvm_isspacep_global:
+    return AS == NVPTXAS::ADDRESS_SPACE_GLOBAL;
+  case Intrinsic::nvvm_isspacep_local:
+    return AS == NVPTXAS::ADDRESS_SPACE_LOCAL;
+  case Intrinsic::nvvm_isspacep_shared:
+    return AS == NVPTXAS::ADDRESS_SPACE_SHARED;
+  case Intrinsic::nvvm_isspacep_shared_cluster:
+    // We can't tell shared from shared_cluster at compile time from AS alone,
+    // but it can't be either is AS is not shared.
+    return AS == NVPTXAS::ADDRESS_SPACE_SHARED ? std::nullopt
+                                               : std::optional{false};
+  case Intrinsic::nvvm_isspacep_const:
+    return AS == NVPTXAS::ADDRESS_SPACE_CONST;
+  default:
+    llvm_unreachable("Unexpected intrinsic");
+  }
+}
+
 // Returns an instruction pointer (may be nullptr if we do not know the answer).
 // Returns nullopt if `II` is not one of the `isspacep` intrinsics.
 static std::optional<Instruction *>
 handleSpaceCheckIntrinsics(InstCombiner &IC, IntrinsicInst &II) {
-  // Returns true/false when we know the answer, nullopt otherwise.
-  auto CheckASMatch = [](unsigned IID, unsigned AS) -> std::optional<bool> {
-    if (AS == NVPTXAS::ADDRESS_SPACE_GENERIC ||
-        AS == NVPTXAS::ADDRESS_SPACE_PARAM)
-      return std::nullopt; // Got to check at run-time.
-    switch (IID) {
-    case Intrinsic::nvvm_isspacep_global:
-      return AS == NVPTXAS::ADDRESS_SPACE_GLOBAL;
-    case Intrinsic::nvvm_isspacep_local:
-      return AS == NVPTXAS::ADDRESS_SPACE_LOCAL;
-    case Intrinsic::nvvm_isspacep_shared:
-      return AS == NVPTXAS::ADDRESS_SPACE_SHARED;
-    case Intrinsic::nvvm_isspacep_shared_cluster:
-      // We can't tell shared from shared_cluster at compile time from AS alone,
-      // but it can't be either is AS is not shared.
-      return AS == NVPTXAS::ADDRESS_SPACE_SHARED ? std::nullopt
-                                                 : std::optional{false};
-    case Intrinsic::nvvm_isspacep_const:
-      return AS == NVPTXAS::ADDRESS_SPACE_CONST;
-    default:
-      llvm_unreachable("Unexpected intrinsic");
-    }
-  };
 
   switch (auto IID = II.getIntrinsicID()) {
   case Intrinsic::nvvm_isspacep_global:
@@ -458,7 +459,7 @@ handleSpaceCheckIntrinsics(InstCombiner &IC, IntrinsicInst &II) {
       if (auto *ASCO = dyn_cast<AddrSpaceCastOperator>(Op0))
         AS = ASCO->getOperand(0)->getType()->getPointerAddressSpace();
 
-    if (std::optional<bool> Answer = CheckASMatch(IID, AS))
+    if (std::optional<bool> Answer = evaluateIsSpace(IID, AS))
       return IC.replaceInstUsesWith(II,
                                     ConstantInt::get(II.getType(), *Answer));
     return nullptr; // Don't know the answer, got to check at run time.
@@ -525,3 +526,37 @@ void NVPTXTTIImpl::getPeelingPreferences(Loop *L, ScalarEvolution &SE,
                                          TTI::PeelingPreferences &PP) {
   BaseT::getPeelingPreferences(L, SE, PP);
 }
+
+bool NVPTXTTIImpl::collectFlatAddressOperands(SmallVectorImpl<int> &OpIndexes,
+                                              Intrinsic::ID IID) const {
+  switch (IID) {
+  case Intrinsic::nvvm_isspacep_const:
+  case Intrinsic::nvvm_isspacep_global:
+  case Intrinsic::nvvm_isspacep_local:
+  case Intrinsic::nvvm_isspacep_shared:
+  case Intrinsic::nvvm_isspacep_shared_cluster: {
+    OpIndexes.push_back(0);
+    return true;
+  }
+  }
+  return false;
+}
+
+Value *NVPTXTTIImpl::rewriteIntrinsicWithAddressSpace(IntrinsicInst *II,
+                                                      Value *OldV,
+                                                      Value *NewV) const {
+  const Intrinsic::ID IID = II->getIntrinsicID();
+  switch (IID) {
+  case Intrinsic::nvvm_isspacep_const:
+  case Intrinsic::nvvm_isspacep_global:
+  case Intrinsic::nvvm_isspacep_local:
+  case Intrinsic::nvvm_isspacep_shared:
+  case Intrinsic::nvvm_isspacep_shared_cluster: {
+    const unsigned NewAS = NewV->getType()->getPointerAddressSpace();
+    if (const auto R = evaluateIsSpace(IID, NewAS))
+      return ConstantInt::get(II->getType(), *R);
+    return nullptr;
+  }
+  }
+  return nullptr;
+}
\ No newline at end of file
diff --git a/llvm/lib/Target/NVPTX/NVPTXTargetTransformInfo.h b/llvm/lib/Target/NVPTX/NVPTXTargetTransformInfo.h
index 86140daa7be489..0f4fb280b2d996 100644
--- a/llvm/lib/Target/NVPTX/NVPTXTargetTransformInfo.h
+++ b/llvm/lib/Target/NVPTX/NVPTXTargetTransformInfo.h
@@ -123,6 +123,12 @@ class NVPTXTTIImpl : public BasicTTIImplBase<NVPTXTTIImpl> {
       return true;
     }
   }
+
+  bool collectFlatAddressOperands(SmallVectorImpl<int> &OpIndexes,
+                                  Intrinsic::ID IID) const;
+
+  Value *rewriteIntrinsicWithAddressSpace(IntrinsicInst *II, Value *OldV,
+                                          Value *NewV) const;
 };
 
 } // end namespace llvm
diff --git a/llvm/test/Transforms/InferAddressSpaces/NVPTX/isspacep.ll b/llvm/test/Transforms/InferAddressSpaces/NVPTX/isspacep.ll
new file mode 100644
index 00000000000000..348fa688770df6
--- /dev/null
+++ b/llvm/test/Transforms/InferAddressSpaces/NVPTX/isspacep.ll
@@ -0,0 +1,144 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
+; RUN: opt -S -mtriple=nvptx64-nvidia-cuda -passes=infer-address-spaces,bdce %s | FileCheck %s
+
+target datalayout = "e-p:64:64:64-p3:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-i128:128:128-f32:32:32-f64:64:64-v16:16:16-v32:32:32-v64:64:64-v128:128:128-n16:32:64"
+target triple = "nvptx64-nvidia-cuda"
+
+declare i1 @llvm.nvvm.isspacep.const(ptr) readnone noinline
+declare i1 @llvm.nvvm.isspacep.global(ptr) readnone noinline
+declare i1 @llvm.nvvm.isspacep.local(ptr) readnone noinline
+declare i1 @llvm.nvvm.isspacep.shared(ptr) readnone noinline
+declare i1 @llvm.nvvm.isspacep.cluster.shared(ptr) readnone noinline
+
+define i1 @test_isspacep_const_true(ptr addrspace(4) %addr) {
+; CHECK-LABEL: define i1 @test_isspacep_const_true(
+; CHECK-SAME: ptr addrspace(4) [[ADDR:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    ret i1 true
+;
+entry:
+  %addr0 = addrspacecast ptr addrspace(4) %addr to ptr
+  %addr1 = getelementptr i8, ptr %addr0, i32 10
+  %val = call i1 @llvm.nvvm.isspacep.const(ptr %addr1)
+  ret i1 %val
+}
+
+define i1 @test_isspacep_const_false(ptr addrspace(1) %addr) {
+; CHECK-LABEL: define i1 @test_isspacep_const_false(
+; CHECK-SAME: ptr addrspace(1) [[ADDR:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    ret i1 false
+;
+entry:
+  %addr0 = addrspacecast ptr addrspace(1) %addr to ptr
+  %addr1 = getelementptr i8, ptr %addr0, i32 10
+  %val = call i1 @llvm.nvvm.isspacep.const(ptr %addr1)
+  ret i1 %val
+}
+
+define i1 @test_isspacep_global_true(ptr addrspace(1) %addr) {
+; CHECK-LABEL: define i1 @test_isspacep_global_true(
+; CHECK-SAME: ptr addrspace(1) [[ADDR:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    ret i1 true
+;
+entry:
+  %addr0 = addrspacecast ptr addrspace(1) %addr to ptr
+  %addr1 = getelementptr i8, ptr %addr0, i32 10
+  %val = call i1 @llvm.nvvm.isspacep.global(ptr %addr1)
+  ret i1 %val
+}
+
+define i1 @test_isspacep_global_false(ptr addrspace(4) %addr) {
+; CHECK-LABEL: define i1 @test_isspacep_global_false(
+; CHECK-SAME: ptr addrspace(4) [[ADDR:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    ret i1 false
+;
+entry:
+  %addr0 = addrspacecast ptr addrspace(4) %addr to ptr
+  %addr1 = getelementptr i8, ptr %addr0, i32 10
+  %val = call i1 @llvm.nvvm.isspacep.global(ptr %addr1)
+  ret i1 %val
+}
+
+define i1 @test_isspacep_local_true(ptr addrspace(5) %addr) {
+; CHECK-LABEL: define i1 @test_isspacep_local_true(
+; CHECK-SAME: ptr addrspace(5) [[ADDR:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    ret i1 true
+;
+entry:
+  %addr0 = addrspacecast ptr addrspace(5) %addr to ptr
+  %addr1 = getelementptr i8, ptr %addr0, i32 10
+  %val = call i1 @llvm.nvvm.isspacep.local(ptr %addr1)
+  ret i1 %val
+}
+
+define i1 @test_isspacep_local_false(ptr addrspace(1) %addr) {
+; CHECK-LABEL: define i1 @test_isspacep_local_false(
+; CHECK-SAME: ptr addrspace(1) [[ADDR:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    ret i1 false
+;
+entry:
+  %addr0 = addrspacecast ptr addrspace(1) %addr to ptr
+  %addr1 = getelementptr i8, ptr %addr0, i32 10
+  %val = call i1 @llvm.nvvm.isspacep.local(ptr %addr1)
+  ret i1 %val
+}
+
+define i1 @test_isspacep_shared_true(ptr addrspace(3) %addr) {
+; CHECK-LABEL: define i1 @test_isspacep_shared_true(
+; CHECK-SAME: ptr addrspace(3) [[ADDR:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    ret i1 true
+;
+entry:
+  %addr0 = addrspacecast ptr addrspace(3) %addr to ptr
+  %addr1 = getelementptr i8, ptr %addr0, i32 10
+  %val = call i1 @llvm.nvvm.isspacep.shared(ptr %addr1)
+  ret i1 %val
+}
+
+define i1 @test_isspacep_shared_false(ptr addrspace(1) %addr) {
+; CHECK-LABEL: define i1 @test_isspacep_shared_false(
+; CHECK-SAME: ptr addrspace(1) [[ADDR:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    ret i1 false
+;
+entry:
+  %addr0 = addrspacecast ptr addrspace(1) %addr to ptr
+  %addr1 = getelementptr i8, ptr %addr0, i32 10
+  %val = call i1 @llvm.nvvm.isspacep.shared(ptr %addr1)
+  ret i1 %val
+}
+
+define i1 @test_isspacep_cluster_shared_unsure(ptr addrspace(3) %addr) {
+; CHECK-LABEL: define i1 @test_isspacep_cluster_shared_unsure(
+; CHECK-SAME: ptr addrspace(3) [[ADDR:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[ADDR1:%.*]] = getelementptr i8, ptr addrspace(3) [[ADDR]], i32 10
+; CHECK-NEXT:    [[TMP0:%.*]] = addrspacecast ptr addrspace(3) [[ADDR1]] to ptr
+; CHECK-NEXT:    [[VAL:%.*]] = call i1 @llvm.nvvm.isspacep.shared.cluster(ptr [[TMP0]])
+; CHECK-NEXT:    ret i1 [[VAL]]
+;
+entry:
+  %addr0 = addrspacecast ptr addrspace(3) %addr to ptr
+  %addr1 = getelementptr i8, ptr %addr0, i32 10
+  %val = call i1 @llvm.nvvm.isspacep.shared.cluster(ptr %addr1)
+  ret i1 %val
+}
+
+define i1 @test_isspacep_cluster_shared_false(ptr addrspace(1) %addr) {
+; CHECK-LABEL: define i1 @test_isspacep_cluster_shared_false(
+; CHECK-SAME: ptr addrspace(1) [[ADDR:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    ret i1 false
+;
+entry:
+  %addr0 = addrspacecast ptr addrspace(1) %addr to ptr
+  %addr1 = getelementptr i8, ptr %addr0, i32 10
+  %val = call i1 @llvm.nvvm.isspacep.shared.cluster(ptr %addr1)
+  ret i1 %val
+}

@llvmbot
Copy link
Member

llvmbot commented Oct 31, 2024

@llvm/pr-subscribers-llvm-transforms

Author: Alex MacLean (AlexMaclean)

Changes

This change enables constant folding of '@<!-- -->llvm.nvvm.isspacep.*' intrinsics if the address space can be propagated in InferAdressSpace.


Full diff: https://github.com/llvm/llvm-project/pull/114486.diff

3 Files Affected:

  • (modified) llvm/lib/Target/NVPTX/NVPTXTargetTransformInfo.cpp (+59-24)
  • (modified) llvm/lib/Target/NVPTX/NVPTXTargetTransformInfo.h (+6)
  • (added) llvm/test/Transforms/InferAddressSpaces/NVPTX/isspacep.ll (+144)
diff --git a/llvm/lib/Target/NVPTX/NVPTXTargetTransformInfo.cpp b/llvm/lib/Target/NVPTX/NVPTXTargetTransformInfo.cpp
index 3507573df1869f..5df211726882ec 100644
--- a/llvm/lib/Target/NVPTX/NVPTXTargetTransformInfo.cpp
+++ b/llvm/lib/Target/NVPTX/NVPTXTargetTransformInfo.cpp
@@ -416,33 +416,34 @@ static Instruction *convertNvvmIntrinsicToLlvm(InstCombiner &IC,
   llvm_unreachable("All SpecialCase enumerators should be handled in switch.");
 }
 
+  // Returns true/false when we know the answer, nullopt otherwise.
+static std::optional<bool> evaluateIsSpace(Intrinsic::ID IID, unsigned AS) {
+  if (AS == NVPTXAS::ADDRESS_SPACE_GENERIC ||
+      AS == NVPTXAS::ADDRESS_SPACE_PARAM)
+    return std::nullopt; // Got to check at run-time.
+  switch (IID) {
+  case Intrinsic::nvvm_isspacep_global:
+    return AS == NVPTXAS::ADDRESS_SPACE_GLOBAL;
+  case Intrinsic::nvvm_isspacep_local:
+    return AS == NVPTXAS::ADDRESS_SPACE_LOCAL;
+  case Intrinsic::nvvm_isspacep_shared:
+    return AS == NVPTXAS::ADDRESS_SPACE_SHARED;
+  case Intrinsic::nvvm_isspacep_shared_cluster:
+    // We can't tell shared from shared_cluster at compile time from AS alone,
+    // but it can't be either is AS is not shared.
+    return AS == NVPTXAS::ADDRESS_SPACE_SHARED ? std::nullopt
+                                               : std::optional{false};
+  case Intrinsic::nvvm_isspacep_const:
+    return AS == NVPTXAS::ADDRESS_SPACE_CONST;
+  default:
+    llvm_unreachable("Unexpected intrinsic");
+  }
+}
+
 // Returns an instruction pointer (may be nullptr if we do not know the answer).
 // Returns nullopt if `II` is not one of the `isspacep` intrinsics.
 static std::optional<Instruction *>
 handleSpaceCheckIntrinsics(InstCombiner &IC, IntrinsicInst &II) {
-  // Returns true/false when we know the answer, nullopt otherwise.
-  auto CheckASMatch = [](unsigned IID, unsigned AS) -> std::optional<bool> {
-    if (AS == NVPTXAS::ADDRESS_SPACE_GENERIC ||
-        AS == NVPTXAS::ADDRESS_SPACE_PARAM)
-      return std::nullopt; // Got to check at run-time.
-    switch (IID) {
-    case Intrinsic::nvvm_isspacep_global:
-      return AS == NVPTXAS::ADDRESS_SPACE_GLOBAL;
-    case Intrinsic::nvvm_isspacep_local:
-      return AS == NVPTXAS::ADDRESS_SPACE_LOCAL;
-    case Intrinsic::nvvm_isspacep_shared:
-      return AS == NVPTXAS::ADDRESS_SPACE_SHARED;
-    case Intrinsic::nvvm_isspacep_shared_cluster:
-      // We can't tell shared from shared_cluster at compile time from AS alone,
-      // but it can't be either is AS is not shared.
-      return AS == NVPTXAS::ADDRESS_SPACE_SHARED ? std::nullopt
-                                                 : std::optional{false};
-    case Intrinsic::nvvm_isspacep_const:
-      return AS == NVPTXAS::ADDRESS_SPACE_CONST;
-    default:
-      llvm_unreachable("Unexpected intrinsic");
-    }
-  };
 
   switch (auto IID = II.getIntrinsicID()) {
   case Intrinsic::nvvm_isspacep_global:
@@ -458,7 +459,7 @@ handleSpaceCheckIntrinsics(InstCombiner &IC, IntrinsicInst &II) {
       if (auto *ASCO = dyn_cast<AddrSpaceCastOperator>(Op0))
         AS = ASCO->getOperand(0)->getType()->getPointerAddressSpace();
 
-    if (std::optional<bool> Answer = CheckASMatch(IID, AS))
+    if (std::optional<bool> Answer = evaluateIsSpace(IID, AS))
       return IC.replaceInstUsesWith(II,
                                     ConstantInt::get(II.getType(), *Answer));
     return nullptr; // Don't know the answer, got to check at run time.
@@ -525,3 +526,37 @@ void NVPTXTTIImpl::getPeelingPreferences(Loop *L, ScalarEvolution &SE,
                                          TTI::PeelingPreferences &PP) {
   BaseT::getPeelingPreferences(L, SE, PP);
 }
+
+bool NVPTXTTIImpl::collectFlatAddressOperands(SmallVectorImpl<int> &OpIndexes,
+                                              Intrinsic::ID IID) const {
+  switch (IID) {
+  case Intrinsic::nvvm_isspacep_const:
+  case Intrinsic::nvvm_isspacep_global:
+  case Intrinsic::nvvm_isspacep_local:
+  case Intrinsic::nvvm_isspacep_shared:
+  case Intrinsic::nvvm_isspacep_shared_cluster: {
+    OpIndexes.push_back(0);
+    return true;
+  }
+  }
+  return false;
+}
+
+Value *NVPTXTTIImpl::rewriteIntrinsicWithAddressSpace(IntrinsicInst *II,
+                                                      Value *OldV,
+                                                      Value *NewV) const {
+  const Intrinsic::ID IID = II->getIntrinsicID();
+  switch (IID) {
+  case Intrinsic::nvvm_isspacep_const:
+  case Intrinsic::nvvm_isspacep_global:
+  case Intrinsic::nvvm_isspacep_local:
+  case Intrinsic::nvvm_isspacep_shared:
+  case Intrinsic::nvvm_isspacep_shared_cluster: {
+    const unsigned NewAS = NewV->getType()->getPointerAddressSpace();
+    if (const auto R = evaluateIsSpace(IID, NewAS))
+      return ConstantInt::get(II->getType(), *R);
+    return nullptr;
+  }
+  }
+  return nullptr;
+}
\ No newline at end of file
diff --git a/llvm/lib/Target/NVPTX/NVPTXTargetTransformInfo.h b/llvm/lib/Target/NVPTX/NVPTXTargetTransformInfo.h
index 86140daa7be489..0f4fb280b2d996 100644
--- a/llvm/lib/Target/NVPTX/NVPTXTargetTransformInfo.h
+++ b/llvm/lib/Target/NVPTX/NVPTXTargetTransformInfo.h
@@ -123,6 +123,12 @@ class NVPTXTTIImpl : public BasicTTIImplBase<NVPTXTTIImpl> {
       return true;
     }
   }
+
+  bool collectFlatAddressOperands(SmallVectorImpl<int> &OpIndexes,
+                                  Intrinsic::ID IID) const;
+
+  Value *rewriteIntrinsicWithAddressSpace(IntrinsicInst *II, Value *OldV,
+                                          Value *NewV) const;
 };
 
 } // end namespace llvm
diff --git a/llvm/test/Transforms/InferAddressSpaces/NVPTX/isspacep.ll b/llvm/test/Transforms/InferAddressSpaces/NVPTX/isspacep.ll
new file mode 100644
index 00000000000000..348fa688770df6
--- /dev/null
+++ b/llvm/test/Transforms/InferAddressSpaces/NVPTX/isspacep.ll
@@ -0,0 +1,144 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
+; RUN: opt -S -mtriple=nvptx64-nvidia-cuda -passes=infer-address-spaces,bdce %s | FileCheck %s
+
+target datalayout = "e-p:64:64:64-p3:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-i128:128:128-f32:32:32-f64:64:64-v16:16:16-v32:32:32-v64:64:64-v128:128:128-n16:32:64"
+target triple = "nvptx64-nvidia-cuda"
+
+declare i1 @llvm.nvvm.isspacep.const(ptr) readnone noinline
+declare i1 @llvm.nvvm.isspacep.global(ptr) readnone noinline
+declare i1 @llvm.nvvm.isspacep.local(ptr) readnone noinline
+declare i1 @llvm.nvvm.isspacep.shared(ptr) readnone noinline
+declare i1 @llvm.nvvm.isspacep.cluster.shared(ptr) readnone noinline
+
+define i1 @test_isspacep_const_true(ptr addrspace(4) %addr) {
+; CHECK-LABEL: define i1 @test_isspacep_const_true(
+; CHECK-SAME: ptr addrspace(4) [[ADDR:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    ret i1 true
+;
+entry:
+  %addr0 = addrspacecast ptr addrspace(4) %addr to ptr
+  %addr1 = getelementptr i8, ptr %addr0, i32 10
+  %val = call i1 @llvm.nvvm.isspacep.const(ptr %addr1)
+  ret i1 %val
+}
+
+define i1 @test_isspacep_const_false(ptr addrspace(1) %addr) {
+; CHECK-LABEL: define i1 @test_isspacep_const_false(
+; CHECK-SAME: ptr addrspace(1) [[ADDR:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    ret i1 false
+;
+entry:
+  %addr0 = addrspacecast ptr addrspace(1) %addr to ptr
+  %addr1 = getelementptr i8, ptr %addr0, i32 10
+  %val = call i1 @llvm.nvvm.isspacep.const(ptr %addr1)
+  ret i1 %val
+}
+
+define i1 @test_isspacep_global_true(ptr addrspace(1) %addr) {
+; CHECK-LABEL: define i1 @test_isspacep_global_true(
+; CHECK-SAME: ptr addrspace(1) [[ADDR:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    ret i1 true
+;
+entry:
+  %addr0 = addrspacecast ptr addrspace(1) %addr to ptr
+  %addr1 = getelementptr i8, ptr %addr0, i32 10
+  %val = call i1 @llvm.nvvm.isspacep.global(ptr %addr1)
+  ret i1 %val
+}
+
+define i1 @test_isspacep_global_false(ptr addrspace(4) %addr) {
+; CHECK-LABEL: define i1 @test_isspacep_global_false(
+; CHECK-SAME: ptr addrspace(4) [[ADDR:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    ret i1 false
+;
+entry:
+  %addr0 = addrspacecast ptr addrspace(4) %addr to ptr
+  %addr1 = getelementptr i8, ptr %addr0, i32 10
+  %val = call i1 @llvm.nvvm.isspacep.global(ptr %addr1)
+  ret i1 %val
+}
+
+define i1 @test_isspacep_local_true(ptr addrspace(5) %addr) {
+; CHECK-LABEL: define i1 @test_isspacep_local_true(
+; CHECK-SAME: ptr addrspace(5) [[ADDR:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    ret i1 true
+;
+entry:
+  %addr0 = addrspacecast ptr addrspace(5) %addr to ptr
+  %addr1 = getelementptr i8, ptr %addr0, i32 10
+  %val = call i1 @llvm.nvvm.isspacep.local(ptr %addr1)
+  ret i1 %val
+}
+
+define i1 @test_isspacep_local_false(ptr addrspace(1) %addr) {
+; CHECK-LABEL: define i1 @test_isspacep_local_false(
+; CHECK-SAME: ptr addrspace(1) [[ADDR:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    ret i1 false
+;
+entry:
+  %addr0 = addrspacecast ptr addrspace(1) %addr to ptr
+  %addr1 = getelementptr i8, ptr %addr0, i32 10
+  %val = call i1 @llvm.nvvm.isspacep.local(ptr %addr1)
+  ret i1 %val
+}
+
+define i1 @test_isspacep_shared_true(ptr addrspace(3) %addr) {
+; CHECK-LABEL: define i1 @test_isspacep_shared_true(
+; CHECK-SAME: ptr addrspace(3) [[ADDR:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    ret i1 true
+;
+entry:
+  %addr0 = addrspacecast ptr addrspace(3) %addr to ptr
+  %addr1 = getelementptr i8, ptr %addr0, i32 10
+  %val = call i1 @llvm.nvvm.isspacep.shared(ptr %addr1)
+  ret i1 %val
+}
+
+define i1 @test_isspacep_shared_false(ptr addrspace(1) %addr) {
+; CHECK-LABEL: define i1 @test_isspacep_shared_false(
+; CHECK-SAME: ptr addrspace(1) [[ADDR:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    ret i1 false
+;
+entry:
+  %addr0 = addrspacecast ptr addrspace(1) %addr to ptr
+  %addr1 = getelementptr i8, ptr %addr0, i32 10
+  %val = call i1 @llvm.nvvm.isspacep.shared(ptr %addr1)
+  ret i1 %val
+}
+
+define i1 @test_isspacep_cluster_shared_unsure(ptr addrspace(3) %addr) {
+; CHECK-LABEL: define i1 @test_isspacep_cluster_shared_unsure(
+; CHECK-SAME: ptr addrspace(3) [[ADDR:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[ADDR1:%.*]] = getelementptr i8, ptr addrspace(3) [[ADDR]], i32 10
+; CHECK-NEXT:    [[TMP0:%.*]] = addrspacecast ptr addrspace(3) [[ADDR1]] to ptr
+; CHECK-NEXT:    [[VAL:%.*]] = call i1 @llvm.nvvm.isspacep.shared.cluster(ptr [[TMP0]])
+; CHECK-NEXT:    ret i1 [[VAL]]
+;
+entry:
+  %addr0 = addrspacecast ptr addrspace(3) %addr to ptr
+  %addr1 = getelementptr i8, ptr %addr0, i32 10
+  %val = call i1 @llvm.nvvm.isspacep.shared.cluster(ptr %addr1)
+  ret i1 %val
+}
+
+define i1 @test_isspacep_cluster_shared_false(ptr addrspace(1) %addr) {
+; CHECK-LABEL: define i1 @test_isspacep_cluster_shared_false(
+; CHECK-SAME: ptr addrspace(1) [[ADDR:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    ret i1 false
+;
+entry:
+  %addr0 = addrspacecast ptr addrspace(1) %addr to ptr
+  %addr1 = getelementptr i8, ptr %addr0, i32 10
+  %val = call i1 @llvm.nvvm.isspacep.shared.cluster(ptr %addr1)
+  ret i1 %val
+}

Copy link

github-actions bot commented Oct 31, 2024

✅ With the latest revision this PR passed the C/C++ code formatter.

Copy link
Contributor

@justinfargnoli justinfargnoli left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@gchak
Copy link

gchak commented Nov 1, 2024

Could be taken up in a separate PR, but could we get these nvvm.isspacep.* intrinsics documented in the NVPTX usage guide?

@AlexMaclean
Copy link
Member Author

@Artem-B When you have a minute could I please get your review on this as well? Thanks!

@AlexMaclean
Copy link
Member Author

Could be taken up in a separate PR, but could we get these nvvm.isspacep.* intrinsics documented in the NVPTX usage guide?

I've created #114839 to address this.

@AlexMaclean
Copy link
Member Author

@Artem-B ping for review

Comment on lines 459 to 464
if (auto *ASCO = dyn_cast<AddrSpaceCastOperator>(Op0))
AS = ASCO->getOperand(0)->getType()->getPointerAddressSpace();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we still need this attempt to peek through the ASC then? If we do manage to see original AS, so would the infer-address-spaces pass, and it would have folded the intrinsic into a constant.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yea, I would assume that infer-address-spaces would handle all these cases we do in instcombine, Though maybe doing it in instcombine will allow some cases to happen earlier.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where do we run AS inference pass in the pipeline? If it's early, then I think it would make sense to keep isspacep folding in one place only, and AS inference pass looks like a better place for that.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like it is only run in llc. I see AMDGPU runs this pass in opt so we should maybe consider doing the same, but I'm not sure how we'd make that decision.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK. Add a TODO comment there for now and we'll handle it separately.

@AlexMaclean AlexMaclean force-pushed the dev/amaclean/upstream-isspacep-mso-1 branch from 730f9bd to 05f4e4e Compare November 7, 2024 23:02
@AlexMaclean AlexMaclean merged commit 1febd71 into llvm:main Nov 8, 2024
9 checks passed
Groverkss pushed a commit to iree-org/llvm-project that referenced this pull request Nov 15, 2024
This change enables constant folding of '`@llvm.nvvm.isspacep.*`'
intrinsics if the address space can be propagated in InferAdressSpace.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants