Index: llvm/lib/Transforms/InstCombine/InstructionCombining.cpp =================================================================== --- llvm/lib/Transforms/InstCombine/InstructionCombining.cpp +++ llvm/lib/Transforms/InstCombine/InstructionCombining.cpp @@ -740,35 +740,33 @@ BinaryOperator *Op1 = dyn_cast(RHS); Instruction::BinaryOps TopLevelOpcode = I.getOpcode(); - { - // Factorization. - Value *A, *B, *C, *D; - Instruction::BinaryOps LHSOpcode, RHSOpcode; - if (Op0) - LHSOpcode = getBinOpsForFactorization(TopLevelOpcode, Op0, A, B); - if (Op1) - RHSOpcode = getBinOpsForFactorization(TopLevelOpcode, Op1, C, D); - - // The instruction has the form "(A op' B) op (C op' D)". Try to factorize - // a common term. - if (Op0 && Op1 && LHSOpcode == RHSOpcode) - if (Value *V = tryFactorization(I, LHSOpcode, A, B, C, D)) + // Factorization. + Value *A, *B, *C, *D; + Instruction::BinaryOps LHSOpcode, RHSOpcode; + if (Op0) + LHSOpcode = getBinOpsForFactorization(TopLevelOpcode, Op0, A, B); + if (Op1) + RHSOpcode = getBinOpsForFactorization(TopLevelOpcode, Op1, C, D); + + // The instruction has the form "(A op' B) op (C op' D)". Try to factorize + // a common term. + if (Op0 && Op1 && LHSOpcode == RHSOpcode) + if (Value *V = tryFactorization(I, LHSOpcode, A, B, C, D)) + return V; + + // The instruction has the form "(A op' B) op (C)". Try to factorize common + // term. + if (Op0) + if (Value *Ident = getIdentityValue(LHSOpcode, RHS)) + if (Value *V = tryFactorization(I, LHSOpcode, A, B, RHS, Ident)) return V; - // The instruction has the form "(A op' B) op (C)". Try to factorize common - // term. - if (Op0) - if (Value *Ident = getIdentityValue(LHSOpcode, RHS)) - if (Value *V = tryFactorization(I, LHSOpcode, A, B, RHS, Ident)) - return V; - - // The instruction has the form "(B) op (C op' D)". Try to factorize common - // term. - if (Op1) - if (Value *Ident = getIdentityValue(RHSOpcode, LHS)) - if (Value *V = tryFactorization(I, RHSOpcode, LHS, Ident, C, D)) - return V; - } + // The instruction has the form "(B) op (C op' D)". Try to factorize common + // term. + if (Op1) + if (Value *Ident = getIdentityValue(RHSOpcode, LHS)) + if (Value *V = tryFactorization(I, RHSOpcode, LHS, Ident, C, D)) + return V; // Expansion. if (Op0 && rightDistributesOverLeft(Op0->getOpcode(), TopLevelOpcode)) { Index: llvm/test/Transforms/InstCombine/add4.ll =================================================================== --- llvm/test/Transforms/InstCombine/add4.ll +++ llvm/test/Transforms/InstCombine/add4.ll @@ -1,6 +1,8 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py ; RUN: opt < %s -passes=instcombine -S | FileCheck %s +declare i32 @use32(i32) + define i64 @match_unsigned(i64 %x) { ; CHECK-LABEL: @match_unsigned( ; CHECK-NEXT: [[UREM:%.*]] = urem i64 [[X:%.*]], 19136 @@ -127,3 +129,103 @@ %t4 = add i32 %t, %t3 ret i32 %t4 } + +; TODO: (x + (-1)) + (x * 5) --> (x * 6) + (-1) +define i8 @mul_add_common_factor_commute0(i8 %x) { +; CHECK-LABEL: @mul_add_common_factor_commute0( +; CHECK-NEXT: [[A0:%.*]] = add i8 [[X:%.*]], -1 +; CHECK-NEXT: [[M:%.*]] = mul i8 [[X]], 5 +; CHECK-NEXT: [[A1:%.*]] = add i8 [[A0]], [[M]] +; CHECK-NEXT: ret i8 [[A1]] +; + %a0 = add i8 %x, -1 + %m = mul i8 %x, 5 + %a1 = add i8 %a0, %m + ret i8 %a1 +} + +; TODO: (x * 4) + (x - 1) --> (x * 5) + (-1) +define i16 @mul_add_common_factor_commute1(i16 %x) { +; CHECK-LABEL: @mul_add_common_factor_commute1( +; CHECK-NEXT: [[A0:%.*]] = add i16 [[X:%.*]], -1 +; CHECK-NEXT: [[M:%.*]] = shl i16 [[X]], 2 +; CHECK-NEXT: [[A1:%.*]] = add i16 [[M]], [[A0]] +; CHECK-NEXT: ret i16 [[A1]] +; + %a0 = add i16 %x, -1 + %m = mul i16 %x, 4 + %a1 = add i16 %m, %a0 + ret i16 %a1 +} + +; TODO: (x + y) + (x * 4) --> (x * 5) + y +define i32 @mul_add_common_factor_commute2(i32 %x, i32 %y) { +; CHECK-LABEL: @mul_add_common_factor_commute2( +; CHECK-NEXT: [[A0:%.*]] = add i32 [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: [[M:%.*]] = shl i32 [[X]], 2 +; CHECK-NEXT: [[A1:%.*]] = add i32 [[A0]], [[M]] +; CHECK-NEXT: ret i32 [[A1]] +; + %a0 = add i32 %x, %y + %m = mul i32 %x, 4 + %a1 = add i32 %a0, %m + ret i32 %a1 +} + +; TODO: (x + y) + (x << 2) --> (x * 5) + y +define i64 @shl_add_common_factor_commute2(i64 %x, i64 %y) { +; CHECK-LABEL: @shl_add_common_factor_commute2( +; CHECK-NEXT: [[A0:%.*]] = add i64 [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: [[S:%.*]] = shl i64 [[X]], 2 +; CHECK-NEXT: [[A1:%.*]] = add i64 [[A0]], [[S]] +; CHECK-NEXT: ret i64 [[A1]] +; + %a0 = add i64 %x, %y + %s = shl i64 %x, 2 + %a1 = add i64 %a0, %s + ret i64 %a1 +} + +; TODO: (x + 2) + (x * t) --> (t + 1) * x + 2 +define i128 @mul_add_common_factor_commute3(i128 %x, i128 %t) { +; CHECK-LABEL: @mul_add_common_factor_commute3( +; CHECK-NEXT: [[A0:%.*]] = add i128 [[X:%.*]], 2 +; CHECK-NEXT: [[M:%.*]] = mul i128 [[X]], [[T:%.*]] +; CHECK-NEXT: [[A1:%.*]] = add i128 [[A0]], [[M]] +; CHECK-NEXT: ret i128 [[A1]] +; + %a0 = add i128 %x, 2 + %m = mul i128 %x, %t + %a1 = add i128 %a0, %m + ret i128 %a1 +} + +; Negative test: The transformation should not create more instructions +define i32 @mul_add_common_factor_commute1_one_use(i32 %x) { +; CHECK-LABEL: @mul_add_common_factor_commute1_one_use( +; CHECK-NEXT: [[A0:%.*]] = add i32 [[X:%.*]], -1 +; CHECK-NEXT: [[M:%.*]] = shl i32 [[X]], 2 +; CHECK-NEXT: call void @use32(i32 [[M]]) +; CHECK-NEXT: [[A1:%.*]] = add i32 [[M]], [[A0]] +; CHECK-NEXT: ret i32 [[A1]] +; + %a0 = add i32 %x, -1 + %m = mul i32 %x, 4 + call void @use32(i32 %m) + %a1 = add i32 %m, %a0 + ret i32 %a1 +} + +; TODO: (x * 4) + (x + 3) --> (x * 5) + 3 +define <2 x i8> @mul_add_common_factor_commute1_vector(<2 x i8> %x) { +; CHECK-LABEL: @mul_add_common_factor_commute1_vector( +; CHECK-NEXT: [[A0:%.*]] = add <2 x i8> [[X:%.*]], +; CHECK-NEXT: [[M:%.*]] = shl <2 x i8> [[X]], +; CHECK-NEXT: [[A1:%.*]] = add <2 x i8> [[M]], [[A0]] +; CHECK-NEXT: ret <2 x i8> [[A1]] +; + %a0 = add <2 x i8> %x, + %m = mul <2 x i8> %x, + %a1 = add <2 x i8> %m, %a0 + ret <2 x i8> %a1 +}