Merge pull request #132 from davidgiven/dtrg-mips
Teach mcg how to merge pushes
This commit is contained in:
commit
c6a1cf8de4
12 changed files with 312 additions and 88 deletions
|
@ -144,9 +144,8 @@ struct hop* platform_epilogue(void)
|
||||||
hop_add_insel(hop, "lw ra, 4(fp)");
|
hop_add_insel(hop, "lw ra, 4(fp)");
|
||||||
hop_add_insel(hop, "lw at, 0(fp)"); /* load old 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, "addiu sp, fp, %d", current_proc->fp_to_ab);
|
||||||
hop_add_insel(hop, "mov fp, at");
|
|
||||||
hop_add_insel(hop, "jr ra");
|
hop_add_insel(hop, "jr ra");
|
||||||
hop_add_insel(hop, "nop");
|
hop_add_insel(hop, "mov fp, at"); /* delay slot */
|
||||||
|
|
||||||
return hop;
|
return hop;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,7 @@
|
||||||
|
OPTIONS
|
||||||
|
|
||||||
|
LOWER_PUSHES_TO_LOADS_AND_STORES;
|
||||||
|
|
||||||
REGISTERS
|
REGISTERS
|
||||||
|
|
||||||
/* Registers are allocated top down. The odd order below is to make sure
|
/* Registers are allocated top down. The odd order below is to make sure
|
||||||
|
@ -35,7 +39,7 @@ REGISTERS
|
||||||
r22 named("r22") int;
|
r22 named("r22") int;
|
||||||
r23 named("r23") int;
|
r23 named("r23") int;
|
||||||
|
|
||||||
r4r5 named("r4", "r5") aliases(r4, r5) long volatilei lret1;
|
r4r5 named("r4", "r5") aliases(r4, r5) long volatile lret1;
|
||||||
r6r7 named("r6", "r7") aliases(r6, r7) long volatile;
|
r6r7 named("r6", "r7") aliases(r6, r7) long volatile;
|
||||||
r8r9 named("r8", "r9") aliases(r8, r9) long volatile;
|
r8r9 named("r8", "r9") aliases(r8, r9) long volatile;
|
||||||
r10r11 named("r10", "r11") aliases(r10, r11) long volatile;
|
r10r11 named("r10", "r11") aliases(r10, r11) long volatile;
|
||||||
|
@ -108,6 +112,9 @@ DECLARATIONS
|
||||||
ushort0; /* bottom 16 bits valid, the rest 0 */
|
ushort0; /* bottom 16 bits valid, the rest 0 */
|
||||||
|
|
||||||
address fragment;
|
address fragment;
|
||||||
|
intregorzero fragment;
|
||||||
|
byteregorzero fragment;
|
||||||
|
shortregorzero fragment;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -121,27 +128,6 @@ PATTERNS
|
||||||
|
|
||||||
/* Miscellaneous special things */
|
/* Miscellaneous special things */
|
||||||
|
|
||||||
PUSH.I(in:(int)reg)
|
|
||||||
emit "addiu sp, sp, -4"
|
|
||||||
emit "sw %in, 0(sp)"
|
|
||||||
cost 8;
|
|
||||||
|
|
||||||
PUSH.L(in:(long)reg)
|
|
||||||
emit "addiu sp, sp, -8"
|
|
||||||
emit "sw %in.0, 0(sp)"
|
|
||||||
emit "sw %in.1, 4(sp)"
|
|
||||||
cost 12;
|
|
||||||
|
|
||||||
PUSH.F(in:(float)reg)
|
|
||||||
emit "addiu sp, sp, -4"
|
|
||||||
emit "swc1 %in, 0(sp)"
|
|
||||||
cost 8;
|
|
||||||
|
|
||||||
PUSH.D(in:(double)reg)
|
|
||||||
emit "addiu sp, sp, -8"
|
|
||||||
emit "sdc1 %in, 0(sp)"
|
|
||||||
cost 8;
|
|
||||||
|
|
||||||
out:(int)reg = POP.I
|
out:(int)reg = POP.I
|
||||||
emit "lw %out, 0(sp)"
|
emit "lw %out, 0(sp)"
|
||||||
emit "addiu sp, sp, 4"
|
emit "addiu sp, sp, 4"
|
||||||
|
@ -184,11 +170,11 @@ PATTERNS
|
||||||
emit "addiu sp, sp, $delta"
|
emit "addiu sp, sp, $delta"
|
||||||
cost 4;
|
cost 4;
|
||||||
|
|
||||||
STACKADJUST.I(in:(int)reg)
|
STACKADJUST.I(in:intregorzero)
|
||||||
emit "addu sp, sp, %in"
|
emit "addu sp, sp, %in"
|
||||||
cost 4;
|
cost 4;
|
||||||
|
|
||||||
STACKADJUST.I(NEG.I(in:(int)reg))
|
STACKADJUST.I(NEG.I(in:intregorzero))
|
||||||
emit "subu sp, sp, %in"
|
emit "subu sp, sp, %in"
|
||||||
cost 4;
|
cost 4;
|
||||||
|
|
||||||
|
@ -241,29 +227,29 @@ PATTERNS
|
||||||
emit "sw %value.1, 4+%addr"
|
emit "sw %value.1, 4+%addr"
|
||||||
cost 8;
|
cost 8;
|
||||||
|
|
||||||
STORE.I(addr:address, value:(int)reg)
|
STORE.I(addr:address, value:intregorzero)
|
||||||
emit "sw %value, %addr"
|
emit "sw %value, %addr"
|
||||||
cost 4;
|
cost 4;
|
||||||
|
|
||||||
STORE.I(label:LABEL.I, value:(int)reg)
|
STORE.I(label:LABEL.I, value:intregorzero)
|
||||||
emit "lui at, ha16[$label]"
|
emit "lui at, ha16[$label]"
|
||||||
emit "sw %value, lo16[$label] (at)"
|
emit "sw %value, lo16[$label] (at)"
|
||||||
cost 8;
|
cost 8;
|
||||||
|
|
||||||
STOREH.I(addr:address, value:(int)ushortX)
|
STOREH.I(addr:address, value:shortregorzero)
|
||||||
emit "sh %value, %addr"
|
emit "sh %value, %addr"
|
||||||
cost 4;
|
cost 4;
|
||||||
|
|
||||||
STOREH.I(label:LABEL.I, value:(int)reg)
|
STOREH.I(label:LABEL.I, value:shortregorzero)
|
||||||
emit "lui at, ha16[$label]"
|
emit "lui at, ha16[$label]"
|
||||||
emit "sh %value, lo16[$label] (at)"
|
emit "sh %value, lo16[$label] (at)"
|
||||||
cost 8;
|
cost 8;
|
||||||
|
|
||||||
STOREB.I(addr:address, value:(int)ubyteX)
|
STOREB.I(addr:address, value:byteregorzero)
|
||||||
emit "sb %value, %addr"
|
emit "sb %value, %addr"
|
||||||
cost 4;
|
cost 4;
|
||||||
|
|
||||||
STOREB.I(label:LABEL.I, value:(int)reg)
|
STOREB.I(label:LABEL.I, value:byteregorzero)
|
||||||
emit "lui at, ha16[$label]"
|
emit "lui at, ha16[$label]"
|
||||||
emit "sb %value, lo16[$label] (at)"
|
emit "sb %value, lo16[$label] (at)"
|
||||||
cost 8;
|
cost 8;
|
||||||
|
@ -272,7 +258,7 @@ PATTERNS
|
||||||
emit "swc1 %value, %addr"
|
emit "swc1 %value, %addr"
|
||||||
cost 4;
|
cost 4;
|
||||||
|
|
||||||
STORE.F(label:LABEL.I, value:(int)reg)
|
STORE.F(label:LABEL.I, value:(float)reg)
|
||||||
emit "lui at, ha16[$label]"
|
emit "lui at, ha16[$label]"
|
||||||
emit "swc1 %value, lo16[$label] (at)"
|
emit "swc1 %value, lo16[$label] (at)"
|
||||||
cost 8;
|
cost 8;
|
||||||
|
@ -281,7 +267,7 @@ PATTERNS
|
||||||
emit "sdc1 %value, %addr"
|
emit "sdc1 %value, %addr"
|
||||||
cost 4;
|
cost 4;
|
||||||
|
|
||||||
STORE.D(label:LABEL.I, value:(int)reg)
|
STORE.D(label:LABEL.I, value:(double)reg)
|
||||||
emit "lui at, ha16[$label]"
|
emit "lui at, ha16[$label]"
|
||||||
emit "sdc1 %value, lo16[$label] (at)"
|
emit "sdc1 %value, lo16[$label] (at)"
|
||||||
cost 8;
|
cost 8;
|
||||||
|
@ -406,11 +392,11 @@ PATTERNS
|
||||||
|
|
||||||
/* Extensions and conversions */
|
/* Extensions and conversions */
|
||||||
|
|
||||||
out:(int)reg = EXTENDB.I(in:(int)reg)
|
out:(int)reg = EXTENDB.I(in:intregorzero)
|
||||||
emit "seb %out, %in"
|
emit "seb %out, %in"
|
||||||
cost 4;
|
cost 4;
|
||||||
|
|
||||||
out:(int)reg = EXTENDH.I(in:(int)reg)
|
out:(int)reg = EXTENDH.I(in:intregorzero)
|
||||||
emit "seh %out, %in"
|
emit "seh %out, %in"
|
||||||
cost 4;
|
cost 4;
|
||||||
|
|
||||||
|
@ -448,9 +434,45 @@ PATTERNS
|
||||||
emit "mov %out, %in.1"
|
emit "mov %out, %in.1"
|
||||||
cost 4;
|
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 */
|
|
||||||
|
/* Locals and stack-relatives */
|
||||||
|
|
||||||
out:(int)reg = in:LOCAL.I
|
out:(int)reg = in:LOCAL.I
|
||||||
emit "addiu %out, fp, $in"
|
emit "addiu %out, fp, $in"
|
||||||
|
@ -459,6 +481,10 @@ PATTERNS
|
||||||
address = in:LOCAL.I
|
address = in:LOCAL.I
|
||||||
emit "$in(fp)";
|
emit "$in(fp)";
|
||||||
|
|
||||||
|
address = ADD.I(GETSP.I, offset:CONST.I)
|
||||||
|
when signed_constant(%offset, 16)
|
||||||
|
emit "$offset(sp)";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Memory addressing modes */
|
/* Memory addressing modes */
|
||||||
|
@ -734,17 +760,17 @@ PATTERNS
|
||||||
/* Booleans */
|
/* Booleans */
|
||||||
|
|
||||||
/* If 0 then 1, else 0 */
|
/* If 0 then 1, else 0 */
|
||||||
out:(int)reg = IFEQ.I(in:(int)reg)
|
out:(int)reg = IFEQ.I(in:intregorzero)
|
||||||
emit "sltiu %out, %in, 1"
|
emit "sltiu %out, %in, 1"
|
||||||
cost 4;
|
cost 4;
|
||||||
|
|
||||||
/* If -1 then 1, else 0 */
|
/* If -1 then 1, else 0 */
|
||||||
out:(int)reg = IFLT.I(in:(int)reg)
|
out:(int)reg = IFLT.I(in:intregorzero)
|
||||||
emit "srl %out, %in, 31"
|
emit "srl %out, %in, 31"
|
||||||
cost 4;
|
cost 4;
|
||||||
|
|
||||||
/* If 1 or 0 then 1, else 0 */
|
/* If 1 or 0 then 1, else 0 */
|
||||||
out:(int)reg = IFLE.I(in:(int)reg)
|
out:(int)reg = IFLE.I(in:intregorzero)
|
||||||
emit "slti %out, %in, 1"
|
emit "slti %out, %in, 1"
|
||||||
cost 4;
|
cost 4;
|
||||||
|
|
||||||
|
@ -768,20 +794,20 @@ PATTERNS
|
||||||
|
|
||||||
/* reg + reg */
|
/* reg + reg */
|
||||||
#define ALUR(name, instr) \
|
#define ALUR(name, instr) \
|
||||||
out:(int)reg = name(left:(int)reg, right:(int)reg) \
|
out:(int)reg = name(left:intregorzero, right:intregorzero) \
|
||||||
emit instr " %out, %left, %right" \
|
emit instr " %out, %left, %right" \
|
||||||
cost 4; \
|
cost 4; \
|
||||||
|
|
||||||
/* reg + const */
|
/* reg + const */
|
||||||
#define ALUC(name, instr) \
|
#define ALUC(name, instr) \
|
||||||
out:(int)reg = name(left:(int)reg, right:CONST.I) \
|
out:(int)reg = name(left:intregorzero, right:CONST.I) \
|
||||||
when signed_constant(%right, 16) \
|
when signed_constant(%right, 16) \
|
||||||
emit instr " %out, %left, $right" \
|
emit instr " %out, %left, $right" \
|
||||||
cost 4; \
|
cost 4; \
|
||||||
|
|
||||||
/* const + reg */
|
/* const + reg */
|
||||||
#define ALUC_reversed(name, instr) \
|
#define ALUC_reversed(name, instr) \
|
||||||
out:(int)reg = name(left:CONST.I, right:(int)reg) \
|
out:(int)reg = name(left:CONST.I, right:intregorzero) \
|
||||||
when signed_constant(%left, 16) \
|
when signed_constant(%left, 16) \
|
||||||
emit instr " %out, %right, $left" \
|
emit instr " %out, %right, $left" \
|
||||||
cost 4; \
|
cost 4; \
|
||||||
|
@ -794,30 +820,30 @@ PATTERNS
|
||||||
ALUR(ADD.I, "addu")
|
ALUR(ADD.I, "addu")
|
||||||
ALUCC(ADD.I, "addiu")
|
ALUCC(ADD.I, "addiu")
|
||||||
|
|
||||||
out:(int)reg = SUB.I(left:(int)reg, right:(int)reg)
|
out:(int)reg = SUB.I(left:intregorzero, right:intregorzero)
|
||||||
emit "subu %out, %left, %right"
|
emit "subu %out, %left, %right"
|
||||||
cost 4;
|
cost 4;
|
||||||
|
|
||||||
out:(int)reg = SUB.I(left:(int)reg, right:CONST.I)
|
out:(int)reg = SUB.I(left:intregorzero, right:CONST.I)
|
||||||
emit "addiu %out, %left, -[$right]"
|
emit "addiu %out, %left, -[$right]"
|
||||||
cost 4;
|
cost 4;
|
||||||
|
|
||||||
out:(int)reg = DIV.I(left:(int)reg, right:(int)reg)
|
out:(int)reg = DIV.I(left:intregorzero, right:intregorzero)
|
||||||
emit "div %left, %right"
|
emit "div %left, %right"
|
||||||
emit "mflo %out"
|
emit "mflo %out"
|
||||||
cost 8;
|
cost 8;
|
||||||
|
|
||||||
out:(int)reg = DIVU.I(left:(int)reg, right:(int)reg)
|
out:(int)reg = DIVU.I(left:intregorzero, right:intregorzero)
|
||||||
emit "divu %left, %right"
|
emit "divu %left, %right"
|
||||||
emit "mflo %out"
|
emit "mflo %out"
|
||||||
cost 8;
|
cost 8;
|
||||||
|
|
||||||
out:(int)reg = MOD.I(left:(int)reg, right:(int)reg)
|
out:(int)reg = MOD.I(left:intregorzero, right:intregorzero)
|
||||||
emit "div %left, %right"
|
emit "div %left, %right"
|
||||||
emit "mfhi %out"
|
emit "mfhi %out"
|
||||||
cost 8;
|
cost 8;
|
||||||
|
|
||||||
out:(int)reg = MODU.I(left:(int)reg, right:(int)reg)
|
out:(int)reg = MODU.I(left:intregorzero, right:intregorzero)
|
||||||
emit "divu %left, %right"
|
emit "divu %left, %right"
|
||||||
emit "mfhi %out"
|
emit "mfhi %out"
|
||||||
cost 8;
|
cost 8;
|
||||||
|
@ -834,11 +860,11 @@ PATTERNS
|
||||||
ALUR(LSR.I, "srlv")
|
ALUR(LSR.I, "srlv")
|
||||||
ALUC(LSR.I, "srl")
|
ALUC(LSR.I, "srl")
|
||||||
|
|
||||||
out:(int)reg = NEG.I(left:(int)reg)
|
out:(int)reg = NEG.I(left:intregorzero)
|
||||||
emit "subu %out, zero, %left"
|
emit "subu %out, zero, %left"
|
||||||
cost 4;
|
cost 4;
|
||||||
|
|
||||||
out:(int)reg = NOT.I(in:(int)reg)
|
out:(int)reg = NOT.I(in:intregorzero)
|
||||||
emit "nor %out, %in, %in"
|
emit "nor %out, %in, %in"
|
||||||
cost 4;
|
cost 4;
|
||||||
|
|
||||||
|
@ -949,7 +975,7 @@ PATTERNS
|
||||||
emit "neg.s %out, %left"
|
emit "neg.s %out, %left"
|
||||||
cost 4;
|
cost 4;
|
||||||
|
|
||||||
out:(float)reg = FROMSI.F(in:(int)reg)
|
out:(float)reg = FROMSI.F(in:intregorzero)
|
||||||
emit "mtc1 %in, %out" /* mtc1 has reversed parameters */
|
emit "mtc1 %in, %out" /* mtc1 has reversed parameters */
|
||||||
emit "cvt.s.w %out, %out"
|
emit "cvt.s.w %out, %out"
|
||||||
cost 4;
|
cost 4;
|
||||||
|
@ -975,7 +1001,7 @@ PATTERNS
|
||||||
emit "nop"
|
emit "nop"
|
||||||
cost 30;
|
cost 30;
|
||||||
|
|
||||||
out:(float)reg = COPYI.F(in:(int)reg)
|
out:(float)reg = COPYI.F(in:intregorzero)
|
||||||
emit "mtc1 %in, %out" /* mtc1 has reversed parameters */
|
emit "mtc1 %in, %out" /* mtc1 has reversed parameters */
|
||||||
cost 4;
|
cost 4;
|
||||||
|
|
||||||
|
|
|
@ -112,6 +112,7 @@ extern void pass_infer_types(void);
|
||||||
extern void pass_insert_moves(void);
|
extern void pass_insert_moves(void);
|
||||||
extern void pass_instruction_selector(void);
|
extern void pass_instruction_selector(void);
|
||||||
extern void pass_live_vreg_analysis(void);
|
extern void pass_live_vreg_analysis(void);
|
||||||
|
extern void pass_lower_pushes(void);
|
||||||
extern void pass_add_prologue_epilogue(void);
|
extern void pass_add_prologue_epilogue(void);
|
||||||
extern void pass_register_allocator(void);
|
extern void pass_register_allocator(void);
|
||||||
extern void pass_remove_dead_blocks(void);
|
extern void pass_remove_dead_blocks(void);
|
||||||
|
|
|
@ -105,7 +105,9 @@ static void constrain_input_reg_preserved(int child)
|
||||||
struct vreg* vreg = find_vreg_of_child(child);
|
struct vreg* vreg = find_vreg_of_child(child);
|
||||||
struct constraint* c;
|
struct constraint* c;
|
||||||
|
|
||||||
assert(vreg);
|
if (!vreg)
|
||||||
|
fatal("child %d of instruction is not a register and cannot be constrained", child);
|
||||||
|
|
||||||
array_appendu(¤t_hop->throughs, vreg);
|
array_appendu(¤t_hop->throughs, vreg);
|
||||||
get_constraint(vreg)->preserved = true;
|
get_constraint(vreg)->preserved = true;
|
||||||
}
|
}
|
||||||
|
|
140
mach/proto/mcg/pass_lowerpushes.c
Normal file
140
mach/proto/mcg/pass_lowerpushes.c
Normal file
|
@ -0,0 +1,140 @@
|
||||||
|
#include "mcg.h"
|
||||||
|
|
||||||
|
#if defined MCGG_OPTION_LOWER_PUSHES_TO_LOADS_AND_STORES
|
||||||
|
|
||||||
|
/* On architectures which can't push and pop cheaply, a push typically
|
||||||
|
*
|
||||||
|
* sub sp, sp, -4
|
||||||
|
* sw r5, 0(sp)
|
||||||
|
*
|
||||||
|
* This is hugely wasteful when you want to push or multiple things
|
||||||
|
* at once, which happens a lot because that's how the procedure calling
|
||||||
|
* convention works. This code detects these runs and turns them into a
|
||||||
|
* single stack adjustment and then offsetted accesses via the stack
|
||||||
|
* pointer. In order to be efficient, the table needs to know how to
|
||||||
|
* handle this efficiently:
|
||||||
|
*
|
||||||
|
* STACKADJUST(CONST(-4))
|
||||||
|
* STORE.I(ADD.I(GETSP(), CONST(0)))
|
||||||
|
*
|
||||||
|
* ...otherwise the code will be *even worse*.
|
||||||
|
*
|
||||||
|
* We have to be careful, though, because after we do the adjustment,
|
||||||
|
* the physical stack pointer won't match em's idea of the stack pointer
|
||||||
|
* until the last 'push' happens. So we need to check that this is never
|
||||||
|
* used.
|
||||||
|
*
|
||||||
|
* With this option set, PUSH will never be seen by the instruction
|
||||||
|
* selector.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static struct basicblock* current_bb;
|
||||||
|
static int cursor;
|
||||||
|
|
||||||
|
static bool accesses_stack_pointer_cb(struct ir* ir, void* user)
|
||||||
|
{
|
||||||
|
switch (ir->opcode)
|
||||||
|
{
|
||||||
|
case IR_SETSP:
|
||||||
|
case IR_GETSP:
|
||||||
|
case IR_CALL:
|
||||||
|
case IR_STACKADJUST:
|
||||||
|
return true;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool accesses_stack_pointer(struct ir* ir)
|
||||||
|
{
|
||||||
|
return !!ir_walk(ir, accesses_stack_pointer_cb, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void consider_push(struct ir* ir)
|
||||||
|
{
|
||||||
|
int runstart;
|
||||||
|
int delta;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (ir->opcode != IR_PUSH)
|
||||||
|
{
|
||||||
|
cursor++;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This is the first push of a run; we'll want to insert the STACKADJUST
|
||||||
|
* before this one. */
|
||||||
|
|
||||||
|
tracef('P', "found push in %s at IR index %d\n", current_bb->name, cursor);
|
||||||
|
runstart = cursor;
|
||||||
|
|
||||||
|
/* Now start walking forward until we find an IR which isn't a safe push.
|
||||||
|
* The current IR is always safe. */
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
struct ir* ir;
|
||||||
|
|
||||||
|
cursor++;
|
||||||
|
if (cursor == current_bb->irs.count)
|
||||||
|
break;
|
||||||
|
|
||||||
|
ir = current_bb->irs.item[cursor];
|
||||||
|
if (ir->opcode != IR_PUSH)
|
||||||
|
break;
|
||||||
|
if (accesses_stack_pointer(ir))
|
||||||
|
break;
|
||||||
|
|
||||||
|
delta += ir->size;
|
||||||
|
}
|
||||||
|
|
||||||
|
tracef('P', "found end of run at IR index %d\n", cursor);
|
||||||
|
|
||||||
|
/* Now work backwards, converting each push into a stack write. */
|
||||||
|
|
||||||
|
delta = 0;
|
||||||
|
i = cursor - 1;
|
||||||
|
while (i >= runstart)
|
||||||
|
{
|
||||||
|
struct ir* ir = current_bb->irs.item[i];
|
||||||
|
struct ir* value_ir = ir->left;
|
||||||
|
assert(ir->opcode == IR_PUSH);
|
||||||
|
|
||||||
|
ir->opcode = IR_STORE;
|
||||||
|
ir->left = new_ir2(
|
||||||
|
IR_ADD, EM_pointersize,
|
||||||
|
new_ir0(IR_GETSP, EM_pointersize),
|
||||||
|
new_wordir(delta)
|
||||||
|
);
|
||||||
|
ir->left->root = ir->left->left->root = ir->left->right->root = ir->root;
|
||||||
|
ir->right = value_ir;
|
||||||
|
|
||||||
|
delta += ir->size;
|
||||||
|
i--;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* And finally, before the place where the first push was, adjust the
|
||||||
|
* stack. */
|
||||||
|
|
||||||
|
ir = new_ir1(IR_STACKADJUST, EM_pointersize, new_wordir(-delta));
|
||||||
|
ir->left->root = ir->root = ir;
|
||||||
|
array_insert(¤t_bb->irs, ir, runstart);
|
||||||
|
cursor++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pass_lower_pushes(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i=0; i<current_proc->blocks.count; i++)
|
||||||
|
{
|
||||||
|
current_bb = current_proc->blocks.item[i];
|
||||||
|
|
||||||
|
cursor = 0;
|
||||||
|
while (cursor < current_bb->irs.count)
|
||||||
|
consider_push(current_bb->irs.item[cursor]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -18,6 +18,8 @@ static int insert_moves(struct basicblock* bb, int index,
|
||||||
|
|
||||||
static bool type_match(struct hreg* hreg, struct vreg* vreg);
|
static bool type_match(struct hreg* hreg, struct vreg* vreg);
|
||||||
|
|
||||||
|
static bool constraints_match(struct hreg* hreg, struct vreg* vreg);
|
||||||
|
|
||||||
static void populate_hregs(void)
|
static void populate_hregs(void)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
@ -102,33 +104,47 @@ static struct hreg* evict(struct vreg* vreg)
|
||||||
* doing some calculation here to figure out the cheapest register to
|
* doing some calculation here to figure out the cheapest register to
|
||||||
* evict, but for now we're picking the first one. FIXME. */
|
* evict, but for now we're picking the first one. FIXME. */
|
||||||
|
|
||||||
|
tracef('R', "R: considering evicting a register to rehome %%%d\n", vreg->id);
|
||||||
for (i=0; i<hregs.count; i++)
|
for (i=0; i<hregs.count; i++)
|
||||||
{
|
{
|
||||||
struct hreg* hreg = hregs.item[i];
|
struct hreg* hreg = hregs.item[i];
|
||||||
struct vreg* candidatein = pmap_findleft(current_ins, hreg);
|
if ((hreg->attrs & vreg->type) && constraints_match(hreg, vreg))
|
||||||
struct vreg* candidateout = pmap_findleft(current_outs, hreg);
|
|
||||||
|
|
||||||
if (hreg->attrs & vreg->type)
|
|
||||||
{
|
{
|
||||||
if (!candidatein &&
|
/* Our vreg can be stored in this hreg. But it's only safe to
|
||||||
!candidateout &&
|
* evict the hreg if we can also evict all the hreg's aliases. */
|
||||||
!register_used(current_ins, hreg) &&
|
|
||||||
!register_used(current_outs, hreg))
|
int j;
|
||||||
{
|
for (j=0; j<hreg->aliases.count; j++)
|
||||||
/* This hreg is unused, so we don't need to evict anything.
|
{
|
||||||
* Shouldn't really happen in real life. */
|
struct hreg* alias = hreg->aliases.item[j];
|
||||||
return hreg;
|
struct vreg* candidatein = pmap_findleft(current_ins, alias);
|
||||||
}
|
struct vreg* candidateout = pmap_findleft(current_outs, alias);
|
||||||
if (candidatein && candidateout && (candidatein == candidateout))
|
/* Check this is a through. */
|
||||||
{
|
if (candidatein != candidateout)
|
||||||
/* This is a through register. */
|
goto next_hreg;
|
||||||
tracef('R', "R: evicting %%%d from %s\n", candidatein->id, hreg->id);
|
}
|
||||||
pmap_put(&evicted, candidatein, hreg);
|
|
||||||
pmap_remove(current_ins, hreg, candidatein);
|
/* We've now verified that this hreg is safe to evict. */
|
||||||
pmap_remove(current_outs, hreg, candidatein);
|
|
||||||
return hreg;
|
for (j=0; j<hreg->aliases.count; j++)
|
||||||
}
|
{
|
||||||
|
struct hreg* alias = hreg->aliases.item[j];
|
||||||
|
struct vreg* candidatein = pmap_findleft(current_ins, alias);
|
||||||
|
struct vreg* candidateout = pmap_findleft(current_outs, alias);
|
||||||
|
/* Check this is a through. */
|
||||||
|
if (candidatein && (candidatein == candidateout))
|
||||||
|
{
|
||||||
|
tracef('R', "R: evicting %%%d from %s so we can use %s\n", candidatein->id, alias->id, hreg->id);
|
||||||
|
pmap_put(&evicted, candidatein, alias);
|
||||||
|
pmap_remove(current_ins, alias, candidatein);
|
||||||
|
pmap_remove(current_outs, alias, candidatein);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return hreg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
next_hreg:;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Couldn't find anything to evict */
|
/* Couldn't find anything to evict */
|
||||||
|
@ -233,7 +249,12 @@ static void add_input_register(struct vreg* vreg, struct hreg* hreg)
|
||||||
|
|
||||||
if (hreg)
|
if (hreg)
|
||||||
{
|
{
|
||||||
if (hreg->is_stacked)
|
if (!constraints_match(hreg, vreg))
|
||||||
|
{
|
||||||
|
/* This hint isn't allowed for this instruction. */
|
||||||
|
hreg = NULL;
|
||||||
|
}
|
||||||
|
else if (hreg->is_stacked)
|
||||||
{
|
{
|
||||||
/* This vreg is stacked; we need to put it in a register. That's
|
/* This vreg is stacked; we need to put it in a register. That's
|
||||||
* slightly exciting because the vreg might be a through, which
|
* slightly exciting because the vreg might be a through, which
|
||||||
|
@ -559,7 +580,7 @@ static void assign_hregs_to_vregs(void)
|
||||||
|
|
||||||
select_registers(hop, old, in, out);
|
select_registers(hop, old, in, out);
|
||||||
|
|
||||||
tracef('R', "R: %d from $%d: [", hop->id, hop->ir->id);
|
tracef('R', "R: %d from $%d: ins: [", hop->id, hop->ir->id);
|
||||||
for (k=0; k<hop->regsin.count; k++)
|
for (k=0; k<hop->regsin.count; k++)
|
||||||
{
|
{
|
||||||
struct hreg* hreg = hop->regsin.item[k].left;
|
struct hreg* hreg = hop->regsin.item[k].left;
|
||||||
|
@ -568,7 +589,7 @@ static void assign_hregs_to_vregs(void)
|
||||||
tracef('R', " ");
|
tracef('R', " ");
|
||||||
tracef('R', "%%%d=>%s", vreg->id, hreg->id);
|
tracef('R', "%%%d=>%s", vreg->id, hreg->id);
|
||||||
}
|
}
|
||||||
tracef('R', "] [");
|
tracef('R', "] outs: [");
|
||||||
for (k=0; k<hop->regsout.count; k++)
|
for (k=0; k<hop->regsout.count; k++)
|
||||||
{
|
{
|
||||||
struct hreg* hreg = hop->regsout.item[k].left;
|
struct hreg* hreg = hop->regsout.item[k].left;
|
||||||
|
@ -612,17 +633,25 @@ static int insert_moves(struct basicblock* bb, int index,
|
||||||
struct hreg* other;
|
struct hreg* other;
|
||||||
struct hop* hop;
|
struct hop* hop;
|
||||||
|
|
||||||
/* Try and find a destination which isn't a source. */
|
/* Try and find a destination which isn't a source (or an alias of a source). */
|
||||||
|
|
||||||
src = NULL;
|
src = NULL;
|
||||||
for (i=0; i<copies.count; i++)
|
for (i=0; i<copies.count; i++)
|
||||||
{
|
{
|
||||||
|
int j;
|
||||||
dest = copies.item[i].right;
|
dest = copies.item[i].right;
|
||||||
if (!pmap_findleft(&copies, dest))
|
|
||||||
{
|
for (j=0; j<dest->aliases.count; j++)
|
||||||
src = copies.item[i].left;
|
{
|
||||||
break;
|
struct hreg* alias = dest->aliases.item[j];
|
||||||
}
|
if (pmap_findleft(&copies, alias))
|
||||||
|
goto nextcopy;
|
||||||
|
}
|
||||||
|
|
||||||
|
src = copies.item[i].left;
|
||||||
|
break;
|
||||||
|
|
||||||
|
nextcopy:;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (src)
|
if (src)
|
||||||
|
|
|
@ -199,6 +199,9 @@ void procedure_compile(struct procedure* proc)
|
||||||
print_blocks('3');
|
print_blocks('3');
|
||||||
pass_wire_up_return_values();
|
pass_wire_up_return_values();
|
||||||
pass_convert_stack_ops();
|
pass_convert_stack_ops();
|
||||||
|
#if defined MCGG_OPTION_LOWER_PUSHES_TO_LOADS_AND_STORES
|
||||||
|
pass_lower_pushes();
|
||||||
|
#endif
|
||||||
print_blocks('4');
|
print_blocks('4');
|
||||||
pass_convert_locals_to_ssa();
|
pass_convert_locals_to_ssa();
|
||||||
print_blocks('5');
|
print_blocks('5');
|
||||||
|
|
|
@ -36,6 +36,7 @@ extern int yylex(void);
|
||||||
%term FRAGMENT
|
%term FRAGMENT
|
||||||
%term NAMED
|
%term NAMED
|
||||||
%term NOTEQUALS
|
%term NOTEQUALS
|
||||||
|
%term OPTIONS
|
||||||
%term PATTERNS
|
%term PATTERNS
|
||||||
%term PREFERS
|
%term PREFERS
|
||||||
%term PRESERVED
|
%term PRESERVED
|
||||||
|
@ -66,11 +67,27 @@ extern int yylex(void);
|
||||||
%%
|
%%
|
||||||
|
|
||||||
spec
|
spec
|
||||||
: REGISTERS registers
|
: optionaloptions
|
||||||
|
REGISTERS registers
|
||||||
DECLARATIONS declarations
|
DECLARATIONS declarations
|
||||||
PATTERNS patterns
|
PATTERNS patterns
|
||||||
;
|
;
|
||||||
|
|
||||||
|
optionaloptions
|
||||||
|
: /* nothing */
|
||||||
|
| OPTIONS options
|
||||||
|
;
|
||||||
|
|
||||||
|
options
|
||||||
|
: /* nothing */
|
||||||
|
| options option ';'
|
||||||
|
| option ';'
|
||||||
|
;
|
||||||
|
|
||||||
|
option
|
||||||
|
: ID { option($1); }
|
||||||
|
;
|
||||||
|
|
||||||
registers
|
registers
|
||||||
: /* nothing */
|
: /* nothing */
|
||||||
| registers register ';'
|
| registers register ';'
|
||||||
|
|
|
@ -836,6 +836,11 @@ static void emitheader(void)
|
||||||
printh("#define MCG_DEFS_H\n\n");
|
printh("#define MCG_DEFS_H\n\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void option(const char* o)
|
||||||
|
{
|
||||||
|
printh("#define MCGG_OPTION_%s\n", o);
|
||||||
|
}
|
||||||
|
|
||||||
/* computekids - compute paths to kids in tree t */
|
/* computekids - compute paths to kids in tree t */
|
||||||
static char* computekids(Tree node, const char* v, char* bp, int* ip)
|
static char* computekids(Tree node, const char* v, char* bp, int* ip)
|
||||||
{
|
{
|
||||||
|
|
|
@ -72,6 +72,7 @@ struct regattr
|
||||||
int number; /* identifying number */
|
int number; /* identifying number */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
extern void option(const char* name);
|
||||||
extern struct reg* makereg(const char* name);
|
extern struct reg* makereg(const char* name);
|
||||||
extern void setregnames(struct reg* reg, struct stringlist* names);
|
extern void setregnames(struct reg* reg, struct stringlist* names);
|
||||||
extern void addregattr(struct reg* reg, const char* regattr);
|
extern void addregattr(struct reg* reg, const char* regattr);
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
# Types:
|
# The second column indicates the type inference rules:
|
||||||
#
|
#
|
||||||
# I, F, L, D: int, float, long, double
|
# I, F, L, D: int, float, long, double
|
||||||
# i, F: int, float; promoted to long, double based on size
|
# i, f: int, float; promoted to long, double based on size
|
||||||
# .: ignore this parameter
|
# .: ignore this parameter
|
||||||
# ?: pull/push types from other ? parameters
|
# ?: pull/push types from other ? parameters
|
||||||
|
|
||||||
|
|
|
@ -40,6 +40,7 @@ static int braces = 0;
|
||||||
"DECLARATIONS" return DECLARATIONS;
|
"DECLARATIONS" return DECLARATIONS;
|
||||||
"PATTERNS" return PATTERNS;
|
"PATTERNS" return PATTERNS;
|
||||||
"REGISTERS" return REGISTERS;
|
"REGISTERS" return REGISTERS;
|
||||||
|
"OPTIONS" return OPTIONS;
|
||||||
"aliases" return ALIASES;
|
"aliases" return ALIASES;
|
||||||
"corrupted" return CORRUPTED;
|
"corrupted" return CORRUPTED;
|
||||||
"cost" return COST;
|
"cost" return COST;
|
||||||
|
|
Loading…
Reference in a new issue