summaryrefslogtreecommitdiffstats
path: root/llvm/lib/CodeGen
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/CodeGen')
-rw-r--r--llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp10
-rw-r--r--llvm/lib/CodeGen/XRayInstrumentation.cpp110
2 files changed, 92 insertions, 28 deletions
diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
index 0fed4e91eef..ccc1691232c 100644
--- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
@@ -2606,3 +2606,13 @@ GCMetadataPrinter *AsmPrinter::GetOrCreateGCPrinter(GCStrategy &S) {
AsmPrinterHandler::~AsmPrinterHandler() {}
void AsmPrinterHandler::markFunctionEnd() {}
+
+void AsmPrinter::recordSled(MCSymbol *Sled, const MachineInstr &MI,
+ SledKind Kind) {
+ auto Fn = MI.getParent()->getParent()->getFunction();
+ auto Attr = Fn->getFnAttribute("function-instrument");
+ bool AlwaysInstrument =
+ Attr.isStringAttribute() && Attr.getValueAsString() == "xray-always";
+ Sleds.emplace_back(
+ XRayFunctionEntry{ Sled, CurrentFnSym, Kind, AlwaysInstrument, Fn });
+}
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;
}
OpenPOWER on IntegriCloud