added ir_get_meta / ir_set_meta

This commit is contained in:
Anthony Pesch 2017-08-09 00:05:12 -04:00
parent 47bb023092
commit a546ed04ff
4 changed files with 217 additions and 47 deletions

View File

@ -8,6 +8,10 @@ const struct ir_opdef ir_opdefs[IR_NUM_OPS] = {
#include "jit/ir/ir_ops.inc"
};
const char *ir_meta_names[IR_NUM_META] = {
"addr", "cycles", "fastmem", "reg",
};
static void *ir_calloc(struct ir *ir, int size) {
CHECK_LE(ir->used + size, ir->capacity);
uint8_t *ptr = ir->buffer + ir->used;
@ -215,7 +219,7 @@ struct ir_value *ir_alloc_int(struct ir *ir, int64_t c, enum ir_type type) {
v->i64 = c;
break;
default:
LOG_FATAL("Unexpected value type");
LOG_FATAL("unexpected value type");
break;
}
v->reg = NO_REGISTER;
@ -358,11 +362,48 @@ uint64_t ir_zext_constant(const struct ir_value *v) {
case VALUE_I64:
return (uint64_t)v->i64;
default:
LOG_FATAL("Unexpected value type");
LOG_FATAL("unexpected value type");
break;
}
}
struct ir_value *ir_get_meta(struct ir *ir, const void *obj, int kind) {
struct list *bkt = hash_bkt(ir->meta[kind], obj);
hash_bkt_for_each_entry(meta, bkt, struct ir_meta, it) {
if (meta->key == obj) {
CHECK(ir_is_constant(meta->value));
return meta->value;
}
}
return NULL;
}
void ir_set_meta(struct ir *ir, const void *obj, int kind,
struct ir_value *value) {
struct list *bkt = hash_bkt(ir->meta[kind], obj);
struct ir_meta *meta = NULL;
CHECK(ir_is_constant(value));
/* reuse existing meta object if possible */
hash_bkt_for_each_entry(it, bkt, struct ir_meta, it) {
if (it->key == obj) {
meta = it;
break;
}
}
if (!meta) {
meta = ir_calloc(ir, sizeof(struct ir_meta));
meta->key = obj;
hash_add(bkt, &meta->it);
}
meta->value = value;
}
void ir_source_info(struct ir *ir, uint32_t addr, int index) {
struct ir_instr *instr = ir_append_instr(ir, OP_SOURCE_INFO, VALUE_V);
ir_set_arg0(ir, instr, ir_alloc_i32(ir, addr));

View File

@ -3,6 +3,7 @@
#include <stdio.h>
#include "core/assert.h"
#include "core/hash.h"
#include "core/list.h"
#define IR_MAX_ARGS 4
@ -45,6 +46,14 @@ enum ir_cmp {
CMP_ULT
};
enum ir_meta_type {
IR_META_ADDR,
IR_META_CYCLES,
IR_META_FASTMEM,
IR_META_REG,
IR_NUM_META,
};
struct ir_block;
struct ir_instr;
struct ir_value;
@ -95,6 +104,12 @@ struct ir_value {
intptr_t tag;
};
struct ir_meta {
const void *key;
struct ir_value *value;
struct list_node it;
};
struct ir_instr {
enum ir_op op;
@ -117,7 +132,7 @@ struct ir_instr {
struct list_node it;
};
/* blocks are collections of instructions, terminating in a single branch */
/* control flow edge between blocks */
struct ir_edge {
struct ir_block *src;
struct ir_block *dst;
@ -126,6 +141,7 @@ struct ir_edge {
struct list_node it;
};
/* blocks are collections of instructions, terminating in a single branch */
struct ir_block {
struct list instrs;
@ -133,11 +149,10 @@ struct ir_block {
struct list outgoing;
struct list incoming;
/* intrusive iterator used by ir struct */
struct list_node it;
/* generic meta data used by optimization passes */
intptr_t tag;
struct list_node it;
};
/* locals are allocated for values that need to be spilled to the stack
@ -153,21 +168,26 @@ struct ir_insert_point {
};
struct ir {
/* backing memory buffer used by all ir allocations */
/* backing memory buffer used by all allocations */
uint8_t *buffer;
int capacity;
int used;
/* total size of locals allocated */
int locals_size;
/* current insert point */
struct ir_insert_point cursor;
/* current blocks in ir unit */
struct list blocks;
/* total size of locals allocated */
int locals_size;
/* hashtables for each kind of meta data, keyed by each user's pointer */
DECLARE_HASHTABLE(meta[IR_NUM_META], 7);
};
extern const struct ir_opdef ir_opdefs[IR_NUM_OPS];
extern const char *ir_meta_names[IR_NUM_META];
static inline int ir_type_size(enum ir_type type) {
switch (type) {
@ -251,6 +271,11 @@ void ir_replace_uses(struct ir_value *v, struct ir_value *other);
uint64_t ir_zext_constant(const struct ir_value *v);
/* attach meta data to instructions and blocks */
struct ir_value *ir_get_meta(struct ir *ir, const void *obj, int kind);
void ir_set_meta(struct ir *ir, const void *obj, int kind,
struct ir_value *value);
/* provides information to map guest instructions to host instructions */
void ir_source_info(struct ir *ir, uint32_t addr, int index);

View File

@ -80,7 +80,7 @@ static void ir_lex_next(struct ir_parser *p) {
}
/* test for assignment operator */
if (next == ':' || next == ',' || next == '=') {
if (next == ':' || next == ',' || next == '=' || next == '!') {
snprintf(p->val.s, sizeof(p->val.s), "%c", next);
p->tok = TOK_OPERATOR;
return;
@ -307,6 +307,49 @@ static int ir_parse_label(struct ir_parser *p, int *label) {
return 1;
}
static int ir_parse_constant(struct ir_parser *p, enum ir_type type,
struct ir_value **value) {
if (p->tok != TOK_INTEGER) {
LOG_INFO("unexpected token %d when parsing constant", p->tok);
return 0;
}
switch (type) {
case VALUE_I8: {
uint8_t v = (uint8_t)p->val.i;
*value = ir_alloc_i8(p->ir, v);
} break;
case VALUE_I16: {
uint16_t v = (uint16_t)p->val.i;
*value = ir_alloc_i16(p->ir, v);
} break;
case VALUE_I32: {
uint32_t v = (uint32_t)p->val.i;
*value = ir_alloc_i32(p->ir, v);
} break;
case VALUE_I64: {
uint64_t v = (uint64_t)p->val.i;
*value = ir_alloc_i64(p->ir, v);
} break;
case VALUE_F32: {
uint32_t v = (uint32_t)p->val.i;
*value = ir_alloc_f32(p->ir, *(float *)&v);
} break;
case VALUE_F64: {
uint64_t v = (uint64_t)p->val.i;
*value = ir_alloc_f64(p->ir, *(double *)&v);
} break;
default:
LOG_FATAL("unexpected value type");
break;
}
/* eat token */
ir_lex_next(p);
return 1;
}
static int ir_parse_arg(struct ir_parser *p, struct ir_instr *instr, int arg) {
/* parse value type */
enum ir_type type;
@ -327,48 +370,62 @@ static int ir_parse_arg(struct ir_parser *p, struct ir_instr *instr, int arg) {
been parsed */
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(p->ir, v);
} break;
case VALUE_I16: {
uint16_t v = (uint16_t)p->val.i;
value = ir_alloc_i16(p->ir, v);
} break;
case VALUE_I32: {
uint32_t v = (uint32_t)p->val.i;
value = ir_alloc_i32(p->ir, v);
} break;
case VALUE_I64: {
uint64_t v = (uint64_t)p->val.i;
value = ir_alloc_i64(p->ir, v);
} break;
case VALUE_F32: {
uint32_t v = (uint32_t)p->val.i;
value = ir_alloc_f32(p->ir, *(float *)&v);
} break;
case VALUE_F64: {
uint64_t v = (uint64_t)p->val.i;
value = ir_alloc_f64(p->ir, *(double *)&v);
} break;
default:
LOG_FATAL("unexpected value type");
break;
/* eat token */
ir_lex_next(p);
} else {
struct ir_value *value = NULL;
if (!ir_parse_constant(p, type, &value)) {
return 0;
}
ir_set_arg(p->ir, instr, arg, value);
} else {
LOG_INFO("unexpected token %d when parsing value: %s", p->tok, p->val.s);
return 0;
}
/* eat token */
return 1;
}
static int ir_parse_meta(struct ir_parser *p, void *obj) {
if (p->tok != TOK_OPERATOR || p->val.s[0] != '!') {
/* meta data is optional */
return 1;
}
ir_lex_next(p);
while (p->tok == TOK_IDENTIFIER) {
for (int kind = 0; kind < IR_NUM_META; kind++) {
if (strcasecmp(p->val.s, ir_meta_names[kind])) {
continue;
}
/* eat name */
ir_lex_next(p);
/* parse value type */
enum ir_type type;
if (!ir_parse_type(p, &type)) {
return 0;
}
/* parse value */
struct ir_value *value = NULL;
if (!ir_parse_constant(p, type, &value)) {
return 0;
}
/* attach meta data to object */
ir_set_meta(p->ir, obj, kind, value);
/* break if no comma */
if (p->tok != TOK_OPERATOR) {
break;
}
/* eat comma and move onto the next argument */
ir_lex_next(p);
}
}
return 1;
}
@ -407,6 +464,7 @@ static int ir_parse_instr(struct ir_parser *p) {
return 0;
}
/* break if no comma */
if (p->tok != TOK_OPERATOR) {
break;
}
@ -416,6 +474,10 @@ static int ir_parse_instr(struct ir_parser *p) {
}
}
if (!ir_parse_meta(p, instr)) {
return 0;
}
ir_insert_instr_label(p, instr, p->next_label++);
return 1;
@ -442,6 +504,10 @@ static int ir_parse_block(struct ir_parser *p) {
ir_insert_block_label(p, block, p->next_label++);
ir_set_current_block(p->ir, block);
if (!ir_parse_meta(p, block)) {
return 0;
}
return 1;
}

View File

@ -115,6 +115,35 @@ static void ir_write_value(struct ir_writer *w, const struct ir_value *value,
}
}
static void ir_write_meta(struct ir_writer *w, const void *obj, FILE *output) {
int need_exclamation = 1;
int need_comma = 0;
for (int kind = 0; kind < IR_NUM_META; kind++) {
struct ir_value *value = ir_get_meta(w->ir, obj, kind);
if (!value) {
continue;
}
if (need_exclamation) {
fprintf(output, " !");
need_exclamation = 0;
}
if (need_comma) {
fprintf(output, ", ");
need_comma = 0;
}
fprintf(output, "%s ", ir_meta_names[kind]);
ir_write_value(w, value, output);
need_comma = 1;
}
}
static void ir_write_instr(struct ir_writer *w, const struct ir_instr *instr,
FILE *output) {
/* print result value if it exists */
@ -125,9 +154,9 @@ static void ir_write_instr(struct ir_writer *w, const struct ir_instr *instr,
/* print the actual op */
ir_write_op(w, instr->op, output);
fprintf(output, " ");
/* print each argument */
int need_space = 1;
int need_comma = 0;
for (int i = 0; i < 3; i++) {
@ -137,6 +166,11 @@ static void ir_write_instr(struct ir_writer *w, const struct ir_instr *instr,
continue;
}
if (need_space) {
fprintf(output, " ");
need_space = 0;
}
if (need_comma) {
fprintf(output, ", ");
need_comma = 0;
@ -147,6 +181,8 @@ static void ir_write_instr(struct ir_writer *w, const struct ir_instr *instr,
need_comma = 1;
}
ir_write_meta(w, instr, output);
#if 0
fprintf(output, "\t# tag=%" PRId64 " reg=%d", instr->tag,
instr->result ? instr->result->reg : -1);
@ -157,7 +193,9 @@ static void ir_write_instr(struct ir_writer *w, const struct ir_instr *instr,
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));
fprintf(output, "%%%d:", ir_get_block_label(w, block));
ir_write_meta(w, block, output);
fprintf(output, "\n");
list_for_each_entry(instr, &block->instrs, struct ir_instr, it) {
ir_write_instr(w, instr, output);