v6: fix loops with blocks at the end nothing points to skip blocks with no instructions and no predecessors
Signed-off-by: Karol Herbst <kher...@redhat.com> --- .../drivers/nouveau/codegen/nv50_ir_from_nir.cpp | 270 ++++++++++++++++++++- 1 file changed, 268 insertions(+), 2 deletions(-) diff --git a/src/gallium/drivers/nouveau/codegen/nv50_ir_from_nir.cpp b/src/gallium/drivers/nouveau/codegen/nv50_ir_from_nir.cpp index 538c85b6a69..a10038f9a88 100644 --- a/src/gallium/drivers/nouveau/codegen/nv50_ir_from_nir.cpp +++ b/src/gallium/drivers/nouveau/codegen/nv50_ir_from_nir.cpp @@ -55,8 +55,10 @@ private: typedef decltype(nir_ssa_def().index) NirSSADefIdx; typedef decltype(nir_ssa_def().bit_size) NirSSADefBitSize; typedef std::unordered_map<NirSSADefIdx, LValues> NirDefMap; + typedef std::unordered_map<decltype(nir_block().index), BasicBlock*> NirBlockMap; LValues& convert(nir_alu_dest *); + BasicBlock* convert(nir_block *); LValues& convert(nir_dest *); LValues& convert(nir_register *); LValues& convert(nir_ssa_def *); @@ -98,15 +100,46 @@ private: bool assignSlots(); bool parseNIR(); + bool visit(nir_block *); + bool visit(nir_cf_node *); + bool visit(nir_function *); + bool visit(nir_if *); + bool visit(nir_instr *); + bool visit(nir_jump_instr *); + bool visit(nir_loop *); + nir_shader *nir; NirDefMap ssaDefs; NirDefMap regDefs; + NirBlockMap blocks; + unsigned int curLoopDepth; + + BasicBlock *exit; + + union { + struct { + Value *position; + } fp; + }; }; Converter::Converter(Program *prog, nir_shader *nir, nv50_ir_prog_info *info) : ConverterCommon(prog, info), - nir(nir) {} + nir(nir), + curLoopDepth(0) {} + +BasicBlock * +Converter::convert(nir_block *block) +{ + NirBlockMap::iterator it = blocks.find(block->index); + if (it != blocks.end()) + return (*it).second; + + BasicBlock *bb = new BasicBlock(func); + blocks[block->index] = bb; + return bb; +} bool Converter::isFloatType(nir_alu_type type) @@ -1039,6 +1072,234 @@ Converter::parseNIR() return true; } +bool +Converter::visit(nir_function *function) +{ + /* we only support emiting the main function for now */ + assert(!strcmp(function->name, "main")); + assert(function->impl); + + /* usually the blocks will set everything up, but main is special */ + BasicBlock *entry = new BasicBlock(prog->main); + exit = new BasicBlock(prog->main); + blocks[nir_start_block(function->impl)->index] = entry; + prog->main->setEntry(entry); + prog->main->setExit(exit); + + setPosition(entry, true); + + switch (prog->getType()) { + case Program::TYPE_TESSELLATION_CONTROL: + outBase = mkOp2v( + OP_SUB, TYPE_U32, getSSA(), + mkOp1v(OP_RDSV, TYPE_U32, getSSA(), mkSysVal(SV_LANEID, 0)), + mkOp1v(OP_RDSV, TYPE_U32, getSSA(), mkSysVal(SV_INVOCATION_ID, 0))); + break; + case Program::TYPE_FRAGMENT: { + Symbol *sv = mkSysVal(SV_POSITION, 3); + fragCoord[3] = mkOp1v(OP_RDSV, TYPE_F32, getSSA(), sv); + fp.position = mkOp1v(OP_RCP, TYPE_F32, fragCoord[3], fragCoord[3]); + break; + } + default: + break; + } + + nir_index_ssa_defs(function->impl); + foreach_list_typed(nir_cf_node, node, node, &function->impl->body) { + if (!visit(node)) + return false; + } + + bb->cfg.attach(&exit->cfg, Graph::Edge::TREE); + setPosition(exit, true); + + /* TODO: for non main function this needs to be a OP_RETURN */ + mkOp(OP_EXIT, TYPE_NONE, NULL)->terminator = 1; + return true; +} + +bool +Converter::visit(nir_cf_node *node) +{ + switch (node->type) { + case nir_cf_node_block: + if (!visit(nir_cf_node_as_block(node))) + return false; + break; + case nir_cf_node_if: + if (!visit(nir_cf_node_as_if(node))) + return false; + break; + case nir_cf_node_loop: + if (!visit(nir_cf_node_as_loop(node))) + return false; + break; + default: + ERROR("unknown nir_cf_node type %u\n", node->type); + return false; + } + return true; +} + +bool +Converter::visit(nir_block *block) +{ + if (!block->predecessors->entries && block->instr_list.is_empty()) + return true; + + BasicBlock *bb = convert(block); + + setPosition(bb, true); + nir_foreach_instr(insn, block) { + if (!visit(insn)) + return false; + } + return true; +} + +bool +Converter::visit(nir_if *nif) +{ + DataType sType = getSType(nif->condition, false, false); + Value *src = getSrc(&nif->condition, 0); + + nir_block *lastThen = nir_if_last_then_block(nif); + nir_block *lastElse = nir_if_last_else_block(nif); + + assert(!lastThen->successors[1]); + assert(!lastElse->successors[1]); + + BasicBlock *ifBB = convert(nir_if_first_then_block(nif)); + BasicBlock *elseBB = convert(nir_if_first_else_block(nif)); + + bb->cfg.attach(&ifBB->cfg, Graph::Edge::TREE); + bb->cfg.attach(&elseBB->cfg, Graph::Edge::TREE); + + /* + * we only insert joinats, if both nodes end up at the end of the if again. + * the reason for this to not happens are breaks/continues/ret/... which + * have their own handling + */ + if (lastThen->successors[0] == lastElse->successors[0]) + bb->joinAt = mkFlow(OP_JOINAT, convert(lastThen->successors[0]), + CC_ALWAYS, nullptr); + + mkFlow(OP_BRA, elseBB, CC_EQ, src)->setType(sType); + + foreach_list_typed(nir_cf_node, node, node, &nif->then_list) { + if (!visit(node)) + return false; + } + setPosition(convert(lastThen), true); + if (!bb->getExit() || + !bb->getExit()->asFlow() || + bb->getExit()->asFlow()->op == OP_JOIN) { + BasicBlock *tailBB = convert(lastThen->successors[0]); + mkFlow(OP_BRA, tailBB, CC_ALWAYS, nullptr); + bb->cfg.attach(&tailBB->cfg, Graph::Edge::FORWARD); + } + + foreach_list_typed(nir_cf_node, node, node, &nif->else_list) { + if (!visit(node)) + return false; + } + setPosition(convert(lastElse), true); + if (!bb->getExit() || + !bb->getExit()->asFlow() || + bb->getExit()->asFlow()->op == OP_JOIN) { + BasicBlock *tailBB = convert(lastElse->successors[0]); + mkFlow(OP_BRA, tailBB, CC_ALWAYS, nullptr); + bb->cfg.attach(&tailBB->cfg, Graph::Edge::FORWARD); + } + + if (lastThen->successors[0] == lastElse->successors[0]) { + setPosition(convert(lastThen->successors[0]), true); + mkFlow(OP_JOIN, nullptr, CC_ALWAYS, nullptr)->fixed = 1; + } + + return true; +} + +bool +Converter::visit(nir_loop *loop) +{ + curLoopDepth += 1; + func->loopNestingBound = std::max(func->loopNestingBound, curLoopDepth); + + BasicBlock *loopBB = convert(nir_loop_first_block(loop)); + BasicBlock *tailBB = + convert(nir_cf_node_as_block(nir_cf_node_next(&loop->cf_node))); + bb->cfg.attach(&loopBB->cfg, Graph::Edge::TREE); + + mkFlow(OP_PREBREAK, tailBB, CC_ALWAYS, NULL); + setPosition(loopBB, false); + mkFlow(OP_PRECONT, loopBB, CC_ALWAYS, NULL); + + foreach_list_typed(nir_cf_node, node, node, &loop->body) { + if (!visit(node)) + return false; + } + Instruction *insn = bb->getExit(); + if (bb->cfg.incidentCount() != 0) { + if (!insn || !insn->asFlow()) { + mkFlow(OP_CONT, loopBB, CC_ALWAYS, nullptr); + bb->cfg.attach(&loopBB->cfg, Graph::Edge::BACK); + } else if (insn && insn->op == OP_BRA && !insn->getPredicate() && + tailBB->cfg.incidentCount() == 0) { + /* + * RA doesn't like having blocks around with no incident edge, + * so we create a fake one to make it happy + */ + bb->cfg.attach(&tailBB->cfg, Graph::Edge::TREE); + } + } + + curLoopDepth -= 1; + + return true; +} + +bool +Converter::visit(nir_instr *insn) +{ + switch (insn->type) { + case nir_instr_type_jump: + return visit(nir_instr_as_jump(insn)); + default: + ERROR("unknown nir_instr type %u\n", insn->type); + return false; + } + return true; +} + +bool +Converter::visit(nir_jump_instr *insn) +{ + switch (insn->type) { + case nir_jump_return: + /* TODO: this only works in the main function */ + mkFlow(OP_BRA, exit, CC_ALWAYS, NULL); + bb->cfg.attach(&exit->cfg, Graph::Edge::CROSS); + break; + case nir_jump_break: + case nir_jump_continue: { + bool isBreak = insn->type == nir_jump_break; + nir_block *block = insn->instr.block; + assert(!block->successors[1]); + BasicBlock *target = convert(block->successors[0]); + mkFlow(isBreak ? OP_BREAK : OP_CONT, target, CC_ALWAYS, NULL); + bb->cfg.attach(&target->cfg, isBreak ? Graph::Edge::CROSS : Graph::Edge::BACK); + break; + } + default: + ERROR("unknown nir_jump_type %u\n", insn->type); + return false; + } + + return true; +} + bool Converter::run() { @@ -1085,7 +1346,12 @@ Converter::run() return false; } - return false; + nir_foreach_function(function, nir) { + if (!visit(function)) + return false; + } + + return true; } } // unnamed namespace -- 2.14.3 _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/mesa-dev