diff --git a/src/freedreno/ir3/ir3.c b/src/freedreno/ir3/ir3.c index 54e772a9cac..44cccc8cd05 100644 --- a/src/freedreno/ir3/ir3.c +++ b/src/freedreno/ir3/ir3.c @@ -586,6 +586,94 @@ ir3_block_get_last_phi(struct ir3_block *block) return last_phi; } +struct ir3_instruction * +ir3_find_shpe(struct ir3 *ir) +{ + if (!ir3_has_preamble(ir)) { + return NULL; + } + + foreach_block (block, &ir->block_list) { + struct ir3_instruction *last = ir3_block_get_last_non_terminator(block); + + if (last && last->opc == OPC_SHPE) { + return last; + } + } + + unreachable("preamble without shpe"); +} + +struct ir3_instruction * +ir3_create_empty_preamble(struct ir3 *ir) +{ + assert(!ir3_has_preamble(ir)); + + struct ir3_block *main_start_block = ir3_start_block(ir); + + /* Create a preamble CFG similar to what the frontend would generate. Note + * that the empty else_block is important for ir3_after_preamble to work. + * + * shps_block: + * if (shps) { + * getone_block: + * if (getone) { + * body_block: + * shpe + * } + * } else { + * else_block: + * } + * main_start_block: + */ + struct ir3_block *shps_block = ir3_block_create(ir); + struct ir3_block *getone_block = ir3_block_create(ir); + struct ir3_block *body_block = ir3_block_create(ir); + struct ir3_block *else_block = ir3_block_create(ir); + list_add(&else_block->node, &ir->block_list); + list_add(&body_block->node, &ir->block_list); + list_add(&getone_block->node, &ir->block_list); + list_add(&shps_block->node, &ir->block_list); + + struct ir3_builder b = ir3_builder_at(ir3_after_block(shps_block)); + ir3_SHPS(&b); + shps_block->successors[0] = getone_block; + ir3_block_add_predecessor(getone_block, shps_block); + ir3_block_link_physical(shps_block, getone_block); + shps_block->successors[1] = else_block; + ir3_block_add_predecessor(else_block, shps_block); + ir3_block_link_physical(shps_block, else_block); + + b.cursor = ir3_after_block(getone_block); + ir3_GETONE(&b); + getone_block->divergent_condition = true; + getone_block->successors[0] = body_block; + ir3_block_add_predecessor(body_block, getone_block); + ir3_block_link_physical(getone_block, body_block); + getone_block->successors[1] = main_start_block; + ir3_block_add_predecessor(main_start_block, getone_block); + ir3_block_link_physical(getone_block, main_start_block); + + b.cursor = ir3_after_block(body_block); + struct ir3_instruction *shpe = ir3_SHPE(&b); + shpe->barrier_class = shpe->barrier_conflict = IR3_BARRIER_CONST_W; + array_insert(body_block, body_block->keeps, shpe); + ir3_JUMP(&b); + body_block->successors[0] = main_start_block; + ir3_block_add_predecessor(main_start_block, body_block); + ir3_block_link_physical(body_block, main_start_block); + + b.cursor = ir3_after_block(else_block); + ir3_JUMP(&b); + else_block->successors[0] = main_start_block; + ir3_block_add_predecessor(main_start_block, else_block); + ir3_block_link_physical(else_block, main_start_block); + + main_start_block->reconvergence_point = true; + + return shpe; +} + void ir3_block_add_predecessor(struct ir3_block *block, struct ir3_block *pred) { diff --git a/src/freedreno/ir3/ir3.h b/src/freedreno/ir3/ir3.h index 283b81c7227..86caefc7d59 100644 --- a/src/freedreno/ir3/ir3.h +++ b/src/freedreno/ir3/ir3.h @@ -811,6 +811,17 @@ ir3_after_preamble(struct ir3 *ir) return block; } +static inline bool +ir3_has_preamble(struct ir3 *ir) +{ + return ir3_start_block(ir) != ir3_after_preamble(ir); +} + +struct ir3_instruction *ir3_find_shpe(struct ir3 *ir); + +/* Create an empty preamble and return shpe. */ +struct ir3_instruction *ir3_create_empty_preamble(struct ir3 *ir); + void ir3_block_add_predecessor(struct ir3_block *block, struct ir3_block *pred); void ir3_block_link_physical(struct ir3_block *pred, struct ir3_block *succ); void ir3_block_remove_predecessor(struct ir3_block *block,