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.
This commit is contained in:
@@ -1,60 +0,0 @@
|
||||
#ifndef MIE_IR_REWRITE_H_
|
||||
#define MIE_IR_REWRITE_H_
|
||||
|
||||
#include <mie/misc.h>
|
||||
#include <mie/status.h>
|
||||
#include <stddef.h>
|
||||
|
||||
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
|
||||
@@ -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)
|
||||
|
||||
20
mie/include/mie/rewrite/convert.h
Normal file
20
mie/include/mie/rewrite/convert.h
Normal file
@@ -0,0 +1,20 @@
|
||||
#ifndef MIE_REWRITE_CONVERT_H_
|
||||
#define MIE_REWRITE_CONVERT_H_
|
||||
|
||||
#include <mie/ctx.h>
|
||||
|
||||
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
|
||||
16
mie/include/mie/rewrite/greedy.h
Normal file
16
mie/include/mie/rewrite/greedy.h
Normal file
@@ -0,0 +1,16 @@
|
||||
#ifndef MIE_REWRITE_GREEDY_H_
|
||||
#define MIE_REWRITE_GREEDY_H_
|
||||
|
||||
#include <mie/ctx.h>
|
||||
|
||||
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
|
||||
54
mie/include/mie/rewrite/pattern.h
Normal file
54
mie/include/mie/rewrite/pattern.h
Normal file
@@ -0,0 +1,54 @@
|
||||
#ifndef MIE_REWRITE_PATTERN_H_
|
||||
#define MIE_REWRITE_PATTERN_H_
|
||||
|
||||
#include <mie/vector.h>
|
||||
|
||||
#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
|
||||
108
mie/include/mie/rewrite/rewriter.h
Normal file
108
mie/include/mie/rewrite/rewriter.h
Normal file
@@ -0,0 +1,108 @@
|
||||
#ifndef MIE_IR_REWRITE_H_
|
||||
#define MIE_IR_REWRITE_H_
|
||||
|
||||
#include <mie/ir/emit.h>
|
||||
#include <mie/misc.h>
|
||||
#include <mie/status.h>
|
||||
#include <mie/vector.h>
|
||||
#include <stddef.h>
|
||||
|
||||
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
|
||||
88
mie/rewrite/convert.c
Normal file
88
mie/rewrite/convert.c
Normal file
@@ -0,0 +1,88 @@
|
||||
#include <mie/ctx.h>
|
||||
#include <mie/ir/op-definition.h>
|
||||
#include <mie/ir/op.h>
|
||||
#include <mie/ir/walk.h>
|
||||
#include <mie/rewrite/convert.h>
|
||||
#include <mie/rewrite/pattern.h>
|
||||
#include <mie/rewrite/rewriter.h>
|
||||
#include <mie/vector.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
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;
|
||||
}
|
||||
30
mie/rewrite/pattern-set.c
Normal file
30
mie/rewrite/pattern-set.c
Normal file
@@ -0,0 +1,30 @@
|
||||
#include <mie/rewrite/pattern.h>
|
||||
#include <mie/vector.h>
|
||||
#include <string.h>
|
||||
|
||||
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;
|
||||
}
|
||||
23
mie/rewrite/pattern.c
Normal file
23
mie/rewrite/pattern.c
Normal file
@@ -0,0 +1,23 @@
|
||||
#include <mie/rewrite/pattern.h>
|
||||
|
||||
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);
|
||||
}
|
||||
591
mie/rewrite/rewriter.c
Normal file
591
mie/rewrite/rewriter.c
Normal file
@@ -0,0 +1,591 @@
|
||||
#include <mie/ctx.h>
|
||||
#include <mie/ir/block.h>
|
||||
#include <mie/ir/op-definition.h>
|
||||
#include <mie/ir/op.h>
|
||||
#include <mie/ir/region.h>
|
||||
#include <mie/rewrite/rewriter.h>
|
||||
#include <string.h>
|
||||
|
||||
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;
|
||||
}
|
||||
Reference in New Issue
Block a user