diff --git a/mie/include/mie/ctx.h b/mie/include/mie/ctx.h index b009e29..d5f6a69 100644 --- a/mie/include/mie/ctx.h +++ b/mie/include/mie/ctx.h @@ -43,7 +43,6 @@ MIE_API void mie_ctx_destroy(struct mie_ctx *ctx); MIE_API struct mie_op *mie_ctx_create_op( const struct mie_ctx *ctx, const char *dialect, const char *op); -MIE_API bool mie_ctx_resolve_op(const struct mie_ctx *ctx, struct mie_op *op); MIE_API struct mie_dialect *mie_ctx_get_dialect( const struct mie_ctx *ctx, const char *name); diff --git a/mie/include/mie/ir/block.h b/mie/include/mie/ir/block.h index 18f1943..0455784 100644 --- a/mie/include/mie/ir/block.h +++ b/mie/include/mie/ir/block.h @@ -6,13 +6,26 @@ #include #include +#define MIE_BLOCK_ID_INVALID ((size_t)0) + struct mie_op; struct mie_register; +struct mie_block_predecessor { + struct mie_block *p_block; +}; + struct mie_block { struct mie_name b_name; struct mie_region *b_parent; + + /* immediate predecessor blocks */ + MIE_VECTOR_DECLARE(struct mie_block_predecessor, b_ipred); + /* used by struct mie_region */ + unsigned int b_id; + struct mie_block *b_idom; + // struct mie_block *b_sdom, *b_dfs_parent; b_queue_entry b_entry; MIE_VECTOR_DECLARE(struct mie_register, b_params); @@ -29,9 +42,33 @@ MIE_API struct mie_op *mie_block_get_next_op( const struct mie_block *block, const struct mie_op *after); MIE_API struct mie_op *mie_block_get_last_op(const struct mie_block *block); +MIE_API struct mie_op *mie_block_get_terminator(const struct mie_block *block); + +MIE_API struct mie_op_successor *mie_block_get_first_successor( + const struct mie_block *block); +MIE_API struct mie_op_successor *mie_block_get_prev_successor( + const struct mie_block *block, const struct mie_op_successor *before); +MIE_API struct mie_op_successor *mie_block_get_next_successor( + const struct mie_block *block, const struct mie_op_successor *after); +MIE_API struct mie_op_successor *mie_block_get_last_successor( + const struct mie_block *block); + +MIE_API struct mie_block_predecessor *mie_block_get_first_predecessor( + const struct mie_block *block); +MIE_API struct mie_block_predecessor *mie_block_get_prev_predecessor( + const struct mie_block *block, const struct mie_block_predecessor *before); +MIE_API struct mie_block_predecessor *mie_block_get_next_predecessor( + const struct mie_block *block, const struct mie_block_predecessor *after); +MIE_API struct mie_block_predecessor *mie_block_get_last_predecessor( + const struct mie_block *block); + MIE_API struct mie_op *mie_block_add_op(struct mie_block *block); MIE_API struct mie_op *mie_block_add_op_after( struct mie_block *block, struct mie_op *after); MIE_API struct mie_register *mie_block_add_param(struct mie_block *block); +MIE_API struct mie_register *mie_block_find_register( + const struct mie_block *block, const char *name, + const struct mie_op *start_point); + #endif diff --git a/mie/include/mie/ir/op.h b/mie/include/mie/ir/op.h index 963c757..1893078 100644 --- a/mie/include/mie/ir/op.h +++ b/mie/include/mie/ir/op.h @@ -9,8 +9,8 @@ #include #include +struct mie_ctx; struct mie_type; - struct mie_value; struct mie_block; struct mie_region; @@ -37,6 +37,7 @@ struct mie_op_arg { struct mie_op_successor { enum mie_op_flags s_flags; + struct mie_file_span s_name_span; union { /* only valid if F_SUCCESSOR_RESOLVED is set in s_flags; */ @@ -53,8 +54,8 @@ struct mie_op { /* used by struct mie_block */ b_queue_entry op_entry; - /* these pointers are only valid if the F_OP_RESOLVED flag is set */ - const struct mie_dialect *op_dialect; + struct mie_line_source *op_src; + /* this pointer is only valid if the F_OP_RESOLVED flag is set */ const struct mie_op_definition *op_info; struct mie_block *op_container; @@ -78,6 +79,10 @@ MIE_API void mie_op_cleanup(struct mie_op *op); MIE_API size_t mie_op_get_name(const struct mie_op *op, char *out, size_t max); +MIE_API bool mie_op_resolve_self(struct mie_op *op, struct mie_ctx *ctx); +MIE_API bool mie_op_resolve_args(struct mie_op *op, struct mie_ctx *ctx); +MIE_API bool mie_op_resolve_successors(struct mie_op *op, struct mie_ctx *ctx); + MIE_API struct mie_op_arg *mie_op_add_arg(struct mie_op *op); MIE_API struct mie_register *mie_op_add_result( struct mie_op *op, const struct mie_type *ty); @@ -102,6 +107,8 @@ MIE_API struct mie_region *mie_op_get_next_region( MIE_API struct mie_region *mie_op_get_last_region(const struct mie_op *op); MIE_API struct mie_register *mie_op_get_arg(const struct mie_op *op, size_t index); +MIE_API struct mie_register *mie_op_get_result_with_name( + const struct mie_op *op, const char *name); MIE_API struct mie_op *mie_op_get_first_child_op(const struct mie_op *op); MIE_API struct mie_op *mie_op_get_last_child_op(const struct mie_op *op); diff --git a/mie/include/mie/ir/region.h b/mie/include/mie/ir/region.h index dabc140..34456f6 100644 --- a/mie/include/mie/ir/region.h +++ b/mie/include/mie/ir/region.h @@ -1,12 +1,14 @@ #ifndef MIE_IR_REGION_H_ #define MIE_IR_REGION_H_ +#include #include #include #include #include struct mie_op; +struct mie_ctx; struct mie_block; struct mie_region { @@ -16,6 +18,9 @@ struct mie_region { b_queue_entry r_entry; /* queue of struct mie_block */ b_queue r_blocks; + /* bst of struct mie_block, as numbered by a depth-first search. + * this ordering is recalculated by mie_region_refresh_dominance */ + b_btree r_blocks_s; }; MIE_API struct mie_block *mie_region_get_first_block( @@ -29,5 +34,22 @@ MIE_API struct mie_block *mie_region_get_last_block(const struct mie_region *reg MIE_API struct mie_block *mie_region_add_block(struct mie_region *region); MIE_API struct mie_block *mie_region_add_block_after( struct mie_region *region, struct mie_block *after); +MIE_API struct mie_block *mie_region_find_block( + const struct mie_region *region, const char *name); +MIE_API struct mie_register *mie_region_find_register( + const struct mie_region *region, const char *name); + +/* calculate the dominance-tree of all blocks in a region. + * this function populates the following attributes of every block in the + * region: + * b_id + * b_node + * b_parent + * as well as the following attributes of the region itself: + * r_blocks_s + * only top-level blocks and ops are considered by this function. if an op + * within the region itself contains one/more child regions, these are ignored. + */ +MIE_API void mie_region_refresh_dominance(struct mie_region *region); #endif diff --git a/mie/include/mie/ir/register.h b/mie/include/mie/ir/register.h index c4a46af..d24f240 100644 --- a/mie/include/mie/ir/register.h +++ b/mie/include/mie/ir/register.h @@ -37,6 +37,7 @@ struct mie_register_use { struct mie_register { enum mie_register_flags reg_flags; + struct mie_file_span reg_span; union { /* only valid if F_VIRTUAL is set. */ struct mie_name reg_name; diff --git a/mie/include/mie/ir/resolve.h b/mie/include/mie/ir/resolve.h new file mode 100644 index 0000000..5f7350e --- /dev/null +++ b/mie/include/mie/ir/resolve.h @@ -0,0 +1,14 @@ +#ifndef MIE_IR_RESOLVE_H_ +#define MIE_IR_RESOLVE_H_ + +#include +#include + +struct mie_op; +struct mie_ctx; + +MIE_API bool mie_resolve_op_self(struct mie_op *op, struct mie_ctx *ctx); +MIE_API bool mie_resolve_op_args(struct mie_op *op, struct mie_ctx *ctx); +MIE_API bool mie_resolve_op_successors(struct mie_op *op, struct mie_ctx *ctx); + +#endif diff --git a/mie/include/mie/name.h b/mie/include/mie/name.h index 24136e1..1c06410 100644 --- a/mie/include/mie/name.h +++ b/mie/include/mie/name.h @@ -59,7 +59,7 @@ struct mie_name { /* if this name was read from a file, these structs can be used to * record the location within the file where the name is found. */ - struct mie_file_span n_start, n_end; + struct mie_file_span n_span; }; struct mie_name_map { diff --git a/mie/include/mie/parse/lex.h b/mie/include/mie/parse/lex.h index b6a92d6..0434d7d 100644 --- a/mie/include/mie/parse/lex.h +++ b/mie/include/mie/parse/lex.h @@ -16,6 +16,7 @@ MIE_API struct mie_lex *mie_lex_create( MIE_API void mie_lex_destroy(struct mie_lex *lex); MIE_API enum mie_status mie_lex_get_status(const struct mie_lex *lex); +MIE_API struct mie_line_source *mie_lex_get_line_source(const struct mie_lex *lex); MIE_API struct mie_token *mie_lex_peek(struct mie_lex *lex); MIE_API void mie_lex_advance(struct mie_lex *lex); diff --git a/mie/include/mie/print/printer.h b/mie/include/mie/print/printer.h index a730126..3128c9f 100644 --- a/mie/include/mie/print/printer.h +++ b/mie/include/mie/print/printer.h @@ -23,6 +23,8 @@ enum mie_print_flags { MIE_PRINT_F_INCLUDE_TYPE = 0x04u, MIE_PRINT_F_EXCLUDE_BLOCK_HEADER = 0x08u, MIE_PRINT_F_EXCLUDE_FIRST_BLOCK_HEADER = 0x10u, + + MIE_PRINT_F_MARK_UNRESOLVED_ELEMENTS = 0x20u, }; struct mie_printer { diff --git a/mie/include/mie/vector.h b/mie/include/mie/vector.h index 8b16e35..9d70be6 100644 --- a/mie/include/mie/vector.h +++ b/mie/include/mie/vector.h @@ -49,8 +49,8 @@ struct mie_vector_ops { &(vector.max), ops) #define mie_vector_pop_back(vector, ops) \ __mie_vector_pop_back( \ - (void **)&(vector), sizeof *vector, &(vector.count), \ - &(vector.max), ops) + (void **)&(vector.items), sizeof *vector.items, \ + &(vector.count), &(vector.max), ops) #define mie_vector_emplace_back(vector, ops) \ __mie_vector_emplace_back( \ (void **)&(vector.items), sizeof *vector.items, \ @@ -86,6 +86,10 @@ struct mie_vector_ops { __mie_vector_destroy( \ (void **)(vector), sizeof **vector, (vector##_count), \ (vector##_max), ops) +#define mie_vector_ref_get_item(vector, index) (*vector)[index] +#define mie_vector_ref_get_item_ptr(vector, index) (&(*vector)[index]) +#define mie_vector_ref_get_count(vector) *(vector##_count) +#define mie_vector_ref_get_max(vector) *(vector##_count) /* don't use these functions */ MIE_API int __mie_vector_push_back( diff --git a/mie/ir/block.c b/mie/ir/block.c index e8d8ee5..0a91324 100644 --- a/mie/ir/block.c +++ b/mie/ir/block.c @@ -52,6 +52,144 @@ struct mie_op *mie_block_get_last_op(const struct mie_block *block) return b_unbox(struct mie_op, entry, op_entry); } +struct mie_op *mie_block_get_terminator(const struct mie_block *block) +{ + b_queue_entry *op_entry = b_queue_last(&block->b_ops); + return b_unbox(struct mie_op, op_entry, op_entry); +} + +struct mie_op_successor *mie_block_get_first_successor(const struct mie_block *block) +{ + struct mie_op *op = mie_block_get_terminator(block); + if (!op) { + return NULL; + } + + if (MIE_VECTOR_COUNT(op->op_successors) == 0) { + return NULL; + } + + return &op->op_successors.items[0]; +} + +struct mie_op_successor *mie_block_get_prev_successor( + const struct mie_block *block, const struct mie_op_successor *before) +{ + struct mie_op *op = mie_block_get_terminator(block); + if (!op) { + return NULL; + } + + if (MIE_VECTOR_COUNT(op->op_successors) == 0) { + return NULL; + } + + size_t i = before - &op->op_successors.items[0]; + if (i == 0 || i >= MIE_VECTOR_COUNT(op->op_successors)) { + return NULL; + } + + return &op->op_successors.items[i - 1]; +} + +struct mie_op_successor *mie_block_get_next_successor( + const struct mie_block *block, const struct mie_op_successor *after) +{ + struct mie_op *op = mie_block_get_terminator(block); + if (!op) { + return NULL; + } + + if (MIE_VECTOR_COUNT(op->op_successors) == 0) { + return NULL; + } + + size_t i = after - &op->op_successors.items[0]; + if (i >= MIE_VECTOR_COUNT(op->op_successors)) { + return NULL; + } + + if (i + 1 >= MIE_VECTOR_COUNT(op->op_successors)) { + return NULL; + } + + return &op->op_successors.items[i + 1]; +} + +struct mie_op_successor *mie_block_get_last_successor(const struct mie_block *block) +{ + struct mie_op *op = mie_block_get_terminator(block); + if (!op) { + return NULL; + } + + size_t nr_successors = MIE_VECTOR_COUNT(op->op_successors); + + if (nr_successors == 0) { + return NULL; + } + + return &op->op_successors.items[nr_successors - 1]; +} + +struct mie_block_predecessor *mie_block_get_first_predecessor( + const struct mie_block *block) +{ + size_t nr_predecessors = MIE_VECTOR_COUNT(block->b_ipred); + + if (nr_predecessors == 0) { + return NULL; + } + + return &block->b_ipred.items[0]; +} + +struct mie_block_predecessor *mie_block_get_prev_predecessor( + const struct mie_block *block, const struct mie_block_predecessor *before) +{ + if (MIE_VECTOR_COUNT(block->b_ipred) == 0) { + return NULL; + } + + size_t i = before - &block->b_ipred.items[0]; + if (i == 0) { + return NULL; + } + + return &block->b_ipred.items[i - 1]; +} + +struct mie_block_predecessor *mie_block_get_next_predecessor( + const struct mie_block *block, const struct mie_block_predecessor *after) +{ + if (MIE_VECTOR_COUNT(block->b_ipred) == 0) { + return NULL; + } + + size_t i = after - &block->b_ipred.items[0]; + if (i >= MIE_VECTOR_COUNT(block->b_ipred)) { + return NULL; + } + + if (i + 1 >= MIE_VECTOR_COUNT(block->b_ipred)) { + return NULL; + } + + return &block->b_ipred.items[i + 1]; +} + +struct mie_block_predecessor *mie_block_get_last_predecessor( + const struct mie_block *block) +{ + size_t nr_predecessors = MIE_VECTOR_COUNT(block->b_ipred); + + if (nr_predecessors == 0) { + return NULL; + } + + return &block->b_ipred.items[nr_predecessors - 1]; +} + struct mie_op *mie_block_add_op(struct mie_block *block) { struct mie_op *op = malloc(sizeof *op); @@ -100,3 +238,31 @@ struct mie_register *mie_block_add_param(struct mie_block *block) return result; } + +struct mie_register *mie_block_find_register( + const struct mie_block *block, const char *name, + const struct mie_op *start_point) +{ + const b_queue_entry *entry = b_queue_last(&block->b_ops); + if (start_point) { + entry = &start_point->op_entry; + } + + for (size_t i = 0; i < MIE_VECTOR_COUNT(block->b_params); i++) { + if (!strcmp(block->b_params.items[i].reg_name.n_str, name)) { + return &block->b_params.items[i]; + } + } + + while (entry) { + struct mie_op *op = b_unbox(struct mie_op, entry, op_entry); + struct mie_register *reg = mie_op_get_result_with_name(op, name); + if (reg) { + return reg; + } + + entry = b_queue_prev(entry); + } + + return NULL; +} diff --git a/mie/ir/op.c b/mie/ir/op.c index 5fe4b6e..1f5c61a 100644 --- a/mie/ir/op.c +++ b/mie/ir/op.c @@ -1,4 +1,8 @@ #include +#include +#include +#include +#include #include #include #include @@ -260,6 +264,18 @@ struct mie_register *mie_op_get_arg(const struct mie_op *op, size_t index) return arg->arg_value.u_reg; } +struct mie_register *mie_op_get_result_with_name( + const struct mie_op *op, const char *name) +{ + for (size_t i = 0; i < MIE_VECTOR_COUNT(op->op_result); i++) { + if (!strcmp(op->op_result.items[i].reg_name.n_str, name)) { + return &op->op_result.items[i]; + } + } + + return NULL; +} + 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); diff --git a/mie/ir/region.c b/mie/ir/region.c index b34e214..84a20d5 100644 --- a/mie/ir/region.c +++ b/mie/ir/region.c @@ -1,4 +1,9 @@ +#include +#include +#include +#include #include +#include #include #include #include @@ -63,6 +68,7 @@ struct mie_block *mie_region_add_block(struct mie_region *region) memset(block, 0x0, sizeof *block); block->b_parent = region; + block->b_id = MIE_BLOCK_ID_INVALID; b_queue_push_back(®ion->r_blocks, &block->b_entry); @@ -89,3 +95,38 @@ struct mie_block *mie_region_add_block_after( return block; } + +struct mie_block *mie_region_find_block( + const struct mie_region *region, const char *name) +{ + b_queue_entry *cur = b_queue_first(®ion->r_blocks); + while (cur) { + struct mie_block *block = b_unbox(struct mie_block, cur, b_entry); + if (!strcmp(block->b_name.n_str, name)) { + return block; + } + + cur = b_queue_next(cur); + } + + return NULL; +} + +struct mie_register *mie_region_find_register( + const struct mie_region *region, const char *name) +{ + b_queue_entry *cur = b_queue_first(®ion->r_blocks); + + while (cur) { + struct mie_block *block = b_unbox(struct mie_block, cur, b_entry); + struct mie_register *reg + = mie_block_find_register(block, name, NULL); + if (reg) { + return reg; + } + + cur = b_queue_next(cur); + } + + return NULL; +} diff --git a/mie/ir/resolve.c b/mie/ir/resolve.c new file mode 100644 index 0000000..8137a5d --- /dev/null +++ b/mie/ir/resolve.c @@ -0,0 +1,264 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +enum register_find_result { + REG_FIND_NONE = 0, + REG_FIND_USE_BEFORE_DEFINE, + REG_FIND_UNDOMINATED, + REG_FIND_ISOLATED, +}; + +bool mie_op_resolve_self(struct mie_op *op, struct mie_ctx *ctx) +{ + if (op->op_flags & MIE_OP_F_OP_RESOLVED) { + return true; + } + + const char *dialect_name = NULL, *op_name = NULL; + + char *dot = strchr(op->op_name, '.'); + if (dot) { + *dot = 0; + dialect_name = op->op_name; + op_name = dot + 1; + } else { + dialect_name = NULL; + op_name = op->op_name; + } + + const struct mie_dialect *dialect = mie_ctx_get_dialect(ctx, dialect_name); + if (dot) { + *dot = '.'; + } + + /* dialect_name is no longer valid after this point */ + dialect_name = NULL; + + if (!dialect) { + return false; + } + + const struct mie_op_definition *op_info + = mie_dialect_get_op(dialect, op_name); + if (!op_info) { + return false; + } + + op->op_info = op_info; + + free(op->op_name); + op->op_name = NULL; + + op->op_flags |= MIE_OP_F_OP_RESOLVED; + + return true; +} + +static enum register_find_result find_register_wide( + struct mie_op *op, const char *name, struct mie_register **out) +{ + struct mie_region *region = op->op_container->b_parent; + enum register_find_result result = REG_FIND_UNDOMINATED; + struct mie_register *reg = NULL; + + while (region) { + reg = mie_region_find_register(region, name); + if (reg) { + *out = reg; + break; + } + + struct mie_op *op = region->r_parent; + if (mie_op_has_trait(op, "builtin", "isolated-from-above")) { + result = REG_FIND_ISOLATED; + } + + region = op->op_container ? op->op_container->b_parent : NULL; + } + + if (!reg) { + return result; + } + + if (reg->reg_block == op->op_container) { + return REG_FIND_USE_BEFORE_DEFINE; + } + + return result; +} + +static bool resolve_arg( + struct mie_op *op, struct mie_op_arg *arg, struct mie_ctx *ctx) +{ + const char *arg_name = arg->arg_unresolved.reg_name; + struct mie_block *block = op->op_container; + struct mie_op *search_start = op; + struct mie_register *reg = NULL; + + while (block) { + reg = mie_block_find_register(block, arg_name, search_start); + if (reg) { + break; + } + + search_start = NULL; + block = block->b_idom; + } + + if (reg) { + free(arg->arg_unresolved.reg_name); + arg->arg_flags |= MIE_OP_F_ARG_RESOLVED; + + memset(&arg->arg_value, 0x0, sizeof arg->arg_value); + arg->arg_value.u_reg = reg; + arg->arg_value.u_user = op; + b_queue_push_back(®->reg_use, &arg->arg_value.u_entry); + return true; + } + + enum register_find_result find_result + = find_register_wide(op, arg_name, ®); + + struct mie_diag *diag = mie_ctx_push_diag( + ctx, op->op_src, &arg->arg_span.s_start, "builtin", + MIE_BUILTIN_E_UNRESOLVED_VALUE); + mie_diag_push_msg(diag, ctx, "builtin", MIE_BUILTIN_MSG_UNRESOLVED_VALUE); + + struct mie_diag_highlight hl[] = { + { + .hl_type = MIE_DIAG_HIGHLIGHT_ERROR, + .hl_span = arg->arg_span, + }, + }; + + mie_diag_push_snippet( + diag, arg->arg_span.s_start.c_row, arg->arg_span.s_end.c_row, + NULL, 0, hl, 1); + + if (!reg) { + return false; + } + + struct mie_block *reg_container = reg->reg_block; + + switch (find_result) { + case REG_FIND_ISOLATED: + mie_diag_push_msg( + diag, ctx, "builtin", + MIE_BUILTIN_MSG_VALUE_DEFINED_OUTSIDE_ISOLATED_REGION); + break; + case REG_FIND_UNDOMINATED: + mie_diag_push_msg( + diag, ctx, "builtin", + MIE_BUILTIN_MSG_VALUE_DEFINED_IN_NON_DOMINANT_BLOCK); + break; + case REG_FIND_USE_BEFORE_DEFINE: + mie_diag_push_msg( + diag, ctx, "builtin", + MIE_BUILTIN_MSG_VALUE_DEFINED_AFTER_USE); + break; + default: + return false; + } + + hl[0].hl_type = MIE_DIAG_HIGHLIGHT_HINT; + hl[0].hl_span = reg->reg_span; + + mie_diag_push_snippet( + diag, reg->reg_span.s_start.c_row, reg->reg_span.s_end.c_row, + NULL, 0, hl, 1); + + if (!reg_container) { + return false; + } + + hl[0].hl_span = reg_container->b_name.n_span; + + mie_diag_push_snippet( + diag, reg_container->b_name.n_span.s_start.c_row, + reg_container->b_name.n_span.s_end.c_row, NULL, 0, hl, 1); + + return false; +} + +static bool resolve_successor( + struct mie_op *op, struct mie_op_successor *s, struct mie_ctx *ctx) +{ + if (s->s_flags & MIE_OP_F_SUCCESSOR_RESOLVED) { + return true; + } + + struct mie_block *container = op->op_container; + struct mie_region *region = container ? container->b_parent : NULL; + if (!region) { + return false; + } + + struct mie_diag *diag = NULL; + struct mie_block *dest = mie_region_find_block(region, s->s_block_name); + if (!dest) { + diag = mie_ctx_push_diag( + ctx, op->op_src, &s->s_name_span.s_start, "builtin", + MIE_BUILTIN_E_UNRESOLVED_SUCCESSOR); + mie_diag_push_msg( + diag, ctx, "builtin", MIE_BUILTIN_MSG_CANNOT_FIND_BLOCK); + const struct mie_diag_highlight hl[] = { + { + .hl_type = MIE_DIAG_HIGHLIGHT_ERROR, + .hl_span = s->s_name_span, + }, + }; + mie_diag_push_snippet( + diag, s->s_name_span.s_start.c_row, + s->s_name_span.s_end.c_row, NULL, 0, hl, 1); + return false; + } + + free(s->s_block_name); + s->s_block = dest; + s->s_flags |= MIE_OP_F_SUCCESSOR_RESOLVED; + + return true; +} + +bool mie_op_resolve_args(struct mie_op *op, struct mie_ctx *ctx) +{ + bool ok = true; + + for (size_t i = 0; i < MIE_VECTOR_COUNT(op->op_args); i++) { + if (!resolve_arg(op, &op->op_args.items[i], ctx)) { + ok = false; + } + } + + 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++) { + if (!resolve_arg(op, &s->s_args.items[k], ctx)) { + ok = false; + } + } + } + + return ok; +} + +bool mie_op_resolve_successors(struct mie_op *op, struct mie_ctx *ctx) +{ + bool ok = true; + + for (size_t i = 0; i < MIE_VECTOR_COUNT(op->op_successors); i++) { + if (!resolve_successor(op, &op->op_successors.items[i], ctx)) { + ok = false; + } + } + + return ok; +} diff --git a/mie/lt-idom.c b/mie/lt-idom.c new file mode 100644 index 0000000..86fa787 --- /dev/null +++ b/mie/lt-idom.c @@ -0,0 +1,254 @@ +#include +#include +#include +#include + +struct set { + MIE_VECTOR_DECLARE(unsigned int, v); +}; + +struct dfs_stack_item { + struct mie_block *i_parent, *i_node; +}; + +struct lt_ctx { + size_t nr_nodes; + struct mie_block **vertex; + struct set *bucket; + unsigned int *semi; + unsigned int *idom; + unsigned int *samedom; + unsigned int *parent; + unsigned int *ancestor; + unsigned int *label; + + MIE_VECTOR_DECLARE(struct dfs_stack_item, dfstack); +}; + +#if 0 +static B_BTREE_DEFINE_SIMPLE_INSERT(struct mie_block, b_node, b_id, put_block_by_id); +static B_BTREE_DEFINE_SIMPLE_GET( + struct mie_block, size_t, b_node, b_id, get_block_by_id); +#endif + +static void set_add(struct set *set, unsigned int val) +{ + for (size_t i = 0; i < MIE_VECTOR_COUNT(set->v); i++) { + if (set->v.items[i] == val) { + return; + } + } + + mie_vector_push_back(set->v, &val, NULL); +} + +static struct mie_block *pop_block_successor( + MIE_VECTOR_REF_PARAM(struct mie_block *, successors)) +{ + size_t count = mie_vector_ref_get_count(successors); + if (count == 0) { + return false; + } + + struct mie_block *out = mie_vector_ref_get_item(successors, count - 1); + mie_vector_ref_pop_back(successors, NULL); + + return out; +} + +static void enqueue_block_successors( + struct mie_block *block, + MIE_VECTOR_REF_PARAM(struct mie_block *, successors)) +{ + struct mie_op_successor *s = mie_block_get_first_successor(block); + struct mie_block_predecessor pred = {.p_block = block}; + + while (s) { + if (s->s_flags & MIE_OP_F_SUCCESSOR_RESOLVED) { + mie_vector_ref_push_back(successors, &s->s_block, NULL); + mie_vector_push_back(s->s_block->b_ipred, &pred, NULL); + } + + s = mie_block_get_next_successor(block, s); + } +} + +static void dfs_stack_pop( + struct lt_ctx *ctx, struct mie_block **parent, struct mie_block **node) +{ + size_t nr = MIE_VECTOR_COUNT(ctx->dfstack); + if (!nr) { + return; + } + + struct dfs_stack_item *item = &ctx->dfstack.items[nr - 1]; + *parent = item->i_parent; + *node = item->i_node; + mie_vector_pop_back(ctx->dfstack, NULL); +} + +static void dfs_stack_push( + struct lt_ctx *ctx, struct mie_block *parent, struct mie_block *node) +{ + struct dfs_stack_item item = {.i_node = node, .i_parent = parent}; + mie_vector_push_back(ctx->dfstack, &item, NULL); +} + +static void dfs(struct lt_ctx *ctx, struct mie_block *root) +{ + dfs_stack_push(ctx, NULL, root); + unsigned int id = 1; + + while (MIE_VECTOR_COUNT(ctx->dfstack) > 0) { + struct mie_block *p, *n; + dfs_stack_pop(ctx, &p, &n); + + if (n->b_id != MIE_BLOCK_ID_INVALID) { + continue; + } + +#if 0 + printf("dfs(p=%s, n=%s)\n", p ? p->b_name.n_str : "NA", + n->b_name.n_str); +#endif + + n->b_id = id++; + ctx->vertex[n->b_id] = n; + ctx->semi[n->b_id] = n->b_id; + ctx->parent[n->b_id] = p ? p->b_id : MIE_BLOCK_ID_INVALID; + + struct mie_op_successor *s = mie_block_get_first_successor(n); + while (s) { + dfs_stack_push(ctx, n, s->s_block); + mie_vector_push_back(s->s_block->b_ipred, &n, NULL); + s = mie_block_get_next_successor(n, s); + } + } +} + +static void link(struct lt_ctx *ctx, unsigned int parent, unsigned int node) +{ + ctx->ancestor[node] = parent; + ctx->label[node] = node; +} + +static unsigned int eval(struct lt_ctx *ctx, unsigned int v) +{ + unsigned int a = ctx->ancestor[v]; + if (ctx->ancestor[a] > MIE_BLOCK_ID_INVALID) { + unsigned int b = eval(ctx, a); + ctx->ancestor[v] = ctx->ancestor[a]; + if (ctx->semi[b] < ctx->semi[ctx->label[v]]) { + ctx->label[v] = b; + } + } + + return ctx->label[v]; +} + +static void reset_block_relationship_metadata(struct mie_region *region) +{ + b_queue_entry *cur = b_queue_first(®ion->r_blocks); + while (cur) { + struct mie_block *block = b_unbox(struct mie_block, cur, b_entry); + + block->b_id = MIE_BLOCK_ID_INVALID; + block->b_idom = NULL; + // block->b_sdom = block->b_dfs_parent = NULL; + mie_vector_destroy(block->b_ipred, NULL); + + cur = b_queue_next(cur); + } + + memset(®ion->r_blocks_s, 0x0, sizeof region->r_blocks_s); +} + +static void lt_ctx_init(struct lt_ctx *ctx, size_t nr_nodes) +{ + memset(ctx, 0x0, sizeof *ctx); + ctx->idom = calloc(nr_nodes + 1, sizeof(unsigned int)); + ctx->samedom = calloc(nr_nodes + 1, sizeof(unsigned int)); + ctx->vertex = calloc(nr_nodes + 1, sizeof(struct mie_block *)); + ctx->bucket = calloc(nr_nodes + 1, sizeof(struct set)); + ctx->semi = calloc(nr_nodes + 1, sizeof(unsigned int)); + ctx->parent = calloc(nr_nodes + 1, sizeof(unsigned int)); + ctx->ancestor = calloc(nr_nodes + 1, sizeof(unsigned int)); + ctx->label = calloc(nr_nodes + 1, sizeof(unsigned int)); +} + +static void lt_ctx_cleanup(struct lt_ctx *ctx) +{ + free(ctx->idom); + free(ctx->samedom); + free(ctx->vertex); + free(ctx->bucket); + free(ctx->semi); + free(ctx->parent); + free(ctx->ancestor); + free(ctx->label); +} + +void mie_region_refresh_dominance(struct mie_region *region) +{ + struct lt_ctx ctx; + size_t nr_nodes = b_queue_length(®ion->r_blocks); + lt_ctx_init(&ctx, nr_nodes); + + struct mie_block *root = mie_region_get_first_block(region); + + reset_block_relationship_metadata(region); + dfs(&ctx, root); + + for (size_t i = nr_nodes; i > 0; i--) { + struct mie_block *n = ctx.vertex[i]; + unsigned int p = ctx.parent[i]; + unsigned int s = p; + + struct mie_block_predecessor *pred + = mie_block_get_first_predecessor(n); + while (pred) { + struct mie_block *v = pred->p_block; + unsigned int s_prime = MIE_BLOCK_ID_INVALID; + + if (v->b_id <= n->b_id) { + s_prime = v->b_id; + } else { + s_prime = eval(&ctx, v->b_id); + s_prime = ctx.semi[s_prime]; + } + + if (s_prime < s) { + s = s_prime; + } + + pred = mie_block_get_next_predecessor(n, pred); + } + + ctx.semi[n->b_id] = s; + set_add(&ctx.bucket[s], n->b_id); + link(&ctx, p, n->b_id); + + for (size_t k = 0; k < MIE_VECTOR_COUNT(ctx.bucket[p].v); k++) { + unsigned int v = ctx.bucket[p].v.items[k]; + unsigned int y = eval(&ctx, v); + if (ctx.semi[y] == ctx.semi[p]) { + ctx.idom[v] = p; + } else { + ctx.samedom[v] = y; + } + } + } + + for (size_t i = 1; i <= nr_nodes; i++) { + struct mie_block *n = ctx.vertex[i]; + if (ctx.samedom[i] > 0) { + ctx.idom[i] = ctx.idom[ctx.samedom[i]]; + } + + n->b_idom = ctx.vertex[ctx.idom[i]]; + // n->b_sdom = ctx.vertex[ctx.semi[i]]; + // n->b_dfs_parent = ctx.vertex[ctx.parent[i]]; + } + + lt_ctx_cleanup(&ctx); +} diff --git a/mie/parse/lex.c b/mie/parse/lex.c index 7b40511..4878432 100644 --- a/mie/parse/lex.c +++ b/mie/parse/lex.c @@ -211,6 +211,11 @@ enum mie_status mie_lex_get_status(const struct mie_lex *lex) return lex->lex_status; } +struct mie_line_source *mie_lex_get_line_source(const struct mie_lex *lex) +{ + return lex->lex_source; +} + static bool char_can_begin_symbol(char c) { for (size_t i = 0; i < nr_symbols; i++) { @@ -774,8 +779,10 @@ static enum mie_status pump_tokens(struct mie_lex *lex) = mie_line_source_get_cursor(lex->lex_source); unsigned long line = cursor->c_row; const struct mie_diag_highlight hl[] = { - {.hl_type = MIE_DIAG_HIGHLIGHT_ERROR, - .hl_span = {.s_start = *cursor, .s_end = *cursor}}, + { + .hl_type = MIE_DIAG_HIGHLIGHT_ERROR, + .hl_span = {.s_start = *cursor, .s_end = *cursor}, + }, }; const size_t nr_hl = sizeof hl / sizeof hl[0]; mie_diag_push_snippet(diag, line, line, NULL, 0, hl, nr_hl); diff --git a/mie/parse/parser.c b/mie/parse/parser.c index 9713327..c787fb8 100644 --- a/mie/parse/parser.c +++ b/mie/parse/parser.c @@ -543,6 +543,8 @@ bool mie_parser_parse_operand(struct mie_parser *ctx, struct mie_op_arg *out) result = true; } + out->arg_span = loc; + return result; } @@ -611,6 +613,8 @@ bool mie_parser_parse_parameter(struct mie_parser *ctx, struct mie_op_arg *out) return false; } + out->arg_span = loc; + if (!mie_parser_parse_symbol(ctx, MIE_SYM_COLON)) { return false; } @@ -710,6 +714,7 @@ bool mie_parser_parse_register( break; } + out->reg_span = tok->tok_location; mie_parser_advance(ctx); return name != NULL; @@ -927,6 +932,8 @@ bool mie_parser_parse_block( return false; } + memcpy(&block->b_name.n_span, &span, sizeof span); + if (mie_parser_peek_symbol(ctx) == MIE_SYM_LEFT_PAREN && !parse_block_parameters(ctx, names, block)) { return false; @@ -964,9 +971,8 @@ bool mie_parser_parse_successor(struct mie_parser *ctx, struct mie_op_successor memset(out, 0x0, sizeof *out); b_string *str = get_temp_string(ctx); bool result = false; - struct mie_file_span span; - if (!mie_parser_parse_blockname(ctx, str, &span)) { + if (!mie_parser_parse_blockname(ctx, str, &out->s_name_span)) { return false; } @@ -1159,6 +1165,15 @@ bool mie_parser_parse_op( } } + for (size_t i = 0; i < MIE_VECTOR_COUNT(dest->op_result); i++) { + struct mie_register *reg = &dest->op_result.items[i]; + reg->reg_flags |= MIE_REGISTER_F_OP_RESULT; + reg->reg_op = dest; + reg->reg_block = dest->op_container; + } + + dest->op_src = mie_lex_get_line_source(ctx->p_lex); + if (mie_parser_check_type(ctx, MIE_TOK_NAME)) { /* custom-format operation */ return parse_custom_op(ctx, names, dest); diff --git a/mie/print/op.c b/mie/print/op.c index f4b19b2..5977684 100644 --- a/mie/print/op.c +++ b/mie/print/op.c @@ -11,9 +11,13 @@ void mie_printer_print_op_arg( enum mie_register_flags arg_flags = 0; const char *arg_name = NULL; const struct mie_type *arg_type = NULL; + bool resolved = false; if (MIE_TEST_FLAGS(arg->arg_flags, MIE_OP_F_ARG_RESOLVED)) { + resolved = true; + if (!arg->arg_value.u_reg) { + /* this should only be caused by an internal parser/rewriter bug */ arg_flags = 0; arg_name = ""; arg_type = NULL; @@ -36,6 +40,12 @@ void mie_printer_print_op_arg( b_stream_write_string(printer->p_stream, arg_name, NULL); + if (!resolved + && MIE_TEST_FLAGS( + printer->p_flags, MIE_PRINT_F_MARK_UNRESOLVED_ELEMENTS)) { + b_stream_write_char(printer->p_stream, '?'); + } + if (!include_type || !arg_type) { return; } @@ -50,14 +60,23 @@ void mie_printer_print_op_successor( bool compact) { b_stream_write_char(printer->p_stream, '^'); + bool resolved = false; + if (successor->s_flags & MIE_OP_F_SUCCESSOR_RESOLVED) { b_stream_write_string( printer->p_stream, successor->s_block->b_name.n_str, NULL); + resolved = true; } else { b_stream_write_string( printer->p_stream, successor->s_block_name, NULL); } + if (!resolved + && MIE_TEST_FLAGS( + printer->p_flags, MIE_PRINT_F_MARK_UNRESOLVED_ELEMENTS)) { + b_stream_write_char(printer->p_stream, '?'); + } + if (MIE_VECTOR_COUNT(successor->s_args) == 0) { return; } @@ -210,6 +229,11 @@ static void print_generic_op(struct mie_printer *printer, const struct mie_op *o op->op_info->op_parent->d_name, op->op_info->op_name); } else { b_stream_write_string(printer->p_stream, op->op_name, NULL); + + if (MIE_TEST_FLAGS( + printer->p_flags, MIE_PRINT_F_MARK_UNRESOLVED_ELEMENTS)) { + b_stream_write_char(printer->p_stream, '?'); + } } b_stream_write_char(printer->p_stream, '(');