CIRCT  20.0.0git
Utilities.h
Go to the documentation of this file.
1 //===- Utilities.h - SSP <-> circt::scheduling infra conversion -*- C++ -*-===//
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 provides utilities for the conversion between SSP IR and the
10 // extensible problem model in the scheduling infrastructure.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #ifndef CIRCT_DIALECT_SSP_SSPUTILITIES_H
15 #define CIRCT_DIALECT_SSP_SSPUTILITIES_H
16 
21 
22 #include "mlir/IR/ImplicitLocOpBuilder.h"
23 #include "mlir/IR/SymbolTable.h"
24 
25 #include "llvm/ADT/DenseMap.h"
26 #include "llvm/ADT/TypeSwitch.h"
27 
28 #include <functional>
29 
30 namespace circt {
31 namespace ssp {
32 
35 
36 //===----------------------------------------------------------------------===//
37 // ssp.InstanceOp -> circt::scheduling::Problem (or subclasses)
38 //===----------------------------------------------------------------------===//
39 
40 template <typename ProblemT>
41 void loadOperationProperties(ProblemT &, Operation *, ArrayAttr) {}
42 template <typename ProblemT, typename OperationPropertyT,
43  typename... OperationPropertyTs>
44 void loadOperationProperties(ProblemT &prob, Operation *op, ArrayAttr props) {
45  if (!props)
46  return;
47  for (auto prop : props) {
48  TypeSwitch<Attribute>(prop)
49  .Case<OperationPropertyT, OperationPropertyTs...>(
50  [&](auto p) { p.setInProblem(prob, op); });
51  }
52 }
53 
54 template <typename ProblemT>
55 void loadOperatorTypeProperties(ProblemT &, OperatorType, ArrayAttr) {}
56 template <typename ProblemT, typename OperatorTypePropertyT,
57  typename... OperatorTypePropertyTs>
58 void loadOperatorTypeProperties(ProblemT &prob, OperatorType opr,
59  ArrayAttr props) {
60  if (!props)
61  return;
62  for (auto prop : props) {
63  TypeSwitch<Attribute>(prop)
64  .Case<OperatorTypePropertyT, OperatorTypePropertyTs...>(
65  [&](auto p) { p.setInProblem(prob, opr); });
66  }
67 }
68 
69 template <typename ProblemT>
70 void loadDependenceProperties(ProblemT &, Dependence, ArrayAttr) {}
71 template <typename ProblemT, typename DependencePropertyT,
72  typename... DependencePropertyTs>
73 void loadDependenceProperties(ProblemT &prob, Dependence dep, ArrayAttr props) {
74  if (!props)
75  return;
76  for (auto prop : props) {
77  TypeSwitch<Attribute>(prop)
78  .Case<DependencePropertyT, DependencePropertyTs...>(
79  [&](auto p) { p.setInProblem(prob, dep); });
80  }
81 }
82 
83 template <typename ProblemT>
84 void loadInstanceProperties(ProblemT &, ArrayAttr) {}
85 template <typename ProblemT, typename InstancePropertyT,
86  typename... InstancePropertyTs>
87 void loadInstanceProperties(ProblemT &prob, ArrayAttr props) {
88  if (!props)
89  return;
90  for (auto prop : props) {
91  TypeSwitch<Attribute>(prop).Case<InstancePropertyT, InstancePropertyTs...>(
92  [&](auto p) { p.setInProblem(prob); });
93  }
94 }
95 
96 /// Load the operator type represented by \p oprOp into \p prob under a unique
97 /// name informed by \p oprIds, and attempt to set its properties from the
98 /// given attribute classes. The registered name is returned. The template
99 /// instantiation fails if properties are incompatible with \p ProblemT.
100 template <typename ProblemT, typename... OperatorTypePropertyTs>
101 OperatorType loadOperatorType(ProblemT &prob, OperatorTypeOp oprOp,
103  OperatorType opr = oprOp.getNameAttr();
104  unsigned &id = oprIds[opr];
105  if (id > 0)
106  opr = StringAttr::get(opr.getContext(),
107  opr.getValue() + Twine('_') + Twine(id));
108  ++id;
109  assert(!prob.hasOperatorType(opr));
110  prob.insertOperatorType(opr);
111  loadOperatorTypeProperties<ProblemT, OperatorTypePropertyTs...>(
112  prob, opr, oprOp.getSspPropertiesAttr());
113  return opr;
114 }
115 
116 /// Construct an instance of \p ProblemT from \p instOp, and attempt to set
117 /// properties from the given attribute classes. The attribute tuples are used
118 /// solely for grouping/inferring the template parameter packs. The tuple
119 /// elements may therefore be unitialized objects. The template instantiation
120 /// fails if properties are incompatible with \p ProblemT.
121 ///
122 /// Operations may link to operator types in other libraries, but the origin of
123 /// an operator type will not be preserved in the problem instance. As this
124 /// could lead to conflicts, operator types will be automatically renamed in the
125 /// returned instance.
126 ///
127 /// Example: To load an instance of the `circt::scheduling::CyclicProblem` with
128 /// all its input and solution properties, call this as follows:
129 ///
130 /// ```
131 /// loadProblem<CyclicProblem>(instOp,
132 /// std::make_tuple(LinkedOperatorTypeAttr(), StartTimeAttr()),
133 /// std::make_tuple(LatencyAttr()),
134 /// std::make_tuple(DistanceAttr()),
135 /// std::make_tuple(InitiationIntervalAttr()));
136 /// ```
137 template <typename ProblemT, typename... OperationPropertyTs,
138  typename... OperatorTypePropertyTs, typename... DependencePropertyTs,
139  typename... InstancePropertyTs>
140 ProblemT loadProblem(InstanceOp instOp,
141  std::tuple<OperationPropertyTs...> opProps,
142  std::tuple<OperatorTypePropertyTs...> oprProps,
143  std::tuple<DependencePropertyTs...> depProps,
144  std::tuple<InstancePropertyTs...> instProps) {
145  ProblemT prob(instOp);
146 
147  loadInstanceProperties<ProblemT, InstancePropertyTs...>(
148  prob, instOp.getSspPropertiesAttr());
149  if (auto instName = instOp.getSymNameAttr())
150  prob.setInstanceName(instName);
151 
152  // Use IDs to disambiguate operator types with the same name defined in
153  // different libraries.
155  // Map `OperatorTypeOp`s to their (possibly uniqued) name in the problem
156  // instance.
158 
159  // Register all operator types in the instance's library.
160  auto libraryOp = instOp.getOperatorLibrary();
161  libraryOp.walk([&](OperatorTypeOp oprOp) {
162  operatorTypes[oprOp] =
163  loadOperatorType<ProblemT, OperatorTypePropertyTs...>(prob, oprOp,
164  operatorTypeIds);
165  });
166  if (auto libName = libraryOp.getSymNameAttr())
167  prob.setLibraryName(libName);
168 
169  // Register all operations first, in order to retain their original order.
170  auto graphOp = instOp.getDependenceGraph();
171  graphOp.walk([&](OperationOp opOp) {
172  prob.insertOperation(opOp);
173  loadOperationProperties<ProblemT, OperationPropertyTs...>(
174  prob, opOp, opOp.getSspPropertiesAttr());
175  if (auto opName = opOp.getSymNameAttr())
176  prob.setOperationName(opOp, opName);
177 
178  // Nothing else to check if no linked operator type is set for `opOp`,
179  // because the operation doesn't carry a `LinkedOperatorTypeAttr`, or that
180  // class is not part of the `OperationPropertyTs` to load.
181  if (!prob.getLinkedOperatorType(opOp).has_value())
182  return;
183 
184  // Otherwise, inspect the corresponding attribute to make sure the operator
185  // type is available.
186  SymbolRefAttr oprRef = opOp.getLinkedOperatorTypeAttr().getValue();
187 
188  Operation *oprOp;
189  // 1) Look in the instance's library.
190  oprOp = SymbolTable::lookupSymbolIn(libraryOp, oprRef);
191  // 2) Try to resolve a nested reference to the instance's library.
192  if (!oprOp)
193  oprOp = SymbolTable::lookupSymbolIn(instOp, oprRef);
194  // 3) Look outside of the instance.
195  if (!oprOp)
196  oprOp =
197  SymbolTable::lookupNearestSymbolFrom(instOp->getParentOp(), oprRef);
198 
199  assert(oprOp && isa<OperatorTypeOp>(oprOp)); // checked by verifier
200 
201  // Load the operator type from `oprOp` if needed.
202  auto &opr = operatorTypes[oprOp];
203  if (!opr)
204  opr = loadOperatorType<ProblemT, OperatorTypePropertyTs...>(
205  prob, cast<OperatorTypeOp>(oprOp), operatorTypeIds);
206 
207  // Update `opOp`'s property (may be a no-op if `opr` wasn't renamed).
208  prob.setLinkedOperatorType(opOp, opr);
209  });
210 
211  // Then walk them again, and load auxiliary dependences as well as any
212  // dependence properties.
213  graphOp.walk([&](OperationOp opOp) {
214  ArrayAttr depsAttr = opOp.getDependencesAttr();
215  if (!depsAttr)
216  return;
217 
218  for (auto depAttr : depsAttr.getAsRange<DependenceAttr>()) {
219  Dependence dep;
220  if (FlatSymbolRefAttr sourceRef = depAttr.getSourceRef()) {
221  Operation *sourceOp = SymbolTable::lookupSymbolIn(graphOp, sourceRef);
222  assert(sourceOp);
223  dep = Dependence(sourceOp, opOp);
224  LogicalResult res = prob.insertDependence(dep);
225  assert(succeeded(res));
226  (void)res;
227  } else
228  dep = Dependence(&opOp->getOpOperand(depAttr.getOperandIdx()));
229 
230  loadDependenceProperties<ProblemT, DependencePropertyTs...>(
231  prob, dep, depAttr.getProperties());
232  }
233  });
234 
235  return prob;
236 }
237 
238 //===----------------------------------------------------------------------===//
239 // circt::scheduling::Problem (or subclasses) -> ssp.InstanceOp
240 //===----------------------------------------------------------------------===//
241 
242 template <typename ProblemT, typename... OperationPropertyTs>
243 ArrayAttr saveOperationProperties(ProblemT &prob, Operation *op,
244  ImplicitLocOpBuilder &b) {
245  SmallVector<Attribute> props;
246  Attribute prop;
247  // Fold expression: Expands to a `getFromProblem` and a conditional
248  // `push_back` call for each of the `OperationPropertyTs`.
249  ((prop = OperationPropertyTs::getFromProblem(prob, op, b.getContext()),
250  prop ? props.push_back(prop) : (void)prop),
251  ...);
252  return props.empty() ? ArrayAttr() : b.getArrayAttr(props);
253 }
254 
255 template <typename ProblemT, typename... OperatorTypePropertyTs>
256 ArrayAttr saveOperatorTypeProperties(ProblemT &prob, OperatorType opr,
257  ImplicitLocOpBuilder &b) {
258  SmallVector<Attribute> props;
259  Attribute prop;
260  // Fold expression: Expands to a `getFromProblem` and a conditional
261  // `push_back` call for each of the `OperatorTypePropertyTs`.
262  ((prop = OperatorTypePropertyTs::getFromProblem(prob, opr, b.getContext()),
263  prop ? props.push_back(prop) : (void)prop),
264  ...);
265  return props.empty() ? ArrayAttr() : b.getArrayAttr(props);
266 }
267 
268 template <typename ProblemT, typename... DependencePropertyTs>
269 ArrayAttr saveDependenceProperties(ProblemT &prob, Dependence dep,
270  ImplicitLocOpBuilder &b) {
271  SmallVector<Attribute> props;
272  Attribute prop;
273  // Fold expression: Expands to a `getFromProblem` and a conditional
274  // `push_back` call for each of the `DependencePropertyTs`.
275  ((prop = DependencePropertyTs::getFromProblem(prob, dep, b.getContext()),
276  prop ? props.push_back(prop) : (void)prop),
277  ...);
278  return props.empty() ? ArrayAttr() : b.getArrayAttr(props);
279 }
280 
281 template <typename ProblemT, typename... InstancePropertyTs>
282 ArrayAttr saveInstanceProperties(ProblemT &prob, ImplicitLocOpBuilder &b) {
283  SmallVector<Attribute> props;
284  Attribute prop;
285  // Fold expression: Expands to a `getFromProblem` and a conditional
286  // `push_back` call for each of the `InstancePropertyTs`.
287  ((prop = InstancePropertyTs::getFromProblem(prob, b.getContext()),
288  prop ? props.push_back(prop) : (void)prop),
289  ...);
290  return props.empty() ? ArrayAttr() : b.getArrayAttr(props);
291 }
292 
293 /// Construct an `InstanceOp` from a given \p ProblemT instance, and
294 /// create/attach attributes of the given classes for the corresponding
295 /// properties on the scheduling problem. The returned `InstanceOp` uses the
296 /// given \p instanceName and \p problemName. `OperationOp`s are created
297 /// unnamed, unless they represent the source operation in an auxiliary
298 /// dependence, or the \p operationNameFn callback returns a non-null
299 /// `StringAttr` with the desired name. The attribute tuples are used
300 /// solely for grouping/inferring the template parameter packs. The tuple
301 /// elements may therefore be unitialized objects. The template instantiation
302 /// fails if properties are incompatible with \p ProblemT.
303 ///
304 /// Example: To save an instance of the `circt::scheduling::CyclicProblem` with
305 /// all its input and solution properties, and reyling on default operation
306 /// names, call this as follows:
307 ///
308 /// ```
309 /// saveProblem<CyclicProblem>(prob,
310 /// std::make_tuple(LinkedOperatorTypeAttr(), StartTimeAttr()),
311 /// std::make_tuple(LatencyAttr()),
312 /// std::make_tuple(DistanceAttr()),
313 /// std::make_tuple(InitiationIntervalAttr()),
314 /// builder);
315 /// ```
316 template <typename ProblemT, typename... OperationPropertyTs,
317  typename... OperatorTypePropertyTs, typename... DependencePropertyTs,
318  typename... InstancePropertyTs>
319 InstanceOp
320 saveProblem(ProblemT &prob, std::tuple<OperationPropertyTs...> opProps,
321  std::tuple<OperatorTypePropertyTs...> oprProps,
322  std::tuple<DependencePropertyTs...> depProps,
323  std::tuple<InstancePropertyTs...> instProps, OpBuilder &builder) {
324  ImplicitLocOpBuilder b(builder.getUnknownLoc(), builder);
325 
326  // Set up instance.
327  auto instOp = b.create<InstanceOp>(
328  builder.getStringAttr(ProblemT::name),
329  saveInstanceProperties<ProblemT, InstancePropertyTs...>(prob, b));
330  if (auto instName = prob.getInstanceName())
331  instOp.setSymNameAttr(instName);
332 
333  // Emit operator types.
334  b.setInsertionPointToEnd(instOp.getBodyBlock());
335  auto libraryOp = b.create<OperatorLibraryOp>();
336  if (auto libName = prob.getLibraryName())
337  libraryOp.setSymNameAttr(libName);
338  b.setInsertionPointToStart(libraryOp.getBodyBlock());
339 
340  for (auto opr : prob.getOperatorTypes())
341  b.create<OperatorTypeOp>(
342  opr, saveOperatorTypeProperties<ProblemT, OperatorTypePropertyTs...>(
343  prob, opr, b));
344 
345  // Determine which operations act as source ops for auxiliary dependences, and
346  // therefore need a name. Also, honor names provided by the client.
347  DenseMap<Operation *, StringAttr> opNames;
348  for (auto *op : prob.getOperations()) {
349  if (auto opName = prob.getOperationName(op))
350  opNames[op] = opName;
351 
352  for (auto &dep : prob.getDependences(op)) {
353  Operation *src = dep.getSource();
354  if (!dep.isAuxiliary() || opNames.count(src))
355  continue;
356  if (auto srcOpName = prob.getOperationName(src)) {
357  opNames[src] = srcOpName;
358  continue;
359  }
360  opNames[src] = b.getStringAttr(Twine("Op") + Twine(opNames.size()));
361  }
362  }
363 
364  // Construct operations and model their dependences.
365  b.setInsertionPointToEnd(instOp.getBodyBlock());
366  auto graphOp = b.create<DependenceGraphOp>();
367  b.setInsertionPointToStart(graphOp.getBodyBlock());
368 
369  BackedgeBuilder backedgeBuilder(b, b.getLoc());
370  ValueMapper v(&backedgeBuilder);
371  for (auto *op : prob.getOperations()) {
372  // Construct the `dependences attribute`. It contains `DependenceAttr` for
373  // def-use deps _with_ properties, and all aux deps.
374  ArrayAttr dependences;
375  SmallVector<Attribute> depAttrs;
376  unsigned auxOperandIdx = op->getNumOperands();
377  for (auto &dep : prob.getDependences(op)) {
378  ArrayAttr depProps =
379  saveDependenceProperties<ProblemT, DependencePropertyTs...>(prob, dep,
380  b);
381  if (dep.isDefUse() && depProps) {
382  auto depAttr = b.getAttr<DependenceAttr>(*dep.getDestinationIndex(),
383  FlatSymbolRefAttr(), depProps);
384  depAttrs.push_back(depAttr);
385  continue;
386  }
387 
388  if (!dep.isAuxiliary())
389  continue;
390 
391  auto sourceOpName = opNames.lookup(dep.getSource());
392  assert(sourceOpName);
393  auto sourceRef = b.getAttr<FlatSymbolRefAttr>(sourceOpName);
394  auto depAttr =
395  b.getAttr<DependenceAttr>(auxOperandIdx, sourceRef, depProps);
396  depAttrs.push_back(depAttr);
397  ++auxOperandIdx;
398  }
399  if (!depAttrs.empty())
400  dependences = b.getArrayAttr(depAttrs);
401 
402  // Delegate to helper to construct the `properties` attribute.
403  ArrayAttr properties =
404  saveOperationProperties<ProblemT, OperationPropertyTs...>(prob, op, b);
405 
406  // Finally, create the `OperationOp` and inform the value mapper.
407  // NB: sym_name, dependences and properties are optional attributes, so
408  // passing potentially unitialized String/ArrayAttrs is intentional here.
409  auto opOp =
410  b.create<OperationOp>(op->getNumResults(), v.get(op->getOperands()),
411  opNames.lookup(op), dependences, properties);
412  v.set(op->getResults(), opOp->getResults());
413  }
414 
415  return instOp;
416 }
417 
418 /// Dummy struct to query a problem's default properties (i.e. all input and
419 /// solution properties). Specializations shall provide the following
420 /// definitions:
421 ///
422 /// ```
423 /// static constexpr auto operationProperties = std::make_tuple(...);
424 /// static constexpr auto operatorTypeProperties = std::make_tuple(...);
425 /// static constexpr auto dependenceProperties = std::make_tuple(...);
426 /// static constexpr auto instanceProperties = std::make_tuple(...);
427 /// ```
428 template <typename ProblemT>
429 struct Default {};
430 
431 /// Construct an instance of \p ProblemT from \p instOp, and attempt to set all
432 /// of the problem class' properties.
433 ///
434 /// Relies on the specialization of template `circt::ssp::Default` for \p
435 /// ProblemT.
436 template <typename ProblemT>
437 ProblemT loadProblem(InstanceOp instOp) {
438  return loadProblem<ProblemT>(instOp, Default<ProblemT>::operationProperties,
442 }
443 
444 /// Construct an `InstanceOp` from a given \p ProblemT instance, and
445 /// create/attach attributes for all of the problem class' properties.
446 ///
447 /// Relies on the specialization of template `circt::ssp::Default` for \p
448 /// ProblemT.
449 template <typename ProblemT>
450 InstanceOp saveProblem(ProblemT &prob, OpBuilder &builder) {
451  return saveProblem<ProblemT>(prob, Default<ProblemT>::operationProperties,
455 }
456 
457 //===----------------------------------------------------------------------===//
458 // Default property tuples for the built-in problems
459 //===----------------------------------------------------------------------===//
460 
461 template <>
462 struct Default<scheduling::Problem> {
463  static constexpr auto operationProperties =
464  std::make_tuple(LinkedOperatorTypeAttr(), StartTimeAttr());
465  static constexpr auto operatorTypeProperties = std::make_tuple(LatencyAttr());
466  static constexpr auto dependenceProperties = std::make_tuple();
467  static constexpr auto instanceProperties = std::make_tuple();
468 };
469 
470 template <>
471 struct Default<scheduling::CyclicProblem> {
472  static constexpr auto operationProperties =
474  static constexpr auto operatorTypeProperties =
476  static constexpr auto dependenceProperties =
478  std::make_tuple(DistanceAttr()));
479  static constexpr auto instanceProperties =
481  std::make_tuple(InitiationIntervalAttr()));
482 };
483 
484 template <>
485 struct Default<scheduling::ChainingProblem> {
486  static constexpr auto operationProperties =
488  std::make_tuple(StartTimeInCycleAttr()));
489  static constexpr auto operatorTypeProperties =
491  std::make_tuple(IncomingDelayAttr(), OutgoingDelayAttr()));
492  static constexpr auto dependenceProperties =
494  static constexpr auto instanceProperties =
496 };
497 
498 template <>
499 struct Default<scheduling::SharedOperatorsProblem> {
500  static constexpr auto operationProperties =
502  static constexpr auto operatorTypeProperties =
504  std::make_tuple(LimitAttr()));
505  static constexpr auto dependenceProperties =
507  static constexpr auto instanceProperties =
509 };
510 
511 template <>
512 struct Default<scheduling::ModuloProblem> {
513  static constexpr auto operationProperties =
515  static constexpr auto operatorTypeProperties =
517  static constexpr auto dependenceProperties =
519  static constexpr auto instanceProperties =
521 };
522 
523 template <>
524 struct Default<scheduling::ChainingCyclicProblem> {
525  static constexpr auto operationProperties =
527  static constexpr auto operatorTypeProperties =
529  static constexpr auto dependenceProperties =
531  static constexpr auto instanceProperties =
533 };
534 
535 } // namespace ssp
536 } // namespace circt
537 
538 #endif // CIRCT_DIALECT_SSP_SSPUTILITIES_H
assert(baseType &&"element must be base type")
Instantiate one of these and use it to build typed backedges.
The ValueMapper class facilitates the definition and connection of SSA def-use chains between two loc...
Definition: ValueMapper.h:35
void set(mlir::Value from, mlir::Value to, bool replace=false)
mlir::Value get(mlir::Value from, TypeTransformer typeTransformer=ValueMapper::identity)
detail::Dependence Dependence
A thin wrapper to allow a uniform handling of def-use and auxiliary dependences.
Definition: Problems.h:95
mlir::StringAttr OperatorType
Operator types are distinguished by name (chosen by the client).
Definition: Problems.h:98
A wrapper class to uniformly handle def-use and auxiliary dependence edges.
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
Definition: CalyxOps.cpp:55
scheduling::Problem::Dependence Dependence
Definition: Utilities.h:34
void loadInstanceProperties(ProblemT &, ArrayAttr)
Definition: Utilities.h:84
void loadOperationProperties(ProblemT &, Operation *, ArrayAttr)
Definition: Utilities.h:41
ArrayAttr saveDependenceProperties(ProblemT &prob, Dependence dep, ImplicitLocOpBuilder &b)
Definition: Utilities.h:269
void loadOperatorTypeProperties(ProblemT &, OperatorType, ArrayAttr)
Definition: Utilities.h:55
ArrayAttr saveOperatorTypeProperties(ProblemT &prob, OperatorType opr, ImplicitLocOpBuilder &b)
Definition: Utilities.h:256
ProblemT loadProblem(InstanceOp instOp, std::tuple< OperationPropertyTs... > opProps, std::tuple< OperatorTypePropertyTs... > oprProps, std::tuple< DependencePropertyTs... > depProps, std::tuple< InstancePropertyTs... > instProps)
Construct an instance of ProblemT from instOp, and attempt to set properties from the given attribute...
Definition: Utilities.h:140
void loadDependenceProperties(ProblemT &, Dependence, ArrayAttr)
Definition: Utilities.h:70
ArrayAttr saveInstanceProperties(ProblemT &prob, ImplicitLocOpBuilder &b)
Definition: Utilities.h:282
scheduling::Problem::OperatorType OperatorType
Definition: Utilities.h:33
ArrayAttr saveOperationProperties(ProblemT &prob, Operation *op, ImplicitLocOpBuilder &b)
Definition: Utilities.h:243
InstanceOp saveProblem(ProblemT &prob, std::tuple< OperationPropertyTs... > opProps, std::tuple< OperatorTypePropertyTs... > oprProps, std::tuple< DependencePropertyTs... > depProps, std::tuple< InstancePropertyTs... > instProps, OpBuilder &builder)
Construct an InstanceOp from a given ProblemT instance, and create/attach attributes of the given cla...
Definition: Utilities.h:320
OperatorType loadOperatorType(ProblemT &prob, OperatorTypeOp oprOp, SmallDenseMap< StringAttr, unsigned > &oprIds)
Load the operator type represented by oprOp into prob under a unique name informed by oprIds,...
Definition: Utilities.h:101
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
Definition: DebugAnalysis.h:21
Dummy struct to query a problem's default properties (i.e.
Definition: Utilities.h:429