Archival checking of the half-written IR treebuilder.
This commit is contained in:
parent
f992eb28ac
commit
176cd7365c
39
mach/proto/mcg/array.c
Normal file
39
mach/proto/mcg/array.c
Normal 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
23
mach/proto/mcg/array.h
Normal 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
|
||||
|
70
mach/proto/mcg/basicblock.c
Normal file
70
mach/proto/mcg/basicblock.c
Normal 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 : */
|
|
@ -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
113
mach/proto/mcg/data.c
Normal 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
137
mach/proto/mcg/ir.c
Normal 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
33
mach/proto/mcg/ir.dat
Normal 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
53
mach/proto/mcg/ir.h
Normal 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
14
mach/proto/mcg/ircodes.sh
Executable 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
|
||||
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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 "};"
|
||||
}
|
||||
|
|
@ -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
41
mach/proto/mcg/symbol.c
Normal 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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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 : */
|
||||
|
|
Loading…
Reference in a new issue