[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