sparc: peephole - fold copy into restore
authorMatthias Braun <matze@braunis.de>
Sat, 1 Oct 2011 03:11:34 +0000 (05:11 +0200)
committerMatthias Braun <matze@braunis.de>
Tue, 11 Oct 2011 13:26:13 +0000 (15:26 +0200)
ir/be/bepeephole.h
ir/be/sparc/sparc_emitter.c
ir/be/sparc/sparc_finish.c
ir/be/sparc/sparc_spec.pl

index 34fafab..bc55a4b 100644 (file)
@@ -53,7 +53,10 @@ typedef void (*peephole_opt_func) (ir_node *node);
 /**
  * Notify the peephole phase about a newly added node, so it can update its
  * internal state.  This is not needed for the new node, when
- * be_peephole_exchange() is used. */
+ * be_peephole_exchange() is used.
+ * Note: Contrary to normal exchange you mustn't remove the node from the
+ * schedule either before exchange. Exchange will do that for you.
+ */
 void be_peephole_new_node(ir_node *nw);
 
 /**
index f4ed6c4..d1c0fd7 100644 (file)
@@ -860,6 +860,31 @@ static void emit_sparc_Return(const ir_node *node)
        fill_delay_slot();
 }
 
+static const arch_register_t *map_i_to_o_reg(const arch_register_t *reg)
+{
+       unsigned idx = reg->global_index;
+       if (idx < REG_I0 || idx > REG_I7)
+               return reg;
+       idx += REG_O0 - REG_I0;
+       assert(REG_O0 <= idx && idx <= REG_O7);
+       return &sparc_registers[idx];
+}
+
+static void emit_sparc_Restore(const ir_node *node)
+{
+       const arch_register_t *destreg
+               = arch_get_irn_register_out(node, pn_sparc_Restore_res);
+       be_emit_cstring("\trestore ");
+       sparc_emit_source_register(node, 1);
+       be_emit_cstring(", ");
+       sparc_emit_reg_or_imm(node, 2);
+       be_emit_cstring(", ");
+       destreg = map_i_to_o_reg(destreg);
+       be_emit_char('%');
+       be_emit_string(arch_register_get_name(destreg));
+       be_emit_finish_line_gas(node);
+}
+
 static void emit_sparc_FrameAddr(const ir_node *node)
 {
        const sparc_attr_t *attr   = get_sparc_attr_const(node);
@@ -1134,6 +1159,7 @@ static void sparc_register_emitters(void)
        set_emitter(op_sparc_FrameAddr, emit_sparc_FrameAddr);
        set_emitter(op_sparc_SMulh,     emit_sparc_Mulh);
        set_emitter(op_sparc_UMulh,     emit_sparc_Mulh);
+       set_emitter(op_sparc_Restore,   emit_sparc_Restore);
        set_emitter(op_sparc_Return,    emit_sparc_Return);
        set_emitter(op_sparc_SDiv,      emit_sparc_SDiv);
        set_emitter(op_sparc_SwitchJmp, emit_sparc_SwitchJmp);
index 30fd44c..7198e16 100644 (file)
@@ -417,6 +417,55 @@ static void peephole_sparc_FrameAddr(ir_node *node)
        (void) node;
 }
 
+static bool is_restorezeroopt_reg(const arch_register_t *reg)
+{
+       unsigned index = reg->global_index;
+       return (index >= REG_G0 && index <= REG_G7)
+           || (index >= REG_I0 && index <= REG_I7);
+}
+
+static void peephole_sparc_RestoreZero(ir_node *node)
+{
+       /* restore gives us a free "add" instruction, let's try to use that to fold
+        * an instruction in */
+       ir_node *try = sched_prev(node);
+
+       /* output must not be local, or out reg (it would be strange though if
+        * they were) */
+       if (be_is_Copy(try)) {
+               dbg_info *dbgi;
+               ir_node  *block;
+               ir_node  *new_restore;
+               ir_node  *op;
+               ir_node  *fp;
+               ir_node  *res;
+               ir_node  *stack;
+               ir_mode  *mode;
+
+               const arch_register_t *reg = arch_get_irn_register(try);
+               if (!is_restorezeroopt_reg(reg))
+                       return;
+
+               op    = get_irn_n(try, n_be_Copy_op);
+               fp    = get_irn_n(node, n_sparc_RestoreZero_frame_pointer);
+               dbgi  = get_irn_dbg_info(node);
+               block = get_nodes_block(node);
+               new_restore = new_bd_sparc_Restore_imm(dbgi, block, fp, op, NULL, 0);
+               arch_set_irn_register_out(new_restore, pn_sparc_Restore_stack,
+                                         &sparc_registers[REG_SP]);
+               arch_set_irn_register_out(new_restore, pn_sparc_Restore_res,
+                                                                 reg);
+
+               mode  = get_irn_mode(node);
+               stack = new_r_Proj(new_restore, mode, pn_sparc_Restore_stack);
+               res   = new_r_Proj(new_restore, mode, pn_sparc_Restore_res);
+
+               sched_add_before(node, new_restore);
+               be_peephole_exchange(node, stack);
+               be_peephole_exchange(try, res);
+       }
+}
+
 static void finish_sparc_Return(ir_node *node)
 {
        ir_node *schedpoint = node;
@@ -512,6 +561,8 @@ void sparc_finish(ir_graph *irg)
        clear_irp_opcodes_generic_func();
        register_peephole_optimisation(op_be_IncSP,        peephole_be_IncSP);
        register_peephole_optimisation(op_sparc_FrameAddr, peephole_sparc_FrameAddr);
+       register_peephole_optimisation(op_sparc_RestoreZero,
+                                      peephole_sparc_RestoreZero);
        be_peephole_opt(irg);
 
        /* perform legalizations (mostly fix nodes with too big immediates) */
index e7a5f51..01deede 100644 (file)
@@ -104,9 +104,11 @@ $mode_fp4     = "mode_E"; # not correct, we need to register a new mode
 # emit source reg or imm dep. on node's arity
        RI  => "${arch}_emit_reg_or_imm(node, -1);",
        R1I => "${arch}_emit_reg_or_imm(node, 1);",
+       R2I => "${arch}_emit_reg_or_imm(node, 2);",
        S0  => "${arch}_emit_source_register(node, 0);",
        S1  => "${arch}_emit_source_register(node, 1);",
        D0  => "${arch}_emit_dest_register(node, 0);",
+       D1  => "${arch}_emit_dest_register(node, 1);",
        HIM => "${arch}_emit_high_immediate(node);",
        LM  => "${arch}_emit_load_mode(node);",
        SM  => "${arch}_emit_store_mode(node);",
@@ -407,22 +409,19 @@ Save => {
 },
 
 Restore => {
-       emit => '. restore %S0, %R1I, %D0',
-       outs => [ "stack" ],
-       ins  => [ "stack" ],
+       outs => [ "stack", "res" ],
        constructors => {
                imm => {
                        attr       => "ir_entity *immediate_entity, int32_t immediate_value",
                        custominit => "sparc_set_attr_imm(res, immediate_entity, immediate_value);",
-                       reg_req    => { in => [ "sp" ], out => [ "sp:I|S" ] },
-                       ins        => [ "stack" ],
+                       reg_req    => { in => [ "frame_pointer", "gp" ], out => [ "sp:I|S", "gp" ] },
+                       ins        => [ "frame_pointer", "left" ],
                },
                reg => {
-                       reg_req    => { in => [ "sp", "gp" ], out => [ "sp:I|S" ] },
-                       ins        => [ "stack", "increment" ],
+                       reg_req    => { in => [ "frame_pointer", "gp", "gp" ], out => [ "sp:I|S", "gp" ] },
+                       ins        => [ "frame_pointer", "left", "right" ],
                }
        },
-       mode => $mode_gp,
 },
 
 RestoreZero => {