From 287983fa95878d45a2538a470ee9822a33158228 Mon Sep 17 00:00:00 2001 From: Max Wash Date: Sun, 25 Jan 2026 15:06:43 +0000 Subject: [PATCH] mie: implement a full rewriter with pattern-matching and rewriting support the new rewriter interface supports running patterns over an Op's children matching Ops that conform to a pattern, and rewriting Ops in arbitrary ways. --- mie/include/mie/ir/rewrite.h | 60 --- mie/include/mie/macros.h | 21 + mie/include/mie/rewrite/convert.h | 20 + mie/include/mie/rewrite/greedy.h | 16 + mie/include/mie/rewrite/pattern.h | 54 +++ mie/include/mie/rewrite/rewriter.h | 108 ++++++ mie/ir/rewrite.c | 0 mie/rewrite/convert.c | 88 +++++ mie/rewrite/pattern-set.c | 30 ++ mie/rewrite/pattern.c | 23 ++ mie/rewrite/rewriter.c | 591 +++++++++++++++++++++++++++++ 11 files changed, 951 insertions(+), 60 deletions(-) delete mode 100644 mie/include/mie/ir/rewrite.h create mode 100644 mie/include/mie/rewrite/convert.h create mode 100644 mie/include/mie/rewrite/greedy.h create mode 100644 mie/include/mie/rewrite/pattern.h create mode 100644 mie/include/mie/rewrite/rewriter.h delete mode 100644 mie/ir/rewrite.c create mode 100644 mie/rewrite/convert.c create mode 100644 mie/rewrite/pattern-set.c create mode 100644 mie/rewrite/pattern.c create mode 100644 mie/rewrite/rewriter.c diff --git a/mie/include/mie/ir/rewrite.h b/mie/include/mie/ir/rewrite.h deleted file mode 100644 index a9dd5e6..0000000 --- a/mie/include/mie/ir/rewrite.h +++ /dev/null @@ -1,60 +0,0 @@ -#ifndef MIE_IR_REWRITE_H_ -#define MIE_IR_REWRITE_H_ - -#include -#include -#include - -struct mie_op; -struct mie_ctx; -struct mie_rewriter; -struct mie_register; - -#define MIE_REWRITE_RESULT(result, status) \ - ((struct mie_rewrite_result) {.r_result = (result), .r_status = (status)}) - -enum mie_match_result { - MIE_NO_MATCH_FOUND = 0, - MIE_MATCH_FOUND, -}; - -struct mie_rewrite_result { - enum { - MIE_REWRITE_SUCCESS = 0, - MIE_REWRITE_IGNORE, - MIE_REWRITE_FAILURE, - } r_result; - enum mie_status r_status; -}; - -struct mie_rewrite_pattern { - struct { - const char *t_dialect_name, *t_op_name; - const struct mie_op_definition *t_op; - } p_root; - - enum mie_match_result (*p_match)(const struct mie_op *); - struct mie_rewrite_result (*p_rewrite)( - struct mie_op *, struct mie_rewriter *); -}; - -MIE_API struct mie_rewriter *mie_rewriter_create(struct mie_ctx *ctx); - -MIE_API struct mie_block *mie_rewriter_get_insertion_block( - struct mie_rewriter *rewriter); -MIE_API struct mie_op *mie_rewriter_get_insertion_point( - struct mie_rewriter *rewriter); - -MIE_API struct mie_block *mie_rewriter_split_block( - struct mie_rewriter *rewriter, struct mie_block *block, - struct mie_op *before); -MIE_API struct mie_block *mie_rewriter_create_block( - struct mie_rewriter *rewriter, struct mie_block *insert_before); - -MIE_API struct mie_op *mie_rewriter_put_op( - struct mie_rewriter *rewriter, const char *dialect, const char *op, - struct mie_register **args, size_t nr_args); -MIE_API enum mie_status mie_rewriter_erase_op( - struct mie_rewriter *rewriter, struct mie_op *op); - -#endif diff --git a/mie/include/mie/macros.h b/mie/include/mie/macros.h index 166c013..0afc5a9 100644 --- a/mie/include/mie/macros.h +++ b/mie/include/mie/macros.h @@ -246,3 +246,24 @@ } while (0) #endif + +/******************************************************************************/ +/* REWRITE PATTER MACROS */ +/******************************************************************************/ + +#define MIE_REWRITE_PATTERN_BEGIN(name) \ + struct mie_pattern *name##_create(struct mie_pattern_set *set) \ + { \ + struct mie_pattern *self = mie_pattern_set_add(set); \ + if (!self) { \ + return NULL; \ + } +#define MIE_REWRITE_PATTERN_END() \ + return self; \ + } + +#define MIE_REWRITE_PATTERN_ROOT(dialect_name, op_name) \ + self->p_root.t_dialect_name = (dialect_name); \ + self->p_root.t_op_name = (op_name) +#define MIE_REWRITE_PATTERN_MATCH(func) self->p_match = (func) +#define MIE_REWRITE_PATTERN_REWRITE(func) self->p_rewrite = (func) diff --git a/mie/include/mie/rewrite/convert.h b/mie/include/mie/rewrite/convert.h new file mode 100644 index 0000000..5f6f6d1 --- /dev/null +++ b/mie/include/mie/rewrite/convert.h @@ -0,0 +1,20 @@ +#ifndef MIE_REWRITE_CONVERT_H_ +#define MIE_REWRITE_CONVERT_H_ + +#include + +struct mie_pattern_set; +struct mie_convert_config; + +MIE_API struct mie_convert_config *mie_convert_config_create(struct mie_ctx *ctx); +MIE_API void mie_convert_config_destroy(struct mie_convert_config *cfg); + +MIE_API enum mie_status mie_convert_config_add_illegal_op( + struct mie_convert_config *cfg, const char *dialect_name, + const char *op_name); + +MIE_API enum mie_status mie_convert_apply( + struct mie_op *op, struct mie_convert_config *cfg, + struct mie_pattern_set *patterns); + +#endif diff --git a/mie/include/mie/rewrite/greedy.h b/mie/include/mie/rewrite/greedy.h new file mode 100644 index 0000000..55fc72c --- /dev/null +++ b/mie/include/mie/rewrite/greedy.h @@ -0,0 +1,16 @@ +#ifndef MIE_REWRITE_GREEDY_H_ +#define MIE_REWRITE_GREEDY_H_ + +#include + +struct mie_pattern_set; +struct mie_greedy_config; + +MIE_API struct mie_greedy_config *mie_greedy_config_create(struct mie_ctx *ctx); +MIE_API void mie_greedy_config_destroy(struct mie_greedy_config *cfg); + +MIE_API enum mie_status mie_greedy_apply( + struct mie_op *op, struct mie_greedy_config *cfg, + struct mie_pattern_set *patterns); + +#endif diff --git a/mie/include/mie/rewrite/pattern.h b/mie/include/mie/rewrite/pattern.h new file mode 100644 index 0000000..3f89222 --- /dev/null +++ b/mie/include/mie/rewrite/pattern.h @@ -0,0 +1,54 @@ +#ifndef MIE_REWRITE_PATTERN_H_ +#define MIE_REWRITE_PATTERN_H_ + +#include + +#define MIE_REWRITE_RESULT(result, status) \ + ((struct mie_rewrite_result) {.r_result = (result), .r_status = (status)}) + +struct mie_op; +struct mie_rewriter; + +enum mie_match_result { + MIE_NO_MATCH_FOUND = 0, + MIE_MATCH_FOUND, +}; + +struct mie_rewrite_result { + enum { + MIE_REWRITE_SUCCESS = 0, + MIE_REWRITE_IGNORE, + MIE_REWRITE_FAILURE, + } r_result; + enum mie_status r_status; +}; + +struct mie_pattern { + struct { + const char *t_dialect_name, *t_op_name; + const struct mie_op_definition *t_op; + } p_root; + + enum mie_match_result (*p_match)(const struct mie_op *); + struct mie_rewrite_result (*p_rewrite)( + struct mie_op *, struct mie_rewriter *); +}; + +struct mie_pattern_set { + MIE_VECTOR_DECLARE(struct mie_pattern, s_patterns); +}; + +MIE_API void mie_pattern_set_init(struct mie_pattern_set *set); +MIE_API void mie_pattern_set_cleanup(struct mie_pattern_set *set); + +MIE_API struct mie_pattern *mie_pattern_set_add(struct mie_pattern_set *set); +MIE_API struct mie_pattern *mie_pattern_set_match( + struct mie_pattern_set *set, const struct mie_op *op); + +MIE_API enum mie_match_result mie_pattern_match( + const struct mie_pattern *pattern, const struct mie_op *op); +MIE_API struct mie_rewrite_result mie_pattern_rewrite( + const struct mie_pattern *pattern, struct mie_op *op, + struct mie_rewriter *rewriter); + +#endif diff --git a/mie/include/mie/rewrite/rewriter.h b/mie/include/mie/rewrite/rewriter.h new file mode 100644 index 0000000..1792b33 --- /dev/null +++ b/mie/include/mie/rewrite/rewriter.h @@ -0,0 +1,108 @@ +#ifndef MIE_IR_REWRITE_H_ +#define MIE_IR_REWRITE_H_ + +#include +#include +#include +#include +#include + +struct mie_op; +struct mie_ctx; +struct mie_region; +struct mie_register; +struct mie_op_successor; + +struct mie_rewriter { + struct mie_emitter r_base; + struct mie_ctx *r_ctx; + /* anything ops added to the IR are inserted in this block. */ + struct mie_block *r_insert_block; + /* anything ops added to the IR are inserted after this op. + * if this is null, the insertion point is the end of r_insert_block. */ + struct mie_op *r_insert_point; +}; + +MIE_API void mie_rewriter_init(struct mie_rewriter *rw, struct mie_ctx *ctx); +MIE_API void mie_rewriter_cleanup(struct mie_rewriter *rw); + +MIE_API struct mie_ctx *mie_rewriter_get_ctx(const struct mie_rewriter *rw); + +MIE_API struct mie_block *mie_rewriter_get_insertion_block(struct mie_rewriter *rw); +MIE_API struct mie_op *mie_rewriter_get_insertion_point(struct mie_rewriter *rw); + +MIE_API struct mie_block *mie_rewriter_set_insertion_block( + struct mie_rewriter *rw, struct mie_block *block); +MIE_API struct mie_op *mie_rewriter_set_insertion_point( + struct mie_rewriter *rw, struct mie_op *insert_point); + +MIE_API struct mie_block *mie_rewriter_split_block( + struct mie_rewriter *rw, struct mie_block *block, struct mie_op *before, + const char *name); +MIE_API struct mie_block *mie_rewriter_create_block( + struct mie_rewriter *rw, struct mie_block *insert_before, const char *name); + +MIE_API enum mie_status mie_rewriter_move_block_to_start( + struct mie_rewriter *rw, struct mie_block *block, + struct mie_region *from, struct mie_region *to); +MIE_API enum mie_status mie_rewriter_move_block_to_end( + struct mie_rewriter *rw, struct mie_block *block, + struct mie_region *from, struct mie_region *to); +MIE_API enum mie_status mie_rewriter_move_block_before( + struct mie_rewriter *rw, struct mie_block *block, + struct mie_region *from, struct mie_region *to, struct mie_block *before); +MIE_API enum mie_status mie_rewriter_move_block_after( + struct mie_rewriter *rw, struct mie_block *block, + struct mie_region *from, struct mie_region *to, struct mie_block *after); + +MIE_API enum mie_status mie_rewriter_rename_block( + struct mie_rewriter *rw, struct mie_block *block, const char *name); + +MIE_API enum mie_status mie_rewriter_move_blocks_to_start( + struct mie_rewriter *rw, struct mie_region *from, struct mie_region *to); +MIE_API enum mie_status mie_rewriter_move_blocks_to_end( + struct mie_rewriter *rw, struct mie_region *from, struct mie_region *to); +MIE_API enum mie_status mie_rewriter_move_blocks_before( + struct mie_rewriter *rw, struct mie_region *from, struct mie_region *to, + struct mie_block *before); +MIE_API enum mie_status mie_rewriter_move_blocks_after( + struct mie_rewriter *rw, struct mie_region *from, struct mie_region *to, + struct mie_block *after); + +MIE_API enum mie_status mie_rewriter_move_region_to_start( + struct mie_rewriter *rw, struct mie_region *region, struct mie_op *from, + struct mie_op *to); +MIE_API enum mie_status mie_rewriter_move_region_to_end( + struct mie_rewriter *rw, struct mie_region *region, struct mie_op *from, + struct mie_op *to); +MIE_API enum mie_status mie_rewriter_move_region_before( + struct mie_rewriter *rw, struct mie_region *region, struct mie_op *from, + struct mie_op *to, struct mie_region *before); +MIE_API enum mie_status mie_rewriter_move_region_after( + struct mie_rewriter *rw, struct mie_region *region, struct mie_op *from, + struct mie_op *to, struct mie_region *after); + +MIE_API struct mie_op *mie_rewriter_put_op( + struct mie_rewriter *rw, const char *dialect, const char *op, + struct mie_register **args, size_t nr_args); +MIE_API struct mie_op *mie_rewriter_replace_op( + struct mie_rewriter *rw, struct mie_op *op, const char *dialect_name, + const char *op_name); +MIE_API struct mie_op_successor *mie_rewriter_add_op_successor( + struct mie_rewriter *rw, struct mie_op *op, struct mie_block *dest, + struct mie_register **args, size_t nr_args); +MIE_API enum mie_status mie_rewriter_erase_op( + struct mie_rewriter *rw, struct mie_op *op); +MIE_API enum mie_status mie_rewriter_move_op_args_to_successor( + struct mie_rewriter *rw, struct mie_op *op, struct mie_op_successor *s); + +MIE_API enum mie_status mie_rewriter_replace_register( + struct mie_rewriter *rw, struct mie_register *old, + struct mie_register *new); +MIE_API enum mie_status mie_rewriter_rename_register( + struct mie_rewriter *rw, struct mie_register *reg, const char *name); + +MIE_API enum mie_status mie_rewriter_put_name( + struct mie_rewriter *rw, struct mie_name *name, const char *hint); + +#endif diff --git a/mie/ir/rewrite.c b/mie/ir/rewrite.c deleted file mode 100644 index e69de29..0000000 diff --git a/mie/rewrite/convert.c b/mie/rewrite/convert.c new file mode 100644 index 0000000..cc624fc --- /dev/null +++ b/mie/rewrite/convert.c @@ -0,0 +1,88 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct mie_convert_config { + struct mie_ctx *cfg_ctx; + MIE_VECTOR_DECLARE(const struct mie_op_definition *, cfg_illegal_ops); +}; + +struct mie_convert_config *mie_convert_config_create(struct mie_ctx *ctx) +{ + struct mie_convert_config *out = malloc(sizeof *out); + if (!out) { + return NULL; + } + + memset(out, 0x0, sizeof *out); + out->cfg_ctx = ctx; + + return out; +} + +void mie_convert_config_destroy(struct mie_convert_config *cfg) +{ + mie_vector_destroy(cfg->cfg_illegal_ops, NULL); + free(cfg); +} + +enum mie_status mie_convert_config_add_illegal_op( + struct mie_convert_config *cfg, const char *dialect_name, const char *op_name) +{ + const struct mie_op_definition *op + = mie_ctx_get_op_definition(cfg->cfg_ctx, dialect_name, op_name); + if (!op) { + return MIE_ERR_NO_ENTRY; + } + + const struct mie_op_definition **slot + = mie_vector_emplace_back(cfg->cfg_illegal_ops, NULL); + if (!slot) { + return MIE_ERR_NO_MEMORY; + } + + *slot = op; + return MIE_SUCCESS; +} + +enum mie_status mie_convert_apply( + struct mie_op *root, struct mie_convert_config *cfg, + struct mie_pattern_set *patterns) +{ + enum mie_status status = MIE_SUCCESS; + enum mie_walker_flags walk_flags = MIE_WALKER_F_INCLUDE_OPS + | MIE_WALKER_F_POSTORDER + | MIE_WALKER_F_FORWARD; + struct mie_walker walker; + mie_walker_begin(&walker, root, walk_flags); + + struct mie_rewriter rw; + mie_rewriter_init(&rw, cfg->cfg_ctx); + + do { + const struct mie_walk_item *item = mie_walker_get(&walker); + struct mie_op *op = item->i_op; + + struct mie_pattern *pattern = mie_pattern_set_match(patterns, op); + if (!pattern) { + continue; + } + + struct mie_rewrite_result result + = mie_pattern_rewrite(pattern, op, &rw); + if (result.r_result == MIE_REWRITE_FAILURE) { + status = result.r_status; + break; + } + } while (mie_walker_step(&walker) == MIE_SUCCESS); + + mie_walker_end(&walker); + + return status; +} diff --git a/mie/rewrite/pattern-set.c b/mie/rewrite/pattern-set.c new file mode 100644 index 0000000..250016f --- /dev/null +++ b/mie/rewrite/pattern-set.c @@ -0,0 +1,30 @@ +#include +#include +#include + +void mie_pattern_set_init(struct mie_pattern_set *set) +{ + memset(set, 0x0, sizeof *set); +} + +void mie_pattern_set_cleanup(struct mie_pattern_set *set) +{ + mie_vector_destroy(set->s_patterns, NULL); +} + +struct mie_pattern *mie_pattern_set_add(struct mie_pattern_set *set) +{ + return mie_vector_emplace_back(set->s_patterns, NULL); +} + +struct mie_pattern *mie_pattern_set_match( + struct mie_pattern_set *set, const struct mie_op *op) +{ + for (size_t i = 0; i < MIE_VECTOR_COUNT(set->s_patterns); i++) { + if (mie_pattern_match(&set->s_patterns.items[i], op)) { + return &set->s_patterns.items[i]; + } + } + + return NULL; +} diff --git a/mie/rewrite/pattern.c b/mie/rewrite/pattern.c new file mode 100644 index 0000000..c457dd8 --- /dev/null +++ b/mie/rewrite/pattern.c @@ -0,0 +1,23 @@ +#include + +enum mie_match_result mie_pattern_match( + const struct mie_pattern *pattern, const struct mie_op *op) +{ + if (!pattern->p_match) { + return MIE_NO_MATCH_FOUND; + } + + return pattern->p_match(op); +} + +struct mie_rewrite_result mie_pattern_rewrite( + const struct mie_pattern *pattern, struct mie_op *op, + struct mie_rewriter *rewriter) +{ + if (!pattern->p_rewrite) { + return MIE_REWRITE_RESULT( + MIE_REWRITE_FAILURE, MIE_ERR_NOT_SUPPORTED); + } + + return pattern->p_rewrite(op, rewriter); +} diff --git a/mie/rewrite/rewriter.c b/mie/rewrite/rewriter.c new file mode 100644 index 0000000..8030a80 --- /dev/null +++ b/mie/rewrite/rewriter.c @@ -0,0 +1,591 @@ +#include +#include +#include +#include +#include +#include +#include + +void mie_rewriter_init(struct mie_rewriter *rw, struct mie_ctx *ctx) +{ + memset(rw, 0x0, sizeof *rw); + rw->r_ctx = ctx; + + rw->r_base.e_get_ctx = (mie_emit_get_ctx)mie_rewriter_get_ctx; + rw->r_base.e_put_op = (mie_emit_put_op)mie_rewriter_put_op; + rw->r_base.e_put_name = (mie_emit_put_name)mie_rewriter_put_name; + rw->r_base.e_put_block = NULL; +} + +void mie_rewriter_cleanup(struct mie_rewriter *rw) +{ + /* TODO */ +} + +struct mie_ctx *mie_rewriter_get_ctx(const struct mie_rewriter *rw) +{ + return rw->r_ctx; +} + +struct mie_block *mie_rewriter_get_insertion_block(struct mie_rewriter *rw) +{ + return rw->r_insert_block; +} + +struct mie_op *mie_rewriter_get_insertion_point(struct mie_rewriter *rw) +{ + return rw->r_insert_point; +} + +struct mie_block *mie_rewriter_set_insertion_block( + struct mie_rewriter *rw, struct mie_block *block) +{ + rw->r_insert_block = block; + return block; +} + +struct mie_op *mie_rewriter_set_insertion_point( + struct mie_rewriter *rw, struct mie_op *insert_point) +{ + if (!insert_point && rw->r_insert_point) { + insert_point = mie_block_get_last_op(rw->r_insert_block); + } + + rw->r_insert_point = insert_point; + return rw->r_insert_point; +} + +static struct mie_name_map *get_name_map_for_region(struct mie_region *region) +{ + while (region) { + if (region->r_names) { + return region->r_names; + } + + struct mie_op *op = region->r_parent; + if (!op) { + break; + } + + struct mie_block *block = op->op_container; + if (!block) { + break; + } + + region = block->b_parent; + } + + return NULL; +} + +struct mie_block *mie_rewriter_split_block( + struct mie_rewriter *rw, struct mie_block *block, struct mie_op *before, + const char *name) +{ + if (before->op_container != block) { + return NULL; + } + + struct mie_region *region = block->b_parent; + struct mie_name_map *names = get_name_map_for_region(region); + + struct mie_block *new_block = mie_region_add_block_after(region, block); + mie_name_map_put(names, &new_block->b_name, name, 0); + + b_queue_entry *cur = &before->op_entry; + while (cur) { + struct mie_op *cur_op = b_unbox(struct mie_op, cur, op_entry); + b_queue_entry *next = b_queue_next(cur); + b_queue_delete(&block->b_ops, cur); + b_queue_push_back(&new_block->b_ops, cur); + + cur_op->op_container = new_block; + cur = next; + } + + return new_block; +} + +struct mie_block *mie_rewriter_create_block( + struct mie_rewriter *rw, struct mie_block *insert_before, const char *name) +{ + return NULL; +} + +enum mie_status mie_rewriter_move_block_to_start( + struct mie_rewriter *rw, struct mie_block *block, + struct mie_region *from, struct mie_region *to) +{ + if (block->b_parent != from) { + return MIE_ERR_INVALID_ARGUMENT; + } + + b_queue_delete(&from->r_blocks, &block->b_entry); + b_queue_push_front(&to->r_blocks, &block->b_entry); + + block->b_parent = to; + + return MIE_SUCCESS; +} + +enum mie_status mie_rewriter_move_block_to_end( + struct mie_rewriter *rw, struct mie_block *block, + struct mie_region *from, struct mie_region *to) +{ + if (block->b_parent != from) { + return MIE_ERR_INVALID_ARGUMENT; + } + + b_queue_delete(&from->r_blocks, &block->b_entry); + b_queue_push_back(&to->r_blocks, &block->b_entry); + + block->b_parent = to; + + return MIE_SUCCESS; +} + +enum mie_status mie_rewriter_move_block_before( + struct mie_rewriter *rw, struct mie_block *block, + struct mie_region *from, struct mie_region *to, struct mie_block *before) +{ + if (block->b_parent != from) { + return MIE_ERR_INVALID_ARGUMENT; + } + + if (before->b_parent != to) { + return MIE_ERR_INVALID_ARGUMENT; + } + + b_queue_delete(&from->r_blocks, &block->b_entry); + b_queue_insert_before(&to->r_blocks, &block->b_entry, &before->b_entry); + + block->b_parent = to; + + return MIE_SUCCESS; +} + +enum mie_status mie_rewriter_move_block_after( + struct mie_rewriter *rw, struct mie_block *block, + struct mie_region *from, struct mie_region *to, struct mie_block *after) +{ + if (block->b_parent != from) { + return MIE_ERR_INVALID_ARGUMENT; + } + + if (after->b_parent != to) { + return MIE_ERR_INVALID_ARGUMENT; + } + + b_queue_delete(&from->r_blocks, &block->b_entry); + b_queue_insert_after(&to->r_blocks, &block->b_entry, &after->b_entry); + + block->b_parent = to; + + return MIE_SUCCESS; +} + +enum mie_status mie_rewriter_rename_block( + struct mie_rewriter *rw, struct mie_block *block, const char *name) +{ + struct mie_region *region = block->b_parent; + struct mie_name_map *names = get_name_map_for_region(region); + + mie_name_destroy(&block->b_name); + struct mie_name *result = mie_name_map_put(names, &block->b_name, name, 0); + + return result ? MIE_SUCCESS : MIE_ERR_NO_MEMORY; +} + +enum mie_status mie_rewriter_move_blocks_to_start( + struct mie_rewriter *rw, struct mie_region *from, struct mie_region *to) +{ + b_queue_entry *cur = b_queue_first(&from->r_blocks); + b_queue_entry *insert_point = NULL; + while (cur) { + b_queue_entry *next = b_queue_next(cur); + + struct mie_block *block = b_unbox(struct mie_block, cur, b_entry); + b_queue_delete(&from->r_blocks, cur); + + if (insert_point) { + b_queue_insert_after(&to->r_blocks, cur, insert_point); + } else { + b_queue_push_front(&to->r_blocks, cur); + } + + block->b_parent = to; + insert_point = cur; + cur = next; + } + + return MIE_SUCCESS; +} + +enum mie_status mie_rewriter_move_blocks_to_end( + struct mie_rewriter *rw, struct mie_region *from, struct mie_region *to) +{ + b_queue_entry *cur = b_queue_first(&from->r_blocks); + while (cur) { + b_queue_entry *next = b_queue_next(cur); + + struct mie_block *block = b_unbox(struct mie_block, cur, b_entry); + b_queue_delete(&from->r_blocks, cur); + b_queue_push_back(&to->r_blocks, cur); + + block->b_parent = to; + cur = next; + } + + return MIE_SUCCESS; +} + +enum mie_status mie_rewriter_move_blocks_before( + struct mie_rewriter *rw, struct mie_region *from, struct mie_region *to, + struct mie_block *before) +{ + if (before->b_parent != to) { + return MIE_ERR_INVALID_ARGUMENT; + } + + b_queue_entry *cur = b_queue_last(&from->r_blocks); + while (cur) { + b_queue_entry *next = b_queue_prev(cur); + + struct mie_block *block = b_unbox(struct mie_block, cur, b_entry); + b_queue_delete(&from->r_blocks, cur); + b_queue_insert_before(&to->r_blocks, cur, &before->b_entry); + + block->b_parent = to; + cur = next; + } + + return MIE_SUCCESS; +} + +enum mie_status mie_rewriter_move_blocks_after( + struct mie_rewriter *rw, struct mie_region *from, struct mie_region *to, + struct mie_block *after) +{ + if (after->b_parent != to) { + return MIE_ERR_INVALID_ARGUMENT; + } + + b_queue_entry *cur = b_queue_first(&from->r_blocks); + b_queue_entry *insert_point = &after->b_entry; + + while (cur) { + b_queue_entry *next = b_queue_next(cur); + + struct mie_block *block = b_unbox(struct mie_block, cur, b_entry); + b_queue_delete(&from->r_blocks, cur); + b_queue_insert_after(&to->r_blocks, cur, insert_point); + + block->b_parent = to; + insert_point = cur; + cur = next; + } + + return MIE_SUCCESS; +} + +enum mie_status mie_rewriter_move_region_to_start( + struct mie_rewriter *rw, struct mie_region *region, struct mie_op *from, + struct mie_op *to) +{ + if (region->r_parent != from) { + return MIE_ERR_INVALID_ARGUMENT; + } + + b_queue_delete(&from->op_regions, ®ion->r_entry); + b_queue_push_front(&to->op_regions, ®ion->r_entry); + + region->r_parent = to; + + return MIE_SUCCESS; +} + +enum mie_status mie_rewriter_move_region_to_end( + struct mie_rewriter *rw, struct mie_region *region, struct mie_op *from, + struct mie_op *to) +{ + if (region->r_parent != from) { + return MIE_ERR_INVALID_ARGUMENT; + } + + b_queue_delete(&from->op_regions, ®ion->r_entry); + b_queue_push_back(&to->op_regions, ®ion->r_entry); + + region->r_parent = to; + + return MIE_SUCCESS; +} + +enum mie_status mie_rewriter_move_region_before( + struct mie_rewriter *rw, struct mie_region *region, struct mie_op *from, + struct mie_op *to, struct mie_region *before) +{ + if (region->r_parent != from) { + return MIE_ERR_INVALID_ARGUMENT; + } + + if (before->r_parent != to) { + return MIE_ERR_INVALID_ARGUMENT; + } + + b_queue_delete(&from->op_regions, ®ion->r_entry); + b_queue_insert_before(&to->op_regions, ®ion->r_entry, &before->r_entry); + + region->r_parent = to; + + return MIE_SUCCESS; +} + +enum mie_status mie_rewriter_move_region_after( + struct mie_rewriter *rw, struct mie_region *region, struct mie_op *from, + struct mie_op *to, struct mie_region *after) +{ + if (region->r_parent != from) { + return MIE_ERR_INVALID_ARGUMENT; + } + + if (after->r_parent != to) { + return MIE_ERR_INVALID_ARGUMENT; + } + + b_queue_delete(&from->op_regions, ®ion->r_entry); + b_queue_insert_after(&to->op_regions, ®ion->r_entry, &after->r_entry); + + region->r_parent = to; + + return MIE_SUCCESS; +} + +struct mie_op *mie_rewriter_put_op( + struct mie_rewriter *rw, const char *dialect_name, const char *op_name, + struct mie_register **args, size_t nr_args) +{ + if (!rw->r_insert_block) { + return NULL; + } + + const struct mie_op_definition *op_def + = mie_ctx_get_op_definition(rw->r_ctx, dialect_name, op_name); + if (!op_def) { + return NULL; + } + + struct mie_op *op + = mie_block_add_op_after(rw->r_insert_block, rw->r_insert_point); + if (!op) { + return NULL; + } + + 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; +} + +struct mie_op *mie_rewriter_replace_op( + struct mie_rewriter *rw, struct mie_op *op, const char *dialect_name, + const char *op_name) +{ + const struct mie_op_definition *op_def + = mie_ctx_get_op_definition(rw->r_ctx, dialect_name, op_name); + + if (!op_def) { + return NULL; + } + + op->op_info = op_def; + op->op_dialect = op_def->op_parent; + + return op; +} + +struct mie_op_successor *mie_rewriter_add_op_successor( + struct mie_rewriter *rw, struct mie_op *op, struct mie_block *dest, + struct mie_register **args, size_t nr_args) +{ + return mie_op_add_successor(op, dest, args, nr_args); +} + +enum mie_status mie_rewriter_erase_op(struct mie_rewriter *rw, struct mie_op *op) +{ + struct mie_block *parent = op->op_container; + if (!parent) { + return MIE_ERR_BAD_STATE; + } + + b_queue_delete(&parent->b_ops, &op->op_entry); + + for (size_t i = 0; i < MIE_VECTOR_COUNT(op->op_successors); i++) { + struct mie_op_successor *s = &op->op_successors.items[i]; + for (size_t k = 0; k < MIE_VECTOR_COUNT(s->s_args); k++) { + struct mie_op_arg *arg = &s->s_args.items[k]; + if (!(arg->arg_flags & MIE_OP_F_ARG_RESOLVED)) { + continue; + } + + b_queue_delete( + &arg->arg_value.u_reg->reg_use, + &arg->arg_value.u_entry); + } + } + + for (size_t k = 0; k < MIE_VECTOR_COUNT(op->op_args); k++) { + struct mie_op_arg *arg = &op->op_args.items[k]; + if (!(arg->arg_flags & MIE_OP_F_ARG_RESOLVED)) { + continue; + } + + b_queue_delete( + &arg->arg_value.u_reg->reg_use, &arg->arg_value.u_entry); + } + + for (size_t i = 0; i < MIE_VECTOR_COUNT(op->op_result); i++) { + struct mie_register *reg = &op->op_result.items[i]; + + b_queue_entry *cur = b_queue_first(®->reg_use); + while (cur) { + b_queue_entry *next = b_queue_next(cur); + + struct mie_register_use *use + = b_unbox(struct mie_register_use, cur, u_entry); + + b_queue_delete(®->reg_use, &use->u_entry); + use->u_reg = NULL; + cur = next; + } + } + + mie_attribute_map_cleanup(&op->op_attrib); + + free(op); + return MIE_SUCCESS; +} + +enum mie_status mie_rewriter_move_op_args_to_successor( + struct mie_rewriter *rw, struct mie_op *op, struct mie_op_successor *s) +{ + for (size_t i = 0; i < MIE_VECTOR_COUNT(op->op_args); i++) { + struct mie_op_arg *src = &op->op_args.items[i]; + struct mie_op_arg *dest = mie_vector_emplace_back(s->s_args, NULL); + + struct mie_register *reg = NULL; + if (src->arg_flags & MIE_OP_F_ARG_RESOLVED) { + reg = src->arg_value.u_reg; + b_queue_delete(®->reg_use, &src->arg_value.u_entry); + } + + memcpy(dest, src, sizeof *src); + if (reg) { + memset(&dest->arg_value.u_entry, 0x0, + sizeof dest->arg_value.u_entry); + b_queue_push_back(®->reg_use, &dest->arg_value.u_entry); + } + } + + mie_vector_destroy(op->op_args, NULL); + + return MIE_SUCCESS; +} + +static enum mie_status replace_register_usage( + struct mie_op *op, struct mie_register *old, struct mie_register *new) +{ + for (size_t i = 0; i < MIE_VECTOR_COUNT(op->op_args); i++) { + struct mie_op_arg *arg = &op->op_args.items[i]; + if (!(arg->arg_flags & MIE_OP_F_ARG_RESOLVED)) { + continue; + } + + if (arg->arg_value.u_reg != old) { + continue; + } + + b_queue_delete(&old->reg_use, &arg->arg_value.u_entry); + arg->arg_value.u_reg = new; + b_queue_push_back(&new->reg_use, &arg->arg_value.u_entry); + } + + for (size_t i = 0; i < MIE_VECTOR_COUNT(op->op_successors); i++) { + struct mie_op_successor *s = &op->op_successors.items[i]; + for (size_t k = 0; k < MIE_VECTOR_COUNT(s->s_args); k++) { + struct mie_op_arg *arg = &s->s_args.items[i]; + if (!(arg->arg_flags & MIE_OP_F_ARG_RESOLVED)) { + continue; + } + + if (arg->arg_value.u_reg != old) { + continue; + } + + b_queue_delete(&old->reg_use, &arg->arg_value.u_entry); + arg->arg_value.u_reg = new; + b_queue_push_back(&new->reg_use, &arg->arg_value.u_entry); + } + } + + return MIE_SUCCESS; +} + +enum mie_status mie_rewriter_replace_register( + struct mie_rewriter *rw, struct mie_register *old, struct mie_register *new) +{ + b_queue_entry *cur = b_queue_first(&old->reg_use); + while (cur) { + struct mie_register_use *use + = b_unbox(struct mie_register_use, cur, u_entry); + struct mie_op *op = use->u_user; + + if (use->u_reg == old) { + replace_register_usage(op, old, new); + } + + cur = b_queue_next(cur); + } + + return MIE_SUCCESS; +} + +enum mie_status mie_rewriter_rename_register( + struct mie_rewriter *rw, struct mie_register *reg, const char *name) +{ + if (!reg->reg_block) { + return MIE_ERR_INVALID_ARGUMENT; + } + + struct mie_region *region = reg->reg_block->b_parent; + struct mie_name_map *names = get_name_map_for_region(region); + + mie_name_destroy(®->reg_name); + struct mie_name *result = mie_name_map_put(names, ®->reg_name, name, 0); + + return result ? MIE_SUCCESS : MIE_ERR_NO_MEMORY; +} + +enum mie_status mie_rewriter_put_name( + struct mie_rewriter *rw, struct mie_name *name, const char *hint) +{ + if (!rw->r_insert_block) { + return MIE_ERR_BAD_STATE; + } + + struct mie_region *region = rw->r_insert_block->b_parent; + struct mie_name_map *names = get_name_map_for_region(region); + + mie_name_destroy(name); + struct mie_name *result = mie_name_map_put(names, name, hint, 0); + + return result ? MIE_SUCCESS : MIE_ERR_NO_MEMORY; +}