CIRCT  19.0.0git
PrepareForEmission.cpp
Go to the documentation of this file.
1 //===- PrepareForEmission.cpp - IR Prepass for Emitter --------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file implements the "prepare" pass that walks the IR before the emitter
10 // gets involved. This allows us to do some transformations that would be
11 // awkward to implement inline in the emitter.
12 //
13 // NOTE: This file covers the preparation phase of `ExportVerilog` which mainly
14 // legalizes the IR and makes adjustments necessary for emission. This is the
15 // place to mutate the IR if emission needs it. The IR cannot be modified during
16 // emission itself, which happens in parallel.
17 //
18 //===----------------------------------------------------------------------===//
19 
20 #include "../PassDetail.h"
21 #include "ExportVerilogInternals.h"
27 #include "mlir/IR/ImplicitLocOpBuilder.h"
28 #include "llvm/ADT/DenseSet.h"
29 #include "llvm/ADT/SmallPtrSet.h"
30 #include "llvm/ADT/TypeSwitch.h"
31 #include "llvm/Support/CommandLine.h"
32 #include "llvm/Support/Debug.h"
33 
34 #define DEBUG_TYPE "prepare-for-emission"
35 
36 using namespace circt;
37 using namespace comb;
38 using namespace hw;
39 using namespace sv;
40 using namespace ExportVerilog;
41 
42 // Check if the value is from read of a wire or reg or is a port.
44  if (v.isa<BlockArgument>())
45  return true;
46  auto vOp = v.getDefiningOp();
47  if (!vOp)
48  return false;
49  if (v.getType().isa<sv::InOutType>() && isa<sv::WireOp>(vOp))
50  return true;
51  auto read = dyn_cast<ReadInOutOp>(vOp);
52  if (!read)
53  return false;
54  auto readSrc = read.getInput().getDefiningOp();
55  if (!readSrc)
56  return false;
57  return isa<sv::WireOp, RegOp, LogicOp, XMROp, XMRRefOp>(readSrc);
58 }
59 
60 // Check if the value is deemed worth spilling into a wire.
61 static bool shouldSpillWire(Operation &op, const LoweringOptions &options) {
62  if (!isVerilogExpression(&op))
63  return false;
64 
65  // Spill temporary wires if it is not possible to inline.
66  return !ExportVerilog::isExpressionEmittedInline(&op, options);
67 }
68 
69 static StringAttr getArgName(Operation *op, size_t idx) {
70  if (auto inst = dyn_cast<hw::InstanceOp>(op))
71  return inst.getArgumentName(idx);
72  else if (auto inst = dyn_cast<InstanceChoiceOp>(op))
73  return inst.getArgumentName(idx);
74  return {};
75 }
76 
77 // Given an instance, make sure all inputs are driven from wires or ports.
78 static void spillWiresForInstanceInputs(HWInstanceLike op) {
79  Block *block = op->getParentOfType<HWModuleOp>().getBodyBlock();
80  auto builder = ImplicitLocOpBuilder::atBlockBegin(op.getLoc(), block);
81 
82  SmallString<32> nameTmp{"_", op.getInstanceName(), "_"};
83  auto namePrefixSize = nameTmp.size();
84 
85  for (size_t opNum = 0, e = op->getNumOperands(); opNum != e; ++opNum) {
86  auto src = op->getOperand(opNum);
87 
88  if (isSimpleReadOrPort(src))
89  continue;
90 
91  nameTmp.resize(namePrefixSize);
92  if (auto n = getArgName(op, opNum))
93  nameTmp += n.getValue().str();
94  else
95  nameTmp += std::to_string(opNum);
96 
97  auto newWire = builder.create<sv::WireOp>(src.getType(), nameTmp);
98  auto newWireRead = builder.create<ReadInOutOp>(newWire);
99  auto connect = builder.create<AssignOp>(newWire, src);
100  newWireRead->moveBefore(op);
101  connect->moveBefore(op);
102  op->setOperand(opNum, newWireRead);
103  }
104 }
105 
106 static StringAttr getResName(Operation *op, size_t idx) {
107  if (auto inst = dyn_cast<hw::InstanceOp>(op))
108  return inst.getResultName(idx);
109  else if (auto inst = dyn_cast<InstanceChoiceOp>(op))
110  return inst.getResultName(idx);
111  return {};
112 }
113 
114 // Ensure that each output of an instance are used only by a wire
115 static void lowerInstanceResults(HWInstanceLike op) {
116  Block *block = op->getParentOfType<HWModuleOp>().getBodyBlock();
117  auto builder = ImplicitLocOpBuilder::atBlockBegin(op.getLoc(), block);
118 
119  SmallString<32> nameTmp{"_", op.getInstanceName(), "_"};
120  auto namePrefixSize = nameTmp.size();
121 
122  for (size_t resNum = 0, e = op->getNumResults(); resNum != e; ++resNum) {
123  auto result = op->getResult(resNum);
124 
125  // If the result doesn't have a user, the connection won't be emitted by
126  // Emitter, so there's no need to create a wire for it. However, if the
127  // result is a zero bit value, the normal emission code path should be used,
128  // as zero bit values require special handling by the emitter.
129  if (result.use_empty() && !ExportVerilog::isZeroBitType(result.getType()))
130  continue;
131 
132  if (result.hasOneUse()) {
133  OpOperand &use = *result.getUses().begin();
134  if (dyn_cast_or_null<OutputOp>(use.getOwner()))
135  continue;
136  if (auto assign = dyn_cast_or_null<AssignOp>(use.getOwner())) {
137  // Move assign op after instance to resolve cyclic dependencies.
138  assign->moveAfter(op);
139  continue;
140  }
141  }
142 
143  nameTmp.resize(namePrefixSize);
144  if (auto n = getResName(op, resNum))
145  nameTmp += n.getValue().str();
146  else
147  nameTmp += std::to_string(resNum);
148  Value newWire = builder.create<sv::WireOp>(result.getType(), nameTmp);
149 
150  while (!result.use_empty()) {
151  auto newWireRead = builder.create<ReadInOutOp>(newWire);
152  OpOperand &use = *result.getUses().begin();
153  use.set(newWireRead);
154  newWireRead->moveBefore(use.getOwner());
155  }
156 
157  auto connect = builder.create<AssignOp>(newWire, result);
158  connect->moveAfter(op);
159  }
160 }
161 
162 /// Emit an explicit wire or logic to assign operation's result. This function
163 /// is used to create a temporary to legalize a verilog expression or to
164 /// resolve use-before-def in a graph region. If `emitWireAtBlockBegin` is true,
165 /// a temporary wire will be created at the beginning of the block. Otherwise,
166 /// a wire is created just after op's position so that we can inline the
167 /// assignment into its wire declaration.
168 static void lowerUsersToTemporaryWire(Operation &op,
169  bool emitWireAtBlockBegin = false) {
170  Block *block = op.getBlock();
171  auto builder = ImplicitLocOpBuilder::atBlockBegin(op.getLoc(), block);
172  bool isProceduralRegion = op.getParentOp()->hasTrait<ProceduralRegion>();
173 
174  auto createWireForResult = [&](Value result, StringAttr name) {
175  Value newWire;
176  Type wireElementType = result.getType();
177  bool isResultInOut = false;
178 
179  // If the result already is an InOut, make sure to not wrap it again
180  if (auto inoutType = hw::type_dyn_cast<hw::InOutType>(result.getType())) {
181  wireElementType = inoutType.getElementType();
182  isResultInOut = true;
183  }
184 
185  // If the op is in a procedural region, use logic op.
186  if (isProceduralRegion)
187  newWire = builder.create<LogicOp>(wireElementType, name);
188  else
189  newWire = builder.create<sv::WireOp>(wireElementType, name);
190 
191  // Replace all uses with newWire. Wrap in ReadInOutOp if required.
192  while (!result.use_empty()) {
193  OpOperand &use = *result.getUses().begin();
194  if (isResultInOut) {
195  use.set(newWire);
196  } else {
197  auto newWireRead = builder.create<ReadInOutOp>(newWire);
198  use.set(newWireRead);
199  newWireRead->moveBefore(use.getOwner());
200  }
201  }
202 
203  // Assign the original result to the temporary wire.
204  Operation *connect;
205  ReadInOutOp resultRead;
206 
207  if (isResultInOut)
208  resultRead = builder.create<ReadInOutOp>(result);
209 
210  if (isProceduralRegion)
211  connect = builder.create<BPAssignOp>(
212  newWire, isResultInOut ? resultRead.getResult() : result);
213  else
214  connect = builder.create<AssignOp>(
215  newWire, isResultInOut ? resultRead.getResult() : result);
216 
217  connect->moveAfter(&op);
218  if (resultRead)
219  resultRead->moveBefore(connect);
220 
221  // Move the temporary to the appropriate place.
222  if (!emitWireAtBlockBegin) {
223  // `emitWireAtBlockBegin` is intendend to be used for resovling cyclic
224  // dependencies. So when `emitWireAtBlockBegin` is true, we keep the
225  // position of the wire. Otherwise, we move the wire to immediately after
226  // the expression so that the wire and assignment are next to each other.
227  // This ordering will be used by the heurstic to inline assignments.
228  newWire.getDefiningOp()->moveAfter(&op);
229  }
230  };
231 
232  // If the op has a single result, infer a meaningful name from the
233  // value.
234  if (op.getNumResults() == 1) {
235  auto namehint = inferStructuralNameForTemporary(op.getResult(0));
236  op.removeAttr("sv.namehint");
237  createWireForResult(op.getResult(0), namehint);
238  return;
239  }
240 
241  // If the op has multiple results, create wires for each result.
242  for (auto result : op.getResults())
243  createWireForResult(result, StringAttr());
244 }
245 
246 // Given a side effect free "always inline" operation, make sure that it
247 // exists in the same block as its users and that it has one use for each one.
248 static void lowerAlwaysInlineOperation(Operation *op,
249  const LoweringOptions &options) {
250  assert(op->getNumResults() == 1 &&
251  "only support 'always inline' ops with one result");
252 
253  // Moving/cloning an op should pull along its operand tree with it if they are
254  // always inline. This happens when an array index has a constant operand for
255  // example. If the operand is not always inline, then evaluate it to see if
256  // it should be spilled to a wire.
257  auto recursivelyHandleOperands = [&](Operation *op) {
258  for (auto operand : op->getOperands()) {
259  if (auto *operandOp = operand.getDefiningOp()) {
260  if (isExpressionAlwaysInline(operandOp))
261  lowerAlwaysInlineOperation(operandOp, options);
262  else if (shouldSpillWire(*operandOp, options))
263  lowerUsersToTemporaryWire(*operandOp);
264  }
265  }
266  };
267 
268  // If an operation is an assignment that immediately follows the declaration
269  // of its wire, return that wire. Otherwise return the original op. This
270  // ensures that the declaration and assignment don't get split apart by
271  // inlined operations, which allows `ExportVerilog` to trivially emit the
272  // expression inline in the declaration.
273  auto skipToWireImmediatelyBefore = [](Operation *user) {
274  if (!isa<BPAssignOp, AssignOp>(user))
275  return user;
276  auto *wireOp = user->getOperand(0).getDefiningOp();
277  if (wireOp && wireOp->getNextNode() == user)
278  return wireOp;
279  return user;
280  };
281 
282  // If this operation has multiple uses, duplicate it into N-1 of them in
283  // turn.
284  while (!op->hasOneUse()) {
285  OpOperand &use = *op->getUses().begin();
286  Operation *user = skipToWireImmediatelyBefore(use.getOwner());
287 
288  // Clone the op before the user.
289  auto *newOp = op->clone();
290  user->getBlock()->getOperations().insert(Block::iterator(user), newOp);
291  // Change the user to use the new op.
292  use.set(newOp->getResult(0));
293 
294  // If any of the operations of the moved op are always inline, recursively
295  // handle them too.
296  recursivelyHandleOperands(newOp);
297  }
298 
299  // Finally, ensures the op is in the same block as its user so it can be
300  // inlined.
301  Operation *user = skipToWireImmediatelyBefore(*op->getUsers().begin());
302  op->moveBefore(user);
303 
304  // If any of the operations of the moved op are always inline, recursively
305  // move/clone them too.
306  recursivelyHandleOperands(op);
307  return;
308 }
309 
310 // Find a nearest insertion point where logic op can be declared.
311 // Logic ops are emitted as "automatic logic" in procedural regions, but
312 // they must be declared at beginning of blocks.
313 static std::pair<Block *, Block::iterator>
315  // We have to skip `ifdef.procedural` because it is a just macro.
316  if (isa<IfDefProceduralOp>(op->getParentOp()))
317  return findLogicOpInsertionPoint(op->getParentOp());
318  return {op->getBlock(), op->getBlock()->begin()};
319 }
320 
321 /// Lower a variadic fully-associative operation into an expression tree. This
322 /// enables long-line splitting to work with them.
323 /// NOLINTNEXTLINE(misc-no-recursion)
324 static Value lowerFullyAssociativeOp(Operation &op, OperandRange operands,
325  SmallVector<Operation *> &newOps) {
326  // save the top level name
327  auto name = op.getAttr("sv.namehint");
328  if (name)
329  op.removeAttr("sv.namehint");
330  Value lhs, rhs;
331  switch (operands.size()) {
332  case 0:
333  assert(0 && "cannot be called with empty operand range");
334  break;
335  case 1:
336  return operands[0];
337  case 2:
338  lhs = operands[0];
339  rhs = operands[1];
340  break;
341  default:
342  auto firstHalf = operands.size() / 2;
343  lhs = lowerFullyAssociativeOp(op, operands.take_front(firstHalf), newOps);
344  rhs = lowerFullyAssociativeOp(op, operands.drop_front(firstHalf), newOps);
345  break;
346  }
347 
348  OperationState state(op.getLoc(), op.getName());
349  state.addOperands(ValueRange{lhs, rhs});
350  state.addTypes(op.getResult(0).getType());
351  auto *newOp = Operation::create(state);
352  op.getBlock()->getOperations().insert(Block::iterator(&op), newOp);
353  newOps.push_back(newOp);
354  if (name)
355  newOp->setAttr("sv.namehint", name);
356  if (auto twoState = op.getAttr("twoState"))
357  newOp->setAttr("twoState", twoState);
358  return newOp->getResult(0);
359 }
360 
361 /// Transform "a + -cst" ==> "a - cst" for prettier output. This returns the
362 /// first operation emitted.
364  hw::ConstantOp rhsCst) {
365  ImplicitLocOpBuilder builder(add.getLoc(), add);
366 
367  // Get the positive constant.
368  auto negCst = builder.create<hw::ConstantOp>(-rhsCst.getValue());
369  auto sub =
370  builder.create<comb::SubOp>(add.getOperand(0), negCst, add.getTwoState());
371  add.getResult().replaceAllUsesWith(sub);
372  add.erase();
373  if (rhsCst.use_empty())
374  rhsCst.erase();
375  return negCst;
376 }
377 
378 // Transforms a hw.struct_explode operation into a set of hw.struct_extract
379 // operations, and returns the first op generated.
380 static Operation *lowerStructExplodeOp(hw::StructExplodeOp op) {
381  Operation *firstOp = nullptr;
382  ImplicitLocOpBuilder builder(op.getLoc(), op);
383  StructType structType = op.getInput().getType().cast<StructType>();
384  for (auto [res, field] :
385  llvm::zip(op.getResults(), structType.getElements())) {
386  auto extract =
387  builder.create<hw::StructExtractOp>(op.getInput(), field.name);
388  if (!firstOp)
389  firstOp = extract;
390  res.replaceAllUsesWith(extract);
391  }
392  op.erase();
393  return firstOp;
394 }
395 
396 /// Given an operation in a procedural region, scan up the region tree to find
397 /// the first operation in a graph region (typically an always or initial op).
398 ///
399 /// By looking for a graph region, we will stop at graph-region #ifdef's that
400 /// may enclose this operation.
401 static Operation *findParentInNonProceduralRegion(Operation *op) {
402  Operation *parentOp = op->getParentOp();
403  assert(parentOp->hasTrait<ProceduralRegion>() &&
404  "we should only be hoisting from procedural");
405  while (parentOp->getParentOp()->hasTrait<ProceduralRegion>())
406  parentOp = parentOp->getParentOp();
407  return parentOp;
408 }
409 
410 /// This function is invoked on side effecting Verilog expressions when we're in
411 /// 'disallowLocalVariables' mode for old Verilog clients. This ensures that
412 /// any side effecting expressions are only used by a single BPAssign to a
413 /// sv.reg or sv.logic operation. This ensures that the verilog emitter doesn't
414 /// have to worry about spilling them.
415 ///
416 /// This returns true if the op was rewritten, false otherwise.
417 static bool rewriteSideEffectingExpr(Operation *op) {
418  assert(op->getNumResults() == 1 && "isn't a verilog expression");
419 
420  // Check to see if this is already rewritten.
421  if (op->hasOneUse()) {
422  if (auto assign = dyn_cast<BPAssignOp>(*op->user_begin()))
423  return false;
424  }
425 
426  // Otherwise, we have to transform it. Insert a reg at the top level, make
427  // everything using the side effecting expression read the reg, then assign to
428  // it after the side effecting operation.
429  Value opValue = op->getResult(0);
430 
431  // Scan to the top of the region tree to find out where to insert the reg.
432  Operation *parentOp = findParentInNonProceduralRegion(op);
433  OpBuilder builder(parentOp);
434  auto reg = builder.create<RegOp>(op->getLoc(), opValue.getType());
435 
436  // Everything using the expr now uses a read_inout of the reg.
437  auto value = builder.create<ReadInOutOp>(op->getLoc(), reg);
438  opValue.replaceAllUsesWith(value);
439 
440  // We assign the side effect expr to the reg immediately after that expression
441  // is computed.
442  builder.setInsertionPointAfter(op);
443  builder.create<BPAssignOp>(op->getLoc(), reg, opValue);
444  return true;
445 }
446 
447 /// This function is called for non-side-effecting Verilog expressions when
448 /// we're in 'disallowLocalVariables' mode for old Verilog clients. It hoists
449 /// non-constant expressions out to the top level so they don't turn into local
450 /// variable declarations.
451 static bool hoistNonSideEffectExpr(Operation *op) {
452  // Never hoist "always inline" expressions except for inout stuffs - they will
453  // never generate a temporary and in fact must always be emitted inline.
454  if (isExpressionAlwaysInline(op) &&
455  !(isa<sv::ReadInOutOp>(op) ||
456  op->getResult(0).getType().isa<hw::InOutType>()))
457  return false;
458 
459  // Scan to the top of the region tree to find out where to move the op.
460  Operation *parentOp = findParentInNonProceduralRegion(op);
461 
462  // We can typically hoist all the way out to the top level in one step, but
463  // there may be intermediate operands that aren't hoistable. If so, just
464  // hoist one level.
465  bool cantHoist = false;
466  if (llvm::any_of(op->getOperands(), [&](Value operand) -> bool {
467  // The operand value dominates the original operation, but may be
468  // defined in one of the procedural regions between the operation and
469  // the top level of the module. We can tell this quite efficiently by
470  // looking for ops in a procedural region - because procedural regions
471  // live in graph regions but not visa-versa.
472  if (BlockArgument block = operand.dyn_cast<BlockArgument>()) {
473  // References to ports are always ok.
474  if (isa<hw::HWModuleOp>(block.getParentBlock()->getParentOp()))
475  return false;
476 
477  cantHoist = true;
478  return true;
479  }
480  Operation *operandOp = operand.getDefiningOp();
481 
482  if (operandOp->getParentOp()->hasTrait<ProceduralRegion>()) {
483  cantHoist |= operandOp->getBlock() == op->getBlock();
484  return true;
485  }
486  return false;
487  })) {
488 
489  // If the operand is in the same block as the expression then we can't hoist
490  // this out at all.
491  if (cantHoist)
492  return false;
493 
494  // Otherwise, we can hoist it, but not all the way out in one step. Just
495  // hoist one level out.
496  parentOp = op->getParentOp();
497  }
498 
499  op->moveBefore(parentOp);
500  return true;
501 }
502 
503 /// Check whether an op is a declaration that can be moved.
504 static bool isMovableDeclaration(Operation *op) {
505  if (op->getNumResults() != 1 ||
506  !op->getResult(0).getType().isa<InOutType, sv::InterfaceType>())
507  return false;
508 
509  // If all operands (e.g. init value) are constant, it is safe to move
510  return llvm::all_of(op->getOperands(), [](Value operand) -> bool {
511  auto *defOp = operand.getDefiningOp();
512  return !!defOp && isConstantExpression(defOp);
513  });
514 }
515 
516 //===----------------------------------------------------------------------===//
517 // EmittedExpressionStateManager
518 //===----------------------------------------------------------------------===//
519 
521  size_t size = 0;
523  return EmittedExpressionState{1};
524  }
525  void mergeState(const EmittedExpressionState &state) { size += state.size; }
526 };
527 
528 /// This class handles information about AST structures of each expressions.
530  : public hw::TypeOpVisitor<EmittedExpressionStateManager,
531  EmittedExpressionState>,
532  public comb::CombinationalVisitor<EmittedExpressionStateManager,
533  EmittedExpressionState>,
534  public sv::Visitor<EmittedExpressionStateManager,
535  EmittedExpressionState> {
536 public:
538  : options(options){};
539 
540  // Get or caluculate an emitted expression state.
541  EmittedExpressionState getExpressionState(Value value);
542 
543  bool dispatchHeuristic(Operation &op);
544 
545  // Return true if the operation is worth spilling based on the expression
546  // state of the op.
547  bool shouldSpillWireBasedOnState(Operation &op);
548 
549 private:
550  friend class TypeOpVisitor<EmittedExpressionStateManager,
552  friend class CombinationalVisitor<EmittedExpressionStateManager,
556  LLVM_DEBUG(op->emitWarning() << "unhandled by EmittedExpressionState");
557  if (op->getNumOperands() == 0)
559  return mergeOperandsStates(op);
560  }
562  return dispatchTypeOpVisitor(op);
563  }
565  return visitUnhandledExpr(op);
566  }
568  return dispatchSVVisitor(op);
569  }
571  return visitUnhandledExpr(op);
572  }
574  return visitUnhandledExpr(op);
575  }
576 
577  using CombinationalVisitor::visitComb;
578  using Visitor::visitSV;
579 
581 
582  // A helper function to accumulate states.
583  EmittedExpressionState mergeOperandsStates(Operation *op);
584 
585  // This caches the expression states in the module scope.
586  DenseMap<Value, EmittedExpressionState> expressionStates;
587 };
588 
591  auto it = expressionStates.find(v);
592  if (it != expressionStates.end())
593  return it->second;
594 
595  // Ports.
596  if (auto blockArg = v.dyn_cast<BlockArgument>())
598 
599  EmittedExpressionState state =
600  dispatchCombinationalVisitor(v.getDefiningOp());
601  expressionStates.insert({v, state});
602  return state;
603 }
604 
608  for (auto operand : op->getOperands())
609  state.mergeState(getExpressionState(operand));
610 
611  return state;
612 }
613 
614 /// If exactly one use of this op is an assign, replace the other uses with a
615 /// read from the assigned wire or reg. This assumes the preconditions for doing
616 /// so are met: op must be an expression in a non-procedural region.
617 static bool reuseExistingInOut(Operation *op, const LoweringOptions &options) {
618  // Try to collect a single assign and all the other uses of op.
619  sv::AssignOp assign;
620  SmallVector<OpOperand *> uses;
621 
622  // Look at each use.
623  for (OpOperand &use : op->getUses()) {
624  // If it's an assign, try to save it.
625  if (auto assignUse = dyn_cast<AssignOp>(use.getOwner())) {
626  // If there are multiple assigns, bail out.
627  if (assign)
628  return false;
629 
630  // If the assign is not at the top level, it might be conditionally
631  // executed. So bail out.
632  if (!isa<HWModuleOp>(assignUse->getParentOp()))
633  return false;
634 
635  // Remember this assign for later.
636  assign = assignUse;
637  continue;
638  }
639 
640  // If not an assign, remember this use for later.
641  uses.push_back(&use);
642  }
643 
644  // If we didn't find anything, bail out.
645  if (!assign || uses.empty())
646  return false;
647 
648  if (auto *cop = assign.getSrc().getDefiningOp())
649  if (isa<ConstantOp>(cop))
650  return false;
651 
652  // Replace all saved uses with a read from the assigned destination.
653  ImplicitLocOpBuilder builder(assign.getDest().getLoc(), op->getContext());
654  for (OpOperand *use : uses) {
655  builder.setInsertionPoint(use->getOwner());
656  auto read = builder.create<ReadInOutOp>(assign.getDest());
657  use->set(read);
658  }
659  if (auto *destOp = assign.getDest().getDefiningOp())
660  if (isExpressionAlwaysInline(destOp))
661  lowerAlwaysInlineOperation(destOp, options);
662  return true;
663 }
664 
666  // TODO: Consider using virtual functions.
667  if (options.isWireSpillingHeuristicEnabled(
669  if (auto hint = op.getAttrOfType<StringAttr>("sv.namehint")) {
670  // Spill wires if the name doesn't have a prefix "_".
671  if (!hint.getValue().starts_with("_"))
672  return true;
673  // If the name has prefix "_", spill if the size is greater than the
674  // threshould.
675  if (getExpressionState(op.getResult(0)).size >=
676  options.wireSpillingNamehintTermLimit)
677  return true;
678  }
679 
680  return false;
681 }
682 
683 /// Return true if it is beneficial to spill the operation under the specified
684 /// spilling heuristic.
686  // Don't spill wires for inout operations and simple expressions such as read
687  // or constant.
688  if (op.getNumResults() == 0 ||
689  op.getResult(0).getType().isa<hw::InOutType>() ||
690  isa<ReadInOutOp, ConstantOp>(op))
691  return false;
692 
693  // If the operation is only used by an assignment, the op is already spilled
694  // to a wire.
695  if (op.hasOneUse()) {
696  auto *singleUser = *op.getUsers().begin();
697  if (isa<hw::OutputOp, sv::AssignOp, sv::BPAssignOp, hw::InstanceOp,
698  hw::InstanceChoiceOp>(singleUser))
699  return false;
700 
701  // If the single user is bitcast, we check the same property for the bitcast
702  // op since bitcast op is no-op in system verilog.
703  if (singleUser->hasOneUse() && isa<hw::BitcastOp>(singleUser) &&
704  isa<hw::OutputOp, sv::AssignOp, sv::BPAssignOp>(
705  *singleUser->getUsers().begin()))
706  return false;
707  }
708 
709  // If the term size is greater than `maximumNumberOfTermsPerExpression`,
710  // we have to spill the wire.
711  if (options.maximumNumberOfTermsPerExpression <
712  getExpressionState(op.getResult(0)).size)
713  return true;
714  return dispatchHeuristic(op);
715 }
716 
717 /// After the legalization, we are able to know accurate verilog AST structures.
718 /// So this function walks and prettifies verilog IR with a heuristic method
719 /// specified by `options.wireSpillingHeuristic` based on the structures.
721  Block &block, EmittedExpressionStateManager &expressionStateManager) {
722  // TODO: Handle procedural regions as well.
723  if (block.getParentOp()->hasTrait<ProceduralRegion>())
724  return;
725 
726  for (auto &op : llvm::make_early_inc_range(block)) {
727  if (!isVerilogExpression(&op))
728  continue;
729  if (expressionStateManager.shouldSpillWireBasedOnState(op)) {
731  continue;
732  }
733  }
734 
735  for (auto &op : block) {
736  // If the operations has regions, visit each of the region bodies.
737  for (auto &region : op.getRegions()) {
738  if (!region.empty())
739  prettifyAfterLegalization(region.front(), expressionStateManager);
740  }
741  }
742 }
743 
744 struct WireLowering {
745  hw::WireOp wireOp;
746  Block::iterator declarePoint;
747  Block::iterator assignPoint;
748 };
749 
750 /// Determine the insertion location of declaration and assignment ops for
751 /// `hw::WireOp`s in a block. This function tries to place the declaration point
752 /// as late as possible, right before the very first use of the wire. It also
753 /// tries to place the assign point as early as possible, right after the
754 /// assigned value becomes available.
755 static void buildWireLowerings(Block &block,
756  SmallVectorImpl<WireLowering> &wireLowerings) {
757  for (auto hwWireOp : block.getOps<hw::WireOp>()) {
758  // Find the earliest point in the block at which the input operand is
759  // available. The assign operation will have to go after that to not create
760  // a use-before-def situation.
761  Block::iterator assignPoint = block.begin();
762  if (auto *defOp = hwWireOp.getInput().getDefiningOp())
763  if (defOp && defOp->getBlock() == &block)
764  assignPoint = ++Block::iterator(defOp);
765 
766  // Find the earliest use of the wire within the block. The wire declaration
767  // will have to go somewhere before this point to not create a
768  // use-before-def situation.
769  Block::iterator declarePoint = assignPoint;
770  for (auto *user : hwWireOp->getUsers()) {
771  while (user->getBlock() != &block)
772  user = user->getParentOp();
773  if (user->isBeforeInBlock(&*declarePoint))
774  declarePoint = Block::iterator(user);
775  }
776 
777  wireLowerings.push_back({hwWireOp, declarePoint, assignPoint});
778  }
779 }
780 
781 /// Materialize the SV wire declaration and assignment operations in the
782 /// locations previously determined by a call to `buildWireLowerings`. This
783 /// replaces all `hw::WireOp`s with their appropriate SV counterpart.
784 static void applyWireLowerings(Block &block,
785  ArrayRef<WireLowering> wireLowerings) {
786  bool isProceduralRegion = block.getParentOp()->hasTrait<ProceduralRegion>();
787 
788  for (auto [hwWireOp, declarePoint, assignPoint] : wireLowerings) {
789  // Create the declaration.
790  ImplicitLocOpBuilder builder(hwWireOp.getLoc(), &block, declarePoint);
791  Value decl;
792  if (isProceduralRegion) {
793  decl = builder.create<LogicOp>(hwWireOp.getType(), hwWireOp.getNameAttr(),
794  hwWireOp.getInnerSymAttr());
795  } else {
796  decl =
797  builder.create<sv::WireOp>(hwWireOp.getType(), hwWireOp.getNameAttr(),
798  hwWireOp.getInnerSymAttr());
799  }
800 
801  // Carry attributes over to the lowered operation.
802  auto defaultAttrNames = hwWireOp.getAttributeNames();
803  for (auto namedAttr : hwWireOp->getAttrs())
804  if (!llvm::is_contained(defaultAttrNames, namedAttr.getName()))
805  decl.getDefiningOp()->setAttr(namedAttr.getName(),
806  namedAttr.getValue());
807 
808  // Create the assignment. If it is supposed to be at a different point than
809  // the declaration, reposition the builder there. Otherwise we'll just build
810  // the assignment immediately after the declaration.
811  if (assignPoint != declarePoint)
812  builder.setInsertionPoint(&block, assignPoint);
813  if (isProceduralRegion)
814  builder.create<BPAssignOp>(decl, hwWireOp.getInput());
815  else
816  builder.create<AssignOp>(decl, hwWireOp.getInput());
817 
818  // Create the read. If we have created the assignment at a different point
819  // than the declaration, reposition the builder to immediately after the
820  // declaration. Otherwise we'll just build the read immediately after the
821  // assignment.
822  if (assignPoint != declarePoint)
823  builder.setInsertionPointAfterValue(decl);
824  auto readOp = builder.create<sv::ReadInOutOp>(decl);
825 
826  // Replace the HW wire.
827  hwWireOp.replaceAllUsesWith(readOp.getResult());
828  }
829 
830  for (auto [hwWireOp, declarePoint, assignPoint] : wireLowerings)
831  hwWireOp.erase();
832 }
833 
834 /// For each module we emit, do a prepass over the structure, pre-lowering and
835 /// otherwise rewriting operations we don't want to emit.
836 static LogicalResult legalizeHWModule(Block &block,
837  const LoweringOptions &options) {
838 
839  // First step, check any nested blocks that exist in this region. This walk
840  // can pull things out to our level of the hierarchy.
841  for (auto &op : block) {
842  // If the operations has regions, prepare each of the region bodies.
843  for (auto &region : op.getRegions()) {
844  if (!region.empty())
845  if (failed(legalizeHWModule(region.front(), options)))
846  return failure();
847  }
848  }
849 
850  // Lower HW wires into SV wires in the appropriate spots. Try to put the
851  // declaration close to the first use in the block, and the assignment right
852  // after the assigned value becomes available.
853  {
854  SmallVector<WireLowering> wireLowerings;
855  buildWireLowerings(block, wireLowerings);
856  applyWireLowerings(block, wireLowerings);
857  }
858 
859  // Next, walk all of the operations at this level.
860 
861  // True if these operations are in a procedural region.
862  bool isProceduralRegion = block.getParentOp()->hasTrait<ProceduralRegion>();
863 
864  // This tracks "always inline" operation already visited in the iterations to
865  // avoid processing same operations infinitely.
866  DenseSet<Operation *> visitedAlwaysInlineOperations;
867 
868  // Debug operations to be moved to the end of the block such that they don't
869  // create unnecessary spill wires.
870  SmallVector<Operation *> debugOpsToMoveToEnd;
871 
872  for (Block::iterator opIterator = block.begin(), e = block.end();
873  opIterator != e;) {
874  auto &op = *opIterator++;
875 
876  if (!isa<CombDialect, SVDialect, HWDialect, ltl::LTLDialect,
877  verif::VerifDialect, debug::DebugDialect>(op.getDialect())) {
878  auto d = op.emitError() << "dialect \"" << op.getDialect()->getNamespace()
879  << "\" not supported for direct Verilog emission";
880  d.attachNote() << "ExportVerilog cannot emit this operation; it needs "
881  "to be lowered before running ExportVerilog";
882  return failure();
883  }
884 
885  // Do not reorder LTL expressions, which are always emitted inline.
886  if (isa<ltl::LTLDialect>(op.getDialect()))
887  continue;
888 
889  // Move debug operations to the end of the block.
890  if (isa<debug::DebugDialect>(op.getDialect())) {
891  debugOpsToMoveToEnd.push_back(&op);
892  continue;
893  }
894 
895  // Name legalization should have happened in a different pass for these sv
896  // elements and we don't want to change their name through re-legalization
897  // (e.g. letting a temporary take the name of an unvisited wire). Adding
898  // them now ensures any temporary generated will not use one of the names
899  // previously declared.
900  if (auto inst = dyn_cast<HWInstanceLike>(op)) {
901  // Anchor return values to wires early
902  lowerInstanceResults(inst);
903  // Anchor ports of instances when `disallowExpressionInliningInPorts` is
904  // enabled.
907  }
908 
909  // If logic op is located in a procedural region, we have to move the logic
910  // op declaration to a valid program point.
911  if (isProceduralRegion && isa<LogicOp>(op)) {
912  if (options.disallowLocalVariables) {
913  // When `disallowLocalVariables` is enabled, "automatic logic" is
914  // prohibited so hoist the op to a non-procedural region.
915  auto *parentOp = findParentInNonProceduralRegion(&op);
916  op.moveBefore(parentOp);
917  }
918  }
919 
920  // If the target doesn't support local variables, hoist all the expressions
921  // out to the nearest non-procedural region.
922  if (options.disallowLocalVariables && isVerilogExpression(&op) &&
923  isProceduralRegion) {
924 
925  // Force any side-effecting expressions in nested regions into a sv.reg
926  // if we aren't allowing local variable declarations. The Verilog emitter
927  // doesn't want to have to have to know how to synthesize a reg in the
928  // case they have to be spilled for whatever reason.
929  if (!mlir::isMemoryEffectFree(&op)) {
930  if (rewriteSideEffectingExpr(&op))
931  continue;
932  }
933 
934  // Hoist other expressions out to the parent region.
935  //
936  // NOTE: This effectively disables inlining of expressions into if
937  // conditions, $fwrite statements, and instance inputs. We could be
938  // smarter in ExportVerilog itself, but we'd have to teach it to put
939  // spilled expressions (due to line length, multiple-uses, and
940  // non-inlinable expressions) in the outer scope.
941  if (hoistNonSideEffectExpr(&op))
942  continue;
943  }
944 
945  // Duplicate "always inline" expression for each of their users and move
946  // them to be next to their users.
947  if (isExpressionAlwaysInline(&op)) {
948  // Nuke use-less operations.
949  if (op.use_empty()) {
950  op.erase();
951  continue;
952  }
953  // Process the op only when the op is never processed from the top-level
954  // loop.
955  if (visitedAlwaysInlineOperations.insert(&op).second)
956  lowerAlwaysInlineOperation(&op, options);
957 
958  continue;
959  }
960 
961  if (auto aggregateConstantOp = dyn_cast<hw::AggregateConstantOp>(op);
962  options.disallowPackedStructAssignments && aggregateConstantOp) {
963  if (hw::StructType structType =
964  type_dyn_cast<hw::StructType>(aggregateConstantOp.getType())) {
965  // Create hw struct create op and apply the legalization again.
966  SmallVector<Value> operands;
967  ImplicitLocOpBuilder builder(op.getLoc(), op.getContext());
968  builder.setInsertionPointAfter(&op);
969  for (auto [value, field] :
970  llvm::zip(aggregateConstantOp.getFieldsAttr(),
971  structType.getElements())) {
972  if (auto arrayAttr = dyn_cast<mlir::ArrayAttr>(value))
973  operands.push_back(
974  builder.create<hw::AggregateConstantOp>(field.type, arrayAttr));
975  else
976  operands.push_back(builder.create<hw::ConstantOp>(
977  field.type, cast<mlir::IntegerAttr>(value)));
978  }
979 
980  auto structCreate =
981  builder.create<hw::StructCreateOp>(structType, operands);
982  aggregateConstantOp.getResult().replaceAllUsesWith(structCreate);
983  // Reset the iterator.
984  opIterator = std::next(op.getIterator());
985 
986  op.erase();
987  continue;
988  }
989  }
990 
991  if (auto structCreateOp = dyn_cast<hw::StructCreateOp>(op);
992  options.disallowPackedStructAssignments && structCreateOp) {
993  // Force packed struct assignment to be a wire + assignments to each
994  // field.
995  Value wireOp;
996  ImplicitLocOpBuilder builder(op.getLoc(), &op);
997  hw::StructType structType =
998  structCreateOp.getResult().getType().cast<hw::StructType>();
999  bool procedural = op.getParentOp()->hasTrait<ProceduralRegion>();
1000  if (procedural)
1001  wireOp = builder.create<LogicOp>(structType);
1002  else
1003  wireOp = builder.create<sv::WireOp>(structType);
1004 
1005  for (auto [input, field] :
1006  llvm::zip(structCreateOp.getInput(), structType.getElements())) {
1007  auto target =
1008  builder.create<sv::StructFieldInOutOp>(wireOp, field.name);
1009  if (procedural)
1010  builder.create<BPAssignOp>(target, input);
1011  else
1012  builder.create<AssignOp>(target, input);
1013  }
1014  // Have to create a separate read for each use to keep things legal.
1015  for (auto &use :
1016  llvm::make_early_inc_range(structCreateOp.getResult().getUses()))
1017  use.set(builder.create<ReadInOutOp>(wireOp));
1018 
1019  structCreateOp.erase();
1020  continue;
1021  }
1022 
1023  // Force array index expressions to be a simple name when the
1024  // `mitigateVivadoArrayIndexConstPropBug` option is set.
1026  isa<ArraySliceOp, ArrayGetOp, ArrayIndexInOutOp,
1027  IndexedPartSelectInOutOp, IndexedPartSelectOp>(&op)) {
1028 
1029  // Check if the index expression is already a wire.
1030  Value wireOp;
1031  Value readOp;
1032  if (auto maybeReadOp =
1033  op.getOperand(1).getDefiningOp<sv::ReadInOutOp>()) {
1034  if (isa_and_nonnull<sv::WireOp, LogicOp>(
1035  maybeReadOp.getInput().getDefiningOp())) {
1036  wireOp = maybeReadOp.getInput();
1037  readOp = maybeReadOp;
1038  }
1039  }
1040 
1041  // Insert a wire and read if necessary.
1042  ImplicitLocOpBuilder builder(op.getLoc(), &op);
1043  if (!wireOp) {
1044  auto type = op.getOperand(1).getType();
1045  const auto *name = "_GEN_ARRAY_IDX";
1046  if (op.getParentOp()->hasTrait<ProceduralRegion>()) {
1047  wireOp = builder.create<LogicOp>(type, name);
1048  builder.create<BPAssignOp>(wireOp, op.getOperand(1));
1049  } else {
1050  wireOp = builder.create<sv::WireOp>(type, name);
1051  builder.create<AssignOp>(wireOp, op.getOperand(1));
1052  }
1053  readOp = builder.create<ReadInOutOp>(wireOp);
1054  }
1055  op.setOperand(1, readOp);
1056 
1057  // Add a `(* keep = "true" *)` SV attribute to the wire.
1058  sv::addSVAttributes(wireOp.getDefiningOp(),
1059  SVAttributeAttr::get(wireOp.getContext(), "keep",
1060  R"("true")",
1061  /*emitAsComment=*/false));
1062  continue;
1063  }
1064 
1065  // If this expression is deemed worth spilling into a wire, do it here.
1066  if (shouldSpillWire(op, options)) {
1067  // We first check that it is possible to reuse existing wires as a spilled
1068  // wire. Otherwise, create a new wire op.
1069  if (isProceduralRegion || !reuseExistingInOut(&op, options)) {
1070  if (options.disallowLocalVariables) {
1071  // If we're not in a procedural region, or we are, but we can hoist
1072  // out of it, we are good to generate a wire.
1073  if (!isProceduralRegion ||
1074  (isProceduralRegion && hoistNonSideEffectExpr(&op))) {
1075  // If op is moved to a non-procedural region, create a temporary
1076  // wire.
1077  if (!op.getParentOp()->hasTrait<ProceduralRegion>())
1079 
1080  // If we're in a procedural region, we move on to the next op in the
1081  // block. The expression splitting and canonicalization below will
1082  // happen after we recurse back up. If we're not in a procedural
1083  // region, the expression can continue being worked on.
1084  if (isProceduralRegion)
1085  continue;
1086  }
1087  } else {
1088  // If `disallowLocalVariables` is not enabled, we can spill the
1089  // expression to automatic logic declarations even when the op is in a
1090  // procedural region.
1092  }
1093  }
1094  }
1095 
1096  // Lower variadic fully-associative operations with more than two operands
1097  // into balanced operand trees so we can split long lines across multiple
1098  // statements.
1099  // TODO: This is checking the Commutative property, which doesn't seem
1100  // right in general. MLIR doesn't have a "fully associative" property.
1101  if (op.getNumOperands() > 2 && op.getNumResults() == 1 &&
1102  op.hasTrait<mlir::OpTrait::IsCommutative>() &&
1103  mlir::isMemoryEffectFree(&op) && op.getNumRegions() == 0 &&
1104  op.getNumSuccessors() == 0 &&
1105  llvm::all_of(op.getAttrs(), [](NamedAttribute attr) {
1106  return attr.getNameDialect() != nullptr ||
1107  attr.getName() == "twoState";
1108  })) {
1109  // Lower this operation to a balanced binary tree of the same operation.
1110  SmallVector<Operation *> newOps;
1111  auto result = lowerFullyAssociativeOp(op, op.getOperands(), newOps);
1112  op.getResult(0).replaceAllUsesWith(result);
1113  op.erase();
1114 
1115  // Make sure we revisit the newly inserted operations.
1116  opIterator = Block::iterator(newOps.front());
1117  continue;
1118  }
1119 
1120  // Turn a + -cst ==> a - cst
1121  if (auto addOp = dyn_cast<comb::AddOp>(op)) {
1122  if (auto cst = addOp.getOperand(1).getDefiningOp<hw::ConstantOp>()) {
1123  assert(addOp.getNumOperands() == 2 && "commutative lowering is done");
1124  if (cst.getValue().isNegative()) {
1125  Operation *firstOp = rewriteAddWithNegativeConstant(addOp, cst);
1126  opIterator = Block::iterator(firstOp);
1127  continue;
1128  }
1129  }
1130  }
1131 
1132  // Lower hw.struct_explode ops into a set of hw.struct_extract ops which
1133  // have well-defined SV emission semantics.
1134  if (auto structExplodeOp = dyn_cast<hw::StructExplodeOp>(op)) {
1135  Operation *firstOp = lowerStructExplodeOp(structExplodeOp);
1136  opIterator = Block::iterator(firstOp);
1137  continue;
1138  }
1139 
1140  // Try to anticipate expressions that ExportVerilog may spill to a temporary
1141  // inout, and re-use an existing inout when possible. This is legal when op
1142  // is an expression in a non-procedural region.
1143  if (!isProceduralRegion && isVerilogExpression(&op))
1144  (void)reuseExistingInOut(&op, options);
1145  }
1146 
1147  // Move debug operations to the end of the block.
1148  auto debugBuilder = OpBuilder::atBlockEnd(&block);
1149  if (!block.empty() && block.back().mightHaveTrait<OpTrait::IsTerminator>())
1150  debugBuilder.setInsertionPoint(&block.back());
1151  for (auto *op : debugOpsToMoveToEnd) {
1152  op->remove();
1153  debugBuilder.insert(op);
1154  }
1155 
1156  if (isProceduralRegion) {
1157  // If there is no operation, there is nothing to do.
1158  if (block.empty())
1159  return success();
1160 
1161  // In a procedural region, logic operations needs to be top of blocks so
1162  // mvoe logic operations to valid program points.
1163 
1164  // This keeps tracks of an insertion point of logic op.
1165  std::pair<Block *, Block::iterator> logicOpInsertionPoint =
1166  findLogicOpInsertionPoint(&block.front());
1167  for (auto &op : llvm::make_early_inc_range(block)) {
1168  if (auto logic = dyn_cast<LogicOp>(&op)) {
1169  // If the logic op is already located at the given point, increment the
1170  // iterator to keep the order of logic operations in the block.
1171  if (logicOpInsertionPoint.second == logic->getIterator()) {
1172  ++logicOpInsertionPoint.second;
1173  continue;
1174  }
1175  // Otherwise, move the op to the insertion point.
1176  logic->moveBefore(logicOpInsertionPoint.first,
1177  logicOpInsertionPoint.second);
1178  }
1179  }
1180  return success();
1181  }
1182 
1183  // Now that all the basic ops are settled, check for any use-before def issues
1184  // in graph regions. Lower these into explicit wires to keep the emitter
1185  // simple.
1186 
1187  SmallPtrSet<Operation *, 32> seenOperations;
1188 
1189  for (auto &op : llvm::make_early_inc_range(block)) {
1190  // Do not reorder LTL expressions, which are always emitted inline. Ignore
1191  // debug operations which are not emitted as Verilog.
1192  if (isa<ltl::LTLDialect, debug::DebugDialect>(op.getDialect()))
1193  continue;
1194 
1195  // Check the users of any expressions to see if they are
1196  // lexically below the operation itself. If so, it is being used out
1197  // of order.
1198  bool haveAnyOutOfOrderUses = false;
1199  for (auto *userOp : op.getUsers()) {
1200  // If the user is in a suboperation like an always block, then zip up
1201  // to the operation that uses it.
1202  while (&block != &userOp->getParentRegion()->front())
1203  userOp = userOp->getParentOp();
1204 
1205  if (seenOperations.count(userOp)) {
1206  haveAnyOutOfOrderUses = true;
1207  break;
1208  }
1209  }
1210 
1211  // Remember that we've seen this operation.
1212  seenOperations.insert(&op);
1213 
1214  // If all the uses of the operation are below this, then we're ok.
1215  if (!haveAnyOutOfOrderUses)
1216  continue;
1217 
1218  // If this is a reg/wire declaration, then we move it to the top of the
1219  // block. We can't abstract the inout result.
1220  if (isMovableDeclaration(&op)) {
1221  op.moveBefore(&block.front());
1222  continue;
1223  }
1224 
1225  // If this is a constant, then we move it to the top of the block.
1226  if (isConstantExpression(&op)) {
1227  op.moveBefore(&block.front());
1228  continue;
1229  }
1230 
1231  // If this is a an operation reading from a declaration, move it up,
1232  // along with the corresponding declaration.
1233  if (auto readInOut = dyn_cast<ReadInOutOp>(op)) {
1234  auto *def = readInOut.getInput().getDefiningOp();
1235  if (isMovableDeclaration(def)) {
1236  op.moveBefore(&block.front());
1237  def->moveBefore(&block.front());
1238  continue;
1239  }
1240  }
1241 
1242  // Otherwise, we need to lower this to a wire to resolve this.
1244  /*emitWireAtBlockBegin=*/true);
1245  }
1246  return success();
1247 }
1248 
1249 // NOLINTNEXTLINE(misc-no-recursion)
1251  const LoweringOptions &options) {
1252  // Zero-valued logic pruning.
1253  pruneZeroValuedLogic(module);
1254 
1255  // Legalization.
1256  if (failed(legalizeHWModule(*module.getBodyBlock(), options)))
1257  return failure();
1258 
1259  EmittedExpressionStateManager expressionStateManager(options);
1260  // Spill wires to prettify verilog outputs.
1261  prettifyAfterLegalization(*module.getBodyBlock(), expressionStateManager);
1262  return success();
1263 }
1264 
1265 namespace {
1266 
1267 struct PrepareForEmissionPass
1268  : public PrepareForEmissionBase<PrepareForEmissionPass> {
1269  void runOnOperation() override {
1270  HWModuleOp module = getOperation();
1271  LoweringOptions options(cast<mlir::ModuleOp>(module->getParentOp()));
1272  if (failed(prepareHWModule(module, options)))
1273  signalPassFailure();
1274  }
1275 };
1276 
1277 } // end anonymous namespace
1278 
1279 std::unique_ptr<mlir::Pass> circt::createPrepareForEmissionPass() {
1280  return std::make_unique<PrepareForEmissionPass>();
1281 }
assert(baseType &&"element must be base type")
Builder builder
static void lowerUsersToTemporaryWire(Operation &op, bool emitWireAtBlockBegin=false)
Emit an explicit wire or logic to assign operation's result.
static StringAttr getResName(Operation *op, size_t idx)
static std::pair< Block *, Block::iterator > findLogicOpInsertionPoint(Operation *op)
static bool rewriteSideEffectingExpr(Operation *op)
This function is invoked on side effecting Verilog expressions when we're in 'disallowLocalVariables'...
static Operation * lowerStructExplodeOp(hw::StructExplodeOp op)
static void buildWireLowerings(Block &block, SmallVectorImpl< WireLowering > &wireLowerings)
Determine the insertion location of declaration and assignment ops for hw::WireOps in a block.
static StringAttr getArgName(Operation *op, size_t idx)
static void spillWiresForInstanceInputs(HWInstanceLike op)
static void prettifyAfterLegalization(Block &block, EmittedExpressionStateManager &expressionStateManager)
After the legalization, we are able to know accurate verilog AST structures.
static void lowerInstanceResults(HWInstanceLike op)
static bool hoistNonSideEffectExpr(Operation *op)
This function is called for non-side-effecting Verilog expressions when we're in 'disallowLocalVariab...
static Operation * findParentInNonProceduralRegion(Operation *op)
Given an operation in a procedural region, scan up the region tree to find the first operation in a g...
static Operation * rewriteAddWithNegativeConstant(comb::AddOp add, hw::ConstantOp rhsCst)
Transform "a + -cst" ==> "a - cst" for prettier output.
static void lowerAlwaysInlineOperation(Operation *op, const LoweringOptions &options)
static bool reuseExistingInOut(Operation *op, const LoweringOptions &options)
If exactly one use of this op is an assign, replace the other uses with a read from the assigned wire...
static bool isMovableDeclaration(Operation *op)
Check whether an op is a declaration that can be moved.
static LogicalResult legalizeHWModule(Block &block, const LoweringOptions &options)
For each module we emit, do a prepass over the structure, pre-lowering and otherwise rewriting operat...
static Value lowerFullyAssociativeOp(Operation &op, OperandRange operands, SmallVector< Operation * > &newOps)
Lower a variadic fully-associative operation into an expression tree.
static bool shouldSpillWire(Operation &op, const LoweringOptions &options)
static void applyWireLowerings(Block &block, ArrayRef< WireLowering > wireLowerings)
Materialize the SV wire declaration and assignment operations in the locations previously determined ...
This class handles information about AST structures of each expressions.
DenseMap< Value, EmittedExpressionState > expressionStates
EmittedExpressionState visitUnhandledSV(Operation *op)
EmittedExpressionStateManager(const LoweringOptions &options)
EmittedExpressionState visitInvalidComb(Operation *op)
EmittedExpressionState visitUnhandledTypeOp(Operation *op)
EmittedExpressionState getExpressionState(Value value)
const LoweringOptions & options
EmittedExpressionState visitUnhandledComb(Operation *op)
EmittedExpressionState mergeOperandsStates(Operation *op)
EmittedExpressionState visitUnhandledExpr(Operation *op)
bool shouldSpillWireBasedOnState(Operation &op)
Return true if it is beneficial to spill the operation under the specified spilling heuristic.
EmittedExpressionState visitInvalidTypeOp(Operation *op)
Definition: sv.py:68
Definition: sv.py:35
def connect(destination, source)
Definition: support.py:37
LogicalResult prepareHWModule(Block &block, const LoweringOptions &options)
For each module we emit, do a prepass over the structure, pre-lowering and otherwise rewriting operat...
bool isExpressionEmittedInline(Operation *op, const LoweringOptions &options)
Return true if this expression should be emitted inline into any statement that uses it.
bool isVerilogExpression(Operation *op)
This predicate returns true if the specified operation is considered a potentially inlinable Verilog ...
StringAttr inferStructuralNameForTemporary(Value expr)
Given an expression that is spilled into a temporary wire, try to synthesize a better name than "_T_4...
static bool isConstantExpression(Operation *op)
Return whether an operation is a constant.
bool isZeroBitType(Type type)
Return true if this is a zero bit type, e.g.
void pruneZeroValuedLogic(hw::HWModuleOp module)
bool isSimpleReadOrPort(Value v)
Check if the value is from read of a wire or reg or is a port.
static bool isExpressionAlwaysInline(Operation *op)
Return true for operations that must always be inlined into a containing expression for correctness.
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
Definition: CalyxOps.cpp:53
circt::hw::InOutType InOutType
Definition: SVTypes.h:25
unsigned addSVAttributes(mlir::Operation *op, llvm::ArrayRef< SVAttributeAttr > attrs)
Add a list of SV attributes to an operation.
This file defines an intermediate representation for circuits acting as an abstraction for constraint...
Definition: DebugAnalysis.h:21
std::unique_ptr< mlir::Pass > createPrepareForEmissionPass()
Definition: comb.py:1
Definition: hw.py:1
def reg(value, clock, reset=None, reset_value=None, name=None, sym_name=None)
Definition: seq.py:20
Definition: sv.py:1
static EmittedExpressionState getBaseState()
void mergeState(const EmittedExpressionState &state)
Block::iterator declarePoint
Block::iterator assignPoint
Options which control the emission from CIRCT to Verilog.
bool mitigateVivadoArrayIndexConstPropBug
If true, every expression used as an array index is driven by a wire, and the wire is marked as (* ke...
bool disallowLocalVariables
If true, do not emit SystemVerilog locally scoped "automatic" or logic declarations - emit top level ...
bool disallowExpressionInliningInPorts
If true, every expression passed to an instance port is driven by a wire.
bool disallowPackedStructAssignments
If true, eliminate packed struct assignments in favor of a wire + assignments to the individual field...