summaryrefslogtreecommitdiffstats
path: root/llvm/lib/Target/WebAssembly
diff options
context:
space:
mode:
authorSam Clegg <sbc@chromium.org>2018-07-11 04:29:36 +0000
committerSam Clegg <sbc@chromium.org>2018-07-11 04:29:36 +0000
commit92617559bbb432e45efb462658020529c1ac9237 (patch)
tree9396043b7c9da1e1fc1df8b78e2329a4c2163df1 /llvm/lib/Target/WebAssembly
parentfcd1b66ae10520b2189df03405f7bfac687b3e70 (diff)
downloadbcm5719-llvm-92617559bbb432e45efb462658020529c1ac9237.tar.gz
bcm5719-llvm-92617559bbb432e45efb462658020529c1ac9237.zip
[WebAssembly] Add pass to infer prototypes for prototype-less functions
See https://bugs.llvm.org/show_bug.cgi?id=35385 Differential Revision: https://reviews.llvm.org/D48471 llvm-svn: 336759
Diffstat (limited to 'llvm/lib/Target/WebAssembly')
-rw-r--r--llvm/lib/Target/WebAssembly/CMakeLists.txt1
-rw-r--r--llvm/lib/Target/WebAssembly/WebAssembly.h2
-rw-r--r--llvm/lib/Target/WebAssembly/WebAssemblyAddMissingPrototypes.cpp142
-rw-r--r--llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp4
4 files changed, 149 insertions, 0 deletions
diff --git a/llvm/lib/Target/WebAssembly/CMakeLists.txt b/llvm/lib/Target/WebAssembly/CMakeLists.txt
index 2fdb7f9d05f..a928f110efe 100644
--- a/llvm/lib/Target/WebAssembly/CMakeLists.txt
+++ b/llvm/lib/Target/WebAssembly/CMakeLists.txt
@@ -13,6 +13,7 @@ tablegen(LLVM WebAssemblyGenSubtargetInfo.inc -gen-subtarget)
add_public_tablegen_target(WebAssemblyCommonTableGen)
add_llvm_target(WebAssemblyCodeGen
+ WebAssemblyAddMissingPrototypes.cpp
WebAssemblyArgumentMove.cpp
WebAssemblyAsmPrinter.cpp
WebAssemblyCallIndirectFixup.cpp
diff --git a/llvm/lib/Target/WebAssembly/WebAssembly.h b/llvm/lib/Target/WebAssembly/WebAssembly.h
index 0f045088d3c..05b7b21fb59 100644
--- a/llvm/lib/Target/WebAssembly/WebAssembly.h
+++ b/llvm/lib/Target/WebAssembly/WebAssembly.h
@@ -28,6 +28,7 @@ class FunctionPass;
// LLVM IR passes.
ModulePass *createWebAssemblyLowerEmscriptenEHSjLj(bool DoEH, bool DoSjLj);
ModulePass *createWebAssemblyLowerGlobalDtors();
+ModulePass *createWebAssemblyAddMissingPrototypes();
ModulePass *createWebAssemblyFixFunctionBitcasts();
FunctionPass *createWebAssemblyOptimizeReturned();
@@ -55,6 +56,7 @@ FunctionPass *createWebAssemblyPeephole();
FunctionPass *createWebAssemblyCallIndirectFixup();
// PassRegistry initialization declarations.
+void initializeWebAssemblyAddMissingPrototypesPass(PassRegistry &);
void initializeWebAssemblyLowerEmscriptenEHSjLjPass(PassRegistry &);
void initializeLowerGlobalDtorsPass(PassRegistry &);
void initializeFixFunctionBitcastsPass(PassRegistry &);
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyAddMissingPrototypes.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyAddMissingPrototypes.cpp
new file mode 100644
index 00000000000..91b0b4aac2b
--- /dev/null
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyAddMissingPrototypes.cpp
@@ -0,0 +1,142 @@
+//===-- 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";
+ U.getUser()->dump();
+ 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();
+}
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp
index 02810d71b70..9a5f459e9dd 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp
@@ -51,6 +51,7 @@ extern "C" void LLVMInitializeWebAssemblyTarget() {
// Register backend passes
auto &PR = *PassRegistry::getPassRegistry();
+ initializeWebAssemblyAddMissingPrototypesPass(PR);
initializeWebAssemblyLowerEmscriptenEHSjLjPass(PR);
initializeLowerGlobalDtorsPass(PR);
initializeFixFunctionBitcastsPass(PR);
@@ -214,6 +215,9 @@ void WebAssemblyPassConfig::addIRPasses() {
addPass(createAtomicExpandPass());
}
+ // Add signatures to prototype-less function declarations
+ addPass(createWebAssemblyAddMissingPrototypes());
+
// Lower .llvm.global_dtors into .llvm_global_ctors with __cxa_atexit calls.
addPass(createWebAssemblyLowerGlobalDtors());
OpenPOWER on IntegriCloud