xref: /llvm-project/bolt/include/bolt/Passes/ValidateInternalCalls.h (revision a5f3d1a803020167bd9d494a8a3921e7dcc1550a)
1 //===- bolt/Passes/ValidateInternalCalls.h ----------------------*- C++ -*-===//
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 #ifndef BOLT_PASSES_VALIDATEINTERNALCALLS_H
10 #define BOLT_PASSES_VALIDATEINTERNALCALLS_H
11 
12 #include "bolt/Passes/BinaryPasses.h"
13 
14 namespace llvm {
15 namespace bolt {
16 
17 /// Post-processing for internal calls. What are those? They are call
18 /// instructions that do not transfer control to another function, but
19 /// rather branch to a basic block inside the caller function itself.
20 /// This pass checks that the internal calls observed in a function are
21 /// manageable. We support two types:
22 ///
23 ///   1. Position Independent Code (PIC) tricks: in this type of internal
24 ///      call, we don't really have a call because the return address is
25 ///      not utilized for branching to, but only as a base address to
26 ///      reference other objects. We call it a "trick" because this is not
27 ///      the standard way a compiler would do this and this will often come
28 ///      from awkwardly written assembly code.
29 ///
30 ///   2. Real internal calls: in this case, a function was inlined inside
31 ///      a caller, but the CALL instruction wasn't removed. This pair of
32 ///      caller-callee is treated as a single function and is analyzed
33 ///      here.
34 ///
35 /// In general, the rest of the BOLT pipeline (other optimizations, including
36 /// code reordering) will not support neither of these cases. In this pass,
37 /// we just identify them, verify they are safe (do not reference objects
38 /// that will be moved after reordering) and freeze these functions in the
39 /// way they were read. We do this by marking them as non-simple.
40 ///
41 /// Why do we freeze them?
42 ///
43 /// Type 1 is not safe to optimize because any changed offsets will break the
44 /// PIC references made in this code. Type 2 is not safe to optimize because
45 /// it requires BOLT to understand a new CFG format where internal calls are
46 /// broken into two BBs (calling block and returning block), and we currently do
47 /// not support this  elsewhere. Only this pass is able to make sense of these
48 /// non-canonical CFGs (specifically, fixBranches does not support them).
49 ///
50 class ValidateInternalCalls : public BinaryFunctionPass {
51 public:
ValidateInternalCalls(const cl::opt<bool> & PrintPass)52   explicit ValidateInternalCalls(const cl::opt<bool> &PrintPass)
53       : BinaryFunctionPass(PrintPass) {}
54 
getName()55   const char *getName() const override { return "validate-internal-calls"; }
56 
57   Error runOnFunctions(BinaryContext &BC) override;
58 
59 private:
60   /// Fix the CFG to take into consideration internal calls that do not
61   /// return, but are only used as a trick to perform Position Independent
62   /// Code (PIC) computations. This will change internal calls to be treated
63   /// as unconditional jumps.
64   void fixCFGForPIC(BinaryFunction &Function) const;
65 
66   /// Fix the CFG to take into consideration real internal calls (whole
67   /// functions that got inlined inside its caller, but the CALL instruction
68   /// wasn't removed).
69   bool fixCFGForIC(BinaryFunction &Function) const;
70 
71   /// Detect tail calls in the range of the PIC access and fail to validate if
72   /// one is detected. Tail calls are dangerous because they may be emitted
73   /// with a different size in comparison with the original code.
74   /// FIXME: shortenInstructions and NOP sizes can impact offsets too
75   bool hasTailCallsInRange(BinaryFunction &Function) const;
76 
77   /// Check that the PIC computations performed by Type 1 internal calls are
78   /// safe
79   bool analyzeFunction(BinaryFunction &Function) const;
80 
81   /// The annotation tag we use to keep track of internal calls we already
82   /// processed.
getProcessedICTag()83   StringRef getProcessedICTag() const { return "ProcessedInternalCall"; }
84 
clearAnnotations(BinaryFunction & Function)85   void clearAnnotations(BinaryFunction &Function) const {
86     const BinaryContext &BC = Function.getBinaryContext();
87     for (BinaryBasicBlock &BB : Function)
88       for (MCInst &Inst : BB)
89         BC.MIB->removeAnnotation(Inst, getProcessedICTag());
90   }
91 };
92 
93 } // namespace bolt
94 } // namespace llvm
95 
96 #endif
97