1//===- OutputSegment.h -----------------------------------------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "OutputSegment.h"
10#include "InputChunks.h"
11#include "lld/Common/Memory.h"
12
13#define DEBUG_TYPE "lld"
14
15using namespace llvm;
16using namespace llvm::wasm;
17
18namespace lld::wasm {
19
20void OutputSegment::addInputSegment(InputChunk *inSeg) {
21 alignment = std::max(a: alignment, b: inSeg->alignment);
22 // Carry input flags (RETAIN, STRINGS) into the relocatable SegmentInfo
23 // output; otherwise a relocatable link drops them and the downstream link
24 // loses RETAIN (segment GC'd) and STRINGS (string merge disabled).
25 linkingFlags |= inSeg->flags;
26 inputSegments.push_back(x: inSeg);
27 size = llvm::alignTo(Value: size, Align: 1ULL << inSeg->alignment);
28 LLVM_DEBUG(dbgs() << "addInputSegment: " << inSeg->name << " oname=" << name
29 << " size=" << inSeg->getSize()
30 << " align=" << inSeg->alignment << " at:" << size << "\n");
31 inSeg->outputSeg = this;
32 inSeg->outputSegmentOffset = size;
33 size += inSeg->getSize();
34}
35
36// This function scans over the input segments.
37//
38// It removes MergeInputChunks from the input section array and adds
39// new synthetic sections at the location of the first input section
40// that it replaces. It then finalizes each synthetic section in order
41// to compute an output offset for each piece of each input section.
42void OutputSegment::finalizeInputSegments() {
43 LLVM_DEBUG(llvm::dbgs() << "finalizeInputSegments: " << name << "\n");
44 std::vector<SyntheticMergedChunk *> mergedSegments;
45 std::vector<InputChunk *> newSegments;
46 for (InputChunk *s : inputSegments) {
47 MergeInputChunk *ms = dyn_cast<MergeInputChunk>(Val: s);
48 if (!ms) {
49 newSegments.push_back(x: s);
50 continue;
51 }
52
53 // A segment should not make it here unless its alive
54 assert(ms->live);
55
56 auto i = llvm::find_if(Range&: mergedSegments, P: [=](SyntheticMergedChunk *seg) {
57 return seg->flags == ms->flags && seg->alignment == ms->alignment;
58 });
59 if (i == mergedSegments.end()) {
60 LLVM_DEBUG(llvm::dbgs() << "new merge segment: " << name
61 << " alignment=" << ms->alignment << "\n");
62 auto *syn = make<SyntheticMergedChunk>(args&: name, args&: ms->alignment, args&: ms->flags);
63 syn->outputSeg = this;
64 mergedSegments.push_back(x: syn);
65 i = std::prev(x: mergedSegments.end());
66 newSegments.push_back(x: syn);
67 } else {
68 LLVM_DEBUG(llvm::dbgs() << "adding to merge segment: " << name << "\n");
69 }
70 (*i)->addMergeChunk(ms);
71 }
72
73 for (auto *ms : mergedSegments)
74 ms->finalizeContents();
75
76 inputSegments = newSegments;
77 size = 0;
78 for (InputChunk *seg : inputSegments) {
79 size = llvm::alignTo(Value: size, Align: 1ULL << seg->alignment);
80 LLVM_DEBUG(llvm::dbgs() << "outputSegmentOffset set: " << seg->name
81 << " -> " << size << "\n");
82 seg->outputSegmentOffset = size;
83 size += seg->getSize();
84 }
85}
86
87} // namespace lld::wasm
88