Jlm
RhlsToFirrtlConverter.hpp
Go to the documentation of this file.
1 /*
2  * Copyright 2021 Magnus Sjalander <work@sjalander.com>
3  * See COPYING for terms of redistribution.
4  */
5 
6 #ifndef JLM_HLS_BACKEND_RHLS2FIRRTL_RHLSTOFIRRTLCONVERTER_HPP
7 #define JLM_HLS_BACKEND_RHLS2FIRRTL_RHLSTOFIRRTLCONVERTER_HPP
8 
10 #include <jlm/hls/ir/hls.hpp>
16 #include <jlm/rvsdg/traverser.hpp>
17 
18 #include <mlir/IR/Builders.h>
19 #include <mlir/IR/BuiltinOps.h>
20 #include <mlir/IR/BuiltinTypes.h>
21 #include <mlir/IR/Verifier.h>
22 
23 #include <circt/Dialect/FIRRTL/FIREmitter.h>
24 #include <circt/Dialect/FIRRTL/FIRParser.h>
25 #include <circt/Dialect/FIRRTL/FIRRTLDialect.h>
26 #include <circt/Dialect/FIRRTL/FIRRTLOps.h>
27 #include <circt/Dialect/FIRRTL/FIRRTLTypes.h>
28 #include <circt/Dialect/FIRRTL/Namespace.h>
29 #include <circt/Support/LLVM.h>
30 
31 namespace jlm::hls
32 {
33 
35 {
36  std::string
37  extension() override
38  {
39  return ".fir";
40  }
41 
42 public:
43  std::string
45  {
46  return "MLIR/FIRRTL generator";
47  }
48 
50  : Context_(std::make_unique<::mlir::MLIRContext>()),
51  DefaultFIRVersion_{ 4, 0, 0 }
52  {
53  Context_->getOrLoadDialect<circt::firrtl::FIRRTLDialect>();
54  Builder_ = std::make_unique<::mlir::OpBuilder>(Context_.get());
55  }
56 
58 
60 
62  operator=(const RhlsToFirrtlConverter &) = delete;
63 
66 
67  circt::firrtl::CircuitOp
68  MlirGen(const rvsdg::LambdaNode * lamdaNode);
69 
70  void
71  WriteModuleToFile(const circt::firrtl::FModuleOp fModuleOp, const rvsdg::Node * node);
72 
73  void
74  WriteCircuitToFile(const circt::firrtl::CircuitOp circuit, std::string name);
75 
76  std::string
78  {
79  // Generate a FIRRTL circuit of the rvsdgModule
80  auto lambdaNode = get_hls_lambda(rvsdgModule);
81  auto mlirGen = RhlsToFirrtlConverter();
82  auto circuit = mlirGen.MlirGen(lambdaNode);
83  // Write the FIRRTL to a file
84  return mlirGen.toString(circuit);
85  }
86 
87  std::unique_ptr<mlir::ModuleOp>
89  {
90  auto lambdaNode = get_hls_lambda(rvsdgModule);
91  auto mlirGen = RhlsToFirrtlConverter();
92  auto circuit = mlirGen.MlirGen(lambdaNode);
93  std::unique_ptr<mlir::ModuleOp> module =
94  std::make_unique<mlir::ModuleOp>(mlir::ModuleOp::create(Builder_->getUnknownLoc()));
95  module->push_back(circuit);
96  return module;
97  }
98 
99 private:
100  std::string
101  toString(const circt::firrtl::CircuitOp circuit);
102 
103  std::unordered_map<std::string, circt::firrtl::FModuleLike> modules;
104  // FIRRTL generating functions
105  circt::firrtl::FModuleOp
106  MlirGen(LoopNode * loopNode, mlir::Block * circuitBody);
107  circt::firrtl::FModuleLike
108  MlirGen(rvsdg::Region * subRegion, mlir::Block * circuitBody);
109  circt::firrtl::FModuleLike
110  MlirGen(const jlm::rvsdg::SimpleNode * node);
111  // Operations
112  circt::firrtl::FModuleOp
113  MlirGenSink(const jlm::rvsdg::SimpleNode * node);
114  circt::firrtl::FModuleOp
116  circt::firrtl::FModuleOp
117  MlirGenFork(const jlm::rvsdg::SimpleNode * node);
118  circt::firrtl::FModuleOp
120  circt::firrtl::FModuleOp
121  MlirGenMem(const jlm::rvsdg::SimpleNode * node);
128  circt::firrtl::FModuleOp
136  circt::firrtl::FModuleOp
138  circt::firrtl::FModuleOp
140  circt::firrtl::FModuleOp
142  circt::firrtl::FModuleOp
144  circt::firrtl::FModuleOp
146  circt::firrtl::FModuleOp
148  circt::firrtl::FModuleOp
149  MlirGenPrint(const jlm::rvsdg::SimpleNode * node);
150  circt::firrtl::FModuleOp
152  circt::firrtl::FModuleOp
154  circt::firrtl::FModuleOp
156  circt::firrtl::FModuleOp
157  MlirGenDMux(const jlm::rvsdg::SimpleNode * node);
158  circt::firrtl::FModuleOp
159  MlirGenNDMux(const jlm::rvsdg::SimpleNode * node);
160  circt::firrtl::FModuleOp
162  circt::firrtl::FModuleOp
164  circt::firrtl::FExtModuleOp
166 
167  // Helper functions
168  void
169  AddClockPort(::llvm::SmallVector<circt::firrtl::PortInfo> * ports);
170  void
171  AddResetPort(::llvm::SmallVector<circt::firrtl::PortInfo> * ports);
172  void
173  AddMemReqPort(::llvm::SmallVector<circt::firrtl::PortInfo> * ports);
174  void
175  AddMemResPort(::llvm::SmallVector<circt::firrtl::PortInfo> * ports);
176  void
178  ::llvm::SmallVector<circt::firrtl::PortInfo> * ports,
179  circt::firrtl::Direction direction,
180  std::string name,
181  circt::firrtl::FIRRTLBaseType type);
182  circt::firrtl::BundleType
183  GetBundleType(const circt::firrtl::FIRRTLBaseType & type);
184  circt::firrtl::SubfieldOp
185  GetSubfield(mlir::Block * body, mlir::Value value, int index);
186  circt::firrtl::SubfieldOp
187  GetSubfield(mlir::Block * body, mlir::Value value, ::llvm::StringRef fieldName);
188  mlir::OpResult
189  GetInstancePort(circt::firrtl::InstanceOp & instance, std::string portName);
190  mlir::BlockArgument
191  GetPort(circt::firrtl::FModuleOp & module, std::string portName);
192  mlir::BlockArgument
193  GetInPort(circt::firrtl::FModuleOp & module, size_t portNr);
194  mlir::BlockArgument
195  GetOutPort(circt::firrtl::FModuleOp & module, size_t portNr);
196  void
197  Connect(mlir::Block * body, mlir::Value sink, mlir::Value source);
198  // Primary operations
199  circt::firrtl::BitsPrimOp
200  AddBitsOp(mlir::Block * body, mlir::Value value, int high, int low);
201  circt::firrtl::AndPrimOp
202  AddAndOp(mlir::Block * body, mlir::Value first, mlir::Value second);
203  circt::firrtl::NodeOp
204  AddNodeOp(mlir::Block * body, mlir::Value value, std::string name);
205  circt::firrtl::XorPrimOp
206  AddXorOp(mlir::Block * body, mlir::Value first, mlir::Value second);
207  circt::firrtl::OrPrimOp
208  AddOrOp(mlir::Block * body, mlir::Value first, mlir::Value second);
209  circt::firrtl::NotPrimOp
210  AddNotOp(mlir::Block * body, mlir::Value first);
211  circt::firrtl::AddPrimOp
212  AddAddOp(mlir::Block * body, mlir::Value first, mlir::Value second);
213  circt::firrtl::SubPrimOp
214  AddSubOp(mlir::Block * body, mlir::Value first, mlir::Value second);
215  circt::firrtl::MulPrimOp
216  AddMulOp(mlir::Block * body, mlir::Value first, mlir::Value second);
217  circt::firrtl::DivPrimOp
218  AddDivOp(mlir::Block * body, mlir::Value first, mlir::Value second);
219  circt::firrtl::DShrPrimOp
220  AddDShrOp(mlir::Block * body, mlir::Value first, mlir::Value second);
221  circt::firrtl::DShlPrimOp
222  AddDShlOp(mlir::Block * body, mlir::Value first, mlir::Value second);
223  circt::firrtl::RemPrimOp
224  AddRemOp(mlir::Block * body, mlir::Value first, mlir::Value second);
225  circt::firrtl::EQPrimOp
226  AddEqOp(mlir::Block * body, mlir::Value first, mlir::Value second);
227  circt::firrtl::NEQPrimOp
228  AddNeqOp(mlir::Block * body, mlir::Value first, mlir::Value second);
229  circt::firrtl::GTPrimOp
230  AddGtOp(mlir::Block * body, mlir::Value first, mlir::Value second);
231  circt::firrtl::GEQPrimOp
232  AddGeqOp(mlir::Block * body, mlir::Value first, mlir::Value second);
233  circt::firrtl::LTPrimOp
234  AddLtOp(mlir::Block * body, mlir::Value first, mlir::Value second);
235  circt::firrtl::LEQPrimOp
236  AddLeqOp(mlir::Block * body, mlir::Value first, mlir::Value second);
237  circt::firrtl::MuxPrimOp
238  AddMuxOp(mlir::Block * body, mlir::Value select, mlir::Value high, mlir::Value low);
239  circt::firrtl::AsSIntPrimOp
240  AddAsSIntOp(mlir::Block * body, mlir::Value value);
241  circt::firrtl::AsUIntPrimOp
242  AddAsUIntOp(mlir::Block * body, mlir::Value value);
243  circt::firrtl::PadPrimOp
244  AddPadOp(mlir::Block * body, mlir::Value value, int amount);
245  circt::firrtl::CvtPrimOp
246  AddCvtOp(mlir::Block * body, mlir::Value value);
247  circt::firrtl::WireOp
248  AddWireOp(mlir::Block * body, std::string name, int size);
249  circt::firrtl::WhenOp
250  AddWhenOp(mlir::Block * body, mlir::Value condition, bool elseStatment);
251  circt::firrtl::InstanceOp
252  AddInstanceOp(mlir::Block * circuitBody, jlm::rvsdg::Node * node);
253  circt::firrtl::ConstantOp
254  GetConstant(mlir::Block * body, int size, int value);
255  circt::firrtl::InvalidValueOp
256  GetInvalid(mlir::Block * body, int size);
257  void
258  ConnectInvalid(mlir::Block * body, mlir::Value value);
259 
260  circt::firrtl::BitsPrimOp
261  DropMSBs(mlir::Block * body, mlir::Value value, int amount);
262 
265 
266  rvsdg::Output *
268 
269  void
270  InitializeMemReq(circt::firrtl::FModuleOp module);
271  circt::firrtl::BundleType::BundleElement
272  GetReadyElement();
273  circt::firrtl::BundleType::BundleElement
274  GetValidElement();
275  mlir::BlockArgument
276  GetClockSignal(circt::firrtl::FModuleOp module);
277  mlir::BlockArgument
278  GetResetSignal(circt::firrtl::FModuleOp module);
279  circt::firrtl::FModuleOp
280  nodeToModule(const jlm::rvsdg::Node * node, bool mem = false);
281  circt::firrtl::IntType
282  GetIntType(int size);
283  circt::firrtl::IntType
284  GetIntType(const jlm::rvsdg::Type * type, int extend = 0);
285  circt::firrtl::FIRRTLBaseType
287  std::string
288  GetModuleName(const rvsdg::Node * node);
289  bool
291  void
292  check_module(circt::firrtl::FModuleOp & module);
293 
294  std::unique_ptr<::mlir::OpBuilder> Builder_;
295  std::unique_ptr<::mlir::MLIRContext> Context_;
296  const circt::firrtl::FIRVersion DefaultFIRVersion_;
297 };
298 
299 } // namespace jlm::hls
300 
301 #endif // JLM_HLS_BACKEND_RHLS2FIRRTL_RHLSTOFIRRTLCONVERTER_HPP
const rvsdg::LambdaNode * get_hls_lambda(llvm::LlvmRvsdgModule &rm)
Definition: base-hls.cpp:136
circt::firrtl::InstanceOp AddInstanceOp(mlir::Block *circuitBody, jlm::rvsdg::Node *node)
RhlsToFirrtlConverter(const RhlsToFirrtlConverter &)=delete
circt::firrtl::GEQPrimOp AddGeqOp(mlir::Block *body, mlir::Value first, mlir::Value second)
circt::firrtl::FModuleOp MlirGenBuffer(const jlm::rvsdg::SimpleNode *node)
mlir::BlockArgument GetPort(circt::firrtl::FModuleOp &module, std::string portName)
circt::firrtl::FModuleOp MlirGenHlsMemReq(const jlm::rvsdg::SimpleNode *node)
circt::firrtl::EQPrimOp AddEqOp(mlir::Block *body, mlir::Value first, mlir::Value second)
circt::firrtl::LTPrimOp AddLtOp(mlir::Block *body, mlir::Value first, mlir::Value second)
circt::firrtl::BitsPrimOp AddBitsOp(mlir::Block *body, mlir::Value value, int high, int low)
void check_module(circt::firrtl::FModuleOp &module)
circt::firrtl::XorPrimOp AddXorOp(mlir::Block *body, mlir::Value first, mlir::Value second)
std::unique_ptr<::mlir::MLIRContext > Context_
circt::firrtl::FModuleOp MlirGenNDMux(const jlm::rvsdg::SimpleNode *node)
circt::firrtl::BundleType GetBundleType(const circt::firrtl::FIRRTLBaseType &type)
circt::firrtl::BitsPrimOp DropMSBs(mlir::Block *body, mlir::Value value, int amount)
circt::firrtl::WireOp AddWireOp(mlir::Block *body, std::string name, int size)
void AddMemResPort(::llvm::SmallVector< circt::firrtl::PortInfo > *ports)
circt::firrtl::RemPrimOp AddRemOp(mlir::Block *body, mlir::Value first, mlir::Value second)
std::string ToString(llvm::LlvmRvsdgModule &rvsdgModule)
std::unordered_map< std::string, circt::firrtl::FModuleLike > modules
circt::firrtl::FModuleOp MlirGenFork(const jlm::rvsdg::SimpleNode *node)
circt::firrtl::FModuleOp nodeToModule(const jlm::rvsdg::Node *node, bool mem=false)
void WriteModuleToFile(const circt::firrtl::FModuleOp fModuleOp, const rvsdg::Node *node)
rvsdg::Output * TraceStructuralOutput(rvsdg::StructuralOutput *out)
circt::firrtl::NodeOp AddNodeOp(mlir::Block *body, mlir::Value value, std::string name)
circt::firrtl::FModuleOp MlirGenTrigger(const jlm::rvsdg::SimpleNode *node)
circt::firrtl::DShrPrimOp AddDShrOp(mlir::Block *body, mlir::Value first, mlir::Value second)
circt::firrtl::NEQPrimOp AddNeqOp(mlir::Block *body, mlir::Value first, mlir::Value second)
circt::firrtl::FModuleOp MlirGenPrint(const jlm::rvsdg::SimpleNode *node)
circt::firrtl::FModuleOp MlirGenHlsMemResp(const jlm::rvsdg::SimpleNode *node)
circt::firrtl::BundleType::BundleElement GetReadyElement()
std::unique_ptr< mlir::ModuleOp > ConvertToMduleOp(llvm::LlvmRvsdgModule &rvsdgModule)
std::string GetText(llvm::LlvmRvsdgModule &) override
RhlsToFirrtlConverter & operator=(RhlsToFirrtlConverter &&)=delete
circt::firrtl::BundleType::BundleElement GetValidElement()
void AddResetPort(::llvm::SmallVector< circt::firrtl::PortInfo > *ports)
circt::firrtl::FModuleOp MlirGenStateGate(const jlm::rvsdg::SimpleNode *node)
const circt::firrtl::FIRVersion DefaultFIRVersion_
void InitializeMemReq(circt::firrtl::FModuleOp module)
circt::firrtl::FModuleOp MlirGenSink(const jlm::rvsdg::SimpleNode *node)
void Connect(mlir::Block *body, mlir::Value sink, mlir::Value source)
circt::firrtl::FModuleOp MlirGenHlsStore(const jlm::rvsdg::SimpleNode *node)
circt::firrtl::FIRRTLBaseType GetFirrtlType(const jlm::rvsdg::Type *type)
void AddMemReqPort(::llvm::SmallVector< circt::firrtl::PortInfo > *ports)
circt::firrtl::DShlPrimOp AddDShlOp(mlir::Block *body, mlir::Value first, mlir::Value second)
void WriteCircuitToFile(const circt::firrtl::CircuitOp circuit, std::string name)
bool IsIdentityMapping(const rvsdg::MatchOperation &op)
circt::firrtl::CircuitOp MlirGen(const rvsdg::LambdaNode *lamdaNode)
circt::firrtl::FModuleOp MlirGenSimpleNode(const jlm::rvsdg::SimpleNode *node)
mlir::BlockArgument GetResetSignal(circt::firrtl::FModuleOp module)
std::string toString(const circt::firrtl::CircuitOp circuit)
circt::firrtl::ConstantOp GetConstant(mlir::Block *body, int size, int value)
circt::firrtl::InvalidValueOp GetInvalid(mlir::Block *body, int size)
mlir::BlockArgument GetOutPort(circt::firrtl::FModuleOp &module, size_t portNr)
circt::firrtl::FModuleOp MlirGenBranch(const jlm::rvsdg::SimpleNode *node)
circt::firrtl::SubPrimOp AddSubOp(mlir::Block *body, mlir::Value first, mlir::Value second)
circt::firrtl::PadPrimOp AddPadOp(mlir::Block *body, mlir::Value value, int amount)
circt::firrtl::MuxPrimOp AddMuxOp(mlir::Block *body, mlir::Value select, mlir::Value high, mlir::Value low)
circt::firrtl::WhenOp AddWhenOp(mlir::Block *body, mlir::Value condition, bool elseStatment)
circt::firrtl::AsUIntPrimOp AddAsUIntOp(mlir::Block *body, mlir::Value value)
circt::firrtl::FModuleOp MlirGenPredicationBuffer(const jlm::rvsdg::SimpleNode *node)
circt::firrtl::NotPrimOp AddNotOp(mlir::Block *body, mlir::Value first)
circt::firrtl::FModuleOp MlirGenAddrQueue(const jlm::rvsdg::SimpleNode *node)
circt::firrtl::GTPrimOp AddGtOp(mlir::Block *body, mlir::Value first, mlir::Value second)
circt::firrtl::FExtModuleOp MlirGenExtModule(const jlm::rvsdg::SimpleNode *node)
void AddClockPort(::llvm::SmallVector< circt::firrtl::PortInfo > *ports)
circt::firrtl::FModuleOp MlirGenHlsDLoad(const jlm::rvsdg::SimpleNode *node)
circt::firrtl::FModuleOp MlirGenLoopConstBuffer(const jlm::rvsdg::SimpleNode *node)
circt::firrtl::OrPrimOp AddOrOp(mlir::Block *body, mlir::Value first, mlir::Value second)
circt::firrtl::IntType GetIntType(int size)
circt::firrtl::MulPrimOp AddMulOp(mlir::Block *body, mlir::Value first, mlir::Value second)
circt::firrtl::LEQPrimOp AddLeqOp(mlir::Block *body, mlir::Value first, mlir::Value second)
circt::firrtl::FModuleOp MlirGenHlsLocalMem(const jlm::rvsdg::SimpleNode *node)
RhlsToFirrtlConverter & operator=(const RhlsToFirrtlConverter &)=delete
std::string GetModuleName(const rvsdg::Node *node)
jlm::rvsdg::Output * TraceArgument(rvsdg::RegionArgument *arg)
std::unique_ptr<::mlir::OpBuilder > Builder_
circt::firrtl::AsSIntPrimOp AddAsSIntOp(mlir::Block *body, mlir::Value value)
circt::firrtl::FModuleOp MlirGenDMux(const jlm::rvsdg::SimpleNode *node)
circt::firrtl::DivPrimOp AddDivOp(mlir::Block *body, mlir::Value first, mlir::Value second)
circt::firrtl::FModuleOp MlirGenHlsLoad(const jlm::rvsdg::SimpleNode *node)
RhlsToFirrtlConverter(RhlsToFirrtlConverter &&)=delete
circt::firrtl::AddPrimOp AddAddOp(mlir::Block *body, mlir::Value first, mlir::Value second)
mlir::BlockArgument GetInPort(circt::firrtl::FModuleOp &module, size_t portNr)
circt::firrtl::CvtPrimOp AddCvtOp(mlir::Block *body, mlir::Value value)
circt::firrtl::SubfieldOp GetSubfield(mlir::Block *body, mlir::Value value, int index)
mlir::OpResult GetInstancePort(circt::firrtl::InstanceOp &instance, std::string portName)
mlir::BlockArgument GetClockSignal(circt::firrtl::FModuleOp module)
circt::firrtl::AndPrimOp AddAndOp(mlir::Block *body, mlir::Value first, mlir::Value second)
void ConnectInvalid(mlir::Block *body, mlir::Value value)
circt::firrtl::FModuleOp MlirGenMem(const jlm::rvsdg::SimpleNode *node)
void AddBundlePort(::llvm::SmallVector< circt::firrtl::PortInfo > *ports, circt::firrtl::Direction direction, std::string name, circt::firrtl::FIRRTLBaseType type)
Lambda node.
Definition: lambda.hpp:83
Represents the argument of a region.
Definition: region.hpp:41
Represent acyclic RVSDG subgraphs.
Definition: region.hpp:213
static std::string type(const Node *n)
Definition: view.cpp:255