Index: llvm/trunk/lib/Transforms/InstCombine/InstCombineCasts.cpp =================================================================== --- llvm/trunk/lib/Transforms/InstCombine/InstCombineCasts.cpp +++ llvm/trunk/lib/Transforms/InstCombine/InstCombineCasts.cpp @@ -185,8 +185,14 @@ case Instruction::Shl: case Instruction::UDiv: case Instruction::URem: { - Value *LHS = EvaluateInDifferentType(I->getOperand(0), Ty, isSigned); - Value *RHS = EvaluateInDifferentType(I->getOperand(1), Ty, isSigned); + Value *LHS, *RHS; + if (I->getOperand(0) == I->getOperand(1)) { + // Don't create an unnecessary value if the operands are repeated. + LHS = RHS = EvaluateInDifferentType(I->getOperand(0), Ty, isSigned); + } else { + LHS = EvaluateInDifferentType(I->getOperand(0), Ty, isSigned); + RHS = EvaluateInDifferentType(I->getOperand(1), Ty, isSigned); + } Res = BinaryOperator::Create((Instruction::BinaryOps)Opc, LHS, RHS); break; } @@ -320,10 +326,12 @@ assert(!isa(V) && "Constant should already be handled."); if (!isa(V)) return true; - // We can't extend or shrink something that has multiple uses: doing so would - // require duplicating the instruction in general, which isn't profitable. + // We can't extend or shrink something that has multiple uses -- unless those + // multiple uses are all in the same instruction -- doing so would require + // duplicating the instruction which isn't profitable. if (!V->hasOneUse()) - return true; + if (any_of(V->users(), [&](User *U) { return U != V->user_back(); })) + return true; return false; } Index: llvm/trunk/test/Transforms/InstCombine/cast-mul-select.ll =================================================================== --- llvm/trunk/test/Transforms/InstCombine/cast-mul-select.ll +++ llvm/trunk/test/Transforms/InstCombine/cast-mul-select.ll @@ -49,11 +49,9 @@ define i32 @eval_trunc_multi_use_in_one_inst(i32 %x) { ; CHECK-LABEL: @eval_trunc_multi_use_in_one_inst( -; CHECK-NEXT: [[Z:%.*]] = zext i32 [[X:%.*]] to i64 -; CHECK-NEXT: [[A:%.*]] = add nuw nsw i64 [[Z]], 15 -; CHECK-NEXT: [[M:%.*]] = mul i64 [[A]], [[A]] -; CHECK-NEXT: [[T:%.*]] = trunc i64 [[M]] to i32 -; CHECK-NEXT: ret i32 [[T]] +; CHECK-NEXT: [[A:%.*]] = add i32 [[X:%.*]], 15 +; CHECK-NEXT: [[M:%.*]] = mul i32 [[A]], [[A]] +; CHECK-NEXT: ret i32 [[M]] ; %z = zext i32 %x to i64 %a = add nsw nuw i64 %z, 15 @@ -64,11 +62,9 @@ define i32 @eval_zext_multi_use_in_one_inst(i32 %x) { ; CHECK-LABEL: @eval_zext_multi_use_in_one_inst( -; CHECK-NEXT: [[T:%.*]] = trunc i32 [[X:%.*]] to i16 -; CHECK-NEXT: [[A:%.*]] = and i16 [[T]], 5 -; CHECK-NEXT: [[M:%.*]] = mul nuw nsw i16 [[A]], [[A]] -; CHECK-NEXT: [[R:%.*]] = zext i16 [[M]] to i32 -; CHECK-NEXT: ret i32 [[R]] +; CHECK-NEXT: [[A:%.*]] = and i32 [[X:%.*]], 5 +; CHECK-NEXT: [[M:%.*]] = mul nuw nsw i32 [[A]], [[A]] +; CHECK-NEXT: ret i32 [[M]] ; %t = trunc i32 %x to i16 %a = and i16 %t, 5 @@ -79,12 +75,10 @@ define i32 @eval_sext_multi_use_in_one_inst(i32 %x) { ; CHECK-LABEL: @eval_sext_multi_use_in_one_inst( -; CHECK-NEXT: [[T:%.*]] = trunc i32 [[X:%.*]] to i16 -; CHECK-NEXT: [[A:%.*]] = and i16 [[T]], 14 -; CHECK-NEXT: [[M:%.*]] = mul nuw nsw i16 [[A]], [[A]] -; CHECK-NEXT: [[O:%.*]] = or i16 [[M]], -32768 -; CHECK-NEXT: [[R:%.*]] = sext i16 [[O]] to i32 -; CHECK-NEXT: ret i32 [[R]] +; CHECK-NEXT: [[A:%.*]] = and i32 [[X:%.*]], 14 +; CHECK-NEXT: [[M:%.*]] = mul nuw nsw i32 [[A]], [[A]] +; CHECK-NEXT: [[O:%.*]] = or i32 [[M]], -32768 +; CHECK-NEXT: ret i32 [[O]] ; %t = trunc i32 %x to i16 %a = and i16 %t, 14 Index: llvm/trunk/test/Transforms/InstCombine/icmp-mul-zext.ll =================================================================== --- llvm/trunk/test/Transforms/InstCombine/icmp-mul-zext.ll +++ llvm/trunk/test/Transforms/InstCombine/icmp-mul-zext.ll @@ -55,13 +55,12 @@ define void @PR33765(i8 %beth) { ; CHECK-LABEL: @PR33765( -; CHECK-NEXT: [[CONV:%.*]] = zext i8 [[BETH:%.*]] to i32 +; CHECK-NEXT: [[CONV:%.*]] = zext i8 [[BETH:%.*]] to i16 ; CHECK-NEXT: br i1 false, label [[IF_THEN9:%.*]], label [[IF_THEN9]] ; CHECK: if.then9: -; CHECK-NEXT: [[MUL:%.*]] = mul nuw nsw i32 [[CONV]], [[CONV]] +; CHECK-NEXT: [[MUL:%.*]] = mul nuw i16 [[CONV]], [[CONV]] ; CHECK-NEXT: [[TINKY:%.*]] = load i16, i16* @glob, align 2 -; CHECK-NEXT: [[TMP1:%.*]] = trunc i32 [[MUL]] to i16 -; CHECK-NEXT: [[CONV14:%.*]] = and i16 [[TINKY]], [[TMP1]] +; CHECK-NEXT: [[CONV14:%.*]] = and i16 [[TINKY]], [[MUL]] ; CHECK-NEXT: store i16 [[CONV14]], i16* @glob, align 2 ; CHECK-NEXT: ret void ;