summaryrefslogtreecommitdiffstats
path: root/llvm/lib/CodeGen/XRayInstrumentation.cpp
diff options
context:
space:
mode:
authorDean Michael Berris <dberris@google.com>2016-09-19 00:54:35 +0000
committerDean Michael Berris <dberris@google.com>2016-09-19 00:54:35 +0000
commit4640154446cb2f95aa54d001ecd6683d2941d47a (patch)
treeed8544ae856622d7dbb7af82c13508157425a9a0 /llvm/lib/CodeGen/XRayInstrumentation.cpp
parent3c46abb2eab8c0e62f3fdf552a6c5d501aed2738 (diff)
downloadbcm5719-llvm-4640154446cb2f95aa54d001ecd6683d2941d47a.tar.gz
bcm5719-llvm-4640154446cb2f95aa54d001ecd6683d2941d47a.zip
[XRay] ARM 32-bit no-Thumb support in LLVM
This is a port of XRay to ARM 32-bit, without Thumb support yet. The XRay instrumentation support is moving up to AsmPrinter. This is one of 3 commits to different repositories of XRay ARM port. The other 2 are: https://reviews.llvm.org/D23932 (Clang test) https://reviews.llvm.org/D23933 (compiler-rt) Differential Revision: https://reviews.llvm.org/D23931 llvm-svn: 281878
Diffstat (limited to 'llvm/lib/CodeGen/XRayInstrumentation.cpp')
-rw-r--r--llvm/lib/CodeGen/XRayInstrumentation.cpp115
1 files changed, 86 insertions, 29 deletions
diff --git a/llvm/lib/CodeGen/XRayInstrumentation.cpp b/llvm/lib/CodeGen/XRayInstrumentation.cpp
index 043a1a48db6..7a3ca9799bb 100644
--- a/llvm/lib/CodeGen/XRayInstrumentation.cpp
+++ b/llvm/lib/CodeGen/XRayInstrumentation.cpp
@@ -34,37 +34,33 @@ struct XRayInstrumentation : public MachineFunctionPass {
}
bool runOnMachineFunction(MachineFunction &MF) override;
-};
-}
-
-bool XRayInstrumentation::runOnMachineFunction(MachineFunction &MF) {
- auto &F = *MF.getFunction();
- auto InstrAttr = F.getFnAttribute("function-instrument");
- bool AlwaysInstrument = !InstrAttr.hasAttribute(Attribute::None) &&
- InstrAttr.isStringAttribute() &&
- InstrAttr.getValueAsString() == "xray-always";
- Attribute Attr = F.getFnAttribute("xray-instruction-threshold");
- unsigned XRayThreshold = 0;
- if (!AlwaysInstrument) {
- if (Attr.hasAttribute(Attribute::None) || !Attr.isStringAttribute())
- return false; // XRay threshold attribute not found.
- if (Attr.getValueAsString().getAsInteger(10, XRayThreshold))
- return false; // Invalid value for threshold.
- if (F.size() < XRayThreshold)
- return false; // Function is too small.
- }
- // FIXME: Do the loop triviality analysis here or in an earlier pass.
-
- // First, insert an PATCHABLE_FUNCTION_ENTER as the first instruction of the
- // MachineFunction.
- auto &FirstMBB = *MF.begin();
- auto &FirstMI = *FirstMBB.begin();
- auto *TII = MF.getSubtarget().getInstrInfo();
- BuildMI(FirstMBB, FirstMI, FirstMI.getDebugLoc(),
- TII->get(TargetOpcode::PATCHABLE_FUNCTION_ENTER));
+private:
+ // Replace the original RET instruction with the exit sled code ("patchable
+ // ret" pseudo-instruction), so that at runtime XRay can replace the sled
+ // with a code jumping to XRay trampoline, which calls the tracing handler
+ // and, in the end, issues the RET instruction.
+ // This is the approach to go on CPUs which have a single RET instruction,
+ // like x86/x86_64.
+ void replaceRetWithPatchableRet(MachineFunction &MF,
+ const TargetInstrInfo *TII);
+ // Prepend the original return instruction with the exit sled code ("patchable
+ // function exit" pseudo-instruction), preserving the original return
+ // instruction just after the exit sled code.
+ // This is the approach to go on CPUs which have multiple options for the
+ // return instruction, like ARM. For such CPUs we can't just jump into the
+ // XRay trampoline and issue a single return instruction there. We rather
+ // have to call the trampoline and return from it to the original return
+ // instruction of the function being instrumented.
+ void prependRetWithPatchableExit(MachineFunction &MF,
+ const TargetInstrInfo *TII);
+};
+} // anonymous namespace
- // Then we look for *all* terminators and returns, then replace those with
+void XRayInstrumentation::replaceRetWithPatchableRet(MachineFunction &MF,
+ const TargetInstrInfo *TII)
+{
+ // We look for *all* terminators and returns, then replace those with
// PATCHABLE_RET instructions.
SmallVector<MachineInstr *, 4> Terminators;
for (auto &MBB : MF) {
@@ -92,7 +88,68 @@ bool XRayInstrumentation::runOnMachineFunction(MachineFunction &MF) {
for (auto &I : Terminators)
I->eraseFromParent();
+}
+
+void XRayInstrumentation::prependRetWithPatchableExit(MachineFunction &MF,
+ const TargetInstrInfo *TII)
+{
+ for (auto &MBB : MF) {
+ for (auto &T : MBB.terminators()) {
+ if (T.isReturn()) {
+ // Prepend the return instruction with PATCHABLE_FUNCTION_EXIT
+ BuildMI(MBB, T, T.getDebugLoc(),
+ TII->get(TargetOpcode::PATCHABLE_FUNCTION_EXIT));
+ }
+ }
+ }
+}
+
+bool XRayInstrumentation::runOnMachineFunction(MachineFunction &MF) {
+ auto &F = *MF.getFunction();
+ auto InstrAttr = F.getFnAttribute("function-instrument");
+ bool AlwaysInstrument = !InstrAttr.hasAttribute(Attribute::None) &&
+ InstrAttr.isStringAttribute() &&
+ InstrAttr.getValueAsString() == "xray-always";
+ Attribute Attr = F.getFnAttribute("xray-instruction-threshold");
+ unsigned XRayThreshold = 0;
+ if (!AlwaysInstrument) {
+ if (Attr.hasAttribute(Attribute::None) || !Attr.isStringAttribute())
+ return false; // XRay threshold attribute not found.
+ if (Attr.getValueAsString().getAsInteger(10, XRayThreshold))
+ return false; // Invalid value for threshold.
+ if (F.size() < XRayThreshold)
+ return false; // Function is too small.
+ }
+ auto &FirstMBB = *MF.begin();
+ auto &FirstMI = *FirstMBB.begin();
+
+ if (!MF.getSubtarget().isXRaySupported()) {
+ FirstMI.emitError("An attempt to perform XRay instrumentation for an"
+ " unsupported target.");
+ return false;
+ }
+
+ // FIXME: Do the loop triviality analysis here or in an earlier pass.
+
+ // First, insert an PATCHABLE_FUNCTION_ENTER as the first instruction of the
+ // MachineFunction.
+ auto *TII = MF.getSubtarget().getInstrInfo();
+ BuildMI(FirstMBB, FirstMI, FirstMI.getDebugLoc(),
+ TII->get(TargetOpcode::PATCHABLE_FUNCTION_ENTER));
+
+ switch (MF.getTarget().getTargetTriple().getArch()) {
+ case Triple::ArchType::arm:
+ case Triple::ArchType::thumb:
+ // For the architectures which don't have a single return instruction
+ prependRetWithPatchableExit(MF, TII);
+ break;
+ default:
+ // For the architectures that have a single return instruction (such as
+ // RETQ on x86_64).
+ replaceRetWithPatchableRet(MF, TII);
+ break;
+ }
return true;
}
OpenPOWER on IntegriCloud