Coverage Report

Created: 2019-07-24 05:18

/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/lib/CodeGen/XRayInstrumentation.cpp
Line
Count
Source (jump to first uncovered line)
1
//===- XRayInstrumentation.cpp - Adds XRay instrumentation to functions. --===//
2
//
3
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4
// See https://llvm.org/LICENSE.txt for license information.
5
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6
//
7
//===----------------------------------------------------------------------===//
8
//
9
// This file implements a MachineFunctionPass that inserts the appropriate
10
// XRay instrumentation instructions. We look for XRay-specific attributes
11
// on the function to determine whether we should insert the replacement
12
// operations.
13
//
14
//===---------------------------------------------------------------------===//
15
16
#include "llvm/ADT/STLExtras.h"
17
#include "llvm/ADT/SmallVector.h"
18
#include "llvm/ADT/Triple.h"
19
#include "llvm/CodeGen/MachineBasicBlock.h"
20
#include "llvm/CodeGen/MachineDominators.h"
21
#include "llvm/CodeGen/MachineFunction.h"
22
#include "llvm/CodeGen/MachineFunctionPass.h"
23
#include "llvm/CodeGen/MachineInstrBuilder.h"
24
#include "llvm/CodeGen/MachineLoopInfo.h"
25
#include "llvm/CodeGen/TargetInstrInfo.h"
26
#include "llvm/CodeGen/TargetSubtargetInfo.h"
27
#include "llvm/IR/Attributes.h"
28
#include "llvm/IR/Function.h"
29
#include "llvm/Pass.h"
30
#include "llvm/Target/TargetMachine.h"
31
32
using namespace llvm;
33
34
namespace {
35
36
struct InstrumentationOptions {
37
  // Whether to emit PATCHABLE_TAIL_CALL.
38
  bool HandleTailcall;
39
40
  // Whether to emit PATCHABLE_RET/PATCHABLE_FUNCTION_EXIT for all forms of
41
  // return, e.g. conditional return.
42
  bool HandleAllReturns;
43
};
44
45
struct XRayInstrumentation : public MachineFunctionPass {
46
  static char ID;
47
48
36.3k
  XRayInstrumentation() : MachineFunctionPass(ID) {
49
36.3k
    initializeXRayInstrumentationPass(*PassRegistry::getPassRegistry());
50
36.3k
  }
51
52
36.0k
  void getAnalysisUsage(AnalysisUsage &AU) const override {
53
36.0k
    AU.setPreservesCFG();
54
36.0k
    AU.addPreserved<MachineLoopInfo>();
55
36.0k
    AU.addPreserved<MachineDominatorTree>();
56
36.0k
    MachineFunctionPass::getAnalysisUsage(AU);
57
36.0k
  }
58
59
  bool runOnMachineFunction(MachineFunction &MF) override;
60
61
private:
62
  // Replace the original RET instruction with the exit sled code ("patchable
63
  //   ret" pseudo-instruction), so that at runtime XRay can replace the sled
64
  //   with a code jumping to XRay trampoline, which calls the tracing handler
65
  //   and, in the end, issues the RET instruction.
66
  // This is the approach to go on CPUs which have a single RET instruction,
67
  //   like x86/x86_64.
68
  void replaceRetWithPatchableRet(MachineFunction &MF,
69
                                  const TargetInstrInfo *TII,
70
                                  InstrumentationOptions);
71
72
  // Prepend the original return instruction with the exit sled code ("patchable
73
  //   function exit" pseudo-instruction), preserving the original return
74
  //   instruction just after the exit sled code.
75
  // This is the approach to go on CPUs which have multiple options for the
76
  //   return instruction, like ARM. For such CPUs we can't just jump into the
77
  //   XRay trampoline and issue a single return instruction there. We rather
78
  //   have to call the trampoline and return from it to the original return
79
  //   instruction of the function being instrumented.
80
  void prependRetWithPatchableExit(MachineFunction &MF,
81
                                   const TargetInstrInfo *TII,
82
                                   InstrumentationOptions);
83
};
84
85
} // end anonymous namespace
86
87
void XRayInstrumentation::replaceRetWithPatchableRet(
88
    MachineFunction &MF, const TargetInstrInfo *TII,
89
36
    InstrumentationOptions op) {
90
36
  // We look for *all* terminators and returns, then replace those with
91
36
  // PATCHABLE_RET instructions.
92
36
  SmallVector<MachineInstr *, 4> Terminators;
93
56
  for (auto &MBB : MF) {
94
56
    for (auto &T : MBB.terminators()) {
95
54
      unsigned Opc = 0;
96
54
      if (T.isReturn() &&
97
54
          
(41
op.HandleAllReturns41
||
T.getOpcode() == TII->getReturnOpcode()30
)) {
98
37
        // Replace return instructions with:
99
37
        //   PATCHABLE_RET <Opcode>, <Operand>...
100
37
        Opc = TargetOpcode::PATCHABLE_RET;
101
37
      }
102
54
      if (TII->isTailCall(T) && 
op.HandleTailcall6
) {
103
4
        // Treat the tail call as a return instruction, which has a
104
4
        // different-looking sled than the normal return case.
105
4
        Opc = TargetOpcode::PATCHABLE_TAIL_CALL;
106
4
      }
107
54
      if (Opc != 0) {
108
41
        auto MIB = BuildMI(MBB, T, T.getDebugLoc(), TII->get(Opc))
109
41
                       .addImm(T.getOpcode());
110
41
        for (auto &MO : T.operands())
111
83
          MIB.add(MO);
112
41
        Terminators.push_back(&T);
113
41
        if (T.isCall())
114
6
          MF.updateCallSiteInfo(&T);
115
41
      }
116
54
    }
117
56
  }
118
36
119
36
  for (auto &I : Terminators)
120
41
    I->eraseFromParent();
121
36
}
122
123
void XRayInstrumentation::prependRetWithPatchableExit(
124
    MachineFunction &MF, const TargetInstrInfo *TII,
125
35
    InstrumentationOptions op) {
126
35
  for (auto &MBB : MF)
127
43
    for (auto &T : MBB.terminators()) {
128
43
      unsigned Opc = 0;
129
43
      if (T.isReturn() &&
130
43
          
(39
op.HandleAllReturns39
||
T.getOpcode() == TII->getReturnOpcode()0
)) {
131
39
        Opc = TargetOpcode::PATCHABLE_FUNCTION_EXIT;
132
39
      }
133
43
      if (TII->isTailCall(T) && 
op.HandleTailcall3
) {
134
0
        Opc = TargetOpcode::PATCHABLE_TAIL_CALL;
135
0
      }
136
43
      if (Opc != 0) {
137
39
        // Prepend the return instruction with PATCHABLE_FUNCTION_EXIT or
138
39
        //   PATCHABLE_TAIL_CALL .
139
39
        BuildMI(MBB, T, T.getDebugLoc(), TII->get(Opc));
140
39
      }
141
43
    }
142
35
}
143
144
498k
bool XRayInstrumentation::runOnMachineFunction(MachineFunction &MF) {
145
498k
  auto &F = MF.getFunction();
146
498k
  auto InstrAttr = F.getFnAttribute("function-instrument");
147
498k
  bool AlwaysInstrument = !InstrAttr.hasAttribute(Attribute::None) &&
148
498k
                          
InstrAttr.isStringAttribute()308
&&
149
498k
                          
InstrAttr.getValueAsString() == "xray-always"308
;
150
498k
  Attribute Attr = F.getFnAttribute("xray-instruction-threshold");
151
498k
  unsigned XRayThreshold = 0;
152
498k
  if (!AlwaysInstrument) {
153
498k
    if (Attr.hasAttribute(Attribute::None) || 
!Attr.isStringAttribute()8
)
154
498k
      return false; // XRay threshold attribute not found.
155
5
    if (Attr.getValueAsString().getAsInteger(10, XRayThreshold))
156
0
      return false; // Invalid value for threshold.
157
5
158
5
    // Count the number of MachineInstr`s in MachineFunction
159
5
    int64_t MICount = 0;
160
5
    for (const auto &MBB : MF)
161
14
      MICount += MBB.size();
162
5
163
5
    // Get MachineDominatorTree or compute it on the fly if it's unavailable
164
5
    auto *MDT = getAnalysisIfAvailable<MachineDominatorTree>();
165
5
    MachineDominatorTree ComputedMDT;
166
8
    if (
!MDT5
) {
167
8
      ComputedMDT.getBase().recalculate(MF);
168
8
      MDT = &ComputedMDT;
169
8
    }
170
5
171
5
    // Get MachineLoopInfo or compute it on the fly if it's unavailable
172
5
    auto *MLI = getAnalysisIfAvailable<MachineLoopInfo>();
173
5
    MachineLoopInfo ComputedMLI;
174
8
    if (
!MLI5
) {
175
8
      ComputedMLI.getBase().analyze(MDT->getBase());
176
8
      MLI = &ComputedMLI;
177
8
    }
178
5
179
5
    // Check if we have a loop.
180
5
    // FIXME: Maybe make this smarter, and see whether the loops are dependent
181
5
    // on inputs or side-effects?
182
5
    if (MLI->empty() && 
MICount < XRayThreshold4
)
183
3
      return false; // Function is too small and has no loops.
184
68
  }
185
68
186
68
  // We look for the first non-empty MachineBasicBlock, so that we can insert
187
68
  // the function instrumentation in the appropriate place.
188
68
  auto MBI = llvm::find_if(
189
71
      MF, [&](const MachineBasicBlock &MBB) { return !MBB.empty(); });
190
68
  if (MBI == MF.end())
191
0
    return false; // The function is empty.
192
68
193
68
  auto *TII = MF.getSubtarget().getInstrInfo();
194
68
  auto &FirstMBB = *MBI;
195
68
  auto &FirstMI = *FirstMBB.begin();
196
68
197
68
  if (!MF.getSubtarget().isXRaySupported()) {
198
0
    FirstMI.emitError("An attempt to perform XRay instrumentation for an"
199
0
                      " unsupported target.");
200
0
    return false;
201
0
  }
202
68
203
68
  // First, insert an PATCHABLE_FUNCTION_ENTER as the first instruction of the
204
68
  // MachineFunction.
205
68
  BuildMI(FirstMBB, FirstMI, FirstMI.getDebugLoc(),
206
68
          TII->get(TargetOpcode::PATCHABLE_FUNCTION_ENTER));
207
68
208
68
  switch (MF.getTarget().getTargetTriple().getArch()) {
209
68
  case Triple::ArchType::arm:
210
35
  case Triple::ArchType::thumb:
211
35
  case Triple::ArchType::aarch64:
212
35
  case Triple::ArchType::mips:
213
35
  case Triple::ArchType::mipsel:
214
35
  case Triple::ArchType::mips64:
215
35
  case Triple::ArchType::mips64el: {
216
35
    // For the architectures which don't have a single return instruction
217
35
    InstrumentationOptions op;
218
35
    op.HandleTailcall = false;
219
35
    op.HandleAllReturns = true;
220
35
    prependRetWithPatchableExit(MF, TII, op);
221
35
    break;
222
35
  }
223
35
  case Triple::ArchType::ppc64le: {
224
8
    // PPC has conditional returns. Turn them into branch and plain returns.
225
8
    InstrumentationOptions op;
226
8
    op.HandleTailcall = false;
227
8
    op.HandleAllReturns = true;
228
8
    replaceRetWithPatchableRet(MF, TII, op);
229
8
    break;
230
35
  }
231
35
  default: {
232
28
    // For the architectures that have a single return instruction (such as
233
28
    //   RETQ on x86_64).
234
28
    InstrumentationOptions op;
235
28
    op.HandleTailcall = true;
236
28
    op.HandleAllReturns = false;
237
28
    replaceRetWithPatchableRet(MF, TII, op);
238
28
    break;
239
71
  }
240
71
  }
241
71
  return true;
242
71
}
243
244
char XRayInstrumentation::ID = 0;
245
char &llvm::XRayInstrumentationID = XRayInstrumentation::ID;
246
42.3k
INITIALIZE_PASS_BEGIN(XRayInstrumentation, "xray-instrumentation",
247
42.3k
                      "Insert XRay ops", false, false)
248
42.3k
INITIALIZE_PASS_DEPENDENCY(MachineLoopInfo)
249
42.3k
INITIALIZE_PASS_END(XRayInstrumentation, "xray-instrumentation",
250
                    "Insert XRay ops", false, false)