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 emitTest(rtg::TestOp test,
bool emitHeaderFooter =
false) {
108 if (emitHeaderFooter)
109 os <<
"# Begin of " << test.getSymName() <<
"\n\n";
111 for (
auto &op : *test.getBody()) {
112 if (op.hasTrait<OpTrait::ConstantLike>()) {
113 SmallVector<OpFoldResult> results;
114 if (failed(op.fold(results)))
117 for (
auto [val, res] : llvm::zip(op.getResults(), results)) {
118 auto attr = res.dyn_cast<Attribute>();
128 auto res = TypeSwitch<Operation *, LogicalResult>(&op)
129 .Case<InstructionOpInterface, LabelDeclOp, LabelOp>(
130 [&](
auto op) {
return emit(op); })
131 .Default([](
auto op) {
132 return op->emitError(
"emitter unknown RTG operation");
141 if (emitHeaderFooter)
142 os <<
"\n# End of " << test.getSymName() <<
"\n\n";
149 llvm::raw_ostream &os;
152 const DenseSet<StringAttr> &unsupportedInstr;
155 DenseMap<Value, Attribute> state;
162 const std::string &unsupportedInstructionsFile,
163 DenseSet<StringAttr> &unsupportedInstrs) {
164 if (!unsupportedInstructionsFile.empty()) {
165 std::ifstream input(unsupportedInstructionsFile);
167 while (std::getline(input, token,
',')) {
168 auto trimmed = StringRef(token).trim();
169 if (!trimmed.empty())
170 unsupportedInstrs.insert(StringAttr::get(ctxt, trimmed));
175static std::unique_ptr<llvm::ToolOutputFile>
177 function_ref<InFlightDiagnostic()> emitError) {
179 SmallString<128> outputFilename(dirname);
181 auto outputDir = llvm::sys::path::parent_path(outputFilename);
184 std::error_code error = llvm::sys::fs::create_directories(outputDir);
186 emitError() <<
"cannot create output directory \"" << outputDir
187 <<
"\": " << error.message();
192 std::string errorMessage;
193 auto output = mlir::openOutputFile(outputFilename, &errorMessage);
195 emitError() << errorMessage;
204struct EmitRTGISAAssemblyPass
205 :
public rtg::impl::EmitRTGISAAssemblyPassBase<EmitRTGISAAssemblyPass> {
208 void runOnOperation()
override;
211 LogicalResult emitSplit(
const DenseSet<StringAttr> &unsupportedInstr);
214 LogicalResult
emit(
const DenseSet<StringAttr> &unsupportedInstr);
218void EmitRTGISAAssemblyPass::runOnOperation() {
219 if ((!path.hasValue() || path.empty()) && splitOutput) {
220 getOperation().emitError(
"'split-output' option only valid in combination "
221 "with a valid 'path' argument");
222 return signalPassFailure();
225 DenseSet<StringAttr> unsupportedInstr;
226 for (
const auto &instr : unsupportedInstructions)
227 unsupportedInstr.insert(StringAttr::
get(&getContext(), instr));
229 &getContext(), unsupportedInstructionsFile.getValue(), unsupportedInstr);
232 if (failed(emitSplit(unsupportedInstr)))
233 return signalPassFailure();
238 if (failed(
emit(unsupportedInstr)))
239 return signalPassFailure();
243EmitRTGISAAssemblyPass::emit(
const DenseSet<StringAttr> &unsupportedInstr) {
244 std::unique_ptr<llvm::ToolOutputFile> file;
245 bool emitToFile = path.hasValue() && !path.empty();
248 [&]() {
return getOperation().emitError(); });
255 Emitter emitter(emitToFile ? file->os() :
llvm::errs(), unsupportedInstr);
256 for (
auto test : getOperation().getOps<TestOp>())
257 if (failed(emitter.emitTest(test, true)))
263LogicalResult EmitRTGISAAssemblyPass::emitSplit(
264 const DenseSet<StringAttr> &unsupportedInstr) {
265 auto tests = getOperation().getOps<TestOp>();
266 return failableParallelForEach(
267 &getContext(), tests.begin(), tests.end(), [&](rtg::TestOp test) {
268 auto res = createOutputFile(test.getSymName().str() +
".s", path,
269 [&]() { return test.emitError(); });
274 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.