[llvm] d03bfc6 - [SimplifyCFG] Avoid using isNonIntegralPointerType()

via llvm-commits llvm-commits at lists.llvm.org
Tue Sep 23 11:23:23 PDT 2025


Author: Alexander Richardson
Date: 2025-09-23T11:23:19-07:00
New Revision: d03bfc6c0a5e8dbd5b5e24c0dbd48d6ddf6f4e23

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

LOG: [SimplifyCFG] Avoid using isNonIntegralPointerType()

This is an overly broad check, the transformation made here can be done
safely for pointers with index!=repr width. This fixes the codegen
regression introduced by https://github.com/llvm/llvm-project/pull/105735
and should be beneficial for AMDGPU code-generation once the datalayout
there no longer uses the overly strict `ni:` specifier.

Reviewed By: arsenm

Pull Request: https://github.com/llvm/llvm-project/pull/159890

Added: 
    

Modified: 
    llvm/lib/Transforms/Utils/SimplifyCFG.cpp
    llvm/test/Transforms/SimplifyCFG/nonintegral.ll
    llvm/test/Transforms/SimplifyCFG/switch_create-custom-dl.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
index a1f759dd1df83..5e719c6c8cbb7 100644
--- a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
+++ b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
@@ -525,28 +525,33 @@ static bool dominatesMergePoint(
 static ConstantInt *getConstantInt(Value *V, const DataLayout &DL) {
   // Normal constant int.
   ConstantInt *CI = dyn_cast<ConstantInt>(V);
-  if (CI || !isa<Constant>(V) || !V->getType()->isPointerTy() ||
-      DL.isNonIntegralPointerType(V->getType()))
+  if (CI || !isa<Constant>(V) || !V->getType()->isPointerTy())
     return CI;
 
+  // It is not safe to look through inttoptr or ptrtoint when using unstable
+  // pointer types.
+  if (DL.hasUnstableRepresentation(V->getType()))
+    return nullptr;
+
   // This is some kind of pointer constant. Turn it into a pointer-sized
   // ConstantInt if possible.
-  IntegerType *PtrTy = cast<IntegerType>(DL.getIntPtrType(V->getType()));
+  IntegerType *IntPtrTy = cast<IntegerType>(DL.getIntPtrType(V->getType()));
 
   // Null pointer means 0, see SelectionDAGBuilder::getValue(const Value*).
   if (isa<ConstantPointerNull>(V))
-    return ConstantInt::get(PtrTy, 0);
+    return ConstantInt::get(IntPtrTy, 0);
 
-  // IntToPtr const int.
+  // IntToPtr const int, we can look through this if the semantics of
+  // inttoptr for this address space are a simple (truncating) bitcast.
   if (ConstantExpr *CE = dyn_cast<ConstantExpr>(V))
     if (CE->getOpcode() == Instruction::IntToPtr)
       if (ConstantInt *CI = dyn_cast<ConstantInt>(CE->getOperand(0))) {
         // The constant is very likely to have the right type already.
-        if (CI->getType() == PtrTy)
+        if (CI->getType() == IntPtrTy)
           return CI;
         else
           return cast<ConstantInt>(
-              ConstantFoldIntegerCast(CI, PtrTy, /*isSigned=*/false, DL));
+              ConstantFoldIntegerCast(CI, IntPtrTy, /*isSigned=*/false, DL));
       }
   return nullptr;
 }
@@ -866,10 +871,12 @@ Value *SimplifyCFGOpt::isValueEqualityComparison(Instruction *TI) {
       }
     }
 
-  // Unwrap any lossless ptrtoint cast.
+  // Unwrap any lossless ptrtoint cast (except for unstable pointers).
   if (CV) {
     if (PtrToIntInst *PTII = dyn_cast<PtrToIntInst>(CV)) {
       Value *Ptr = PTII->getPointerOperand();
+      if (DL.hasUnstableRepresentation(Ptr->getType()))
+        return CV;
       if (PTII->getType() == DL.getIntPtrType(Ptr->getType()))
         CV = Ptr;
     }
@@ -1427,6 +1434,8 @@ bool SimplifyCFGOpt::performValueComparisonIntoPredecessorFolding(
   Builder.SetInsertPoint(PTI);
   // Convert pointer to int before we switch.
   if (CV->getType()->isPointerTy()) {
+    assert(!DL.hasUnstableRepresentation(CV->getType()) &&
+           "Should not end up here with unstable pointers");
     CV =
         Builder.CreatePtrToInt(CV, DL.getIntPtrType(CV->getType()), "magicptr");
   }
@@ -5246,6 +5255,8 @@ bool SimplifyCFGOpt::simplifyBranchOnICmpChain(BranchInst *BI,
   Builder.SetInsertPoint(BI);
   // Convert pointer to int before we switch.
   if (CompVal->getType()->isPointerTy()) {
+    assert(!DL.hasUnstableRepresentation(CompVal->getType()) &&
+           "Should not end up here with unstable pointers");
     CompVal = Builder.CreatePtrToInt(
         CompVal, DL.getIntPtrType(CompVal->getType()), "magicptr");
   }

diff  --git a/llvm/test/Transforms/SimplifyCFG/nonintegral.ll b/llvm/test/Transforms/SimplifyCFG/nonintegral.ll
index 423ac4d1e69c1..1bdd436f01d02 100644
--- a/llvm/test/Transforms/SimplifyCFG/nonintegral.ll
+++ b/llvm/test/Transforms/SimplifyCFG/nonintegral.ll
@@ -1,12 +1,143 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
 ; RUN: opt -passes=simplifycfg -S < %s | FileCheck %s
 
-target datalayout = "ni:1"
+target datalayout = "pu1:64:64-pe2:64:64:64:32"
 
-define void @test_01(ptr addrspace(1) align 8 %ptr) {
-; CHECK-LABEL: @test_01(
-; CHECK-NOT:   ptrtoint
-; CHECK-NEXT:  icmp eq ptr addrspace(1) %ptr, null
-; CHECK-NOT:   ptrtoint
+;; TODO: it would probably be better to just emit a pointer compare against null.
+define void @test_default_null_base(ptr addrspace(0) align 8 %ptr) {
+; CHECK-LABEL: define void @test_default_null_base(
+; CHECK-SAME: ptr align 8 [[PTR:%.*]]) {
+; CHECK-NEXT:    [[MAGICPTR:%.*]] = ptrtoint ptr [[PTR]] to i64
+; CHECK-NEXT:    [[COND:%.*]] = icmp eq i64 [[MAGICPTR]], 0
+; CHECK-NEXT:    br i1 [[COND]], label %[[TRUE2:.*]], label %[[FALSE1:.*]]
+; CHECK:       [[FALSE1]]:
+; CHECK-NEXT:    store i64 1, ptr [[PTR]], align 8
+; CHECK-NEXT:    store i64 3, ptr [[PTR]], align 8
+; CHECK-NEXT:    br label %[[COMMON_RET:.*]]
+; CHECK:       [[COMMON_RET]]:
+; CHECK-NEXT:    ret void
+; CHECK:       [[TRUE2]]:
+; CHECK-NEXT:    store i64 2, ptr [[PTR]], align 8
+; CHECK-NEXT:    br label %[[COMMON_RET]]
+;
+  %cond1 = icmp eq ptr addrspace(0) %ptr, null
+  %cond2 = icmp eq ptr addrspace(0) %ptr, null
+  br i1 %cond1, label %true1, label %false1
+
+true1:
+  br i1 %cond2, label %true2, label %false2
+
+false1:
+  store i64 1, ptr addrspace(0) %ptr, align 8
+  br label %true1
+
+true2:
+  store i64 2, ptr addrspace(0) %ptr, align 8
+  ret void
+
+false2:
+  store i64 3, ptr addrspace(0) %ptr, align 8
+  ret void
+}
+
+;; We should not introduce ptrtoint instructions with unstable pointers
+define void @test_default_inttoptr_base(ptr addrspace(0) align 8 %ptr) {
+; CHECK-LABEL: define void @test_default_inttoptr_base(
+; CHECK-SAME: ptr align 8 [[PTR:%.*]]) {
+; CHECK-NEXT:    [[MAGICPTR:%.*]] = ptrtoint ptr [[PTR]] to i64
+; CHECK-NEXT:    [[COND:%.*]] = icmp eq i64 [[MAGICPTR]], 4
+; CHECK-NEXT:    br i1 [[COND]], label %[[TRUE2:.*]], label %[[FALSE1:.*]]
+; CHECK:       [[FALSE1]]:
+; CHECK-NEXT:    store i64 1, ptr [[PTR]], align 8
+; CHECK-NEXT:    store i64 3, ptr [[PTR]], align 8
+; CHECK-NEXT:    br label %[[COMMON_RET:.*]]
+; CHECK:       [[COMMON_RET]]:
+; CHECK-NEXT:    ret void
+; CHECK:       [[TRUE2]]:
+; CHECK-NEXT:    store i64 2, ptr [[PTR]], align 8
+; CHECK-NEXT:    br label %[[COMMON_RET]]
+;
+  %cond1 = icmp eq ptr addrspace(0) %ptr, inttoptr (i32 4 to ptr addrspace(0))
+  %cond2 = icmp eq ptr addrspace(0) %ptr, inttoptr (i32 4 to ptr addrspace(0))
+  br i1 %cond1, label %true1, label %false1
+
+true1:
+  br i1 %cond2, label %true2, label %false2
+
+false1:
+  store i64 1, ptr addrspace(0) %ptr, align 8
+  br label %true1
+
+true2:
+  store i64 2, ptr addrspace(0) %ptr, align 8
+  ret void
+
+false2:
+  store i64 3, ptr addrspace(0) %ptr, align 8
+  ret void
+}
+
+;; We should not introduce ptrtoint instructions with unstable pointers
+define void @test_default_mixed_base(ptr addrspace(0) align 8 %ptr) {
+; CHECK-LABEL: define void @test_default_mixed_base(
+; CHECK-SAME: ptr align 8 [[PTR:%.*]]) {
+; CHECK-NEXT:    [[COND2:%.*]] = icmp eq ptr [[PTR]], null
+; CHECK-NEXT:    [[MAGICPTR:%.*]] = ptrtoint ptr [[PTR]] to i64
+; CHECK-NEXT:    [[COND:%.*]] = icmp eq i64 [[MAGICPTR]], 4
+; CHECK-NEXT:    br i1 [[COND]], label %[[FALSE2:.*]], label %[[FALSE1:.*]]
+; CHECK:       [[FALSE1]]:
+; CHECK-NEXT:    store i64 1, ptr [[PTR]], align 8
+; CHECK-NEXT:    br i1 [[COND2]], label %[[TRUE2:.*]], label %[[FALSE2]]
+; CHECK:       [[COMMON_RET:.*]]:
+; CHECK-NEXT:    ret void
+; CHECK:       [[TRUE2]]:
+; CHECK-NEXT:    store i64 2, ptr [[PTR]], align 8
+; CHECK-NEXT:    br label %[[COMMON_RET]]
+; CHECK:       [[FALSE2]]:
+; CHECK-NEXT:    store i64 3, ptr [[PTR]], align 8
+; CHECK-NEXT:    br label %[[COMMON_RET]]
+;
+  %cond1 = icmp eq ptr addrspace(0) %ptr, inttoptr (i32 4 to ptr addrspace(0))
+  %cond2 = icmp eq ptr addrspace(0) %ptr, null
+  br i1 %cond1, label %true1, label %false1
+
+true1:
+  br i1 %cond2, label %true2, label %false2
+
+false1:
+  store i64 1, ptr addrspace(0) %ptr, align 8
+  br label %true1
+
+true2:
+  store i64 2, ptr addrspace(0) %ptr, align 8
+  ret void
+
+false2:
+  store i64 3, ptr addrspace(0) %ptr, align 8
+  ret void
+}
+
+;; We should not introduce ptrtoint instructions with unstable pointers
+define void @test_unstable_null_base(ptr addrspace(1) align 8 %ptr) {
+; CHECK-LABEL: define void @test_unstable_null_base(
+; CHECK-SAME: ptr addrspace(1) align 8 [[PTR:%.*]]) {
+; CHECK-NEXT:    [[COND1:%.*]] = icmp eq ptr addrspace(1) [[PTR]], null
+; CHECK-NEXT:    [[COND2:%.*]] = icmp eq ptr addrspace(1) [[PTR]], null
+; CHECK-NEXT:    br i1 [[COND1]], label %[[TRUE1:.*]], label %[[FALSE1:.*]]
+; CHECK:       [[TRUE1]]:
+; CHECK-NEXT:    br i1 [[COND2]], label %[[TRUE2:.*]], label %[[FALSE2:.*]]
+; CHECK:       [[FALSE1]]:
+; CHECK-NEXT:    store i64 1, ptr addrspace(1) [[PTR]], align 8
+; CHECK-NEXT:    br label %[[TRUE1]]
+; CHECK:       [[COMMON_RET:.*]]:
+; CHECK-NEXT:    ret void
+; CHECK:       [[TRUE2]]:
+; CHECK-NEXT:    store i64 2, ptr addrspace(1) [[PTR]], align 8
+; CHECK-NEXT:    br label %[[COMMON_RET]]
+; CHECK:       [[FALSE2]]:
+; CHECK-NEXT:    store i64 3, ptr addrspace(1) [[PTR]], align 8
+; CHECK-NEXT:    br label %[[COMMON_RET]]
+;
   %cond1 = icmp eq ptr addrspace(1) %ptr, null
   %cond2 = icmp eq ptr addrspace(1) %ptr, null
   br i1 %cond1, label %true1, label %false1
@@ -26,3 +157,200 @@ false2:
   store i64 3, ptr addrspace(1) %ptr, align 8
   ret void
 }
+
+;; We should not introduce ptrtoint instructions with unstable pointers
+define void @test_unstable_inttoptr_base(ptr addrspace(1) align 8 %ptr) {
+; CHECK-LABEL: define void @test_unstable_inttoptr_base(
+; CHECK-SAME: ptr addrspace(1) align 8 [[PTR:%.*]]) {
+; CHECK-NEXT:    [[COND1:%.*]] = icmp eq ptr addrspace(1) [[PTR]], inttoptr (i32 4 to ptr addrspace(1))
+; CHECK-NEXT:    [[COND2:%.*]] = icmp eq ptr addrspace(1) [[PTR]], inttoptr (i32 4 to ptr addrspace(1))
+; CHECK-NEXT:    br i1 [[COND1]], label %[[TRUE1:.*]], label %[[FALSE1:.*]]
+; CHECK:       [[TRUE1]]:
+; CHECK-NEXT:    br i1 [[COND2]], label %[[TRUE2:.*]], label %[[FALSE2:.*]]
+; CHECK:       [[FALSE1]]:
+; CHECK-NEXT:    store i64 1, ptr addrspace(1) [[PTR]], align 8
+; CHECK-NEXT:    br label %[[TRUE1]]
+; CHECK:       [[COMMON_RET:.*]]:
+; CHECK-NEXT:    ret void
+; CHECK:       [[TRUE2]]:
+; CHECK-NEXT:    store i64 2, ptr addrspace(1) [[PTR]], align 8
+; CHECK-NEXT:    br label %[[COMMON_RET]]
+; CHECK:       [[FALSE2]]:
+; CHECK-NEXT:    store i64 3, ptr addrspace(1) [[PTR]], align 8
+; CHECK-NEXT:    br label %[[COMMON_RET]]
+;
+  %cond1 = icmp eq ptr addrspace(1) %ptr, inttoptr (i32 4 to ptr addrspace(1))
+  %cond2 = icmp eq ptr addrspace(1) %ptr, inttoptr (i32 4 to ptr addrspace(1))
+  br i1 %cond1, label %true1, label %false1
+
+true1:
+  br i1 %cond2, label %true2, label %false2
+
+false1:
+  store i64 1, ptr addrspace(1) %ptr, align 8
+  br label %true1
+
+true2:
+  store i64 2, ptr addrspace(1) %ptr, align 8
+  ret void
+
+false2:
+  store i64 3, ptr addrspace(1) %ptr, align 8
+  ret void
+}
+
+;; We should not introduce ptrtoint instructions with unstable pointers
+define void @test_unstable_mixed_base(ptr addrspace(1) align 8 %ptr) {
+; CHECK-LABEL: define void @test_unstable_mixed_base(
+; CHECK-SAME: ptr addrspace(1) align 8 [[PTR:%.*]]) {
+; CHECK-NEXT:    [[COND1:%.*]] = icmp eq ptr addrspace(1) [[PTR]], inttoptr (i32 4 to ptr addrspace(1))
+; CHECK-NEXT:    [[COND2:%.*]] = icmp eq ptr addrspace(1) [[PTR]], null
+; CHECK-NEXT:    br i1 [[COND1]], label %[[TRUE1:.*]], label %[[FALSE1:.*]]
+; CHECK:       [[TRUE1]]:
+; CHECK-NEXT:    br i1 [[COND2]], label %[[TRUE2:.*]], label %[[FALSE2:.*]]
+; CHECK:       [[FALSE1]]:
+; CHECK-NEXT:    store i64 1, ptr addrspace(1) [[PTR]], align 8
+; CHECK-NEXT:    br label %[[TRUE1]]
+; CHECK:       [[COMMON_RET:.*]]:
+; CHECK-NEXT:    ret void
+; CHECK:       [[TRUE2]]:
+; CHECK-NEXT:    store i64 2, ptr addrspace(1) [[PTR]], align 8
+; CHECK-NEXT:    br label %[[COMMON_RET]]
+; CHECK:       [[FALSE2]]:
+; CHECK-NEXT:    store i64 3, ptr addrspace(1) [[PTR]], align 8
+; CHECK-NEXT:    br label %[[COMMON_RET]]
+;
+  %cond1 = icmp eq ptr addrspace(1) %ptr, inttoptr (i32 4 to ptr addrspace(1))
+  %cond2 = icmp eq ptr addrspace(1) %ptr, null
+  br i1 %cond1, label %true1, label %false1
+
+true1:
+  br i1 %cond2, label %true2, label %false2
+
+false1:
+  store i64 1, ptr addrspace(1) %ptr, align 8
+  br label %true1
+
+true2:
+  store i64 2, ptr addrspace(1) %ptr, align 8
+  ret void
+
+false2:
+  store i64 3, ptr addrspace(1) %ptr, align 8
+  ret void
+}
+
+;; This transformation is fine for pointers with external state.
+;; TODO: it would probably be better to just emit a pointer compare against null.
+define void @test_external_null_base(ptr addrspace(2) align 8 %ptr) {
+; CHECK-LABEL: define void @test_external_null_base(
+; CHECK-SAME: ptr addrspace(2) align 8 [[PTR:%.*]]) {
+; CHECK-NEXT:    [[MAGICPTR:%.*]] = ptrtoint ptr addrspace(2) [[PTR]] to i64
+; CHECK-NEXT:    [[COND:%.*]] = icmp eq i64 [[MAGICPTR]], 0
+; CHECK-NEXT:    br i1 [[COND]], label %[[TRUE2:.*]], label %[[FALSE1:.*]]
+; CHECK:       [[FALSE1]]:
+; CHECK-NEXT:    store i64 1, ptr addrspace(2) [[PTR]], align 8
+; CHECK-NEXT:    store i64 3, ptr addrspace(2) [[PTR]], align 8
+; CHECK-NEXT:    br label %[[COMMON_RET:.*]]
+; CHECK:       [[COMMON_RET]]:
+; CHECK-NEXT:    ret void
+; CHECK:       [[TRUE2]]:
+; CHECK-NEXT:    store i64 2, ptr addrspace(2) [[PTR]], align 8
+; CHECK-NEXT:    br label %[[COMMON_RET]]
+;
+  %cond1 = icmp eq ptr addrspace(2) %ptr, null
+  %cond2 = icmp eq ptr addrspace(2) %ptr, null
+  br i1 %cond1, label %true1, label %false1
+
+true1:
+  br i1 %cond2, label %true2, label %false2
+
+false1:
+  store i64 1, ptr addrspace(2) %ptr, align 8
+  br label %true1
+
+true2:
+  store i64 2, ptr addrspace(2) %ptr, align 8
+  ret void
+
+false2:
+  store i64 3, ptr addrspace(2) %ptr, align 8
+  ret void
+}
+
+;; This transformation is fine for pointers with external state (even with inttoptr).
+define void @test_external_inttoptr_base(ptr addrspace(2) align 8 %ptr) {
+; CHECK-LABEL: define void @test_external_inttoptr_base(
+; CHECK-SAME: ptr addrspace(2) align 8 [[PTR:%.*]]) {
+; CHECK-NEXT:    [[MAGICPTR:%.*]] = ptrtoint ptr addrspace(2) [[PTR]] to i64
+; CHECK-NEXT:    [[COND:%.*]] = icmp eq i64 [[MAGICPTR]], 4
+; CHECK-NEXT:    br i1 [[COND]], label %[[TRUE2:.*]], label %[[FALSE1:.*]]
+; CHECK:       [[FALSE1]]:
+; CHECK-NEXT:    store i64 1, ptr addrspace(2) [[PTR]], align 8
+; CHECK-NEXT:    store i64 3, ptr addrspace(2) [[PTR]], align 8
+; CHECK-NEXT:    br label %[[COMMON_RET:.*]]
+; CHECK:       [[COMMON_RET]]:
+; CHECK-NEXT:    ret void
+; CHECK:       [[TRUE2]]:
+; CHECK-NEXT:    store i64 2, ptr addrspace(2) [[PTR]], align 8
+; CHECK-NEXT:    br label %[[COMMON_RET]]
+;
+  %cond1 = icmp eq ptr addrspace(2) %ptr, inttoptr (i32 4 to ptr addrspace(2))
+  %cond2 = icmp eq ptr addrspace(2) %ptr, inttoptr (i32 4 to ptr addrspace(2))
+  br i1 %cond1, label %true1, label %false1
+
+true1:
+  br i1 %cond2, label %true2, label %false2
+
+false1:
+  store i64 1, ptr addrspace(2) %ptr, align 8
+  br label %true1
+
+true2:
+  store i64 2, ptr addrspace(2) %ptr, align 8
+  ret void
+
+false2:
+  store i64 3, ptr addrspace(2) %ptr, align 8
+  ret void
+}
+
+;; This transformation is fine for pointers with external state (even with inttoptr).
+define void @test_external_mixed_base(ptr addrspace(2) align 8 %ptr) {
+; CHECK-LABEL: define void @test_external_mixed_base(
+; CHECK-SAME: ptr addrspace(2) align 8 [[PTR:%.*]]) {
+; CHECK-NEXT:    [[COND2:%.*]] = icmp eq ptr addrspace(2) [[PTR]], null
+; CHECK-NEXT:    [[MAGICPTR:%.*]] = ptrtoint ptr addrspace(2) [[PTR]] to i64
+; CHECK-NEXT:    [[COND:%.*]] = icmp eq i64 [[MAGICPTR]], 4
+; CHECK-NEXT:    br i1 [[COND]], label %[[FALSE2:.*]], label %[[FALSE1:.*]]
+; CHECK:       [[FALSE1]]:
+; CHECK-NEXT:    store i64 1, ptr addrspace(2) [[PTR]], align 8
+; CHECK-NEXT:    br i1 [[COND2]], label %[[TRUE2:.*]], label %[[FALSE2]]
+; CHECK:       [[COMMON_RET:.*]]:
+; CHECK-NEXT:    ret void
+; CHECK:       [[TRUE2]]:
+; CHECK-NEXT:    store i64 2, ptr addrspace(2) [[PTR]], align 8
+; CHECK-NEXT:    br label %[[COMMON_RET]]
+; CHECK:       [[FALSE2]]:
+; CHECK-NEXT:    store i64 3, ptr addrspace(2) [[PTR]], align 8
+; CHECK-NEXT:    br label %[[COMMON_RET]]
+;
+  %cond1 = icmp eq ptr addrspace(2) %ptr, inttoptr (i32 4 to ptr addrspace(2))
+  %cond2 = icmp eq ptr addrspace(2) %ptr, null
+  br i1 %cond1, label %true1, label %false1
+
+true1:
+  br i1 %cond2, label %true2, label %false2
+
+false1:
+  store i64 1, ptr addrspace(2) %ptr, align 8
+  br label %true1
+
+true2:
+  store i64 2, ptr addrspace(2) %ptr, align 8
+  ret void
+
+false2:
+  store i64 3, ptr addrspace(2) %ptr, align 8
+  ret void
+}

diff  --git a/llvm/test/Transforms/SimplifyCFG/switch_create-custom-dl.ll b/llvm/test/Transforms/SimplifyCFG/switch_create-custom-dl.ll
index ddf64591776dd..8103124e3e5a6 100644
--- a/llvm/test/Transforms/SimplifyCFG/switch_create-custom-dl.ll
+++ b/llvm/test/Transforms/SimplifyCFG/switch_create-custom-dl.ll
@@ -1,6 +1,6 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
 ; RUN: opt -S -passes=simplifycfg -simplifycfg-require-and-preserve-domtree=1 -switch-range-to-icmp < %s | FileCheck %s
-target datalayout="p:40:64:64:32"
+target datalayout="p:40:64:64:32-pe200:64:64:64:32-pu201:64:64:64:32"
 
 declare void @foo1()
 
@@ -33,14 +33,13 @@ F:              ; preds = %0
   ret void
 }
 
-; We need to use finer-grained DataLayout properties for non-integral pointers
-; FIXME: Should be using a switch here
 define void @test1_ptr(ptr %V) {
 ; CHECK-LABEL: @test1_ptr(
-; CHECK-NEXT:    [[C1:%.*]] = icmp eq ptr [[V:%.*]], inttoptr (i32 4 to ptr)
-; CHECK-NEXT:    [[C2:%.*]] = icmp eq ptr [[V]], inttoptr (i32 17 to ptr)
-; CHECK-NEXT:    [[CN:%.*]] = or i1 [[C1]], [[C2]]
-; CHECK-NEXT:    br i1 [[CN]], label [[T:%.*]], label [[F:%.*]]
+; CHECK-NEXT:    [[MAGICPTR:%.*]] = ptrtoint ptr [[V:%.*]] to i40
+; CHECK-NEXT:    switch i40 [[MAGICPTR]], label [[F:%.*]] [
+; CHECK-NEXT:      i40 17, label [[T:%.*]]
+; CHECK-NEXT:      i40 4, label [[T]]
+; CHECK-NEXT:    ]
 ; CHECK:       common.ret:
 ; CHECK-NEXT:    ret void
 ; CHECK:       T:
@@ -64,10 +63,11 @@ F:              ; preds = %0
 
 define void @test1_ptr_as1(ptr addrspace(1) %V) {
 ; CHECK-LABEL: @test1_ptr_as1(
-; CHECK-NEXT:    [[C1:%.*]] = icmp eq ptr addrspace(1) [[V:%.*]], inttoptr (i32 4 to ptr addrspace(1))
-; CHECK-NEXT:    [[C2:%.*]] = icmp eq ptr addrspace(1) [[V]], inttoptr (i32 17 to ptr addrspace(1))
-; CHECK-NEXT:    [[CN:%.*]] = or i1 [[C1]], [[C2]]
-; CHECK-NEXT:    br i1 [[CN]], label [[T:%.*]], label [[F:%.*]]
+; CHECK-NEXT:    [[MAGICPTR:%.*]] = ptrtoint ptr addrspace(1) [[V:%.*]] to i40
+; CHECK-NEXT:    switch i40 [[MAGICPTR]], label [[F:%.*]] [
+; CHECK-NEXT:      i40 17, label [[T:%.*]]
+; CHECK-NEXT:      i40 4, label [[T]]
+; CHECK-NEXT:    ]
 ; CHECK:       common.ret:
 ; CHECK-NEXT:    ret void
 ; CHECK:       T:
@@ -89,6 +89,63 @@ F:              ; preds = %0
   ret void
 }
 
+; We also allow the transformation for pointers with external state
+define void @test1_ptr_external_state(ptr addrspace(200) %V) {
+; CHECK-LABEL: @test1_ptr_external_state(
+; CHECK-NEXT:    [[MAGICPTR:%.*]] = ptrtoint ptr addrspace(200) [[V:%.*]] to i64
+; CHECK-NEXT:    switch i64 [[MAGICPTR]], label [[F:%.*]] [
+; CHECK-NEXT:      i64 17, label [[T:%.*]]
+; CHECK-NEXT:      i64 4, label [[T]]
+; CHECK-NEXT:    ]
+; CHECK:       common.ret:
+; CHECK-NEXT:    ret void
+; CHECK:       T:
+; CHECK-NEXT:    call void @foo1()
+; CHECK-NEXT:    br label [[COMMON_RET:%.*]]
+; CHECK:       F:
+; CHECK-NEXT:    call void @foo2()
+; CHECK-NEXT:    br label [[COMMON_RET]]
+;
+  %C1 = icmp eq ptr addrspace(200) %V, inttoptr (i32 4 to ptr addrspace(200))
+  %C2 = icmp eq ptr addrspace(200) %V, inttoptr (i32 17 to ptr addrspace(200))
+  %CN = or i1 %C1, %C2            ; <i1> [#uses=1]
+  br i1 %CN, label %T, label %F
+T:              ; preds = %0
+  call void @foo1( )
+  ret void
+F:              ; preds = %0
+  call void @foo2( )
+  ret void
+}
+
+; But it is not permitted for unstable pointer representations
+define void @test1_ptr_unstable(ptr addrspace(201) %V) {
+; CHECK-LABEL: @test1_ptr_unstable(
+; CHECK-NEXT:    [[C1:%.*]] = icmp eq ptr addrspace(201) [[V:%.*]], inttoptr (i32 4 to ptr addrspace(201))
+; CHECK-NEXT:    [[C2:%.*]] = icmp eq ptr addrspace(201) [[V]], inttoptr (i32 17 to ptr addrspace(201))
+; CHECK-NEXT:    [[CN:%.*]] = or i1 [[C1]], [[C2]]
+; CHECK-NEXT:    br i1 [[CN]], label [[T:%.*]], label [[F:%.*]]
+; CHECK:       common.ret:
+; CHECK-NEXT:    ret void
+; CHECK:       T:
+; CHECK-NEXT:    call void @foo1()
+; CHECK-NEXT:    br label [[COMMON_RET:%.*]]
+; CHECK:       F:
+; CHECK-NEXT:    call void @foo2()
+; CHECK-NEXT:    br label [[COMMON_RET]]
+;
+  %C1 = icmp eq ptr addrspace(201) %V, inttoptr (i32 4 to ptr addrspace(201))
+  %C2 = icmp eq ptr addrspace(201) %V, inttoptr (i32 17 to ptr addrspace(201))
+  %CN = or i1 %C1, %C2            ; <i1> [#uses=1]
+  br i1 %CN, label %T, label %F
+T:              ; preds = %0
+  call void @foo1( )
+  ret void
+F:              ; preds = %0
+  call void @foo2( )
+  ret void
+}
+
 define void @test2(i32 %V) {
 ; CHECK-LABEL: @test2(
 ; CHECK-NEXT:    switch i32 [[V:%.*]], label [[T:%.*]] [


        


More information about the llvm-commits mailing list