blob: 8f15cd9cafe59f73d5c0ac6afad4059d4cbb5f96 [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
Rui Ueyamaa6b71ca2013-06-07 20:18:39 +000013#include <set>
14
Shankar Easwaran34ab70f2013-02-07 20:16:12 +000015#include "lld/Passes/LayoutPass.h"
Michael J. Spencerd4eb47c2013-04-06 00:56:40 +000016#include "lld/Core/Instrumentation.h"
Rui Ueyamaa6b71ca2013-06-07 20:18:39 +000017
18#include "llvm/ADT/Twine.h"
Michael J. Spencer7f09a3d2013-02-26 01:35:30 +000019#include "llvm/Support/Debug.h"
20
Shankar Easwaran34ab70f2013-02-07 20:16:12 +000021using namespace lld;
22
23/// The function compares atoms by sorting atoms in the following order
24/// a) Sorts atoms with the same permissions
25/// b) Sorts atoms with the same content Type
26/// c) Sorts atoms by Section position preference
27/// d) Sorts atoms by how they follow / precede each atom
28/// e) Sorts atoms on how they appear using File Ordinality
29/// f) Sorts atoms on how they appear within the File
30bool LayoutPass::CompareAtoms::operator()(const DefinedAtom *left,
Michael J. Spencer0d9d3112013-05-28 19:03:29 +000031 const DefinedAtom *right) const {
Michael J. Spencer7f09a3d2013-02-26 01:35:30 +000032 DEBUG(llvm::dbgs() << "Sorting " << left->name() << " " << right->name() << "\n");
Shankar Easwaran34ab70f2013-02-07 20:16:12 +000033 if (left == right)
34 return false;
35
Shankar Easwarand8da9892013-05-22 17:41:04 +000036 // Sort by section position preference.
37 DefinedAtom::SectionPosition leftPos = left->sectionPosition();
38 DefinedAtom::SectionPosition rightPos = right->sectionPosition();
39
40 DEBUG(llvm::dbgs() << "Sorting by sectionPos"
41 << "(" << leftPos << "," << rightPos << ")\n");
42
43 bool leftSpecialPos = (leftPos != DefinedAtom::sectionPositionAny);
44 bool rightSpecialPos = (rightPos != DefinedAtom::sectionPositionAny);
45 if (leftSpecialPos || rightSpecialPos) {
46 if (leftPos != rightPos)
47 return leftPos < rightPos;
48 }
49
Shankar Easwaran3c5d2c82013-05-10 16:44:02 +000050 DEBUG(llvm::dbgs() << "Sorting by override\n");
51
52 AtomToOrdinalT::const_iterator lPos = _layout._ordinalOverrideMap.find(left);
53 AtomToOrdinalT::const_iterator rPos = _layout._ordinalOverrideMap.find(right);
54 AtomToOrdinalT::const_iterator end = _layout._ordinalOverrideMap.end();
Shankar Easwaranf1b341c2013-09-12 15:43:09 +000055
56 // Sort atoms by their ordinal overrides only if they fall in the same
57 // chain.
58 const DefinedAtom *leftAtom = _layout._followOnRoots.find(left)->second;
59 const DefinedAtom *rightAtom = _layout._followOnRoots.find(right)->second;
60
61 if (leftAtom == rightAtom) {
62 if ((lPos != end) && (rPos != end)) {
63 return lPos->second < rPos->second;
Shankar Easwaran3c5d2c82013-05-10 16:44:02 +000064 }
65 }
66
Shankar Easwaran34ab70f2013-02-07 20:16:12 +000067 // Sort same permissions together.
68 DefinedAtom::ContentPermissions leftPerms = left->permissions();
69 DefinedAtom::ContentPermissions rightPerms = right->permissions();
Shankar Easwaran8c256852013-03-13 04:05:38 +000070
71 DEBUG(llvm::dbgs() << "Sorting by contentPerms"
72 << "(" << leftPerms << "," << rightPerms << ")\n");
73
Shankar Easwaran34ab70f2013-02-07 20:16:12 +000074 if (leftPerms != rightPerms)
75 return leftPerms < rightPerms;
76
77 // Sort same content types together.
78 DefinedAtom::ContentType leftType = left->contentType();
79 DefinedAtom::ContentType rightType = right->contentType();
Shankar Easwaran8c256852013-03-13 04:05:38 +000080
81 DEBUG(llvm::dbgs() << "Sorting by contentType"
82 << "(" << leftType << "," << rightType << ")\n");
83
Shankar Easwaran34ab70f2013-02-07 20:16:12 +000084 if (leftType != rightType)
85 return leftType < rightType;
86
Shankar Easwaran34ab70f2013-02-07 20:16:12 +000087 // Sort by .o order.
88 const File *leftFile = &left->file();
89 const File *rightFile = &right->file();
Shankar Easwaran8c256852013-03-13 04:05:38 +000090
91 DEBUG(llvm::dbgs()
92 << "Sorting by .o order("
93 << "(" << leftFile->ordinal() << "," << rightFile->ordinal() << ")"
94 << "[" << leftFile->path() << "," << rightFile->path() << "]\n");
95
Shankar Easwaran34ab70f2013-02-07 20:16:12 +000096 if (leftFile != rightFile)
97 return leftFile->ordinal() < rightFile->ordinal();
98
99 // Sort by atom order with .o file.
100 uint64_t leftOrdinal = left->ordinal();
101 uint64_t rightOrdinal = right->ordinal();
Shankar Easwaran8c256852013-03-13 04:05:38 +0000102
103 DEBUG(llvm::dbgs() << "Sorting by ordinal(" << left->ordinal() << ","
104 << right->ordinal() << ")\n");
105
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000106 if (leftOrdinal != rightOrdinal)
107 return leftOrdinal < rightOrdinal;
108
Michael J. Spencer7f09a3d2013-02-26 01:35:30 +0000109 DEBUG(llvm::dbgs() << "Unordered\n");
110
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000111 return false;
112}
113
Rui Ueyamaca8ca552013-05-14 00:41:52 +0000114// Returns the atom immediately followed by the given atom in the followon
115// chain.
116const DefinedAtom *LayoutPass::findAtomFollowedBy(
117 const DefinedAtom *targetAtom) {
118 // Start from the beginning of the chain and follow the chain until
119 // we find the targetChain.
120 const DefinedAtom *atom = _followOnRoots[targetAtom];
121 while (true) {
122 const DefinedAtom *prevAtom = atom;
123 AtomToAtomT::iterator targetFollowOnAtomsIter = _followOnNexts.find(atom);
124 // The target atom must be in the chain of its root.
125 assert(targetFollowOnAtomsIter != _followOnNexts.end());
126 atom = targetFollowOnAtomsIter->second;
127 if (atom == targetAtom)
128 return prevAtom;
129 }
130}
131
132// Check if all the atoms followed by the given target atom are of size zero.
133// When this method is called, an atom being added is not of size zero and
134// will be added to the head of the followon chain. All the atoms between the
135// atom and the targetAtom (specified by layout-after) need to be of size zero
136// in this case. Otherwise the desired layout is impossible.
137bool LayoutPass::checkAllPrevAtomsZeroSize(const DefinedAtom *targetAtom) {
138 const DefinedAtom *atom = _followOnRoots[targetAtom];
139 while (true) {
Rui Ueyamaca8ca552013-05-14 00:41:52 +0000140 if (atom == targetAtom)
141 return true;
Rui Ueyama0196d1062013-05-14 16:53:59 +0000142 if (atom->size() != 0)
Rui Ueyamaca8ca552013-05-14 00:41:52 +0000143 // TODO: print warning that an impossible layout is being desired by the
144 // user.
145 return false;
Rui Ueyama5ec6d1a2013-05-14 01:51:56 +0000146 AtomToAtomT::iterator targetFollowOnAtomsIter = _followOnNexts.find(atom);
147 // The target atom must be in the chain of its root.
148 assert(targetFollowOnAtomsIter != _followOnNexts.end());
149 atom = targetFollowOnAtomsIter->second;
Rui Ueyamaca8ca552013-05-14 00:41:52 +0000150 }
151}
152
153// Set the root of all atoms in targetAtom's chain to the given root.
154void LayoutPass::setChainRoot(const DefinedAtom *targetAtom,
155 const DefinedAtom *root) {
156 // Walk through the followon chain and override each node's root.
157 while (true) {
158 _followOnRoots[targetAtom] = root;
159 AtomToAtomT::iterator targetFollowOnAtomsIter =
160 _followOnNexts.find(targetAtom);
161 if (targetFollowOnAtomsIter == _followOnNexts.end())
162 return;
163 targetAtom = targetFollowOnAtomsIter->second;
164 }
165}
166
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000167/// This pass builds the followon tables described by two DenseMaps
168/// followOnRoots and followonNexts.
169/// The followOnRoots map contains a mapping of a DefinedAtom to its root
170/// The followOnNexts map contains a mapping of what DefinedAtom follows the
171/// current Atom
172/// The algorithm follows a very simple approach
173/// a) If the atom is first seen, then make that as the root atom
Shankar Easwaran8962feb2013-03-14 16:09:49 +0000174/// b) The targetAtom which this Atom contains, has the root thats set to the
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000175/// root of the current atom
176/// c) If the targetAtom is part of a different tree and the root of the
177/// targetAtom is itself, Chain all the atoms that are contained in the tree
178/// to the current Tree
179/// d) If the targetAtom is part of a different chain and the root of the
180/// targetAtom until the targetAtom has all atoms of size 0, then chain the
181/// targetAtoms and its tree to the current chain
182void LayoutPass::buildFollowOnTable(MutableFile::DefinedAtomRange &range) {
Michael J. Spencerd4eb47c2013-04-06 00:56:40 +0000183 ScopedTask task(getDefaultDomain(), "LayoutPass::buildFollowOnTable");
Rui Ueyamaca8ca552013-05-14 00:41:52 +0000184 // Set the initial size of the followon and the followonNext hash to the
185 // number of atoms that we have.
Shankar Easwaran45a5f932013-04-29 03:27:57 +0000186 _followOnRoots.resize(range.size());
187 _followOnNexts.resize(range.size());
Rui Ueyama0196d1062013-05-14 16:53:59 +0000188 for (const DefinedAtom *ai : range) {
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000189 for (const Reference *r : *ai) {
Rui Ueyamaca8ca552013-05-14 00:41:52 +0000190 if (r->kind() != lld::Reference::kindLayoutAfter)
191 continue;
192 const DefinedAtom *targetAtom = llvm::dyn_cast<DefinedAtom>(r->target());
193 _followOnNexts[ai] = targetAtom;
194
195 // If we find a followon for the first time, lets make that atom as the
196 // root atom.
197 if (_followOnRoots.count(ai) == 0)
198 _followOnRoots[ai] = ai;
199
200 auto iter = _followOnRoots.find(targetAtom);
201 if (iter == _followOnRoots.end()) {
202 // If the targetAtom is not a root of any chain, lets make the root of
203 // the targetAtom to the root of the current chain.
204 _followOnRoots[targetAtom] = _followOnRoots[ai];
205 } else if (iter->second == targetAtom) {
206 // If the targetAtom is the root of a chain, the chain becomes part of
207 // the current chain. Rewrite the subchain's root to the current
208 // chain's root.
209 setChainRoot(targetAtom, _followOnRoots[ai]);
210 } else {
211 // The targetAtom is already a part of a chain. If the current atom is
212 // of size zero, we can insert it in the middle of the chain just
213 // before the target atom, while not breaking other atom's followon
214 // relationships. If it's not, we can only insert the current atom at
215 // the beginning of the chain. All the atoms followed by the target
216 // atom must be of size zero in that case to satisfy the followon
217 // relationships.
Rui Ueyama0196d1062013-05-14 16:53:59 +0000218 size_t currentAtomSize = ai->size();
Rui Ueyamaca8ca552013-05-14 00:41:52 +0000219 if (currentAtomSize == 0) {
220 const DefinedAtom *targetPrevAtom = findAtomFollowedBy(targetAtom);
221 _followOnNexts[targetPrevAtom] = ai;
222 _followOnRoots[ai] = _followOnRoots[targetPrevAtom];
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000223 } else {
Rui Ueyamaca8ca552013-05-14 00:41:52 +0000224 if (!checkAllPrevAtomsZeroSize(targetAtom))
225 break;
226 _followOnNexts[ai] = _followOnRoots[targetAtom];
227 setChainRoot(_followOnRoots[targetAtom], _followOnRoots[ai]);
228 }
229 }
230 }
231 }
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000232}
233
234/// This pass builds the followon tables using InGroup relationships
235/// The algorithm follows a very simple approach
236/// a) If the rootAtom is not part of any root, create a new root with the
237/// as the head
238/// b) If the current Atom root is not found, then make the current atoms root
239/// point to the rootAtom
240/// c) If the root of the current Atom is itself a root of some other tree
241/// make all the atoms in the chain point to the ingroup reference
242/// d) Check to see if the current atom is part of the chain from the rootAtom
243/// if not add the atom to the chain, so that the current atom is part of the
244/// the chain where the rootAtom is in
245void LayoutPass::buildInGroupTable(MutableFile::DefinedAtomRange &range) {
Michael J. Spencerd4eb47c2013-04-06 00:56:40 +0000246 ScopedTask task(getDefaultDomain(), "LayoutPass::buildInGroupTable");
Shankar Easwaran8962feb2013-03-14 16:09:49 +0000247 // This table would convert precededby references to follow on
248 // references so that we have only one table
Rui Ueyama0196d1062013-05-14 16:53:59 +0000249 for (const DefinedAtom *ai : range) {
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000250 for (const Reference *r : *ai) {
251 if (r->kind() == lld::Reference::kindInGroup) {
252 const DefinedAtom *rootAtom = llvm::dyn_cast<DefinedAtom>(r->target());
253 // If the root atom is not part of any root
Shankar Easwaran8962feb2013-03-14 16:09:49 +0000254 // create a new root
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000255 if (_followOnRoots.count(rootAtom) == 0) {
256 _followOnRoots[rootAtom] = rootAtom;
257 }
Shankar Easwaran8962feb2013-03-14 16:09:49 +0000258 // If the current Atom has not been seen yet and there is no root
259 // that has been set, set the root of the atom to the targetAtom
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000260 // as the targetAtom points to the ingroup root
261 auto iter = _followOnRoots.find(ai);
262 if (iter == _followOnRoots.end()) {
263 _followOnRoots[ai] = rootAtom;
Rui Ueyamaca8ca552013-05-14 00:41:52 +0000264 } else if (iter->second == ai) {
265 if (iter->second != rootAtom)
266 setChainRoot(iter->second, rootAtom);
267 } else {
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000268 // TODO : Flag an error that the root of the tree
269 // is different, Here is an example
270 // Say there are atoms
271 // chain 1 : a->b->c
272 // chain 2 : d->e->f
273 // and e,f have their ingroup reference as a
274 // this could happen only if the root of e,f that is d
275 // has root as 'a'
276 continue;
277 }
278
279 // Check if the current atom is part of the chain
280 bool isAtomInChain = false;
281 const DefinedAtom *lastAtom = rootAtom;
282 while (true) {
Shankar Easwaran8962feb2013-03-14 16:09:49 +0000283 AtomToAtomT::iterator followOnAtomsIter =
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000284 _followOnNexts.find(lastAtom);
285 if (followOnAtomsIter != _followOnNexts.end()) {
286 lastAtom = followOnAtomsIter->second;
287 if (lastAtom == ai) {
288 isAtomInChain = true;
289 break;
290 }
291 }
Shankar Easwaran8962feb2013-03-14 16:09:49 +0000292 else
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000293 break;
294 } // findAtomInChain
295
Shankar Easwaran8962feb2013-03-14 16:09:49 +0000296 if (!isAtomInChain)
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000297 _followOnNexts[lastAtom] = ai;
298 }
299 }
300 }
301}
302
303/// This pass builds the followon tables using Preceded By relationships
304/// The algorithm follows a very simple approach
305/// a) If the targetAtom is not part of any root and the current atom is not
Shankar Easwaran8962feb2013-03-14 16:09:49 +0000306/// part of any root, create a chain with the current atom as root and
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000307/// the targetAtom as following the current atom
Shankar Easwaran8962feb2013-03-14 16:09:49 +0000308/// b) Chain the targetAtom to the current Atom if the targetAtom is not part
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000309/// of any chain and the currentAtom has no followOn's
310/// c) If the targetAtom is part of a different tree and the root of the
311/// targetAtom is itself, and if the current atom is not part of any root
Shankar Easwaran8962feb2013-03-14 16:09:49 +0000312/// chain all the atoms together
313/// d) If the current atom has no followon and the root of the targetAtom is
314/// not equal to the root of the current atom(the targetAtom is not in the
315/// same chain), chain all the atoms that are lead by the targetAtom into
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000316/// the current chain
317void LayoutPass::buildPrecededByTable(MutableFile::DefinedAtomRange &range) {
Michael J. Spencerd4eb47c2013-04-06 00:56:40 +0000318 ScopedTask task(getDefaultDomain(), "LayoutPass::buildPrecededByTable");
Shankar Easwaran8962feb2013-03-14 16:09:49 +0000319 // This table would convert precededby references to follow on
320 // references so that we have only one table
Rui Ueyama0196d1062013-05-14 16:53:59 +0000321 for (const DefinedAtom *ai : range) {
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000322 for (const Reference *r : *ai) {
323 if (r->kind() == lld::Reference::kindLayoutBefore) {
324 const DefinedAtom *targetAtom = llvm::dyn_cast<DefinedAtom>(r->target());
325 // Is the targetAtom not chained
326 if (_followOnRoots.count(targetAtom) == 0) {
327 // Is the current atom not part of any root ?
328 if (_followOnRoots.count(ai) == 0) {
329 _followOnRoots[ai] = ai;
330 _followOnNexts[ai] = targetAtom;
331 _followOnRoots[targetAtom] = _followOnRoots[ai];
332 } else if (_followOnNexts.count(ai) == 0) {
333 // Chain the targetAtom to the current Atom
334 // if the currentAtom has no followon references
335 _followOnNexts[ai] = targetAtom;
336 _followOnRoots[targetAtom] = _followOnRoots[ai];
337 }
338 } else if (_followOnRoots.find(targetAtom)->second == targetAtom) {
339 // Is the targetAtom in chain with the targetAtom as the root ?
340 bool changeRoots = false;
341 if (_followOnRoots.count(ai) == 0) {
342 _followOnRoots[ai] = ai;
343 _followOnNexts[ai] = targetAtom;
344 _followOnRoots[targetAtom] = _followOnRoots[ai];
345 changeRoots = true;
346 } else if (_followOnNexts.count(ai) == 0) {
347 // Chain the targetAtom to the current Atom
348 // if the currentAtom has no followon references
349 if (_followOnRoots[ai] != _followOnRoots[targetAtom]) {
350 _followOnNexts[ai] = targetAtom;
351 _followOnRoots[targetAtom] = _followOnRoots[ai];
352 changeRoots = true;
353 }
354 }
Shankar Easwaran8962feb2013-03-14 16:09:49 +0000355 // Change the roots of the targetAtom and its chain to
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000356 // the current atoms root
357 if (changeRoots) {
Rui Ueyamaca8ca552013-05-14 00:41:52 +0000358 setChainRoot(_followOnRoots[targetAtom], _followOnRoots[ai]);
359 }
Shankar Easwaran8962feb2013-03-14 16:09:49 +0000360 } // Is targetAtom root
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000361 } // kindLayoutBefore
Rui Ueyamaca8ca552013-05-14 00:41:52 +0000362 } // Reference
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000363 } // atom iteration
Shankar Easwaran8962feb2013-03-14 16:09:49 +0000364} // end function
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000365
366
367/// Build an ordinal override map by traversing the followon chain, and
Shankar Easwaran8962feb2013-03-14 16:09:49 +0000368/// assigning ordinals to each atom, if the atoms have their ordinals
369/// already assigned skip the atom and move to the next. This is the
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000370/// main map thats used to sort the atoms while comparing two atoms together
371void LayoutPass::buildOrdinalOverrideMap(MutableFile::DefinedAtomRange &range) {
Michael J. Spencerd4eb47c2013-04-06 00:56:40 +0000372 ScopedTask task(getDefaultDomain(), "LayoutPass::buildOrdinalOverrideMap");
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000373 uint64_t index = 0;
Rui Ueyama0196d1062013-05-14 16:53:59 +0000374 for (const DefinedAtom *ai : range) {
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000375 const DefinedAtom *atom = ai;
Michael J. Spencer1ecf8902013-03-12 00:10:00 +0000376 if (_ordinalOverrideMap.find(atom) != _ordinalOverrideMap.end())
377 continue;
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000378 AtomToAtomT::iterator start = _followOnRoots.find(atom);
379 if (start != _followOnRoots.end()) {
380 for (const DefinedAtom *nextAtom = start->second; nextAtom != NULL;
381 nextAtom = _followOnNexts[nextAtom]) {
382 AtomToOrdinalT::iterator pos = _ordinalOverrideMap.find(nextAtom);
383 if (pos == _ordinalOverrideMap.end()) {
384 _ordinalOverrideMap[nextAtom] = index++;
385 }
386 }
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000387 }
388 }
389}
390
Rui Ueyamaa6b71ca2013-06-07 20:18:39 +0000391// Helper functions to check follow-on graph.
392#ifndef NDEBUG
393namespace {
394typedef llvm::DenseMap<const DefinedAtom *, const DefinedAtom *> AtomToAtomT;
395
396std::string atomToDebugString(const Atom *atom) {
397 const DefinedAtom *definedAtom = llvm::dyn_cast<DefinedAtom>(atom);
398 std::string str;
399 llvm::raw_string_ostream s(str);
400 if (definedAtom->name().empty())
401 s << "<anonymous " << definedAtom << ">";
402 else
403 s << definedAtom->name();
404 s << " in ";
405 if (definedAtom->customSectionName().empty())
406 s << "<anonymous>";
407 else
408 s << definedAtom->customSectionName();
409 s.flush();
410 return str;
411}
412
413void showCycleDetectedError(AtomToAtomT &followOnNexts,
414 const DefinedAtom *atom) {
415 const DefinedAtom *start = atom;
416 llvm::dbgs() << "There's a cycle in a follow-on chain!\n";
417 do {
418 llvm::dbgs() << " " << atomToDebugString(atom) << "\n";
419 for (const Reference *ref : *atom) {
420 llvm::dbgs() << " " << ref->kindToString()
421 << ": " << atomToDebugString(ref->target()) << "\n";
422 }
423 atom = followOnNexts[atom];
424 } while (atom != start);
Rui Ueyama5b274f32013-07-29 21:50:33 +0000425 llvm::report_fatal_error("Cycle detected");
Rui Ueyamaa6b71ca2013-06-07 20:18:39 +0000426}
427
428/// Exit if there's a cycle in a followon chain reachable from the
429/// given root atom. Uses the tortoise and hare algorithm to detect a
430/// cycle.
431void checkNoCycleInFollowonChain(AtomToAtomT &followOnNexts,
432 const DefinedAtom *root) {
433 const DefinedAtom *tortoise = root;
434 const DefinedAtom *hare = followOnNexts[root];
435 while (true) {
436 if (!tortoise || !hare)
437 return;
438 if (tortoise == hare)
439 showCycleDetectedError(followOnNexts, tortoise);
440 tortoise = followOnNexts[tortoise];
441 hare = followOnNexts[followOnNexts[hare]];
442 }
443}
444
445void checkReachabilityFromRoot(AtomToAtomT &followOnRoots,
446 const DefinedAtom *atom) {
447 if (!atom) return;
448 auto i = followOnRoots.find(atom);
449 if (i == followOnRoots.end()) {
450 Twine msg(Twine("Atom <") + atomToDebugString(atom)
451 + "> has no follow-on root!");
452 llvm_unreachable(msg.str().c_str());
453 }
454 const DefinedAtom *ap = i->second;
455 while (true) {
456 const DefinedAtom *next = followOnRoots[ap];
457 if (!next) {
458 Twine msg(Twine("Atom <" + atomToDebugString(atom)
459 + "> is not reachable from its root!"));
460 llvm_unreachable(msg.str().c_str());
461 }
462 if (next == ap)
463 return;
464 ap = next;
465 }
466}
467
468void printDefinedAtoms(const MutableFile::DefinedAtomRange &atomRange) {
469 for (const DefinedAtom *atom : atomRange) {
470 llvm::dbgs() << " file=" << atom->file().path()
471 << ", name=" << atom->name()
472 << ", size=" << atom->size()
473 << ", type=" << atom->contentType()
474 << ", ordinal=" << atom->ordinal()
475 << "\n";
476 }
477}
478} // end anonymous namespace
479
480/// Verify that the followon chain is sane. Should not be called in
481/// release binary.
482void LayoutPass::checkFollowonChain(MutableFile::DefinedAtomRange &range) {
483 ScopedTask task(getDefaultDomain(), "LayoutPass::checkFollowonChain");
484
485 // Verify that there's no cycle in follow-on chain.
486 std::set<const DefinedAtom *> roots;
487 for (const auto &ai : _followOnRoots)
488 roots.insert(ai.second);
489 for (const DefinedAtom *root : roots)
490 checkNoCycleInFollowonChain(_followOnNexts, root);
491
492 // Verify that all the atoms in followOnNexts have references to
493 // their roots.
494 for (const auto &ai : _followOnNexts) {
495 checkReachabilityFromRoot(_followOnRoots, ai.first);
496 checkReachabilityFromRoot(_followOnRoots, ai.second);
497 }
498}
499#endif // #ifndef NDEBUG
500
Shankar Easwaran8962feb2013-03-14 16:09:49 +0000501/// Perform the actual pass
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000502void LayoutPass::perform(MutableFile &mergedFile) {
Michael J. Spencerbd66d042013-05-28 18:55:39 +0000503 ScopedTask task(getDefaultDomain(), "LayoutPass");
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000504 MutableFile::DefinedAtomRange atomRange = mergedFile.definedAtoms();
505
506 // Build follow on tables
507 buildFollowOnTable(atomRange);
508
509 // Build Ingroup reference table
510 buildInGroupTable(atomRange);
511
512 // Build preceded by tables
513 buildPrecededByTable(atomRange);
514
Rui Ueyamaa6b71ca2013-06-07 20:18:39 +0000515 // Check the structure of followon graph if running in debug mode.
516 DEBUG(checkFollowonChain(atomRange));
517
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000518 // Build override maps
519 buildOrdinalOverrideMap(atomRange);
520
Rui Ueyama9c4f89a2013-05-23 01:31:25 +0000521 DEBUG({
Nick Kledzikf4fa8c02013-04-04 20:32:18 +0000522 llvm::dbgs() << "unsorted atoms:\n";
Rui Ueyamaa6b71ca2013-06-07 20:18:39 +0000523 printDefinedAtoms(atomRange);
Nick Kledzikf4fa8c02013-04-04 20:32:18 +0000524 });
Shankar Easwaran45a5f932013-04-29 03:27:57 +0000525
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000526 // sort the atoms
Michael J. Spencer615c0762013-05-31 00:05:49 +0000527 std::sort(atomRange.begin(), atomRange.end(), _compareAtoms);
Shankar Easwaran45a5f932013-04-29 03:27:57 +0000528
Rui Ueyama9c4f89a2013-05-23 01:31:25 +0000529 DEBUG({
Nick Kledzikf4fa8c02013-04-04 20:32:18 +0000530 llvm::dbgs() << "sorted atoms:\n";
Rui Ueyamaa6b71ca2013-06-07 20:18:39 +0000531 printDefinedAtoms(atomRange);
Nick Kledzikf4fa8c02013-04-04 20:32:18 +0000532 });
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000533}