Loading [MathJax]/jax/input/TeX/config.js
CIRCT 22.0.0git
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
EmitRTGISAAssemblyPass.cpp
Go to the documentation of this file.
1//===- EmitRTGISAAssemblyPass.cpp - RTG Assembly 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 ISA Assembly emitter implementation for the RTG dialect.
10//
11//===----------------------------------------------------------------------===//
12
16#include "circt/Support/Path.h"
17#include "mlir/IR/Threading.h"
18#include "mlir/Support/FileUtilities.h"
19#include "llvm/ADT/SmallString.h"
20#include "llvm/ADT/StringRef.h"
21#include "llvm/ADT/TypeSwitch.h"
22#include "llvm/Support/FileSystem.h"
23#include "llvm/Support/Path.h"
24#include "llvm/Support/ToolOutputFile.h"
25#include "llvm/Support/raw_ostream.h"
26#include <fstream>
27
28namespace circt {
29namespace rtg {
30#define GEN_PASS_DEF_EMITRTGISAASSEMBLYPASS
31#include "circt/Dialect/RTG/Transforms/RTGPasses.h.inc"
32} // namespace rtg
33} // namespace circt
34
35using namespace circt;
36using namespace rtg;
37
38#define DEBUG_TYPE "emit-rtg-isa-assembly"
39
40namespace {
41
42class Emitter {
43public:
44 Emitter(llvm::raw_ostream &os, const DenseSet<StringAttr> &unsupportedInstr)
45 : os(os), unsupportedInstr(unsupportedInstr) {}
46
47 LogicalResult emit(InstructionOpInterface instr) {
48 os << llvm::indent(4);
49 bool useBinary =
50 unsupportedInstr.contains(instr->getName().getIdentifier());
51
52 // TODO: we cannot just assume that double-slash is the way to do a line
53 // comment
54 if (useBinary)
55 os << "# ";
56
57 SmallVector<Attribute> operands;
58 for (auto operand : instr->getOperands()) {
59 if (isa<LabelType>(operand.getType()) && useBinary)
60 return instr->emitError("labels cannot be emitted as binary");
61
62 auto attr = state.lookup(operand);
63 if (!attr)
64 return failure();
65
66 operands.push_back(attr);
67 }
68
69 instr.printInstructionAssembly(os, operands);
70 os << "\n";
71
72 if (!useBinary)
73 return success();
74
75 os << llvm::indent(4);
76 // TODO: don't hardcode '.word'
77 os << ".word 0x";
78 instr.printInstructionBinary(os, operands);
79 os << "\n";
80
81 return success();
82 }
83
84 LogicalResult emit(LabelDeclOp op) {
85 if (!op.getArgs().empty())
86 return op->emitError(
87 "label arguments must be elaborated before emission");
88
89 state[op.getLabel()] = op.getFormatStringAttr();
90 return success();
91 }
92
93 LogicalResult emit(LabelOp op) {
94 auto labelStr = cast<StringAttr>(state[op.getLabel()]).getValue();
95 if (op.getVisibility() == LabelVisibility::external) {
96 os << ".extern " << labelStr << "\n";
97 return success();
98 }
99
100 if (op.getVisibility() == LabelVisibility::global)
101 os << ".global " << labelStr << "\n";
102
103 os << labelStr << ":\n";
104 return success();
105 }
106
107 LogicalResult emit(CommentOp op) {
108 os << llvm::indent(4) << "# " << op.getComment() << "\n";
109 return success();
110 }
111
112 LogicalResult emitTest(rtg::TestOp test, bool emitHeaderFooter = false) {
113 if (emitHeaderFooter)
114 os << "# Begin of " << test.getSymName() << "\n\n";
115
116 for (auto &op : *test.getBody()) {
117 if (op.hasTrait<OpTrait::ConstantLike>()) {
118 SmallVector<OpFoldResult> results;
119 if (failed(op.fold(results)))
120 return failure();
121
122 for (auto [val, res] : llvm::zip(op.getResults(), results)) {
123 auto attr = res.dyn_cast<Attribute>();
124 if (!attr)
125 return failure();
126
127 state[val] = attr;
128 }
129
130 continue;
131 }
132
133 auto res =
134 TypeSwitch<Operation *, LogicalResult>(&op)
135 .Case<InstructionOpInterface, LabelDeclOp, LabelOp, CommentOp>(
136 [&](auto op) { return emit(op); })
137 .Default([](auto op) {
138 return op->emitError("emitter unknown RTG operation");
139 });
140
141 if (failed(res))
142 return failure();
143 }
144
145 state.clear();
146
147 if (emitHeaderFooter)
148 os << "\n# End of " << test.getSymName() << "\n\n";
149
150 return success();
151 }
152
153private:
154 /// Output Stream.
155 llvm::raw_ostream &os;
156
157 /// Instructions to emit in binary.
158 const DenseSet<StringAttr> &unsupportedInstr;
159
160 /// Evaluated values.
161 DenseMap<Value, Attribute> state;
162};
163
164} // namespace
165
166static void
168 const std::string &unsupportedInstructionsFile,
169 DenseSet<StringAttr> &unsupportedInstrs) {
170 if (!unsupportedInstructionsFile.empty()) {
171 std::ifstream input(unsupportedInstructionsFile);
172 std::string token;
173 while (std::getline(input, token, ',')) {
174 auto trimmed = StringRef(token).trim();
175 if (!trimmed.empty())
176 unsupportedInstrs.insert(StringAttr::get(ctxt, trimmed));
177 }
178 }
179}
180
181//===----------------------------------------------------------------------===//
182// EmitRTGISAAssemblyPass
183//===----------------------------------------------------------------------===//
184
185namespace {
186struct EmitRTGISAAssemblyPass
187 : public rtg::impl::EmitRTGISAAssemblyPassBase<EmitRTGISAAssemblyPass> {
188 using Base::Base;
189
190 void runOnOperation() override;
191 /// Emit each 'rtg.test' into a separate file using the test's name as the
192 /// filename.
193 LogicalResult emitSplit(const DenseSet<StringAttr> &unsupportedInstr);
194 /// Emit all tests into a single file (or print them to stderr if no file path
195 /// is given).
196 LogicalResult emit(const DenseSet<StringAttr> &unsupportedInstr);
197};
198} // namespace
199
200void EmitRTGISAAssemblyPass::runOnOperation() {
201 if ((!path.hasValue() || path.empty()) && splitOutput) {
202 getOperation().emitError("'split-output' option only valid in combination "
203 "with a valid 'path' argument");
204 return signalPassFailure();
205 }
206
207 DenseSet<StringAttr> unsupportedInstr;
208 for (const auto &instr : unsupportedInstructions)
209 unsupportedInstr.insert(StringAttr::get(&getContext(), instr));
211 &getContext(), unsupportedInstructionsFile.getValue(), unsupportedInstr);
212
213 if (splitOutput) {
214 if (failed(emitSplit(unsupportedInstr)))
215 return signalPassFailure();
216
217 return;
218 }
219
220 if (failed(emit(unsupportedInstr)))
221 return signalPassFailure();
222}
223
224LogicalResult
225EmitRTGISAAssemblyPass::emit(const DenseSet<StringAttr> &unsupportedInstr) {
226 std::unique_ptr<llvm::ToolOutputFile> file;
227 bool emitToFile = path.hasValue() && !path.empty() && path != "-";
228 if (emitToFile) {
229 file = createOutputFile(path, std::string(),
230 [&]() { return getOperation().emitError(); });
231 if (!file)
232 return failure();
233
234 file->keep();
235 }
236
237 Emitter emitter(emitToFile ? file->os()
238 : (path == "-" ? llvm::outs() : llvm::errs()),
239 unsupportedInstr);
240 for (auto test : getOperation().getOps<TestOp>())
241 if (failed(emitter.emitTest(test, true)))
242 return failure();
243
244 return success();
245}
246
247LogicalResult EmitRTGISAAssemblyPass::emitSplit(
248 const DenseSet<StringAttr> &unsupportedInstr) {
249 auto tests = getOperation().getOps<TestOp>();
250 return failableParallelForEach(
251 &getContext(), tests.begin(), tests.end(), [&](rtg::TestOp test) {
252 auto res = createOutputFile(test.getSymName().str() + ".s", path,
253 [&]() { return test.emitError(); });
254 if (!res)
255 return failure();
256
257 res->keep();
258 return Emitter(res->os(), unsupportedInstr).emitTest(test);
259 });
260}
static void parseUnsupportedInstructionsFile(MLIRContext *ctxt, const std::string &unsupportedInstructionsFile, DenseSet< StringAttr > &unsupportedInstrs)
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
Definition CalyxOps.cpp:55
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
std::unique_ptr< llvm::ToolOutputFile > createOutputFile(StringRef filename, StringRef dirname, function_ref< InFlightDiagnostic()> emitError)
Creates an output file with the given filename in the specified directory.
Definition Path.cpp:37
Definition emit.py:1
Definition rtg.py:1