[SCCP] Support ranges for loads and stores.

Integer ranges can be used for loaded/stored values. Note that widening
can be disabled for loads/stores, as we only rely on instructions that
cause continued increases to ranges to be widened (like binary
operators).

Reviewers: efriedma, mssimpso, davide

Reviewed By: efriedma

Differential Revision: https://reviews.llvm.org/D78433
This commit is contained in:
Florian Hahn 2020-04-26 11:54:35 +01:00
parent c1c5c47e64
commit 7d57d22baa
2 changed files with 23 additions and 38 deletions

View File

@ -1071,8 +1071,9 @@ void SCCPSolver::visitStoreInst(StoreInst &SI) {
return;
// Get the value we are storing into the global, then merge it.
mergeInValue(I->second, GV, getValueState(SI.getOperand(0)));
if (isOverdefined(I->second))
mergeInValue(I->second, GV, getValueState(SI.getOperand(0)),
ValueLatticeElement::MergeOptions().setCheckWiden(false));
if (I->second.isOverdefined())
TrackedGlobals.erase(I); // No need to keep tracking this!
}
@ -1085,7 +1086,7 @@ void SCCPSolver::visitLoadInst(LoadInst &I) {
// ResolvedUndefsIn might mark I as overdefined. Bail out, even if we would
// discover a concrete value later.
if (isOverdefined(ValueState[&I]))
if (ValueState[&I].isOverdefined())
return (void)markOverdefined(&I);
ValueLatticeElement PtrVal = getValueState(I.getOperand(0));
@ -1113,7 +1114,8 @@ void SCCPSolver::visitLoadInst(LoadInst &I) {
// If we are tracking this global, merge in the known value for it.
auto It = TrackedGlobals.find(GV);
if (It != TrackedGlobals.end()) {
mergeInValue(IV, &I, It->second);
mergeInValue(IV, &I, It->second,
ValueLatticeElement::MergeOptions().setCheckWiden(false));
return;
}
}

View File

@ -8,14 +8,10 @@ declare void @use(i1)
define void @test1a() {
; CHECK-LABEL: @test1a(
; CHECK-NEXT: [[X:%.*]] = load i32, i32* @G
; CHECK-NEXT: [[T_1:%.*]] = icmp ne i32 [[X]], 124
; CHECK-NEXT: call void @use(i1 [[T_1]])
; CHECK-NEXT: [[T_2:%.*]] = icmp ult i32 [[X]], 124
; CHECK-NEXT: call void @use(i1 [[T_2]])
; CHECK-NEXT: [[F_1:%.*]] = icmp eq i32 [[X]], 124
; CHECK-NEXT: call void @use(i1 [[F_1]])
; CHECK-NEXT: [[F_2:%.*]] = icmp ugt i32 [[X]], 123
; CHECK-NEXT: call void @use(i1 [[F_2]])
; CHECK-NEXT: call void @use(i1 true)
; CHECK-NEXT: call void @use(i1 true)
; CHECK-NEXT: call void @use(i1 false)
; CHECK-NEXT: call void @use(i1 false)
; CHECK-NEXT: [[C_1:%.*]] = icmp eq i32 [[X]], 20
; CHECK-NEXT: call void @use(i1 [[C_1]])
; CHECK-NEXT: ret void
@ -59,14 +55,10 @@ F:
define void @test2a() {
; CHECK-LABEL: @test2a(
; CHECK-NEXT: [[X:%.*]] = load i32, i32* @H
; CHECK-NEXT: [[T_1:%.*]] = icmp ne i32 [[X]], 124
; CHECK-NEXT: call void @use(i1 [[T_1]])
; CHECK-NEXT: [[T_2:%.*]] = icmp ult i32 [[X]], 124
; CHECK-NEXT: call void @use(i1 [[T_2]])
; CHECK-NEXT: [[F_1:%.*]] = icmp eq i32 [[X]], 124
; CHECK-NEXT: call void @use(i1 [[F_1]])
; CHECK-NEXT: [[F_2:%.*]] = icmp ugt i32 [[X]], 123
; CHECK-NEXT: call void @use(i1 [[F_2]])
; CHECK-NEXT: call void @use(i1 true)
; CHECK-NEXT: call void @use(i1 true)
; CHECK-NEXT: call void @use(i1 false)
; CHECK-NEXT: call void @use(i1 false)
; CHECK-NEXT: [[C_1:%.*]] = icmp eq i32 [[X]], 20
; CHECK-NEXT: call void @use(i1 [[C_1]])
; CHECK-NEXT: ret void
@ -123,14 +115,10 @@ F:
define void @test3a() {
; CHECK-LABEL: @test3a(
; CHECK-NEXT: [[X:%.*]] = load i32, i32* @I
; CHECK-NEXT: [[T_1:%.*]] = icmp ne i32 [[X]], 124
; CHECK-NEXT: call void @use(i1 [[T_1]])
; CHECK-NEXT: [[T_2:%.*]] = icmp ult i32 [[X]], 124
; CHECK-NEXT: call void @use(i1 [[T_2]])
; CHECK-NEXT: [[F_1:%.*]] = icmp eq i32 [[X]], 124
; CHECK-NEXT: call void @use(i1 [[F_1]])
; CHECK-NEXT: [[F_2:%.*]] = icmp ugt i32 [[X]], 123
; CHECK-NEXT: call void @use(i1 [[F_2]])
; CHECK-NEXT: call void @use(i1 true)
; CHECK-NEXT: call void @use(i1 true)
; CHECK-NEXT: call void @use(i1 false)
; CHECK-NEXT: call void @use(i1 false)
; CHECK-NEXT: [[C_1:%.*]] = icmp eq i32 [[X]], 20
; CHECK-NEXT: call void @use(i1 [[C_1]])
; CHECK-NEXT: ret void
@ -245,19 +233,15 @@ exit:
; Same as test1, but storing 4 different values.
@K = internal global i32 0
@K = internal global i32 501
define void @test5a() {
; CHECK-LABEL: @test5a(
; CHECK-NEXT: [[X:%.*]] = load i32, i32* @K
; CHECK-NEXT: [[T_1:%.*]] = icmp ne i32 [[X]], 499
; CHECK-NEXT: call void @use(i1 [[T_1]])
; CHECK-NEXT: [[T_2:%.*]] = icmp ult i32 [[X]], 600
; CHECK-NEXT: call void @use(i1 [[T_2]])
; CHECK-NEXT: [[F_1:%.*]] = icmp eq i32 [[X]], 600
; CHECK-NEXT: call void @use(i1 [[F_1]])
; CHECK-NEXT: [[F_2:%.*]] = icmp ugt i32 [[X]], 600
; CHECK-NEXT: call void @use(i1 [[F_2]])
; CHECK-NEXT: call void @use(i1 true)
; CHECK-NEXT: call void @use(i1 true)
; CHECK-NEXT: call void @use(i1 false)
; CHECK-NEXT: call void @use(i1 false)
; CHECK-NEXT: [[C_1:%.*]] = icmp eq i32 [[X]], 510
; CHECK-NEXT: call void @use(i1 [[C_1]])
; CHECK-NEXT: ret void
@ -319,5 +303,4 @@ T.3:
F.3:
store i32 530, i32* @K
ret void
}