diff --git a/llvm/include/llvm/Target/GlobalISel/Combine.td b/llvm/include/llvm/Target/GlobalISel/Combine.td index 3590ab221ad44..6d5f5f7d43703 100644 --- a/llvm/include/llvm/Target/GlobalISel/Combine.td +++ b/llvm/include/llvm/Target/GlobalISel/Combine.td @@ -747,6 +747,17 @@ def shl_ashr_to_sext_inreg : GICombineRule< (apply [{ Helper.applyAshShlToSextInreg(*${root}, ${info});}]) >; +// Fold sub 0, (and x, 1) -> sext_inreg x, 1 +def neg_and_one_to_sext_inreg : GICombineRule< + (defs root:$dst), + (match (G_AND $and, $x, 1), + (G_SUB $dst, 0, $and), + [{ return MRI.hasOneNonDBGUse(${and}.getReg()) && + Helper.isLegalOrBeforeLegalizer( + {TargetOpcode::G_SEXT_INREG, {MRI.getType(${x}.getReg())}}); }]), + (apply (G_SEXT_INREG $dst, $x, 1)) +>; + // Fold and(and(x, C1), C2) -> C1&C2 ? and(x, C1&C2) : 0 def overlapping_and: GICombineRule < (defs root:$root, build_fn_matchinfo:$info), @@ -2013,7 +2024,7 @@ def all_combines : GICombineGroup<[integer_reassoc_combines, trivial_combines, undef_combines, identity_combines, phi_combines, simplify_add_to_sub, hoist_logic_op_with_same_opcode_hands, shifts_too_big, reassocs, ptr_add_immed_chain, cmp_combines, - shl_ashr_to_sext_inreg, sext_inreg_of_load, + shl_ashr_to_sext_inreg, neg_and_one_to_sext_inreg, sext_inreg_of_load, width_reduction_combines, select_combines, known_bits_simplifications, trunc_shift, not_cmp_fold, opt_brcond_by_inverting_cond, diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/combine-neg-and-one-to-sext-inreg.mir b/llvm/test/CodeGen/AArch64/GlobalISel/combine-neg-and-one-to-sext-inreg.mir new file mode 100644 index 0000000000000..194a15f940da7 --- /dev/null +++ b/llvm/test/CodeGen/AArch64/GlobalISel/combine-neg-and-one-to-sext-inreg.mir @@ -0,0 +1,81 @@ +# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 5 +# RUN: llc -o - -mtriple aarch64-- -run-pass=aarch64-prelegalizer-combiner %s | FileCheck %s +--- +name: test_combine_neg_and_one_to_sext_inreg_s32 +body: | + bb.1: + liveins: $w0 + ; CHECK-LABEL: name: test_combine_neg_and_one_to_sext_inreg_s32 + ; CHECK: liveins: $w0 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: %x:_(s32) = COPY $w0 + ; CHECK-NEXT: %res:_(s32) = G_SEXT_INREG %x, 1 + ; CHECK-NEXT: $w0 = COPY %res(s32) + %x:_(s32) = COPY $w0 + %one:_(s32) = G_CONSTANT i32 1 + %zero:_(s32) = G_CONSTANT i32 0 + %and:_(s32) = G_AND %x:_, %one:_ + %res:_(s32) = G_SUB %zero:_, %and:_ + $w0 = COPY %res:_(s32) +... +--- +name: test_combine_neg_and_one_to_sext_inreg_s64 +body: | + bb.1: + liveins: $x0 + ; CHECK-LABEL: name: test_combine_neg_and_one_to_sext_inreg_s64 + ; CHECK: liveins: $x0 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: %x:_(s64) = COPY $x0 + ; CHECK-NEXT: %res:_(s64) = G_SEXT_INREG %x, 1 + ; CHECK-NEXT: $x0 = COPY %res(s64) + %x:_(s64) = COPY $x0 + %one:_(s64) = G_CONSTANT i64 1 + %zero:_(s64) = G_CONSTANT i64 0 + %and:_(s64) = G_AND %x:_, %one:_ + %res:_(s64) = G_SUB %zero:_, %and:_ + $x0 = COPY %res:_(s64) +... +--- +name: test_combine_neg_and_one_to_sext_inreg_multiuse_should_not_transform +body: | + bb.1: + liveins: $x0 + ; CHECK-LABEL: name: test_combine_neg_and_one_to_sext_inreg_multiuse_should_not_transform + ; CHECK: liveins: $x0 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: %x:_(s64) = COPY $x0 + ; CHECK-NEXT: %one:_(s64) = G_CONSTANT i64 1 + ; CHECK-NEXT: %zero:_(s64) = G_CONSTANT i64 0 + ; CHECK-NEXT: %and:_(s64) = G_AND %x, %one + ; CHECK-NEXT: %res:_(s64) = G_SUB %zero, %and + ; CHECK-NEXT: $x0 = COPY %res(s64) + ; CHECK-NEXT: $x1 = COPY %and(s64) + %x:_(s64) = COPY $x0 + %one:_(s64) = G_CONSTANT i64 1 + %zero:_(s64) = G_CONSTANT i64 0 + %and:_(s64) = G_AND %x:_, %one:_ + %res:_(s64) = G_SUB %zero:_, %and:_ + $x0 = COPY %res:_(s64) + $x1 = COPY %and:_(s64) +... +--- +name: test_combine_neg_and_one_to_sext_inreg_v2i32 +body: | + bb.1: + liveins: $d0 + ; CHECK-LABEL: name: test_combine_neg_and_one_to_sext_inreg_v2i32 + ; CHECK: liveins: $d0 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: %x:_(<2 x s32>) = COPY $d0 + ; CHECK-NEXT: %res:_(<2 x s32>) = G_SEXT_INREG %x, 1 + ; CHECK-NEXT: $d0 = COPY %res(<2 x s32>) + %x:_(<2 x s32>) = COPY $d0 + %one:_(s32) = G_CONSTANT i32 1 + %ones:_(<2 x s32>) = G_BUILD_VECTOR %one, %one + %zero:_(s32) = G_CONSTANT i32 0 + %zeros:_(<2 x s32>) = G_BUILD_VECTOR %zero, %zero + %and:_(<2 x s32>) = G_AND %x:_, %ones:_ + %res:_(<2 x s32>) = G_SUB %zeros:_, %and:_ + $d0 = COPY %res:_(<2 x s32>) +...