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} |