[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
This commit is contained in:
parent
dde000a7d6
commit
d03bfc6c0a
@ -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");
|
||||
}
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
@ -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:%.*]] [
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user