Skip to content

Commit 2128fca

Browse files
authored
[InstCombine] Canonicalize gep T* X, V / sizeof(T) to gep i8* X, V (#76458)
This patch canonicalize `gep T* X, V / sizeof(T)` to `gep i8* X, V`. Alive2: https://alive2.llvm.org/ce/z/7XGjiB As this pattern has been handled by the backends, the motivation of this patch is to reduce the ref count of sdiv, which will enable more optimizations.
1 parent c97a767 commit 2128fca

File tree

2 files changed

+107
-23
lines changed

2 files changed

+107
-23
lines changed

llvm/lib/Transforms/InstCombine/InstructionCombining.cpp

Lines changed: 23 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2469,31 +2469,31 @@ Instruction *InstCombinerImpl::visitGetElementPtrInst(GetElementPtrInst &GEP) {
24692469
DL.getIndexSizeInBits(AS)) {
24702470
uint64_t TyAllocSize = DL.getTypeAllocSize(GEPEltType).getFixedValue();
24712471

2472-
bool Matched = false;
2473-
uint64_t C;
2474-
Value *V = nullptr;
24752472
if (TyAllocSize == 1) {
2476-
V = GEP.getOperand(1);
2477-
Matched = true;
2478-
} else if (match(GEP.getOperand(1),
2479-
m_AShr(m_Value(V), m_ConstantInt(C)))) {
2480-
if (TyAllocSize == 1ULL << C)
2481-
Matched = true;
2482-
} else if (match(GEP.getOperand(1),
2483-
m_SDiv(m_Value(V), m_ConstantInt(C)))) {
2484-
if (TyAllocSize == C)
2485-
Matched = true;
2473+
// Canonicalize (gep i8* X, (ptrtoint Y)-(ptrtoint X)) to (bitcast Y),
2474+
// but only if both point to the same underlying object (otherwise
2475+
// provenance is not necessarily retained).
2476+
Value *X = GEP.getPointerOperand();
2477+
Value *Y;
2478+
if (match(GEP.getOperand(1),
2479+
m_Sub(m_PtrToInt(m_Value(Y)), m_PtrToInt(m_Specific(X)))) &&
2480+
getUnderlyingObject(X) == getUnderlyingObject(Y))
2481+
return CastInst::CreatePointerBitCastOrAddrSpaceCast(Y, GEPType);
2482+
} else {
2483+
// Canonicalize (gep T* X, V / sizeof(T)) to (gep i8* X, V)
2484+
Value *V;
2485+
if ((has_single_bit(TyAllocSize) &&
2486+
match(GEP.getOperand(1),
2487+
m_Exact(m_AShr(m_Value(V),
2488+
m_SpecificInt(countr_zero(TyAllocSize)))))) ||
2489+
match(GEP.getOperand(1),
2490+
m_Exact(m_SDiv(m_Value(V), m_SpecificInt(TyAllocSize))))) {
2491+
GetElementPtrInst *NewGEP = GetElementPtrInst::Create(
2492+
Builder.getInt8Ty(), GEP.getPointerOperand(), V);
2493+
NewGEP->setIsInBounds(GEP.isInBounds());
2494+
return NewGEP;
2495+
}
24862496
}
2487-
2488-
// Canonicalize (gep i8* X, (ptrtoint Y)-(ptrtoint X)) to (bitcast Y), but
2489-
// only if both point to the same underlying object (otherwise provenance
2490-
// is not necessarily retained).
2491-
Value *Y;
2492-
Value *X = GEP.getOperand(0);
2493-
if (Matched &&
2494-
match(V, m_Sub(m_PtrToInt(m_Value(Y)), m_PtrToInt(m_Specific(X)))) &&
2495-
getUnderlyingObject(X) == getUnderlyingObject(Y))
2496-
return CastInst::CreatePointerBitCastOrAddrSpaceCast(Y, GEPType);
24972497
}
24982498
}
24992499
// We do not handle pointer-vector geps here.

llvm/test/Transforms/InstCombine/getelementptr.ll

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1453,4 +1453,88 @@ define ptr @const_gep_chain(ptr %p, i64 %a) {
14531453
ret ptr %p4
14541454
}
14551455

1456+
define ptr @gep_sdiv(ptr %p, i64 %off) {
1457+
; CHECK-LABEL: @gep_sdiv(
1458+
; CHECK-NEXT: [[PTR:%.*]] = getelementptr i8, ptr [[P:%.*]], i64 [[OFF:%.*]]
1459+
; CHECK-NEXT: ret ptr [[PTR]]
1460+
;
1461+
%index = sdiv exact i64 %off, 7
1462+
%ptr = getelementptr %struct.C, ptr %p, i64 %index
1463+
ret ptr %ptr
1464+
}
1465+
1466+
define <2 x ptr> @gep_sdiv_vec(<2 x ptr> %p, <2 x i64> %off) {
1467+
; CHECK-LABEL: @gep_sdiv_vec(
1468+
; CHECK-NEXT: [[PTR:%.*]] = getelementptr i8, <2 x ptr> [[P:%.*]], <2 x i64> [[OFF:%.*]]
1469+
; CHECK-NEXT: ret <2 x ptr> [[PTR]]
1470+
;
1471+
%index = sdiv exact <2 x i64> %off, <i64 7, i64 7>
1472+
%ptr = getelementptr %struct.C, <2 x ptr> %p, <2 x i64> %index
1473+
ret <2 x ptr> %ptr
1474+
}
1475+
1476+
define ptr @gep_sdiv_inbounds(ptr %p, i64 %off) {
1477+
; CHECK-LABEL: @gep_sdiv_inbounds(
1478+
; CHECK-NEXT: [[PTR:%.*]] = getelementptr inbounds i8, ptr [[P:%.*]], i64 [[OFF:%.*]]
1479+
; CHECK-NEXT: ret ptr [[PTR]]
1480+
;
1481+
%index = sdiv exact i64 %off, 7
1482+
%ptr = getelementptr inbounds %struct.C, ptr %p, i64 %index
1483+
ret ptr %ptr
1484+
}
1485+
1486+
define ptr @gep_ashr(ptr %p, i64 %off) {
1487+
; CHECK-LABEL: @gep_ashr(
1488+
; CHECK-NEXT: [[PTR:%.*]] = getelementptr i8, ptr [[P:%.*]], i64 [[OFF:%.*]]
1489+
; CHECK-NEXT: ret ptr [[PTR]]
1490+
;
1491+
%index = ashr exact i64 %off, 2
1492+
%ptr = getelementptr i32, ptr %p, i64 %index
1493+
ret ptr %ptr
1494+
}
1495+
1496+
; Negative tests
1497+
1498+
define ptr @gep_i8(ptr %p, i64 %off) {
1499+
; CHECK-LABEL: @gep_i8(
1500+
; CHECK-NEXT: [[PTR:%.*]] = getelementptr i8, ptr [[P:%.*]], i64 [[OFF:%.*]]
1501+
; CHECK-NEXT: ret ptr [[PTR]]
1502+
;
1503+
%ptr = getelementptr i8, ptr %p, i64 %off
1504+
ret ptr %ptr
1505+
}
1506+
1507+
define ptr @gep_sdiv_mismatched_size(ptr %p, i64 %off) {
1508+
; CHECK-LABEL: @gep_sdiv_mismatched_size(
1509+
; CHECK-NEXT: [[INDEX:%.*]] = sdiv exact i64 [[OFF:%.*]], 20
1510+
; CHECK-NEXT: [[PTR:%.*]] = getelementptr [[STRUCT_C:%.*]], ptr [[P:%.*]], i64 [[INDEX]]
1511+
; CHECK-NEXT: ret ptr [[PTR]]
1512+
;
1513+
%index = sdiv exact i64 %off, 20
1514+
%ptr = getelementptr %struct.C, ptr %p, i64 %index
1515+
ret ptr %ptr
1516+
}
1517+
1518+
define ptr @gep_sdiv_without_exact(ptr %p, i64 %off) {
1519+
; CHECK-LABEL: @gep_sdiv_without_exact(
1520+
; CHECK-NEXT: [[INDEX:%.*]] = sdiv i64 [[OFF:%.*]], 7
1521+
; CHECK-NEXT: [[PTR:%.*]] = getelementptr [[STRUCT_C:%.*]], ptr [[P:%.*]], i64 [[INDEX]]
1522+
; CHECK-NEXT: ret ptr [[PTR]]
1523+
;
1524+
%index = sdiv i64 %off, 7
1525+
%ptr = getelementptr %struct.C, ptr %p, i64 %index
1526+
ret ptr %ptr
1527+
}
1528+
1529+
define ptr @gep_ashr_without_exact(ptr %p, i64 %off) {
1530+
; CHECK-LABEL: @gep_ashr_without_exact(
1531+
; CHECK-NEXT: [[INDEX:%.*]] = ashr i64 [[OFF:%.*]], 2
1532+
; CHECK-NEXT: [[PTR:%.*]] = getelementptr i32, ptr [[P:%.*]], i64 [[INDEX]]
1533+
; CHECK-NEXT: ret ptr [[PTR]]
1534+
;
1535+
%index = ashr i64 %off, 2
1536+
%ptr = getelementptr i32, ptr %p, i64 %index
1537+
ret ptr %ptr
1538+
}
1539+
14561540
!0 = !{!"branch_weights", i32 2, i32 10}

0 commit comments

Comments
 (0)