1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
|
//===-- WebAssemblyAddMissingPrototypes.cpp - Fix prototypeless functions -===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
///
/// \file
/// Add prototypes to prototypes-less functions.
///
/// WebAssembly has strict function prototype checking so we need functions
/// declarations to match the call sites. Clang treats prototype-less functions
/// as varargs (foo(...)) which happens to work on existing platforms but
/// doesn't under WebAssembly. This pass will find all the call sites of each
/// prototype-less function, ensure they agree, and then set the signature
/// on the function declaration accordingly.
///
//===----------------------------------------------------------------------===//
#include "WebAssembly.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Operator.h"
#include "llvm/Transforms/Utils/ModuleUtils.h"
#include "llvm/Transforms/Utils/Local.h"
#include "llvm/Pass.h"
#include "llvm/Support/Debug.h"
using namespace llvm;
#define DEBUG_TYPE "wasm-add-missing-prototypes"
namespace {
class WebAssemblyAddMissingPrototypes final : public ModulePass {
StringRef getPassName() const override {
return "Add prototypes to prototypes-less functions";
}
void getAnalysisUsage(AnalysisUsage &AU) const override {
AU.setPreservesCFG();
ModulePass::getAnalysisUsage(AU);
}
bool runOnModule(Module &M) override;
public:
static char ID;
WebAssemblyAddMissingPrototypes() : ModulePass(ID) {}
};
} // End anonymous namespace
char WebAssemblyAddMissingPrototypes::ID = 0;
INITIALIZE_PASS(WebAssemblyAddMissingPrototypes, DEBUG_TYPE,
"Add prototypes to prototypes-less functions", false, false)
ModulePass *llvm::createWebAssemblyAddMissingPrototypes() {
return new WebAssemblyAddMissingPrototypes();
}
bool WebAssemblyAddMissingPrototypes::runOnModule(Module &M) {
LLVM_DEBUG(dbgs() << "runnning AddMissingPrototypes\n");
std::vector<std::pair<Function*, Function*>> Replacements;
// Find all the prototype-less function declarations
for (Function &F : M) {
if (!F.isDeclaration() || !F.hasFnAttribute("no-prototype"))
continue;
LLVM_DEBUG(dbgs() << "Found no-prototype function: " << F.getName() << "\n");
// When clang emits prototype-less C functions it uses (...), i.e. varargs
// function that take no arguments (have no sentinel). When we see a
// no-prototype attribute we expect the function have these properties.
if (!F.isVarArg())
report_fatal_error(
"Functions with 'no-prototype' attribute must take varargs: " +
F.getName());
if (F.getFunctionType()->getNumParams() != 0)
report_fatal_error(
"Functions with 'no-prototype' attribute should not have params: " +
F.getName());
// Create a function prototype based on the first call site (first bitcast)
// that we find.
FunctionType *NewType = nullptr;
Function* NewF = nullptr;
for (Use &U : F.uses()) {
LLVM_DEBUG(dbgs() << "prototype-less use: " << F.getName() << "\n");
if (BitCastOperator *BC = dyn_cast<BitCastOperator>(U.getUser())) {
FunctionType *DestType =
cast<FunctionType>(BC->getDestTy()->getPointerElementType());
// Create a new function with the correct type
NewType = DestType;
NewF = Function::Create(NewType, F.getLinkage(), F.getName());
NewF->setAttributes(F.getAttributes());
NewF->removeFnAttr("no-prototype");
break;
}
}
if (!NewType) {
LLVM_DEBUG(
dbgs() << "could not derive a function prototype from usage: " +
F.getName() + "\n");
continue;
}
for (Use &U : F.uses()) {
if (BitCastOperator *BC = dyn_cast<BitCastOperator>(U.getUser())) {
FunctionType *DestType =
cast<FunctionType>(BC->getDestTy()->getPointerElementType());
if (NewType != DestType) {
report_fatal_error(
"Prototypeless function used with conflicting signatures: " +
F.getName());
}
BC->replaceAllUsesWith(NewF);
Replacements.emplace_back(&F, NewF);
} else {
dbgs() << *U.getUser()->getType() << "\n";
#ifndef NDEBUG
U.getUser()->dump();
#endif
report_fatal_error(
"unexpected use of prototypeless function: " + F.getName() + "\n");
}
}
}
// Finally replace the old function declarations with the new ones
for (auto &Pair : Replacements) {
Function* Old = Pair.first;
Function* New = Pair.second;
Old->eraseFromParent();
M.getFunctionList().push_back(New);
}
return !Replacements.empty();
}
|