Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 13 additions & 11 deletions llvm/lib/Analysis/ConstantFolding.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1495,30 +1495,31 @@ Constant *llvm::ConstantFoldCastOperand(unsigned Opcode, Constant *C,
default:
llvm_unreachable("Missing case");
case Instruction::PtrToAddr:
// TODO: Add some of the ptrtoint folds here as well.
break;
case Instruction::PtrToInt:
if (auto *CE = dyn_cast<ConstantExpr>(C)) {
Constant *FoldedValue = nullptr;
// If the input is a inttoptr, eliminate the pair. This requires knowing
// If the input is an inttoptr, eliminate the pair. This requires knowing
// the width of a pointer, so it can't be done in ConstantExpr::getCast.
if (CE->getOpcode() == Instruction::IntToPtr) {
// zext/trunc the inttoptr to pointer size.
FoldedValue = ConstantFoldIntegerCast(CE->getOperand(0),
DL.getIntPtrType(CE->getType()),
// zext/trunc the inttoptr to pointer/address size.
Type *MidTy = Opcode == Instruction::PtrToInt
? DL.getAddressType(CE->getType())
: DL.getIntPtrType(CE->getType());
FoldedValue = ConstantFoldIntegerCast(CE->getOperand(0), MidTy,
/*IsSigned=*/false, DL);
} else if (auto *GEP = dyn_cast<GEPOperator>(CE)) {
// If we have GEP, we can perform the following folds:
// (ptrtoint (gep null, x)) -> x
// (ptrtoint (gep (gep null, x), y) -> x + y, etc.
// (ptrtoint/ptrtoaddr (gep null, x)) -> x
// (ptrtoint/ptrtoaddr (gep (gep null, x), y) -> x + y, etc.
unsigned BitWidth = DL.getIndexTypeSizeInBits(GEP->getType());
APInt BaseOffset(BitWidth, 0);
auto *Base = cast<Constant>(GEP->stripAndAccumulateConstantOffsets(
DL, BaseOffset, /*AllowNonInbounds=*/true));
if (Base->isNullValue()) {
FoldedValue = ConstantInt::get(CE->getContext(), BaseOffset);
} else {
// ptrtoint (gep i8, Ptr, (sub 0, V)) -> sub (ptrtoint Ptr), V
// ptrtoint/ptrtoaddr (gep i8, Ptr, (sub 0, V))
// -> sub (ptrtoint/ptrtoaddr Ptr), V
if (GEP->getNumIndices() == 1 &&
GEP->getSourceElementType()->isIntegerTy(8)) {
auto *Ptr = cast<Constant>(GEP->getPointerOperand());
Expand All @@ -1528,12 +1529,13 @@ Constant *llvm::ConstantFoldCastOperand(unsigned Opcode, Constant *C,
Sub->getOpcode() == Instruction::Sub &&
Sub->getOperand(0)->isNullValue())
FoldedValue = ConstantExpr::getSub(
ConstantExpr::getPtrToInt(Ptr, IntIdxTy), Sub->getOperand(1));
ConstantExpr::getCast(Opcode, Ptr, IntIdxTy),
Copy link
Member

Choose a reason for hiding this comment

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

I am not sure these folds are valid for unstable GC pointers, but since this has been like this for a long time and I have no detailed knowledge of GC pointer support I imagine it's fine.

Sub->getOperand(1));
}
}
}
if (FoldedValue) {
// Do a zext or trunc to get to the ptrtoint dest size.
// Do a zext or trunc to get to the ptrtoint/ptrtoaddr dest size.
return ConstantFoldIntegerCast(FoldedValue, DestTy, /*IsSigned=*/false,
DL);
}
Expand Down
46 changes: 41 additions & 5 deletions llvm/test/Transforms/InstCombine/ptrtoaddr.ll
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
; RUN: opt < %s -passes=instcombine -S | FileCheck %s
target datalayout = "p1:64:64:64:32"

; The ptrtoaddr folds are also valid for pointers that have external state.
target datalayout = "pe1:64:64:64:32"

@g = external global i8
@g2 = external global i8

@g.as1 = external addrspace(1) global i8
@g2.as1 = external addrspace(1) global i8

define i32 @ptrtoaddr_inttoptr_arg(i32 %a) {
; CHECK-LABEL: define i32 @ptrtoaddr_inttoptr_arg(
Expand All @@ -24,14 +32,14 @@ define i32 @ptrtoaddr_inttoptr() {

define i32 @ptrtoaddr_inttoptr_diff_size1() {
; CHECK-LABEL: define i32 @ptrtoaddr_inttoptr_diff_size1() {
; CHECK-NEXT: ret i32 ptrtoaddr (ptr addrspace(1) inttoptr (i64 -1 to ptr addrspace(1)) to i32)
; CHECK-NEXT: ret i32 -1
;
ret i32 ptrtoaddr (ptr addrspace(1) inttoptr (i64 -1 to ptr addrspace(1)) to i32)
}

define i32 @ptrtoaddr_inttoptr_diff_size2() {
; CHECK-LABEL: define i32 @ptrtoaddr_inttoptr_diff_size2() {
; CHECK-NEXT: ret i32 ptrtoaddr (ptr addrspace(1) inttoptr (i16 -1 to ptr addrspace(1)) to i32)
; CHECK-NEXT: ret i32 65535
;
ret i32 ptrtoaddr (ptr addrspace(1) inttoptr (i16 -1 to ptr addrspace(1)) to i32)
}
Expand All @@ -52,14 +60,42 @@ define i64 @ptr2addr2_inttoptr_noas2() {

define i64 @ptrtoaddr_inttoptr_noas_diff_size1() {
; CHECK-LABEL: define i64 @ptrtoaddr_inttoptr_noas_diff_size1() {
; CHECK-NEXT: ret i64 ptrtoaddr (ptr inttoptr (i32 -1 to ptr) to i64)
; CHECK-NEXT: ret i64 4294967295
;
ret i64 ptrtoaddr (ptr inttoptr (i32 -1 to ptr) to i64)
}

define i64 @ptrtoaddr_inttoptr_noas_diff_size2() {
; CHECK-LABEL: define i64 @ptrtoaddr_inttoptr_noas_diff_size2() {
; CHECK-NEXT: ret i64 ptrtoaddr (ptr inttoptr (i128 -1 to ptr) to i64)
; CHECK-NEXT: ret i64 -1
;
ret i64 ptrtoaddr (ptr inttoptr (i128 -1 to ptr) to i64)
}

define i64 @ptrtoaddr_gep_null() {
; CHECK-LABEL: define i64 @ptrtoaddr_gep_null() {
; CHECK-NEXT: ret i64 42
;
ret i64 ptrtoaddr (ptr getelementptr (i8, ptr null, i64 42) to i64)
}

define i32 @ptrtoaddr_gep_null_addrsize() {
; CHECK-LABEL: define i32 @ptrtoaddr_gep_null_addrsize() {
; CHECK-NEXT: ret i32 42
;
ret i32 ptrtoaddr (ptr addrspace(1) getelementptr (i8, ptr addrspace(1) null, i32 42) to i32)
}

define i64 @ptrtoaddr_gep_sub() {
; CHECK-LABEL: define i64 @ptrtoaddr_gep_sub() {
; CHECK-NEXT: ret i64 sub (i64 ptrtoaddr (ptr @g to i64), i64 ptrtoaddr (ptr @g2 to i64))
;
ret i64 ptrtoaddr (ptr getelementptr (i8, ptr @g, i64 sub (i64 0, i64 ptrtoaddr (ptr @g2 to i64))) to i64)
}

define i32 @ptrtoaddr_gep_sub_addrsize() {
; CHECK-LABEL: define i32 @ptrtoaddr_gep_sub_addrsize() {
; CHECK-NEXT: ret i32 sub (i32 ptrtoaddr (ptr addrspace(1) @g.as1 to i32), i32 ptrtoaddr (ptr addrspace(1) @g2.as1 to i32))
;
ret i32 ptrtoaddr (ptr addrspace(1) getelementptr (i8, ptr addrspace(1) @g.as1, i32 sub (i32 0, i32 ptrtoaddr (ptr addrspace(1) @g2.as1 to i32))) to i32)
}