1 //===-- WebAssemblyAddMissingPrototypes.cpp - Fix prototypeless functions -===//
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
7 //===----------------------------------------------------------------------===//
10 /// Add prototypes to prototypes-less functions.
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.
19 //===----------------------------------------------------------------------===//
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"
32 #define DEBUG_TYPE "wasm-add-missing-prototypes"
35 class WebAssemblyAddMissingPrototypes final : public ModulePass {
36 StringRef getPassName() const override {
37 return "Add prototypes to prototypes-less functions";
40 void getAnalysisUsage(AnalysisUsage &AU) const override {
42 ModulePass::getAnalysisUsage(AU);
45 bool runOnModule(Module &M) override;
49 WebAssemblyAddMissingPrototypes() : ModulePass(ID) {}
51 } // End anonymous namespace
53 char WebAssemblyAddMissingPrototypes::ID = 0;
54 INITIALIZE_PASS(WebAssemblyAddMissingPrototypes, DEBUG_TYPE,
55 "Add prototypes to prototypes-less functions", false, false)
57 ModulePass *llvm::createWebAssemblyAddMissingPrototypes() {
58 return new WebAssemblyAddMissingPrototypes();
61 bool WebAssemblyAddMissingPrototypes::runOnModule(Module &M) {
62 LLVM_DEBUG(dbgs() << "********** Add Missing Prototypes **********\n");
64 std::vector<std::pair<Function *, Function *>> Replacements;
66 // Find all the prototype-less function declarations
67 for (Function &F : M) {
68 if (!F.isDeclaration() || !F.hasFnAttribute("no-prototype"))
71 LLVM_DEBUG(dbgs() << "Found no-prototype function: " << F.getName()
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 unsigned NumParams = F.getFunctionType()->getNumParams();
83 if (!(NumParams == 1 && F.arg_begin()->hasStructRetAttr()))
84 report_fatal_error("Functions with 'no-prototype' attribute should "
89 // Create a function prototype based on the first call site (first bitcast)
91 FunctionType *NewType = nullptr;
92 for (Use &U : F.uses()) {
93 LLVM_DEBUG(dbgs() << "prototype-less use: " << F.getName() << "\n");
94 LLVM_DEBUG(dbgs() << *U.getUser() << "\n");
95 if (auto *BC = dyn_cast<BitCastOperator>(U.getUser())) {
96 if (auto *DestType = dyn_cast<FunctionType>(
97 BC->getDestTy()->getPointerElementType())) {
99 // Create a new function with the correct type
101 LLVM_DEBUG(dbgs() << "found function type: " << *NewType << "\n");
102 } else if (NewType != DestType) {
103 errs() << "warning: prototype-less function used with "
104 "conflicting signatures: "
105 << F.getName() << "\n";
106 LLVM_DEBUG(dbgs() << " " << *DestType << "\n");
107 LLVM_DEBUG(dbgs() << " "<< *NewType << "\n");
115 dbgs() << "could not derive a function prototype from usage: " +
117 // We could not derive a type for this function. In this case strip
118 // the isVarArg and make it a simple zero-arg function. This has more
119 // chance of being correct. The current signature of (...) is illegal in
120 // C since it doesn't have any arguments before the "...", we this at
121 // least makes it possible for this symbol to be resolved by the linker.
122 NewType = FunctionType::get(F.getFunctionType()->getReturnType(), false);
126 Function::Create(NewType, F.getLinkage(), F.getName() + ".fixed_sig");
127 NewF->setAttributes(F.getAttributes());
128 NewF->removeFnAttr("no-prototype");
129 Replacements.emplace_back(&F, NewF);
132 for (auto &Pair : Replacements) {
133 Function *OldF = Pair.first;
134 Function *NewF = Pair.second;
135 std::string Name = OldF->getName();
136 M.getFunctionList().push_back(NewF);
137 OldF->replaceAllUsesWith(
138 ConstantExpr::getPointerBitCastOrAddrSpaceCast(NewF, OldF->getType()));
139 OldF->eraseFromParent();
143 return !Replacements.empty();