Files
ivy/mie/ir/builder.c

794 lines
16 KiB
C

#include <blue/object/string.h>
#include <mie/ctx.h>
#include <mie/ir/alloca.h>
#include <mie/ir/block.h>
#include <mie/ir/branch.h>
#include <mie/ir/builder.h>
#include <mie/ir/data.h>
#include <mie/ir/func.h>
#include <mie/ir/module.h>
#include <mie/ir/msg.h>
#include <mie/ir/op.h>
#include <mie/ir/ptr.h>
#include <mie/ir/record.h>
#include <mie/type.h>
#include <stdlib.h>
#include <string.h>
struct mie_builder *mie_builder_create(struct mie_ctx *ctx, struct mie_module *mod)
{
struct mie_builder *out = malloc(sizeof *out);
if (!out) {
return NULL;
}
memset(out, 0x0, sizeof *out);
out->b_ctx = ctx;
out->b_module = mod;
return out;
}
void mie_builder_destroy(struct mie_builder *builder)
{
free(builder);
}
struct mie_func *mie_builder_get_current_func(struct mie_builder *builder)
{
struct mie_block *block = builder->b_current_block;
if (!block) {
return NULL;
}
return block->b_parent;
}
struct mie_record *mie_builder_put_record(
struct mie_builder *builder, struct mie_const *val, const char *name)
{
if (!builder->b_module) {
return NULL;
}
b_queue_iterator it = {};
b_queue_foreach (&it, &builder->b_module->m_records) {
struct mie_value *rec
= b_unbox(struct mie_value, it.entry, v_entry);
if (!strcmp(rec->v_name.n_str, name)) {
/* TODO what to do about `val` here? */
return MIE_RECORD(rec);
}
}
struct mie_record *rec = mie_record_create(val);
rec->r_base.v_name.n_str = b_strdup(name);
b_queue_push_back(&builder->b_module->m_records, &rec->r_base.v_entry);
return rec;
}
struct mie_record *mie_builder_get_record(
struct mie_builder *builder, const char *name)
{
if (!builder->b_module) {
return NULL;
}
b_queue_iterator it = {};
b_queue_foreach (&it, &builder->b_module->m_records) {
struct mie_value *rec
= b_unbox(struct mie_value, it.entry, v_entry);
if (!strcmp(rec->v_name.n_str, name)) {
return MIE_RECORD(rec);
}
}
return NULL;
}
#if 0
void mie_builder_put_data(struct mie_builder *builder, struct mie_data *data)
{
if (!builder->b_module) {
return;
}
const char *data_name = data->d_base.v_name.n_str;
struct mie_data *v = mie_module_get_data(builder->b_module, data_name);
if (v) {
return;
}
mie_module_put_data(builder->b_module, data);
}
#endif
#if 0
void mie_builder_put_type(struct mie_builder *builder, struct mie_type *type)
{
if (!builder->b_module) {
return;
}
const char *type_name = type->t_base.v_name.n_str;
struct mie_data *v = mie_module_get_data(builder->b_module, type_name);
if (v) {
return;
}
mie_module_put_data(builder->b_module, MIE_VALUE);
}
#endif
void mie_builder_set_insert_point(
struct mie_builder *builder, struct mie_block *block)
{
builder->b_current_block = block;
}
struct mie_value *mie_builder_get_data_ptr(
struct mie_builder *builder, const char *data_ident)
{
if (!builder->b_module) {
return NULL;
}
struct mie_data *data = mie_module_get_data(builder->b_module, data_ident);
if (!data) {
struct mie_type *id
= mie_ctx_get_type(builder->b_ctx, MIE_TYPE_ID);
data = mie_data_create_extern_global(id, data_ident);
if (!data) {
return NULL;
}
mie_module_put_data(builder->b_module, data, data_ident);
}
return MIE_VALUE(data);
}
struct mie_value *mie_builder_get_string_ptr(
struct mie_builder *builder, const char *s)
{
if (!builder->b_module) {
return NULL;
}
struct mie_data *data = mie_module_get_string_ptr(builder->b_module, s);
if (!data) {
struct mie_type *str
= mie_ctx_get_type(builder->b_ctx, MIE_TYPE_STR);
struct mie_value *value = mie_ctx_get_string(builder->b_ctx, s);
data = mie_data_create_const((struct mie_const *)value);
if (!data) {
return NULL;
}
mie_module_put_data(builder->b_module, data, ".str");
}
return MIE_VALUE(data);
}
struct mie_value *mie_builder_ret(struct mie_builder *builder, struct mie_value *val)
{
if (!builder->b_current_block) {
return NULL;
}
if (builder->b_current_block->b_terminator) {
return NULL;
}
struct mie_ret *ret = malloc(sizeof *ret);
if (!ret) {
return NULL;
}
mie_instr_init(&ret->r_base, MIE_INSTR_RET);
ret->r_val = val;
if (!mie_block_add_instr(builder->b_current_block, &ret->r_base)) {
free(ret);
return NULL;
}
return MIE_VALUE(ret);
}
struct mie_value *mie_builder_add(
struct mie_builder *builder, struct mie_value *left,
struct mie_value *right, const char *name)
{
if (!builder->b_current_block) {
return NULL;
}
if (builder->b_current_block->b_terminator) {
return NULL;
}
struct mie_binary_op *add = malloc(sizeof *add);
if (!add) {
return NULL;
}
memset(add, 0x0, sizeof *add);
mie_instr_init(&add->op_base, MIE_INSTR_ADD);
add->op_left = left;
add->op_right = right;
add->op_type = mie_value_get_type(left, builder->b_ctx);
if (!mie_block_add_instr(builder->b_current_block, &add->op_base)) {
free(add);
return NULL;
}
mie_func_generate_value_name(
builder->b_current_block->b_parent, MIE_VALUE(add), name);
return MIE_VALUE(add);
}
struct mie_value *mie_builder_sub(
struct mie_builder *builder, struct mie_value *left,
struct mie_value *right, const char *name)
{
if (!builder->b_current_block) {
return NULL;
}
if (builder->b_current_block->b_terminator) {
return NULL;
}
struct mie_binary_op *sub = malloc(sizeof *sub);
if (!sub) {
return NULL;
}
memset(sub, 0x0, sizeof *sub);
mie_instr_init(&sub->op_base, MIE_INSTR_SUB);
sub->op_left = left;
sub->op_right = right;
sub->op_type = mie_value_get_type(left, builder->b_ctx);
if (!mie_block_add_instr(builder->b_current_block, &sub->op_base)) {
free(sub);
return NULL;
}
mie_func_generate_value_name(
builder->b_current_block->b_parent, MIE_VALUE(sub), name);
return MIE_VALUE(sub);
}
struct mie_value *mie_builder_mul(
struct mie_builder *builder, struct mie_value *left,
struct mie_value *right, const char *name)
{
if (!builder->b_current_block) {
return NULL;
}
if (builder->b_current_block->b_terminator) {
return NULL;
}
struct mie_binary_op *mul = malloc(sizeof *mul);
if (!mul) {
return NULL;
}
memset(mul, 0x0, sizeof *mul);
mie_instr_init(&mul->op_base, MIE_INSTR_MUL);
mul->op_left = left;
mul->op_right = right;
mul->op_type = mie_value_get_type(left, builder->b_ctx);
if (!mie_block_add_instr(builder->b_current_block, &mul->op_base)) {
free(mul);
return NULL;
}
mie_func_generate_value_name(
builder->b_current_block->b_parent, MIE_VALUE(mul), name);
return MIE_VALUE(mul);
}
struct mie_value *mie_builder_div(
struct mie_builder *builder, struct mie_value *left,
struct mie_value *right, const char *name)
{
if (!builder->b_current_block) {
return NULL;
}
if (builder->b_current_block->b_terminator) {
return NULL;
}
struct mie_binary_op *div = malloc(sizeof *div);
if (!div) {
return NULL;
}
memset(div, 0x0, sizeof *div);
mie_instr_init(&div->op_base, MIE_INSTR_DIV);
div->op_left = left;
div->op_right = right;
div->op_type = mie_value_get_type(left, builder->b_ctx);
if (!mie_block_add_instr(builder->b_current_block, &div->op_base)) {
free(div);
return NULL;
}
mie_func_generate_value_name(
builder->b_current_block->b_parent, MIE_VALUE(div), name);
return MIE_VALUE(div);
}
struct mie_value *mie_builder_load(
struct mie_builder *builder, struct mie_type *type,
struct mie_value *src, const char *name)
{
if (!builder->b_current_block) {
return NULL;
}
if (builder->b_current_block->b_terminator) {
return NULL;
}
struct mie_load *load = malloc(sizeof *load);
if (!load) {
return NULL;
}
mie_instr_init(&load->l_base, MIE_INSTR_LOAD);
load->l_src = src;
load->l_type = type;
if (!mie_block_add_instr(builder->b_current_block, &load->l_base)) {
free(load);
return NULL;
}
mie_func_generate_value_name(
builder->b_current_block->b_parent, MIE_VALUE(load), name);
return MIE_VALUE(load);
}
struct mie_value *mie_builder_store(
struct mie_builder *builder, struct mie_value *val, struct mie_value *dest)
{
if (!builder->b_current_block) {
return NULL;
}
if (builder->b_current_block->b_terminator) {
return NULL;
}
struct mie_store *store = malloc(sizeof *store);
if (!store) {
return NULL;
}
mie_instr_init(&store->s_base, MIE_INSTR_STORE);
store->s_val = val;
store->s_dest = dest;
if (!mie_block_add_instr(builder->b_current_block, &store->s_base)) {
free(store);
return NULL;
}
return MIE_VALUE(store);
}
struct mie_value *mie_builder_alloca(
struct mie_builder *builder, struct mie_type *type, const char *name)
{
if (!builder->b_current_block) {
return NULL;
}
if (builder->b_current_block->b_terminator) {
return NULL;
}
struct mie_alloca *alloca = malloc(sizeof *alloca);
if (!alloca) {
return NULL;
}
mie_instr_init(&alloca->a_base, MIE_INSTR_ALLOCA);
alloca->a_type = type;
if (!mie_block_add_instr(builder->b_current_block, &alloca->a_base)) {
free(alloca);
return NULL;
}
mie_func_generate_value_name(
builder->b_current_block->b_parent, MIE_VALUE(alloca), name);
return MIE_VALUE(alloca);
}
struct mie_value *mie_builder_switch(
struct mie_builder *builder, struct mie_value *cond,
struct mie_switch_branch *branches, size_t nr_branches,
struct mie_block *default_block)
{
return NULL;
}
struct mie_value *mie_builder_br(struct mie_builder *builder, struct mie_block *dest)
{
if (!builder->b_current_block) {
return NULL;
}
if (builder->b_current_block->b_terminator) {
return NULL;
}
struct mie_branch *br = malloc(sizeof *br);
if (!br) {
return NULL;
}
memset(br, 0x0, sizeof *br);
mie_instr_init(&br->b_base, MIE_INSTR_BR);
br->b_dest = dest;
if (!mie_block_add_instr(builder->b_current_block, &br->b_base)) {
free(br);
return NULL;
}
return MIE_VALUE(br);
}
struct mie_value *mie_builder_br_if(
struct mie_builder *builder, struct mie_value *cond,
struct mie_block *if_true, struct mie_block *if_false)
{
if (!builder->b_current_block) {
return NULL;
}
if (builder->b_current_block->b_terminator) {
return NULL;
}
struct mie_branch_if *br = malloc(sizeof *br);
if (!br) {
return NULL;
}
memset(br, 0x0, sizeof *br);
mie_instr_init(&br->b_base, MIE_INSTR_BR_IF);
br->b_cond = cond;
br->b_true_block = if_true;
br->b_false_block = if_false;
if (!mie_block_add_instr(builder->b_current_block, &br->b_base)) {
free(br);
return NULL;
}
return MIE_VALUE(br);
}
struct mie_value *mie_builder_msg(
struct mie_builder *builder, struct mie_type *ret_type,
struct mie_value *recipient, struct mie_value *selector,
struct mie_value **args, size_t nr_args, enum mie_builder_flags flags,
const char *name)
{
if (!builder->b_current_block) {
return NULL;
}
if (builder->b_current_block->b_terminator) {
return NULL;
}
if ((flags & MIE_BUILDER_IGNORE_RESULT) && name) {
return NULL;
}
struct mie_msg *msg = malloc(sizeof *msg);
if (!msg) {
return NULL;
}
memset(msg, 0x0, sizeof *msg);
mie_instr_init(&msg->msg_base, MIE_INSTR_MSG);
msg->msg_ret_type = ret_type;
msg->msg_recipient = recipient;
msg->msg_selector = selector;
msg->msg_nr_args = nr_args;
msg->msg_args = calloc(nr_args, sizeof(struct mie_value *));
memcpy(msg->msg_args, args, nr_args * sizeof(struct mie_value *));
if (!mie_block_add_instr(builder->b_current_block, &msg->msg_base)) {
free(msg);
return NULL;
}
if (!(flags & MIE_BUILDER_IGNORE_RESULT)) {
mie_func_generate_value_name(
builder->b_current_block->b_parent, MIE_VALUE(msg), name);
}
return MIE_VALUE(msg);
}
struct mie_value *mie_builder_cmp_eq(
struct mie_builder *builder, struct mie_value *left,
struct mie_value *right, const char *name)
{
if (!builder->b_current_block) {
return NULL;
}
if (builder->b_current_block->b_terminator) {
return NULL;
}
struct mie_binary_op *sub = malloc(sizeof *sub);
if (!sub) {
return NULL;
}
memset(sub, 0x0, sizeof *sub);
mie_instr_init(&sub->op_base, MIE_INSTR_CMP_EQ);
sub->op_left = left;
sub->op_right = right;
sub->op_type = mie_value_get_type(left, builder->b_ctx);
if (!mie_block_add_instr(builder->b_current_block, &sub->op_base)) {
free(sub);
return NULL;
}
mie_func_generate_value_name(
builder->b_current_block->b_parent, MIE_VALUE(sub), name);
return MIE_VALUE(sub);
}
struct mie_value *mie_builder_cmp_neq(
struct mie_builder *builder, struct mie_value *left,
struct mie_value *right, const char *name)
{
if (!builder->b_current_block) {
return NULL;
}
if (builder->b_current_block->b_terminator) {
return NULL;
}
struct mie_binary_op *sub = malloc(sizeof *sub);
if (!sub) {
return NULL;
}
memset(sub, 0x0, sizeof *sub);
mie_instr_init(&sub->op_base, MIE_INSTR_CMP_NEQ);
sub->op_left = left;
sub->op_right = right;
sub->op_type = mie_value_get_type(left, builder->b_ctx);
if (!mie_block_add_instr(builder->b_current_block, &sub->op_base)) {
free(sub);
return NULL;
}
mie_func_generate_value_name(
builder->b_current_block->b_parent, MIE_VALUE(sub), name);
return MIE_VALUE(sub);
}
struct mie_value *mie_builder_cmp_lt(
struct mie_builder *builder, struct mie_value *left,
struct mie_value *right, const char *name)
{
if (!builder->b_current_block) {
return NULL;
}
if (builder->b_current_block->b_terminator) {
return NULL;
}
struct mie_binary_op *sub = malloc(sizeof *sub);
if (!sub) {
return NULL;
}
memset(sub, 0x0, sizeof *sub);
mie_instr_init(&sub->op_base, MIE_INSTR_CMP_LT);
sub->op_left = left;
sub->op_right = right;
sub->op_type = mie_value_get_type(left, builder->b_ctx);
if (!mie_block_add_instr(builder->b_current_block, &sub->op_base)) {
free(sub);
return NULL;
}
mie_func_generate_value_name(
builder->b_current_block->b_parent, MIE_VALUE(sub), name);
return MIE_VALUE(sub);
}
struct mie_value *mie_builder_cmp_gt(
struct mie_builder *builder, struct mie_value *left,
struct mie_value *right, const char *name)
{
if (!builder->b_current_block) {
return NULL;
}
if (builder->b_current_block->b_terminator) {
return NULL;
}
struct mie_binary_op *sub = malloc(sizeof *sub);
if (!sub) {
return NULL;
}
memset(sub, 0x0, sizeof *sub);
mie_instr_init(&sub->op_base, MIE_INSTR_CMP_GT);
sub->op_left = left;
sub->op_right = right;
sub->op_type = mie_value_get_type(left, builder->b_ctx);
if (!mie_block_add_instr(builder->b_current_block, &sub->op_base)) {
free(sub);
return NULL;
}
mie_func_generate_value_name(
builder->b_current_block->b_parent, MIE_VALUE(sub), name);
return MIE_VALUE(sub);
}
struct mie_value *mie_builder_cmp_leq(
struct mie_builder *builder, struct mie_value *left,
struct mie_value *right, const char *name)
{
if (!builder->b_current_block) {
return NULL;
}
if (builder->b_current_block->b_terminator) {
return NULL;
}
struct mie_binary_op *sub = malloc(sizeof *sub);
if (!sub) {
return NULL;
}
memset(sub, 0x0, sizeof *sub);
mie_instr_init(&sub->op_base, MIE_INSTR_CMP_LEQ);
sub->op_left = left;
sub->op_right = right;
sub->op_type = mie_value_get_type(left, builder->b_ctx);
if (!mie_block_add_instr(builder->b_current_block, &sub->op_base)) {
free(sub);
return NULL;
}
mie_func_generate_value_name(
builder->b_current_block->b_parent, MIE_VALUE(sub), name);
return MIE_VALUE(sub);
}
struct mie_value *mie_builder_cmp_geq(
struct mie_builder *builder, struct mie_value *left,
struct mie_value *right, const char *name)
{
if (!builder->b_current_block) {
return NULL;
}
if (builder->b_current_block->b_terminator) {
return NULL;
}
struct mie_binary_op *sub = malloc(sizeof *sub);
if (!sub) {
return NULL;
}
memset(sub, 0x0, sizeof *sub);
mie_instr_init(&sub->op_base, MIE_INSTR_CMP_GEQ);
sub->op_left = left;
sub->op_right = right;
sub->op_type = mie_value_get_type(left, builder->b_ctx);
if (!mie_block_add_instr(builder->b_current_block, &sub->op_base)) {
free(sub);
return NULL;
}
mie_func_generate_value_name(
builder->b_current_block->b_parent, MIE_VALUE(sub), name);
return MIE_VALUE(sub);
}
struct mie_value *mie_builder_getelementptr(
struct mie_builder *builder, struct mie_type *container_type,
struct mie_value *container, struct mie_value *index, const char *name)
{
return NULL;
}
struct mie_value *mie_builder_setelementptr(
struct mie_builder *builder, struct mie_type *container_type,
struct mie_value *container, struct mie_value *index)
{
return NULL;
}
struct mie_phi *mie_builder_phi(
struct mie_builder *builder, struct mie_type *type,
unsigned int nr_edges, const char *name)
{
return NULL;
}