; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6 ; RUN: llc -mtriple=aarch64-none-eabi -global-isel -verify-machineinstrs %s -o - | FileCheck %s ; (sub a, (mul x, K)) where K is a constant lowers to MADD with -K. ; Basic positive K: madd with -7. define i32 @sub_of_mul_const_pos_k(i32 %x, i32 %a) { ; CHECK-LABEL: sub_of_mul_const_pos_k: ; CHECK: // %bb.0: ; CHECK-NEXT: sub w8, w0, w0, lsl #3 ; CHECK-NEXT: add w0, w1, w8 ; CHECK-NEXT: ret %mul = mul i32 %x, 7 %sub = sub i32 %a, %mul ret i32 %sub } ; Negative K: madd with +7. define i32 @sub_of_mul_const_neg_k(i32 %x, i32 %a) { ; CHECK-LABEL: sub_of_mul_const_neg_k: ; CHECK: // %bb.0: ; CHECK-NEXT: lsl w8, w0, #3 ; CHECK-NEXT: sub w8, w8, w0 ; CHECK-NEXT: add w0, w1, w8 ; CHECK-NEXT: ret %mul = mul i32 %x, -7 %sub = sub i32 %a, %mul ret i32 %sub } ; A = 0: collapses via combine_add_with_zero to mul x, -K. define i32 @sub_of_mul_const_zero_a(i32 %x) { ; CHECK-LABEL: sub_of_mul_const_zero_a: ; CHECK: // %bb.0: ; CHECK-NEXT: sub w0, w0, w0, lsl #3 ; CHECK-NEXT: ret %mul = mul i32 %x, 7 %sub = sub i32 0, %mul ret i32 %sub } ; i64 width. define i64 @sub_of_mul_const_i64(i64 %x, i64 %a) { ; CHECK-LABEL: sub_of_mul_const_i64: ; CHECK: // %bb.0: ; CHECK-NEXT: sub x8, x0, x0, lsl #3 ; CHECK-NEXT: add x0, x1, x8 ; CHECK-NEXT: ret %mul = mul i64 %x, 7 %sub = sub i64 %a, %mul ret i64 %sub } ; K is not a constant: bail (msub with the original operand). define i32 @sub_of_mul_non_const(i32 %x, i32 %y, i32 %a) { ; CHECK-LABEL: sub_of_mul_non_const: ; CHECK: // %bb.0: ; CHECK-NEXT: msub w0, w0, w1, w2 ; CHECK-NEXT: ret %mul = mul i32 %x, %y %sub = sub i32 %a, %mul ret i32 %sub } ; Mul has multiple users: bail (would either duplicate or regress). define i32 @sub_of_mul_const_multi_use(i32 %x, i32 %a, ptr %p) { ; CHECK-LABEL: sub_of_mul_const_multi_use: ; CHECK: // %bb.0: ; CHECK-NEXT: lsl w8, w0, #3 ; CHECK-NEXT: sub w8, w8, w0 ; CHECK-NEXT: sub w0, w1, w8 ; CHECK-NEXT: str w8, [x2] ; CHECK-NEXT: ret %mul = mul i32 %x, 7 %sub = sub i32 %a, %mul store i32 %mul, ptr %p ret i32 %sub } ; Vector splat: not handled in this scalar-only first cut. define <4 x i32> @sub_of_mul_const_vector_splat(<4 x i32> %x, <4 x i32> %a) { ; CHECK-LABEL: sub_of_mul_const_vector_splat: ; CHECK: // %bb.0: ; CHECK-NEXT: movi v2.4s, #7 ; CHECK-NEXT: mls v1.4s, v0.4s, v2.4s ; CHECK-NEXT: mov v0.16b, v1.16b ; CHECK-NEXT: ret %mul = mul <4 x i32> %x, %sub = sub <4 x i32> %a, %mul ret <4 x i32> %sub }