AINSTR_END, /* array */
};
+/* protos */
+static void ir_gen_extparam(ir_builder *ir);
+
+/* error functions */
+
static void irerror(lex_ctx ctx, const char *msg, ...)
{
va_list ap;
/* emite parameter-stores */
for (p = 0; p < vec_size(call->params); ++p) {
/* assert(call->params_count <= self->locals_count); */
- if (!ir_block_create_store(block, self->locals[p], call->params[p])) {
+ if (!ir_block_create_store(block, call->context, self->locals[p], call->params[p])) {
irerror(call->context, "failed to create tailcall store instruction for parameter %i", (int)p);
return false;
}
}
- if (!ir_block_create_jump(block, self->blocks[0])) {
+ if (!ir_block_create_jump(block, call->context, self->blocks[0])) {
irerror(call->context, "failed to create tailcall jump");
return false;
}
*IR Instructions
*/
-ir_instr* ir_instr_new(ir_block* owner, int op)
+ir_instr* ir_instr_new(lex_ctx ctx, ir_block* owner, int op)
{
ir_instr *self;
self = (ir_instr*)mem_a(sizeof(*self));
return NULL;
self->owner = owner;
- self->context.file = "<@no context>";
- self->context.line = 0;
+ self->context = ctx;
self->opcode = op;
self->_ops[0] = NULL;
self->_ops[1] = NULL;
*IR main operations
*/
-bool ir_block_create_store_op(ir_block *self, int op, ir_value *target, ir_value *what)
+bool ir_block_create_store_op(ir_block *self, lex_ctx ctx, int op, ir_value *target, ir_value *what)
{
ir_instr *in;
if (self->final) {
irerror(self->context, "unreachable statement (%s)", self->label);
return false;
}
- in = ir_instr_new(self, op);
+ in = ir_instr_new(ctx, self, op);
if (!in)
return false;
return true;
}
-bool ir_block_create_store(ir_block *self, ir_value *target, ir_value *what)
+bool ir_block_create_store(ir_block *self, lex_ctx ctx, ir_value *target, ir_value *what)
{
int op = 0;
int vtype;
op = INSTR_STORE_V;
}
- return ir_block_create_store_op(self, op, target, what);
+ return ir_block_create_store_op(self, ctx, op, target, what);
}
-bool ir_block_create_storep(ir_block *self, ir_value *target, ir_value *what)
+bool ir_block_create_storep(ir_block *self, lex_ctx ctx, ir_value *target, ir_value *what)
{
int op = 0;
int vtype;
op = INSTR_STOREP_V;
}
- return ir_block_create_store_op(self, op, target, what);
+ return ir_block_create_store_op(self, ctx, op, target, what);
}
-bool ir_block_create_return(ir_block *self, ir_value *v)
+bool ir_block_create_return(ir_block *self, lex_ctx ctx, ir_value *v)
{
ir_instr *in;
if (self->final) {
}
self->final = true;
self->is_return = true;
- in = ir_instr_new(self, INSTR_RETURN);
+ in = ir_instr_new(ctx, self, INSTR_RETURN);
if (!in)
return false;
return true;
}
-bool ir_block_create_if(ir_block *self, ir_value *v,
+bool ir_block_create_if(ir_block *self, lex_ctx ctx, ir_value *v,
ir_block *ontrue, ir_block *onfalse)
{
ir_instr *in;
return false;
}
self->final = true;
- /*in = ir_instr_new(self, (v->vtype == TYPE_STRING ? INSTR_IF_S : INSTR_IF_F));*/
- in = ir_instr_new(self, VINSTR_COND);
+ /*in = ir_instr_new(ctx, self, (v->vtype == TYPE_STRING ? INSTR_IF_S : INSTR_IF_F));*/
+ in = ir_instr_new(ctx, self, VINSTR_COND);
if (!in)
return false;
return true;
}
-bool ir_block_create_jump(ir_block *self, ir_block *to)
+bool ir_block_create_jump(ir_block *self, lex_ctx ctx, ir_block *to)
{
ir_instr *in;
if (self->final) {
return false;
}
self->final = true;
- in = ir_instr_new(self, VINSTR_JUMP);
+ in = ir_instr_new(ctx, self, VINSTR_JUMP);
if (!in)
return false;
return true;
}
-bool ir_block_create_goto(ir_block *self, ir_block *to)
+bool ir_block_create_goto(ir_block *self, lex_ctx ctx, ir_block *to)
{
ir_instr *in;
if (self->final) {
return false;
}
self->final = true;
- in = ir_instr_new(self, INSTR_GOTO);
+ in = ir_instr_new(ctx, self, INSTR_GOTO);
if (!in)
return false;
return true;
}
-ir_instr* ir_block_create_phi(ir_block *self, const char *label, int ot)
+ir_instr* ir_block_create_phi(ir_block *self, lex_ctx ctx, const char *label, int ot)
{
ir_value *out;
ir_instr *in;
- in = ir_instr_new(self, VINSTR_PHI);
+ in = ir_instr_new(ctx, self, VINSTR_PHI);
if (!in)
return NULL;
out = ir_value_out(self->owner, label, store_value, ot);
}
/* call related code */
-ir_instr* ir_block_create_call(ir_block *self, const char *label, ir_value *func)
+ir_instr* ir_block_create_call(ir_block *self, lex_ctx ctx, const char *label, ir_value *func)
{
ir_value *out;
ir_instr *in;
- in = ir_instr_new(self, INSTR_CALL0);
+ in = ir_instr_new(ctx, self, INSTR_CALL0);
if (!in)
return NULL;
out = ir_value_out(self->owner, label, (func->outtype == TYPE_VOID) ? store_return : store_value, func->outtype);
/* binary op related code */
-ir_value* ir_block_create_binop(ir_block *self,
+ir_value* ir_block_create_binop(ir_block *self, lex_ctx ctx,
const char *label, int opcode,
ir_value *left, ir_value *right)
{
return NULL;
}
- return ir_block_create_general_instr(self, label, opcode, left, right, ot);
+ return ir_block_create_general_instr(self, ctx, label, opcode, left, right, ot);
}
-ir_value* ir_block_create_unary(ir_block *self,
+ir_value* ir_block_create_unary(ir_block *self, lex_ctx ctx,
const char *label, int opcode,
ir_value *operand)
{
}
/* let's use the general instruction creator and pass NULL for OPB */
- return ir_block_create_general_instr(self, label, opcode, operand, NULL, ot);
+ return ir_block_create_general_instr(self, ctx, label, opcode, operand, NULL, ot);
}
-ir_value* ir_block_create_general_instr(ir_block *self, const char *label,
+ir_value* ir_block_create_general_instr(ir_block *self, lex_ctx ctx, const char *label,
int op, ir_value *a, ir_value *b, int outype)
{
ir_instr *instr;
if (!out)
return NULL;
- instr = ir_instr_new(self, op);
+ instr = ir_instr_new(ctx, self, op);
if (!instr) {
ir_value_delete(out);
return NULL;
return NULL;
}
-ir_value* ir_block_create_fieldaddress(ir_block *self, const char *label, ir_value *ent, ir_value *field)
+ir_value* ir_block_create_fieldaddress(ir_block *self, lex_ctx ctx, const char *label, ir_value *ent, ir_value *field)
{
ir_value *v;
if (field->vtype != TYPE_FIELD)
return NULL;
- v = ir_block_create_general_instr(self, label, INSTR_ADDRESS, ent, field, TYPE_POINTER);
+ v = ir_block_create_general_instr(self, ctx, label, INSTR_ADDRESS, ent, field, TYPE_POINTER);
v->fieldtype = field->fieldtype;
return v;
}
-ir_value* ir_block_create_load_from_ent(ir_block *self, const char *label, ir_value *ent, ir_value *field, int outype)
+ir_value* ir_block_create_load_from_ent(ir_block *self, lex_ctx ctx, const char *label, ir_value *ent, ir_value *field, int outype)
{
int op;
if (ent->vtype != TYPE_ENTITY)
return NULL;
}
- return ir_block_create_general_instr(self, label, op, ent, field, outype);
+ return ir_block_create_general_instr(self, ctx, label, op, ent, field, outype);
}
-ir_value* ir_block_create_add(ir_block *self,
+ir_value* ir_block_create_add(ir_block *self, lex_ctx ctx,
const char *label,
ir_value *left, ir_value *right)
{
return NULL;
}
}
- return ir_block_create_binop(self, label, op, left, right);
+ return ir_block_create_binop(self, ctx, label, op, left, right);
}
-ir_value* ir_block_create_sub(ir_block *self,
+ir_value* ir_block_create_sub(ir_block *self, lex_ctx ctx,
const char *label,
ir_value *left, ir_value *right)
{
return NULL;
}
}
- return ir_block_create_binop(self, label, op, left, right);
+ return ir_block_create_binop(self, ctx, label, op, left, right);
}
-ir_value* ir_block_create_mul(ir_block *self,
+ir_value* ir_block_create_mul(ir_block *self, lex_ctx ctx,
const char *label,
ir_value *left, ir_value *right)
{
return NULL;
}
}
- return ir_block_create_binop(self, label, op, left, right);
+ return ir_block_create_binop(self, ctx, label, op, left, right);
}
-ir_value* ir_block_create_div(ir_block *self,
+ir_value* ir_block_create_div(ir_block *self, lex_ctx ctx,
const char *label,
ir_value *left, ir_value *right)
{
return NULL;
}
}
- return ir_block_create_binop(self, label, op, left, right);
+ return ir_block_create_binop(self, ctx, label, op, left, right);
}
/* PHI resolving breaks the SSA, and must thus be the last
vec_pop(b->instr);
b->final = false;
instr->_ops[0]->store = store_global;
- if (!ir_block_create_store(b, instr->_ops[0], v))
+ if (!ir_block_create_store(b, instr->context, instr->_ops[0], v))
return false;
instr->_ops[0]->store = store_value;
vec_push(b->instr, prevjump);
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) {
- irerror(global->context, "FIXME: Relocation support");
- return false;
- }
-
/* copy the field's value */
ir_value_code_setaddr(global, vec_size(code_globals));
- vec_push(code_globals, code_globals[fld->code.globaladdr]);
+ vec_push(code_globals, fld->code.fieldaddr);
if (global->fieldtype == TYPE_VECTOR) {
- vec_push(code_globals, code_globals[fld->code.globaladdr]+1);
- vec_push(code_globals, code_globals[fld->code.globaladdr]+2);
+ vec_push(code_globals, fld->code.fieldaddr+1);
+ vec_push(code_globals, fld->code.fieldaddr+2);
}
}
else
stmt.o1.s1 = (target->code_start) - vec_size(code_statements);
stmt.o2.s1 = 0;
stmt.o3.s1 = 0;
- vec_push(code_statements, stmt);
+ code_push_statement(&stmt, instr->context.line);
/* no further instructions can be in this block */
return true;
if (ontrue->generated) {
stmt.opcode = INSTR_IF;
stmt.o2.s1 = (ontrue->code_start) - vec_size(code_statements);
- vec_push(code_statements, stmt);
+ code_push_statement(&stmt, instr->context.line);
}
if (onfalse->generated) {
stmt.opcode = INSTR_IFNOT;
stmt.o2.s1 = (onfalse->code_start) - vec_size(code_statements);
- vec_push(code_statements, stmt);
+ code_push_statement(&stmt, instr->context.line);
}
if (!ontrue->generated) {
if (onfalse->generated) {
ontrue = tmp;
}
stidx = vec_size(code_statements);
- vec_push(code_statements, stmt);
+ code_push_statement(&stmt, instr->context.line);
/* on false we jump, so add ontrue-path */
if (!gen_blocks_recursive(func, ontrue))
return false;
stmt.o1.s1 = (onfalse->code_start) - vec_size(code_statements);
stmt.o2.s1 = 0;
stmt.o3.s1 = 0;
- vec_push(code_statements, stmt);
+ code_push_statement(&stmt, instr->context.line);
return true;
}
/* if not, generate now */
stmt.opcode = type_store_instr[param->vtype];
stmt.o1.u1 = ir_value_code_addr(param);
stmt.o2.u1 = OFS_PARM0 + 3 * p;
- vec_push(code_statements, stmt);
+ code_push_statement(&stmt, instr->context.line);
}
/* Now handle extparams */
first = vec_size(instr->params);
ir_value *param = instr->params[p];
ir_value *targetparam;
- if (p-8 >= vec_size(ir->extparams)) {
- irerror(instr->context, "Not enough extparam-globals have been created");
- return false;
- }
+ if (p-8 >= vec_size(ir->extparams))
+ ir_gen_extparam(ir);
targetparam = ir->extparams[p-8];
stmt.opcode = type_store_instr[param->vtype];
stmt.o1.u1 = ir_value_code_addr(param);
stmt.o2.u1 = ir_value_code_addr(targetparam);
- vec_push(code_statements, stmt);
+ code_push_statement(&stmt, instr->context.line);
}
stmt.opcode = INSTR_CALL0 + vec_size(instr->params);
stmt.o1.u1 = ir_value_code_addr(instr->_ops[1]);
stmt.o2.u1 = 0;
stmt.o3.u1 = 0;
- vec_push(code_statements, stmt);
+ code_push_statement(&stmt, instr->context.line);
retvalue = instr->_ops[0];
if (retvalue && retvalue->store != store_return && vec_size(retvalue->life))
stmt.o1.u1 = OFS_RETURN;
stmt.o2.u1 = ir_value_code_addr(retvalue);
stmt.o3.u1 = 0;
- vec_push(code_statements, stmt);
+ code_push_statement(&stmt, instr->context.line);
}
continue;
}
stmt.o3.u1 = 0;
}
- vec_push(code_statements, stmt);
+ code_push_statement(&stmt, instr->context.line);
}
return true;
}
stmt.o1.u1 = 0;
stmt.o2.u1 = 0;
stmt.o3.u1 = 0;
- vec_push(code_statements, stmt);
+ code_push_statement(&stmt, vec_last(code_linenums));
return true;
}
fun.nargs = 8;
for (i = 0;i < 8; ++i) {
- if (i >= fun.nargs)
+ if ((int32_t)i >= fun.nargs)
fun.argsize[i] = 0;
else
fun.argsize[i] = type_sizeof[irfun->params[i]];
fun.locals = vec_size(code_globals) - fun.firstlocal;
if (irfun->builtin)
- fun.entry = irfun->builtin;
+ fun.entry = irfun->builtin+1;
else {
irfun->code_function_def = vec_size(code_functions);
fun.entry = vec_size(code_statements);
}
stmt.o1.u1 = ir_value_code_addr(ep);
stmt.o2.u1 = ir_value_code_addr(self->locals[i]);
- vec_push(code_statements, stmt);
+ code_push_statement(&stmt, self->context.line);
}
return true;
irfun = global->constval.vfunc;
if (!irfun) {
- irwarning(global->context, WARN_IMPLICIT_FUNCTION_POINTER,
- "function `%s` has no body and in QC implicitly becomes a function-pointer", global->name);
+ if (global->cvq == CV_NONE) {
+ irwarning(global->context, WARN_IMPLICIT_FUNCTION_POINTER,
+ "function `%s` has no body and in QC implicitly becomes a function-pointer", global->name);
+ }
/* this was a function pointer, don't generate code for those */
return true;
}
}
}
+static void ir_builder_prepare_field(ir_value *field)
+{
+ field->code.fieldaddr = code_alloc_field(type_sizeof[field->fieldtype]);
+}
+
static bool ir_builder_gen_field(ir_builder *self, ir_value *field)
{
prog_section_def def;
return false;
}
- fld.offset = code_alloc_field(type_sizeof[field->fieldtype]);
+ fld.offset = field->code.fieldaddr;
vec_push(code_fields, fld);
{
prog_section_statement stmt;
size_t i;
+ char *lnofile = NULL;
code_init();
+ for (i = 0; i < vec_size(self->fields); ++i)
+ {
+ ir_builder_prepare_field(self->fields[i]);
+ }
+
for (i = 0; i < vec_size(self->globals); ++i)
{
if (!ir_builder_gen_global(self, self->globals[i], false)) {
stmt.o1.u1 = 0;
stmt.o2.u1 = 0;
stmt.o3.u1 = 0;
- vec_push(code_statements, stmt);
+ code_push_statement(&stmt, vec_last(code_linenums));
+
+ if (opts_pp_only)
+ return true;
+
+ if (vec_size(code_statements) != vec_size(code_linenums)) {
+ con_err("Linecounter wrong: %lu != %lu\n",
+ (unsigned long)vec_size(code_statements),
+ (unsigned long)vec_size(code_linenums));
+ } else if (OPTS_FLAG(LNO)) {
+ char *dot;
+ size_t filelen = strlen(filename);
+
+ memcpy(vec_add(lnofile, filelen+1), filename, filelen+1);
+ dot = strrchr(lnofile, '.');
+ if (!dot) {
+ vec_pop(lnofile);
+ } else {
+ vec_shrinkto(lnofile, dot - lnofile);
+ }
+ memcpy(vec_add(lnofile, 5), ".lno", 5);
+ }
- if (!opts_pp_only)
- con_out("writing '%s'...\n", filename);
- return code_write(filename);
+ if (lnofile)
+ con_out("writing '%s' and '%s'...\n", filename, lnofile);
+ else
+ con_out("writing '%s'\n", filename);
+ if (!code_write(filename, lnofile)) {
+ vec_free(lnofile);
+ return false;
+ }
+ vec_free(lnofile);
+ return true;
}
/***********************************************************************