[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
This commit is contained in:
Nikita Popov
2024-06-04 14:40:09 +02:00
parent 1bae10879d
commit da5f45f593
2 changed files with 47 additions and 10 deletions

View File

@@ -866,8 +866,6 @@ Constant *SymbolicallyEvaluateGEP(const GEPOperator *GEP,
ArrayRef<Constant *> Ops,
const DataLayout &DL,
const TargetLibraryInfo *TLI) {
bool InBounds = GEP->isInBounds();
Type *SrcElemTy = GEP->getSourceElementType();
Type *ResTy = GEP->getType();
if (!SrcElemTy->isSized() || isa<ScalableVectorType>(SrcElemTy))
@@ -898,8 +896,10 @@ Constant *SymbolicallyEvaluateGEP(const GEPOperator *GEP,
InRange = InRange->sextOrTrunc(BitWidth);
// If this is a GEP of a GEP, fold it all into a single GEP.
GEPNoWrapFlags NW = GEP->getNoWrapFlags();
bool Overflow = false;
while (auto *GEP = dyn_cast<GEPOperator>(Ptr)) {
InBounds &= GEP->isInBounds();
NW &= GEP->getNoWrapFlags();
SmallVector<Value *, 4> NestedOps(llvm::drop_begin(GEP->operands()));
@@ -923,9 +923,16 @@ Constant *SymbolicallyEvaluateGEP(const GEPOperator *GEP,
Ptr = cast<Constant>(GEP->getOperand(0));
SrcElemTy = GEP->getSourceElementType();
Offset += APInt(BitWidth, DL.getIndexedOffsetInType(SrcElemTy, NestedOps));
Offset = Offset.sadd_ov(
APInt(BitWidth, DL.getIndexedOffsetInType(SrcElemTy, NestedOps)),
Overflow);
}
// Preserving nusw (without inbounds) also requires that the offset
// additions did not overflow.
if (NW.hasNoUnsignedSignedWrap() && !NW.isInBounds() && Overflow)
NW = NW.withoutNoUnsignedSignedWrap();
// If the base value for this address is a literal integer value, fold the
// getelementptr to the resulting integer value casted to the pointer type.
APInt BasePtr(BitWidth, 0);
@@ -944,17 +951,19 @@ Constant *SymbolicallyEvaluateGEP(const GEPOperator *GEP,
}
// Try to infer inbounds for GEPs of globals.
if (!InBounds && Offset.isNonNegative()) {
// TODO(gep_nowrap): Also infer nuw flag.
if (!NW.isInBounds() && Offset.isNonNegative()) {
bool CanBeNull, CanBeFreed;
uint64_t DerefBytes =
Ptr->getPointerDereferenceableBytes(DL, CanBeNull, CanBeFreed);
InBounds = DerefBytes != 0 && !CanBeNull && Offset.sle(DerefBytes);
if (DerefBytes != 0 && !CanBeNull && Offset.sle(DerefBytes))
NW |= GEPNoWrapFlags::inBounds();
}
// Otherwise canonicalize this to a single ptradd.
LLVMContext &Ctx = Ptr->getContext();
return ConstantExpr::getGetElementPtr(Type::getInt8Ty(Ctx), Ptr,
ConstantInt::get(Ctx, Offset), InBounds,
ConstantInt::get(Ctx, Offset), NW,
InRange);
}

View File

@@ -419,20 +419,48 @@ define ptr @test_index_canon_nusw_nuw(ptr %X, i32 %Idx) {
ret ptr %R
}
define ptr @test_index_canon_const_expr_inbounds(ptr %X, i32 %Idx) {
define ptr @test_index_canon_const_expr_inbounds() {
; CHECK-LABEL: @test_index_canon_const_expr_inbounds(
; CHECK-NEXT: ret ptr getelementptr inbounds (i8, ptr @Global, i64 123)
;
ret ptr getelementptr inbounds (i8, ptr @Global, i32 123)
}
define ptr @test_index_canon_const_expr_nuw_nusw(ptr %X, i32 %Idx) {
define ptr @test_index_canon_const_expr_nuw_nusw() {
; CHECK-LABEL: @test_index_canon_const_expr_nuw_nusw(
; CHECK-NEXT: ret ptr getelementptr (i8, ptr @Global, i64 123)
; CHECK-NEXT: ret ptr getelementptr nusw nuw (i8, ptr @Global, i64 123)
;
ret ptr getelementptr nusw nuw (i8, ptr @Global, i32 123)
}
define ptr @test_const_gep_gep_nuw() {
; CHECK-LABEL: @test_const_gep_gep_nuw(
; CHECK-NEXT: ret ptr getelementptr nuw (i8, ptr @Global, i64 246)
;
ret ptr getelementptr nuw (i8, ptr getelementptr nuw (i8, ptr @Global, i64 123), i64 123)
}
define ptr @test_const_gep_gep_nusw_no_overflow() {
; CHECK-LABEL: @test_const_gep_gep_nusw_no_overflow(
; CHECK-NEXT: ret ptr getelementptr nusw (i8, ptr @Global, i64 246)
;
ret ptr getelementptr nusw (i8, ptr getelementptr nusw (i8, ptr @Global, i64 123), i64 123)
}
define ptr @test_const_gep_gep_nusw_no_overflow_neg() {
; CHECK-LABEL: @test_const_gep_gep_nusw_no_overflow_neg(
; CHECK-NEXT: ret ptr getelementptr nusw (i8, ptr @Global, i64 -246)
;
ret ptr getelementptr nusw (i8, ptr getelementptr nusw (i8, ptr @Global, i64 -123), i64 -123)
}
define ptr @test_const_gep_gep_nusw_overflow() {
; CHECK-LABEL: @test_const_gep_gep_nusw_overflow(
; CHECK-NEXT: ret ptr getelementptr (i8, ptr @Global, i64 -2)
;
ret ptr getelementptr nusw (i8, ptr getelementptr nusw (i8, ptr @Global, i64 u0x7fffffffffffffff), i64 u0x7fffffffffffffff)
}
define i1 @test17(ptr %P, i32 %I, i32 %J) {
; CHECK-LABEL: @test17(
; CHECK-NEXT: [[C:%.*]] = icmp slt i32 [[I:%.*]], [[J:%.*]]