[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:
Nikita Popov 2020-09-05 10:27:23 +02:00
parent da79b1eecc
commit 9fb46a452d
2 changed files with 25 additions and 12 deletions

View File

@ -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

View File

@ -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)