blob: f6bf980006dd0ddc200f69d5ae3fdb28342ef242 [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
32 // Sort same permissions together.
33 DefinedAtom::ContentPermissions leftPerms = left->permissions();
34 DefinedAtom::ContentPermissions rightPerms = right->permissions();
Shankar Easwaran8c256852013-03-13 04:05:38 +000035
36 DEBUG(llvm::dbgs() << "Sorting by contentPerms"
37 << "(" << leftPerms << "," << rightPerms << ")\n");
38
Shankar Easwaran34ab70f2013-02-07 20:16:12 +000039 if (leftPerms != rightPerms)
40 return leftPerms < rightPerms;
41
42 // Sort same content types together.
43 DefinedAtom::ContentType leftType = left->contentType();
44 DefinedAtom::ContentType rightType = right->contentType();
Shankar Easwaran8c256852013-03-13 04:05:38 +000045
46 DEBUG(llvm::dbgs() << "Sorting by contentType"
47 << "(" << leftType << "," << rightType << ")\n");
48
Shankar Easwaran34ab70f2013-02-07 20:16:12 +000049 if (leftType != rightType)
50 return leftType < rightType;
51
52 // TO DO: Sort atoms in customs sections together.
53
54 // Sort by section position preference.
55 DefinedAtom::SectionPosition leftPos = left->sectionPosition();
56 DefinedAtom::SectionPosition rightPos = right->sectionPosition();
Shankar Easwaran8c256852013-03-13 04:05:38 +000057
58 DEBUG(llvm::dbgs() << "Sorting by sectionPos"
59 << "(" << leftPos << "," << rightPos << ")\n");
60
Shankar Easwaran34ab70f2013-02-07 20:16:12 +000061 bool leftSpecialPos = (leftPos != DefinedAtom::sectionPositionAny);
62 bool rightSpecialPos = (rightPos != DefinedAtom::sectionPositionAny);
63 if (leftSpecialPos || rightSpecialPos) {
64 if (leftPos != rightPos)
65 return leftPos < rightPos;
66 }
67
Michael J. Spencer7f09a3d2013-02-26 01:35:30 +000068 DEBUG(llvm::dbgs() << "Sorting by override\n");
69
Shankar Easwaran34ab70f2013-02-07 20:16:12 +000070 AtomToOrdinalT::const_iterator lPos = _layout._ordinalOverrideMap.find(left);
71 AtomToOrdinalT::const_iterator rPos = _layout._ordinalOverrideMap.find(right);
72 AtomToOrdinalT::const_iterator end = _layout._ordinalOverrideMap.end();
73 if (lPos != end) {
74 if (rPos != end) {
75 // both left and right are overridden, so compare overridden ordinals
Michael J. Spencer7f09a3d2013-02-26 01:35:30 +000076 if (lPos->second != rPos->second)
77 return lPos->second < rPos->second;
Shankar Easwaran34ab70f2013-02-07 20:16:12 +000078 } else {
79 // left is overridden and right is not, so left < right
80 return true;
81 }
82 } else {
83 if (rPos != end) {
84 // right is overridden and left is not, so right < left
85 return false;
86 } else {
Shankar Easwaran8962feb2013-03-14 16:09:49 +000087 // neither are overridden,
Shankar Easwaran34ab70f2013-02-07 20:16:12 +000088 // fall into default sorting below
89 }
90 }
91
92 // Sort by .o order.
93 const File *leftFile = &left->file();
94 const File *rightFile = &right->file();
Shankar Easwaran8c256852013-03-13 04:05:38 +000095
96 DEBUG(llvm::dbgs()
97 << "Sorting by .o order("
98 << "(" << leftFile->ordinal() << "," << rightFile->ordinal() << ")"
99 << "[" << leftFile->path() << "," << rightFile->path() << "]\n");
100
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000101 if (leftFile != rightFile)
102 return leftFile->ordinal() < rightFile->ordinal();
103
104 // Sort by atom order with .o file.
105 uint64_t leftOrdinal = left->ordinal();
106 uint64_t rightOrdinal = right->ordinal();
Shankar Easwaran8c256852013-03-13 04:05:38 +0000107
108 DEBUG(llvm::dbgs() << "Sorting by ordinal(" << left->ordinal() << ","
109 << right->ordinal() << ")\n");
110
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000111 if (leftOrdinal != rightOrdinal)
112 return leftOrdinal < rightOrdinal;
113
Michael J. Spencer7f09a3d2013-02-26 01:35:30 +0000114 DEBUG(llvm::dbgs() << "Unordered\n");
115
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000116 return false;
117}
118
119/// This pass builds the followon tables described by two DenseMaps
120/// followOnRoots and followonNexts.
121/// The followOnRoots map contains a mapping of a DefinedAtom to its root
122/// The followOnNexts map contains a mapping of what DefinedAtom follows the
123/// current Atom
124/// The algorithm follows a very simple approach
125/// a) If the atom is first seen, then make that as the root atom
Shankar Easwaran8962feb2013-03-14 16:09:49 +0000126/// b) The targetAtom which this Atom contains, has the root thats set to the
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000127/// root of the current atom
128/// c) If the targetAtom is part of a different tree and the root of the
129/// targetAtom is itself, Chain all the atoms that are contained in the tree
130/// to the current Tree
131/// d) If the targetAtom is part of a different chain and the root of the
132/// targetAtom until the targetAtom has all atoms of size 0, then chain the
133/// targetAtoms and its tree to the current chain
134void LayoutPass::buildFollowOnTable(MutableFile::DefinedAtomRange &range) {
135 for (auto ai : range) {
136 for (const Reference *r : *ai) {
137 if (r->kind() == lld::Reference::kindLayoutAfter) {
138 const DefinedAtom *targetAtom = llvm::dyn_cast<DefinedAtom>(r->target());
139 _followOnNexts[ai] = targetAtom;
140 // If we find a followon for the first time, lets make that
141 // atom as the root atom
142 if (_followOnRoots.count(ai) == 0) {
143 _followOnRoots[ai] = ai;
144 }
Shankar Easwaran8962feb2013-03-14 16:09:49 +0000145 // If the targetAtom is not a root of any chain, lets make
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000146 // the root of the targetAtom to the root of the current chain
147 auto iter = _followOnRoots.find(targetAtom);
148 if (iter == _followOnRoots.end()) {
Michael J. Spencer52fdb8b2013-03-09 01:41:27 +0000149 auto tmp = _followOnRoots[ai];
150 _followOnRoots[targetAtom] = tmp;
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000151 } else {
152 // The followon is part of another chain
153 if (iter->second == targetAtom) {
154 const DefinedAtom *a = targetAtom;
155 while (true) {
156 _followOnRoots[a] = _followOnRoots[ai];
157 // Set all the follow on's for the targetAtom to be
158 // the current root
159 AtomToAtomT::iterator targetFollowOnAtomsIter =
160 _followOnNexts.find(a);
161
162 if (targetFollowOnAtomsIter != _followOnNexts.end())
163 a = targetFollowOnAtomsIter->second;
164 else
165 break;
166 } // while true
167 } else { // the atom could be part of chain already
168 // Get to the root of the chain
169 const DefinedAtom *a = _followOnRoots[targetAtom];
Shankar Easwaranc44bc342013-03-06 21:59:27 +0000170 const DefinedAtom *targetPrevAtom = nullptr;
171
Shankar Easwaran8962feb2013-03-14 16:09:49 +0000172 // If the size of the atom is 0, and the target
Shankar Easwaranc44bc342013-03-06 21:59:27 +0000173 // is already part of a chain, lets bring the current
174 // atom into the chain
175 size_t currentAtomSize = (*ai).size();
176
Shankar Easwaran8962feb2013-03-14 16:09:49 +0000177 // Lets add to the chain only if the atoms that
178 // appear before the targetAtom in the chain
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000179 // are of size 0
180 bool foundNonZeroSizeAtom = false;
181 while (true) {
Shankar Easwaranc44bc342013-03-06 21:59:27 +0000182 targetPrevAtom = a;
183
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000184 // Set all the follow on's for the targetAtom to be
185 // the current root
186 AtomToAtomT::iterator targetFollowOnAtomsIter =
187 _followOnNexts.find(a);
188
189 if (targetFollowOnAtomsIter != _followOnNexts.end())
190 a = targetFollowOnAtomsIter->second;
191 else
192 break;
193
Shankar Easwaranc44bc342013-03-06 21:59:27 +0000194 if ((a->size() != 0) && (currentAtomSize != 0)) {
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000195 foundNonZeroSizeAtom = true;
196 break;
197 }
Shankar Easwaranc44bc342013-03-06 21:59:27 +0000198
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000199 if (a == targetAtom)
200 break;
Shankar Easwaranc44bc342013-03-06 21:59:27 +0000201
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000202 } // while true
203 if (foundNonZeroSizeAtom) {
Shankar Easwaran8962feb2013-03-14 16:09:49 +0000204 // TODO: print warning that an impossible layout
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000205 // is being desired by the user
Shankar Easwaran8962feb2013-03-14 16:09:49 +0000206 // Continue to the next atom
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000207 break;
208 }
209
Shankar Easwaranc44bc342013-03-06 21:59:27 +0000210 // If the atom is a zero sized atom, then make the target
211 // follow the zero sized atom, as the zero sized atom may be
212 // a weak symbol
213 if ((currentAtomSize == 0) && (targetPrevAtom)) {
214 _followOnNexts[targetPrevAtom] = ai;
215 _followOnRoots[ai] = _followOnRoots[targetPrevAtom];
216 _followOnNexts[ai] = targetAtom;
217 } else {
218 _followOnNexts[ai] = _followOnRoots[targetAtom];
Shankar Easwaran8962feb2013-03-14 16:09:49 +0000219 // Set the root of all atoms in the
Shankar Easwaranc44bc342013-03-06 21:59:27 +0000220 a = _followOnRoots[targetAtom];
221 while (true) {
222 _followOnRoots[a] = _followOnRoots[ai];
223 // Set all the follow on's for the targetAtom to be
224 // the current root
225 AtomToAtomT::iterator targetFollowOnAtomsIter =
226 _followOnNexts.find(a);
227 if (targetFollowOnAtomsIter != _followOnNexts.end())
228 a = targetFollowOnAtomsIter->second;
229 else
230 break;
231 } // while true
232 } // end else (currentAtomSize != 0)
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000233 } // end else
234 } // else
235 } // kindLayoutAfter
236 } // Reference
237 } // range
238}
239
240/// This pass builds the followon tables using InGroup relationships
241/// The algorithm follows a very simple approach
242/// a) If the rootAtom is not part of any root, create a new root with the
243/// as the head
244/// b) If the current Atom root is not found, then make the current atoms root
245/// point to the rootAtom
246/// c) If the root of the current Atom is itself a root of some other tree
247/// make all the atoms in the chain point to the ingroup reference
248/// d) Check to see if the current atom is part of the chain from the rootAtom
249/// if not add the atom to the chain, so that the current atom is part of the
250/// the chain where the rootAtom is in
251void LayoutPass::buildInGroupTable(MutableFile::DefinedAtomRange &range) {
Shankar Easwaran8962feb2013-03-14 16:09:49 +0000252 // This table would convert precededby references to follow on
253 // references so that we have only one table
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000254 for (auto ai : range) {
255 for (const Reference *r : *ai) {
256 if (r->kind() == lld::Reference::kindInGroup) {
257 const DefinedAtom *rootAtom = llvm::dyn_cast<DefinedAtom>(r->target());
258 // If the root atom is not part of any root
Shankar Easwaran8962feb2013-03-14 16:09:49 +0000259 // create a new root
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000260 if (_followOnRoots.count(rootAtom) == 0) {
261 _followOnRoots[rootAtom] = rootAtom;
262 }
Shankar Easwaran8962feb2013-03-14 16:09:49 +0000263 // If the current Atom has not been seen yet and there is no root
264 // that has been set, set the root of the atom to the targetAtom
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000265 // as the targetAtom points to the ingroup root
266 auto iter = _followOnRoots.find(ai);
267 if (iter == _followOnRoots.end()) {
268 _followOnRoots[ai] = rootAtom;
269 }
270 else if (iter->second == ai) {
271 if (iter->second != rootAtom) {
272 const DefinedAtom *a = iter->second;
273 // Change all the followon next references to the ingroup reference root
274 while (true) {
275 _followOnRoots[a] = rootAtom;
276 // Set all the follow on's for the targetAtom to be
277 // the current root
278 AtomToAtomT::iterator targetFollowOnAtomsIter =
279 _followOnNexts.find(a);
280 if (targetFollowOnAtomsIter != _followOnNexts.end())
281 a = targetFollowOnAtomsIter->second;
282 else
283 break;
284 } // while true
285 }
286 }
287 else {
288 // TODO : Flag an error that the root of the tree
289 // is different, Here is an example
290 // Say there are atoms
291 // chain 1 : a->b->c
292 // chain 2 : d->e->f
293 // and e,f have their ingroup reference as a
294 // this could happen only if the root of e,f that is d
295 // has root as 'a'
296 continue;
297 }
298
299 // Check if the current atom is part of the chain
300 bool isAtomInChain = false;
301 const DefinedAtom *lastAtom = rootAtom;
302 while (true) {
Shankar Easwaran8962feb2013-03-14 16:09:49 +0000303 AtomToAtomT::iterator followOnAtomsIter =
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000304 _followOnNexts.find(lastAtom);
305 if (followOnAtomsIter != _followOnNexts.end()) {
306 lastAtom = followOnAtomsIter->second;
307 if (lastAtom == ai) {
308 isAtomInChain = true;
309 break;
310 }
311 }
Shankar Easwaran8962feb2013-03-14 16:09:49 +0000312 else
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000313 break;
314 } // findAtomInChain
315
Shankar Easwaran8962feb2013-03-14 16:09:49 +0000316 if (!isAtomInChain)
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000317 _followOnNexts[lastAtom] = ai;
318 }
319 }
320 }
321}
322
323/// This pass builds the followon tables using Preceded By relationships
324/// The algorithm follows a very simple approach
325/// a) If the targetAtom is not part of any root and the current atom is not
Shankar Easwaran8962feb2013-03-14 16:09:49 +0000326/// part of any root, create a chain with the current atom as root and
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000327/// the targetAtom as following the current atom
Shankar Easwaran8962feb2013-03-14 16:09:49 +0000328/// b) Chain the targetAtom to the current Atom if the targetAtom is not part
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000329/// of any chain and the currentAtom has no followOn's
330/// c) If the targetAtom is part of a different tree and the root of the
331/// targetAtom is itself, and if the current atom is not part of any root
Shankar Easwaran8962feb2013-03-14 16:09:49 +0000332/// chain all the atoms together
333/// d) If the current atom has no followon and the root of the targetAtom is
334/// not equal to the root of the current atom(the targetAtom is not in the
335/// same chain), chain all the atoms that are lead by the targetAtom into
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000336/// the current chain
337void LayoutPass::buildPrecededByTable(MutableFile::DefinedAtomRange &range) {
Shankar Easwaran8962feb2013-03-14 16:09:49 +0000338 // This table would convert precededby references to follow on
339 // references so that we have only one table
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000340 for (auto ai : range) {
341 for (const Reference *r : *ai) {
342 if (r->kind() == lld::Reference::kindLayoutBefore) {
343 const DefinedAtom *targetAtom = llvm::dyn_cast<DefinedAtom>(r->target());
344 // Is the targetAtom not chained
345 if (_followOnRoots.count(targetAtom) == 0) {
346 // Is the current atom not part of any root ?
347 if (_followOnRoots.count(ai) == 0) {
348 _followOnRoots[ai] = ai;
349 _followOnNexts[ai] = targetAtom;
350 _followOnRoots[targetAtom] = _followOnRoots[ai];
351 } else if (_followOnNexts.count(ai) == 0) {
352 // Chain the targetAtom to the current Atom
353 // if the currentAtom has no followon references
354 _followOnNexts[ai] = targetAtom;
355 _followOnRoots[targetAtom] = _followOnRoots[ai];
356 }
357 } else if (_followOnRoots.find(targetAtom)->second == targetAtom) {
358 // Is the targetAtom in chain with the targetAtom as the root ?
359 bool changeRoots = false;
360 if (_followOnRoots.count(ai) == 0) {
361 _followOnRoots[ai] = ai;
362 _followOnNexts[ai] = targetAtom;
363 _followOnRoots[targetAtom] = _followOnRoots[ai];
364 changeRoots = true;
365 } else if (_followOnNexts.count(ai) == 0) {
366 // Chain the targetAtom to the current Atom
367 // if the currentAtom has no followon references
368 if (_followOnRoots[ai] != _followOnRoots[targetAtom]) {
369 _followOnNexts[ai] = targetAtom;
370 _followOnRoots[targetAtom] = _followOnRoots[ai];
371 changeRoots = true;
372 }
373 }
Shankar Easwaran8962feb2013-03-14 16:09:49 +0000374 // Change the roots of the targetAtom and its chain to
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000375 // the current atoms root
376 if (changeRoots) {
377 const DefinedAtom *a = _followOnRoots[targetAtom];
378 while (true) {
379 _followOnRoots[a] = _followOnRoots[ai];
380 // Set all the follow on's for the targetAtom to be
381 // the current root
382 AtomToAtomT::iterator targetFollowOnAtomsIter =
383 _followOnNexts.find(a);
384 if (targetFollowOnAtomsIter != _followOnNexts.end())
385 a = targetFollowOnAtomsIter->second;
386 else
387 break;
388 }
389 } // changeRoots
Shankar Easwaran8962feb2013-03-14 16:09:49 +0000390 } // Is targetAtom root
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000391 } // kindLayoutBefore
392 } // Reference
393 } // atom iteration
Shankar Easwaran8962feb2013-03-14 16:09:49 +0000394} // end function
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000395
396
397/// Build an ordinal override map by traversing the followon chain, and
Shankar Easwaran8962feb2013-03-14 16:09:49 +0000398/// assigning ordinals to each atom, if the atoms have their ordinals
399/// already assigned skip the atom and move to the next. This is the
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000400/// main map thats used to sort the atoms while comparing two atoms together
401void LayoutPass::buildOrdinalOverrideMap(MutableFile::DefinedAtomRange &range) {
402 uint64_t index = 0;
403 for (auto ai : range) {
404 const DefinedAtom *atom = ai;
Michael J. Spencer1ecf8902013-03-12 00:10:00 +0000405 if (_ordinalOverrideMap.find(atom) != _ordinalOverrideMap.end())
406 continue;
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000407 AtomToAtomT::iterator start = _followOnRoots.find(atom);
408 if (start != _followOnRoots.end()) {
409 for (const DefinedAtom *nextAtom = start->second; nextAtom != NULL;
410 nextAtom = _followOnNexts[nextAtom]) {
411 AtomToOrdinalT::iterator pos = _ordinalOverrideMap.find(nextAtom);
412 if (pos == _ordinalOverrideMap.end()) {
413 _ordinalOverrideMap[nextAtom] = index++;
414 }
415 }
416 } else {
417 _ordinalOverrideMap[atom] = index;
418 }
419 }
420}
421
Shankar Easwaran8962feb2013-03-14 16:09:49 +0000422/// Perform the actual pass
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000423void LayoutPass::perform(MutableFile &mergedFile) {
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000424 MutableFile::DefinedAtomRange atomRange = mergedFile.definedAtoms();
425
426 // Build follow on tables
427 buildFollowOnTable(atomRange);
428
429 // Build Ingroup reference table
430 buildInGroupTable(atomRange);
431
432 // Build preceded by tables
433 buildPrecededByTable(atomRange);
434
435 // Build override maps
436 buildOrdinalOverrideMap(atomRange);
437
438 // sort the atoms
439 std::sort(atomRange.begin(), atomRange.end(), _compareAtoms);
440}