Skip to content

Commit dee86c3

Browse files
committed
[SCEV] Do not use non-deterministic constant folding results for exhaustive trip counts
1 parent 5ba64c3 commit dee86c3

File tree

4 files changed

+56
-25
lines changed

4 files changed

+56
-25
lines changed

llvm/include/llvm/Analysis/ConstantFolding.h

+11-3
Original file line numberDiff line numberDiff line change
@@ -68,9 +68,15 @@ Constant *ConstantFoldConstant(const Constant *C, const DataLayout &DL,
6868
/// fold instructions like loads and stores, which have no constant expression
6969
/// form.
7070
///
71+
/// In some cases, constant folding may return one value chosen from a set of
72+
/// multiple legal return values. Using such a result is usually only valid if
73+
/// all uses of the original operation are replaced by the constant-folded
74+
/// result. The \p AllowNonDeterministic parameter controls whether this is
75+
/// allowed.
7176
Constant *ConstantFoldInstOperands(Instruction *I, ArrayRef<Constant *> Ops,
7277
const DataLayout &DL,
73-
const TargetLibraryInfo *TLI = nullptr);
78+
const TargetLibraryInfo *TLI = nullptr,
79+
bool AllowNonDeterministic = true);
7480

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

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

195203
Constant *ConstantFoldBinaryIntrinsic(Intrinsic::ID ID, Constant *LHS,
196204
Constant *RHS, Type *Ty,

llvm/lib/Analysis/ConstantFolding.cpp

+31-11
Original file line numberDiff line numberDiff line change
@@ -992,7 +992,8 @@ Constant *SymbolicallyEvaluateGEP(const GEPOperator *GEP,
992992
Constant *ConstantFoldInstOperandsImpl(const Value *InstOrCE, unsigned Opcode,
993993
ArrayRef<Constant *> Ops,
994994
const DataLayout &DL,
995-
const TargetLibraryInfo *TLI) {
995+
const TargetLibraryInfo *TLI,
996+
bool AllowNonDeterministic) {
996997
Type *DestTy = InstOrCE->getType();
997998

998999
if (Instruction::isUnaryOp(Opcode))
@@ -1011,7 +1012,8 @@ Constant *ConstantFoldInstOperandsImpl(const Value *InstOrCE, unsigned Opcode,
10111012
// TODO: If a constant expression is being folded rather than an
10121013
// instruction, denormals will not be flushed/treated as zero
10131014
if (const auto *I = dyn_cast<Instruction>(InstOrCE)) {
1014-
return ConstantFoldFPInstOperands(Opcode, Ops[0], Ops[1], DL, I);
1015+
return ConstantFoldFPInstOperands(Opcode, Ops[0], Ops[1], DL, I,
1016+
AllowNonDeterministic);
10151017
}
10161018
}
10171019
return ConstantFoldBinaryOpOperands(Opcode, Ops[0], Ops[1], DL);
@@ -1053,7 +1055,8 @@ Constant *ConstantFoldInstOperandsImpl(const Value *InstOrCE, unsigned Opcode,
10531055
if (auto *F = dyn_cast<Function>(Ops.back())) {
10541056
const auto *Call = cast<CallBase>(InstOrCE);
10551057
if (canConstantFoldCallTo(Call, F))
1056-
return ConstantFoldCall(Call, F, Ops.slice(0, Ops.size() - 1), TLI);
1058+
return ConstantFoldCall(Call, F, Ops.slice(0, Ops.size() - 1), TLI,
1059+
AllowNonDeterministic);
10571060
}
10581061
return nullptr;
10591062
case Instruction::Select:
@@ -1114,8 +1117,8 @@ ConstantFoldConstantImpl(const Constant *C, const DataLayout &DL,
11141117
}
11151118

11161119
if (auto *CE = dyn_cast<ConstantExpr>(C)) {
1117-
if (Constant *Res =
1118-
ConstantFoldInstOperandsImpl(CE, CE->getOpcode(), Ops, DL, TLI))
1120+
if (Constant *Res = ConstantFoldInstOperandsImpl(
1121+
CE, CE->getOpcode(), Ops, DL, TLI, /*AllowNonDeterministic=*/true))
11191122
return Res;
11201123
return const_cast<Constant *>(C);
11211124
}
@@ -1183,8 +1186,10 @@ Constant *llvm::ConstantFoldConstant(const Constant *C, const DataLayout &DL,
11831186
Constant *llvm::ConstantFoldInstOperands(Instruction *I,
11841187
ArrayRef<Constant *> Ops,
11851188
const DataLayout &DL,
1186-
const TargetLibraryInfo *TLI) {
1187-
return ConstantFoldInstOperandsImpl(I, I->getOpcode(), Ops, DL, TLI);
1189+
const TargetLibraryInfo *TLI,
1190+
bool AllowNonDeterministic) {
1191+
return ConstantFoldInstOperandsImpl(I, I->getOpcode(), Ops, DL, TLI,
1192+
AllowNonDeterministic);
11881193
}
11891194

11901195
Constant *llvm::ConstantFoldCompareInstOperands(
@@ -1357,7 +1362,8 @@ Constant *llvm::FlushFPConstant(Constant *Operand, const Instruction *I,
13571362

13581363
Constant *llvm::ConstantFoldFPInstOperands(unsigned Opcode, Constant *LHS,
13591364
Constant *RHS, const DataLayout &DL,
1360-
const Instruction *I) {
1365+
const Instruction *I,
1366+
bool AllowNonDeterministic) {
13611367
if (Instruction::isBinaryOp(Opcode)) {
13621368
// Flush denormal inputs if needed.
13631369
Constant *Op0 = FlushFPConstant(LHS, I, /* IsOutput */ false);
@@ -1373,7 +1379,15 @@ Constant *llvm::ConstantFoldFPInstOperands(unsigned Opcode, Constant *LHS,
13731379
return nullptr;
13741380

13751381
// Flush denormal output if needed.
1376-
return FlushFPConstant(C, I, /* IsOutput */ true);
1382+
C = FlushFPConstant(C, I, /* IsOutput */ true);
1383+
if (!C)
1384+
return nullptr;
1385+
1386+
// The precise NaN value is non-deterministic.
1387+
if (!AllowNonDeterministic && C->isNaN())
1388+
return nullptr;
1389+
1390+
return C;
13771391
}
13781392
// If instruction lacks a parent/function and the denormal mode cannot be
13791393
// determined, use the default (IEEE).
@@ -3401,7 +3415,8 @@ Constant *llvm::ConstantFoldBinaryIntrinsic(Intrinsic::ID ID, Constant *LHS,
34013415

34023416
Constant *llvm::ConstantFoldCall(const CallBase *Call, Function *F,
34033417
ArrayRef<Constant *> Operands,
3404-
const TargetLibraryInfo *TLI) {
3418+
const TargetLibraryInfo *TLI,
3419+
bool AllowNonDeterministic) {
34053420
if (Call->isNoBuiltin())
34063421
return nullptr;
34073422
if (!F->hasName())
@@ -3417,8 +3432,13 @@ Constant *llvm::ConstantFoldCall(const CallBase *Call, Function *F,
34173432
return nullptr;
34183433
}
34193434

3420-
StringRef Name = F->getName();
3435+
// Conservatively assume that floating-point libcalls may be
3436+
// non-deterministic.
34213437
Type *Ty = F->getReturnType();
3438+
if (!AllowNonDeterministic && Ty->isFPOrFPVectorTy())
3439+
return nullptr;
3440+
3441+
StringRef Name = F->getName();
34223442
if (auto *FVTy = dyn_cast<FixedVectorType>(Ty))
34233443
return ConstantFoldFixedVectorCall(
34243444
Name, IID, FVTy, Operands, F->getParent()->getDataLayout(), TLI, Call);

llvm/lib/Analysis/ScalarEvolution.cpp

+4-2
Original file line numberDiff line numberDiff line change
@@ -9540,7 +9540,8 @@ static Constant *EvaluateExpression(Value *V, const Loop *L,
95409540
Operands[i] = C;
95419541
}
95429542

9543-
return ConstantFoldInstOperands(I, Operands, DL, TLI);
9543+
return ConstantFoldInstOperands(I, Operands, DL, TLI,
9544+
/*AllowNonDeterministic=*/false);
95449545
}
95459546

95469547

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

1003210033
Constant *C = nullptr;
1003310034
const DataLayout &DL = getDataLayout();
10034-
C = ConstantFoldInstOperands(I, Operands, DL, &TLI);
10035+
C = ConstantFoldInstOperands(I, Operands, DL, &TLI,
10036+
/*AllowNonDeterministic=*/false);
1003510037
if (!C)
1003610038
return V;
1003710039
return getSCEV(C);

llvm/test/Analysis/ScalarEvolution/exhaustive-trip-counts.ll

+10-9
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,14 @@ for.cond.cleanup:
2727
ret void
2828
}
2929

30-
30+
; Do not compute exhaustive trip count based on FP libcalls, as their exact
31+
; return value may not be specified.
3132
define i64 @test_fp_libcall() {
3233
; CHECK-LABEL: 'test_fp_libcall'
3334
; CHECK-NEXT: Determining loop execution counts for: @test_fp_libcall
34-
; CHECK-NEXT: Loop %loop: backedge-taken count is i32 90
35-
; CHECK-NEXT: Loop %loop: constant max backedge-taken count is i32 90
36-
; CHECK-NEXT: Loop %loop: symbolic max backedge-taken count is i32 90
37-
; CHECK-NEXT: Loop %loop: Trip multiple is 91
35+
; CHECK-NEXT: Loop %loop: Unpredictable backedge-taken count.
36+
; CHECK-NEXT: Loop %loop: Unpredictable constant max backedge-taken count.
37+
; CHECK-NEXT: Loop %loop: Unpredictable symbolic max backedge-taken count.
3838
;
3939
entry:
4040
br label %loop
@@ -52,13 +52,14 @@ exit:
5252
ret i64 %iv
5353
}
5454

55+
; Do not compute exhaustive trip count based on FP constant folding resulting
56+
; in NaN values, as we don't specify which NaN exactly is returned.
5557
define i64 @test_nan_sign() {
5658
; CHECK-LABEL: 'test_nan_sign'
5759
; CHECK-NEXT: Determining loop execution counts for: @test_nan_sign
58-
; CHECK-NEXT: Loop %loop: backedge-taken count is i32 46
59-
; CHECK-NEXT: Loop %loop: constant max backedge-taken count is i32 46
60-
; CHECK-NEXT: Loop %loop: symbolic max backedge-taken count is i32 46
61-
; CHECK-NEXT: Loop %loop: Trip multiple is 47
60+
; CHECK-NEXT: Loop %loop: Unpredictable backedge-taken count.
61+
; CHECK-NEXT: Loop %loop: Unpredictable constant max backedge-taken count.
62+
; CHECK-NEXT: Loop %loop: Unpredictable symbolic max backedge-taken count.
6263
;
6364
entry:
6465
br label %loop

0 commit comments

Comments
 (0)