WebAssemblyAddMissingPrototypes.cpp revision 336809
1178825Sdfr//===-- WebAssemblyAddMissingPrototypes.cpp - Fix prototypeless functions -===// 2178825Sdfr// 3178825Sdfr// The LLVM Compiler Infrastructure 4178825Sdfr// 5178825Sdfr// This file is distributed under the University of Illinois Open Source 6178825Sdfr// License. See LICENSE.TXT for details. 7178825Sdfr// 8178825Sdfr//===----------------------------------------------------------------------===// 9178825Sdfr/// 10178825Sdfr/// \file 11178825Sdfr/// Add prototypes to prototypes-less functions. 12178825Sdfr/// 13178825Sdfr/// WebAssembly has strict function prototype checking so we need functions 14178825Sdfr/// declarations to match the call sites. Clang treats prototype-less functions 15178825Sdfr/// as varargs (foo(...)) which happens to work on existing platforms but 16178825Sdfr/// doesn't under WebAssembly. This pass will find all the call sites of each 17178825Sdfr/// prototype-less function, ensure they agree, and then set the signature 18178825Sdfr/// on the function declaration accordingly. 19178825Sdfr/// 20178825Sdfr//===----------------------------------------------------------------------===// 21178825Sdfr 22178825Sdfr#include "WebAssembly.h" 23178825Sdfr#include "llvm/IR/Constants.h" 24178825Sdfr#include "llvm/IR/IRBuilder.h" 25178825Sdfr#include "llvm/IR/Module.h" 26178825Sdfr#include "llvm/IR/Operator.h" 27178825Sdfr#include "llvm/Transforms/Utils/ModuleUtils.h" 28178825Sdfr#include "llvm/Transforms/Utils/Local.h" 29178825Sdfr#include "llvm/Pass.h" 30178825Sdfr#include "llvm/Support/Debug.h" 31178825Sdfrusing namespace llvm; 32178825Sdfr 33178825Sdfr#define DEBUG_TYPE "wasm-add-missing-prototypes" 34178825Sdfr 35178825Sdfrnamespace { 36178825Sdfrclass WebAssemblyAddMissingPrototypes final : public ModulePass { 37178825Sdfr StringRef getPassName() const override { 38178825Sdfr return "Add prototypes to prototypes-less functions"; 39178825Sdfr } 40178825Sdfr 41178825Sdfr void getAnalysisUsage(AnalysisUsage &AU) const override { 42178825Sdfr AU.setPreservesCFG(); 43178825Sdfr ModulePass::getAnalysisUsage(AU); 44178825Sdfr } 45178825Sdfr 46178825Sdfr bool runOnModule(Module &M) override; 47178825Sdfr 48178825Sdfrpublic: 49178825Sdfr static char ID; 50178825Sdfr WebAssemblyAddMissingPrototypes() : ModulePass(ID) {} 51178825Sdfr}; 52178825Sdfr} // End anonymous namespace 53178825Sdfr 54178825Sdfrchar WebAssemblyAddMissingPrototypes::ID = 0; 55178825SdfrINITIALIZE_PASS(WebAssemblyAddMissingPrototypes, DEBUG_TYPE, 56178825Sdfr "Add prototypes to prototypes-less functions", false, false) 57178825Sdfr 58178825SdfrModulePass *llvm::createWebAssemblyAddMissingPrototypes() { 59178825Sdfr return new WebAssemblyAddMissingPrototypes(); 60178825Sdfr} 61178825Sdfr 62178825Sdfrbool WebAssemblyAddMissingPrototypes::runOnModule(Module &M) { 63178825Sdfr LLVM_DEBUG(dbgs() << "runnning AddMissingPrototypes\n"); 64178825Sdfr 65178825Sdfr std::vector<std::pair<Function*, Function*>> Replacements; 66178825Sdfr 67178825Sdfr // Find all the prototype-less function declarations 68178825Sdfr for (Function &F : M) { 69178825Sdfr if (!F.isDeclaration() || !F.hasFnAttribute("no-prototype")) 70178825Sdfr continue; 71178825Sdfr 72178825Sdfr LLVM_DEBUG(dbgs() << "Found no-prototype function: " << F.getName() << "\n"); 73178825Sdfr 74178825Sdfr // When clang emits prototype-less C functions it uses (...), i.e. varargs 75178825Sdfr // function that take no arguments (have no sentinel). When we see a 76178825Sdfr // no-prototype attribute we expect the function have these properties. 77178825Sdfr if (!F.isVarArg()) 78178825Sdfr report_fatal_error( 79178825Sdfr "Functions with 'no-prototype' attribute must take varargs: " + 80178825Sdfr F.getName()); 81178825Sdfr if (F.getFunctionType()->getNumParams() != 0) 82178825Sdfr report_fatal_error( 83178825Sdfr "Functions with 'no-prototype' attribute should not have params: " + 84178825Sdfr F.getName()); 85178825Sdfr 86178825Sdfr 87178825Sdfr // Create a function prototype based on the first call site (first bitcast) 88178825Sdfr // that we find. 89178825Sdfr FunctionType *NewType = nullptr; 90178825Sdfr Function* NewF = nullptr; 91178825Sdfr for (Use &U : F.uses()) { 92178825Sdfr LLVM_DEBUG(dbgs() << "prototype-less use: " << F.getName() << "\n"); 93178825Sdfr if (BitCastOperator *BC = dyn_cast<BitCastOperator>(U.getUser())) { 94178825Sdfr FunctionType *DestType = 95178825Sdfr cast<FunctionType>(BC->getDestTy()->getPointerElementType()); 96178825Sdfr 97178825Sdfr // Create a new function with the correct type 98178825Sdfr NewType = DestType; 99178825Sdfr NewF = Function::Create(NewType, F.getLinkage(), F.getName()); 100178825Sdfr NewF->setAttributes(F.getAttributes()); 101178825Sdfr NewF->removeFnAttr("no-prototype"); 102178825Sdfr break; 103178825Sdfr } 104178825Sdfr } 105178825Sdfr 106178825Sdfr if (!NewType) { 107178825Sdfr LLVM_DEBUG( 108178825Sdfr dbgs() << "could not derive a function prototype from usage: " + 109178825Sdfr F.getName() + "\n"); 110178825Sdfr continue; 111178825Sdfr } 112178825Sdfr 113178825Sdfr for (Use &U : F.uses()) { 114178825Sdfr if (BitCastOperator *BC = dyn_cast<BitCastOperator>(U.getUser())) { 115178825Sdfr FunctionType *DestType = 116178825Sdfr cast<FunctionType>(BC->getDestTy()->getPointerElementType()); 117178825Sdfr if (NewType != DestType) { 118178825Sdfr report_fatal_error( 119178825Sdfr "Prototypeless function used with conflicting signatures: " + 120178825Sdfr F.getName()); 121178825Sdfr } 122178825Sdfr BC->replaceAllUsesWith(NewF); 123178825Sdfr Replacements.emplace_back(&F, NewF); 124178825Sdfr } else { 125178825Sdfr dbgs() << *U.getUser()->getType() << "\n"; 126178825Sdfr#ifndef NDEBUG 127178825Sdfr U.getUser()->dump(); 128178825Sdfr#endif 129178825Sdfr report_fatal_error( 130178825Sdfr "unexpected use of prototypeless function: " + F.getName() + "\n"); 131178825Sdfr } 132178825Sdfr } 133178825Sdfr } 134178825Sdfr 135178825Sdfr // Finally replace the old function declarations with the new ones 136178825Sdfr for (auto &Pair : Replacements) { 137178825Sdfr Function* Old = Pair.first; 138178825Sdfr Function* New = Pair.second; 139178825Sdfr Old->eraseFromParent(); 140178825Sdfr M.getFunctionList().push_back(New); 141178825Sdfr } 142178825Sdfr 143178825Sdfr return !Replacements.empty(); 144178825Sdfr} 145178825Sdfr