From 731691731bef35f7db5fde1dd304b328eabed5ed Mon Sep 17 00:00:00 2001 From: Henner Zeller Date: Fri, 20 Dec 2024 13:42:38 -0800 Subject: [PATCH] Reduce cyclomatic complexity in ir->block passes. If we're only considering one of function or procs, easier to just 'continue' the loop if precondition not met. PiperOrigin-RevId: 708416259 --- xls/codegen/convert_ir_to_blocks_passes.cc | 304 +++++++++++---------- 1 file changed, 155 insertions(+), 149 deletions(-) diff --git a/xls/codegen/convert_ir_to_blocks_passes.cc b/xls/codegen/convert_ir_to_blocks_passes.cc index 97dd020667..6158d778ae 100644 --- a/xls/codegen/convert_ir_to_blocks_passes.cc +++ b/xls/codegen/convert_ir_to_blocks_passes.cc @@ -43,6 +43,12 @@ #include "xls/ir/topo_sort.h" #include "xls/scheduling/pipeline_schedule.h" +// -- Implementations of +// ConvertFuncsToCombinationalBlocksPass +// ConvertProcsToCombinationalBlocksPass +// ConvertFuncsToPipelinedBlocksPass +// ConvertProcsToPipelinedBlocksPass + namespace xls::verilog { absl::StatusOr ConvertFuncsToCombinationalBlocksPass::RunInternal( @@ -51,71 +57,68 @@ absl::StatusOr ConvertFuncsToCombinationalBlocksPass::RunInternal( bool changed = false; for (auto& [fb, block] : unit->function_base_to_block_) { - if (fb->IsFunction()) { - Function* f = fb->AsFunctionOrDie(); - - VLOG(3) << "Converting function to a combinationalblock:"; - XLS_VLOG_LINES(3, f->DumpIr()); - - // A map from the nodes in 'f' to their corresponding node in the block. - absl::flat_hash_map node_map; - - // Emit the parameters first to ensure their order is preserved in the - // block. - auto func_interface = FindFunctionInterface( - options.codegen_options.package_interface(), f->name()); - - for (Param* param : f->params()) { - XLS_ASSIGN_OR_RETURN( - node_map[param], - block->AddInputPort(param->GetName(), param->GetType(), - param->loc())); - - if (func_interface) { - auto name = - absl::c_find_if(func_interface->parameters(), - [&](const PackageInterfaceProto::NamedValue& p) { - return p.name() == param->name(); - }); - if (name != func_interface->parameters().end() && - name->has_sv_type()) { - unit->metadata[block] - .streaming_io_and_pipeline - .input_port_sv_type[node_map[param]->As()] = - name->sv_type(); - } + if (!fb->IsFunction()) { + continue; + } + Function* const f = fb->AsFunctionOrDie(); + + VLOG(3) << "Converting function to a combinationalblock:"; + XLS_VLOG_LINES(3, f->DumpIr()); + + // A map from the nodes in 'f' to their corresponding node in the block. + absl::flat_hash_map nodes_function2block; + + // Emit the parameters first to ensure their order is preserved in the + // block. + auto func_interface = FindFunctionInterface( + options.codegen_options.package_interface(), f->name()); + + for (Param* param : f->params()) { + XLS_ASSIGN_OR_RETURN(nodes_function2block[param], + block->AddInputPort(param->GetName(), + param->GetType(), param->loc())); + + if (func_interface) { + auto name = + absl::c_find_if(func_interface->parameters(), + [&](const PackageInterfaceProto::NamedValue& p) { + return p.name() == param->name(); + }); + if (name != func_interface->parameters().end() && name->has_sv_type()) { + unit->metadata[block].streaming_io_and_pipeline.input_port_sv_type + [nodes_function2block[param]->As()] = name->sv_type(); } } + } - for (Node* node : TopoSort(f)) { - if (node->Is()) { - continue; - } - - std::vector new_operands; - for (Node* operand : node->operands()) { - new_operands.push_back(node_map.at(operand)); - } - XLS_ASSIGN_OR_RETURN(Node * block_node, - node->CloneInNewFunction(new_operands, block)); - node_map[node] = block_node; + for (Node* node : TopoSort(f)) { + if (node->Is()) { + continue; } - XLS_ASSIGN_OR_RETURN( - OutputPort * output, - block->AddOutputPort(options.codegen_options.output_port_name(), - node_map.at(f->return_value()))); - if (func_interface && func_interface->has_sv_result_type()) { - unit->metadata[block] - .streaming_io_and_pipeline.output_port_sv_type[output] = - func_interface->sv_result_type(); + std::vector new_operands; + for (Node* operand : node->operands()) { + new_operands.push_back(nodes_function2block.at(operand)); } + XLS_ASSIGN_OR_RETURN(Node * block_node, + node->CloneInNewFunction(new_operands, block)); + nodes_function2block[node] = block_node; + } + XLS_ASSIGN_OR_RETURN( + OutputPort * output, + block->AddOutputPort(options.codegen_options.output_port_name(), + nodes_function2block.at(f->return_value()))); + if (func_interface && func_interface->has_sv_result_type()) { unit->metadata[block] - .conversion_metadata.emplace(); - - changed = true; + .streaming_io_and_pipeline.output_port_sv_type[output] = + func_interface->sv_result_type(); } + + unit->metadata[block] + .conversion_metadata.emplace(); + + changed = true; } if (changed) { @@ -130,71 +133,72 @@ absl::StatusOr ConvertProcsToCombinationalBlocksPass::RunInternal( bool changed = false; for (auto& [fb, block] : unit->function_base_to_block_) { - if (fb->IsProc()) { - Proc* proc = fb->AsProcOrDie(); - - VLOG(3) << "Converting proc to a pipelined block:"; - XLS_VLOG_LINES(3, proc->DumpIr()); - - // In a combinational module, the proc cannot have any state to avoid - // combinational loops. That is, the only loop state must be empty tuples. - if (proc->GetStateElementCount() > 1 && - !absl::c_all_of(proc->StateElements(), [&](StateElement* st) { - return st->type() == proc->package()->GetTupleType({}); - })) { - return absl::InvalidArgumentError(absl::StrFormat( - "Proc must have no state (or state type is all empty tuples) when " - "lowering to a combinational block. Proc state type is: {%s}", - absl::StrJoin(proc->StateElements(), ", ", - [](std::string* out, StateElement* st) { - absl::StrAppend(out, st->type()->ToString()); - }))); - } + if (!fb->IsProc()) { + continue; + } + Proc* const proc = fb->AsProcOrDie(); + + VLOG(3) << "Converting proc to a pipelined block:"; + XLS_VLOG_LINES(3, proc->DumpIr()); + + // In a combinational module, the proc cannot have any state to avoid + // combinational loops. That is, the only loop state must be empty tuples. + if (proc->GetStateElementCount() > 1 && + !absl::c_all_of(proc->StateElements(), [&](StateElement* st) { + return st->type() == proc->package()->GetTupleType({}); + })) { + return absl::InvalidArgumentError(absl::StrFormat( + "Proc must have no state (or state type is all empty tuples) when " + "lowering to a combinational block. Proc state type is: {%s}", + absl::StrJoin(proc->StateElements(), ", ", + [](std::string* out, StateElement* st) { + absl::StrAppend(out, st->type()->ToString()); + }))); + } - XLS_ASSIGN_OR_RETURN( - StreamingIOPipeline streaming_io, - CloneProcNodesIntoBlock(proc, options.codegen_options, block)); + XLS_ASSIGN_OR_RETURN( + StreamingIOPipeline streaming_io, + CloneProcNodesIntoBlock(proc, options.codegen_options, block)); - int64_t number_of_outputs = 0; - for (const auto& outputs : streaming_io.outputs) { - number_of_outputs += outputs.size(); - } + int64_t number_of_outputs = 0; + for (const auto& outputs : streaming_io.outputs) { + number_of_outputs += outputs.size(); + } - if (number_of_outputs > 1) { - // TODO: do this analysis on a per-stage basis - XLS_ASSIGN_OR_RETURN(bool streaming_outputs_mutually_exclusive, - AreStreamingOutputsMutuallyExclusive(proc)); - - if (streaming_outputs_mutually_exclusive) { - VLOG(3) << absl::StrFormat( - "%d streaming outputs determined to be mutually exclusive", - number_of_outputs); - } else { - return absl::UnimplementedError(absl::StrFormat( - "Proc combinational generator only supports streaming " - "output channels which can be determined to be mutually " - "exclusive, got %d output channels which were not proven " - "to be mutually exclusive", - number_of_outputs)); - } + if (number_of_outputs > 1) { + // TODO: do this analysis on a per-stage basis + XLS_ASSIGN_OR_RETURN(bool streaming_outputs_mutually_exclusive, + AreStreamingOutputsMutuallyExclusive(proc)); + + if (streaming_outputs_mutually_exclusive) { + VLOG(3) << absl::StrFormat( + "%d streaming outputs determined to be mutually exclusive", + number_of_outputs); + } else { + return absl::UnimplementedError(absl::StrFormat( + "Proc combinational generator only supports streaming " + "output channels which can be determined to be mutually " + "exclusive, got %d output channels which were not proven " + "to be mutually exclusive", + number_of_outputs)); } + } - XLS_RET_CHECK_EQ(streaming_io.pipeline_registers.size(), 0); + XLS_RET_CHECK_EQ(streaming_io.pipeline_registers.size(), 0); - XLS_RETURN_IF_ERROR(AddCombinationalFlowControl( - streaming_io.inputs, streaming_io.outputs, streaming_io.stage_valid, - options.codegen_options, block)); + XLS_RETURN_IF_ERROR(AddCombinationalFlowControl( + streaming_io.inputs, streaming_io.outputs, streaming_io.stage_valid, + options.codegen_options, block)); - // TODO(tedhong): 2021-09-23 Remove and add any missing functionality to - // codegen pipeline. - unit->metadata[block] = CodegenMetadata{ - .streaming_io_and_pipeline = std::move(streaming_io), - .conversion_metadata = ProcConversionMetadata(), - .concurrent_stages = std::nullopt, - }; + // TODO(tedhong): 2021-09-23 Remove and add any missing functionality to + // codegen pipeline. + unit->metadata[block] = CodegenMetadata{ + .streaming_io_and_pipeline = std::move(streaming_io), + .conversion_metadata = ProcConversionMetadata(), + .concurrent_stages = std::nullopt, + }; - changed = true; - } + changed = true; } if (changed) { @@ -209,30 +213,31 @@ absl::StatusOr ConvertFuncsToPipelinedBlocksPass::RunInternal( bool changed = false; for (auto& [fb, block] : unit->function_base_to_block_) { - if (fb->IsFunction()) { - if (options.codegen_options.manual_control().has_value()) { - return absl::UnimplementedError( - "Manual pipeline control not implemented"); - } - if (options.codegen_options.split_outputs()) { - return absl::UnimplementedError("Splitting outputs not supported."); - } - if (options.codegen_options.reset().has_value() && - options.codegen_options.reset()->reset_data_path()) { - return absl::UnimplementedError("Data path reset not supported"); - } + if (!fb->IsFunction()) { + continue; + } + if (options.codegen_options.manual_control().has_value()) { + return absl::UnimplementedError( + "Manual pipeline control not implemented"); + } + if (options.codegen_options.split_outputs()) { + return absl::UnimplementedError("Splitting outputs not supported."); + } + if (options.codegen_options.reset().has_value() && + options.codegen_options.reset()->reset_data_path()) { + return absl::UnimplementedError("Data path reset not supported"); + } - Function* f = fb->AsFunctionOrDie(); + Function* const f = fb->AsFunctionOrDie(); - VLOG(3) << "Converting function to a pipelined block:"; - XLS_VLOG_LINES(3, f->DumpIr()); + VLOG(3) << "Converting function to a pipelined block:"; + XLS_VLOG_LINES(3, f->DumpIr()); - PipelineSchedule& schedule = unit->function_base_to_schedule_.at(fb); - XLS_RETURN_IF_ERROR(SingleFunctionToPipelinedBlock( - schedule, options.codegen_options, *unit, f, block)); + PipelineSchedule& schedule = unit->function_base_to_schedule_.at(fb); + XLS_RETURN_IF_ERROR(SingleFunctionToPipelinedBlock( + schedule, options.codegen_options, *unit, f, block)); - changed = true; - } + changed = true; } if (changed) { @@ -247,26 +252,27 @@ absl::StatusOr ConvertProcsToPipelinedBlocksPass::RunInternal( bool changed = false; for (auto& [fb, block] : unit->function_base_to_block_) { - if (fb->IsProc()) { - if (options.codegen_options.manual_control().has_value()) { - return absl::UnimplementedError( - "Manual pipeline control not implemented"); - } - if (options.codegen_options.split_outputs()) { - return absl::UnimplementedError("Splitting outputs not supported."); - } + if (!fb->IsProc()) { + continue; + } + if (options.codegen_options.manual_control().has_value()) { + return absl::UnimplementedError( + "Manual pipeline control not implemented"); + } + if (options.codegen_options.split_outputs()) { + return absl::UnimplementedError("Splitting outputs not supported."); + } - Proc* proc = fb->AsProcOrDie(); + Proc* const proc = fb->AsProcOrDie(); - VLOG(3) << "Converting proc to a pipelined block:"; - XLS_VLOG_LINES(3, proc->DumpIr()); + VLOG(3) << "Converting proc to a pipelined block:"; + XLS_VLOG_LINES(3, proc->DumpIr()); - PipelineSchedule& schedule = unit->function_base_to_schedule_.at(fb); - XLS_RETURN_IF_ERROR(SingleProcToPipelinedBlock( - schedule, options.codegen_options, *unit, proc, block)); + PipelineSchedule& schedule = unit->function_base_to_schedule_.at(fb); + XLS_RETURN_IF_ERROR(SingleProcToPipelinedBlock( + schedule, options.codegen_options, *unit, proc, block)); - changed = true; - } + changed = true; } if (changed) {