Skip to content

Commit da5f45f

Browse files
committed
[ConstantFolding] Preserve nowrap flags in gep of gep fold
A caveat here is that we can only preserve nusw if the offset additions did not overflow. Proofs: https://alive2.llvm.org/ce/z/u56z_u
1 parent 1bae108 commit da5f45f

File tree

2 files changed

+47
-10
lines changed

2 files changed

+47
-10
lines changed

llvm/lib/Analysis/ConstantFolding.cpp

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -866,8 +866,6 @@ Constant *SymbolicallyEvaluateGEP(const GEPOperator *GEP,
866866
ArrayRef<Constant *> Ops,
867867
const DataLayout &DL,
868868
const TargetLibraryInfo *TLI) {
869-
bool InBounds = GEP->isInBounds();
870-
871869
Type *SrcElemTy = GEP->getSourceElementType();
872870
Type *ResTy = GEP->getType();
873871
if (!SrcElemTy->isSized() || isa<ScalableVectorType>(SrcElemTy))
@@ -898,8 +896,10 @@ Constant *SymbolicallyEvaluateGEP(const GEPOperator *GEP,
898896
InRange = InRange->sextOrTrunc(BitWidth);
899897

900898
// If this is a GEP of a GEP, fold it all into a single GEP.
899+
GEPNoWrapFlags NW = GEP->getNoWrapFlags();
900+
bool Overflow = false;
901901
while (auto *GEP = dyn_cast<GEPOperator>(Ptr)) {
902-
InBounds &= GEP->isInBounds();
902+
NW &= GEP->getNoWrapFlags();
903903

904904
SmallVector<Value *, 4> NestedOps(llvm::drop_begin(GEP->operands()));
905905

@@ -923,9 +923,16 @@ Constant *SymbolicallyEvaluateGEP(const GEPOperator *GEP,
923923

924924
Ptr = cast<Constant>(GEP->getOperand(0));
925925
SrcElemTy = GEP->getSourceElementType();
926-
Offset += APInt(BitWidth, DL.getIndexedOffsetInType(SrcElemTy, NestedOps));
926+
Offset = Offset.sadd_ov(
927+
APInt(BitWidth, DL.getIndexedOffsetInType(SrcElemTy, NestedOps)),
928+
Overflow);
927929
}
928930

931+
// Preserving nusw (without inbounds) also requires that the offset
932+
// additions did not overflow.
933+
if (NW.hasNoUnsignedSignedWrap() && !NW.isInBounds() && Overflow)
934+
NW = NW.withoutNoUnsignedSignedWrap();
935+
929936
// If the base value for this address is a literal integer value, fold the
930937
// getelementptr to the resulting integer value casted to the pointer type.
931938
APInt BasePtr(BitWidth, 0);
@@ -944,17 +951,19 @@ Constant *SymbolicallyEvaluateGEP(const GEPOperator *GEP,
944951
}
945952

946953
// Try to infer inbounds for GEPs of globals.
947-
if (!InBounds && Offset.isNonNegative()) {
954+
// TODO(gep_nowrap): Also infer nuw flag.
955+
if (!NW.isInBounds() && Offset.isNonNegative()) {
948956
bool CanBeNull, CanBeFreed;
949957
uint64_t DerefBytes =
950958
Ptr->getPointerDereferenceableBytes(DL, CanBeNull, CanBeFreed);
951-
InBounds = DerefBytes != 0 && !CanBeNull && Offset.sle(DerefBytes);
959+
if (DerefBytes != 0 && !CanBeNull && Offset.sle(DerefBytes))
960+
NW |= GEPNoWrapFlags::inBounds();
952961
}
953962

954963
// Otherwise canonicalize this to a single ptradd.
955964
LLVMContext &Ctx = Ptr->getContext();
956965
return ConstantExpr::getGetElementPtr(Type::getInt8Ty(Ctx), Ptr,
957-
ConstantInt::get(Ctx, Offset), InBounds,
966+
ConstantInt::get(Ctx, Offset), NW,
958967
InRange);
959968
}
960969

llvm/test/Transforms/InstCombine/getelementptr.ll

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -419,20 +419,48 @@ define ptr @test_index_canon_nusw_nuw(ptr %X, i32 %Idx) {
419419
ret ptr %R
420420
}
421421

422-
define ptr @test_index_canon_const_expr_inbounds(ptr %X, i32 %Idx) {
422+
define ptr @test_index_canon_const_expr_inbounds() {
423423
; CHECK-LABEL: @test_index_canon_const_expr_inbounds(
424424
; CHECK-NEXT: ret ptr getelementptr inbounds (i8, ptr @Global, i64 123)
425425
;
426426
ret ptr getelementptr inbounds (i8, ptr @Global, i32 123)
427427
}
428428

429-
define ptr @test_index_canon_const_expr_nuw_nusw(ptr %X, i32 %Idx) {
429+
define ptr @test_index_canon_const_expr_nuw_nusw() {
430430
; CHECK-LABEL: @test_index_canon_const_expr_nuw_nusw(
431-
; CHECK-NEXT: ret ptr getelementptr (i8, ptr @Global, i64 123)
431+
; CHECK-NEXT: ret ptr getelementptr nusw nuw (i8, ptr @Global, i64 123)
432432
;
433433
ret ptr getelementptr nusw nuw (i8, ptr @Global, i32 123)
434434
}
435435

436+
define ptr @test_const_gep_gep_nuw() {
437+
; CHECK-LABEL: @test_const_gep_gep_nuw(
438+
; CHECK-NEXT: ret ptr getelementptr nuw (i8, ptr @Global, i64 246)
439+
;
440+
ret ptr getelementptr nuw (i8, ptr getelementptr nuw (i8, ptr @Global, i64 123), i64 123)
441+
}
442+
443+
define ptr @test_const_gep_gep_nusw_no_overflow() {
444+
; CHECK-LABEL: @test_const_gep_gep_nusw_no_overflow(
445+
; CHECK-NEXT: ret ptr getelementptr nusw (i8, ptr @Global, i64 246)
446+
;
447+
ret ptr getelementptr nusw (i8, ptr getelementptr nusw (i8, ptr @Global, i64 123), i64 123)
448+
}
449+
450+
define ptr @test_const_gep_gep_nusw_no_overflow_neg() {
451+
; CHECK-LABEL: @test_const_gep_gep_nusw_no_overflow_neg(
452+
; CHECK-NEXT: ret ptr getelementptr nusw (i8, ptr @Global, i64 -246)
453+
;
454+
ret ptr getelementptr nusw (i8, ptr getelementptr nusw (i8, ptr @Global, i64 -123), i64 -123)
455+
}
456+
457+
define ptr @test_const_gep_gep_nusw_overflow() {
458+
; CHECK-LABEL: @test_const_gep_gep_nusw_overflow(
459+
; CHECK-NEXT: ret ptr getelementptr (i8, ptr @Global, i64 -2)
460+
;
461+
ret ptr getelementptr nusw (i8, ptr getelementptr nusw (i8, ptr @Global, i64 u0x7fffffffffffffff), i64 u0x7fffffffffffffff)
462+
}
463+
436464
define i1 @test17(ptr %P, i32 %I, i32 %J) {
437465
; CHECK-LABEL: @test17(
438466
; CHECK-NEXT: [[C:%.*]] = icmp slt i32 [[I:%.*]], [[J:%.*]]

0 commit comments

Comments
 (0)