convert to integer based labels in ir_read / ir_write

This commit is contained in:
Anthony Pesch 2017-08-07 17:14:08 -04:00
parent 2364f9d764
commit 89541723f7
4 changed files with 149 additions and 132 deletions

View File

@ -119,24 +119,6 @@ struct ir_block *ir_split_block(struct ir *ir, struct ir_instr *before) {
return new_block;
}
void ir_set_block_label(struct ir *ir, struct ir_block *block,
const char *format, ...) {
va_list args;
va_start(args, format);
int label_len = vsnprintf(0, 0, format, args);
int label_size = label_len + 1;
CHECK_LE(label_size, IR_MAX_LABEL);
char *label = ir_calloc(ir, label_size);
va_end(args);
va_start(args, format);
vsnprintf(label, label_size, format, args);
va_end(args);
block->label = label;
}
void ir_remove_block(struct ir *ir, struct ir_block *block) {
/* remove all instructions */
list_for_each_entry_safe(instr, &block->instrs, struct ir_instr, it) {
@ -201,24 +183,6 @@ struct ir_instr *ir_append_instr(struct ir *ir, enum ir_op op,
return instr;
}
void ir_set_instr_label(struct ir *ir, struct ir_instr *instr,
const char *format, ...) {
va_list args;
va_start(args, format);
int label_len = vsnprintf(0, 0, format, args);
int label_size = label_len + 1;
CHECK_LE(label_size, IR_MAX_LABEL);
char *label = ir_calloc(ir, label_size);
va_end(args);
va_start(args, format);
vsnprintf(label, label_size, format, args);
va_end(args);
instr->label = label;
}
void ir_remove_instr(struct ir *ir, struct ir_instr *instr) {
/* remove arguments from the use lists of their values */
for (int i = 0; i < IR_MAX_ARGS; i++) {

View File

@ -5,7 +5,6 @@
#include "core/assert.h"
#include "core/list.h"
#define IR_MAX_LABEL 128
#define IR_MAX_ARGS 4
#define NO_REGISTER -1
@ -99,8 +98,6 @@ struct ir_value {
};
struct ir_instr {
const char *label;
enum ir_op op;
/* values used by each argument. note, the argument / use is split into two
@ -132,8 +129,6 @@ struct ir_edge {
};
struct ir_block {
const char *label;
struct list instrs;
/* edges between this block and others */
@ -226,15 +221,11 @@ void ir_set_current_instr(struct ir *ir, struct ir_instr *instr);
struct ir_block *ir_insert_block(struct ir *ir, struct ir_block *after);
struct ir_block *ir_append_block(struct ir *ir);
struct ir_block *ir_split_block(struct ir *ir, struct ir_instr *before);
void ir_set_block_label(struct ir *ir, struct ir_block *block,
const char *format, ...);
void ir_remove_block(struct ir *ir, struct ir_block *block);
void ir_add_edge(struct ir *ir, struct ir_block *src, struct ir_block *dst);
struct ir_instr *ir_append_instr(struct ir *ir, enum ir_op op,
enum ir_type result_type);
void ir_set_instr_label(struct ir *ir, struct ir_instr *instr,
const char *format, ...);
void ir_remove_instr(struct ir *ir, struct ir_instr *instr);
struct ir_value *ir_alloc_int(struct ir *ir, int64_t c, enum ir_type type);

View File

@ -16,7 +16,7 @@ struct ir_reference {
struct ir_instr *instr;
int arg;
enum ir_type type;
char name[IR_MAX_LABEL];
int label;
struct list_node it;
};
@ -29,9 +29,14 @@ struct ir_lexeme {
struct ir_parser {
FILE *input;
struct ir *ir;
enum ir_token tok;
struct ir_lexeme val;
struct list refs;
int *labels;
int next_label;
};
static const char *typenames[] = {"", "i8", "i16", "i32", "i64",
@ -154,40 +159,62 @@ static void ir_lex_next(struct ir_parser *p) {
}
static void ir_destroy_parser(struct ir_parser *p) {
free(p->labels);
list_for_each_entry_safe(ref, &p->refs, struct ir_reference, it) {
free(ref);
}
}
static int ir_resolve_references(struct ir_parser *p, struct ir *ir) {
static void ir_insert_block_label(struct ir_parser *p,
const struct ir_block *block, int label) {
p->labels[(uint8_t *)block - p->ir->buffer] = label;
}
static void ir_insert_instr_label(struct ir_parser *p,
const struct ir_instr *instr, int label) {
p->labels[(uint8_t *)instr - p->ir->buffer] = label;
}
static int ir_get_block_label(struct ir_parser *p,
const struct ir_block *block) {
return p->labels[(uint8_t *)block - p->ir->buffer];
}
static int ir_get_instr_label(struct ir_parser *p,
const struct ir_instr *instr) {
return p->labels[(uint8_t *)instr - p->ir->buffer];
}
static int ir_resolve_references(struct ir_parser *p) {
list_for_each_entry(ref, &p->refs, struct ir_reference, it) {
struct ir_value *value = NULL;
if (ref->type == VALUE_BLOCK) {
struct ir_block *found = NULL;
list_for_each_entry(block, &ir->blocks, struct ir_block, it) {
if (block->label && !strcmp(block->label, ref->name)) {
list_for_each_entry(block, &p->ir->blocks, struct ir_block, it) {
if (ir_get_block_label(p, block) == ref->label) {
found = block;
break;
}
}
if (!found) {
LOG_INFO("Failed to resolve reference for %%%s", ref->name);
LOG_INFO("failed to resolve reference for %%%d", ref->label);
return 0;
}
value = ir_alloc_block_ref(ir, found);
value = ir_alloc_block_ref(p->ir, found);
} else {
struct ir_instr *found = NULL;
list_for_each_entry(block, &ir->blocks, struct ir_block, it) {
list_for_each_entry(block, &p->ir->blocks, struct ir_block, it) {
if (found) {
break;
}
list_for_each_entry(instr, &block->instrs, struct ir_instr, it) {
if (instr->label && !strcmp(instr->label, ref->name)) {
if (ir_get_instr_label(p, instr) == ref->label) {
found = instr;
break;
}
@ -195,33 +222,32 @@ static int ir_resolve_references(struct ir_parser *p, struct ir *ir) {
}
if (!found) {
LOG_INFO("Failed to resolve reference for %%%s", ref->name);
LOG_INFO("failed to resolve reference for %%%d", ref->label);
return 0;
}
value = found->result;
}
ir_set_arg(ir, ref->instr, ref->arg, value);
ir_set_arg(p->ir, ref->instr, ref->arg, value);
}
return 1;
}
static void ir_defer_reference(struct ir_parser *p, struct ir_instr *instr,
int arg, enum ir_type type, const char *name) {
int arg, enum ir_type type, int label) {
struct ir_reference *ref = calloc(1, sizeof(struct ir_reference));
ref->instr = instr;
ref->arg = arg;
ref->type = type;
strncpy(ref->name, name, sizeof(ref->name));
ref->label = label;
list_add(&p->refs, &ref->it);
}
static int ir_parse_type(struct ir_parser *p, struct ir *ir,
enum ir_type *type) {
static int ir_parse_type(struct ir_parser *p, enum ir_type *type) {
if (p->tok != TOK_TYPE) {
LOG_INFO("Unexpected token %d when parsing type", p->tok);
LOG_INFO("unexpected token %d when parsing type", p->tok);
return 0;
}
@ -233,9 +259,9 @@ static int ir_parse_type(struct ir_parser *p, struct ir *ir,
return 1;
}
static int ir_parse_op(struct ir_parser *p, struct ir *ir, enum ir_op *op) {
static int ir_parse_op(struct ir_parser *p, enum ir_op *op) {
if (p->tok != TOK_OP) {
LOG_INFO("Unexpected token %d when parsing op", p->tok);
LOG_INFO("unexpected token %d when parsing op", p->tok);
return 0;
}
@ -247,11 +273,11 @@ static int ir_parse_op(struct ir_parser *p, struct ir *ir, enum ir_op *op) {
return 1;
}
static int ir_parse_operator(struct ir_parser *p, struct ir *ir) {
static int ir_parse_operator(struct ir_parser *p) {
const char *op_str = p->val.s;
if (strcmp(op_str, "=")) {
LOG_INFO("Unexpected operator '%s'", op_str);
LOG_INFO("unexpected operator '%s'", op_str);
return 0;
}
@ -263,28 +289,28 @@ static int ir_parse_operator(struct ir_parser *p, struct ir *ir) {
return 1;
}
static int ir_parse_label(struct ir_parser *p, struct ir *ir, char *label) {
static int ir_parse_label(struct ir_parser *p, int *label) {
if (p->tok != TOK_IDENTIFIER) {
LOG_INFO("Unexpected token %d when parsing label", p->tok);
LOG_INFO("unexpected token %d when parsing label", p->tok);
return 0;
}
const char *ident = p->val.s;
if (ident[0] != '%') {
LOG_INFO("Expected label '%s' to begin with %%", ident);
LOG_INFO("expected label '%s' to begin with %%", ident);
return 0;
}
strcpy(label, &ident[1]);
*label = strtol(&ident[1], NULL, 10);
ir_lex_next(p);
return 1;
}
static int ir_parse_arg(struct ir_parser *p, struct ir *ir,
struct ir_instr *instr, int arg) {
static int ir_parse_arg(struct ir_parser *p, struct ir_instr *instr, int arg) {
/* parse value type */
enum ir_type type;
if (!ir_parse_type(p, ir, &type)) {
if (!ir_parse_type(p, &type)) {
return 0;
}
@ -293,53 +319,53 @@ static int ir_parse_arg(struct ir_parser *p, struct ir *ir,
const char *ident = p->val.s;
if (ident[0] != '%') {
LOG_INFO("Expected identifier to begin with %%");
LOG_INFO("expected identifier to begin with %%");
return 0;
}
/* label reference, defer resolution until after all blocks / values have
been parsed */
const char *name = &ident[1];
ir_defer_reference(p, instr, arg, type, name);
int id = strtol(&ident[1], NULL, 10);
ir_defer_reference(p, instr, arg, type, id);
} else if (p->tok == TOK_INTEGER || p->tok == TOK_STRING) {
struct ir_value *value = NULL;
switch (type) {
case VALUE_I8: {
uint8_t v = (uint8_t)p->val.i;
value = ir_alloc_i8(ir, v);
value = ir_alloc_i8(p->ir, v);
} break;
case VALUE_I16: {
uint16_t v = (uint16_t)p->val.i;
value = ir_alloc_i16(ir, v);
value = ir_alloc_i16(p->ir, v);
} break;
case VALUE_I32: {
uint32_t v = (uint32_t)p->val.i;
value = ir_alloc_i32(ir, v);
value = ir_alloc_i32(p->ir, v);
} break;
case VALUE_I64: {
uint64_t v = (uint64_t)p->val.i;
value = ir_alloc_i64(ir, v);
value = ir_alloc_i64(p->ir, v);
} break;
case VALUE_F32: {
uint32_t v = (uint32_t)p->val.i;
value = ir_alloc_f32(ir, *(float *)&v);
value = ir_alloc_f32(p->ir, *(float *)&v);
} break;
case VALUE_F64: {
uint64_t v = (uint64_t)p->val.i;
value = ir_alloc_f64(ir, *(double *)&v);
value = ir_alloc_f64(p->ir, *(double *)&v);
} break;
case VALUE_STRING: {
value = ir_alloc_str(ir, p->val.s);
value = ir_alloc_str(p->ir, p->val.s);
} break;
default:
LOG_FATAL("Unexpected value type");
LOG_FATAL("unexpected value type");
break;
}
ir_set_arg(ir, instr, arg, value);
ir_set_arg(p->ir, instr, arg, value);
} else {
LOG_INFO("Unexpected token %d when parsing value: %s", p->tok, p->val.s);
LOG_INFO("unexpected token %d when parsing value: %s", p->tok, p->val.s);
return 0;
}
@ -349,38 +375,38 @@ static int ir_parse_arg(struct ir_parser *p, struct ir *ir,
return 1;
}
static int ir_parse_instr(struct ir_parser *p, struct ir *ir) {
static int ir_parse_instr(struct ir_parser *p) {
enum ir_type type = VALUE_V;
char label[IR_MAX_LABEL] = {0};
int label = 0;
/* parse result type and label */
if (p->tok == TOK_TYPE) {
if (!ir_parse_type(p, ir, &type)) {
if (!ir_parse_type(p, &type)) {
return 0;
}
if (!ir_parse_label(p, ir, label)) {
if (!ir_parse_label(p, &label)) {
return 0;
}
if (!ir_parse_operator(p, ir)) {
if (!ir_parse_operator(p)) {
return 0;
}
}
/* parse op */
enum ir_op op;
if (!ir_parse_op(p, ir, &op)) {
if (!ir_parse_op(p, &op)) {
return 0;
}
/* create instruction */
struct ir_instr *instr = ir_append_instr(ir, op, type);
struct ir_instr *instr = ir_append_instr(p->ir, op, type);
/* parse arguments */
if (p->tok == TOK_TYPE) {
for (int i = 0; i < IR_MAX_ARGS; i++) {
if (!ir_parse_arg(p, ir, instr, i)) {
if (!ir_parse_arg(p, instr, i)) {
return 0;
}
@ -393,33 +419,31 @@ static int ir_parse_instr(struct ir_parser *p, struct ir *ir) {
}
}
if (label[0]) {
ir_set_instr_label(ir, instr, label);
}
ir_insert_instr_label(p, instr, p->next_label++);
return 1;
}
static int ir_parse_block(struct ir_parser *p, struct ir *ir) {
static int ir_parse_block(struct ir_parser *p) {
if (p->tok != TOK_IDENTIFIER) {
LOG_INFO("Unexpected token %d when parsing block", p->tok);
LOG_INFO("unexpected token %d when parsing block", p->tok);
return 0;
}
char label[IR_MAX_LABEL];
if (!ir_parse_label(p, ir, label)) {
int label;
if (!ir_parse_label(p, &label)) {
return 0;
}
if (p->tok != TOK_OPERATOR || p->val.s[0] != ':') {
LOG_INFO("Expected label to be followed by : operator");
LOG_INFO("expected label to be followed by : operator");
return 0;
}
ir_lex_next(p);
struct ir_block *block = ir_append_block(ir);
ir_set_block_label(ir, block, label);
ir_set_current_block(ir, block);
struct ir_block *block = ir_append_block(p->ir);
ir_insert_block_label(p, block, p->next_label++);
ir_set_current_block(p->ir, block);
return 1;
}
@ -427,6 +451,8 @@ static int ir_parse_block(struct ir_parser *p, struct ir *ir) {
int ir_read(FILE *input, struct ir *ir) {
struct ir_parser p = {0};
p.input = input;
p.ir = ir;
p.labels = malloc(sizeof(int) * ir->capacity);
int res = 1;
@ -434,19 +460,19 @@ int ir_read(FILE *input, struct ir *ir) {
ir_lex_next(&p);
if (p.tok == TOK_EOF) {
if (!ir_resolve_references(&p, ir)) {
if (!ir_resolve_references(&p)) {
res = 0;
}
break;
}
if (p.tok == TOK_IDENTIFIER) {
if (!ir_parse_block(&p, ir)) {
if (!ir_parse_block(&p)) {
res = 0;
break;
}
} else {
if (!ir_parse_instr(&p, ir)) {
if (!ir_parse_instr(&p)) {
res = 0;
break;
}

View File

@ -2,7 +2,37 @@
#include "core/string.h"
#include "jit/ir/ir.h"
static void ir_write_type(enum ir_type type, FILE *output) {
struct ir_writer {
struct ir *ir;
int *labels;
};
static void ir_destroy_writer(struct ir_writer *w) {
free(w->labels);
}
static void ir_insert_block_label(struct ir_writer *w,
const struct ir_block *block, int label) {
w->labels[(uint8_t *)block - w->ir->buffer] = label;
}
static void ir_insert_instr_label(struct ir_writer *w,
const struct ir_instr *instr, int label) {
w->labels[(uint8_t *)instr - w->ir->buffer] = label;
}
static int ir_get_block_label(struct ir_writer *w,
const struct ir_block *block) {
return w->labels[(uint8_t *)block - w->ir->buffer];
}
static int ir_get_instr_label(struct ir_writer *w,
const struct ir_instr *instr) {
return w->labels[(uint8_t *)instr - w->ir->buffer];
}
static void ir_write_type(struct ir_writer *w, enum ir_type type,
FILE *output) {
switch (type) {
case VALUE_I8:
fprintf(output, "i8");
@ -32,12 +62,12 @@ static void ir_write_type(enum ir_type type, FILE *output) {
fprintf(output, "blk");
break;
default:
LOG_FATAL("Unexpected value type");
LOG_FATAL("unexpected value type");
break;
}
}
static void ir_write_op(enum ir_op op, FILE *output) {
static void ir_write_op(struct ir_writer *w, enum ir_op op, FILE *output) {
const struct ir_opdef *def = &ir_opdefs[op];
const char *name = def->name;
@ -47,8 +77,9 @@ static void ir_write_op(enum ir_op op, FILE *output) {
}
}
static void ir_write_value(const struct ir_value *value, FILE *output) {
ir_write_type(value->type, output);
static void ir_write_value(struct ir_writer *w, const struct ir_value *value,
FILE *output) {
ir_write_type(w, value->type, output);
fprintf(output, " ");
@ -79,26 +110,27 @@ static void ir_write_value(const struct ir_value *value, FILE *output) {
fprintf(output, "'%s'", value->str);
} break;
case VALUE_BLOCK:
fprintf(output, "%%%s", value->blk->label);
fprintf(output, "%%%d", ir_get_block_label(w, value->blk));
break;
default:
LOG_FATAL("Unexpected value type");
LOG_FATAL("unexpected value type");
break;
}
} else {
fprintf(output, "%%%s", value->def->label);
fprintf(output, "%%%d", ir_get_instr_label(w, value->def));
}
}
static void ir_write_instr(const struct ir_instr *instr, FILE *output) {
static void ir_write_instr(struct ir_writer *w, const struct ir_instr *instr,
FILE *output) {
/* print result value if it exists */
if (instr->result) {
ir_write_value(instr->result, output);
ir_write_value(w, instr->result, output);
fprintf(output, " = ");
}
/* print the actual op */
ir_write_op(instr->op, output);
ir_write_op(w, instr->op, output);
fprintf(output, " ");
/* print each argument */
@ -116,7 +148,7 @@ static void ir_write_instr(const struct ir_instr *instr, FILE *output) {
need_comma = 0;
}
ir_write_value(arg, output);
ir_write_value(w, arg, output);
need_comma = 1;
}
@ -129,36 +161,40 @@ static void ir_write_instr(const struct ir_instr *instr, FILE *output) {
fprintf(output, "\n");
}
static void ir_write_block(const struct ir_block *block, FILE *output) {
fprintf(output, "%%%s:\n", block->label);
static void ir_write_block(struct ir_writer *w, const struct ir_block *block,
FILE *output) {
fprintf(output, "%%%d:\n", ir_get_block_label(w, block));
list_for_each_entry(instr, &block->instrs, struct ir_instr, it) {
ir_write_instr(instr, output);
ir_write_instr(w, instr, output);
}
fprintf(output, "\n");
}
static void ir_assign_default_labels(struct ir *ir) {
int id = 0;
static void ir_assign_labels(struct ir_writer *w) {
int label = 0;
list_for_each_entry(block, &ir->blocks, struct ir_block, it) {
if (!block->label) {
ir_set_block_label(ir, block, "%d", id++);
}
w->labels = malloc(sizeof(int) * w->ir->capacity);
list_for_each_entry(block, &w->ir->blocks, struct ir_block, it) {
ir_insert_block_label(w, block, label++);
list_for_each_entry(instr, &block->instrs, struct ir_instr, it) {
if (!instr->label) {
ir_set_instr_label(ir, instr, "%d", id++);
}
ir_insert_instr_label(w, instr, label++);
}
}
}
void ir_write(struct ir *ir, FILE *output) {
ir_assign_default_labels(ir);
struct ir_writer w = {0};
w.ir = ir;
ir_assign_labels(&w);
list_for_each_entry(block, &ir->blocks, struct ir_block, it) {
ir_write_block(block, output);
ir_write_block(&w, block, output);
}
ir_destroy_writer(&w);
}