+ /* this implementation only works with frame pointers currently */
+ assert(layout->sp_relative == false);
+
+ /* TODO: this implementation is slower than necessary.
+ The longterm goal is however to avoid the memperm node completely */
+
+ memperm_arity = be_get_MemPerm_entity_arity(node);
+ // we use our local registers - so this is limited to 8 inputs !
+ if (memperm_arity > 8)
+ panic("memperm with more than 8 inputs not supported yet");
+
+ be_emit_irprintf("\tsub %%sp, %d, %%sp", memperm_arity*4);
+ be_emit_finish_line_gas(node);
+
+ for (i = 0; i < memperm_arity; ++i) {
+ ir_entity *entity = be_get_MemPerm_in_entity(node, i);
+ int offset = be_get_stack_entity_offset(layout, entity, 0);
+
+ /* spill register */
+ be_emit_irprintf("\tst %%l%d, [%%sp%+d]", i, sp_change + SPARC_MIN_STACKSIZE);
+ be_emit_finish_line_gas(node);
+
+ /* load from entity */
+ be_emit_irprintf("\tld [%%fp%+d], %%l%d", offset, i);
+ be_emit_finish_line_gas(node);
+ sp_change += 4;
+ }
+
+ for (i = memperm_arity-1; i >= 0; --i) {
+ ir_entity *entity = be_get_MemPerm_out_entity(node, i);
+ int offset = be_get_stack_entity_offset(layout, entity, 0);
+
+ sp_change -= 4;
+
+ /* store to new entity */
+ be_emit_irprintf("\tst %%l%d, [%%fp%+d]", i, offset);
+ be_emit_finish_line_gas(node);
+ /* restore register */
+ be_emit_irprintf("\tld [%%sp%+d], %%l%d", sp_change + SPARC_MIN_STACKSIZE, i);
+ be_emit_finish_line_gas(node);
+ }
+
+ be_emit_irprintf("\tadd %%sp, %d, %%sp", memperm_arity*4);
+ be_emit_finish_line_gas(node);
+
+ assert(sp_change == 0);
+}
+
+static void emit_be_Return(const ir_node *node)
+{
+ const char *destreg = "%o7";
+
+ /* hack: we don't explicitely model register changes because of the
+ * restore node. So we have to do it manually here */
+ if (delay_slot_filler != NULL &&
+ (is_sparc_Restore(delay_slot_filler)
+ || is_sparc_RestoreZero(delay_slot_filler))) {
+ destreg = "%i7";
+ }
+ be_emit_cstring("\tjmp ");
+ be_emit_string(destreg);
+ be_emit_cstring("+8");
+ be_emit_finish_line_gas(node);
+ fill_delay_slot();
+}
+
+static void emit_sparc_FrameAddr(const ir_node *node)
+{
+ const sparc_attr_t *attr = get_sparc_attr_const(node);
+
+ // no need to fix offset as we are adressing via the framepointer
+ if (attr->immediate_value >= 0) {
+ be_emit_cstring("\tadd ");
+ sparc_emit_source_register(node, 0);
+ be_emit_cstring(", ");
+ be_emit_irprintf("%ld", attr->immediate_value);
+ } else {
+ be_emit_cstring("\tsub ");
+ sparc_emit_source_register(node, 0);
+ be_emit_cstring(", ");
+ be_emit_irprintf("%ld", -attr->immediate_value);
+ }
+
+ be_emit_cstring(", ");
+ sparc_emit_dest_register(node, 0);
+ be_emit_finish_line_gas(node);
+}
+
+static const char *get_icc_unsigned(ir_relation relation)
+{
+ switch (relation & (ir_relation_less_equal_greater)) {
+ case ir_relation_false: return "bn";
+ case ir_relation_equal: return "be";
+ case ir_relation_less: return "blu";
+ case ir_relation_less_equal: return "bleu";
+ case ir_relation_greater: return "bgu";
+ case ir_relation_greater_equal: return "bgeu";
+ case ir_relation_less_greater: return "bne";
+ case ir_relation_less_equal_greater: return "ba";
+ default: panic("Cmp has unsupported relation");
+ }
+}
+
+static const char *get_icc_signed(ir_relation relation)
+{
+ switch (relation & (ir_relation_less_equal_greater)) {
+ case ir_relation_false: return "bn";
+ case ir_relation_equal: return "be";
+ case ir_relation_less: return "bl";
+ case ir_relation_less_equal: return "ble";
+ case ir_relation_greater: return "bg";
+ case ir_relation_greater_equal: return "bge";
+ case ir_relation_less_greater: return "bne";
+ case ir_relation_less_equal_greater: return "ba";
+ default: panic("Cmp has unsupported relation");
+ }
+}
+
+static const char *get_fcc(ir_relation relation)
+{
+ switch (relation) {
+ case ir_relation_false: return "fbn";
+ case ir_relation_equal: return "fbe";
+ case ir_relation_less: return "fbl";
+ case ir_relation_less_equal: return "fble";
+ case ir_relation_greater: return "fbg";
+ case ir_relation_greater_equal: return "fbge";
+ case ir_relation_less_greater: return "fblg";
+ case ir_relation_less_equal_greater: return "fbo";
+ case ir_relation_unordered: return "fbu";
+ case ir_relation_unordered_equal: return "fbue";
+ case ir_relation_unordered_less: return "fbul";
+ case ir_relation_unordered_less_equal: return "fbule";
+ case ir_relation_unordered_greater: return "fbug";
+ case ir_relation_unordered_greater_equal: return "fbuge";
+ case ir_relation_unordered_less_greater: return "fbne";
+ case ir_relation_true: return "fba";
+ }
+ panic("invalid relation");
+}
+
+typedef const char* (*get_cc_func)(ir_relation relation);
+
+static void emit_sparc_branch(const ir_node *node, get_cc_func get_cc)