LLVM  15.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  // Find calls of this function, looking through bitcasts.
91  SmallVector<Value *> Worklist;
92  Worklist.push_back(&F);
93  while (!Worklist.empty()) {
94  Value *V = Worklist.pop_back_val();
95  for (User *U : V->users()) {
96  if (auto *BC = dyn_cast<BitCastOperator>(U))
97  Worklist.push_back(BC);
98  else if (auto *CB = dyn_cast<CallBase>(U))
99  if (CB->getCalledOperand() == V)
100  Calls.push_back(CB);
101  }
102  }
103 
104  // Create a function prototype based on the first call site that we find.
105  FunctionType *NewType = nullptr;
106  for (CallBase *CB : Calls) {
107  LLVM_DEBUG(dbgs() << "prototype-less call of " << F.getName() << ":\n");
108  LLVM_DEBUG(dbgs() << *CB << "\n");
109  FunctionType *DestType = CB->getFunctionType();
110  if (!NewType) {
111  // Create a new function with the correct type
112  NewType = DestType;
113  LLVM_DEBUG(dbgs() << "found function type: " << *NewType << "\n");
114  } else if (NewType != DestType) {
115  errs() << "warning: prototype-less function used with "
116  "conflicting signatures: "
117  << F.getName() << "\n";
118  LLVM_DEBUG(dbgs() << " " << *DestType << "\n");
119  LLVM_DEBUG(dbgs() << " " << *NewType << "\n");
120  }
121  }
122 
123  if (!NewType) {
124  LLVM_DEBUG(
125  dbgs() << "could not derive a function prototype from usage: " +
126  F.getName() + "\n");
127  // We could not derive a type for this function. In this case strip
128  // the isVarArg and make it a simple zero-arg function. This has more
129  // chance of being correct. The current signature of (...) is illegal in
130  // C since it doesn't have any arguments before the "...", we this at
131  // least makes it possible for this symbol to be resolved by the linker.
132  NewType = FunctionType::get(F.getFunctionType()->getReturnType(), false);
133  }
134 
135  Function *NewF =
136  Function::Create(NewType, F.getLinkage(), F.getName() + ".fixed_sig");
137  NewF->setAttributes(F.getAttributes());
138  NewF->removeFnAttr("no-prototype");
139  Replacements.emplace_back(&F, NewF);
140  }
141 
142  for (auto &Pair : Replacements) {
143  Function *OldF = Pair.first;
144  Function *NewF = Pair.second;
145  std::string Name = std::string(OldF->getName());
146  M.getFunctionList().push_back(NewF);
147  OldF->replaceAllUsesWith(
149  OldF->eraseFromParent();
150  NewF->setName(Name);
151  }
152 
153  return !Replacements.empty();
154 }
llvm
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:17
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:248
llvm::Function
Definition: Function.h:60
Pass.h
llvm::Function::eraseFromParent
void eraseFromParent()
eraseFromParent - This method unlinks 'this' from the containing module and deletes it.
Definition: Function.cpp:364
llvm::SmallVector
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1185
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:361
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:893
llvm::SmallVectorImpl::pop_back_val
LLVM_NODISCARD T pop_back_val()
Definition: SmallVector.h:654
LLVM_DEBUG
#define LLVM_DEBUG(X)
Definition: Debug.h:101
F
#define F(x, y, z)
Definition: MD5.cpp:55
llvm::dbgs
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition: Debug.cpp:163
Constants.h
llvm::User
Definition: User.h:44
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:143
llvm::Value::setName
void setName(const Twine &Name)
Change the name of the value.
Definition: Value.cpp:372
llvm::CallingConv::ID
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition: CallingConv.h:24
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:65
llvm::createWebAssemblyAddMissingPrototypes
ModulePass * createWebAssemblyAddMissingPrototypes()
llvm::AnalysisUsage::setPreservesCFG
void setPreservesCFG()
This function should be called by the pass, iff they do not:
Definition: Pass.cpp:263
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:529
llvm::Value::getName
StringRef getName() const
Return a constant reference to the value's name.
Definition: Value.cpp:305
llvm::GraphProgram::Name
Name
Definition: GraphWriter.h:50
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:2085
ModuleUtils.h
llvm::Function::removeFnAttr
void removeFnAttr(Attribute::AttrKind Kind)
Remove function attributes from this function.
Definition: Function.cpp:583
llvm::CallBase
Base class for all callable instructions (InvokeInst and CallInst) Holds everything related to callin...
Definition: InstrTypes.h:1174
llvm::GlobalValue::getType
PointerType * getType() const
Global values are always pointers.
Definition: GlobalValue.h:270
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:97
llvm::Function::setAttributes
void setAttributes(AttributeList Attrs)
Set the attribute list for this Function.
Definition: Function.h:317
llvm::Value
LLVM Value Representation.
Definition: Value.h:74
Debug.h
INITIALIZE_PASS
INITIALIZE_PASS(WebAssemblyAddMissingPrototypes, DEBUG_TYPE, "Add prototypes to prototypes-less functions", false, false) ModulePass *llvm
Definition: WebAssemblyAddMissingPrototypes.cpp:54
llvm::Value::users
iterator_range< user_iterator > users()
Definition: Value.h:421
llvm::FunctionType
Class to represent function types.
Definition: DerivedTypes.h:103
llvm::Intrinsic::ID
unsigned ID
Definition: TargetTransformInfo.h:37