Merge branch 'irgen'

This commit is contained in:
Dale Weiler 2012-06-07 11:24:55 -04:00
commit 04cf1d549f
12 changed files with 591 additions and 78 deletions

View file

@ -1,5 +1,21 @@
CC ?= clang
CFLAGS += -Wall -I. -pedantic-errors -std=c90 -Wno-attributes
CFLAGS += -Wall -I. -pedantic-errors -std=c90
#turn on tons of warnings if clang is present
ifeq ($(CC), clang)
CFLAGS += \
-Weverything \
-Wno-missing-prototypes \
-Wno-unused-parameter \
-Wno-sign-compare \
-Wno-implicit-fallthrough \
-Wno-sign-conversion \
-Wno-conversion \
-Wno-disabled-macro-expansion \
-Wno-padded \
-Wno-format-nonliteral
endif
OBJ = lex.o \
error.o \
parse.o \
@ -34,3 +50,5 @@ all: test gmqcc
clean:
rm -f *.o gmqcc test_ast test_ir test/*.o

23
asm.c
View file

@ -44,7 +44,7 @@ VECTOR_MAKE(asm_sym, asm_symbols);
* Assembly text processing: this handles the internal collection
* of text to allow parsing and assemblation.
*/
static char *const asm_getline(size_t *byte, FILE *fp) {
static char* asm_getline(size_t *byte, FILE *fp) {
char *line = NULL;
size_t read = util_getline(&line, byte, fp);
*byte = read;
@ -65,7 +65,7 @@ void asm_init(const char *file, FILE **fp) {
}
void asm_close(FILE *fp) {
fclose(fp);
code_write();
code_write("program.dat");
}
void asm_clear() {
size_t i = 0;
@ -530,24 +530,6 @@ static GMQCC_INLINE bool asm_parse_stmt(const char *skip, size_t line, asm_state
* This needs to have a fall state, we start from the
* end of the string and work backwards.
*/
#define OPFILL(X) \
do { \
size_t w = 0; \
if (!(c = strrchr(c, ','))) { \
printf("error, expected more operands\n"); \
return false; \
} \
c++; \
w++; \
while (*c == ' ' || *c == '\t') { \
c++; \
w++; \
} \
X = (const char*)c; \
c -= w; \
*c = '\0'; \
c = (char*)skip; \
} while (0)
#define OPEATS(X,Y) X##Y
#define OPCCAT(X,Y) OPEATS(X,Y)
#define OPLOAD(X,Y) \
@ -597,7 +579,6 @@ static GMQCC_INLINE bool asm_parse_stmt(const char *skip, size_t line, asm_state
OPLOAD(s.o1.s1, c);
break;
}
#undef OPFILL
#undef OPLOAD
#undef OPCCAT
}

28
ast.c
View file

@ -36,7 +36,7 @@
( (ast_node*)self )->node.destroy = (ast_node_delete*)destroyfn
/* It must not be possible to get here. */
static void _ast_node_destroy(ast_node *self)
static GMQCC_NORETURN void _ast_node_destroy(ast_node *self)
{
fprintf(stderr, "ast node missing destroy()\n");
abort();
@ -925,31 +925,31 @@ bool ast_loop_codegen(ast_loop *self, ast_function *func, bool lvalue, ir_value
{
ast_expression_codegen *cgen;
ir_value *dummy;
ir_value *precond;
ir_value *postcond;
ir_value *dummy = NULL;
ir_value *precond = NULL;
ir_value *postcond = NULL;
/* Since we insert some jumps "late" so we have blocks
* ordered "nicely", we need to keep track of the actual end-blocks
* of expressions to add the jumps to.
*/
ir_block *bbody, *end_bbody;
ir_block *bprecond, *end_bprecond;
ir_block *bpostcond, *end_bpostcond;
ir_block *bincrement, *end_bincrement;
ir_block *bout, *bin;
ir_block *bbody = NULL, *end_bbody = NULL;
ir_block *bprecond = NULL, *end_bprecond = NULL;
ir_block *bpostcond = NULL, *end_bpostcond = NULL;
ir_block *bincrement = NULL, *end_bincrement = NULL;
ir_block *bout = NULL, *bin = NULL;
/* let's at least move the outgoing block to the end */
size_t bout_id;
/* 'break' and 'continue' need to be able to find the right blocks */
ir_block *bcontinue = NULL;
ir_block *bbreak = NULL;
ir_block *bcontinue = NULL;
ir_block *bbreak = NULL;
ir_block *old_bcontinue;
ir_block *old_bbreak;
ir_block *old_bcontinue = NULL;
ir_block *old_bbreak = NULL;
ir_block *tmpblock;
ir_block *tmpblock = NULL;
(void)lvalue;
(void)out;

54
code.c
View file

@ -1,6 +1,6 @@
/*
* Copyright (C) 2012
* Dale Weiler
* Dale Weiler, Wolfgang Bumiller
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
@ -103,6 +103,32 @@ void code_init() {
code_statements_add(empty_statement);
}
uint32_t code_genstring(const char *str)
{
uint32_t off = code_chars_elements;
while (*str) {
code_chars_add(*str);
++str;
}
return off;
}
uint32_t code_cachedstring(const char *str)
{
size_t s = 0;
/* We could implement knuth-morris-pratt or something
* and also take substrings, but I'm uncomfortable with
* pointing to subparts of strings for the sake of clarity...
*/
while (s < code_chars_elements) {
if (!strcmp(str, code_chars_data + s))
return s;
while (code_chars_data[s]) ++s;
++s;
}
return code_genstring(str);
}
void code_test() {
prog_section_def d1 = { TYPE_VOID, 28, 1 };
prog_section_def d2 = { TYPE_FUNCTION, 29, 8 };
@ -144,7 +170,7 @@ void code_test() {
code_statements_add(s3);
}
void code_write() {
bool code_write(const char *filename) {
prog_header code_header;
FILE *fp = NULL;
size_t it = 2;
@ -184,14 +210,21 @@ void code_write() {
util_endianswap(code_functions_data, code_functions_elements, sizeof(prog_section_function));
util_endianswap(code_globals_data, code_globals_elements, sizeof(int32_t));
fp = fopen("program.dat", "wb");
fwrite(&code_header, 1, sizeof(prog_header), fp);
fwrite(code_statements_data, 1, sizeof(prog_section_statement)*code_statements_elements, fp);
fwrite(code_defs_data, 1, sizeof(prog_section_def) *code_defs_elements, fp);
fwrite(code_fields_data, 1, sizeof(prog_section_field) *code_fields_elements, fp);
fwrite(code_functions_data, 1, sizeof(prog_section_function) *code_functions_elements, fp);
fwrite(code_globals_data, 1, sizeof(int32_t) *code_globals_elements, fp);
fwrite(code_chars_data, 1, 1 *code_chars_elements, fp);
fp = fopen(filename, "wb");
if (!fp)
return false;
if (1 != fwrite(&code_header, sizeof(prog_header), 1, fp) ||
code_statements_elements != fwrite(code_statements_data, sizeof(prog_section_statement), code_statements_elements, fp) ||
code_defs_elements != fwrite(code_defs_data, sizeof(prog_section_def) , code_defs_elements , fp) ||
code_fields_elements != fwrite(code_fields_data, sizeof(prog_section_field) , code_fields_elements , fp) ||
code_functions_elements != fwrite(code_functions_data, sizeof(prog_section_function) , code_functions_elements , fp) ||
code_globals_elements != fwrite(code_globals_data, sizeof(int32_t) , code_globals_elements , fp) ||
code_chars_elements != fwrite(code_chars_data, 1 , code_chars_elements , fp))
{
fclose(fp);
return false;
}
util_debug("GEN","HEADER:\n");
util_debug("GEN"," version: = %d\n", code_header.version );
@ -254,4 +287,5 @@ void code_write() {
mem_d(code_globals_data);
mem_d(code_chars_data);
fclose(fp);
return true;
}

18
error.c
View file

@ -29,14 +29,16 @@
* intereting like colors for the console.
*/
#ifndef WIN32
# define CON_BLACK 30
# define CON_RED 31
# define CON_GREEN 32
# define CON_BROWN 33
# define CON_BLUE 34
# define CON_MAGENTA 35
# define CON_CYAN 36
# define CON_WHITE 37
enum {
CON_BLACK = 30,
CON_RED,
CON_GREEN,
CON_BROWN,
CON_BLUE,
CON_MAGENTA,
CON_CYAN ,
CON_WHITE
};
static const int error_color[] = {
CON_RED,
CON_CYAN,

61
gmqcc.h
View file

@ -52,11 +52,16 @@
# endif /* !true */
# define false (0)
# define true (1)
# define bool _Bool
# if __STDC_VERSION__ < 199901L && __GNUC__ < 3
typedef int _Bool
# endif
# endif /* !__cplusplus */
# ifdef __STDC_VERSION__
# if __STDC_VERSION__ < 199901L && __GNUC__ < 3
typedef int bool;
# else
typedef _Bool bool;
# endif
# else
typedef int bool;
# endif /* !__STDC_VERSION__ */
#endif /* !__cplusplus */
/*
* Of some functions which are generated we want to make sure
@ -79,18 +84,34 @@
* like gcc and clang might have an inline attribute we can
* use if present.
*/
#if __STDC_VERSION__ < 199901L
# if defined(__GNUC__) || defined (__CLANG__)
# if __GNUC__ < 2
# define GMQCC_INLINE
#ifdef __STDC_VERSION__
# if __STDC_VERSION__ < 199901L
# if defined(__GNUC__) || defined (__CLANG__)
# if __GNUC__ < 2
# define GMQCC_INLINE
# else
# define GMQCC_INLINE __attribute__ ((always_inline))
# endif
# else
# define GMQCC_INLINE __attribute__ ((always_inline))
# define GMQCC_INLINE
# endif
# else
# define GMQCC_INLINE
# endif
# else
# define GMQCC_INLINE inline
# endif
#else
# define GMQCC_INLINE inline
# define GMQCC_INLINE
#endif /* !__STDC_VERSION__ */
/*
* noreturn is present in GCC and clang
* it's required for _ast_node_destory otherwise -Wmissing-noreturn
* in clang complains about there being no return since abort() is
* called.
*/
#if (defined(__GNUC__) && __GNUC__ >= 2) || defined(__CLANG__)
# define GMQCC_NORETURN __attribute__ ((noreturn))
#else
# define GMQCC_NORETURN
#endif
/*
@ -135,8 +156,8 @@
* fail. There is no valid way to get a 64bit type at this point
* without making assumptions of too many things.
*/
typedef char int64_t;
typedef char uint64_t;
typedef struct { char _fail : 0; } int64_t;
typedef struct { char _fail : 0; } uint64_t;
# endif
#endif
#ifdef _LP64 /* long pointer == 64 */
@ -148,7 +169,7 @@
#endif
/* Ensure type sizes are correct: */
typedef char uint8_size_is_correct [sizeof(uint8_t) == 1?1:-1];
typedef char uint16_size_if_correct [sizeof(uint16_t) == 2?1:-1];
typedef char uint16_size_is_correct [sizeof(uint16_t) == 2?1:-1];
typedef char uint32_size_is_correct [sizeof(uint32_t) == 4?1:-1];
typedef char uint64_size_is_correct [sizeof(uint64_t) == 8?1:-1];
typedef char int16_size_if_correct [sizeof(int16_t) == 2?1:-1];
@ -532,8 +553,10 @@ VECTOR_PROT(char, code_chars );
* code_write -- writes out the compiled file
* code_init -- prepares the code file
*/
void code_write ();
void code_init ();
bool code_write (const char *filename);
void code_init ();
uint32_t code_genstring (const char *string);
uint32_t code_cachedstring(const char *string);
/*===================================================================*/
/*========================= assembler.c =============================*/

436
ir.c
View file

@ -34,6 +34,9 @@ ir_builder* ir_builder_new(const char *modulename)
ir_builder* self;
self = (ir_builder*)mem_a(sizeof(*self));
if (!self)
return NULL;
MEM_VECTOR_INIT(self, functions);
MEM_VECTOR_INIT(self, globals);
self->name = NULL;
@ -140,6 +143,10 @@ ir_function* ir_function_new(ir_builder* owner)
{
ir_function *self;
self = (ir_function*)mem_a(sizeof(*self));
if (!self)
return NULL;
self->name = NULL;
if (!ir_function_set_name(self, "<@unnamed>")) {
mem_d(self);
@ -252,6 +259,11 @@ ir_block* ir_block_new(ir_function* owner, const char *name)
{
ir_block *self;
self = (ir_block*)mem_a(sizeof(*self));
if (!self)
return NULL;
memset(self, 0, sizeof(*self));
self->label = NULL;
if (!ir_block_set_label(self, name)) {
mem_d(self);
@ -269,6 +281,9 @@ ir_block* ir_block_new(ir_function* owner, const char *name)
self->is_return = false;
self->run_id = 0;
MEM_VECTOR_INIT(self, living);
self->generated = false;
return self;
}
MEM_VEC_FUNCTIONS(ir_block, ir_instr*, instr)
@ -305,6 +320,9 @@ ir_instr* ir_instr_new(ir_block* owner, int op)
{
ir_instr *self;
self = (ir_instr*)mem_a(sizeof(*self));
if (!self)
return NULL;
self->owner = owner;
self->context.file = "<@no context>";
self->context.line = 0;
@ -381,6 +399,7 @@ ir_value* ir_value_var(const char *name, int storetype, int vtype)
ir_value *self;
self = (ir_value*)mem_a(sizeof(*self));
self->vtype = vtype;
self->fieldtype = TYPE_VOID;
self->store = storetype;
MEM_VECTOR_INIT(self, reads);
MEM_VECTOR_INIT(self, writes);
@ -390,6 +409,9 @@ ir_value* ir_value_var(const char *name, int storetype, int vtype)
self->name = NULL;
ir_value_set_name(self, name);
memset(&self->constval, 0, sizeof(self->constval));
memset(&self->code, 0, sizeof(self->code));
MEM_VECTOR_INIT(self, life);
return self;
}
@ -1655,6 +1677,420 @@ on_error:
return false;
}
/***********************************************************************
*IR Code-Generation
*
* Since the IR has the convention of putting 'write' operands
* at the beginning, we have to rotate the operands of instructions
* properly in order to generate valid QCVM code.
*
* Having destinations at a fixed position is more convenient. In QC
* this is *mostly* OPC, but FTE adds at least 2 instructions which
* read from from OPA, and store to OPB rather than OPC. Which is
* partially the reason why the implementation of these instructions
* in darkplaces has been delayed for so long.
*
* Breaking conventions is annoying...
*/
static bool ir_builder_gen_global(ir_builder *self, ir_value *global);
static bool gen_global_field(ir_value *global)
{
if (global->isconst)
{
ir_value *fld = global->constval.vpointer;
if (!fld) {
printf("Invalid field constant with no field: %s\n", global->name);
return false;
}
/* Now, in this case, a relocation would be impossible to code
* since it looks like this:
* .vector v = origin; <- parse error, wtf is 'origin'?
* .vector origin;
*
* But we will need a general relocation support later anyway
* for functions... might as well support that here.
*/
if (!fld->code.globaladdr) {
printf("FIXME: Relocation support\n");
return false;
}
/* copy the field's value */
global->code.globaladdr = code_globals_add(code_globals_data[fld->code.globaladdr]);
}
else
{
prog_section_field fld;
fld.name = global->code.name;
fld.offset = code_fields_elements;
fld.type = global->fieldtype;
if (fld.type == TYPE_VOID) {
printf("Field is missing a type: %s\n", global->name);
return false;
}
if (code_fields_add(fld) < 0)
return false;
global->code.globaladdr = code_globals_add(fld.offset);
}
if (global->code.globaladdr < 0)
return false;
return true;
}
static bool gen_global_pointer(ir_value *global)
{
if (global->isconst)
{
ir_value *target = global->constval.vpointer;
if (!target) {
printf("Invalid pointer constant: %s\n", global->name);
/* NULL pointers are pointing to the NULL constant, which also
* sits at address 0, but still has an ir_value for itself.
*/
return false;
}
/* Here, relocations ARE possible - in fteqcc-enhanced-qc:
* void() foo; <- proto
* void() *fooptr = &foo;
* void() foo = { code }
*/
if (!target->code.globaladdr) {
/* FIXME: Check for the constant nullptr ir_value!
* because then code.globaladdr being 0 is valid.
*/
printf("FIXME: Relocation support\n");
return false;
}
global->code.globaladdr = code_globals_add(target->code.globaladdr);
}
else
{
global->code.globaladdr = code_globals_add(0);
}
if (global->code.globaladdr < 0)
return false;
return true;
}
static bool gen_blocks_recursive(ir_function *func, ir_block *block)
{
prog_section_statement stmt;
prog_section_statement *stptr;
ir_instr *instr;
ir_block *target;
ir_block *ontrue;
ir_block *onfalse;
size_t stidx;
size_t i;
tailcall:
block->generated = true;
block->code_start = code_statements_elements;
for (i = 0; i < block->instr_count; ++i)
{
instr = block->instr[i];
if (instr->opcode == VINSTR_PHI) {
printf("cannot generate virtual instruction (phi)\n");
return false;
}
if (instr->opcode == VINSTR_JUMP) {
target = instr->bops[0];
/* for uncoditional jumps, if the target hasn't been generated
* yet, we generate them right here.
*/
if (!target->generated) {
block = target;
goto tailcall;
}
/* otherwise we generate a jump instruction */
stmt.opcode = INSTR_GOTO;
stmt.o1.s1 = (target->code_start-1) - code_statements_elements;
stmt.o2.s1 = 0;
stmt.o3.s1 = 0;
if (code_statements_add(stmt) < 0)
return false;
/* no further instructions can be in this block */
return true;
}
if (instr->opcode == VINSTR_COND) {
ontrue = instr->bops[0];
onfalse = instr->bops[1];
/* TODO: have the AST signal which block should
* come first: eg. optimize IFs without ELSE...
*/
stmt.o1.s1 = instr->_ops[0]->code.globaladdr;
stmt.o3.s1 = 0;
if (ontrue->generated) {
stmt.opcode = INSTR_IF;
stmt.o2.s1 = (ontrue->code_start-1) - code_statements_elements;
if (code_statements_add(stmt) < 0)
return false;
}
if (onfalse->generated) {
stmt.opcode = INSTR_IFNOT;
stmt.o2.s1 = (onfalse->code_start-1) - code_statements_elements;
if (code_statements_add(stmt) < 0)
return false;
}
if (!ontrue->generated) {
if (onfalse->generated) {
block = ontrue;
goto tailcall;
}
}
if (!onfalse->generated) {
if (ontrue->generated) {
block = onfalse;
goto tailcall;
}
}
/* neither ontrue nor onfalse exist */
stmt.opcode = INSTR_IFNOT;
stidx = code_statements_elements - 1;
if (code_statements_add(stmt) < 0)
return false;
stptr = &code_statements_data[stidx];
/* on false we jump, so add ontrue-path */
if (!gen_blocks_recursive(func, ontrue))
return false;
/* fixup the jump address */
stptr->o2.s1 = (ontrue->code_start-1) - (stidx+1);
/* generate onfalse path */
if (onfalse->generated) {
/* may have been generated in the previous recursive call */
stmt.opcode = INSTR_GOTO;
stmt.o2.s1 = 0;
stmt.o3.s1 = 0;
stmt.o1.s1 = (onfalse->code_start-1) - code_statements_elements;
return (code_statements_add(stmt) >= 0);
}
/* if not, generate now */
block = onfalse;
goto tailcall;
}
if (instr->opcode >= INSTR_CALL0 && instr->opcode <= INSTR_CALL8) {
printf("TODO: call instruction\n");
return false;
}
if (instr->opcode == INSTR_STATE) {
printf("TODO: state instruction\n");
return false;
}
stmt.opcode = instr->opcode;
stmt.o1.u1 = 0;
stmt.o2.u1 = 0;
stmt.o3.u1 = 0;
/* This is the general order of operands */
if (instr->_ops[0])
stmt.o3.u1 = instr->_ops[0]->code.globaladdr;
if (instr->_ops[1])
stmt.o1.u1 = instr->_ops[1]->code.globaladdr;
if (instr->_ops[2])
stmt.o2.u1 = instr->_ops[2]->code.globaladdr;
if (stmt.opcode == INSTR_RETURN)
{
stmt.o1.u1 = stmt.o3.u1;
stmt.o3.u1 = 0;
}
if (code_statements_add(stmt) < 0)
return false;
}
return true;
}
static bool gen_function_code(ir_function *self)
{
ir_block *block;
/* Starting from entry point, we generate blocks "as they come"
* for now. Dead blocks will not be translated obviously.
*/
if (!self->blocks_count) {
printf("Function '%s' declared without body.\n", self->name);
return false;
}
block = self->blocks[0];
if (block->generated)
return true;
if (!gen_blocks_recursive(self, block)) {
printf("failed to generate blocks for '%s'\n", self->name);
return false;
}
return true;
}
static bool gen_global_function(ir_builder *ir, ir_value *global)
{
prog_section_function fun;
ir_function *irfun;
size_t i;
if (!global->isconst ||
!global->constval.vfunc)
{
printf("Invalid state of function-global: not constant: %s\n", global->name);
return false;
}
irfun = global->constval.vfunc;
fun.name = global->code.name;
fun.file = code_cachedstring(global->context.file);
fun.profile = 0; /* always 0 */
fun.nargs = irfun->params_count;
for (i = 0;i < 8; ++i) {
if (i >= fun.nargs)
fun.argsize[i] = 0;
else if (irfun->params[i] == TYPE_VECTOR)
fun.argsize[i] = 3;
else
fun.argsize[i] = 1;
}
fun.locals = irfun->locals_count;
fun.firstlocal = code_globals_elements;
for (i = 0; i < irfun->locals_count; ++i) {
if (!ir_builder_gen_global(ir, irfun->locals[i])) {
printf("Failed to generate global %s\n", irfun->locals[i]->name);
return false;
}
}
fun.entry = code_statements_elements;
if (!gen_function_code(irfun)) {
printf("Failed to generate code for function %s\n", irfun->name);
return false;
}
return (code_functions_add(fun) >= 0);
}
static bool ir_builder_gen_global(ir_builder *self, ir_value *global)
{
int32_t *iptr;
prog_section_def def;
def.type = global->vtype;
def.offset = code_globals_elements;
def.name = global->code.name = code_genstring(global->name);
switch (global->vtype)
{
case TYPE_POINTER:
if (code_defs_add(def) < 0)
return false;
return gen_global_pointer(global);
case TYPE_FIELD:
if (code_defs_add(def) < 0)
return false;
return gen_global_field(global);
case TYPE_ENTITY:
if (code_defs_add(def) < 0)
return false;
case TYPE_FLOAT:
{
if (code_defs_add(def) < 0)
return false;
if (global->isconst) {
iptr = (int32_t*)&global->constval.vfloat;
global->code.globaladdr = code_globals_add(*iptr);
} else
global->code.globaladdr = code_globals_add(0);
return global->code.globaladdr >= 0;
}
case TYPE_STRING:
{
if (code_defs_add(def) < 0)
return false;
if (global->isconst)
global->code.globaladdr = code_globals_add(code_cachedstring(global->constval.vstring));
else
global->code.globaladdr = code_globals_add(0);
return global->code.globaladdr >= 0;
}
case TYPE_VECTOR:
{
if (code_defs_add(def) < 0)
return false;
if (global->isconst) {
iptr = (int32_t*)&global->constval.vvec;
global->code.globaladdr = code_globals_add(iptr[0]);
if (code_globals_add(iptr[1]) < 0 || code_globals_add(iptr[2]) < 0)
return false;
} else {
global->code.globaladdr = code_globals_add(0);
if (code_globals_add(0) < 0 || code_globals_add(0) < 0)
return false;
}
return global->code.globaladdr >= 0;
}
case TYPE_FUNCTION:
if (code_defs_add(def) < 0)
return false;
return gen_global_function(self, global);
case TYPE_VARIANT:
/* assume biggest type */
global->code.globaladdr = code_globals_add(0);
code_globals_add(0);
code_globals_add(0);
return true;
default:
/* refuse to create 'void' type or any other fancy business. */
printf("Invalid type for global variable %s\n", global->name);
return false;
}
}
bool ir_builder_generate(ir_builder *self, const char *filename)
{
size_t i;
code_init();
/* FIXME: generate TYPE_FUNCTION globals and link them
* to their ir_function.
*/
for (i = 0; i < self->globals_count; ++i)
{
if (!ir_builder_gen_global(self, self->globals[i]))
return false;
}
printf("writing '%s'...\n", filename);
return code_write(filename);
}
/***********************************************************************
*IR DEBUG Dump functions...
*/

17
ir.h
View file

@ -38,6 +38,8 @@ typedef struct ir_value_s {
int vtype;
int store;
lex_ctx context;
/* even the IR knows the subtype of a field */
int fieldtype;
MEM_VECTOR_MAKE(struct ir_instr_s*, reads);
MEM_VECTOR_MAKE(struct ir_instr_s*, writes);
@ -50,8 +52,14 @@ typedef struct ir_value_s {
vector vvec;
char *vstring;
struct ir_value_s *vpointer;
struct ir_function_s *vfunc;
} constval;
struct {
int32_t globaladdr;
int32_t name;
} code;
/* For the temp allocator */
MEM_VECTOR_MAKE(ir_life_entry_t, life);
} ir_value;
@ -137,6 +145,9 @@ typedef struct ir_block_s
size_t run_id;
struct ir_function_s *owner;
bool generated;
size_t code_start;
} ir_block;
ir_block* ir_block_new(struct ir_function_s *owner, const char *label);
@ -264,6 +275,12 @@ ir_function* ir_builder_create_function(ir_builder*, const char *name);
ir_value* ir_builder_get_global(ir_builder*, const char *fun);
ir_value* ir_builder_create_global(ir_builder*, const char *name, int vtype);
bool ir_builder_generate(ir_builder *self, const char *filename);
void ir_builder_dump(ir_builder*, int (*oprintf)(const char*, ...));
/* This code assumes 32 bit floats while generating binary */
extern int check_int_and_float_size
[ (sizeof(int32_t) == sizeof(( (ir_value*)(NULL) )->constval.vvec.x)) ? 1 : -1 ];
#endif

1
lex.c
View file

@ -124,7 +124,6 @@ static int lex_trigraph(lex_file *file) {
default:
lex_unget('?', file);
lex_unget(ch , file);
return '?';
}
return '?';
}

3
main.c
View file

@ -24,7 +24,7 @@
typedef struct { char *name, type; } argitem;
VECTOR_MAKE(argitem, items);
static const int usage(const char *const app) {
static int usage(const char *app) {
printf("usage:\n"
" %s -c<file> -oprog.dat -- compile file\n"
" %s -a<file> -oprog.dat -- assemble file\n"
@ -105,7 +105,6 @@ int main(int argc, char **argv) {
if (util_strncmpexact(&argv[1][1], "memchk", 6)) { opts_memchk = true; break; }
if (util_strncmpexact(&argv[1][1], "help", 4)) {
return usage(app);
break;
}
/* compiler type selection */
if (util_strncmpexact(&argv[1][1], "std=qcc" , 7 )) { opts_compiler = COMPILER_QCC; break; }

View file

@ -192,7 +192,7 @@ STATE(ASSIGN(STORE_F, vi, BIN(ADD_F, vi, f1)));
ENDWHILE();
ENDFUNCTION(main);
ir = ir_builder_new("ast_test");
assert(ir);
@ -216,6 +216,10 @@ ENDFUNCTION(main);
/* dump */
ir_builder_dump(ir, printf);
/* Now create a file */
if (!ir_builder_generate(ir, "test_ast.dat"))
printf("*** failed to generate code\n");
/* ir cleanup */
ir_builder_delete(ir);

View file

@ -71,7 +71,7 @@ int typedef_add(lex_file *file, const char *from, const char *to) {
return -100;
} else {
/* search the typedefs for it (typedef-a-typedef?) */
typedef_node *find = typedef_table[typedef_hash(from)];
find = typedef_table[typedef_hash(from)];
if (find) {
typedef_table[hash] = mem_a(sizeof(typedef_node));
if (typedef_table[hash])