Coverage Report

Created: 2019-07-24 05:18

/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/lib/Target/WebAssembly/WebAssemblyAddMissingPrototypes.cpp
Line
Count
Source (jump to first uncovered line)
1
//===-- WebAssemblyAddMissingPrototypes.cpp - Fix prototypeless 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
/// \file
10
/// Add prototypes to prototypes-less functions.
11
///
12
/// WebAssembly has strict function prototype checking so we need functions
13
/// declarations to match the call sites.  Clang treats prototype-less functions
14
/// as varargs (foo(...)) which happens to work on existing platforms but
15
/// doesn't under WebAssembly.  This pass will find all the call sites of each
16
/// prototype-less function, ensure they agree, and then set the signature
17
/// on the function declaration accordingly.
18
///
19
//===----------------------------------------------------------------------===//
20
21
#include "WebAssembly.h"
22
#include "llvm/IR/Constants.h"
23
#include "llvm/IR/IRBuilder.h"
24
#include "llvm/IR/Module.h"
25
#include "llvm/IR/Operator.h"
26
#include "llvm/Pass.h"
27
#include "llvm/Support/Debug.h"
28
#include "llvm/Transforms/Utils/Local.h"
29
#include "llvm/Transforms/Utils/ModuleUtils.h"
30
using namespace llvm;
31
32
#define DEBUG_TYPE "wasm-add-missing-prototypes"
33
34
namespace {
35
class WebAssemblyAddMissingPrototypes final : public ModulePass {
36
0
  StringRef getPassName() const override {
37
0
    return "Add prototypes to prototypes-less functions";
38
0
  }
39
40
428
  void getAnalysisUsage(AnalysisUsage &AU) const override {
41
428
    AU.setPreservesCFG();
42
428
    ModulePass::getAnalysisUsage(AU);
43
428
  }
44
45
  bool runOnModule(Module &M) override;
46
47
public:
48
  static char ID;
49
428
  WebAssemblyAddMissingPrototypes() : ModulePass(ID) {}
50
};
51
} // End anonymous namespace
52
53
char WebAssemblyAddMissingPrototypes::ID = 0;
54
INITIALIZE_PASS(WebAssemblyAddMissingPrototypes, DEBUG_TYPE,
55
                "Add prototypes to prototypes-less functions", false, false)
56
57
426
ModulePass *llvm::createWebAssemblyAddMissingPrototypes() {
58
426
  return new WebAssemblyAddMissingPrototypes();
59
426
}
60
61
428
bool WebAssemblyAddMissingPrototypes::runOnModule(Module &M) {
62
428
  LLVM_DEBUG(dbgs() << "********** Add Missing Prototypes **********\n");
63
428
64
428
  std::vector<std::pair<Function *, Function *>> Replacements;
65
428
66
428
  // Find all the prototype-less function declarations
67
5.18k
  for (Function &F : M) {
68
5.18k
    if (!F.isDeclaration() || 
!F.hasFnAttribute("no-prototype")724
)
69
5.18k
      continue;
70
4
71
4
    LLVM_DEBUG(dbgs() << "Found no-prototype function: " << F.getName()
72
4
                      << "\n");
73
4
74
4
    // When clang emits prototype-less C functions it uses (...), i.e. varargs
75
4
    // function that take no arguments (have no sentinel).  When we see a
76
4
    // no-prototype attribute we expect the function have these properties.
77
4
    if (!F.isVarArg())
78
0
      report_fatal_error(
79
0
          "Functions with 'no-prototype' attribute must take varargs: " +
80
0
          F.getName());
81
4
    unsigned NumParams = F.getFunctionType()->getNumParams();
82
4
    if (NumParams != 0) {
83
1
      if (!(NumParams == 1 && F.arg_begin()->hasStructRetAttr()))
84
0
        report_fatal_error("Functions with 'no-prototype' attribute should "
85
0
                           "not have params: " +
86
0
                           F.getName());
87
4
    }
88
4
89
4
    // Create a function prototype based on the first call site (first bitcast)
90
4
    // that we find.
91
4
    FunctionType *NewType = nullptr;
92
9
    for (Use &U : F.uses()) {
93
9
      LLVM_DEBUG(dbgs() << "prototype-less use: " << F.getName() << "\n");
94
9
      LLVM_DEBUG(dbgs() << *U.getUser() << "\n");
95
9
      if (auto *BC = dyn_cast<BitCastOperator>(U.getUser())) {
96
7
        if (auto *DestType = dyn_cast<FunctionType>(
97
5
                BC->getDestTy()->getPointerElementType())) {
98
5
          if (!NewType) {
99
3
            // Create a new function with the correct type
100
3
            NewType = DestType;
101
3
            LLVM_DEBUG(dbgs() << "found function type: " << *NewType << "\n");
102
3
          } else 
if (2
NewType != DestType2
) {
103
1
            errs() << "warning: prototype-less function used with "
104
1
                      "conflicting signatures: "
105
1
                   << F.getName() << "\n";
106
1
            LLVM_DEBUG(dbgs() << "  " << *DestType << "\n");
107
1
            LLVM_DEBUG(dbgs() << "  "<<  *NewType << "\n");
108
1
          }
109
5
        }
110
7
      }
111
9
    }
112
4
113
4
    if (!NewType) {
114
1
      LLVM_DEBUG(
115
1
          dbgs() << "could not derive a function prototype from usage: " +
116
1
                        F.getName() + "\n");
117
1
      // We could not derive a type for this function.  In this case strip
118
1
      // the isVarArg and make it a simple zero-arg function.  This has more
119
1
      // chance of being correct.  The current signature of (...) is illegal in
120
1
      // C since it doesn't have any arguments before the "...", we this at
121
1
      // least makes it possible for this symbol to be resolved by the linker.
122
1
      NewType = FunctionType::get(F.getFunctionType()->getReturnType(), false);
123
1
    }
124
4
125
4
    Function *NewF =
126
4
        Function::Create(NewType, F.getLinkage(), F.getName() + ".fixed_sig");
127
4
    NewF->setAttributes(F.getAttributes());
128
4
    NewF->removeFnAttr("no-prototype");
129
4
    Replacements.emplace_back(&F, NewF);
130
4
  }
131
428
132
428
  for (auto &Pair : Replacements) {
133
4
    Function *OldF = Pair.first;
134
4
    Function *NewF = Pair.second;
135
4
    std::string Name = OldF->getName();
136
4
    M.getFunctionList().push_back(NewF);
137
4
    OldF->replaceAllUsesWith(
138
4
        ConstantExpr::getPointerBitCastOrAddrSpaceCast(NewF, OldF->getType()));
139
4
    OldF->eraseFromParent();
140
4
    NewF->setName(Name);
141
4
  }
142
428
143
428
  return !Replacements.empty();
144
428
}