diff options
author | Kai Nacke <kai@redstar.de> | 2022-09-08 23:19:18 -0400 |
---|---|---|
committer | Kai Nacke <kai@redstar.de> | 2022-11-13 11:07:57 -0500 |
commit | cf0e46afd13afca6c22ee04995f691b552dbe345 (patch) | |
tree | 1fa928631e99392bcb6aa89979a4fefa75da7707 | |
parent | b99c558013e5bd99e91d9b78d732dc9d7bf21b94 (diff) | |
download | llvm-cf0e46afd13afca6c22ee04995f691b552dbe345.zip llvm-cf0e46afd13afca6c22ee04995f691b552dbe345.tar.gz llvm-cf0e46afd13afca6c22ee04995f691b552dbe345.tar.bz2 |
[m88k] More combine rules with carry operations.
Adds some more special cases which turns a comparison into an arithmetic
expression involving the carry bit.
-rw-r--r-- | llvm/lib/Target/M88k/GISel/M88kPostLegalizerCombiner.cpp | 131 | ||||
-rw-r--r-- | llvm/lib/Target/M88k/M88kCombine.td | 45 | ||||
-rw-r--r-- | llvm/test/CodeGen/M88k/add.ll | 74 |
3 files changed, 236 insertions, 14 deletions
diff --git a/llvm/lib/Target/M88k/GISel/M88kPostLegalizerCombiner.cpp b/llvm/lib/Target/M88k/GISel/M88kPostLegalizerCombiner.cpp index 65f6aee..8034513 100644 --- a/llvm/lib/Target/M88k/GISel/M88kPostLegalizerCombiner.cpp +++ b/llvm/lib/Target/M88k/GISel/M88kPostLegalizerCombiner.cpp @@ -180,7 +180,7 @@ bool matchAddCmpToSubAdd2(MachineInstr &MI, MachineOperand &Src1, // - Pred = unsigned <= // - Pred = equal and either SrcB or SrcC being zero // The returned MatchInfo transforms this sequence into -// Unused, Carry = G_USUBU SrcB', SrcC' +// Unused, Carry = G_USUBO SrcB', SrcC' // Dst, UnusedCarry = G_UADDE SrcA, Zero, Carry // with SrcB' and SrcC' derived from SrcB and SrcC, inserting a zero constant // value if necessary. @@ -202,23 +202,21 @@ bool matchAddSubFromAddICmp(MachineInstr &MI, MachineRegisterInfo &MRI, switch (Pred) { case CmpInst::ICMP_UGE: - std::swap(SrcRegB, SrcRegC); ZeroReg = MRI.createGenericVirtualRegister(LLT::scalar(32)); break; case CmpInst::ICMP_ULE: + std::swap(SrcRegB, SrcRegC); ZeroReg = MRI.createGenericVirtualRegister(LLT::scalar(32)); break; - case CmpInst::ICMP_EQ: { - int64_t Cst; - if (mi_match(SrcRegB, MRI, m_ICst(Cst)) && Cst == 0) { + case CmpInst::ICMP_EQ: + if (mi_match(SrcRegB, MRI, m_ZeroInt())) { ZeroReg = SrcRegB; - } else if (mi_match(SrcRegC, MRI, m_ICst(Cst)) && Cst == 0) { + } else if (mi_match(SrcRegC, MRI, m_ZeroInt())) { std::swap(SrcRegB, SrcRegC); ZeroReg = SrcRegB; } else return false; break; - } default: return false; } @@ -239,6 +237,125 @@ bool matchAddSubFromAddICmp(MachineInstr &MI, MachineRegisterInfo &MRI, } // Match +// Dst = G_SUB SrcA, (G_ZEXT (G_ICMP Pred, SrcB, SrcC) +// with: +// - Pred = unsigned > +// - Pred = unsigned < +// - Pred = not equal and either SrcB or SrcC being zero +// The returned MatchInfo transforms this sequence into +// Unused, Carry = G_USUBO SrcB', SrcC' +// Dst, UnusedCarry = G_USUBE SrcA, Zero, Carry +// with SrcB' and SrcC' derived from SrcB and SrcC, inserting a zero constant +// value if necessary. +bool matchSubSubFromSubICmp(MachineInstr &MI, MachineRegisterInfo &MRI, + BuildFnTy &MatchInfo) { + assert(MI.getOpcode() == TargetOpcode::G_SUB); + + Register DstReg = MI.getOperand(0).getReg(); + Register SrcRegA; + Register SrcRegB; + Register SrcRegC; + Register ZeroReg; + CmpInst::Predicate Pred; + if (!mi_match( + MI, MRI, + m_GSub(m_Reg(SrcRegA), m_GZExt(m_GICmp(m_Pred(Pred), m_Reg(SrcRegB), + m_Reg(SrcRegC)))))) + return false; + + switch (Pred) { + case CmpInst::ICMP_UGT: + std::swap(SrcRegB, SrcRegC); + ZeroReg = MRI.createGenericVirtualRegister(LLT::scalar(32)); + break; + case CmpInst::ICMP_ULT: + ZeroReg = MRI.createGenericVirtualRegister(LLT::scalar(32)); + break; + case CmpInst::ICMP_NE: + if (mi_match(SrcRegB, MRI, m_ZeroInt())) { + ZeroReg = SrcRegB; + } else if (mi_match(SrcRegC, MRI, m_ZeroInt())) { + std::swap(SrcRegB, SrcRegC); + ZeroReg = SrcRegB; + } else + return false; + break; + default: + return false; + } + + Register Carry = MRI.createGenericVirtualRegister(LLT::scalar(1)); + Register UnusedReg = MRI.createGenericVirtualRegister(LLT::scalar(32)); + Register UnusedCarry = MRI.createGenericVirtualRegister(LLT::scalar(1)); + + MatchInfo = [=](MachineIRBuilder &B) { + if (Pred != CmpInst::ICMP_NE) + B.buildConstant(ZeroReg, 0); + B.buildInstr(TargetOpcode::G_USUBO, {UnusedReg, Carry}, {SrcRegB, SrcRegC}); + B.buildInstr(TargetOpcode::G_USUBE, {DstReg, UnusedCarry}, + {SrcRegA, ZeroReg, Carry}); + }; + + return true; +} + +// Match +// Dst = G_SUB SrcA, (G_ZEXT (G_ICMP Pred, SrcB, SrcC) +// with: +// - Pred = signed >= and SrcC equals zero +// - Pred = signed <= and SrcB equals zero +// The returned MatchInfo transforms this sequence into +// Unused, Carry = G_UADDO SrcB', SrcC' +// Dst, UnusedCarry = G_USUBE SrcA, Zero, Carry +// with SrcB' and SrcC' derived from SrcB and SrcC. +bool matchSubAddFromSubICmp(MachineInstr &MI, MachineRegisterInfo &MRI, + BuildFnTy &MatchInfo) { + assert(MI.getOpcode() == TargetOpcode::G_SUB); + + Register DstReg = MI.getOperand(0).getReg(); + Register SrcRegA; + Register SrcRegB; + Register SrcRegC; + Register ZeroReg; + CmpInst::Predicate Pred; + if (!mi_match( + MI, MRI, + m_GSub(m_Reg(SrcRegA), m_GZExt(m_GICmp(m_Pred(Pred), m_Reg(SrcRegB), + m_Reg(SrcRegC)))))) + return false; + + switch (Pred) { + case CmpInst::ICMP_SGE: + if (mi_match(SrcRegC, MRI, m_ZeroInt())) { + ZeroReg = SrcRegC; + } else + return false; + break; + case CmpInst::ICMP_SLE: + if (mi_match(SrcRegB, MRI, m_ZeroInt())) { + std::swap(SrcRegB, SrcRegC); + ZeroReg = SrcRegC; + } else + return false; + break; + default: + return false; + } + + Register Carry = MRI.createGenericVirtualRegister(LLT::scalar(1)); + Register UnusedReg = MRI.createGenericVirtualRegister(LLT::scalar(32)); + Register UnusedCarry = MRI.createGenericVirtualRegister(LLT::scalar(1)); + + MatchInfo = [=](MachineIRBuilder &B) { + B.buildInstr(TargetOpcode::G_UADDO, {UnusedReg, Carry}, {SrcRegB, SrcRegB}); + B.buildInstr(TargetOpcode::G_USUBE, {DstReg, UnusedCarry}, + {SrcRegA, ZeroReg, Carry}); + }; + + return true; +} + +// Match // Unused, CarryBit = G_USUBU SrcB, SrcC // Carry = G_ZEXT CarryBit // Dst = G_UADD SrcA, Carry diff --git a/llvm/lib/Target/M88k/M88kCombine.td b/llvm/lib/Target/M88k/M88kCombine.td index 63f51fe..9453c3a 100644 --- a/llvm/lib/Target/M88k/M88kCombine.td +++ b/llvm/lib/Target/M88k/M88kCombine.td @@ -83,7 +83,7 @@ def subadd_from_icmpadd2 : GICombineRule< // - Pred = unsigned <= // - Pred = equal and either SrcB or SrcC being zero // into the instruction sequence -// Unused, Carry = G_USUBU SrcB', SrcC' +// Unused, Carry = G_USUBO SrcB', SrcC' // Dst, UnusedCarry = G_UADDE SrcA, Zero, Carry // with SrcB' and SrcC' derived from SrcB and SrcC, inserting a zero constant // value if necessary. @@ -94,11 +94,43 @@ def addsub_from_addicmp : GICombineRule< (apply [{ Helper.applyBuildFn(*${root}, ${matchinfo}); }])>; // Combine +// Dst = G_SUB SrcA, (G_ZEXT (G_ICMP Pred, SrcB, SrcC) +// with: +// - Pred = unsigned > +// - Pred = unsigned < +// - Pred = not equal and either SrcB or SrcC being zero +// into the instruction sequence +// Unused, Carry = G_USUBO SrcB', SrcC' +// Dst, UnusedCarry = G_USUBE SrcA, Zero, Carry +// with SrcB' and SrcC' derived from SrcB and SrcC, inserting a zero constant +// value if necessary. +def subsub_from_subicmp : GICombineRule< + (defs root:$root, build_fn_matchinfo:$matchinfo), + (match (wip_match_opcode G_SUB):$root, + [{ return matchSubSubFromSubICmp(*${root}, MRI, ${matchinfo}); }]), + (apply [{ Helper.applyBuildFn(*${root}, ${matchinfo}); }])>; + +// Combine +// Dst = G_SUB SrcA, (G_ZEXT (G_ICMP Pred, SrcB, SrcC) +// with: +// - Pred = signed >= and SrcC equals zero +// - Pred = signed <= and SrcB equals zero +// The returned MatchInfo transforms this sequence into +// Unused, Carry = G_UADDO SrcB', SrcC' +// Dst, UnusedCarry = G_USUBE SrcA, Zero, Carry +// with SrcB' and SrcC' derived from SrcB and SrcC. +def subadd_from_subicmp : GICombineRule< + (defs root:$root, build_fn_matchinfo:$matchinfo), + (match (wip_match_opcode G_SUB):$root, + [{ return matchSubAddFromSubICmp(*${root}, MRI, ${matchinfo}); }]), + (apply [{ Helper.applyBuildFn(*${root}, ${matchinfo}); }])>; + +// Combine // Unused, CarryBit = G_USUBU SrcB, SrcC // Carry = G_ZEXT CarryBit // Dst = G_UADD SrcA, Carry // into the instruction sequence -// Unused, Carry = G_USUBU SrcB, SrcC +// Unused, Carry = G_USUBO SrcB, SrcC // Dst, UnusedCarry = G_UADDE SrcA, Zero, Carry // inserting a zero constant value if necessary. def addsub_from_addsub : GICombineRule< @@ -107,13 +139,14 @@ def addsub_from_addsub : GICombineRule< [{ return matchAddSubFromAddSub(*${root}, MRI, ${matchinfo}); }]), (apply [{ Helper.applyBuildFn(*${root}, ${matchinfo}); }])>; +// All combiner rules turning a comparison into an operation with carry. +def compare_to_carry : GICombineGroup<[addsub_from_addicmp, addsub_from_addsub, + subadd_from_subicmp, subsub_from_subicmp]>; + // Post-legalization combines which are primarily optimizations. def M88kPostLegalizerCombinerHelper: GICombinerHelper< "M88kGenPostLegalizerCombinerHelper", [ - //subadd_from_icmpadd1, - //subadd_from_icmpadd2, - addsub_from_addicmp, - addsub_from_addsub, + compare_to_carry, form_bitfield_extract, // Some rules require legalizer rotate_out_of_range // Required for left rotates, which produce a negative constant ]> { diff --git a/llvm/test/CodeGen/M88k/add.ll b/llvm/test/CodeGen/M88k/add.ll index c8d9050..ad1950e 100644 --- a/llvm/test/CodeGen/M88k/add.ll +++ b/llvm/test/CodeGen/M88k/add.ll @@ -84,7 +84,7 @@ declare { i32, i1 } @llvm.usub.with.overflow.i32(i32, i32) ; Special case: return (a >= b) + c define i32 @f9(i32 %a, i32 %b, i32 %c) { ; CHECK-LABEL: f9: -; CHECK: subu.co %r2, %r3, %r2 +; CHECK: subu.co %r2, %r2, %r3 ; CHECK-NEXT: addu.ci %r2, %r4, %r5 ; CHECK-NEXT: jmp %r1 %cmp = icmp uge i32 %a, %b @@ -92,3 +92,75 @@ define i32 @f9(i32 %a, i32 %b, i32 %c) { %sum = add i32 %conv, %c ret i32 %sum } + +; Special case: return (a <= b) + c +define i32 @f10(i32 %a, i32 %b, i32 %c) { +; CHECK-LABEL: f10: +; CHECK: subu.co %r2, %r3, %r2 +; CHECK-NEXT: addu.ci %r2, %r4, %r5 +; CHECK-NEXT: jmp %r1 + %cmp = icmp ule i32 %a, %b + %conv = zext i1 %cmp to i32 + %sum = add i32 %conv, %c + ret i32 %sum +} + +; Special case: return a - (b < c) +define i32 @f11(i32 %a, i32 %b, i32 %c) { +; CHECK-LABEL: f11: +; CHECK: subu.co %r3, %r3, %r4 +; CHECK-NEXT: subu.ci %r2, %r2, %r5 +; CHECK-NEXT: jmp %r1 + %cmp = icmp ult i32 %b, %c + %conv = zext i1 %cmp to i32 + %dif = sub i32 %a, %conv + ret i32 %dif +} + +; Special case: return a - (b > c) +define i32 @f12(i32 %a, i32 %b, i32 %c) { +; CHECK-LABEL: f12: +; CHECK: subu.co %r3, %r4, %r3 +; CHECK-NEXT: subu.ci %r2, %r2, %r5 +; CHECK-NEXT: jmp %r1 + %cmp = icmp ugt i32 %b, %c + %conv = zext i1 %cmp to i32 + %dif = sub i32 %a, %conv + ret i32 %dif +} + +; Special case: return a - (b != 0) +define i32 @f13(i32 %a, i32 %b) { +; CHECK-LABEL: f13: +; CHECK: subu.co %r3, %r4, %r3 +; CHECK-NEXT: subu.ci %r2, %r2, %r4 +; CHECK-NEXT: jmp %r1 + %cmp = icmp ne i32 %b, 0 + %conv = zext i1 %cmp to i32 + %dif = sub i32 %a, %conv + ret i32 %dif +} + +; Special case: return a - (b >= 0) +define i32 @f14(i32 %a, i32 %b) { +; CHECK-LABEL: f14: +; CHECK: addu.co %r3, %r3, %r3 +; CHECK-NEXT: subu.ci %r2, %r2, %r4 +; CHECK-NEXT: jmp %r1 + %cmp = icmp sge i32 %b, 0 + %conv = zext i1 %cmp to i32 + %dif = sub i32 %a, %conv + ret i32 %dif +} + +; Special case: return a - (0 <= b) +define i32 @f15(i32 %a, i32 %b) { +; CHECK-LABEL: f15: +; CHECK: addu.co %r3, %r3, %r3 +; CHECK-NEXT: subu.ci %r2, %r2, %r4 +; CHECK-NEXT: jmp %r1 + %cmp = icmp sle i32 0, %b + %conv = zext i1 %cmp to i32 + %dif = sub i32 %a, %conv + ret i32 %dif +} |