ack/mach/proto/mcg/hop.c
David Given b5c1d622f5 Rework the way stack frames are laid out to be simpler and, hopefully, more
correct. Saved registers are now placed in what may be the right place.
2016-11-11 21:17:45 +01:00

329 lines
7.5 KiB
C

#include "mcg.h"
static int hop_count = 1;
static struct hop* current_hop;
static char* buffer = NULL;
static int bufferlen = 0;
static int buffersize = 0;
static const struct burm_emitter_data emitter_data;
struct hop* new_hop(struct basicblock* bb, struct ir* ir)
{
struct hop* hop = calloc(1, sizeof *hop);
hop->id = hop_count++;
hop->bb = bb;
hop->ir = ir;
return hop;
}
static struct insel* new_insel(enum insel_type type)
{
struct insel* insel = calloc(1, sizeof(*insel));
insel->type = type;
return insel;
}
void hop_add_string_insel(struct hop* hop, const char* string)
{
struct insel* insel = new_insel(INSEL_STRING);
insel->u.string = string;
array_append(&hop->insels, insel);
}
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, int index)
{
struct insel* insel = new_insel(INSEL_VREG);
insel->u.vreg = vreg;
insel->index = index;
array_append(&hop->insels, insel);
}
void hop_add_value_insel(struct hop* hop, struct ir* ir)
{
struct insel* insel = new_insel(INSEL_VALUE);
insel->u.value = ir;
array_append(&hop->insels, insel);
}
void hop_add_st_offset_insel(struct hop* hop, struct hreg* hreg)
{
struct insel* insel = new_insel(INSEL_ST_OFFSET);
insel->u.hreg = hreg;
array_append(&hop->insels, insel);
}
void hop_add_ab_offset_insel(struct hop* hop, int offset)
{
struct insel* insel = new_insel(INSEL_AB_OFFSET);
insel->u.offset = offset;
array_append(&hop->insels, insel);
}
void hop_add_lb_offset_insel(struct hop* hop, int offset)
{
struct insel* insel = new_insel(INSEL_LB_OFFSET);
insel->u.offset = offset;
array_append(&hop->insels, insel);
}
void hop_add_eoi_insel(struct hop* hop)
{
struct insel* insel = new_insel(INSEL_EOI);
array_append(&hop->insels, insel);
}
void hop_add_insel(struct hop* hop, const char* fmt, ...)
{
va_list ap;
va_start(ap, fmt);
while (*fmt)
{
if (*fmt == '%')
{
int index = 0;
fmt += 2;
again:
switch (fmt[-1])
{
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
index = fmt[-1] - '0';
fmt++;
goto again;
case 'd':
hop_add_string_insel(hop, aprintf("%d", va_arg(ap, int)));
break;
case 's':
hop_add_string_insel(hop, va_arg(ap, const char*));
break;
case 'S':
hop_add_st_offset_insel(hop, va_arg(ap, struct hreg*));
break;
case 'A':
hop_add_ab_offset_insel(hop, va_arg(ap, int));
break;
case 'L':
hop_add_lb_offset_insel(hop, va_arg(ap, int));
break;
case 'H':
hop_add_hreg_insel(hop, va_arg(ap, struct hreg*), index);
break;
case 'V':
hop_add_vreg_insel(hop, va_arg(ap, struct vreg*), index);
break;
}
}
else
{
const char* end = strchr(fmt, '%');
const char* s;
if (end)
{
int len = end - fmt;
s = strndup(fmt, len);
fmt = end;
}
else
{
s = fmt;
fmt += strlen(fmt);
}
hop_add_string_insel(hop, s);
}
}
hop_add_eoi_insel(hop);
va_end(ap);
}
static void print_header(char k, struct hop* hop)
{
int i;
tracef(k, "%c: %d", k, hop->id);
if (hop->ir)
tracef(k, " from $%d", hop->ir->id);
tracef(k, ":");
for (i=0; i<hop->ins.count; i++)
tracef(k, " r%%%d", hop->ins.item[i]->id);
for (i=0; i<hop->throughs.count; i++)
tracef(k, " =%%%d", hop->throughs.item[i]->id);
for (i=0; i<hop->outs.count; i++)
tracef(k, " w%%%d", hop->outs.item[i]->id);
tracef(k, " ");
}
static char* appendf(const char* fmt, ...)
{
int n;
char* p;
va_list ap;
va_start(ap, fmt);
n = bufferlen + vsnprintf(NULL, 0, fmt, ap) + 1;
va_end(ap);
if (n > buffersize)
{
buffersize *= 2;
if (buffersize < n)
buffersize = n*2;
buffer = realloc(buffer, buffersize);
}
va_start(ap, fmt);
vsprintf(buffer+bufferlen, fmt, ap);
va_end(ap);
bufferlen = n - 1; /* remember the \0 at the end */
return p;
}
char* hop_render(struct hop* hop)
{
int i;
appendf(""); /* ensure the buffer has been allocated */
bufferlen = 0;
buffer[0] = '\0';
for (i=0; i<hop->insels.count; i++)
{
struct insel* insel = hop->insels.item[i];
switch (insel->type)
{
case INSEL_EOI:
appendf("\n");
break;
case INSEL_HREG:
{
struct hreg* hreg = insel->u.hreg;
if (hreg->brd)
appendf("%s", hreg->brd->names[insel->index]);
else
appendf("%s.%d", hreg->id, insel->index);
break;
}
case INSEL_VREG:
{
struct vreg* vreg = insel->u.vreg;
struct hreg* hreg = pmap_findright(&hop->regsin, vreg);
if (!hreg)
hreg = pmap_findright(&hop->regsout, vreg);
if (hreg)
appendf("%s", hreg->brd->names[insel->index]);
else
appendf("%%%d.%d", vreg->id, insel->index);
break;
}
case INSEL_STRING:
appendf("%s", insel->u.string);
break;
case INSEL_ST_OFFSET:
appendf("%d", current_proc->fp_to_sb + insel->u.hreg->offset);
break;
case INSEL_AB_OFFSET:
appendf("%d", current_proc->fp_to_ab + insel->u.offset);
break;
case INSEL_LB_OFFSET:
appendf("%d", current_proc->fp_to_lb + insel->u.offset);
break;
case INSEL_VALUE:
{
struct ir* ir = insel->u.value;
switch (ir->opcode)
{
case IR_BLOCK:
appendf("%s", platform_label(ir->u.bvalue->name));
break;
case IR_LABEL:
appendf("%s", platform_label(ir->u.lvalue));
break;
case IR_LOCAL:
if (ir->u.ivalue >= 0)
appendf("%d", current_proc->fp_to_ab + ir->u.ivalue);
else
appendf("%d", current_proc->fp_to_lb + ir->u.ivalue);
break;
case IR_CONST:
appendf("%d", ir->u.ivalue);
break;
default:
assert(false);
}
break;
}
default:
assert(false);
}
}
return buffer;
}
void hop_print(char k, struct hop* hop)
{
int i;
bool soi = false;
char* p;
hop_render(hop);
p = strtok(buffer, "\n");
print_header(k, hop);
while (p)
{
tracef(k, "%s", p);
p = strtok(NULL, "\n");
if (p)
{
tracef(k, "\n");
print_header(k, hop);
}
}
tracef(k, "\n");
}
/* vim: set sw=4 ts=4 expandtab : */