forked from OSchip/llvm-project
[SCCP] Compute ranges for supported intrinsics
For intrinsics supported by ConstantRange, compute the result range based on the argument ranges. We do this independently of whether some or all of the input ranges are full, as we can often still constrain the result in some way. Differential Revision: https://reviews.llvm.org/D87183
This commit is contained in:
parent
da79b1eecc
commit
9fb46a452d
|
@ -1350,6 +1350,25 @@ void SCCPSolver::handleCallResult(CallBase &CB) {
|
||||||
|
|
||||||
return (void)mergeInValue(IV, &CB, CopyOfVal);
|
return (void)mergeInValue(IV, &CB, CopyOfVal);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ConstantRange::isIntrinsicSupported(II->getIntrinsicID())) {
|
||||||
|
// Compute result range for intrinsics supported by ConstantRange.
|
||||||
|
// Do this even if we don't know a range for all operands, as we may
|
||||||
|
// still know something about the result range, e.g. of abs(x).
|
||||||
|
SmallVector<ConstantRange, 2> OpRanges;
|
||||||
|
for (Value *Op : II->args()) {
|
||||||
|
const ValueLatticeElement &State = getValueState(Op);
|
||||||
|
if (State.isConstantRange())
|
||||||
|
OpRanges.push_back(State.getConstantRange());
|
||||||
|
else
|
||||||
|
OpRanges.push_back(
|
||||||
|
ConstantRange::getFull(Op->getType()->getScalarSizeInBits()));
|
||||||
|
}
|
||||||
|
|
||||||
|
ConstantRange Result =
|
||||||
|
ConstantRange::intrinsic(II->getIntrinsicID(), OpRanges);
|
||||||
|
return (void)mergeInValue(II, ValueLatticeElement::getRange(Result));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// The common case is that we aren't tracking the callee, either because we
|
// The common case is that we aren't tracking the callee, either because we
|
||||||
|
|
|
@ -12,10 +12,8 @@ define void @abs1(i8* %p) {
|
||||||
; CHECK-LABEL: @abs1(
|
; CHECK-LABEL: @abs1(
|
||||||
; CHECK-NEXT: [[X:%.*]] = load i8, i8* [[P:%.*]], align 1, [[RNG0:!range !.*]]
|
; CHECK-NEXT: [[X:%.*]] = load i8, i8* [[P:%.*]], align 1, [[RNG0:!range !.*]]
|
||||||
; CHECK-NEXT: [[ABS:%.*]] = call i8 @llvm.abs.i8(i8 [[X]], i1 false)
|
; CHECK-NEXT: [[ABS:%.*]] = call i8 @llvm.abs.i8(i8 [[X]], i1 false)
|
||||||
; CHECK-NEXT: [[CMP1:%.*]] = icmp sge i8 [[ABS]], 0
|
; CHECK-NEXT: call void @use(i1 true)
|
||||||
; CHECK-NEXT: call void @use(i1 [[CMP1]])
|
; CHECK-NEXT: call void @use(i1 true)
|
||||||
; CHECK-NEXT: [[CMP2:%.*]] = icmp slt i8 [[ABS]], 10
|
|
||||||
; CHECK-NEXT: call void @use(i1 [[CMP2]])
|
|
||||||
; CHECK-NEXT: [[CMP3:%.*]] = icmp sge i8 [[ABS]], 1
|
; CHECK-NEXT: [[CMP3:%.*]] = icmp sge i8 [[ABS]], 1
|
||||||
; CHECK-NEXT: call void @use(i1 [[CMP3]])
|
; CHECK-NEXT: call void @use(i1 [[CMP3]])
|
||||||
; CHECK-NEXT: [[CMP4:%.*]] = icmp slt i8 [[ABS]], 9
|
; CHECK-NEXT: [[CMP4:%.*]] = icmp slt i8 [[ABS]], 9
|
||||||
|
@ -40,8 +38,7 @@ define void @abs1(i8* %p) {
|
||||||
define void @abs2(i8 %x) {
|
define void @abs2(i8 %x) {
|
||||||
; CHECK-LABEL: @abs2(
|
; CHECK-LABEL: @abs2(
|
||||||
; CHECK-NEXT: [[ABS:%.*]] = call i8 @llvm.abs.i8(i8 [[X:%.*]], i1 true)
|
; CHECK-NEXT: [[ABS:%.*]] = call i8 @llvm.abs.i8(i8 [[X:%.*]], i1 true)
|
||||||
; CHECK-NEXT: [[CMP:%.*]] = icmp sge i8 [[ABS]], 0
|
; CHECK-NEXT: call void @use(i1 true)
|
||||||
; CHECK-NEXT: call void @use(i1 [[CMP]])
|
|
||||||
; CHECK-NEXT: ret void
|
; CHECK-NEXT: ret void
|
||||||
;
|
;
|
||||||
%abs = call i8 @llvm.abs.i8(i8 %x, i1 true)
|
%abs = call i8 @llvm.abs.i8(i8 %x, i1 true)
|
||||||
|
@ -68,10 +65,8 @@ define void @umax1(i8* %p1, i8* %p2) {
|
||||||
; CHECK-NEXT: [[X1:%.*]] = load i8, i8* [[P1:%.*]], align 1, [[RNG1:!range !.*]]
|
; CHECK-NEXT: [[X1:%.*]] = load i8, i8* [[P1:%.*]], align 1, [[RNG1:!range !.*]]
|
||||||
; CHECK-NEXT: [[X2:%.*]] = load i8, i8* [[P2:%.*]], align 1, [[RNG2:!range !.*]]
|
; CHECK-NEXT: [[X2:%.*]] = load i8, i8* [[P2:%.*]], align 1, [[RNG2:!range !.*]]
|
||||||
; CHECK-NEXT: [[M:%.*]] = call i8 @llvm.umax.i8(i8 [[X1]], i8 [[X2]])
|
; CHECK-NEXT: [[M:%.*]] = call i8 @llvm.umax.i8(i8 [[X1]], i8 [[X2]])
|
||||||
; CHECK-NEXT: [[CMP1:%.*]] = icmp uge i8 [[M]], 5
|
; CHECK-NEXT: call void @use(i1 true)
|
||||||
; CHECK-NEXT: call void @use(i1 [[CMP1]])
|
; CHECK-NEXT: call void @use(i1 true)
|
||||||
; CHECK-NEXT: [[CMP2:%.*]] = icmp ult i8 [[M]], 15
|
|
||||||
; CHECK-NEXT: call void @use(i1 [[CMP2]])
|
|
||||||
; CHECK-NEXT: [[CMP3:%.*]] = icmp uge i8 [[M]], 6
|
; CHECK-NEXT: [[CMP3:%.*]] = icmp uge i8 [[M]], 6
|
||||||
; CHECK-NEXT: call void @use(i1 [[CMP3]])
|
; CHECK-NEXT: call void @use(i1 [[CMP3]])
|
||||||
; CHECK-NEXT: [[CMP4:%.*]] = icmp ult i8 [[M]], 14
|
; CHECK-NEXT: [[CMP4:%.*]] = icmp ult i8 [[M]], 14
|
||||||
|
@ -95,8 +90,7 @@ define void @umax1(i8* %p1, i8* %p2) {
|
||||||
define void @umax2(i8 %x) {
|
define void @umax2(i8 %x) {
|
||||||
; CHECK-LABEL: @umax2(
|
; CHECK-LABEL: @umax2(
|
||||||
; CHECK-NEXT: [[M:%.*]] = call i8 @llvm.umax.i8(i8 [[X:%.*]], i8 10)
|
; CHECK-NEXT: [[M:%.*]] = call i8 @llvm.umax.i8(i8 [[X:%.*]], i8 10)
|
||||||
; CHECK-NEXT: [[CMP:%.*]] = icmp uge i8 [[M]], 10
|
; CHECK-NEXT: call void @use(i1 true)
|
||||||
; CHECK-NEXT: call void @use(i1 [[CMP]])
|
|
||||||
; CHECK-NEXT: ret void
|
; CHECK-NEXT: ret void
|
||||||
;
|
;
|
||||||
%m = call i8 @llvm.umax.i8(i8 %x, i8 10)
|
%m = call i8 @llvm.umax.i8(i8 %x, i8 10)
|
||||||
|
|
Loading…
Reference in New Issue