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 {
|
normalrule {
|
||||||
name = "push_pop_c",
|
name = "ircodes",
|
||||||
outleaves = { "push_pop.c" },
|
outleaves = { "ircodes.h", "ircodes.c" },
|
||||||
ins = {
|
ins = {
|
||||||
"./push_pop.awk",
|
"./ircodes.sh",
|
||||||
"h/em_table"
|
"./ir.dat"
|
||||||
},
|
},
|
||||||
commands = {
|
commands = {
|
||||||
"awk -f %{ins[1]} %{ins[2]} > %{outs}"
|
"%{ins[1]} %{ins[2]} %{outs[1]} %{outs[2]}"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,16 +14,22 @@ cprogram {
|
||||||
name = "mcg",
|
name = "mcg",
|
||||||
srcs = {
|
srcs = {
|
||||||
"./*.c",
|
"./*.c",
|
||||||
"+push_pop_c",
|
matching(filenamesof("+ircodes"), "%.c$")
|
||||||
},
|
},
|
||||||
deps = {
|
deps = {
|
||||||
|
"+ircodes",
|
||||||
"h+emheaders",
|
"h+emheaders",
|
||||||
"modules+headers",
|
"modules+headers",
|
||||||
"modules/src/read_em+lib_kv",
|
"modules/src/alloc+lib",
|
||||||
"modules/src/em_code+lib_k",
|
"modules/src/em_code+lib_k",
|
||||||
"modules/src/em_data+lib",
|
"modules/src/em_data+lib",
|
||||||
"modules/src/alloc+lib",
|
"modules/src/idf+lib",
|
||||||
|
"modules/src/read_em+lib_kv",
|
||||||
"modules/src/system+lib",
|
"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 "mcg.h"
|
||||||
#include "em_comp.h"
|
|
||||||
|
|
||||||
void fatal(const char* msg, ...)
|
void fatal(const char* msg, ...)
|
||||||
{
|
{
|
||||||
|
@ -13,8 +12,31 @@ void fatal(const char* msg, ...)
|
||||||
abort();
|
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[])
|
int main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
|
symbol_init();
|
||||||
|
|
||||||
if (!EM_open(argv[1]))
|
if (!EM_open(argv[1]))
|
||||||
fatal("Couldn't open input file: %s", EM_error);
|
fatal("Couldn't open input file: %s", EM_error);
|
||||||
|
|
||||||
|
|
|
@ -16,24 +16,69 @@
|
||||||
#include "em_mnem.h"
|
#include "em_mnem.h"
|
||||||
#include "em_flag.h"
|
#include "em_flag.h"
|
||||||
#include "em_ptyp.h"
|
#include "em_ptyp.h"
|
||||||
|
#include "array.h"
|
||||||
|
#include "ir.h"
|
||||||
|
|
||||||
extern char em_pseu[][4];
|
extern char em_pseu[][4];
|
||||||
extern char em_mnem[][4];
|
extern char em_mnem[][4];
|
||||||
extern char em_flag[];
|
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 void fatal(const char* s, ...);
|
||||||
|
extern const char* aprintf(const char* fmt, ...);
|
||||||
|
|
||||||
extern void parse_em(void);
|
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_filestart(void);
|
||||||
extern void tb_fileend(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_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_procstart(const char* label, size_t nlocals);
|
||||||
extern void tb_procend(void);
|
extern void tb_procend(void);
|
||||||
extern void tb_regvar(arith offset, int size, int type, int priority);
|
extern void tb_regvar(arith offset, int size, int type, int priority);
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include "mcg.h"
|
#include "mcg.h"
|
||||||
|
|
||||||
static struct e_instr insn;
|
static struct e_instr insn;
|
||||||
|
static const char* current_proc;
|
||||||
|
|
||||||
static const char* type_to_str(int type)
|
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));
|
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)
|
static const char* ilabel_to_str(label l)
|
||||||
{
|
{
|
||||||
char s[16];
|
assert(current_proc != NULL);
|
||||||
sprintf(s, "__I%d", l);
|
return aprintf("__%s_I%d", current_proc, l);
|
||||||
return strdup(s);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char* dlabel_to_str(label l)
|
static const char* dlabel_to_str(label l)
|
||||||
{
|
{
|
||||||
char s[16];
|
return aprintf("__D%d", l);
|
||||||
sprintf(s, ".%d", l);
|
|
||||||
return strdup(s);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void parse_pseu(void)
|
static void parse_pseu(void)
|
||||||
|
@ -90,17 +71,17 @@ static void parse_pseu(void)
|
||||||
switch (insn.em_arg.ema_argtype)
|
switch (insn.em_arg.ema_argtype)
|
||||||
{
|
{
|
||||||
case pro_ptyp:
|
case pro_ptyp:
|
||||||
tb_symbol(strdup(insn.em_pnam), export, proc);
|
symbol_declare(strdup(insn.em_pnam), export, proc);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case sof_ptyp:
|
case sof_ptyp:
|
||||||
assert(insn.em_off == 0);
|
assert(insn.em_off == 0);
|
||||||
tb_symbol(strdup(insn.em_dnam), export, proc);
|
symbol_declare(strdup(insn.em_dnam), export, proc);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case nof_ptyp:
|
case nof_ptyp:
|
||||||
assert(insn.em_off == 0);
|
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;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -120,24 +101,24 @@ static void parse_pseu(void)
|
||||||
case uco_ptyp:
|
case uco_ptyp:
|
||||||
{
|
{
|
||||||
arith val = atol(insn.em_string);
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case str_ptyp:
|
case str_ptyp:
|
||||||
tb_data(strdup(insn.em_string), insn.em_size, ro);
|
data_block(strdup(insn.em_string), insn.em_size, ro);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case cst_ptyp:
|
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;
|
break;
|
||||||
|
|
||||||
case nof_ptyp:
|
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;
|
break;
|
||||||
|
|
||||||
case ilb_ptyp:
|
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;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -151,7 +132,7 @@ static void parse_pseu(void)
|
||||||
switch (insn.em_arg.ema_argtype)
|
switch (insn.em_arg.ema_argtype)
|
||||||
{
|
{
|
||||||
case cst_ptyp:
|
case cst_ptyp:
|
||||||
tb_bss(EM_bsssize, EM_bssinit);
|
data_bss(EM_bsssize, insn.em_cst);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -164,11 +145,13 @@ static void parse_pseu(void)
|
||||||
if (insn.em_nlocals == -1)
|
if (insn.em_nlocals == -1)
|
||||||
fatal("procedures with unspecified number of locals are not supported yet");
|
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;
|
break;
|
||||||
|
|
||||||
case ps_end: /* procedure end */
|
case ps_end: /* procedure end */
|
||||||
tb_procend();
|
tb_procend();
|
||||||
|
current_proc = NULL;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -228,16 +211,16 @@ void parse_em(void)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EM_DEFDLB:
|
case EM_DEFDLB:
|
||||||
tb_dlabel(dlabel_to_str(insn.em_dlb));
|
data_label(dlabel_to_str(insn.em_dlb));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EM_DEFDNAM:
|
case EM_DEFDNAM:
|
||||||
tb_dlabel(strdup(insn.em_dnam));
|
data_label(strdup(insn.em_dnam));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EM_STARTMES:
|
case EM_STARTMES:
|
||||||
parse_mes();
|
parse_mes();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EM_MNEM:
|
case EM_MNEM:
|
||||||
{
|
{
|
||||||
|
@ -268,8 +251,12 @@ void parse_em(void)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case cst_ptyp:
|
case cst_ptyp:
|
||||||
tb_insn_value(insn.em_opcode, flags,
|
if ((flags & EM_PAR) == PAR_B)
|
||||||
insn.em_cst);
|
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;
|
break;
|
||||||
|
|
||||||
default:
|
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"
|
#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)
|
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",
|
int i;
|
||||||
name,
|
|
||||||
is_exported ? "yes" : "no",
|
for (i=0; i<stackptr; i++)
|
||||||
is_proc ? "yes" : "no");
|
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)
|
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)
|
#if 0
|
||||||
{
|
if (currentbb->irs_count == 0)
|
||||||
printf("; data size=%d ro=%s\n",
|
{
|
||||||
size,
|
/* Current BB has no instructions, so just alias it to the
|
||||||
is_ro ? "yes" : "no");
|
* 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)
|
if ((currentbb->irs_count == 0) ||
|
||||||
{
|
!currentbb->irs[currentbb->irs_count-1]->terminates)
|
||||||
printf("; data label=%s offset=%d ro=%s\n",
|
{
|
||||||
label, offset,
|
APPEND(currentbb->outblocks, newbb);
|
||||||
is_ro ? "yes" : "no");
|
appendir(
|
||||||
}
|
new_ir1(
|
||||||
|
IR_JUMP, 0,
|
||||||
|
new_labelir(label)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
void tb_bss(size_t size, uint8_t init)
|
changeblock(newbb);
|
||||||
{
|
}
|
||||||
printf("; bss size=%d init=0x%x\n",
|
|
||||||
size, init);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void tb_procstart(const char* label, size_t nlocals)
|
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)
|
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)
|
void tb_regvar(arith offset, int size, int type, int priority)
|
||||||
{
|
{
|
||||||
printf("; regvar offset=%d size=%d type=%d priority=%d\n",
|
/* ignored */
|
||||||
offset, size, type, priority);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void printinsn(int opcode, int flags)
|
static struct ir* address_of_local(int index)
|
||||||
{
|
{
|
||||||
printf("; insn %s %c%c%c%c ",
|
return
|
||||||
em_mnem[opcode - sp_fmnem],
|
new_ir2(
|
||||||
"/CDNFLGWSZOPBR"[flags & EM_PAR],
|
IR_ADD, EM_pointersize,
|
||||||
(flags & FLO_C) ? 'c' : '.',
|
new_regir((index < 0) ? IRR_LB : IRR_AB),
|
||||||
(flags & FLO_P) ? 'p' : '.',
|
new_wordir(index)
|
||||||
(flags & FLO_T) ? 't' : '.');
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
void tb_insn_simple(int opcode, int flags)
|
||||||
{
|
{
|
||||||
printinsn(opcode, flags);
|
switch (opcode)
|
||||||
printf("\n");
|
{
|
||||||
|
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)
|
void tb_insn_label(int opcode, int flags, const char* label, arith offset)
|
||||||
{
|
{
|
||||||
printinsn(opcode, flags);
|
materialise();
|
||||||
printf("label=%s offset=%d\n", label, offset);
|
|
||||||
|
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)
|
void tb_insn_value(int opcode, int flags, arith value)
|
||||||
{
|
{
|
||||||
printinsn(opcode, flags);
|
struct ir* left;
|
||||||
printf("value=%d\n", value);
|
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 : */
|
/* vim: set sw=4 ts=4 expandtab : */
|
||||||
|
|
Loading…
Reference in a new issue