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"
30#define GEN_PASS_DEF_EMITRTGISAASSEMBLYPASS
31#include "circt/Dialect/RTG/Transforms/RTGPasses.h.inc"
38#define DEBUG_TYPE "emit-rtg-isa-assembly"
44 Emitter(llvm::raw_ostream &os,
const DenseSet<StringAttr> &unsupportedInstr)
45 : os(os), unsupportedInstr(unsupportedInstr) {}
47 LogicalResult
emit(InstructionOpInterface instr) {
48 os << llvm::indent(4);
50 unsupportedInstr.contains(instr->getName().getIdentifier());
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");
62 auto attr = state.lookup(operand);
66 operands.push_back(attr);
69 instr.printInstructionAssembly(os, operands);
75 os << llvm::indent(4);
78 instr.printInstructionBinary(os, operands);
84 LogicalResult
emit(LabelDeclOp op) {
85 if (!op.getArgs().empty())
87 "label arguments must be elaborated before emission");
89 state[op.getLabel()] = op.getFormatStringAttr();
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";
100 if (op.getVisibility() == LabelVisibility::global)
101 os <<
".global " << labelStr <<
"\n";
103 os << labelStr <<
":\n";
107 LogicalResult
emit(CommentOp op) {
108 os << llvm::indent(4) <<
"# " << op.getComment() <<
"\n";
112 LogicalResult emitTest(rtg::TestOp test,
bool emitHeaderFooter =
false) {
113 if (emitHeaderFooter)
114 os <<
"# Begin of " << test.getSymName() <<
"\n\n";
116 for (
auto &op : *test.getBody()) {
117 if (op.hasTrait<OpTrait::ConstantLike>()) {
118 SmallVector<OpFoldResult> results;
119 if (failed(op.fold(results)))
122 for (
auto [val, res] : llvm::zip(op.getResults(), results)) {
123 auto attr = res.dyn_cast<Attribute>();
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");
147 if (emitHeaderFooter)
148 os <<
"\n# End of " << test.getSymName() <<
"\n\n";
155 llvm::raw_ostream &os;
158 const DenseSet<StringAttr> &unsupportedInstr;
161 DenseMap<Value, Attribute> state;
168 const std::string &unsupportedInstructionsFile,
169 DenseSet<StringAttr> &unsupportedInstrs) {
170 if (!unsupportedInstructionsFile.empty()) {
171 std::ifstream input(unsupportedInstructionsFile);
173 while (std::getline(input, token,
',')) {
174 auto trimmed = StringRef(token).trim();
175 if (!trimmed.empty())
176 unsupportedInstrs.insert(StringAttr::get(ctxt, trimmed));
181static std::unique_ptr<llvm::ToolOutputFile>
183 function_ref<InFlightDiagnostic()> emitError) {
185 SmallString<128> outputFilename(dirname);
187 auto outputDir = llvm::sys::path::parent_path(outputFilename);
190 std::error_code error = llvm::sys::fs::create_directories(outputDir);
192 emitError() <<
"cannot create output directory \"" << outputDir
193 <<
"\": " << error.message();
198 std::string errorMessage;
199 auto output = mlir::openOutputFile(outputFilename, &errorMessage);
201 emitError() << errorMessage;
210struct EmitRTGISAAssemblyPass
211 :
public rtg::impl::EmitRTGISAAssemblyPassBase<EmitRTGISAAssemblyPass> {
214 void runOnOperation()
override;
217 LogicalResult emitSplit(
const DenseSet<StringAttr> &unsupportedInstr);
220 LogicalResult
emit(
const DenseSet<StringAttr> &unsupportedInstr);
224void EmitRTGISAAssemblyPass::runOnOperation() {
225 if ((!path.hasValue() || path.empty()) && splitOutput) {
226 getOperation().emitError(
"'split-output' option only valid in combination "
227 "with a valid 'path' argument");
228 return signalPassFailure();
231 DenseSet<StringAttr> unsupportedInstr;
232 for (
const auto &instr : unsupportedInstructions)
233 unsupportedInstr.insert(StringAttr::
get(&getContext(), instr));
235 &getContext(), unsupportedInstructionsFile.getValue(), unsupportedInstr);
238 if (failed(emitSplit(unsupportedInstr)))
239 return signalPassFailure();
244 if (failed(
emit(unsupportedInstr)))
245 return signalPassFailure();
249EmitRTGISAAssemblyPass::emit(
const DenseSet<StringAttr> &unsupportedInstr) {
250 std::unique_ptr<llvm::ToolOutputFile> file;
251 bool emitToFile = path.hasValue() && !path.empty() && path !=
"-";
254 [&]() {
return getOperation().emitError(); });
261 Emitter emitter(emitToFile ? file->os()
262 : (path ==
"-" ?
llvm::outs() :
llvm::errs()),
264 for (
auto test : getOperation().getOps<TestOp>())
265 if (failed(emitter.emitTest(test, true)))
271LogicalResult EmitRTGISAAssemblyPass::emitSplit(
272 const DenseSet<StringAttr> &unsupportedInstr) {
273 auto tests = getOperation().getOps<TestOp>();
274 return failableParallelForEach(
275 &getContext(), tests.begin(), tests.end(), [&](rtg::TestOp test) {
276 auto res = createOutputFile(test.getSymName().str() +
".s", path,
277 [&]() { return test.emitError(); });
282 return Emitter(res->os(), unsupportedInstr).emitTest(test);
static void parseUnsupportedInstructionsFile(MLIRContext *ctxt, const std::string &unsupportedInstructionsFile, DenseSet< StringAttr > &unsupportedInstrs)
static std::unique_ptr< llvm::ToolOutputFile > createOutputFile(StringRef filename, StringRef dirname, function_ref< InFlightDiagnostic()> emitError)
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
void appendPossiblyAbsolutePath(llvm::SmallVectorImpl< char > &base, const llvm::Twine &suffix)
Append a path to an existing path, replacing it if the other path is absolute.