mirror of https://github.com/inolen/redream.git
added ir_get_meta / ir_set_meta
This commit is contained in:
parent
47bb023092
commit
a546ed04ff
|
@ -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));
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue