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
25 changes: 19 additions & 6 deletions llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2760,21 +2760,34 @@ Instruction *InstCombinerImpl::visitSub(BinaryOperator &I) {
// Optimize pointer differences into the same array into a size. Consider:
// &A[10] - &A[0]: we should compile this to "10".
Value *LHSOp, *RHSOp;
if (match(Op0, m_PtrToInt(m_Value(LHSOp))) &&
match(Op1, m_PtrToInt(m_Value(RHSOp))))
if (match(Op0, m_PtrToIntOrAddr(m_Value(LHSOp))) &&
match(Op1, m_PtrToIntOrAddr(m_Value(RHSOp))))
if (Value *Res = OptimizePointerDifference(LHSOp, RHSOp, I.getType(),
I.hasNoUnsignedWrap()))
return replaceInstUsesWith(I, Res);

// trunc(p)-trunc(q) -> trunc(p-q)
if (match(Op0, m_Trunc(m_PtrToInt(m_Value(LHSOp)))) &&
match(Op1, m_Trunc(m_PtrToInt(m_Value(RHSOp)))))
if (match(Op0, m_Trunc(m_PtrToIntOrAddr(m_Value(LHSOp)))) &&
match(Op1, m_Trunc(m_PtrToIntOrAddr(m_Value(RHSOp)))))
if (Value *Res = OptimizePointerDifference(LHSOp, RHSOp, I.getType(),
/* IsNUW */ false))
return replaceInstUsesWith(I, Res);

if (match(Op0, m_ZExt(m_PtrToIntSameSize(DL, m_Value(LHSOp)))) &&
match(Op1, m_ZExtOrSelf(m_PtrToInt(m_Value(RHSOp))))) {
auto MatchSubOfZExtOfPtrToIntOrAddr = [&]() {
if (match(Op0, m_ZExt(m_PtrToIntSameSize(DL, m_Value(LHSOp)))) &&
match(Op1, m_ZExt(m_PtrToIntSameSize(DL, m_Value(RHSOp)))))
return true;
if (match(Op0, m_ZExt(m_PtrToAddr(m_Value(LHSOp)))) &&
match(Op1, m_ZExt(m_PtrToAddr(m_Value(RHSOp)))))
return true;
// Special case for non-canonical ptrtoint in constant expression,
// where the zext has been folded into the ptrtoint.
if (match(Op0, m_ZExt(m_PtrToIntSameSize(DL, m_Value(LHSOp)))) &&
match(Op1, m_PtrToInt(m_Value(RHSOp))))
return true;
return false;
};
if (MatchSubOfZExtOfPtrToIntOrAddr()) {
if (auto *GEP = dyn_cast<GEPOperator>(LHSOp)) {
if (GEP->getPointerOperand() == RHSOp) {
if (GEP->hasNoUnsignedWrap() || GEP->hasNoUnsignedSignedWrap()) {
Expand Down
131 changes: 131 additions & 0 deletions llvm/test/Transforms/InstCombine/ptrtoaddr.ll
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,134 @@ define i128 @ptrtoaddr_sext(ptr %p) {
%ext = sext i64 %p.addr to i128
ret i128 %ext
}

define i64 @sub_ptrtoaddr(ptr %p, i64 %offset) {
; CHECK-LABEL: define i64 @sub_ptrtoaddr(
; CHECK-SAME: ptr [[P:%.*]], i64 [[OFFSET:%.*]]) {
; CHECK-NEXT: ret i64 [[OFFSET]]
;
%p2 = getelementptr i8, ptr %p, i64 %offset
%p.addr = ptrtoaddr ptr %p to i64
%p2.addr = ptrtoaddr ptr %p2 to i64
%sub = sub i64 %p2.addr, %p.addr
ret i64 %sub
}

define i64 @sub_ptrtoint_ptrtoaddr(ptr %p, i64 %offset) {
; CHECK-LABEL: define i64 @sub_ptrtoint_ptrtoaddr(
; CHECK-SAME: ptr [[P:%.*]], i64 [[OFFSET:%.*]]) {
; CHECK-NEXT: ret i64 [[OFFSET]]
;
%p2 = getelementptr i8, ptr %p, i64 %offset
%p.int = ptrtoint ptr %p to i64
%p2.addr = ptrtoaddr ptr %p2 to i64
%sub = sub i64 %p2.addr, %p.int
ret i64 %sub
}

define i32 @sub_ptrtoaddr_addrsize(ptr addrspace(1) %p, i32 %offset) {
; CHECK-LABEL: define i32 @sub_ptrtoaddr_addrsize(
; CHECK-SAME: ptr addrspace(1) [[P:%.*]], i32 [[OFFSET:%.*]]) {
; CHECK-NEXT: ret i32 [[OFFSET]]
;
%p2 = getelementptr i8, ptr addrspace(1) %p, i32 %offset
%p.addr = ptrtoaddr ptr addrspace(1) %p to i32
%p2.addr = ptrtoaddr ptr addrspace(1) %p2 to i32
%sub = sub i32 %p2.addr, %p.addr
ret i32 %sub
}

define i32 @sub_trunc_ptrtoaddr(ptr %p, i64 %offset) {
; CHECK-LABEL: define i32 @sub_trunc_ptrtoaddr(
; CHECK-SAME: ptr [[P:%.*]], i64 [[OFFSET:%.*]]) {
; CHECK-NEXT: [[SUB:%.*]] = trunc i64 [[OFFSET]] to i32
; CHECK-NEXT: ret i32 [[SUB]]
;
%p2 = getelementptr i8, ptr %p, i64 %offset
%p.addr = ptrtoaddr ptr %p to i64
%p2.addr = ptrtoaddr ptr %p2 to i64
%p.addr.trunc = trunc i64 %p.addr to i32
%p2.addr.trunc = trunc i64 %p2.addr to i32
%sub = sub i32 %p2.addr.trunc, %p.addr.trunc
ret i32 %sub
}

define i16 @sub_trunc_ptrtoaddr_addrsize(ptr addrspace(1) %p, i32 %offset) {
; CHECK-LABEL: define i16 @sub_trunc_ptrtoaddr_addrsize(
; CHECK-SAME: ptr addrspace(1) [[P:%.*]], i32 [[OFFSET:%.*]]) {
; CHECK-NEXT: [[SUB:%.*]] = trunc i32 [[OFFSET]] to i16
; CHECK-NEXT: ret i16 [[SUB]]
;
%p2 = getelementptr i8, ptr addrspace(1) %p, i32 %offset
%p.addr = ptrtoaddr ptr addrspace(1) %p to i32
%p2.addr = ptrtoaddr ptr addrspace(1) %p2 to i32
%p.addr.trunc = trunc i32 %p.addr to i16
%p2.addr.trunc = trunc i32 %p2.addr to i16
%sub = sub i16 %p2.addr.trunc, %p.addr.trunc
ret i16 %sub
}

define i16 @sub_trunc_ptrtoint_ptrtoaddr_addrsize(ptr addrspace(1) %p, i32 %offset) {
; CHECK-LABEL: define i16 @sub_trunc_ptrtoint_ptrtoaddr_addrsize(
; CHECK-SAME: ptr addrspace(1) [[P:%.*]], i32 [[OFFSET:%.*]]) {
; CHECK-NEXT: [[SUB:%.*]] = trunc i32 [[OFFSET]] to i16
; CHECK-NEXT: ret i16 [[SUB]]
;
%p2 = getelementptr i8, ptr addrspace(1) %p, i32 %offset
%p.int = ptrtoint ptr addrspace(1) %p to i64
%p2.addr = ptrtoaddr ptr addrspace(1) %p2 to i32
%p.int.trunc = trunc i64 %p.int to i16
%p2.addr.trunc = trunc i32 %p2.addr to i16
%sub = sub i16 %p2.addr.trunc, %p.int.trunc
ret i16 %sub
}

define i128 @sub_zext_ptrtoaddr(ptr %p, i64 %offset) {
; CHECK-LABEL: define i128 @sub_zext_ptrtoaddr(
; CHECK-SAME: ptr [[P:%.*]], i64 [[OFFSET:%.*]]) {
; CHECK-NEXT: [[SUB:%.*]] = zext i64 [[OFFSET]] to i128
; CHECK-NEXT: ret i128 [[SUB]]
;
%p2 = getelementptr nuw i8, ptr %p, i64 %offset
%p.addr = ptrtoaddr ptr %p to i64
%p2.addr = ptrtoaddr ptr %p2 to i64
%p.addr.ext = zext i64 %p.addr to i128
%p2.addr.ext = zext i64 %p2.addr to i128
%sub = sub i128 %p2.addr.ext, %p.addr.ext
ret i128 %sub
}

define i64 @sub_zext_ptrtoaddr_addrsize(ptr addrspace(1) %p, i32 %offset) {
; CHECK-LABEL: define i64 @sub_zext_ptrtoaddr_addrsize(
; CHECK-SAME: ptr addrspace(1) [[P:%.*]], i32 [[OFFSET:%.*]]) {
; CHECK-NEXT: [[SUB:%.*]] = zext i32 [[OFFSET]] to i64
; CHECK-NEXT: ret i64 [[SUB]]
;
%p2 = getelementptr nuw i8, ptr addrspace(1) %p, i32 %offset
%p.addr = ptrtoaddr ptr addrspace(1) %p to i32
%p2.addr = ptrtoaddr ptr addrspace(1) %p2 to i32
%p.addr.ext = zext i32 %p.addr to i64
%p2.addr.ext = zext i32 %p2.addr to i64
%sub = sub i64 %p2.addr.ext, %p.addr.ext
ret i64 %sub
}

define i128 @sub_zext_ptrtoint_ptrtoaddr_addrsize(ptr addrspace(1) %p, i32 %offset) {
; CHECK-LABEL: define i128 @sub_zext_ptrtoint_ptrtoaddr_addrsize(
; CHECK-SAME: ptr addrspace(1) [[P:%.*]], i32 [[OFFSET:%.*]]) {
; CHECK-NEXT: [[P2:%.*]] = getelementptr nuw i8, ptr addrspace(1) [[P]], i32 [[OFFSET]]
; CHECK-NEXT: [[P_INT:%.*]] = ptrtoint ptr addrspace(1) [[P]] to i64
; CHECK-NEXT: [[P2_ADDR:%.*]] = ptrtoaddr ptr addrspace(1) [[P2]] to i32
; CHECK-NEXT: [[P_INT_EXT:%.*]] = zext i64 [[P_INT]] to i128
; CHECK-NEXT: [[P2_ADDR_EXT:%.*]] = zext i32 [[P2_ADDR]] to i128
; CHECK-NEXT: [[SUB:%.*]] = sub nsw i128 [[P2_ADDR_EXT]], [[P_INT_EXT]]
; CHECK-NEXT: ret i128 [[SUB]]
;
%p2 = getelementptr nuw i8, ptr addrspace(1) %p, i32 %offset
%p.int = ptrtoint ptr addrspace(1) %p to i64
%p2.addr = ptrtoaddr ptr addrspace(1) %p2 to i32
%p.int.ext = zext i64 %p.int to i128
%p2.addr.ext = zext i32 %p2.addr to i128
%sub = sub i128 %p2.addr.ext, %p.int.ext
ret i128 %sub
}
33 changes: 32 additions & 1 deletion llvm/test/Transforms/InstCombine/sub-gep.ll
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -S -passes=instcombine < %s | FileCheck %s

target datalayout = "e-p:64:64:64-p1:16:16:16-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-p2:32:32"
target datalayout = "e-p:64:64:64-p1:16:16:16-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-p2:32:32-p3:32:32:32:16"

define i64 @test_inbounds(ptr %base, i64 %idx) {
; CHECK-LABEL: @test_inbounds(
Expand Down Expand Up @@ -505,6 +505,23 @@ define i64 @negative_zext_ptrtoint_sub_ptrtoint_as2_nuw(i32 %offset) {
ret i64 %D
}

define i64 @negative_zext_ptrtoint_sub_zext_ptrtoint_as2_nuw_truncating(i32 %offset) {
; CHECK-LABEL: @negative_zext_ptrtoint_sub_zext_ptrtoint_as2_nuw_truncating(
; CHECK-NEXT: [[A:%.*]] = getelementptr nuw bfloat, ptr addrspace(2) @Arr_as2, i32 [[OFFSET:%.*]]
; CHECK-NEXT: [[A_IDX:%.*]] = ptrtoint ptr addrspace(2) [[A]] to i32
; CHECK-NEXT: [[E:%.*]] = zext i32 [[A_IDX]] to i64
; CHECK-NEXT: [[D:%.*]] = zext i16 ptrtoint (ptr addrspace(2) @Arr_as2 to i16) to i64
; CHECK-NEXT: [[E1:%.*]] = sub nsw i64 [[E]], [[D]]
; CHECK-NEXT: ret i64 [[E1]]
;
%A = getelementptr nuw bfloat, ptr addrspace(2) @Arr_as2, i32 %offset
%B = ptrtoint ptr addrspace(2) %A to i32
%C = zext i32 %B to i64
%D = zext i16 ptrtoint (ptr addrspace(2) @Arr_as2 to i16) to i64
%E = sub i64 %C, %D
ret i64 %E
}

define i64 @ptrtoint_sub_zext_ptrtoint_as2_inbounds_local(ptr addrspace(2) %p, i32 %offset) {
; CHECK-LABEL: @ptrtoint_sub_zext_ptrtoint_as2_inbounds_local(
; CHECK-NEXT: [[A:%.*]] = getelementptr inbounds bfloat, ptr addrspace(2) [[P:%.*]], i32 [[OFFSET:%.*]]
Expand Down Expand Up @@ -614,6 +631,20 @@ define i64 @negative_zext_ptrtoint_sub_ptrtoint_as2_nuw_local(ptr addrspace(2) %
ret i64 %D
}

define i64 @zext_ptrtoint_sub_ptrtoint_as3_nuw_local(ptr addrspace(3) %p, i16 %offset) {
; CHECK-LABEL: @zext_ptrtoint_sub_ptrtoint_as3_nuw_local(
; CHECK-NEXT: [[SUB:%.*]] = zext i16 [[GEP_IDX:%.*]] to i64
; CHECK-NEXT: ret i64 [[SUB]]
;
%gep = getelementptr nuw i8, ptr addrspace(3) %p, i16 %offset
%gep.int = ptrtoint ptr addrspace(3) %gep to i32
%p.int = ptrtoint ptr addrspace(3) %p to i32
%gep.int.ext = zext i32 %gep.int to i64
%p.int.ext = zext i32 %p.int to i64
%sub = sub i64 %gep.int.ext, %p.int.ext
ret i64 %sub
}

define i64 @test30(ptr %foo, i64 %i, i64 %j) {
; CHECK-LABEL: @test30(
; CHECK-NEXT: [[GEP1_IDX:%.*]] = shl nsw i64 [[I:%.*]], 2
Expand Down