diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp index 73ec4514f8414..9bee523c7b7e5 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp @@ -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(LHSOp)) { if (GEP->getPointerOperand() == RHSOp) { if (GEP->hasNoUnsignedWrap() || GEP->hasNoUnsignedSignedWrap()) { diff --git a/llvm/test/Transforms/InstCombine/ptrtoaddr.ll b/llvm/test/Transforms/InstCombine/ptrtoaddr.ll index 410c43c807ed9..f19cca8f808c8 100644 --- a/llvm/test/Transforms/InstCombine/ptrtoaddr.ll +++ b/llvm/test/Transforms/InstCombine/ptrtoaddr.ll @@ -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 +} diff --git a/llvm/test/Transforms/InstCombine/sub-gep.ll b/llvm/test/Transforms/InstCombine/sub-gep.ll index 8eeaea1533bcf..ee70137e8fbd7 100644 --- a/llvm/test/Transforms/InstCombine/sub-gep.ll +++ b/llvm/test/Transforms/InstCombine/sub-gep.ll @@ -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( @@ -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:%.*]] @@ -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