Skip to content

Commit

Permalink
[SCEV] Do not use non-deterministic constant folding results for exha…
Browse files Browse the repository at this point in the history
…ustive trip counts
  • Loading branch information
nikic committed May 3, 2024
1 parent 5ba64c3 commit dee86c3
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 25 deletions.
14 changes: 11 additions & 3 deletions llvm/include/llvm/Analysis/ConstantFolding.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,15 @@ Constant *ConstantFoldConstant(const Constant *C, const DataLayout &DL,
/// fold instructions like loads and stores, which have no constant expression
/// form.
///
/// In some cases, constant folding may return one value chosen from a set of
/// multiple legal return values. Using such a result is usually only valid if
/// all uses of the original operation are replaced by the constant-folded
/// result. The \p AllowNonDeterministic parameter controls whether this is
/// allowed.
Constant *ConstantFoldInstOperands(Instruction *I, ArrayRef<Constant *> Ops,
const DataLayout &DL,
const TargetLibraryInfo *TLI = nullptr);
const TargetLibraryInfo *TLI = nullptr,
bool AllowNonDeterministic = true);

/// Attempt to constant fold a compare instruction (icmp/fcmp) with the
/// specified operands. Returns null or a constant expression of the specified
Expand All @@ -95,7 +101,8 @@ Constant *ConstantFoldBinaryOpOperands(unsigned Opcode, Constant *LHS,
/// Returns null or a constant expression of the specified operands on failure.
Constant *ConstantFoldFPInstOperands(unsigned Opcode, Constant *LHS,
Constant *RHS, const DataLayout &DL,
const Instruction *I);
const Instruction *I,
bool AllowNonDeterministic = true);

/// Attempt to flush float point constant according to denormal mode set in the
/// instruction's parent function attributes. If so, return a zero with the
Expand Down Expand Up @@ -190,7 +197,8 @@ bool canConstantFoldCallTo(const CallBase *Call, const Function *F);
/// with the specified arguments, returning null if unsuccessful.
Constant *ConstantFoldCall(const CallBase *Call, Function *F,
ArrayRef<Constant *> Operands,
const TargetLibraryInfo *TLI = nullptr);
const TargetLibraryInfo *TLI = nullptr,
bool AllowNonDeterministic = true);

Constant *ConstantFoldBinaryIntrinsic(Intrinsic::ID ID, Constant *LHS,
Constant *RHS, Type *Ty,
Expand Down
42 changes: 31 additions & 11 deletions llvm/lib/Analysis/ConstantFolding.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -992,7 +992,8 @@ Constant *SymbolicallyEvaluateGEP(const GEPOperator *GEP,
Constant *ConstantFoldInstOperandsImpl(const Value *InstOrCE, unsigned Opcode,
ArrayRef<Constant *> Ops,
const DataLayout &DL,
const TargetLibraryInfo *TLI) {
const TargetLibraryInfo *TLI,
bool AllowNonDeterministic) {
Type *DestTy = InstOrCE->getType();

if (Instruction::isUnaryOp(Opcode))
Expand All @@ -1011,7 +1012,8 @@ Constant *ConstantFoldInstOperandsImpl(const Value *InstOrCE, unsigned Opcode,
// TODO: If a constant expression is being folded rather than an
// instruction, denormals will not be flushed/treated as zero
if (const auto *I = dyn_cast<Instruction>(InstOrCE)) {
return ConstantFoldFPInstOperands(Opcode, Ops[0], Ops[1], DL, I);
return ConstantFoldFPInstOperands(Opcode, Ops[0], Ops[1], DL, I,
AllowNonDeterministic);
}
}
return ConstantFoldBinaryOpOperands(Opcode, Ops[0], Ops[1], DL);
Expand Down Expand Up @@ -1053,7 +1055,8 @@ Constant *ConstantFoldInstOperandsImpl(const Value *InstOrCE, unsigned Opcode,
if (auto *F = dyn_cast<Function>(Ops.back())) {
const auto *Call = cast<CallBase>(InstOrCE);
if (canConstantFoldCallTo(Call, F))
return ConstantFoldCall(Call, F, Ops.slice(0, Ops.size() - 1), TLI);
return ConstantFoldCall(Call, F, Ops.slice(0, Ops.size() - 1), TLI,
AllowNonDeterministic);
}
return nullptr;
case Instruction::Select:
Expand Down Expand Up @@ -1114,8 +1117,8 @@ ConstantFoldConstantImpl(const Constant *C, const DataLayout &DL,
}

if (auto *CE = dyn_cast<ConstantExpr>(C)) {
if (Constant *Res =
ConstantFoldInstOperandsImpl(CE, CE->getOpcode(), Ops, DL, TLI))
if (Constant *Res = ConstantFoldInstOperandsImpl(
CE, CE->getOpcode(), Ops, DL, TLI, /*AllowNonDeterministic=*/true))
return Res;
return const_cast<Constant *>(C);
}
Expand Down Expand Up @@ -1183,8 +1186,10 @@ Constant *llvm::ConstantFoldConstant(const Constant *C, const DataLayout &DL,
Constant *llvm::ConstantFoldInstOperands(Instruction *I,
ArrayRef<Constant *> Ops,
const DataLayout &DL,
const TargetLibraryInfo *TLI) {
return ConstantFoldInstOperandsImpl(I, I->getOpcode(), Ops, DL, TLI);
const TargetLibraryInfo *TLI,
bool AllowNonDeterministic) {
return ConstantFoldInstOperandsImpl(I, I->getOpcode(), Ops, DL, TLI,
AllowNonDeterministic);
}

Constant *llvm::ConstantFoldCompareInstOperands(
Expand Down Expand Up @@ -1357,7 +1362,8 @@ Constant *llvm::FlushFPConstant(Constant *Operand, const Instruction *I,

Constant *llvm::ConstantFoldFPInstOperands(unsigned Opcode, Constant *LHS,
Constant *RHS, const DataLayout &DL,
const Instruction *I) {
const Instruction *I,
bool AllowNonDeterministic) {
if (Instruction::isBinaryOp(Opcode)) {
// Flush denormal inputs if needed.
Constant *Op0 = FlushFPConstant(LHS, I, /* IsOutput */ false);
Expand All @@ -1373,7 +1379,15 @@ Constant *llvm::ConstantFoldFPInstOperands(unsigned Opcode, Constant *LHS,
return nullptr;

// Flush denormal output if needed.
return FlushFPConstant(C, I, /* IsOutput */ true);
C = FlushFPConstant(C, I, /* IsOutput */ true);
if (!C)
return nullptr;

// The precise NaN value is non-deterministic.
if (!AllowNonDeterministic && C->isNaN())
return nullptr;

return C;
}
// If instruction lacks a parent/function and the denormal mode cannot be
// determined, use the default (IEEE).
Expand Down Expand Up @@ -3401,7 +3415,8 @@ Constant *llvm::ConstantFoldBinaryIntrinsic(Intrinsic::ID ID, Constant *LHS,

Constant *llvm::ConstantFoldCall(const CallBase *Call, Function *F,
ArrayRef<Constant *> Operands,
const TargetLibraryInfo *TLI) {
const TargetLibraryInfo *TLI,
bool AllowNonDeterministic) {
if (Call->isNoBuiltin())
return nullptr;
if (!F->hasName())
Expand All @@ -3417,8 +3432,13 @@ Constant *llvm::ConstantFoldCall(const CallBase *Call, Function *F,
return nullptr;
}

StringRef Name = F->getName();
// Conservatively assume that floating-point libcalls may be
// non-deterministic.
Type *Ty = F->getReturnType();
if (!AllowNonDeterministic && Ty->isFPOrFPVectorTy())
return nullptr;

StringRef Name = F->getName();
if (auto *FVTy = dyn_cast<FixedVectorType>(Ty))
return ConstantFoldFixedVectorCall(
Name, IID, FVTy, Operands, F->getParent()->getDataLayout(), TLI, Call);
Expand Down
6 changes: 4 additions & 2 deletions llvm/lib/Analysis/ScalarEvolution.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9540,7 +9540,8 @@ static Constant *EvaluateExpression(Value *V, const Loop *L,
Operands[i] = C;
}

return ConstantFoldInstOperands(I, Operands, DL, TLI);
return ConstantFoldInstOperands(I, Operands, DL, TLI,
/*AllowNonDeterministic=*/false);
}


Expand Down Expand Up @@ -10031,7 +10032,8 @@ const SCEV *ScalarEvolution::computeSCEVAtScope(const SCEV *V, const Loop *L) {

Constant *C = nullptr;
const DataLayout &DL = getDataLayout();
C = ConstantFoldInstOperands(I, Operands, DL, &TLI);
C = ConstantFoldInstOperands(I, Operands, DL, &TLI,
/*AllowNonDeterministic=*/false);
if (!C)
return V;
return getSCEV(C);
Expand Down
19 changes: 10 additions & 9 deletions llvm/test/Analysis/ScalarEvolution/exhaustive-trip-counts.ll
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,14 @@ for.cond.cleanup:
ret void
}


; Do not compute exhaustive trip count based on FP libcalls, as their exact
; return value may not be specified.
define i64 @test_fp_libcall() {
; CHECK-LABEL: 'test_fp_libcall'
; CHECK-NEXT: Determining loop execution counts for: @test_fp_libcall
; CHECK-NEXT: Loop %loop: backedge-taken count is i32 90
; CHECK-NEXT: Loop %loop: constant max backedge-taken count is i32 90
; CHECK-NEXT: Loop %loop: symbolic max backedge-taken count is i32 90
; CHECK-NEXT: Loop %loop: Trip multiple is 91
; CHECK-NEXT: Loop %loop: Unpredictable backedge-taken count.
; CHECK-NEXT: Loop %loop: Unpredictable constant max backedge-taken count.
; CHECK-NEXT: Loop %loop: Unpredictable symbolic max backedge-taken count.
;
entry:
br label %loop
Expand All @@ -52,13 +52,14 @@ exit:
ret i64 %iv
}

; Do not compute exhaustive trip count based on FP constant folding resulting
; in NaN values, as we don't specify which NaN exactly is returned.
define i64 @test_nan_sign() {
; CHECK-LABEL: 'test_nan_sign'
; CHECK-NEXT: Determining loop execution counts for: @test_nan_sign
; CHECK-NEXT: Loop %loop: backedge-taken count is i32 46
; CHECK-NEXT: Loop %loop: constant max backedge-taken count is i32 46
; CHECK-NEXT: Loop %loop: symbolic max backedge-taken count is i32 46
; CHECK-NEXT: Loop %loop: Trip multiple is 47
; CHECK-NEXT: Loop %loop: Unpredictable backedge-taken count.
; CHECK-NEXT: Loop %loop: Unpredictable constant max backedge-taken count.
; CHECK-NEXT: Loop %loop: Unpredictable symbolic max backedge-taken count.
;
entry:
br label %loop
Expand Down

0 comments on commit dee86c3

Please sign in to comment.