192 lines
4.4 KiB
C
192 lines
4.4 KiB
C
#include <mie/ctx.h>
|
|
#include <mie/ir/block.h>
|
|
#include <mie/ir/builder.h>
|
|
#include <mie/ir/op-definition.h>
|
|
#include <mie/ir/op.h>
|
|
#include <mie/ir/region.h>
|
|
|
|
struct builder_scope {
|
|
b_queue_entry s_entry;
|
|
struct mie_op *s_op;
|
|
struct mie_region *s_region;
|
|
struct mie_block *s_block;
|
|
};
|
|
|
|
struct mie_builder {
|
|
struct mie_ctx *b_ctx;
|
|
b_queue b_scope_stack;
|
|
struct mie_op *b_root;
|
|
struct mie_op *b_prev_op;
|
|
};
|
|
|
|
struct mie_builder *mie_builder_create(struct mie_ctx *ctx, struct mie_op *root)
|
|
{
|
|
struct mie_builder *out = malloc(sizeof *out);
|
|
if (!out) {
|
|
return NULL;
|
|
}
|
|
|
|
memset(out, 0x0, sizeof *out);
|
|
|
|
out->b_ctx = ctx;
|
|
out->b_root = root;
|
|
|
|
mie_builder_step_into_op(out, root);
|
|
|
|
return out;
|
|
}
|
|
|
|
struct mie_ctx *mie_builder_get_ctx(struct mie_builder *builder)
|
|
{
|
|
return builder->b_ctx;
|
|
}
|
|
|
|
static struct mie_name_map *get_current_name_map(struct mie_builder *builder)
|
|
{
|
|
b_queue_entry *cur = b_queue_last(&builder->b_scope_stack);
|
|
while (cur) {
|
|
struct builder_scope *scope
|
|
= b_unbox(struct builder_scope, cur, s_entry);
|
|
|
|
if (scope->s_region && scope->s_region->r_names) {
|
|
return scope->s_region->r_names;
|
|
}
|
|
|
|
cur = b_queue_prev(cur);
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
struct mie_block *mie_builder_get_current_block(struct mie_builder *builder)
|
|
{
|
|
b_queue_entry *entry = b_queue_last(&builder->b_scope_stack);
|
|
if (!entry) {
|
|
return NULL;
|
|
}
|
|
|
|
struct builder_scope *scope
|
|
= b_unbox(struct builder_scope, entry, s_entry);
|
|
|
|
return scope->s_block;
|
|
}
|
|
|
|
void mie_builder_step_into_op(struct mie_builder *builder, struct mie_op *op)
|
|
{
|
|
struct mie_region *region = NULL;
|
|
|
|
if (MIE_VECTOR_COUNT(op->op_regions) == 0) {
|
|
region = mie_op_add_region(op);
|
|
} else {
|
|
region = &op->op_regions.items[MIE_VECTOR_COUNT(op->op_regions) - 1];
|
|
}
|
|
|
|
mie_builder_step_into_region(builder, region);
|
|
}
|
|
|
|
void mie_builder_step_into_region(
|
|
struct mie_builder *builder, struct mie_region *region)
|
|
{
|
|
struct mie_block *block = NULL;
|
|
|
|
if (MIE_VECTOR_COUNT(region->r_blocks) == 0) {
|
|
block = mie_region_add_block(region);
|
|
} else {
|
|
block = ®ion->r_blocks.items[MIE_VECTOR_COUNT(region->r_blocks) - 1];
|
|
}
|
|
|
|
mie_builder_step_into_block(builder, block);
|
|
}
|
|
|
|
void mie_builder_step_into_block(struct mie_builder *builder, struct mie_block *block)
|
|
{
|
|
struct builder_scope *scope = malloc(sizeof *scope);
|
|
if (!scope) {
|
|
return;
|
|
}
|
|
|
|
memset(scope, 0x0, sizeof *scope);
|
|
|
|
scope->s_block = block;
|
|
scope->s_region = block->b_parent;
|
|
scope->s_op = scope->s_region->r_parent;
|
|
|
|
b_queue_push_back(&builder->b_scope_stack, &scope->s_entry);
|
|
}
|
|
|
|
void mie_builder_step_out(struct mie_builder *builder)
|
|
{
|
|
b_queue_entry *entry = b_queue_last(&builder->b_scope_stack);
|
|
if (!entry) {
|
|
return;
|
|
}
|
|
|
|
struct builder_scope *scope
|
|
= b_unbox(struct builder_scope, entry, s_entry);
|
|
b_queue_delete(&builder->b_scope_stack, entry);
|
|
free(scope);
|
|
}
|
|
|
|
static struct mie_block *create_current_block(struct mie_builder *builder)
|
|
{
|
|
struct mie_region *region = NULL;
|
|
|
|
if (MIE_VECTOR_COUNT(builder->b_root->op_regions) == 0) {
|
|
region = mie_op_add_region(builder->b_root);
|
|
} else {
|
|
region = &builder->b_root->op_regions
|
|
.items[MIE_VECTOR_COUNT(builder->b_root->op_result) - 1];
|
|
}
|
|
|
|
struct mie_block *block = NULL;
|
|
|
|
if (MIE_VECTOR_COUNT(region->r_blocks) == 0) {
|
|
block = mie_region_add_block(region);
|
|
} else {
|
|
block = ®ion->r_blocks.items[MIE_VECTOR_COUNT(region->r_blocks)];
|
|
}
|
|
|
|
return block;
|
|
}
|
|
|
|
struct mie_op *mie_builder_put_op(
|
|
struct mie_builder *builder, const char *dialect, const char *op_name,
|
|
struct mie_register **args, size_t nr_args)
|
|
{
|
|
struct mie_block *block = mie_builder_get_current_block(builder);
|
|
|
|
const struct mie_op_definition *op_def
|
|
= mie_ctx_get_op_definition(builder->b_ctx, dialect, op_name);
|
|
if (!op_def) {
|
|
return NULL;
|
|
}
|
|
|
|
struct mie_op *op = mie_block_add_op(block);
|
|
op->op_flags = MIE_OP_F_OP_RESOLVED;
|
|
op->op_info = op_def;
|
|
op->op_dialect = op_def->op_parent;
|
|
|
|
for (size_t i = 0; i < nr_args; i++) {
|
|
struct mie_op_arg *arg = mie_op_add_arg(op);
|
|
arg->arg_flags = MIE_OP_F_ARG_RESOLVED;
|
|
arg->arg_value.u_reg = args[i];
|
|
arg->arg_value.u_user = op;
|
|
b_queue_push_back(&args[i]->reg_use, &arg->arg_value.u_entry);
|
|
}
|
|
|
|
return op;
|
|
}
|
|
|
|
enum mie_status mie_builder_put_name(
|
|
struct mie_builder *builder, struct mie_name *name, const char *hint)
|
|
{
|
|
struct mie_name_map *map = get_current_name_map(builder);
|
|
if (!map) {
|
|
return MIE_ERR_BAD_STATE;
|
|
}
|
|
|
|
struct mie_name *result = mie_name_map_put(map, name, hint, 0);
|
|
|
|
return result ? MIE_SUCCESS : MIE_ERR_NAME_EXISTS;
|
|
}
|