From e4fec71f9c5d0911f6f9075cffcfb9eaad20962a Mon Sep 17 00:00:00 2001 From: David Given Date: Wed, 19 Oct 2016 23:29:05 +0200 Subject: [PATCH] Lots more opcodes; better eviction behaviour; better register moves. Lots more PowerPC stuff (some working). --- mach/powerpc/mcg/platform.c | 45 +++++++++++++++++++--- mach/powerpc/mcg/table | 34 +++++++++++++++- mach/proto/mcg/pass_instructionselection.c | 2 +- mach/proto/mcg/pass_prologueepilogue.c | 12 +++++- mach/proto/mcg/pass_registerallocator.c | 33 ++++++++++------ mach/proto/mcg/treebuilder.c | 30 ++++++++------- util/mcgg/ir.dat | 11 ++++++ 7 files changed, 131 insertions(+), 36 deletions(-) diff --git a/mach/powerpc/mcg/platform.c b/mach/powerpc/mcg/platform.c index 2e598335a..0feaf0da7 100644 --- a/mach/powerpc/mcg/platform.c +++ b/mach/powerpc/mcg/platform.c @@ -99,14 +99,47 @@ struct hop* platform_move(struct basicblock* bb, struct hreg* src, struct hreg* { struct hop* hop = new_hop(bb, NULL); - if ((src->type & burm_int_ATTR) && (dest->type & burm_int_ATTR)) - { - if (src->is_stacked) - hop_add_insel(hop, "lwz %H, %S(fp) ! %H", dest, src, src); - else if (dest->is_stacked) + if (!src->is_stacked && dest->is_stacked) + { + if (src->type & burm_int_ATTR) hop_add_insel(hop, "stw %H, %S(fp) ! %H", src, dest, dest); - else + else if (src->type & burm_float_ATTR) + hop_add_insel(hop, "stfs %H, %S(fp) ! %H", src, dest, dest); + else + assert(false); + } + else if (src->is_stacked && !dest->is_stacked) + { + if (src->type & burm_int_ATTR) + hop_add_insel(hop, "lwz %H, %S(fp) ! %H", dest, src, src); + else if (src->type & burm_float_ATTR) + hop_add_insel(hop, "lfs %H, %S(fp) ! %H", dest, src, src); + else + assert(false); + } + else if (!src->is_stacked && !dest->is_stacked) + { + if ((src->type & burm_int_ATTR) && (dest->type & burm_int_ATTR)) hop_add_insel(hop, "mr %H, %H", dest, src); + else if ((src->type & burm_float_ATTR) && (dest->type & burm_float_ATTR)) + hop_add_insel(hop, "fmr %H, %H", dest, src); + else + { + if (src->type & burm_int_ATTR) + hop_add_insel(hop, "stwu %H, -4(sp)", src); + else if (src->type & burm_float_ATTR) + hop_add_insel(hop, "stfsu %H, -4(sp)", src); + else + assert(false); + + if (dest->type & burm_int_ATTR) + hop_add_insel(hop, "lwz %H, 0(sp)", dest); + else if (dest->type & burm_float_ATTR) + hop_add_insel(hop, "lfs %H, 0(sp)", dest); + else + assert(false); + hop_add_insel(hop, "addi sp, sp, 4"); + } } else fatal("cannot generate move from %s to %s", src->name, dest->name); diff --git a/mach/powerpc/mcg/table b/mach/powerpc/mcg/table index 93bdb1929..3a1da6fd6 100644 --- a/mach/powerpc/mcg/table +++ b/mach/powerpc/mcg/table @@ -16,7 +16,7 @@ REGISTERS r6 "r6" bytes4! int! volatile; r5 "r5" bytes4! int! volatile; r4 "r4" bytes4! int! volatile; - r3 "r3" bytes4! int! ret volatile; + r3 "r3" bytes4! int! volatile ret; r31 "r31" bytes4! int!; r30 "r30" bytes4! int!; @@ -48,7 +48,7 @@ REGISTERS f6 "f6" bytes4! float! volatile; f5 "f5" bytes4! float! volatile; f4 "f4" bytes4! float! volatile; - f3 "f3" bytes4! float! volatile; + f3 "f3" bytes4! float! volatile fret; f2 "f2" bytes4! float! volatile; f1 "f1" bytes4! float! volatile; f0 "f0" bytes4! float! volatile; @@ -476,6 +476,10 @@ PATTERNS /* FPU operations */ + out:(float)reg = LOADF4(addr:address) + emit "lfs %out, %addr" + cost 4; + out:(float)reg = value:CONSTF4 emit "lfs %out, address-containing-$value" cost 8; @@ -488,6 +492,32 @@ PATTERNS emit "fsubs %out, %left, %right" cost 4; + out:(float)reg = MULF4(left:(float)reg, right:(float)reg) + emit "fmuls %out, %left, %right" + cost 4; + + out:(float)reg = NEGF4(left:(float)reg) + emit "fneg %out, %left" + cost 4; + + cr:(cr)cr = COMPAREF4(left:(float)reg, right:(float)reg) + emit "fcmpu %cr, %left, %right" + cost 4; + + cr:(cr)cr = COMPARES4(COMPAREF4(left:(float)reg, right:(float)reg), result:CONST4) + when specific_constant(%result, 0) + emit "fcmpu %cr, %left, %right" + cost 4; + + out:(ret)reg = CFI44(val:(fret)reg) + with corrupted(volatile) + emit "bl .cfi4" + cost 4; + + out:(fret)reg = CIF44(val:(ret)reg) + with corrupted(volatile) + emit "bl .cif4" + cost 4; /* vim: set sw=4 ts=4 expandtab : */ diff --git a/mach/proto/mcg/pass_instructionselection.c b/mach/proto/mcg/pass_instructionselection.c index 82d7f9875..fcfb55182 100644 --- a/mach/proto/mcg/pass_instructionselection.c +++ b/mach/proto/mcg/pass_instructionselection.c @@ -27,7 +27,7 @@ void burm_trace(struct burm_node* p, int ruleno, int cost, int bestcost) { void burm_panic_cannot_match(struct burm_node* node) { fprintf(stderr, "could not find any patterns to match:\n"); - ir_print(0, node->ir); + ir_print('!', node->ir); fprintf(stderr, "aborting!\n"); exit(1); } diff --git a/mach/proto/mcg/pass_prologueepilogue.c b/mach/proto/mcg/pass_prologueepilogue.c index 9a5762e8d..3b0c517cb 100644 --- a/mach/proto/mcg/pass_prologueepilogue.c +++ b/mach/proto/mcg/pass_prologueepilogue.c @@ -14,10 +14,18 @@ void pass_add_prologue_epilogue(void) struct hop* hop = bb->hops.item[j]; for (k=0; kregsin.count; k++) - array_appendu(¤t_proc->usedregs, hop->regsin.item[k].left); + { + struct hreg* hreg = hop->regsin.item[k].left; + if (!hreg->is_stacked) + array_appendu(¤t_proc->usedregs, hreg); + } for (k=0; kregsout.count; k++) - array_appendu(¤t_proc->usedregs, hop->regsout.item[k].left); + { + struct hreg* hreg = hop->regsout.item[k].left; + if (!hreg->is_stacked) + array_appendu(¤t_proc->usedregs, hreg); + } } } diff --git a/mach/proto/mcg/pass_registerallocator.c b/mach/proto/mcg/pass_registerallocator.c index 393395e37..93a9b1dad 100644 --- a/mach/proto/mcg/pass_registerallocator.c +++ b/mach/proto/mcg/pass_registerallocator.c @@ -16,6 +16,8 @@ static register_assignment_t* current_outs; static int insert_moves(struct basicblock* bb, int index, register_assignment_t* srcregs, register_assignment_t* destregs); +static bool type_match(struct hreg* hreg, struct vreg* vreg); + static void populate_hregs(void) { const struct burm_register_data* brd = burm_register_data; @@ -65,9 +67,7 @@ static struct hreg* allocate_phi_hreg(register_assignment_t* regs, static bool evictable(struct hreg* hreg, struct vreg* vreg) { - struct constraint* c = pmap_findleft(¤t_hop->constraints, vreg); - return (hreg->attrs & c->attrs) && !array_contains(¤t_hop->ins, vreg); - /* Find an unused output register of the right class which is not also being used as an input register. */ + return type_match(hreg, vreg) && !array_contains(¤t_hop->ins, vreg); } static struct hreg* evict(struct vreg* vreg) @@ -81,17 +81,26 @@ static struct hreg* evict(struct vreg* vreg) for (i=0; iid, hreg->name); - pmap_put(&evicted, candidate, hreg); - pmap_remove(current_ins, hreg, candidate); - pmap_remove(current_outs, hreg, candidate); - return hreg; + if (!candidatein && !candidateout) + { + /* This hreg is unused, so we don't need to evict anything. + * Shouldn't really happen in real life. */ + return hreg; + } + if (candidatein == candidateout) + { + /* This is a through register. */ + tracef('R', "R: evicting %%%d from %s\n", candidatein->id, hreg->name); + pmap_put(&evicted, candidatein, hreg); + pmap_remove(current_ins, hreg, candidatein); + pmap_remove(current_outs, hreg, candidatein); + return hreg; + } } } diff --git a/mach/proto/mcg/treebuilder.c b/mach/proto/mcg/treebuilder.c index 9fbae16d1..8684f1fd5 100644 --- a/mach/proto/mcg/treebuilder.c +++ b/mach/proto/mcg/treebuilder.c @@ -197,6 +197,8 @@ static void insn_simple(int opcode) case op_cii: simple_convert(IR_CII1); break; case op_ciu: simple_convert(IR_CIU1); break; case op_cui: simple_convert(IR_CUI1); break; + case op_cfi: simple_convert(IR_CFI1); break; + case op_cif: simple_convert(IR_CIF1); break; case op_cmp: push( @@ -460,6 +462,11 @@ static void insn_ivalue(int opcode, arith value) case op_dvf: simple_alu2(opcode, value, IR_DIVF); break; case op_ngf: simple_alu1(opcode, value, IR_NEGF); break; + case op_cmu: /* fall through */ + case op_cms: push(tristate_compare(value, IR_COMPAREU)); break; + case op_cmi: push(tristate_compare(value, IR_COMPARES)); break; + case op_cmf: push(tristate_compare(value, IR_COMPAREF)); break; + case op_lol: push( new_ir1( @@ -469,6 +476,15 @@ static void insn_ivalue(int opcode, arith value) ); break; + case op_ldl: + push( + new_ir1( + IR_LOAD, EM_wordsize*2, + new_localir(value) + ) + ); + break; + case op_stl: appendir( new_ir2( @@ -634,19 +650,6 @@ static void insn_ivalue(int opcode, arith value) break; } - case op_cmi: - push( - tristate_compare(value, IR_COMPARES) - ); - break; - - case op_cmu: - case op_cms: - push( - tristate_compare(value, IR_COMPAREU) - ); - break; - case op_ads: { struct ir* off = pop(value); @@ -953,6 +956,7 @@ static void insn_lvalue(int opcode, const char* label, arith offset) { switch (opcode) { + case op_lpi: case op_lae: push( address_of_external(label, offset) diff --git a/util/mcgg/ir.dat b/util/mcgg/ir.dat index 44e28e9f8..6f40ae3c0 100644 --- a/util/mcgg/ir.dat +++ b/util/mcgg/ir.dat @@ -63,9 +63,20 @@ S CUI2 S CUI4 S CUI8 +S CFI1 +S CFI2 +S CFI4 +S CFI8 + +S CIF1 +S CIF2 +S CIF4 +S CIF8 + # Tristate comparisons S COMPARES S COMPAREU +S COMPAREF # Boolean comparisons S IFEQ