From 28d4b456a582c1388fc3dde45e98cc97389485dc Mon Sep 17 00:00:00 2001 From: Vasily Khoruzhick Date: Sun, 18 Aug 2019 23:37:23 -0700 Subject: [PATCH] lima/ppir: add control flow support This commit adds support for nir_jump_instr, if and loop nir_cf_nodes. Tested-by: Andreas Baierl Reviewed-by: Qiang Yu Reviewed-by: Erico Nunes Signed-off-by: Vasily Khoruzhick --- src/gallium/drivers/lima/ir/pp/codegen.c | 12 ++- src/gallium/drivers/lima/ir/pp/instr.c | 6 +- src/gallium/drivers/lima/ir/pp/lower.c | 22 ++-- src/gallium/drivers/lima/ir/pp/nir.c | 130 +++++++++++++++++++++-- src/gallium/drivers/lima/ir/pp/node.c | 17 ++- src/gallium/drivers/lima/ir/pp/ppir.h | 4 + 6 files changed, 168 insertions(+), 23 deletions(-) diff --git a/src/gallium/drivers/lima/ir/pp/codegen.c b/src/gallium/drivers/lima/ir/pp/codegen.c index 4b1c48dffa3..f08f83a9f43 100644 --- a/src/gallium/drivers/lima/ir/pp/codegen.c +++ b/src/gallium/drivers/lima/ir/pp/codegen.c @@ -558,6 +558,7 @@ static void ppir_codegen_encode_branch(ppir_node *node, void *code) ppir_codegen_field_branch *b = code; ppir_branch_node *branch; ppir_instr *target_instr; + ppir_block *target; if (node->op == ppir_op_discard) { ppir_codegen_encode_discard(node, code); return; @@ -586,7 +587,16 @@ static void ppir_codegen_encode_branch(ppir_node *node, void *code) assert(false); } - target_instr = list_first_entry(&branch->target->instr_list, ppir_instr, list); + target = branch->target; + while (list_empty(&target->instr_list)) { + if (!target->list.next) + break; + target = LIST_ENTRY(ppir_block, target->list.next, list); + } + + assert(!list_empty(&target->instr_list)); + + target_instr = list_first_entry(&target->instr_list, ppir_instr, list); b->branch.target = target_instr->offset - node->instr->offset; b->branch.next_count = target_instr->encode_size; } diff --git a/src/gallium/drivers/lima/ir/pp/instr.c b/src/gallium/drivers/lima/ir/pp/instr.c index 474f9ca8cab..74b6e5fbaea 100644 --- a/src/gallium/drivers/lima/ir/pp/instr.c +++ b/src/gallium/drivers/lima/ir/pp/instr.c @@ -273,6 +273,7 @@ void ppir_instr_print_list(ppir_compiler *comp) printf("const0|1\n"); list_for_each_entry(ppir_block, block, &comp->block_list, list) { + printf("-------block %3d-------\n", block->index); list_for_each_entry(ppir_instr, instr, &block->instr_list, list) { printf("%c%03d: ", instr->is_end ? '*' : ' ', instr->index); for (int i = 0; i < PPIR_INSTR_SLOT_NUM; i++) { @@ -291,8 +292,8 @@ void ppir_instr_print_list(ppir_compiler *comp) } printf("\n"); } - printf("------------------------\n"); } + printf("===========================\n"); } static void ppir_instr_print_sub(ppir_instr *instr) @@ -325,12 +326,13 @@ void ppir_instr_print_dep(ppir_compiler *comp) printf("======ppir instr depend======\n"); list_for_each_entry(ppir_block, block, &comp->block_list, list) { + printf("-------block %3d-------\n", block->index); list_for_each_entry(ppir_instr, instr, &block->instr_list, list) { if (ppir_instr_is_root(instr)) { ppir_instr_print_sub(instr); printf("\n"); } } - printf("------------------------\n"); } + printf("=============================\n"); } diff --git a/src/gallium/drivers/lima/ir/pp/lower.c b/src/gallium/drivers/lima/ir/pp/lower.c index cd175cc0879..5aca32e683e 100644 --- a/src/gallium/drivers/lima/ir/pp/lower.c +++ b/src/gallium/drivers/lima/ir/pp/lower.c @@ -227,22 +227,20 @@ static bool ppir_lower_select(ppir_block *block, ppir_node *node) move_dest->pipeline = ppir_pipeline_reg_fmul; move_dest->write_mask = 1; - ppir_node_foreach_pred(node, dep) { - ppir_node *pred = dep->pred; - ppir_dest *dest = ppir_node_get_dest(pred); - if (ppir_node_target_equal(alu->src, dest)) { - ppir_node_replace_pred(dep, move); - ppir_node_add_dep(move, pred); - } - } + ppir_node *pred = alu->src[0].node; + ppir_dep *dep = ppir_dep_for_pred(node, pred); + if (dep) + ppir_node_replace_pred(dep, move); + else + ppir_node_add_dep(node, move); - /* move must be the first pred of select node which make sure - * the float mul slot is free when node to instr - */ - assert(ppir_node_first_pred(node) == move); + /* pred can be a register */ + if (pred) + ppir_node_add_dep(move, pred); src->swizzle[0] = 0; ppir_node_target_assign(alu->src, move); + return true; } diff --git a/src/gallium/drivers/lima/ir/pp/nir.c b/src/gallium/drivers/lima/ir/pp/nir.c index 831c50b3cd0..4852e55a8b6 100644 --- a/src/gallium/drivers/lima/ir/pp/nir.c +++ b/src/gallium/drivers/lima/ir/pp/nir.c @@ -463,8 +463,39 @@ static ppir_block *ppir_get_block(ppir_compiler *comp, nir_block *nblock) static ppir_node *ppir_emit_jump(ppir_block *block, nir_instr *ni) { - ppir_error("nir_jump_instr not support\n"); - return NULL; + ppir_node *node; + ppir_compiler *comp = block->comp; + ppir_branch_node *branch; + ppir_block *jump_block; + nir_jump_instr *jump = nir_instr_as_jump(ni); + + switch (jump->type) { + case nir_jump_break: { + assert(comp->current_block->successors[0]); + assert(!comp->current_block->successors[1]); + jump_block = comp->current_block->successors[0]; + } + break; + case nir_jump_continue: + jump_block = comp->loop_cont_block; + break; + default: + ppir_error("nir_jump_instr not support\n"); + return NULL; + } + + assert(jump_block != NULL); + + node = ppir_node_create(block, ppir_op_branch, -1, 0); + if (!node) + return NULL; + branch = ppir_node_to_branch(node); + + /* Unconditional */ + branch->num_src = 0; + branch->target = jump_block; + + return node; } static ppir_node *(*ppir_emit_instr[nir_instr_type_phi])(ppir_block *, nir_instr *) = { @@ -494,6 +525,8 @@ static bool ppir_emit_block(ppir_compiler *comp, nir_block *nblock) { ppir_block *block = ppir_get_block(comp, nblock); + comp->current_block = block; + list_addtail(&block->list, &comp->block_list); nir_foreach_instr(instr, nblock) { @@ -508,16 +541,99 @@ static bool ppir_emit_block(ppir_compiler *comp, nir_block *nblock) return true; } -static bool ppir_emit_if(ppir_compiler *comp, nir_if *nif) +static bool ppir_emit_cf_list(ppir_compiler *comp, struct exec_list *list); + +static bool ppir_emit_if(ppir_compiler *comp, nir_if *if_stmt) { - ppir_error("if nir_cf_node not support\n"); - return false; + ppir_node *node; + ppir_branch_node *else_branch, *after_branch; + nir_block *nir_else_block = nir_if_first_else_block(if_stmt); + bool empty_else_block = + (nir_else_block == nir_if_last_else_block(if_stmt) && + exec_list_is_empty(&nir_else_block->instr_list)); + ppir_block *block = comp->current_block; + + node = ppir_node_create(block, ppir_op_branch, -1, 0); + if (!node) + return false; + else_branch = ppir_node_to_branch(node); + ppir_node_add_src(block->comp, node, &else_branch->src[0], + &if_stmt->condition, 1); + else_branch->num_src = 1; + /* Negate condition to minimize branching. We're generating following: + * current_block: { ...; if (!statement) branch else_block; } + * then_block: { ...; branch after_block; } + * else_block: { ... } + * after_block: { ... } + * + * or if else list is empty: + * block: { if (!statement) branch else_block; } + * then_block: { ... } + * else_block: after_block: { ... } + */ + else_branch->negate = true; + list_addtail(&else_branch->node.list, &block->node_list); + + ppir_emit_cf_list(comp, &if_stmt->then_list); + if (empty_else_block) { + nir_block *nblock = nir_if_last_else_block(if_stmt); + assert(nblock->successors[0]); + assert(!nblock->successors[1]); + else_branch->target = ppir_get_block(comp, nblock->successors[0]); + /* Add empty else block to the list */ + list_addtail(&block->successors[1]->list, &comp->block_list); + return true; + } + + else_branch->target = ppir_get_block(comp, nir_if_first_else_block(if_stmt)); + + nir_block *last_then_block = nir_if_last_then_block(if_stmt); + assert(last_then_block->successors[0]); + assert(!last_then_block->successors[1]); + block = ppir_get_block(comp, last_then_block); + node = ppir_node_create(block, ppir_op_branch, -1, 0); + if (!node) + return false; + after_branch = ppir_node_to_branch(node); + /* Unconditional */ + after_branch->num_src = 0; + after_branch->target = ppir_get_block(comp, last_then_block->successors[0]); + /* Target should be after_block, will fixup later */ + list_addtail(&after_branch->node.list, &block->node_list); + + ppir_emit_cf_list(comp, &if_stmt->else_list); + + return true; } static bool ppir_emit_loop(ppir_compiler *comp, nir_loop *nloop) { - ppir_error("loop nir_cf_node not support\n"); - return false; + ppir_block *save_loop_cont_block = comp->loop_cont_block; + ppir_block *block; + ppir_branch_node *loop_branch; + nir_block *loop_last_block; + ppir_node *node; + + comp->loop_cont_block = ppir_get_block(comp, nir_loop_first_block(nloop)); + + ppir_emit_cf_list(comp, &nloop->body); + + loop_last_block = nir_loop_last_block(nloop); + block = ppir_get_block(comp, loop_last_block); + node = ppir_node_create(block, ppir_op_branch, -1, 0); + if (!node) + return false; + loop_branch = ppir_node_to_branch(node); + /* Unconditional */ + loop_branch->num_src = 0; + loop_branch->target = comp->loop_cont_block; + list_addtail(&loop_branch->node.list, &block->node_list); + + comp->loop_cont_block = save_loop_cont_block; + + comp->num_loops++; + + return true; } static bool ppir_emit_function(ppir_compiler *comp, nir_function_impl *nfunc) diff --git a/src/gallium/drivers/lima/ir/pp/node.c b/src/gallium/drivers/lima/ir/pp/node.c index 59635df3cdf..db141cac5c1 100644 --- a/src/gallium/drivers/lima/ir/pp/node.c +++ b/src/gallium/drivers/lima/ir/pp/node.c @@ -469,6 +469,21 @@ void ppir_node_replace_pred(ppir_dep *dep, ppir_node *new_pred) list_addtail(&dep->succ_link, &new_pred->succ_list); } +ppir_dep *ppir_dep_for_pred(ppir_node *node, ppir_node *pred) +{ + if (!pred) + return NULL; + + if (node->block != pred->block) + return NULL; + + ppir_node_foreach_pred(node, dep) { + if (dep->pred == pred) + return dep; + } + return NULL; +} + void ppir_node_replace_all_succ(ppir_node *dst, ppir_node *src) { ppir_node_foreach_succ_safe(src, dep) { @@ -573,7 +588,7 @@ void ppir_node_print_prog(ppir_compiler *comp) printf("========prog========\n"); list_for_each_entry(ppir_block, block, &comp->block_list, list) { - printf("-------block------\n"); + printf("-------block %3d-------\n", block->index); list_for_each_entry(ppir_node, node, &block->node_list, list) { if (ppir_node_is_root(node)) ppir_node_print_node(node, 0); diff --git a/src/gallium/drivers/lima/ir/pp/ppir.h b/src/gallium/drivers/lima/ir/pp/ppir.h index db8087ede62..462cd93538a 100644 --- a/src/gallium/drivers/lima/ir/pp/ppir.h +++ b/src/gallium/drivers/lima/ir/pp/ppir.h @@ -369,6 +369,9 @@ typedef struct ppir_compiler { int num_fills; ppir_block *discard_block; + ppir_block *current_block; + ppir_block *loop_break_block; + ppir_block *loop_cont_block; } ppir_compiler; void *ppir_node_create(ppir_block *block, ppir_op op, int index, unsigned mask); @@ -379,6 +382,7 @@ void ppir_node_print_prog(ppir_compiler *comp); void ppir_node_replace_child(ppir_node *parent, ppir_node *old_child, ppir_node *new_child); void ppir_node_replace_all_succ(ppir_node *dst, ppir_node *src); void ppir_node_replace_pred(ppir_dep *dep, ppir_node *new_pred); +ppir_dep *ppir_dep_for_pred(ppir_node *node, ppir_node *pred); ppir_node *ppir_node_clone(ppir_block *block, ppir_node *node); static inline bool ppir_node_is_root(ppir_node *node) -- 2.30.2