From: David Given Date: Sat, 29 Sep 2018 09:28:35 +0000 (+0200) Subject: Retry graphcolouring merge, better this time. X-Git-Url: https://git.ndcode.org/public/gitweb.cgi?a=commitdiff_plain;h=582ac91d66eb808dab9a390e48f1685191aa0861;p=ack.git Retry graphcolouring merge, better this time. --- 582ac91d66eb808dab9a390e48f1685191aa0861 diff --cc mach/mips/mcg/platform.c index 000000000,a29a69ebe..ddbeac903 mode 000000,100644..100644 --- a/mach/mips/mcg/platform.c +++ b/mach/mips/mcg/platform.c @@@ -1,0 -1,309 +1,310 @@@ + #include "mcg.h" + + /* mcg stack frames are laid out as: + * + * | ...params... + * | --------------- <- ab + * | old FR + * | old FP - * | --------------- <- fp (a.k.a. lb) ++ * | --------------- <- fp (a.k.a. lb) + * | locals + * | --------------- + * | spills + * | --------------- <- sb + * | saved regs + * | --------------- <- sp, rb + * V ...user area... + * + * st indexes up; lb indexes down. + * + * Note that [fp] == old_fp and ab == fp + 8. + */ + + static ARRAYOF(struct hreg) saved_regs; + + void platform_calculate_offsets(void) + { + int i; + + saved_regs.count = 0; - for (i=0; iusedregs.count; i++) - { - struct hreg* hreg = current_proc->usedregs.item[i]; - - if (!(hreg->attrs & burm_volatile_ATTR) && - ((hreg->attrs & burm_long_ATTR) || (hreg->attrs & burm_double_ATTR))) - { - hreg->offset = current_proc->saved_size; - current_proc->saved_size += 8; - array_append(&saved_regs, hreg); - } - } - for (i=0; iusedregs.count; i++) - { - struct hreg* hreg = current_proc->usedregs.item[i]; - - if (!(hreg->attrs & burm_volatile_ATTR) && - ((hreg->attrs & burm_int_ATTR) || (hreg->attrs & burm_float_ATTR))) - { - hreg->offset = current_proc->saved_size; - current_proc->saved_size += 4; - array_append(&saved_regs, hreg); - } - } ++ // for (i=0; iusedregs.count; i++) ++ // { ++ // struct hreg* hreg = current_proc->usedregs.item[i]; ++ ++ // if (!(hreg->attrs & burm_volatile_ATTR) && ++ // ((hreg->attrs & burm_long_ATTR) || (hreg->attrs & burm_double_ATTR))) ++ // { ++ // hreg->offset = current_proc->saved_size; ++ // current_proc->saved_size += 8; ++ // array_append(&saved_regs, hreg); ++ // } ++ // } ++ // for (i=0; iusedregs.count; i++) ++ // { ++ // struct hreg* hreg = current_proc->usedregs.item[i]; ++ ++ // if (!(hreg->attrs & burm_volatile_ATTR) && ++ // ((hreg->attrs & burm_int_ATTR) || (hreg->attrs & burm_float_ATTR))) ++ // { ++ // hreg->offset = current_proc->saved_size; ++ // current_proc->saved_size += 4; ++ // array_append(&saved_regs, hreg); ++ // } ++ // } + + current_proc->fp_to_ab = 8; + current_proc->fp_to_lb = 0; + current_proc->fp_to_sb = -(current_proc->locals_size + current_proc->spills_size); + current_proc->fp_to_rb = current_proc->fp_to_sb - current_proc->saved_size; + } + + struct hop* platform_prologue(void) + { + int i; + int spoffset = current_proc->saved_size + current_proc->spills_size + + current_proc->locals_size; + struct hop* hop = new_hop(current_proc->entry, NULL); + + hop_add_insel(hop, "! locals_size = %d", current_proc->locals_size); + hop_add_insel(hop, "! spills_size = %d", current_proc->spills_size); + hop_add_insel(hop, "! saved_size = %d", current_proc->saved_size); + hop_add_insel(hop, "! params @ fp+%d", current_proc->fp_to_ab); - hop_add_insel(hop, "! lr @ fp+4"); - hop_add_insel(hop, "! fp @ fp+0"); ++ hop_add_insel(hop, "! lr @ fp+4"); ++ hop_add_insel(hop, "! fp @ fp+0"); + hop_add_insel(hop, "! locals @ fp-%d to fp+0", + current_proc->locals_size); + hop_add_insel(hop, "! spills @ fp-%d to fp-%d", + -current_proc->fp_to_sb, current_proc->locals_size); + for (i=saved_regs.count-1; i>=0; i--) + { + struct hreg* hreg = saved_regs.item[i]; + hop_add_insel(hop, "! %s @ fp-%d", + hreg->id, -(current_proc->fp_to_rb + hreg->offset)); + } + + hop_add_insel(hop, "addiu sp, sp, %d", -(spoffset + 8)); + hop_add_insel(hop, "sw fp, %d(sp)", spoffset + 0); + hop_add_insel(hop, "sw ra, %d(sp)", spoffset + 4); + hop_add_insel(hop, "addiu fp, sp, %d", spoffset); + + /* Saved reg offsets are negative. */ + for (i=0; iattrs & burm_int_ATTR) + hop_add_insel(hop, "sw %H, %d(fp)", + hreg, current_proc->fp_to_rb + hreg->offset); + else if (hreg->attrs & burm_long_ATTR) + { + hop_add_insel(hop, "sw %0H, %d(fp)", + hreg, current_proc->fp_to_rb + hreg->offset + 0); + hop_add_insel(hop, "sw %1H, %d(fp)", + hreg, current_proc->fp_to_rb + hreg->offset + 4); + } + else if (hreg->attrs & burm_float_ATTR) + hop_add_insel(hop, "swc1 %H, %d(fp)", + hreg, current_proc->fp_to_rb + hreg->offset); + else if (hreg->attrs & burm_double_ATTR) + hop_add_insel(hop, "sdc1 %H, %d(fp)", + hreg, current_proc->fp_to_rb + hreg->offset); + else + fatal("unsavable non-volatile register %s", hreg->id); + } + return hop; + } + + struct hop* platform_epilogue(void) + { + struct hop* hop = new_hop(current_proc->exit, NULL); + int i; + + for (i=0; iattrs & burm_int_ATTR) + hop_add_insel(hop, "lw %H, %d(fp)", + hreg, current_proc->fp_to_rb + hreg->offset); + else if (hreg->attrs & burm_long_ATTR) + { + hop_add_insel(hop, "lw %0H, %d(fp)", + hreg, current_proc->fp_to_rb + hreg->offset + 0); + hop_add_insel(hop, "lw %1H, %d(fp)", + hreg, current_proc->fp_to_rb + hreg->offset + 4); + } + else if (hreg->attrs & burm_float_ATTR) + hop_add_insel(hop, "lwc1 %H, %d(fp)", + hreg, current_proc->fp_to_rb + hreg->offset); + else if (hreg->attrs & burm_double_ATTR) + hop_add_insel(hop, "ldc1 %H, %d(fp)", + hreg, current_proc->fp_to_rb + hreg->offset); + else + fatal("unloadable non-volatile register %s", hreg->id); + } + + hop_add_insel(hop, "lw ra, 4(fp)"); + hop_add_insel(hop, "lw at, 0(fp)"); /* load old fp */ + hop_add_insel(hop, "addiu sp, fp, %d", current_proc->fp_to_ab); + hop_add_insel(hop, "jr ra"); + hop_add_insel(hop, "mov fp, at"); /* delay slot */ + + return hop; + } + + struct hop* platform_move(struct basicblock* bb, struct vreg* vreg, struct hreg* src, struct hreg* dest) + { + struct hop* hop = new_hop(bb, NULL); + + if ((src->attrs & TYPE_ATTRS) != (dest->attrs & TYPE_ATTRS)) + fatal("hreg move of %%%d from %s to %s with mismatched types", vreg->id, src->id, dest->id); + else + { + uint32_t type = src->attrs & TYPE_ATTRS; + tracef('R', "R: non-converting move from %s to %s of type 0x%x\n", src->id, dest->id, type); + + if (!src->is_stacked && dest->is_stacked) + { + switch (type) + { + case burm_int_ATTR: + hop_add_insel(hop, "sw %H, %S(fp) ! %H", src, dest, dest); + break; + + case burm_long_ATTR: + hop_add_insel(hop, "sw %0H, 0+%S(fp) ! %H", src, dest, dest); + hop_add_insel(hop, "sw %1H, 4+%S(fp) ! %H", src, dest, dest); + break; + + case burm_float_ATTR: + hop_add_insel(hop, "swc1 %H, %S(fp) ! %H", src, dest, dest); + break; + + case burm_double_ATTR: + hop_add_insel(hop, "sdc1 %H, %S(fp) ! %H", src, dest, dest); + break; + + default: + goto nomove; + } + } + else if (src->is_stacked && !dest->is_stacked) + { + switch (type) + { + case burm_int_ATTR: + hop_add_insel(hop, "lw %H, %S(fp) ! %H", dest, src, src); + break; + + case burm_long_ATTR: + /* Can't load straight into dest because it might overlap with src. */ + hop_add_insel(hop, "lw at, 0+%S(fp) ! %H", dest, src, src); + hop_add_insel(hop, "lw %1H, 4+%S(fp) ! %H", dest, src, src); + hop_add_insel(hop, "mov %0H, at", dest); + break; + + case burm_float_ATTR: + hop_add_insel(hop, "lwc1 %H, %S(fp) ! %H", dest, src, src); + break; + + case burm_double_ATTR: + hop_add_insel(hop, "ldc1 %H, %S(fp) ! %H", dest, src, src); + break; + + default: + goto nomove; + } + } + else if (!src->is_stacked && !dest->is_stacked) + { + switch (type) + { + case burm_int_ATTR: + hop_add_insel(hop, "mov %H, %H", dest, src); + break; + + case burm_long_ATTR: + hop_add_insel(hop, "mov %0H, %0H", dest, src); + hop_add_insel(hop, "mov %1H, %1H", dest, src); + break; + + case burm_float_ATTR: + hop_add_insel(hop, "mov.s %H, %H", dest, src); + break; + + case burm_double_ATTR: + hop_add_insel(hop, "mov.d %H, %H", dest, src); + break; + + default: + goto nomove; + } + } + else if (src->is_stacked && dest->is_stacked) + fatal("tried to move stacked object %%%d of type 0x%x from %s to %s", vreg->id, type, src->id, dest->id); + else + goto nomove; + } + + return hop; + + nomove: + fatal("cannot move %s to %s", src->id, dest->id); ++ return NULL; + } + + 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->is_stacked); + assert(!dest->is_stacked); + assert((src->attrs & TYPE_ATTRS) == (dest->attrs & TYPE_ATTRS)); + + 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; + } + + return hop; + } + + const char* platform_label(const char* label) + { + /* Labels starting with . are internal, not exported, and don't need mangling. */ + + if (label[0] == '.') + return label; + + /* Otherwise, mangle. */ + + return aprintf("_%s", label); + } + + /* vim: set sw=4 ts=4 expandtab : */ + diff --cc mach/mips/mcg/table index 000000000,2a580e27f..cf80ef1b8 mode 000000,100644..100644 --- a/mach/mips/mcg/table +++ b/mach/mips/mcg/table @@@ -1,0 -1,1018 +1,1024 @@@ + OPTIONS + + LOWER_PUSHES_TO_LOADS_AND_STORES; + + REGISTERS + + /* Registers are allocated top down. The odd order below is to make sure + * that cheap registers get allocated first. + * - * Attributes may have at most one of: int, float, long, double. These - * indicate that the register is used to store a value of that type. If - * your register can store more than one type, create an alias. Registers - * with none of these cannot be copied by the code generator (and so cannot - * be moved from register to register or spilt). ++ * Each register must be declared as having at least one type (listed above). ++ * This allows the register to contain values of that type. They may also be ++ * declared as having any number of additional attributes, which can be used ++ * to constrain register selection. ++ * ++ * Register aliases may be defined with uses(reg1, reg2, ...). These work like ++ * any other register, but they share hardware resources with some real registers. + */ + + r4 int volatile; + r5 int volatile; + r6 int volatile; + r7 int volatile; + r8 int volatile; + r9 int volatile; + r10 int volatile; + r11 int volatile; + r12 int volatile; + r13 int volatile; + r14 int volatile; + r15 int volatile; + r24 int volatile; + r25 int volatile; + r2 int volatile iret; + r3 int volatile; + - r17 named("r16") int; ++ r17 named("r17") int; + r18 named("r18") int; + r19 named("r19") int; + r20 named("r20") int; + r21 named("r21") int; + r22 named("r22") int; + r23 named("r23") int; + - r4r5 named("r4", "r5") aliases(r4, r5) long volatile lret1; - r6r7 named("r6", "r7") aliases(r6, r7) long volatile; - r8r9 named("r8", "r9") aliases(r8, r9) long volatile; - r10r11 named("r10", "r11") aliases(r10, r11) long volatile; - r12r13 named("r12", "r13") aliases(r12, r13) long volatile; - r14r15 named("r14", "r15") aliases(r14, r15) long volatile; - r24r25 named("r24", "r25") aliases(r24, r25) long volatile; - r2r3 named("r2", "r3") aliases(r2, r3) long volatile lret; ++ r4r5 named("r4", "r5") uses(r4, r5) long volatile lret1; ++ r6r7 named("r6", "r7") uses(r6, r7) long volatile; ++ r8r9 named("r8", "r9") uses(r8, r9) long volatile; ++ r10r11 named("r10", "r11") uses(r10, r11) long volatile; ++ r12r13 named("r12", "r13") uses(r12, r13) long volatile; ++ r14r15 named("r14", "r15") uses(r14, r15) long volatile; ++ r24r25 named("r24", "r25") uses(r24, r25) long volatile; ++ r2r3 named("r2", "r3") uses(r2, r3) long volatile lret; + - r17r18 named("r17", "r18") aliases(r17, r18) long; - r19r20 named("r19", "r20") aliases(r19, r20) long; - r21r22 named("r21", "r22") aliases(r21, r22) long; ++ r17r18 named("r17", "r18") uses(r17, r18) long; ++ r19r20 named("r19", "r20") uses(r19, r20) long; ++ r21r22 named("r21", "r22") uses(r21, r22) long; + + f0 float volatile fret; + f1 float volatile; + f2 float volatile; + f3 float volatile; + f4 float volatile; + f5 float volatile; + f6 float volatile; + f7 float volatile; + f8 float volatile; + f9 float volatile; + f10 float volatile; + f11 float volatile; + f12 float volatile; + f13 float volatile; + f14 float volatile; + f15 float volatile; + f16 float volatile; + f17 float volatile; + f18 float volatile; + f19 float volatile; + + f20 float; + f21 float; + f22 float; + f23 float; + f24 float; + f25 float; + f26 float; + f27 float; + f28 float; + f29 float; + /* f30 and f31 is used by the compiler as a temporary. */ + - d0 named("f0") aliases(f0, f1) double volatile dret; - d2 named("f2") aliases(f2, f3) double volatile; - d4 named("f4") aliases(f4, f5) double volatile; - d6 named("f6") aliases(f6, f7) double volatile; - d8 named("f8") aliases(f8, f9) double volatile; - d10 named("f10") aliases(f10, f11) double volatile; - d12 named("f12") aliases(f12, f13) double volatile; - d14 named("f14") aliases(f14, f15) double volatile; - d16 named("f16") aliases(f16, f17) double volatile; - d18 named("f18") aliases(f18, f19) double volatile; ++ d0 named("f0") uses(f0, f1) double volatile dret; ++ d2 named("f2") uses(f2, f3) double volatile; ++ d4 named("f4") uses(f4, f5) double volatile; ++ d6 named("f6") uses(f6, f7) double volatile; ++ d8 named("f8") uses(f8, f9) double volatile; ++ d10 named("f10") uses(f10, f11) double volatile; ++ d12 named("f12") uses(f12, f13) double volatile; ++ d14 named("f14") uses(f14, f15) double volatile; ++ d16 named("f16") uses(f16, f17) double volatile; ++ d18 named("f18") uses(f18, f19) double volatile; + - d20 named("f20") aliases(f20, f21) double; - d22 named("f22") aliases(f22, f23) double; - d24 named("f24") aliases(f24, f25) double; - d26 named("f26") aliases(f26, f27) double; - d28 named("f28") aliases(f28, f29) double; ++ d20 named("f20") uses(f20, f21) double; ++ d22 named("f22") uses(f22, f23) double; ++ d24 named("f24") uses(f24, f25) double; ++ d26 named("f26") uses(f26, f27) double; ++ d28 named("f28") uses(f28, f29) double; + + + + DECLARATIONS + + ubyteX; /* bottom 8 bits valid, the rest undefined */ + ubyte0; /* bottom 8 bits valid, the rest 0 */ + ushortX; /* bottom 16 bits valid, the rest undefined */ + ushort0; /* bottom 16 bits valid, the rest 0 */ + + address fragment; + intregorzero fragment; + byteregorzero fragment; + shortregorzero fragment; + + + + PATTERNS + + /* Special */ + + PAIR(BLOCK.I, BLOCK.I); + + + + /* Miscellaneous special things */ + + out:(int)reg = POP.I + emit "lw %out, 0(sp)" + emit "addiu sp, sp, 4" + cost 8; + + out:(long)reg = POP.L + emit "lw %out.0, 4(sp)" + emit "lw %out.1, 0(sp)" + emit "addiu sp, sp, 8" + cost 12; + + out:(float)reg = POP.F + emit "lwc1 %out, 0(sp)" + emit "addiu sp, sp, 4" + cost 8; + + out:(double)reg = POP.D + emit "ldc1 %out, 0(sp)" + emit "addiu sp, sp, 8" + cost 8; + + SETRET.I(in:(iret)reg) + emit "! setret.i" + cost 1; + + SETRET.L(in:(lret)reg) + emit "! setret.l" + cost 1; + + SETRET.F(in:(fret)reg) + emit "! setret.f" + cost 1; + + SETRET.D(in:(dret)reg) + emit "! setret.d" + cost 1; + + STACKADJUST.I(delta:CONST.I) + when signed_constant(%delta, 16) + emit "addiu sp, sp, $delta" + cost 4; + + STACKADJUST.I(in:intregorzero) + emit "addu sp, sp, %in" + cost 4; + + STACKADJUST.I(NEG.I(in:intregorzero)) + emit "subu sp, sp, %in" + cost 4; + + out:(int)reg = GETFP.I + emit "mov %out, fp" + cost 4; + + SETFP.I(in:(int)reg) + emit "mov fp, %in" + cost 4; + + out:(int)reg = CHAINFP.I(in:(int)reg) + emit "lw %out, 0(%in)" + cost 4; + + out:(int)reg = FPTOAB.I(GETFP.I) + emit "addiu %out, fp, 8" + cost 4; + + out:(int)reg = FPTOAB.I(in:(int)reg) + emit "addiu %out, %in, 8" + cost 4; + + out:(int)reg = FPTOLB.I(in:(int)reg) + with %out == %in + cost 1; + + out:(int)reg = GETSP.I + emit "mov %out, sp" + cost 4; + + SETSP.I(in:(int)reg) + emit "mov sp, %in" + cost 4; + + out:(int)reg = ANY.I + cost 1; + + out:(long)reg = ANY.L + cost 1; + + + + /* Memory operations */ + + /* Stores */ + + STORE.L(addr:address, value:(long)reg) + emit "sw %value.0, 0+%addr" + emit "sw %value.1, 4+%addr" + cost 8; + + STORE.I(addr:address, value:intregorzero) + emit "sw %value, %addr" + cost 4; + + STORE.I(label:LABEL.I, value:intregorzero) + emit "lui at, ha16[$label]" + emit "sw %value, lo16[$label] (at)" + cost 8; + + STOREH.I(addr:address, value:shortregorzero) + emit "sh %value, %addr" + cost 4; + + STOREH.I(label:LABEL.I, value:shortregorzero) + emit "lui at, ha16[$label]" + emit "sh %value, lo16[$label] (at)" + cost 8; + + STOREB.I(addr:address, value:byteregorzero) + emit "sb %value, %addr" + cost 4; + + STOREB.I(label:LABEL.I, value:byteregorzero) + emit "lui at, ha16[$label]" + emit "sb %value, lo16[$label] (at)" + cost 8; + + STORE.F(addr:address, value:(float)reg) + emit "swc1 %value, %addr" + cost 4; + + STORE.F(label:LABEL.I, value:(float)reg) + emit "lui at, ha16[$label]" + emit "swc1 %value, lo16[$label] (at)" + cost 8; + + STORE.D(addr:address, value:(double)reg) + emit "sdc1 %value, %addr" + cost 4; + + STORE.D(label:LABEL.I, value:(double)reg) + emit "lui at, ha16[$label]" + emit "sdc1 %value, lo16[$label] (at)" + cost 8; + + /* Loads */ + + out:(int)reg = LOAD.I(addr:address) + emit "lw %out, %addr" + cost 4; + + out:(int)reg = LOAD.I(label:LABEL.I) + emit "lui at, ha16[$label]" + emit "lw %out, lo16[$label] (at)" + cost 8; + + /* We can't just load directly because %out.0 and %addr might share + * a register, resulting in %addr being corrupted before %out.1 is + * loaded. */ + out:(long)reg = LOAD.L(addr:address) + emit "lw at, 0+%addr" + emit "lw %out.1, 4+%addr" + emit "mov %out.0, at" + cost 12; + + out:(int)ushort0 = LOADH.I(addr:address) + emit "lhu %out, %addr" + cost 4; + + out:(int)reg = EXTENDH.I(LOADH.I(addr:address)) + emit "lh %out, %addr" + cost 4; + + out:(int)ushort0 = LOADH.I(label:LABEL.I) + emit "lui at, ha16[$label]" + emit "lhu %out, lo16[$label] (at)" + cost 8; + + out:(int)reg = EXTENDH.I(LOADH.I(label:LABEL.I)) + emit "lui at, ha16[$label]" + emit "lh %out, lo16[$label] (at)" + cost 8; + + out:(int)ubyte0 = LOADB.I(addr:address) + emit "lbu %out, %addr" + cost 4; + + out:(int)reg = EXTENDB.I(LOADB.I(addr:address)) + emit "lb %out, %addr" + cost 4; + + out:(int)ubyte0 = LOADB.I(label:LABEL.I) + emit "lui at, ha16[$label]" + emit "lbu %out, lo16[$label] (at)" + cost 8; + + out:(int)reg = EXTENDB.I(LOADB.I(label:LABEL.I)) + emit "lui at, ha16[$label]" + emit "lb %out, lo16[$label] (at)" + cost 8; + + out:(float)reg = LOAD.F(addr:address) + emit "lwc1 %out, %addr" + cost 4; + + out:(float)reg = LOAD.F(label:LABEL.I) + emit "lui at, ha16[$label]" + emit "lwc1 %out, lo16[$label] (at)" + cost 8; + + out:(double)reg = LOAD.D(addr:address) + emit "ldc1 %out, %addr" + cost 4; + + out:(double)reg = LOAD.D(label:LABEL.I) + emit "lui at, ha16[$label]" + emit "ldc1 %out, lo16[$label] (at)" + cost 8; + + /* ubyte intrinsics */ + + out:(int)ubyteX = in:(int)ubyte0 + with %out == %in + emit "! ubyte0 -> ubyteX" + cost 1; + + out:(int)ubyte0 = in:(int)ubyteX + emit "andiu %out, %in, 0xff ! ubyteX -> ubyte0" + cost 4; + + out:(int)reg = in:(int)ubyte0 + with %out == %in + emit "! ubyte0 -> reg" + cost 4; + + out:(int)ubyteX = in:(int)reg + with %out == %in + emit "! reg -> ubyteX" + cost 1; + + /* ushort intrinsics */ + + out:(int)ushortX = in:(int)ushort0 + with %out == %in + emit "! ushort0 -> ushortX" + cost 1; + + out:(int)ushort0 = in:(int)ushortX + emit "andiu %out, %in, 0xffff ! ushortX -> ushort0" + cost 4; + + out:(int)reg = in:(int)ushort0 + with %out == %in + emit "! ushort0 -> reg" + cost 4; + + out:(int)ushortX = in:(int)reg + with %out == %in + emit "! reg -> ushortX" + cost 1; + + + + /* Extensions and conversions */ + + out:(int)reg = EXTENDB.I(in:intregorzero) + emit "seb %out, %in" + cost 4; + + out:(int)reg = EXTENDH.I(in:intregorzero) + emit "seh %out, %in" + cost 4; + + out:(int)reg = FROMSI.I(in:(int)reg) + with %out == %in + emit "! FROMSI.I(int) -> int" + cost 1; + + out:(int)reg = FROMUI.I(in:(int)reg) + with %out == %in + emit "! FROMUI.I(int) -> int" + cost 1; + + out:(long)reg = FROMSI.L(in:(int)reg) + emit "mov %out.0, %in" + emit "sra %out.1, %in, 31" + cost 8; + + out:(long)reg = FROMUI.L(in:(int)reg) + emit "mr %out.0, %in" + emit "li %out.1, 0" + cost 8; + + out:(lret)reg = FROMIPAIR.L(in1:(int)reg, in2:(int)reg) - with preserved(%in1), preserved(%in2) ++ with corrupted(%in1), corrupted(%in2) + emit "mov %out.0, %in1" + emit "mov %out.1, %in2" + cost 8; - ++ + out:(int)reg = FROML0.I(in:(long)reg) + emit "mov %out, %in.0" + cost 4; + + out:(int)reg = FROML1.I(in:(long)reg) + emit "mov %out, %in.1" + cost 4; + + intregorzero = zero:CONST.I + when specific_constant(%zero, 0) + emit "zero"; + + intregorzero = value:(int)reg + emit "%value"; + + intregorzero = value:(int)ubyte0 + emit "%value"; + + intregorzero = value:(int)ushort0 + emit "%value"; + + shortregorzero = zero:CONST.I + when specific_constant(%zero, 0) + emit "zero"; + + shortregorzero = value:(int)ushort0 + emit "%value"; + + shortregorzero = value:(int)ushortX + emit "%value"; + + shortregorzero = value:(int)ubyte0 + emit "%value"; + + byteregorzero = zero:CONST.I + when specific_constant(%zero, 0) + emit "zero"; + + byteregorzero = value:(int)ubyte0 + emit "%value"; + + byteregorzero = value:(int)ubyteX + emit "%value"; + + + + /* Locals and stack-relatives */ + + out:(int)reg = in:LOCAL.I + emit "addiu %out, fp, $in" + cost 4; + + address = in:LOCAL.I + emit "$in(fp)"; + + address = ADD.I(GETSP.I, offset:CONST.I) + when signed_constant(%offset, 16) + emit "$offset(sp)"; + + + + /* Memory addressing modes */ + + address = ADD.I(addr:(int)reg, offset:CONST.I) + when signed_constant(%offset, 16) + emit "$offset(%addr)"; + + address = addr:(int)reg + emit "0(%addr)"; + + + + /* Branches */ + + JUMP(addr:BLOCK.I) + emit "b $addr" + emit "nop" + cost 8; + + FARJUMP(addr:LABEL.I) + with corrupted(volatile) + emit "j $addr" + emit "nop" + cost 8; + + JUMP(dest:(int)reg) + emit "jr %dest" + emit "nop" + cost 8; + + CJUMPEQ(left:(int)reg, PAIR(true:BLOCK.I, false:BLOCK.I)) + emit "beq %left, zero, $true" + emit "nop" + emit "b $false" + emit "nop" + cost 16; + + CJUMPLT(left:(int)reg, PAIR(true:BLOCK.I, false:BLOCK.I)) + emit "bltz %left, $true" + emit "nop" + emit "b $false" + emit "nop" + cost 20; + + CJUMPLE(left:(int)reg, PAIR(true:BLOCK.I, false:BLOCK.I)) + emit "blez %left, $true" + emit "nop" + emit "b $false" + emit "nop" + cost 20; + + #define CALLLABEL(insn) \ + insn (dest:LABEL.I) \ + with corrupted(volatile) \ + emit "jal $dest" \ + emit "nop" \ + cost 8; + + CALLLABEL(CALL) + out:(iret)reg = CALLLABEL(CALL.I) ++ out:(fret)reg = CALLLABEL(CALL.F) + out:(lret)reg = CALLLABEL(CALL.L) ++ out:(dret)reg = CALLLABEL(CALL.D) + + #define CALLINDIRECT(insn) \ + insn (dest:(int)reg) \ + with corrupted(volatile) \ + emit "jalr %dest" \ + emit "nop" \ + cost 8; + + CALLINDIRECT(CALL) + out:(iret)reg = CALLINDIRECT(CALL.I) ++ out:(fret)reg = CALLINDIRECT(CALL.F) + out:(lret)reg = CALLINDIRECT(CALL.L) ++ out:(dret)reg = CALLINDIRECT(CALL.D) + + JUMP(dest:LABEL.I) + emit "b $dest" + emit "nop" + cost 8; + + + + /* Conditional branches */ + + /* Normally COMPARE returns a condition code (in a flags register) which the CJUMP + * instructions can then operate on. But MIPS doesn't have a flags register, and + * requires you to know what condition you're testing for when you do the comparison. + * mcg doesn't like this much and we have to list every combination individually. + */ + + /* Signed integer comparisons against zero */ + + CJUMPEQ(COMPARESI.I(left:(int)reg, zero:CONST.I), PAIR(true:BLOCK.I, false:BLOCK.I)) + when specific_constant(%zero, 0) + emit "beq %left, zero, $true" + emit "nop" + emit "b $false" + emit "nop" + cost 16; + + CJUMPLT(COMPARESI.I(left:(int)reg, zero:CONST.I), PAIR(true:BLOCK.I, false:BLOCK.I)) + when specific_constant(%zero, 0) + emit "bltz %left, $true" + emit "nop" + emit "b $false" + emit "nop" + cost 16; + + CJUMPLE(COMPARESI.I(left:(int)reg, zero:CONST.I), PAIR(true:BLOCK.I, false:BLOCK.I)) + when specific_constant(%zero, 0) + emit "blez %left, $true" + emit "nop" + emit "b $false" + emit "nop" + cost 16; + + /* Signed integer comparisons against a constant */ + + CJUMPEQ(COMPARESI.I(left:(int)reg, value:CONST.I), PAIR(true:BLOCK.I, false:BLOCK.I)) + emit "li at, $value" + emit "beq %left, at, $true" + emit "nop" + emit "b $false" + emit "nop" + cost 20; + + CJUMPLT(COMPARESI.I(left:(int)reg, value:CONST.I), PAIR(true:BLOCK.I, false:BLOCK.I)) + when signed_constant(%value, 16) + emit "slti at, %left, $value" + emit "bne at, zero, $true" + emit "nop" + emit "b $false" + emit "nop" + cost 20; + + CJUMPLE(COMPARESI.I(left:(int)reg, value:CONST.I), PAIR(true:BLOCK.I, false:BLOCK.I)) + when constant_within_inclusive_range(%value, -0x8000, 0x7ffe) + emit "slti at, %left, 1+$value" + emit "bne at, zero, $true" + emit "nop" + emit "b $false" + emit "nop" + cost 20; + + /* Signed integer comparisons against a register */ + + CJUMPEQ(COMPARESI.I(left:(int)reg, right:(int)reg), PAIR(true:BLOCK.I, false:BLOCK.I)) + emit "beq %left, %right, $true" + emit "nop" + emit "b $false" + emit "nop" + cost 20; + + CJUMPLT(COMPARESI.I(left:(int)reg, right:(int)reg), PAIR(true:BLOCK.I, false:BLOCK.I)) + emit "slt at, %left, %right" + emit "bne at, zero, $true" + emit "nop" + emit "b $false" + emit "nop" + cost 20; + + CJUMPLE(COMPARESI.I(left:(int)reg, right:(int)reg), PAIR(true:BLOCK.I, false:BLOCK.I)) + emit "slt at, %right, %left" + emit "beq at, zero, $true" + emit "nop" + emit "b $false" + emit "nop" + cost 20; + + /* Unsigned integer comparisons against a constant */ + + CJUMPLT(COMPARESI.I(COMPAREUI.I(left:(int)reg, right:CONST.I), alwayszero:CONST.I), PAIR(true:BLOCK.I, false:BLOCK.I)) + when signed_constant(%right, 16) + when specific_constant(%alwayszero, 0) + emit "sltiu at, %left, $right" + emit "bne at, zero, $true" + emit "nop" + emit "b $false" + emit "nop" + cost 16; + + CJUMPLE(COMPARESI.I(COMPAREUI.I(left:(int)reg, right:CONST.I), alwayszero:CONST.I), PAIR(true:BLOCK.I, false:BLOCK.I)) + when constant_within_inclusive_range(%right, -0x8000, 0x7ffe) + when specific_constant(%alwayszero, 0) + emit "sltiu at, %left, 1+$right" + emit "bne at, zero, $true" + emit "nop" + emit "b $false" + emit "nop" + cost 20; + + /* Unsigned integer comparisons against registers */ + + CJUMPEQ(COMPARESI.I(COMPAREUI.I(left:(int)reg, right:(int)reg), alwayszero:CONST.I), PAIR(true:BLOCK.I, false:BLOCK.I)) + when specific_constant(%alwayszero, 0) + emit "beq %left, %right, $true" + emit "nop" + emit "b $false" + emit "nop" + cost 16; + + CJUMPLT(COMPARESI.I(COMPAREUI.I(left:(int)reg, right:(int)reg), alwayszero:CONST.I), PAIR(true:BLOCK.I, false:BLOCK.I)) + when specific_constant(%alwayszero, 0) + emit "sltu at, %left, %right" + emit "bne at, zero, $true" + emit "nop" + emit "b $false" + emit "nop" + cost 16; + + CJUMPLE(COMPARESI.I(COMPAREUI.I(left:(int)reg, right:(int)reg), alwayszero:CONST.I), PAIR(true:BLOCK.I, false:BLOCK.I)) + when specific_constant(%alwayszero, 0) + emit "sltu at, %right, %left" + emit "beq at, zero, $true" + emit "nop" + emit "b $false" + emit "nop" + cost 16; + + + + + /* Comparisons */ + + /* The COMPARE nodes return tristate integer values; -1, 0 or 1. */ + + out:(int)reg = COMPARESI.I(left:(int)reg, right:(int)reg) - with preserved(%left), preserved(%right) ++ with corrupted(%left), corrupted(%right) + emit "slt at, %left, %right" + emit "bne at, zero, 1f" + emit "li %out, -1" /* delay slot */ + emit "slt %out, %right, %left" + emit "1:" + cost 20; + + out:(int)reg = COMPAREUI.I(left:(int)reg, right:(int)reg) - with preserved(%left), preserved(%right) ++ with corrupted(%left), corrupted(%right) + emit "sltu at, %left, %right" + emit "bne at, zero, 1f" + emit "li %out, -1" /* delay slot */ + emit "sltu %out, %right, %left" + emit "1:" + cost 20; + + out:(iret)reg = COMPAREUL.I(left:(lret)reg, right:(lret1)reg) + emit "jal .compareul" + emit "nop" + cost 30; + + out:(int)reg = COMPAREF.I(left:(float)reg, right:(float)reg) - with preserved(%left), preserved(%right) ++ with corrupted(%left), corrupted(%right) + emit "c.lt.s 0, %left, %right" + emit "li %out, -1" + emit "bc1t 0, 1f" + emit "nop" + emit "c.lt.s 0, %right, %left" + emit "li %out, 1" + emit "movf %out, zero, 0" + emit "1:" + cost 28; + + out:(int)reg = COMPARED.I(left:(double)reg, right:(double)reg) - with preserved(%left), preserved(%right) ++ with corrupted(%left), corrupted(%right) + emit "c.lt.d 0, %left, %right" + emit "li %out, -1" + emit "bc1t 0, 1f" + emit "nop" + emit "c.lt.d 0, %right, %left" + emit "li %out, 1" + emit "movf %out, zero, 0" + emit "1:" + cost 28; + + /* Booleans */ + + /* If 0 then 1, else 0 */ + out:(int)reg = IFEQ.I(in:intregorzero) + emit "sltiu %out, %in, 1" + cost 4; + + /* If -1 then 1, else 0 */ + out:(int)reg = IFLT.I(in:intregorzero) + emit "srl %out, %in, 31" + cost 4; + + /* If 1 or 0 then 1, else 0 */ + out:(int)reg = IFLE.I(in:intregorzero) + emit "slti %out, %in, 1" + cost 4; + + + + /* Conversions */ + + #if 0 + out:(int)reg = CIU44(in:(int)reg) + with %out == %in + emit "! ciu44" + cost 4; + + out:(int)reg = CUI44(in:(int)reg) + with %out == %in + emit "! cui44" + cost 4; + #endif + + /* ALU operations */ + + /* reg + reg */ + #define ALUR(name, instr) \ + out:(int)reg = name(left:intregorzero, right:intregorzero) \ + emit instr " %out, %left, %right" \ + cost 4; \ + + /* reg + const */ + #define ALUC(name, instr) \ + out:(int)reg = name(left:intregorzero, right:CONST.I) \ + when signed_constant(%right, 16) \ + emit instr " %out, %left, $right" \ + cost 4; \ + + /* const + reg */ + #define ALUC_reversed(name, instr) \ + out:(int)reg = name(left:CONST.I, right:intregorzero) \ + when signed_constant(%left, 16) \ + emit instr " %out, %right, $left" \ + cost 4; \ + + /* reg + const AND const + reg */ + #define ALUCC(name, instr) \ + ALUC(name, instr) \ + ALUC_reversed(name, instr) + + ALUR(ADD.I, "addu") + ALUCC(ADD.I, "addiu") + + out:(int)reg = SUB.I(left:intregorzero, right:intregorzero) + emit "subu %out, %left, %right" + cost 4; + + out:(int)reg = SUB.I(left:intregorzero, right:CONST.I) + emit "addiu %out, %left, -[$right]" + cost 4; + + out:(int)reg = DIV.I(left:intregorzero, right:intregorzero) + emit "div %left, %right" + emit "mflo %out" + cost 8; + + out:(int)reg = DIVU.I(left:intregorzero, right:intregorzero) + emit "divu %left, %right" + emit "mflo %out" + cost 8; + + out:(int)reg = MOD.I(left:intregorzero, right:intregorzero) + emit "div %left, %right" + emit "mfhi %out" + cost 8; + + out:(int)reg = MODU.I(left:intregorzero, right:intregorzero) + emit "divu %left, %right" + emit "mfhi %out" + cost 8; + + ALUR(MUL.I, "mul") + + ALUR(ASL.I, "sllv") + ALUC(ASL.I, "sll") + ALUR(ASR.I, "srav") + ALUC(ASR.I, "sra") + + ALUR(LSL.I, "sllv") + ALUC(LSL.I, "sll") + ALUR(LSR.I, "srlv") + ALUC(LSR.I, "srl") + + out:(int)reg = NEG.I(left:intregorzero) + emit "subu %out, zero, %left" + cost 4; + + out:(int)reg = NOT.I(in:intregorzero) + emit "nor %out, %in, %in" + cost 4; + + ALUR(AND.I, "and") + ALUCC(AND.I, "andi") + + ALUR(OR.I, "or") + ALUCC(OR.I, "ori") + + ALUR(EOR.I, "xor") + ALUCC(EOR.I, "xori") + + out:(int)reg = value:LABEL.I + emit "lui %out, hi16[$value]" + emit "ori %out, %out, lo16[$value]" + cost 4; + + out:(int)reg = value:BLOCK.I + emit "lui %out, hi16[$value]" + emit "ori %out, %out, lo16[$value]" + cost 4; + + out:(int)reg = value:CONST.I + emit "li %out, $value" + cost 4; + + + + /* FPU operations */ + + /* Doubles */ + + out:(double)reg = ADDF.D(left:(double)reg, right:(double)reg) + emit "add.d %out, %left, %right" + cost 4; + + out:(double)reg = SUBF.D(left:(double)reg, right:(double)reg) + emit "sub.d %out, %left, %right" + cost 4; + + out:(double)reg = MULF.D(left:(double)reg, right:(double)reg) + emit "mul.d %out, %left, %right" + cost 4; + + out:(double)reg = DIVF.D(left:(double)reg, right:(double)reg) + emit "div.d %out, %left, %right" + cost 4; + + out:(double)reg = NEGF.D(left:(double)reg) + emit "neg.d %out, %left" + cost 4; + + out:(double)reg = FROMSI.D(in:(int)reg) + emit "mtc1 %in, %out" /* mtc1 has reversed parameters */ + emit "cvt.d.w %out, %out" + cost 4; + + out:(dret)reg = FROMUI.D(in:(iret)reg) + emit "jal .c_ui_d" + emit "nop" + cost 30; + + out:(int)reg = FROMSD.I(in:(double)reg) + emit "trunc.w.d f30, %in" + emit "mfc1 %out, f30" + cost 8; + + out:(lret)reg = FROMSD.L(in:(dret)reg) + emit "jal .c_sd_l" + emit "nop" + cost 30; + + out:(iret)reg = FROMUD.I(in:(dret)reg) + with corrupted(dret) + emit "jal .c_ud_i" + emit "nop" + cost 30; + + out:(double)reg = COPYL.D(in:(long)reg) + emit "mtc1 %in.0, %out" /* mtc1 has reversed parameters */ + emit "mthc1 %in.1, %out" /* mtc1 has reversed parameters */ + cost 8; + + out:(long)reg = COPYD.L(in:(double)reg) + emit "mfc1 %out.0, %in" + emit "mfhc1 %out.1, %in" + cost 8; + + /* Floats */ + + out:(float)reg = ADDF.F(left:(float)reg, right:(float)reg) + emit "add.d %out, %left, %right" + cost 4; + + out:(float)reg = SUBF.F(left:(float)reg, right:(float)reg) + emit "sub.d %out, %left, %right" + cost 4; + + out:(float)reg = MULF.F(left:(float)reg, right:(float)reg) + emit "mul.d %out, %left, %right" + cost 4; + + out:(float)reg = DIVF.F(left:(float)reg, right:(float)reg) + emit "div.d %out, %left, %right" + cost 4; + + out:(float)reg = NEGF.F(left:(float)reg) + emit "neg.s %out, %left" + cost 4; + + out:(float)reg = FROMSI.F(in:intregorzero) + emit "mtc1 %in, %out" /* mtc1 has reversed parameters */ + emit "cvt.s.w %out, %out" + cost 4; + + out:(int)reg = FROMSF.I(in:(float)reg) + emit "trunc.w.s f30, %in" + emit "mfc1 %out, f30" + cost 8; + + out:(lret)reg = FROMSF.L(in:(fret)reg) + emit "jal .c_sf_l" + emit "nop" + cost 30; + + out:(fret)reg = FROMUI.F(in:(iret)reg) + emit "jal .c_ui_f" + emit "nop" + cost 30; + + out:(iret)reg = FROMUF.I(in:(fret)reg) + with corrupted(fret) + emit "jal .c_uf_i" + emit "nop" + cost 30; + + out:(float)reg = COPYI.F(in:intregorzero) + emit "mtc1 %in, %out" /* mtc1 has reversed parameters */ + cost 4; + + out:(int)reg = COPYF.I(in:(float)reg) + emit "mfc1 %out, %in" + cost 4; + + out:(float)reg = value:CONST.F + when specific_constant(%value, 0) + emit "mtc1 zero, %out" /* mtc1 has reversed parameters */ + cost 4; + + /* vim: set sw=4 ts=4 expandtab : */ + diff --cc mach/proto/mcg/data.c index 4e722ce58,95d828650..dfd3651d4 --- a/mach/proto/mcg/data.c +++ b/mach/proto/mcg/data.c @@@ -80,22 -73,10 +73,10 @@@ void data_float(const char* data, size_ emit_header(is_ro ? SECTION_ROM : SECTION_DATA); assert((size == 4) || (size == 8)); - i = float_cst((char*) data, size, (char*) buffer); - if ((i != 0) && (i != 2)) /* 2 == overflow */ - fatal("cannot parse floating point constant %s sz %d", data, size); - - fprintf(outputfile, "\t!float %s sz %zd\n", data, size); - fprintf(outputfile, "\t.data1 "); - writehex(buffer[0], 1); - for (i=1; i", EM_error); if (outputfilename) @@@ -123,17 -123,17 +147,6 @@@ fclose(outputfile); EM_close(); -- if (cfg_dot_file) -- { -- fprintf(cfg_dot_file, "}\n"); -- fclose(cfg_dot_file); -- } -- if (dominance_dot_file) -- { -- fprintf(dominance_dot_file, "}\n"); -- fclose(dominance_dot_file); -- } -- return 0; } diff --cc mach/proto/mcg/mcg.h index 2863177c2,0bd9928df..f8f4a4160 --- a/mach/proto/mcg/mcg.h +++ b/mach/proto/mcg/mcg.h @@@ -8,8 -8,7 +8,8 @@@ #include #include #include + #include +#include "hashtable.h" - #include "flt_arith.h" #include "em_arith.h" #include "em_label.h" #include "em.h" @@@ -121,9 -112,9 +121,10 @@@ extern void pass_group_irs(void) extern void pass_infer_types(void); extern void pass_insert_moves(void); extern void pass_instruction_selector(void); -extern void pass_live_vreg_analysis(void); +extern void pass_live_value_analysis(void); + extern void pass_lower_pushes(void); extern void pass_add_prologue_epilogue(void); +extern void pass_prune_stray_moves(void); extern void pass_register_allocator(void); extern void pass_remove_dead_blocks(void); extern void pass_remove_dead_phis(void); diff --cc mach/proto/mcg/parse_em.c index 441b14e8b,e8859d2fb..db85aaa3f --- a/mach/proto/mcg/parse_em.c +++ b/mach/proto/mcg/parse_em.c @@@ -237,16 -281,16 +281,20 @@@ static void parse_pseu(void } case str_ptyp: - data_block((const uint8_t*) strdup(em.em_string), em.em_size, ro); + { + uint8_t* copy = malloc(em.em_size); + memcpy(copy, em.em_string, em.em_size); + data_block(copy, em.em_size, ro); break; + } case cst_ptyp: - data_int(em.em_cst, EM_wordsize, ro); + { + arith value = em.em_cst; + data_int(value, EM_wordsize, ro); + data_block_int(value); break; + } case nof_ptyp: data_offset(dlabel_to_str(em.em_dlb), em.em_off, ro); diff --cc mach/proto/mcg/procedure.c index 004b6068d,d8b5fd18c..f7dc813d1 --- a/mach/proto/mcg/procedure.c +++ b/mach/proto/mcg/procedure.c @@@ -209,41 -196,27 +209,45 @@@ void procedure_compile(struct procedure /* Passes from here on can't alter the BB graph without also updating prevs * and nexts (and then calling update_graph_data()). */ - print_blocks('3'); + print_blocks('e'); pass_wire_up_return_values(); + pass_convert_stack_ops(); + #if defined MCGG_OPTION_LOWER_PUSHES_TO_LOADS_AND_STORES + pass_lower_pushes(); + #endif - print_blocks('4'); + print_blocks('f'); + pass_convert_stack_ops(); + print_blocks('g'); pass_convert_locals_to_ssa(); - print_blocks('5'); + print_blocks('h'); + pass_convert_inputs_to_phis(); + print_blocks('i'); + pass_convert_nonlocal_phis(); + print_blocks('j'); pass_remove_dead_phis(); + print_blocks('k'); pass_infer_types(); - print_blocks('6'); - + print_blocks('l'); pass_instruction_selector(); - print_hops('7'); - pass_find_phi_congruence_groups(); - pass_live_vreg_analysis(); - print_hops('8'); + print_hops('m'); + pass_live_value_analysis(); + print_hops('n'); + pass_assign_vregs(); + print_hops('o'); + pass_convert_copies_to_moves(); + print_hops('p'); + pass_collapse_adjacent_moves(); + print_hops('q'); + pass_prune_stray_moves(); + print_hops('r'); + pass_calculate_vreg_spillibility(); + print_hops('s'); pass_register_allocator(); + print_hops('t'); +#if 0 pass_add_prologue_epilogue(); print_hops('9'); +#endif emit_procedure(proc); diff --cc mach/proto/mcg/reg.h index d7e2924a9,b3f231494..109a6aae5 --- a/mach/proto/mcg/reg.h +++ b/mach/proto/mcg/reg.h @@@ -15,17 -24,18 +15,18 @@@ struct hre struct vreg { - int id; - uint32_t type; - struct phicongruence* congruence; - struct hop* defined; - ARRAYOF(struct hop) used; + int id; + struct value* value; + struct vreg* coalesced_with; + int hreg; + int neighbours; + bool needs_register; + bool is_spilt; + const struct burm_regclass_data* regclass; + burm_register_bitmap_t registers; + struct hreg* evicted; /* stack slot to evict to */ }; -typedef PMAPOF(struct hreg, struct vreg) register_assignment_t; - -extern struct vreg* new_vreg(void); - extern struct hreg* new_hreg(const struct burm_register_data* brd); extern struct hreg* new_stacked_hreg(uint32_t type); diff --cc mach/proto/mcg/treebuilder.c index d9ded4cb8,c1b5c7eb6..0e9c9a879 --- a/mach/proto/mcg/treebuilder.c +++ b/mach/proto/mcg/treebuilder.c @@@ -5,6 -5,12 +5,12 @@@ static struct basicblock* current_bb static int stackptr; static struct ir* stack[64]; + struct jumptable + { ++ struct hashtable targets; + struct basicblock* defaulttarget; - IMAPOF(struct basicblock) targets; + }; + static struct ir* convert(struct ir* src, int srcsize, int destsize, int opcode); static struct ir* appendir(struct ir* ir); static void insn_ivalue(int opcode, arith value); @@@ -1332,25 -1328,34 +1328,36 @@@ static void insn_ivalue(int opcode, ari } case op_csa: + { + struct ir* descriptor = pop(EM_pointersize); + struct ir* targetvalue = appendir(pop(EM_pointersize)); - struct jumptable jumptable = {}; ++ struct jumptable jumptable = { HASHTABLE_OF_INTS }; + int i; + + if (descriptor->opcode != IR_LABEL) + fatal("csa is only supported if it refers " + "directly to a descriptor block"); + + parse_csa(bb_get(descriptor->u.lvalue), &jumptable); + emit_jumptable(targetvalue, &jumptable); ++ hashtable_reset(&jumptable.targets); + break; + } + case op_csb: { - const char* helper = aprintf(".%s", - (opcode == op_csa) ? "csa" : "csb"); struct ir* descriptor = pop(EM_pointersize); + struct ir* targetvalue = appendir(pop(EM_pointersize)); - struct jumptable jumptable = {}; ++ struct jumptable jumptable = { HASHTABLE_OF_INTS }; + int i; if (descriptor->opcode != IR_LABEL) - fatal("csa/csb are only supported if they refer " + fatal("csb is only supported if it refers " "directly to a descriptor block"); - push(descriptor); - materialise_stack(); - appendir( - new_ir2( - IR_FARJUMP, 0, - new_labelir(helper), - extract_block_refs(bb_get(descriptor->u.lvalue)) - ) - ); + parse_csb(bb_get(descriptor->u.lvalue), &jumptable); + emit_jumptable(targetvalue, &jumptable); ++ hashtable_reset(&jumptable.targets); break; } @@@ -1757,4 -1760,133 +1762,133 @@@ void tb_procedure(void generate_tree(current_proc->blocks.item[i]); } + static void parse_csa(struct basicblock* data_bb, struct jumptable* table) + { + struct em* em; + int lowerbound; + int count; + int i; + + assert(data_bb->ems.count >= 3); + + /* Default target */ + + em = data_bb->ems.item[0]; + assert(em->opcode == op_bra); + assert(em->paramtype == PARAM_BVALUE); + table->defaulttarget = em->u.bvalue.left; + + /* Lower bound */ + + em = data_bb->ems.item[1]; + assert(em->opcode == op_loc); + assert(em->paramtype == PARAM_IVALUE); + lowerbound = em->u.ivalue; + + /* Count */ + + em = data_bb->ems.item[2]; + assert(em->opcode == op_loc); + assert(em->paramtype == PARAM_IVALUE); + count = em->u.ivalue + 1; /* value in descriptor is inclusive */ + assert(data_bb->ems.count >= (count + 3)); + + /* Now, each target in turn. */ + + for (i=0; iems.item[3 + i]; + assert(em->opcode == op_bra); + assert(em->paramtype == PARAM_BVALUE); + target = em->u.bvalue.left; + - imap_put(&table->targets, lowerbound+i, target); ++ hashtable_puti(&table->targets, lowerbound+i, target); + } + } + + static void parse_csb(struct basicblock* data_bb, struct jumptable* table) + { + struct em* em; + int count; + int i; + + assert(data_bb->ems.count >= 2); + + /* Default target */ + + em = data_bb->ems.item[0]; + assert(em->opcode == op_bra); + assert(em->paramtype == PARAM_BVALUE); + table->defaulttarget = em->u.bvalue.left; + + /* Number of targets */ + + em = data_bb->ems.item[1]; + assert(em->opcode == op_loc); + assert(em->paramtype == PARAM_IVALUE); + count = em->u.ivalue; + assert(data_bb->ems.count >= (count*2 + 2)); + + /* Now, each target in turn. */ + + for (i=0; iems.item[2 + i*2]; + assert(em->opcode == op_loc); + assert(em->paramtype == PARAM_IVALUE); + value = em->u.ivalue; + + em = data_bb->ems.item[3 + i*2]; + assert(em->opcode == op_bra); + assert(em->paramtype == PARAM_BVALUE); + target = em->u.bvalue.left; + - imap_put(&table->targets, value, target); ++ hashtable_puti(&table->targets, value, target); + } + } + + static void emit_jumptable(struct ir* targetvalue, struct jumptable* jumptable) + { - int i; ++ struct hashtable_iterator hit = {}; + + materialise_stack(); - for (i=0; itargets.count; i++) ++ while (hashtable_next(&jumptable->targets, &hit)) + { - int value = jumptable->targets.item[i].left; - struct basicblock* target = jumptable->targets.item[i].right; ++ int value = (int) hit.key; ++ struct basicblock* target = hit.value; + struct basicblock* nextblock = bb_get(NULL); + + array_append(¤t_proc->blocks, nextblock); + appendir( + new_ir2( + IR_CJUMPEQ, 0, + new_ir2( + IR_COMPARESI, EM_wordsize, + targetvalue, + new_wordir(value) + ), + new_ir2( + IR_PAIR, 0, + new_bbir(target), + new_bbir(nextblock) + ) + ) + ); + + current_bb = nextblock; + } + + appendir( + new_ir1( + IR_JUMP, 0, + new_bbir(jumptable->defaulttarget) + ) + ); + } + /* vim: set sw=4 ts=4 expandtab : */ diff --cc modules/src/data/hashtable.c index 1610347d0,000000000..8e6a5e388 mode 100644,000000..100644 --- a/modules/src/data/hashtable.c +++ b/modules/src/data/hashtable.c @@@ -1,289 -1,0 +1,313 @@@ +#include +#include +#include +#include +#include +#include "hashtable.h" + +struct hashnode +{ + struct hashnode* next; + void* key; + void* value; +}; + ++uint32_t standard_int_hash_function(void* key) ++{ ++ uint32_t x = (uint32_t) key; ++ x = ((x >> 16) ^ x) * 0x45d9f3b; ++ x = ((x >> 16) ^ x) * 0x45d9f3b; ++ x = (x >> 16) ^ x; ++ return x; ++} ++ ++bool standard_int_comparison_function(void* key1, void* key2) ++{ ++ return (key1 == key2); ++} ++ +uint32_t standard_pointer_hash_function(void* key) +{ + /* Basile-Starynkevitch pointer hash */ + uintptr_t ptr = (uintptr_t) key; + return (uint32_t) ((13 * ptr) ^ (ptr >> 15)); +} + +bool standard_pointer_comparison_function(void* key1, void* key2) +{ + return (key1 == key2); +} + +uint32_t standard_string_hash_function(void* key) +{ + char* s = key; + uint32_t hash = 0; + + while (*s) + { + hash = ((hash << 5) + hash) ^ *s; + s++; + } + + return hash; +} + +bool standard_string_comparison_function(void* key1, void* key2) +{ + return strcmp(key1, key2) == 0; +} + +static void lazy_init(struct hashtable* ht) +{ + if (!ht->num_buckets) + ht->num_buckets = 7; + + if (!ht->hashfunction) + ht->hashfunction = standard_pointer_hash_function; + + if (!ht->cmpfunction) + ht->cmpfunction = standard_pointer_comparison_function; + + if (!ht->allocfunction) + ht->allocfunction = calloc; + + if (!ht->freefunction) + ht->freefunction = free; + + if (!ht->buckets) + ht->buckets = ht->allocfunction(ht->num_buckets, sizeof(struct hashnode*)); +} + +void hashtable_empty(struct hashtable* ht) +{ + while (ht->size) + hashtable_pop(ht); +} + +void hashtable_reset(struct hashtable* ht) +{ + lazy_init(ht); + hashtable_empty(ht); + ht->freefunction(ht->buckets); + ht->buckets = NULL; +} + +void hashtable_rebucket(struct hashtable* ht, unsigned int num_buckets) +{ + struct hashnode** old_buckets = ht->buckets; + int old_num_buckets = ht->num_buckets; + int i; + + ht->num_buckets = num_buckets; + ht->buckets = ht->allocfunction(num_buckets, sizeof(struct hashnode*)); + + for (i=0; ihashfunction(hn->key) & (num_buckets-1); + + old_buckets[i] = hn->next; + hn->next = ht->buckets[hash]; + ht->buckets[hash] = hn; + } + } + + ht->freefunction(old_buckets); +} + +static struct hashnode** findnodep(struct hashtable* ht, void* key) +{ + uint32_t hash; + struct hashnode** hnp; + + lazy_init(ht); + hash = ht->hashfunction(key) & (ht->num_buckets-1); + hnp = &ht->buckets[hash]; + + for (;;) + { + void* k; + + if (!*hnp) + break; + k = (*hnp)->key; + if ((k == key) || ht->cmpfunction(k, key)) + break; + + hnp = &(*hnp)->next; + } + + return hnp; +} + +void* hashtable_put(struct hashtable* ht, void* key, void* value) +{ + void* oldvalue; + struct hashnode** hnp = findnodep(ht, key); + if (!*hnp) + { + if (ht->size == (ht->num_buckets*2)) + { + hashtable_rebucket(ht, ht->num_buckets*4); + return hashtable_put(ht, key, value); + } + + *hnp = ht->allocfunction(1, sizeof(struct hashnode)); + ht->size++; + } + + oldvalue = (*hnp)->value; + (*hnp)->key = key; + (*hnp)->value = value; + return oldvalue; +} + ++void* hashtable_puti(struct hashtable* ht, int key, void* value) ++{ ++ return hashtable_put(ht, (void*)key, value); ++} ++ +void* hashtable_get(struct hashtable* ht, void* key) +{ + if (ht) + { + struct hashnode** hnp = findnodep(ht, key); + if (*hnp) + return (*hnp)->value; + } + return NULL; +} + ++void* hashtable_geti(struct hashtable* ht, int key) ++{ ++ return hashtable_get(ht, (void*)key); ++} ++ +void* hashtable_remove(struct hashtable* ht, void* key) +{ + struct hashnode** hnp = findnodep(ht, key); + if (*hnp) + { + struct hashnode* hn = *hnp; + void* value = hn->value; + *hnp = hn->next; + ht->freefunction(hn); + ht->size--; + return value; + } + + return NULL; +} + +void* hashtable_pop(struct hashtable* ht) +{ + int i; + + if (!ht || (ht->size == 0)) + return NULL; + + lazy_init(ht); + for (i=0; inum_buckets; i++) + { + struct hashnode** hnp = &ht->buckets[i]; + if (*hnp) + { + struct hashnode* hn = *hnp; + void* value = hn->value; + *hnp = hn->next; + ht->freefunction(hn); + ht->size--; + return value; + } + } + + return NULL; +} + +void* hashtable_next(struct hashtable* ht, struct hashtable_iterator* it) +{ + if (!ht) + return NULL; + + lazy_init(ht); + + if (!it->running) + { + /* Find the first node and return it; the stored state in the iterator + * is invalid. */ + + while (it->bucket < ht->num_buckets) + { + it->node = ht->buckets[it->bucket]; + if (it->node) + goto found; + it->bucket++; + } + + /* hashtable is empty! */ + } + else + { + /* The iterator is running; the stored state in the iterator points at + * the current node, so find the next one. */ + + if (!it->advanced) + it->node = it->node->next; + if (it->node) + goto found; + + for (;;) + { + it->bucket++; + if (it->bucket == ht->num_buckets) + break; + + it->node = ht->buckets[it->bucket]; + if (it->node) + goto found; + } + + /* nothing left found! */ + } + + /* EOF: reset the iterator. */ + + it->running = false; + it->advanced = false; + it->key = it->value = NULL; + it->bucket = 0; + it->node = NULL; + return NULL; + +found: + it->running = true; + it->advanced = false; + it->key = it->node->key; + it->value = it->node->value; + return it->value; +} + +void hashtable_delete_current(struct hashtable* ht, struct hashtable_iterator* it) +{ + struct hashnode** hnp; + + assert(ht); + assert(it->running); + + hnp = findnodep(ht, it->node->key); + it->node = it->node->next; + ht->freefunction(*hnp); + ht->size--; + *hnp = it->node; + + it->advanced = true; +} + +void hashtable_copy_all(struct hashtable* src, struct hashtable* dest) +{ + struct hashtable_iterator hit = {}; + while (hashtable_next(src, &hit)) + hashtable_put(dest, hit.key, hit.value); +} diff --cc modules/src/data/hashtable.h index 1c5598fd2,000000000..32c046fe8 mode 100644,000000..100644 --- a/modules/src/data/hashtable.h +++ b/modules/src/data/hashtable.h @@@ -1,57 -1,0 +1,65 @@@ +#ifndef HASHTABLE_H +#define HASHTABLE_H + +/* A simple, autoresizing hash table. */ + +typedef uint32_t hashfunction_t(void* key); +typedef bool cmpfunction_t(void* key1, void* key2); +typedef void* allocfunction_t(size_t nmemb, size_t size); +typedef void freefunction_t(void* ptr); + ++extern uint32_t standard_int_hash_function(void* key); ++extern bool standard_int_comparison_function(void* key1, void* key2); ++ +extern uint32_t standard_pointer_hash_function(void* key); +extern bool standard_pointer_comparison_function(void* key1, void* key2); + +extern uint32_t standard_string_hash_function(void* key); +extern bool standard_string_comparison_function(void* key1, void* key2); + +struct hashtable +{ + hashfunction_t* hashfunction; + cmpfunction_t* cmpfunction; + allocfunction_t* allocfunction; + freefunction_t* freefunction; + unsigned int num_buckets; /* power of 2 */ + struct hashnode** buckets; + int size; +}; + ++#define HASHTABLE_OF_INTS \ ++ { standard_int_hash_function, standard_int_comparison_function } ++ +#define HASHTABLE_OF_STRINGS \ + { standard_string_hash_function, standard_string_comparison_function } + +struct hashtable_iterator +{ + /* Public */ + void* key; + void* value; + + /* Private */ + bool running; + bool advanced; + int bucket; + struct hashnode* node; +}; + +extern void hashtable_empty(struct hashtable* ht); +extern void hashtable_reset(struct hashtable* ht); +extern void hashtable_rebucket(struct hashtable* ht, unsigned int num_buckets); + +extern void* hashtable_put(struct hashtable* ht, void* key, void* data); ++extern void* hashtable_puti(struct hashtable* ht, int key, void* data); +extern void* hashtable_get(struct hashtable* ht, void* key); ++extern void* hashtable_geti(struct hashtable* ht, int key); +extern void* hashtable_remove(struct hashtable* ht, void* key); +extern void* hashtable_pop(struct hashtable* ht); +extern void* hashtable_next(struct hashtable* ht, struct hashtable_iterator* it); +extern void hashtable_delete_current(struct hashtable* ht, struct hashtable_iterator* it); + +extern void hashtable_copy_all(struct hashtable* src, struct hashtable* dest); + +#endif diff --cc util/mcgg/gram.y index 5a985f231,18b88aec5..d837943c0 --- a/util/mcgg/gram.y +++ b/util/mcgg/gram.y @@@ -37,8 -36,10 +37,9 @@@ extern int yylex(void) %term FRAGMENT %term NAMED %term NOTEQUALS + %term OPTIONS %term PATTERNS %term PREFERS -%term PRESERVED %term REGISTERS %term WHEN %term WITH diff --cc util/mcgg/iburg.c index d934645cb,cd5be61af..0706cdaeb --- a/util/mcgg/iburg.c +++ b/util/mcgg/iburg.c @@@ -13,10 -13,13 +13,13 @@@ #include "iburg.h" #include "ircodes.h" #include "astring.h" -#include "smap.h" -#include "mcgg.h" +#include "registers.h" +#include "bitmap.h" - static char rcsid[] = "$Id$"; + #define REGATTR_INT 0 + #define REGATTR_LONG 1 + #define REGATTR_FLOAT 2 + #define REGATTR_DOUBLE 3 int maxcost = SHRT_MAX / 2; diff --cc util/mcgg/scan.l index ae6cf6900,5e61f31f9..a5cad692a --- a/util/mcgg/scan.l +++ b/util/mcgg/scan.l @@@ -39,7 -40,8 +40,8 @@@ static int braces = 0 "DECLARATIONS" return DECLARATIONS; "PATTERNS" return PATTERNS; "REGISTERS" return REGISTERS; + "OPTIONS" return OPTIONS; -"aliases" return ALIASES; +"uses" return USES; "corrupted" return CORRUPTED; "cost" return COST; "emit" return EMIT;