diff --git a/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp b/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp index b4f4da6fb0e..230b80e2724 100644 --- a/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp +++ b/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp @@ -336,6 +336,19 @@ Instruction *InstCombiner::commonIDivTransforms(BinaryOperator &I) { return 0; } +/// dyn_castZExtVal - Checks if V is a zext or constant that can +/// be truncated to Ty without losing bits. +static Value *dyn_castZExtVal(Value *V, const Type *Ty) { + if (ZExtInst *Z = dyn_cast(V)) { + if (Z->getSrcTy() == Ty) + return Z->getOperand(0); + } else if (ConstantInt *C = dyn_cast(V)) { + if (C->getValue().getActiveBits() <= cast(Ty)->getBitWidth()) + return ConstantExpr::getTrunc(C, Ty); + } + return 0; +} + Instruction *InstCombiner::visitUDiv(BinaryOperator &I) { Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1); @@ -394,6 +407,14 @@ Instruction *InstCombiner::visitUDiv(BinaryOperator &I) { return SelectInst::Create(Cond, TSI, FSI); } } + + // (zext A) udiv (zext B) --> zext (A udiv B) + if (ZExtInst *ZOp0 = dyn_cast(Op0)) + if (Value *ZOp1 = dyn_castZExtVal(Op1, ZOp0->getSrcTy())) + return new ZExtInst(Builder->CreateUDiv(ZOp0->getOperand(0), ZOp1, "div", + I.isExact()), + I.getType()); + return 0; } @@ -568,7 +589,13 @@ Instruction *InstCombiner::visitURem(BinaryOperator &I) { return SelectInst::Create(Cond, TrueAnd, FalseAnd); } } - + + // (zext A) urem (zext B) --> zext (A urem B) + if (ZExtInst *ZOp0 = dyn_cast(Op0)) + if (Value *ZOp1 = dyn_castZExtVal(Op1, ZOp0->getSrcTy())) + return new ZExtInst(Builder->CreateURem(ZOp0->getOperand(0), ZOp1), + I.getType()); + return 0; } diff --git a/test/Transforms/InstCombine/udivrem-change-width.ll b/test/Transforms/InstCombine/udivrem-change-width.ll index 9983944df8d..b388a3b0634 100644 --- a/test/Transforms/InstCombine/udivrem-change-width.ll +++ b/test/Transforms/InstCombine/udivrem-change-width.ll @@ -1,14 +1,16 @@ -; RUN: opt < %s -instcombine -S | not grep zext -; PR4548 +; RUN: opt < %s -instcombine -S | FileCheck %s target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128" +; PR4548 define i8 @udiv_i8(i8 %a, i8 %b) nounwind { %conv = zext i8 %a to i32 %conv2 = zext i8 %b to i32 %div = udiv i32 %conv, %conv2 %conv3 = trunc i32 %div to i8 ret i8 %conv3 +; CHECK: @udiv_i8 +; CHECK: udiv i8 %a, %b } define i8 @urem_i8(i8 %a, i8 %b) nounwind { @@ -17,5 +19,44 @@ define i8 @urem_i8(i8 %a, i8 %b) nounwind { %div = urem i32 %conv, %conv2 %conv3 = trunc i32 %div to i8 ret i8 %conv3 +; CHECK: @urem_i8 +; CHECK: urem i8 %a, %b } +define i32 @udiv_i32(i8 %a, i8 %b) nounwind { + %conv = zext i8 %a to i32 + %conv2 = zext i8 %b to i32 + %div = udiv i32 %conv, %conv2 + ret i32 %div +; CHECK: @udiv_i32 +; CHECK: udiv i8 %a, %b +; CHECK: zext +} + +define i32 @urem_i32(i8 %a, i8 %b) nounwind { + %conv = zext i8 %a to i32 + %conv2 = zext i8 %b to i32 + %div = urem i32 %conv, %conv2 + ret i32 %div +; CHECK: @urem_i32 +; CHECK: urem i8 %a, %b +; CHECK: zext +} + +define i32 @udiv_i32_c(i8 %a) nounwind { + %conv = zext i8 %a to i32 + %div = udiv i32 %conv, 10 + ret i32 %div +; CHECK: @udiv_i32_c +; CHECK: udiv i8 %a, 10 +; CHECK: zext +} + +define i32 @urem_i32_c(i8 %a) nounwind { + %conv = zext i8 %a to i32 + %div = urem i32 %conv, 10 + ret i32 %div +; CHECK: @urem_i32_c +; CHECK: urem i8 %a, 10 +; CHECK: zext +}