1 //===-- WebAssemblyAddMissingPrototypes.cpp - Fix prototypeless functions -===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
11 /// Add prototypes to prototypes-less functions.
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.
20 //===----------------------------------------------------------------------===//
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/Transforms/Utils/ModuleUtils.h"
28 #include "llvm/Transforms/Utils/Local.h"
29 #include "llvm/Pass.h"
30 #include "llvm/Support/Debug.h"
33 #define DEBUG_TYPE "wasm-add-missing-prototypes"
36 class WebAssemblyAddMissingPrototypes final : public ModulePass {
37 StringRef getPassName() const override {
38 return "Add prototypes to prototypes-less functions";
41 void getAnalysisUsage(AnalysisUsage &AU) const override {
43 ModulePass::getAnalysisUsage(AU);
46 bool runOnModule(Module &M) override;
50 WebAssemblyAddMissingPrototypes() : ModulePass(ID) {}
52 } // End anonymous namespace
54 char WebAssemblyAddMissingPrototypes::ID = 0;
55 INITIALIZE_PASS(WebAssemblyAddMissingPrototypes, DEBUG_TYPE,
56 "Add prototypes to prototypes-less functions", false, false)
58 ModulePass *llvm::createWebAssemblyAddMissingPrototypes() {
59 return new WebAssemblyAddMissingPrototypes();
62 bool WebAssemblyAddMissingPrototypes::runOnModule(Module &M) {
63 LLVM_DEBUG(dbgs() << "runnning AddMissingPrototypes\n");
65 std::vector<std::pair<Function*, Function*>> Replacements;
67 // Find all the prototype-less function declarations
68 for (Function &F : M) {
69 if (!F.isDeclaration() || !F.hasFnAttribute("no-prototype"))
72 LLVM_DEBUG(dbgs() << "Found no-prototype function: " << F.getName() << "\n");
74 // When clang emits prototype-less C functions it uses (...), i.e. varargs
75 // function that take no arguments (have no sentinel). When we see a
76 // no-prototype attribute we expect the function have these properties.
79 "Functions with 'no-prototype' attribute must take varargs: " +
81 if (F.getFunctionType()->getNumParams() != 0)
83 "Functions with 'no-prototype' attribute should not have params: " +
87 // Create a function prototype based on the first call site (first bitcast)
89 FunctionType *NewType = nullptr;
90 Function* NewF = nullptr;
91 for (Use &U : F.uses()) {
92 LLVM_DEBUG(dbgs() << "prototype-less use: " << F.getName() << "\n");
93 if (BitCastOperator *BC = dyn_cast<BitCastOperator>(U.getUser())) {
94 FunctionType *DestType =
95 cast<FunctionType>(BC->getDestTy()->getPointerElementType());
97 // Create a new function with the correct type
99 NewF = Function::Create(NewType, F.getLinkage(), F.getName());
100 NewF->setAttributes(F.getAttributes());
101 NewF->removeFnAttr("no-prototype");
108 dbgs() << "could not derive a function prototype from usage: " +
113 for (Use &U : F.uses()) {
114 if (BitCastOperator *BC = dyn_cast<BitCastOperator>(U.getUser())) {
115 FunctionType *DestType =
116 cast<FunctionType>(BC->getDestTy()->getPointerElementType());
117 if (NewType != DestType) {
119 "Prototypeless function used with conflicting signatures: " +
122 BC->replaceAllUsesWith(NewF);
123 Replacements.emplace_back(&F, NewF);
125 dbgs() << *U.getUser()->getType() << "\n";
130 "unexpected use of prototypeless function: " + F.getName() + "\n");
135 // Finally replace the old function declarations with the new ones
136 for (auto &Pair : Replacements) {
137 Function* Old = Pair.first;
138 Function* New = Pair.second;
139 Old->eraseFromParent();
140 M.getFunctionList().push_back(New);
143 return !Replacements.empty();