if (!BlockValueSet.insert(BV).second)
return false; // It's already in the stack.
+ DEBUG(dbgs() << "PUSH: " << *BV.second << " in " << BV.first->getName()
+ << "\n");
BlockValueStack.push(BV);
return true;
}
assert(hasCachedValueInfo(e.second, e.first) &&
"Result should be in cache!");
+ DEBUG(dbgs() << "POP " << *e.second << " in " << e.first->getName()
+ << " = " << lookup(e.second)[e.first] << "\n");
+
BlockValueStack.pop();
BlockValueSet.erase(e);
} else {
return false;
}
+/// Returns true if this lattice value represents at most one possible value.
+/// This is as precise as any lattice value can get while still representing
+/// reachable code.
+static bool hasSingleValue(LVILatticeVal Val) {
+ if (Val.isConstantRange() &&
+ Val.getConstantRange().isSingleElement())
+ // Integer constants are single element ranges
+ return true;
+ if (Val.isConstant())
+ // Non integer constants
+ return true;
+ return false;
+}
+
+/// Combine two sets of facts about the same value into a single set of
+/// facts. Note that this method is not suitable for merging facts along
+/// different paths in a CFG; that's what the mergeIn function is for. This
+/// is for merging facts gathered about the same value at the same location
+/// through two independent means.
+/// Notes:
+/// * This method does not promise to return the most precise possible lattice
+/// value implied by A and B. It is allowed to return any lattice element
+/// which is at least as strong as *either* A or B (unless our facts
+/// conflict, see below).
+/// * Due to unreachable code, the intersection of two lattice values could be
+/// contradictory. If this happens, we return some valid lattice value so as
+/// not confuse the rest of LVI. Ideally, we'd always return Undefined, but
+/// we do not make this guarantee. TODO: This would be a useful enhancement.
+static LVILatticeVal intersect(LVILatticeVal A, LVILatticeVal B) {
+ // Undefined is the strongest state. It means the value is known to be along
+ // an unreachable path.
+ if (A.isUndefined())
+ return A;
+ if (B.isUndefined())
+ return B;
+
+ // If we gave up for one, but got a useable fact from the other, use it.
+ if (A.isOverdefined())
+ return B;
+ if (B.isOverdefined())
+ return A;
+
+ // Can't get any more precise than constants.
+ if (hasSingleValue(A))
+ return A;
+ if (hasSingleValue(B))
+ return B;
+
+ // Could be either constant range or not constant here.
+ if (!A.isConstantRange() || !B.isConstantRange()) {
+ // TODO: Arbitrary choice, could be improved
+ return A;
+ }
+
+ // Intersect two constant ranges
+ ConstantRange Range =
+ A.getConstantRange().intersectWith(B.getConstantRange());
+ // Note: An empty range is implicitly converted to overdefined internally.
+ // TODO: We could instead use Undefined here since we've proven a conflict
+ // and thus know this path must be unreachable.
+ return LVILatticeVal::getRange(Range);
+}
+
/// \brief Compute the value of Val on the edge BBFrom -> BBTo or the value at
/// the basic block if the edge does not constrain Val.
bool LazyValueInfoCache::getEdgeValue(Value *Val, BasicBlock *BBFrom,
return true;
}
- if (getEdgeValueLocal(Val, BBFrom, BBTo, Result)) {
- if (!Result.isConstantRange() ||
- Result.getConstantRange().getSingleElement())
- return true;
-
- // FIXME: this check should be moved to the beginning of the function when
- // LVI better supports recursive values. Even for the single value case, we
- // can intersect to detect dead code (an empty range).
- if (!hasBlockValue(Val, BBFrom)) {
- if (pushBlockValue(std::make_pair(BBFrom, Val)))
- return false;
- Result.markOverdefined();
- return true;
- }
-
- // Try to intersect ranges of the BB and the constraint on the edge.
- LVILatticeVal InBlock = getBlockValue(Val, BBFrom);
- mergeAssumeBlockValueConstantRange(Val, InBlock, BBFrom->getTerminator());
- // See note on the use of the CxtI with mergeAssumeBlockValueConstantRange,
- // and caching, below.
- mergeAssumeBlockValueConstantRange(Val, InBlock, CxtI);
- if (!InBlock.isConstantRange())
- return true;
-
- ConstantRange Range =
- Result.getConstantRange().intersectWith(InBlock.getConstantRange());
- Result = LVILatticeVal::getRange(Range);
+ LVILatticeVal LocalResult;
+ if (!getEdgeValueLocal(Val, BBFrom, BBTo, LocalResult))
+ // If we couldn't constrain the value on the edge, LocalResult doesn't
+ // provide any information.
+ LocalResult.markOverdefined();
+
+ if (hasSingleValue(LocalResult)) {
+ // Can't get any more precise here
+ Result = LocalResult;
return true;
}
if (!hasBlockValue(Val, BBFrom)) {
if (pushBlockValue(std::make_pair(BBFrom, Val)))
return false;
- Result.markOverdefined();
+ // No new information.
+ Result = LocalResult;
return true;
}
- // If we couldn't compute the value on the edge, use the value from the BB.
- Result = getBlockValue(Val, BBFrom);
- mergeAssumeBlockValueConstantRange(Val, Result, BBFrom->getTerminator());
+ // Try to intersect ranges of the BB and the constraint on the edge.
+ LVILatticeVal InBlock = getBlockValue(Val, BBFrom);
+ mergeAssumeBlockValueConstantRange(Val, InBlock, BBFrom->getTerminator());
// We can use the context instruction (generically the ultimate instruction
// the calling pass is trying to simplify) here, even though the result of
// this function is generally cached when called from the solve* functions
// functions, the context instruction is not provided. When called from
// LazyValueInfoCache::getValueOnEdge, the context instruction is provided,
// but then the result is not cached.
- mergeAssumeBlockValueConstantRange(Val, Result, CxtI);
+ mergeAssumeBlockValueConstantRange(Val, InBlock, CxtI);
+
+ Result = intersect(LocalResult, InBlock);
return true;
}
--- /dev/null
+; RUN: opt -correlated-propagation -S < %s | FileCheck %s
+; Checks that we don't crash on conflicting facts about a value
+; (i.e. unreachable code)
+
+; Test that we can handle conflict edge facts
+define i8 @test(i8 %a) {
+; CHECK-LABEL: @test
+ %cmp1 = icmp eq i8 %a, 5
+ br i1 %cmp1, label %next, label %exit
+next:
+ %cmp2 = icmp eq i8 %a, 3
+; CHECK: br i1 false, label %dead, label %exit
+ br i1 %cmp2, label %dead, label %exit
+dead:
+; CHECK-LABEL: dead:
+; CHECK: ret i8 5
+; NOTE: undef, or 3 would be equal valid
+ ret i8 %a
+exit:
+ ret i8 0
+}
+
+declare void @llvm.assume(i1)
+
+; Test that we can handle conflicting assume vs edge facts
+define i8 @test2(i8 %a) {
+; CHECK-LABEL: @test2
+ %cmp1 = icmp eq i8 %a, 5
+ call void @llvm.assume(i1 %cmp1)
+ %cmp2 = icmp eq i8 %a, 3
+; CHECK: br i1 false, label %dead, label %exit
+ br i1 %cmp2, label %dead, label %exit
+dead:
+ ret i8 %a
+exit:
+ ret i8 0
+}
+
+define i8 @test3(i8 %a) {
+; CHECK-LABEL: @test3
+ %cmp1 = icmp eq i8 %a, 5
+ br i1 %cmp1, label %dead, label %exit
+dead:
+ %cmp2 = icmp eq i8 %a, 3
+; CHECK: call void @llvm.assume(i1 false)
+ call void @llvm.assume(i1 %cmp2)
+ ret i8 %a
+exit:
+ ret i8 0
+}