Coverage Report

Created: 2019-07-24 05:18

/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/lib/Transforms/Utils/CtorUtils.cpp
Line
Count
Source (jump to first uncovered line)
1
//===- CtorUtils.cpp - Helpers for working with global_ctors ----*- 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
// This file defines functions that are used to process llvm.global_ctors.
10
//
11
//===----------------------------------------------------------------------===//
12
13
#include "llvm/Transforms/Utils/CtorUtils.h"
14
#include "llvm/ADT/BitVector.h"
15
#include "llvm/IR/Constants.h"
16
#include "llvm/IR/Function.h"
17
#include "llvm/IR/GlobalVariable.h"
18
#include "llvm/IR/Module.h"
19
#include "llvm/Support/Debug.h"
20
#include "llvm/Support/raw_ostream.h"
21
22
#define DEBUG_TYPE "ctor_utils"
23
24
using namespace llvm;
25
26
/// Given a specified llvm.global_ctors list, remove the listed elements.
27
81
static void removeGlobalCtors(GlobalVariable *GCL, const BitVector &CtorsToRemove) {
28
81
  // Filter out the initializer elements to remove.
29
81
  ConstantArray *OldCA = cast<ConstantArray>(GCL->getInitializer());
30
81
  SmallVector<Constant *, 10> CAList;
31
185
  for (unsigned I = 0, E = OldCA->getNumOperands(); I < E; 
++I104
)
32
104
    if (!CtorsToRemove.test(I))
33
7
      CAList.push_back(OldCA->getOperand(I));
34
81
35
81
  // Create the new array initializer.
36
81
  ArrayType *ATy =
37
81
      ArrayType::get(OldCA->getType()->getElementType(), CAList.size());
38
81
  Constant *CA = ConstantArray::get(ATy, CAList);
39
81
40
81
  // If we didn't change the number of elements, don't create a new GV.
41
81
  if (CA->getType() == OldCA->getType()) {
42
0
    GCL->setInitializer(CA);
43
0
    return;
44
0
  }
45
81
46
81
  // Create the new global and insert it next to the existing list.
47
81
  GlobalVariable *NGV =
48
81
      new GlobalVariable(CA->getType(), GCL->isConstant(), GCL->getLinkage(),
49
81
                         CA, "", GCL->getThreadLocalMode());
50
81
  GCL->getParent()->getGlobalList().insert(GCL->getIterator(), NGV);
51
81
  NGV->takeName(GCL);
52
81
53
81
  // Nuke the old list, replacing any uses with the new one.
54
81
  if (!GCL->use_empty()) {
55
1
    Constant *V = NGV;
56
1
    if (V->getType() != GCL->getType())
57
1
      V = ConstantExpr::getBitCast(V, GCL->getType());
58
1
    GCL->replaceAllUsesWith(V);
59
1
  }
60
81
  GCL->eraseFromParent();
61
81
}
62
63
/// Given a llvm.global_ctors list that we can understand,
64
/// return a list of the functions and null terminator as a vector.
65
1.81k
static std::vector<Function *> parseGlobalCtors(GlobalVariable *GV) {
66
1.81k
  if (GV->getInitializer()->isNullValue())
67
445
    return std::vector<Function *>();
68
1.37k
  ConstantArray *CA = cast<ConstantArray>(GV->getInitializer());
69
1.37k
  std::vector<Function *> Result;
70
1.37k
  Result.reserve(CA->getNumOperands());
71
1.47k
  for (auto &V : CA->operands()) {
72
1.47k
    ConstantStruct *CS = cast<ConstantStruct>(V);
73
1.47k
    Result.push_back(dyn_cast<Function>(CS->getOperand(1)));
74
1.47k
  }
75
1.37k
  return Result;
76
1.37k
}
77
78
/// Find the llvm.global_ctors list, verifying that all initializers have an
79
/// init priority of 65535.
80
72.2k
static GlobalVariable *findGlobalCtors(Module &M) {
81
72.2k
  GlobalVariable *GV = M.getGlobalVariable("llvm.global_ctors");
82
72.2k
  if (!GV)
83
70.2k
    return nullptr;
84
1.97k
85
1.97k
  // Verify that the initializer is simple enough for us to handle. We are
86
1.97k
  // only allowed to optimize the initializer if it is unique.
87
1.97k
  if (!GV->hasUniqueInitializer())
88
0
    return nullptr;
89
1.97k
90
1.97k
  if (isa<ConstantAggregateZero>(GV->getInitializer()))
91
445
    return GV;
92
1.53k
  ConstantArray *CA = cast<ConstantArray>(GV->getInitializer());
93
1.53k
94
1.65k
  for (auto &V : CA->operands()) {
95
1.65k
    if (isa<ConstantAggregateZero>(V))
96
0
      continue;
97
1.65k
    ConstantStruct *CS = cast<ConstantStruct>(V);
98
1.65k
    if (isa<ConstantPointerNull>(CS->getOperand(1)))
99
4
      continue;
100
1.64k
101
1.64k
    // Must have a function or null ptr.
102
1.64k
    if (!isa<Function>(CS->getOperand(1)))
103
36
      return nullptr;
104
1.61k
105
1.61k
    // Init priority must be standard.
106
1.61k
    ConstantInt *CI = cast<ConstantInt>(CS->getOperand(0));
107
1.61k
    if (CI->getZExtValue() != 65535)
108
125
      return nullptr;
109
1.61k
  }
110
1.53k
111
1.53k
  
return GV1.37k
;
112
1.53k
}
113
114
/// Call "ShouldRemove" for every entry in M's global_ctor list and remove the
115
/// entries for which it returns true.  Return true if anything changed.
116
bool llvm::optimizeGlobalCtorsList(
117
72.2k
    Module &M, function_ref<bool(Function *)> ShouldRemove) {
118
72.2k
  GlobalVariable *GlobalCtors = findGlobalCtors(M);
119
72.2k
  if (!GlobalCtors)
120
70.3k
    return false;
121
1.81k
122
1.81k
  std::vector<Function *> Ctors = parseGlobalCtors(GlobalCtors);
123
1.81k
  if (Ctors.empty())
124
445
    return false;
125
1.37k
126
1.37k
  bool MadeChange = false;
127
1.37k
128
1.37k
  // Loop over global ctors, optimizing them when we can.
129
1.37k
  unsigned NumCtors = Ctors.size();
130
1.37k
  BitVector CtorsToRemove(NumCtors);
131
2.85k
  for (unsigned i = 0; i != Ctors.size() && 
NumCtors > 01.47k
;
++i1.47k
) {
132
1.47k
    Function *F = Ctors[i];
133
1.47k
    // Found a null terminator in the middle of the list, prune off the rest of
134
1.47k
    // the list.
135
1.47k
    if (!F)
136
4
      continue;
137
1.47k
138
1.47k
    LLVM_DEBUG(dbgs() << "Optimizing Global Constructor: " << *F << "\n");
139
1.47k
140
1.47k
    // We cannot simplify external ctor functions.
141
1.47k
    if (F->empty())
142
39
      continue;
143
1.43k
144
1.43k
    // If we can evaluate the ctor at compile time, do.
145
1.43k
    if (ShouldRemove(F)) {
146
97
      Ctors[i] = nullptr;
147
97
      CtorsToRemove.set(i);
148
97
      NumCtors--;
149
97
      MadeChange = true;
150
97
      continue;
151
97
    }
152
1.43k
  }
153
1.37k
154
1.37k
  if (!MadeChange)
155
1.29k
    return false;
156
80
157
80
  removeGlobalCtors(GlobalCtors, CtorsToRemove);
158
80
  return true;
159
80
}