MLLIF
a MLIR-based Language to Language Interoperability Flyover
Loading...
Searching...
No Matches
CIRAdapter.cxx
Go to the documentation of this file.
1/*
2 * Copyright 2025 Yeong-won Seo
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "pch.h"
18
23
24namespace {
25 auto GetArgNames(cir::FuncOp &fn) -> std::vector<std::string> {
26
27 std::vector<std::string> argNames;
28 argNames.reserve(fn.getNumArguments());
29
30 fn.getBody().walk([&argNames](mlir::Operation *op) {
31 if (auto alloca = llvm::dyn_cast<cir::AllocaOp>(op); alloca && alloca.getInit()) {
32 argNames.push_back(alloca.getName().str());
33 }
34 });
35
36 return argNames;
37 }
38} // namespace
39
41 std::deque<std::string> Path;
42 std::string Tag;
43 bool Skip;
44 bool Success;
45
46 explicit CIRAnnotatedData(cir::FuncOp &fn) : Skip(true), Success(true) {
47 if (const auto annot = fn.getAnnotations(); !annot || annot.value().empty()) {
48 return;
49 }
50
51 for (auto attr : fn.getAnnotationsAttr()) {
52 auto annotAttr = mlir::dyn_cast<cir::AnnotationAttr>(attr);
53 if (!annotAttr) {
54 continue;
55 }
56
57 mllif::shared::Annotation annot{annotAttr.getName().str()};
58 if (!annot.Key.starts_with(mllif::shared::Namespace + '.')) {
59 continue;
60 }
61 annot.Key = annot.Key.substr(mllif::shared::Namespace.size() + 1);
62
63 Skip = false;
64
65 if (annot.Key == mllif::shared::prefix::Path) {
66 Path.assign(annot.Values.begin(), annot.Values.end());
67
68 } else if (annot.Key == mllif::shared::prefix::Type) {
69 if (annot.Values.size() != 1) {
70 llvm::errs() << "error: type of function should be specified once (" << fn.getSymName() << ")\n";
71 Success = false;
72 continue;
73 }
74
75 Tag = annot.Values.front();
76
77 } else {
78 llvm::errs() << "error: unrecognized key '" << annot.Key << "' for function '" << fn.getSymName() << "'\n";
79 Success = false;
80 }
81 }
82 }
83};
84
85void mllif::mlir::cir::CIRAdapter::handle(Tree &symbols, std::shared_ptr<::mlir::ModuleOp> module, ::mlir::Operation *op) {
86 auto fn = dyn_cast<::cir::FuncOp>(op);
87 if (!fn) {
88 return;
89 }
90
91 CIRAnnotatedData annotated{fn};
92 if (annotated.Skip) {
93 return;
94 }
95 if (!annotated.Success) {
96 llvm::errs() << "error: function '" << fn.getSymName() << "' has invalid annotations\n";
97 return;
98 }
99
100 const auto args = fn.getArguments();
101
102 std::vector<std::string> argNames = GetArgNames(fn);
103
104 if (args.size() != argNames.size()) {
105 llvm::errs() << "error: invalid function signature for '" << fn.getSymName() << "' (annotation mismatched)\n";
106 return;
107 }
108
109 auto copyPath = annotated.Path;
110 const auto fnSym = symbols.root().insert_inplace(copyPath, annotated.Tag);
111 if (!fnSym) {
112 llvm::errs() << "error: couldn't create symbol node (";
113 for (auto seg : annotated.Path) {
114 llvm::errs() << '/' << seg;
115 }
116 llvm::errs() << "). is there a invalid path for symbol?\n";
117 return;
118 }
119
120 fnSym->attributes().emplace_back(std::make_pair("sym", fn.getSymName()));
121
122 const auto rets = fn.getResultTypes();
123
124 std::string typeStr;
125 if (rets.size() > 0) {
126 auto type = Types::From(rets[0], module);
127 if (!type) {
128 llvm::errs() << "error: unrecognized return type '";
129 rets[0].print(llvm::errs());
130 llvm::errs() << "'\n";
131 return;
132 }
133 typeStr = type->store(symbols);
134 } else {
135 typeStr = "void";
136 }
137
138 fnSym->attributes().emplace_back(std::make_pair("ret", typeStr));
139
140 auto iParm = 0;
141
142 if (annotated.Tag == shared::type::Method) {
143 annotated.Path.pop_back();
144 const auto parentNode = symbols.root().insert_inplace(annotated.Path, "");
145 assert(parentNode && "parent of a symbol cannot be null");
146
147 // Only object can hold methods
148 parentNode->tag() = shared::type::Object;
149
150 // Skip 'this' parameter
151 iParm++;
152 }
153
154 for (; iParm < args.size(); ++iParm) {
155 auto type = Types::From(args[iParm].getType(), module);
156 if (!type) {
157 llvm::errs() << "error: unrecognized type '";
158 args[iParm].getType().print(llvm::errs());
159 llvm::errs() << "'\n";
160 return;
161 }
162 const auto typeStr = type->store(symbols);
163
164 fnSym
165 ->children()
166 .emplace_back("param", argNames[iParm])
167 .attributes()
168 .emplace_back("type", typeStr);
169 }
170}
171
172namespace {
173 [[maybe_unused]]
175}
std::vector< std::pair< std::string, std::string > > & attributes()
Gets attributes of node.
Definition Tree.h:99
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:46
A tree struct for symbol tree. It's just a simple wrapper for root node.
Definition Tree.h:147
Node & root()
Gets a root node of the tree.
Definition Tree.h:160
void handle(Tree &symbols, std::shared_ptr<::mlir::ModuleOp > module, ::mlir::Operation *op) override
constexpr std::string Path
Definition annotation.h:30
constexpr std::string Type
Definition annotation.h:31
constexpr std::string Method
Definition annotation.h:36
constexpr std::string Object
Definition annotation.h:37
constexpr std::string Namespace
Definition annotation.h:27
std::deque< std::string > Path
std::string Tag
CIRAnnotatedData(cir::FuncOp &fn)