1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-26 04:32:44 +01:00

[SCCP] Propagate inequalities

Teach SCCP to create notconstant lattice values from inequality
assumes and nonnull metadata, and update getConstant() to make
use of them. Additionally isOverdefined() needs to be changed to
consider notconstant an overdefined value.

Handling inequality branches is delayed until our branch on undef
story in other passes has been improved.

Differential Revision: https://reviews.llvm.org/D83643
This commit is contained in:
Nikita Popov 2020-07-07 22:50:12 +02:00
parent a69cebb049
commit a43b952b5a
4 changed files with 42 additions and 29 deletions

View File

@ -11,6 +11,7 @@
#include "llvm/IR/ConstantRange.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/Instructions.h"
//
//===----------------------------------------------------------------------===//
// ValueLatticeElement
@ -456,6 +457,16 @@ public:
if (isConstant() && Other.isConstant())
return ConstantExpr::getCompare(Pred, getConstant(), Other.getConstant());
if (ICmpInst::isEquality(Pred)) {
// not(C) != C => true, not(C) == C => false.
if ((isNotConstant() && Other.isConstant() &&
getNotConstant() == Other.getConstant()) ||
(isConstant() && Other.isNotConstant() &&
getConstant() == Other.getNotConstant()))
return Pred == ICmpInst::ICMP_NE
? ConstantInt::getTrue(Ty) : ConstantInt::getFalse(Ty);
}
// Integer constants are represented as ConstantRanges with single
// elements.
if (!isConstantRange() || !Other.isConstantRange())

View File

@ -104,8 +104,7 @@ bool isConstant(const ValueLatticeElement &LV) {
// ValueLatticeElement::isOverdefined() and is intended to be used in the
// transition to ValueLatticeElement.
bool isOverdefined(const ValueLatticeElement &LV) {
return LV.isOverdefined() ||
(LV.isConstantRange() && !LV.getConstantRange().isSingleElement());
return !LV.isUnknownOrUndef() && !isConstant(LV);
}
//===----------------------------------------------------------------------===//
@ -1123,7 +1122,9 @@ static ValueLatticeElement getValueFromMetadata(const Instruction *I) {
if (I->getType()->isIntegerTy())
return ValueLatticeElement::getRange(
getConstantRangeFromMetadata(*Ranges));
// TODO: Also handle MD_nonnull.
if (I->hasMetadata(LLVMContext::MD_nonnull))
return ValueLatticeElement::getNot(
ConstantPointerNull::get(cast<PointerType>(I->getType())));
return ValueLatticeElement::getOverdefined();
}
@ -1291,6 +1292,17 @@ void SCCPSolver::handleCallResult(CallBase &CB) {
return;
}
// TODO: Actually filp MayIncludeUndef for the created range to false,
// once most places in the optimizer respect the branches on
// undef/poison are UB rule. The reason why the new range cannot be
// undef is as follows below:
// The new range is based on a branch condition. That guarantees that
// neither of the compare operands can be undef in the branch targets,
// unless we have conditions that are always true/false (e.g. icmp ule
// i32, %a, i32_max). For the latter overdefined/empty range will be
// inferred, but the branch will get folded accordingly anyways.
bool MayIncludeUndef = !isa<PredicateAssume>(PI);
ValueLatticeElement CondVal = getValueState(OtherOp);
ValueLatticeElement &IV = ValueState[&CB];
if (CondVal.isConstantRange() || CopyOfVal.isConstantRange()) {
@ -1316,18 +1328,9 @@ void SCCPSolver::handleCallResult(CallBase &CB) {
NewCR = CopyOfCR;
addAdditionalUser(OtherOp, &CB);
// TODO: Actually filp MayIncludeUndef for the created range to false,
// once most places in the optimizer respect the branches on
// undef/poison are UB rule. The reason why the new range cannot be
// undef is as follows below:
// The new range is based on a branch condition. That guarantees that
// neither of the compare operands can be undef in the branch targets,
// unless we have conditions that are always true/false (e.g. icmp ule
// i32, %a, i32_max). For the latter overdefined/empty range will be
// inferred, but the branch will get folded accordingly anyways.
mergeInValue(
IV, &CB,
ValueLatticeElement::getRange(NewCR, /*MayIncludeUndef=*/true));
ValueLatticeElement::getRange(NewCR, MayIncludeUndef));
return;
} else if (Pred == CmpInst::ICMP_EQ && CondVal.isConstant()) {
// For non-integer values or integer constant expressions, only
@ -1335,6 +1338,13 @@ void SCCPSolver::handleCallResult(CallBase &CB) {
addAdditionalUser(OtherOp, &CB);
mergeInValue(IV, &CB, CondVal);
return;
} else if (Pred == CmpInst::ICMP_NE && CondVal.isConstant() &&
!MayIncludeUndef) {
// Propagate inequalities.
addAdditionalUser(OtherOp, &CB);
mergeInValue(IV, &CB,
ValueLatticeElement::getNot(CondVal.getConstant()));
return;
}
return (void)mergeInValue(IV, &CB, CopyOfVal);

View File

@ -51,14 +51,10 @@ define void @nonnull(i32* %v) {
; CHECK-LABEL: @nonnull(
; CHECK-NEXT: [[A:%.*]] = icmp ne i32* [[V:%.*]], null
; CHECK-NEXT: call void @llvm.assume(i1 [[A]])
; CHECK-NEXT: [[C1:%.*]] = icmp eq i32* [[V]], null
; CHECK-NEXT: call void @use(i1 [[C1]])
; CHECK-NEXT: [[C2:%.*]] = icmp ne i32* [[V]], null
; CHECK-NEXT: call void @use(i1 [[C2]])
; CHECK-NEXT: [[C3:%.*]] = icmp eq i32* null, [[V]]
; CHECK-NEXT: call void @use(i1 [[C3]])
; CHECK-NEXT: [[C4:%.*]] = icmp ne i32* null, [[V]]
; CHECK-NEXT: call void @use(i1 [[C4]])
; CHECK-NEXT: call void @use(i1 false)
; CHECK-NEXT: call void @use(i1 true)
; CHECK-NEXT: call void @use(i1 false)
; CHECK-NEXT: call void @use(i1 true)
; CHECK-NEXT: ret void
;
%a = icmp ne i32* %v, null

View File

@ -48,14 +48,10 @@ define void @load_nonnull(i32** %p, i32** %p2) {
; CHECK-LABEL: @load_nonnull(
; CHECK-NEXT: [[V:%.*]] = load i32*, i32** [[P:%.*]], align 8, !nonnull !2
; CHECK-NEXT: [[V2:%.*]] = load i32*, i32** [[P2:%.*]], align 8, !nonnull !2
; CHECK-NEXT: [[C1:%.*]] = icmp ne i32* [[V]], null
; CHECK-NEXT: call void @use(i1 [[C1]])
; CHECK-NEXT: [[C2:%.*]] = icmp eq i32* [[V]], null
; CHECK-NEXT: call void @use(i1 [[C2]])
; CHECK-NEXT: [[C3:%.*]] = icmp ne i32* null, [[V]]
; CHECK-NEXT: call void @use(i1 [[C3]])
; CHECK-NEXT: [[C4:%.*]] = icmp eq i32* null, [[V]]
; CHECK-NEXT: call void @use(i1 [[C4]])
; CHECK-NEXT: call void @use(i1 true)
; CHECK-NEXT: call void @use(i1 false)
; CHECK-NEXT: call void @use(i1 true)
; CHECK-NEXT: call void @use(i1 false)
; CHECK-NEXT: [[C5:%.*]] = icmp eq i32* [[V]], [[V2]]
; CHECK-NEXT: call void @use(i1 [[C5]])
; CHECK-NEXT: [[C6:%.*]] = icmp ne i32* [[V]], [[V2]]