-
Notifications
You must be signed in to change notification settings - Fork 237
Expand file tree
/
Copy pathblock.h
More file actions
669 lines (570 loc) · 28.7 KB
/
block.h
File metadata and controls
669 lines (570 loc) · 28.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
// Copyright 2021 The XLS Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef XLS_IR_BLOCK_H_
#define XLS_IR_BLOCK_H_
#include <cstdint>
#include <memory>
#include <optional>
#include <string>
#include <string_view>
#include <utility>
#include <variant>
#include <vector>
#include "absl/algorithm/container.h"
#include "absl/base/casts.h"
#include "absl/container/flat_hash_map.h"
#include "absl/log/check.h"
#include "absl/log/log.h"
#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "absl/types/span.h"
#include "xls/codegen/module_signature.pb.h"
#include "xls/common/status/status_macros.h"
#include "xls/ir/channel.h"
#include "xls/ir/function_base.h"
#include "xls/ir/instantiation.h"
#include "xls/ir/ir_annotator.h"
#include "xls/ir/name_uniquer.h"
#include "xls/ir/node.h"
#include "xls/ir/nodes.h"
#include "xls/ir/package.h"
#include "xls/ir/register.h"
#include "xls/ir/source_location.h"
#include "xls/ir/type.h"
#include "xls/ir/value.h"
namespace xls {
enum class BlockProvenanceKind : int8_t { kProc, kFunction };
// Metadata used during codegen which describes where a block comes from.
struct BlockProvenance {
// The name of the proc or function the block was lowered from.
std::string name;
// The kind of IR construct (proc or function) this block was lowered from.
BlockProvenanceKind kind;
bool IsFromProc() const { return kind == BlockProvenanceKind::kProc; }
bool IsFromFunction() const { return kind == BlockProvenanceKind::kFunction; }
bool operator==(const BlockProvenance& other) const {
return name == other.name && kind == other.kind;
}
template <typename Sink>
friend void AbslStringify(Sink& sink, const BlockProvenance& v) {
absl::Format(&sink, "provenance(name=\"%s\", kind=\"%s\")", v.name,
v.kind == BlockProvenanceKind::kProc ? "proc" : "function");
}
template <typename H>
friend H AbslHashValue(H h, const BlockProvenance& v) {
return H::combine(std::move(h), v.name, v.kind);
}
};
// Metadata which maps ports back to the channels the were derived from.
struct ChannelPortMetadata {
std::string channel_name;
Type* type;
// The direction of the data/valid port (send or receive).
ChannelDirection direction;
ChannelKind channel_kind;
FlopKind flop_kind;
// Names of the ports for data/valid/ready signals for the channel. The value
// is std::nullopt if no such port exists.
std::optional<std::string> data_port;
std::optional<std::string> valid_port;
std::optional<std::string> ready_port;
// For channels with no flow control, this is the number of cycles after reset
// in which a value appears on the port (direction is kSend) or when a value
// is read at the data port (direction is kReceive). Unused otherwise.
std::optional<int64_t> stage;
std::string ToString() const;
};
// Abstraction representing the clock port. Needed to keep track of the name for
// verilog conversion.
struct ClockPort {
std::string name;
};
// Abstraction representing a Verilog module used in code generation. Blocks are
// function-level constructs similar to functions and procs. Like functions and
// procs, blocks contain (and own) a data-flow graph of nodes. With a small
// number of exceptions (e.g., send/receive) blocks may contain arbitrary nodes
// including dead nodes. Blocks allow an arbitrary number of inputs and outputs
// represented with ports, and blocks may contain registers.
//
// Blocks contain a single token parameter and a single terminal token. These
// tokens are used for supporting token-requiring operations such as assert.
class Block : public FunctionBase {
public:
Block(std::string_view name, Package* package)
: FunctionBase(name, package), register_name_uniquer_("__") {}
~Block() override = default;
// Representation of a port of a block. Ports are the interface of the block
// and represent ports on a Verilog module.
using Port = std::variant<InputPort*, OutputPort*, ClockPort*>;
// Returns the name of the port.
static std::string PortName(const Port& port);
// Returns the ports in the block. The ports are returned in the order that
// they will be emitted in the generated Verilog module. Input and output
// ports may be arbitrarily ordered.
absl::Span<const Port> GetPorts() const { return ports_; }
// Returns the input/output ports of the block. Ports are ordered by the
// position in the generated Verilog module.
absl::Span<InputPort* const> GetInputPorts() const { return input_ports_; }
absl::Span<OutputPort* const> GetOutputPorts() const { return output_ports_; }
// Return the input/output port of the given name.
absl::StatusOr<PortNode*> GetPortNode(std::string_view name) const;
// Returns a given input/output port by name.
absl::StatusOr<InputPort*> GetInputPort(std::string_view name) const;
bool HasInputPort(std::string_view name) const;
absl::StatusOr<OutputPort*> GetOutputPort(std::string_view name) const;
bool HasOutputPort(std::string_view name) const;
// Adds an input/output port to the block. These methods should be used to add
// ports rather than FunctionBase::AddNode and FunctionBase::MakeNode (checked
// later by the verifier).
absl::StatusOr<InputPort*> AddInputPort(std::string_view name, Type* type,
const SourceInfo& loc = SourceInfo());
absl::StatusOr<OutputPort*> AddOutputPort(
std::string_view name, Node* operand,
const SourceInfo& loc = SourceInfo());
// Add/get a clock port to the block. The clock is not represented as a value
// within the IR (no input_port operation), but rather a ClockPort
// object is added to the list of ports as a place-holder for the clock which
// records the port name and position.
absl::Status AddClockPort(std::string_view name);
const std::optional<ClockPort>& GetClockPort() const { return clock_port_; }
// Adds a new single-bit input port to the block and sets it as the reset port
// with the given behavior. Returns the port.
absl::StatusOr<InputPort*> AddResetPort(std::string_view port_name,
ResetBehavior behavior);
// Set an existing port in the block to be the reset port with the given
// behavior. If the block already has a reset port an error is returned.
absl::Status SetResetPort(InputPort* input_port, ResetBehavior behavior);
// Override the reset behavior of the block. The block must already have a
// reset port set (and necessarily an existing reset behavior defined).
absl::Status OverrideResetBehavior(ResetBehavior behavior);
// Returns the reset port or reset behavior of the block, or std::nullopt if
// the block has no reset port. Either both reset port and reset behavior is
// set, or neither is set.
std::optional<InputPort*> GetResetPort() const { return reset_port_; }
std::optional<ResetBehavior> GetResetBehavior() const {
return reset_behavior_;
};
absl::Status RemoveNode(Node* n) override;
// Re-orders the ports of the block as determined by `port_order`. The order
// of the ports in a block determines their order in the emitted verilog
// module. `port_names` must include (exactly) the name of every port.
absl::Status ReorderPorts(absl::Span<const std::string> port_names);
absl::Status ReorderInputPorts(absl::Span<const std::string> port_names);
absl::Status ReorderOutputPorts(absl::Span<const std::string> port_names);
// Returns all registers in the block in the order they were added.
absl::Span<Register* const> GetRegisters() const { return register_vec_; }
// Returns the register in the block with the given name. Returns an error
// if no such register exists.
absl::StatusOr<Register*> GetRegister(std::string_view name) const;
// Adds a register to the block.
//
// The requested_name is the name which will be used if possible. If the
// name is already used a uniquified name will be used. Query the register
// to get the actual name used by the register.
absl::StatusOr<Register*> AddRegister(
std::string_view requested_name, Type* type,
std::optional<Value> reset_value = std::nullopt);
// Adds a register with a reset value of zero.
absl::StatusOr<Register*> AddRegisterWithZeroResetValue(
std::string_view requested_name, Type* type);
// Removes the given register from the block. If the register is not owned
// by the block then an error is returned.
absl::Status RemoveRegister(Register* reg);
// Returns the unique register read or write operation associated with the
// given register. Returns an error if the register is not owned by the
// block or if no or more than one such read/write operation exists. A block
// with a register without both a read and write operation is malformed but
// may exist temporarily after the creation of the register and before
// adding the read and write operations. A register must have only one
// register read, but may have multiple register writes.
absl::StatusOr<RegisterRead*> GetRegisterRead(Register* reg) const;
absl::StatusOr<RegisterWrite*> GetUniqueRegisterWrite(Register* reg) const;
// Returns the register write operations associated with given register. A
// register may have multiple writes, but only one may activate in a given
// cycle.
absl::StatusOr<absl::Span<RegisterWrite* const>> GetRegisterWrites(
Register* reg) const;
// Add an instantiation of the given block `instantiated_block` to this
// block. InstantiationInput and InstantiationOutput operations must be later
// added to connect the instantiation to the data-flow graph.
absl::StatusOr<BlockInstantiation*> AddBlockInstantiation(
std::string_view instantiation_name, Block* instantiated_block);
struct BlockInstantiationAndConnections {
BlockInstantiation* instantiation;
absl::flat_hash_map<std::string, InstantiationInput*> inputs;
absl::flat_hash_map<std::string, InstantiationOutput*> outputs;
};
// Adds an instantiation of `instantiated_block` and creates the associated
// InstantiationConnection nodes. Reset and clock are automatically connected,
// if applicable. `inputs` includes the values to connect to the instantiation
// inputs and should contain a value for every non-reset input port on
// `instantiated_block`.
absl::StatusOr<BlockInstantiationAndConnections>
AddAndConnectBlockInstantiation(
std::string_view instantiation_name, Block* instantiated_block,
const absl::flat_hash_map<std::string, Node*>& inputs);
struct DelayLineInstantiationAndConnections {
DelayLineInstantiation* instantiation;
InstantiationInput* data_input;
InstantiationOutput* data_output;
std::optional<InstantiationInput*> reset;
};
// Adds a delay line instantiation and creates the associated
// InstantiationConnection nodes. Reset and clock are automatically connected,
// if applicable. `input` is the data input to the delay line.
absl::StatusOr<DelayLineInstantiationAndConnections>
AddAndConnectDelayLineInstantiation(
std::string_view instantiation_name, int64_t latency, Node* input,
std::optional<std::string_view> channel = std::nullopt);
// Add an instantiation of a FIFO to this block. InstantiationInput and
// InstantiationOutput operations must be later added to connect the
// instantiation to the data-flow graph.
absl::StatusOr<FifoInstantiation*> AddFifoInstantiation(
std::string_view name, FifoConfig fifo_config, Type* data_type,
std::optional<std::string_view> channel = std::nullopt);
absl::StatusOr<DelayLineInstantiation*> AddDelayLineInstantiation(
std::string_view name, int64_t latency, Type* data_type,
std::optional<std::string_view> channel = std::nullopt,
std::optional<ResetBehavior> reset_behavior = std::nullopt);
absl::StatusOr<Instantiation*> AddInstantiation(
std::string_view name, std::unique_ptr<Instantiation> instantiation);
// Removes the given instantiation from the block. InstantiationInput or
// InstantiationOutput operations for this instantiation should be removed
// prior to calling this method
absl::Status RemoveInstantiation(Instantiation* instantiation);
// Removes an instantiation and all of the associated InstantiationConnection
// nodes. These nodes must have no users.
absl::Status RemoveInstantiationAndConnections(Instantiation* instantiation);
// Replaces all uses of old_isnt with new_inst and removes old_inst. Both
// must be currently owned by this block.
// If new_inst has different port names, an optional mapping of old to new
// port names can be provided.
absl::Status ReplaceInstantiationWith(
Instantiation* old_inst, Instantiation* new_inst,
absl::flat_hash_map<std::string, std::string> port_renaming = {});
// Returns all instantiations owned by this block.
absl::Span<Instantiation* const> GetInstantiations() const {
return instantiation_vec_;
}
// Return the instantiation owned by this block with the given name or an
// error if no such one exists.
absl::StatusOr<Instantiation*> GetInstantiation(std::string_view name) const;
// Returns the instantiation inputs/outputs associated with the given
// instantiation.
absl::Span<InstantiationInput* const> GetInstantiationInputs(
Instantiation* instantiation) const;
absl::Span<InstantiationOutput* const> GetInstantiationOutputs(
Instantiation* instantiation) const;
// Returns the instantiation input/output node associated with the port of the
// given name.
absl::StatusOr<InstantiationOutput*> GetInstantiationOutput(
Instantiation* instantiation, std::string_view port_name) const;
absl::StatusOr<InstantiationInput*> GetInstantiationInput(
Instantiation* instantiation, std::string_view port_name) const;
// Returns true if the given block-scoped construct (register or
// instantiation) is owned by this block.
bool IsOwned(Register* reg) const {
return registers_.contains(reg->name()) &&
registers_.at(reg->name()).get() == reg;
}
bool IsOwned(Instantiation* instantiation) const {
return instantiations_.contains(instantiation->name()) &&
instantiations_.at(instantiation->name()).get() == instantiation;
}
void AddStage(Stage stage) {
CHECK(stage.IsControlled());
FunctionBase::AddStage(std::move(stage));
}
absl::StatusOr<bool> RemoveNodeFromStage(Node* node);
bool HasImplicitUse(Node* node) const override {
return absl::c_any_of(stages_, [node](const Stage& stage) {
return stage.inputs_valid() == node || stage.outputs_valid() == node ||
stage.active_inputs_valid() == node ||
stage.outputs_ready() == node;
});
}
// Creates a clone of the block with the new name 'new_name'.
// reg_name_map is a map from old register names to new ones. If a register
// name is not present it is an identity mapping.
//
// If a block is present in 'block_instantiation_map' the corresponding
// block is used to provide an instantiation implementation. All
// instantiated blocks must be present if target_package is not null and not
// the existing block package.
absl::StatusOr<Block*> Clone(
std::string_view new_name, Package* target_package = nullptr,
const absl::flat_hash_map<std::string, std::string>& reg_name_map = {},
const absl::flat_hash_map<const Block*, Block*>& block_instantiation_map =
{},
bool preserve_schedule = true) const;
std::vector<std::string> AttributeIrStrings() const override;
using FunctionBase::DumpIr;
std::string DumpIr(const IrAnnotator& annotate) const override;
FunctionBase::Kind kind() const final { return FunctionBase::Kind::kBlock; }
// Add metadata describing the mapping from ports to the channel they are
// derived from.
absl::Status AddChannelPortMetadata(ChannelPortMetadata metadata);
absl::Status AddChannelPortMetadata(
ChannelRef channel, ChannelDirection direction,
std::optional<std::string> data_port,
std::optional<std::string> valid_port,
std::optional<std::string> ready_port,
std::optional<int64_t> stage = std::nullopt);
// Returns the metadata for all channels which have port metadata.
const absl::flat_hash_map<std::pair<std::string, ChannelDirection>,
ChannelPortMetadata>&
GetChannelPortMetadata() const {
return channel_port_metadata_;
}
// Returns the port metadata for the channel with the given name or an error
// if no such metadata exists.
absl::StatusOr<ChannelPortMetadata> GetChannelPortMetadata(
std::string_view channel_name, ChannelDirection direction) const;
bool HasChannelPortMetadata(std::string_view channel_name,
ChannelDirection direction) const {
return channel_port_metadata_.contains(
std::pair<std::string, ChannelDirection>(channel_name, direction));
}
const absl::flat_hash_map<std::pair<std::string, ChannelDirection>,
ChannelPortMetadata>&
GetAllChannelPortMetadata() const {
return channel_port_metadata_;
}
// Returns the port node associated with the ready/valid/data signal for the
// given channel. Returns an error if no port metadata exists for the given
// channel. Returns std::nullopt if port metadata exists for the channel but
// no ready/valid/data port exists for the channel (for example, a data port
// for a empty tuple typed channel).
absl::StatusOr<std::optional<PortNode*>> GetReadyPortForChannel(
std::string_view channel_name, ChannelDirection direction) const;
absl::StatusOr<std::optional<PortNode*>> GetValidPortForChannel(
std::string_view channel_name, ChannelDirection direction) const;
absl::StatusOr<std::optional<PortNode*>> GetDataPortForChannel(
std::string_view channel_name, ChannelDirection direction) const;
// Returns the FifoInstantiation reresenting the channel with the given name.
absl::StatusOr<Instantiation*> GetInstantiationForChannel(
std::string_view channel_name) const;
// Returns the instantiation input/output associated with teh ready/valid/data
// signal for the given channel in the given direction.
absl::StatusOr<std::optional<InstantiationConnection*>>
GetReadyInstantiationConnectionForChannel(std::string_view channel_name,
ChannelDirection direction) const;
absl::StatusOr<std::optional<InstantiationConnection*>>
GetValidInstantiationConnectionForChannel(std::string_view channel_name,
ChannelDirection direction) const;
absl::StatusOr<std::optional<InstantiationConnection*>>
GetDataInstantiationConnectionForChannel(std::string_view channel_name,
ChannelDirection direction) const;
// Returns the names of and directions of channels which correspond to ports
// on this block.
std::vector<std::pair<std::string, ChannelDirection>>
GetChannelsWithMappedPorts() const;
void SetFunctionBaseProvenance(FunctionBase* fb) {
BlockProvenanceKind kind;
if (fb->IsFunction()) {
kind = BlockProvenanceKind::kFunction;
} else {
CHECK(fb->IsProc());
kind = BlockProvenanceKind::kProc;
}
SetProvenance(BlockProvenance{.name = fb->name(), .kind = kind});
}
void SetProvenance(std::optional<BlockProvenance> value) {
provenance_ = value;
}
const std::optional<BlockProvenance>& GetProvenance() const {
return provenance_;
}
const std::optional<verilog::ModuleSignatureProto>& GetSignature() const {
return signature_;
}
void SetSignature(verilog::ModuleSignatureProto signature) {
signature_ = std::move(signature);
}
void ClearSignature() { signature_.reset(); }
protected:
absl::Status InternalRebuildSideTables() final {
return absl::UnimplementedError(
"Cannot rebuild block side tables at this time.");
}
private:
// Sets the name of the given port node (InputPort or OutputPort) to the
// given name. Unlike xls::Node::SetName which may name the node `name` with
// an added suffix to ensure name uniqueness, SetNamePortExactly ensures the
// given node is assigned the given name. This is useful for ports because
// the port name is part of the interface of the generated Verilog module.
// To avoid name collisions, if another *non-port* node already exists with
// the name in the block, then that is node given an alternative name. If
// another *port* node already exists with the name an error is returned.
//
// Fundamentally, port nodes have hard constraints on their name while
// naming of interior nodes is best-effort. The problem this function solves
// is if a node in the best-effort-naming category captures a name which is
// required by a node in the hard-constraint-naming category.
absl::Status SetPortNameExactly(std::string_view name, Node* port_node);
Node* AddNodeInternal(std::unique_ptr<Node> node) override;
// Hides AddEmptyStages from FunctionBase, and crashes if called through the
// base class. Scheduled blocks use controlled stages, so it's impossible to
// add empty stages in bulk.
void AddEmptyStages(int64_t n) override {
LOG(FATAL) << "Cannot add empty stages to a block.";
}
// Returns the order of emission of block nodes in the text IR
// (Block::DumpIR() output). The order is a topological sort with additional
// constraints for readability such that logical pipeline stages tend to get
// emitted together.
std::vector<Node*> DumpOrder() const;
absl::StatusOr<const ChannelPortMetadata*> GetChannelPortMetadataInternal(
std::string_view channel_name, ChannelDirection direction) const;
// All ports in the block in the order they appear in the Verilog module.
std::vector<Port> ports_;
// Ports indexed by name.
absl::flat_hash_map<std::string, Port> ports_by_name_;
// All input/output ports in the order they appear in the Verilog module.
std::vector<InputPort*> input_ports_;
std::vector<OutputPort*> output_ports_;
// Registers within this block. Indexed by register name. Stored as
// std::unique_ptrs for pointer stability.
absl::flat_hash_map<std::string, std::unique_ptr<Register>> registers_;
// Register read and write operations associated with each register.
absl::flat_hash_map<Register*, std::vector<RegisterRead*>> register_reads_;
absl::flat_hash_map<Register*, std::vector<RegisterWrite*>> register_writes_;
// Vector of register pointers. Ordered by register creation time. Kept in
// sync with the registers_ map. Enables easy, stable iteration over
// registers. With this vector, deletion of a register is O(n) with the
// number of registers. If this is a problem, a linked list might be used
// instead.
std::vector<Register*> register_vec_;
// Instantiations owned by this block. Indexed by name. Stored as
// std::unique_ptrs for pointer stability.
absl::flat_hash_map<std::string, std::unique_ptr<Instantiation>>
instantiations_;
// Instiation input and output operations associated with instantiations in
// this block.
absl::flat_hash_map<Instantiation*, std::vector<InstantiationInput*>>
instantiation_inputs_;
absl::flat_hash_map<Instantiation*, std::vector<InstantiationOutput*>>
instantiation_outputs_;
std::vector<Instantiation*> instantiation_vec_;
std::optional<ClockPort> clock_port_;
std::optional<InputPort*> reset_port_;
std::optional<ResetBehavior> reset_behavior_;
NameUniquer register_name_uniquer_;
// Map from channel name and direction to the data structure describing
// which ports are associated with the channel (ready/valid/data ports).
absl::flat_hash_map<std::pair<std::string, ChannelDirection>,
ChannelPortMetadata>
channel_port_metadata_;
std::optional<BlockProvenance> provenance_;
std::optional<verilog::ModuleSignatureProto> signature_;
};
// A block which has been scheduled and contains information about which
// nodes execute in which pipeline stage, and how the control-flow logic is
// connected.
class ScheduledBlock : public Block {
public:
ScheduledBlock(std::string_view name, Package* package)
: Block(name, package) {}
bool IsScheduled() const override { return true; }
// Returns the entity that this block was derived from. This is `nullptr`
// except during intermediate stages of lowering a proc or function to a
// block. In those stages, we still need to refer to parts of the source
// entity that cannot reside in a block. The source entity is a stripped-down
// skeleton that does not contain the logic. The nodes in this block may refer
// to state, channels, and params in the source.
FunctionBase* source() {
return source_ == nullptr ? nullptr : source_.get();
}
const FunctionBase* source() const {
return source_ == nullptr ? nullptr : source_.get();
}
// Sets the source entity that this block was derived from.
void SetSource(std::unique_ptr<FunctionBase> source) {
source_ = std::move(source);
if (source_ != nullptr) {
source_->SetIsBlockSource(true);
}
}
// Returns the source function return value. This is `nullptr` except when
// `source()` yields a function. We store the return value directly in the
// block because it would have to be a forward reference in IR text if it
// resided in the source function.
Node* source_return_value() const { return source_return_value_; }
void SetSourceReturnValue(Node* value) { source_return_value_ = value; }
bool HasImplicitUse(Node* node) const override {
return (source_return_value_ != nullptr && node == source_return_value_) ||
Block::HasImplicitUse(node);
}
// Returns true if the given node is either in this block or its source
// entity.
virtual bool Contains(const Node* node) const override {
return node->function_base() == this ||
(source_ != nullptr && source_->Contains(node));
}
// Returns true if there is a source proc.
bool HasEffectiveProc() const override {
return Block::HasEffectiveProc() ||
(source_ != nullptr && source_->HasEffectiveProc());
}
// Returns the source proc, if any.
const Proc* GetEffectiveProcOrDie() const final {
CHECK(source_ != nullptr);
return source_->GetEffectiveProcOrDie();
}
Proc* GetEffectiveProcOrDie() final {
CHECK(source_ != nullptr);
return source_->GetEffectiveProcOrDie();
}
// Creates a clone of the scheduled block with the new name 'new_name'.
// reg_name_map is a map from old register names to new ones. If a register
// name is not present it is an identity mapping.
//
// If a block is present in 'block_instantiation_map' the corresponding
// block is used to provide an instantiation implementation. All
// instantiated blocks must be present if target_package is not null and not
// the existing block package.
absl::StatusOr<ScheduledBlock*> Clone(
std::string_view new_name, Package* target_package = nullptr,
const absl::flat_hash_map<std::string, std::string>& reg_name_map = {},
const absl::flat_hash_map<const Block*, Block*>& block_instantiation_map =
{}) const {
XLS_ASSIGN_OR_RETURN(Block * cloned_block,
Block::Clone(new_name, target_package, reg_name_map,
block_instantiation_map));
return absl::down_cast<ScheduledBlock*>(cloned_block);
}
// Creates a clone of the scheduled block with the new name 'new_name', but
// dropping the scheduling information (ending up with a regular block).
// reg_name_map is a map from old register names to new ones. If a register
// name is not present it is an identity mapping.
//
// If a block is present in 'block_instantiation_map' the corresponding
// block is used to provide an instantiation implementation. All
// instantiated blocks must be present if target_package is not null and not
// the existing block package.
absl::StatusOr<Block*> CloneWithoutSchedule(
std::string_view new_name, Package* target_package = nullptr,
const absl::flat_hash_map<std::string, std::string>& reg_name_map = {},
const absl::flat_hash_map<const Block*, Block*>& block_instantiation_map =
{}) const {
return Block::Clone(new_name, target_package, reg_name_map,
block_instantiation_map,
/*preserve_schedule=*/false);
}
private:
std::unique_ptr<FunctionBase> source_;
Node* source_return_value_ = nullptr;
};
} // namespace xls
#endif // XLS_IR_BLOCK_H_