CIRCT 22.0.0git
Loading...
Searching...
No Matches
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
17#include "circt/Support/Path.h"
18#include "mlir/Support/FileUtilities.h"
19#include "llvm/ADT/StringRef.h"
20#include "llvm/ADT/TypeSwitch.h"
21#include "llvm/Support/ToolOutputFile.h"
22#include "llvm/Support/raw_ostream.h"
23#include <fstream>
24
25namespace circt {
26namespace rtg {
27#define GEN_PASS_DEF_EMITRTGISAASSEMBLYPASS
28#include "circt/Dialect/RTG/Transforms/RTGPasses.h.inc"
29} // namespace rtg
30} // namespace circt
31
32using namespace circt;
33using namespace rtg;
34
35#define DEBUG_TYPE "emit-rtg-isa-assembly"
36
37namespace {
38
39class Emitter {
40public:
41 Emitter(llvm::raw_ostream &os, const DenseSet<StringAttr> &unsupportedInstr)
42 : os(os), unsupportedInstr(unsupportedInstr) {}
43
44 LogicalResult emitFile(emit::FileOp fileOp) {
45 for (auto &op : *fileOp.getBody()) {
46 if (op.hasTrait<OpTrait::ConstantLike>()) {
47 SmallVector<OpFoldResult> results;
48 if (failed(op.fold(results)))
49 return failure();
50
51 for (auto [val, res] : llvm::zip(op.getResults(), results)) {
52 auto attr = res.dyn_cast<Attribute>();
53 if (!attr)
54 return failure();
55
56 state[val] = attr;
57 }
58
59 continue;
60 }
61
62 auto res =
63 TypeSwitch<Operation *, LogicalResult>(&op)
64 .Case<InstructionOpInterface, LabelDeclOp, LabelOp, CommentOp>(
65 [&](auto op) { return emit(op); })
66 .Default([](auto op) {
67 return op->emitError("emitter unknown RTG operation");
68 });
69
70 if (failed(res))
71 return failure();
72 }
73
74 state.clear();
75 return success();
76 }
77
78private:
79 LogicalResult emit(InstructionOpInterface instr) {
80 os << llvm::indent(4);
81 bool useBinary =
82 unsupportedInstr.contains(instr->getName().getIdentifier());
83
84 // TODO: we cannot just assume that double-slash is the way to do a line
85 // comment
86 if (useBinary)
87 os << "# ";
88
89 SmallVector<Attribute> operands;
90 for (auto operand : instr->getOperands()) {
91 if (isa<LabelType>(operand.getType()) && useBinary)
92 return instr->emitError("labels cannot be emitted as binary");
93
94 auto attr = state.lookup(operand);
95 if (!attr)
96 return failure();
97
98 operands.push_back(attr);
99 }
100
101 instr.printInstructionAssembly(os, operands);
102 os << "\n";
103
104 if (!useBinary)
105 return success();
106
107 os << llvm::indent(4);
108 // TODO: don't hardcode '.word'
109 os << ".word 0x";
110 instr.printInstructionBinary(os, operands);
111 os << "\n";
112
113 return success();
114 }
115
116 LogicalResult emit(LabelDeclOp op) {
117 if (!op.getArgs().empty())
118 return op->emitError(
119 "label arguments must be elaborated before emission");
120
121 state[op.getLabel()] = op.getFormatStringAttr();
122 return success();
123 }
124
125 LogicalResult emit(LabelOp op) {
126 auto labelStr = cast<StringAttr>(state[op.getLabel()]).getValue();
127 if (op.getVisibility() == LabelVisibility::external) {
128 os << ".extern " << labelStr << "\n";
129 return success();
130 }
131
132 if (op.getVisibility() == LabelVisibility::global)
133 os << ".global " << labelStr << "\n";
134
135 os << labelStr << ":\n";
136 return success();
137 }
138
139 LogicalResult emit(CommentOp op) {
140 os << llvm::indent(4) << "# " << op.getComment() << "\n";
141 return success();
142 }
143
144private:
145 /// Output Stream.
146 llvm::raw_ostream &os;
147
148 /// Instructions to emit in binary.
149 const DenseSet<StringAttr> &unsupportedInstr;
150
151 /// Evaluated values.
152 DenseMap<Value, Attribute> state;
153};
154
155} // namespace
156
157static void
159 const std::string &unsupportedInstructionsFile,
160 DenseSet<StringAttr> &unsupportedInstrs) {
161 if (!unsupportedInstructionsFile.empty()) {
162 std::ifstream input(unsupportedInstructionsFile, std::ios::in);
163 std::string token;
164 while (std::getline(input, token, ',')) {
165 auto trimmed = StringRef(token).trim();
166 if (!trimmed.empty())
167 unsupportedInstrs.insert(StringAttr::get(ctxt, trimmed));
168 }
169 }
170}
171
172//===----------------------------------------------------------------------===//
173// EmitRTGISAAssemblyPass
174//===----------------------------------------------------------------------===//
175
176namespace {
177struct EmitRTGISAAssemblyPass
178 : public rtg::impl::EmitRTGISAAssemblyPassBase<EmitRTGISAAssemblyPass> {
179 using Base::Base;
180 void runOnOperation() override;
181};
182} // namespace
183
184void EmitRTGISAAssemblyPass::runOnOperation() {
185 // Get the set of instructions not supported by the assembler
186 DenseSet<StringAttr> unsupportedInstr;
187 for (const auto &instr : unsupportedInstructions)
188 unsupportedInstr.insert(StringAttr::get(&getContext(), instr));
190 &getContext(), unsupportedInstructionsFile.getValue(), unsupportedInstr);
191
192 // Create the output file
193 auto filename = getOperation().getFileName();
194 std::unique_ptr<llvm::ToolOutputFile> file;
195 bool emitToFile = !filename.empty() && filename != "-";
196 if (emitToFile) {
197 file = createOutputFile(filename, std::string(),
198 [&]() { return getOperation().emitError(); });
199 if (!file)
200 return signalPassFailure();
201
202 file->keep();
203 }
204
205 Emitter emitter(emitToFile ? file->os()
206 : (filename.empty() ? llvm::errs() : llvm::outs()),
207 unsupportedInstr);
208 if (failed(emitter.emitFile(getOperation())))
209 return signalPassFailure();
210}
static void parseUnsupportedInstructionsFile(MLIRContext *ctxt, const std::string &unsupportedInstructionsFile, DenseSet< StringAttr > &unsupportedInstrs)
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 InstancePath empty
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