diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp index 21588aca51275..fe5e478ef371d 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp @@ -2631,6 +2631,23 @@ Instruction *InstCombinerImpl::visitSub(BinaryOperator &I) { /* 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))))) { + if (auto *GEP = dyn_cast(LHSOp)) { + if (GEP->getPointerOperand() == RHSOp) { + if (GEP->hasNoUnsignedWrap() || GEP->hasNoUnsignedSignedWrap()) { + Value *Offset = EmitGEPOffset(GEP); + Value *Res = GEP->hasNoUnsignedWrap() + ? Builder.CreateZExt( + Offset, I.getType(), "", + /*IsNonNeg=*/GEP->hasNoUnsignedSignedWrap()) + : Builder.CreateSExt(Offset, I.getType()); + return replaceInstUsesWith(I, Res); + } + } + } + } + // Canonicalize a shifty way to code absolute value to the common pattern. // There are 2 potential commuted variants. // We're relying on the fact that we only do this transform when the shift has diff --git a/llvm/test/Transforms/InstCombine/sub-gep.ll b/llvm/test/Transforms/InstCombine/sub-gep.ll index b773d106b2c98..f7a54ab2141bd 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" +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" define i64 @test_inbounds(ptr %base, i64 %idx) { ; CHECK-LABEL: @test_inbounds( @@ -270,6 +270,70 @@ define i64 @test25(ptr %P, i64 %A){ ret i64 %G } +define i64 @zext_ptrtoint_sub_ptrtoint(ptr %p, i32 %offset) { +; CHECK-LABEL: @zext_ptrtoint_sub_ptrtoint( +; CHECK-NEXT: [[TMP1:%.*]] = sext i32 [[OFFSET:%.*]] to i64 +; CHECK-NEXT: [[A:%.*]] = getelementptr bfloat, ptr @Arr, i64 [[TMP1]] +; CHECK-NEXT: [[TMP2:%.*]] = ptrtoint ptr [[A]] to i64 +; CHECK-NEXT: [[C:%.*]] = and i64 [[TMP2]], 4294967294 +; CHECK-NEXT: [[D:%.*]] = sub i64 [[C]], ptrtoint (ptr @Arr to i64) +; CHECK-NEXT: ret i64 [[D]] +; + %A = getelementptr bfloat, ptr @Arr, i32 %offset + %B = ptrtoint ptr %A to i32 + %C = zext i32 %B to i64 + %D = sub i64 %C, ptrtoint (ptr @Arr to i64) + ret i64 %D +} + +define i64 @ptrtoint_sub_zext_ptrtoint(ptr %p, i32 %offset) { +; CHECK-LABEL: @ptrtoint_sub_zext_ptrtoint( +; CHECK-NEXT: [[TMP1:%.*]] = sext i32 [[OFFSET:%.*]] to i64 +; CHECK-NEXT: [[A:%.*]] = getelementptr bfloat, ptr @Arr, i64 [[TMP1]] +; CHECK-NEXT: [[TMP2:%.*]] = ptrtoint ptr [[A]] to i64 +; CHECK-NEXT: [[C:%.*]] = and i64 [[TMP2]], 4294967294 +; CHECK-NEXT: [[D:%.*]] = sub i64 ptrtoint (ptr @Arr to i64), [[C]] +; CHECK-NEXT: ret i64 [[D]] +; + %A = getelementptr bfloat, ptr @Arr, i32 %offset + %B = ptrtoint ptr %A to i32 + %C = zext i32 %B to i64 + %D = sub i64 ptrtoint (ptr @Arr to i64), %C + ret i64 %D +} + +define i64 @negative_zext_ptrtoint_sub_ptrtoint(ptr %p, i32 %offset) { +; CHECK-LABEL: @negative_zext_ptrtoint_sub_ptrtoint( +; CHECK-NEXT: [[TMP1:%.*]] = sext i32 [[OFFSET:%.*]] to i64 +; CHECK-NEXT: [[A:%.*]] = getelementptr bfloat, ptr @Arr, i64 [[TMP1]] +; CHECK-NEXT: [[TMP2:%.*]] = ptrtoint ptr [[A]] to i64 +; CHECK-NEXT: [[C:%.*]] = and i64 [[TMP2]], 65534 +; CHECK-NEXT: [[D:%.*]] = sub i64 [[C]], ptrtoint (ptr @Arr to i64) +; CHECK-NEXT: ret i64 [[D]] +; + %A = getelementptr bfloat, ptr @Arr, i32 %offset + %B = ptrtoint ptr %A to i16 + %C = zext i16 %B to i64 + %D = sub i64 %C, ptrtoint (ptr @Arr to i64) + ret i64 %D +} + +define i64 @negative_ptrtoint_sub_zext_ptrtoint(ptr %p, i32 %offset) { +; CHECK-LABEL: @negative_ptrtoint_sub_zext_ptrtoint( +; CHECK-NEXT: [[TMP1:%.*]] = sext i32 [[OFFSET:%.*]] to i64 +; CHECK-NEXT: [[A:%.*]] = getelementptr bfloat, ptr @Arr, i64 [[TMP1]] +; CHECK-NEXT: [[TMP2:%.*]] = ptrtoint ptr [[A]] to i64 +; CHECK-NEXT: [[C:%.*]] = and i64 [[TMP2]], 65534 +; CHECK-NEXT: [[D:%.*]] = sub i64 ptrtoint (ptr @Arr to i64), [[C]] +; CHECK-NEXT: ret i64 [[D]] +; + %A = getelementptr bfloat, ptr @Arr, i32 %offset + %B = ptrtoint ptr %A to i16 + %C = zext i16 %B to i64 + %D = sub i64 ptrtoint (ptr @Arr to i64), %C + ret i64 %D +} + @Arr_as1 = external addrspace(1) global [42 x i16] define i16 @test25_as1(ptr addrspace(1) %P, i64 %A) { @@ -285,6 +349,215 @@ define i16 @test25_as1(ptr addrspace(1) %P, i64 %A) { ret i16 %G } +@Arr_as2 = external addrspace(2) global [42 x i16] + +define i64 @ptrtoint_sub_zext_ptrtoint_as2_inbounds(i32 %offset) { +; CHECK-LABEL: @ptrtoint_sub_zext_ptrtoint_as2_inbounds( +; CHECK-NEXT: [[A:%.*]] = getelementptr inbounds bfloat, ptr addrspace(2) @Arr_as2, i32 [[OFFSET:%.*]] +; CHECK-NEXT: [[B:%.*]] = ptrtoint ptr addrspace(2) [[A]] to i32 +; CHECK-NEXT: [[C:%.*]] = zext i32 [[B]] to i64 +; CHECK-NEXT: [[D:%.*]] = sub nsw i64 ptrtoint (ptr addrspace(2) @Arr_as2 to i64), [[C]] +; CHECK-NEXT: ret i64 [[D]] +; + %A = getelementptr inbounds bfloat, ptr addrspace(2) @Arr_as2, i32 %offset + %B = ptrtoint ptr addrspace(2) %A to i32 + %C = zext i32 %B to i64 + %D = sub i64 ptrtoint (ptr addrspace(2) @Arr_as2 to i64), %C + ret i64 %D +} + +define i64 @zext_ptrtoint_sub_ptrtoint_as2_nusw(i32 %offset) { +; CHECK-LABEL: @zext_ptrtoint_sub_ptrtoint_as2_nusw( +; CHECK-NEXT: [[A_IDX:%.*]] = shl nsw i32 [[OFFSET:%.*]], 1 +; CHECK-NEXT: [[D:%.*]] = sext i32 [[A_IDX]] to i64 +; CHECK-NEXT: ret i64 [[D]] +; + %A = getelementptr nusw bfloat, ptr addrspace(2) @Arr_as2, i32 %offset + %B = ptrtoint ptr addrspace(2) %A to i32 + %C = zext i32 %B to i64 + %D = sub i64 %C, ptrtoint (ptr addrspace(2) @Arr_as2 to i64) + ret i64 %D +} + +define i64 @zext_ptrtoint_sub_ptrtoint_as2_nuw(i32 %offset) { +; CHECK-LABEL: @zext_ptrtoint_sub_ptrtoint_as2_nuw( +; CHECK-NEXT: [[A_IDX:%.*]] = shl nuw i32 [[OFFSET:%.*]], 1 +; CHECK-NEXT: [[D:%.*]] = zext i32 [[A_IDX]] to i64 +; CHECK-NEXT: ret i64 [[D]] +; + %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 = sub i64 %C, ptrtoint (ptr addrspace(2) @Arr_as2 to i64) + ret i64 %D +} + +define i64 @zext_ptrtoint_sub_ptrtoint_as2_nusw_nuw(i32 %offset) { +; CHECK-LABEL: @zext_ptrtoint_sub_ptrtoint_as2_nusw_nuw( +; CHECK-NEXT: [[A_IDX:%.*]] = shl nuw nsw i32 [[OFFSET:%.*]], 1 +; CHECK-NEXT: [[D:%.*]] = zext nneg i32 [[A_IDX]] to i64 +; CHECK-NEXT: ret i64 [[D]] +; + %A = getelementptr nusw nuw bfloat, ptr addrspace(2) @Arr_as2, i32 %offset + %B = ptrtoint ptr addrspace(2) %A to i32 + %C = zext i32 %B to i64 + %D = sub i64 %C, ptrtoint (ptr addrspace(2) @Arr_as2 to i64) + ret i64 %D +} + +define i64 @zext_ptrtoint_sub_zext_ptrtoint_as2_nusw(i32 %offset) { +; CHECK-LABEL: @zext_ptrtoint_sub_zext_ptrtoint_as2_nusw( +; CHECK-NEXT: [[A_IDX:%.*]] = shl nsw i32 [[OFFSET:%.*]], 1 +; CHECK-NEXT: [[E:%.*]] = sext i32 [[A_IDX]] to i64 +; CHECK-NEXT: ret i64 [[E]] +; + %A = getelementptr nusw bfloat, ptr addrspace(2) @Arr_as2, i32 %offset + %B = ptrtoint ptr addrspace(2) %A to i32 + %C = zext i32 %B to i64 + %D = zext i32 ptrtoint (ptr addrspace(2) @Arr_as2 to i32) to i64 + %E = sub i64 %C, %D + ret i64 %E +} + +define i64 @zext_ptrtoint_sub_zext_ptrtoint_as2_nuw(i32 %offset) { +; CHECK-LABEL: @zext_ptrtoint_sub_zext_ptrtoint_as2_nuw( +; CHECK-NEXT: [[A_IDX:%.*]] = shl nuw i32 [[OFFSET:%.*]], 1 +; CHECK-NEXT: [[E:%.*]] = zext i32 [[A_IDX]] to i64 +; CHECK-NEXT: ret i64 [[E]] +; + %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 i32 ptrtoint (ptr addrspace(2) @Arr_as2 to i32) to i64 + %E = sub i64 %C, %D + ret i64 %E +} + +define i64 @negative_zext_ptrtoint_sub_ptrtoint_as2_nuw(i32 %offset) { +; CHECK-LABEL: @negative_zext_ptrtoint_sub_ptrtoint_as2_nuw( +; CHECK-NEXT: [[A:%.*]] = getelementptr nuw bfloat, ptr addrspace(2) @Arr_as2, i32 [[OFFSET:%.*]] +; CHECK-NEXT: [[TMP1:%.*]] = ptrtoint ptr addrspace(2) [[A]] to i32 +; CHECK-NEXT: [[B_MASK:%.*]] = and i32 [[TMP1]], 65534 +; CHECK-NEXT: [[C:%.*]] = zext nneg i32 [[B_MASK]] to i64 +; CHECK-NEXT: [[D:%.*]] = sub nsw i64 [[C]], ptrtoint (ptr addrspace(2) @Arr_as2 to i64) +; CHECK-NEXT: ret i64 [[D]] +; + %A = getelementptr nuw bfloat, ptr addrspace(2) @Arr_as2, i32 %offset + %B = ptrtoint ptr addrspace(2) %A to i16 + %C = zext i16 %B to i64 + %D = sub i64 %C, ptrtoint (ptr addrspace(2) @Arr_as2 to i64) + ret i64 %D +} + +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:%.*]] +; CHECK-NEXT: [[B:%.*]] = ptrtoint ptr addrspace(2) [[A]] to i32 +; CHECK-NEXT: [[C:%.*]] = zext i32 [[B]] to i64 +; CHECK-NEXT: [[TMP1:%.*]] = ptrtoint ptr addrspace(2) [[P]] to i32 +; CHECK-NEXT: [[CC:%.*]] = zext i32 [[TMP1]] to i64 +; CHECK-NEXT: [[D:%.*]] = sub nsw i64 [[CC]], [[C]] +; CHECK-NEXT: ret i64 [[D]] +; + %A = getelementptr inbounds bfloat, ptr addrspace(2) %p, i32 %offset + %B = ptrtoint ptr addrspace(2) %A to i32 + %C = zext i32 %B to i64 + %CC = ptrtoint ptr addrspace(2) %p to i64 + %D = sub i64 %CC, %C + ret i64 %D +} + +define i64 @zext_ptrtoint_sub_ptrtoint_as2_nusw_local(ptr addrspace(2) %p, i32 %offset) { +; CHECK-LABEL: @zext_ptrtoint_sub_ptrtoint_as2_nusw_local( +; CHECK-NEXT: [[A_IDX:%.*]] = shl nsw i32 [[OFFSET:%.*]], 1 +; CHECK-NEXT: [[D:%.*]] = sext i32 [[A_IDX]] to i64 +; CHECK-NEXT: ret i64 [[D]] +; + %A = getelementptr nusw bfloat, ptr addrspace(2) %p, i32 %offset + %B = ptrtoint ptr addrspace(2) %A to i32 + %C = zext i32 %B to i64 + %CC = ptrtoint ptr addrspace(2) %p to i64 + %D = sub i64 %C, %CC + ret i64 %D +} + +define i64 @zext_ptrtoint_sub_ptrtoint_as2_nuw_local(ptr addrspace(2) %p, i32 %offset) { +; CHECK-LABEL: @zext_ptrtoint_sub_ptrtoint_as2_nuw_local( +; CHECK-NEXT: [[A_IDX:%.*]] = shl nuw i32 [[OFFSET:%.*]], 1 +; CHECK-NEXT: [[D:%.*]] = zext i32 [[A_IDX]] to i64 +; CHECK-NEXT: ret i64 [[D]] +; + %A = getelementptr nuw bfloat, ptr addrspace(2) %p, i32 %offset + %B = ptrtoint ptr addrspace(2) %A to i32 + %C = zext i32 %B to i64 + %CC = ptrtoint ptr addrspace(2) %p to i64 + %D = sub i64 %C, %CC + ret i64 %D +} + +define i64 @zext_ptrtoint_sub_ptrtoint_as2_nusw_nuw_local(ptr addrspace(2) %p, i32 %offset) { +; CHECK-LABEL: @zext_ptrtoint_sub_ptrtoint_as2_nusw_nuw_local( +; CHECK-NEXT: [[A_IDX:%.*]] = shl nuw nsw i32 [[OFFSET:%.*]], 1 +; CHECK-NEXT: [[D:%.*]] = zext nneg i32 [[A_IDX]] to i64 +; CHECK-NEXT: ret i64 [[D]] +; + %A = getelementptr nusw nuw bfloat, ptr addrspace(2) %p, i32 %offset + %B = ptrtoint ptr addrspace(2) %A to i32 + %C = zext i32 %B to i64 + %CC = ptrtoint ptr addrspace(2) %p to i64 + %D = sub i64 %C, %CC + ret i64 %D +} + +define i64 @zext_ptrtoint_sub_zext_ptrtoint_as2_nusw_local(ptr addrspace(2) %p, i32 %offset) { +; CHECK-LABEL: @zext_ptrtoint_sub_zext_ptrtoint_as2_nusw_local( +; CHECK-NEXT: [[A_IDX:%.*]] = shl nsw i32 [[OFFSET:%.*]], 1 +; CHECK-NEXT: [[E:%.*]] = sext i32 [[A_IDX]] to i64 +; CHECK-NEXT: ret i64 [[E]] +; + %A = getelementptr nusw bfloat, ptr addrspace(2) %p, i32 %offset + %B = ptrtoint ptr addrspace(2) %A to i32 + %C = zext i32 %B to i64 + %CC = ptrtoint ptr addrspace(2) %p to i32 + %D = zext i32 %CC to i64 + %E = sub i64 %C, %D + ret i64 %E +} + +define i64 @zext_ptrtoint_sub_zext_ptrtoint_as2_nuw_local(ptr addrspace(2) %p, i32 %offset) { +; CHECK-LABEL: @zext_ptrtoint_sub_zext_ptrtoint_as2_nuw_local( +; CHECK-NEXT: [[A_IDX:%.*]] = shl nuw i32 [[OFFSET:%.*]], 1 +; CHECK-NEXT: [[E:%.*]] = zext i32 [[A_IDX]] to i64 +; CHECK-NEXT: ret i64 [[E]] +; + %A = getelementptr nuw bfloat, ptr addrspace(2) %p, i32 %offset + %B = ptrtoint ptr addrspace(2) %A to i32 + %C = zext i32 %B to i64 + %CC = ptrtoint ptr addrspace(2) %p to i32 + %D = zext i32 %CC to i64 + %E = sub i64 %C, %D + ret i64 %E +} + +define i64 @negative_zext_ptrtoint_sub_ptrtoint_as2_nuw_local(ptr addrspace(2) %p, i32 %offset) { +; CHECK-LABEL: @negative_zext_ptrtoint_sub_ptrtoint_as2_nuw_local( +; CHECK-NEXT: [[A:%.*]] = getelementptr nuw bfloat, ptr addrspace(2) [[P:%.*]], i32 [[OFFSET:%.*]] +; CHECK-NEXT: [[TMP1:%.*]] = ptrtoint ptr addrspace(2) [[A]] to i32 +; CHECK-NEXT: [[B_MASK:%.*]] = and i32 [[TMP1]], 65535 +; CHECK-NEXT: [[C:%.*]] = zext nneg i32 [[B_MASK]] to i64 +; CHECK-NEXT: [[TMP2:%.*]] = ptrtoint ptr addrspace(2) [[P]] to i32 +; CHECK-NEXT: [[CC:%.*]] = zext i32 [[TMP2]] to i64 +; CHECK-NEXT: [[D:%.*]] = sub nsw i64 [[C]], [[CC]] +; CHECK-NEXT: ret i64 [[D]] +; + %A = getelementptr nuw bfloat, ptr addrspace(2) %p, i32 %offset + %B = ptrtoint ptr addrspace(2) %A to i16 + %C = zext i16 %B to i64 + %CC = ptrtoint ptr addrspace(2) %p to i64 + %D = sub i64 %C, %CC + ret i64 %D +} + define i64 @test30(ptr %foo, i64 %i, i64 %j) { ; CHECK-LABEL: @test30( ; CHECK-NEXT: [[GEP1_IDX:%.*]] = shl nsw i64 [[I:%.*]], 2