From d9638080af13025e8cc9bfd2db99cf63f0cc8e08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thorsten=20Sch=C3=BCtt?= Date: Mon, 1 Jul 2024 20:25:58 +0200 Subject: [PATCH 1/6] [GlobalIsel] Combine G_ADD and G_SUB with constants --- .../llvm/CodeGen/GlobalISel/CombinerHelper.h | 9 ++ .../include/llvm/Target/GlobalISel/Combine.td | 57 ++++++- .../lib/CodeGen/GlobalISel/CombinerHelper.cpp | 150 ++++++++++++++++++ .../AArch64/GlobalISel/combine-add-of-sub.mir | 41 +++-- .../AArch64/GlobalISel/combine-integer.mir | 117 ++++++++++++++ 5 files changed, 351 insertions(+), 23 deletions(-) diff --git a/llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h b/llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h index 05d7e882f5135..48b3c3c381763 100644 --- a/llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h +++ b/llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h @@ -892,6 +892,15 @@ class CombinerHelper { bool matchCastOfSelect(const MachineInstr &Cast, const MachineInstr &SelectMI, BuildFnTy &MatchInfo); + bool matchFoldAPlusC1MinusC2(const MachineInstr &MI, BuildFnTy &MatchInfo); + + bool matchFoldC2MinusAPlusC1(const MachineInstr &MI, BuildFnTy &MatchInfo); + + bool matchFoldAMinusC1MinusC2(const MachineInstr &MI, BuildFnTy &MatchInfo); + + bool matchFoldC1Minus2MinusC2(const MachineInstr &MI, BuildFnTy &MatchInfo); + + bool matchFoldAMinusC2PlusC2(const MachineInstr &MI, BuildFnTy &MatchInfo); private: /// Checks for legality of an indexed variant of \p LdSt. diff --git a/llvm/include/llvm/Target/GlobalISel/Combine.td b/llvm/include/llvm/Target/GlobalISel/Combine.td index 1f26132561cca..10028ce1a8aa6 100644 --- a/llvm/include/llvm/Target/GlobalISel/Combine.td +++ b/llvm/include/llvm/Target/GlobalISel/Combine.td @@ -1747,6 +1747,56 @@ def APlusBMinusCPlusA : GICombineRule< (G_ADD $root, $A, $sub1)), (apply (G_SUB $root, $B, $C))>; +// fold (A+C1)-C2 -> A+(C1-C2) +def APlusC1MinusC2: GICombineRule< + (defs root:$root, build_fn_matchinfo:$matchinfo), + (match (G_CONSTANT $c2, $imm2), + (G_CONSTANT $c1, $imm1), + (G_ADD $add, $A, $c1), + (G_SUB $root, $add, $c2):$root, + [{ return Helper.matchFoldAPlusC1MinusC2(*${root}, ${matchinfo}); }]), + (apply [{ Helper.applyBuildFn(*${root}, ${matchinfo}); }])>; + +// fold C2-(A+C1) -> (C2-C1)-A +def C2MinusAPlusC1: GICombineRule< + (defs root:$root, build_fn_matchinfo:$matchinfo), + (match (G_CONSTANT $c2, $imm2), + (G_CONSTANT $c1, $imm1), + (G_ADD $add, $A, $c1), + (G_SUB $root, $c2, $add):$root, + [{ return Helper.matchFoldC2MinusAPlusC1(*${root}, ${matchinfo}); }]), + (apply [{ Helper.applyBuildFn(*${root}, ${matchinfo}); }])>; + +// fold (A-C1)-C2 -> A-(C1+C2) +def AMinusC1MinusC2: GICombineRule< + (defs root:$root, build_fn_matchinfo:$matchinfo), + (match (G_CONSTANT $c2, $imm2), + (G_CONSTANT $c1, $imm1), + (G_SUB $sub1, $A, $c1), + (G_SUB $root, $sub1, $c2):$root, + [{ return Helper.matchFoldAMinusC1MinusC2(*${root}, ${matchinfo}); }]), + (apply [{ Helper.applyBuildFn(*${root}, ${matchinfo}); }])>; + +// fold (C1-A)-C2 -> (C1-C2)-A +def C1Minus2MinusC2: GICombineRule< + (defs root:$root, build_fn_matchinfo:$matchinfo), + (match (G_CONSTANT $c2, $imm2), + (G_CONSTANT $c1, $imm1), + (G_SUB $sub1, $c1, $A), + (G_SUB $root, $sub1, $c2):$root, + [{ return Helper.matchFoldC1Minus2MinusC2(*${root}, ${matchinfo}); }]), + (apply [{ Helper.applyBuildFn(*${root}, ${matchinfo}); }])>; + +// fold ((A-C1)+C2) -> (A+(C2-C1)) +def AMinusC2PlusC2: GICombineRule< + (defs root:$root, build_fn_matchinfo:$matchinfo), + (match (G_CONSTANT $c2, $imm2), + (G_CONSTANT $c1, $imm1), + (G_SUB $sub, $A, $c1), + (G_ADD $root, $sub, $c2):$root, + [{ return Helper.matchFoldAMinusC2PlusC2(*${root}, ${matchinfo}); }]), + (apply [{ Helper.applyBuildFn(*${root}, ${matchinfo}); }])>; + def integer_reassoc_combines: GICombineGroup<[ ZeroMinusAPlusB, APlusZeroMinusB, @@ -1755,7 +1805,12 @@ def integer_reassoc_combines: GICombineGroup<[ AMinusBPlusCMinusA, AMinusBPlusBMinusC, APlusBMinusAplusC, - APlusBMinusCPlusA + APlusBMinusCPlusA, + APlusC1MinusC2, + C2MinusAPlusC1, + AMinusC1MinusC2, + C1Minus2MinusC2, + AMinusC2PlusC2 ]>; def freeze_of_non_undef_non_poison : GICombineRule< diff --git a/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp b/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp index d930ab2984629..14382477a61dc 100644 --- a/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp +++ b/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp @@ -7433,3 +7433,153 @@ void CombinerHelper::applyExpandFPowI(MachineInstr &MI, int64_t Exponent) { Builder.buildCopy(Dst, *Res); MI.eraseFromParent(); } + +bool CombinerHelper::matchFoldAPlusC1MinusC2(const MachineInstr &MI, + BuildFnTy &MatchInfo) { + // fold (A+C1)-C2 -> A+(C1-C2) + const GSub *Sub = cast(&MI); + GAdd *Add = cast(MRI.getVRegDef(Sub->getLHSReg())); + + if (!MRI.hasOneNonDBGUse(Add->getReg(0))) + return false; + + // Cannot fail due to pattern. + std::optional MaybeC2 = getIConstantVRegVal(Sub->getRHSReg(), MRI); + if (!MaybeC2) + return false; + + // Cannot fail due to pattern. + std::optional MaybeC1 = getIConstantVRegVal(Add->getRHSReg(), MRI); + if (!MaybeC1) + return false; + + Register Dst = Sub->getReg(0); + LLT DstTy = MRI.getType(Dst); + + MatchInfo = [=](MachineIRBuilder &B) { + auto Const = B.buildConstant(DstTy, *MaybeC1 - *MaybeC2); + B.buildAdd(Dst, Add->getLHSReg(), Const); + }; + + return true; +} + +bool CombinerHelper::matchFoldC2MinusAPlusC1(const MachineInstr &MI, + BuildFnTy &MatchInfo) { + // fold C2-(A+C1) -> (C2-C1)-A + const GSub *Sub = cast(&MI); + GAdd *Add = cast(MRI.getVRegDef(Sub->getRHSReg())); + + if (!MRI.hasOneNonDBGUse(Add->getReg(0))) + return false; + + // Cannot fail due to pattern. + std::optional MaybeC2 = getIConstantVRegVal(Sub->getLHSReg(), MRI); + if (!MaybeC2) + return false; + + // Cannot fail due to pattern. + std::optional MaybeC1 = getIConstantVRegVal(Add->getRHSReg(), MRI); + if (!MaybeC1) + return false; + + Register Dst = Sub->getReg(0); + LLT DstTy = MRI.getType(Dst); + + MatchInfo = [=](MachineIRBuilder &B) { + auto Const = B.buildConstant(DstTy, *MaybeC2 - *MaybeC1); + B.buildSub(Dst, Const, Add->getLHSReg()); + }; + + return true; +} + +bool CombinerHelper::matchFoldAMinusC1MinusC2(const MachineInstr &MI, + BuildFnTy &MatchInfo) { + // fold (A-C1)-C2 -> A-(C1+C2) + const GSub *Sub1 = cast(&MI); + GSub *Sub2 = cast(MRI.getVRegDef(Sub1->getLHSReg())); + + if (!MRI.hasOneNonDBGUse(Sub2->getReg(0))) + return false; + + // Cannot fail due to pattern. + std::optional MaybeC2 = getIConstantVRegVal(Sub1->getRHSReg(), MRI); + if (!MaybeC2) + return false; + + // Cannot fail due to pattern. + std::optional MaybeC1 = getIConstantVRegVal(Sub2->getRHSReg(), MRI); + if (!MaybeC1) + return false; + + Register Dst = Sub1->getReg(0); + LLT DstTy = MRI.getType(Dst); + + MatchInfo = [=](MachineIRBuilder &B) { + auto Const = B.buildConstant(DstTy, *MaybeC1 + *MaybeC2); + B.buildSub(Dst, Sub2->getLHSReg(), Const); + }; + + return true; +} + +bool CombinerHelper::matchFoldC1Minus2MinusC2(const MachineInstr &MI, + BuildFnTy &MatchInfo) { + // fold (C1-A)-C2 -> (C1-C2)-A + const GSub *Sub1 = cast(&MI); + GSub *Sub2 = cast(MRI.getVRegDef(Sub1->getLHSReg())); + + if (!MRI.hasOneNonDBGUse(Sub2->getReg(0))) + return false; + + // Cannot fail due to pattern. + std::optional MaybeC2 = getIConstantVRegVal(Sub1->getRHSReg(), MRI); + if (!MaybeC2) + return false; + + // Cannot fail due to pattern. + std::optional MaybeC1 = getIConstantVRegVal(Sub2->getLHSReg(), MRI); + if (!MaybeC1) + return false; + + Register Dst = Sub1->getReg(0); + LLT DstTy = MRI.getType(Dst); + + MatchInfo = [=](MachineIRBuilder &B) { + auto Const = B.buildConstant(DstTy, *MaybeC1 - *MaybeC2); + B.buildSub(Dst, Sub2->getRHSReg(), Const); + }; + + return true; +} + +bool CombinerHelper::matchFoldAMinusC2PlusC2(const MachineInstr &MI, + BuildFnTy &MatchInfo) { + // fold ((A-C1)+C2) -> (A+(C2-C1)) + const GAdd *Add = cast(&MI); + GSub *Sub = cast(MRI.getVRegDef(Add->getLHSReg())); + + if (!MRI.hasOneNonDBGUse(Sub->getReg(0))) + return false; + + // Cannot fail due to pattern. + std::optional MaybeC2 = getIConstantVRegVal(Add->getRHSReg(), MRI); + if (!MaybeC2) + return false; + + // Cannot fail due to pattern. + std::optional MaybeC1 = getIConstantVRegVal(Sub->getRHSReg(), MRI); + if (!MaybeC1) + return false; + + Register Dst = Add->getReg(0); + LLT DstTy = MRI.getType(Dst); + + MatchInfo = [=](MachineIRBuilder &B) { + auto Const = B.buildConstant(DstTy, *MaybeC2 - *MaybeC1); + B.buildAdd(Dst, Sub->getLHSReg(), Const); + }; + + return true; +} diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/combine-add-of-sub.mir b/llvm/test/CodeGen/AArch64/GlobalISel/combine-add-of-sub.mir index ac42d2da16d56..6bd1d996da85f 100644 --- a/llvm/test/CodeGen/AArch64/GlobalISel/combine-add-of-sub.mir +++ b/llvm/test/CodeGen/AArch64/GlobalISel/combine-add-of-sub.mir @@ -3,12 +3,12 @@ ... --- +# (x + y) - y -> x name: simplify_to_x tracksRegLiveness: true body: | bb.0: liveins: $w0, $w1 - ; (x + y) - y -> x ; CHECK-LABEL: name: simplify_to_x ; CHECK: liveins: $w0, $w1 ; CHECK-NEXT: {{ $}} @@ -23,12 +23,12 @@ body: | RET_ReallyLR implicit $w0 ... --- +# (x + y) - x -> y name: simplify_to_y tracksRegLiveness: true body: | bb.0: liveins: $w0, $w1 - ; (x + y) - x -> y ; CHECK-LABEL: name: simplify_to_y ; CHECK: liveins: $w0, $w1 ; CHECK-NEXT: {{ $}} @@ -43,12 +43,12 @@ body: | RET_ReallyLR implicit $w0 ... --- +# (x + 1) - 1 -> x name: simplify_to_constant_x tracksRegLiveness: true body: | bb.0: liveins: $w0, $w1 - ; (x + 1) - 1 -> x ; CHECK-LABEL: name: simplify_to_constant_x ; CHECK: liveins: $w0, $w1 ; CHECK-NEXT: {{ $}} @@ -64,12 +64,12 @@ body: | RET_ReallyLR implicit $w0 ... --- +# (x + y) - x -> y name: simplify_to_constant_y tracksRegLiveness: true body: | bb.0: liveins: $w0, $w1 - ; (x + y) - x -> y ; CHECK-LABEL: name: simplify_to_constant_y ; CHECK: liveins: $w0, $w1 ; CHECK-NEXT: {{ $}} @@ -85,12 +85,12 @@ body: | RET_ReallyLR implicit $w0 ... --- +# (x + y) - y -> x name: vector_simplify_to_x tracksRegLiveness: true body: | bb.0: liveins: $d0, $d1 - ; (x + y) - y -> x ; CHECK-LABEL: name: vector_simplify_to_x ; CHECK: liveins: $d0, $d1 ; CHECK-NEXT: {{ $}} @@ -105,12 +105,12 @@ body: | RET_ReallyLR implicit $d0 ... --- +# (x + 1) - 1 -> x name: splat_simplify_to_x tracksRegLiveness: true body: | bb.0: liveins: $d0, $d1 - ; (x + 1) - 1 -> x ; CHECK-LABEL: name: splat_simplify_to_x ; CHECK: liveins: $d0, $d1 ; CHECK-NEXT: {{ $}} @@ -127,6 +127,7 @@ body: | RET_ReallyLR implicit $d0 ... --- +# (x + y) - x -> y name: unique_registers_no_fold tracksRegLiveness: true body: | @@ -151,20 +152,18 @@ body: | RET_ReallyLR implicit $w0 ... --- +# (x + y) - x -> y name: unique_constants_no_fold tracksRegLiveness: true body: | bb.0: liveins: $w0, $w1 - ; (x + y) - x -> y ; CHECK-LABEL: name: unique_constants_no_fold ; CHECK: liveins: $w0, $w1 ; CHECK-NEXT: {{ $}} - ; CHECK-NEXT: %x1:_(s32) = G_CONSTANT i32 1 - ; CHECK-NEXT: %x2:_(s32) = G_CONSTANT i32 2 ; CHECK-NEXT: %y:_(s32) = COPY $w1 - ; CHECK-NEXT: %add:_(s32) = G_ADD %y, %x1 - ; CHECK-NEXT: %sub:_(s32) = G_SUB %add, %x2 + ; CHECK-NEXT: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 -1 + ; CHECK-NEXT: %sub:_(s32) = G_ADD %y, [[C]] ; CHECK-NEXT: $w0 = COPY %sub(s32) ; CHECK-NEXT: RET_ReallyLR implicit $w0 %x1:_(s32) = G_CONSTANT i32 1 @@ -176,12 +175,12 @@ body: | RET_ReallyLR implicit $w0 ... --- +# x - (y + x) -> 0 - y name: simplify_to_neg_y tracksRegLiveness: true body: | bb.0: liveins: $w0, $w1 - ; x - (y + x) -> 0 - y ; CHECK-LABEL: name: simplify_to_neg_y ; CHECK: liveins: $w0, $w1 ; CHECK-NEXT: {{ $}} @@ -198,12 +197,12 @@ body: | RET_ReallyLR implicit $w0 ... --- +# y - (y + x) -> 0 - x name: simplify_to_neg_x tracksRegLiveness: true body: | bb.0: liveins: $w0, $w1 - ; y - (y + x) -> 0 - x ; CHECK-LABEL: name: simplify_to_neg_x ; CHECK: liveins: $w0, $w1 ; CHECK-NEXT: {{ $}} @@ -220,12 +219,12 @@ body: | RET_ReallyLR implicit $w0 ... --- +# x - (y + x) -> 0 - y name: simplify_to_neg_y_constant tracksRegLiveness: true body: | bb.0: liveins: $w0, $w1 - ; x - (y + x) -> 0 - y ; CHECK-LABEL: name: simplify_to_neg_y_constant ; CHECK: liveins: $w0, $w1 ; CHECK-NEXT: {{ $}} @@ -243,12 +242,12 @@ body: | RET_ReallyLR implicit $w0 ... --- +# y - (y + x) -> 0 - x name: simplify_to_neg_x_constant tracksRegLiveness: true body: | bb.0: liveins: $w0, $w1 - ; y - (y + x) -> 0 - x ; CHECK-LABEL: name: simplify_to_neg_x_constant ; CHECK: liveins: $w0, $w1 ; CHECK-NEXT: {{ $}} @@ -266,12 +265,12 @@ body: | RET_ReallyLR implicit $w0 ... --- +# y - (y + x) -> 0 - x name: vector_simplify_to_neg_x tracksRegLiveness: true body: | bb.0: liveins: $d0, $d1 - ; y - (y + x) -> 0 - x ; CHECK-LABEL: name: vector_simplify_to_neg_x ; CHECK: liveins: $d0, $d1 ; CHECK-NEXT: {{ $}} @@ -289,12 +288,12 @@ body: | RET_ReallyLR implicit $d0 ... --- +# x - (y + x) -> 0 - y name: vector_simplify_to_neg_y_constant tracksRegLiveness: true body: | bb.0: liveins: $d0, $d1 - ; x - (y + x) -> 0 - y ; CHECK-LABEL: name: vector_simplify_to_neg_y_constant ; CHECK: liveins: $d0, $d1 ; CHECK-NEXT: {{ $}} @@ -314,12 +313,12 @@ body: | RET_ReallyLR implicit $d0 ... --- +# y - (y + x) -> 0 - x name: unique_registers_neg_no_fold tracksRegLiveness: true body: | bb.0: liveins: $w0, $w1, $w2 - ; y - (y + x) -> 0 - x ; CHECK-LABEL: name: unique_registers_neg_no_fold ; CHECK: liveins: $w0, $w1, $w2 ; CHECK-NEXT: {{ $}} @@ -339,20 +338,18 @@ body: | RET_ReallyLR implicit $w0 ... --- +# x - (y + x) -> 0 - y name: wrong_constant_neg_no_fold tracksRegLiveness: true body: | bb.0: liveins: $w0, $w1 - ; x - (y + x) -> 0 - y ; CHECK-LABEL: name: wrong_constant_neg_no_fold ; CHECK: liveins: $w0, $w1 ; CHECK-NEXT: {{ $}} ; CHECK-NEXT: %x1:_(s32) = G_CONSTANT i32 1 - ; CHECK-NEXT: %x2:_(s32) = G_CONSTANT i32 2 ; CHECK-NEXT: %y:_(s32) = COPY $w1 - ; CHECK-NEXT: %add:_(s32) = G_ADD %y, %x1 - ; CHECK-NEXT: %sub:_(s32) = G_SUB %x2, %add + ; CHECK-NEXT: %sub:_(s32) = G_SUB %x1, %y ; CHECK-NEXT: $w0 = COPY %sub(s32) ; CHECK-NEXT: RET_ReallyLR implicit $w0 %x1:_(s32) = G_CONSTANT i32 1 diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/combine-integer.mir b/llvm/test/CodeGen/AArch64/GlobalISel/combine-integer.mir index be33f9f7b284b..e1859ef26a713 100644 --- a/llvm/test/CodeGen/AArch64/GlobalISel/combine-integer.mir +++ b/llvm/test/CodeGen/AArch64/GlobalISel/combine-integer.mir @@ -250,3 +250,120 @@ body: | %add:_(<2 x s64>) = G_ADD %a, %sub1 $q0 = COPY %add RET_ReallyLR implicit $x0 + +... +--- +name: APlusC1MinusC2 +body: | + bb.0: + liveins: $w0, $w1 + + ; CHECK-LABEL: name: APlusC1MinusC2 + ; CHECK: liveins: $w0, $w1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: %a:_(s64) = COPY $x0 + ; CHECK-NEXT: [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 -2 + ; CHECK-NEXT: %sub:_(s64) = G_ADD %a, [[C]] + ; CHECK-NEXT: $x0 = COPY %sub(s64) + ; CHECK-NEXT: RET_ReallyLR implicit $x0 + %a:_(s64) = COPY $x0 + %c1:_(s64) = G_CONSTANT i64 5 + %c2:_(s64) = G_CONSTANT i64 7 + %add:_(s64) = G_ADD %a, %c1 + %sub:_(s64) = G_SUB %add, %c2 + $x0 = COPY %sub + RET_ReallyLR implicit $x0 + +... +--- +name: C2MinusAPlusC1 +body: | + bb.0: + liveins: $w0, $w1 + + ; CHECK-LABEL: name: C2MinusAPlusC1 + ; CHECK: liveins: $w0, $w1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: %a:_(s64) = COPY $x0 + ; CHECK-NEXT: [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 5 + ; CHECK-NEXT: %sub:_(s64) = G_SUB [[C]], %a + ; CHECK-NEXT: $x0 = COPY %sub(s64) + ; CHECK-NEXT: RET_ReallyLR implicit $x0 + %a:_(s64) = COPY $x0 + %c1:_(s64) = G_CONSTANT i64 4 + %c2:_(s64) = G_CONSTANT i64 9 + %add:_(s64) = G_ADD %a, %c1 + %sub:_(s64) = G_SUB %c2, %add + $x0 = COPY %sub + RET_ReallyLR implicit $x0 + +... +--- +name: AMinusC1MinusC2 +body: | + bb.0: + liveins: $w0, $w1 + + ; CHECK-LABEL: name: AMinusC1MinusC2 + ; CHECK: liveins: $w0, $w1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: %a:_(s64) = COPY $x0 + ; CHECK-NEXT: [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 71 + ; CHECK-NEXT: %sub:_(s64) = G_SUB %a, [[C]] + ; CHECK-NEXT: $x0 = COPY %sub(s64) + ; CHECK-NEXT: RET_ReallyLR implicit $x0 + %a:_(s64) = COPY $x0 + %c1:_(s64) = G_CONSTANT i64 11 + %c2:_(s64) = G_CONSTANT i64 60 + %sub1:_(s64) = G_SUB %a, %c1 + %sub:_(s64) = G_SUB %sub1, %c2 + $x0 = COPY %sub + RET_ReallyLR implicit $x0 + +... +--- +name: C1Minus2MinusC2 +body: | + bb.0: + liveins: $w0, $w1 + + ; CHECK-LABEL: name: C1Minus2MinusC2 + ; CHECK: liveins: $w0, $w1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: %a:_(s64) = COPY $x0 + ; CHECK-NEXT: [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 -49 + ; CHECK-NEXT: %sub:_(s64) = G_SUB %a, [[C]] + ; CHECK-NEXT: $x0 = COPY %sub(s64) + ; CHECK-NEXT: RET_ReallyLR implicit $x0 + %a:_(s64) = COPY $x0 + %c1:_(s64) = G_CONSTANT i64 11 + %c2:_(s64) = G_CONSTANT i64 60 + %sub1:_(s64) = G_SUB %c1, %a + %sub:_(s64) = G_SUB %sub1, %c2 + $x0 = COPY %sub + RET_ReallyLR implicit $x0 + + +... +--- +name: AMinusC2PlusC2 +body: | + bb.0: + liveins: $w0, $w1 + + ; CHECK-LABEL: name: AMinusC2PlusC2 + ; CHECK: liveins: $w0, $w1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: %a:_(s64) = COPY $x0 + ; CHECK-NEXT: [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 43 + ; CHECK-NEXT: %add:_(s64) = G_ADD %a, [[C]] + ; CHECK-NEXT: $x0 = COPY %add(s64) + ; CHECK-NEXT: RET_ReallyLR implicit $x0 + %a:_(s64) = COPY $x0 + %c1:_(s64) = G_CONSTANT i64 13 + %c2:_(s64) = G_CONSTANT i64 56 + %sub:_(s64) = G_SUB %a, %c1 + %add:_(s64) = G_ADD %sub, %c2 + $x0 = COPY %add + RET_ReallyLR implicit $x0 + From dfaf3291d9ec18b0f7b206d8717b4fd5d0297bee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thorsten=20Sch=C3=BCtt?= Date: Fri, 5 Jul 2024 00:07:27 +0200 Subject: [PATCH 2/6] small fix --- llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp | 2 +- llvm/test/CodeGen/AArch64/GlobalISel/combine-integer.mir | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp b/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp index 14382477a61dc..88441a5de62c7 100644 --- a/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp +++ b/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp @@ -7548,7 +7548,7 @@ bool CombinerHelper::matchFoldC1Minus2MinusC2(const MachineInstr &MI, MatchInfo = [=](MachineIRBuilder &B) { auto Const = B.buildConstant(DstTy, *MaybeC1 - *MaybeC2); - B.buildSub(Dst, Sub2->getRHSReg(), Const); + B.buildSub(Dst, Const, Sub2->getRHSReg()); }; return true; diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/combine-integer.mir b/llvm/test/CodeGen/AArch64/GlobalISel/combine-integer.mir index e1859ef26a713..2f10a497fa74c 100644 --- a/llvm/test/CodeGen/AArch64/GlobalISel/combine-integer.mir +++ b/llvm/test/CodeGen/AArch64/GlobalISel/combine-integer.mir @@ -332,7 +332,7 @@ body: | ; CHECK-NEXT: {{ $}} ; CHECK-NEXT: %a:_(s64) = COPY $x0 ; CHECK-NEXT: [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 -49 - ; CHECK-NEXT: %sub:_(s64) = G_SUB %a, [[C]] + ; CHECK-NEXT: %sub:_(s64) = G_SUB [[C]], %a ; CHECK-NEXT: $x0 = COPY %sub(s64) ; CHECK-NEXT: RET_ReallyLR implicit $x0 %a:_(s64) = COPY $x0 From 3dbd3c250faaf3f050cf0e357dc3f3a41d3547a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thorsten=20Sch=C3=BCtt?= Date: Fri, 5 Jul 2024 08:27:42 +0200 Subject: [PATCH 3/6] IR test --- .../AArch64/GlobalISel/combine-integer-ll.ll | 71 +++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 llvm/test/CodeGen/AArch64/GlobalISel/combine-integer-ll.ll diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/combine-integer-ll.ll b/llvm/test/CodeGen/AArch64/GlobalISel/combine-integer-ll.ll new file mode 100644 index 0000000000000..03dcbafd73e87 --- /dev/null +++ b/llvm/test/CodeGen/AArch64/GlobalISel/combine-integer-ll.ll @@ -0,0 +1,71 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5 +; RUN: llc -mtriple=aarch64 -verify-machineinstrs %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-SD +; RUN: llc -mtriple=aarch64 -global-isel -global-isel-abort=2 -verify-machineinstrs %s -o - 2>&1 | FileCheck %s --check-prefixes=CHECK,CHECK-GI + + + +define i64 @APlusC1MinusC2(i64 %a) { +; CHECK-LABEL: APlusC1MinusC2: +; CHECK: // %bb.0: // %entry +; CHECK-NEXT: sub x0, x0, #1 +; CHECK-NEXT: ret +entry: +; fold (A+C1)-C2 -> A+(C1-C2) + %add1 = add i64 %a, 5 + %sub1 = sub i64 %add1, 6 + ret i64 %sub1 +} + +define i64 @C2MinusAPlusC1(i64 %a) { +; CHECK-LABEL: C2MinusAPlusC1: +; CHECK: // %bb.0: // %entry +; CHECK-NEXT: mov w8, #3 // =0x3 +; CHECK-NEXT: sub x0, x8, x0 +; CHECK-NEXT: ret +entry: +; fold C2-(A+C1) -> (C2-C1)-A + %add1 = add i64 %a, 6 + %sub1 = sub i64 9, %add1 + ret i64 %sub1 +} + +define i64 @AMinusC1MinusC2(i64 %a) { +; CHECK-LABEL: AMinusC1MinusC2: +; CHECK: // %bb.0: // %entry +; CHECK-NEXT: sub x0, x0, #15 +; CHECK-NEXT: ret +entry: +; fold (A-C1)-C2 -> A-(C1+C2) + %sub2 = sub i64 %a, 6 + %sub1 = sub i64 %sub2, 9 + ret i64 %sub1 +} + +define i64 @C1Minus2MinusC2(i64 %a) { +; CHECK-LABEL: C1Minus2MinusC2: +; CHECK: // %bb.0: // %entry +; CHECK-NEXT: mov w8, #3 // =0x3 +; CHECK-NEXT: sub x0, x8, x0 +; CHECK-NEXT: ret +entry: +; fold (C1-A)-C2 -> (C1-C2)-A + %sub2 = sub i64 14, %a + %sub1 = sub i64 %sub2, 11 + ret i64 %sub1 +} + +define i64 @AMinusC2PlusC2(i64 %a) { +; CHECK-LABEL: AMinusC2PlusC2: +; CHECK: // %bb.0: // %entry +; CHECK-NEXT: sub x0, x0, #4 +; CHECK-NEXT: ret +entry: +; fold ((A-C1)+C2) -> (A+(C2-C1)) + %sub1 = sub i64 %a, 21 + %add1 = add i64 %sub1, 17 + ret i64 %add1 +} + +;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line: +; CHECK-GI: {{.*}} +; CHECK-SD: {{.*}} From 490ef262a9a3733d3b42811b0abe614e6891f8bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thorsten=20Sch=C3=BCtt?= Date: Fri, 19 Jul 2024 14:23:01 +0200 Subject: [PATCH 4/6] removed comments --- llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp b/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp index 88441a5de62c7..553d23a9a5887 100644 --- a/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp +++ b/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp @@ -7443,12 +7443,10 @@ bool CombinerHelper::matchFoldAPlusC1MinusC2(const MachineInstr &MI, if (!MRI.hasOneNonDBGUse(Add->getReg(0))) return false; - // Cannot fail due to pattern. std::optional MaybeC2 = getIConstantVRegVal(Sub->getRHSReg(), MRI); if (!MaybeC2) return false; - // Cannot fail due to pattern. std::optional MaybeC1 = getIConstantVRegVal(Add->getRHSReg(), MRI); if (!MaybeC1) return false; @@ -7473,12 +7471,10 @@ bool CombinerHelper::matchFoldC2MinusAPlusC1(const MachineInstr &MI, if (!MRI.hasOneNonDBGUse(Add->getReg(0))) return false; - // Cannot fail due to pattern. std::optional MaybeC2 = getIConstantVRegVal(Sub->getLHSReg(), MRI); if (!MaybeC2) return false; - // Cannot fail due to pattern. std::optional MaybeC1 = getIConstantVRegVal(Add->getRHSReg(), MRI); if (!MaybeC1) return false; @@ -7503,12 +7499,10 @@ bool CombinerHelper::matchFoldAMinusC1MinusC2(const MachineInstr &MI, if (!MRI.hasOneNonDBGUse(Sub2->getReg(0))) return false; - // Cannot fail due to pattern. std::optional MaybeC2 = getIConstantVRegVal(Sub1->getRHSReg(), MRI); if (!MaybeC2) return false; - // Cannot fail due to pattern. std::optional MaybeC1 = getIConstantVRegVal(Sub2->getRHSReg(), MRI); if (!MaybeC1) return false; @@ -7533,12 +7527,10 @@ bool CombinerHelper::matchFoldC1Minus2MinusC2(const MachineInstr &MI, if (!MRI.hasOneNonDBGUse(Sub2->getReg(0))) return false; - // Cannot fail due to pattern. std::optional MaybeC2 = getIConstantVRegVal(Sub1->getRHSReg(), MRI); if (!MaybeC2) return false; - // Cannot fail due to pattern. std::optional MaybeC1 = getIConstantVRegVal(Sub2->getLHSReg(), MRI); if (!MaybeC1) return false; @@ -7563,12 +7555,10 @@ bool CombinerHelper::matchFoldAMinusC2PlusC2(const MachineInstr &MI, if (!MRI.hasOneNonDBGUse(Sub->getReg(0))) return false; - // Cannot fail due to pattern. std::optional MaybeC2 = getIConstantVRegVal(Add->getRHSReg(), MRI); if (!MaybeC2) return false; - // Cannot fail due to pattern. std::optional MaybeC1 = getIConstantVRegVal(Sub->getRHSReg(), MRI); if (!MaybeC1) return false; From 89d058d444e5817ff1f1041130fb8967f8e293d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thorsten=20Sch=C3=BCtt?= Date: Mon, 5 Aug 2024 18:06:28 +0200 Subject: [PATCH 5/6] small fix --- llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h | 3 ++- llvm/include/llvm/Target/GlobalISel/Combine.td | 6 +++--- llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h b/llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h index 48b3c3c381763..c76a54ed26ed5 100644 --- a/llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h +++ b/llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h @@ -900,7 +900,8 @@ class CombinerHelper { bool matchFoldC1Minus2MinusC2(const MachineInstr &MI, BuildFnTy &MatchInfo); - bool matchFoldAMinusC2PlusC2(const MachineInstr &MI, BuildFnTy &MatchInfo); + // fold ((A-C1)+C2) -> (A+(C2-C1)) + bool matchFoldAMinusC1PlusC2(const MachineInstr &MI, BuildFnTy &MatchInfo); private: /// Checks for legality of an indexed variant of \p LdSt. diff --git a/llvm/include/llvm/Target/GlobalISel/Combine.td b/llvm/include/llvm/Target/GlobalISel/Combine.td index 10028ce1a8aa6..54fb14d24b48e 100644 --- a/llvm/include/llvm/Target/GlobalISel/Combine.td +++ b/llvm/include/llvm/Target/GlobalISel/Combine.td @@ -1788,13 +1788,13 @@ def C1Minus2MinusC2: GICombineRule< (apply [{ Helper.applyBuildFn(*${root}, ${matchinfo}); }])>; // fold ((A-C1)+C2) -> (A+(C2-C1)) -def AMinusC2PlusC2: GICombineRule< +def AMinusC1PlusC2: GICombineRule< (defs root:$root, build_fn_matchinfo:$matchinfo), (match (G_CONSTANT $c2, $imm2), (G_CONSTANT $c1, $imm1), (G_SUB $sub, $A, $c1), (G_ADD $root, $sub, $c2):$root, - [{ return Helper.matchFoldAMinusC2PlusC2(*${root}, ${matchinfo}); }]), + [{ return Helper.matchFoldAMinusC1PlusC2(*${root}, ${matchinfo}); }]), (apply [{ Helper.applyBuildFn(*${root}, ${matchinfo}); }])>; def integer_reassoc_combines: GICombineGroup<[ @@ -1810,7 +1810,7 @@ def integer_reassoc_combines: GICombineGroup<[ C2MinusAPlusC1, AMinusC1MinusC2, C1Minus2MinusC2, - AMinusC2PlusC2 + AMinusC1PlusC2 ]>; def freeze_of_non_undef_non_poison : GICombineRule< diff --git a/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp b/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp index 553d23a9a5887..01b01ce525818 100644 --- a/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp +++ b/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp @@ -7546,7 +7546,7 @@ bool CombinerHelper::matchFoldC1Minus2MinusC2(const MachineInstr &MI, return true; } -bool CombinerHelper::matchFoldAMinusC2PlusC2(const MachineInstr &MI, +bool CombinerHelper::matchFoldAMinusC1PlusC2(const MachineInstr &MI, BuildFnTy &MatchInfo) { // fold ((A-C1)+C2) -> (A+(C2-C1)) const GAdd *Add = cast(&MI); From 6b5121acc9cb93fe923e3ed4b761161bf5faeff4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thorsten=20Sch=C3=BCtt?= Date: Wed, 7 Aug 2024 19:57:46 +0200 Subject: [PATCH 6/6] address review comments II --- llvm/include/llvm/CodeGen/GlobalISel/Utils.h | 4 ++ .../lib/CodeGen/GlobalISel/CombinerHelper.cpp | 55 +++++-------------- llvm/lib/CodeGen/GlobalISel/Utils.cpp | 7 +++ 3 files changed, 26 insertions(+), 40 deletions(-) diff --git a/llvm/include/llvm/CodeGen/GlobalISel/Utils.h b/llvm/include/llvm/CodeGen/GlobalISel/Utils.h index 08736acebca8a..cf5fd6d6f288b 100644 --- a/llvm/include/llvm/CodeGen/GlobalISel/Utils.h +++ b/llvm/include/llvm/CodeGen/GlobalISel/Utils.h @@ -22,6 +22,7 @@ #include "llvm/IR/DebugLoc.h" #include "llvm/Support/Alignment.h" #include "llvm/Support/Casting.h" + #include namespace llvm { @@ -178,6 +179,9 @@ std::optional getIConstantVRegVal(Register VReg, std::optional getIConstantVRegSExtVal(Register VReg, const MachineRegisterInfo &MRI); +/// \p VReg is defined by a G_CONSTANT, return the corresponding value. +APInt getIConstantFromReg(Register VReg, const MachineRegisterInfo &MRI); + /// Simple struct used to hold a constant integer value and a virtual /// register. struct ValueAndVReg { diff --git a/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp b/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp index 01b01ce525818..d363e6794cb01 100644 --- a/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp +++ b/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp @@ -7443,19 +7443,14 @@ bool CombinerHelper::matchFoldAPlusC1MinusC2(const MachineInstr &MI, if (!MRI.hasOneNonDBGUse(Add->getReg(0))) return false; - std::optional MaybeC2 = getIConstantVRegVal(Sub->getRHSReg(), MRI); - if (!MaybeC2) - return false; - - std::optional MaybeC1 = getIConstantVRegVal(Add->getRHSReg(), MRI); - if (!MaybeC1) - return false; + APInt C2 = getIConstantFromReg(Sub->getRHSReg(), MRI); + APInt C1 = getIConstantFromReg(Add->getRHSReg(), MRI); Register Dst = Sub->getReg(0); LLT DstTy = MRI.getType(Dst); MatchInfo = [=](MachineIRBuilder &B) { - auto Const = B.buildConstant(DstTy, *MaybeC1 - *MaybeC2); + auto Const = B.buildConstant(DstTy, C1 - C2); B.buildAdd(Dst, Add->getLHSReg(), Const); }; @@ -7471,19 +7466,14 @@ bool CombinerHelper::matchFoldC2MinusAPlusC1(const MachineInstr &MI, if (!MRI.hasOneNonDBGUse(Add->getReg(0))) return false; - std::optional MaybeC2 = getIConstantVRegVal(Sub->getLHSReg(), MRI); - if (!MaybeC2) - return false; - - std::optional MaybeC1 = getIConstantVRegVal(Add->getRHSReg(), MRI); - if (!MaybeC1) - return false; + APInt C2 = getIConstantFromReg(Sub->getLHSReg(), MRI); + APInt C1 = getIConstantFromReg(Add->getRHSReg(), MRI); Register Dst = Sub->getReg(0); LLT DstTy = MRI.getType(Dst); MatchInfo = [=](MachineIRBuilder &B) { - auto Const = B.buildConstant(DstTy, *MaybeC2 - *MaybeC1); + auto Const = B.buildConstant(DstTy, C2 - C1); B.buildSub(Dst, Const, Add->getLHSReg()); }; @@ -7499,19 +7489,14 @@ bool CombinerHelper::matchFoldAMinusC1MinusC2(const MachineInstr &MI, if (!MRI.hasOneNonDBGUse(Sub2->getReg(0))) return false; - std::optional MaybeC2 = getIConstantVRegVal(Sub1->getRHSReg(), MRI); - if (!MaybeC2) - return false; - - std::optional MaybeC1 = getIConstantVRegVal(Sub2->getRHSReg(), MRI); - if (!MaybeC1) - return false; + APInt C2 = getIConstantFromReg(Sub1->getRHSReg(), MRI); + APInt C1 = getIConstantFromReg(Sub2->getRHSReg(), MRI); Register Dst = Sub1->getReg(0); LLT DstTy = MRI.getType(Dst); MatchInfo = [=](MachineIRBuilder &B) { - auto Const = B.buildConstant(DstTy, *MaybeC1 + *MaybeC2); + auto Const = B.buildConstant(DstTy, C1 + C2); B.buildSub(Dst, Sub2->getLHSReg(), Const); }; @@ -7527,19 +7512,14 @@ bool CombinerHelper::matchFoldC1Minus2MinusC2(const MachineInstr &MI, if (!MRI.hasOneNonDBGUse(Sub2->getReg(0))) return false; - std::optional MaybeC2 = getIConstantVRegVal(Sub1->getRHSReg(), MRI); - if (!MaybeC2) - return false; - - std::optional MaybeC1 = getIConstantVRegVal(Sub2->getLHSReg(), MRI); - if (!MaybeC1) - return false; + APInt C2 = getIConstantFromReg(Sub1->getRHSReg(), MRI); + APInt C1 = getIConstantFromReg(Sub2->getLHSReg(), MRI); Register Dst = Sub1->getReg(0); LLT DstTy = MRI.getType(Dst); MatchInfo = [=](MachineIRBuilder &B) { - auto Const = B.buildConstant(DstTy, *MaybeC1 - *MaybeC2); + auto Const = B.buildConstant(DstTy, C1 - C2); B.buildSub(Dst, Const, Sub2->getRHSReg()); }; @@ -7555,19 +7535,14 @@ bool CombinerHelper::matchFoldAMinusC1PlusC2(const MachineInstr &MI, if (!MRI.hasOneNonDBGUse(Sub->getReg(0))) return false; - std::optional MaybeC2 = getIConstantVRegVal(Add->getRHSReg(), MRI); - if (!MaybeC2) - return false; - - std::optional MaybeC1 = getIConstantVRegVal(Sub->getRHSReg(), MRI); - if (!MaybeC1) - return false; + APInt C2 = getIConstantFromReg(Add->getRHSReg(), MRI); + APInt C1 = getIConstantFromReg(Sub->getRHSReg(), MRI); Register Dst = Add->getReg(0); LLT DstTy = MRI.getType(Dst); MatchInfo = [=](MachineIRBuilder &B) { - auto Const = B.buildConstant(DstTy, *MaybeC2 - *MaybeC1); + auto Const = B.buildConstant(DstTy, C2 - C1); B.buildAdd(Dst, Sub->getLHSReg(), Const); }; diff --git a/llvm/lib/CodeGen/GlobalISel/Utils.cpp b/llvm/lib/CodeGen/GlobalISel/Utils.cpp index 080664843aaeb..cfdd9905c16fa 100644 --- a/llvm/lib/CodeGen/GlobalISel/Utils.cpp +++ b/llvm/lib/CodeGen/GlobalISel/Utils.cpp @@ -303,6 +303,13 @@ std::optional llvm::getIConstantVRegVal(Register VReg, return ValAndVReg->Value; } +APInt llvm::getIConstantFromReg(Register Reg, const MachineRegisterInfo &MRI) { + MachineInstr *Const = MRI.getVRegDef(Reg); + assert((Const && Const->getOpcode() == TargetOpcode::G_CONSTANT) && + "expected a G_CONSTANT on Reg"); + return Const->getOperand(1).getCImm()->getValue(); +} + std::optional llvm::getIConstantVRegSExtVal(Register VReg, const MachineRegisterInfo &MRI) { std::optional Val = getIConstantVRegVal(VReg, MRI);