#include "llvm/IR/ConstantRange.h"
#include "llvm/IR/Constants.h"
+#include "llvm/IR/Instructions.h"
//
//===----------------------------------------------------------------------===//
// ValueLatticeElement
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())
// 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);
}
//===----------------------------------------------------------------------===//
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();
}
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()) {
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
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);
; 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
; 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]]