blob: 38afcc1b595231e40a32dc6e6f19794c96be1cc5 [file] [log] [blame]
Shankar Easwaran34ab70f2013-02-07 20:16:12 +00001//===- Passes/LayoutPass.cpp - Layout atoms -------------------------------===//
2//
3// The LLVM Linker
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//===----------------------------------------------------------------------===//
10
Michael J. Spencer7f09a3d2013-02-26 01:35:30 +000011#define DEBUG_TYPE "LayoutPass"
12
Shankar Easwaran34ab70f2013-02-07 20:16:12 +000013#include "lld/Passes/LayoutPass.h"
14
Michael J. Spencer7f09a3d2013-02-26 01:35:30 +000015#include "llvm/Support/Debug.h"
16
Shankar Easwaran34ab70f2013-02-07 20:16:12 +000017using namespace lld;
18
19/// The function compares atoms by sorting atoms in the following order
20/// a) Sorts atoms with the same permissions
21/// b) Sorts atoms with the same content Type
22/// c) Sorts atoms by Section position preference
23/// d) Sorts atoms by how they follow / precede each atom
24/// e) Sorts atoms on how they appear using File Ordinality
25/// f) Sorts atoms on how they appear within the File
26bool LayoutPass::CompareAtoms::operator()(const DefinedAtom *left,
27 const DefinedAtom *right) {
Michael J. Spencer7f09a3d2013-02-26 01:35:30 +000028 DEBUG(llvm::dbgs() << "Sorting " << left->name() << " " << right->name() << "\n");
Shankar Easwaran34ab70f2013-02-07 20:16:12 +000029 if (left == right)
30 return false;
31
Michael J. Spencer7f09a3d2013-02-26 01:35:30 +000032 DEBUG(llvm::dbgs() << "Sorting by perms\n");
33
Shankar Easwaran34ab70f2013-02-07 20:16:12 +000034 // Sort same permissions together.
35 DefinedAtom::ContentPermissions leftPerms = left->permissions();
36 DefinedAtom::ContentPermissions rightPerms = right->permissions();
37 if (leftPerms != rightPerms)
38 return leftPerms < rightPerms;
39
Michael J. Spencer7f09a3d2013-02-26 01:35:30 +000040 DEBUG(llvm::dbgs() << "Sorting by contentType\n");
41
Shankar Easwaran34ab70f2013-02-07 20:16:12 +000042 // Sort same content types together.
43 DefinedAtom::ContentType leftType = left->contentType();
44 DefinedAtom::ContentType rightType = right->contentType();
45 if (leftType != rightType)
46 return leftType < rightType;
47
48 // TO DO: Sort atoms in customs sections together.
49
Michael J. Spencer7f09a3d2013-02-26 01:35:30 +000050 DEBUG(llvm::dbgs() << "Sorting by sectionPos\n");
51
Shankar Easwaran34ab70f2013-02-07 20:16:12 +000052 // Sort by section position preference.
53 DefinedAtom::SectionPosition leftPos = left->sectionPosition();
54 DefinedAtom::SectionPosition rightPos = right->sectionPosition();
55 bool leftSpecialPos = (leftPos != DefinedAtom::sectionPositionAny);
56 bool rightSpecialPos = (rightPos != DefinedAtom::sectionPositionAny);
57 if (leftSpecialPos || rightSpecialPos) {
58 if (leftPos != rightPos)
59 return leftPos < rightPos;
60 }
61
Michael J. Spencer7f09a3d2013-02-26 01:35:30 +000062 DEBUG(llvm::dbgs() << "Sorting by override\n");
63
Shankar Easwaran34ab70f2013-02-07 20:16:12 +000064 AtomToOrdinalT::const_iterator lPos = _layout._ordinalOverrideMap.find(left);
65 AtomToOrdinalT::const_iterator rPos = _layout._ordinalOverrideMap.find(right);
66 AtomToOrdinalT::const_iterator end = _layout._ordinalOverrideMap.end();
67 if (lPos != end) {
68 if (rPos != end) {
69 // both left and right are overridden, so compare overridden ordinals
Michael J. Spencer7f09a3d2013-02-26 01:35:30 +000070 if (lPos->second != rPos->second)
71 return lPos->second < rPos->second;
Shankar Easwaran34ab70f2013-02-07 20:16:12 +000072 } else {
73 // left is overridden and right is not, so left < right
74 return true;
75 }
76 } else {
77 if (rPos != end) {
78 // right is overridden and left is not, so right < left
79 return false;
80 } else {
81 // neither are overridden,
82 // fall into default sorting below
83 }
84 }
85
Michael J. Spencer7f09a3d2013-02-26 01:35:30 +000086 DEBUG(llvm::dbgs() << "Sorting by .o order\n");
87
Shankar Easwaran34ab70f2013-02-07 20:16:12 +000088 // Sort by .o order.
89 const File *leftFile = &left->file();
90 const File *rightFile = &right->file();
91 if (leftFile != rightFile)
92 return leftFile->ordinal() < rightFile->ordinal();
93
Michael J. Spencer7f09a3d2013-02-26 01:35:30 +000094 DEBUG(llvm::dbgs() << "Sorting by ordinal\n");
95
Shankar Easwaran34ab70f2013-02-07 20:16:12 +000096 // Sort by atom order with .o file.
97 uint64_t leftOrdinal = left->ordinal();
98 uint64_t rightOrdinal = right->ordinal();
99 if (leftOrdinal != rightOrdinal)
100 return leftOrdinal < rightOrdinal;
101
Michael J. Spencer7f09a3d2013-02-26 01:35:30 +0000102 DEBUG(llvm::dbgs() << "Unordered\n");
103
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000104 return false;
105}
106
107/// This pass builds the followon tables described by two DenseMaps
108/// followOnRoots and followonNexts.
109/// The followOnRoots map contains a mapping of a DefinedAtom to its root
110/// The followOnNexts map contains a mapping of what DefinedAtom follows the
111/// current Atom
112/// The algorithm follows a very simple approach
113/// a) If the atom is first seen, then make that as the root atom
114/// b) The targetAtom which this Atom contains, has the root thats set to the
115/// root of the current atom
116/// c) If the targetAtom is part of a different tree and the root of the
117/// targetAtom is itself, Chain all the atoms that are contained in the tree
118/// to the current Tree
119/// d) If the targetAtom is part of a different chain and the root of the
120/// targetAtom until the targetAtom has all atoms of size 0, then chain the
121/// targetAtoms and its tree to the current chain
122void LayoutPass::buildFollowOnTable(MutableFile::DefinedAtomRange &range) {
123 for (auto ai : range) {
124 for (const Reference *r : *ai) {
125 if (r->kind() == lld::Reference::kindLayoutAfter) {
126 const DefinedAtom *targetAtom = llvm::dyn_cast<DefinedAtom>(r->target());
127 _followOnNexts[ai] = targetAtom;
128 // If we find a followon for the first time, lets make that
129 // atom as the root atom
130 if (_followOnRoots.count(ai) == 0) {
131 _followOnRoots[ai] = ai;
132 }
133 // If the targetAtom is not a root of any chain, lets make
134 // the root of the targetAtom to the root of the current chain
135 auto iter = _followOnRoots.find(targetAtom);
136 if (iter == _followOnRoots.end()) {
137 _followOnRoots[targetAtom] = _followOnRoots[ai];
138 } else {
139 // The followon is part of another chain
140 if (iter->second == targetAtom) {
141 const DefinedAtom *a = targetAtom;
142 while (true) {
143 _followOnRoots[a] = _followOnRoots[ai];
144 // Set all the follow on's for the targetAtom to be
145 // the current root
146 AtomToAtomT::iterator targetFollowOnAtomsIter =
147 _followOnNexts.find(a);
148
149 if (targetFollowOnAtomsIter != _followOnNexts.end())
150 a = targetFollowOnAtomsIter->second;
151 else
152 break;
153 } // while true
154 } else { // the atom could be part of chain already
155 // Get to the root of the chain
156 const DefinedAtom *a = _followOnRoots[targetAtom];
157 // Lets add to the chain only if the atoms that
158 // appear before the targetAtom in the chain
159 // are of size 0
160 bool foundNonZeroSizeAtom = false;
161 while (true) {
162 // Set all the follow on's for the targetAtom to be
163 // the current root
164 AtomToAtomT::iterator targetFollowOnAtomsIter =
165 _followOnNexts.find(a);
166
167 if (targetFollowOnAtomsIter != _followOnNexts.end())
168 a = targetFollowOnAtomsIter->second;
169 else
170 break;
171
172 if (a->size() != 0) {
173 foundNonZeroSizeAtom = true;
174 break;
175 }
176 if (a == targetAtom)
177 break;
178 } // while true
179 if (foundNonZeroSizeAtom) {
180 // TODO: print warning that an impossible layout
181 // is being desired by the user
182 // Continue to the next atom
183 break;
184 }
185
186 _followOnNexts[ai] = _followOnRoots[targetAtom];
187 // Set the root of all atoms in the
188 a = _followOnRoots[targetAtom];
189 while (true) {
190 _followOnRoots[a] = _followOnRoots[ai];
191 // Set all the follow on's for the targetAtom to be
192 // the current root
193 AtomToAtomT::iterator targetFollowOnAtomsIter =
194 _followOnNexts.find(a);
195 if (targetFollowOnAtomsIter != _followOnNexts.end())
196 a = targetFollowOnAtomsIter->second;
197 else
198 break;
199 } // while true
200 } // end else
201 } // else
202 } // kindLayoutAfter
203 } // Reference
204 } // range
205}
206
207/// This pass builds the followon tables using InGroup relationships
208/// The algorithm follows a very simple approach
209/// a) If the rootAtom is not part of any root, create a new root with the
210/// as the head
211/// b) If the current Atom root is not found, then make the current atoms root
212/// point to the rootAtom
213/// c) If the root of the current Atom is itself a root of some other tree
214/// make all the atoms in the chain point to the ingroup reference
215/// d) Check to see if the current atom is part of the chain from the rootAtom
216/// if not add the atom to the chain, so that the current atom is part of the
217/// the chain where the rootAtom is in
218void LayoutPass::buildInGroupTable(MutableFile::DefinedAtomRange &range) {
219 // This table would convert precededby references to follow on
220 // references so that we have only one table
221 for (auto ai : range) {
222 for (const Reference *r : *ai) {
223 if (r->kind() == lld::Reference::kindInGroup) {
224 const DefinedAtom *rootAtom = llvm::dyn_cast<DefinedAtom>(r->target());
225 // If the root atom is not part of any root
226 // create a new root
227 if (_followOnRoots.count(rootAtom) == 0) {
228 _followOnRoots[rootAtom] = rootAtom;
229 }
230 // If the current Atom has not been seen yet and there is no root
231 // that has been set, set the root of the atom to the targetAtom
232 // as the targetAtom points to the ingroup root
233 auto iter = _followOnRoots.find(ai);
234 if (iter == _followOnRoots.end()) {
235 _followOnRoots[ai] = rootAtom;
236 }
237 else if (iter->second == ai) {
238 if (iter->second != rootAtom) {
239 const DefinedAtom *a = iter->second;
240 // Change all the followon next references to the ingroup reference root
241 while (true) {
242 _followOnRoots[a] = rootAtom;
243 // Set all the follow on's for the targetAtom to be
244 // the current root
245 AtomToAtomT::iterator targetFollowOnAtomsIter =
246 _followOnNexts.find(a);
247 if (targetFollowOnAtomsIter != _followOnNexts.end())
248 a = targetFollowOnAtomsIter->second;
249 else
250 break;
251 } // while true
252 }
253 }
254 else {
255 // TODO : Flag an error that the root of the tree
256 // is different, Here is an example
257 // Say there are atoms
258 // chain 1 : a->b->c
259 // chain 2 : d->e->f
260 // and e,f have their ingroup reference as a
261 // this could happen only if the root of e,f that is d
262 // has root as 'a'
263 continue;
264 }
265
266 // Check if the current atom is part of the chain
267 bool isAtomInChain = false;
268 const DefinedAtom *lastAtom = rootAtom;
269 while (true) {
270 AtomToAtomT::iterator followOnAtomsIter =
271 _followOnNexts.find(lastAtom);
272 if (followOnAtomsIter != _followOnNexts.end()) {
273 lastAtom = followOnAtomsIter->second;
274 if (lastAtom == ai) {
275 isAtomInChain = true;
276 break;
277 }
278 }
279 else
280 break;
281 } // findAtomInChain
282
283 if (!isAtomInChain)
284 _followOnNexts[lastAtom] = ai;
285 }
286 }
287 }
288}
289
290/// This pass builds the followon tables using Preceded By relationships
291/// The algorithm follows a very simple approach
292/// a) If the targetAtom is not part of any root and the current atom is not
293/// part of any root, create a chain with the current atom as root and
294/// the targetAtom as following the current atom
295/// b) Chain the targetAtom to the current Atom if the targetAtom is not part
296/// of any chain and the currentAtom has no followOn's
297/// c) If the targetAtom is part of a different tree and the root of the
298/// targetAtom is itself, and if the current atom is not part of any root
299/// chain all the atoms together
300/// d) If the current atom has no followon and the root of the targetAtom is
301/// not equal to the root of the current atom(the targetAtom is not in the
302/// same chain), chain all the atoms that are lead by the targetAtom into
303/// the current chain
304void LayoutPass::buildPrecededByTable(MutableFile::DefinedAtomRange &range) {
305 // This table would convert precededby references to follow on
306 // references so that we have only one table
307 for (auto ai : range) {
308 for (const Reference *r : *ai) {
309 if (r->kind() == lld::Reference::kindLayoutBefore) {
310 const DefinedAtom *targetAtom = llvm::dyn_cast<DefinedAtom>(r->target());
311 // Is the targetAtom not chained
312 if (_followOnRoots.count(targetAtom) == 0) {
313 // Is the current atom not part of any root ?
314 if (_followOnRoots.count(ai) == 0) {
315 _followOnRoots[ai] = ai;
316 _followOnNexts[ai] = targetAtom;
317 _followOnRoots[targetAtom] = _followOnRoots[ai];
318 } else if (_followOnNexts.count(ai) == 0) {
319 // Chain the targetAtom to the current Atom
320 // if the currentAtom has no followon references
321 _followOnNexts[ai] = targetAtom;
322 _followOnRoots[targetAtom] = _followOnRoots[ai];
323 }
324 } else if (_followOnRoots.find(targetAtom)->second == targetAtom) {
325 // Is the targetAtom in chain with the targetAtom as the root ?
326 bool changeRoots = false;
327 if (_followOnRoots.count(ai) == 0) {
328 _followOnRoots[ai] = ai;
329 _followOnNexts[ai] = targetAtom;
330 _followOnRoots[targetAtom] = _followOnRoots[ai];
331 changeRoots = true;
332 } else if (_followOnNexts.count(ai) == 0) {
333 // Chain the targetAtom to the current Atom
334 // if the currentAtom has no followon references
335 if (_followOnRoots[ai] != _followOnRoots[targetAtom]) {
336 _followOnNexts[ai] = targetAtom;
337 _followOnRoots[targetAtom] = _followOnRoots[ai];
338 changeRoots = true;
339 }
340 }
341 // Change the roots of the targetAtom and its chain to
342 // the current atoms root
343 if (changeRoots) {
344 const DefinedAtom *a = _followOnRoots[targetAtom];
345 while (true) {
346 _followOnRoots[a] = _followOnRoots[ai];
347 // Set all the follow on's for the targetAtom to be
348 // the current root
349 AtomToAtomT::iterator targetFollowOnAtomsIter =
350 _followOnNexts.find(a);
351 if (targetFollowOnAtomsIter != _followOnNexts.end())
352 a = targetFollowOnAtomsIter->second;
353 else
354 break;
355 }
356 } // changeRoots
357 } // Is targetAtom root
358 } // kindLayoutBefore
359 } // Reference
360 } // atom iteration
361} // end function
362
363
364/// Build an ordinal override map by traversing the followon chain, and
365/// assigning ordinals to each atom, if the atoms have their ordinals
366/// already assigned skip the atom and move to the next. This is the
367/// main map thats used to sort the atoms while comparing two atoms together
368void LayoutPass::buildOrdinalOverrideMap(MutableFile::DefinedAtomRange &range) {
369 uint64_t index = 0;
370 for (auto ai : range) {
371 const DefinedAtom *atom = ai;
372 AtomToAtomT::iterator start = _followOnRoots.find(atom);
373 if (start != _followOnRoots.end()) {
374 for (const DefinedAtom *nextAtom = start->second; nextAtom != NULL;
375 nextAtom = _followOnNexts[nextAtom]) {
376 AtomToOrdinalT::iterator pos = _ordinalOverrideMap.find(nextAtom);
377 if (pos == _ordinalOverrideMap.end()) {
378 _ordinalOverrideMap[nextAtom] = index++;
379 }
380 }
381 } else {
382 _ordinalOverrideMap[atom] = index;
383 }
384 }
385}
386
387/// Perform the actual pass
388void LayoutPass::perform(MutableFile &mergedFile) {
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000389 MutableFile::DefinedAtomRange atomRange = mergedFile.definedAtoms();
390
391 // Build follow on tables
392 buildFollowOnTable(atomRange);
393
394 // Build Ingroup reference table
395 buildInGroupTable(atomRange);
396
397 // Build preceded by tables
398 buildPrecededByTable(atomRange);
399
400 // Build override maps
401 buildOrdinalOverrideMap(atomRange);
402
403 // sort the atoms
404 std::sort(atomRange.begin(), atomRange.end(), _compareAtoms);
405}