Lots more opcodes. Rearrange the stack layout so that fp->ab is a fixed value
(needed for CHAINFP and FPTOAB). Wire up lfrs to calls via a phi when necessary, to allow call-bra-lfr chains.
This commit is contained in:
parent
bfa65168e2
commit
2cc2c0ae98
|
@ -4,19 +4,20 @@
|
||||||
*
|
*
|
||||||
* | ...params...
|
* | ...params...
|
||||||
* | --------------- <- ab
|
* | --------------- <- ab
|
||||||
|
* | old FR
|
||||||
|
* | old FP
|
||||||
|
* | --------------- <- st, fp (a.k.a. lb)
|
||||||
* | spills
|
* | spills
|
||||||
* | ---------------
|
* | ---------------
|
||||||
* | saved regs
|
* | saved regs
|
||||||
* | LR
|
* | ---------------
|
||||||
* | FP
|
|
||||||
* | --------------- <- st, fp (a.k.a. lb)
|
|
||||||
* | locals
|
* | locals
|
||||||
* | --------------- <- sp
|
* | --------------- <- sp
|
||||||
* V ...user area...
|
* V ...user area...
|
||||||
*
|
*
|
||||||
* st indexes up; lb indexes down.
|
* st indexes up; lb indexes down.
|
||||||
*
|
*
|
||||||
* We ensure that dereferencing fp always produces the caller's fp.
|
* Note that [fp] == old_fp and ab == fp + 8.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static ARRAYOF(struct hreg) saved_regs;
|
static ARRAYOF(struct hreg) saved_regs;
|
||||||
|
@ -39,28 +40,29 @@ void platform_calculate_offsets(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
current_proc->fp_to_st = 0;
|
current_proc->fp_to_st = 0;
|
||||||
current_proc->fp_to_ab = current_proc->spills_size + current_proc->saved_size + 8;
|
current_proc->fp_to_ab = 8;
|
||||||
current_proc->fp_to_lb = 0;
|
current_proc->fp_to_lb = -(current_proc->spills_size + current_proc->saved_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct hop* platform_prologue(void)
|
struct hop* platform_prologue(void)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
int saved_offset;
|
int saved_offset;
|
||||||
|
int spoffset = current_proc->saved_size + current_proc->spills_size +
|
||||||
|
current_proc->locals_size;
|
||||||
struct hop* hop = new_hop(current_proc->entry, NULL);
|
struct hop* hop = new_hop(current_proc->entry, NULL);
|
||||||
|
|
||||||
hop_add_insel(hop, "! saved_size = %d+8 bytes", current_proc->saved_size);
|
hop_add_insel(hop, "! saved_size = %d bytes", current_proc->saved_size);
|
||||||
hop_add_insel(hop, "! spills_size = %d bytes", current_proc->spills_size);
|
hop_add_insel(hop, "! spills_size = %d bytes", current_proc->spills_size);
|
||||||
hop_add_insel(hop, "! locals_size = %d bytes", current_proc->locals_size);
|
hop_add_insel(hop, "! locals_size = %d bytes", current_proc->locals_size);
|
||||||
hop_add_insel(hop, "addi sp, sp, %d", -(current_proc->fp_to_ab + current_proc->locals_size));
|
hop_add_insel(hop, "addi sp, sp, %d", -(spoffset + 8));
|
||||||
hop_add_insel(hop, "mfspr r0, lr");
|
hop_add_insel(hop, "mfspr r0, lr");
|
||||||
|
hop_add_insel(hop, "stw fp, %d(sp)", spoffset + 0);
|
||||||
hop_add_insel(hop, "stw fp, %d(sp)", current_proc->locals_size + 0);
|
hop_add_insel(hop, "stw r0, %d(sp)", spoffset + 4);
|
||||||
hop_add_insel(hop, "stw r0, %d(sp)", current_proc->locals_size + 4);
|
hop_add_insel(hop, "addi fp, sp, %d", spoffset);
|
||||||
hop_add_insel(hop, "addi fp, sp, %d", current_proc->locals_size);
|
|
||||||
|
|
||||||
/* Saved reg offsets are negative. */
|
/* Saved reg offsets are negative. */
|
||||||
saved_offset = current_proc->saved_size + 8;
|
saved_offset = -current_proc->spills_size;
|
||||||
for (i=0; i<saved_regs.count; i++)
|
for (i=0; i<saved_regs.count; i++)
|
||||||
{
|
{
|
||||||
struct hreg* hreg = saved_regs.item[i];
|
struct hreg* hreg = saved_regs.item[i];
|
||||||
|
@ -80,7 +82,7 @@ struct hop* platform_epilogue(void)
|
||||||
int saved_offset;
|
int saved_offset;
|
||||||
|
|
||||||
/* Saved reg offsets are negative. */
|
/* Saved reg offsets are negative. */
|
||||||
saved_offset = current_proc->saved_size + 8;
|
saved_offset = -current_proc->spills_size;
|
||||||
for (i=0; i<saved_regs.count; i++)
|
for (i=0; i<saved_regs.count; i++)
|
||||||
{
|
{
|
||||||
struct hreg* hreg = saved_regs.item[i];
|
struct hreg* hreg = saved_regs.item[i];
|
||||||
|
|
|
@ -210,18 +210,26 @@ PATTERNS
|
||||||
emit "mr %out, fp"
|
emit "mr %out, fp"
|
||||||
cost 4;
|
cost 4;
|
||||||
|
|
||||||
|
SETFP.I(in:(int)reg)
|
||||||
|
emit "mr fp, %in"
|
||||||
|
cost 4;
|
||||||
|
|
||||||
out:(int)reg = CHAINFP.I(in:(int)reg)
|
out:(int)reg = CHAINFP.I(in:(int)reg)
|
||||||
emit "lwz %out, 0(%in)"
|
emit "lwz %out, 0(%in)"
|
||||||
cost 4;
|
cost 4;
|
||||||
|
|
||||||
out:(int)reg = FPTOARGS.I(GETFP.I)
|
out:(int)reg = FPTOAB.I(GETFP.I)
|
||||||
emit "addi %out, fp, 8"
|
emit "addi %out, fp, 8"
|
||||||
cost 4;
|
cost 4;
|
||||||
|
|
||||||
out:(int)reg = FPTOARGS.I(in:(int)reg)
|
out:(int)reg = FPTOAB.I(in:(int)reg)
|
||||||
emit "addi %out, %in, 8"
|
emit "addi %out, %in, 8"
|
||||||
cost 4;
|
cost 4;
|
||||||
|
|
||||||
|
out:(int)reg = FPTOLB.I(in:(int)reg)
|
||||||
|
with %out == %in
|
||||||
|
cost 1;
|
||||||
|
|
||||||
out:(int)reg = GETSP.I
|
out:(int)reg = GETSP.I
|
||||||
emit "mr %out, sp"
|
emit "mr %out, sp"
|
||||||
cost 4;
|
cost 4;
|
||||||
|
@ -230,6 +238,9 @@ PATTERNS
|
||||||
emit "mr sp, %in"
|
emit "mr sp, %in"
|
||||||
cost 4;
|
cost 4;
|
||||||
|
|
||||||
|
out:(int)reg = ANY.I
|
||||||
|
cost 1;
|
||||||
|
|
||||||
out:(int)reg = COPYF.I(in:(float)reg)
|
out:(int)reg = COPYF.I(in:(float)reg)
|
||||||
emit "stfsu %in, -4(sp)"
|
emit "stfsu %in, -4(sp)"
|
||||||
emit "lwz %out, 0(sp)"
|
emit "lwz %out, 0(sp)"
|
||||||
|
@ -376,6 +387,11 @@ PATTERNS
|
||||||
emit "srawi %out.1, %out.0, 31"
|
emit "srawi %out.1, %out.0, 31"
|
||||||
cost 8;
|
cost 8;
|
||||||
|
|
||||||
|
out:(ret)reg = FROMF.I(in:(dret)reg)
|
||||||
|
with corrupted(volatile)
|
||||||
|
emit "bl .fromf2i"
|
||||||
|
cost 4;
|
||||||
|
|
||||||
out:(ret)reg = FROMD.I(in:(dret)reg)
|
out:(ret)reg = FROMD.I(in:(dret)reg)
|
||||||
with corrupted(volatile)
|
with corrupted(volatile)
|
||||||
emit "bl .fromd2i"
|
emit "bl .fromd2i"
|
||||||
|
@ -391,54 +407,16 @@ PATTERNS
|
||||||
emit "bl .fromsi2d"
|
emit "bl .fromsi2d"
|
||||||
cost 4;
|
cost 4;
|
||||||
|
|
||||||
#if 0
|
out:(fret)reg = FROMUI.F(in:(ret)reg)
|
||||||
/* byte conversions */
|
with corrupted(volatile)
|
||||||
|
emit "bl .fromui2f"
|
||||||
out:(int)ubyte0 = CIU14(in:(int)ubyte0)
|
|
||||||
with %out == %in
|
|
||||||
emit "! CIU14(ubyte0) -> ubyte0"
|
|
||||||
cost 1;
|
|
||||||
|
|
||||||
out:(int)ubyte0 = CIU41(in:(int)ubyte0)
|
|
||||||
with %out == %in
|
|
||||||
emit "! CIU41(ubyte0) -> ubyte0"
|
|
||||||
cost 1;
|
|
||||||
|
|
||||||
out:(int)ubyteX = CIU41(in:(int)ubyteX)
|
|
||||||
with %out == %in
|
|
||||||
emit "! CIU41(ubyteX) -> ubyteX"
|
|
||||||
cost 1;
|
|
||||||
|
|
||||||
out:(int)reg = CII14(in:(int)ubyteX)
|
|
||||||
emit "extsb %out, %in ! CII14(ubyteX) -> reg"
|
|
||||||
cost 4;
|
cost 4;
|
||||||
|
|
||||||
/* short conversions */
|
out:(dret)reg = FROMUI.D(in:(ret)reg)
|
||||||
|
with corrupted(volatile)
|
||||||
|
emit "bl .fromui2d"
|
||||||
|
cost 4;
|
||||||
|
|
||||||
out:(int)ushort0 = CIU24(in:(int)ushort0)
|
|
||||||
with %out == %in
|
|
||||||
emit "! CIU24(ushort0) -> ushort0"
|
|
||||||
cost 1;
|
|
||||||
|
|
||||||
out:(int)ushort0 = CIU42(in:(int)ushort0)
|
|
||||||
with %out == %in
|
|
||||||
emit "! CIU42(ushort0) -> ushort0"
|
|
||||||
cost 1;
|
|
||||||
|
|
||||||
out:(int)ushortX = CIU42(in:(int)ushortX)
|
|
||||||
with %out == %in
|
|
||||||
emit "! CIU42(ushortX) -> ushortX"
|
|
||||||
cost 1;
|
|
||||||
|
|
||||||
out:(int)reg = CII24(in:(int)ushort0)
|
|
||||||
with %out == %in
|
|
||||||
emit "! CII24(ushort0) -> reg"
|
|
||||||
cost 4;
|
|
||||||
|
|
||||||
out:(int)reg = CII24(in:(int)ushortX)
|
|
||||||
emit "extsh %out, %in"
|
|
||||||
cost 4;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
/* Locals */
|
/* Locals */
|
||||||
|
@ -452,6 +430,7 @@ PATTERNS
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Memory addressing modes */
|
/* Memory addressing modes */
|
||||||
|
|
||||||
address = ADD.I(addr:(int)reg, offset:CONST.I)
|
address = ADD.I(addr:(int)reg, offset:CONST.I)
|
||||||
|
@ -484,38 +463,26 @@ PATTERNS
|
||||||
emit "b $false"
|
emit "b $false"
|
||||||
cost 8;
|
cost 8;
|
||||||
|
|
||||||
CALL(dest:LABEL.I)
|
#define CALLLABEL(insn) \
|
||||||
with corrupted(volatile)
|
insn (dest:LABEL.I) \
|
||||||
emit "bl $dest"
|
with corrupted(volatile) \
|
||||||
cost 4;
|
emit "bl $dest" \
|
||||||
|
cost 4;
|
||||||
|
|
||||||
out:(ret)reg = CALL.I(dest:LABEL.I)
|
CALLLABEL(CALL)
|
||||||
with corrupted(volatile)
|
out:(int)reg = CALLLABEL(CALL.I)
|
||||||
emit "bl $dest"
|
out:(long)reg = CALLLABEL(CALL.L)
|
||||||
cost 4;
|
|
||||||
|
|
||||||
out:(lret)reg = CALL.L(dest:LABEL.I)
|
#define CALLINDIRECT(insn) \
|
||||||
with corrupted(volatile)
|
insn (dest:(int)reg) \
|
||||||
emit "bl $dest"
|
with corrupted(volatile) \
|
||||||
cost 4;
|
emit "mtspr ctr, %dest" \
|
||||||
|
emit "bcctrl 20, 0, 0" \
|
||||||
|
cost 8;
|
||||||
|
|
||||||
CALL(dest:(int)reg)
|
CALLINDIRECT(CALL)
|
||||||
with corrupted(volatile)
|
out:(int)reg = CALLINDIRECT(CALL.I)
|
||||||
emit "mtspr ctr, %dest"
|
out:(long)reg = CALLINDIRECT(CALL.L)
|
||||||
emit "bcctrl 20, 0, 0"
|
|
||||||
cost 8;
|
|
||||||
|
|
||||||
out:(ret)reg = CALL.I(dest:(int)reg)
|
|
||||||
with corrupted(volatile)
|
|
||||||
emit "mtspr ctr, %dest"
|
|
||||||
emit "bcctrl 20, 0, 0"
|
|
||||||
cost 8;
|
|
||||||
|
|
||||||
out:(lret)reg = CALL.L(dest:(int)reg)
|
|
||||||
with corrupted(volatile)
|
|
||||||
emit "mtspr ctr, %dest"
|
|
||||||
emit "bcctrl 20, 0, 0"
|
|
||||||
cost 8;
|
|
||||||
|
|
||||||
JUMP(dest:LABEL.I)
|
JUMP(dest:LABEL.I)
|
||||||
emit "b $dest"
|
emit "b $dest"
|
||||||
|
@ -701,6 +668,12 @@ PATTERNS
|
||||||
emit "lfd %out, %addr"
|
emit "lfd %out, %addr"
|
||||||
cost 4;
|
cost 4;
|
||||||
|
|
||||||
|
out:(float)reg = in:CONST.F
|
||||||
|
when specific_constant(%in, 0)
|
||||||
|
emit "la r0, .fd_00000000"
|
||||||
|
emit "lfs %out, 0(r0)"
|
||||||
|
cost 12;
|
||||||
|
|
||||||
FPU4R(ADDF.F, "fadds")
|
FPU4R(ADDF.F, "fadds")
|
||||||
FPU8R(ADDF.D, "fadd")
|
FPU8R(ADDF.D, "fadd")
|
||||||
|
|
||||||
|
@ -729,35 +702,5 @@ PATTERNS
|
||||||
emit "fcmpu %cr, %left, %right"
|
emit "fcmpu %cr, %left, %right"
|
||||||
cost 4;
|
cost 4;
|
||||||
|
|
||||||
#if 0
|
|
||||||
out:(ret)reg = CFI44(val:(fret)reg)
|
|
||||||
with corrupted(volatile)
|
|
||||||
emit "bl .cfi44"
|
|
||||||
cost 4;
|
|
||||||
|
|
||||||
out:(fret)reg = CIF44(val:(ret)reg)
|
|
||||||
with corrupted(volatile)
|
|
||||||
emit "bl .cif44"
|
|
||||||
cost 4;
|
|
||||||
|
|
||||||
out:(ret)reg = CFI84(val:(dret)reg)
|
|
||||||
with corrupted(volatile)
|
|
||||||
emit "bl .cfi84"
|
|
||||||
cost 4;
|
|
||||||
|
|
||||||
out:(dret)reg = CIF48(val:(ret)reg)
|
|
||||||
with corrupted(volatile)
|
|
||||||
emit "bl .cif48"
|
|
||||||
cost 4;
|
|
||||||
|
|
||||||
out:(float)reg = CFF84(val:(double)reg)
|
|
||||||
emit "frsp %out, %val"
|
|
||||||
cost 4;
|
|
||||||
|
|
||||||
out:(double)reg = CFF48(val:(float)reg)
|
|
||||||
emit "fmr %out, %val"
|
|
||||||
cost 1;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* vim: set sw=4 ts=4 expandtab : */
|
/* vim: set sw=4 ts=4 expandtab : */
|
||||||
|
|
||||||
|
|
|
@ -282,9 +282,15 @@ char* hop_render(struct hop* hop)
|
||||||
case IR_CONST:
|
case IR_CONST:
|
||||||
appendf("%d", ir->u.ivalue);
|
appendf("%d", ir->u.ivalue);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
assert(false);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
assert(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -118,6 +118,7 @@ extern void pass_register_allocator(void);
|
||||||
extern void pass_remove_dead_blocks(void);
|
extern void pass_remove_dead_blocks(void);
|
||||||
extern void pass_remove_dead_phis(void);
|
extern void pass_remove_dead_phis(void);
|
||||||
extern void pass_split_critical_edges(void);
|
extern void pass_split_critical_edges(void);
|
||||||
|
extern void pass_wire_up_return_values(void);
|
||||||
|
|
||||||
extern void platform_calculate_offsets(void);
|
extern void platform_calculate_offsets(void);
|
||||||
extern struct hop* platform_prologue(void);
|
extern struct hop* platform_prologue(void);
|
||||||
|
|
|
@ -67,6 +67,8 @@ void pass_live_vreg_analysis(void)
|
||||||
propagate_liveness(dominance.postorder.item[i]);
|
propagate_liveness(dominance.postorder.item[i]);
|
||||||
}
|
}
|
||||||
while (!finished);
|
while (!finished);
|
||||||
|
|
||||||
|
//assert(cfg.entry->liveins.count == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* vim: set sw=4 ts=4 expandtab : */
|
/* vim: set sw=4 ts=4 expandtab : */
|
||||||
|
|
|
@ -120,7 +120,7 @@ static struct hreg* evict(struct vreg* vreg)
|
||||||
* Shouldn't really happen in real life. */
|
* Shouldn't really happen in real life. */
|
||||||
return hreg;
|
return hreg;
|
||||||
}
|
}
|
||||||
if (candidatein == candidateout)
|
if (candidatein && candidateout && (candidatein == candidateout))
|
||||||
{
|
{
|
||||||
/* This is a through register. */
|
/* This is a through register. */
|
||||||
tracef('R', "R: evicting %%%d from %s\n", candidatein->id, hreg->id);
|
tracef('R', "R: evicting %%%d from %s\n", candidatein->id, hreg->id);
|
||||||
|
@ -513,8 +513,9 @@ static void assign_hregs_to_vregs(void)
|
||||||
phi->prev->regsout, phi->ir->result);
|
phi->prev->regsout, phi->ir->result);
|
||||||
if (hreg && !pmap_findleft(old, hreg))
|
if (hreg && !pmap_findleft(old, hreg))
|
||||||
{
|
{
|
||||||
tracef('R', "R: import hreg %s for phi input %%%d from %s\n",
|
tracef('R', "R: import hreg %s for %%%d, imported from %s %%%d\n",
|
||||||
hreg->id, vreg->id, phi->prev->name);
|
hreg->id, vreg->id,
|
||||||
|
phi->prev->name, phi->ir->id);
|
||||||
pmap_put(old, hreg, vreg);
|
pmap_put(old, hreg, vreg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -534,8 +535,9 @@ static void assign_hregs_to_vregs(void)
|
||||||
struct phicongruence* c = vreg->congruence;
|
struct phicongruence* c = vreg->congruence;
|
||||||
struct hreg* hreg = allocate_phi_hreg(old, vreg, c->type);
|
struct hreg* hreg = allocate_phi_hreg(old, vreg, c->type);
|
||||||
|
|
||||||
tracef('R', "R: import fallback hreg %s for phi input %%%d from %s\n",
|
tracef('R', "R: import fallback hreg %s for %%%d, imported from %s %%%d\n",
|
||||||
hreg->id, vreg->id, phi->prev->name);
|
hreg->id, vreg->id,
|
||||||
|
phi->prev->name, phi->ir->id);
|
||||||
pmap_add(old, hreg, vreg);
|
pmap_add(old, hreg, vreg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
123
mach/proto/mcg/pass_returnvalues.c
Normal file
123
mach/proto/mcg/pass_returnvalues.c
Normal file
|
@ -0,0 +1,123 @@
|
||||||
|
#include "mcg.h"
|
||||||
|
|
||||||
|
/* The ACK returns values from functions not on the stack but in a special
|
||||||
|
* 'register' which are read with lfr. This register is defined to survive
|
||||||
|
* asp, bra and gto. The way it's intended to work is that value just gets put
|
||||||
|
* in a particular hreg and stays there until lfr brings it to the attention of
|
||||||
|
* the code generator.
|
||||||
|
*
|
||||||
|
* Trouble is, while that worked on ncg, it doesn't work here because the
|
||||||
|
* register allocator may decide to insert moves arbitrarily. So we need to
|
||||||
|
* somehow turn this special register into a real register so that it can be
|
||||||
|
* kept alive.
|
||||||
|
*
|
||||||
|
* The easiest thing to do is to just push the result of call onto the stack...
|
||||||
|
* but that doesn't work either, because if someone does a call without an lfr,
|
||||||
|
* we don't want to be left with an unpopped value.
|
||||||
|
*
|
||||||
|
* So what we do is we find lfrs, and then we search for the call which
|
||||||
|
* generated the value, and then we hook up the IRs so there's a connection
|
||||||
|
* between the two. But beware! The lfr value survives bra! Which means a
|
||||||
|
* single lfr may actually read the value produced by *several* call
|
||||||
|
* instructions. You know what that means? Phis.
|
||||||
|
*
|
||||||
|
* (Luckily a single call instruction can't be read by multiple lfrs, because
|
||||||
|
* conditional branches trash the lfr value.)
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void find_call(struct basicblock* bb, int index, struct ir* lfr,
|
||||||
|
struct basicblock** callbb, struct ir** callir)
|
||||||
|
{
|
||||||
|
if (index == -1)
|
||||||
|
index = bb->irs.count - 1;
|
||||||
|
|
||||||
|
while (index >= 0)
|
||||||
|
{
|
||||||
|
struct ir* ir = bb->irs.item[index];
|
||||||
|
switch (ir->opcode)
|
||||||
|
{
|
||||||
|
case IR_CALL:
|
||||||
|
ir->size = lfr->size;
|
||||||
|
*callbb = bb;
|
||||||
|
*callir = ir;
|
||||||
|
return;
|
||||||
|
|
||||||
|
case IR_STACKADJUST:
|
||||||
|
case IR_GETRET:
|
||||||
|
case IR_JUMP:
|
||||||
|
/* lfr value preserved */
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
/* lfr value has been corrupted. */
|
||||||
|
fatal("lfr reading corrupted value in %s", bb->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
index--;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Our search hit the top of the block; we need to import the
|
||||||
|
* lfr value from a previous block. */
|
||||||
|
|
||||||
|
if (bb->prevs.count == 1)
|
||||||
|
{
|
||||||
|
/* Only a single predecessor, so no phi is necessary. */
|
||||||
|
|
||||||
|
find_call(bb->prevs.item[0], -1, lfr, callbb, callir);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* We have multiple predecessors. This means that the lfr value may
|
||||||
|
* come from any of these blocks. We need a phi. */
|
||||||
|
|
||||||
|
int i;
|
||||||
|
struct ir* phi = new_ir0(IR_PHI, lfr->size);
|
||||||
|
|
||||||
|
phi->root = phi;
|
||||||
|
array_insert(&bb->irs, phi, 0);
|
||||||
|
|
||||||
|
for (i=0; i<bb->prevs.count; i++)
|
||||||
|
{
|
||||||
|
struct basicblock* prev = bb->prevs.item[i];
|
||||||
|
struct basicblock* parentbb;
|
||||||
|
struct ir* parentir;
|
||||||
|
|
||||||
|
find_call(prev, -1, phi, &parentbb, &parentir);
|
||||||
|
|
||||||
|
pmap_add(&phi->u.phivalue, parentbb, parentir);
|
||||||
|
}
|
||||||
|
|
||||||
|
*callbb = bb;
|
||||||
|
*callir = phi;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void wire_up_ir(struct basicblock* bb, int index)
|
||||||
|
{
|
||||||
|
struct ir* lfr = bb->irs.item[index];
|
||||||
|
struct basicblock* callbb;
|
||||||
|
struct ir* callir;
|
||||||
|
|
||||||
|
find_call(bb, index, lfr, &callbb, &callir);
|
||||||
|
|
||||||
|
lfr->left = callir;
|
||||||
|
lfr->opcode = IR_NOP;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pass_wire_up_return_values(void)
|
||||||
|
{
|
||||||
|
int i, j;
|
||||||
|
|
||||||
|
for (i=0; i<cfg.preorder.count; i++)
|
||||||
|
{
|
||||||
|
struct basicblock* bb = cfg.preorder.item[i];
|
||||||
|
for (j=0; j<bb->irs.count; j++)
|
||||||
|
{
|
||||||
|
struct ir* ir = bb->irs.item[j];
|
||||||
|
if (ir->opcode == IR_GETRET)
|
||||||
|
wire_up_ir(bb, j);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* vim: set sw=4 ts=4 expandtab : */
|
|
@ -218,8 +218,8 @@ static struct ir* new_copy(char wanted, char real, struct ir* ir)
|
||||||
else if ((wanted == 'L') && (real == 'D'))
|
else if ((wanted == 'L') && (real == 'D'))
|
||||||
opcode = IR_COPYD;
|
opcode = IR_COPYD;
|
||||||
else
|
else
|
||||||
fatal("type mismatch: parent IR wanted %c, child IR provided %c",
|
fatal("type mismatch: parent IR $%d wanted %c, child IR provided %c",
|
||||||
wanted, real);
|
ir->id, wanted, real);
|
||||||
|
|
||||||
copy = new_ir1(opcode, ir->size, ir);
|
copy = new_ir1(opcode, ir->size, ir);
|
||||||
copy->type = wanted;
|
copy->type = wanted;
|
||||||
|
|
|
@ -179,6 +179,7 @@ void procedure_compile(struct procedure* proc)
|
||||||
* and nexts (and then calling update_graph_data()). */
|
* and nexts (and then calling update_graph_data()). */
|
||||||
|
|
||||||
print_blocks('3');
|
print_blocks('3');
|
||||||
|
pass_wire_up_return_values();
|
||||||
pass_convert_stack_ops();
|
pass_convert_stack_ops();
|
||||||
print_blocks('4');
|
print_blocks('4');
|
||||||
pass_convert_locals_to_ssa();
|
pass_convert_locals_to_ssa();
|
||||||
|
|
|
@ -4,7 +4,6 @@ static struct basicblock* current_bb;
|
||||||
|
|
||||||
static int stackptr;
|
static int stackptr;
|
||||||
static struct ir* stack[64];
|
static struct ir* stack[64];
|
||||||
static struct ir* lastcall;
|
|
||||||
|
|
||||||
static struct ir* convert(struct ir* src, int srcsize, int destsize, int opcode);
|
static struct ir* convert(struct ir* src, int srcsize, int destsize, int opcode);
|
||||||
static struct ir* appendir(struct ir* ir);
|
static struct ir* appendir(struct ir* ir);
|
||||||
|
@ -340,6 +339,20 @@ static void simple_test_neg(int size, int irop)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void helper_function(const char* name)
|
||||||
|
{
|
||||||
|
/* Delegates to a helper function; these leave their result on the stack
|
||||||
|
* rather than returning values through lfr. */
|
||||||
|
|
||||||
|
materialise_stack();
|
||||||
|
appendir(
|
||||||
|
new_ir1(
|
||||||
|
IR_CALL, 0,
|
||||||
|
new_labelir(name)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
static void insn_simple(int opcode)
|
static void insn_simple(int opcode)
|
||||||
{
|
{
|
||||||
switch (opcode)
|
switch (opcode)
|
||||||
|
@ -364,6 +377,7 @@ static void insn_simple(int opcode)
|
||||||
case op_cfu: simple_convert(IR_FROMF); break; /* FIXME: technically wrong */
|
case op_cfu: simple_convert(IR_FROMF); break; /* FIXME: technically wrong */
|
||||||
case op_cfi: simple_convert(IR_FROMF); break;
|
case op_cfi: simple_convert(IR_FROMF); break;
|
||||||
case op_cif: simple_convert(IR_FROMSI); break;
|
case op_cif: simple_convert(IR_FROMSI); break;
|
||||||
|
case op_cuf: simple_convert(IR_FROMUI); break;
|
||||||
case op_cff: simple_convert(IR_FROMF); break;
|
case op_cff: simple_convert(IR_FROMF); break;
|
||||||
|
|
||||||
case op_cmp:
|
case op_cmp:
|
||||||
|
@ -384,7 +398,7 @@ static void insn_simple(int opcode)
|
||||||
struct ir* dest = pop(EM_pointersize);
|
struct ir* dest = pop(EM_pointersize);
|
||||||
|
|
||||||
materialise_stack();
|
materialise_stack();
|
||||||
lastcall = appendir(
|
appendir(
|
||||||
new_ir1(
|
new_ir1(
|
||||||
IR_CALL, 0,
|
IR_CALL, 0,
|
||||||
dest
|
dest
|
||||||
|
@ -421,7 +435,7 @@ static void insn_simple(int opcode)
|
||||||
{
|
{
|
||||||
push(
|
push(
|
||||||
new_ir1(
|
new_ir1(
|
||||||
IR_LOAD, 2,
|
(EM_wordsize == 2) ? IR_LOAD : IR_LOADH, EM_wordsize,
|
||||||
new_labelir(".ignmask")
|
new_labelir(".ignmask")
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
@ -432,7 +446,7 @@ static void insn_simple(int opcode)
|
||||||
{
|
{
|
||||||
appendir(
|
appendir(
|
||||||
new_ir2(
|
new_ir2(
|
||||||
IR_STORE, 2,
|
(EM_wordsize == 2) ? IR_STORE : IR_STOREH, EM_wordsize,
|
||||||
new_labelir(".ignmask"),
|
new_labelir(".ignmask"),
|
||||||
pop(EM_wordsize)
|
pop(EM_wordsize)
|
||||||
)
|
)
|
||||||
|
@ -440,31 +454,32 @@ static void insn_simple(int opcode)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case op_trp:
|
case op_trp: helper_function(".trp"); break;
|
||||||
{
|
case op_sig: helper_function(".sig"); break;
|
||||||
materialise_stack();
|
case op_rtt: helper_function(".rtt"); break;
|
||||||
appendir(
|
|
||||||
new_ir1(
|
|
||||||
IR_CALL, 0,
|
|
||||||
new_labelir(".trp")
|
|
||||||
)
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* FIXME: These instructions are really complex and barely used
|
/* FIXME: These instructions are really complex and barely used
|
||||||
* (Modula-2 bitset support, I believe). Leave them until leter. */
|
* (Modula-2 bitset support, I believe). Leave them until later. */
|
||||||
case op_set:
|
case op_set: helper_function(".unimplemented_set"); break;
|
||||||
case op_ior:
|
case op_ior: helper_function(".unimplemented_ior"); break;
|
||||||
{
|
|
||||||
appendir(
|
case op_dch:
|
||||||
|
push(
|
||||||
new_ir1(
|
new_ir1(
|
||||||
IR_CALL, 0,
|
IR_CHAINFP, EM_pointersize,
|
||||||
new_labelir(".unimplemented")
|
pop(EM_pointersize)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case op_lpb:
|
||||||
|
push(
|
||||||
|
new_ir1(
|
||||||
|
IR_FPTOAB, EM_pointersize,
|
||||||
|
pop(EM_pointersize)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
|
|
||||||
case op_lni:
|
case op_lni:
|
||||||
{
|
{
|
||||||
|
@ -598,6 +613,28 @@ static struct ir* ptradd(struct ir* address, int offset)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void blockmove(struct ir* dest, struct ir* src, struct ir* size)
|
||||||
|
{
|
||||||
|
/* memmove stack: ( size src dest -- ) */
|
||||||
|
push(size);
|
||||||
|
push(src);
|
||||||
|
push(dest);
|
||||||
|
|
||||||
|
materialise_stack();
|
||||||
|
appendir(
|
||||||
|
new_ir1(
|
||||||
|
IR_CALL, 0,
|
||||||
|
new_labelir("memmove")
|
||||||
|
)
|
||||||
|
);
|
||||||
|
appendir(
|
||||||
|
new_ir1(
|
||||||
|
IR_STACKADJUST, EM_pointersize,
|
||||||
|
new_wordir(EM_pointersize*2 + EM_wordsize)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
static void insn_ivalue(int opcode, arith value)
|
static void insn_ivalue(int opcode, arith value)
|
||||||
{
|
{
|
||||||
switch (opcode)
|
switch (opcode)
|
||||||
|
@ -725,7 +762,7 @@ static void insn_ivalue(int opcode, arith value)
|
||||||
case op_zrf:
|
case op_zrf:
|
||||||
{
|
{
|
||||||
struct ir* ir = new_constir(value, 0);
|
struct ir* ir = new_constir(value, 0);
|
||||||
ir->opcode = IR_CONSTF;
|
ir->opcode = IR_CONST;
|
||||||
push(ir);
|
push(ir);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1012,9 +1049,13 @@ static void insn_ivalue(int opcode, arith value)
|
||||||
|
|
||||||
case op_lfr:
|
case op_lfr:
|
||||||
{
|
{
|
||||||
assert(lastcall != NULL);
|
push(
|
||||||
lastcall->size = value;
|
appendir(
|
||||||
push(lastcall);
|
new_ir0(
|
||||||
|
IR_GETRET, value
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1063,7 +1104,7 @@ static void insn_ivalue(int opcode, arith value)
|
||||||
* the physical stack (which is very dubious). */
|
* the physical stack (which is very dubious). */
|
||||||
appendir(
|
appendir(
|
||||||
new_ir1(
|
new_ir1(
|
||||||
IR_CALL, EM_wordsize,
|
IR_CALL, 0,
|
||||||
new_labelir(helper)
|
new_labelir(helper)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
@ -1094,26 +1135,11 @@ static void insn_ivalue(int opcode, arith value)
|
||||||
|
|
||||||
case op_lxa:
|
case op_lxa:
|
||||||
{
|
{
|
||||||
struct ir* ir;
|
/* What does this actually *do*? The spec doesn't say. */
|
||||||
|
appendir(
|
||||||
/* Walk the static chain. */
|
|
||||||
|
|
||||||
ir = new_ir0(
|
|
||||||
IR_GETFP, EM_pointersize
|
|
||||||
);
|
|
||||||
|
|
||||||
while (value--)
|
|
||||||
{
|
|
||||||
ir = new_ir1(
|
|
||||||
IR_CHAINFP, EM_pointersize,
|
|
||||||
ir
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
push(
|
|
||||||
new_ir1(
|
new_ir1(
|
||||||
IR_FPTOARGS, EM_pointersize,
|
IR_CALL, 0,
|
||||||
ir
|
new_labelir(".unimplemented_lxa")
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
|
@ -1166,6 +1192,17 @@ static void insn_ivalue(int opcode, arith value)
|
||||||
{
|
{
|
||||||
switch (value)
|
switch (value)
|
||||||
{
|
{
|
||||||
|
case 0:
|
||||||
|
appendir(
|
||||||
|
new_ir1(
|
||||||
|
IR_FPTOLB, EM_pointersize,
|
||||||
|
new_ir0(
|
||||||
|
IR_GETFP, EM_pointersize
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
|
||||||
case 1:
|
case 1:
|
||||||
appendir(
|
appendir(
|
||||||
new_ir0(
|
new_ir0(
|
||||||
|
@ -1185,6 +1222,15 @@ static void insn_ivalue(int opcode, arith value)
|
||||||
{
|
{
|
||||||
switch (value)
|
switch (value)
|
||||||
{
|
{
|
||||||
|
case 0:
|
||||||
|
appendir(
|
||||||
|
new_ir1(
|
||||||
|
IR_SETFP, EM_pointersize,
|
||||||
|
pop(EM_pointersize)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
|
||||||
case 1:
|
case 1:
|
||||||
appendir(
|
appendir(
|
||||||
new_ir1(
|
new_ir1(
|
||||||
|
@ -1204,27 +1250,19 @@ static void insn_ivalue(int opcode, arith value)
|
||||||
case op_blm:
|
case op_blm:
|
||||||
{
|
{
|
||||||
/* Input stack: ( src dest -- ) */
|
/* Input stack: ( src dest -- ) */
|
||||||
/* Memmove stack: ( size src dest -- ) */
|
|
||||||
struct ir* dest = pop(EM_pointersize);
|
struct ir* dest = pop(EM_pointersize);
|
||||||
struct ir* src = pop(EM_pointersize);
|
struct ir* src = pop(EM_pointersize);
|
||||||
|
blockmove(dest, src, new_wordir(value));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
push(new_wordir(value));
|
case op_bls:
|
||||||
push(src);
|
{
|
||||||
push(dest);
|
/* Input stack: ( src dest size -- ) */
|
||||||
|
struct ir* dest = pop(EM_pointersize);
|
||||||
materialise_stack();
|
struct ir* src = pop(EM_pointersize);
|
||||||
appendir(
|
struct ir* size = pop(EM_wordsize);
|
||||||
new_ir1(
|
blockmove(dest, src, size);
|
||||||
IR_CALL, 0,
|
|
||||||
new_labelir("memmove")
|
|
||||||
)
|
|
||||||
);
|
|
||||||
appendir(
|
|
||||||
new_ir1(
|
|
||||||
IR_STACKADJUST, EM_pointersize,
|
|
||||||
new_wordir(EM_pointersize*2 + EM_wordsize)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1426,7 +1464,7 @@ static void insn_lvalue(int opcode, const char* label, arith offset)
|
||||||
case op_cal:
|
case op_cal:
|
||||||
assert(offset == 0);
|
assert(offset == 0);
|
||||||
materialise_stack();
|
materialise_stack();
|
||||||
lastcall = appendir(
|
appendir(
|
||||||
new_ir1(
|
new_ir1(
|
||||||
IR_CALL, 0,
|
IR_CALL, 0,
|
||||||
new_labelir(label)
|
new_labelir(label)
|
||||||
|
@ -1513,8 +1551,6 @@ void tb_procedure(void)
|
||||||
|
|
||||||
for (i=0; i<current_proc->blocks.count; i++)
|
for (i=0; i<current_proc->blocks.count; i++)
|
||||||
generate_tree(current_proc->blocks.item[i]);
|
generate_tree(current_proc->blocks.item[i]);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* vim: set sw=4 ts=4 expandtab : */
|
/* vim: set sw=4 ts=4 expandtab : */
|
||||||
|
|
||||||
|
|
|
@ -6,8 +6,7 @@
|
||||||
# ?: pull/push types from other ? parameters
|
# ?: pull/push types from other ? parameters
|
||||||
|
|
||||||
# Simple terminals
|
# Simple terminals
|
||||||
S ?=.. CONST # must be followed by float form
|
S ?=.. CONST
|
||||||
S ?=.. CONSTF
|
|
||||||
V ?=.. REG
|
V ?=.. REG
|
||||||
S ?=?. NOP
|
S ?=?. NOP
|
||||||
S I=.. LABEL
|
S I=.. LABEL
|
||||||
|
@ -95,7 +94,9 @@ S I=I. IFLT
|
||||||
S I=I. IFLE
|
S I=I. IFLE
|
||||||
|
|
||||||
# Procedures
|
# Procedures
|
||||||
S i=.. CALL
|
S i=I. CALL
|
||||||
|
S i=?. GETRET
|
||||||
|
S ?=i. SETRET
|
||||||
|
|
||||||
# Flow control --- these never return
|
# Flow control --- these never return
|
||||||
V .=i. JUMP
|
V .=i. JUMP
|
||||||
|
@ -106,10 +107,11 @@ V .=.. RET
|
||||||
|
|
||||||
# Special
|
# Special
|
||||||
S ?=i. STACKADJUST
|
S ?=i. STACKADJUST
|
||||||
S ?=i. SETRET
|
|
||||||
S i=.. GETFP
|
S i=.. GETFP
|
||||||
|
S ?=i. SETFP
|
||||||
S i=.. GETSP
|
S i=.. GETSP
|
||||||
S ?=i. SETSP
|
S ?=i. SETSP
|
||||||
S i=i. CHAINFP
|
S i=i. CHAINFP
|
||||||
S i=i. FPTOARGS
|
S i=i. FPTOAB
|
||||||
|
S i=i. FPTOLB
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue