- be_emit_cstring("\txor ");
- sparc_emit_source_register(irn, 1);
- be_emit_cstring(", ");
- sparc_emit_source_register(irn, 0);
- be_emit_cstring(", ");
- sparc_emit_source_register(irn, 0);
- be_emit_finish_line_gas(NULL);
-
- be_emit_cstring("\txor ");
- sparc_emit_source_register(irn, 1);
- be_emit_cstring(", ");
- sparc_emit_source_register(irn, 0);
- be_emit_cstring(", ");
- sparc_emit_source_register(irn, 1);
- be_emit_finish_line_gas(NULL);
-
- be_emit_cstring("\txor ");
- sparc_emit_source_register(irn, 1);
- be_emit_cstring(", ");
- sparc_emit_source_register(irn, 0);
- be_emit_cstring(", ");
- sparc_emit_source_register(irn, 0);
- be_emit_finish_line_gas(irn);
+ assert(n_spilled < n_to_spill);
+
+ if (n_spilled == 0) {
+ /* We always reserve stack space for two registers because during copy
+ * processing we don't know yet if we also need to handle a cycle which
+ * needs two registers. More complicated code in emit_MemPerm would
+ * prevent wasting SPARC_REGISTER_SIZE bytes of stack space but
+ * it is not worth the worse readability of emit_MemPerm. */
+
+ /* Keep stack pointer aligned. */
+ unsigned sp_change = get_aligned_sp_change(2);
+ sparc_emitf(node, "sub %%sp, %u, %%sp", sp_change);
+
+ /* Spill register l0. */
+ sparc_emitf(node, "st %%l0, [%%sp%+d]", SPARC_MIN_STACKSIZE);
+ }
+
+ if (n_to_spill == 2) {
+ /* Spill register l1. */
+ sparc_emitf(node, "st %%l1, [%%sp%+d]", SPARC_MIN_STACKSIZE + SPARC_REGISTER_SIZE);
+ }
+}
+
+/* Restore register l0 or both l0 and l1, depending on n_spilled. */
+static void memperm_emit_restore_registers(const ir_node *node, int n_spilled)
+{
+ if (n_spilled == 2) {
+ /* Restore register l1. */
+ sparc_emitf(node, "ld [%%sp%+d], %%l1", SPARC_MIN_STACKSIZE + SPARC_REGISTER_SIZE);
+ }
+
+ /* Restore register l0. */
+ sparc_emitf(node, "ld [%%sp%+d], %%l0", SPARC_MIN_STACKSIZE);
+
+ /* Restore stack pointer. */
+ unsigned sp_change = get_aligned_sp_change(2);
+ sparc_emitf(node, "add %%sp, %u, %%sp", sp_change);
+}
+
+/* Emit code to copy in_ent to out_ent. Only uses l0. */
+static void memperm_emit_copy(const ir_node *node, ir_entity *in_ent,
+ ir_entity *out_ent)
+{
+ ir_graph *irg = get_irn_irg(node);
+ be_stack_layout_t *layout = be_get_irg_stack_layout(irg);
+ int off_in = be_get_stack_entity_offset(layout, in_ent, 0);
+ int off_out = be_get_stack_entity_offset(layout, out_ent, 0);
+
+ /* Load from input entity. */
+ sparc_emitf(node, "ld [%%fp%+d], %%l0", off_in);
+ /* Store to output entity. */
+ sparc_emitf(node, "st %%l0, [%%fp%+d]", off_out);