diff --git a/mie/include/mie/ir/walk.h b/mie/include/mie/ir/walk.h index 1f83a1a..0b2ee40 100644 --- a/mie/include/mie/ir/walk.h +++ b/mie/include/mie/ir/walk.h @@ -7,7 +7,6 @@ #include struct mie_op; -struct mie_walker; enum mie_walker_flags { MIE_WALKER_F_NONE = 0x00u, @@ -38,7 +37,7 @@ struct mie_walk_item { int _f; b_queue_entry _e; enum mie_walk_item_type i_type; - size_t i_index; + // size_t i_index; size_t i_depth; union { struct mie_op *i_op; @@ -47,8 +46,21 @@ struct mie_walk_item { }; }; -MIE_API struct mie_walker *mie_walker_begin( - struct mie_op *op, enum mie_walker_flags flags); +struct mie_walker { + enum mie_walker_flags w_flags; + union { + /* used for recursive walks */ + b_queue w_stack; + /* used for non-recursive walks */ + struct { + struct mie_walk_item w_region, w_block, w_op; + }; + }; +}; + +MIE_API void mie_walker_begin( + struct mie_walker *walker, const struct mie_op *op, + enum mie_walker_flags flags); MIE_API void mie_walker_end(struct mie_walker *walker); MIE_API enum mie_status mie_walker_step(struct mie_walker *walker); diff --git a/mie/ir/walk.c b/mie/ir/walk.c index f2cbe25..6b931ae 100644 --- a/mie/ir/walk.c +++ b/mie/ir/walk.c @@ -11,12 +11,6 @@ #define ITEM_TYPE(f) ((f) & 0x0Fu) -struct mie_walker { - enum mie_walker_flags w_flags; - struct mie_op *w_root; - b_queue w_stack; -}; - static bool should_ignore_item( const struct mie_walker *walker, const struct mie_walk_item *item) { @@ -56,15 +50,31 @@ static void pop_walk_item(struct mie_walker *walker) static struct mie_walk_item *current_item(struct mie_walker *walker) { + struct mie_walk_item *item = NULL; + bool recursive = (walker->w_flags & MIE_WALKER_F_RECURSIVE) != 0; + if (!recursive) { + if (walker->w_flags & MIE_WALKER_F_INCLUDE_REGIONS) { + item = &walker->w_region; + } else if (walker->w_flags & MIE_WALKER_F_INCLUDE_BLOCKS) { + item = &walker->w_block; + } else { + item = &walker->w_op; + } + + bool eof = !item || item->i_type != MIE_WALK_ITEM_NONE; + return eof ? item : NULL; + } + b_queue_entry *entry = b_queue_last(&walker->w_stack); if (!entry) { return NULL; } - struct mie_walk_item *item = b_unbox(struct mie_walk_item, entry, _e); + item = b_unbox(struct mie_walk_item, entry, _e); return item->i_type != MIE_WALK_ITEM_NONE ? item : NULL; } +#if 0 static struct mie_op *get_first_child(struct mie_walker *walker, struct mie_op *op) { bool backwards = (walker->w_flags & MIE_WALKER_F_BACKWARD) != 0; @@ -95,16 +105,17 @@ static struct mie_op *get_first_child(struct mie_walker *walker, struct mie_op * return op; } +#endif -static size_t walk_item_get_nr_children(const struct mie_walk_item *item) +static bool walk_item_has_children(const struct mie_walk_item *item) { switch (item->i_type) { case MIE_WALK_ITEM_OP: - return MIE_VECTOR_COUNT(item->i_op->op_regions); + return mie_op_get_first_region(item->i_op) != NULL; case MIE_WALK_ITEM_BLOCK: - return MIE_VECTOR_COUNT(item->i_block->b_ops); + return mie_block_get_first_op(item->i_block) != NULL; case MIE_WALK_ITEM_REGION: - return MIE_VECTOR_COUNT(item->i_region->r_blocks); + return mie_region_get_first_block(item->i_region) != NULL; default: return 0; } @@ -128,42 +139,68 @@ static bool should_correct_depth( return false; } -static bool walk_item_get_child( +static bool walk_item_get_first_child( struct mie_walker *walker, const struct mie_walk_item *item, - size_t index, struct mie_walk_item *child) + struct mie_walk_item *child) { bool ok = false; + b_queue_entry *entry = NULL; switch (item->i_type) { case MIE_WALK_ITEM_OP: - if (MIE_VECTOR_COUNT(item->i_op->op_regions) <= index) { - ok = false; - break; - } - child->i_type = MIE_WALK_ITEM_REGION; - child->i_region = &item->i_op->op_regions.items[index]; - ok = true; + child->i_region = mie_op_get_first_region(item->i_op); + ok = child->i_region != NULL; break; case MIE_WALK_ITEM_BLOCK: - if (MIE_VECTOR_COUNT(item->i_block->b_ops) <= index) { - ok = false; - break; - } - child->i_type = MIE_WALK_ITEM_OP; - child->i_op = &item->i_block->b_ops.items[index]; - ok = true; + child->i_op = mie_block_get_first_op(item->i_block); + ok = child->i_op != NULL; break; case MIE_WALK_ITEM_REGION: - if (MIE_VECTOR_COUNT(item->i_region->r_blocks) <= index) { - ok = false; - break; - } - child->i_type = MIE_WALK_ITEM_BLOCK; - child->i_block = &item->i_region->r_blocks.items[index]; - ok = true; + child->i_block = mie_region_get_first_block(item->i_region); + ok = child->i_block != NULL; + break; + default: + break; + } + + if (!ok) { + return false; + } + + child->i_depth = item->i_depth + 1; + + if (should_correct_depth(walker, item)) { + child->i_depth--; + } + + return true; +} + +static bool walk_item_get_last_child( + struct mie_walker *walker, const struct mie_walk_item *item, + struct mie_walk_item *child) +{ + bool ok = false; + b_queue_entry *entry = NULL; + + switch (item->i_type) { + case MIE_WALK_ITEM_OP: + child->i_type = MIE_WALK_ITEM_REGION; + child->i_region = mie_op_get_last_region(item->i_op); + ok = child->i_region != NULL; + break; + case MIE_WALK_ITEM_BLOCK: + child->i_type = MIE_WALK_ITEM_OP; + child->i_op = mie_block_get_last_op(item->i_block); + ok = child->i_op != NULL; + break; + case MIE_WALK_ITEM_REGION: + child->i_type = MIE_WALK_ITEM_BLOCK; + child->i_block = mie_region_get_last_block(item->i_region); + ok = child->i_block != NULL; break; default: break; @@ -174,7 +211,6 @@ static bool walk_item_get_child( } child->i_depth = item->i_depth + 1; - child->i_index = index; if (should_correct_depth(walker, item)) { child->i_depth--; @@ -192,8 +228,9 @@ static bool walk_item_get_next_sibling( sibling->i_depth = item->i_depth; sibling->i_type = item->i_type; - sibling->i_index = item->i_index + 1; + size_t index = 0; + b_queue_entry *entry = NULL; struct mie_region *parent_r = NULL; struct mie_block *parent_b = NULL; struct mie_op *parent_o = NULL; @@ -205,36 +242,26 @@ static bool walk_item_get_next_sibling( return false; } - if (item->i_index + 1 >= MIE_VECTOR_COUNT(parent_b->b_ops)) { - return false; - } - - sibling->i_op = &parent_b->b_ops.items[item->i_index + 1]; - return true; + sibling->i_op = mie_block_get_next_op(parent_b, item->i_op); + return sibling->i_op != NULL; case MIE_WALK_ITEM_BLOCK: parent_r = item->i_block->b_parent; if (!parent_r) { return false; } - if (item->i_index + 1 >= MIE_VECTOR_COUNT(parent_r->r_blocks)) { - return false; - } - - sibling->i_block = &parent_r->r_blocks.items[item->i_index + 1]; - return true; + sibling->i_block + = mie_region_get_next_block(parent_r, item->i_block); + return sibling->i_block != NULL; case MIE_WALK_ITEM_REGION: parent_o = item->i_region->r_parent; if (!parent_o) { return false; } - if (item->i_index + 1 >= MIE_VECTOR_COUNT(parent_o->op_regions)) { - return false; - } - - sibling->i_region = &parent_o->op_regions.items[item->i_index + 1]; - return true; + sibling->i_region + = mie_op_get_next_region(parent_o, item->i_region); + return sibling->i_region != NULL; default: return false; } @@ -243,14 +270,14 @@ static bool walk_item_get_next_sibling( static bool walk_item_get_prev_sibling( const struct mie_walk_item *item, struct mie_walk_item *sibling) { - if (item->i_depth == 0 || item->i_index == 0) { + if (item->i_depth == 0) { return false; } sibling->i_depth = item->i_depth; sibling->i_type = item->i_type; - sibling->i_index = item->i_index - 1; + size_t index = 0; struct mie_region *parent_r = NULL; struct mie_block *parent_b = NULL; struct mie_op *parent_o = NULL; @@ -262,24 +289,26 @@ static bool walk_item_get_prev_sibling( return false; } - sibling->i_op = &parent_b->b_ops.items[item->i_index - 1]; - return true; + sibling->i_op = mie_block_get_prev_op(parent_b, item->i_op); + return sibling->i_op != NULL; case MIE_WALK_ITEM_BLOCK: parent_r = item->i_block->b_parent; if (!parent_r) { return false; } - sibling->i_block = &parent_r->r_blocks.items[item->i_index - 1]; - return true; + sibling->i_block + = mie_region_get_prev_block(parent_r, item->i_block); + return sibling->i_block != NULL; case MIE_WALK_ITEM_REGION: parent_o = item->i_region->r_parent; if (!parent_o) { return false; } - sibling->i_region = &parent_o->op_regions.items[item->i_index - 1]; - return true; + sibling->i_region + = mie_op_get_prev_region(parent_o, item->i_region); + return sibling->i_region != NULL; default: return false; } @@ -334,9 +363,9 @@ static bool step_pre_f(struct mie_walker *walker) struct mie_walk_item next; bool ok = false; - size_t nr_children = walk_item_get_nr_children(item); - if (nr_children > 0) { - ok = walk_item_get_child(walker, item, 0, &next); + bool has_children = walk_item_has_children(item); + if (has_children) { + ok = walk_item_get_first_child(walker, item, &next); if (ok) { push_walk_item(walker, &next); @@ -384,9 +413,9 @@ static bool step_pre_b(struct mie_walker *walker) struct mie_walk_item next; bool ok = false; - size_t nr_children = walk_item_get_nr_children(item); - if (nr_children > 0) { - ok = walk_item_get_child(walker, item, nr_children - 1, &next); + bool has_children = walk_item_has_children(item); + if (has_children) { + ok = walk_item_get_last_child(walker, item, &next); if (ok) { push_walk_item(walker, &next); @@ -437,10 +466,10 @@ static bool step_post_f(struct mie_walker *walker) while (1) { item = current_item(walker); - size_t nr_children = walk_item_get_nr_children(item); + bool has_children = walk_item_has_children(item); - if (nr_children > 0 && !(item->_f & WALK_ITEM_F_CHILDREN_VISITED)) { - ok = walk_item_get_child(walker, item, 0, &next); + if (has_children && !(item->_f & WALK_ITEM_F_CHILDREN_VISITED)) { + ok = walk_item_get_first_child(walker, item, &next); if (ok) { push_walk_item(walker, &next); @@ -449,7 +478,7 @@ static bool step_post_f(struct mie_walker *walker) return ok; } - if (nr_children == 0 && !(item->_f & WALK_ITEM_F_VISITED)) { + if (!has_children && !(item->_f & WALK_ITEM_F_VISITED)) { return true; } @@ -469,6 +498,55 @@ static bool step_post_f(struct mie_walker *walker) } } +static bool step_flat_f(struct mie_walker *walker) +{ + struct mie_walk_item *stack[] = { + &walker->w_region, + &walker->w_block, + &walker->w_op, + }; + const int stack_size = sizeof stack / sizeof stack[0]; + + int start; + if (walker->w_flags & MIE_WALKER_F_INCLUDE_REGIONS) { + start = 0; + } else if (walker->w_flags & MIE_WALKER_F_INCLUDE_BLOCKS) { + start = 1; + } else { + start = 2; + } + + int i; + for (i = start; i >= 0; i--) { + struct mie_walk_item *item = stack[i]; + struct mie_walk_item next; + if (walk_item_get_next_sibling(item, &next)) { + *item = next; + break; + } + } + + if (i < 0) { + return false; + } + + for (int k = i; k < stack_size - 1; k++) { + struct mie_walk_item *parent = stack[k]; + struct mie_walk_item *child = stack[k + 1]; + + if (!walk_item_get_first_child(walker, parent, child)) { + return false; + } + } + + return true; +} + +static bool step_flat_b(struct mie_walker *walker) +{ + return false; +} + static bool step_post_b(struct mie_walker *walker) { /* backward, post-order traversal: @@ -485,11 +563,10 @@ static bool step_post_b(struct mie_walker *walker) while (1) { item = current_item(walker); - size_t nr_children = walk_item_get_nr_children(item); + bool has_children = walk_item_has_children(item); - if (nr_children > 0 && !(item->_f & WALK_ITEM_F_CHILDREN_VISITED)) { - ok = walk_item_get_child( - walker, item, nr_children - 1, &next); + if (has_children && !(item->_f & WALK_ITEM_F_CHILDREN_VISITED)) { + ok = walk_item_get_last_child(walker, item, &next); if (ok) { push_walk_item(walker, &next); @@ -498,7 +575,7 @@ static bool step_post_b(struct mie_walker *walker) return ok; } - if (nr_children == 0 && !(item->_f & WALK_ITEM_F_VISITED)) { + if (!has_children && !(item->_f & WALK_ITEM_F_VISITED)) { return true; } @@ -520,25 +597,106 @@ static bool step_post_b(struct mie_walker *walker) static bool step(struct mie_walker *walker) { + bool recursive = (walker->w_flags & MIE_WALKER_F_RECURSIVE) != 0; bool backward = (walker->w_flags & MIE_WALKER_F_BACKWARD) != 0; bool postorder = (walker->w_flags & MIE_WALKER_F_POSTORDER) != 0; - if (backward) { - if (postorder) { - return step_post_b(walker); - } - - return step_pre_b(walker); + if (!recursive) { + return backward ? step_flat_b(walker) : step_flat_f(walker); + } else if (postorder) { + return backward ? step_post_b(walker) : step_post_f(walker); + } else { + return backward ? step_pre_b(walker) : step_pre_f(walker); } - - if (postorder) { - return step_post_f(walker); - } - - return step_pre_f(walker); } -static enum mie_status prepare_preorder_traversal(struct mie_walker *walker) +static enum mie_status prepare_flat_traversal( + struct mie_walker *walker, const struct mie_op *op) +{ + bool backward = (walker->w_flags & MIE_WALKER_F_BACKWARD) != 0; + bool ok = false; + enum mie_walk_item_type target_type = MIE_WALK_ITEM_NONE; + enum mie_status status = MIE_SUCCESS; + + struct mie_walk_item root = {}; + root.i_op = (struct mie_op *)op; + root.i_type = MIE_WALK_ITEM_OP; + + if (walker->w_flags & MIE_WALKER_F_INCLUDE_REGIONS) { + target_type = MIE_WALK_ITEM_REGION; + } else if (walker->w_flags & MIE_WALKER_F_INCLUDE_BLOCKS) { + target_type = MIE_WALK_ITEM_BLOCK; + } else { + target_type = MIE_WALK_ITEM_OP; + } + + bool has_children = walk_item_has_children(&root); + if (!has_children) { + return MIE_ERR_NO_DATA; + } + + if (backward) { + ok = walk_item_get_last_child(walker, &root, &walker->w_region); + status = ok ? MIE_SUCCESS : MIE_ERR_NO_DATA; + } else { + ok = walk_item_get_first_child(walker, &root, &walker->w_region); + status = ok ? MIE_SUCCESS : MIE_ERR_NO_DATA; + } + + if (status != MIE_SUCCESS) { + return status; + } + + if (target_type == MIE_WALK_ITEM_REGION) { + walker->w_region.i_depth = 1; + return MIE_SUCCESS; + } + + has_children = walk_item_has_children(&walker->w_region); + if (!has_children) { + return MIE_ERR_NO_DATA; + } + + if (backward) { + ok = walk_item_get_last_child( + walker, &walker->w_region, &walker->w_block); + status = ok ? MIE_SUCCESS : MIE_ERR_NO_DATA; + } else { + ok = walk_item_get_first_child( + walker, &walker->w_region, &walker->w_block); + status = ok ? MIE_SUCCESS : MIE_ERR_NO_DATA; + } + + if (status != MIE_SUCCESS) { + return status; + } + + if (target_type == MIE_WALK_ITEM_BLOCK) { + walker->w_block.i_depth = 1; + return MIE_SUCCESS; + } + + has_children = walk_item_has_children(&walker->w_block); + if (!has_children) { + return MIE_ERR_NO_DATA; + } + + if (backward) { + ok = walk_item_get_last_child( + walker, &walker->w_block, &walker->w_op); + status = ok ? MIE_SUCCESS : MIE_ERR_NO_DATA; + } else { + ok = walk_item_get_first_child( + walker, &walker->w_block, &walker->w_op); + status = ok ? MIE_SUCCESS : MIE_ERR_NO_DATA; + } + + walker->w_op.i_depth = 1; + return status; +} + +static enum mie_status prepare_preorder_traversal( + struct mie_walker *walker, const struct mie_op *root) { struct mie_walk_item *item = malloc(sizeof *item); if (!item) { @@ -546,7 +704,7 @@ static enum mie_status prepare_preorder_traversal(struct mie_walker *walker) } memset(item, 0x0, sizeof *item); - item->i_op = walker->w_root; + item->i_op = (struct mie_op *)root; item->i_type = MIE_WALK_ITEM_OP; push_walk_item(walker, item); @@ -554,10 +712,11 @@ static enum mie_status prepare_preorder_traversal(struct mie_walker *walker) return MIE_SUCCESS; } -static enum mie_status prepare_postorder_traversal(struct mie_walker *walker) +static enum mie_status prepare_postorder_traversal( + struct mie_walker *walker, const struct mie_op *root) { struct mie_walk_item item = {}; - item.i_op = walker->w_root; + item.i_op = (struct mie_op *)root; item.i_type = MIE_WALK_ITEM_OP; push_walk_item(walker, &item); @@ -568,18 +727,17 @@ static enum mie_status prepare_postorder_traversal(struct mie_walker *walker) while (1) { struct mie_walk_item *current = current_item(walker); struct mie_walk_item child; - size_t nr_children = walk_item_get_nr_children(current); - if (!nr_children) { + bool has_children = walk_item_has_children(current); + if (!has_children) { break; } bool ok = false; if (backward) { - ok = walk_item_get_child( - walker, current, nr_children - 1, &child); + ok = walk_item_get_last_child(walker, current, &child); } else { - ok = walk_item_get_child(walker, current, 0, &child); + ok = walk_item_get_first_child(walker, current, &child); } if (!ok) { @@ -592,30 +750,26 @@ static enum mie_status prepare_postorder_traversal(struct mie_walker *walker) return ok ? MIE_SUCCESS : MIE_ERR_NO_DATA; } -struct mie_walker *mie_walker_begin(struct mie_op *op, enum mie_walker_flags flags) +void mie_walker_begin( + struct mie_walker *walker, const struct mie_op *op, + enum mie_walker_flags flags) { - struct mie_walker *out = malloc(sizeof *out); - if (!out) { - return NULL; - } + memset(walker, 0x0, sizeof *walker); - memset(out, 0x0, sizeof *out); + walker->w_flags = flags; - out->w_flags = flags; - out->w_root = op; - - if (flags & MIE_WALKER_F_POSTORDER) { - prepare_postorder_traversal(out); + if (!(flags & MIE_WALKER_F_RECURSIVE)) { + prepare_flat_traversal(walker, op); + } else if (flags & MIE_WALKER_F_POSTORDER) { + prepare_postorder_traversal(walker, op); } else { - prepare_preorder_traversal(out); + prepare_preorder_traversal(walker, op); } - struct mie_walk_item *cur = current_item(out); - if (should_ignore_item(out, cur)) { - mie_walker_step(out); + struct mie_walk_item *cur = current_item(walker); + if (cur && should_ignore_item(walker, cur)) { + mie_walker_step(walker); } - - return out; } void mie_walker_end(struct mie_walker *walker) @@ -631,9 +785,9 @@ enum mie_status mie_walker_step(struct mie_walker *walker) do { ok = step(walker); cur = current_item(walker); - } while (cur && should_ignore_item(walker, cur)); + } while (ok && cur && should_ignore_item(walker, cur)); - return cur ? MIE_SUCCESS : MIE_ERR_NO_DATA; + return (ok && cur) ? MIE_SUCCESS : MIE_ERR_NO_DATA; } struct mie_walk_item *mie_walker_get(struct mie_walker *walker)