Skip to content

Commit 897de23

Browse files
committed
[lld][macho] Move unwind logic from equalsVariable to equalsConstant
Since equalsVariable runs a lot more times, we want to minimize the work it needs to do. Anything not dependent on the icfEqClass values should get hoisted out. With this change, ICF runs ~1.7% faster when linking clang. Benchmarking approach: cbdr sample -b ~/extract-icf-time.sh ~/old/ld64.lld bin/ld64.lld --timeout=300s | cbdr analyze -s 95 `extract-icf-time.sh` runs the clang link command with the `--icf=all --time-trace` flags, then parses out the ICF duration from the resulting time trace using `jq`: jq '{ICF: (.traceEvents[] | select(.name == "Fold Identical Code Sections") | .dur)}' Output: </Users/jezng/extract-icf-time.sh ["/Users/jezng/old/ld64.lld"]> </Users/jezng/extract-icf-time.sh ["bin/ld64.lld"]> difference (95% CI) ICF 83678.207 ± 1502.778 82234.751 ± 1290.984 [ -2.0% .. -1.4%] samples 208 225
1 parent 60ab8c8 commit 897de23

File tree

1 file changed

+34
-22
lines changed

1 file changed

+34
-22
lines changed

lld/MachO/ICF.cpp

Lines changed: 34 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -179,8 +179,30 @@ bool ICF::equalsConstant(const ConcatInputSection *ia,
179179
return isecA->getOffset(ra.addend) == isecB->getOffset(rb.addend);
180180
}
181181
};
182-
return std::equal(ia->relocs.begin(), ia->relocs.end(), ib->relocs.begin(),
183-
f);
182+
if (!std::equal(ia->relocs.begin(), ia->relocs.end(), ib->relocs.begin(), f))
183+
return false;
184+
185+
// Check unwind info structural compatibility: if there are symbols with
186+
// associated unwind info, check that both sections have compatible symbol
187+
// layouts. For simplicity, we only attempt folding when all symbols are at
188+
// offset zero within the section (which is typically the case with
189+
// .subsections_via_symbols.)
190+
auto hasUnwind = [](Defined *d) { return d->unwindEntry() != nullptr; };
191+
const auto *itA = llvm::find_if(ia->symbols, hasUnwind);
192+
const auto *itB = llvm::find_if(ib->symbols, hasUnwind);
193+
if (itA == ia->symbols.end())
194+
return itB == ib->symbols.end();
195+
if (itB == ib->symbols.end())
196+
return false;
197+
const Defined *da = *itA;
198+
const Defined *db = *itB;
199+
if (da->value != 0 || db->value != 0)
200+
return false;
201+
auto isZero = [](Defined *d) { return d->value == 0; };
202+
return std::find_if_not(std::next(itA), ia->symbols.end(), isZero) ==
203+
ia->symbols.end() &&
204+
std::find_if_not(std::next(itB), ib->symbols.end(), isZero) ==
205+
ib->symbols.end();
184206
}
185207

186208
// Compare the "moving" parts of two ConcatInputSections -- i.e. everything not
@@ -220,28 +242,18 @@ bool ICF::equalsVariable(const ConcatInputSection *ia,
220242
if (!std::equal(ia->relocs.begin(), ia->relocs.end(), ib->relocs.begin(), f))
221243
return false;
222244

223-
// If there are symbols with associated unwind info, check that the unwind
224-
// info matches. For simplicity, we only handle the case where there are only
225-
// symbols at offset zero within the section (which is typically the case with
226-
// .subsections_via_symbols.)
245+
// Compare unwind info equivalence classes.
227246
auto hasUnwind = [](Defined *d) { return d->unwindEntry() != nullptr; };
228247
const auto *itA = llvm::find_if(ia->symbols, hasUnwind);
229-
const auto *itB = llvm::find_if(ib->symbols, hasUnwind);
230-
if (itA == ia->symbols.end())
231-
return itB == ib->symbols.end();
232-
if (itB == ib->symbols.end())
233-
return false;
234-
const Defined *da = *itA;
235-
const Defined *db = *itB;
236-
if (da->unwindEntry()->icfEqClass[icfPass % 2] !=
237-
db->unwindEntry()->icfEqClass[icfPass % 2] ||
238-
da->value != 0 || db->value != 0)
239-
return false;
240-
auto isZero = [](Defined *d) { return d->value == 0; };
241-
return std::find_if_not(std::next(itA), ia->symbols.end(), isZero) ==
242-
ia->symbols.end() &&
243-
std::find_if_not(std::next(itB), ib->symbols.end(), isZero) ==
244-
ib->symbols.end();
248+
if (itA != ia->symbols.end()) {
249+
const Defined *da = *itA;
250+
// equalsConstant() guarantees that both sections have unwind info.
251+
const Defined *db = *llvm::find_if(ib->symbols, hasUnwind);
252+
if (da->unwindEntry()->icfEqClass[icfPass % 2] !=
253+
db->unwindEntry()->icfEqClass[icfPass % 2])
254+
return false;
255+
}
256+
return true;
245257
}
246258

247259
// Find the first InputSection after BEGIN whose equivalence class differs

0 commit comments

Comments
 (0)