[llvm] fc734da - [JITLink][MachO][arm64] Add support for splitting compact-unwind sections.
Lang Hames via llvm-commits
llvm-commits at lists.llvm.org
Tue Sep 28 17:37:16 PDT 2021
Author: Lang Hames
Date: 2021-09-28T17:29:05-07:00
New Revision: fc734da79549fd74cff71b8c4c8e689de4a0340f
URL: https://github.com/llvm/llvm-project/commit/fc734da79549fd74cff71b8c4c8e689de4a0340f
DIFF: https://github.com/llvm/llvm-project/commit/fc734da79549fd74cff71b8c4c8e689de4a0340f.diff
LOG: [JITLink][MachO][arm64] Add support for splitting compact-unwind sections.
CompactUnwindSplitter splits compact-unwind sections on record boundaries and
adds keep-alive edges from target functions back to their respective records.
In MachO_arm64.cpp, a CompactUnwindSplitter pass is added to the pre-prune pass
list when setting up the standard pipeline.
This patch does not provide runtime support for compact-unwind, but is a first
step towards enabling it.
Added:
llvm/test/ExecutionEngine/JITLink/AArch64/MachO_arm64_compact_unwind.s
Modified:
llvm/lib/ExecutionEngine/JITLink/MachOLinkGraphBuilder.cpp
llvm/lib/ExecutionEngine/JITLink/MachOLinkGraphBuilder.h
llvm/lib/ExecutionEngine/JITLink/MachO_arm64.cpp
Removed:
################################################################################
diff --git a/llvm/lib/ExecutionEngine/JITLink/MachOLinkGraphBuilder.cpp b/llvm/lib/ExecutionEngine/JITLink/MachOLinkGraphBuilder.cpp
index 34bda09f1cacc..22f17331503d9 100644
--- a/llvm/lib/ExecutionEngine/JITLink/MachOLinkGraphBuilder.cpp
+++ b/llvm/lib/ExecutionEngine/JITLink/MachOLinkGraphBuilder.cpp
@@ -701,5 +701,119 @@ Error MachOLinkGraphBuilder::graphifyCStringSection(
return Error::success();
}
+Error CompactUnwindSplitter::operator()(LinkGraph &G) {
+ auto *CUSec = G.findSectionByName(CompactUnwindSectionName);
+ if (!CUSec)
+ return Error::success();
+
+ if (!G.getTargetTriple().isOSBinFormatMachO())
+ return make_error<JITLinkError>(
+ "Error linking " + G.getName() +
+ ": compact unwind splitting not supported on non-macho target " +
+ G.getTargetTriple().str());
+
+ unsigned CURecordSize = 0;
+ unsigned PersonalityEdgeOffset = 0;
+ unsigned LSDAEdgeOffset = 0;
+ switch (G.getTargetTriple().getArch()) {
+ case Triple::aarch64:
+ case Triple::x86_64:
+ // 64-bit compact-unwind record format:
+ // Range start: 8 bytes.
+ // Range size: 4 bytes.
+ // CU encoding: 4 bytes.
+ // Personality: 8 bytes.
+ // LSDA: 8 bytes.
+ CURecordSize = 32;
+ PersonalityEdgeOffset = 16;
+ LSDAEdgeOffset = 24;
+ break;
+ default:
+ return make_error<JITLinkError>(
+ "Error linking " + G.getName() +
+ ": compact unwind splitting not supported on " +
+ G.getTargetTriple().getArchName());
+ }
+
+ std::vector<Block *> OriginalBlocks(CUSec->blocks().begin(),
+ CUSec->blocks().end());
+ LLVM_DEBUG({
+ dbgs() << "In " << G.getName() << " splitting compact unwind section "
+ << CompactUnwindSectionName << " containing "
+ << OriginalBlocks.size() << " initial blocks...\n";
+ });
+
+ while (!OriginalBlocks.empty()) {
+ auto *B = OriginalBlocks.back();
+ OriginalBlocks.pop_back();
+
+ if (B->getSize() == 0) {
+ LLVM_DEBUG({
+ dbgs() << " Skipping empty block at "
+ << formatv("{0:x16}", B->getAddress()) << "\n";
+ });
+ continue;
+ }
+
+ LLVM_DEBUG({
+ dbgs() << " Splitting block at " << formatv("{0:x16}", B->getAddress())
+ << " into " << (B->getSize() / CURecordSize)
+ << " compact unwind record(s)\n";
+ });
+
+ if (B->getSize() % CURecordSize)
+ return make_error<JITLinkError>(
+ "Error splitting compact unwind record in " + G.getName() +
+ ": block at " + formatv("{0:x}", B->getAddress()) + " has size " +
+ formatv("{0:x}", B->getSize()) +
+ " (not a multiple of CU record size of " +
+ formatv("{0:x}", CURecordSize) + ")");
+
+ unsigned NumBlocks = B->getSize() / CURecordSize;
+ LinkGraph::SplitBlockCache C;
+
+ for (unsigned I = 0; I != NumBlocks; ++I) {
+ auto &CURec = G.splitBlock(*B, CURecordSize, &C);
+ bool AddedKeepAlive = false;
+
+ for (auto &E : CURec.edges()) {
+ if (E.getOffset() == 0) {
+ LLVM_DEBUG({
+ dbgs() << " Updating compact unwind record at "
+ << formatv("{0:x16}", CURec.getAddress()) << " to point to "
+ << (E.getTarget().hasName() ? E.getTarget().getName()
+ : StringRef())
+ << " (at " << formatv("{0:x16}", E.getTarget().getAddress())
+ << ")\n";
+ });
+
+ if (E.getTarget().isExternal())
+ return make_error<JITLinkError>(
+ "Error adding keep-alive edge for compact unwind record at " +
+ formatv("{0:x}", CURec.getAddress()) + ": target " +
+ E.getTarget().getName() + " is an external symbol");
+ auto &TgtBlock = E.getTarget().getBlock();
+ auto &CURecSym =
+ G.addAnonymousSymbol(CURec, 0, CURecordSize, 0, false);
+ TgtBlock.addEdge(Edge::KeepAlive, 0, CURecSym, 0);
+ AddedKeepAlive = true;
+ } else if (E.getOffset() != PersonalityEdgeOffset &&
+ E.getOffset() != LSDAEdgeOffset)
+ return make_error<JITLinkError>("Unexpected edge at offset " +
+ formatv("{0:x}", E.getOffset()) +
+ " in compact unwind record at " +
+ formatv("{0:x}", CURec.getAddress()));
+ }
+
+ if (!AddedKeepAlive)
+ return make_error<JITLinkError>(
+ "Error adding keep-alive edge for compact unwind record at " +
+ formatv("{0:x}", CURec.getAddress()) +
+ ": no outgoing target edge at offset 0");
+ }
+ }
+ return Error::success();
+}
+
} // end namespace jitlink
} // end namespace llvm
diff --git a/llvm/lib/ExecutionEngine/JITLink/MachOLinkGraphBuilder.h b/llvm/lib/ExecutionEngine/JITLink/MachOLinkGraphBuilder.h
index 90b14c44ff8a8..4c82768f9fdbf 100644
--- a/llvm/lib/ExecutionEngine/JITLink/MachOLinkGraphBuilder.h
+++ b/llvm/lib/ExecutionEngine/JITLink/MachOLinkGraphBuilder.h
@@ -231,6 +231,17 @@ class MachOLinkGraphBuilder {
StringMap<SectionParserFunction> CustomSectionParserFunctions;
};
+/// A pass to split up __LD,__compact_unwind sections.
+class CompactUnwindSplitter {
+public:
+ CompactUnwindSplitter(StringRef CompactUnwindSectionName)
+ : CompactUnwindSectionName(CompactUnwindSectionName) {}
+ Error operator()(LinkGraph &G);
+
+private:
+ StringRef CompactUnwindSectionName;
+};
+
} // end namespace jitlink
} // end namespace llvm
diff --git a/llvm/lib/ExecutionEngine/JITLink/MachO_arm64.cpp b/llvm/lib/ExecutionEngine/JITLink/MachO_arm64.cpp
index 169e20a1d1d32..8a2c7e527aa05 100644
--- a/llvm/lib/ExecutionEngine/JITLink/MachO_arm64.cpp
+++ b/llvm/lib/ExecutionEngine/JITLink/MachO_arm64.cpp
@@ -683,6 +683,10 @@ void link_MachO_arm64(std::unique_ptr<LinkGraph> G,
else
Config.PrePrunePasses.push_back(markAllSymbolsLive);
+ // Add compact unwind splitter pass.
+ Config.PrePrunePasses.push_back(
+ CompactUnwindSplitter("__LD,__compact_unwind"));
+
// Add an in-place GOT/Stubs pass.
Config.PostPrunePasses.push_back(
PerGraphGOTAndPLTStubsBuilder_MachO_arm64::asPass);
diff --git a/llvm/test/ExecutionEngine/JITLink/AArch64/MachO_arm64_compact_unwind.s b/llvm/test/ExecutionEngine/JITLink/AArch64/MachO_arm64_compact_unwind.s
new file mode 100644
index 0000000000000..20534d5a48656
--- /dev/null
+++ b/llvm/test/ExecutionEngine/JITLink/AArch64/MachO_arm64_compact_unwind.s
@@ -0,0 +1,20 @@
+# REQUIRES: asserts
+# RUN: llvm-mc -triple=arm64-apple-ios -filetype=obj -o %t %s
+# RUN: llvm-jitlink -noexec -debug-only=jitlink %t 2>&1 | FileCheck %s
+#
+# Check that splitting of compact-unwind sections works.
+#
+# CHECK: splitting {{.*}} __LD,__compact_unwind containing 1 initial blocks...
+# CHECK: Splitting {{.*}} into 1 compact unwind record(s)
+# CHECK: Updating {{.*}} to point to _main {{.*}}
+
+ .section __TEXT,__text,regular,pure_instructions
+ .globl _main
+ .p2align 2
+_main:
+ .cfi_startproc
+ ret
+ .cfi_endproc
+
+.subsections_via_symbols
+
More information about the llvm-commits
mailing list