Skip to content

Commit 6ff77e6

Browse files
committed
[MLIR][mlir-link] Extract common llvm linker interface
1 parent 737d8c2 commit 6ff77e6

File tree

4 files changed

+464
-431
lines changed

4 files changed

+464
-431
lines changed
Lines changed: 293 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,293 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// This file defines the helper functions for the LLVM-like linkage behavior.
10+
// It is used by the LLVMLinker and other dialects that have same linkage
11+
// semantics.
12+
//
13+
//===----------------------------------------------------------------------===//
14+
15+
#ifndef MLIR_LINKER_LLVMLINKERMIXIN_H
16+
#define MLIR_LINKER_LLVMLINKERMIXIN_H
17+
18+
#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
19+
#include "mlir/IR/BuiltinOps.h"
20+
#include "mlir/Linker/LinkerInterface.h"
21+
22+
namespace mlir::link {
23+
24+
using Linkage = LLVM::Linkage;
25+
26+
//===----------------------------------------------------------------------===//
27+
// Linkage helpers
28+
//===----------------------------------------------------------------------===//
29+
30+
static inline bool isExternalLinkage(Linkage linkage) {
31+
return linkage == Linkage::External;
32+
}
33+
34+
static inline bool isAvailableExternallyLinkage(Linkage linkage) {
35+
return linkage == Linkage::AvailableExternally;
36+
}
37+
38+
static inline bool isLinkOnceAnyLinkage(Linkage linkage) {
39+
return linkage == Linkage::Linkonce;
40+
}
41+
42+
static inline bool isLinkOnceODRLinkage(Linkage linkage) {
43+
return linkage == Linkage::LinkonceODR;
44+
}
45+
46+
static inline bool isLinkOnceLinkage(Linkage linkage) {
47+
return isLinkOnceAnyLinkage(linkage) || isLinkOnceODRLinkage(linkage);
48+
}
49+
50+
static inline bool isWeakAnyLinkage(Linkage linkage) {
51+
return linkage == Linkage::Weak;
52+
}
53+
54+
static inline bool isWeakODRLinkage(Linkage linkage) {
55+
return linkage == Linkage::WeakODR;
56+
}
57+
58+
static inline bool isWeakLinkage(Linkage linkage) {
59+
return isWeakAnyLinkage(linkage) || isWeakODRLinkage(linkage);
60+
}
61+
62+
static inline bool isAppendingLinkage(Linkage linkage) {
63+
return linkage == Linkage::Appending;
64+
}
65+
66+
static inline bool isInternalLinkage(Linkage linkage) {
67+
return linkage == Linkage::Internal;
68+
}
69+
70+
static inline bool isPrivateLinkage(Linkage linkage) {
71+
return linkage == Linkage::Private;
72+
}
73+
74+
static inline bool isLocalLinkage(Linkage linkage) {
75+
return isInternalLinkage(linkage) || isPrivateLinkage(linkage);
76+
}
77+
78+
static inline bool isExternalWeakLinkage(Linkage linkage) {
79+
return linkage == Linkage::ExternWeak;
80+
}
81+
82+
static inline bool isCommonLinkage(Linkage linkage) {
83+
return linkage == Linkage::Common;
84+
}
85+
86+
static inline bool isWeakForLinker(Linkage linkage) {
87+
return linkage == Linkage::Weak || linkage == Linkage::WeakODR ||
88+
linkage == Linkage::Linkonce || linkage == Linkage::LinkonceODR ||
89+
linkage == Linkage::Common || linkage == Linkage::ExternWeak;
90+
}
91+
92+
//===----------------------------------------------------------------------===//
93+
// Visibility helpers
94+
//===----------------------------------------------------------------------===//
95+
96+
using Visibility = LLVM::Visibility;
97+
98+
static inline bool isHiddenVisibility(Visibility visibility) {
99+
return visibility == Visibility::Hidden;
100+
}
101+
102+
static inline bool isProtectedVisibility(Visibility visibility) {
103+
return visibility == Visibility::Protected;
104+
}
105+
106+
static inline Visibility getMinVisibility(Visibility lhs, Visibility rhs) {
107+
if (isHiddenVisibility(lhs) || isHiddenVisibility(rhs))
108+
return Visibility::Hidden;
109+
if (isProtectedVisibility(lhs) || isProtectedVisibility(rhs))
110+
return Visibility::Protected;
111+
return Visibility::Default;
112+
}
113+
114+
//===----------------------------------------------------------------------===//
115+
// LLVMLinkerMixin
116+
//===----------------------------------------------------------------------===//
117+
118+
enum class ConflictResolution {
119+
LinkFromSrc,
120+
LinkFromDst,
121+
LinkFromBothAndRenameDst,
122+
LinkFromBothAndRenameSrc,
123+
};
124+
125+
template <typename DerivedLinkerInterface>
126+
class LLVMLinkerMixin {
127+
const DerivedLinkerInterface &getDerived() const {
128+
return static_cast<const DerivedLinkerInterface &>(*this);
129+
}
130+
131+
public:
132+
bool isDeclarationForLinker(Operation *op) const {
133+
const DerivedLinkerInterface &derived = getDerived();
134+
if (isAvailableExternallyLinkage(derived.getLinkage(op)))
135+
return true;
136+
return derived.isDeclaration(op);
137+
}
138+
139+
bool isLinkNeeded(Conflict pair, bool forDependency) const {
140+
const DerivedLinkerInterface &derived = getDerived();
141+
assert(derived.canBeLinked(pair.src) && "expected linkable operation");
142+
if (pair.src == pair.dst)
143+
return false;
144+
145+
Linkage srcLinkage = derived.getLinkage(pair.src);
146+
147+
// Always import variables with appending linkage.
148+
if (isAppendingLinkage(srcLinkage))
149+
return true;
150+
151+
bool alreadyDeclared = pair.dst && derived.isDeclaration(pair.dst);
152+
153+
// Don't import globals that are already declared
154+
if (derived.shouldLinkOnlyNeeded() && !alreadyDeclared)
155+
return false;
156+
157+
// Private dependencies are gonna be renamed and linked
158+
if (isLocalLinkage(srcLinkage))
159+
return forDependency;
160+
161+
// Always import dependencies that are not yet defined or declared
162+
if (forDependency && !pair.dst)
163+
return true;
164+
165+
if (derived.isDeclaration(pair.src))
166+
return false;
167+
168+
if (derived.shouldOverrideFromSrc())
169+
return true;
170+
171+
if (pair.dst)
172+
return true;
173+
174+
// Linkage specifies to keep operation only in source
175+
return !(isLinkOnceLinkage(srcLinkage) ||
176+
isAvailableExternallyLinkage(srcLinkage));
177+
}
178+
179+
ConflictResolution resolveConflict(Conflict pair) {
180+
const DerivedLinkerInterface &derived = getDerived();
181+
assert(derived.canBeLinked(pair.src) && "expected linkable operation");
182+
assert(derived.canBeLinked(pair.dst) && "expected linkable operation");
183+
184+
Linkage srcLinkage = derived.getLinkage(pair.src);
185+
Linkage dstLinkage = derived.getLinkage(pair.dst);
186+
187+
Visibility srcVisibility = derived.getVisibility(pair.src);
188+
Visibility dstVisibility = derived.getVisibility(pair.dst);
189+
Visibility visibility = getMinVisibility(srcVisibility, dstVisibility);
190+
191+
derived.setVisibility(pair.src, visibility);
192+
derived.setVisibility(pair.dst, visibility);
193+
194+
const bool srcIsDeclaration = isDeclarationForLinker(pair.src);
195+
const bool dstIsDeclaration = isDeclarationForLinker(pair.dst);
196+
197+
if (isAvailableExternallyLinkage(srcLinkage) && dstIsDeclaration) {
198+
return ConflictResolution::LinkFromSrc;
199+
}
200+
201+
// If both `src` and `dst` are declarations, we can ignore the conflict
202+
// and keep the `dst` declaration.
203+
if (srcIsDeclaration && dstIsDeclaration)
204+
return ConflictResolution::LinkFromDst;
205+
206+
// If the `dst` is a declaration import `src` definition
207+
// Link an available_externally over a declaration.
208+
if (dstIsDeclaration && !srcIsDeclaration)
209+
return ConflictResolution::LinkFromSrc;
210+
211+
// Conflicting private values are to be renamed.
212+
if (isLocalLinkage(dstLinkage))
213+
return ConflictResolution::LinkFromBothAndRenameDst;
214+
215+
if (isLocalLinkage(srcLinkage))
216+
return ConflictResolution::LinkFromBothAndRenameSrc;
217+
218+
if (isLinkOnceLinkage(srcLinkage))
219+
return ConflictResolution::LinkFromDst;
220+
221+
if (isLinkOnceLinkage(dstLinkage) || isWeakLinkage(dstLinkage))
222+
return ConflictResolution::LinkFromSrc;
223+
224+
if (isCommonLinkage(srcLinkage)) {
225+
if (!isCommonLinkage(dstLinkage))
226+
return ConflictResolution::LinkFromDst;
227+
if (derived.getBitWidth(pair.src) > derived.getBitWidth(pair.dst))
228+
return ConflictResolution::LinkFromSrc;
229+
return ConflictResolution::LinkFromDst;
230+
}
231+
232+
if (isWeakForLinker(srcLinkage)) {
233+
assert(!isExternalWeakLinkage(dstLinkage));
234+
assert(!isAvailableExternallyLinkage(dstLinkage));
235+
if (isLinkOnceLinkage(dstLinkage) && isWeakLinkage(srcLinkage)) {
236+
return ConflictResolution::LinkFromSrc;
237+
} else {
238+
// No need to link the `src`
239+
return ConflictResolution::LinkFromDst;
240+
}
241+
}
242+
243+
if (isWeakForLinker(dstLinkage)) {
244+
assert(isExternalLinkage(srcLinkage));
245+
return ConflictResolution::LinkFromSrc;
246+
}
247+
248+
llvm_unreachable("unimplemented conflict resolution");
249+
}
250+
};
251+
252+
//===----------------------------------------------------------------------===//
253+
// SymbolAttrLLVMLinkerMixin
254+
//===----------------------------------------------------------------------===//
255+
256+
template <typename DerivedLinkerInterface>
257+
class SymbolAttrLLVMLinkerInterface
258+
: public SymbolAttrLinkerInterface,
259+
public LLVMLinkerMixin<DerivedLinkerInterface> {
260+
public:
261+
using SymbolAttrLinkerInterface::SymbolAttrLinkerInterface;
262+
263+
using LinkerMixin = LLVMLinkerMixin<DerivedLinkerInterface>;
264+
265+
bool isLinkNeeded(Conflict pair, bool forDependency) const override {
266+
return LinkerMixin::isLinkNeeded(pair, forDependency);
267+
}
268+
269+
LogicalResult resolveConflict(Conflict pair) override {
270+
ConflictResolution resolution = LinkerMixin::resolveConflict(pair);
271+
272+
switch (resolution) {
273+
case ConflictResolution::LinkFromSrc:
274+
registerForLink(pair.src);
275+
return success();
276+
case ConflictResolution::LinkFromDst:
277+
return success();
278+
case ConflictResolution::LinkFromBothAndRenameDst:
279+
uniqued.insert(pair.dst);
280+
registerForLink(pair.src);
281+
return success();
282+
case ConflictResolution::LinkFromBothAndRenameSrc:
283+
uniqued.insert(pair.src);
284+
return success();
285+
}
286+
287+
llvm_unreachable("unimplemented conflict resolution");
288+
}
289+
};
290+
291+
} // namespace mlir::link
292+
293+
#endif // MLIR_LINKER_LLVMLINKERMIXIN_H

mlir/include/mlir/Linker/LinkerInterface.h

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -63,10 +63,10 @@ class LinkerInterface : public DialectInterface::Base<ConcreteType> {
6363
LinkerInterface(Dialect *dialect)
6464
: DialectInterface::Base<ConcreteType>(dialect) {}
6565

66-
/// TODO comment
67-
virtual LogicalResult initialize(ModuleOp src) = 0;
66+
/// Runs initialization of alinker before summarization for the given module
67+
virtual LogicalResult initialize(ModuleOp src) { return success(); }
6868

69-
/// TODO comment
69+
/// Link operations from current summary using state builder
7070
virtual LogicalResult link(LinkState &state) const = 0;
7171
};
7272

@@ -111,8 +111,10 @@ class SymbolLinkerInterface : public LinkerInterface<SymbolLinkerInterface> {
111111
/// Records a non-conflicting operation for linking.
112112
virtual void registerForLink(Operation *op) = 0;
113113

114-
/// Materialize new operation for the given conflict pair.
115-
virtual Operation *materialize(Operation *src, LinkState &state) const = 0;
114+
/// Materialize new operation for the given conflict src operation.
115+
virtual Operation *materialize(Operation *src, LinkState &state) const {
116+
return state.clone(src);
117+
}
116118

117119
/// Dependencies of the given operation required to be linked.
118120
virtual SmallVector<Operation *> dependencies(Operation *op) const = 0;
@@ -139,14 +141,27 @@ class SymbolAttrLinkerInterface : public SymbolLinkerInterface {
139141
public:
140142
using SymbolLinkerInterface::SymbolLinkerInterface;
141143

144+
/// Link operations from current summary using state builder
145+
LogicalResult link(LinkState &state) const override;
146+
142147
/// Returns the symbol for the given operation.
143148
StringRef getSymbol(Operation *op) const override;
144149

145150
/// Checks if an operation conflicts with existing linked operations.
146151
Conflict findConflict(Operation *src) const override;
147152

153+
/// Records a non-conflicting operation for linking.
154+
void registerForLink(Operation *op) override;
155+
156+
/// Dependencies of the given operation required to be linked.
157+
SmallVector<Operation *> dependencies(Operation *op) const override;
158+
148159
protected:
160+
// Operations that are to be linked with the original name.
149161
llvm::StringMap<Operation *> summary;
162+
163+
// Operations that are to be linked with unique names.
164+
SetVector<Operation *> uniqued;
150165
};
151166

152167
//===----------------------------------------------------------------------===//

0 commit comments

Comments
 (0)