aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKai Nacke <kai@redstar.de>2022-09-08 23:19:18 -0400
committerKai Nacke <kai@redstar.de>2022-11-13 11:07:57 -0500
commitcf0e46afd13afca6c22ee04995f691b552dbe345 (patch)
tree1fa928631e99392bcb6aa89979a4fefa75da7707
parentb99c558013e5bd99e91d9b78d732dc9d7bf21b94 (diff)
downloadllvm-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.cpp131
-rw-r--r--llvm/lib/Target/M88k/M88kCombine.td45
-rw-r--r--llvm/test/CodeGen/M88k/add.ll74
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
+}