...
Below you find an example how to use late expand for the sparc.ad file. Further down you see the code generated by adlc. Perhaps you can find better use cases for this feature.
--- a/src/cpu/sparc/vm/sparc.ad 2012-11-21 12:27:04.591486000 +0100
+++ b/src/cpu/sparc/vm/sparc.ad 2012-11-19 14:45:15.059452000 +0100
@@ -1933,7 +1937,7 @@
}
// Does the CPU require late expand (see block.cpp for description of late expand)?
-const bool Matcher::require_late_expand = false;
+const bool Matcher::require_late_expand = true;
// Should the Matcher clone shifts on addressing modes, expecting them to
// be subsumed into complex addressing expressions or compute them into
@@ -7497,6 +7501,7 @@
// Register Division
instruct divI_reg_reg(iRegI dst, iRegIsafe src1, iRegIsafe src2) %{
match(Set dst (DivI src1 src2));
+ predicate(!UseNewCode);
ins_cost((2+71)*DEFAULT_COST);
format %{ "SRA $src2,0,$src2\n\t"
@@ -7506,6 +7511,68 @@
ins_pipe(sdiv_reg_reg);
%}
+//------------------------------------------------------------------------------------
+
+encode %{
+
+ enc_class lateExpandIdiv_reg_reg(iRegI dst, iRegIsafe src1, iRegIsafe src2) %{
+ MachNode *m1 = new (C) divI_reg_reg_SRANode();
+ MachNode *m2 = new (C) divI_reg_reg_SRANode();
+ MachNode *m3 = new (C) divI_reg_reg_SDIVXNode();
+
+ m1->add_req(n_region, n_src1);
+ m2->add_req(n_region, n_src2);
+ m3->add_req(n_region, m1, m2);
+
+ m1->_opnds[0] = _opnds[1]->clone(C);
+ m1->_opnds[1] = _opnds[1]->clone(C);
+
+ m2->_opnds[0] = _opnds[2]->clone(C);
+ m2->_opnds[1] = _opnds[2]->clone(C);
+
+ m3->_opnds[0] = _opnds[0]->clone(C);
+ m3->_opnds[1] = _opnds[1]->clone(C);
+ m3->_opnds[2] = _opnds[2]->clone(C);
+
+ ra_->set1(m1->_idx, ra_->get_reg_first(n_src1));
+ ra_->set1(m2->_idx, ra_->get_reg_first(n_src2));
+ ra_->set1(m3->_idx, ra_->get_reg_first(this));
+
+ nodes->push(m1);
+ nodes->push(m2);
+ nodes->push(m3);
+ %}
+%}
+
+instruct divI_reg_reg_SRA(iRegIsafe dst) %{
+ effect(USE_DEF dst);
+ size(4);
+ format %{ "SRA $dst,0,$dst\n\t" %}
+ ins_encode %{ __ sra($dst$$Register, 0, $dst$$Register); %}
+ ins_pipe(ialu_reg_reg);
+%}
+
+instruct divI_reg_reg_SDIVX(iRegI dst, iRegIsafe src1, iRegIsafe src2) %{
+ effect(DEF dst, USE src1, USE src2);
+ size(4);
+ format %{ "SDIVX $src1,$src2,$dst\n\t" %}
+ ins_encode %{ __ sdivx($dst$$Register, 0, $dst$$Register); %}
+ ins_pipe(sdiv_reg_reg);
+%}
+
+instruct divI_reg_reg_Ex(iRegI dst, iRegIsafe src1, iRegIsafe src2) %{
+ match(Set dst (DivI src1 src2));
+ predicate(UseNewCode);
+ ins_cost((2+71)*DEFAULT_COST);
+
+ format %{ "SRA $src2,0,$src2\n\t"
+ "SRA $src1,0,$src1\n\t"
+ "SDIVX $src1,$src2,$dst" %}
+ lateExpand( lateExpandIdiv_reg_reg(src1, src2, dst) );
+%}
+
+//------------------------------------------------------------------------------------
+
// Immediate Division
instruct divI_reg_imm13(iRegI dst, iRegIsafe src1, immI13 src2) %{
match(Set dst (DivI src1 src2));
Code generated by adlc:
class divI_reg_reg_ExNode : public MachNode {
// ...
virtual bool requires_late_expand() const { return true; }
virtual void lateExpand(GrowableArray <Node *> *nodes, PhaseRegAlloc *ra_);
// ...
};
...