Archival checking of the half-written IR treebuilder.

This commit is contained in:
David Given 2016-09-18 23:24:54 +02:00
parent f992eb28ac
commit 176cd7365c
16 changed files with 998 additions and 158 deletions

39
mach/proto/mcg/array.c Normal file
View file

@ -0,0 +1,39 @@
#include "mcg.h"
#include "array.h"
void array_append(void*** array, int* count, int* max, void* value)
{
if (*count == *max)
{
int newmax = (*max == 0) ? 8 : (*max * 2);
void** newarray = realloc(*array, newmax * sizeof(void*));
if (!newarray)
fatal("memory allocation failure");
*max = newmax;
*array = newarray;
}
(*array)[*count] = value;
(*count)++;
}
bool array_contains(void** array, int count, void* value)
{
int i;
for (i=0; i<count; i++)
if (array[i] == value)
return true;
return false;
}
void array_appendu(void*** array, int* count, int* max, void* value)
{
if (!array_contains(*array, *count, value))
array_append(array, count, max, value);
}
/* vim: set sw=4 ts=4 expandtab : */

23
mach/proto/mcg/array.h Normal file
View file

@ -0,0 +1,23 @@
#ifndef ARRAY_H
#define ARRAY_H
#define ARRAY(TYPE, NAME) \
TYPE** NAME; \
int NAME##_count; \
int NAME##_max
#define APPEND(ARRAY, VALUE) \
array_append((void***) &ARRAY, &ARRAY##_count, &ARRAY##_max, VALUE)
#define CONTAINS(ARRAY, VALUE) \
array_contains((void**) ARRAY, ARRAY##_count, VALUE)
#define APPENDU(ARRAY, VALUE) \
array_appendu((void***) &ARRAY, &ARRAY##_count, &ARRAY##_max, VALUE)
extern void array_append(void*** array, int* count, int* max, void* value);
extern bool array_contains(void** array, int count, void* value);
extern void array_appendu(void*** array, int* count, int* max, void* value);
#endif

View file

@ -0,0 +1,70 @@
#include "mcg.h"
static void init_idf();
static struct idf* str2idf(char* tg, int cp);
#define IDF_TYPE struct basicblock*
#define IDF_NAME block
#include <idf_pkg.spec>
#include <idf_pkg.body>
static int next_id = 0;
void bb_init(void)
{
init_idf();
}
struct basicblock* bb_get(const char* name)
{
struct idf* p;
if (!name)
name = aprintf("___anon_bb_%d", next_id++);
p = str2idf((char*) name, 0);
if (!p->block)
{
p->block = calloc(sizeof(struct basicblock), 1);
p->block->name = name;
}
return p->block;
}
void bb_alias(struct basicblock* block, const char* name)
{
struct idf* p = str2idf((char*) name, -1);
assert(p == NULL);
p = str2idf((char*) name, 0);
p->block = block;
}
void bb_wire_outs_to_ins(struct basicblock* inblock, struct basicblock* outblock)
{
int i;
if (!outblock->is_wired)
{
for (i=0; i<inblock->outs_count; i++)
{
struct ir* value = inblock->outs[i];
APPEND(outblock->ins,
new_phiir(value->size)
);
}
outblock->is_wired = true;
}
assert(inblock->outs_count == outblock->ins_count);
for (i=0; i<inblock->outs_count; i++)
{
struct ir* srcvalue = inblock->outs[i];
struct ir* destvalue = outblock->ins[i];
assert(srcvalue->size == destvalue->size);
assert(destvalue->opcode == IR_PHI);
APPENDU(destvalue->u.phivalue.srcs, srcvalue);
}
}
/* vim: set sw=4 ts=4 expandtab : */

View file

@ -1,12 +1,12 @@
normalrule {
name = "push_pop_c",
outleaves = { "push_pop.c" },
name = "ircodes",
outleaves = { "ircodes.h", "ircodes.c" },
ins = {
"./push_pop.awk",
"h/em_table"
"./ircodes.sh",
"./ir.dat"
},
commands = {
"awk -f %{ins[1]} %{ins[2]} > %{outs}"
"%{ins[1]} %{ins[2]} %{outs[1]} %{outs[2]}"
}
}
@ -14,16 +14,22 @@ cprogram {
name = "mcg",
srcs = {
"./*.c",
"+push_pop_c",
matching(filenamesof("+ircodes"), "%.c$")
},
deps = {
"+ircodes",
"h+emheaders",
"modules+headers",
"modules/src/read_em+lib_kv",
"modules/src/alloc+lib",
"modules/src/em_code+lib_k",
"modules/src/em_data+lib",
"modules/src/alloc+lib",
"modules/src/idf+lib",
"modules/src/read_em+lib_kv",
"modules/src/system+lib",
"./*.h",
},
vars = {
["+cflags"] = {"-Werror-implicit-function-declaration"}
}
}

113
mach/proto/mcg/data.c Normal file
View file

@ -0,0 +1,113 @@
#include "mcg.h"
#include <ctype.h>
static struct symbol* pending;
void data_label(const char* label)
{
if (pending)
fatal("two consecutive data labels ('%s' and '%s')",
pending->name, label);
pending = symbol_get(label);
if (pending->is_defined)
fatal("label '%s' defined twice", pending->name);
pending->is_defined = true;
}
static const char* section_to_str(int section)
{
switch (section)
{
case SECTION_ROM: return ".rom";
case SECTION_DATA: return ".data";
case SECTION_BSS: return ".bss";
case SECTION_TEXT: return ".text";
default: return "unknown";
}
}
static void emit_header(int desired_section)
{
if (pending)
{
if (pending->section == SECTION_UNKNOWN)
pending->section = desired_section;
else if (pending->section != desired_section)
fatal("label '%s' can't change sections", pending->name);
printf("\n.sect %s\n", section_to_str(pending->section));
printf("%s:\n", pending->name);
pending = NULL;
}
}
void data_int(arith data, size_t size, bool is_ro)
{
emit_header(is_ro ? SECTION_ROM : SECTION_DATA);
assert((size == 1) || (size == 2) || (size == 4) || (size == 8));
printf("\t.data%d 0x%0*lld\n", size, size*2, data);
}
void data_block(const uint8_t* data, size_t size, bool is_ro)
{
const uint8_t* start = data;
const uint8_t* end = data + size;
const uint8_t* p = data;
emit_header(is_ro ? SECTION_ROM : SECTION_DATA);
start = p = data;
while (p < end)
{
while ((p < end) && isprint(*p))
p++;
if (start < p)
{
printf("\t.ascii \"");
while (start < p)
{
printf("%c", *start);
start++;
}
printf("\"\n");
}
while ((p < end) && !isprint(*p))
p++;
if (start < p)
{
bool first = true;
printf("\t.data1 ");
while (start < p)
{
if (!first)
printf(", ");
printf("0x%02x", *start);
start++;
first = false;
}
printf("\n");
}
}
}
void data_offset(const char* label, arith offset, bool is_ro)
{
emit_header(is_ro ? SECTION_ROM : SECTION_DATA);
printf("\t.data%d %s+%lld\n", EM_pointersize, label, offset);
}
void data_bss(arith size, int init)
{
if (init != 0)
fatal("non-zero-initialised bss not supported");
emit_header(SECTION_BSS);
printf("\t.space %lld\n", size);
}
/* vim: set sw=4 ts=4 expandtab : */

137
mach/proto/mcg/ir.c Normal file
View file

@ -0,0 +1,137 @@
#include "mcg.h"
static int next_id = 0;
struct ir* new_ir0(int opcode, int size)
{
struct ir* ir = calloc(sizeof(struct ir), 1);
ir->id = next_id++;
ir->opcode = opcode;
ir->size = size;
switch (ir->opcode)
{
case IR_JUMP:
case IR_CJUMP:
ir->terminates = true;
break;
}
return ir;
}
struct ir* new_ir1(int opcode, int size,
struct ir* c1)
{
struct ir* ir = new_ir0(opcode, size);
ir->children[0] = c1;
return ir;
}
struct ir* new_ir2(int opcode, int size,
struct ir* c1, struct ir* c2)
{
struct ir* ir = new_ir0(opcode, size);
ir->children[0] = c1;
ir->children[1] = c2;
return ir;
}
struct ir* new_ir3(int opcode, int size,
struct ir* c1, struct ir* c2, struct ir* c3)
{
struct ir* ir = new_ir0(opcode, size);
ir->children[0] = c1;
ir->children[1] = c2;
ir->children[2] = c3;
return ir;
}
struct ir* new_labelir(const char* label)
{
struct ir* ir = new_ir0(IR_LABEL, EM_pointersize);
ir->u.lvalue = label;
return ir;
}
struct ir* new_wordir(arith value)
{
struct ir* ir = new_ir0(IR_ICONST, EM_wordsize);
ir->u.ivalue = value;
return ir;
}
struct ir* new_regir(int reg)
{
struct ir* ir = new_ir0(IR_REG, EM_pointersize);
ir->u.rvalue = reg;
return ir;
}
struct ir* new_bbir(struct basicblock* bb)
{
struct ir* ir = new_ir0(IR_BLOCK, EM_pointersize);
ir->u.bvalue = bb;
return ir;
}
struct ir* new_anyir(int size)
{
return new_ir0(IR_ANY, size);
}
struct ir* new_phiir(int size)
{
return new_ir0(IR_PHI, size);
}
void ir_print(const struct ir* ir)
{
int i;
for (i=0; i<sizeof(ir->children)/sizeof(*ir->children); i++)
{
if (ir->children[i])
ir_print(ir->children[i]);
}
printf("\t; %c ",
ir->sequence ? 'S' : ' ');
printf("$%d = ", ir->id);
printf("%s%d(",
ir_names[ir->opcode],
ir->size);
switch (ir->opcode)
{
case IR_ICONST:
printf("%d", ir->u.ivalue);
break;
case IR_LABEL:
printf("%s", ir->u.lvalue);
break;
case IR_REG:
printf("%d", ir->u.rvalue);
break;
case IR_BLOCK:
printf("%s", ir->u.bvalue->name);
break;
default:
for (i=0; i<sizeof(ir->children)/sizeof(*ir->children); i++)
{
if (ir->children[i])
{
if (i > 0)
printf(", ");
printf("$%d", ir->children[i]->id);
}
}
}
printf(")\n");
}
/* vim: set sw=4 ts=4 expandtab : */

33
mach/proto/mcg/ir.dat Normal file
View file

@ -0,0 +1,33 @@
# Simple terminals
ICONST
REG
LABEL
BLOCK
ANY
PHI
# Memory operations
LOAD
STORE
# Arithemetic operations
ADD
# Conversions
FROMI1
FROMI2
FROMI4
FROMI8
# Comparisons
COMPARES
COMPAREU
# Flow control
JUMP
CJUMP
RET
# Special
SETREG

53
mach/proto/mcg/ir.h Normal file
View file

@ -0,0 +1,53 @@
#ifndef IR_H
#define IR_H
#include "ircodes.h"
enum
{
IRR_LB = -1,
IRR_AB = -2,
IRR_SP = -3,
IRR_RR = -4,
};
struct ir
{
int id;
int opcode;
int size;
struct ir* children[3];
union {
arith ivalue;
int rvalue;
const char* lvalue;
struct basicblock* bvalue;
struct {
ARRAY(struct ir, srcs);
} phivalue;
} u;
bool sequence : 1;
bool terminates : 1;
};
extern const char* ir_names[];
extern struct ir* new_ir0(int opcode, int size);
extern struct ir* new_ir1(int opcode, int size,
struct ir* c1);
extern struct ir* new_ir2(int opcode, int size,
struct ir* c1, struct ir* c2);
extern struct ir* new_ir3(int opcode, int size,
struct ir* c1, struct ir* c2, struct ir* c3);
extern struct ir* new_labelir(const char* label);
extern struct ir* new_regir(int reg);
extern struct ir* new_wordir(arith value);
extern struct ir* new_bbir(struct basicblock* bb);
extern struct ir* new_anyir(int size);
extern struct ir* new_phiir(int size);
extern void ir_print(const struct ir* ir);
#endif

14
mach/proto/mcg/ircodes.sh Executable file
View file

@ -0,0 +1,14 @@
#!/bin/sh
in=$1
header=$2
source=$3
echo "enum {" > $header
sed -n 's/^[A-Z].*$/IR_&,/p' < $in >> $header
echo "};" >> $header
echo "const char* ir_names[] = {" > $source
sed -n 's/^[A-Z].*$/"&",/p' < $in >> $source
echo "};" >> $source

View file

@ -1,5 +1,4 @@
#include "mcg.h"
#include "em_comp.h"
void fatal(const char* msg, ...)
{
@ -13,8 +12,31 @@ void fatal(const char* msg, ...)
abort();
}
const char* aprintf(const char* fmt, ...)
{
int n;
char* p;
va_list ap;
va_start(ap, fmt);
n = vsnprintf(NULL, 0, fmt, ap) + 1;
va_end(ap);
p = malloc(n);
if (!p)
return NULL;
va_start(ap, fmt);
vsnprintf(p, n, fmt, ap);
va_end(ap);
return p;
}
int main(int argc, char* argv[])
{
symbol_init();
if (!EM_open(argv[1]))
fatal("Couldn't open input file: %s", EM_error);

View file

@ -16,24 +16,69 @@
#include "em_mnem.h"
#include "em_flag.h"
#include "em_ptyp.h"
#include "array.h"
#include "ir.h"
extern char em_pseu[][4];
extern char em_mnem[][4];
extern char em_flag[];
enum {
SECTION_UNKNOWN = 0,
SECTION_ROM,
SECTION_DATA,
SECTION_BSS,
SECTION_TEXT
};
struct symbol {
const char* name;
int section;
bool is_defined : 1;
bool is_exported : 1;
bool is_proc : 1;
};
enum {
PARAM_NONE,
PARAM_VALUE,
PARAM_LABEL
};
struct basicblock {
const char* name;
ARRAY(struct ir, irs);
ARRAY(struct basicblock, inblocks);
ARRAY(struct basicblock, outblocks);
ARRAY(struct ir, outs);
ARRAY(struct ir, ins);
bool is_wired : 1;
};
extern void fatal(const char* s, ...);
extern const char* aprintf(const char* fmt, ...);
extern void parse_em(void);
extern void symbol_init(void);
extern bool symbol_exists(const char* name);
extern struct symbol* symbol_get(const char* name);
extern void symbol_declare(const char* name, bool is_exported, bool is_proc);
extern void data_label(const char* name);
extern void data_int(arith data, size_t size, bool is_ro);
extern void data_block(const uint8_t* data, size_t size, bool is_ro);
extern void data_offset(const char* label, arith offset, bool is_ro);
extern void data_bss(arith size, int init);
extern void bb_init(void);
extern struct basicblock* bb_get(const char* name);
extern void bb_alias(struct basicblock* block, const char* name);
extern void bb_wire_outs_to_ins(struct basicblock* outblock, struct basicblock* inblock);
extern void tb_filestart(void);
extern void tb_fileend(void);
extern void tb_symbol(const char* name, bool is_exported, bool is_proc);
extern void tb_dlabel(const char* label);
extern void tb_ilabel(const char* label);
extern void tb_data(const uint8_t* data, size_t size, bool is_ro);
extern void tb_data_offset(const char* label, arith offset, bool is_ro);
extern void tb_bss(size_t size, uint8_t init);
extern void tb_procstart(const char* label, size_t nlocals);
extern void tb_procend(void);
extern void tb_regvar(arith offset, int size, int type, int priority);

View file

@ -1,6 +1,7 @@
#include "mcg.h"
static struct e_instr insn;
static const char* current_proc;
static const char* type_to_str(int type)
{
@ -44,35 +45,15 @@ static void unknown_type(const char* s)
argtype_to_str(insn.em_arg.ema_argtype));
}
static const uint8_t* arith_to_bytes(arith a, size_t sz)
{
uint8_t* p = malloc(8);
switch (sz)
{
case 1: *(uint8_t*)p = a; break;
case 2: *(uint16_t*)p = a; break;
case 4: *(uint32_t*)p = a; break;
case 8: *(uint64_t*)p = a; break;
default:
fatal("bad constant size '%d'", sz);
}
return p;
}
static const char* ilabel_to_str(label l)
{
char s[16];
sprintf(s, "__I%d", l);
return strdup(s);
assert(current_proc != NULL);
return aprintf("__%s_I%d", current_proc, l);
}
static const char* dlabel_to_str(label l)
{
char s[16];
sprintf(s, ".%d", l);
return strdup(s);
return aprintf("__D%d", l);
}
static void parse_pseu(void)
@ -90,17 +71,17 @@ static void parse_pseu(void)
switch (insn.em_arg.ema_argtype)
{
case pro_ptyp:
tb_symbol(strdup(insn.em_pnam), export, proc);
symbol_declare(strdup(insn.em_pnam), export, proc);
break;
case sof_ptyp:
assert(insn.em_off == 0);
tb_symbol(strdup(insn.em_dnam), export, proc);
symbol_declare(strdup(insn.em_dnam), export, proc);
break;
case nof_ptyp:
assert(insn.em_off == 0);
tb_symbol(dlabel_to_str(insn.em_dlb), export, proc);
symbol_declare(dlabel_to_str(insn.em_dlb), export, proc);
break;
default:
@ -120,24 +101,24 @@ static void parse_pseu(void)
case uco_ptyp:
{
arith val = atol(insn.em_string);
tb_data(arith_to_bytes(val, insn.em_size), insn.em_size, ro);
data_int(val, insn.em_size, ro);
break;
}
case str_ptyp:
tb_data(strdup(insn.em_string), insn.em_size, ro);
data_block(strdup(insn.em_string), insn.em_size, ro);
break;
case cst_ptyp:
tb_data(arith_to_bytes(insn.em_cst, EM_wordsize), EM_wordsize, ro);
data_int(insn.em_cst, EM_wordsize, ro);
break;
case nof_ptyp:
tb_data_offset(dlabel_to_str(insn.em_dlb), insn.em_off, ro);
data_offset(dlabel_to_str(insn.em_dlb), insn.em_off, ro);
break;
case ilb_ptyp:
tb_data_offset(ilabel_to_str(insn.em_ilb), 0, ro);
data_offset(ilabel_to_str(insn.em_ilb), 0, ro);
break;
default:
@ -151,7 +132,7 @@ static void parse_pseu(void)
switch (insn.em_arg.ema_argtype)
{
case cst_ptyp:
tb_bss(EM_bsssize, EM_bssinit);
data_bss(EM_bsssize, insn.em_cst);
break;
default:
@ -164,11 +145,13 @@ static void parse_pseu(void)
if (insn.em_nlocals == -1)
fatal("procedures with unspecified number of locals are not supported yet");
tb_procstart(strdup(insn.em_pnam), insn.em_nlocals);
current_proc = strdup(insn.em_pnam);
tb_procstart(current_proc, insn.em_nlocals);
break;
case ps_end: /* procedure end */
tb_procend();
current_proc = NULL;
break;
default:
@ -228,16 +211,16 @@ void parse_em(void)
break;
case EM_DEFDLB:
tb_dlabel(dlabel_to_str(insn.em_dlb));
data_label(dlabel_to_str(insn.em_dlb));
break;
case EM_DEFDNAM:
tb_dlabel(strdup(insn.em_dnam));
data_label(strdup(insn.em_dnam));
break;
case EM_STARTMES:
parse_mes();
break;
break;
case EM_MNEM:
{
@ -268,8 +251,12 @@ void parse_em(void)
break;
case cst_ptyp:
tb_insn_value(insn.em_opcode, flags,
insn.em_cst);
if ((flags & EM_PAR) == PAR_B)
tb_insn_label(insn.em_opcode, flags,
ilabel_to_str(insn.em_ilb), 0);
else
tb_insn_value(insn.em_opcode, flags,
insn.em_cst);
break;
default:

View file

@ -1,52 +0,0 @@
BEGIN {
print "#include <stdbool.h>"
print "#include \"push_pop.h\""
print ""
s = 0;
count = 0;
}
/^aar/ {
s = 1;
}
/^[a-z]/ {
if (!s)
next;
opcode[count++] = $1;
data[$1] = $3;
}
END {
for (op in data)
{
print "static const struct stackop so_" op "[] = {";
pushpops = data[op]
if (pushpops != "0")
{
for (i=1; i<=length(pushpops); i+=2)
{
printf "\t{ ";
if (substr(pushpops, i, 1) == "+")
printf "true, ";
else
printf "false, ";
printf("'%s' },\n", substr(pushpops, i+1, 1));
}
}
print "\t{ false, 0 }"
print "};";
print "";
}
print "const struct stackop* const stackops[] = {";
for (i=0; i<count; i++)
print "\tso_" opcode[i] ","
print "};"
}

View file

@ -1,12 +0,0 @@
#ifndef PUSH_POP_H
#define PUSH_POP_H
struct stackop {
bool push : 1;
char type : 7;
};
extern const struct stackop* const stackops[];
#endif

41
mach/proto/mcg/symbol.c Normal file
View file

@ -0,0 +1,41 @@
#include "mcg.h"
static void init_idf();
static struct idf* str2idf(char* tg, int cp);
#define IDF_TYPE struct symbol
#define IDF_NAME symbol
#include <idf_pkg.spec>
#include <idf_pkg.body>
void symbol_init(void)
{
init_idf();
}
bool symbol_exists(const char* name)
{
return !!findidf((char*) name);
}
struct symbol* symbol_get(const char* name)
{
struct idf* p = str2idf((char*) name, 0);
p->symbol.name = p->id_text;
return &p->symbol;
}
void symbol_declare(const char* name, bool is_exported, bool is_proc)
{
struct symbol* s = symbol_get(name);
s->is_exported = is_exported;
if (is_proc)
{
if (s->section == SECTION_UNKNOWN)
s->section = SECTION_TEXT;
else if (s->section != SECTION_TEXT)
fatal("section mismatch for '%s'", name);
}
}

View file

@ -1,5 +1,43 @@
#include "mcg.h"
static struct symbol* currentproc;
static struct basicblock* rootbb;
static struct basicblock* currentbb;
static int stackptr;
static struct ir* stack[64];
static void resetstack(void)
{
stackptr = 0;
}
static void push(struct ir* ir)
{
if (stackptr == sizeof(stack)/sizeof(*stack))
fatal("stack overflow");
stack[stackptr++] = ir;
}
static struct ir* pop(void)
{
if (stackptr == 0)
fatal("stack underflow");
return stack[--stackptr];
}
static struct ir* appendir(struct ir* ir)
{
assert(currentbb != NULL);
ir->sequence = true;
APPEND(currentbb->irs, ir);
ir_print(ir);
return ir;
}
void tb_filestart(void)
{
}
@ -8,86 +46,369 @@ void tb_fileend(void)
{
}
void tb_symbol(const char* name, bool is_exported, bool is_proc)
static void materialise(void)
{
printf("; symbol name=%s, exported=%s, is_proc=%s\n",
name,
is_exported ? "yes" : "no",
is_proc ? "yes" : "no");
int i;
for (i=0; i<stackptr; i++)
appendir(stack[i]);
}
void tb_dlabel(const char* label)
static void changeblock(struct basicblock* bb)
{
printf("; dlabel name=%s\n", label);
int i;
if (stackptr > 0)
{
printf("\t; block exiting with %d on stack:\n", stackptr);
for (i=0; i<stackptr; i++)
{
struct ir* ir = stack[i];
printf("\t; $%d size %d\n", ir->id, ir->size);
APPENDU(currentbb->outs, ir);
}
}
for (i=0; i<currentbb->outblocks_count; i++)
bb_wire_outs_to_ins(currentbb, currentbb->outblocks[i]);
currentbb = bb;
printf("; new block: %s\n", currentbb->name);
resetstack();
if (currentbb->ins_count > 0)
{
printf("\t; block entering with %d on stack:\n", currentbb->ins_count);
for (i=0; i<currentbb->ins_count; i++)
{
struct ir* ir = currentbb->ins[i];
printf("\t; $%d size %d\n", ir->id, ir->size);
push(ir);
}
}
}
void tb_ilabel(const char* label)
{
printf("; ilabel name=%s\n", label);
}
materialise();
void tb_data(const uint8_t* data, size_t size, bool is_ro)
{
printf("; data size=%d ro=%s\n",
size,
is_ro ? "yes" : "no");
}
#if 0
if (currentbb->irs_count == 0)
{
/* Current BB has no instructions, so just alias it to the
* new name.
*/
bb_alias(currentbb, label);
}
else
#endif
{
struct basicblock* newbb = bb_get(label);
void tb_data_offset(const char* label, arith offset, bool is_ro)
{
printf("; data label=%s offset=%d ro=%s\n",
label, offset,
is_ro ? "yes" : "no");
}
if ((currentbb->irs_count == 0) ||
!currentbb->irs[currentbb->irs_count-1]->terminates)
{
APPEND(currentbb->outblocks, newbb);
appendir(
new_ir1(
IR_JUMP, 0,
new_labelir(label)
)
);
}
void tb_bss(size_t size, uint8_t init)
{
printf("; bss size=%d init=0x%x\n",
size, init);
changeblock(newbb);
}
}
void tb_procstart(const char* label, size_t nlocals)
{
printf("; proc name=%s nlocals=%d\n", label, nlocals);
assert(currentproc == NULL);
currentproc = symbol_get(label);
currentproc->section = SECTION_TEXT;
rootbb = calloc(sizeof(struct basicblock), 1);
currentbb = rootbb;
resetstack();
}
void tb_procend(void)
{
printf("; endproc\n");
assert(currentproc != NULL);
printf("\n.text\n");
printf("%s:\n", currentproc->name);
currentproc = NULL;
}
void tb_regvar(arith offset, int size, int type, int priority)
{
printf("; regvar offset=%d size=%d type=%d priority=%d\n",
offset, size, type, priority);
/* ignored */
}
static void printinsn(int opcode, int flags)
static struct ir* address_of_local(int index)
{
printf("; insn %s %c%c%c%c ",
em_mnem[opcode - sp_fmnem],
"/CDNFLGWSZOPBR"[flags & EM_PAR],
(flags & FLO_C) ? 'c' : '.',
(flags & FLO_P) ? 'p' : '.',
(flags & FLO_T) ? 't' : '.');
return
new_ir2(
IR_ADD, EM_pointersize,
new_regir((index < 0) ? IRR_LB : IRR_AB),
new_wordir(index)
);
}
static struct ir* tristate_compare(int size, int opcode)
{
struct ir* right = pop();
struct ir* left = pop();
return
new_ir2(
opcode, size,
left, right
);
}
static struct ir* convert(int destsize, int srcsize, int opcode)
{
switch (srcsize)
{
case 1: opcode += 0; break;
case 2: opcode += 1; break;
case 4: opcode += 2; break;
case 8: opcode += 3; break;
default:
fatal("can't convert from things of size %d", srcsize);
}
return
new_ir1(
opcode, destsize,
pop()
);
}
void tb_insn_simple(int opcode, int flags)
{
printinsn(opcode, flags);
printf("\n");
switch (opcode)
{
case op_cii:
{
struct ir* destsize = pop();
struct ir* srcsize = pop();
assert(srcsize->opcode == IR_ICONST);
assert(destsize->opcode == IR_ICONST);
push(
convert(destsize->u.ivalue, srcsize->u.ivalue, IR_FROMI1)
);
break;
}
default:
fatal("unknown insn_simple instruction '%s'",
em_mnem[opcode - sp_fmnem]);
}
}
void tb_insn_label(int opcode, int flags, const char* label, arith offset)
{
printinsn(opcode, flags);
printf("label=%s offset=%d\n", label, offset);
materialise();
switch (opcode)
{
case op_zne:
{
struct basicblock* truebb = bb_get(label);
struct basicblock* falsebb = bb_get(NULL);
APPENDU(currentbb->outblocks, truebb);
APPENDU(currentbb->outblocks, falsebb);
appendir(
new_ir3(
IR_CJUMP, 0,
pop(),
new_bbir(truebb),
new_bbir(falsebb)
)
);
changeblock(falsebb);
break;
}
case op_bra:
{
struct basicblock* destbb = bb_get(label);
APPENDU(currentbb->outblocks, destbb);
appendir(
new_ir1(
IR_JUMP, 0,
new_bbir(destbb)
)
);
break;
}
default:
fatal("unknown insn_label instruction '%s'",
em_mnem[opcode - sp_fmnem]);
}
}
void tb_insn_value(int opcode, int flags, arith value)
{
printinsn(opcode, flags);
printf("value=%d\n", value);
struct ir* left;
struct ir* right;
switch (opcode)
{
case op_lol:
push(
new_ir1(
IR_LOAD, EM_wordsize,
address_of_local(value)
)
);
break;
case op_stl:
appendir(
new_ir2(
IR_STORE, EM_wordsize,
address_of_local(value),
pop()
)
);
break;
case op_loc:
push(
new_wordir(value)
);
break;
case op_loi:
push(
new_ir1(
IR_LOAD, value,
pop()
)
);
break;
case op_sti:
right = pop();
left = pop();
appendir(
new_ir2(
IR_STORE, value,
right, left
)
);
break;
case op_cmi:
push(
tristate_compare(value, IR_COMPARES)
);
break;
case op_cmu:
push(
tristate_compare(value, IR_COMPAREU)
);
break;
case op_ads:
right = pop();
left = pop();
if (value != EM_pointersize)
right = convert(EM_pointersize, value, IR_FROMI1);
push(
new_ir2(
IR_ADD, EM_wordsize,
left, right
)
);
break;
case op_dup:
{
struct ir* v = pop();
appendir(v);
push(v);
push(v);
break;
}
case op_asp:
{
switch (value)
{
case 0:
break;
case -1:
case -2:
case -4:
case -8:
push(new_anyir(-value));
break;
default:
appendir(
new_ir2(
IR_SETREG, EM_pointersize,
new_regir(IRR_SP),
new_ir2(
IR_ADD, EM_pointersize,
new_regir(IRR_SP),
new_wordir(value)
)
)
);
break;
}
break;
}
case op_ret:
{
if (value > 0)
{
left = pop();
assert(left->size == value);
appendir(
new_ir2(
IR_SETREG, value,
new_regir(IRR_RR),
left
)
);
}
appendir(
new_ir0(
IR_RET, 0
)
);
break;
}
default:
fatal("unknown insn_value instruction '%s'",
em_mnem[opcode - sp_fmnem]);
}
}
/* vim: set sw=4 ts=4 expandtab : */