LCOV - code coverage report
Current view: top level - lib/Target/WebAssembly - WebAssemblyAddMissingPrototypes.cpp (source / functions) Hit Total Coverage
Test: llvm-toolchain.info Lines: 34 45 75.6 %
Date: 2018-10-20 13:21:21 Functions: 5 6 83.3 %
Legend: Lines: hit not hit

          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             : }

Generated by: LCOV version 1.13