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