277 lines
5.8 KiB
C
277 lines
5.8 KiB
C
#include <assert.h>
|
|
#include <mie/dialect/dialect.h>
|
|
#include <mie/ir/block.h>
|
|
#include <mie/ir/op-definition.h>
|
|
#include <mie/ir/op.h>
|
|
#include <mie/ir/region.h>
|
|
#include <stdlib.h>
|
|
|
|
static enum mie_status op_arg_cleanup(void *p)
|
|
{
|
|
struct mie_op_arg *arg = p;
|
|
|
|
if (arg->arg_flags & MIE_OP_F_ARG_RESOLVED) {
|
|
b_queue_delete(
|
|
&arg->arg_value.u_reg->reg_use, &arg->arg_value.u_entry);
|
|
}
|
|
|
|
return MIE_SUCCESS;
|
|
}
|
|
|
|
static enum mie_status op_arg_move(void *dst, void *src, size_t itemsz)
|
|
{
|
|
assert(itemsz == sizeof(struct mie_op_arg));
|
|
struct mie_op_arg *dest_arg = dst, *src_arg = src;
|
|
memmove(dest_arg, src_arg, sizeof *src_arg);
|
|
|
|
if (src_arg->arg_flags & MIE_OP_F_ARG_RESOLVED) {
|
|
mie_register_use_move(&dest_arg->arg_value, &src_arg->arg_value);
|
|
}
|
|
|
|
return MIE_SUCCESS;
|
|
}
|
|
|
|
struct mie_vector_ops op_arg_vector_ops = {
|
|
.v_destroy = op_arg_cleanup,
|
|
.v_move = op_arg_move,
|
|
};
|
|
|
|
struct mie_op *mie_op_create(void)
|
|
{
|
|
struct mie_op *out = malloc(sizeof *out);
|
|
if (!out) {
|
|
return NULL;
|
|
}
|
|
|
|
mie_op_init(out);
|
|
|
|
return out;
|
|
}
|
|
|
|
void mie_op_destroy(struct mie_op *op)
|
|
{
|
|
mie_op_cleanup(op);
|
|
free(op);
|
|
}
|
|
|
|
void mie_op_init(struct mie_op *op)
|
|
{
|
|
memset(op, 0x0, sizeof *op);
|
|
|
|
mie_attribute_map_init(&op->op_attrib);
|
|
}
|
|
|
|
void mie_op_cleanup(struct mie_op *op)
|
|
{
|
|
/* TODO */
|
|
}
|
|
|
|
struct mie_op_arg *mie_op_add_arg(struct mie_op *op)
|
|
{
|
|
return mie_vector_emplace_back(op->op_args, &op_arg_vector_ops);
|
|
}
|
|
|
|
struct mie_register *mie_op_add_result(struct mie_op *op, const struct mie_type *ty)
|
|
{
|
|
struct mie_register *result = mie_vector_emplace_back(
|
|
op->op_result, &mie_register_vector_ops);
|
|
result->reg_flags = MIE_REGISTER_F_VIRTUAL | MIE_REGISTER_F_OP_RESULT;
|
|
result->reg_type = ty;
|
|
result->reg_op = op;
|
|
result->reg_block = op->op_container;
|
|
|
|
return result;
|
|
}
|
|
|
|
struct mie_op_successor *mie_op_add_successor(
|
|
struct mie_op *op, struct mie_block *block, struct mie_register **args,
|
|
size_t nr_args)
|
|
{
|
|
struct mie_op_successor *s
|
|
= mie_vector_emplace_back(op->op_successors, NULL);
|
|
|
|
s->s_flags = MIE_OP_F_SUCCESSOR_RESOLVED;
|
|
s->s_block = block;
|
|
|
|
for (size_t i = 0; i < nr_args; i++) {
|
|
struct mie_op_arg *arg
|
|
= mie_vector_emplace_back(s->s_args, &op_arg_vector_ops);
|
|
|
|
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 s;
|
|
}
|
|
|
|
static bool is_isolated(const struct mie_op *op)
|
|
{
|
|
const struct mie_trait *isolated = mie_trait_table_get_unique(
|
|
&op->op_info->op_traits, "builtin", "isolated-from-above");
|
|
return isolated != NULL;
|
|
}
|
|
|
|
struct mie_region *mie_op_add_region(struct mie_op *op)
|
|
{
|
|
bool isolated = is_isolated(op);
|
|
|
|
struct mie_region *region = malloc(sizeof *region);
|
|
if (!region) {
|
|
return NULL;
|
|
}
|
|
|
|
region->r_parent = op;
|
|
|
|
if (isolated) {
|
|
region->r_names = mie_name_map_create(NULL);
|
|
}
|
|
|
|
b_queue_push_back(&op->op_regions, ®ion->r_entry);
|
|
|
|
return region;
|
|
}
|
|
|
|
bool mie_op_is(const struct mie_op *op, const char *dialect_name, const char *op_name)
|
|
{
|
|
if (!op->op_info || !op->op_dialect) {
|
|
return false;
|
|
}
|
|
|
|
if (strcmp(op->op_dialect->d_name, dialect_name) != 0) {
|
|
return false;
|
|
}
|
|
|
|
if (strcmp(op->op_info->op_name, op_name) != 0) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool mie_op_has_trait(
|
|
const struct mie_op *op, const char *dialect_name, const char *trait_name)
|
|
{
|
|
if (!op->op_info) {
|
|
return false;
|
|
}
|
|
|
|
if (mie_trait_table_get_unique(
|
|
&op->op_info->op_traits, dialect_name, trait_name)) {
|
|
return true;
|
|
}
|
|
|
|
struct mie_trait_table_iterator it;
|
|
enum mie_status status = mie_trait_table_get_generic(
|
|
&op->op_info->op_traits, dialect_name, trait_name, &it);
|
|
|
|
return (status == MIE_SUCCESS);
|
|
}
|
|
|
|
bool mie_op_has_interface(
|
|
const struct mie_op *op, const char *dialect_name, const char *iface_name)
|
|
{
|
|
if (!op->op_info) {
|
|
return false;
|
|
}
|
|
|
|
const struct mie_interface *p = mie_interface_map_get(
|
|
&op->op_info->op_iface, dialect_name, iface_name);
|
|
return p != NULL;
|
|
}
|
|
|
|
struct mie_region *mie_op_get_first_region(const struct mie_op *op)
|
|
{
|
|
b_queue_entry *entry = b_queue_first(&op->op_regions);
|
|
if (!entry) {
|
|
return NULL;
|
|
}
|
|
|
|
return b_unbox(struct mie_region, entry, r_entry);
|
|
}
|
|
|
|
struct mie_region *mie_op_get_prev_region(
|
|
const struct mie_op *op, const struct mie_region *before)
|
|
{
|
|
if (!before || before->r_parent != op) {
|
|
return NULL;
|
|
}
|
|
|
|
b_queue_entry *entry = b_queue_prev(&before->r_entry);
|
|
if (!entry) {
|
|
return NULL;
|
|
}
|
|
|
|
return b_unbox(struct mie_region, entry, r_entry);
|
|
}
|
|
|
|
struct mie_region *mie_op_get_next_region(
|
|
const struct mie_op *op, const struct mie_region *after)
|
|
{
|
|
if (!after || after->r_parent != op) {
|
|
return NULL;
|
|
}
|
|
|
|
b_queue_entry *entry = b_queue_next(&after->r_entry);
|
|
if (!entry) {
|
|
return NULL;
|
|
}
|
|
|
|
return b_unbox(struct mie_region, entry, r_entry);
|
|
}
|
|
|
|
struct mie_region *mie_op_get_last_region(const struct mie_op *op)
|
|
{
|
|
b_queue_entry *entry = b_queue_last(&op->op_regions);
|
|
if (!entry) {
|
|
return NULL;
|
|
}
|
|
|
|
return b_unbox(struct mie_region, entry, r_entry);
|
|
}
|
|
|
|
struct mie_register *mie_op_get_arg(const struct mie_op *op, size_t index)
|
|
{
|
|
if (MIE_VECTOR_COUNT(op->op_args) <= index) {
|
|
return NULL;
|
|
}
|
|
|
|
const struct mie_op_arg *arg = &op->op_args.items[index];
|
|
if (!(arg->arg_flags & MIE_OP_F_ARG_RESOLVED)) {
|
|
return NULL;
|
|
}
|
|
|
|
return arg->arg_value.u_reg;
|
|
}
|
|
|
|
struct mie_op *mie_op_get_first_child_op(const struct mie_op *op)
|
|
{
|
|
struct mie_region *first_region = mie_op_get_first_region(op);
|
|
if (!first_region) {
|
|
return NULL;
|
|
}
|
|
|
|
struct mie_block *first_block = mie_region_get_first_block(first_region);
|
|
if (!first_block) {
|
|
return NULL;
|
|
}
|
|
|
|
return mie_block_get_first_op(first_block);
|
|
}
|
|
|
|
struct mie_op *mie_op_get_last_child_op(const struct mie_op *op)
|
|
{
|
|
struct mie_region *last_region = mie_op_get_last_region(op);
|
|
if (!last_region) {
|
|
return NULL;
|
|
}
|
|
|
|
struct mie_block *last_block = mie_region_get_last_block(last_region);
|
|
if (!last_block) {
|
|
return NULL;
|
|
}
|
|
|
|
return mie_block_get_last_op(last_block);
|
|
}
|