diff --git a/llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h b/llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h --- a/llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h +++ b/llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h @@ -243,6 +243,12 @@ /// Erase \p MI bool eraseInst(MachineInstr &MI); + /// Return true if MI is a G_ADD which can be simplified to a G_SUB. + bool matchSimplifyAddToSub(MachineInstr &MI, + std::tuple &MatchInfo); + bool applySimplifyAddToSub(MachineInstr &MI, + std::tuple &MatchInfo); + /// Try to transform \p MI by using all of the above /// combine functions. Returns true if changed. bool tryCombine(MachineInstr &MI); diff --git a/llvm/include/llvm/Target/GlobalISel/Combine.td b/llvm/include/llvm/Target/GlobalISel/Combine.td --- a/llvm/include/llvm/Target/GlobalISel/Combine.td +++ b/llvm/include/llvm/Target/GlobalISel/Combine.td @@ -232,6 +232,14 @@ (apply [{ return Helper.eraseInst(*${root}); }]) >; +def simplify_add_to_sub_matchinfo: GIDefMatchData<"std::tuple">; +def simplify_add_to_sub: GICombineRule < + (defs root:$root, simplify_add_to_sub_matchinfo:$info), + (match (wip_match_opcode G_ADD):$root, + [{ return Helper.matchSimplifyAddToSub(*${root}, ${info}); }]), + (apply [{ return Helper.applySimplifyAddToSub(*${root}, ${info});}]) +>; + // FIXME: These should use the custom predicate feature once it lands. def undef_combines : GICombineGroup<[undef_to_fp_zero, undef_to_int_zero, undef_to_negative_one, @@ -247,4 +255,4 @@ def trivial_combines : GICombineGroup<[copy_prop, mul_to_shl]>; def all_combines : GICombineGroup<[trivial_combines, ptr_add_immed_chain, combines_for_extload, combine_indexed_load_store, undef_combines, - identity_combines]>; + identity_combines, simplify_add_to_sub]>; diff --git a/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp b/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp --- a/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp +++ b/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp @@ -1671,6 +1671,38 @@ return true; } +bool CombinerHelper::matchSimplifyAddToSub( + MachineInstr &MI, std::tuple &MatchInfo) { + Register LHS = MI.getOperand(1).getReg(); + Register RHS = MI.getOperand(2).getReg(); + Register &NewLHS = std::get<0>(MatchInfo); + Register &NewRHS = std::get<1>(MatchInfo); + + // Helper lambda to check for opportunities for + // ((0-A) + B) -> B - A + // (A + (0-B)) -> A - B + auto CheckFold = [&](Register &MaybeSub, Register &MaybeNewLHS) { + int64_t Cst; + if (!mi_match(MaybeSub, MRI, m_GSub(m_ICst(Cst), m_Reg(NewRHS))) || + Cst != 0) + return false; + NewLHS = MaybeNewLHS; + return true; + }; + + return CheckFold(LHS, RHS) || CheckFold(RHS, LHS); +} + +bool CombinerHelper::applySimplifyAddToSub( + MachineInstr &MI, std::tuple &MatchInfo) { + Builder.setInstr(MI); + Register SubLHS, SubRHS; + std::tie(SubLHS, SubRHS) = MatchInfo; + Builder.buildSub(MI.getOperand(0).getReg(), SubLHS, SubRHS); + MI.eraseFromParent(); + return true; +} + bool CombinerHelper::tryCombine(MachineInstr &MI) { if (tryCombineCopy(MI)) return true; diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/prelegalizercombiner-simplify-add.mir b/llvm/test/CodeGen/AArch64/GlobalISel/prelegalizercombiner-simplify-add.mir new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/AArch64/GlobalISel/prelegalizercombiner-simplify-add.mir @@ -0,0 +1,48 @@ +# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py +# RUN: llc -mtriple aarch64 -run-pass=aarch64-prelegalizer-combiner -verify-machineinstrs %s -o - | FileCheck %s + +name: pat1 +tracksRegLiveness: true +body: | + bb.0: + liveins: $x0, $x1 + ; Fold ((0-A) + B) -> B - A + ; CHECK-LABEL: name: pat1 + ; CHECK: liveins: $x0, $x1 + ; CHECK: %copy1:_(s64) = COPY $x0 + ; CHECK: %copy2:_(s64) = COPY $x1 + ; CHECK: %add:_(s64) = G_SUB %copy2, %copy1 + ; CHECK: $x0 = COPY %add(s64) + ; CHECK: RET_ReallyLR implicit $x0 + %copy1:_(s64) = COPY $x0 + %copy2:_(s64) = COPY $x1 + %zero:_(s64) = G_CONSTANT i64 0 + %sub:_(s64) = G_SUB %zero, %copy1 + %add:_(s64) = G_ADD %sub, %copy2 + $x0 = COPY %add(s64) + RET_ReallyLR implicit $x0 + +... +--- +name: pat2 +tracksRegLiveness: true +body: | + bb.0: + liveins: $x0, $x1 + ; Fold (A + (0-B)) -> A - B + ; CHECK-LABEL: name: pat2 + ; CHECK: liveins: $x0, $x1 + ; CHECK: %copy1:_(s64) = COPY $x0 + ; CHECK: %copy2:_(s64) = COPY $x1 + ; CHECK: %add:_(s64) = G_SUB %copy1, %copy2 + ; CHECK: $x0 = COPY %add(s64) + ; CHECK: RET_ReallyLR implicit $x0 + %copy1:_(s64) = COPY $x0 + %copy2:_(s64) = COPY $x1 + %zero:_(s64) = G_CONSTANT i64 0 + %sub:_(s64) = G_SUB %zero, %copy2 + %add:_(s64) = G_ADD %copy1, %sub + $x0 = COPY %add(s64) + RET_ReallyLR implicit $x0 + +...