本文整理汇总了C++中SmallDenseMap类的典型用法代码示例。如果您正苦于以下问题:C++ SmallDenseMap类的具体用法?C++ SmallDenseMap怎么用?C++ SmallDenseMap使用的例子?那么, 这里精选的类代码示例或许可以为您提供帮助。
在下文中一共展示了SmallDenseMap类的9个代码示例,这些例子默认根据受欢迎程度排序。您可以为喜欢或者感觉有用的代码点赞,您的评价将有助于系统推荐出更棒的C++代码示例。
示例1: shuffleValueUseLists
static void shuffleValueUseLists(Value *V, std::minstd_rand0 &Gen,
DenseSet<Value *> &Seen) {
if (!Seen.insert(V).second)
return;
if (auto *C = dyn_cast<Constant>(V))
if (!isa<GlobalValue>(C))
for (Value *Op : C->operands())
shuffleValueUseLists(Op, Gen, Seen);
if (V->use_empty() || std::next(V->use_begin()) == V->use_end())
// Nothing to shuffle for 0 or 1 users.
return;
// Generate random numbers between 10 and 99, which will line up nicely in
// debug output. We're not worried about collisons here.
DEBUG(dbgs() << "V = "; V->dump());
std::uniform_int_distribution<short> Dist(10, 99);
SmallDenseMap<const Use *, short, 16> Order;
for (const Use &U : V->uses()) {
auto I = Dist(Gen);
Order[&U] = I;
DEBUG(dbgs() << " - order: " << I << ", U = "; U.getUser()->dump());
}
DEBUG(dbgs() << " => shuffle\n");
V->sortUseList(
[&Order](const Use &L, const Use &R) { return Order[&L] < Order[&R]; });
DEBUG({
for (const Use &U : V->uses())
DEBUG(dbgs() << " - order: " << Order.lookup(&U) << ", U = ";
U.getUser()->dump());
});
示例2: sortLocalVars
/// Sort local variables so that variables appearing inside of helper
/// expressions come first.
static SmallVector<DbgVariable *, 8>
sortLocalVars(SmallVectorImpl<DbgVariable *> &Input) {
SmallVector<DbgVariable *, 8> Result;
SmallVector<PointerIntPair<DbgVariable *, 1>, 8> WorkList;
// Map back from a DIVariable to its containing DbgVariable.
SmallDenseMap<const DILocalVariable *, DbgVariable *> DbgVar;
// Set of DbgVariables in Result.
SmallDenseSet<DbgVariable *, 8> Visited;
// For cycle detection.
SmallDenseSet<DbgVariable *, 8> Visiting;
// Initialize the worklist and the DIVariable lookup table.
for (auto Var : reverse(Input)) {
DbgVar.insert({Var->getVariable(), Var});
WorkList.push_back({Var, 0});
}
// Perform a stable topological sort by doing a DFS.
while (!WorkList.empty()) {
auto Item = WorkList.back();
DbgVariable *Var = Item.getPointer();
bool visitedAllDependencies = Item.getInt();
WorkList.pop_back();
// Dependency is in a different lexical scope or a global.
if (!Var)
continue;
// Already handled.
if (Visited.count(Var))
continue;
// Add to Result if all dependencies are visited.
if (visitedAllDependencies) {
Visited.insert(Var);
Result.push_back(Var);
continue;
}
// Detect cycles.
auto Res = Visiting.insert(Var);
if (!Res.second) {
assert(false && "dependency cycle in local variables");
return Result;
}
// Push dependencies and this node onto the worklist, so that this node is
// visited again after all of its dependencies are handled.
WorkList.push_back({Var, 1});
for (auto *Dependency : dependencies(Var)) {
auto Dep = dyn_cast_or_null<const DILocalVariable>(Dependency);
WorkList.push_back({DbgVar[Dep], 0});
}
}
return Result;
}
示例3: calculateIterationsToInvariance
// This function calculates the number of iterations after which the given Phi
// becomes an invariant. The pre-calculated values are memorized in the map. The
// function (shortcut is I) is calculated according to the following definition:
// Given %x = phi <Inputs from above the loop>, ..., [%y, %back.edge].
// If %y is a loop invariant, then I(%x) = 1.
// If %y is a Phi from the loop header, I(%x) = I(%y) + 1.
// Otherwise, I(%x) is infinite.
// TODO: Actually if %y is an expression that depends only on Phi %z and some
// loop invariants, we can estimate I(%x) = I(%z) + 1. The example
// looks like:
// %x = phi(0, %a), <-- becomes invariant starting from 3rd iteration.
// %y = phi(0, 5),
// %a = %y + 1.
static unsigned calculateIterationsToInvariance(
PHINode *Phi, Loop *L, BasicBlock *BackEdge,
SmallDenseMap<PHINode *, unsigned> &IterationsToInvariance) {
assert(Phi->getParent() == L->getHeader() &&
"Non-loop Phi should not be checked for turning into invariant.");
assert(BackEdge == L->getLoopLatch() && "Wrong latch?");
// If we already know the answer, take it from the map.
auto I = IterationsToInvariance.find(Phi);
if (I != IterationsToInvariance.end())
return I->second;
// Otherwise we need to analyze the input from the back edge.
Value *Input = Phi->getIncomingValueForBlock(BackEdge);
// Place infinity to map to avoid infinite recursion for cycled Phis. Such
// cycles can never stop on an invariant.
IterationsToInvariance[Phi] = InfiniteIterationsToInvariance;
unsigned ToInvariance = InfiniteIterationsToInvariance;
if (L->isLoopInvariant(Input))
ToInvariance = 1u;
else if (PHINode *IncPhi = dyn_cast<PHINode>(Input)) {
// Only consider Phis in header block.
if (IncPhi->getParent() != L->getHeader())
return InfiniteIterationsToInvariance;
// If the input becomes an invariant after X iterations, then our Phi
// becomes an invariant after X + 1 iterations.
unsigned InputToInvariance = calculateIterationsToInvariance(
IncPhi, L, BackEdge, IterationsToInvariance);
if (InputToInvariance != InfiniteIterationsToInvariance)
ToInvariance = InputToInvariance + 1u;
}
// If we found that this Phi lies in an invariant chain, update the map.
if (ToInvariance != InfiniteIterationsToInvariance)
IterationsToInvariance[Phi] = ToInvariance;
return ToInvariance;
}
示例4: IsEquivalentPHI
static bool IsEquivalentPHI(PHINode *PHI,
SmallDenseMap<BasicBlock*, Value*, 8> &ValueMapping) {
unsigned PHINumValues = PHI->getNumIncomingValues();
if (PHINumValues != ValueMapping.size())
return false;
// Scan the phi to see if it matches.
for (unsigned i = 0, e = PHINumValues; i != e; ++i)
if (ValueMapping[PHI->getIncomingBlock(i)] !=
PHI->getIncomingValue(i)) {
return false;
}
return true;
}
示例5: removeDeadFunctions
/// Remove dead functions that are not included in DNR (Do Not Remove) list.
bool Inliner::removeDeadFunctions(CallGraph &CG, bool AlwaysInlineOnly) {
SmallVector<CallGraphNode*, 16> FunctionsToRemove;
SmallVector<CallGraphNode *, 16> DeadFunctionsInComdats;
SmallDenseMap<const Comdat *, int, 16> ComdatEntriesAlive;
auto RemoveCGN = [&](CallGraphNode *CGN) {
// Remove any call graph edges from the function to its callees.
CGN->removeAllCalledFunctions();
// Remove any edges from the external node to the function's call graph
// node. These edges might have been made irrelegant due to
// optimization of the program.
CG.getExternalCallingNode()->removeAnyCallEdgeTo(CGN);
// Removing the node for callee from the call graph and delete it.
FunctionsToRemove.push_back(CGN);
};
// Scan for all of the functions, looking for ones that should now be removed
// from the program. Insert the dead ones in the FunctionsToRemove set.
for (CallGraph::iterator I = CG.begin(), E = CG.end(); I != E; ++I) {
CallGraphNode *CGN = I->second;
Function *F = CGN->getFunction();
if (!F || F->isDeclaration())
continue;
// Handle the case when this function is called and we only want to care
// about always-inline functions. This is a bit of a hack to share code
// between here and the InlineAlways pass.
if (AlwaysInlineOnly && !F->hasFnAttribute(Attribute::AlwaysInline))
continue;
// If the only remaining users of the function are dead constants, remove
// them.
F->removeDeadConstantUsers();
if (!F->isDefTriviallyDead())
continue;
// It is unsafe to drop a function with discardable linkage from a COMDAT
// without also dropping the other members of the COMDAT.
// The inliner doesn't visit non-function entities which are in COMDAT
// groups so it is unsafe to do so *unless* the linkage is local.
if (!F->hasLocalLinkage()) {
if (const Comdat *C = F->getComdat()) {
--ComdatEntriesAlive[C];
DeadFunctionsInComdats.push_back(CGN);
continue;
}
}
RemoveCGN(CGN);
}
if (!DeadFunctionsInComdats.empty()) {
// Count up all the entities in COMDAT groups
auto ComdatGroupReferenced = [&](const Comdat *C) {
auto I = ComdatEntriesAlive.find(C);
if (I != ComdatEntriesAlive.end())
++(I->getSecond());
};
for (const Function &F : CG.getModule())
if (const Comdat *C = F.getComdat())
ComdatGroupReferenced(C);
for (const GlobalVariable &GV : CG.getModule().globals())
if (const Comdat *C = GV.getComdat())
ComdatGroupReferenced(C);
for (const GlobalAlias &GA : CG.getModule().aliases())
if (const Comdat *C = GA.getComdat())
ComdatGroupReferenced(C);
for (CallGraphNode *CGN : DeadFunctionsInComdats) {
Function *F = CGN->getFunction();
const Comdat *C = F->getComdat();
int NumAlive = ComdatEntriesAlive[C];
// We can remove functions in a COMDAT group if the entire group is dead.
assert(NumAlive >= 0);
if (NumAlive > 0)
continue;
RemoveCGN(CGN);
}
}
if (FunctionsToRemove.empty())
return false;
// Now that we know which functions to delete, do so. We didn't want to do
// this inline, because that would invalidate our CallGraph::iterator
// objects. :(
//
// Note that it doesn't matter that we are iterating over a non-stable order
// here to do this, it doesn't matter which order the functions are deleted
// in.
array_pod_sort(FunctionsToRemove.begin(), FunctionsToRemove.end());
FunctionsToRemove.erase(std::unique(FunctionsToRemove.begin(),
FunctionsToRemove.end()),
FunctionsToRemove.end());
for (SmallVectorImpl<CallGraphNode *>::iterator I = FunctionsToRemove.begin(),
E = FunctionsToRemove.end();
I != E; ++I) {
//.........这里部分代码省略.........
示例6: DEBUG
//.........这里部分代码省略.........
EmitDiag(" with run-time trip count");
}
DEBUG(dbgs() << "!\n");
}
bool ContinueOnTrue = L->contains(BI->getSuccessor(0));
BasicBlock *LoopExit = BI->getSuccessor(ContinueOnTrue);
// For the first iteration of the loop, we should use the precloned values for
// PHI nodes. Insert associations now.
ValueToValueMapTy LastValueMap;
std::vector<PHINode*> OrigPHINode;
for (BasicBlock::iterator I = Header->begin(); isa<PHINode>(I); ++I) {
OrigPHINode.push_back(cast<PHINode>(I));
}
std::vector<BasicBlock*> Headers;
std::vector<BasicBlock*> Latches;
Headers.push_back(Header);
Latches.push_back(LatchBlock);
// The current on-the-fly SSA update requires blocks to be processed in
// reverse postorder so that LastValueMap contains the correct value at each
// exit.
LoopBlocksDFS DFS(L);
DFS.perform(LI);
// Stash the DFS iterators before adding blocks to the loop.
LoopBlocksDFS::RPOIterator BlockBegin = DFS.beginRPO();
LoopBlocksDFS::RPOIterator BlockEnd = DFS.endRPO();
for (unsigned It = 1; It != Count; ++It) {
std::vector<BasicBlock*> NewBlocks;
SmallDenseMap<const Loop *, Loop *, 4> NewLoops;
NewLoops[L] = L;
for (LoopBlocksDFS::RPOIterator BB = BlockBegin; BB != BlockEnd; ++BB) {
ValueToValueMapTy VMap;
BasicBlock *New = CloneBasicBlock(*BB, VMap, "." + Twine(It));
Header->getParent()->getBasicBlockList().push_back(New);
// Tell LI about New.
if (*BB == Header) {
assert(LI->getLoopFor(*BB) == L && "Header should not be in a sub-loop");
L->addBasicBlockToLoop(New, *LI);
} else {
// Figure out which loop New is in.
const Loop *OldLoop = LI->getLoopFor(*BB);
assert(OldLoop && "Should (at least) be in the loop being unrolled!");
Loop *&NewLoop = NewLoops[OldLoop];
if (!NewLoop) {
// Found a new sub-loop.
assert(*BB == OldLoop->getHeader() &&
"Header should be first in RPO");
Loop *NewLoopParent = NewLoops.lookup(OldLoop->getParentLoop());
assert(NewLoopParent &&
"Expected parent loop before sub-loop in RPO");
NewLoop = new Loop;
NewLoopParent->addChildLoop(NewLoop);
// Forget the old loop, since its inputs may have changed.
if (SE)
SE->forgetLoop(OldLoop);
}
示例7: sinkInstruction
// Sinks \p I from the loop \p L's preheader to its uses. Returns true if
// sinking is successful.
// \p LoopBlockNumber is used to sort the insertion blocks to ensure
// determinism.
static bool sinkInstruction(Loop &L, Instruction &I,
const SmallVectorImpl<BasicBlock *> &ColdLoopBBs,
const SmallDenseMap<BasicBlock *, int, 16> &LoopBlockNumber,
LoopInfo &LI, DominatorTree &DT,
BlockFrequencyInfo &BFI) {
// Compute the set of blocks in loop L which contain a use of I.
SmallPtrSet<BasicBlock *, 2> BBs;
for (auto &U : I.uses()) {
Instruction *UI = cast<Instruction>(U.getUser());
// We cannot sink I to PHI-uses.
if (dyn_cast<PHINode>(UI))
return false;
// We cannot sink I if it has uses outside of the loop.
if (!L.contains(LI.getLoopFor(UI->getParent())))
return false;
BBs.insert(UI->getParent());
}
// findBBsToSinkInto is O(BBs.size() * ColdLoopBBs.size()). We cap the max
// BBs.size() to avoid expensive computation.
// FIXME: Handle code size growth for min_size and opt_size.
if (BBs.size() > MaxNumberOfUseBBsForSinking)
return false;
// Find the set of BBs that we should insert a copy of I.
SmallPtrSet<BasicBlock *, 2> BBsToSinkInto =
findBBsToSinkInto(L, BBs, ColdLoopBBs, DT, BFI);
if (BBsToSinkInto.empty())
return false;
// Copy the final BBs into a vector and sort them using the total ordering
// of the loop block numbers as iterating the set doesn't give a useful
// order. No need to stable sort as the block numbers are a total ordering.
SmallVector<BasicBlock *, 2> SortedBBsToSinkInto;
SortedBBsToSinkInto.insert(SortedBBsToSinkInto.begin(), BBsToSinkInto.begin(),
BBsToSinkInto.end());
std::sort(SortedBBsToSinkInto.begin(), SortedBBsToSinkInto.end(),
[&](BasicBlock *A, BasicBlock *B) {
return *LoopBlockNumber.find(A) < *LoopBlockNumber.find(B);
});
BasicBlock *MoveBB = *SortedBBsToSinkInto.begin();
// FIXME: Optimize the efficiency for cloned value replacement. The current
// implementation is O(SortedBBsToSinkInto.size() * I.num_uses()).
for (BasicBlock *N : SortedBBsToSinkInto) {
if (N == MoveBB)
continue;
// Clone I and replace its uses.
Instruction *IC = I.clone();
IC->setName(I.getName());
IC->insertBefore(&*N->getFirstInsertionPt());
// Replaces uses of I with IC in N
for (Value::use_iterator UI = I.use_begin(), UE = I.use_end(); UI != UE;) {
Use &U = *UI++;
auto *I = cast<Instruction>(U.getUser());
if (I->getParent() == N)
U.set(IC);
}
// Replaces uses of I with IC in blocks dominated by N
replaceDominatedUsesWith(&I, IC, DT, N);
DEBUG(dbgs() << "Sinking a clone of " << I << " To: " << N->getName()
<< '\n');
NumLoopSunkCloned++;
}
DEBUG(dbgs() << "Sinking " << I << " To: " << MoveBB->getName() << '\n');
NumLoopSunk++;
I.moveBefore(&*MoveBB->getFirstInsertionPt());
return true;
}
示例8: formLCSSAForInstructions
/// For every instruction from the worklist, check to see if it has any uses
/// that are outside the current loop. If so, insert LCSSA PHI nodes and
/// rewrite the uses.
bool llvm::formLCSSAForInstructions(SmallVectorImpl<Instruction *> &Worklist,
DominatorTree &DT, LoopInfo &LI) {
SmallVector<Use *, 16> UsesToRewrite;
SmallSetVector<PHINode *, 16> PHIsToRemove;
PredIteratorCache PredCache;
bool Changed = false;
// Cache the Loop ExitBlocks across this loop. We expect to get a lot of
// instructions within the same loops, computing the exit blocks is
// expensive, and we're not mutating the loop structure.
SmallDenseMap<Loop*, SmallVector<BasicBlock *,1>> LoopExitBlocks;
while (!Worklist.empty()) {
UsesToRewrite.clear();
Instruction *I = Worklist.pop_back_val();
BasicBlock *InstBB = I->getParent();
Loop *L = LI.getLoopFor(InstBB);
if (!LoopExitBlocks.count(L))
L->getExitBlocks(LoopExitBlocks[L]);
assert(LoopExitBlocks.count(L));
const SmallVectorImpl<BasicBlock *> &ExitBlocks = LoopExitBlocks[L];
if (ExitBlocks.empty())
continue;
// Tokens cannot be used in PHI nodes, so we skip over them.
// We can run into tokens which are live out of a loop with catchswitch
// instructions in Windows EH if the catchswitch has one catchpad which
// is inside the loop and another which is not.
if (I->getType()->isTokenTy())
continue;
for (Use &U : I->uses()) {
Instruction *User = cast<Instruction>(U.getUser());
BasicBlock *UserBB = User->getParent();
if (PHINode *PN = dyn_cast<PHINode>(User))
UserBB = PN->getIncomingBlock(U);
if (InstBB != UserBB && !L->contains(UserBB))
UsesToRewrite.push_back(&U);
}
// If there are no uses outside the loop, exit with no change.
if (UsesToRewrite.empty())
continue;
++NumLCSSA; // We are applying the transformation
// Invoke instructions are special in that their result value is not
// available along their unwind edge. The code below tests to see whether
// DomBB dominates the value, so adjust DomBB to the normal destination
// block, which is effectively where the value is first usable.
BasicBlock *DomBB = InstBB;
if (InvokeInst *Inv = dyn_cast<InvokeInst>(I))
DomBB = Inv->getNormalDest();
DomTreeNode *DomNode = DT.getNode(DomBB);
SmallVector<PHINode *, 16> AddedPHIs;
SmallVector<PHINode *, 8> PostProcessPHIs;
SmallVector<PHINode *, 4> InsertedPHIs;
SSAUpdater SSAUpdate(&InsertedPHIs);
SSAUpdate.Initialize(I->getType(), I->getName());
// Insert the LCSSA phi's into all of the exit blocks dominated by the
// value, and add them to the Phi's map.
for (BasicBlock *ExitBB : ExitBlocks) {
if (!DT.dominates(DomNode, DT.getNode(ExitBB)))
continue;
// If we already inserted something for this BB, don't reprocess it.
if (SSAUpdate.HasValueForBlock(ExitBB))
continue;
PHINode *PN = PHINode::Create(I->getType(), PredCache.size(ExitBB),
I->getName() + ".lcssa", &ExitBB->front());
// Add inputs from inside the loop for this PHI.
for (BasicBlock *Pred : PredCache.get(ExitBB)) {
PN->addIncoming(I, Pred);
// If the exit block has a predecessor not within the loop, arrange for
// the incoming value use corresponding to that predecessor to be
// rewritten in terms of a different LCSSA PHI.
if (!L->contains(Pred))
UsesToRewrite.push_back(
&PN->getOperandUse(PN->getOperandNumForIncomingValue(
PN->getNumIncomingValues() - 1)));
}
AddedPHIs.push_back(PN);
// Remember that this phi makes the value alive in this block.
SSAUpdate.AddAvailableValue(ExitBB, PN);
//.........这里部分代码省略.........
示例9: if
// Create output section objects and add them to OutputSections.
template <class ELFT> void Writer<ELFT>::createSections() {
// .interp needs to be on the first page in the output file.
if (needsInterpSection())
OutputSections.push_back(Out<ELFT>::Interp);
SmallDenseMap<SectionKey<ELFT::Is64Bits>, OutputSectionBase<ELFT> *> Map;
std::vector<OutputSectionBase<ELFT> *> RegularSections;
for (const std::unique_ptr<ObjectFile<ELFT>> &F : Symtab.getObjectFiles()) {
for (InputSectionBase<ELFT> *C : F->getSections()) {
if (isDiscarded(C))
continue;
const Elf_Shdr *H = C->getSectionHdr();
uintX_t OutFlags = H->sh_flags & ~SHF_GROUP;
// For SHF_MERGE we create different output sections for each sh_entsize.
// This makes each output section simple and keeps a single level
// mapping from input to output.
typename InputSectionBase<ELFT>::Kind K = C->SectionKind;
uintX_t EntSize = K != InputSectionBase<ELFT>::Merge ? 0 : H->sh_entsize;
uint32_t OutType = H->sh_type;
if (OutType == SHT_PROGBITS && C->getSectionName() == ".eh_frame" &&
Config->EMachine == EM_X86_64)
OutType = SHT_X86_64_UNWIND;
SectionKey<ELFT::Is64Bits> Key{getOutputSectionName(C->getSectionName()),
OutType, OutFlags, EntSize};
OutputSectionBase<ELFT> *&Sec = Map[Key];
if (!Sec) {
switch (K) {
case InputSectionBase<ELFT>::Regular:
Sec = new (SecAlloc.Allocate())
OutputSection<ELFT>(Key.Name, Key.Type, Key.Flags);
break;
case InputSectionBase<ELFT>::EHFrame:
Sec = new (EHSecAlloc.Allocate())
EHOutputSection<ELFT>(Key.Name, Key.Type, Key.Flags);
break;
case InputSectionBase<ELFT>::Merge:
Sec = new (MSecAlloc.Allocate())
MergeOutputSection<ELFT>(Key.Name, Key.Type, Key.Flags);
break;
}
OutputSections.push_back(Sec);
RegularSections.push_back(Sec);
}
switch (K) {
case InputSectionBase<ELFT>::Regular:
static_cast<OutputSection<ELFT> *>(Sec)
->addSection(cast<InputSection<ELFT>>(C));
break;
case InputSectionBase<ELFT>::EHFrame:
static_cast<EHOutputSection<ELFT> *>(Sec)
->addSection(cast<EHInputSection<ELFT>>(C));
break;
case InputSectionBase<ELFT>::Merge:
static_cast<MergeOutputSection<ELFT> *>(Sec)
->addSection(cast<MergeInputSection<ELFT>>(C));
break;
}
}
}
Out<ELFT>::Bss = static_cast<OutputSection<ELFT> *>(
Map[{".bss", SHT_NOBITS, SHF_ALLOC | SHF_WRITE, 0}]);
Out<ELFT>::Dynamic->PreInitArraySec = Map.lookup(
{".preinit_array", SHT_PREINIT_ARRAY, SHF_WRITE | SHF_ALLOC, 0});
Out<ELFT>::Dynamic->InitArraySec =
Map.lookup({".init_array", SHT_INIT_ARRAY, SHF_WRITE | SHF_ALLOC, 0});
Out<ELFT>::Dynamic->FiniArraySec =
Map.lookup({".fini_array", SHT_FINI_ARRAY, SHF_WRITE | SHF_ALLOC, 0});
auto AddStartEnd = [&](StringRef Start, StringRef End,
OutputSectionBase<ELFT> *OS) {
if (OS) {
Symtab.addSyntheticSym(Start, *OS, 0);
Symtab.addSyntheticSym(End, *OS, OS->getSize());
} else {
Symtab.addIgnoredSym(Start);
Symtab.addIgnoredSym(End);
}
};
AddStartEnd("__preinit_array_start", "__preinit_array_end",
Out<ELFT>::Dynamic->PreInitArraySec);
AddStartEnd("__init_array_start", "__init_array_end",
Out<ELFT>::Dynamic->InitArraySec);
AddStartEnd("__fini_array_start", "__fini_array_end",
Out<ELFT>::Dynamic->FiniArraySec);
for (OutputSectionBase<ELFT> *Sec : RegularSections)
addStartStopSymbols(Sec);
// __tls_get_addr is defined by the dynamic linker for dynamic ELFs. For
// static linking the linker is required to optimize away any references to
// __tls_get_addr, so it's not defined anywhere. Create a hidden definition
// to avoid the undefined symbol error.
if (!isOutputDynamic())
Symtab.addIgnoredSym("__tls_get_addr");
//.........这里部分代码省略.........