mie: ir: walk: re-implement walker with a stack rather than a queue

This commit is contained in:
2026-01-23 22:50:05 +00:00
parent 89ebbcc462
commit d0ac8a9fed
2 changed files with 562 additions and 253 deletions

View File

@@ -1,6 +1,7 @@
#ifndef MIE_IR_WALK_H_ #ifndef MIE_IR_WALK_H_
#define MIE_IR_WALK_H_ #define MIE_IR_WALK_H_
#include <blue/core/queue.h>
#include <mie/misc.h> #include <mie/misc.h>
#include <mie/status.h> #include <mie/status.h>
#include <stddef.h> #include <stddef.h>
@@ -26,12 +27,25 @@ enum mie_walker_flags {
MIE_WALKER_F_INCLUDE_BLOCKS = 0x20u, MIE_WALKER_F_INCLUDE_BLOCKS = 0x20u,
}; };
struct mie_walker_item { enum mie_walk_item_type {
MIE_WALK_ITEM_NONE = 0,
MIE_WALK_ITEM_OP,
MIE_WALK_ITEM_BLOCK,
MIE_WALK_ITEM_REGION,
};
struct mie_walk_item {
int _f;
b_queue_entry _e;
enum mie_walk_item_type i_type;
size_t i_index;
size_t i_depth; size_t i_depth;
union {
struct mie_op *i_op; struct mie_op *i_op;
struct mie_block *i_block; struct mie_block *i_block;
struct mie_region *i_region; struct mie_region *i_region;
}; };
};
MIE_API struct mie_walker *mie_walker_begin( MIE_API struct mie_walker *mie_walker_begin(
struct mie_op *op, enum mie_walker_flags flags); struct mie_op *op, enum mie_walker_flags flags);
@@ -39,6 +53,6 @@ MIE_API void mie_walker_end(struct mie_walker *walker);
MIE_API enum mie_status mie_walker_step(struct mie_walker *walker); MIE_API enum mie_status mie_walker_step(struct mie_walker *walker);
MIE_API struct mie_walker_item *mie_walker_get(struct mie_walker *walker); MIE_API struct mie_walk_item *mie_walker_get(struct mie_walker *walker);
#endif #endif

View File

@@ -1,253 +1,595 @@
#include <mie/dialect/dialect.h>
#include <mie/ir/block.h> #include <mie/ir/block.h>
#include <mie/ir/op-definition.h>
#include <mie/ir/op.h> #include <mie/ir/op.h>
#include <mie/ir/region.h> #include <mie/ir/region.h>
#include <mie/ir/walk.h> #include <mie/ir/walk.h>
#include <stdio.h>
#define WALK_ITEM_F_CHILDREN_VISITED 0x01u
#define WALK_ITEM_F_VISITED 0x02u
#define ITEM_TYPE(f) ((f) & 0x0Fu) #define ITEM_TYPE(f) ((f) & 0x0Fu)
enum walk_schedule_item_flags {
SCHED_ITEM_F_NONE = 0,
SCHED_ITEM_F_OP = 0x01u,
SCHED_ITEM_F_BLOCK = 0x02u,
SCHED_ITEM_F_REGION = 0x04u,
SCHED_ITEM_F_VISITED = 0x10u,
SCHED_ITEM_F_CHILDREN_SCHEDULED = 0x20u,
};
struct walk_schedule_item {
enum walk_schedule_item_flags i_flags;
b_queue_entry i_entry;
size_t i_depth;
union {
struct mie_op *i_op;
struct mie_block *i_block;
struct mie_region *i_region;
};
};
struct mie_walker { struct mie_walker {
enum mie_walker_flags w_flags; enum mie_walker_flags w_flags;
struct mie_op *w_root; struct mie_op *w_root;
struct mie_walker_item w_cur; b_queue w_stack;
b_queue w_sched;
}; };
static struct walk_schedule_item *op_schedule_item_create(struct mie_op *op)
{
struct walk_schedule_item *out = malloc(sizeof *out);
if (!out) {
return NULL;
}
memset(out, 0x0, sizeof *out);
out->i_flags = SCHED_ITEM_F_OP;
out->i_op = op;
return out;
}
static struct walk_schedule_item *block_schedule_item_create(struct mie_block *block)
{
struct walk_schedule_item *out = malloc(sizeof *out);
if (!out) {
return NULL;
}
memset(out, 0x0, sizeof *out);
out->i_flags = SCHED_ITEM_F_BLOCK;
out->i_block = block;
return out;
}
static struct walk_schedule_item *region_schedule_item_create(
struct mie_region *region)
{
struct walk_schedule_item *out = malloc(sizeof *out);
if (!out) {
return NULL;
}
memset(out, 0x0, sizeof *out);
out->i_flags = SCHED_ITEM_F_REGION;
out->i_region = region;
return out;
}
static bool should_ignore_item( static bool should_ignore_item(
const struct mie_walker *walker, const struct walk_schedule_item *item) const struct mie_walker *walker, const struct mie_walk_item *item)
{ {
switch (ITEM_TYPE(item->i_flags)) { switch (item->i_type) {
case SCHED_ITEM_F_OP: case MIE_WALK_ITEM_OP:
return (walker->w_flags & MIE_WALKER_F_INCLUDE_OPS) == 0; return (walker->w_flags & MIE_WALKER_F_INCLUDE_OPS) == 0;
case SCHED_ITEM_F_BLOCK: case MIE_WALK_ITEM_BLOCK:
return (walker->w_flags & MIE_WALKER_F_INCLUDE_BLOCKS) == 0; return (walker->w_flags & MIE_WALKER_F_INCLUDE_BLOCKS) == 0;
case SCHED_ITEM_F_REGION: case MIE_WALK_ITEM_REGION:
return (walker->w_flags & MIE_WALKER_F_INCLUDE_REGIONS) == 0; return (walker->w_flags & MIE_WALKER_F_INCLUDE_REGIONS) == 0;
default: default:
return true; return true;
} }
} }
static void schedule_child( static void push_walk_item(
struct mie_walker *walker, struct walk_schedule_item *parent, struct mie_walker *walker, const struct mie_walk_item *item)
struct walk_schedule_item *child, b_queue_entry **ep)
{ {
#define REVERSE 0x04u struct mie_walk_item *i = malloc(sizeof *i);
if (!i) {
enum {
PREORDER = 0x01u,
PREORDER_REVERSE = PREORDER | REVERSE,
POSTORDER = 0x02u,
POSTORDER_REVERSE = POSTORDER | REVERSE,
} mode;
if (walker->w_flags & MIE_WALKER_F_POSTORDER) {
mode = POSTORDER;
} else {
mode = PREORDER;
}
if (walker->w_flags & MIE_WALKER_F_BACKWARD) {
mode |= REVERSE;
}
child->i_depth = parent->i_depth;
if (!should_ignore_item(walker, child)) {
child->i_depth++;
}
switch (mode) {
case PREORDER:
b_queue_insert_after(&walker->w_sched, &child->i_entry, *ep);
*ep = &child->i_entry;
break;
case PREORDER_REVERSE:
b_queue_insert_after(
&walker->w_sched, &child->i_entry, &parent->i_entry);
*ep = &parent->i_entry;
break;
case POSTORDER:
if (*ep == &parent->i_entry) {
b_queue_insert_before(
&walker->w_sched, &child->i_entry, *ep);
} else {
b_queue_insert_after(
&walker->w_sched, &child->i_entry, *ep);
}
*ep = &child->i_entry;
break;
case POSTORDER_REVERSE:
b_queue_insert_before(&walker->w_sched, &child->i_entry, *ep);
*ep = &child->i_entry;
break;
default:
return; return;
} }
#undef REVERSE memcpy(i, item, sizeof *i);
b_queue_push_back(&walker->w_stack, &i->_e);
} }
static enum mie_status schedule_children_of_region( static void pop_walk_item(struct mie_walker *walker)
struct mie_walker *walker, struct walk_schedule_item *item)
{ {
struct mie_region *region = item->i_region; b_queue_entry *entry = b_queue_pop_back(&walker->w_stack);
if (entry) {
b_queue_entry *tmp = &item->i_entry; struct mie_walk_item *item
= b_unbox(struct mie_walk_item, entry, _e);
for (size_t i = 0; i < MIE_VECTOR_COUNT(region->r_blocks); i++) { free(item);
struct mie_block *block = &region->r_blocks.items[i]; }
struct walk_schedule_item *child
= block_schedule_item_create(block);
schedule_child(walker, item, child, &tmp);
} }
return MIE_SUCCESS; static struct mie_walk_item *current_item(struct mie_walker *walker)
}
static enum mie_status schedule_children_of_block(
struct mie_walker *walker, struct walk_schedule_item *item)
{ {
struct mie_block *block = item->i_block; b_queue_entry *entry = b_queue_last(&walker->w_stack);
if (!entry) {
b_queue_entry *tmp = &item->i_entry; return NULL;
for (size_t i = 0; i < MIE_VECTOR_COUNT(block->b_ops); i++) {
struct mie_op *op = &block->b_ops.items[i];
struct walk_schedule_item *child = op_schedule_item_create(op);
schedule_child(walker, item, child, &tmp);
} }
return MIE_SUCCESS; struct mie_walk_item *item = b_unbox(struct mie_walk_item, entry, _e);
return item->i_type != MIE_WALK_ITEM_NONE ? item : NULL;
} }
static enum mie_status schedule_children_of_op( static struct mie_op *get_first_child(struct mie_walker *walker, struct mie_op *op)
struct mie_walker *walker, struct walk_schedule_item *item)
{ {
struct mie_op *op = item->i_op; bool backwards = (walker->w_flags & MIE_WALKER_F_BACKWARD) != 0;
b_queue_entry *tmp = &item->i_entry; while (1) {
if (MIE_VECTOR_COUNT(op->op_regions) == 0) {
for (size_t i = 0; i < MIE_VECTOR_COUNT(op->op_regions); i++) {
struct mie_region *region = &op->op_regions.items[i];
struct walk_schedule_item *child
= region_schedule_item_create(region);
schedule_child(walker, item, child, &tmp);
}
return MIE_SUCCESS;
}
static enum mie_status schedule_children(
struct mie_walker *walker, struct walk_schedule_item *item)
{
if (item->i_flags & SCHED_ITEM_F_CHILDREN_SCHEDULED) {
return MIE_SUCCESS;
}
enum mie_status status;
switch (ITEM_TYPE(item->i_flags)) {
case SCHED_ITEM_F_BLOCK:
status = schedule_children_of_block(walker, item);
break; break;
case SCHED_ITEM_F_REGION: }
status = schedule_children_of_region(walker, item);
size_t region_index
= backwards ? MIE_VECTOR_COUNT(op->op_regions) - 1 : 0;
struct mie_region *region = &op->op_regions.items[region_index];
if (MIE_VECTOR_COUNT(region->r_blocks) == 0) {
break; break;
case SCHED_ITEM_F_OP: }
status = schedule_children_of_op(walker, item);
size_t block_index
= backwards ? MIE_VECTOR_COUNT(region->r_blocks) - 1 : 0;
struct mie_block *block = &region->r_blocks.items[block_index];
if (MIE_VECTOR_COUNT(block->b_ops) == 0) {
break;
}
size_t op_index
= backwards ? MIE_VECTOR_COUNT(block->b_ops) - 1 : 0;
op = &block->b_ops.items[op_index];
}
return op;
}
static size_t walk_item_get_nr_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);
case MIE_WALK_ITEM_BLOCK:
return MIE_VECTOR_COUNT(item->i_block->b_ops);
case MIE_WALK_ITEM_REGION:
return MIE_VECTOR_COUNT(item->i_region->r_blocks);
default:
return 0;
}
}
static bool should_correct_depth(
struct mie_walker *walker, const struct mie_walk_item *item)
{
if (should_ignore_item(walker, item)) {
return true;
}
size_t temp = 0;
switch (item->i_type) {
case MIE_WALK_ITEM_BLOCK:
return false; //(walker->w_flags & MIE_WALKER_F_INCLUDE_OPS) == 0;
default:
break;
}
return false;
}
static bool walk_item_get_child(
struct mie_walker *walker, const struct mie_walk_item *item,
size_t index, struct mie_walk_item *child)
{
bool ok = false;
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;
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;
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;
break; break;
default: default:
status = MIE_ERR_BAD_STATE;
break; break;
} }
item->i_flags |= SCHED_ITEM_F_CHILDREN_SCHEDULED; if (!ok) {
return false;
}
child->i_depth = item->i_depth + 1;
child->i_index = index;
if (should_correct_depth(walker, item)) {
child->i_depth--;
}
return true;
}
static bool walk_item_get_next_sibling(
const struct mie_walk_item *item, struct mie_walk_item *sibling)
{
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;
struct mie_region *parent_r = NULL;
struct mie_block *parent_b = NULL;
struct mie_op *parent_o = NULL;
switch (item->i_type) {
case MIE_WALK_ITEM_OP:
parent_b = item->i_op->op_container;
if (!parent_b) {
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;
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;
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;
default:
return false;
}
}
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) {
return false;
}
sibling->i_depth = item->i_depth;
sibling->i_type = item->i_type;
sibling->i_index = item->i_index - 1;
struct mie_region *parent_r = NULL;
struct mie_block *parent_b = NULL;
struct mie_op *parent_o = NULL;
switch (item->i_type) {
case MIE_WALK_ITEM_OP:
parent_b = item->i_op->op_container;
if (!parent_b) {
return false;
}
sibling->i_op = &parent_b->b_ops.items[item->i_index - 1];
return true;
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;
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;
default:
return false;
}
}
static void print_stack(struct mie_walker *walker)
{
b_queue_entry *entry = b_queue_last(&walker->w_stack);
while (entry) {
struct mie_walk_item *item
= b_unbox(struct mie_walk_item, entry, _e);
switch (item->i_type) {
case MIE_WALK_ITEM_OP:
printf("* %zu: op %p", item->i_depth, item->i_op);
if (item->i_op->op_flags & MIE_OP_F_OP_RESOLVED) {
printf(" %s.%s", item->i_op->op_dialect->d_name,
item->i_op->op_info->op_name);
} else {
printf(" %s", item->i_op->op_name);
}
break;
case MIE_WALK_ITEM_BLOCK:
printf("* %zu: block %p %s", item->i_depth,
item->i_block, item->i_block->b_name.n_str);
break;
case MIE_WALK_ITEM_REGION:
printf("* %zu: region %p", item->i_depth, item->i_region);
break;
default:
printf(" unknown");
break;
}
printf("\n");
entry = b_queue_prev(entry);
}
}
static bool step_pre_f(struct mie_walker *walker)
{
/* forward, pre-order traversal:
* if this item has children, we need to visit the first one.
* if this item has no children, we need to visit the next sibling.
* if this is the last sibling, step up until we find an item that
* has a next sibling.
* if no item is found, we are done. */
struct mie_walk_item *item = current_item(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);
if (ok) {
push_walk_item(walker, &next);
}
return ok;
}
if (walk_item_get_next_sibling(item, &next)) {
pop_walk_item(walker);
push_walk_item(walker, &next);
return true;
}
static int i = 0;
while (1) {
pop_walk_item(walker);
struct mie_walk_item *parent = current_item(walker);
if (!parent) {
return false;
}
ok = walk_item_get_next_sibling(parent, &next);
if (ok) {
pop_walk_item(walker);
push_walk_item(walker, &next);
break;
}
}
return ok;
}
static bool step_pre_b(struct mie_walker *walker)
{
/* backward, pre-order traversal:
* if this item has children, we need to visit the last one.
* if this item has no children, we need to visit the previous sibling.
* if this is the first sibling, step up until we find an item that
* has a previous sibling.
* if no item is found, we are done. */
struct mie_walk_item *item = current_item(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);
if (ok) {
push_walk_item(walker, &next);
}
return ok;
}
if (walk_item_get_prev_sibling(item, &next)) {
pop_walk_item(walker);
push_walk_item(walker, &next);
return true;
}
static int i = 0;
while (1) {
pop_walk_item(walker);
struct mie_walk_item *parent = current_item(walker);
if (!parent) {
return false;
}
ok = walk_item_get_prev_sibling(parent, &next);
if (ok) {
pop_walk_item(walker);
push_walk_item(walker, &next);
break;
}
}
return ok;
}
static bool step_post_f(struct mie_walker *walker)
{
/* forward, post-order traversal:
* if this item has children:
* if they have already been visited, visit the item itself
* if they haven't been visited yet, visit the first one.
* if this item has a next sibling, move to the sibling and goto step 1.
* if this item is the last child, we need to visit the parent next. */
struct mie_walk_item *item = current_item(walker);
item->_f |= WALK_ITEM_F_VISITED;
struct mie_walk_item next;
bool ok = false;
while (1) {
item = current_item(walker);
size_t nr_children = walk_item_get_nr_children(item);
if (nr_children > 0 && !(item->_f & WALK_ITEM_F_CHILDREN_VISITED)) {
ok = walk_item_get_child(walker, item, 0, &next);
if (ok) {
push_walk_item(walker, &next);
}
return ok;
}
if (nr_children == 0 && !(item->_f & WALK_ITEM_F_VISITED)) {
return true;
}
if (walk_item_get_next_sibling(item, &next)) {
pop_walk_item(walker);
push_walk_item(walker, &next);
continue;
}
pop_walk_item(walker);
struct mie_walk_item *parent = current_item(walker);
if (parent) {
parent->_f |= WALK_ITEM_F_CHILDREN_VISITED;
}
return parent != NULL;
}
}
static bool step_post_b(struct mie_walker *walker)
{
/* backward, post-order traversal:
* if this item has children:
* if they have already been visited, visit the item itself
* if they haven't been visited yet, visit the last one.
* if this item has a previous sibling, move to the sibling and goto step 1.
* if this item is the first child, we need to visit the parent next. */
struct mie_walk_item *item = current_item(walker);
item->_f |= WALK_ITEM_F_VISITED;
struct mie_walk_item next;
bool ok = false;
while (1) {
item = current_item(walker);
size_t nr_children = walk_item_get_nr_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 (ok) {
push_walk_item(walker, &next);
}
return ok;
}
if (nr_children == 0 && !(item->_f & WALK_ITEM_F_VISITED)) {
return true;
}
if (walk_item_get_prev_sibling(item, &next)) {
pop_walk_item(walker);
push_walk_item(walker, &next);
continue;
}
pop_walk_item(walker);
struct mie_walk_item *parent = current_item(walker);
if (parent) {
parent->_f |= WALK_ITEM_F_CHILDREN_VISITED;
}
return parent != NULL;
}
}
static bool step(struct mie_walker *walker)
{
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 (postorder) {
return step_post_f(walker);
}
return step_pre_f(walker);
}
static enum mie_status prepare_preorder_traversal(struct mie_walker *walker)
{
struct mie_walk_item *item = malloc(sizeof *item);
if (!item) {
return MIE_ERR_NO_MEMORY;
}
memset(item, 0x0, sizeof *item);
item->i_op = walker->w_root;
item->i_type = MIE_WALK_ITEM_OP;
push_walk_item(walker, item);
return MIE_SUCCESS; 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)
{ {
b_queue_entry *cur = b_queue_last(&walker->w_sched); struct mie_walk_item item = {};
while (cur) { item.i_op = walker->w_root;
struct walk_schedule_item *item item.i_type = MIE_WALK_ITEM_OP;
= b_unbox(struct walk_schedule_item, cur, i_entry);
schedule_children(walker, item);
cur = b_queue_prev(cur); push_walk_item(walker, &item);
bool backward = walker->w_flags & MIE_WALKER_F_BACKWARD;
bool ok = false;
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) {
break;
} }
return MIE_SUCCESS; bool ok = false;
if (backward) {
ok = walk_item_get_child(
walker, current, nr_children - 1, &child);
} else {
ok = walk_item_get_child(walker, current, 0, &child);
}
if (!ok) {
break;
}
push_walk_item(walker, &child);
}
return ok ? MIE_SUCCESS : MIE_ERR_NO_DATA;
} }
struct mie_walker *mie_walker_begin(struct mie_op *op, enum mie_walker_flags flags) struct mie_walker *mie_walker_begin(struct mie_op *op, enum mie_walker_flags flags)
@@ -262,11 +604,15 @@ struct mie_walker *mie_walker_begin(struct mie_op *op, enum mie_walker_flags fla
out->w_flags = flags; out->w_flags = flags;
out->w_root = op; out->w_root = op;
struct walk_schedule_item *item = op_schedule_item_create(op);
b_queue_push_back(&out->w_sched, &item->i_entry);
if (flags & MIE_WALKER_F_POSTORDER) { if (flags & MIE_WALKER_F_POSTORDER) {
prepare_postorder_traversal(out); prepare_postorder_traversal(out);
} else {
prepare_preorder_traversal(out);
}
struct mie_walk_item *cur = current_item(out);
if (should_ignore_item(out, cur)) {
mie_walker_step(out);
} }
return out; return out;
@@ -274,74 +620,23 @@ struct mie_walker *mie_walker_begin(struct mie_op *op, enum mie_walker_flags fla
void mie_walker_end(struct mie_walker *walker) void mie_walker_end(struct mie_walker *walker)
{ {
} /* TODO */
static struct walk_schedule_item *current_item(struct mie_walker *walker)
{
b_queue_entry *top = b_queue_first(&walker->w_sched);
if (!top) {
return NULL;
}
return b_unbox(struct walk_schedule_item, top, i_entry);
}
static enum mie_status step(struct mie_walker *walker)
{
struct walk_schedule_item *cur = current_item(walker);
if (!cur) {
return MIE_ERR_NO_DATA;
}
if (walker->w_flags & MIE_WALKER_F_RECURSIVE || cur->i_depth == 0) {
schedule_children(walker, cur);
}
b_queue_delete(&walker->w_sched, &cur->i_entry);
free(cur);
if (!current_item(walker)) {
return MIE_ERR_NO_DATA;
}
return MIE_SUCCESS;
} }
enum mie_status mie_walker_step(struct mie_walker *walker) enum mie_status mie_walker_step(struct mie_walker *walker)
{ {
struct walk_schedule_item *cur = current_item(walker); struct mie_walk_item *cur = current_item(walker);
bool ok = false;
do { do {
step(walker); ok = step(walker);
cur = current_item(walker); cur = current_item(walker);
} while (cur && should_ignore_item(walker, cur)); } while (cur && should_ignore_item(walker, cur));
return cur ? MIE_SUCCESS : MIE_ERR_NO_DATA; return cur ? MIE_SUCCESS : MIE_ERR_NO_DATA;
} }
struct mie_walker_item *mie_walker_get(struct mie_walker *walker) struct mie_walk_item *mie_walker_get(struct mie_walker *walker)
{ {
struct walk_schedule_item *cur = current_item(walker); return current_item(walker);
if (!cur) {
return NULL;
}
memset(&walker->w_cur, 0x0, sizeof walker->w_cur);
walker->w_cur.i_depth = cur->i_depth;
switch (ITEM_TYPE(cur->i_flags)) {
case SCHED_ITEM_F_OP:
walker->w_cur.i_op = cur->i_op;
break;
case SCHED_ITEM_F_BLOCK:
walker->w_cur.i_block = cur->i_block;
break;
case SCHED_ITEM_F_REGION:
walker->w_cur.i_region = cur->i_region;
break;
default:
return NULL;
}
return &walker->w_cur;
} }