MLLIF
a MLIR-based Language to Language Interoperability Flyover
Loading...
Searching...
No Matches
main.cxx
Go to the documentation of this file.
1#include "pch.h"
2
3#include <llvm/Support/MemoryBuffer.h>
4#include <llvm/Support/SourceMgr.h>
5#include <mlir/Parser/Parser.h>
8
9namespace {
10 auto LoadModule(mlir::MLIRContext& context, const std::string& filename) -> std::unique_ptr<mlir::ModuleOp> {
11
12 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> fileOrErr = llvm::MemoryBuffer::getFile(filename);
13 if (const std::error_code ec = fileOrErr.getError()) {
14 llvm::errs() << "error: couldn't open input file: " << ec.message() << "\n";
15 return nullptr;
16 }
17
18 llvm::SourceMgr sourceManager;
19 sourceManager.AddNewSourceBuffer(std::move(*fileOrErr), llvm::SMLoc());
20 mlir::OwningOpRef<mlir::ModuleOp> owningModule = mlir::parseSourceFile<mlir::ModuleOp>(sourceManager, &context);
21 if (!owningModule) {
22 llvm::errs() << "error: couldn't load file " << filename << "\n";
23 return nullptr;
24 }
25
26
27 return std::make_unique<mlir::ModuleOp>(owningModule.release());
28 }
29
30 template<typename T>
31 auto Store(const mlir::ArrayAttr& array, std::string from, std::string name, T& container) -> bool {
32 bool success = true;
33 for (auto value : array) {
34 const auto str = mlir::dyn_cast<mlir::StringAttr>(value);
35 if (!str) {
36 llvm::errs() << "error: " << name << " should be string (" << from << ")\n";
37 success = false;
38 continue;
39 }
40
41 container.emplace_back(str.getValue());
42 }
43
44 return success;
45 }
46}
47
48auto main(int argc, char **argv) -> int {
49 mlir::MLIRContext context;
50
51 mlir::DialectRegistry registry;
52 registry.insert<
53 mlir::BuiltinDialect,
54 mlir::arith::ArithDialect,
55 cir::CIRDialect,
56 mlir::memref::MemRefDialect,
57 mlir::LLVM::LLVMDialect,
58 mlir::DLTIDialect,
59 mlir::omp::OpenMPDialect>();
60 context.appendDialectRegistry(registry);
61
62 if (argc <= 2) {
63 llvm::errs() << "usage: mllif-mlir <output> <file>...\n";
64 return 1;
65 }
66 const std::string output = argv[1];
67
68
70
71 for (auto i = 2; i < argc; ++i) {
72 auto module = LoadModule(context, std::string(argv[i]));
73
74 module->walk([&module, &tree](mlir::Operation* op, const mlir::WalkStage& stage) {
75 auto fn = mlir::dyn_cast<cir::FuncOp>(op);
76 if (!fn || !stage.isAfterAllRegions()) {
77 return;
78 }
79
80 const auto annotations = fn.getAnnotations();
81 if (!annotations || annotations->empty()) {
82 return;
83 }
84
85 std::deque<std::string> path;
86 std::string tag;
87 bool success = true;
88
89 for (auto attribute : annotations.value()) {
90 auto annotation = mlir::dyn_cast<cir::AnnotationAttr>(attribute);
91 if (!annotation) {
92 continue;
93 }
94
95 auto key = annotation.getName().getValue();
96 if (!key.starts_with(mllif::shared::Namespace + '.')) {
97 continue;
98 }
99
100 key = key.substr(mllif::shared::Namespace.size() + 1);
101
102 if (key == mllif::shared::prefix::Path) {
103 success &= Store(annotation.getArgs(), fn.getSymName().str(), "path segment", path);
104
105 } else if (key == mllif::shared::prefix::Type) {
106 const auto args = annotation.getArgs().getValue();
107 if (args.size() < 1) {
108 llvm::errs() << "error: insufficient argument number: function type should be specified for function '" << fn.getSymName() << "'\n";
109 success = false;
110 continue;
111 }
112
113 const auto str = mlir::dyn_cast<mlir::StringAttr>(args[0]);
114 if (!str) {
115 llvm::errs() << "error: function type should be string (" << fn.getSymName() << ")\n";
116 success = false;
117 continue;
118 }
119
120 tag = str.getValue();
121
122 } else {
123 llvm::errs() << "error: unrecognized key '" << key << "' for function '" << fn.getSymName() << "'\n";
124 success = false;
125 }
126 }
127
128 if (!success) {
129 llvm::errs() << "error: function '" << fn.getSymName() << "' has invalid annotations; couldn't be exported\n";
130 return;
131 }
132
133
134 const auto args = fn.getArguments();
135
136 std::vector<std::string> argNames;
137 argNames.reserve(args.size());
138 fn.getBody().walk([&argNames](mlir::Operation* op) {
139 if (auto alloca = llvm::dyn_cast<cir::AllocaOp>(op); alloca && alloca.getInit()) {
140 argNames.push_back(alloca.getName().str());
141 }
142 });
143
144 if (args.size() != argNames.size()) {
145 llvm::errs() << "error: invalid function signature for '" << fn.getSymName() << "' (annotation mismatched)\n";
146 return;
147 }
148
149 const auto fnSym = tree.root().insert_inplace(path, tag);
150
151 for (auto iParm = 0; iParm < args.size(); ++iParm) {
152 std::string buffer;
153 llvm::raw_string_ostream os(buffer);
154 args[iParm].getType().print(os);
155 os.flush();
156
157 fnSym
158 ->children()
159 .emplace_back("param", argNames[iParm])
160 .attributes()
161 .emplace_back("type", buffer);
162 }
163 });
164 }
165
166 std::error_code error;
167 llvm::raw_fd_ostream os(output, error);
168 if (error.value()) {
169 llvm::errs() << "error: couldn't open file '" << output << "': " << error.message() << "\n";
170 return 1;
171 }
172
173 tree.root().print(os);
174
175 return 0;
176}
Node * insert_inplace(std::deque< std::string > &path, const std::string &tag)
Inserts new node in-place at given path (first element of path is not id of this node)
Definition Tree.cxx:28
A tree struct for symbol tree. It's just a simple wrapper for root node.
Definition Tree.h:131
Node & root()
Gets a root node of the tree.
Definition Tree.h:144
auto main(int argc, char **argv) -> int
Definition main.cxx:48
constexpr std::string Path
Definition annotation.h:13
constexpr std::string Type
Definition annotation.h:14
constexpr std::string Namespace
Definition annotation.h:10