[llvm] 6c1fc82 - [InstCombine] fold `sub(zext(ptrtoint),zext(ptrtoint))` (#115369)
via llvm-commits
llvm-commits at lists.llvm.org
Fri Nov 15 06:36:39 PST 2024
Author: Nikolay Panchenko
Date: 2024-11-15T15:36:35+01:00
New Revision: 6c1fc8213ee40896681ed84a3f91b1b5b56a4de8
URL: https://github.com/llvm/llvm-project/commit/6c1fc8213ee40896681ed84a3f91b1b5b56a4de8
DIFF: https://github.com/llvm/llvm-project/commit/6c1fc8213ee40896681ed84a3f91b1b5b56a4de8.diff
LOG: [InstCombine] fold `sub(zext(ptrtoint),zext(ptrtoint))` (#115369)
On a 32-bit target if pointer arithmetic with `addrspace` is used in i64
computation, the missed folding in InstCombine results to suboptimal
performance, unlike same code compiled for 64bit target.
Added:
Modified:
llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
llvm/test/Transforms/InstCombine/sub-gep.ll
Removed:
################################################################################
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
index 21588aca512758..fe5e478ef371d2 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<GEPOperator>(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 b773d106b2c98a..f7a54ab2141bd7 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
}
+ at 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
More information about the llvm-commits
mailing list