Add (pretty crummy) support for register aliases and static pairs of registers.
We should have enough functionality now for rather buggy 8-bit ints and doubles. Rework the table and the platform.c to match.
This commit is contained in:
parent
d6984d60ac
commit
4db402f229
|
@ -98,51 +98,122 @@ struct hop* platform_epilogue(void)
|
|||
struct hop* platform_move(struct basicblock* bb, struct hreg* src, struct hreg* dest)
|
||||
{
|
||||
struct hop* hop = new_hop(bb, NULL);
|
||||
const uint32_t type_attrs =
|
||||
burm_int_ATTR | burm_pair_ATTR | burm_float_ATTR | burm_double_ATTR;
|
||||
|
||||
if ((src->type & type_attrs) != (dest->type & type_attrs))
|
||||
{
|
||||
assert(!src->is_stacked);
|
||||
assert(!dest->is_stacked);
|
||||
|
||||
switch (src->type & type_attrs)
|
||||
{
|
||||
case burm_int_ATTR:
|
||||
hop_add_insel(hop, "stwu %H, -4(sp)", src);
|
||||
break;
|
||||
|
||||
case burm_float_ATTR:
|
||||
hop_add_insel(hop, "stfsu %H, -4(sp)", src);
|
||||
break;
|
||||
|
||||
case burm_double_ATTR:
|
||||
hop_add_insel(hop, "stfdu %H, -8(sp)", src);
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
|
||||
switch (dest->type & type_attrs)
|
||||
{
|
||||
case burm_int_ATTR:
|
||||
hop_add_insel(hop, "lwz %H, 0(sp)", dest);
|
||||
break;
|
||||
|
||||
case burm_float_ATTR:
|
||||
hop_add_insel(hop, "lfs %H, 0(sp)", dest);
|
||||
break;
|
||||
|
||||
case burm_double_ATTR:
|
||||
hop_add_insel(hop, "lfd %H, 0(sp)", dest);
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
|
||||
switch (dest->type & type_attrs)
|
||||
{
|
||||
case burm_int_ATTR:
|
||||
case burm_float_ATTR:
|
||||
hop_add_insel(hop, "addi sp, sp, 4");
|
||||
break;
|
||||
|
||||
case burm_double_ATTR:
|
||||
case burm_pair_ATTR:
|
||||
hop_add_insel(hop, "addi sp, sp, 8");
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
uint32_t type = src->type & type_attrs;
|
||||
|
||||
if (!src->is_stacked && dest->is_stacked)
|
||||
{
|
||||
if (src->type & burm_int_ATTR)
|
||||
switch (type)
|
||||
{
|
||||
case burm_int_ATTR:
|
||||
hop_add_insel(hop, "stw %H, %S(fp) ! %H", src, dest, dest);
|
||||
else if (src->type & burm_float_ATTR)
|
||||
break;
|
||||
|
||||
case burm_float_ATTR:
|
||||
hop_add_insel(hop, "stfs %H, %S(fp) ! %H", src, dest, dest);
|
||||
else
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
else if (src->is_stacked && !dest->is_stacked)
|
||||
{
|
||||
if (src->type & burm_int_ATTR)
|
||||
switch (type)
|
||||
{
|
||||
case burm_int_ATTR:
|
||||
hop_add_insel(hop, "lwz %H, %S(fp) ! %H", dest, src, src);
|
||||
else if (src->type & burm_float_ATTR)
|
||||
break;
|
||||
|
||||
case burm_float_ATTR:
|
||||
hop_add_insel(hop, "lfs %H, %S(fp) ! %H", dest, src, src);
|
||||
else
|
||||
break;
|
||||
|
||||
default:
|
||||
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
|
||||
switch (type)
|
||||
{
|
||||
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);
|
||||
case burm_int_ATTR:
|
||||
hop_add_insel(hop, "mr %H, %H", dest, src);
|
||||
break;
|
||||
|
||||
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);
|
||||
case burm_float_ATTR:
|
||||
case burm_double_ATTR:
|
||||
hop_add_insel(hop, "fmr %H, %H", dest, src);
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
else
|
||||
assert(false);
|
||||
hop_add_insel(hop, "addi sp, sp, 4");
|
||||
}
|
||||
}
|
||||
else
|
||||
fatal("cannot generate move from %s to %s", src->name, dest->name);
|
||||
|
||||
return hop;
|
||||
}
|
||||
|
|
|
@ -7,71 +7,122 @@ REGISTERS
|
|||
* a register into another register (e.g. for eviction).
|
||||
*/
|
||||
|
||||
r12 "r12" bytes4! int! volatile;
|
||||
r11 "r11" bytes4! int! volatile;
|
||||
r10 "r10" bytes4! int! volatile;
|
||||
r9 "r9" bytes4! int! volatile;
|
||||
r8 "r8" bytes4! int! volatile;
|
||||
r7 "r7" bytes4! int! volatile;
|
||||
r6 "r6" bytes4! int! volatile;
|
||||
r5 "r5" bytes4! int! volatile;
|
||||
r4 "r4" bytes4! int! volatile;
|
||||
r3 "r3" bytes4! int! volatile ret;
|
||||
r12 bytes4! int! volatile;
|
||||
r11 bytes4! int! volatile;
|
||||
r10 bytes4! int! volatile;
|
||||
r9 bytes4! int! volatile;
|
||||
r8 bytes4! int! volatile;
|
||||
r7 bytes4! int! volatile;
|
||||
r6 bytes4! int! volatile;
|
||||
r5 bytes4! int! volatile;
|
||||
r4 bytes4! int! volatile;
|
||||
r3 bytes4! int! volatile ret;
|
||||
|
||||
r31 "r31" bytes4! int!;
|
||||
r30 "r30" bytes4! int!;
|
||||
r29 "r29" bytes4! int!;
|
||||
r28 "r28" bytes4! int!;
|
||||
r27 "r27" bytes4! int!;
|
||||
r26 "r26" bytes4! int!;
|
||||
r25 "r25" bytes4! int!;
|
||||
r24 "r24" bytes4! int!;
|
||||
r23 "r23" bytes4! int!;
|
||||
r22 "r22" bytes4! int!;
|
||||
r21 "r21" bytes4! int!;
|
||||
r20 "r20" bytes4! int!;
|
||||
r19 "r19" bytes4! int!;
|
||||
r18 "r18" bytes4! int!;
|
||||
r17 "r17" bytes4! int!;
|
||||
r16 "r16" bytes4! int!;
|
||||
r15 "r15" bytes4! int!;
|
||||
r14 "r14" bytes4! int!;
|
||||
r31 bytes4! int!;
|
||||
r30 bytes4! int!;
|
||||
r29 bytes4! int!;
|
||||
r28 bytes4! int!;
|
||||
r27 bytes4! int!;
|
||||
r26 bytes4! int!;
|
||||
r25 bytes4! int!;
|
||||
r24 bytes4! int!;
|
||||
r23 bytes4! int!;
|
||||
r22 bytes4! int!;
|
||||
r21 bytes4! int!;
|
||||
r20 bytes4! int!;
|
||||
r19 bytes4! int!;
|
||||
r18 bytes4! int!;
|
||||
r17 bytes4! int!;
|
||||
r16 bytes4! int!;
|
||||
r15 bytes4! int!;
|
||||
r14 bytes4! int!;
|
||||
r13 bytes4! int!;
|
||||
|
||||
f14 "f14" bytes4! float! volatile;
|
||||
f13 "f13" bytes4! float! volatile;
|
||||
f12 "f12" bytes4! float! volatile;
|
||||
f11 "f11" bytes4! float! volatile;
|
||||
f10 "f10" bytes4! float! volatile;
|
||||
f9 "f9" bytes4! float! volatile;
|
||||
f8 "f8" bytes4! float! volatile;
|
||||
f7 "f7" bytes4! float! volatile;
|
||||
f6 "f6" bytes4! float! volatile;
|
||||
f5 "f5" bytes4! float! volatile;
|
||||
f4 "f4" bytes4! float! volatile;
|
||||
f3 "f3" bytes4! float! volatile fret;
|
||||
f2 "f2" bytes4! float! volatile;
|
||||
f1 "f1" bytes4! float! volatile;
|
||||
f0 "f0" bytes4! float! volatile;
|
||||
r11r12 named("r11", "r12") aliases(r11, r12) bytes8! pair! volatile;
|
||||
r9r10 named("r9", "r10") aliases(r9, r10) bytes8! pair! volatile;
|
||||
r7r8 named("r7", "r8") aliases(r7, r8) bytes8! pair! volatile;
|
||||
r5r6 named("r5", "r6") aliases(r6, r6) bytes8! pair! volatile;
|
||||
r3r4 named("r3", "r4") aliases(r3, r4) bytes8! pair! volatile pret;
|
||||
|
||||
f31 "f31" bytes4! float!;
|
||||
f30 "f30" bytes4! float!;
|
||||
f29 "f29" bytes4! float!;
|
||||
f28 "f28" bytes4! float!;
|
||||
f27 "f27" bytes4! float!;
|
||||
f26 "f26" bytes4! float!;
|
||||
f25 "f25" bytes4! float!;
|
||||
f24 "f24" bytes4! float!;
|
||||
f23 "f23" bytes4! float!;
|
||||
f22 "f22" bytes4! float!;
|
||||
f21 "f21" bytes4! float!;
|
||||
f20 "f20" bytes4! float!;
|
||||
f19 "f19" bytes4! float!;
|
||||
f18 "f18" bytes4! float!;
|
||||
f17 "f17" bytes4! float!;
|
||||
f16 "f16" bytes4! float!;
|
||||
f15 "f15" bytes4! float!;
|
||||
r29r30 named("r29", "r30") aliases(r29, r30) bytes8! pair!;
|
||||
r27r28 named("r27", "r28") aliases(r27, r28) bytes8! pair!;
|
||||
r25r26 named("r25", "r26") aliases(r25, r26) bytes8! pair!;
|
||||
r23r24 named("r23", "r24") aliases(r23, r24) bytes8! pair!;
|
||||
r21r22 named("r21", "r22") aliases(r21, r22) bytes8! pair!;
|
||||
r19r20 named("r19", "r20") aliases(r19, r20) bytes8! pair!;
|
||||
r17r18 named("r17", "r18") aliases(r17, r18) bytes8! pair!;
|
||||
r15r16 named("r15", "r16") aliases(r15, r16) bytes8! pair!;
|
||||
r13r14 named("r13", "r14") aliases(r13, r14) bytes8! pair!;
|
||||
|
||||
cr0 "cr0" cr!;
|
||||
f14 bytes4! float! volatile;
|
||||
f13 bytes4! float! volatile;
|
||||
f12 bytes4! float! volatile;
|
||||
f11 bytes4! float! volatile;
|
||||
f10 bytes4! float! volatile;
|
||||
f9 bytes4! float! volatile;
|
||||
f8 bytes4! float! volatile;
|
||||
f7 bytes4! float! volatile;
|
||||
f6 bytes4! float! volatile;
|
||||
f5 bytes4! float! volatile;
|
||||
f4 bytes4! float! volatile;
|
||||
f3 bytes4! float! volatile fret;
|
||||
f2 bytes4! float! volatile;
|
||||
f1 bytes4! float! volatile;
|
||||
f0 bytes4! float! volatile;
|
||||
|
||||
f31 bytes4! float!;
|
||||
f30 bytes4! float!;
|
||||
f29 bytes4! float!;
|
||||
f28 bytes4! float!;
|
||||
f27 bytes4! float!;
|
||||
f26 bytes4! float!;
|
||||
f25 bytes4! float!;
|
||||
f24 bytes4! float!;
|
||||
f23 bytes4! float!;
|
||||
f22 bytes4! float!;
|
||||
f21 bytes4! float!;
|
||||
f20 bytes4! float!;
|
||||
f19 bytes4! float!;
|
||||
f18 bytes4! float!;
|
||||
f17 bytes4! float!;
|
||||
f16 bytes4! float!;
|
||||
f15 bytes4! float!;
|
||||
|
||||
d14 named("f14") aliases(f14) bytes8! double! volatile;
|
||||
d13 named("f13") aliases(f13) bytes8! double! volatile;
|
||||
d12 named("f12") aliases(f12) bytes8! double! volatile;
|
||||
d11 named("f11") aliases(f11) bytes8! double! volatile;
|
||||
d10 named("f10") aliases(f10) bytes8! double! volatile;
|
||||
d9 named("f9") aliases(f9) bytes8! double! volatile;
|
||||
d8 named("f8") aliases(f8) bytes8! double! volatile;
|
||||
d7 named("f7") aliases(f7) bytes8! double! volatile;
|
||||
d6 named("f6") aliases(f6) bytes8! double! volatile;
|
||||
d5 named("f5") aliases(f5) bytes8! double! volatile;
|
||||
d4 named("f4") aliases(f4) bytes8! double! volatile;
|
||||
d3 named("f3") aliases(f3) bytes8! double! volatile dret;
|
||||
d2 named("f2") aliases(f2) bytes8! double! volatile;
|
||||
d1 named("f1") aliases(f1) bytes8! double! volatile;
|
||||
d0 named("f0") aliases(f0) bytes8! double! volatile;
|
||||
|
||||
d31 named("f31") aliases(f31) bytes8! double!;
|
||||
d30 named("f30") aliases(f30) bytes8! double!;
|
||||
d29 named("f29") aliases(f29) bytes8! double!;
|
||||
d28 named("f28") aliases(f28) bytes8! double!;
|
||||
d27 named("f27") aliases(f27) bytes8! double!;
|
||||
d26 named("f26") aliases(f26) bytes8! double!;
|
||||
d25 named("f25") aliases(f25) bytes8! double!;
|
||||
d24 named("f24") aliases(f24) bytes8! double!;
|
||||
d23 named("f23") aliases(f23) bytes8! double!;
|
||||
d22 named("f22") aliases(f22) bytes8! double!;
|
||||
d21 named("f21") aliases(f21) bytes8! double!;
|
||||
d20 named("f20") aliases(f20) bytes8! double!;
|
||||
d19 named("f19") aliases(f19) bytes8! double!;
|
||||
d18 named("f18") aliases(f18) bytes8! double!;
|
||||
d17 named("f17") aliases(f17) bytes8! double!;
|
||||
d16 named("f16") aliases(f16) bytes8! double!;
|
||||
d15 named("f15") aliases(f15) bytes8! double!;
|
||||
|
||||
cr0 cr!;
|
||||
|
||||
|
||||
|
||||
|
@ -101,6 +152,11 @@ PATTERNS
|
|||
emit "stwu %in, -4(sp)"
|
||||
cost 4;
|
||||
|
||||
PUSH8(in:(pair)reg)
|
||||
emit "stwu %in.0, -4(sp)"
|
||||
emit "stwu %in.1, -4(sp)"
|
||||
cost 8;
|
||||
|
||||
out:(int)reg = POP4
|
||||
emit "lwz %out, 0(sp)"
|
||||
emit "addi sp, sp, 4"
|
||||
|
@ -113,12 +169,20 @@ PATTERNS
|
|||
|
||||
SETRET4(in:(ret)reg)
|
||||
emit "! setret4"
|
||||
cost 4;
|
||||
cost 1;
|
||||
|
||||
SETRET8(in:(pret)reg)
|
||||
emit "! setret8"
|
||||
cost 1;
|
||||
|
||||
(ret)reg = GETRET4
|
||||
emit "! getret4"
|
||||
cost 1;
|
||||
|
||||
(pret)reg = GETRET8
|
||||
emit "! getret8"
|
||||
cost 1;
|
||||
|
||||
STACKADJUST4(delta:CONST4)
|
||||
when signed_constant(%delta, 16)
|
||||
emit "addi sp, sp, $delta"
|
||||
|
@ -142,6 +206,11 @@ PATTERNS
|
|||
|
||||
/* Stores */
|
||||
|
||||
STORE8(addr:address, value:(pair)reg)
|
||||
emit "stw %value.0, 4+%addr"
|
||||
emit "stw %value.1, 0+%addr"
|
||||
cost 4;
|
||||
|
||||
STORE4(addr:address, value:(int)reg)
|
||||
emit "stw %value, %addr"
|
||||
cost 4;
|
||||
|
@ -168,6 +237,11 @@ PATTERNS
|
|||
emit "lwz %out, %addr"
|
||||
cost 4;
|
||||
|
||||
out:(pair)reg = LOAD8(addr:address)
|
||||
emit "lwz %out.0, 4+%addr"
|
||||
emit "lwz %out.1, 0+%addr"
|
||||
cost 8;
|
||||
|
||||
out:(int)ushort0 = LOAD2(addr:address)
|
||||
emit "lhz %out, %addr"
|
||||
cost 4;
|
||||
|
@ -480,6 +554,10 @@ PATTERNS
|
|||
emit "lfs %out, %addr"
|
||||
cost 4;
|
||||
|
||||
out:(double)reg = LOADF8(addr:address)
|
||||
emit "lfd %out, %addr"
|
||||
cost 4;
|
||||
|
||||
out:(float)reg = value:CONSTF4
|
||||
emit "lfs %out, address-containing-$value"
|
||||
cost 8;
|
||||
|
@ -488,6 +566,10 @@ PATTERNS
|
|||
emit "fadds %out, %left, %right"
|
||||
cost 4;
|
||||
|
||||
out:(double)reg = ADDF8(left:(double)reg, right:(double)reg)
|
||||
emit "fadd %out, %left, %right"
|
||||
cost 4;
|
||||
|
||||
out:(float)reg = SUBF4(left:(float)reg, right:(float)reg)
|
||||
emit "fsubs %out, %left, %right"
|
||||
cost 4;
|
||||
|
|
|
@ -31,17 +31,19 @@ void hop_add_string_insel(struct hop* hop, const char* string)
|
|||
array_append(&hop->insels, insel);
|
||||
}
|
||||
|
||||
void hop_add_hreg_insel(struct hop* hop, struct hreg* hreg)
|
||||
void hop_add_hreg_insel(struct hop* hop, struct hreg* hreg, int index)
|
||||
{
|
||||
struct insel* insel = new_insel(INSEL_HREG);
|
||||
insel->u.hreg = hreg;
|
||||
insel->index = index;
|
||||
array_append(&hop->insels, insel);
|
||||
}
|
||||
|
||||
void hop_add_vreg_insel(struct hop* hop, struct vreg* vreg)
|
||||
void hop_add_vreg_insel(struct hop* hop, struct vreg* vreg, int index)
|
||||
{
|
||||
struct insel* insel = new_insel(INSEL_VREG);
|
||||
insel->u.vreg = vreg;
|
||||
insel->index = index;
|
||||
array_append(&hop->insels, insel);
|
||||
}
|
||||
|
||||
|
@ -108,11 +110,11 @@ void hop_add_insel(struct hop* hop, const char* fmt, ...)
|
|||
break;
|
||||
|
||||
case 'H':
|
||||
hop_add_hreg_insel(hop, va_arg(ap, struct hreg*));
|
||||
hop_add_hreg_insel(hop, va_arg(ap, struct hreg*), 0);
|
||||
break;
|
||||
|
||||
case 'V':
|
||||
hop_add_vreg_insel(hop, va_arg(ap, struct vreg*));
|
||||
hop_add_vreg_insel(hop, va_arg(ap, struct vreg*), 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -205,7 +207,7 @@ char* hop_render(struct hop* hop)
|
|||
case INSEL_HREG:
|
||||
{
|
||||
struct hreg* hreg = insel->u.hreg;
|
||||
appendf("%s", hreg->realname);
|
||||
appendf("%s", hreg->brd->names[insel->index]);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -216,7 +218,7 @@ char* hop_render(struct hop* hop)
|
|||
if (!hreg)
|
||||
hreg = pmap_findright(&hop->regsout, vreg);
|
||||
if (hreg)
|
||||
appendf("%s", hreg->realname);
|
||||
appendf("%s", hreg->brd->names[insel->index]);
|
||||
else
|
||||
appendf("%%%d", vreg->id);
|
||||
break;
|
||||
|
|
|
@ -16,6 +16,7 @@ enum insel_type
|
|||
struct insel
|
||||
{
|
||||
enum insel_type type;
|
||||
int index;
|
||||
union
|
||||
{
|
||||
const char* string;
|
||||
|
@ -54,8 +55,8 @@ struct hop
|
|||
extern struct hop* new_hop(struct basicblock* bb, struct ir* ir);
|
||||
|
||||
extern void hop_add_string_insel(struct hop* hop, const char* string);
|
||||
extern void hop_add_hreg_insel(struct hop* hop, struct hreg* hreg);
|
||||
extern void hop_add_vreg_insel(struct hop* hop, struct vreg* vreg);
|
||||
extern void hop_add_hreg_insel(struct hop* hop, struct hreg* hreg, int index);
|
||||
extern void hop_add_vreg_insel(struct hop* hop, struct vreg* vreg, int index);
|
||||
extern void hop_add_value_insel(struct hop* hop, struct ir* ir);
|
||||
extern void hop_add_st_offset_insel(struct hop* hop, struct hreg* hreg);
|
||||
extern void hop_add_ab_offset_insel(struct hop* hop, int offset);
|
||||
|
|
|
@ -32,9 +32,9 @@ void burm_panic_cannot_match(struct burm_node* node)
|
|||
exit(1);
|
||||
}
|
||||
|
||||
static void emit_return_reg(void)
|
||||
static void emit_return_reg(int index)
|
||||
{
|
||||
hop_add_vreg_insel(current_hop, current_hop->output);
|
||||
hop_add_vreg_insel(current_hop, current_hop->output, index);
|
||||
}
|
||||
|
||||
static struct vreg* find_vreg_of_child(int child)
|
||||
|
@ -47,13 +47,13 @@ static struct vreg* find_vreg_of_child(int child)
|
|||
return insn->ir->result;
|
||||
}
|
||||
|
||||
static void emit_reg(int child)
|
||||
static void emit_reg(int child, int index)
|
||||
{
|
||||
struct vreg* vreg = find_vreg_of_child(child);
|
||||
|
||||
if (vreg)
|
||||
{
|
||||
hop_add_vreg_insel(current_hop, vreg);
|
||||
hop_add_vreg_insel(current_hop, vreg, index);
|
||||
array_appendu(&vreg->used, current_hop);
|
||||
}
|
||||
}
|
||||
|
@ -109,7 +109,7 @@ static uint32_t find_type_from_constraint(uint32_t attr)
|
|||
* this. */
|
||||
|
||||
const struct burm_register_data* brd = burm_register_data;
|
||||
while (brd->name)
|
||||
while (brd->id)
|
||||
{
|
||||
if (brd->attrs & attr)
|
||||
return brd->type;
|
||||
|
|
|
@ -48,7 +48,7 @@ static void promote(struct ir* ir)
|
|||
{
|
||||
int i;
|
||||
for (i=0; i<ir->u.phivalue.count; i++)
|
||||
array_appendu(&promotable, ir->u.phivalue.item[i].right);
|
||||
promote(ir->u.phivalue.item[i].right);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,14 +20,30 @@ static bool type_match(struct hreg* hreg, struct vreg* vreg);
|
|||
|
||||
static void populate_hregs(void)
|
||||
{
|
||||
int i;
|
||||
const struct burm_register_data* brd = burm_register_data;
|
||||
|
||||
hregs.count = 0;
|
||||
while (brd->name)
|
||||
while (brd->id)
|
||||
{
|
||||
array_append(&hregs, new_hreg(brd));
|
||||
brd++;
|
||||
}
|
||||
|
||||
/* Wire up the register aliases. */
|
||||
|
||||
for (i=0; i<hregs.count; i++)
|
||||
{
|
||||
struct hreg* hreg = hregs.item[i];
|
||||
const struct burm_register_data** alias = hreg->brd->aliases;
|
||||
|
||||
while (*alias)
|
||||
{
|
||||
int index = *alias - burm_register_data;
|
||||
array_append(&hreg->aliases, hregs.item[index]);
|
||||
alias++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void wire_up_blocks_ins_outs(void)
|
||||
|
@ -43,6 +59,20 @@ static void wire_up_blocks_ins_outs(void)
|
|||
}
|
||||
}
|
||||
|
||||
static bool register_used(register_assignment_t* regs, struct hreg* hreg)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0; i<hreg->aliases.count; i++)
|
||||
{
|
||||
struct hreg* alias = hreg->aliases.item[i];
|
||||
if (pmap_findleft(regs, alias))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static struct hreg* allocate_phi_hreg(register_assignment_t* regs,
|
||||
struct vreg* vreg, uint32_t type)
|
||||
{
|
||||
|
@ -54,7 +84,7 @@ static struct hreg* allocate_phi_hreg(register_assignment_t* regs,
|
|||
for (i=0; i<hregs.count; i++)
|
||||
{
|
||||
struct hreg* hreg = hregs.item[i];
|
||||
if (!pmap_findleft(regs, hreg) && (hreg->type == type))
|
||||
if (!register_used(regs, hreg) && (hreg->type == type))
|
||||
{
|
||||
/* This one is unused. Use it. */
|
||||
return hreg;
|
||||
|
@ -86,7 +116,10 @@ static struct hreg* evict(struct vreg* vreg)
|
|||
|
||||
if (evictable(hreg, vreg))
|
||||
{
|
||||
if (!candidatein && !candidateout)
|
||||
if (!candidatein &&
|
||||
!candidateout &&
|
||||
!register_used(current_ins, hreg) &&
|
||||
!register_used(current_outs, hreg))
|
||||
{
|
||||
/* This hreg is unused, so we don't need to evict anything.
|
||||
* Shouldn't really happen in real life. */
|
||||
|
@ -95,7 +128,7 @@ static struct hreg* evict(struct vreg* vreg)
|
|||
if (candidatein == candidateout)
|
||||
{
|
||||
/* This is a through register. */
|
||||
tracef('R', "R: evicting %%%d from %s\n", candidatein->id, hreg->name);
|
||||
tracef('R', "R: evicting %%%d from %s\n", candidatein->id, hreg->id);
|
||||
pmap_put(&evicted, candidatein, hreg);
|
||||
pmap_remove(current_ins, hreg, candidatein);
|
||||
pmap_remove(current_outs, hreg, candidatein);
|
||||
|
@ -120,13 +153,13 @@ static bool type_match(struct hreg* hreg, struct vreg* vreg)
|
|||
|
||||
static bool allocatable_stackable_input(struct hreg* hreg, struct vreg* vreg)
|
||||
{
|
||||
return !pmap_findleft(current_ins, hreg) &&
|
||||
return !register_used(current_ins, hreg) &&
|
||||
type_match(hreg, vreg);
|
||||
}
|
||||
|
||||
static bool allocatable_stackable_output(struct hreg* hreg, struct vreg* vreg)
|
||||
{
|
||||
return !pmap_findleft(current_outs, hreg) &&
|
||||
return !register_used(current_outs, hreg) &&
|
||||
type_match(hreg, vreg) &&
|
||||
!(hreg->attrs & current_hop->insndata->corrupts);
|
||||
}
|
||||
|
@ -295,7 +328,7 @@ static void add_output_register(struct vreg* vreg)
|
|||
|
||||
pmap_add(current_outs, hreg, vreg);
|
||||
tracef('R', "R: output equality constraint requires extra move of %%%d => %s\n",
|
||||
c->equals_to->id, hreg->name);
|
||||
c->equals_to->id, hreg->id);
|
||||
pmap_add(current_ins, hreg, c->equals_to);
|
||||
}
|
||||
else
|
||||
|
@ -332,7 +365,7 @@ static void add_through_register(struct vreg* vreg, struct hreg* hreg)
|
|||
/* Nope, can't honour the hint. Mark the register as evicted; we'll
|
||||
* put it in something later (probably a stack slot). */
|
||||
|
||||
tracef('R', "R: cannot place %%%d in %s, evicting\n", vreg->id, hreg->name);
|
||||
tracef('R', "R: cannot place %%%d in %s, evicting\n", vreg->id, hreg->id);
|
||||
pmap_put(&evicted, vreg, hreg);
|
||||
pmap_remove(current_ins, hreg, vreg);
|
||||
pmap_remove(current_outs, hreg, vreg);
|
||||
|
@ -372,7 +405,7 @@ static void find_new_home_for_evicted_register(struct vreg* vreg, struct hreg* s
|
|||
array_append(&hregs, hreg);
|
||||
|
||||
found:
|
||||
tracef('R', "R: evicted %%%d moving to %s\n", vreg->id, hreg->name);
|
||||
tracef('R', "R: evicted %%%d moving to %s\n", vreg->id, hreg->id);
|
||||
pmap_add(current_ins, hreg, vreg);
|
||||
pmap_add(current_outs, hreg, vreg);
|
||||
}
|
||||
|
@ -452,7 +485,7 @@ static void assign_hregs_to_vregs(void)
|
|||
if (hreg)
|
||||
{
|
||||
tracef('R', "R: import hreg %s for input %%%d from %s\n",
|
||||
hreg->name, vreg->id, prevbb->name);
|
||||
hreg->id, vreg->id, prevbb->name);
|
||||
assert(!pmap_findleft(old, hreg));
|
||||
pmap_put(old, hreg, vreg);
|
||||
goto nextvreg;
|
||||
|
@ -482,7 +515,7 @@ static void assign_hregs_to_vregs(void)
|
|||
if (hreg && !pmap_findleft(old, hreg))
|
||||
{
|
||||
tracef('R', "R: import hreg %s for phi input %%%d from %s\n",
|
||||
hreg->name, vreg->id, phi->prev->name);
|
||||
hreg->id, vreg->id, phi->prev->name);
|
||||
pmap_put(old, hreg, vreg);
|
||||
}
|
||||
}
|
||||
|
@ -503,7 +536,7 @@ static void assign_hregs_to_vregs(void)
|
|||
struct hreg* hreg = allocate_phi_hreg(old, vreg, c->type);
|
||||
|
||||
tracef('R', "R: import fallback hreg %s for phi input %%%d from %s\n",
|
||||
hreg->name, vreg->id, phi->prev->name);
|
||||
hreg->id, vreg->id, phi->prev->name);
|
||||
pmap_add(old, hreg, vreg);
|
||||
}
|
||||
}
|
||||
|
@ -525,7 +558,7 @@ static void assign_hregs_to_vregs(void)
|
|||
struct vreg* vreg = hop->regsin.item[k].right;
|
||||
if (k != 0)
|
||||
tracef('R', " ");
|
||||
tracef('R', "%%%d=>%s", vreg->id, hreg->name);
|
||||
tracef('R', "%%%d=>%s", vreg->id, hreg->id);
|
||||
}
|
||||
tracef('R', "] [");
|
||||
for (k=0; k<hop->regsout.count; k++)
|
||||
|
@ -534,7 +567,7 @@ static void assign_hregs_to_vregs(void)
|
|||
struct vreg* vreg = hop->regsout.item[k].right;
|
||||
if (k != 0)
|
||||
tracef('R', " ");
|
||||
tracef('R', "%%%d=>%s", vreg->id, hreg->name);
|
||||
tracef('R', "%%%d=>%s", vreg->id, hreg->id);
|
||||
}
|
||||
tracef('R', "]\n");
|
||||
|
||||
|
@ -551,9 +584,9 @@ static struct hop* create_swap(struct basicblock* bb, struct hreg* src, struct h
|
|||
struct hop* hop = new_hop(bb, NULL);
|
||||
|
||||
hop_add_string_insel(hop, "! swap ");
|
||||
hop_add_hreg_insel(hop, src);
|
||||
hop_add_hreg_insel(hop, src, 0);
|
||||
hop_add_string_insel(hop, " <-> ");
|
||||
hop_add_hreg_insel(hop, dest);
|
||||
hop_add_hreg_insel(hop, dest, 0);
|
||||
hop_add_eoi_insel(hop);
|
||||
|
||||
return hop;
|
||||
|
@ -661,7 +694,7 @@ static void insert_phi_copies(void)
|
|||
|
||||
tracef('R', "R: map %%%d -> %%%d (%s)\n",
|
||||
phi->ir->result->id,
|
||||
vreg->id, dest->name);
|
||||
vreg->id, dest->id);
|
||||
|
||||
pmap_put(&destregs, dest, phi->ir->result);
|
||||
}
|
||||
|
|
|
@ -12,11 +12,12 @@ struct vreg* new_vreg(void)
|
|||
struct hreg* new_hreg(const struct burm_register_data* brd)
|
||||
{
|
||||
struct hreg* hreg = calloc(1, sizeof *hreg);
|
||||
hreg->name = brd->name;
|
||||
hreg->realname = brd->realname;
|
||||
hreg->id = brd->id;
|
||||
hreg->brd = brd;
|
||||
hreg->type = brd->type;
|
||||
hreg->attrs = brd->attrs;
|
||||
hreg->is_stacked = false;
|
||||
/* The aliases array needs to be initialised later. */
|
||||
return hreg;
|
||||
}
|
||||
|
||||
|
@ -24,12 +25,12 @@ struct hreg* new_stacked_hreg(uint32_t type)
|
|||
{
|
||||
static int hreg_count = 1;
|
||||
struct hreg* hreg = calloc(1, sizeof *hreg);
|
||||
hreg->name = aprintf("stacked_%d_id_%d", type, hreg_count++);
|
||||
hreg->realname = hreg->name;
|
||||
hreg->id = aprintf("stacked_%d_id_%d", type, hreg_count++);
|
||||
hreg->type = type;
|
||||
hreg->attrs = type;
|
||||
hreg->is_stacked = true;
|
||||
hreg->offset = -1;
|
||||
array_append(&hreg->aliases, hreg);
|
||||
return hreg;
|
||||
}
|
||||
|
||||
|
|
|
@ -13,12 +13,13 @@ struct phicongruence
|
|||
|
||||
struct hreg
|
||||
{
|
||||
const char* name;
|
||||
const char* realname;
|
||||
const char* id;
|
||||
const struct burm_register_data* brd;
|
||||
uint32_t type;
|
||||
uint32_t attrs;
|
||||
bool is_stacked;
|
||||
int offset;
|
||||
ARRAYOF(struct hreg) aliases;
|
||||
};
|
||||
|
||||
struct vreg
|
||||
|
|
|
@ -495,6 +495,16 @@ static void insn_ivalue(int opcode, arith value)
|
|||
);
|
||||
break;
|
||||
|
||||
case op_sdl:
|
||||
appendir(
|
||||
new_ir2(
|
||||
IR_STORE, EM_wordsize*2,
|
||||
new_localir(value),
|
||||
pop(EM_wordsize*2)
|
||||
)
|
||||
);
|
||||
break;
|
||||
|
||||
case op_lal:
|
||||
push(
|
||||
new_localir(value)
|
||||
|
@ -972,6 +982,15 @@ static void insn_lvalue(int opcode, const char* label, arith offset)
|
|||
);
|
||||
break;
|
||||
|
||||
case op_lde:
|
||||
push(
|
||||
new_ir1(
|
||||
IR_LOAD, EM_wordsize*2,
|
||||
address_of_external(label, offset)
|
||||
)
|
||||
);
|
||||
break;
|
||||
|
||||
case op_ste:
|
||||
appendir(
|
||||
new_ir2(
|
||||
|
@ -982,6 +1001,16 @@ static void insn_lvalue(int opcode, const char* label, arith offset)
|
|||
);
|
||||
break;
|
||||
|
||||
case op_sde:
|
||||
appendir(
|
||||
new_ir2(
|
||||
IR_STORE, EM_wordsize*2,
|
||||
address_of_external(label, offset),
|
||||
pop(EM_wordsize*2)
|
||||
)
|
||||
);
|
||||
break;
|
||||
|
||||
case op_zre:
|
||||
appendir(
|
||||
new_ir2(
|
||||
|
|
|
@ -33,6 +33,7 @@ extern int yylex(void);
|
|||
%term EMIT
|
||||
%term EQUALS
|
||||
%term FRAGMENT
|
||||
%term NAMED
|
||||
%term NOTEQUALS
|
||||
%term PATTERNS
|
||||
%term PREFERS
|
||||
|
@ -44,7 +45,6 @@ extern int yylex(void);
|
|||
%token <string> ID
|
||||
%token <string> QFRAGMENT
|
||||
|
||||
%type <stringlist> aliases;
|
||||
%type <constraint> constraint
|
||||
%type <constraint> constraints
|
||||
%type <expr> predicate
|
||||
|
@ -55,6 +55,8 @@ extern int yylex(void);
|
|||
%type <rule> pattern
|
||||
%type <rule> pattern_constraints
|
||||
%type <rule> pattern_emit
|
||||
%type <stringlist> aliases;
|
||||
%type <stringlist> names;
|
||||
%type <stringlist> qfragments
|
||||
%type <terminfo> terminfo
|
||||
%type <tree> rhs
|
||||
|
@ -73,12 +75,18 @@ registers
|
|||
;
|
||||
|
||||
register
|
||||
: ID QFRAGMENT { $$ = makereg($1, $2); }
|
||||
: ID { $$ = makereg($1); }
|
||||
| register NAMED '(' names ')' { $$ = $1; setregnames($$, $4); }
|
||||
| register ALIASES '(' aliases ')' { $$ = $1; addregaliases($$, $4); }
|
||||
| register ID { $$ = $1; addregattr($1, $2, false); }
|
||||
| register ID '!' { $$ = $1; addregattr($1, $2, true); }
|
||||
;
|
||||
|
||||
names
|
||||
: QFRAGMENT { $$ = calloc(1, sizeof(*$$)); stringlist_add($$, $1); }
|
||||
| names ',' QFRAGMENT { $$ = $1; stringlist_add($$, $3); }
|
||||
;
|
||||
|
||||
aliases
|
||||
: ID { $$ = calloc(1, sizeof(*$$)); stringlist_add($$, $1); }
|
||||
| aliases ',' ID { $$ = $1; stringlist_add($$, $3); }
|
||||
|
|
|
@ -268,7 +268,7 @@ static void* install(const char* name)
|
|||
return &p->sym;
|
||||
}
|
||||
|
||||
struct reg* makereg(const char* id, const char* realname)
|
||||
struct reg* makereg(const char* id)
|
||||
{
|
||||
struct reg* p = smap_get(®isters, id);
|
||||
static int number = 0;
|
||||
|
@ -277,7 +277,6 @@ struct reg* makereg(const char* id, const char* realname)
|
|||
yyerror("redefinition of '%s'", id);
|
||||
p = calloc(1, sizeof(*p));
|
||||
p->name = id;
|
||||
p->realname = realname;
|
||||
p->number = number++;
|
||||
array_append(&p->aliases, p);
|
||||
smap_put(®isters, id, p);
|
||||
|
@ -285,6 +284,14 @@ struct reg* makereg(const char* id, const char* realname)
|
|||
return p;
|
||||
}
|
||||
|
||||
void setregnames(struct reg* reg, struct stringlist* names)
|
||||
{
|
||||
if (reg->names)
|
||||
yyerror("you can only set one set of register names");
|
||||
|
||||
reg->names = names;
|
||||
}
|
||||
|
||||
struct regattr* makeregattr(const char* id)
|
||||
{
|
||||
struct regattr* p = smap_get(®isterattrs, id);
|
||||
|
@ -629,14 +636,33 @@ static void emitregisters(void)
|
|||
print("NULL\n};\n");
|
||||
}
|
||||
|
||||
for (i=0; i<registers.count; i++)
|
||||
{
|
||||
struct reg* r = registers.item[i].right;
|
||||
|
||||
print("const char* %Pregister_names_%d_%s[] = {\n%1", i, r->name);
|
||||
if (r->names)
|
||||
{
|
||||
struct stringfragment* f = r->names->first;
|
||||
while (f)
|
||||
{
|
||||
print("\"%s\", ", f->data);
|
||||
f = f->next;
|
||||
}
|
||||
}
|
||||
else
|
||||
print("\"%s\", ", r->name);
|
||||
print("NULL\n};\n");
|
||||
}
|
||||
|
||||
print("const struct %Pregister_data %Pregister_data[] = {\n");
|
||||
for (i=0; i<registers.count; i++)
|
||||
{
|
||||
struct reg* r = registers.item[i].right;
|
||||
assert(r->number == i);
|
||||
|
||||
print("%1{ \"%s\", \"%s\", 0x%x, 0x%x, %Pregister_aliases_%d_%s },\n",
|
||||
r->name, r->realname, r->type, r->attrs, i, r->name);
|
||||
print("%1{ \"%s\", 0x%x, 0x%x, %Pregister_names_%d_%s, %Pregister_aliases_%d_%s },\n",
|
||||
r->name, r->type, r->attrs, i, r->name, i, r->name);
|
||||
}
|
||||
print("%1{ NULL }\n");
|
||||
print("};\n\n");
|
||||
|
@ -1215,14 +1241,18 @@ static void emitinsndata(Rule rules)
|
|||
|
||||
while (f)
|
||||
{
|
||||
switch (f->data[0])
|
||||
char* data = strdup(f->data);
|
||||
int type = *data++;
|
||||
char* label = strtok(data, ".");
|
||||
char* nameindex_s = strtok(NULL, ".");
|
||||
int nameindex = nameindex_s ? atoi(nameindex_s) : 0;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case '%':
|
||||
{
|
||||
const char* label = f->data + 1;
|
||||
|
||||
if (r->label && (strcmp(label, r->label) == 0))
|
||||
print("%1data->emit_return_reg();\n", label);
|
||||
print("%1data->emit_return_reg(%d);\n", nameindex);
|
||||
else
|
||||
{
|
||||
Tree node;
|
||||
|
@ -1234,25 +1264,25 @@ static void emitinsndata(Rule rules)
|
|||
if (nt->kind == NONTERM)
|
||||
{
|
||||
if (nt->is_fragment)
|
||||
print("%1data->emit_fragment(");
|
||||
print("%1data->emit_fragment(%d);\n", index);
|
||||
else
|
||||
print("%1data->emit_reg(");
|
||||
print("%1data->emit_reg(%d, %d);\n", index, nameindex);
|
||||
}
|
||||
else
|
||||
print("%1data->emit_reg(");
|
||||
|
||||
print("%d);\n", index);
|
||||
print("%1data->emit_reg(%d, %d);\n", index, nameindex);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case '$':
|
||||
{
|
||||
const char* label = f->data + 1;
|
||||
int index = 0;
|
||||
if (!find_child_index(r->pattern, label, &index, NULL))
|
||||
label_not_found(r, label);
|
||||
|
||||
if (nameindex != 0)
|
||||
yyerror("indices other than 0 make no sense for $-values");
|
||||
|
||||
print("%1data->emit_value(%d);\n", index);
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -59,10 +59,10 @@ struct terminfo
|
|||
struct reg
|
||||
{
|
||||
const char* name; /* friendly register name */
|
||||
const char* realname; /* name used in assembly output */
|
||||
int number; /* identifying number */
|
||||
uint32_t attrs; /* bitfield of register attributes */
|
||||
uint32_t type; /* register type */
|
||||
struct stringlist* names; /* register names */
|
||||
ARRAYOF(struct reg) aliases; /* registers that this one aliases */
|
||||
};
|
||||
|
||||
|
@ -72,7 +72,8 @@ struct regattr
|
|||
int number; /* identifying number */
|
||||
};
|
||||
|
||||
extern struct reg* makereg(const char* name, const char* realname);
|
||||
extern struct reg* makereg(const char* name);
|
||||
extern void setregnames(struct reg* reg, struct stringlist* names);
|
||||
extern void addregattr(struct reg* reg, const char* regattr, bool exact);
|
||||
extern void addregaliases(struct reg* reg, struct stringlist* aliases);
|
||||
extern struct regattr* getregattr(const char* name);
|
||||
|
|
|
@ -23,6 +23,7 @@ S POPF
|
|||
S LOAD # must be followed by float form
|
||||
S LOADF
|
||||
S STORE
|
||||
S STOREF
|
||||
|
||||
# Arithemetic operations
|
||||
S ADD
|
||||
|
|
|
@ -40,8 +40,8 @@ struct burm_emitter_data
|
|||
{
|
||||
void (*emit_string)(const char* data);
|
||||
void (*emit_fragment)(int child);
|
||||
void (*emit_return_reg)(void);
|
||||
void (*emit_reg)(int child);
|
||||
void (*emit_return_reg)(int index);
|
||||
void (*emit_reg)(int child, int index);
|
||||
void (*emit_value)(int child);
|
||||
void (*emit_eoi)(void);
|
||||
void (*constrain_input_reg)(int child, uint32_t attr);
|
||||
|
@ -63,10 +63,10 @@ extern const struct burm_instruction_data burm_instruction_data[];
|
|||
|
||||
struct burm_register_data
|
||||
{
|
||||
const char* name;
|
||||
const char* realname;
|
||||
const char* id;
|
||||
uint32_t type;
|
||||
uint32_t attrs;
|
||||
const char** names;
|
||||
const struct burm_register_data** aliases;
|
||||
};
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@ static int braces = 0;
|
|||
<INITIAL>"\"" BEGIN(QSTRING);
|
||||
<QSTRING>"\"" BEGIN(INITIAL);
|
||||
|
||||
<QSTRING>[%$][a-zA-Z_][a-zA_Z_0-9]+ {
|
||||
<QSTRING>[%$][a-zA-Z_][a-zA_Z_0-9]+(\.[0-9]+)? {
|
||||
yylval.string = strdup(yytext);
|
||||
return QFRAGMENT;
|
||||
}
|
||||
|
@ -44,6 +44,7 @@ static int braces = 0;
|
|||
"cost" return COST;
|
||||
"emit" return EMIT;
|
||||
"fragment" return FRAGMENT;
|
||||
"named" return NAMED;
|
||||
"prefers" return PREFERS;
|
||||
"when" return WHEN;
|
||||
"with" return WITH;
|
||||
|
|
Loading…
Reference in a new issue