LLVM  10.0.0svn
WebAssemblyAddMissingPrototypes.cpp
Go to the documentation of this file.
1 //===-- WebAssemblyAddMissingPrototypes.cpp - Fix prototypeless functions -===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 ///
9 /// \file
10 /// Add prototypes to prototypes-less functions.
11 ///
12 /// WebAssembly has strict function prototype checking so we need functions
13 /// declarations to match the call sites. Clang treats prototype-less functions
14 /// as varargs (foo(...)) which happens to work on existing platforms but
15 /// doesn't under WebAssembly. This pass will find all the call sites of each
16 /// prototype-less function, ensure they agree, and then set the signature
17 /// on the function declaration accordingly.
18 ///
19 //===----------------------------------------------------------------------===//
20 
21 #include "WebAssembly.h"
22 #include "llvm/IR/Constants.h"
23 #include "llvm/IR/IRBuilder.h"
24 #include "llvm/IR/Module.h"
25 #include "llvm/IR/Operator.h"
26 #include "llvm/Pass.h"
27 #include "llvm/Support/Debug.h"
30 using namespace llvm;
31 
32 #define DEBUG_TYPE "wasm-add-missing-prototypes"
33 
34 namespace {
35 class WebAssemblyAddMissingPrototypes final : public ModulePass {
36  StringRef getPassName() const override {
37  return "Add prototypes to prototypes-less functions";
38  }
39 
40  void getAnalysisUsage(AnalysisUsage &AU) const override {
41  AU.setPreservesCFG();
43  }
44 
45  bool runOnModule(Module &M) override;
46 
47 public:
48  static char ID;
49  WebAssemblyAddMissingPrototypes() : ModulePass(ID) {}
50 };
51 } // End anonymous namespace
52 
54 INITIALIZE_PASS(WebAssemblyAddMissingPrototypes, DEBUG_TYPE,
55  "Add prototypes to prototypes-less functions", false, false)
56 
58  return new WebAssemblyAddMissingPrototypes();
59 }
60 
61 bool WebAssemblyAddMissingPrototypes::runOnModule(Module &M) {
62  LLVM_DEBUG(dbgs() << "********** Add Missing Prototypes **********\n");
63 
64  std::vector<std::pair<Function *, Function *>> Replacements;
65 
66  // Find all the prototype-less function declarations
67  for (Function &F : M) {
68  if (!F.isDeclaration() || !F.hasFnAttribute("no-prototype"))
69  continue;
70 
71  LLVM_DEBUG(dbgs() << "Found no-prototype function: " << F.getName()
72  << "\n");
73 
74  // When clang emits prototype-less C functions it uses (...), i.e. varargs
75  // function that take no arguments (have no sentinel). When we see a
76  // no-prototype attribute we expect the function have these properties.
77  if (!F.isVarArg())
79  "Functions with 'no-prototype' attribute must take varargs: " +
80  F.getName());
81  unsigned NumParams = F.getFunctionType()->getNumParams();
82  if (NumParams != 0) {
83  if (!(NumParams == 1 && F.arg_begin()->hasStructRetAttr()))
84  report_fatal_error("Functions with 'no-prototype' attribute should "
85  "not have params: " +
86  F.getName());
87  }
88 
89  // Create a function prototype based on the first call site (first bitcast)
90  // that we find.
91  FunctionType *NewType = nullptr;
92  for (Use &U : F.uses()) {
93  LLVM_DEBUG(dbgs() << "prototype-less use: " << F.getName() << "\n");
94  LLVM_DEBUG(dbgs() << *U.getUser() << "\n");
95  if (auto *BC = dyn_cast<BitCastOperator>(U.getUser())) {
96  if (auto *DestType = dyn_cast<FunctionType>(
97  BC->getDestTy()->getPointerElementType())) {
98  if (!NewType) {
99  // Create a new function with the correct type
100  NewType = DestType;
101  LLVM_DEBUG(dbgs() << "found function type: " << *NewType << "\n");
102  } else if (NewType != DestType) {
103  errs() << "warning: prototype-less function used with "
104  "conflicting signatures: "
105  << F.getName() << "\n";
106  LLVM_DEBUG(dbgs() << " " << *DestType << "\n");
107  LLVM_DEBUG(dbgs() << " "<< *NewType << "\n");
108  }
109  }
110  }
111  }
112 
113  if (!NewType) {
114  LLVM_DEBUG(
115  dbgs() << "could not derive a function prototype from usage: " +
116  F.getName() + "\n");
117  // We could not derive a type for this function. In this case strip
118  // the isVarArg and make it a simple zero-arg function. This has more
119  // chance of being correct. The current signature of (...) is illegal in
120  // C since it doesn't have any arguments before the "...", we this at
121  // least makes it possible for this symbol to be resolved by the linker.
122  NewType = FunctionType::get(F.getFunctionType()->getReturnType(), false);
123  }
124 
125  Function *NewF =
126  Function::Create(NewType, F.getLinkage(), F.getName() + ".fixed_sig");
127  NewF->setAttributes(F.getAttributes());
128  NewF->removeFnAttr("no-prototype");
129  Replacements.emplace_back(&F, NewF);
130  }
131 
132  for (auto &Pair : Replacements) {
133  Function *OldF = Pair.first;
134  Function *NewF = Pair.second;
135  std::string Name = OldF->getName();
136  M.getFunctionList().push_back(NewF);
137  OldF->replaceAllUsesWith(
139  OldF->eraseFromParent();
140  NewF->setName(Name);
141  }
142 
143  return !Replacements.empty();
144 }
raw_ostream & errs()
This returns a reference to a raw_ostream for standard error.
static Constant * getPointerBitCastOrAddrSpaceCast(Constant *C, Type *Ty)
Create a BitCast or AddrSpaceCast for a pointer type depending on the address space.
Definition: Constants.cpp:1633
LLVM_ATTRIBUTE_NORETURN void report_fatal_error(Error Err, bool gen_crash_diag=true)
Report a serious error, calling any installed error handler.
Definition: Error.cpp:139
This class represents lattice values for constants.
Definition: AllocatorList.h:23
A Module instance is used to store all the information related to an LLVM module. ...
Definition: Module.h:65
amdgpu Simplify well known AMD library false FunctionCallee Value const Twine & Name
F(f)
virtual StringRef getPassName() const
getPassName - Return a nice clean name for a pass.
Definition: Pass.cpp:79
This file contains the entry points for global functions defined in the LLVM WebAssembly back-end...
A Use represents the edge between a Value definition and its users.
Definition: Use.h:55
void setName(const Twine &Name)
Change the name of the value.
Definition: Value.cpp:285
Class to represent function types.
Definition: DerivedTypes.h:103
virtual void getAnalysisUsage(AnalysisUsage &) const
getAnalysisUsage - This function should be overriden by passes that need analysis information to do t...
Definition: Pass.cpp:96
void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
Definition: Value.cpp:429
ModulePass * createWebAssemblyAddMissingPrototypes()
static Function * Create(FunctionType *Ty, LinkageTypes Linkage, unsigned AddrSpace, const Twine &N="", Module *M=nullptr)
Definition: Function.h:135
INITIALIZE_PASS(WebAssemblyAddMissingPrototypes, DEBUG_TYPE, "Add prototypes to prototypes-less functions", false, false) ModulePass *llvm
This file contains the declarations for the subclasses of Constant, which represent the different fla...
Represent the analysis usage information of a pass.
static FunctionType * get(Type *Result, ArrayRef< Type *> Params, bool isVarArg)
This static method is the primary way of constructing a FunctionType.
Definition: Type.cpp:296
Module.h This file contains the declarations for the Module class.
void setPreservesCFG()
This function should be called by the pass, iff they do not:
Definition: Pass.cpp:301
void setAttributes(AttributeList Attrs)
Set the attribute list for this Function.
Definition: Function.h:226
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition: Debug.cpp:132
StringRef getName() const
Return a constant reference to the value&#39;s name.
Definition: Value.cpp:214
ModulePass class - This class is used to implement unstructured interprocedural optimizations and ana...
Definition: Pass.h:224
void eraseFromParent()
eraseFromParent - This method unlinks &#39;this&#39; from the containing module and deletes it...
Definition: Function.cpp:226
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:48
#define LLVM_DEBUG(X)
Definition: Debug.h:122
PointerType * getType() const
Global values are always pointers.
Definition: GlobalValue.h:277