/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | // WebAssemblyMCInstLower.cpp - Convert WebAssembly MachineInstr to an MCInst // |
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 contains code to lower WebAssembly MachineInstrs to their |
11 | | /// corresponding MCInst records. |
12 | | /// |
13 | | //===----------------------------------------------------------------------===// |
14 | | |
15 | | #include "WebAssemblyMCInstLower.h" |
16 | | #include "WebAssemblyAsmPrinter.h" |
17 | | #include "WebAssemblyMachineFunctionInfo.h" |
18 | | #include "WebAssemblyRuntimeLibcallSignatures.h" |
19 | | #include "MCTargetDesc/WebAssemblyMCTargetDesc.h" |
20 | | #include "llvm/CodeGen/AsmPrinter.h" |
21 | | #include "llvm/CodeGen/MachineFunction.h" |
22 | | #include "llvm/IR/Constants.h" |
23 | | #include "llvm/MC/MCAsmInfo.h" |
24 | | #include "llvm/MC/MCContext.h" |
25 | | #include "llvm/MC/MCExpr.h" |
26 | | #include "llvm/MC/MCInst.h" |
27 | | #include "llvm/MC/MCSymbolWasm.h" |
28 | | #include "llvm/Support/ErrorHandling.h" |
29 | | #include "llvm/Support/raw_ostream.h" |
30 | | using namespace llvm; |
31 | | |
32 | | // Defines llvm::WebAssembly::getStackOpcode to convert register instructions to |
33 | | // stack instructions |
34 | | #define GET_INSTRMAP_INFO 1 |
35 | | #include "WebAssemblyGenInstrInfo.inc" |
36 | | |
37 | | // This disables the removal of registers when lowering into MC, as required |
38 | | // by some current tests. |
39 | | cl::opt<bool> |
40 | | WasmKeepRegisters("wasm-keep-registers", cl::Hidden, |
41 | | cl::desc("WebAssembly: output stack registers in" |
42 | | " instruction output for test purposes only."), |
43 | | cl::init(false)); |
44 | | |
45 | | static void removeRegisterOperands(const MachineInstr *MI, MCInst &OutMI); |
46 | | |
47 | | MCSymbol * |
48 | 1.25k | WebAssemblyMCInstLower::GetGlobalAddressSymbol(const MachineOperand &MO) const { |
49 | 1.25k | const GlobalValue *Global = MO.getGlobal(); |
50 | 1.25k | auto *WasmSym = cast<MCSymbolWasm>(Printer.getSymbol(Global)); |
51 | 1.25k | |
52 | 1.25k | if (const auto *FuncTy = dyn_cast<FunctionType>(Global->getValueType())) { |
53 | 727 | const MachineFunction &MF = *MO.getParent()->getParent()->getParent(); |
54 | 727 | const TargetMachine &TM = MF.getTarget(); |
55 | 727 | const Function &CurrentFunc = MF.getFunction(); |
56 | 727 | |
57 | 727 | SmallVector<MVT, 1> ResultMVTs; |
58 | 727 | SmallVector<MVT, 4> ParamMVTs; |
59 | 727 | computeSignatureVTs(FuncTy, CurrentFunc, TM, ParamMVTs, ResultMVTs); |
60 | 727 | |
61 | 727 | auto Signature = signatureFromMVTs(ResultMVTs, ParamMVTs); |
62 | 727 | WasmSym->setSignature(Signature.get()); |
63 | 727 | Printer.addSignature(std::move(Signature)); |
64 | 727 | WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION); |
65 | 727 | } |
66 | 1.25k | |
67 | 1.25k | return WasmSym; |
68 | 1.25k | } |
69 | | |
70 | | MCSymbol *WebAssemblyMCInstLower::GetExternalSymbolSymbol( |
71 | 772 | const MachineOperand &MO) const { |
72 | 772 | const char *Name = MO.getSymbolName(); |
73 | 772 | auto *WasmSym = cast<MCSymbolWasm>(Printer.GetExternalSymbolSymbol(Name)); |
74 | 772 | const WebAssemblySubtarget &Subtarget = Printer.getSubtarget(); |
75 | 772 | |
76 | 772 | // Except for certain known symbols, all symbols used by CodeGen are |
77 | 772 | // functions. It's OK to hardcode knowledge of specific symbols here; this |
78 | 772 | // method is precisely there for fetching the signatures of known |
79 | 772 | // Clang-provided symbols. |
80 | 772 | if (strcmp(Name, "__stack_pointer") == 0 || strcmp(Name, "__tls_base") == 0327 || |
81 | 772 | strcmp(Name, "__memory_base") == 0301 || strcmp(Name, "__table_base") == 0290 || |
82 | 772 | strcmp(Name, "__tls_size") == 0287 || strcmp(Name, "__tls_align") == 0281 ) { |
83 | 495 | bool Mutable = |
84 | 495 | strcmp(Name, "__stack_pointer") == 0 || strcmp(Name, "__tls_base") == 050 ; |
85 | 495 | WasmSym->setType(wasm::WASM_SYMBOL_TYPE_GLOBAL); |
86 | 495 | WasmSym->setGlobalType(wasm::WasmGlobalType{ |
87 | 495 | uint8_t(Subtarget.hasAddr64() ? wasm::WASM_TYPE_I640 |
88 | 495 | : wasm::WASM_TYPE_I32), |
89 | 495 | Mutable}); |
90 | 495 | return WasmSym; |
91 | 495 | } |
92 | 277 | |
93 | 277 | SmallVector<wasm::ValType, 4> Returns; |
94 | 277 | SmallVector<wasm::ValType, 4> Params; |
95 | 277 | if (strcmp(Name, "__cpp_exception") == 0) { |
96 | 51 | WasmSym->setType(wasm::WASM_SYMBOL_TYPE_EVENT); |
97 | 51 | // We can't confirm its signature index for now because there can be |
98 | 51 | // imported exceptions. Set it to be 0 for now. |
99 | 51 | WasmSym->setEventType( |
100 | 51 | {wasm::WASM_EVENT_ATTRIBUTE_EXCEPTION, /* SigIndex */ 0}); |
101 | 51 | // We may have multiple C++ compilation units to be linked together, each of |
102 | 51 | // which defines the exception symbol. To resolve them, we declare them as |
103 | 51 | // weak. |
104 | 51 | WasmSym->setWeak(true); |
105 | 51 | WasmSym->setExternal(true); |
106 | 51 | |
107 | 51 | // All C++ exceptions are assumed to have a single i32 (for wasm32) or i64 |
108 | 51 | // (for wasm64) param type and void return type. The reaon is, all C++ |
109 | 51 | // exception values are pointers, and to share the type section with |
110 | 51 | // functions, exceptions are assumed to have void return type. |
111 | 51 | Params.push_back(Subtarget.hasAddr64() ? wasm::ValType::I640 |
112 | 51 | : wasm::ValType::I32); |
113 | 226 | } else { // Function symbols |
114 | 226 | WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION); |
115 | 226 | getLibcallSignature(Subtarget, Name, Returns, Params); |
116 | 226 | } |
117 | 277 | auto Signature = |
118 | 277 | make_unique<wasm::WasmSignature>(std::move(Returns), std::move(Params)); |
119 | 277 | WasmSym->setSignature(Signature.get()); |
120 | 277 | Printer.addSignature(std::move(Signature)); |
121 | 277 | |
122 | 277 | return WasmSym; |
123 | 277 | } |
124 | | |
125 | | MCOperand WebAssemblyMCInstLower::lowerSymbolOperand(const MachineOperand &MO, |
126 | 2.03k | MCSymbol *Sym) const { |
127 | 2.03k | MCSymbolRefExpr::VariantKind Kind = MCSymbolRefExpr::VK_None; |
128 | 2.03k | unsigned TargetFlags = MO.getTargetFlags(); |
129 | 2.03k | |
130 | 2.03k | switch (TargetFlags) { |
131 | 2.03k | case WebAssemblyII::MO_NO_FLAG: |
132 | 1.98k | break; |
133 | 2.03k | case WebAssemblyII::MO_GOT: |
134 | 40 | Kind = MCSymbolRefExpr::VK_GOT; |
135 | 40 | break; |
136 | 2.03k | case WebAssemblyII::MO_MEMORY_BASE_REL: |
137 | 11 | Kind = MCSymbolRefExpr::VK_WASM_MBREL; |
138 | 11 | break; |
139 | 2.03k | case WebAssemblyII::MO_TABLE_BASE_REL: |
140 | 3 | Kind = MCSymbolRefExpr::VK_WASM_TBREL; |
141 | 3 | break; |
142 | 2.03k | default: |
143 | 0 | llvm_unreachable("Unknown target flag on GV operand"); |
144 | 2.03k | } |
145 | 2.03k | |
146 | 2.03k | const MCExpr *Expr = MCSymbolRefExpr::create(Sym, Kind, Ctx); |
147 | 2.03k | |
148 | 2.03k | if (MO.getOffset() != 0) { |
149 | 102 | const auto *WasmSym = cast<MCSymbolWasm>(Sym); |
150 | 102 | if (TargetFlags == WebAssemblyII::MO_GOT) |
151 | 0 | report_fatal_error("GOT symbol references do not support offsets"); |
152 | 102 | if (WasmSym->isFunction()) |
153 | 0 | report_fatal_error("Function addresses with offsets not supported"); |
154 | 102 | if (WasmSym->isGlobal()) |
155 | 0 | report_fatal_error("Global indexes with offsets not supported"); |
156 | 102 | if (WasmSym->isEvent()) |
157 | 0 | report_fatal_error("Event indexes with offsets not supported"); |
158 | 102 | |
159 | 102 | Expr = MCBinaryExpr::createAdd( |
160 | 102 | Expr, MCConstantExpr::create(MO.getOffset(), Ctx), Ctx); |
161 | 102 | } |
162 | 2.03k | |
163 | 2.03k | return MCOperand::createExpr(Expr); |
164 | 2.03k | } |
165 | | |
166 | | // Return the WebAssembly type associated with the given register class. |
167 | 171 | static wasm::ValType getType(const TargetRegisterClass *RC) { |
168 | 171 | if (RC == &WebAssembly::I32RegClass) |
169 | 144 | return wasm::ValType::I32; |
170 | 27 | if (RC == &WebAssembly::I64RegClass) |
171 | 13 | return wasm::ValType::I64; |
172 | 14 | if (RC == &WebAssembly::F32RegClass) |
173 | 5 | return wasm::ValType::F32; |
174 | 9 | if (RC == &WebAssembly::F64RegClass) |
175 | 5 | return wasm::ValType::F64; |
176 | 4 | if (RC == &WebAssembly::V128RegClass) |
177 | 4 | return wasm::ValType::V128; |
178 | 0 | llvm_unreachable("Unexpected register class"); |
179 | 0 | } |
180 | | |
181 | | void WebAssemblyMCInstLower::lower(const MachineInstr *MI, |
182 | 47.7k | MCInst &OutMI) const { |
183 | 47.7k | OutMI.setOpcode(MI->getOpcode()); |
184 | 47.7k | |
185 | 47.7k | const MCInstrDesc &Desc = MI->getDesc(); |
186 | 278k | for (unsigned I = 0, E = MI->getNumOperands(); I != E; ++I230k ) { |
187 | 230k | const MachineOperand &MO = MI->getOperand(I); |
188 | 230k | |
189 | 230k | MCOperand MCOp; |
190 | 230k | switch (MO.getType()) { |
191 | 230k | default: |
192 | 0 | MI->print(errs()); |
193 | 0 | llvm_unreachable("unknown operand type"); |
194 | 230k | case MachineOperand::MO_MachineBasicBlock: |
195 | 0 | MI->print(errs()); |
196 | 0 | llvm_unreachable("MachineBasicBlock operand should have been rewritten"); |
197 | 230k | case MachineOperand::MO_Register: { |
198 | 200k | // Ignore all implicit register operands. |
199 | 200k | if (MO.isImplicit()) |
200 | 120k | continue; |
201 | 79.4k | const WebAssemblyFunctionInfo &MFI = |
202 | 79.4k | *MI->getParent()->getParent()->getInfo<WebAssemblyFunctionInfo>(); |
203 | 79.4k | unsigned WAReg = MFI.getWAReg(MO.getReg()); |
204 | 79.4k | MCOp = MCOperand::createReg(WAReg); |
205 | 79.4k | break; |
206 | 79.4k | } |
207 | 79.4k | case MachineOperand::MO_Immediate: |
208 | 28.4k | if (I < Desc.NumOperands) { |
209 | 28.3k | const MCOperandInfo &Info = Desc.OpInfo[I]; |
210 | 28.3k | if (Info.OperandType == WebAssembly::OPERAND_TYPEINDEX) { |
211 | 70 | MCSymbol *Sym = Printer.createTempSymbol("typeindex"); |
212 | 70 | |
213 | 70 | SmallVector<wasm::ValType, 4> Returns; |
214 | 70 | SmallVector<wasm::ValType, 4> Params; |
215 | 70 | |
216 | 70 | const MachineRegisterInfo &MRI = |
217 | 70 | MI->getParent()->getParent()->getRegInfo(); |
218 | 70 | for (const MachineOperand &MO : MI->defs()) |
219 | 50 | Returns.push_back(getType(MRI.getRegClass(MO.getReg()))); |
220 | 70 | for (const MachineOperand &MO : MI->explicit_uses()) |
221 | 261 | if (MO.isReg()) |
222 | 121 | Params.push_back(getType(MRI.getRegClass(MO.getReg()))); |
223 | 70 | |
224 | 70 | // call_indirect instructions have a callee operand at the end which |
225 | 70 | // doesn't count as a param. |
226 | 70 | if (WebAssembly::isCallIndirect(MI->getOpcode())) |
227 | 70 | Params.pop_back(); |
228 | 70 | |
229 | 70 | auto *WasmSym = cast<MCSymbolWasm>(Sym); |
230 | 70 | auto Signature = make_unique<wasm::WasmSignature>(std::move(Returns), |
231 | 70 | std::move(Params)); |
232 | 70 | WasmSym->setSignature(Signature.get()); |
233 | 70 | Printer.addSignature(std::move(Signature)); |
234 | 70 | WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION); |
235 | 70 | |
236 | 70 | const MCExpr *Expr = MCSymbolRefExpr::create( |
237 | 70 | WasmSym, MCSymbolRefExpr::VK_WASM_TYPEINDEX, Ctx); |
238 | 70 | MCOp = MCOperand::createExpr(Expr); |
239 | 70 | break; |
240 | 70 | } |
241 | 28.3k | } |
242 | 28.3k | MCOp = MCOperand::createImm(MO.getImm()); |
243 | 28.3k | break; |
244 | 28.3k | case MachineOperand::MO_FPImmediate: { |
245 | 251 | // TODO: MC converts all floating point immediate operands to double. |
246 | 251 | // This is fine for numeric values, but may cause NaNs to change bits. |
247 | 251 | const ConstantFP *Imm = MO.getFPImm(); |
248 | 251 | if (Imm->getType()->isFloatTy()) |
249 | 129 | MCOp = MCOperand::createFPImm(Imm->getValueAPF().convertToFloat()); |
250 | 122 | else if (Imm->getType()->isDoubleTy()) |
251 | 122 | MCOp = MCOperand::createFPImm(Imm->getValueAPF().convertToDouble()); |
252 | 122 | else |
253 | 122 | llvm_unreachable0 ("unknown floating point immediate type"); |
254 | 251 | break; |
255 | 251 | } |
256 | 1.25k | case MachineOperand::MO_GlobalAddress: |
257 | 1.25k | MCOp = lowerSymbolOperand(MO, GetGlobalAddressSymbol(MO)); |
258 | 1.25k | break; |
259 | 772 | case MachineOperand::MO_ExternalSymbol: |
260 | 772 | // The target flag indicates whether this is a symbol for a |
261 | 772 | // variable or a function. |
262 | 772 | assert(MO.getTargetFlags() == 0 && |
263 | 772 | "WebAssembly uses only symbol flags on ExternalSymbols"); |
264 | 772 | MCOp = lowerSymbolOperand(MO, GetExternalSymbolSymbol(MO)); |
265 | 772 | break; |
266 | 251 | case MachineOperand::MO_MCSymbol: |
267 | 13 | // This is currently used only for LSDA symbols (GCC_except_table), |
268 | 13 | // because global addresses or other external symbols are handled above. |
269 | 13 | assert(MO.getTargetFlags() == 0 && |
270 | 13 | "WebAssembly does not use target flags on MCSymbol"); |
271 | 13 | MCOp = lowerSymbolOperand(MO, MO.getMCSymbol()); |
272 | 13 | break; |
273 | 110k | } |
274 | 110k | |
275 | 110k | OutMI.addOperand(MCOp); |
276 | 110k | } |
277 | 47.7k | |
278 | 47.7k | if (!WasmKeepRegisters) |
279 | 7.35k | removeRegisterOperands(MI, OutMI); |
280 | 47.7k | } |
281 | | |
282 | 7.35k | static void removeRegisterOperands(const MachineInstr *MI, MCInst &OutMI) { |
283 | 7.35k | // Remove all uses of stackified registers to bring the instruction format |
284 | 7.35k | // into its final stack form used thruout MC, and transition opcodes to |
285 | 7.35k | // their _S variant. |
286 | 7.35k | // We do this seperate from the above code that still may need these |
287 | 7.35k | // registers for e.g. call_indirect signatures. |
288 | 7.35k | // See comments in lib/Target/WebAssembly/WebAssemblyInstrFormats.td for |
289 | 7.35k | // details. |
290 | 7.35k | // TODO: the code above creates new registers which are then removed here. |
291 | 7.35k | // That code could be slightly simplified by not doing that, though maybe |
292 | 7.35k | // it is simpler conceptually to keep the code above in "register mode" |
293 | 7.35k | // until this transition point. |
294 | 7.35k | // FIXME: we are not processing inline assembly, which contains register |
295 | 7.35k | // operands, because it is used by later target generic code. |
296 | 7.35k | if (MI->isDebugInstr()7.35k || MI->isLabel()7.35k || MI->isInlineAsm()) |
297 | 0 | return; |
298 | 7.35k | |
299 | 7.35k | // Transform to _S instruction. |
300 | 7.35k | auto RegOpcode = OutMI.getOpcode(); |
301 | 7.35k | auto StackOpcode = WebAssembly::getStackOpcode(RegOpcode); |
302 | 7.35k | assert(StackOpcode != -1 && "Failed to stackify instruction"); |
303 | 7.35k | OutMI.setOpcode(StackOpcode); |
304 | 7.35k | |
305 | 7.35k | // Remove register operands. |
306 | 22.4k | for (auto I = OutMI.getNumOperands(); I; --I15.0k ) { |
307 | 15.0k | auto &MO = OutMI.getOperand(I - 1); |
308 | 15.0k | if (MO.isReg()) { |
309 | 9.51k | OutMI.erase(&MO); |
310 | 9.51k | } |
311 | 15.0k | } |
312 | 7.35k | } |