blob: 0a8a2f66c0a0df8506863c65593f0a7b73a35d89 [file] [log] [blame]
Shankar Easwaran2bc24922013-10-29 05:12:14 +00001//===--Passes/LayoutPass.cpp - Layout atoms -------------------------------===//
Shankar Easwaran34ab70f2013-02-07 20:16:12 +00002//
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//===----------------------------------------------------------------------===//
Shankar Easwaran34ab70f2013-02-07 20:16:12 +00009
Michael J. Spencer7f09a3d2013-02-26 01:35:30 +000010#define DEBUG_TYPE "LayoutPass"
11
Rui Ueyamaa6b71ca2013-06-07 20:18:39 +000012#include <set>
13
Shankar Easwaran34ab70f2013-02-07 20:16:12 +000014#include "lld/Passes/LayoutPass.h"
Michael J. Spencerd4eb47c2013-04-06 00:56:40 +000015#include "lld/Core/Instrumentation.h"
Rui Ueyamaa6b71ca2013-06-07 20:18:39 +000016
17#include "llvm/ADT/Twine.h"
Michael J. Spencer7f09a3d2013-02-26 01:35:30 +000018#include "llvm/Support/Debug.h"
19
Shankar Easwaran34ab70f2013-02-07 20:16:12 +000020using namespace lld;
21
Rui Ueyama52062222013-10-18 03:18:54 +000022#ifndef NDEBUG
Rui Ueyama6a607b62013-10-18 02:56:31 +000023namespace {
24// Return "reason (leftval, rightval)"
25std::string formatReason(StringRef reason, int leftVal, int rightVal) {
26 Twine msg =
27 Twine(reason) + " (" + Twine(leftVal) + ", " + Twine(rightVal) + ")";
Rui Ueyamac74157c2013-11-01 20:40:33 +000028 return msg.str();
Rui Ueyama6a607b62013-10-18 02:56:31 +000029}
Rui Ueyama46bf8282013-10-19 03:18:18 +000030} // end anonymous namespace
31
32// Less-than relationship of two atoms must be transitive, which is, if a < b
33// and b < c, a < c must be true. This function checks the transitivity by
34// checking the sort results.
35void LayoutPass::checkTransitivity(DefinedAtomIter begin,
36 DefinedAtomIter end) const {
37 for (DefinedAtomIter i = begin; (i + 1) != end; ++i) {
38 for (DefinedAtomIter j = i + 1; j != end; ++j) {
39 assert(_compareAtoms(*i, *j));
40 assert(!_compareAtoms(*j, *i));
41 }
42 }
Rui Ueyama6a607b62013-10-18 02:56:31 +000043}
Rui Ueyama52062222013-10-18 03:18:54 +000044#endif // NDEBUG
Rui Ueyama6a607b62013-10-18 02:56:31 +000045
Shankar Easwaran34ab70f2013-02-07 20:16:12 +000046/// The function compares atoms by sorting atoms in the following order
Shankar Easwarand6d1b522013-09-12 15:59:34 +000047/// a) Sorts atoms by Section position preference
48/// b) Sorts atoms by their ordinal overrides
49/// (layout-after/layout-before/ingroup)
50/// c) Sorts atoms by their permissions
51/// d) Sorts atoms by their content
Shankar Easwaran34ab70f2013-02-07 20:16:12 +000052/// e) Sorts atoms on how they appear using File Ordinality
53/// f) Sorts atoms on how they appear within the File
Rui Ueyama6a607b62013-10-18 02:56:31 +000054bool LayoutPass::CompareAtoms::compare(const DefinedAtom *left,
55 const DefinedAtom *right,
56 std::string &reason) const {
57 if (left == right) {
58 reason = "same";
Shankar Easwaran34ab70f2013-02-07 20:16:12 +000059 return false;
Rui Ueyama6a607b62013-10-18 02:56:31 +000060 }
Shankar Easwaran34ab70f2013-02-07 20:16:12 +000061
Shankar Easwarand8da9892013-05-22 17:41:04 +000062 // Sort by section position preference.
63 DefinedAtom::SectionPosition leftPos = left->sectionPosition();
64 DefinedAtom::SectionPosition rightPos = right->sectionPosition();
65
Shankar Easwarand8da9892013-05-22 17:41:04 +000066 bool leftSpecialPos = (leftPos != DefinedAtom::sectionPositionAny);
67 bool rightSpecialPos = (rightPos != DefinedAtom::sectionPositionAny);
68 if (leftSpecialPos || rightSpecialPos) {
Rui Ueyama6a607b62013-10-18 02:56:31 +000069 if (leftPos != rightPos) {
70 DEBUG(reason = formatReason("sectionPos", (int)leftPos, (int)rightPos));
Shankar Easwarand8da9892013-05-22 17:41:04 +000071 return leftPos < rightPos;
Rui Ueyama6a607b62013-10-18 02:56:31 +000072 }
Shankar Easwarand8da9892013-05-22 17:41:04 +000073 }
74
Rui Ueyama46bf8282013-10-19 03:18:18 +000075 // Find the root of the chain if it is a part of a follow-on chain.
76 auto leftFind = _layout._followOnRoots.find(left);
77 auto rightFind = _layout._followOnRoots.find(right);
78 const DefinedAtom *leftRoot =
79 (leftFind == _layout._followOnRoots.end()) ? left : leftFind->second;
80 const DefinedAtom *rightRoot =
81 (rightFind == _layout._followOnRoots.end()) ? right : rightFind->second;
Shankar Easwaranf1b341c2013-09-12 15:43:09 +000082
83 // Sort atoms by their ordinal overrides only if they fall in the same
84 // chain.
Rui Ueyama46bf8282013-10-19 03:18:18 +000085 AtomToOrdinalT::const_iterator lPos = _layout._ordinalOverrideMap.find(left);
86 AtomToOrdinalT::const_iterator rPos = _layout._ordinalOverrideMap.find(right);
87 AtomToOrdinalT::const_iterator end = _layout._ordinalOverrideMap.end();
88 if (leftRoot == rightRoot && lPos != end && rPos != end) {
89 DEBUG(reason = formatReason("override", lPos->second, rPos->second));
90 return lPos->second < rPos->second;
Shankar Easwaran3c5d2c82013-05-10 16:44:02 +000091 }
92
Shankar Easwaran34ab70f2013-02-07 20:16:12 +000093 // Sort same permissions together.
Rui Ueyama46bf8282013-10-19 03:18:18 +000094 DefinedAtom::ContentPermissions leftPerms = leftRoot->permissions();
95 DefinedAtom::ContentPermissions rightPerms = rightRoot->permissions();
Shankar Easwaran8c256852013-03-13 04:05:38 +000096
Rui Ueyama6a607b62013-10-18 02:56:31 +000097 if (leftPerms != rightPerms) {
98 DEBUG(reason =
99 formatReason("contentPerms", (int)leftPerms, (int)rightPerms));
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000100 return leftPerms < rightPerms;
Rui Ueyama6a607b62013-10-18 02:56:31 +0000101 }
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000102
103 // Sort same content types together.
Rui Ueyama46bf8282013-10-19 03:18:18 +0000104 DefinedAtom::ContentType leftType = leftRoot->contentType();
105 DefinedAtom::ContentType rightType = rightRoot->contentType();
Shankar Easwaran8c256852013-03-13 04:05:38 +0000106
Rui Ueyama6a607b62013-10-18 02:56:31 +0000107 if (leftType != rightType) {
108 DEBUG(reason = formatReason("contentType", (int)leftType, (int)rightType));
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000109 return leftType < rightType;
Rui Ueyama6a607b62013-10-18 02:56:31 +0000110 }
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000111
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000112 // Sort by .o order.
Rui Ueyama46bf8282013-10-19 03:18:18 +0000113 const File *leftFile = &leftRoot->file();
114 const File *rightFile = &rightRoot->file();
Shankar Easwaran8c256852013-03-13 04:05:38 +0000115
Rui Ueyama6a607b62013-10-18 02:56:31 +0000116 if (leftFile != rightFile) {
117 DEBUG(reason = formatReason(".o order", (int)leftFile->ordinal(),
118 (int)rightFile->ordinal()));
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000119 return leftFile->ordinal() < rightFile->ordinal();
Rui Ueyama6a607b62013-10-18 02:56:31 +0000120 }
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000121
122 // Sort by atom order with .o file.
Rui Ueyama46bf8282013-10-19 03:18:18 +0000123 uint64_t leftOrdinal = leftRoot->ordinal();
124 uint64_t rightOrdinal = rightRoot->ordinal();
Shankar Easwaran8c256852013-03-13 04:05:38 +0000125
Rui Ueyama6a607b62013-10-18 02:56:31 +0000126 if (leftOrdinal != rightOrdinal) {
Rui Ueyama46bf8282013-10-19 03:18:18 +0000127 DEBUG(reason = formatReason("ordinal", (int)leftRoot->ordinal(),
128 (int)rightRoot->ordinal()));
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000129 return leftOrdinal < rightOrdinal;
Rui Ueyama6a607b62013-10-18 02:56:31 +0000130 }
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000131
Rui Ueyamacd480752013-11-27 01:33:42 +0000132 llvm::errs() << "Unordered: <" << left->name() << "> <"
133 << right->name() << ">\n";
Shankar Easwaranbcf36562013-10-11 01:50:04 +0000134 llvm_unreachable("Atoms with Same Ordinal!");
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000135}
136
Rui Ueyama6a607b62013-10-18 02:56:31 +0000137bool LayoutPass::CompareAtoms::operator()(const DefinedAtom *left,
138 const DefinedAtom *right) const {
139 std::string reason;
140 bool result = compare(left, right, reason);
141 DEBUG({
Rui Ueyama4050b202013-10-18 03:18:52 +0000142 StringRef comp = result ? "<" : ">=";
Rui Ueyama6a607b62013-10-18 02:56:31 +0000143 llvm::dbgs() << "Layout: '" << left->name() << "' " << comp << " '"
144 << right->name() << "' (" << reason << ")\n";
145 });
146 return result;
147}
148
Rui Ueyamaca8ca552013-05-14 00:41:52 +0000149// Returns the atom immediately followed by the given atom in the followon
150// chain.
151const DefinedAtom *LayoutPass::findAtomFollowedBy(
152 const DefinedAtom *targetAtom) {
153 // Start from the beginning of the chain and follow the chain until
154 // we find the targetChain.
155 const DefinedAtom *atom = _followOnRoots[targetAtom];
156 while (true) {
157 const DefinedAtom *prevAtom = atom;
158 AtomToAtomT::iterator targetFollowOnAtomsIter = _followOnNexts.find(atom);
159 // The target atom must be in the chain of its root.
160 assert(targetFollowOnAtomsIter != _followOnNexts.end());
161 atom = targetFollowOnAtomsIter->second;
162 if (atom == targetAtom)
163 return prevAtom;
164 }
165}
166
167// Check if all the atoms followed by the given target atom are of size zero.
168// When this method is called, an atom being added is not of size zero and
169// will be added to the head of the followon chain. All the atoms between the
170// atom and the targetAtom (specified by layout-after) need to be of size zero
171// in this case. Otherwise the desired layout is impossible.
172bool LayoutPass::checkAllPrevAtomsZeroSize(const DefinedAtom *targetAtom) {
173 const DefinedAtom *atom = _followOnRoots[targetAtom];
174 while (true) {
Rui Ueyamaca8ca552013-05-14 00:41:52 +0000175 if (atom == targetAtom)
176 return true;
Rui Ueyama0196d1062013-05-14 16:53:59 +0000177 if (atom->size() != 0)
Rui Ueyamaca8ca552013-05-14 00:41:52 +0000178 // TODO: print warning that an impossible layout is being desired by the
179 // user.
180 return false;
Rui Ueyama5ec6d1a2013-05-14 01:51:56 +0000181 AtomToAtomT::iterator targetFollowOnAtomsIter = _followOnNexts.find(atom);
182 // The target atom must be in the chain of its root.
183 assert(targetFollowOnAtomsIter != _followOnNexts.end());
184 atom = targetFollowOnAtomsIter->second;
Rui Ueyamaca8ca552013-05-14 00:41:52 +0000185 }
186}
187
188// Set the root of all atoms in targetAtom's chain to the given root.
189void LayoutPass::setChainRoot(const DefinedAtom *targetAtom,
190 const DefinedAtom *root) {
191 // Walk through the followon chain and override each node's root.
192 while (true) {
193 _followOnRoots[targetAtom] = root;
194 AtomToAtomT::iterator targetFollowOnAtomsIter =
195 _followOnNexts.find(targetAtom);
196 if (targetFollowOnAtomsIter == _followOnNexts.end())
197 return;
198 targetAtom = targetFollowOnAtomsIter->second;
199 }
200}
201
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000202/// This pass builds the followon tables described by two DenseMaps
203/// followOnRoots and followonNexts.
204/// The followOnRoots map contains a mapping of a DefinedAtom to its root
205/// The followOnNexts map contains a mapping of what DefinedAtom follows the
206/// current Atom
207/// The algorithm follows a very simple approach
208/// a) If the atom is first seen, then make that as the root atom
Shankar Easwaran8962feb2013-03-14 16:09:49 +0000209/// b) The targetAtom which this Atom contains, has the root thats set to the
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000210/// root of the current atom
211/// c) If the targetAtom is part of a different tree and the root of the
212/// targetAtom is itself, Chain all the atoms that are contained in the tree
213/// to the current Tree
214/// d) If the targetAtom is part of a different chain and the root of the
215/// targetAtom until the targetAtom has all atoms of size 0, then chain the
216/// targetAtoms and its tree to the current chain
217void LayoutPass::buildFollowOnTable(MutableFile::DefinedAtomRange &range) {
Michael J. Spencerd4eb47c2013-04-06 00:56:40 +0000218 ScopedTask task(getDefaultDomain(), "LayoutPass::buildFollowOnTable");
Rui Ueyamaca8ca552013-05-14 00:41:52 +0000219 // Set the initial size of the followon and the followonNext hash to the
220 // number of atoms that we have.
Shankar Easwaran45a5f932013-04-29 03:27:57 +0000221 _followOnRoots.resize(range.size());
222 _followOnNexts.resize(range.size());
Rui Ueyama0196d1062013-05-14 16:53:59 +0000223 for (const DefinedAtom *ai : range) {
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000224 for (const Reference *r : *ai) {
Rui Ueyamaca8ca552013-05-14 00:41:52 +0000225 if (r->kind() != lld::Reference::kindLayoutAfter)
226 continue;
Rui Ueyamac1800be2013-11-05 01:37:40 +0000227 const DefinedAtom *targetAtom = dyn_cast<DefinedAtom>(r->target());
Rui Ueyamaca8ca552013-05-14 00:41:52 +0000228 _followOnNexts[ai] = targetAtom;
229
Alp Toker22593762013-12-02 01:28:14 +0000230 // If we find a followon for the first time, let's make that atom as the
Rui Ueyamaca8ca552013-05-14 00:41:52 +0000231 // root atom.
232 if (_followOnRoots.count(ai) == 0)
233 _followOnRoots[ai] = ai;
234
235 auto iter = _followOnRoots.find(targetAtom);
236 if (iter == _followOnRoots.end()) {
Alp Toker22593762013-12-02 01:28:14 +0000237 // If the targetAtom is not a root of any chain, let's make the root of
Rui Ueyamaca8ca552013-05-14 00:41:52 +0000238 // the targetAtom to the root of the current chain.
239 _followOnRoots[targetAtom] = _followOnRoots[ai];
240 } else if (iter->second == targetAtom) {
241 // If the targetAtom is the root of a chain, the chain becomes part of
242 // the current chain. Rewrite the subchain's root to the current
243 // chain's root.
244 setChainRoot(targetAtom, _followOnRoots[ai]);
245 } else {
246 // The targetAtom is already a part of a chain. If the current atom is
247 // of size zero, we can insert it in the middle of the chain just
248 // before the target atom, while not breaking other atom's followon
249 // relationships. If it's not, we can only insert the current atom at
250 // the beginning of the chain. All the atoms followed by the target
251 // atom must be of size zero in that case to satisfy the followon
252 // relationships.
Rui Ueyama0196d1062013-05-14 16:53:59 +0000253 size_t currentAtomSize = ai->size();
Rui Ueyamaca8ca552013-05-14 00:41:52 +0000254 if (currentAtomSize == 0) {
255 const DefinedAtom *targetPrevAtom = findAtomFollowedBy(targetAtom);
256 _followOnNexts[targetPrevAtom] = ai;
257 _followOnRoots[ai] = _followOnRoots[targetPrevAtom];
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000258 } else {
Rui Ueyamaca8ca552013-05-14 00:41:52 +0000259 if (!checkAllPrevAtomsZeroSize(targetAtom))
260 break;
261 _followOnNexts[ai] = _followOnRoots[targetAtom];
262 setChainRoot(_followOnRoots[targetAtom], _followOnRoots[ai]);
263 }
264 }
265 }
266 }
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000267}
268
269/// This pass builds the followon tables using InGroup relationships
270/// The algorithm follows a very simple approach
271/// a) If the rootAtom is not part of any root, create a new root with the
272/// as the head
273/// b) If the current Atom root is not found, then make the current atoms root
274/// point to the rootAtom
275/// c) If the root of the current Atom is itself a root of some other tree
276/// make all the atoms in the chain point to the ingroup reference
277/// d) Check to see if the current atom is part of the chain from the rootAtom
278/// if not add the atom to the chain, so that the current atom is part of the
279/// the chain where the rootAtom is in
280void LayoutPass::buildInGroupTable(MutableFile::DefinedAtomRange &range) {
Michael J. Spencerd4eb47c2013-04-06 00:56:40 +0000281 ScopedTask task(getDefaultDomain(), "LayoutPass::buildInGroupTable");
Shankar Easwaran8962feb2013-03-14 16:09:49 +0000282 // This table would convert precededby references to follow on
283 // references so that we have only one table
Rui Ueyama0196d1062013-05-14 16:53:59 +0000284 for (const DefinedAtom *ai : range) {
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000285 for (const Reference *r : *ai) {
286 if (r->kind() == lld::Reference::kindInGroup) {
Rui Ueyamac1800be2013-11-05 01:37:40 +0000287 const DefinedAtom *rootAtom = dyn_cast<DefinedAtom>(r->target());
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000288 // If the root atom is not part of any root
Shankar Easwaran8962feb2013-03-14 16:09:49 +0000289 // create a new root
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000290 if (_followOnRoots.count(rootAtom) == 0) {
291 _followOnRoots[rootAtom] = rootAtom;
292 }
Shankar Easwaran8962feb2013-03-14 16:09:49 +0000293 // If the current Atom has not been seen yet and there is no root
294 // that has been set, set the root of the atom to the targetAtom
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000295 // as the targetAtom points to the ingroup root
296 auto iter = _followOnRoots.find(ai);
297 if (iter == _followOnRoots.end()) {
298 _followOnRoots[ai] = rootAtom;
Rui Ueyamaca8ca552013-05-14 00:41:52 +0000299 } else if (iter->second == ai) {
300 if (iter->second != rootAtom)
301 setChainRoot(iter->second, rootAtom);
302 } else {
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000303 // TODO : Flag an error that the root of the tree
304 // is different, Here is an example
305 // Say there are atoms
306 // chain 1 : a->b->c
307 // chain 2 : d->e->f
308 // and e,f have their ingroup reference as a
309 // this could happen only if the root of e,f that is d
310 // has root as 'a'
311 continue;
312 }
313
314 // Check if the current atom is part of the chain
315 bool isAtomInChain = false;
316 const DefinedAtom *lastAtom = rootAtom;
317 while (true) {
Shankar Easwaran8962feb2013-03-14 16:09:49 +0000318 AtomToAtomT::iterator followOnAtomsIter =
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000319 _followOnNexts.find(lastAtom);
320 if (followOnAtomsIter != _followOnNexts.end()) {
321 lastAtom = followOnAtomsIter->second;
322 if (lastAtom == ai) {
323 isAtomInChain = true;
324 break;
325 }
326 }
Shankar Easwaran8962feb2013-03-14 16:09:49 +0000327 else
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000328 break;
329 } // findAtomInChain
330
Shankar Easwaran8962feb2013-03-14 16:09:49 +0000331 if (!isAtomInChain)
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000332 _followOnNexts[lastAtom] = ai;
333 }
334 }
335 }
336}
337
338/// This pass builds the followon tables using Preceded By relationships
339/// The algorithm follows a very simple approach
340/// a) If the targetAtom is not part of any root and the current atom is not
Shankar Easwaran8962feb2013-03-14 16:09:49 +0000341/// part of any root, create a chain with the current atom as root and
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000342/// the targetAtom as following the current atom
Shankar Easwaran8962feb2013-03-14 16:09:49 +0000343/// b) Chain the targetAtom to the current Atom if the targetAtom is not part
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000344/// of any chain and the currentAtom has no followOn's
345/// c) If the targetAtom is part of a different tree and the root of the
346/// targetAtom is itself, and if the current atom is not part of any root
Shankar Easwaran8962feb2013-03-14 16:09:49 +0000347/// chain all the atoms together
348/// d) If the current atom has no followon and the root of the targetAtom is
349/// not equal to the root of the current atom(the targetAtom is not in the
350/// same chain), chain all the atoms that are lead by the targetAtom into
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000351/// the current chain
352void LayoutPass::buildPrecededByTable(MutableFile::DefinedAtomRange &range) {
Michael J. Spencerd4eb47c2013-04-06 00:56:40 +0000353 ScopedTask task(getDefaultDomain(), "LayoutPass::buildPrecededByTable");
Shankar Easwaran8962feb2013-03-14 16:09:49 +0000354 // This table would convert precededby references to follow on
355 // references so that we have only one table
Rui Ueyama0196d1062013-05-14 16:53:59 +0000356 for (const DefinedAtom *ai : range) {
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000357 for (const Reference *r : *ai) {
358 if (r->kind() == lld::Reference::kindLayoutBefore) {
Rui Ueyamac1800be2013-11-05 01:37:40 +0000359 const DefinedAtom *targetAtom = dyn_cast<DefinedAtom>(r->target());
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000360 // Is the targetAtom not chained
361 if (_followOnRoots.count(targetAtom) == 0) {
362 // Is the current atom not part of any root ?
363 if (_followOnRoots.count(ai) == 0) {
364 _followOnRoots[ai] = ai;
365 _followOnNexts[ai] = targetAtom;
366 _followOnRoots[targetAtom] = _followOnRoots[ai];
367 } else if (_followOnNexts.count(ai) == 0) {
368 // Chain the targetAtom to the current Atom
369 // if the currentAtom has no followon references
370 _followOnNexts[ai] = targetAtom;
371 _followOnRoots[targetAtom] = _followOnRoots[ai];
372 }
373 } else if (_followOnRoots.find(targetAtom)->second == targetAtom) {
374 // Is the targetAtom in chain with the targetAtom as the root ?
375 bool changeRoots = false;
376 if (_followOnRoots.count(ai) == 0) {
377 _followOnRoots[ai] = ai;
378 _followOnNexts[ai] = targetAtom;
379 _followOnRoots[targetAtom] = _followOnRoots[ai];
380 changeRoots = true;
381 } else if (_followOnNexts.count(ai) == 0) {
382 // Chain the targetAtom to the current Atom
383 // if the currentAtom has no followon references
384 if (_followOnRoots[ai] != _followOnRoots[targetAtom]) {
385 _followOnNexts[ai] = targetAtom;
386 _followOnRoots[targetAtom] = _followOnRoots[ai];
387 changeRoots = true;
388 }
389 }
Shankar Easwaran8962feb2013-03-14 16:09:49 +0000390 // Change the roots of the targetAtom and its chain to
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000391 // the current atoms root
392 if (changeRoots) {
Rui Ueyamaca8ca552013-05-14 00:41:52 +0000393 setChainRoot(_followOnRoots[targetAtom], _followOnRoots[ai]);
394 }
Shankar Easwaran8962feb2013-03-14 16:09:49 +0000395 } // Is targetAtom root
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000396 } // kindLayoutBefore
Rui Ueyamaca8ca552013-05-14 00:41:52 +0000397 } // Reference
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000398 } // atom iteration
Shankar Easwaran8962feb2013-03-14 16:09:49 +0000399} // end function
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000400
401
402/// Build an ordinal override map by traversing the followon chain, and
Shankar Easwaran8962feb2013-03-14 16:09:49 +0000403/// assigning ordinals to each atom, if the atoms have their ordinals
404/// already assigned skip the atom and move to the next. This is the
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000405/// main map thats used to sort the atoms while comparing two atoms together
406void LayoutPass::buildOrdinalOverrideMap(MutableFile::DefinedAtomRange &range) {
Michael J. Spencerd4eb47c2013-04-06 00:56:40 +0000407 ScopedTask task(getDefaultDomain(), "LayoutPass::buildOrdinalOverrideMap");
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000408 uint64_t index = 0;
Rui Ueyama0196d1062013-05-14 16:53:59 +0000409 for (const DefinedAtom *ai : range) {
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000410 const DefinedAtom *atom = ai;
Michael J. Spencer1ecf8902013-03-12 00:10:00 +0000411 if (_ordinalOverrideMap.find(atom) != _ordinalOverrideMap.end())
412 continue;
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000413 AtomToAtomT::iterator start = _followOnRoots.find(atom);
414 if (start != _followOnRoots.end()) {
415 for (const DefinedAtom *nextAtom = start->second; nextAtom != NULL;
416 nextAtom = _followOnNexts[nextAtom]) {
417 AtomToOrdinalT::iterator pos = _ordinalOverrideMap.find(nextAtom);
418 if (pos == _ordinalOverrideMap.end()) {
419 _ordinalOverrideMap[nextAtom] = index++;
420 }
421 }
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000422 }
423 }
424}
425
Rui Ueyamaa6b71ca2013-06-07 20:18:39 +0000426// Helper functions to check follow-on graph.
427#ifndef NDEBUG
428namespace {
429typedef llvm::DenseMap<const DefinedAtom *, const DefinedAtom *> AtomToAtomT;
430
431std::string atomToDebugString(const Atom *atom) {
Rui Ueyamac1800be2013-11-05 01:37:40 +0000432 const DefinedAtom *definedAtom = dyn_cast<DefinedAtom>(atom);
Rui Ueyamaa6b71ca2013-06-07 20:18:39 +0000433 std::string str;
434 llvm::raw_string_ostream s(str);
435 if (definedAtom->name().empty())
436 s << "<anonymous " << definedAtom << ">";
437 else
438 s << definedAtom->name();
439 s << " in ";
440 if (definedAtom->customSectionName().empty())
441 s << "<anonymous>";
442 else
443 s << definedAtom->customSectionName();
444 s.flush();
445 return str;
446}
447
448void showCycleDetectedError(AtomToAtomT &followOnNexts,
449 const DefinedAtom *atom) {
450 const DefinedAtom *start = atom;
451 llvm::dbgs() << "There's a cycle in a follow-on chain!\n";
452 do {
453 llvm::dbgs() << " " << atomToDebugString(atom) << "\n";
454 for (const Reference *ref : *atom) {
455 llvm::dbgs() << " " << ref->kindToString()
456 << ": " << atomToDebugString(ref->target()) << "\n";
457 }
458 atom = followOnNexts[atom];
459 } while (atom != start);
Rui Ueyama5b274f32013-07-29 21:50:33 +0000460 llvm::report_fatal_error("Cycle detected");
Rui Ueyamaa6b71ca2013-06-07 20:18:39 +0000461}
462
463/// Exit if there's a cycle in a followon chain reachable from the
464/// given root atom. Uses the tortoise and hare algorithm to detect a
465/// cycle.
466void checkNoCycleInFollowonChain(AtomToAtomT &followOnNexts,
467 const DefinedAtom *root) {
468 const DefinedAtom *tortoise = root;
469 const DefinedAtom *hare = followOnNexts[root];
470 while (true) {
471 if (!tortoise || !hare)
472 return;
473 if (tortoise == hare)
474 showCycleDetectedError(followOnNexts, tortoise);
475 tortoise = followOnNexts[tortoise];
476 hare = followOnNexts[followOnNexts[hare]];
477 }
478}
479
480void checkReachabilityFromRoot(AtomToAtomT &followOnRoots,
481 const DefinedAtom *atom) {
482 if (!atom) return;
483 auto i = followOnRoots.find(atom);
484 if (i == followOnRoots.end()) {
485 Twine msg(Twine("Atom <") + atomToDebugString(atom)
486 + "> has no follow-on root!");
487 llvm_unreachable(msg.str().c_str());
488 }
489 const DefinedAtom *ap = i->second;
490 while (true) {
491 const DefinedAtom *next = followOnRoots[ap];
492 if (!next) {
493 Twine msg(Twine("Atom <" + atomToDebugString(atom)
494 + "> is not reachable from its root!"));
495 llvm_unreachable(msg.str().c_str());
496 }
497 if (next == ap)
498 return;
499 ap = next;
500 }
501}
502
503void printDefinedAtoms(const MutableFile::DefinedAtomRange &atomRange) {
504 for (const DefinedAtom *atom : atomRange) {
505 llvm::dbgs() << " file=" << atom->file().path()
506 << ", name=" << atom->name()
507 << ", size=" << atom->size()
508 << ", type=" << atom->contentType()
509 << ", ordinal=" << atom->ordinal()
510 << "\n";
511 }
512}
513} // end anonymous namespace
514
515/// Verify that the followon chain is sane. Should not be called in
516/// release binary.
517void LayoutPass::checkFollowonChain(MutableFile::DefinedAtomRange &range) {
518 ScopedTask task(getDefaultDomain(), "LayoutPass::checkFollowonChain");
519
520 // Verify that there's no cycle in follow-on chain.
521 std::set<const DefinedAtom *> roots;
522 for (const auto &ai : _followOnRoots)
523 roots.insert(ai.second);
524 for (const DefinedAtom *root : roots)
525 checkNoCycleInFollowonChain(_followOnNexts, root);
526
527 // Verify that all the atoms in followOnNexts have references to
528 // their roots.
529 for (const auto &ai : _followOnNexts) {
530 checkReachabilityFromRoot(_followOnRoots, ai.first);
531 checkReachabilityFromRoot(_followOnRoots, ai.second);
532 }
533}
534#endif // #ifndef NDEBUG
535
Shankar Easwaran8962feb2013-03-14 16:09:49 +0000536/// Perform the actual pass
Shankar Easwaran2bc24922013-10-29 05:12:14 +0000537void LayoutPass::perform(std::unique_ptr<MutableFile> &mergedFile) {
Michael J. Spencerbd66d042013-05-28 18:55:39 +0000538 ScopedTask task(getDefaultDomain(), "LayoutPass");
Shankar Easwaran2bc24922013-10-29 05:12:14 +0000539 MutableFile::DefinedAtomRange atomRange = mergedFile->definedAtoms();
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000540
541 // Build follow on tables
542 buildFollowOnTable(atomRange);
543
544 // Build Ingroup reference table
545 buildInGroupTable(atomRange);
546
547 // Build preceded by tables
548 buildPrecededByTable(atomRange);
549
Rui Ueyamaa6b71ca2013-06-07 20:18:39 +0000550 // Check the structure of followon graph if running in debug mode.
551 DEBUG(checkFollowonChain(atomRange));
552
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000553 // Build override maps
554 buildOrdinalOverrideMap(atomRange);
555
Rui Ueyama9c4f89a2013-05-23 01:31:25 +0000556 DEBUG({
Nick Kledzikf4fa8c02013-04-04 20:32:18 +0000557 llvm::dbgs() << "unsorted atoms:\n";
Rui Ueyamaa6b71ca2013-06-07 20:18:39 +0000558 printDefinedAtoms(atomRange);
Nick Kledzikf4fa8c02013-04-04 20:32:18 +0000559 });
Shankar Easwaran45a5f932013-04-29 03:27:57 +0000560
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000561 // sort the atoms
Shankar Easwaranbcf36562013-10-11 01:50:04 +0000562 std::sort(atomRange.begin(), atomRange.end(), _compareAtoms);
Shankar Easwaran45a5f932013-04-29 03:27:57 +0000563
Rui Ueyama46bf8282013-10-19 03:18:18 +0000564 DEBUG(checkTransitivity(atomRange.begin(), atomRange.end()));
565
Rui Ueyama9c4f89a2013-05-23 01:31:25 +0000566 DEBUG({
Nick Kledzikf4fa8c02013-04-04 20:32:18 +0000567 llvm::dbgs() << "sorted atoms:\n";
Rui Ueyamaa6b71ca2013-06-07 20:18:39 +0000568 printDefinedAtoms(atomRange);
Nick Kledzikf4fa8c02013-04-04 20:32:18 +0000569 });
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000570}