GlobalISel: Try to combine G_[SU]DIV and G_[SU]REM
It is good to have a combined `divrem` instruction when the
`div` and `rem` are computed from identical input operands.
Some targets can lower them through a single expansion that
computes both division and remainder. It effectively reduces
the number of instructions than individually expanding them.
Reviewed By: arsenm, paquette
Differential Revision: https://reviews.llvm.org/D96013
diff --git a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
index 5fef853..f74ef8e 100644
--- a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
@@ -3148,6 +3148,9 @@
}
case G_SELECT:
return lowerSelect(MI);
+ case G_SDIVREM:
+ case G_UDIVREM:
+ return lowerDIVREM(MI);
}
}
@@ -6341,3 +6344,19 @@
MI.eraseFromParent();
return Legalized;
}
+
+LegalizerHelper::LegalizeResult LegalizerHelper::lowerDIVREM(MachineInstr &MI) {
+ // Split DIVREM into individual instructions.
+ unsigned Opcode = MI.getOpcode();
+
+ MIRBuilder.buildInstr(
+ Opcode == TargetOpcode::G_SDIVREM ? TargetOpcode::G_SDIV
+ : TargetOpcode::G_UDIV,
+ {MI.getOperand(0).getReg()}, {MI.getOperand(2), MI.getOperand(3)});
+ MIRBuilder.buildInstr(
+ Opcode == TargetOpcode::G_SDIVREM ? TargetOpcode::G_SREM
+ : TargetOpcode::G_UREM,
+ {MI.getOperand(1).getReg()}, {MI.getOperand(2), MI.getOperand(3)});
+ MI.eraseFromParent();
+ return Legalized;
+}