From fb129a97000bf935c176befe5d1b3a38766156eb Mon Sep 17 00:00:00 2001 From: "Jeffrey H. Johnson" Date: Thu, 16 Jul 2026 09:00:01 -0400 Subject: [PATCH] Fix the Linux/MIPS backend 1. Swap needs to handle reg/stack and stack/reg 2. After swap, rewrite sources and not dests, the old code was incorrect of cycles >2. 3. Fix data labels for correct word alignment. 4. simple_test_neg used incorrect bitwise nor. I can't say it's perfect, but it now builds https://gitlab.com/dps8m/crc.git correctly and the full CRC test suite (make test) now passes. Signed-off-by: Jeffrey H. Johnson --- mach/mips/mcg/platform.c | 164 ++++++++++++++++++++---- mach/proto/mcg/data.c | 17 +++ mach/proto/mcg/pass_registerallocator.c | 11 +- mach/proto/mcg/treebuilder.c | 7 +- 4 files changed, 167 insertions(+), 32 deletions(-) diff --git a/mach/mips/mcg/platform.c b/mach/mips/mcg/platform.c index a29a69ebec..b752432461 100644 --- a/mach/mips/mcg/platform.c +++ b/mach/mips/mcg/platform.c @@ -250,44 +250,160 @@ struct hop* platform_move(struct basicblock* bb, struct vreg* vreg, struct hreg* fatal("cannot move %s to %s", src->id, dest->id); } -struct hop* platform_swap(struct basicblock* bb, struct hreg* src, struct hreg* dest) +static void swap_reg_and_stack(struct hop* hop, struct hreg* reg, struct hreg* stack) { - struct hop* hop = new_hop(bb, NULL); - - tracef('R', "R: swap of %s to %s\n", src->id, dest->id); - assert(!src->is_stacked); - assert(!dest->is_stacked); - assert((src->attrs & TYPE_ATTRS) == (dest->attrs & TYPE_ATTRS)); - - switch (src->attrs & TYPE_ATTRS) + switch (reg->attrs & TYPE_ATTRS) { case burm_int_ATTR: - hop_add_insel(hop, "mov at, %H", src); - hop_add_insel(hop, "mov %H, %H", src, dest); - hop_add_insel(hop, "mov %H, at", dest); + hop_add_insel(hop, "mov at, %H", reg); + hop_add_insel(hop, "lw %H, %S(fp) ! %H", reg, stack, stack); + hop_add_insel(hop, "sw at, %S(fp) ! %H", stack, stack); break; case burm_long_ATTR: - hop_add_insel(hop, "mov at, %0H", src); - hop_add_insel(hop, "mov %0H, %0H", src, dest); - hop_add_insel(hop, "mov %0H, at", dest); + hop_add_insel(hop, "mov at, %0H", reg); + hop_add_insel(hop, "lw %0H, 0+%S(fp) ! %H", reg, stack, stack); + hop_add_insel(hop, "sw at, 0+%S(fp) ! %H", stack, stack); - hop_add_insel(hop, "mov at, %1H", src); - hop_add_insel(hop, "mov %1H, %1H", src, dest); - hop_add_insel(hop, "mov %1H, at", dest); + hop_add_insel(hop, "mov at, %1H", reg); + hop_add_insel(hop, "lw %1H, 4+%S(fp) ! %H", reg, stack, stack); + hop_add_insel(hop, "sw at, 4+%S(fp) ! %H", stack, stack); break; case burm_float_ATTR: - hop_add_insel(hop, "mov.s f30, %H", src); - hop_add_insel(hop, "mov.s %H, %H", src, dest); - hop_add_insel(hop, "mov.s %H, f30", dest); + hop_add_insel(hop, "mov.s f30, %H", reg); + hop_add_insel(hop, "lwc1 %H, %S(fp) ! %H", reg, stack, stack); + hop_add_insel(hop, "swc1 f30, %S(fp) ! %H", stack, stack); break; case burm_double_ATTR: - hop_add_insel(hop, "mov.d f30, %H", src); - hop_add_insel(hop, "mov.d %H, %H", src, dest); - hop_add_insel(hop, "mov.d %H, f30", dest); + hop_add_insel(hop, "mov.d f30, %H", reg); + hop_add_insel(hop, "ldc1 %H, %S(fp) ! %H", reg, stack, stack); + hop_add_insel(hop, "sdc1 f30, %S(fp) ! %H", stack, stack); + break; + + default: + fatal("cannot swap %s and %s", reg->id, stack->id); + } +} + +static void swap_stack_and_stack(struct hop* hop, struct hreg* src, struct hreg* dest) +{ + switch (src->attrs & TYPE_ATTRS) + { + case burm_int_ATTR: + case burm_float_ATTR: + hop_add_insel(hop, "addiu sp, sp, -4"); + if (src->attrs & burm_int_ATTR) + { + hop_add_insel(hop, "lw at, %S(fp) ! %H", src, src); + hop_add_insel(hop, "sw at, 0(sp)"); + hop_add_insel(hop, "lw at, %S(fp) ! %H", dest, dest); + hop_add_insel(hop, "sw at, %S(fp) ! %H", src, src); + hop_add_insel(hop, "lw at, 0(sp)"); + hop_add_insel(hop, "sw at, %S(fp) ! %H", dest, dest); + } + else + { + hop_add_insel(hop, "lwc1 f30, %S(fp) ! %H", src, src); + hop_add_insel(hop, "swc1 f30, 0(sp)"); + hop_add_insel(hop, "lwc1 f30, %S(fp) ! %H", dest, dest); + hop_add_insel(hop, "swc1 f30, %S(fp) ! %H", src, src); + hop_add_insel(hop, "lwc1 f30, 0(sp)"); + hop_add_insel(hop, "swc1 f30, %S(fp) ! %H", dest, dest); + } + hop_add_insel(hop, "addiu sp, sp, 4"); break; + + case burm_long_ATTR: + case burm_double_ATTR: + hop_add_insel(hop, "addiu sp, sp, -8"); + if (src->attrs & burm_long_ATTR) + { + hop_add_insel(hop, "lw at, 0+%S(fp) ! %H", src, src); + hop_add_insel(hop, "sw at, 0(sp)"); + hop_add_insel(hop, "lw at, 4+%S(fp) ! %H", src, src); + hop_add_insel(hop, "sw at, 4(sp)"); + + hop_add_insel(hop, "lw at, 0+%S(fp) ! %H", dest, dest); + hop_add_insel(hop, "sw at, 0+%S(fp) ! %H", src, src); + hop_add_insel(hop, "lw at, 4+%S(fp) ! %H", dest, dest); + hop_add_insel(hop, "sw at, 4+%S(fp) ! %H", src, src); + + hop_add_insel(hop, "lw at, 0(sp)"); + hop_add_insel(hop, "sw at, 0+%S(fp) ! %H", dest, dest); + hop_add_insel(hop, "lw at, 4(sp)"); + hop_add_insel(hop, "sw at, 4+%S(fp) ! %H", dest, dest); + } + else + { + hop_add_insel(hop, "ldc1 f30, %S(fp) ! %H", src, src); + hop_add_insel(hop, "sdc1 f30, 0(sp)"); + hop_add_insel(hop, "ldc1 f30, %S(fp) ! %H", dest, dest); + hop_add_insel(hop, "sdc1 f30, %S(fp) ! %H", src, src); + hop_add_insel(hop, "ldc1 f30, 0(sp)"); + hop_add_insel(hop, "sdc1 f30, %S(fp) ! %H", dest, dest); + } + hop_add_insel(hop, "addiu sp, sp, 8"); + break; + + default: + fatal("cannot swap %s and %s", src->id, dest->id); + } +} + +struct hop* platform_swap(struct basicblock* bb, struct hreg* src, struct hreg* dest) +{ + struct hop* hop = new_hop(bb, NULL); + + tracef('R', "R: swap of %s to %s\n", src->id, dest->id); + assert((src->attrs & TYPE_ATTRS) == (dest->attrs & TYPE_ATTRS)); + + if (src->is_stacked && dest->is_stacked) + { + swap_stack_and_stack(hop, src, dest); + } + else if (src->is_stacked || dest->is_stacked) + { + struct hreg* reg = src->is_stacked ? dest : src; + struct hreg* stack = src->is_stacked ? src : dest; + swap_reg_and_stack(hop, reg, stack); + } + else + { + switch (src->attrs & TYPE_ATTRS) + { + case burm_int_ATTR: + hop_add_insel(hop, "mov at, %H", src); + hop_add_insel(hop, "mov %H, %H", src, dest); + hop_add_insel(hop, "mov %H, at", dest); + break; + + case burm_long_ATTR: + hop_add_insel(hop, "mov at, %0H", src); + hop_add_insel(hop, "mov %0H, %0H", src, dest); + hop_add_insel(hop, "mov %0H, at", dest); + + hop_add_insel(hop, "mov at, %1H", src); + hop_add_insel(hop, "mov %1H, %1H", src, dest); + hop_add_insel(hop, "mov %1H, at", dest); + break; + + case burm_float_ATTR: + hop_add_insel(hop, "mov.s f30, %H", src); + hop_add_insel(hop, "mov.s %H, %H", src, dest); + hop_add_insel(hop, "mov.s %H, f30", dest); + break; + + case burm_double_ATTR: + hop_add_insel(hop, "mov.d f30, %H", src); + hop_add_insel(hop, "mov.d %H, %H", src, dest); + hop_add_insel(hop, "mov.d %H, f30", dest); + break; + + default: + fatal("cannot swap %s and %s", src->id, dest->id); + } } return hop; diff --git a/mach/proto/mcg/data.c b/mach/proto/mcg/data.c index a137196e98..7fdc524908 100644 --- a/mach/proto/mcg/data.c +++ b/mach/proto/mcg/data.c @@ -32,6 +32,11 @@ static const char* section_to_str(int section) } } +static void align_to_word(void) +{ + fprintf(outputfile, "\t.align %d\n", (int)EM_wordsize); +} + static void emit_header(int desired_section) { if (pending) @@ -42,6 +47,7 @@ static void emit_header(int desired_section) fatal("label '%s' can't change sections", pending->name); fprintf(outputfile, "\n.sect %s\n", section_to_str(pending->section)); + align_to_word(); fprintf(outputfile, "%s:\n", platform_label(pending->name)); pending = NULL; } @@ -57,8 +63,12 @@ static void writehex(arith data, int size) void data_int(arith data, size_t size, bool is_ro) { + bool had_pending = (pending != NULL); + emit_header(is_ro ? SECTION_ROM : SECTION_DATA); assert((size == 1) || (size == 2) || (size == 4) || (size == 8)); + if (!had_pending && size >= EM_wordsize) + align_to_word(); fprintf(outputfile, "\t.data%ld ", size); writehex(data, size); fprintf(outputfile, "\n"); @@ -69,9 +79,12 @@ void data_float(const char* data, size_t size, bool is_ro) { unsigned char buffer[8]; int i; + bool had_pending = (pending != NULL); emit_header(is_ro ? SECTION_ROM : SECTION_DATA); assert((size == 4) || (size == 8)); + if (!had_pending) + align_to_word(); fprintf(outputfile, "\t.dataf%ld %s\n", size, data); } @@ -134,7 +147,11 @@ void data_block(const uint8_t* data, size_t datalen, size_t size, bool is_ro) void data_offset(const char* label, arith offset, bool is_ro) { + bool had_pending = (pending != NULL); + emit_header(is_ro ? SECTION_ROM : SECTION_DATA); + if (!had_pending) + align_to_word(); fprintf(outputfile, "\t.data%d %s+%ld\n", EM_pointersize, platform_label(label), offset); } diff --git a/mach/proto/mcg/pass_registerallocator.c b/mach/proto/mcg/pass_registerallocator.c index 5ec1f3a035..66f383160e 100644 --- a/mach/proto/mcg/pass_registerallocator.c +++ b/mach/proto/mcg/pass_registerallocator.c @@ -686,14 +686,15 @@ static int insert_moves(struct basicblock* bb, int index, hop = platform_swap(bb, src, dest); pmap_remove(&copies, src, dest); - /* Now src and dest are swapped. We know that the old src is in the right place - * and now contains dest. Any copies from the old dest (now containing src) must - * be patched to point at the old src. */ + /* After swap(src, dest), dest holds the value that was in src (so src->dest + * is done). The value that was in dest is now in src. Any remaining copy + * that still reads from dest must be rewritten to read from src instead. + * Rewriting destinations is wrong for cycles longer than 2. */ for (i=0; i