74 DeviceOp device = getOperation();
76 Builder builder(device.getContext());
82 DenseMap<StringRef, SmallVector<LinkArtifact, 2>> funcToObjs;
83 bool badMetadata =
false;
84 for (
auto funcOp : device.getOps<mlir::func::FuncOp>()) {
85 auto linkWith = funcOp->getAttrOfType<mlir::StringAttr>(
"link_with");
86 auto modeAttr = funcOp->getAttrOfType<mlir::StringAttr>(
"link_with_mode");
87 if (modeAttr && !linkWith) {
89 <<
"func '" << funcOp.getName()
90 <<
"' has link_with_mode but no link_with; link_with_mode only "
91 "describes how the link_with artifact is linked";
100 if (modeAttr.getValue() !=
"merge") {
102 <<
"func '" << funcOp.getName()
103 <<
"' has unknown link_with_mode '" << modeAttr.getValue()
104 <<
"'; the only supported value is 'merge'";
110 funcToObjs[funcOp.getName()].push_back({linkWith.getValue(), merge});
113 return signalPassFailure();
118 llvm::DenseSet<StringRef> usedFuncs;
125 SmallVector<CoreLinkFiles> coreFiles;
126 device.walk([&](CoreOp core) {
133 if (
auto lw = core.getLinkWith()) {
135 "link_with on aie.core is deprecated; attach link_with to "
136 "the func.func declaration instead");
137 files.linkFiles.insert(lw.value());
138 files.hadDeprecatedLinkWith =
true;
143 core.walk([&](Operation *op) {
144 if (
auto call = dyn_cast<mlir::func::CallOp>(op)) {
145 usedFuncs.insert(call.getCallee());
146 auto it = funcToObjs.find(call.getCallee());
147 if (it != funcToObjs.end())
148 for (
const LinkArtifact &artifact : it->second)
149 (artifact.merge ? files.mergeFiles : files.linkFiles)
150 .insert(artifact.path);
151 }
else if (
auto indCall = dyn_cast<mlir::func::CallIndirectOp>(op)) {
153 "indirect call in core body — link_with attributes on "
154 "indirectly-called functions are not automatically resolved; "
155 "add a direct func.call to the required func.func declaration "
156 "so that aie-assign-core-link-files can trace the dependency");
160 coreFiles.push_back(std::move(files));
168 llvm::MapVector<StringRef, CoreOp> linkedBy;
169 for (CoreLinkFiles &files : coreFiles)
170 for (StringRef path : files.linkFiles)
171 linkedBy.insert({path, files.core});
172 bool conflict =
false;
173 for (CoreLinkFiles &files : coreFiles)
174 for (StringRef path : files.mergeFiles) {
175 auto *it = linkedBy.find(path);
176 if (it == linkedBy.end())
179 InFlightDiagnostic diag =
180 files.core.emitError()
181 <<
"artifact '" << path
182 <<
"' is merged into an LLVM module here but object-linked in the "
183 "same aie.device; an artifact must use a single link mode "
184 "across all cores of a device";
185 diag.attachNote(it->second.getLoc())
186 <<
"artifact '" << path <<
"' is object-linked here";
189 return signalPassFailure();
192 for (CoreLinkFiles &files : coreFiles) {
193 if (files.hadDeprecatedLinkWith)
194 files.core->removeAttr(
"link_with");
197 if (!files.linkFiles.empty())
198 files.core.setLinkFilesAttr(
199 builder.getStrArrayAttr(files.linkFiles.getArrayRef()));
200 if (!files.mergeFiles.empty())
201 files.core.setLinkMergeFilesAttr(
202 builder.getStrArrayAttr(files.mergeFiles.getArrayRef()));
206 for (
auto &[funcName, objs] : funcToObjs) {
207 if (!usedFuncs.count(funcName)) {
208 if (
auto funcOp = device.lookupSymbol<mlir::func::FuncOp>(funcName))
210 <<
"func '" << funcName
211 <<
"' has link_with but is never called from any core; "
212 "its artifact will not be linked or merged";