1*0b57cec5SDimitry Andric //===-- PatchableFunction.cpp - Patchable prologues for LLVM -------------===//
2*0b57cec5SDimitry Andric //
3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*0b57cec5SDimitry Andric //
7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
8*0b57cec5SDimitry Andric //
9*0b57cec5SDimitry Andric // This file implements edits function bodies in place to support the
10*0b57cec5SDimitry Andric // "patchable-function" attribute.
11*0b57cec5SDimitry Andric //
12*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
13*0b57cec5SDimitry Andric
14*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunction.h"
15*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h"
16*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h"
17*0b57cec5SDimitry Andric #include "llvm/CodeGen/Passes.h"
18*0b57cec5SDimitry Andric #include "llvm/CodeGen/TargetFrameLowering.h"
19*0b57cec5SDimitry Andric #include "llvm/CodeGen/TargetInstrInfo.h"
20*0b57cec5SDimitry Andric #include "llvm/CodeGen/TargetSubtargetInfo.h"
21*0b57cec5SDimitry Andric #include "llvm/InitializePasses.h"
22*0b57cec5SDimitry Andric
23*0b57cec5SDimitry Andric using namespace llvm;
24*0b57cec5SDimitry Andric
25*0b57cec5SDimitry Andric namespace {
26*0b57cec5SDimitry Andric struct PatchableFunction : public MachineFunctionPass {
27*0b57cec5SDimitry Andric static char ID; // Pass identification, replacement for typeid
PatchableFunction__anon6480d9920111::PatchableFunction28*0b57cec5SDimitry Andric PatchableFunction() : MachineFunctionPass(ID) {
29*0b57cec5SDimitry Andric initializePatchableFunctionPass(*PassRegistry::getPassRegistry());
30*0b57cec5SDimitry Andric }
31*0b57cec5SDimitry Andric
32*0b57cec5SDimitry Andric bool runOnMachineFunction(MachineFunction &F) override;
getRequiredProperties__anon6480d9920111::PatchableFunction33*0b57cec5SDimitry Andric MachineFunctionProperties getRequiredProperties() const override {
34*0b57cec5SDimitry Andric return MachineFunctionProperties().set(
35*0b57cec5SDimitry Andric MachineFunctionProperties::Property::NoVRegs);
36*0b57cec5SDimitry Andric }
37*0b57cec5SDimitry Andric };
38*0b57cec5SDimitry Andric }
39*0b57cec5SDimitry Andric
40*0b57cec5SDimitry Andric /// Returns true if instruction \p MI will not result in actual machine code
41*0b57cec5SDimitry Andric /// instructions.
doesNotGeneratecode(const MachineInstr & MI)42*0b57cec5SDimitry Andric static bool doesNotGeneratecode(const MachineInstr &MI) {
43*0b57cec5SDimitry Andric // TODO: Introduce an MCInstrDesc flag for this
44*0b57cec5SDimitry Andric switch (MI.getOpcode()) {
45*0b57cec5SDimitry Andric default: return false;
46*0b57cec5SDimitry Andric case TargetOpcode::IMPLICIT_DEF:
47*0b57cec5SDimitry Andric case TargetOpcode::KILL:
48*0b57cec5SDimitry Andric case TargetOpcode::CFI_INSTRUCTION:
49*0b57cec5SDimitry Andric case TargetOpcode::EH_LABEL:
50*0b57cec5SDimitry Andric case TargetOpcode::GC_LABEL:
51*0b57cec5SDimitry Andric case TargetOpcode::DBG_VALUE:
52*0b57cec5SDimitry Andric case TargetOpcode::DBG_LABEL:
53*0b57cec5SDimitry Andric return true;
54*0b57cec5SDimitry Andric }
55*0b57cec5SDimitry Andric }
56*0b57cec5SDimitry Andric
runOnMachineFunction(MachineFunction & MF)57*0b57cec5SDimitry Andric bool PatchableFunction::runOnMachineFunction(MachineFunction &MF) {
58*0b57cec5SDimitry Andric if (MF.getFunction().hasFnAttribute("patchable-function-entry")) {
59*0b57cec5SDimitry Andric MachineBasicBlock &FirstMBB = *MF.begin();
60*0b57cec5SDimitry Andric const TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo();
61*0b57cec5SDimitry Andric // The initial .loc covers PATCHABLE_FUNCTION_ENTER.
62*0b57cec5SDimitry Andric BuildMI(FirstMBB, FirstMBB.begin(), DebugLoc(),
63*0b57cec5SDimitry Andric TII->get(TargetOpcode::PATCHABLE_FUNCTION_ENTER));
64*0b57cec5SDimitry Andric return true;
65*0b57cec5SDimitry Andric }
66*0b57cec5SDimitry Andric
67*0b57cec5SDimitry Andric if (!MF.getFunction().hasFnAttribute("patchable-function"))
68*0b57cec5SDimitry Andric return false;
69*0b57cec5SDimitry Andric
70*0b57cec5SDimitry Andric #ifndef NDEBUG
71*0b57cec5SDimitry Andric Attribute PatchAttr = MF.getFunction().getFnAttribute("patchable-function");
72*0b57cec5SDimitry Andric StringRef PatchType = PatchAttr.getValueAsString();
73*0b57cec5SDimitry Andric assert(PatchType == "prologue-short-redirect" && "Only possibility today!");
74*0b57cec5SDimitry Andric #endif
75*0b57cec5SDimitry Andric
76*0b57cec5SDimitry Andric auto &FirstMBB = *MF.begin();
77*0b57cec5SDimitry Andric MachineBasicBlock::iterator FirstActualI = FirstMBB.begin();
78*0b57cec5SDimitry Andric for (; doesNotGeneratecode(*FirstActualI); ++FirstActualI)
79*0b57cec5SDimitry Andric assert(FirstActualI != FirstMBB.end());
80*0b57cec5SDimitry Andric
81*0b57cec5SDimitry Andric auto *TII = MF.getSubtarget().getInstrInfo();
82*0b57cec5SDimitry Andric auto MIB = BuildMI(FirstMBB, FirstActualI, FirstActualI->getDebugLoc(),
83*0b57cec5SDimitry Andric TII->get(TargetOpcode::PATCHABLE_OP))
84*0b57cec5SDimitry Andric .addImm(2)
85*0b57cec5SDimitry Andric .addImm(FirstActualI->getOpcode());
86*0b57cec5SDimitry Andric
87*0b57cec5SDimitry Andric for (auto &MO : FirstActualI->operands())
88*0b57cec5SDimitry Andric MIB.add(MO);
89
90 FirstActualI->eraseFromParent();
91 MF.ensureAlignment(Align(16));
92 return true;
93 }
94
95 char PatchableFunction::ID = 0;
96 char &llvm::PatchableFunctionID = PatchableFunction::ID;
97 INITIALIZE_PASS(PatchableFunction, "patchable-function",
98 "Implement the 'patchable-function' attribute", false, false)
99