return ValueLatticeElement::getOverdefined();
}
+// Handle conditions of the form
+// extractvalue(op.with.overflow(%x, C), 1).
+static ValueLatticeElement getValueFromOverflowCondition(
+ Value *Val, WithOverflowInst *WO, bool IsTrueDest) {
+ // TODO: This only works with a constant RHS for now. We could also compute
+ // the range of the RHS, but this doesn't fit into the current structure of
+ // the edge value calculation.
+ const APInt *C;
+ if (WO->getLHS() != Val || !match(WO->getRHS(), m_APInt(C)))
+ return ValueLatticeElement::getOverdefined();
+
+ // Calculate the possible values of %x for which no overflow occurs.
+ ConstantRange NWR = ConstantRange::makeGuaranteedNoWrapRegion(
+ WO->getBinaryOp(), ConstantRange(*C), WO->getNoWrapKind());
+
+ // If overflow is false, %x is constrained to NWR. If overflow is true, %x is
+ // constrained to it's inverse (all values that might cause overflow).
+ if (IsTrueDest)
+ NWR = NWR.inverse();
+ return ValueLatticeElement::getRange(NWR);
+}
+
static ValueLatticeElement
getValueFromCondition(Value *Val, Value *Cond, bool isTrueDest,
DenseMap<Value*, ValueLatticeElement> &Visited);
if (ICmpInst *ICI = dyn_cast<ICmpInst>(Cond))
return getValueFromICmpCondition(Val, ICI, isTrueDest);
+ if (auto *EVI = dyn_cast<ExtractValueInst>(Cond))
+ if (auto *WO = dyn_cast<WithOverflowInst>(EVI->getAggregateOperand()))
+ if (EVI->getNumIndices() == 1 && *EVI->idx_begin() == 1)
+ return getValueFromOverflowCondition(Val, WO, isTrueDest);
+
// Handle conditions in the form of (cond1 && cond2), we know that on the
// true dest path both of the conditions hold. Similarly for conditions of
// the form (cond1 || cond2), we know that on the false dest path neither
; CHECK: no_overflow:
; CHECK-NEXT: [[C1:%.*]] = icmp ugt i8 [[X]], -102
; CHECK-NEXT: store i1 [[C1]], i1* [[PC:%.*]]
-; CHECK-NEXT: [[C2:%.*]] = icmp ugt i8 [[X]], -101
-; CHECK-NEXT: ret i1 [[C2]]
+; CHECK-NEXT: ret i1 false
; CHECK: trap:
; CHECK-NEXT: call void @llvm.trap()
; CHECK-NEXT: unreachable
; CHECK: overflow:
; CHECK-NEXT: [[C1:%.*]] = icmp ugt i8 [[X]], -100
; CHECK-NEXT: store i1 [[C1]], i1* [[PC:%.*]]
-; CHECK-NEXT: [[C2:%.*]] = icmp ugt i8 [[X]], -101
-; CHECK-NEXT: ret i1 [[C2]]
+; CHECK-NEXT: ret i1 true
; CHECK: trap:
; CHECK-NEXT: call void @llvm.trap()
; CHECK-NEXT: unreachable
; CHECK: no_overflow:
; CHECK-NEXT: [[C1:%.*]] = icmp sgt i8 [[X]], 26
; CHECK-NEXT: store i1 [[C1]], i1* [[PC:%.*]]
-; CHECK-NEXT: [[C2:%.*]] = icmp sgt i8 [[X]], 27
-; CHECK-NEXT: ret i1 [[C2]]
+; CHECK-NEXT: ret i1 false
; CHECK: trap:
; CHECK-NEXT: call void @llvm.trap()
; CHECK-NEXT: unreachable
; CHECK: overflow:
; CHECK-NEXT: [[C1:%.*]] = icmp sgt i8 [[X]], 28
; CHECK-NEXT: store i1 [[C1]], i1* [[PC:%.*]]
-; CHECK-NEXT: [[C2:%.*]] = icmp sgt i8 [[X]], 27
-; CHECK-NEXT: ret i1 [[C2]]
+; CHECK-NEXT: ret i1 true
; CHECK: trap:
; CHECK-NEXT: call void @llvm.trap()
; CHECK-NEXT: unreachable
; CHECK: no_overflow:
; CHECK-NEXT: [[C1:%.*]] = icmp ult i8 [[X]], 101
; CHECK-NEXT: store i1 [[C1]], i1* [[PC:%.*]]
-; CHECK-NEXT: [[C2:%.*]] = icmp ult i8 [[X]], 100
-; CHECK-NEXT: ret i1 [[C2]]
+; CHECK-NEXT: ret i1 false
; CHECK: trap:
; CHECK-NEXT: call void @llvm.trap()
; CHECK-NEXT: unreachable
; CHECK: overflow:
; CHECK-NEXT: [[C1:%.*]] = icmp ult i8 [[X]], 99
; CHECK-NEXT: store i1 [[C1]], i1* [[PC:%.*]]
-; CHECK-NEXT: [[C2:%.*]] = icmp ult i8 [[X]], 100
-; CHECK-NEXT: ret i1 [[C2]]
+; CHECK-NEXT: ret i1 true
; CHECK: trap:
; CHECK-NEXT: call void @llvm.trap()
; CHECK-NEXT: unreachable
; CHECK: no_overflow:
; CHECK-NEXT: [[C1:%.*]] = icmp slt i8 [[X]], -27
; CHECK-NEXT: store i1 [[C1]], i1* [[PC:%.*]]
-; CHECK-NEXT: [[C2:%.*]] = icmp slt i8 [[X]], -28
-; CHECK-NEXT: ret i1 [[C2]]
+; CHECK-NEXT: ret i1 false
; CHECK: trap:
; CHECK-NEXT: call void @llvm.trap()
; CHECK-NEXT: unreachable
; CHECK: overflow:
; CHECK-NEXT: [[C1:%.*]] = icmp slt i8 [[X]], -29
; CHECK-NEXT: store i1 [[C1]], i1* [[PC:%.*]]
-; CHECK-NEXT: [[C2:%.*]] = icmp slt i8 [[X]], -28
-; CHECK-NEXT: ret i1 [[C2]]
+; CHECK-NEXT: ret i1 true
; CHECK: trap:
; CHECK-NEXT: call void @llvm.trap()
; CHECK-NEXT: unreachable
; CHECK: no_overflow:
; CHECK-NEXT: [[C1:%.*]] = icmp ugt i8 [[X]], 24
; CHECK-NEXT: store i1 [[C1]], i1* [[PC:%.*]]
-; CHECK-NEXT: [[C2:%.*]] = icmp ugt i8 [[X]], 25
-; CHECK-NEXT: ret i1 [[C2]]
+; CHECK-NEXT: ret i1 false
; CHECK: trap:
; CHECK-NEXT: call void @llvm.trap()
; CHECK-NEXT: unreachable
; CHECK: overflow:
; CHECK-NEXT: [[C1:%.*]] = icmp ugt i8 [[X]], 26
; CHECK-NEXT: store i1 [[C1]], i1* [[PC:%.*]]
-; CHECK-NEXT: [[C2:%.*]] = icmp ugt i8 [[X]], 25
-; CHECK-NEXT: ret i1 [[C2]]
+; CHECK-NEXT: ret i1 true
; CHECK: trap:
; CHECK-NEXT: call void @llvm.trap()
; CHECK-NEXT: unreachable
; CHECK: no_overflow:
; CHECK-NEXT: [[C1:%.*]] = icmp slt i8 [[X]], -11
; CHECK-NEXT: store i1 [[C1]], i1* [[PC:%.*]]
-; CHECK-NEXT: [[C2:%.*]] = icmp slt i8 [[X]], -12
-; CHECK-NEXT: ret i1 [[C2]]
+; CHECK-NEXT: ret i1 false
; CHECK: trap:
; CHECK-NEXT: call void @llvm.trap()
; CHECK-NEXT: unreachable
; CHECK: no_overflow:
; CHECK-NEXT: [[C1:%.*]] = icmp sgt i8 [[X]], 11
; CHECK-NEXT: store i1 [[C1]], i1* [[PC:%.*]]
-; CHECK-NEXT: [[C2:%.*]] = icmp sgt i8 [[X]], 12
-; CHECK-NEXT: ret i1 [[C2]]
+; CHECK-NEXT: ret i1 false
; CHECK: trap:
; CHECK-NEXT: call void @llvm.trap()
; CHECK-NEXT: unreachable
; CHECK: overflow:
; CHECK-NEXT: [[C1:%.*]] = icmp eq i8 [[X]], -13
; CHECK-NEXT: store i1 [[C1]], i1* [[PC:%.*]]
-; CHECK-NEXT: [[C2:%.*]] = icmp eq i8 [[X]], -12
-; CHECK-NEXT: ret i1 [[C2]]
+; CHECK-NEXT: ret i1 false
; CHECK: trap:
; CHECK-NEXT: call void @llvm.trap()
; CHECK-NEXT: unreachable
; CHECK: overflow:
; CHECK-NEXT: [[C1:%.*]] = icmp eq i8 [[X]], 13
; CHECK-NEXT: store i1 [[C1]], i1* [[PC:%.*]]
-; CHECK-NEXT: [[C2:%.*]] = icmp eq i8 [[X]], 12
-; CHECK-NEXT: ret i1 [[C2]]
+; CHECK-NEXT: ret i1 false
; CHECK: trap:
; CHECK-NEXT: call void @llvm.trap()
; CHECK-NEXT: unreachable