"Number of saturating arithmetics converted to normal arithmetics");
STATISTIC(NumNonNull, "Number of function pointer arguments marked non-null");
STATISTIC(NumMinMax, "Number of llvm.[us]{min,max} intrinsics removed");
-STATISTIC(NumURemExpanded, "Number of bound urem's expanded");
+STATISTIC(NumUDivURemsNarrowedExpanded,
+ "Number of bound udiv's/urem's expanded");
namespace {
return true;
}
-static bool processURem(BinaryOperator *Instr, const ConstantRange &XCR,
- const ConstantRange &YCR) {
- assert(Instr->getOpcode() == Instruction::URem);
- assert(!Instr->getType()->isVectorTy());
+static bool expandUDivOrURem(BinaryOperator *Instr, const ConstantRange &XCR,
+ const ConstantRange &YCR) {
+ Type *Ty = Instr->getType();
+ assert(Instr->getOpcode() == Instruction::UDiv ||
+ Instr->getOpcode() == Instruction::URem);
+ assert(!Ty->isVectorTy());
+ bool IsRem = Instr->getOpcode() == Instruction::URem;
Value *X = Instr->getOperand(0);
Value *Y = Instr->getOperand(1);
+ // X u/ Y -> 0 iff X u< Y
// X u% Y -> X iff X u< Y
if (XCR.icmp(ICmpInst::ICMP_ULT, YCR)) {
- Instr->replaceAllUsesWith(X);
+ Instr->replaceAllUsesWith(IsRem ? X : Constant::getNullValue(Ty));
Instr->eraseFromParent();
- ++NumURemExpanded;
+ ++NumUDivURemsNarrowedExpanded;
return true;
}
return false;
IRBuilder<> B(Instr);
- // NOTE: this transformation introduces two uses of X,
- // but it may be undef so we must freeze it first.
- Value *FrozenX = B.CreateFreeze(X, X->getName() + ".frozen");
- auto *AdjX = B.CreateNUWSub(FrozenX, Y, Instr->getName() + ".urem");
- auto *Cmp =
- B.CreateICmp(ICmpInst::ICMP_ULT, FrozenX, Y, Instr->getName() + ".cmp");
- auto *ExpandedURem = B.CreateSelect(Cmp, FrozenX, AdjX);
- ExpandedURem->takeName(Instr);
- Instr->replaceAllUsesWith(ExpandedURem);
+ Value *ExpandedOp;
+ if (IsRem) {
+ // NOTE: this transformation introduces two uses of X,
+ // but it may be undef so we must freeze it first.
+ Value *FrozenX = B.CreateFreeze(X, X->getName() + ".frozen");
+ auto *AdjX = B.CreateNUWSub(FrozenX, Y, Instr->getName() + ".urem");
+ auto *Cmp =
+ B.CreateICmp(ICmpInst::ICMP_ULT, FrozenX, Y, Instr->getName() + ".cmp");
+ ExpandedOp = B.CreateSelect(Cmp, FrozenX, AdjX);
+ } else {
+ auto *Cmp =
+ B.CreateICmp(ICmpInst::ICMP_UGE, X, Y, Instr->getName() + ".cmp");
+ ExpandedOp = B.CreateZExt(Cmp, Ty, Instr->getName() + ".udiv");
+ }
+ ExpandedOp->takeName(Instr);
+ Instr->replaceAllUsesWith(ExpandedOp);
Instr->eraseFromParent();
- ++NumURemExpanded;
+ ++NumUDivURemsNarrowedExpanded;
return true;
}
ConstantRange XCR = LVI->getConstantRangeAtUse(Instr->getOperandUse(0));
ConstantRange YCR = LVI->getConstantRangeAtUse(Instr->getOperandUse(1));
- if (Instr->getOpcode() == Instruction::URem && processURem(Instr, XCR, YCR))
+ if (expandUDivOrURem(Instr, XCR, YCR))
return true;
return narrowUDivOrURem(Instr, XCR, YCR);
; CHECK-LABEL: @constant.divisor.v3(
; CHECK-NEXT: [[CMP_X_UPPER:%.*]] = icmp ult i8 [[X:%.*]], 3
; CHECK-NEXT: call void @llvm.assume(i1 [[CMP_X_UPPER]])
-; CHECK-NEXT: [[DIV:%.*]] = udiv i8 [[X]], 3
; CHECK-NEXT: ret i8 0
;
%cmp.x.upper = icmp ult i8 %x, 3
; CHECK-LABEL: @constant.divisor.v4(
; CHECK-NEXT: [[CMP_X_UPPER:%.*]] = icmp ult i8 [[X:%.*]], 4
; CHECK-NEXT: call void @llvm.assume(i1 [[CMP_X_UPPER]])
-; CHECK-NEXT: [[DIV:%.*]] = udiv i8 [[X]], 3
+; CHECK-NEXT: [[DIV_CMP:%.*]] = icmp uge i8 [[X]], 3
+; CHECK-NEXT: [[DIV:%.*]] = zext i1 [[DIV_CMP]] to i8
; CHECK-NEXT: ret i8 [[DIV]]
;
%cmp.x.upper = icmp ult i8 %x, 4
define i8 @constant.divisor.x.range.v4(ptr %x.ptr) {
; CHECK-LABEL: @constant.divisor.x.range.v4(
; CHECK-NEXT: [[X:%.*]] = load i8, ptr [[X_PTR:%.*]], align 1, !range [[RNG0:![0-9]+]]
-; CHECK-NEXT: [[DIV:%.*]] = udiv i8 [[X]], 3
+; CHECK-NEXT: [[DIV_CMP:%.*]] = icmp uge i8 [[X]], 3
+; CHECK-NEXT: [[DIV:%.*]] = zext i1 [[DIV_CMP]] to i8
; CHECK-NEXT: ret i8 [[DIV]]
;
%x = load i8, ptr %x.ptr, !range !{ i8 0, i8 4 }
define i8 @constant.divisor.x.mask.v4(i8 %x) {
; CHECK-LABEL: @constant.divisor.x.mask.v4(
; CHECK-NEXT: [[X_MASKED:%.*]] = and i8 [[X:%.*]], 3
-; CHECK-NEXT: [[DIV:%.*]] = udiv i8 [[X_MASKED]], 3
+; CHECK-NEXT: [[DIV_CMP:%.*]] = icmp uge i8 [[X_MASKED]], 3
+; CHECK-NEXT: [[DIV:%.*]] = zext i1 [[DIV_CMP]] to i8
; CHECK-NEXT: ret i8 [[DIV]]
;
%x.masked = and i8 %x, 3
; CHECK-LABEL: @constant.divisor.v5(
; CHECK-NEXT: [[CMP_X_UPPER:%.*]] = icmp ult i8 [[X:%.*]], 5
; CHECK-NEXT: call void @llvm.assume(i1 [[CMP_X_UPPER]])
-; CHECK-NEXT: [[DIV:%.*]] = udiv i8 [[X]], 3
+; CHECK-NEXT: [[DIV_CMP:%.*]] = icmp uge i8 [[X]], 3
+; CHECK-NEXT: [[DIV:%.*]] = zext i1 [[DIV_CMP]] to i8
; CHECK-NEXT: ret i8 [[DIV]]
;
%cmp.x.upper = icmp ult i8 %x, 5
; CHECK-LABEL: @constant.divisor.v6(
; CHECK-NEXT: [[CMP_X_UPPER:%.*]] = icmp ult i8 [[X:%.*]], 6
; CHECK-NEXT: call void @llvm.assume(i1 [[CMP_X_UPPER]])
-; CHECK-NEXT: [[DIV:%.*]] = udiv i8 [[X]], 3
+; CHECK-NEXT: [[DIV_CMP:%.*]] = icmp uge i8 [[X]], 3
+; CHECK-NEXT: [[DIV:%.*]] = zext i1 [[DIV_CMP]] to i8
; CHECK-NEXT: ret i8 [[DIV]]
;
%cmp.x.upper = icmp ult i8 %x, 6
; CHECK-NEXT: call void @llvm.assume(i1 [[CMP_Y_LOWER]])
; CHECK-NEXT: [[CMP_Y_UPPER:%.*]] = icmp ule i8 [[Y]], 4
; CHECK-NEXT: call void @llvm.assume(i1 [[CMP_Y_UPPER]])
-; CHECK-NEXT: [[DIV:%.*]] = udiv i8 [[X]], [[Y]]
; CHECK-NEXT: ret i8 0
;
%cmp.x = icmp ult i8 %x, 3
; CHECK-NEXT: call void @llvm.assume(i1 [[CMP_Y_LOWER]])
; CHECK-NEXT: [[CMP_Y_UPPER:%.*]] = icmp ule i8 [[Y]], 4
; CHECK-NEXT: call void @llvm.assume(i1 [[CMP_Y_UPPER]])
-; CHECK-NEXT: [[DIV:%.*]] = udiv i8 [[X]], [[Y]]
+; CHECK-NEXT: [[DIV_CMP:%.*]] = icmp uge i8 [[X]], [[Y]]
+; CHECK-NEXT: [[DIV:%.*]] = zext i1 [[DIV_CMP]] to i8
; CHECK-NEXT: ret i8 [[DIV]]
;
%cmp.x = icmp ult i8 %x, 4
; CHECK-LABEL: @variable.v4.range(
; CHECK-NEXT: [[X:%.*]] = load i8, ptr [[X_PTR:%.*]], align 1, !range [[RNG0]]
; CHECK-NEXT: [[Y:%.*]] = load i8, ptr [[Y_PTR:%.*]], align 1, !range [[RNG1:![0-9]+]]
-; CHECK-NEXT: [[DIV:%.*]] = udiv i8 [[X]], [[Y]]
+; CHECK-NEXT: [[DIV_CMP:%.*]] = icmp uge i8 [[X]], [[Y]]
+; CHECK-NEXT: [[DIV:%.*]] = zext i1 [[DIV_CMP]] to i8
; CHECK-NEXT: ret i8 [[DIV]]
;
%x = load i8, ptr %x.ptr, !range !{ i8 0, i8 4 }
; CHECK-NEXT: call void @llvm.assume(i1 [[CMP_Y_LOWER]])
; CHECK-NEXT: [[CMP_Y_UPPER:%.*]] = icmp ule i8 [[Y]], 4
; CHECK-NEXT: call void @llvm.assume(i1 [[CMP_Y_UPPER]])
-; CHECK-NEXT: [[DIV:%.*]] = udiv i8 [[X]], [[Y]]
+; CHECK-NEXT: [[DIV_CMP:%.*]] = icmp uge i8 [[X]], [[Y]]
+; CHECK-NEXT: [[DIV:%.*]] = zext i1 [[DIV_CMP]] to i8
; CHECK-NEXT: ret i8 [[DIV]]
;
%cmp.x = icmp ult i8 %x, 5
; CHECK-NEXT: call void @llvm.assume(i1 [[CMP_Y_LOWER]])
; CHECK-NEXT: [[CMP_Y_UPPER:%.*]] = icmp ule i8 [[Y]], 4
; CHECK-NEXT: call void @llvm.assume(i1 [[CMP_Y_UPPER]])
-; CHECK-NEXT: [[DIV:%.*]] = udiv i8 [[X]], [[Y]]
+; CHECK-NEXT: [[DIV_CMP:%.*]] = icmp uge i8 [[X]], [[Y]]
+; CHECK-NEXT: [[DIV:%.*]] = zext i1 [[DIV_CMP]] to i8
; CHECK-NEXT: ret i8 [[DIV]]
;
%cmp.x = icmp ult i8 %x, 6
; CHECK-LABEL: @large.divisor.v0(
; CHECK-NEXT: [[CMP_X_UPPER:%.*]] = icmp ult i8 [[X:%.*]], 127
; CHECK-NEXT: call void @llvm.assume(i1 [[CMP_X_UPPER]])
-; CHECK-NEXT: [[DIV:%.*]] = udiv i8 [[X]], 127
; CHECK-NEXT: ret i8 0
;
%cmp.x.upper = icmp ult i8 %x, 127
; CHECK-LABEL: @large.divisor.v1(
; CHECK-NEXT: [[CMP_X_UPPER:%.*]] = icmp ult i8 [[X:%.*]], -128
; CHECK-NEXT: call void @llvm.assume(i1 [[CMP_X_UPPER]])
-; CHECK-NEXT: [[DIV:%.*]] = udiv i8 [[X]], 127
+; CHECK-NEXT: [[DIV_CMP:%.*]] = icmp uge i8 [[X]], 127
+; CHECK-NEXT: [[DIV:%.*]] = zext i1 [[DIV_CMP]] to i8
; CHECK-NEXT: ret i8 [[DIV]]
;
%cmp.x.upper = icmp ult i8 %x, 128
define i8 @large.divisor.v1.range(ptr %x.ptr) {
; CHECK-LABEL: @large.divisor.v1.range(
; CHECK-NEXT: [[X:%.*]] = load i8, ptr [[X_PTR:%.*]], align 1, !range [[RNG2:![0-9]+]]
-; CHECK-NEXT: [[DIV:%.*]] = udiv i8 [[X]], 127
+; CHECK-NEXT: [[DIV_CMP:%.*]] = icmp uge i8 [[X]], 127
+; CHECK-NEXT: [[DIV:%.*]] = zext i1 [[DIV_CMP]] to i8
; CHECK-NEXT: ret i8 [[DIV]]
;
%x = load i8, ptr %x.ptr, !range !{ i8 0, i8 128 }
; CHECK-LABEL: @large.divisor.with.overflow.v0(
; CHECK-NEXT: [[CMP_X_UPPER:%.*]] = icmp ult i8 [[X:%.*]], -128
; CHECK-NEXT: call void @llvm.assume(i1 [[CMP_X_UPPER]])
-; CHECK-NEXT: [[DIV:%.*]] = udiv i8 [[X]], -128
; CHECK-NEXT: ret i8 0
;
%cmp.x.upper = icmp ult i8 %x, 128
; CHECK-LABEL: @large.divisor.with.overflow.v1(
; CHECK-NEXT: [[CMP_X_UPPER:%.*]] = icmp ult i8 [[X:%.*]], -127
; CHECK-NEXT: call void @llvm.assume(i1 [[CMP_X_UPPER]])
-; CHECK-NEXT: [[DIV:%.*]] = udiv i8 [[X]], -128
+; CHECK-NEXT: [[DIV_CMP:%.*]] = icmp uge i8 [[X]], -128
+; CHECK-NEXT: [[DIV:%.*]] = zext i1 [[DIV_CMP]] to i8
; CHECK-NEXT: ret i8 [[DIV]]
;
%cmp.x.upper = icmp ult i8 %x, 129
define i8 @large.divisor.with.overflow.v1.range(ptr %x.ptr) {
; CHECK-LABEL: @large.divisor.with.overflow.v1.range(
; CHECK-NEXT: [[X:%.*]] = load i8, ptr [[X_PTR:%.*]], align 1, !range [[RNG3:![0-9]+]]
-; CHECK-NEXT: [[DIV:%.*]] = udiv i8 [[X]], -128
+; CHECK-NEXT: [[DIV_CMP:%.*]] = icmp uge i8 [[X]], -128
+; CHECK-NEXT: [[DIV:%.*]] = zext i1 [[DIV_CMP]] to i8
; CHECK-NEXT: ret i8 [[DIV]]
;
%x = load i8, ptr %x.ptr, !range !{ i8 0, i8 129 }
}
define i8 @large.divisor.with.overflow.v2.unbound.x(i8 %x) {
; CHECK-LABEL: @large.divisor.with.overflow.v2.unbound.x(
-; CHECK-NEXT: [[DIV:%.*]] = udiv i8 [[X:%.*]], -128
+; CHECK-NEXT: [[DIV_CMP:%.*]] = icmp uge i8 [[X:%.*]], -128
+; CHECK-NEXT: [[DIV:%.*]] = zext i1 [[DIV_CMP]] to i8
; CHECK-NEXT: ret i8 [[DIV]]
;
%div = udiv i8 %x, 128