LLVM  14.0.0git
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 = std::string(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 }
llvm
---------------------— PointerInfo ------------------------------------—
Definition: AllocatorList.h:23
WebAssembly.h
M
We currently emits eax Perhaps this is what we really should generate is Is imull three or four cycles eax eax The current instruction priority is based on pattern complexity The former is more complex because it folds a load so the latter will not be emitted Perhaps we should use AddedComplexity to give LEA32r a higher priority We should always try to match LEA first since the LEA matching code does some estimate to determine whether the match is profitable if we care more about code then imull is better It s two bytes shorter than movl leal On a Pentium M
Definition: README.txt:252
llvm::ModulePass
ModulePass class - This class is used to implement unstructured interprocedural optimizations and ana...
Definition: Pass.h:238
llvm::Function
Definition: Function.h:61
Pass.h
llvm::Function::eraseFromParent
void eraseFromParent()
eraseFromParent - This method unlinks 'this' from the containing module and deletes it.
Definition: Function.cpp:365
llvm::FunctionType::get
static FunctionType * get(Type *Result, ArrayRef< Type * > Params, bool isVarArg)
This static method is the primary way of constructing a FunctionType.
Definition: Type.cpp:327
Local.h
Module.h
Operator.h
llvm::errs
raw_fd_ostream & errs()
This returns a reference to a raw_ostream for standard error.
Definition: raw_ostream.cpp:892
LLVM_DEBUG
#define LLVM_DEBUG(X)
Definition: Debug.h:122
F
#define F(x, y, z)
Definition: MD5.cpp:56
llvm::dbgs
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition: Debug.cpp:163
Constants.h
llvm::AnalysisUsage
Represent the analysis usage information of a pass.
Definition: PassAnalysisSupport.h:47
llvm::report_fatal_error
void report_fatal_error(Error Err, bool gen_crash_diag=true)
Report a serious error, calling any installed error handler.
Definition: Error.cpp:140
llvm::Value::setName
void setName(const Twine &Name)
Change the name of the value.
Definition: Value.cpp:364
llvm::Function::Create
static Function * Create(FunctionType *Ty, LinkageTypes Linkage, unsigned AddrSpace, const Twine &N="", Module *M=nullptr)
Definition: Function.h:137
IRBuilder.h
llvm::Module
A Module instance is used to store all the information related to an LLVM module.
Definition: Module.h:67
llvm::createWebAssemblyAddMissingPrototypes
ModulePass * createWebAssemblyAddMissingPrototypes()
llvm::AnalysisUsage::setPreservesCFG
void setPreservesCFG()
This function should be called by the pass, iff they do not:
Definition: Pass.cpp:253
llvm::StringRef
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:58
llvm::Value::replaceAllUsesWith
void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
Definition: Value.cpp:520
llvm::Value::getName
StringRef getName() const
Return a constant reference to the value's name.
Definition: Value.cpp:297
llvm::GraphProgram::Name
Name
Definition: GraphWriter.h:52
DEBUG_TYPE
#define DEBUG_TYPE
Definition: WebAssemblyAddMissingPrototypes.cpp:32
llvm::ConstantExpr::getPointerBitCastOrAddrSpaceCast
static Constant * getPointerBitCastOrAddrSpaceCast(Constant *C, Type *Ty)
Create a BitCast or AddrSpaceCast for a pointer type depending on the address space.
Definition: Constants.cpp:2048
ModuleUtils.h
llvm::GlobalValue::getType
PointerType * getType() const
Global values are always pointers.
Definition: GlobalValue.h:271
llvm::Pass::getAnalysisUsage
virtual void getAnalysisUsage(AnalysisUsage &) const
getAnalysisUsage - This function should be overriden by passes that need analysis information to do t...
Definition: Pass.cpp:93
llvm::Function::setAttributes
void setAttributes(AttributeList Attrs)
Set the attribute list for this Function.
Definition: Function.h:252
llvm::Function::removeFnAttr
void removeFnAttr(Attribute::AttrKind Kind)
Remove function attributes from this function.
Definition: Function.h:271
Debug.h
INITIALIZE_PASS
INITIALIZE_PASS(WebAssemblyAddMissingPrototypes, DEBUG_TYPE, "Add prototypes to prototypes-less functions", false, false) ModulePass *llvm
Definition: WebAssemblyAddMissingPrototypes.cpp:54
llvm::FunctionType
Class to represent function types.
Definition: DerivedTypes.h:102
llvm::Use
A Use represents the edge between a Value definition and its users.
Definition: Use.h:44
llvm::Intrinsic::ID
unsigned ID
Definition: TargetTransformInfo.h:38