Line data Source code
1 : //===-- WebAssemblyAddMissingPrototypes.cpp - Fix prototypeless functions -===//
2 : //
3 : // The LLVM Compiler Infrastructure
4 : //
5 : // This file is distributed under the University of Illinois Open Source
6 : // License. See LICENSE.TXT for details.
7 : //
8 : //===----------------------------------------------------------------------===//
9 : ///
10 : /// \file
11 : /// Add prototypes to prototypes-less functions.
12 : ///
13 : /// WebAssembly has strict function prototype checking so we need functions
14 : /// declarations to match the call sites. Clang treats prototype-less functions
15 : /// as varargs (foo(...)) which happens to work on existing platforms but
16 : /// doesn't under WebAssembly. This pass will find all the call sites of each
17 : /// prototype-less function, ensure they agree, and then set the signature
18 : /// on the function declaration accordingly.
19 : ///
20 : //===----------------------------------------------------------------------===//
21 :
22 : #include "WebAssembly.h"
23 : #include "llvm/IR/Constants.h"
24 : #include "llvm/IR/IRBuilder.h"
25 : #include "llvm/IR/Module.h"
26 : #include "llvm/IR/Operator.h"
27 : #include "llvm/Pass.h"
28 : #include "llvm/Support/Debug.h"
29 : #include "llvm/Transforms/Utils/Local.h"
30 : #include "llvm/Transforms/Utils/ModuleUtils.h"
31 : using namespace llvm;
32 :
33 : #define DEBUG_TYPE "wasm-add-missing-prototypes"
34 :
35 : namespace {
36 : class WebAssemblyAddMissingPrototypes final : public ModulePass {
37 0 : StringRef getPassName() const override {
38 0 : return "Add prototypes to prototypes-less functions";
39 : }
40 :
41 306 : void getAnalysisUsage(AnalysisUsage &AU) const override {
42 306 : AU.setPreservesCFG();
43 306 : ModulePass::getAnalysisUsage(AU);
44 306 : }
45 :
46 : bool runOnModule(Module &M) override;
47 :
48 : public:
49 : static char ID;
50 306 : WebAssemblyAddMissingPrototypes() : ModulePass(ID) {}
51 : };
52 : } // End anonymous namespace
53 :
54 : char WebAssemblyAddMissingPrototypes::ID = 0;
55 199030 : INITIALIZE_PASS(WebAssemblyAddMissingPrototypes, DEBUG_TYPE,
56 : "Add prototypes to prototypes-less functions", false, false)
57 :
58 305 : ModulePass *llvm::createWebAssemblyAddMissingPrototypes() {
59 305 : return new WebAssemblyAddMissingPrototypes();
60 : }
61 :
62 307 : bool WebAssemblyAddMissingPrototypes::runOnModule(Module &M) {
63 : LLVM_DEBUG(dbgs() << "runnning AddMissingPrototypes\n");
64 :
65 : std::vector<std::pair<Function *, Function *>> Replacements;
66 :
67 : // Find all the prototype-less function declarations
68 4013 : for (Function &F : M) {
69 4196 : if (!F.isDeclaration() || !F.hasFnAttribute("no-prototype"))
70 3705 : continue;
71 :
72 : LLVM_DEBUG(dbgs() << "Found no-prototype function: " << F.getName()
73 : << "\n");
74 :
75 : // When clang emits prototype-less C functions it uses (...), i.e. varargs
76 : // function that take no arguments (have no sentinel). When we see a
77 : // no-prototype attribute we expect the function have these properties.
78 1 : if (!F.isVarArg())
79 0 : report_fatal_error(
80 : "Functions with 'no-prototype' attribute must take varargs: " +
81 0 : F.getName());
82 1 : if (F.getFunctionType()->getNumParams() != 0)
83 0 : report_fatal_error(
84 : "Functions with 'no-prototype' attribute should not have params: " +
85 0 : F.getName());
86 :
87 : // Create a function prototype based on the first call site (first bitcast)
88 : // that we find.
89 : FunctionType *NewType = nullptr;
90 1 : Function *NewF = nullptr;
91 1 : for (Use &U : F.uses()) {
92 : LLVM_DEBUG(dbgs() << "prototype-less use: " << F.getName() << "\n");
93 1 : if (BitCastOperator *BC = dyn_cast<BitCastOperator>(U.getUser())) {
94 : FunctionType *DestType =
95 1 : cast<FunctionType>(BC->getDestTy()->getPointerElementType());
96 :
97 : // Create a new function with the correct type
98 : NewType = DestType;
99 2 : NewF = Function::Create(NewType, F.getLinkage(), F.getName());
100 : NewF->setAttributes(F.getAttributes());
101 1 : NewF->removeFnAttr("no-prototype");
102 1 : break;
103 : }
104 : }
105 :
106 1 : if (!NewType) {
107 : LLVM_DEBUG(
108 : dbgs() << "could not derive a function prototype from usage: " +
109 : F.getName() + "\n");
110 : continue;
111 : }
112 :
113 2 : for (Use &U : F.uses()) {
114 1 : if (BitCastOperator *BC = dyn_cast<BitCastOperator>(U.getUser())) {
115 : FunctionType *DestType =
116 1 : cast<FunctionType>(BC->getDestTy()->getPointerElementType());
117 1 : if (NewType != DestType) {
118 0 : report_fatal_error(
119 : "Prototypeless function used with conflicting signatures: " +
120 0 : F.getName());
121 : }
122 1 : BC->replaceAllUsesWith(NewF);
123 1 : Replacements.emplace_back(&F, NewF);
124 : } else {
125 0 : dbgs() << *U.getUser()->getType() << "\n";
126 : #ifndef NDEBUG
127 : U.getUser()->dump();
128 : #endif
129 0 : report_fatal_error(
130 0 : "unexpected use of prototypeless function: " + F.getName() + "\n");
131 : }
132 : }
133 : }
134 :
135 : // Finally replace the old function declarations with the new ones
136 308 : for (auto &Pair : Replacements) {
137 1 : Function *Old = Pair.first;
138 1 : Function *New = Pair.second;
139 1 : Old->eraseFromParent();
140 1 : M.getFunctionList().push_back(New);
141 : }
142 :
143 307 : return !Replacements.empty();
144 : }
|