LLVM 24.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/Analysis.h"
23#include "llvm/IR/Constants.h"
24#include "llvm/IR/Module.h"
25#include "llvm/IR/Operator.h"
26#include "llvm/IR/PassManager.h"
27#include "llvm/Pass.h"
28#include "llvm/Support/Debug.h"
31using namespace llvm;
32
33#define DEBUG_TYPE "wasm-add-missing-prototypes"
34
35namespace {
36class WebAssemblyAddMissingPrototypesLegacy final : public ModulePass {
37 StringRef getPassName() const override {
38 return "Add prototypes to prototypes-less functions";
39 }
40
41 void getAnalysisUsage(AnalysisUsage &AU) const override {
42 AU.setPreservesCFG();
44 }
45
46 bool runOnModule(Module &M) override;
47
48public:
49 static char ID;
50 WebAssemblyAddMissingPrototypesLegacy() : ModulePass(ID) {}
51};
52} // End anonymous namespace
53
54char WebAssemblyAddMissingPrototypesLegacy::ID = 0;
55INITIALIZE_PASS(WebAssemblyAddMissingPrototypesLegacy, DEBUG_TYPE,
56 "Add prototypes to prototypes-less functions", false, false)
57
59 return new WebAssemblyAddMissingPrototypesLegacy();
60}
61
63 LLVM_DEBUG(dbgs() << "********** Add Missing Prototypes **********\n");
64
65 std::vector<std::pair<Function *, Function *>> Replacements;
66
67 // Find all the prototype-less function declarations
68 for (Function &F : M) {
69 if (!F.isDeclaration() || !F.hasFnAttribute("no-prototype"))
70 continue;
71
72 LLVM_DEBUG(dbgs() << "Found no-prototype function: " << F.getName()
73 << "\n");
74
75 // When clang emits prototype-less C functions it uses (...), i.e. varargs
76 // function that take no arguments (have no sentinel). When we see a
77 // no-prototype attribute we expect the function have these properties.
78 if (!F.isVarArg())
80 "Functions with 'no-prototype' attribute must take varargs: " +
81 F.getName());
82 unsigned NumParams = F.getFunctionType()->getNumParams();
83 if (NumParams != 0) {
84 if (!(NumParams == 1 && F.arg_begin()->hasStructRetAttr()))
85 report_fatal_error("Functions with 'no-prototype' attribute should "
86 "not have params: " +
87 F.getName());
88 }
89
90 // Find calls of this function, looking through bitcasts.
92 SmallVector<Value *> Worklist;
93 Worklist.push_back(&F);
94 while (!Worklist.empty()) {
95 Value *V = Worklist.pop_back_val();
96 for (User *U : V->users()) {
97 if (auto *BC = dyn_cast<BitCastOperator>(U))
98 Worklist.push_back(BC);
99 else if (auto *CB = dyn_cast<CallBase>(U))
100 if (CB->getCalledOperand() == V)
101 Calls.push_back(CB);
102 }
103 }
104
105 // Create a function prototype based on the first call site that we find.
106 FunctionType *NewType = nullptr;
107 for (CallBase *CB : Calls) {
108 LLVM_DEBUG(dbgs() << "prototype-less call of " << F.getName() << ":\n");
109 LLVM_DEBUG(dbgs() << *CB << "\n");
110 FunctionType *DestType = CB->getFunctionType();
111 if (!NewType) {
112 // Create a new function with the correct type
113 NewType = DestType;
114 LLVM_DEBUG(dbgs() << "found function type: " << *NewType << "\n");
115 } else if (NewType != DestType) {
116 errs() << "warning: prototype-less function used with "
117 "conflicting signatures: "
118 << F.getName() << "\n";
119 LLVM_DEBUG(dbgs() << " " << *DestType << "\n");
120 LLVM_DEBUG(dbgs() << " " << *NewType << "\n");
121 }
122 }
123
124 if (!NewType) {
126 dbgs() << "could not derive a function prototype from usage: " +
127 F.getName() + "\n");
128 // We could not derive a type for this function. In this case strip
129 // the isVarArg and make it a simple zero-arg function. This has more
130 // chance of being correct. The current signature of (...) is illegal in
131 // C since it doesn't have any arguments before the "...", we this at
132 // least makes it possible for this symbol to be resolved by the linker.
133 NewType = FunctionType::get(F.getFunctionType()->getReturnType(), false);
134 }
135
136 Function *NewF =
137 Function::Create(NewType, F.getLinkage(), F.getName() + ".fixed_sig");
138 NewF->setAttributes(F.getAttributes());
139 NewF->removeFnAttr("no-prototype");
140 Replacements.emplace_back(&F, NewF);
141 }
142
143 for (auto &Pair : Replacements) {
144 Function *OldF = Pair.first;
145 Function *NewF = Pair.second;
146 std::string Name = std::string(OldF->getName());
147 M.getFunctionList().push_back(NewF);
148 OldF->replaceAllUsesWith(
150 OldF->eraseFromParent();
151 NewF->setName(Name);
152 }
153
154 return !Replacements.empty();
155}
156
157bool WebAssemblyAddMissingPrototypesLegacy::runOnModule(Module &M) {
158 return addMissingPrototypes(M);
159}
160
161PreservedAnalyses
This file contains the declarations for the subclasses of Constant, which represent the different fla...
#define DEBUG_TYPE
Module.h This file contains the declarations for the Module class.
This header defines various interfaces for pass management in LLVM.
#define F(x, y, z)
Definition MD5.cpp:54
ModuleAnalysisManager MAM
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Definition PassSupport.h:56
#define LLVM_DEBUG(...)
Definition Debug.h:119
static bool addMissingPrototypes(Module &M)
This file contains the entry points for global functions defined in the LLVM WebAssembly back-end.
Represent the analysis usage information of a pass.
LLVM_ABI void setPreservesCFG()
This function should be called by the pass, iff they do not:
Definition Pass.cpp:275
Represents analyses that only rely on functions' control flow.
Definition Analysis.h:73
Base class for all callable instructions (InvokeInst and CallInst) Holds everything related to callin...
static LLVM_ABI Constant * getPointerBitCastOrAddrSpaceCast(Constant *C, Type *Ty)
Create a BitCast or AddrSpaceCast for a pointer type depending on the address space.
static LLVM_ABI FunctionType * get(Type *Result, ArrayRef< Type * > Params, bool isVarArg)
This static method is the primary way of constructing a FunctionType.
static Function * Create(FunctionType *Ty, LinkageTypes Linkage, unsigned AddrSpace, const Twine &N="", Module *M=nullptr)
Definition Function.h:168
void eraseFromParent()
eraseFromParent - This method unlinks 'this' from the containing module and deletes it.
Definition Function.cpp:444
void removeFnAttr(Attribute::AttrKind Kind)
Remove function attributes from this function.
Definition Function.cpp:681
void setAttributes(AttributeList Attrs)
Set the attribute list for this Function.
Definition Function.h:331
PointerType * getType() const
Global values are always pointers.
ModulePass class - This class is used to implement unstructured interprocedural optimizations and ana...
Definition Pass.h:255
A Module instance is used to store all the information related to an LLVM module.
Definition Module.h:67
virtual void getAnalysisUsage(AnalysisUsage &) const
getAnalysisUsage - This function should be overriden by passes that need analysis information to do t...
Definition Pass.cpp:112
static PreservedAnalyses none()
Convenience factory function for the empty preserved set.
Definition Analysis.h:115
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
Definition Analysis.h:118
PreservedAnalyses & preserveSet()
Mark an analysis set as preserved.
Definition Analysis.h:151
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Represent a constant reference to a string, i.e.
Definition StringRef.h:56
LLVM Value Representation.
Definition Value.h:75
LLVM_ABI void setName(const Twine &Name)
Change the name of the value.
Definition Value.cpp:394
LLVM_ABI void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
Definition Value.cpp:553
iterator_range< user_iterator > users()
Definition Value.h:426
LLVM_ABI StringRef getName() const
Return a constant reference to the value's name.
Definition Value.cpp:319
PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM)
Pass manager infrastructure for declaring and invalidating analyses.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition CallingConv.h:24
This is an optimization pass for GlobalISel generic memory operations.
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:209
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
Definition Error.cpp:163
LLVM_ABI raw_fd_ostream & errs()
This returns a reference to a raw_ostream for standard error.
ModulePass * createWebAssemblyAddMissingPrototypesLegacyPass()
AnalysisManager< Module > ModuleAnalysisManager
Convenience typedef for the Module analysis manager.
Definition MIRParser.h:39