Skip to content

Commit d56b0ad

Browse files
committed
[ConstantHoist] Remove check for notional overindexing
ConstantHoist currently only hoists GEPs if there is no notional overindexing. As this transform only hoists address arithmetic, it shouldn't care about whether any overindexing occurs or not. There is one caveat: If the hoisted base GEP is inbounds, and a later non-inbounds GEP is rewritten in terms of it, the value may be incorrectly poisoned. To avoid this, restrict the transform to inbounds GEPs for now, as the notional overindexing check effectively did that as well. The inbounds restriction could be dropped by dropping inbounds from the base GEP expression. Differential Revision: https://reviews.llvm.org/D117201
1 parent a115bbe commit d56b0ad

File tree

2 files changed

+55
-2
lines changed

2 files changed

+55
-2
lines changed

llvm/lib/Transforms/Scalar/ConstantHoisting.cpp

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -414,6 +414,14 @@ void ConstantHoistingPass::collectConstantCandidates(
414414
IntegerType *PtrIntTy = DL->getIntPtrType(*Ctx, GVPtrTy->getAddressSpace());
415415
APInt Offset(DL->getTypeSizeInBits(PtrIntTy), /*val*/0, /*isSigned*/true);
416416
auto *GEPO = cast<GEPOperator>(ConstExpr);
417+
418+
// TODO: If we have a mix of inbounds and non-inbounds GEPs, then basing a
419+
// non-inbounds GEP on an inbounds GEP is potentially incorrect. Restrict to
420+
// inbounds GEP for now -- alternatively, we could drop inbounds from the
421+
// constant expression,
422+
if (!GEPO->isInBounds())
423+
return;
424+
417425
if (!GEPO->accumulateConstantOffset(*DL, Offset))
418426
return;
419427

@@ -470,7 +478,7 @@ void ConstantHoistingPass::collectConstantCandidates(
470478
// Visit constant expressions that have constant integers.
471479
if (auto ConstExpr = dyn_cast<ConstantExpr>(Opnd)) {
472480
// Handle constant gep expressions.
473-
if (ConstHoistGEP && ConstExpr->isGEPWithNoNotionalOverIndexing())
481+
if (ConstHoistGEP && isa<GEPOperator>(ConstExpr))
474482
collectConstantCandidates(ConstCandMap, Inst, Idx, ConstExpr);
475483

476484
// Only visit constant cast expressions.
@@ -810,7 +818,7 @@ void ConstantHoistingPass::emitBaseConstants(Instruction *Base,
810818

811819
// Visit constant expression.
812820
if (auto ConstExpr = dyn_cast<ConstantExpr>(Opnd)) {
813-
if (ConstExpr->isGEPWithNoNotionalOverIndexing()) {
821+
if (isa<GEPOperator>(ConstExpr)) {
814822
// Operand is a ConstantGEP, replace it.
815823
updateOperand(ConstUser.Inst, ConstUser.OpndIdx, Mat);
816824
return;
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2+
; RUN: opt -consthoist -consthoist-gep -S -o - %s | FileCheck %s
3+
4+
target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64"
5+
target triple = "thumbv6m-none--musleabi"
6+
7+
%0 = type { [10 x i32], [10 x i16] }
8+
9+
@global = external local_unnamed_addr global %0, align 4
10+
11+
define void @test_inbounds() {
12+
; CHECK-LABEL: @test_inbounds(
13+
; CHECK-NEXT: bb:
14+
; CHECK-NEXT: [[CONST:%.*]] = bitcast i16* getelementptr inbounds ([[TMP0:%.*]], %0* @global, i32 0, i32 1, i32 0) to i16*
15+
; CHECK-NEXT: store i16 undef, i16* [[CONST]], align 2
16+
; CHECK-NEXT: [[BASE_BITCAST:%.*]] = bitcast i16* [[CONST]] to i8*
17+
; CHECK-NEXT: [[MAT_GEP:%.*]] = getelementptr i8, i8* [[BASE_BITCAST]], i32 2
18+
; CHECK-NEXT: [[MAT_BITCAST:%.*]] = bitcast i8* [[MAT_GEP]] to i16*
19+
; CHECK-NEXT: store i16 undef, i16* [[MAT_BITCAST]], align 2
20+
; CHECK-NEXT: [[BASE_BITCAST1:%.*]] = bitcast i16* [[CONST]] to i8*
21+
; CHECK-NEXT: [[MAT_GEP2:%.*]] = getelementptr i8, i8* [[BASE_BITCAST1]], i32 20
22+
; CHECK-NEXT: [[MAT_BITCAST3:%.*]] = bitcast i8* [[MAT_GEP2]] to i16*
23+
; CHECK-NEXT: store i16 undef, i16* [[MAT_BITCAST3]], align 2
24+
; CHECK-NEXT: ret void
25+
;
26+
bb:
27+
store i16 undef, i16* getelementptr inbounds (%0, %0* @global, i32 0, i32 1, i32 0)
28+
store i16 undef, i16* getelementptr inbounds (%0, %0* @global, i32 0, i32 1, i32 1)
29+
store i16 undef, i16* getelementptr inbounds (%0, %0* @global, i32 0, i32 1, i32 10)
30+
ret void
31+
}
32+
33+
define dso_local void @test_non_inbounds() {
34+
; CHECK-LABEL: @test_non_inbounds(
35+
; CHECK-NEXT: bb:
36+
; CHECK-NEXT: store i16 undef, i16* getelementptr inbounds ([[TMP0:%.*]], %0* @global, i32 0, i32 1, i32 11), align 2
37+
; CHECK-NEXT: store i16 undef, i16* getelementptr ([[TMP0]], %0* @global, i32 0, i32 1, i32 12), align 2
38+
; CHECK-NEXT: ret void
39+
;
40+
bb:
41+
store i16 undef, i16* getelementptr inbounds (%0, %0* @global, i32 0, i32 1, i32 11)
42+
store i16 undef, i16* getelementptr (%0, %0* @global, i32 0, i32 1, i32 12)
43+
ret void
44+
}
45+

0 commit comments

Comments
 (0)