[llvm] da5f45f - [ConstantFolding] Preserve nowrap flags in gep of gep fold
Nikita Popov via llvm-commits
llvm-commits at lists.llvm.org
Tue Jun 11 06:03:18 PDT 2024
Author: Nikita Popov
Date: 2024-06-11T15:03:10+02:00
New Revision: da5f45f5937d3cde4ff76aeeb208e72ee504baaf
URL: https://github.com/llvm/llvm-project/commit/da5f45f5937d3cde4ff76aeeb208e72ee504baaf
DIFF: https://github.com/llvm/llvm-project/commit/da5f45f5937d3cde4ff76aeeb208e72ee504baaf.diff
LOG: [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
Added:
Modified:
llvm/lib/Analysis/ConstantFolding.cpp
llvm/test/Transforms/InstCombine/getelementptr.ll
Removed:
################################################################################
diff --git a/llvm/lib/Analysis/ConstantFolding.cpp b/llvm/lib/Analysis/ConstantFolding.cpp
index 3ca3ae951fcd7..e0f5bf0ab8365 100644
--- a/llvm/lib/Analysis/ConstantFolding.cpp
+++ b/llvm/lib/Analysis/ConstantFolding.cpp
@@ -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);
}
diff --git a/llvm/test/Transforms/InstCombine/getelementptr.ll b/llvm/test/Transforms/InstCombine/getelementptr.ll
index 871913610429b..f968fa6f9afd0 100644
--- a/llvm/test/Transforms/InstCombine/getelementptr.ll
+++ b/llvm/test/Transforms/InstCombine/getelementptr.ll
@@ -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:%.*]]
More information about the llvm-commits
mailing list