diff options
author | Dean Michael Berris <dberris@google.com> | 2016-09-08 00:19:04 +0000 |
---|---|---|
committer | Dean Michael Berris <dberris@google.com> | 2016-09-08 00:19:04 +0000 |
commit | 17d94e279e43c02833628a455a97d78cd8aafb5e (patch) | |
tree | 0d31e55bdef4a64dc547dc93d19bec12c607ce5a /llvm/lib/CodeGen/XRayInstrumentation.cpp | |
parent | 6b96c15b83d3249f7cc7ebf0075a41d9e95a1add (diff) | |
download | bcm5719-llvm-17d94e279e43c02833628a455a97d78cd8aafb5e.tar.gz bcm5719-llvm-17d94e279e43c02833628a455a97d78cd8aafb5e.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:
1. https://reviews.llvm.org/D23932 (Clang test)
2. https://reviews.llvm.org/D23933 (compiler-rt)
Differential Revision: https://reviews.llvm.org/D23931
llvm-svn: 280888
Diffstat (limited to 'llvm/lib/CodeGen/XRayInstrumentation.cpp')
-rw-r--r-- | llvm/lib/CodeGen/XRayInstrumentation.cpp | 110 |
1 files changed, 82 insertions, 28 deletions
diff --git a/llvm/lib/CodeGen/XRayInstrumentation.cpp b/llvm/lib/CodeGen/XRayInstrumentation.cpp index 043a1a48db6..ea29d4cb597 100644 --- a/llvm/lib/CodeGen/XRayInstrumentation.cpp +++ b/llvm/lib/CodeGen/XRayInstrumentation.cpp @@ -34,7 +34,74 @@ struct XRayInstrumentation : public MachineFunctionPass { } bool runOnMachineFunction(MachineFunction &MF) override; + +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 + +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) { + for (auto &T : MBB.terminators()) { + unsigned Opc = 0; + if (T.isReturn() && T.getOpcode() == TII->getReturnOpcode()) { + // Replace return instructions with: + // PATCHABLE_RET <Opcode>, <Operand>... + Opc = TargetOpcode::PATCHABLE_RET; + } + if (TII->isTailCall(T)) { + // Treat the tail call as a return instruction, which has a + // different-looking sled than the normal return case. + Opc = TargetOpcode::PATCHABLE_TAIL_CALL; + } + if (Opc != 0) { + auto MIB = BuildMI(MBB, T, T.getDebugLoc(), TII->get(Opc)) + .addImm(T.getOpcode()); + for (auto &MO : T.operands()) + MIB.addOperand(MO); + Terminators.push_back(&T); + } + } + } + + 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 + auto MIB = BuildMI(MBB, T, T.getDebugLoc(), + TII->get(TargetOpcode::PATCHABLE_FUNCTION_EXIT)); + } + } + } } bool XRayInstrumentation::runOnMachineFunction(MachineFunction &MF) { @@ -54,6 +121,11 @@ bool XRayInstrumentation::runOnMachineFunction(MachineFunction &MF) { return false; // Function is too small. } + if (!MF.getSubtarget().isXRaySupported()) { + //FIXME: can this be reported somehow? + 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 @@ -64,35 +136,17 @@ bool XRayInstrumentation::runOnMachineFunction(MachineFunction &MF) { BuildMI(FirstMBB, FirstMI, FirstMI.getDebugLoc(), TII->get(TargetOpcode::PATCHABLE_FUNCTION_ENTER)); - // Then we look for *all* terminators and returns, then replace those with - // PATCHABLE_RET instructions. - SmallVector<MachineInstr *, 4> Terminators; - for (auto &MBB : MF) { - for (auto &T : MBB.terminators()) { - unsigned Opc = 0; - if (T.isReturn() && T.getOpcode() == TII->getReturnOpcode()) { - // Replace return instructions with: - // PATCHABLE_RET <Opcode>, <Operand>... - Opc = TargetOpcode::PATCHABLE_RET; - } - if (TII->isTailCall(T)) { - // Treat the tail call as a return instruction, which has a - // different-looking sled than the normal return case. - Opc = TargetOpcode::PATCHABLE_TAIL_CALL; - } - if (Opc != 0) { - auto MIB = BuildMI(MBB, T, T.getDebugLoc(), TII->get(Opc)) - .addImm(T.getOpcode()); - for (auto &MO : T.operands()) - MIB.addOperand(MO); - Terminators.push_back(&T); - } - } + switch (MF.getTarget().getTargetTriple().getArch()) { + case Triple::ArchType::arm: + // 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; } - - for (auto &I : Terminators) - I->eraseFromParent(); - return true; } |