File: | build/source/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmTypeCheck.cpp |
Warning: | line 296, column 40 Called C++ object pointer is uninitialized |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | //==- WebAssemblyAsmTypeCheck.cpp - Assembler for WebAssembly -*- C++ -*-==// | |||
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 | /// This file is part of the WebAssembly Assembler. | |||
11 | /// | |||
12 | /// It contains code to translate a parsed .s file into MCInsts. | |||
13 | /// | |||
14 | //===----------------------------------------------------------------------===// | |||
15 | ||||
16 | #include "AsmParser/WebAssemblyAsmTypeCheck.h" | |||
17 | #include "MCTargetDesc/WebAssemblyMCTargetDesc.h" | |||
18 | #include "MCTargetDesc/WebAssemblyMCTypeUtilities.h" | |||
19 | #include "MCTargetDesc/WebAssemblyTargetStreamer.h" | |||
20 | #include "TargetInfo/WebAssemblyTargetInfo.h" | |||
21 | #include "WebAssembly.h" | |||
22 | #include "llvm/MC/MCContext.h" | |||
23 | #include "llvm/MC/MCExpr.h" | |||
24 | #include "llvm/MC/MCInst.h" | |||
25 | #include "llvm/MC/MCInstrInfo.h" | |||
26 | #include "llvm/MC/MCParser/MCParsedAsmOperand.h" | |||
27 | #include "llvm/MC/MCParser/MCTargetAsmParser.h" | |||
28 | #include "llvm/MC/MCSectionWasm.h" | |||
29 | #include "llvm/MC/MCStreamer.h" | |||
30 | #include "llvm/MC/MCSubtargetInfo.h" | |||
31 | #include "llvm/MC/MCSymbol.h" | |||
32 | #include "llvm/MC/MCSymbolWasm.h" | |||
33 | #include "llvm/MC/TargetRegistry.h" | |||
34 | #include "llvm/Support/Compiler.h" | |||
35 | #include "llvm/Support/Endian.h" | |||
36 | #include "llvm/Support/SourceMgr.h" | |||
37 | ||||
38 | using namespace llvm; | |||
39 | ||||
40 | #define DEBUG_TYPE"wasm-asm-parser" "wasm-asm-parser" | |||
41 | ||||
42 | extern StringRef GetMnemonic(unsigned Opc); | |||
43 | ||||
44 | namespace llvm { | |||
45 | ||||
46 | WebAssemblyAsmTypeCheck::WebAssemblyAsmTypeCheck(MCAsmParser &Parser, | |||
47 | const MCInstrInfo &MII, bool is64) | |||
48 | : Parser(Parser), MII(MII), is64(is64) { | |||
49 | } | |||
50 | ||||
51 | void WebAssemblyAsmTypeCheck::funcDecl(const wasm::WasmSignature &Sig) { | |||
52 | LocalTypes.assign(Sig.Params.begin(), Sig.Params.end()); | |||
53 | ReturnTypes.assign(Sig.Returns.begin(), Sig.Returns.end()); | |||
54 | } | |||
55 | ||||
56 | void WebAssemblyAsmTypeCheck::localDecl(const SmallVector<wasm::ValType, 4> &Locals) { | |||
57 | LocalTypes.insert(LocalTypes.end(), Locals.begin(), Locals.end()); | |||
58 | } | |||
59 | ||||
60 | void WebAssemblyAsmTypeCheck::dumpTypeStack(Twine Msg) { | |||
61 | LLVM_DEBUG({do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("wasm-asm-parser")) { { std::string s; for (auto VT : Stack) { s += WebAssembly::typeToString(VT); s += " "; } dbgs() << Msg << s << '\n'; }; } } while (false) | |||
62 | std::string s;do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("wasm-asm-parser")) { { std::string s; for (auto VT : Stack) { s += WebAssembly::typeToString(VT); s += " "; } dbgs() << Msg << s << '\n'; }; } } while (false) | |||
63 | for (auto VT : Stack) {do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("wasm-asm-parser")) { { std::string s; for (auto VT : Stack) { s += WebAssembly::typeToString(VT); s += " "; } dbgs() << Msg << s << '\n'; }; } } while (false) | |||
64 | s += WebAssembly::typeToString(VT);do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("wasm-asm-parser")) { { std::string s; for (auto VT : Stack) { s += WebAssembly::typeToString(VT); s += " "; } dbgs() << Msg << s << '\n'; }; } } while (false) | |||
65 | s += " ";do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("wasm-asm-parser")) { { std::string s; for (auto VT : Stack) { s += WebAssembly::typeToString(VT); s += " "; } dbgs() << Msg << s << '\n'; }; } } while (false) | |||
66 | }do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("wasm-asm-parser")) { { std::string s; for (auto VT : Stack) { s += WebAssembly::typeToString(VT); s += " "; } dbgs() << Msg << s << '\n'; }; } } while (false) | |||
67 | dbgs() << Msg << s << '\n';do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("wasm-asm-parser")) { { std::string s; for (auto VT : Stack) { s += WebAssembly::typeToString(VT); s += " "; } dbgs() << Msg << s << '\n'; }; } } while (false) | |||
68 | })do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("wasm-asm-parser")) { { std::string s; for (auto VT : Stack) { s += WebAssembly::typeToString(VT); s += " "; } dbgs() << Msg << s << '\n'; }; } } while (false); | |||
69 | } | |||
70 | ||||
71 | bool WebAssemblyAsmTypeCheck::typeError(SMLoc ErrorLoc, const Twine &Msg) { | |||
72 | // Once you get one type error in a function, it will likely trigger more | |||
73 | // which are mostly not helpful. | |||
74 | if (TypeErrorThisFunction) | |||
75 | return true; | |||
76 | // If we're currently in unreachable code, we suppress errors completely. | |||
77 | if (Unreachable) | |||
78 | return false; | |||
79 | TypeErrorThisFunction = true; | |||
80 | dumpTypeStack("current stack: "); | |||
81 | return Parser.Error(ErrorLoc, Msg); | |||
82 | } | |||
83 | ||||
84 | bool WebAssemblyAsmTypeCheck::popType(SMLoc ErrorLoc, | |||
85 | std::optional<wasm::ValType> EVT) { | |||
86 | if (Stack.empty()) { | |||
87 | return typeError(ErrorLoc, | |||
88 | EVT ? StringRef("empty stack while popping ") + | |||
89 | WebAssembly::typeToString(*EVT) | |||
90 | : StringRef("empty stack while popping value")); | |||
91 | } | |||
92 | auto PVT = Stack.pop_back_val(); | |||
93 | if (EVT && *EVT != PVT) { | |||
94 | return typeError(ErrorLoc, | |||
95 | StringRef("popped ") + WebAssembly::typeToString(PVT) + | |||
96 | ", expected " + WebAssembly::typeToString(*EVT)); | |||
97 | } | |||
98 | return false; | |||
99 | } | |||
100 | ||||
101 | bool WebAssemblyAsmTypeCheck::popRefType(SMLoc ErrorLoc) { | |||
102 | if (Stack.empty()) { | |||
103 | return typeError(ErrorLoc, StringRef("empty stack while popping reftype")); | |||
104 | } | |||
105 | auto PVT = Stack.pop_back_val(); | |||
106 | if (!WebAssembly::isRefType(PVT)) { | |||
107 | return typeError(ErrorLoc, StringRef("popped ") + | |||
108 | WebAssembly::typeToString(PVT) + | |||
109 | ", expected reftype"); | |||
110 | } | |||
111 | return false; | |||
112 | } | |||
113 | ||||
114 | bool WebAssemblyAsmTypeCheck::getLocal(SMLoc ErrorLoc, const MCInst &Inst, | |||
115 | wasm::ValType &Type) { | |||
116 | auto Local = static_cast<size_t>(Inst.getOperand(0).getImm()); | |||
117 | if (Local >= LocalTypes.size()) | |||
118 | return typeError(ErrorLoc, StringRef("no local type specified for index ") + | |||
119 | std::to_string(Local)); | |||
120 | Type = LocalTypes[Local]; | |||
121 | return false; | |||
122 | } | |||
123 | ||||
124 | bool WebAssemblyAsmTypeCheck::checkEnd(SMLoc ErrorLoc, bool PopVals) { | |||
125 | if (LastSig.Returns.size() > Stack.size()) | |||
126 | return typeError(ErrorLoc, "end: insufficient values on the type stack"); | |||
127 | ||||
128 | if (PopVals) { | |||
129 | for (auto VT : llvm::reverse(LastSig.Returns)) { | |||
130 | if (popType(ErrorLoc, VT)) | |||
131 | return true; | |||
132 | } | |||
133 | return false; | |||
134 | } | |||
135 | ||||
136 | for (size_t i = 0; i < LastSig.Returns.size(); i++) { | |||
137 | auto EVT = LastSig.Returns[i]; | |||
138 | auto PVT = Stack[Stack.size() - LastSig.Returns.size() + i]; | |||
139 | if (PVT != EVT) | |||
140 | return typeError( | |||
141 | ErrorLoc, StringRef("end got ") + WebAssembly::typeToString(PVT) + | |||
142 | ", expected " + WebAssembly::typeToString(EVT)); | |||
143 | } | |||
144 | return false; | |||
145 | } | |||
146 | ||||
147 | bool WebAssemblyAsmTypeCheck::checkSig(SMLoc ErrorLoc, | |||
148 | const wasm::WasmSignature& Sig) { | |||
149 | for (auto VT : llvm::reverse(Sig.Params)) | |||
150 | if (popType(ErrorLoc, VT)) return true; | |||
151 | Stack.insert(Stack.end(), Sig.Returns.begin(), Sig.Returns.end()); | |||
152 | return false; | |||
153 | } | |||
154 | ||||
155 | bool WebAssemblyAsmTypeCheck::getSymRef(SMLoc ErrorLoc, const MCInst &Inst, | |||
156 | const MCSymbolRefExpr *&SymRef) { | |||
157 | auto Op = Inst.getOperand(0); | |||
158 | if (!Op.isExpr()) | |||
159 | return typeError(ErrorLoc, StringRef("expected expression operand")); | |||
160 | SymRef = dyn_cast<MCSymbolRefExpr>(Op.getExpr()); | |||
161 | if (!SymRef) | |||
162 | return typeError(ErrorLoc, StringRef("expected symbol operand")); | |||
163 | return false; | |||
164 | } | |||
165 | ||||
166 | bool WebAssemblyAsmTypeCheck::getGlobal(SMLoc ErrorLoc, const MCInst &Inst, | |||
167 | wasm::ValType &Type) { | |||
168 | const MCSymbolRefExpr *SymRef; | |||
169 | if (getSymRef(ErrorLoc, Inst, SymRef)) | |||
170 | return true; | |||
171 | auto WasmSym = cast<MCSymbolWasm>(&SymRef->getSymbol()); | |||
172 | switch (WasmSym->getType().value_or(wasm::WASM_SYMBOL_TYPE_DATA)) { | |||
173 | case wasm::WASM_SYMBOL_TYPE_GLOBAL: | |||
174 | Type = static_cast<wasm::ValType>(WasmSym->getGlobalType().Type); | |||
175 | break; | |||
176 | case wasm::WASM_SYMBOL_TYPE_FUNCTION: | |||
177 | case wasm::WASM_SYMBOL_TYPE_DATA: | |||
178 | switch (SymRef->getKind()) { | |||
179 | case MCSymbolRefExpr::VK_GOT: | |||
180 | case MCSymbolRefExpr::VK_WASM_GOT_TLS: | |||
181 | Type = is64 ? wasm::ValType::I64 : wasm::ValType::I32; | |||
182 | return false; | |||
183 | default: | |||
184 | break; | |||
185 | } | |||
186 | [[fallthrough]]; | |||
187 | default: | |||
188 | return typeError(ErrorLoc, StringRef("symbol ") + WasmSym->getName() + | |||
189 | " missing .globaltype"); | |||
190 | } | |||
191 | return false; | |||
192 | } | |||
193 | ||||
194 | bool WebAssemblyAsmTypeCheck::getTable(SMLoc ErrorLoc, const MCInst &Inst, | |||
195 | wasm::ValType &Type) { | |||
196 | const MCSymbolRefExpr *SymRef; | |||
197 | if (getSymRef(ErrorLoc, Inst, SymRef)) | |||
198 | return true; | |||
199 | auto WasmSym = cast<MCSymbolWasm>(&SymRef->getSymbol()); | |||
200 | if (WasmSym->getType().value_or(wasm::WASM_SYMBOL_TYPE_DATA) != | |||
201 | wasm::WASM_SYMBOL_TYPE_TABLE) | |||
202 | return typeError(ErrorLoc, StringRef("symbol ") + WasmSym->getName() + | |||
203 | " missing .tabletype"); | |||
204 | Type = static_cast<wasm::ValType>(WasmSym->getTableType().ElemType); | |||
205 | return false; | |||
206 | } | |||
207 | ||||
208 | bool WebAssemblyAsmTypeCheck::endOfFunction(SMLoc ErrorLoc) { | |||
209 | // Check the return types. | |||
210 | for (auto RVT : llvm::reverse(ReturnTypes)) { | |||
211 | if (popType(ErrorLoc, RVT)) | |||
212 | return true; | |||
213 | } | |||
214 | if (!Stack.empty()) { | |||
215 | return typeError(ErrorLoc, std::to_string(Stack.size()) + | |||
216 | " superfluous return values"); | |||
217 | } | |||
218 | Unreachable = true; | |||
219 | return false; | |||
220 | } | |||
221 | ||||
222 | bool WebAssemblyAsmTypeCheck::typeCheck(SMLoc ErrorLoc, const MCInst &Inst, | |||
223 | OperandVector &Operands) { | |||
224 | auto Opc = Inst.getOpcode(); | |||
225 | auto Name = GetMnemonic(Opc); | |||
226 | dumpTypeStack("typechecking " + Name + ": "); | |||
227 | wasm::ValType Type; | |||
228 | if (Name == "local.get") { | |||
| ||||
229 | if (getLocal(Operands[1]->getStartLoc(), Inst, Type)) | |||
230 | return true; | |||
231 | Stack.push_back(Type); | |||
232 | } else if (Name == "local.set") { | |||
233 | if (getLocal(Operands[1]->getStartLoc(), Inst, Type)) | |||
234 | return true; | |||
235 | if (popType(ErrorLoc, Type)) | |||
236 | return true; | |||
237 | } else if (Name == "local.tee") { | |||
238 | if (getLocal(Operands[1]->getStartLoc(), Inst, Type)) | |||
239 | return true; | |||
240 | if (popType(ErrorLoc, Type)) | |||
241 | return true; | |||
242 | Stack.push_back(Type); | |||
243 | } else if (Name == "global.get") { | |||
244 | if (getGlobal(Operands[1]->getStartLoc(), Inst, Type)) | |||
245 | return true; | |||
246 | Stack.push_back(Type); | |||
247 | } else if (Name == "global.set") { | |||
248 | if (getGlobal(Operands[1]->getStartLoc(), Inst, Type)) | |||
249 | return true; | |||
250 | if (popType(ErrorLoc, Type)) | |||
251 | return true; | |||
252 | } else if (Name == "table.get") { | |||
253 | if (getTable(Operands[1]->getStartLoc(), Inst, Type)) | |||
254 | return true; | |||
255 | if (popType(ErrorLoc, wasm::ValType::I32)) | |||
256 | return true; | |||
257 | Stack.push_back(Type); | |||
258 | } else if (Name == "table.set") { | |||
259 | if (getTable(Operands[1]->getStartLoc(), Inst, Type)) | |||
260 | return true; | |||
261 | if (popType(ErrorLoc, Type)) | |||
262 | return true; | |||
263 | if (popType(ErrorLoc, wasm::ValType::I32)) | |||
264 | return true; | |||
265 | } else if (Name == "table.fill") { | |||
266 | if (getTable(Operands[1]->getStartLoc(), Inst, Type)) | |||
267 | return true; | |||
268 | if (popType(ErrorLoc, wasm::ValType::I32)) | |||
269 | return true; | |||
270 | if (popType(ErrorLoc, Type)) | |||
271 | return true; | |||
272 | if (popType(ErrorLoc, wasm::ValType::I32)) | |||
273 | return true; | |||
274 | } else if (Name == "drop") { | |||
275 | if (popType(ErrorLoc, {})) | |||
276 | return true; | |||
277 | } else if (Name == "end_block" || Name == "end_loop" || Name == "end_if" || | |||
278 | Name == "else" || Name == "end_try") { | |||
279 | if (checkEnd(ErrorLoc, Name == "else")) | |||
280 | return true; | |||
281 | if (Name == "end_block") | |||
282 | Unreachable = false; | |||
283 | } else if (Name == "return") { | |||
284 | if (endOfFunction(ErrorLoc)) | |||
285 | return true; | |||
286 | } else if (Name == "call_indirect" || Name == "return_call_indirect") { | |||
287 | // Function value. | |||
288 | if (popType(ErrorLoc, wasm::ValType::I32)) return true; | |||
289 | if (checkSig(ErrorLoc, LastSig)) return true; | |||
290 | if (Name == "return_call_indirect" && endOfFunction(ErrorLoc)) | |||
291 | return true; | |||
292 | } else if (Name == "call" || Name == "return_call") { | |||
293 | const MCSymbolRefExpr *SymRef; | |||
294 | if (getSymRef(Operands[1]->getStartLoc(), Inst, SymRef)) | |||
295 | return true; | |||
296 | auto WasmSym = cast<MCSymbolWasm>(&SymRef->getSymbol()); | |||
| ||||
297 | auto Sig = WasmSym->getSignature(); | |||
298 | if (!Sig || WasmSym->getType() != wasm::WASM_SYMBOL_TYPE_FUNCTION) | |||
299 | return typeError(Operands[1]->getStartLoc(), StringRef("symbol ") + | |||
300 | WasmSym->getName() + | |||
301 | " missing .functype"); | |||
302 | if (checkSig(ErrorLoc, *Sig)) return true; | |||
303 | if (Name == "return_call" && endOfFunction(ErrorLoc)) | |||
304 | return true; | |||
305 | } else if (Name == "catch") { | |||
306 | const MCSymbolRefExpr *SymRef; | |||
307 | if (getSymRef(Operands[1]->getStartLoc(), Inst, SymRef)) | |||
308 | return true; | |||
309 | const auto *WasmSym = cast<MCSymbolWasm>(&SymRef->getSymbol()); | |||
310 | const auto *Sig = WasmSym->getSignature(); | |||
311 | if (!Sig || WasmSym->getType() != wasm::WASM_SYMBOL_TYPE_TAG) | |||
312 | return typeError(Operands[1]->getStartLoc(), StringRef("symbol ") + | |||
313 | WasmSym->getName() + | |||
314 | " missing .tagtype"); | |||
315 | // catch instruction pushes values whose types are specified in the tag's | |||
316 | // "params" part | |||
317 | Stack.insert(Stack.end(), Sig->Params.begin(), Sig->Params.end()); | |||
318 | } else if (Name == "unreachable") { | |||
319 | Unreachable = true; | |||
320 | } else if (Name == "ref.is_null") { | |||
321 | if (popRefType(ErrorLoc)) | |||
322 | return true; | |||
323 | Stack.push_back(wasm::ValType::I32); | |||
324 | } else { | |||
325 | // The current instruction is a stack instruction which doesn't have | |||
326 | // explicit operands that indicate push/pop types, so we get those from | |||
327 | // the register version of the same instruction. | |||
328 | auto RegOpc = WebAssembly::getRegisterOpcode(Opc); | |||
329 | assert(RegOpc != -1 && "Failed to get register version of MC instruction")(static_cast <bool> (RegOpc != -1 && "Failed to get register version of MC instruction" ) ? void (0) : __assert_fail ("RegOpc != -1 && \"Failed to get register version of MC instruction\"" , "llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmTypeCheck.cpp" , 329, __extension__ __PRETTY_FUNCTION__)); | |||
330 | const auto &II = MII.get(RegOpc); | |||
331 | // First pop all the uses off the stack and check them. | |||
332 | for (unsigned I = II.getNumOperands(); I > II.getNumDefs(); I--) { | |||
333 | const auto &Op = II.operands()[I - 1]; | |||
334 | if (Op.OperandType == MCOI::OPERAND_REGISTER) { | |||
335 | auto VT = WebAssembly::regClassToValType(Op.RegClass); | |||
336 | if (popType(ErrorLoc, VT)) | |||
337 | return true; | |||
338 | } | |||
339 | } | |||
340 | // Now push all the defs onto the stack. | |||
341 | for (unsigned I = 0; I < II.getNumDefs(); I++) { | |||
342 | const auto &Op = II.operands()[I]; | |||
343 | assert(Op.OperandType == MCOI::OPERAND_REGISTER && "Register expected")(static_cast <bool> (Op.OperandType == MCOI::OPERAND_REGISTER && "Register expected") ? void (0) : __assert_fail ( "Op.OperandType == MCOI::OPERAND_REGISTER && \"Register expected\"" , "llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmTypeCheck.cpp" , 343, __extension__ __PRETTY_FUNCTION__)); | |||
344 | auto VT = WebAssembly::regClassToValType(Op.RegClass); | |||
345 | Stack.push_back(VT); | |||
346 | } | |||
347 | } | |||
348 | return false; | |||
349 | } | |||
350 | ||||
351 | } // end namespace llvm |