CIRCT  20.0.0git
ExportSystemC.cpp
Go to the documentation of this file.
1 //===- ExportSystemC.cpp - SystemC 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 is the main SystemC emitter implementation.
10 //
11 //===----------------------------------------------------------------------===//
12 
14 #include "EmissionPrinter.h"
15 #include "RegisterAllEmitters.h"
19 #include "mlir/Dialect/EmitC/IR/EmitC.h"
20 #include "mlir/IR/BuiltinOps.h"
21 #include "mlir/Support/FileUtilities.h"
22 #include "mlir/Tools/mlir-translate/Translation.h"
23 #include "llvm/Support/FileSystem.h"
24 #include "llvm/Support/Path.h"
25 #include "llvm/Support/ToolOutputFile.h"
26 #include <regex>
27 
28 using namespace circt;
29 using namespace circt::ExportSystemC;
30 
31 #define DEBUG_TYPE "export-systemc"
32 
33 /// Helper to convert a file-path to a macro name that can be used to guard a
34 /// header file.
35 static std::string pathToMacroName(StringRef path) {
36  // Replace characters that represent a path hierarchy with underscore to match
37  // the usual header guard formatting.
38  auto str = std::regex_replace(path.upper(), std::regex("[\\\\./]"), "_");
39  // Remove invalid characters. TODO: a digit is not allowed as the first
40  // character, but not fixed here.
41  return std::regex_replace(str, std::regex("[^a-zA-Z0-9_$]+"), "");
42 }
43 
44 /// Emits the given operation to a file represented by the passed ostream and
45 /// file-path.
46 static LogicalResult emitFile(ArrayRef<Operation *> operations,
47  StringRef filePath, raw_ostream &os) {
48  mlir::raw_indented_ostream ios(os);
49 
50  ios << "// " << filePath << "\n";
51  std::string macroname = pathToMacroName(filePath);
52  ios << "#ifndef " << macroname << "\n";
53  ios << "#define " << macroname << "\n\n";
54 
55  bool failed = false;
56 
57  if (!operations.empty()) {
58  OpEmissionPatternSet opPatterns;
59  registerAllOpEmitters(opPatterns, operations[0]->getContext());
60  TypeEmissionPatternSet typePatterns;
61  registerAllTypeEmitters(typePatterns);
62  AttrEmissionPatternSet attrPatterns;
63  registerAllAttrEmitters(attrPatterns);
64  EmissionPrinter printer(ios, opPatterns, typePatterns, attrPatterns,
65  operations[0]->getLoc());
66 
67  for (auto *op : operations)
68  printer.emitOp(op);
69 
70  failed = printer.exitState().failed();
71  }
72 
73  ios << "\n#endif // " << macroname << "\n\n";
74 
75  return failure(failed);
76 }
77 
78 //===----------------------------------------------------------------------===//
79 // Unified and Split Emitter implementation
80 //===----------------------------------------------------------------------===//
81 
82 LogicalResult ExportSystemC::exportSystemC(ModuleOp module,
83  llvm::raw_ostream &os) {
84  return emitFile({module}, "stdout.h", os);
85 }
86 
87 LogicalResult ExportSystemC::exportSplitSystemC(ModuleOp module,
88  StringRef directory) {
89  // Collect all includes to emit them in every file.
90  SmallVector<Operation *> includes;
91  module->walk([&](mlir::emitc::IncludeOp op) { includes.push_back(op); });
92 
93  for (Operation &op : module.getRegion().front()) {
94  if (auto symbolOp = dyn_cast<mlir::SymbolOpInterface>(op)) {
95  // Create the output directory if needed.
96  if (std::error_code error = llvm::sys::fs::create_directories(directory))
97  return module.emitError("cannot create output directory \"")
98  << directory << "\": " << error.message();
99 
100  // Open or create the output file.
101  std::string fileName = symbolOp.getName().str() + ".h";
102  SmallString<128> filePath(directory);
103  llvm::sys::path::append(filePath, fileName);
104  std::string errorMessage;
105  auto output = mlir::openOutputFile(filePath, &errorMessage);
106  if (!output)
107  return module.emitError(errorMessage);
108 
109  // Emit the content to the file.
110  SmallVector<Operation *> opsInThisFile(includes);
111  opsInThisFile.push_back(symbolOp);
112  if (failed(emitFile(opsInThisFile, filePath, output->os())))
113  return symbolOp->emitError("failed to emit to file \"")
114  << filePath << "\"";
115 
116  // Do not delete the file if emission was successful.
117  output->keep();
118  }
119  }
120 
121  return success();
122 }
123 
124 //===----------------------------------------------------------------------===//
125 // circt-translate registration
126 //===----------------------------------------------------------------------===//
127 
129 
130  static llvm::cl::opt<std::string> directory(
131  "export-dir", llvm::cl::desc("Directory path to write the files to."),
132  llvm::cl::init("./"));
133 
134  static mlir::TranslateFromMLIRRegistration toSystemC(
135  "export-systemc", "export SystemC",
136  [](ModuleOp module, raw_ostream &output) {
137  return ExportSystemC::exportSystemC(module, output);
138  },
139  [](mlir::DialectRegistry &registry) {
140  registry.insert<hw::HWDialect, comb::CombDialect,
141  systemc::SystemCDialect, mlir::emitc::EmitCDialect>();
142  });
143 
144  static mlir::TranslateFromMLIRRegistration toSplitSystemC(
145  "export-split-systemc", "export SystemC (split)",
146  [](ModuleOp module, raw_ostream &output) {
147  return ExportSystemC::exportSplitSystemC(module, directory);
148  },
149  [](mlir::DialectRegistry &registry) {
150  registry.insert<hw::HWDialect, comb::CombDialect,
151  systemc::SystemCDialect, mlir::emitc::EmitCDialect>();
152  });
153 }
static std::string pathToMacroName(StringRef path)
Helper to convert a file-path to a macro name that can be used to guard a header file.
static LogicalResult emitFile(ArrayRef< Operation * > operations, StringRef filePath, raw_ostream &os)
Emits the given operation to a file represented by the passed ostream and file-path.
static StringAttr append(StringAttr base, const Twine &suffix)
Return a attribute with the specified suffix appended.
This class collects a set of emission patterns with base type 'PatternTy'.
This is intended to be the driving class for all pattern-based IR emission.
void emitOp(Operation *op)
Emit the given operation as a statement to the ostream associated with this printer according to the ...
LogicalResult exitState() const
Returns whether everything was printed successfully or some error occurred (e.g., there was an operat...
void registerExportSystemCTranslation()
LogicalResult exportSplitSystemC(ModuleOp module, StringRef directory)
void registerAllTypeEmitters(TypeEmissionPatternSet &patterns)
Collects the type emission patterns of all supported dialects.
LogicalResult exportSystemC(ModuleOp module, llvm::raw_ostream &os)
void registerAllOpEmitters(OpEmissionPatternSet &patterns, MLIRContext *context)
Collects the operation emission patterns of all supported dialects.
void registerAllAttrEmitters(AttrEmissionPatternSet &patterns)
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
Definition: DebugAnalysis.h:21