Deleted Added
full compact
WebAssemblyAddMissingPrototypes.cpp (344779) WebAssemblyAddMissingPrototypes.cpp (353358)
1//===-- WebAssemblyAddMissingPrototypes.cpp - Fix prototypeless functions -===//
2//
1//===-- WebAssemblyAddMissingPrototypes.cpp - Fix prototypeless functions -===//
2//
3// The LLVM Compiler Infrastructure
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
4//
6//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9///
10/// \file
11/// Add prototypes to prototypes-less functions.
12///
13/// WebAssembly has strict function prototype checking so we need functions
14/// declarations to match the call sites. Clang treats prototype-less functions
15/// as varargs (foo(...)) which happens to work on existing platforms but

--- 58 unchanged lines hidden (view full) ---

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())
79 report_fatal_error(
80 "Functions with 'no-prototype' attribute must take varargs: " +
81 F.getName());
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

--- 58 unchanged lines hidden (view full) ---

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())
78 report_fatal_error(
79 "Functions with 'no-prototype' attribute must take varargs: " +
80 F.getName());
82 if (F.getFunctionType()->getNumParams() != 0)
83 report_fatal_error(
84 "Functions with 'no-prototype' attribute should not have params: " +
85 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 }
86
87 // Create a function prototype based on the first call site (first bitcast)
88 // that we find.
89 FunctionType *NewType = nullptr;
88
89 // Create a function prototype based on the first call site (first bitcast)
90 // that we find.
91 FunctionType *NewType = nullptr;
90 Function *NewF = nullptr;
91 for (Use &U : F.uses()) {
92 LLVM_DEBUG(dbgs() << "prototype-less use: " << F.getName() << "\n");
92 for (Use &U : F.uses()) {
93 LLVM_DEBUG(dbgs() << "prototype-less use: " << F.getName() << "\n");
94 LLVM_DEBUG(dbgs() << *U.getUser() << "\n");
93 if (auto *BC = dyn_cast<BitCastOperator>(U.getUser())) {
94 if (auto *DestType = dyn_cast<FunctionType>(
95 BC->getDestTy()->getPointerElementType())) {
96 if (!NewType) {
97 // Create a new function with the correct type
98 NewType = DestType;
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;
99 NewF = Function::Create(NewType, F.getLinkage(), F.getName());
100 NewF->setAttributes(F.getAttributes());
101 NewF->removeFnAttr("no-prototype");
102 } else {
103 if (NewType != DestType) {
104 report_fatal_error("Prototypeless function used with "
105 "conflicting signatures: " +
106 F.getName());
107 }
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");
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 continue;
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);
118 }
119
123 }
124
120 SmallVector<Instruction *, 4> DeadInsts;
121
122 for (Use &US : F.uses()) {
123 User *U = US.getUser();
124 if (auto *BC = dyn_cast<BitCastOperator>(U)) {
125 if (auto *Inst = dyn_cast<BitCastInst>(U)) {
126 // Replace with a new bitcast
127 IRBuilder<> Builder(Inst);
128 Value *NewCast = Builder.CreatePointerCast(NewF, BC->getDestTy());
129 Inst->replaceAllUsesWith(NewCast);
130 DeadInsts.push_back(Inst);
131 } else if (auto *Const = dyn_cast<ConstantExpr>(U)) {
132 Constant *NewConst =
133 ConstantExpr::getPointerCast(NewF, BC->getDestTy());
134 Const->replaceAllUsesWith(NewConst);
135 } else {
136 dbgs() << *U->getType() << "\n";
137#ifndef NDEBUG
138 U->dump();
139#endif
140 report_fatal_error("unexpected use of prototypeless function: " +
141 F.getName() + "\n");
142 }
143 }
144 }
145
146 for (auto I : DeadInsts)
147 I->eraseFromParent();
125 Function *NewF =
126 Function::Create(NewType, F.getLinkage(), F.getName() + ".fixed_sig");
127 NewF->setAttributes(F.getAttributes());
128 NewF->removeFnAttr("no-prototype");
148 Replacements.emplace_back(&F, NewF);
149 }
150
129 Replacements.emplace_back(&F, NewF);
130 }
131
151
152 // Finally replace the old function declarations with the new ones
153 for (auto &Pair : Replacements) {
132 for (auto &Pair : Replacements) {
154 Function *Old = Pair.first;
155 Function *New = Pair.second;
156 Old->eraseFromParent();
157 M.getFunctionList().push_back(New);
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(
138 ConstantExpr::getPointerBitCastOrAddrSpaceCast(NewF, OldF->getType()));
139 OldF->eraseFromParent();
140 NewF->setName(Name);
158 }
159
160 return !Replacements.empty();
161}
141 }
142
143 return !Replacements.empty();
144}