mirror of
https://github.com/intel/llvm.git
synced 2026-01-16 13:35:38 +08:00
[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:
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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:%.*]]
|
||||
|
||||
Reference in New Issue
Block a user