CIRCT  20.0.0git
LTLToCore.cpp
Go to the documentation of this file.
1 //===- LTLToCore.cpp -----------------------------------------------------===//
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 // Converts LTL and Verif operations to Core operations
10 //
11 //===----------------------------------------------------------------------===//
12 
16 #include "circt/Dialect/HW/HWOps.h"
20 #include "circt/Dialect/SV/SVOps.h"
25 #include "mlir/Dialect/Func/IR/FuncOps.h"
26 #include "mlir/Dialect/LLVMIR/LLVMDialect.h"
27 #include "mlir/Dialect/SCF/IR/SCF.h"
28 #include "mlir/Pass/Pass.h"
29 #include "mlir/Transforms/DialectConversion.h"
30 #include "llvm/Support/MathExtras.h"
31 
32 namespace circt {
33 #define GEN_PASS_DEF_LOWERLTLTOCORE
34 #include "circt/Conversion/Passes.h.inc"
35 } // namespace circt
36 
37 using namespace mlir;
38 using namespace circt;
39 using namespace hw;
40 
41 //===----------------------------------------------------------------------===//
42 // Conversion patterns
43 //===----------------------------------------------------------------------===//
44 
45 namespace {
46 struct HasBeenResetOpConversion : OpConversionPattern<verif::HasBeenResetOp> {
48 
49  // HasBeenReset generates a 1 bit register that is set to one once the reset
50  // has been raised and lowered at at least once.
51  LogicalResult
52  matchAndRewrite(verif::HasBeenResetOp op, OpAdaptor adaptor,
53  ConversionPatternRewriter &rewriter) const override {
54  auto i1 = rewriter.getI1Type();
55  // Generate the constant used to set the register value
56  Value constZero = seq::createConstantInitialValue(
57  rewriter, op->getLoc(), rewriter.getIntegerAttr(i1, 0));
58 
59  // Generate the constant used to enegate the
60  Value constOne = rewriter.create<hw::ConstantOp>(op.getLoc(), i1, 1);
61 
62  // Create a backedge for the register to be used in the OrOp
63  circt::BackedgeBuilder bb(rewriter, op.getLoc());
64  circt::Backedge reg = bb.get(rewriter.getI1Type());
65 
66  // Generate an or between the reset and the register's value to store
67  // whether or not the reset has been active at least once
68  Value orReset =
69  rewriter.create<comb::OrOp>(op.getLoc(), adaptor.getReset(), reg);
70 
71  // This register should not be reset, so we give it dummy reset and resetval
72  // operands to fit the build signature
73  Value reset, resetval;
74 
75  // Finally generate the register to set the backedge
76  reg.setValue(rewriter.create<seq::CompRegOp>(
77  op.getLoc(), orReset,
78  rewriter.createOrFold<seq::ToClockOp>(op.getLoc(), adaptor.getClock()),
79  rewriter.getStringAttr("hbr"), reset, resetval, constZero,
80  InnerSymAttr{} // inner_sym
81  ));
82 
83  // We also need to consider the case where we are currently in a reset cycle
84  // in which case our hbr register should be down-
85  // Practically this means converting it to (and hbr (not reset))
86  Value notReset =
87  rewriter.create<comb::XorOp>(op.getLoc(), adaptor.getReset(), constOne);
88  rewriter.replaceOpWithNewOp<comb::AndOp>(op, reg, notReset);
89 
90  return success();
91  }
92 };
93 
94 } // namespace
95 
96 //===----------------------------------------------------------------------===//
97 // Lower LTL To Core pass
98 //===----------------------------------------------------------------------===//
99 
100 namespace {
101 struct LowerLTLToCorePass
102  : public circt::impl::LowerLTLToCoreBase<LowerLTLToCorePass> {
103  LowerLTLToCorePass() = default;
104  void runOnOperation() override;
105 };
106 } // namespace
107 
108 // Simply applies the conversion patterns defined above
109 void LowerLTLToCorePass::runOnOperation() {
110 
111  // Set target dialects: We don't want to see any ltl or verif that might
112  // come from an AssertProperty left in the result
113  ConversionTarget target(getContext());
114  target.addLegalDialect<hw::HWDialect>();
115  target.addLegalDialect<comb::CombDialect>();
116  target.addLegalDialect<sv::SVDialect>();
117  target.addLegalDialect<seq::SeqDialect>();
118  target.addLegalDialect<ltl::LTLDialect>();
119  target.addLegalDialect<verif::VerifDialect>();
120  target.addIllegalOp<verif::HasBeenResetOp>();
121 
122  // Create type converters, mostly just to convert an ltl property to a bool
123  mlir::TypeConverter converter;
124 
125  // Convert the ltl property type to a built-in type
126  converter.addConversion([](IntegerType type) { return type; });
127  converter.addConversion([](ltl::PropertyType type) {
128  return IntegerType::get(type.getContext(), 1);
129  });
130  converter.addConversion([](ltl::SequenceType type) {
131  return IntegerType::get(type.getContext(), 1);
132  });
133 
134  // Basic materializations
135  converter.addTargetMaterialization(
136  [&](mlir::OpBuilder &builder, mlir::Type resultType,
137  mlir::ValueRange inputs, mlir::Location loc) -> mlir::Value {
138  if (inputs.size() != 1)
139  return Value();
140  return builder
141  .create<UnrealizedConversionCastOp>(loc, resultType, inputs[0])
142  ->getResult(0);
143  });
144 
145  converter.addSourceMaterialization(
146  [&](mlir::OpBuilder &builder, mlir::Type resultType,
147  mlir::ValueRange inputs, mlir::Location loc) -> mlir::Value {
148  if (inputs.size() != 1)
149  return Value();
150  return builder
151  .create<UnrealizedConversionCastOp>(loc, resultType, inputs[0])
152  ->getResult(0);
153  });
154 
155  // Create the operation rewrite patters
156  RewritePatternSet patterns(&getContext());
157  patterns.add<HasBeenResetOpConversion>(converter, patterns.getContext());
158 
159  // Apply the conversions
160  if (failed(
161  applyPartialConversion(getOperation(), target, std::move(patterns))))
162  return signalPassFailure();
163 }
164 
165 // Basic default constructor
166 std::unique_ptr<mlir::Pass> circt::createLowerLTLToCorePass() {
167  return std::make_unique<LowerLTLToCorePass>();
168 }
Instantiate one of these and use it to build typed backedges.
Backedge is a wrapper class around a Value.
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
Definition: CalyxOps.cpp:55
mlir::TypedValue< seq::ImmutableType > createConstantInitialValue(OpBuilder builder, Location loc, mlir::IntegerAttr attr)
Definition: SeqOps.cpp:1065
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
Definition: DebugAnalysis.h:21
std::unique_ptr< mlir::Pass > createLowerLTLToCorePass()
Definition: LTLToCore.cpp:166
Definition: hw.py:1
def reg(value, clock, reset=None, reset_value=None, name=None, sym_name=None)
Definition: seq.py:21