Skip to content

Commit b0a0b50

Browse files
ericastorcopybara-github
authored andcommitted
[XLS] Switch from external-adapter channel legalization to internal arbitration
To support relaxed channel strictness settings (allowing multiple operations per channel per activation), we previously translated all operations to take place on their own channels, then inserted an external arbitrating adapter to mux the channels back together. This resulted in duplicated control-flow logic, and was difficult to optimize well without full-powered proc inlining - which ran into its own problems. Instead, we now implement relaxed strictnesses by implementing additional legalizations within the proc: adding token-typed state to avoid cross-activation conflicts, and adding scheduling constraints to avoid having multiple (non-mutually-exclusive) operations in the same activation trigger at the same time. To support this, we also modify codegen to allow multiple operations per channel, relying on earlier compilation steps to ensure that we never see more than one trigger in a given cycle. This passes all existing tests, except for a few where it revealed issues that were previously hidden by our choices in implementing the external adapter. We modify those tests accordingly. As best as I can tell, this should be no worse for performance than the previous version. NOTE: This will also allow us to support proven-mutually-exclusive channels with mutually-exclusive operations that can't be merged, which reduces merging to an optimization; we'll remove the forced-merge logic for this case in a followup CL. Fixes #2180 PiperOrigin-RevId: 760612461
1 parent 906ac05 commit b0a0b50

32 files changed

+1549
-1705
lines changed

xls/codegen/BUILD

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,7 @@ cc_library(
217217
"//xls/common/status:status_macros",
218218
"//xls/ir",
219219
"//xls/ir:op",
220+
"//xls/ir:proc_elaboration",
220221
"//xls/ir:state_element",
221222
"//xls/ir:xls_ir_interface_cc_proto",
222223
"//xls/passes:pass_base",
@@ -228,6 +229,7 @@ cc_library(
228229
"@com_google_absl//absl/status:statusor",
229230
"@com_google_absl//absl/strings",
230231
"@com_google_absl//absl/strings:str_format",
232+
"@com_google_absl//absl/types:span",
231233
],
232234
)
233235

@@ -438,26 +440,30 @@ cc_library(
438440
srcs = ["conversion_utils.cc"],
439441
hdrs = ["conversion_utils.h"],
440442
deps = [
441-
":codegen_checker",
442443
":codegen_options",
443444
":codegen_pass",
444-
":codegen_wrapper_pass",
445445
":register_legalization_pass",
446446
"//xls/codegen/vast",
447+
"//xls/common:casts",
447448
"//xls/common/status:ret_check",
448449
"//xls/common/status:status_macros",
449450
"//xls/ir",
451+
"//xls/ir:bits",
450452
"//xls/ir:channel",
451453
"//xls/ir:node_util",
452454
"//xls/ir:op",
455+
"//xls/ir:proc_elaboration",
453456
"//xls/ir:register",
454457
"//xls/ir:source_location",
458+
"//xls/ir:value",
455459
"//xls/ir:xls_ir_interface_cc_proto",
456460
"//xls/passes:dataflow_simplification_pass",
457461
"//xls/passes:dce_pass",
458462
"//xls/passes:optimization_pass",
459463
"//xls/passes:pass_base",
460464
"@com_google_absl//absl/algorithm:container",
465+
"@com_google_absl//absl/container:btree",
466+
"@com_google_absl//absl/container:flat_hash_map",
461467
"@com_google_absl//absl/log:check",
462468
"@com_google_absl//absl/status",
463469
"@com_google_absl//absl/status:statusor",

xls/codegen/block_conversion.cc

Lines changed: 33 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -296,9 +296,10 @@ absl::Status AddCombinationalFlowControl(
296296
std::vector<std::vector<StreamingInput>>& streaming_inputs,
297297
std::vector<std::vector<StreamingOutput>>& streaming_outputs,
298298
std::vector<std::optional<Node*>>& stage_valid,
299-
const CodegenOptions& options, Block* block) {
299+
const CodegenOptions& options, Proc* proc, Block* block) {
300300
std::string_view valid_suffix = options.streaming_channel_valid_suffix();
301301
std::string_view ready_suffix = options.streaming_channel_ready_suffix();
302+
std::string_view data_suffix = options.streaming_channel_data_suffix();
302303

303304
XLS_ASSIGN_OR_RETURN(
304305
std::vector<Node*> all_active_outputs_ready,
@@ -316,10 +317,14 @@ absl::Status AddCombinationalFlowControl(
316317
std::vector<Node*> next_stage_open{literal_1};
317318
XLS_RETURN_IF_ERROR(MakeOutputValidPortsForOutputChannels(
318319
all_active_inputs_valid, pipelined_valids, next_stage_open,
319-
streaming_outputs, valid_suffix, block));
320+
streaming_outputs, valid_suffix, proc, {}, block));
321+
XLS_RETURN_IF_ERROR(MakeOutputDataPortsForOutputChannels(
322+
all_active_inputs_valid, pipelined_valids, next_stage_open,
323+
streaming_outputs, data_suffix, block));
320324

321325
XLS_RETURN_IF_ERROR(MakeOutputReadyPortsForInputChannels(
322-
all_active_outputs_ready, streaming_inputs, ready_suffix, block));
326+
all_active_outputs_ready, streaming_inputs, ready_suffix, proc, {},
327+
block));
323328

324329
XLS_RET_CHECK(stage_valid.empty());
325330
XLS_RET_CHECK_EQ(all_active_inputs_valid.size(), 1);
@@ -634,7 +639,8 @@ absl::StatusOr<Node*> AddZeroLatencyBufferToRDVNodes(
634639
}
635640

636641
absl::StatusOr<std::vector<FunctionBase*>> GetBlockConversionOrder(
637-
Package* package, absl::Span<Proc* const> procs_to_convert) {
642+
Package* package, absl::Span<Proc* const> procs_to_convert,
643+
const std::optional<ProcElaboration>& proc_elab) {
638644
FunctionBase* top = *package->GetTop();
639645
if (top->IsFunction()) {
640646
XLS_RET_CHECK(procs_to_convert.empty());
@@ -643,17 +649,18 @@ absl::StatusOr<std::vector<FunctionBase*>> GetBlockConversionOrder(
643649
CHECK(top->IsProc());
644650
if (package->ChannelsAreProcScoped()) {
645651
XLS_RET_CHECK(procs_to_convert.empty());
652+
XLS_RET_CHECK(proc_elab.has_value());
646653
// The order of block conversion must be from the leaf up as *instantiated*
647654
// procs must be converted before *instantiating* proc.
648-
XLS_ASSIGN_OR_RETURN(ProcElaboration elab,
649-
ProcElaboration::Elaborate(top->AsProcOrDie()));
650-
std::vector<FunctionBase*> order(elab.procs().begin(), elab.procs().end());
655+
std::vector<FunctionBase*> order(proc_elab->procs().begin(),
656+
proc_elab->procs().end());
651657
std::reverse(order.begin(), order.end());
652658
return order;
653659
}
654660
// For the non-proc-scoped channels case, the set of procs to convert must be
655661
// given.
656662
XLS_RET_CHECK(!procs_to_convert.empty());
663+
XLS_RET_CHECK(!proc_elab.has_value());
657664
std::vector<FunctionBase*> order(procs_to_convert.begin(),
658665
procs_to_convert.end());
659666
std::sort(order.begin(), order.end(), FunctionBase::NameLessThan);
@@ -686,8 +693,16 @@ absl::StatusOr<CodegenContext> PackageToPipelinedBlocks(
686693
}
687694
}
688695
}
689-
XLS_ASSIGN_OR_RETURN(std::vector<FunctionBase*> conversion_order,
690-
GetBlockConversionOrder(package, procs_to_convert));
696+
697+
std::optional<ProcElaboration> proc_elab;
698+
if (top->IsProc() && package->ChannelsAreProcScoped()) {
699+
XLS_ASSIGN_OR_RETURN(proc_elab,
700+
ProcElaboration::Elaborate(top->AsProcOrDie()));
701+
}
702+
703+
XLS_ASSIGN_OR_RETURN(
704+
std::vector<FunctionBase*> conversion_order,
705+
GetBlockConversionOrder(package, procs_to_convert, proc_elab));
691706

692707
// Make `unit` optional because we haven't created the top block yet. We will
693708
// create it on the first iteration and emplace `unit`.
@@ -732,8 +747,13 @@ absl::StatusOr<CodegenContext> PackageToPipelinedBlocks(
732747
package->AddBlock(std::make_unique<Block>(sub_block_name, package));
733748
}
734749
if (fb->IsProc()) {
750+
absl::Span<ProcInstance* const> instances;
751+
if (package->ChannelsAreProcScoped()) {
752+
XLS_RET_CHECK(proc_elab.has_value());
753+
instances = proc_elab->GetInstances(fb->AsProcOrDie());
754+
}
735755
XLS_RETURN_IF_ERROR(SingleProcToPipelinedBlock(
736-
schedule, options, context, fb->AsProcOrDie(), sub_block,
756+
schedule, options, context, fb->AsProcOrDie(), instances, sub_block,
737757
converted_blocks));
738758
} else if (fb->IsFunction()) {
739759
XLS_RET_CHECK_EQ(conversion_order.size(), 1);
@@ -888,9 +908,9 @@ absl::StatusOr<CodegenContext> ProcToCombinationalBlock(
888908

889909
XLS_RET_CHECK_EQ(streaming_io.pipeline_registers.size(), 0);
890910

891-
XLS_RETURN_IF_ERROR(
892-
AddCombinationalFlowControl(streaming_io.inputs, streaming_io.outputs,
893-
streaming_io.stage_valid, options, block));
911+
XLS_RETURN_IF_ERROR(AddCombinationalFlowControl(
912+
streaming_io.inputs, streaming_io.outputs, streaming_io.stage_valid,
913+
options, proc, block));
894914

895915
// TODO(tedhong): 2021-09-23 Remove and add any missing functionality to
896916
// codegen pipeline.

xls/codegen/block_conversion.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
#include "xls/ir/node.h"
3636
#include "xls/ir/nodes.h"
3737
#include "xls/ir/proc.h"
38+
#include "xls/ir/proc_elaboration.h"
3839
#include "xls/scheduling/pipeline_schedule.h"
3940

4041
namespace xls::verilog {
@@ -131,7 +132,7 @@ absl::Status AddCombinationalFlowControl(
131132
std::vector<std::vector<StreamingInput>>& streaming_inputs,
132133
std::vector<std::vector<StreamingOutput>>& streaming_outputs,
133134
std::vector<std::optional<Node*>>& stage_valid,
134-
const CodegenOptions& options, Block* block);
135+
const CodegenOptions& options, Proc* proc, Block* block);
135136

136137
// Update io channel metadata with latest information from block conversion.
137138
absl::Status UpdateChannelMetadata(const StreamingIOPipeline& io, Block* block);
@@ -143,7 +144,8 @@ absl::StatusOr<std::string> StreamingIOName(Node* node);
143144
// bottom up in the tree of proc instantiations. `procs_to_convert` is the set
144145
// of Procs to convert. `procs_to_convert` must not be specified otherwise.
145146
absl::StatusOr<std::vector<FunctionBase*>> GetBlockConversionOrder(
146-
Package* package, absl::Span<Proc* const> procs_to_convert = {});
147+
Package* package, absl::Span<Proc* const> procs_to_convert = {},
148+
const std::optional<ProcElaboration>& proc_elab = std::nullopt);
147149

148150
} // namespace xls::verilog
149151

0 commit comments

Comments
 (0)