File: | build/source/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp |
Warning: | line 2152, column 9 The result of the left shift is undefined due to shifting by '127', which is greater or equal to the width of type 'long long' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | //=- WebAssemblyISelLowering.cpp - WebAssembly DAG Lowering Implementation -==// | |||
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 implements the WebAssemblyTargetLowering class. | |||
11 | /// | |||
12 | //===----------------------------------------------------------------------===// | |||
13 | ||||
14 | #include "WebAssemblyISelLowering.h" | |||
15 | #include "MCTargetDesc/WebAssemblyMCTargetDesc.h" | |||
16 | #include "Utils/WebAssemblyTypeUtilities.h" | |||
17 | #include "Utils/WebAssemblyUtilities.h" | |||
18 | #include "WebAssemblyMachineFunctionInfo.h" | |||
19 | #include "WebAssemblySubtarget.h" | |||
20 | #include "WebAssemblyTargetMachine.h" | |||
21 | #include "llvm/CodeGen/CallingConvLower.h" | |||
22 | #include "llvm/CodeGen/MachineFrameInfo.h" | |||
23 | #include "llvm/CodeGen/MachineFunctionPass.h" | |||
24 | #include "llvm/CodeGen/MachineInstrBuilder.h" | |||
25 | #include "llvm/CodeGen/MachineJumpTableInfo.h" | |||
26 | #include "llvm/CodeGen/MachineModuleInfo.h" | |||
27 | #include "llvm/CodeGen/MachineRegisterInfo.h" | |||
28 | #include "llvm/CodeGen/SelectionDAG.h" | |||
29 | #include "llvm/CodeGen/SelectionDAGNodes.h" | |||
30 | #include "llvm/IR/DiagnosticInfo.h" | |||
31 | #include "llvm/IR/DiagnosticPrinter.h" | |||
32 | #include "llvm/IR/Function.h" | |||
33 | #include "llvm/IR/Intrinsics.h" | |||
34 | #include "llvm/IR/IntrinsicsWebAssembly.h" | |||
35 | #include "llvm/Support/Debug.h" | |||
36 | #include "llvm/Support/ErrorHandling.h" | |||
37 | #include "llvm/Support/KnownBits.h" | |||
38 | #include "llvm/Support/MathExtras.h" | |||
39 | #include "llvm/Support/raw_ostream.h" | |||
40 | #include "llvm/Target/TargetOptions.h" | |||
41 | using namespace llvm; | |||
42 | ||||
43 | #define DEBUG_TYPE"wasm-lower" "wasm-lower" | |||
44 | ||||
45 | WebAssemblyTargetLowering::WebAssemblyTargetLowering( | |||
46 | const TargetMachine &TM, const WebAssemblySubtarget &STI) | |||
47 | : TargetLowering(TM), Subtarget(&STI) { | |||
48 | auto MVTPtr = Subtarget->hasAddr64() ? MVT::i64 : MVT::i32; | |||
49 | ||||
50 | // Booleans always contain 0 or 1. | |||
51 | setBooleanContents(ZeroOrOneBooleanContent); | |||
52 | // Except in SIMD vectors | |||
53 | setBooleanVectorContents(ZeroOrNegativeOneBooleanContent); | |||
54 | // We don't know the microarchitecture here, so just reduce register pressure. | |||
55 | setSchedulingPreference(Sched::RegPressure); | |||
56 | // Tell ISel that we have a stack pointer. | |||
57 | setStackPointerRegisterToSaveRestore( | |||
58 | Subtarget->hasAddr64() ? WebAssembly::SP64 : WebAssembly::SP32); | |||
59 | // Set up the register classes. | |||
60 | addRegisterClass(MVT::i32, &WebAssembly::I32RegClass); | |||
61 | addRegisterClass(MVT::i64, &WebAssembly::I64RegClass); | |||
62 | addRegisterClass(MVT::f32, &WebAssembly::F32RegClass); | |||
63 | addRegisterClass(MVT::f64, &WebAssembly::F64RegClass); | |||
64 | if (Subtarget->hasSIMD128()) { | |||
65 | addRegisterClass(MVT::v16i8, &WebAssembly::V128RegClass); | |||
66 | addRegisterClass(MVT::v8i16, &WebAssembly::V128RegClass); | |||
67 | addRegisterClass(MVT::v4i32, &WebAssembly::V128RegClass); | |||
68 | addRegisterClass(MVT::v4f32, &WebAssembly::V128RegClass); | |||
69 | addRegisterClass(MVT::v2i64, &WebAssembly::V128RegClass); | |||
70 | addRegisterClass(MVT::v2f64, &WebAssembly::V128RegClass); | |||
71 | } | |||
72 | if (Subtarget->hasReferenceTypes()) { | |||
73 | addRegisterClass(MVT::externref, &WebAssembly::EXTERNREFRegClass); | |||
74 | addRegisterClass(MVT::funcref, &WebAssembly::FUNCREFRegClass); | |||
75 | } | |||
76 | // Compute derived properties from the register classes. | |||
77 | computeRegisterProperties(Subtarget->getRegisterInfo()); | |||
78 | ||||
79 | // Transform loads and stores to pointers in address space 1 to loads and | |||
80 | // stores to WebAssembly global variables, outside linear memory. | |||
81 | for (auto T : {MVT::i32, MVT::i64, MVT::f32, MVT::f64}) { | |||
82 | setOperationAction(ISD::LOAD, T, Custom); | |||
83 | setOperationAction(ISD::STORE, T, Custom); | |||
84 | } | |||
85 | if (Subtarget->hasSIMD128()) { | |||
86 | for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v4f32, MVT::v2i64, | |||
87 | MVT::v2f64}) { | |||
88 | setOperationAction(ISD::LOAD, T, Custom); | |||
89 | setOperationAction(ISD::STORE, T, Custom); | |||
90 | } | |||
91 | } | |||
92 | if (Subtarget->hasReferenceTypes()) { | |||
93 | // We need custom load and store lowering for both externref, funcref and | |||
94 | // Other. The MVT::Other here represents tables of reference types. | |||
95 | for (auto T : {MVT::externref, MVT::funcref, MVT::Other}) { | |||
96 | setOperationAction(ISD::LOAD, T, Custom); | |||
97 | setOperationAction(ISD::STORE, T, Custom); | |||
98 | } | |||
99 | } | |||
100 | ||||
101 | setOperationAction(ISD::GlobalAddress, MVTPtr, Custom); | |||
102 | setOperationAction(ISD::GlobalTLSAddress, MVTPtr, Custom); | |||
103 | setOperationAction(ISD::ExternalSymbol, MVTPtr, Custom); | |||
104 | setOperationAction(ISD::JumpTable, MVTPtr, Custom); | |||
105 | setOperationAction(ISD::BlockAddress, MVTPtr, Custom); | |||
106 | setOperationAction(ISD::BRIND, MVT::Other, Custom); | |||
107 | ||||
108 | // Take the default expansion for va_arg, va_copy, and va_end. There is no | |||
109 | // default action for va_start, so we do that custom. | |||
110 | setOperationAction(ISD::VASTART, MVT::Other, Custom); | |||
111 | setOperationAction(ISD::VAARG, MVT::Other, Expand); | |||
112 | setOperationAction(ISD::VACOPY, MVT::Other, Expand); | |||
113 | setOperationAction(ISD::VAEND, MVT::Other, Expand); | |||
114 | ||||
115 | for (auto T : {MVT::f32, MVT::f64, MVT::v4f32, MVT::v2f64}) { | |||
116 | // Don't expand the floating-point types to constant pools. | |||
117 | setOperationAction(ISD::ConstantFP, T, Legal); | |||
118 | // Expand floating-point comparisons. | |||
119 | for (auto CC : {ISD::SETO, ISD::SETUO, ISD::SETUEQ, ISD::SETONE, | |||
120 | ISD::SETULT, ISD::SETULE, ISD::SETUGT, ISD::SETUGE}) | |||
121 | setCondCodeAction(CC, T, Expand); | |||
122 | // Expand floating-point library function operators. | |||
123 | for (auto Op : | |||
124 | {ISD::FSIN, ISD::FCOS, ISD::FSINCOS, ISD::FPOW, ISD::FREM, ISD::FMA}) | |||
125 | setOperationAction(Op, T, Expand); | |||
126 | // Note supported floating-point library function operators that otherwise | |||
127 | // default to expand. | |||
128 | for (auto Op : | |||
129 | {ISD::FCEIL, ISD::FFLOOR, ISD::FTRUNC, ISD::FNEARBYINT, ISD::FRINT}) | |||
130 | setOperationAction(Op, T, Legal); | |||
131 | // Support minimum and maximum, which otherwise default to expand. | |||
132 | setOperationAction(ISD::FMINIMUM, T, Legal); | |||
133 | setOperationAction(ISD::FMAXIMUM, T, Legal); | |||
134 | // WebAssembly currently has no builtin f16 support. | |||
135 | setOperationAction(ISD::FP16_TO_FP, T, Expand); | |||
136 | setOperationAction(ISD::FP_TO_FP16, T, Expand); | |||
137 | setLoadExtAction(ISD::EXTLOAD, T, MVT::f16, Expand); | |||
138 | setTruncStoreAction(T, MVT::f16, Expand); | |||
139 | } | |||
140 | ||||
141 | // Expand unavailable integer operations. | |||
142 | for (auto Op : | |||
143 | {ISD::BSWAP, ISD::SMUL_LOHI, ISD::UMUL_LOHI, ISD::MULHS, ISD::MULHU, | |||
144 | ISD::SDIVREM, ISD::UDIVREM, ISD::SHL_PARTS, ISD::SRA_PARTS, | |||
145 | ISD::SRL_PARTS, ISD::ADDC, ISD::ADDE, ISD::SUBC, ISD::SUBE}) { | |||
146 | for (auto T : {MVT::i32, MVT::i64}) | |||
147 | setOperationAction(Op, T, Expand); | |||
148 | if (Subtarget->hasSIMD128()) | |||
149 | for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v2i64}) | |||
150 | setOperationAction(Op, T, Expand); | |||
151 | } | |||
152 | ||||
153 | if (Subtarget->hasNontrappingFPToInt()) | |||
154 | for (auto Op : {ISD::FP_TO_SINT_SAT, ISD::FP_TO_UINT_SAT}) | |||
155 | for (auto T : {MVT::i32, MVT::i64}) | |||
156 | setOperationAction(Op, T, Custom); | |||
157 | ||||
158 | // SIMD-specific configuration | |||
159 | if (Subtarget->hasSIMD128()) { | |||
160 | // Hoist bitcasts out of shuffles | |||
161 | setTargetDAGCombine(ISD::VECTOR_SHUFFLE); | |||
162 | ||||
163 | // Combine extends of extract_subvectors into widening ops | |||
164 | setTargetDAGCombine({ISD::SIGN_EXTEND, ISD::ZERO_EXTEND}); | |||
165 | ||||
166 | // Combine int_to_fp or fp_extend of extract_vectors and vice versa into | |||
167 | // conversions ops | |||
168 | setTargetDAGCombine({ISD::SINT_TO_FP, ISD::UINT_TO_FP, ISD::FP_EXTEND, | |||
169 | ISD::EXTRACT_SUBVECTOR}); | |||
170 | ||||
171 | // Combine fp_to_{s,u}int_sat or fp_round of concat_vectors or vice versa | |||
172 | // into conversion ops | |||
173 | setTargetDAGCombine({ISD::FP_TO_SINT_SAT, ISD::FP_TO_UINT_SAT, | |||
174 | ISD::FP_ROUND, ISD::CONCAT_VECTORS}); | |||
175 | ||||
176 | setTargetDAGCombine(ISD::TRUNCATE); | |||
177 | ||||
178 | // Support saturating add for i8x16 and i16x8 | |||
179 | for (auto Op : {ISD::SADDSAT, ISD::UADDSAT}) | |||
180 | for (auto T : {MVT::v16i8, MVT::v8i16}) | |||
181 | setOperationAction(Op, T, Legal); | |||
182 | ||||
183 | // Support integer abs | |||
184 | for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v2i64}) | |||
185 | setOperationAction(ISD::ABS, T, Legal); | |||
186 | ||||
187 | // Custom lower BUILD_VECTORs to minimize number of replace_lanes | |||
188 | for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v4f32, MVT::v2i64, | |||
189 | MVT::v2f64}) | |||
190 | setOperationAction(ISD::BUILD_VECTOR, T, Custom); | |||
191 | ||||
192 | // We have custom shuffle lowering to expose the shuffle mask | |||
193 | for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v4f32, MVT::v2i64, | |||
194 | MVT::v2f64}) | |||
195 | setOperationAction(ISD::VECTOR_SHUFFLE, T, Custom); | |||
196 | ||||
197 | // Support splatting | |||
198 | for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v4f32, MVT::v2i64, | |||
199 | MVT::v2f64}) | |||
200 | setOperationAction(ISD::SPLAT_VECTOR, T, Legal); | |||
201 | ||||
202 | // Custom lowering since wasm shifts must have a scalar shift amount | |||
203 | for (auto Op : {ISD::SHL, ISD::SRA, ISD::SRL}) | |||
204 | for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v2i64}) | |||
205 | setOperationAction(Op, T, Custom); | |||
206 | ||||
207 | // Custom lower lane accesses to expand out variable indices | |||
208 | for (auto Op : {ISD::EXTRACT_VECTOR_ELT, ISD::INSERT_VECTOR_ELT}) | |||
209 | for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v4f32, MVT::v2i64, | |||
210 | MVT::v2f64}) | |||
211 | setOperationAction(Op, T, Custom); | |||
212 | ||||
213 | // There is no i8x16.mul instruction | |||
214 | setOperationAction(ISD::MUL, MVT::v16i8, Expand); | |||
215 | ||||
216 | // There is no vector conditional select instruction | |||
217 | for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v4f32, MVT::v2i64, | |||
218 | MVT::v2f64}) | |||
219 | setOperationAction(ISD::SELECT_CC, T, Expand); | |||
220 | ||||
221 | // Expand integer operations supported for scalars but not SIMD | |||
222 | for (auto Op : | |||
223 | {ISD::SDIV, ISD::UDIV, ISD::SREM, ISD::UREM, ISD::ROTL, ISD::ROTR}) | |||
224 | for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v2i64}) | |||
225 | setOperationAction(Op, T, Expand); | |||
226 | ||||
227 | // But we do have integer min and max operations | |||
228 | for (auto Op : {ISD::SMIN, ISD::SMAX, ISD::UMIN, ISD::UMAX}) | |||
229 | for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32}) | |||
230 | setOperationAction(Op, T, Legal); | |||
231 | ||||
232 | // And we have popcnt for i8x16. It can be used to expand ctlz/cttz. | |||
233 | setOperationAction(ISD::CTPOP, MVT::v16i8, Legal); | |||
234 | setOperationAction(ISD::CTLZ, MVT::v16i8, Expand); | |||
235 | setOperationAction(ISD::CTTZ, MVT::v16i8, Expand); | |||
236 | ||||
237 | // Custom lower bit counting operations for other types to scalarize them. | |||
238 | for (auto Op : {ISD::CTLZ, ISD::CTTZ, ISD::CTPOP}) | |||
239 | for (auto T : {MVT::v8i16, MVT::v4i32, MVT::v2i64}) | |||
240 | setOperationAction(Op, T, Custom); | |||
241 | ||||
242 | // Expand float operations supported for scalars but not SIMD | |||
243 | for (auto Op : {ISD::FCOPYSIGN, ISD::FLOG, ISD::FLOG2, ISD::FLOG10, | |||
244 | ISD::FEXP, ISD::FEXP2, ISD::FRINT}) | |||
245 | for (auto T : {MVT::v4f32, MVT::v2f64}) | |||
246 | setOperationAction(Op, T, Expand); | |||
247 | ||||
248 | // Unsigned comparison operations are unavailable for i64x2 vectors. | |||
249 | for (auto CC : {ISD::SETUGT, ISD::SETUGE, ISD::SETULT, ISD::SETULE}) | |||
250 | setCondCodeAction(CC, MVT::v2i64, Custom); | |||
251 | ||||
252 | // 64x2 conversions are not in the spec | |||
253 | for (auto Op : | |||
254 | {ISD::SINT_TO_FP, ISD::UINT_TO_FP, ISD::FP_TO_SINT, ISD::FP_TO_UINT}) | |||
255 | for (auto T : {MVT::v2i64, MVT::v2f64}) | |||
256 | setOperationAction(Op, T, Expand); | |||
257 | ||||
258 | // But saturating fp_to_int converstions are | |||
259 | for (auto Op : {ISD::FP_TO_SINT_SAT, ISD::FP_TO_UINT_SAT}) | |||
260 | setOperationAction(Op, MVT::v4i32, Custom); | |||
261 | } | |||
262 | ||||
263 | // As a special case, these operators use the type to mean the type to | |||
264 | // sign-extend from. | |||
265 | setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i1, Expand); | |||
266 | if (!Subtarget->hasSignExt()) { | |||
267 | // Sign extends are legal only when extending a vector extract | |||
268 | auto Action = Subtarget->hasSIMD128() ? Custom : Expand; | |||
269 | for (auto T : {MVT::i8, MVT::i16, MVT::i32}) | |||
270 | setOperationAction(ISD::SIGN_EXTEND_INREG, T, Action); | |||
271 | } | |||
272 | for (auto T : MVT::integer_fixedlen_vector_valuetypes()) | |||
273 | setOperationAction(ISD::SIGN_EXTEND_INREG, T, Expand); | |||
274 | ||||
275 | // Dynamic stack allocation: use the default expansion. | |||
276 | setOperationAction(ISD::STACKSAVE, MVT::Other, Expand); | |||
277 | setOperationAction(ISD::STACKRESTORE, MVT::Other, Expand); | |||
278 | setOperationAction(ISD::DYNAMIC_STACKALLOC, MVTPtr, Expand); | |||
279 | ||||
280 | setOperationAction(ISD::FrameIndex, MVT::i32, Custom); | |||
281 | setOperationAction(ISD::FrameIndex, MVT::i64, Custom); | |||
282 | setOperationAction(ISD::CopyToReg, MVT::Other, Custom); | |||
283 | ||||
284 | // Expand these forms; we pattern-match the forms that we can handle in isel. | |||
285 | for (auto T : {MVT::i32, MVT::i64, MVT::f32, MVT::f64}) | |||
286 | for (auto Op : {ISD::BR_CC, ISD::SELECT_CC}) | |||
287 | setOperationAction(Op, T, Expand); | |||
288 | ||||
289 | // We have custom switch handling. | |||
290 | setOperationAction(ISD::BR_JT, MVT::Other, Custom); | |||
291 | ||||
292 | // WebAssembly doesn't have: | |||
293 | // - Floating-point extending loads. | |||
294 | // - Floating-point truncating stores. | |||
295 | // - i1 extending loads. | |||
296 | // - truncating SIMD stores and most extending loads | |||
297 | setLoadExtAction(ISD::EXTLOAD, MVT::f64, MVT::f32, Expand); | |||
298 | setTruncStoreAction(MVT::f64, MVT::f32, Expand); | |||
299 | for (auto T : MVT::integer_valuetypes()) | |||
300 | for (auto Ext : {ISD::EXTLOAD, ISD::ZEXTLOAD, ISD::SEXTLOAD}) | |||
301 | setLoadExtAction(Ext, T, MVT::i1, Promote); | |||
302 | if (Subtarget->hasSIMD128()) { | |||
303 | for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v2i64, MVT::v4f32, | |||
304 | MVT::v2f64}) { | |||
305 | for (auto MemT : MVT::fixedlen_vector_valuetypes()) { | |||
306 | if (MVT(T) != MemT) { | |||
307 | setTruncStoreAction(T, MemT, Expand); | |||
308 | for (auto Ext : {ISD::EXTLOAD, ISD::ZEXTLOAD, ISD::SEXTLOAD}) | |||
309 | setLoadExtAction(Ext, T, MemT, Expand); | |||
310 | } | |||
311 | } | |||
312 | } | |||
313 | // But some vector extending loads are legal | |||
314 | for (auto Ext : {ISD::EXTLOAD, ISD::SEXTLOAD, ISD::ZEXTLOAD}) { | |||
315 | setLoadExtAction(Ext, MVT::v8i16, MVT::v8i8, Legal); | |||
316 | setLoadExtAction(Ext, MVT::v4i32, MVT::v4i16, Legal); | |||
317 | setLoadExtAction(Ext, MVT::v2i64, MVT::v2i32, Legal); | |||
318 | } | |||
319 | setLoadExtAction(ISD::EXTLOAD, MVT::v2f64, MVT::v2f32, Legal); | |||
320 | } | |||
321 | ||||
322 | // Don't do anything clever with build_pairs | |||
323 | setOperationAction(ISD::BUILD_PAIR, MVT::i64, Expand); | |||
324 | ||||
325 | // Trap lowers to wasm unreachable | |||
326 | setOperationAction(ISD::TRAP, MVT::Other, Legal); | |||
327 | setOperationAction(ISD::DEBUGTRAP, MVT::Other, Legal); | |||
328 | ||||
329 | // Exception handling intrinsics | |||
330 | setOperationAction(ISD::INTRINSIC_WO_CHAIN, MVT::Other, Custom); | |||
331 | setOperationAction(ISD::INTRINSIC_W_CHAIN, MVT::Other, Custom); | |||
332 | setOperationAction(ISD::INTRINSIC_VOID, MVT::Other, Custom); | |||
333 | ||||
334 | setMaxAtomicSizeInBitsSupported(64); | |||
335 | ||||
336 | // Override the __gnu_f2h_ieee/__gnu_h2f_ieee names so that the f32 name is | |||
337 | // consistent with the f64 and f128 names. | |||
338 | setLibcallName(RTLIB::FPEXT_F16_F32, "__extendhfsf2"); | |||
339 | setLibcallName(RTLIB::FPROUND_F32_F16, "__truncsfhf2"); | |||
340 | ||||
341 | // Define the emscripten name for return address helper. | |||
342 | // TODO: when implementing other Wasm backends, make this generic or only do | |||
343 | // this on emscripten depending on what they end up doing. | |||
344 | setLibcallName(RTLIB::RETURN_ADDRESS, "emscripten_return_address"); | |||
345 | ||||
346 | // Always convert switches to br_tables unless there is only one case, which | |||
347 | // is equivalent to a simple branch. This reduces code size for wasm, and we | |||
348 | // defer possible jump table optimizations to the VM. | |||
349 | setMinimumJumpTableEntries(2); | |||
350 | } | |||
351 | ||||
352 | MVT WebAssemblyTargetLowering::getPointerTy(const DataLayout &DL, | |||
353 | uint32_t AS) const { | |||
354 | if (AS == WebAssembly::WasmAddressSpace::WASM_ADDRESS_SPACE_EXTERNREF) | |||
355 | return MVT::externref; | |||
356 | if (AS == WebAssembly::WasmAddressSpace::WASM_ADDRESS_SPACE_FUNCREF) | |||
357 | return MVT::funcref; | |||
358 | return TargetLowering::getPointerTy(DL, AS); | |||
359 | } | |||
360 | ||||
361 | MVT WebAssemblyTargetLowering::getPointerMemTy(const DataLayout &DL, | |||
362 | uint32_t AS) const { | |||
363 | if (AS == WebAssembly::WasmAddressSpace::WASM_ADDRESS_SPACE_EXTERNREF) | |||
364 | return MVT::externref; | |||
365 | if (AS == WebAssembly::WasmAddressSpace::WASM_ADDRESS_SPACE_FUNCREF) | |||
366 | return MVT::funcref; | |||
367 | return TargetLowering::getPointerMemTy(DL, AS); | |||
368 | } | |||
369 | ||||
370 | TargetLowering::AtomicExpansionKind | |||
371 | WebAssemblyTargetLowering::shouldExpandAtomicRMWInIR(AtomicRMWInst *AI) const { | |||
372 | // We have wasm instructions for these | |||
373 | switch (AI->getOperation()) { | |||
374 | case AtomicRMWInst::Add: | |||
375 | case AtomicRMWInst::Sub: | |||
376 | case AtomicRMWInst::And: | |||
377 | case AtomicRMWInst::Or: | |||
378 | case AtomicRMWInst::Xor: | |||
379 | case AtomicRMWInst::Xchg: | |||
380 | return AtomicExpansionKind::None; | |||
381 | default: | |||
382 | break; | |||
383 | } | |||
384 | return AtomicExpansionKind::CmpXChg; | |||
385 | } | |||
386 | ||||
387 | bool WebAssemblyTargetLowering::shouldScalarizeBinop(SDValue VecOp) const { | |||
388 | // Implementation copied from X86TargetLowering. | |||
389 | unsigned Opc = VecOp.getOpcode(); | |||
390 | ||||
391 | // Assume target opcodes can't be scalarized. | |||
392 | // TODO - do we have any exceptions? | |||
393 | if (Opc >= ISD::BUILTIN_OP_END) | |||
394 | return false; | |||
395 | ||||
396 | // If the vector op is not supported, try to convert to scalar. | |||
397 | EVT VecVT = VecOp.getValueType(); | |||
398 | if (!isOperationLegalOrCustomOrPromote(Opc, VecVT)) | |||
399 | return true; | |||
400 | ||||
401 | // If the vector op is supported, but the scalar op is not, the transform may | |||
402 | // not be worthwhile. | |||
403 | EVT ScalarVT = VecVT.getScalarType(); | |||
404 | return isOperationLegalOrCustomOrPromote(Opc, ScalarVT); | |||
405 | } | |||
406 | ||||
407 | FastISel *WebAssemblyTargetLowering::createFastISel( | |||
408 | FunctionLoweringInfo &FuncInfo, const TargetLibraryInfo *LibInfo) const { | |||
409 | return WebAssembly::createFastISel(FuncInfo, LibInfo); | |||
410 | } | |||
411 | ||||
412 | MVT WebAssemblyTargetLowering::getScalarShiftAmountTy(const DataLayout & /*DL*/, | |||
413 | EVT VT) const { | |||
414 | unsigned BitWidth = NextPowerOf2(VT.getSizeInBits() - 1); | |||
415 | if (BitWidth > 1 && BitWidth < 8) | |||
416 | BitWidth = 8; | |||
417 | ||||
418 | if (BitWidth > 64) { | |||
419 | // The shift will be lowered to a libcall, and compiler-rt libcalls expect | |||
420 | // the count to be an i32. | |||
421 | BitWidth = 32; | |||
422 | assert(BitWidth >= Log2_32_Ceil(VT.getSizeInBits()) &&(static_cast <bool> (BitWidth >= Log2_32_Ceil(VT.getSizeInBits ()) && "32-bit shift counts ought to be enough for anyone" ) ? void (0) : __assert_fail ("BitWidth >= Log2_32_Ceil(VT.getSizeInBits()) && \"32-bit shift counts ought to be enough for anyone\"" , "llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp", 423 , __extension__ __PRETTY_FUNCTION__)) | |||
423 | "32-bit shift counts ought to be enough for anyone")(static_cast <bool> (BitWidth >= Log2_32_Ceil(VT.getSizeInBits ()) && "32-bit shift counts ought to be enough for anyone" ) ? void (0) : __assert_fail ("BitWidth >= Log2_32_Ceil(VT.getSizeInBits()) && \"32-bit shift counts ought to be enough for anyone\"" , "llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp", 423 , __extension__ __PRETTY_FUNCTION__)); | |||
424 | } | |||
425 | ||||
426 | MVT Result = MVT::getIntegerVT(BitWidth); | |||
427 | assert(Result != MVT::INVALID_SIMPLE_VALUE_TYPE &&(static_cast <bool> (Result != MVT::INVALID_SIMPLE_VALUE_TYPE && "Unable to represent scalar shift amount type") ? void (0) : __assert_fail ("Result != MVT::INVALID_SIMPLE_VALUE_TYPE && \"Unable to represent scalar shift amount type\"" , "llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp", 428 , __extension__ __PRETTY_FUNCTION__)) | |||
428 | "Unable to represent scalar shift amount type")(static_cast <bool> (Result != MVT::INVALID_SIMPLE_VALUE_TYPE && "Unable to represent scalar shift amount type") ? void (0) : __assert_fail ("Result != MVT::INVALID_SIMPLE_VALUE_TYPE && \"Unable to represent scalar shift amount type\"" , "llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp", 428 , __extension__ __PRETTY_FUNCTION__)); | |||
429 | return Result; | |||
430 | } | |||
431 | ||||
432 | // Lower an fp-to-int conversion operator from the LLVM opcode, which has an | |||
433 | // undefined result on invalid/overflow, to the WebAssembly opcode, which | |||
434 | // traps on invalid/overflow. | |||
435 | static MachineBasicBlock *LowerFPToInt(MachineInstr &MI, DebugLoc DL, | |||
436 | MachineBasicBlock *BB, | |||
437 | const TargetInstrInfo &TII, | |||
438 | bool IsUnsigned, bool Int64, | |||
439 | bool Float64, unsigned LoweredOpcode) { | |||
440 | MachineRegisterInfo &MRI = BB->getParent()->getRegInfo(); | |||
441 | ||||
442 | Register OutReg = MI.getOperand(0).getReg(); | |||
443 | Register InReg = MI.getOperand(1).getReg(); | |||
444 | ||||
445 | unsigned Abs = Float64 ? WebAssembly::ABS_F64 : WebAssembly::ABS_F32; | |||
446 | unsigned FConst = Float64 ? WebAssembly::CONST_F64 : WebAssembly::CONST_F32; | |||
447 | unsigned LT = Float64 ? WebAssembly::LT_F64 : WebAssembly::LT_F32; | |||
448 | unsigned GE = Float64 ? WebAssembly::GE_F64 : WebAssembly::GE_F32; | |||
449 | unsigned IConst = Int64 ? WebAssembly::CONST_I64 : WebAssembly::CONST_I32; | |||
450 | unsigned Eqz = WebAssembly::EQZ_I32; | |||
451 | unsigned And = WebAssembly::AND_I32; | |||
452 | int64_t Limit = Int64 ? INT64_MIN(-9223372036854775807L -1) : INT32_MIN(-2147483647-1); | |||
453 | int64_t Substitute = IsUnsigned ? 0 : Limit; | |||
454 | double CmpVal = IsUnsigned ? -(double)Limit * 2.0 : -(double)Limit; | |||
455 | auto &Context = BB->getParent()->getFunction().getContext(); | |||
456 | Type *Ty = Float64 ? Type::getDoubleTy(Context) : Type::getFloatTy(Context); | |||
457 | ||||
458 | const BasicBlock *LLVMBB = BB->getBasicBlock(); | |||
459 | MachineFunction *F = BB->getParent(); | |||
460 | MachineBasicBlock *TrueMBB = F->CreateMachineBasicBlock(LLVMBB); | |||
461 | MachineBasicBlock *FalseMBB = F->CreateMachineBasicBlock(LLVMBB); | |||
462 | MachineBasicBlock *DoneMBB = F->CreateMachineBasicBlock(LLVMBB); | |||
463 | ||||
464 | MachineFunction::iterator It = ++BB->getIterator(); | |||
465 | F->insert(It, FalseMBB); | |||
466 | F->insert(It, TrueMBB); | |||
467 | F->insert(It, DoneMBB); | |||
468 | ||||
469 | // Transfer the remainder of BB and its successor edges to DoneMBB. | |||
470 | DoneMBB->splice(DoneMBB->begin(), BB, std::next(MI.getIterator()), BB->end()); | |||
471 | DoneMBB->transferSuccessorsAndUpdatePHIs(BB); | |||
472 | ||||
473 | BB->addSuccessor(TrueMBB); | |||
474 | BB->addSuccessor(FalseMBB); | |||
475 | TrueMBB->addSuccessor(DoneMBB); | |||
476 | FalseMBB->addSuccessor(DoneMBB); | |||
477 | ||||
478 | unsigned Tmp0, Tmp1, CmpReg, EqzReg, FalseReg, TrueReg; | |||
479 | Tmp0 = MRI.createVirtualRegister(MRI.getRegClass(InReg)); | |||
480 | Tmp1 = MRI.createVirtualRegister(MRI.getRegClass(InReg)); | |||
481 | CmpReg = MRI.createVirtualRegister(&WebAssembly::I32RegClass); | |||
482 | EqzReg = MRI.createVirtualRegister(&WebAssembly::I32RegClass); | |||
483 | FalseReg = MRI.createVirtualRegister(MRI.getRegClass(OutReg)); | |||
484 | TrueReg = MRI.createVirtualRegister(MRI.getRegClass(OutReg)); | |||
485 | ||||
486 | MI.eraseFromParent(); | |||
487 | // For signed numbers, we can do a single comparison to determine whether | |||
488 | // fabs(x) is within range. | |||
489 | if (IsUnsigned) { | |||
490 | Tmp0 = InReg; | |||
491 | } else { | |||
492 | BuildMI(BB, DL, TII.get(Abs), Tmp0).addReg(InReg); | |||
493 | } | |||
494 | BuildMI(BB, DL, TII.get(FConst), Tmp1) | |||
495 | .addFPImm(cast<ConstantFP>(ConstantFP::get(Ty, CmpVal))); | |||
496 | BuildMI(BB, DL, TII.get(LT), CmpReg).addReg(Tmp0).addReg(Tmp1); | |||
497 | ||||
498 | // For unsigned numbers, we have to do a separate comparison with zero. | |||
499 | if (IsUnsigned) { | |||
500 | Tmp1 = MRI.createVirtualRegister(MRI.getRegClass(InReg)); | |||
501 | Register SecondCmpReg = | |||
502 | MRI.createVirtualRegister(&WebAssembly::I32RegClass); | |||
503 | Register AndReg = MRI.createVirtualRegister(&WebAssembly::I32RegClass); | |||
504 | BuildMI(BB, DL, TII.get(FConst), Tmp1) | |||
505 | .addFPImm(cast<ConstantFP>(ConstantFP::get(Ty, 0.0))); | |||
506 | BuildMI(BB, DL, TII.get(GE), SecondCmpReg).addReg(Tmp0).addReg(Tmp1); | |||
507 | BuildMI(BB, DL, TII.get(And), AndReg).addReg(CmpReg).addReg(SecondCmpReg); | |||
508 | CmpReg = AndReg; | |||
509 | } | |||
510 | ||||
511 | BuildMI(BB, DL, TII.get(Eqz), EqzReg).addReg(CmpReg); | |||
512 | ||||
513 | // Create the CFG diamond to select between doing the conversion or using | |||
514 | // the substitute value. | |||
515 | BuildMI(BB, DL, TII.get(WebAssembly::BR_IF)).addMBB(TrueMBB).addReg(EqzReg); | |||
516 | BuildMI(FalseMBB, DL, TII.get(LoweredOpcode), FalseReg).addReg(InReg); | |||
517 | BuildMI(FalseMBB, DL, TII.get(WebAssembly::BR)).addMBB(DoneMBB); | |||
518 | BuildMI(TrueMBB, DL, TII.get(IConst), TrueReg).addImm(Substitute); | |||
519 | BuildMI(*DoneMBB, DoneMBB->begin(), DL, TII.get(TargetOpcode::PHI), OutReg) | |||
520 | .addReg(FalseReg) | |||
521 | .addMBB(FalseMBB) | |||
522 | .addReg(TrueReg) | |||
523 | .addMBB(TrueMBB); | |||
524 | ||||
525 | return DoneMBB; | |||
526 | } | |||
527 | ||||
528 | static MachineBasicBlock * | |||
529 | LowerCallResults(MachineInstr &CallResults, DebugLoc DL, MachineBasicBlock *BB, | |||
530 | const WebAssemblySubtarget *Subtarget, | |||
531 | const TargetInstrInfo &TII) { | |||
532 | MachineInstr &CallParams = *CallResults.getPrevNode(); | |||
533 | assert(CallParams.getOpcode() == WebAssembly::CALL_PARAMS)(static_cast <bool> (CallParams.getOpcode() == WebAssembly ::CALL_PARAMS) ? void (0) : __assert_fail ("CallParams.getOpcode() == WebAssembly::CALL_PARAMS" , "llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp", 533 , __extension__ __PRETTY_FUNCTION__)); | |||
534 | assert(CallResults.getOpcode() == WebAssembly::CALL_RESULTS ||(static_cast <bool> (CallResults.getOpcode() == WebAssembly ::CALL_RESULTS || CallResults.getOpcode() == WebAssembly::RET_CALL_RESULTS ) ? void (0) : __assert_fail ("CallResults.getOpcode() == WebAssembly::CALL_RESULTS || CallResults.getOpcode() == WebAssembly::RET_CALL_RESULTS" , "llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp", 535 , __extension__ __PRETTY_FUNCTION__)) | |||
535 | CallResults.getOpcode() == WebAssembly::RET_CALL_RESULTS)(static_cast <bool> (CallResults.getOpcode() == WebAssembly ::CALL_RESULTS || CallResults.getOpcode() == WebAssembly::RET_CALL_RESULTS ) ? void (0) : __assert_fail ("CallResults.getOpcode() == WebAssembly::CALL_RESULTS || CallResults.getOpcode() == WebAssembly::RET_CALL_RESULTS" , "llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp", 535 , __extension__ __PRETTY_FUNCTION__)); | |||
536 | ||||
537 | bool IsIndirect = | |||
538 | CallParams.getOperand(0).isReg() || CallParams.getOperand(0).isFI(); | |||
539 | bool IsRetCall = CallResults.getOpcode() == WebAssembly::RET_CALL_RESULTS; | |||
540 | ||||
541 | bool IsFuncrefCall = false; | |||
542 | if (IsIndirect && CallParams.getOperand(0).isReg()) { | |||
543 | Register Reg = CallParams.getOperand(0).getReg(); | |||
544 | const MachineFunction *MF = BB->getParent(); | |||
545 | const MachineRegisterInfo &MRI = MF->getRegInfo(); | |||
546 | const TargetRegisterClass *TRC = MRI.getRegClass(Reg); | |||
547 | IsFuncrefCall = (TRC == &WebAssembly::FUNCREFRegClass); | |||
548 | assert(!IsFuncrefCall || Subtarget->hasReferenceTypes())(static_cast <bool> (!IsFuncrefCall || Subtarget->hasReferenceTypes ()) ? void (0) : __assert_fail ("!IsFuncrefCall || Subtarget->hasReferenceTypes()" , "llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp", 548 , __extension__ __PRETTY_FUNCTION__)); | |||
549 | } | |||
550 | ||||
551 | unsigned CallOp; | |||
552 | if (IsIndirect && IsRetCall) { | |||
553 | CallOp = WebAssembly::RET_CALL_INDIRECT; | |||
554 | } else if (IsIndirect) { | |||
555 | CallOp = WebAssembly::CALL_INDIRECT; | |||
556 | } else if (IsRetCall) { | |||
557 | CallOp = WebAssembly::RET_CALL; | |||
558 | } else { | |||
559 | CallOp = WebAssembly::CALL; | |||
560 | } | |||
561 | ||||
562 | MachineFunction &MF = *BB->getParent(); | |||
563 | const MCInstrDesc &MCID = TII.get(CallOp); | |||
564 | MachineInstrBuilder MIB(MF, MF.CreateMachineInstr(MCID, DL)); | |||
565 | ||||
566 | // See if we must truncate the function pointer. | |||
567 | // CALL_INDIRECT takes an i32, but in wasm64 we represent function pointers | |||
568 | // as 64-bit for uniformity with other pointer types. | |||
569 | // See also: WebAssemblyFastISel::selectCall | |||
570 | if (IsIndirect && MF.getSubtarget<WebAssemblySubtarget>().hasAddr64()) { | |||
571 | Register Reg32 = | |||
572 | MF.getRegInfo().createVirtualRegister(&WebAssembly::I32RegClass); | |||
573 | auto &FnPtr = CallParams.getOperand(0); | |||
574 | BuildMI(*BB, CallResults.getIterator(), DL, | |||
575 | TII.get(WebAssembly::I32_WRAP_I64), Reg32) | |||
576 | .addReg(FnPtr.getReg()); | |||
577 | FnPtr.setReg(Reg32); | |||
578 | } | |||
579 | ||||
580 | // Move the function pointer to the end of the arguments for indirect calls | |||
581 | if (IsIndirect) { | |||
582 | auto FnPtr = CallParams.getOperand(0); | |||
583 | CallParams.removeOperand(0); | |||
584 | ||||
585 | // For funcrefs, call_indirect is done through __funcref_call_table and the | |||
586 | // funcref is always installed in slot 0 of the table, therefore instead of | |||
587 | // having the function pointer added at the end of the params list, a zero | |||
588 | // (the index in | |||
589 | // __funcref_call_table is added). | |||
590 | if (IsFuncrefCall) { | |||
591 | Register RegZero = | |||
592 | MF.getRegInfo().createVirtualRegister(&WebAssembly::I32RegClass); | |||
593 | MachineInstrBuilder MIBC0 = | |||
594 | BuildMI(MF, DL, TII.get(WebAssembly::CONST_I32), RegZero).addImm(0); | |||
595 | ||||
596 | BB->insert(CallResults.getIterator(), MIBC0); | |||
597 | MachineInstrBuilder(MF, CallParams).addReg(RegZero); | |||
598 | } else | |||
599 | CallParams.addOperand(FnPtr); | |||
600 | } | |||
601 | ||||
602 | for (auto Def : CallResults.defs()) | |||
603 | MIB.add(Def); | |||
604 | ||||
605 | if (IsIndirect) { | |||
606 | // Placeholder for the type index. | |||
607 | MIB.addImm(0); | |||
608 | // The table into which this call_indirect indexes. | |||
609 | MCSymbolWasm *Table = IsFuncrefCall | |||
610 | ? WebAssembly::getOrCreateFuncrefCallTableSymbol( | |||
611 | MF.getContext(), Subtarget) | |||
612 | : WebAssembly::getOrCreateFunctionTableSymbol( | |||
613 | MF.getContext(), Subtarget); | |||
614 | if (Subtarget->hasReferenceTypes()) { | |||
615 | MIB.addSym(Table); | |||
616 | } else { | |||
617 | // For the MVP there is at most one table whose number is 0, but we can't | |||
618 | // write a table symbol or issue relocations. Instead we just ensure the | |||
619 | // table is live and write a zero. | |||
620 | Table->setNoStrip(); | |||
621 | MIB.addImm(0); | |||
622 | } | |||
623 | } | |||
624 | ||||
625 | for (auto Use : CallParams.uses()) | |||
626 | MIB.add(Use); | |||
627 | ||||
628 | BB->insert(CallResults.getIterator(), MIB); | |||
629 | CallParams.eraseFromParent(); | |||
630 | CallResults.eraseFromParent(); | |||
631 | ||||
632 | // If this is a funcref call, to avoid hidden GC roots, we need to clear the | |||
633 | // table slot with ref.null upon call_indirect return. | |||
634 | // | |||
635 | // This generates the following code, which comes right after a call_indirect | |||
636 | // of a funcref: | |||
637 | // | |||
638 | // i32.const 0 | |||
639 | // ref.null func | |||
640 | // table.set __funcref_call_table | |||
641 | if (IsIndirect && IsFuncrefCall) { | |||
642 | MCSymbolWasm *Table = WebAssembly::getOrCreateFuncrefCallTableSymbol( | |||
643 | MF.getContext(), Subtarget); | |||
644 | Register RegZero = | |||
645 | MF.getRegInfo().createVirtualRegister(&WebAssembly::I32RegClass); | |||
646 | MachineInstr *Const0 = | |||
647 | BuildMI(MF, DL, TII.get(WebAssembly::CONST_I32), RegZero).addImm(0); | |||
648 | BB->insertAfter(MIB.getInstr()->getIterator(), Const0); | |||
649 | ||||
650 | Register RegFuncref = | |||
651 | MF.getRegInfo().createVirtualRegister(&WebAssembly::FUNCREFRegClass); | |||
652 | MachineInstr *RefNull = | |||
653 | BuildMI(MF, DL, TII.get(WebAssembly::REF_NULL_FUNCREF), RegFuncref); | |||
654 | BB->insertAfter(Const0->getIterator(), RefNull); | |||
655 | ||||
656 | MachineInstr *TableSet = | |||
657 | BuildMI(MF, DL, TII.get(WebAssembly::TABLE_SET_FUNCREF)) | |||
658 | .addSym(Table) | |||
659 | .addReg(RegZero) | |||
660 | .addReg(RegFuncref); | |||
661 | BB->insertAfter(RefNull->getIterator(), TableSet); | |||
662 | } | |||
663 | ||||
664 | return BB; | |||
665 | } | |||
666 | ||||
667 | MachineBasicBlock *WebAssemblyTargetLowering::EmitInstrWithCustomInserter( | |||
668 | MachineInstr &MI, MachineBasicBlock *BB) const { | |||
669 | const TargetInstrInfo &TII = *Subtarget->getInstrInfo(); | |||
670 | DebugLoc DL = MI.getDebugLoc(); | |||
671 | ||||
672 | switch (MI.getOpcode()) { | |||
673 | default: | |||
674 | llvm_unreachable("Unexpected instr type to insert")::llvm::llvm_unreachable_internal("Unexpected instr type to insert" , "llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp", 674 ); | |||
675 | case WebAssembly::FP_TO_SINT_I32_F32: | |||
676 | return LowerFPToInt(MI, DL, BB, TII, false, false, false, | |||
677 | WebAssembly::I32_TRUNC_S_F32); | |||
678 | case WebAssembly::FP_TO_UINT_I32_F32: | |||
679 | return LowerFPToInt(MI, DL, BB, TII, true, false, false, | |||
680 | WebAssembly::I32_TRUNC_U_F32); | |||
681 | case WebAssembly::FP_TO_SINT_I64_F32: | |||
682 | return LowerFPToInt(MI, DL, BB, TII, false, true, false, | |||
683 | WebAssembly::I64_TRUNC_S_F32); | |||
684 | case WebAssembly::FP_TO_UINT_I64_F32: | |||
685 | return LowerFPToInt(MI, DL, BB, TII, true, true, false, | |||
686 | WebAssembly::I64_TRUNC_U_F32); | |||
687 | case WebAssembly::FP_TO_SINT_I32_F64: | |||
688 | return LowerFPToInt(MI, DL, BB, TII, false, false, true, | |||
689 | WebAssembly::I32_TRUNC_S_F64); | |||
690 | case WebAssembly::FP_TO_UINT_I32_F64: | |||
691 | return LowerFPToInt(MI, DL, BB, TII, true, false, true, | |||
692 | WebAssembly::I32_TRUNC_U_F64); | |||
693 | case WebAssembly::FP_TO_SINT_I64_F64: | |||
694 | return LowerFPToInt(MI, DL, BB, TII, false, true, true, | |||
695 | WebAssembly::I64_TRUNC_S_F64); | |||
696 | case WebAssembly::FP_TO_UINT_I64_F64: | |||
697 | return LowerFPToInt(MI, DL, BB, TII, true, true, true, | |||
698 | WebAssembly::I64_TRUNC_U_F64); | |||
699 | case WebAssembly::CALL_RESULTS: | |||
700 | case WebAssembly::RET_CALL_RESULTS: | |||
701 | return LowerCallResults(MI, DL, BB, Subtarget, TII); | |||
702 | } | |||
703 | } | |||
704 | ||||
705 | const char * | |||
706 | WebAssemblyTargetLowering::getTargetNodeName(unsigned Opcode) const { | |||
707 | switch (static_cast<WebAssemblyISD::NodeType>(Opcode)) { | |||
708 | case WebAssemblyISD::FIRST_NUMBER: | |||
709 | case WebAssemblyISD::FIRST_MEM_OPCODE: | |||
710 | break; | |||
711 | #define HANDLE_NODETYPE(NODE) \ | |||
712 | case WebAssemblyISD::NODE: \ | |||
713 | return "WebAssemblyISD::" #NODE; | |||
714 | #define HANDLE_MEM_NODETYPE(NODE) HANDLE_NODETYPE(NODE) | |||
715 | #include "WebAssemblyISD.def" | |||
716 | #undef HANDLE_MEM_NODETYPE | |||
717 | #undef HANDLE_NODETYPE | |||
718 | } | |||
719 | return nullptr; | |||
720 | } | |||
721 | ||||
722 | std::pair<unsigned, const TargetRegisterClass *> | |||
723 | WebAssemblyTargetLowering::getRegForInlineAsmConstraint( | |||
724 | const TargetRegisterInfo *TRI, StringRef Constraint, MVT VT) const { | |||
725 | // First, see if this is a constraint that directly corresponds to a | |||
726 | // WebAssembly register class. | |||
727 | if (Constraint.size() == 1) { | |||
728 | switch (Constraint[0]) { | |||
729 | case 'r': | |||
730 | assert(VT != MVT::iPTR && "Pointer MVT not expected here")(static_cast <bool> (VT != MVT::iPTR && "Pointer MVT not expected here" ) ? void (0) : __assert_fail ("VT != MVT::iPTR && \"Pointer MVT not expected here\"" , "llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp", 730 , __extension__ __PRETTY_FUNCTION__)); | |||
731 | if (Subtarget->hasSIMD128() && VT.isVector()) { | |||
732 | if (VT.getSizeInBits() == 128) | |||
733 | return std::make_pair(0U, &WebAssembly::V128RegClass); | |||
734 | } | |||
735 | if (VT.isInteger() && !VT.isVector()) { | |||
736 | if (VT.getSizeInBits() <= 32) | |||
737 | return std::make_pair(0U, &WebAssembly::I32RegClass); | |||
738 | if (VT.getSizeInBits() <= 64) | |||
739 | return std::make_pair(0U, &WebAssembly::I64RegClass); | |||
740 | } | |||
741 | if (VT.isFloatingPoint() && !VT.isVector()) { | |||
742 | switch (VT.getSizeInBits()) { | |||
743 | case 32: | |||
744 | return std::make_pair(0U, &WebAssembly::F32RegClass); | |||
745 | case 64: | |||
746 | return std::make_pair(0U, &WebAssembly::F64RegClass); | |||
747 | default: | |||
748 | break; | |||
749 | } | |||
750 | } | |||
751 | break; | |||
752 | default: | |||
753 | break; | |||
754 | } | |||
755 | } | |||
756 | ||||
757 | return TargetLowering::getRegForInlineAsmConstraint(TRI, Constraint, VT); | |||
758 | } | |||
759 | ||||
760 | bool WebAssemblyTargetLowering::isCheapToSpeculateCttz(Type *Ty) const { | |||
761 | // Assume ctz is a relatively cheap operation. | |||
762 | return true; | |||
763 | } | |||
764 | ||||
765 | bool WebAssemblyTargetLowering::isCheapToSpeculateCtlz(Type *Ty) const { | |||
766 | // Assume clz is a relatively cheap operation. | |||
767 | return true; | |||
768 | } | |||
769 | ||||
770 | bool WebAssemblyTargetLowering::isLegalAddressingMode(const DataLayout &DL, | |||
771 | const AddrMode &AM, | |||
772 | Type *Ty, unsigned AS, | |||
773 | Instruction *I) const { | |||
774 | // WebAssembly offsets are added as unsigned without wrapping. The | |||
775 | // isLegalAddressingMode gives us no way to determine if wrapping could be | |||
776 | // happening, so we approximate this by accepting only non-negative offsets. | |||
777 | if (AM.BaseOffs < 0) | |||
778 | return false; | |||
779 | ||||
780 | // WebAssembly has no scale register operands. | |||
781 | if (AM.Scale != 0) | |||
782 | return false; | |||
783 | ||||
784 | // Everything else is legal. | |||
785 | return true; | |||
786 | } | |||
787 | ||||
788 | bool WebAssemblyTargetLowering::allowsMisalignedMemoryAccesses( | |||
789 | EVT /*VT*/, unsigned /*AddrSpace*/, Align /*Align*/, | |||
790 | MachineMemOperand::Flags /*Flags*/, unsigned *Fast) const { | |||
791 | // WebAssembly supports unaligned accesses, though it should be declared | |||
792 | // with the p2align attribute on loads and stores which do so, and there | |||
793 | // may be a performance impact. We tell LLVM they're "fast" because | |||
794 | // for the kinds of things that LLVM uses this for (merging adjacent stores | |||
795 | // of constants, etc.), WebAssembly implementations will either want the | |||
796 | // unaligned access or they'll split anyway. | |||
797 | if (Fast) | |||
798 | *Fast = 1; | |||
799 | return true; | |||
800 | } | |||
801 | ||||
802 | bool WebAssemblyTargetLowering::isIntDivCheap(EVT VT, | |||
803 | AttributeList Attr) const { | |||
804 | // The current thinking is that wasm engines will perform this optimization, | |||
805 | // so we can save on code size. | |||
806 | return true; | |||
807 | } | |||
808 | ||||
809 | bool WebAssemblyTargetLowering::isVectorLoadExtDesirable(SDValue ExtVal) const { | |||
810 | EVT ExtT = ExtVal.getValueType(); | |||
811 | EVT MemT = cast<LoadSDNode>(ExtVal->getOperand(0))->getValueType(0); | |||
812 | return (ExtT == MVT::v8i16 && MemT == MVT::v8i8) || | |||
813 | (ExtT == MVT::v4i32 && MemT == MVT::v4i16) || | |||
814 | (ExtT == MVT::v2i64 && MemT == MVT::v2i32); | |||
815 | } | |||
816 | ||||
817 | bool WebAssemblyTargetLowering::isOffsetFoldingLegal( | |||
818 | const GlobalAddressSDNode *GA) const { | |||
819 | // Wasm doesn't support function addresses with offsets | |||
820 | const GlobalValue *GV = GA->getGlobal(); | |||
821 | return isa<Function>(GV) ? false : TargetLowering::isOffsetFoldingLegal(GA); | |||
822 | } | |||
823 | ||||
824 | EVT WebAssemblyTargetLowering::getSetCCResultType(const DataLayout &DL, | |||
825 | LLVMContext &C, | |||
826 | EVT VT) const { | |||
827 | if (VT.isVector()) | |||
828 | return VT.changeVectorElementTypeToInteger(); | |||
829 | ||||
830 | // So far, all branch instructions in Wasm take an I32 condition. | |||
831 | // The default TargetLowering::getSetCCResultType returns the pointer size, | |||
832 | // which would be useful to reduce instruction counts when testing | |||
833 | // against 64-bit pointers/values if at some point Wasm supports that. | |||
834 | return EVT::getIntegerVT(C, 32); | |||
835 | } | |||
836 | ||||
837 | bool WebAssemblyTargetLowering::getTgtMemIntrinsic(IntrinsicInfo &Info, | |||
838 | const CallInst &I, | |||
839 | MachineFunction &MF, | |||
840 | unsigned Intrinsic) const { | |||
841 | switch (Intrinsic) { | |||
842 | case Intrinsic::wasm_memory_atomic_notify: | |||
843 | Info.opc = ISD::INTRINSIC_W_CHAIN; | |||
844 | Info.memVT = MVT::i32; | |||
845 | Info.ptrVal = I.getArgOperand(0); | |||
846 | Info.offset = 0; | |||
847 | Info.align = Align(4); | |||
848 | // atomic.notify instruction does not really load the memory specified with | |||
849 | // this argument, but MachineMemOperand should either be load or store, so | |||
850 | // we set this to a load. | |||
851 | // FIXME Volatile isn't really correct, but currently all LLVM atomic | |||
852 | // instructions are treated as volatiles in the backend, so we should be | |||
853 | // consistent. The same applies for wasm_atomic_wait intrinsics too. | |||
854 | Info.flags = MachineMemOperand::MOVolatile | MachineMemOperand::MOLoad; | |||
855 | return true; | |||
856 | case Intrinsic::wasm_memory_atomic_wait32: | |||
857 | Info.opc = ISD::INTRINSIC_W_CHAIN; | |||
858 | Info.memVT = MVT::i32; | |||
859 | Info.ptrVal = I.getArgOperand(0); | |||
860 | Info.offset = 0; | |||
861 | Info.align = Align(4); | |||
862 | Info.flags = MachineMemOperand::MOVolatile | MachineMemOperand::MOLoad; | |||
863 | return true; | |||
864 | case Intrinsic::wasm_memory_atomic_wait64: | |||
865 | Info.opc = ISD::INTRINSIC_W_CHAIN; | |||
866 | Info.memVT = MVT::i64; | |||
867 | Info.ptrVal = I.getArgOperand(0); | |||
868 | Info.offset = 0; | |||
869 | Info.align = Align(8); | |||
870 | Info.flags = MachineMemOperand::MOVolatile | MachineMemOperand::MOLoad; | |||
871 | return true; | |||
872 | default: | |||
873 | return false; | |||
874 | } | |||
875 | } | |||
876 | ||||
877 | void WebAssemblyTargetLowering::computeKnownBitsForTargetNode( | |||
878 | const SDValue Op, KnownBits &Known, const APInt &DemandedElts, | |||
879 | const SelectionDAG &DAG, unsigned Depth) const { | |||
880 | switch (Op.getOpcode()) { | |||
881 | default: | |||
882 | break; | |||
883 | case ISD::INTRINSIC_WO_CHAIN: { | |||
884 | unsigned IntNo = Op.getConstantOperandVal(0); | |||
885 | switch (IntNo) { | |||
886 | default: | |||
887 | break; | |||
888 | case Intrinsic::wasm_bitmask: { | |||
889 | unsigned BitWidth = Known.getBitWidth(); | |||
890 | EVT VT = Op.getOperand(1).getSimpleValueType(); | |||
891 | unsigned PossibleBits = VT.getVectorNumElements(); | |||
892 | APInt ZeroMask = APInt::getHighBitsSet(BitWidth, BitWidth - PossibleBits); | |||
893 | Known.Zero |= ZeroMask; | |||
894 | break; | |||
895 | } | |||
896 | } | |||
897 | } | |||
898 | } | |||
899 | } | |||
900 | ||||
901 | TargetLoweringBase::LegalizeTypeAction | |||
902 | WebAssemblyTargetLowering::getPreferredVectorAction(MVT VT) const { | |||
903 | if (VT.isFixedLengthVector()) { | |||
904 | MVT EltVT = VT.getVectorElementType(); | |||
905 | // We have legal vector types with these lane types, so widening the | |||
906 | // vector would let us use some of the lanes directly without having to | |||
907 | // extend or truncate values. | |||
908 | if (EltVT == MVT::i8 || EltVT == MVT::i16 || EltVT == MVT::i32 || | |||
909 | EltVT == MVT::i64 || EltVT == MVT::f32 || EltVT == MVT::f64) | |||
910 | return TypeWidenVector; | |||
911 | } | |||
912 | ||||
913 | return TargetLoweringBase::getPreferredVectorAction(VT); | |||
914 | } | |||
915 | ||||
916 | bool WebAssemblyTargetLowering::shouldSimplifyDemandedVectorElts( | |||
917 | SDValue Op, const TargetLoweringOpt &TLO) const { | |||
918 | // ISel process runs DAGCombiner after legalization; this step is called | |||
919 | // SelectionDAG optimization phase. This post-legalization combining process | |||
920 | // runs DAGCombiner on each node, and if there was a change to be made, | |||
921 | // re-runs legalization again on it and its user nodes to make sure | |||
922 | // everythiing is in a legalized state. | |||
923 | // | |||
924 | // The legalization calls lowering routines, and we do our custom lowering for | |||
925 | // build_vectors (LowerBUILD_VECTOR), which converts undef vector elements | |||
926 | // into zeros. But there is a set of routines in DAGCombiner that turns unused | |||
927 | // (= not demanded) nodes into undef, among which SimplifyDemandedVectorElts | |||
928 | // turns unused vector elements into undefs. But this routine does not work | |||
929 | // with our custom LowerBUILD_VECTOR, which turns undefs into zeros. This | |||
930 | // combination can result in a infinite loop, in which undefs are converted to | |||
931 | // zeros in legalization and back to undefs in combining. | |||
932 | // | |||
933 | // So after DAG is legalized, we prevent SimplifyDemandedVectorElts from | |||
934 | // running for build_vectors. | |||
935 | if (Op.getOpcode() == ISD::BUILD_VECTOR && TLO.LegalOps && TLO.LegalTys) | |||
936 | return false; | |||
937 | return true; | |||
938 | } | |||
939 | ||||
940 | //===----------------------------------------------------------------------===// | |||
941 | // WebAssembly Lowering private implementation. | |||
942 | //===----------------------------------------------------------------------===// | |||
943 | ||||
944 | //===----------------------------------------------------------------------===// | |||
945 | // Lowering Code | |||
946 | //===----------------------------------------------------------------------===// | |||
947 | ||||
948 | static void fail(const SDLoc &DL, SelectionDAG &DAG, const char *Msg) { | |||
949 | MachineFunction &MF = DAG.getMachineFunction(); | |||
950 | DAG.getContext()->diagnose( | |||
951 | DiagnosticInfoUnsupported(MF.getFunction(), Msg, DL.getDebugLoc())); | |||
952 | } | |||
953 | ||||
954 | // Test whether the given calling convention is supported. | |||
955 | static bool callingConvSupported(CallingConv::ID CallConv) { | |||
956 | // We currently support the language-independent target-independent | |||
957 | // conventions. We don't yet have a way to annotate calls with properties like | |||
958 | // "cold", and we don't have any call-clobbered registers, so these are mostly | |||
959 | // all handled the same. | |||
960 | return CallConv == CallingConv::C || CallConv == CallingConv::Fast || | |||
961 | CallConv == CallingConv::Cold || | |||
962 | CallConv == CallingConv::PreserveMost || | |||
963 | CallConv == CallingConv::PreserveAll || | |||
964 | CallConv == CallingConv::CXX_FAST_TLS || | |||
965 | CallConv == CallingConv::WASM_EmscriptenInvoke || | |||
966 | CallConv == CallingConv::Swift; | |||
967 | } | |||
968 | ||||
969 | SDValue | |||
970 | WebAssemblyTargetLowering::LowerCall(CallLoweringInfo &CLI, | |||
971 | SmallVectorImpl<SDValue> &InVals) const { | |||
972 | SelectionDAG &DAG = CLI.DAG; | |||
973 | SDLoc DL = CLI.DL; | |||
974 | SDValue Chain = CLI.Chain; | |||
975 | SDValue Callee = CLI.Callee; | |||
976 | MachineFunction &MF = DAG.getMachineFunction(); | |||
977 | auto Layout = MF.getDataLayout(); | |||
978 | ||||
979 | CallingConv::ID CallConv = CLI.CallConv; | |||
980 | if (!callingConvSupported(CallConv)) | |||
981 | fail(DL, DAG, | |||
982 | "WebAssembly doesn't support language-specific or target-specific " | |||
983 | "calling conventions yet"); | |||
984 | if (CLI.IsPatchPoint) | |||
985 | fail(DL, DAG, "WebAssembly doesn't support patch point yet"); | |||
986 | ||||
987 | if (CLI.IsTailCall) { | |||
988 | auto NoTail = [&](const char *Msg) { | |||
989 | if (CLI.CB && CLI.CB->isMustTailCall()) | |||
990 | fail(DL, DAG, Msg); | |||
991 | CLI.IsTailCall = false; | |||
992 | }; | |||
993 | ||||
994 | if (!Subtarget->hasTailCall()) | |||
995 | NoTail("WebAssembly 'tail-call' feature not enabled"); | |||
996 | ||||
997 | // Varargs calls cannot be tail calls because the buffer is on the stack | |||
998 | if (CLI.IsVarArg) | |||
999 | NoTail("WebAssembly does not support varargs tail calls"); | |||
1000 | ||||
1001 | // Do not tail call unless caller and callee return types match | |||
1002 | const Function &F = MF.getFunction(); | |||
1003 | const TargetMachine &TM = getTargetMachine(); | |||
1004 | Type *RetTy = F.getReturnType(); | |||
1005 | SmallVector<MVT, 4> CallerRetTys; | |||
1006 | SmallVector<MVT, 4> CalleeRetTys; | |||
1007 | computeLegalValueVTs(F, TM, RetTy, CallerRetTys); | |||
1008 | computeLegalValueVTs(F, TM, CLI.RetTy, CalleeRetTys); | |||
1009 | bool TypesMatch = CallerRetTys.size() == CalleeRetTys.size() && | |||
1010 | std::equal(CallerRetTys.begin(), CallerRetTys.end(), | |||
1011 | CalleeRetTys.begin()); | |||
1012 | if (!TypesMatch) | |||
1013 | NoTail("WebAssembly tail call requires caller and callee return types to " | |||
1014 | "match"); | |||
1015 | ||||
1016 | // If pointers to local stack values are passed, we cannot tail call | |||
1017 | if (CLI.CB) { | |||
1018 | for (auto &Arg : CLI.CB->args()) { | |||
1019 | Value *Val = Arg.get(); | |||
1020 | // Trace the value back through pointer operations | |||
1021 | while (true) { | |||
1022 | Value *Src = Val->stripPointerCastsAndAliases(); | |||
1023 | if (auto *GEP = dyn_cast<GetElementPtrInst>(Src)) | |||
1024 | Src = GEP->getPointerOperand(); | |||
1025 | if (Val == Src) | |||
1026 | break; | |||
1027 | Val = Src; | |||
1028 | } | |||
1029 | if (isa<AllocaInst>(Val)) { | |||
1030 | NoTail( | |||
1031 | "WebAssembly does not support tail calling with stack arguments"); | |||
1032 | break; | |||
1033 | } | |||
1034 | } | |||
1035 | } | |||
1036 | } | |||
1037 | ||||
1038 | SmallVectorImpl<ISD::InputArg> &Ins = CLI.Ins; | |||
1039 | SmallVectorImpl<ISD::OutputArg> &Outs = CLI.Outs; | |||
1040 | SmallVectorImpl<SDValue> &OutVals = CLI.OutVals; | |||
1041 | ||||
1042 | // The generic code may have added an sret argument. If we're lowering an | |||
1043 | // invoke function, the ABI requires that the function pointer be the first | |||
1044 | // argument, so we may have to swap the arguments. | |||
1045 | if (CallConv == CallingConv::WASM_EmscriptenInvoke && Outs.size() >= 2 && | |||
1046 | Outs[0].Flags.isSRet()) { | |||
1047 | std::swap(Outs[0], Outs[1]); | |||
1048 | std::swap(OutVals[0], OutVals[1]); | |||
1049 | } | |||
1050 | ||||
1051 | bool HasSwiftSelfArg = false; | |||
1052 | bool HasSwiftErrorArg = false; | |||
1053 | unsigned NumFixedArgs = 0; | |||
1054 | for (unsigned I = 0; I < Outs.size(); ++I) { | |||
1055 | const ISD::OutputArg &Out = Outs[I]; | |||
1056 | SDValue &OutVal = OutVals[I]; | |||
1057 | HasSwiftSelfArg |= Out.Flags.isSwiftSelf(); | |||
1058 | HasSwiftErrorArg |= Out.Flags.isSwiftError(); | |||
1059 | if (Out.Flags.isNest()) | |||
1060 | fail(DL, DAG, "WebAssembly hasn't implemented nest arguments"); | |||
1061 | if (Out.Flags.isInAlloca()) | |||
1062 | fail(DL, DAG, "WebAssembly hasn't implemented inalloca arguments"); | |||
1063 | if (Out.Flags.isInConsecutiveRegs()) | |||
1064 | fail(DL, DAG, "WebAssembly hasn't implemented cons regs arguments"); | |||
1065 | if (Out.Flags.isInConsecutiveRegsLast()) | |||
1066 | fail(DL, DAG, "WebAssembly hasn't implemented cons regs last arguments"); | |||
1067 | if (Out.Flags.isByVal() && Out.Flags.getByValSize() != 0) { | |||
1068 | auto &MFI = MF.getFrameInfo(); | |||
1069 | int FI = MFI.CreateStackObject(Out.Flags.getByValSize(), | |||
1070 | Out.Flags.getNonZeroByValAlign(), | |||
1071 | /*isSS=*/false); | |||
1072 | SDValue SizeNode = | |||
1073 | DAG.getConstant(Out.Flags.getByValSize(), DL, MVT::i32); | |||
1074 | SDValue FINode = DAG.getFrameIndex(FI, getPointerTy(Layout)); | |||
1075 | Chain = DAG.getMemcpy( | |||
1076 | Chain, DL, FINode, OutVal, SizeNode, Out.Flags.getNonZeroByValAlign(), | |||
1077 | /*isVolatile*/ false, /*AlwaysInline=*/false, | |||
1078 | /*isTailCall*/ false, MachinePointerInfo(), MachinePointerInfo()); | |||
1079 | OutVal = FINode; | |||
1080 | } | |||
1081 | // Count the number of fixed args *after* legalization. | |||
1082 | NumFixedArgs += Out.IsFixed; | |||
1083 | } | |||
1084 | ||||
1085 | bool IsVarArg = CLI.IsVarArg; | |||
1086 | auto PtrVT = getPointerTy(Layout); | |||
1087 | ||||
1088 | // For swiftcc, emit additional swiftself and swifterror arguments | |||
1089 | // if there aren't. These additional arguments are also added for callee | |||
1090 | // signature They are necessary to match callee and caller signature for | |||
1091 | // indirect call. | |||
1092 | if (CallConv == CallingConv::Swift) { | |||
1093 | if (!HasSwiftSelfArg) { | |||
1094 | NumFixedArgs++; | |||
1095 | ISD::OutputArg Arg; | |||
1096 | Arg.Flags.setSwiftSelf(); | |||
1097 | CLI.Outs.push_back(Arg); | |||
1098 | SDValue ArgVal = DAG.getUNDEF(PtrVT); | |||
1099 | CLI.OutVals.push_back(ArgVal); | |||
1100 | } | |||
1101 | if (!HasSwiftErrorArg) { | |||
1102 | NumFixedArgs++; | |||
1103 | ISD::OutputArg Arg; | |||
1104 | Arg.Flags.setSwiftError(); | |||
1105 | CLI.Outs.push_back(Arg); | |||
1106 | SDValue ArgVal = DAG.getUNDEF(PtrVT); | |||
1107 | CLI.OutVals.push_back(ArgVal); | |||
1108 | } | |||
1109 | } | |||
1110 | ||||
1111 | // Analyze operands of the call, assigning locations to each operand. | |||
1112 | SmallVector<CCValAssign, 16> ArgLocs; | |||
1113 | CCState CCInfo(CallConv, IsVarArg, MF, ArgLocs, *DAG.getContext()); | |||
1114 | ||||
1115 | if (IsVarArg) { | |||
1116 | // Outgoing non-fixed arguments are placed in a buffer. First | |||
1117 | // compute their offsets and the total amount of buffer space needed. | |||
1118 | for (unsigned I = NumFixedArgs; I < Outs.size(); ++I) { | |||
1119 | const ISD::OutputArg &Out = Outs[I]; | |||
1120 | SDValue &Arg = OutVals[I]; | |||
1121 | EVT VT = Arg.getValueType(); | |||
1122 | assert(VT != MVT::iPTR && "Legalized args should be concrete")(static_cast <bool> (VT != MVT::iPTR && "Legalized args should be concrete" ) ? void (0) : __assert_fail ("VT != MVT::iPTR && \"Legalized args should be concrete\"" , "llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp", 1122 , __extension__ __PRETTY_FUNCTION__)); | |||
1123 | Type *Ty = VT.getTypeForEVT(*DAG.getContext()); | |||
1124 | Align Alignment = | |||
1125 | std::max(Out.Flags.getNonZeroOrigAlign(), Layout.getABITypeAlign(Ty)); | |||
1126 | unsigned Offset = | |||
1127 | CCInfo.AllocateStack(Layout.getTypeAllocSize(Ty), Alignment); | |||
1128 | CCInfo.addLoc(CCValAssign::getMem(ArgLocs.size(), VT.getSimpleVT(), | |||
1129 | Offset, VT.getSimpleVT(), | |||
1130 | CCValAssign::Full)); | |||
1131 | } | |||
1132 | } | |||
1133 | ||||
1134 | unsigned NumBytes = CCInfo.getAlignedCallFrameSize(); | |||
1135 | ||||
1136 | SDValue FINode; | |||
1137 | if (IsVarArg && NumBytes) { | |||
1138 | // For non-fixed arguments, next emit stores to store the argument values | |||
1139 | // to the stack buffer at the offsets computed above. | |||
1140 | int FI = MF.getFrameInfo().CreateStackObject(NumBytes, | |||
1141 | Layout.getStackAlignment(), | |||
1142 | /*isSS=*/false); | |||
1143 | unsigned ValNo = 0; | |||
1144 | SmallVector<SDValue, 8> Chains; | |||
1145 | for (SDValue Arg : drop_begin(OutVals, NumFixedArgs)) { | |||
1146 | assert(ArgLocs[ValNo].getValNo() == ValNo &&(static_cast <bool> (ArgLocs[ValNo].getValNo() == ValNo && "ArgLocs should remain in order and only hold varargs args" ) ? void (0) : __assert_fail ("ArgLocs[ValNo].getValNo() == ValNo && \"ArgLocs should remain in order and only hold varargs args\"" , "llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp", 1147 , __extension__ __PRETTY_FUNCTION__)) | |||
1147 | "ArgLocs should remain in order and only hold varargs args")(static_cast <bool> (ArgLocs[ValNo].getValNo() == ValNo && "ArgLocs should remain in order and only hold varargs args" ) ? void (0) : __assert_fail ("ArgLocs[ValNo].getValNo() == ValNo && \"ArgLocs should remain in order and only hold varargs args\"" , "llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp", 1147 , __extension__ __PRETTY_FUNCTION__)); | |||
1148 | unsigned Offset = ArgLocs[ValNo++].getLocMemOffset(); | |||
1149 | FINode = DAG.getFrameIndex(FI, getPointerTy(Layout)); | |||
1150 | SDValue Add = DAG.getNode(ISD::ADD, DL, PtrVT, FINode, | |||
1151 | DAG.getConstant(Offset, DL, PtrVT)); | |||
1152 | Chains.push_back( | |||
1153 | DAG.getStore(Chain, DL, Arg, Add, | |||
1154 | MachinePointerInfo::getFixedStack(MF, FI, Offset))); | |||
1155 | } | |||
1156 | if (!Chains.empty()) | |||
1157 | Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, Chains); | |||
1158 | } else if (IsVarArg) { | |||
1159 | FINode = DAG.getIntPtrConstant(0, DL); | |||
1160 | } | |||
1161 | ||||
1162 | if (Callee->getOpcode() == ISD::GlobalAddress) { | |||
1163 | // If the callee is a GlobalAddress node (quite common, every direct call | |||
1164 | // is) turn it into a TargetGlobalAddress node so that LowerGlobalAddress | |||
1165 | // doesn't at MO_GOT which is not needed for direct calls. | |||
1166 | GlobalAddressSDNode *GA = cast<GlobalAddressSDNode>(Callee); | |||
1167 | Callee = DAG.getTargetGlobalAddress(GA->getGlobal(), DL, | |||
1168 | getPointerTy(DAG.getDataLayout()), | |||
1169 | GA->getOffset()); | |||
1170 | Callee = DAG.getNode(WebAssemblyISD::Wrapper, DL, | |||
1171 | getPointerTy(DAG.getDataLayout()), Callee); | |||
1172 | } | |||
1173 | ||||
1174 | // Compute the operands for the CALLn node. | |||
1175 | SmallVector<SDValue, 16> Ops; | |||
1176 | Ops.push_back(Chain); | |||
1177 | Ops.push_back(Callee); | |||
1178 | ||||
1179 | // Add all fixed arguments. Note that for non-varargs calls, NumFixedArgs | |||
1180 | // isn't reliable. | |||
1181 | Ops.append(OutVals.begin(), | |||
1182 | IsVarArg ? OutVals.begin() + NumFixedArgs : OutVals.end()); | |||
1183 | // Add a pointer to the vararg buffer. | |||
1184 | if (IsVarArg) | |||
1185 | Ops.push_back(FINode); | |||
1186 | ||||
1187 | SmallVector<EVT, 8> InTys; | |||
1188 | for (const auto &In : Ins) { | |||
1189 | assert(!In.Flags.isByVal() && "byval is not valid for return values")(static_cast <bool> (!In.Flags.isByVal() && "byval is not valid for return values" ) ? void (0) : __assert_fail ("!In.Flags.isByVal() && \"byval is not valid for return values\"" , "llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp", 1189 , __extension__ __PRETTY_FUNCTION__)); | |||
1190 | assert(!In.Flags.isNest() && "nest is not valid for return values")(static_cast <bool> (!In.Flags.isNest() && "nest is not valid for return values" ) ? void (0) : __assert_fail ("!In.Flags.isNest() && \"nest is not valid for return values\"" , "llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp", 1190 , __extension__ __PRETTY_FUNCTION__)); | |||
1191 | if (In.Flags.isInAlloca()) | |||
1192 | fail(DL, DAG, "WebAssembly hasn't implemented inalloca return values"); | |||
1193 | if (In.Flags.isInConsecutiveRegs()) | |||
1194 | fail(DL, DAG, "WebAssembly hasn't implemented cons regs return values"); | |||
1195 | if (In.Flags.isInConsecutiveRegsLast()) | |||
1196 | fail(DL, DAG, | |||
1197 | "WebAssembly hasn't implemented cons regs last return values"); | |||
1198 | // Ignore In.getNonZeroOrigAlign() because all our arguments are passed in | |||
1199 | // registers. | |||
1200 | InTys.push_back(In.VT); | |||
1201 | } | |||
1202 | ||||
1203 | // Lastly, if this is a call to a funcref we need to add an instruction | |||
1204 | // table.set to the chain and transform the call. | |||
1205 | if (CLI.CB && | |||
1206 | WebAssembly::isFuncrefType(CLI.CB->getCalledOperand()->getType())) { | |||
1207 | // In the absence of function references proposal where a funcref call is | |||
1208 | // lowered to call_ref, using reference types we generate a table.set to set | |||
1209 | // the funcref to a special table used solely for this purpose, followed by | |||
1210 | // a call_indirect. Here we just generate the table set, and return the | |||
1211 | // SDValue of the table.set so that LowerCall can finalize the lowering by | |||
1212 | // generating the call_indirect. | |||
1213 | SDValue Chain = Ops[0]; | |||
1214 | ||||
1215 | MCSymbolWasm *Table = WebAssembly::getOrCreateFuncrefCallTableSymbol( | |||
1216 | MF.getContext(), Subtarget); | |||
1217 | SDValue Sym = DAG.getMCSymbol(Table, PtrVT); | |||
1218 | SDValue TableSlot = DAG.getConstant(0, DL, MVT::i32); | |||
1219 | SDValue TableSetOps[] = {Chain, Sym, TableSlot, Callee}; | |||
1220 | SDValue TableSet = DAG.getMemIntrinsicNode( | |||
1221 | WebAssemblyISD::TABLE_SET, DL, DAG.getVTList(MVT::Other), TableSetOps, | |||
1222 | MVT::funcref, | |||
1223 | // Machine Mem Operand args | |||
1224 | MachinePointerInfo( | |||
1225 | WebAssembly::WasmAddressSpace::WASM_ADDRESS_SPACE_FUNCREF), | |||
1226 | CLI.CB->getCalledOperand()->getPointerAlignment(DAG.getDataLayout()), | |||
1227 | MachineMemOperand::MOStore); | |||
1228 | ||||
1229 | Ops[0] = TableSet; // The new chain is the TableSet itself | |||
1230 | } | |||
1231 | ||||
1232 | if (CLI.IsTailCall) { | |||
1233 | // ret_calls do not return values to the current frame | |||
1234 | SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue); | |||
1235 | return DAG.getNode(WebAssemblyISD::RET_CALL, DL, NodeTys, Ops); | |||
1236 | } | |||
1237 | ||||
1238 | InTys.push_back(MVT::Other); | |||
1239 | SDVTList InTyList = DAG.getVTList(InTys); | |||
1240 | SDValue Res = DAG.getNode(WebAssemblyISD::CALL, DL, InTyList, Ops); | |||
1241 | ||||
1242 | for (size_t I = 0; I < Ins.size(); ++I) | |||
1243 | InVals.push_back(Res.getValue(I)); | |||
1244 | ||||
1245 | // Return the chain | |||
1246 | return Res.getValue(Ins.size()); | |||
1247 | } | |||
1248 | ||||
1249 | bool WebAssemblyTargetLowering::CanLowerReturn( | |||
1250 | CallingConv::ID /*CallConv*/, MachineFunction & /*MF*/, bool /*IsVarArg*/, | |||
1251 | const SmallVectorImpl<ISD::OutputArg> &Outs, | |||
1252 | LLVMContext & /*Context*/) const { | |||
1253 | // WebAssembly can only handle returning tuples with multivalue enabled | |||
1254 | return Subtarget->hasMultivalue() || Outs.size() <= 1; | |||
1255 | } | |||
1256 | ||||
1257 | SDValue WebAssemblyTargetLowering::LowerReturn( | |||
1258 | SDValue Chain, CallingConv::ID CallConv, bool /*IsVarArg*/, | |||
1259 | const SmallVectorImpl<ISD::OutputArg> &Outs, | |||
1260 | const SmallVectorImpl<SDValue> &OutVals, const SDLoc &DL, | |||
1261 | SelectionDAG &DAG) const { | |||
1262 | assert((Subtarget->hasMultivalue() || Outs.size() <= 1) &&(static_cast <bool> ((Subtarget->hasMultivalue() || Outs .size() <= 1) && "MVP WebAssembly can only return up to one value" ) ? void (0) : __assert_fail ("(Subtarget->hasMultivalue() || Outs.size() <= 1) && \"MVP WebAssembly can only return up to one value\"" , "llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp", 1263 , __extension__ __PRETTY_FUNCTION__)) | |||
1263 | "MVP WebAssembly can only return up to one value")(static_cast <bool> ((Subtarget->hasMultivalue() || Outs .size() <= 1) && "MVP WebAssembly can only return up to one value" ) ? void (0) : __assert_fail ("(Subtarget->hasMultivalue() || Outs.size() <= 1) && \"MVP WebAssembly can only return up to one value\"" , "llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp", 1263 , __extension__ __PRETTY_FUNCTION__)); | |||
1264 | if (!callingConvSupported(CallConv)) | |||
1265 | fail(DL, DAG, "WebAssembly doesn't support non-C calling conventions"); | |||
1266 | ||||
1267 | SmallVector<SDValue, 4> RetOps(1, Chain); | |||
1268 | RetOps.append(OutVals.begin(), OutVals.end()); | |||
1269 | Chain = DAG.getNode(WebAssemblyISD::RETURN, DL, MVT::Other, RetOps); | |||
1270 | ||||
1271 | // Record the number and types of the return values. | |||
1272 | for (const ISD::OutputArg &Out : Outs) { | |||
1273 | assert(!Out.Flags.isByVal() && "byval is not valid for return values")(static_cast <bool> (!Out.Flags.isByVal() && "byval is not valid for return values" ) ? void (0) : __assert_fail ("!Out.Flags.isByVal() && \"byval is not valid for return values\"" , "llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp", 1273 , __extension__ __PRETTY_FUNCTION__)); | |||
1274 | assert(!Out.Flags.isNest() && "nest is not valid for return values")(static_cast <bool> (!Out.Flags.isNest() && "nest is not valid for return values" ) ? void (0) : __assert_fail ("!Out.Flags.isNest() && \"nest is not valid for return values\"" , "llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp", 1274 , __extension__ __PRETTY_FUNCTION__)); | |||
1275 | assert(Out.IsFixed && "non-fixed return value is not valid")(static_cast <bool> (Out.IsFixed && "non-fixed return value is not valid" ) ? void (0) : __assert_fail ("Out.IsFixed && \"non-fixed return value is not valid\"" , "llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp", 1275 , __extension__ __PRETTY_FUNCTION__)); | |||
1276 | if (Out.Flags.isInAlloca()) | |||
1277 | fail(DL, DAG, "WebAssembly hasn't implemented inalloca results"); | |||
1278 | if (Out.Flags.isInConsecutiveRegs()) | |||
1279 | fail(DL, DAG, "WebAssembly hasn't implemented cons regs results"); | |||
1280 | if (Out.Flags.isInConsecutiveRegsLast()) | |||
1281 | fail(DL, DAG, "WebAssembly hasn't implemented cons regs last results"); | |||
1282 | } | |||
1283 | ||||
1284 | return Chain; | |||
1285 | } | |||
1286 | ||||
1287 | SDValue WebAssemblyTargetLowering::LowerFormalArguments( | |||
1288 | SDValue Chain, CallingConv::ID CallConv, bool IsVarArg, | |||
1289 | const SmallVectorImpl<ISD::InputArg> &Ins, const SDLoc &DL, | |||
1290 | SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals) const { | |||
1291 | if (!callingConvSupported(CallConv)) | |||
1292 | fail(DL, DAG, "WebAssembly doesn't support non-C calling conventions"); | |||
1293 | ||||
1294 | MachineFunction &MF = DAG.getMachineFunction(); | |||
1295 | auto *MFI = MF.getInfo<WebAssemblyFunctionInfo>(); | |||
1296 | ||||
1297 | // Set up the incoming ARGUMENTS value, which serves to represent the liveness | |||
1298 | // of the incoming values before they're represented by virtual registers. | |||
1299 | MF.getRegInfo().addLiveIn(WebAssembly::ARGUMENTS); | |||
1300 | ||||
1301 | bool HasSwiftErrorArg = false; | |||
1302 | bool HasSwiftSelfArg = false; | |||
1303 | for (const ISD::InputArg &In : Ins) { | |||
1304 | HasSwiftSelfArg |= In.Flags.isSwiftSelf(); | |||
1305 | HasSwiftErrorArg |= In.Flags.isSwiftError(); | |||
1306 | if (In.Flags.isInAlloca()) | |||
1307 | fail(DL, DAG, "WebAssembly hasn't implemented inalloca arguments"); | |||
1308 | if (In.Flags.isNest()) | |||
1309 | fail(DL, DAG, "WebAssembly hasn't implemented nest arguments"); | |||
1310 | if (In.Flags.isInConsecutiveRegs()) | |||
1311 | fail(DL, DAG, "WebAssembly hasn't implemented cons regs arguments"); | |||
1312 | if (In.Flags.isInConsecutiveRegsLast()) | |||
1313 | fail(DL, DAG, "WebAssembly hasn't implemented cons regs last arguments"); | |||
1314 | // Ignore In.getNonZeroOrigAlign() because all our arguments are passed in | |||
1315 | // registers. | |||
1316 | InVals.push_back(In.Used ? DAG.getNode(WebAssemblyISD::ARGUMENT, DL, In.VT, | |||
1317 | DAG.getTargetConstant(InVals.size(), | |||
1318 | DL, MVT::i32)) | |||
1319 | : DAG.getUNDEF(In.VT)); | |||
1320 | ||||
1321 | // Record the number and types of arguments. | |||
1322 | MFI->addParam(In.VT); | |||
1323 | } | |||
1324 | ||||
1325 | // For swiftcc, emit additional swiftself and swifterror arguments | |||
1326 | // if there aren't. These additional arguments are also added for callee | |||
1327 | // signature They are necessary to match callee and caller signature for | |||
1328 | // indirect call. | |||
1329 | auto PtrVT = getPointerTy(MF.getDataLayout()); | |||
1330 | if (CallConv == CallingConv::Swift) { | |||
1331 | if (!HasSwiftSelfArg) { | |||
1332 | MFI->addParam(PtrVT); | |||
1333 | } | |||
1334 | if (!HasSwiftErrorArg) { | |||
1335 | MFI->addParam(PtrVT); | |||
1336 | } | |||
1337 | } | |||
1338 | // Varargs are copied into a buffer allocated by the caller, and a pointer to | |||
1339 | // the buffer is passed as an argument. | |||
1340 | if (IsVarArg) { | |||
1341 | MVT PtrVT = getPointerTy(MF.getDataLayout()); | |||
1342 | Register VarargVreg = | |||
1343 | MF.getRegInfo().createVirtualRegister(getRegClassFor(PtrVT)); | |||
1344 | MFI->setVarargBufferVreg(VarargVreg); | |||
1345 | Chain = DAG.getCopyToReg( | |||
1346 | Chain, DL, VarargVreg, | |||
1347 | DAG.getNode(WebAssemblyISD::ARGUMENT, DL, PtrVT, | |||
1348 | DAG.getTargetConstant(Ins.size(), DL, MVT::i32))); | |||
1349 | MFI->addParam(PtrVT); | |||
1350 | } | |||
1351 | ||||
1352 | // Record the number and types of arguments and results. | |||
1353 | SmallVector<MVT, 4> Params; | |||
1354 | SmallVector<MVT, 4> Results; | |||
1355 | computeSignatureVTs(MF.getFunction().getFunctionType(), &MF.getFunction(), | |||
1356 | MF.getFunction(), DAG.getTarget(), Params, Results); | |||
1357 | for (MVT VT : Results) | |||
1358 | MFI->addResult(VT); | |||
1359 | // TODO: Use signatures in WebAssemblyMachineFunctionInfo too and unify | |||
1360 | // the param logic here with ComputeSignatureVTs | |||
1361 | assert(MFI->getParams().size() == Params.size() &&(static_cast <bool> (MFI->getParams().size() == Params .size() && std::equal(MFI->getParams().begin(), MFI ->getParams().end(), Params.begin())) ? void (0) : __assert_fail ("MFI->getParams().size() == Params.size() && std::equal(MFI->getParams().begin(), MFI->getParams().end(), Params.begin())" , "llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp", 1363 , __extension__ __PRETTY_FUNCTION__)) | |||
1362 | std::equal(MFI->getParams().begin(), MFI->getParams().end(),(static_cast <bool> (MFI->getParams().size() == Params .size() && std::equal(MFI->getParams().begin(), MFI ->getParams().end(), Params.begin())) ? void (0) : __assert_fail ("MFI->getParams().size() == Params.size() && std::equal(MFI->getParams().begin(), MFI->getParams().end(), Params.begin())" , "llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp", 1363 , __extension__ __PRETTY_FUNCTION__)) | |||
1363 | Params.begin()))(static_cast <bool> (MFI->getParams().size() == Params .size() && std::equal(MFI->getParams().begin(), MFI ->getParams().end(), Params.begin())) ? void (0) : __assert_fail ("MFI->getParams().size() == Params.size() && std::equal(MFI->getParams().begin(), MFI->getParams().end(), Params.begin())" , "llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp", 1363 , __extension__ __PRETTY_FUNCTION__)); | |||
1364 | ||||
1365 | return Chain; | |||
1366 | } | |||
1367 | ||||
1368 | void WebAssemblyTargetLowering::ReplaceNodeResults( | |||
1369 | SDNode *N, SmallVectorImpl<SDValue> &Results, SelectionDAG &DAG) const { | |||
1370 | switch (N->getOpcode()) { | |||
1371 | case ISD::SIGN_EXTEND_INREG: | |||
1372 | // Do not add any results, signifying that N should not be custom lowered | |||
1373 | // after all. This happens because simd128 turns on custom lowering for | |||
1374 | // SIGN_EXTEND_INREG, but for non-vector sign extends the result might be an | |||
1375 | // illegal type. | |||
1376 | break; | |||
1377 | default: | |||
1378 | llvm_unreachable(::llvm::llvm_unreachable_internal("ReplaceNodeResults not implemented for this op for WebAssembly!" , "llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp", 1379 ) | |||
1379 | "ReplaceNodeResults not implemented for this op for WebAssembly!")::llvm::llvm_unreachable_internal("ReplaceNodeResults not implemented for this op for WebAssembly!" , "llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp", 1379 ); | |||
1380 | } | |||
1381 | } | |||
1382 | ||||
1383 | //===----------------------------------------------------------------------===// | |||
1384 | // Custom lowering hooks. | |||
1385 | //===----------------------------------------------------------------------===// | |||
1386 | ||||
1387 | SDValue WebAssemblyTargetLowering::LowerOperation(SDValue Op, | |||
1388 | SelectionDAG &DAG) const { | |||
1389 | SDLoc DL(Op); | |||
1390 | switch (Op.getOpcode()) { | |||
| ||||
1391 | default: | |||
1392 | llvm_unreachable("unimplemented operation lowering")::llvm::llvm_unreachable_internal("unimplemented operation lowering" , "llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp", 1392 ); | |||
1393 | return SDValue(); | |||
1394 | case ISD::FrameIndex: | |||
1395 | return LowerFrameIndex(Op, DAG); | |||
1396 | case ISD::GlobalAddress: | |||
1397 | return LowerGlobalAddress(Op, DAG); | |||
1398 | case ISD::GlobalTLSAddress: | |||
1399 | return LowerGlobalTLSAddress(Op, DAG); | |||
1400 | case ISD::ExternalSymbol: | |||
1401 | return LowerExternalSymbol(Op, DAG); | |||
1402 | case ISD::JumpTable: | |||
1403 | return LowerJumpTable(Op, DAG); | |||
1404 | case ISD::BR_JT: | |||
1405 | return LowerBR_JT(Op, DAG); | |||
1406 | case ISD::VASTART: | |||
1407 | return LowerVASTART(Op, DAG); | |||
1408 | case ISD::BlockAddress: | |||
1409 | case ISD::BRIND: | |||
1410 | fail(DL, DAG, "WebAssembly hasn't implemented computed gotos"); | |||
1411 | return SDValue(); | |||
1412 | case ISD::RETURNADDR: | |||
1413 | return LowerRETURNADDR(Op, DAG); | |||
1414 | case ISD::FRAMEADDR: | |||
1415 | return LowerFRAMEADDR(Op, DAG); | |||
1416 | case ISD::CopyToReg: | |||
1417 | return LowerCopyToReg(Op, DAG); | |||
1418 | case ISD::EXTRACT_VECTOR_ELT: | |||
1419 | case ISD::INSERT_VECTOR_ELT: | |||
1420 | return LowerAccessVectorElement(Op, DAG); | |||
1421 | case ISD::INTRINSIC_VOID: | |||
1422 | case ISD::INTRINSIC_WO_CHAIN: | |||
1423 | case ISD::INTRINSIC_W_CHAIN: | |||
1424 | return LowerIntrinsic(Op, DAG); | |||
1425 | case ISD::SIGN_EXTEND_INREG: | |||
1426 | return LowerSIGN_EXTEND_INREG(Op, DAG); | |||
1427 | case ISD::BUILD_VECTOR: | |||
1428 | return LowerBUILD_VECTOR(Op, DAG); | |||
1429 | case ISD::VECTOR_SHUFFLE: | |||
1430 | return LowerVECTOR_SHUFFLE(Op, DAG); | |||
1431 | case ISD::SETCC: | |||
1432 | return LowerSETCC(Op, DAG); | |||
1433 | case ISD::SHL: | |||
1434 | case ISD::SRA: | |||
1435 | case ISD::SRL: | |||
1436 | return LowerShift(Op, DAG); | |||
1437 | case ISD::FP_TO_SINT_SAT: | |||
1438 | case ISD::FP_TO_UINT_SAT: | |||
1439 | return LowerFP_TO_INT_SAT(Op, DAG); | |||
1440 | case ISD::LOAD: | |||
1441 | return LowerLoad(Op, DAG); | |||
1442 | case ISD::STORE: | |||
1443 | return LowerStore(Op, DAG); | |||
1444 | case ISD::CTPOP: | |||
1445 | case ISD::CTLZ: | |||
1446 | case ISD::CTTZ: | |||
1447 | return DAG.UnrollVectorOp(Op.getNode()); | |||
1448 | } | |||
1449 | } | |||
1450 | ||||
1451 | static bool IsWebAssemblyGlobal(SDValue Op) { | |||
1452 | if (const GlobalAddressSDNode *GA = dyn_cast<GlobalAddressSDNode>(Op)) | |||
1453 | return WebAssembly::isWasmVarAddressSpace(GA->getAddressSpace()); | |||
1454 | ||||
1455 | return false; | |||
1456 | } | |||
1457 | ||||
1458 | static std::optional<unsigned> IsWebAssemblyLocal(SDValue Op, | |||
1459 | SelectionDAG &DAG) { | |||
1460 | const FrameIndexSDNode *FI = dyn_cast<FrameIndexSDNode>(Op); | |||
1461 | if (!FI) | |||
1462 | return std::nullopt; | |||
1463 | ||||
1464 | auto &MF = DAG.getMachineFunction(); | |||
1465 | return WebAssemblyFrameLowering::getLocalForStackObject(MF, FI->getIndex()); | |||
1466 | } | |||
1467 | ||||
1468 | SDValue WebAssemblyTargetLowering::LowerStore(SDValue Op, | |||
1469 | SelectionDAG &DAG) const { | |||
1470 | SDLoc DL(Op); | |||
1471 | StoreSDNode *SN = cast<StoreSDNode>(Op.getNode()); | |||
1472 | const SDValue &Value = SN->getValue(); | |||
1473 | const SDValue &Base = SN->getBasePtr(); | |||
1474 | const SDValue &Offset = SN->getOffset(); | |||
1475 | ||||
1476 | if (IsWebAssemblyGlobal(Base)) { | |||
1477 | if (!Offset->isUndef()) | |||
1478 | report_fatal_error("unexpected offset when storing to webassembly global", | |||
1479 | false); | |||
1480 | ||||
1481 | SDVTList Tys = DAG.getVTList(MVT::Other); | |||
1482 | SDValue Ops[] = {SN->getChain(), Value, Base}; | |||
1483 | return DAG.getMemIntrinsicNode(WebAssemblyISD::GLOBAL_SET, DL, Tys, Ops, | |||
1484 | SN->getMemoryVT(), SN->getMemOperand()); | |||
1485 | } | |||
1486 | ||||
1487 | if (std::optional<unsigned> Local = IsWebAssemblyLocal(Base, DAG)) { | |||
1488 | if (!Offset->isUndef()) | |||
1489 | report_fatal_error("unexpected offset when storing to webassembly local", | |||
1490 | false); | |||
1491 | ||||
1492 | SDValue Idx = DAG.getTargetConstant(*Local, Base, MVT::i32); | |||
1493 | SDVTList Tys = DAG.getVTList(MVT::Other); // The chain. | |||
1494 | SDValue Ops[] = {SN->getChain(), Idx, Value}; | |||
1495 | return DAG.getNode(WebAssemblyISD::LOCAL_SET, DL, Tys, Ops); | |||
1496 | } | |||
1497 | ||||
1498 | if (WebAssembly::isWasmVarAddressSpace(SN->getAddressSpace())) | |||
1499 | report_fatal_error( | |||
1500 | "Encountered an unlowerable store to the wasm_var address space", | |||
1501 | false); | |||
1502 | ||||
1503 | return Op; | |||
1504 | } | |||
1505 | ||||
1506 | SDValue WebAssemblyTargetLowering::LowerLoad(SDValue Op, | |||
1507 | SelectionDAG &DAG) const { | |||
1508 | SDLoc DL(Op); | |||
1509 | LoadSDNode *LN = cast<LoadSDNode>(Op.getNode()); | |||
1510 | const SDValue &Base = LN->getBasePtr(); | |||
1511 | const SDValue &Offset = LN->getOffset(); | |||
1512 | ||||
1513 | if (IsWebAssemblyGlobal(Base)) { | |||
1514 | if (!Offset->isUndef()) | |||
1515 | report_fatal_error( | |||
1516 | "unexpected offset when loading from webassembly global", false); | |||
1517 | ||||
1518 | SDVTList Tys = DAG.getVTList(LN->getValueType(0), MVT::Other); | |||
1519 | SDValue Ops[] = {LN->getChain(), Base}; | |||
1520 | return DAG.getMemIntrinsicNode(WebAssemblyISD::GLOBAL_GET, DL, Tys, Ops, | |||
1521 | LN->getMemoryVT(), LN->getMemOperand()); | |||
1522 | } | |||
1523 | ||||
1524 | if (std::optional<unsigned> Local = IsWebAssemblyLocal(Base, DAG)) { | |||
1525 | if (!Offset->isUndef()) | |||
1526 | report_fatal_error( | |||
1527 | "unexpected offset when loading from webassembly local", false); | |||
1528 | ||||
1529 | SDValue Idx = DAG.getTargetConstant(*Local, Base, MVT::i32); | |||
1530 | EVT LocalVT = LN->getValueType(0); | |||
1531 | SDValue LocalGet = DAG.getNode(WebAssemblyISD::LOCAL_GET, DL, LocalVT, | |||
1532 | {LN->getChain(), Idx}); | |||
1533 | SDValue Result = DAG.getMergeValues({LocalGet, LN->getChain()}, DL); | |||
1534 | assert(Result->getNumValues() == 2 && "Loads must carry a chain!")(static_cast <bool> (Result->getNumValues() == 2 && "Loads must carry a chain!") ? void (0) : __assert_fail ("Result->getNumValues() == 2 && \"Loads must carry a chain!\"" , "llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp", 1534 , __extension__ __PRETTY_FUNCTION__)); | |||
1535 | return Result; | |||
1536 | } | |||
1537 | ||||
1538 | if (WebAssembly::isWasmVarAddressSpace(LN->getAddressSpace())) | |||
1539 | report_fatal_error( | |||
1540 | "Encountered an unlowerable load from the wasm_var address space", | |||
1541 | false); | |||
1542 | ||||
1543 | return Op; | |||
1544 | } | |||
1545 | ||||
1546 | SDValue WebAssemblyTargetLowering::LowerCopyToReg(SDValue Op, | |||
1547 | SelectionDAG &DAG) const { | |||
1548 | SDValue Src = Op.getOperand(2); | |||
1549 | if (isa<FrameIndexSDNode>(Src.getNode())) { | |||
1550 | // CopyToReg nodes don't support FrameIndex operands. Other targets select | |||
1551 | // the FI to some LEA-like instruction, but since we don't have that, we | |||
1552 | // need to insert some kind of instruction that can take an FI operand and | |||
1553 | // produces a value usable by CopyToReg (i.e. in a vreg). So insert a dummy | |||
1554 | // local.copy between Op and its FI operand. | |||
1555 | SDValue Chain = Op.getOperand(0); | |||
1556 | SDLoc DL(Op); | |||
1557 | Register Reg = cast<RegisterSDNode>(Op.getOperand(1))->getReg(); | |||
1558 | EVT VT = Src.getValueType(); | |||
1559 | SDValue Copy(DAG.getMachineNode(VT == MVT::i32 ? WebAssembly::COPY_I32 | |||
1560 | : WebAssembly::COPY_I64, | |||
1561 | DL, VT, Src), | |||
1562 | 0); | |||
1563 | return Op.getNode()->getNumValues() == 1 | |||
1564 | ? DAG.getCopyToReg(Chain, DL, Reg, Copy) | |||
1565 | : DAG.getCopyToReg(Chain, DL, Reg, Copy, | |||
1566 | Op.getNumOperands() == 4 ? Op.getOperand(3) | |||
1567 | : SDValue()); | |||
1568 | } | |||
1569 | return SDValue(); | |||
1570 | } | |||
1571 | ||||
1572 | SDValue WebAssemblyTargetLowering::LowerFrameIndex(SDValue Op, | |||
1573 | SelectionDAG &DAG) const { | |||
1574 | int FI = cast<FrameIndexSDNode>(Op)->getIndex(); | |||
1575 | return DAG.getTargetFrameIndex(FI, Op.getValueType()); | |||
1576 | } | |||
1577 | ||||
1578 | SDValue WebAssemblyTargetLowering::LowerRETURNADDR(SDValue Op, | |||
1579 | SelectionDAG &DAG) const { | |||
1580 | SDLoc DL(Op); | |||
1581 | ||||
1582 | if (!Subtarget->getTargetTriple().isOSEmscripten()) { | |||
1583 | fail(DL, DAG, | |||
1584 | "Non-Emscripten WebAssembly hasn't implemented " | |||
1585 | "__builtin_return_address"); | |||
1586 | return SDValue(); | |||
1587 | } | |||
1588 | ||||
1589 | if (verifyReturnAddressArgumentIsConstant(Op, DAG)) | |||
1590 | return SDValue(); | |||
1591 | ||||
1592 | unsigned Depth = Op.getConstantOperandVal(0); | |||
1593 | MakeLibCallOptions CallOptions; | |||
1594 | return makeLibCall(DAG, RTLIB::RETURN_ADDRESS, Op.getValueType(), | |||
1595 | {DAG.getConstant(Depth, DL, MVT::i32)}, CallOptions, DL) | |||
1596 | .first; | |||
1597 | } | |||
1598 | ||||
1599 | SDValue WebAssemblyTargetLowering::LowerFRAMEADDR(SDValue Op, | |||
1600 | SelectionDAG &DAG) const { | |||
1601 | // Non-zero depths are not supported by WebAssembly currently. Use the | |||
1602 | // legalizer's default expansion, which is to return 0 (what this function is | |||
1603 | // documented to do). | |||
1604 | if (Op.getConstantOperandVal(0) > 0) | |||
1605 | return SDValue(); | |||
1606 | ||||
1607 | DAG.getMachineFunction().getFrameInfo().setFrameAddressIsTaken(true); | |||
1608 | EVT VT = Op.getValueType(); | |||
1609 | Register FP = | |||
1610 | Subtarget->getRegisterInfo()->getFrameRegister(DAG.getMachineFunction()); | |||
1611 | return DAG.getCopyFromReg(DAG.getEntryNode(), SDLoc(Op), FP, VT); | |||
1612 | } | |||
1613 | ||||
1614 | SDValue | |||
1615 | WebAssemblyTargetLowering::LowerGlobalTLSAddress(SDValue Op, | |||
1616 | SelectionDAG &DAG) const { | |||
1617 | SDLoc DL(Op); | |||
1618 | const auto *GA = cast<GlobalAddressSDNode>(Op); | |||
1619 | ||||
1620 | MachineFunction &MF = DAG.getMachineFunction(); | |||
1621 | if (!MF.getSubtarget<WebAssemblySubtarget>().hasBulkMemory()) | |||
1622 | report_fatal_error("cannot use thread-local storage without bulk memory", | |||
1623 | false); | |||
1624 | ||||
1625 | const GlobalValue *GV = GA->getGlobal(); | |||
1626 | ||||
1627 | // Currently only Emscripten supports dynamic linking with threads. Therefore, | |||
1628 | // on other targets, if we have thread-local storage, only the local-exec | |||
1629 | // model is possible. | |||
1630 | auto model = Subtarget->getTargetTriple().isOSEmscripten() | |||
1631 | ? GV->getThreadLocalMode() | |||
1632 | : GlobalValue::LocalExecTLSModel; | |||
1633 | ||||
1634 | // Unsupported TLS modes | |||
1635 | assert(model != GlobalValue::NotThreadLocal)(static_cast <bool> (model != GlobalValue::NotThreadLocal ) ? void (0) : __assert_fail ("model != GlobalValue::NotThreadLocal" , "llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp", 1635 , __extension__ __PRETTY_FUNCTION__)); | |||
1636 | assert(model != GlobalValue::InitialExecTLSModel)(static_cast <bool> (model != GlobalValue::InitialExecTLSModel ) ? void (0) : __assert_fail ("model != GlobalValue::InitialExecTLSModel" , "llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp", 1636 , __extension__ __PRETTY_FUNCTION__)); | |||
1637 | ||||
1638 | if (model == GlobalValue::LocalExecTLSModel || | |||
1639 | model == GlobalValue::LocalDynamicTLSModel || | |||
1640 | (model == GlobalValue::GeneralDynamicTLSModel && | |||
1641 | getTargetMachine().shouldAssumeDSOLocal(*GV->getParent(), GV))) { | |||
1642 | // For DSO-local TLS variables we use offset from __tls_base | |||
1643 | ||||
1644 | MVT PtrVT = getPointerTy(DAG.getDataLayout()); | |||
1645 | auto GlobalGet = PtrVT == MVT::i64 ? WebAssembly::GLOBAL_GET_I64 | |||
1646 | : WebAssembly::GLOBAL_GET_I32; | |||
1647 | const char *BaseName = MF.createExternalSymbolName("__tls_base"); | |||
1648 | ||||
1649 | SDValue BaseAddr( | |||
1650 | DAG.getMachineNode(GlobalGet, DL, PtrVT, | |||
1651 | DAG.getTargetExternalSymbol(BaseName, PtrVT)), | |||
1652 | 0); | |||
1653 | ||||
1654 | SDValue TLSOffset = DAG.getTargetGlobalAddress( | |||
1655 | GV, DL, PtrVT, GA->getOffset(), WebAssemblyII::MO_TLS_BASE_REL); | |||
1656 | SDValue SymOffset = | |||
1657 | DAG.getNode(WebAssemblyISD::WrapperREL, DL, PtrVT, TLSOffset); | |||
1658 | ||||
1659 | return DAG.getNode(ISD::ADD, DL, PtrVT, BaseAddr, SymOffset); | |||
1660 | } | |||
1661 | ||||
1662 | assert(model == GlobalValue::GeneralDynamicTLSModel)(static_cast <bool> (model == GlobalValue::GeneralDynamicTLSModel ) ? void (0) : __assert_fail ("model == GlobalValue::GeneralDynamicTLSModel" , "llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp", 1662 , __extension__ __PRETTY_FUNCTION__)); | |||
1663 | ||||
1664 | EVT VT = Op.getValueType(); | |||
1665 | return DAG.getNode(WebAssemblyISD::Wrapper, DL, VT, | |||
1666 | DAG.getTargetGlobalAddress(GA->getGlobal(), DL, VT, | |||
1667 | GA->getOffset(), | |||
1668 | WebAssemblyII::MO_GOT_TLS)); | |||
1669 | } | |||
1670 | ||||
1671 | SDValue WebAssemblyTargetLowering::LowerGlobalAddress(SDValue Op, | |||
1672 | SelectionDAG &DAG) const { | |||
1673 | SDLoc DL(Op); | |||
1674 | const auto *GA = cast<GlobalAddressSDNode>(Op); | |||
1675 | EVT VT = Op.getValueType(); | |||
1676 | assert(GA->getTargetFlags() == 0 &&(static_cast <bool> (GA->getTargetFlags() == 0 && "Unexpected target flags on generic GlobalAddressSDNode") ? void (0) : __assert_fail ("GA->getTargetFlags() == 0 && \"Unexpected target flags on generic GlobalAddressSDNode\"" , "llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp", 1677 , __extension__ __PRETTY_FUNCTION__)) | |||
1677 | "Unexpected target flags on generic GlobalAddressSDNode")(static_cast <bool> (GA->getTargetFlags() == 0 && "Unexpected target flags on generic GlobalAddressSDNode") ? void (0) : __assert_fail ("GA->getTargetFlags() == 0 && \"Unexpected target flags on generic GlobalAddressSDNode\"" , "llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp", 1677 , __extension__ __PRETTY_FUNCTION__)); | |||
1678 | if (!WebAssembly::isValidAddressSpace(GA->getAddressSpace())) | |||
1679 | fail(DL, DAG, "Invalid address space for WebAssembly target"); | |||
1680 | ||||
1681 | unsigned OperandFlags = 0; | |||
1682 | if (isPositionIndependent()) { | |||
1683 | const GlobalValue *GV = GA->getGlobal(); | |||
1684 | if (getTargetMachine().shouldAssumeDSOLocal(*GV->getParent(), GV)) { | |||
1685 | MachineFunction &MF = DAG.getMachineFunction(); | |||
1686 | MVT PtrVT = getPointerTy(MF.getDataLayout()); | |||
1687 | const char *BaseName; | |||
1688 | if (GV->getValueType()->isFunctionTy()) { | |||
1689 | BaseName = MF.createExternalSymbolName("__table_base"); | |||
1690 | OperandFlags = WebAssemblyII::MO_TABLE_BASE_REL; | |||
1691 | } else { | |||
1692 | BaseName = MF.createExternalSymbolName("__memory_base"); | |||
1693 | OperandFlags = WebAssemblyII::MO_MEMORY_BASE_REL; | |||
1694 | } | |||
1695 | SDValue BaseAddr = | |||
1696 | DAG.getNode(WebAssemblyISD::Wrapper, DL, PtrVT, | |||
1697 | DAG.getTargetExternalSymbol(BaseName, PtrVT)); | |||
1698 | ||||
1699 | SDValue SymAddr = DAG.getNode( | |||
1700 | WebAssemblyISD::WrapperREL, DL, VT, | |||
1701 | DAG.getTargetGlobalAddress(GA->getGlobal(), DL, VT, GA->getOffset(), | |||
1702 | OperandFlags)); | |||
1703 | ||||
1704 | return DAG.getNode(ISD::ADD, DL, VT, BaseAddr, SymAddr); | |||
1705 | } | |||
1706 | OperandFlags = WebAssemblyII::MO_GOT; | |||
1707 | } | |||
1708 | ||||
1709 | return DAG.getNode(WebAssemblyISD::Wrapper, DL, VT, | |||
1710 | DAG.getTargetGlobalAddress(GA->getGlobal(), DL, VT, | |||
1711 | GA->getOffset(), OperandFlags)); | |||
1712 | } | |||
1713 | ||||
1714 | SDValue | |||
1715 | WebAssemblyTargetLowering::LowerExternalSymbol(SDValue Op, | |||
1716 | SelectionDAG &DAG) const { | |||
1717 | SDLoc DL(Op); | |||
1718 | const auto *ES = cast<ExternalSymbolSDNode>(Op); | |||
1719 | EVT VT = Op.getValueType(); | |||
1720 | assert(ES->getTargetFlags() == 0 &&(static_cast <bool> (ES->getTargetFlags() == 0 && "Unexpected target flags on generic ExternalSymbolSDNode") ? void (0) : __assert_fail ("ES->getTargetFlags() == 0 && \"Unexpected target flags on generic ExternalSymbolSDNode\"" , "llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp", 1721 , __extension__ __PRETTY_FUNCTION__)) | |||
1721 | "Unexpected target flags on generic ExternalSymbolSDNode")(static_cast <bool> (ES->getTargetFlags() == 0 && "Unexpected target flags on generic ExternalSymbolSDNode") ? void (0) : __assert_fail ("ES->getTargetFlags() == 0 && \"Unexpected target flags on generic ExternalSymbolSDNode\"" , "llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp", 1721 , __extension__ __PRETTY_FUNCTION__)); | |||
1722 | return DAG.getNode(WebAssemblyISD::Wrapper, DL, VT, | |||
1723 | DAG.getTargetExternalSymbol(ES->getSymbol(), VT)); | |||
1724 | } | |||
1725 | ||||
1726 | SDValue WebAssemblyTargetLowering::LowerJumpTable(SDValue Op, | |||
1727 | SelectionDAG &DAG) const { | |||
1728 | // There's no need for a Wrapper node because we always incorporate a jump | |||
1729 | // table operand into a BR_TABLE instruction, rather than ever | |||
1730 | // materializing it in a register. | |||
1731 | const JumpTableSDNode *JT = cast<JumpTableSDNode>(Op); | |||
1732 | return DAG.getTargetJumpTable(JT->getIndex(), Op.getValueType(), | |||
1733 | JT->getTargetFlags()); | |||
1734 | } | |||
1735 | ||||
1736 | SDValue WebAssemblyTargetLowering::LowerBR_JT(SDValue Op, | |||
1737 | SelectionDAG &DAG) const { | |||
1738 | SDLoc DL(Op); | |||
1739 | SDValue Chain = Op.getOperand(0); | |||
1740 | const auto *JT = cast<JumpTableSDNode>(Op.getOperand(1)); | |||
1741 | SDValue Index = Op.getOperand(2); | |||
1742 | assert(JT->getTargetFlags() == 0 && "WebAssembly doesn't set target flags")(static_cast <bool> (JT->getTargetFlags() == 0 && "WebAssembly doesn't set target flags") ? void (0) : __assert_fail ("JT->getTargetFlags() == 0 && \"WebAssembly doesn't set target flags\"" , "llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp", 1742 , __extension__ __PRETTY_FUNCTION__)); | |||
1743 | ||||
1744 | SmallVector<SDValue, 8> Ops; | |||
1745 | Ops.push_back(Chain); | |||
1746 | Ops.push_back(Index); | |||
1747 | ||||
1748 | MachineJumpTableInfo *MJTI = DAG.getMachineFunction().getJumpTableInfo(); | |||
1749 | const auto &MBBs = MJTI->getJumpTables()[JT->getIndex()].MBBs; | |||
1750 | ||||
1751 | // Add an operand for each case. | |||
1752 | for (auto *MBB : MBBs) | |||
1753 | Ops.push_back(DAG.getBasicBlock(MBB)); | |||
1754 | ||||
1755 | // Add the first MBB as a dummy default target for now. This will be replaced | |||
1756 | // with the proper default target (and the preceding range check eliminated) | |||
1757 | // if possible by WebAssemblyFixBrTableDefaults. | |||
1758 | Ops.push_back(DAG.getBasicBlock(*MBBs.begin())); | |||
1759 | return DAG.getNode(WebAssemblyISD::BR_TABLE, DL, MVT::Other, Ops); | |||
1760 | } | |||
1761 | ||||
1762 | SDValue WebAssemblyTargetLowering::LowerVASTART(SDValue Op, | |||
1763 | SelectionDAG &DAG) const { | |||
1764 | SDLoc DL(Op); | |||
1765 | EVT PtrVT = getPointerTy(DAG.getMachineFunction().getDataLayout()); | |||
1766 | ||||
1767 | auto *MFI = DAG.getMachineFunction().getInfo<WebAssemblyFunctionInfo>(); | |||
1768 | const Value *SV = cast<SrcValueSDNode>(Op.getOperand(2))->getValue(); | |||
1769 | ||||
1770 | SDValue ArgN = DAG.getCopyFromReg(DAG.getEntryNode(), DL, | |||
1771 | MFI->getVarargBufferVreg(), PtrVT); | |||
1772 | return DAG.getStore(Op.getOperand(0), DL, ArgN, Op.getOperand(1), | |||
1773 | MachinePointerInfo(SV)); | |||
1774 | } | |||
1775 | ||||
1776 | SDValue WebAssemblyTargetLowering::LowerIntrinsic(SDValue Op, | |||
1777 | SelectionDAG &DAG) const { | |||
1778 | MachineFunction &MF = DAG.getMachineFunction(); | |||
1779 | unsigned IntNo; | |||
1780 | switch (Op.getOpcode()) { | |||
1781 | case ISD::INTRINSIC_VOID: | |||
1782 | case ISD::INTRINSIC_W_CHAIN: | |||
1783 | IntNo = Op.getConstantOperandVal(1); | |||
1784 | break; | |||
1785 | case ISD::INTRINSIC_WO_CHAIN: | |||
1786 | IntNo = Op.getConstantOperandVal(0); | |||
1787 | break; | |||
1788 | default: | |||
1789 | llvm_unreachable("Invalid intrinsic")::llvm::llvm_unreachable_internal("Invalid intrinsic", "llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp" , 1789); | |||
1790 | } | |||
1791 | SDLoc DL(Op); | |||
1792 | ||||
1793 | switch (IntNo) { | |||
1794 | default: | |||
1795 | return SDValue(); // Don't custom lower most intrinsics. | |||
1796 | ||||
1797 | case Intrinsic::wasm_lsda: { | |||
1798 | auto PtrVT = getPointerTy(MF.getDataLayout()); | |||
1799 | const char *SymName = MF.createExternalSymbolName( | |||
1800 | "GCC_except_table" + std::to_string(MF.getFunctionNumber())); | |||
1801 | if (isPositionIndependent()) { | |||
1802 | SDValue Node = DAG.getTargetExternalSymbol( | |||
1803 | SymName, PtrVT, WebAssemblyII::MO_MEMORY_BASE_REL); | |||
1804 | const char *BaseName = MF.createExternalSymbolName("__memory_base"); | |||
1805 | SDValue BaseAddr = | |||
1806 | DAG.getNode(WebAssemblyISD::Wrapper, DL, PtrVT, | |||
1807 | DAG.getTargetExternalSymbol(BaseName, PtrVT)); | |||
1808 | SDValue SymAddr = | |||
1809 | DAG.getNode(WebAssemblyISD::WrapperREL, DL, PtrVT, Node); | |||
1810 | return DAG.getNode(ISD::ADD, DL, PtrVT, BaseAddr, SymAddr); | |||
1811 | } | |||
1812 | SDValue Node = DAG.getTargetExternalSymbol(SymName, PtrVT); | |||
1813 | return DAG.getNode(WebAssemblyISD::Wrapper, DL, PtrVT, Node); | |||
1814 | } | |||
1815 | ||||
1816 | case Intrinsic::wasm_shuffle: { | |||
1817 | // Drop in-chain and replace undefs, but otherwise pass through unchanged | |||
1818 | SDValue Ops[18]; | |||
1819 | size_t OpIdx = 0; | |||
1820 | Ops[OpIdx++] = Op.getOperand(1); | |||
1821 | Ops[OpIdx++] = Op.getOperand(2); | |||
1822 | while (OpIdx < 18) { | |||
1823 | const SDValue &MaskIdx = Op.getOperand(OpIdx + 1); | |||
1824 | if (MaskIdx.isUndef() || | |||
1825 | cast<ConstantSDNode>(MaskIdx.getNode())->getZExtValue() >= 32) { | |||
1826 | bool isTarget = MaskIdx.getNode()->getOpcode() == ISD::TargetConstant; | |||
1827 | Ops[OpIdx++] = DAG.getConstant(0, DL, MVT::i32, isTarget); | |||
1828 | } else { | |||
1829 | Ops[OpIdx++] = MaskIdx; | |||
1830 | } | |||
1831 | } | |||
1832 | return DAG.getNode(WebAssemblyISD::SHUFFLE, DL, Op.getValueType(), Ops); | |||
1833 | } | |||
1834 | } | |||
1835 | } | |||
1836 | ||||
1837 | SDValue | |||
1838 | WebAssemblyTargetLowering::LowerSIGN_EXTEND_INREG(SDValue Op, | |||
1839 | SelectionDAG &DAG) const { | |||
1840 | SDLoc DL(Op); | |||
1841 | // If sign extension operations are disabled, allow sext_inreg only if operand | |||
1842 | // is a vector extract of an i8 or i16 lane. SIMD does not depend on sign | |||
1843 | // extension operations, but allowing sext_inreg in this context lets us have | |||
1844 | // simple patterns to select extract_lane_s instructions. Expanding sext_inreg | |||
1845 | // everywhere would be simpler in this file, but would necessitate large and | |||
1846 | // brittle patterns to undo the expansion and select extract_lane_s | |||
1847 | // instructions. | |||
1848 | assert(!Subtarget->hasSignExt() && Subtarget->hasSIMD128())(static_cast <bool> (!Subtarget->hasSignExt() && Subtarget->hasSIMD128()) ? void (0) : __assert_fail ("!Subtarget->hasSignExt() && Subtarget->hasSIMD128()" , "llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp", 1848 , __extension__ __PRETTY_FUNCTION__)); | |||
1849 | if (Op.getOperand(0).getOpcode() != ISD::EXTRACT_VECTOR_ELT) | |||
1850 | return SDValue(); | |||
1851 | ||||
1852 | const SDValue &Extract = Op.getOperand(0); | |||
1853 | MVT VecT = Extract.getOperand(0).getSimpleValueType(); | |||
1854 | if (VecT.getVectorElementType().getSizeInBits() > 32) | |||
1855 | return SDValue(); | |||
1856 | MVT ExtractedLaneT = | |||
1857 | cast<VTSDNode>(Op.getOperand(1).getNode())->getVT().getSimpleVT(); | |||
1858 | MVT ExtractedVecT = | |||
1859 | MVT::getVectorVT(ExtractedLaneT, 128 / ExtractedLaneT.getSizeInBits()); | |||
1860 | if (ExtractedVecT == VecT) | |||
1861 | return Op; | |||
1862 | ||||
1863 | // Bitcast vector to appropriate type to ensure ISel pattern coverage | |||
1864 | const SDNode *Index = Extract.getOperand(1).getNode(); | |||
1865 | if (!isa<ConstantSDNode>(Index)) | |||
1866 | return SDValue(); | |||
1867 | unsigned IndexVal = cast<ConstantSDNode>(Index)->getZExtValue(); | |||
1868 | unsigned Scale = | |||
1869 | ExtractedVecT.getVectorNumElements() / VecT.getVectorNumElements(); | |||
1870 | assert(Scale > 1)(static_cast <bool> (Scale > 1) ? void (0) : __assert_fail ("Scale > 1", "llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp" , 1870, __extension__ __PRETTY_FUNCTION__)); | |||
1871 | SDValue NewIndex = | |||
1872 | DAG.getConstant(IndexVal * Scale, DL, Index->getValueType(0)); | |||
1873 | SDValue NewExtract = DAG.getNode( | |||
1874 | ISD::EXTRACT_VECTOR_ELT, DL, Extract.getValueType(), | |||
1875 | DAG.getBitcast(ExtractedVecT, Extract.getOperand(0)), NewIndex); | |||
1876 | return DAG.getNode(ISD::SIGN_EXTEND_INREG, DL, Op.getValueType(), NewExtract, | |||
1877 | Op.getOperand(1)); | |||
1878 | } | |||
1879 | ||||
1880 | static SDValue LowerConvertLow(SDValue Op, SelectionDAG &DAG) { | |||
1881 | SDLoc DL(Op); | |||
1882 | if (Op.getValueType() != MVT::v2f64) | |||
1883 | return SDValue(); | |||
1884 | ||||
1885 | auto GetConvertedLane = [](SDValue Op, unsigned &Opcode, SDValue &SrcVec, | |||
1886 | unsigned &Index) -> bool { | |||
1887 | switch (Op.getOpcode()) { | |||
1888 | case ISD::SINT_TO_FP: | |||
1889 | Opcode = WebAssemblyISD::CONVERT_LOW_S; | |||
1890 | break; | |||
1891 | case ISD::UINT_TO_FP: | |||
1892 | Opcode = WebAssemblyISD::CONVERT_LOW_U; | |||
1893 | break; | |||
1894 | case ISD::FP_EXTEND: | |||
1895 | Opcode = WebAssemblyISD::PROMOTE_LOW; | |||
1896 | break; | |||
1897 | default: | |||
1898 | return false; | |||
1899 | } | |||
1900 | ||||
1901 | auto ExtractVector = Op.getOperand(0); | |||
1902 | if (ExtractVector.getOpcode() != ISD::EXTRACT_VECTOR_ELT) | |||
1903 | return false; | |||
1904 | ||||
1905 | if (!isa<ConstantSDNode>(ExtractVector.getOperand(1).getNode())) | |||
1906 | return false; | |||
1907 | ||||
1908 | SrcVec = ExtractVector.getOperand(0); | |||
1909 | Index = ExtractVector.getConstantOperandVal(1); | |||
1910 | return true; | |||
1911 | }; | |||
1912 | ||||
1913 | unsigned LHSOpcode, RHSOpcode, LHSIndex, RHSIndex; | |||
1914 | SDValue LHSSrcVec, RHSSrcVec; | |||
1915 | if (!GetConvertedLane(Op.getOperand(0), LHSOpcode, LHSSrcVec, LHSIndex) || | |||
1916 | !GetConvertedLane(Op.getOperand(1), RHSOpcode, RHSSrcVec, RHSIndex)) | |||
1917 | return SDValue(); | |||
1918 | ||||
1919 | if (LHSOpcode != RHSOpcode) | |||
1920 | return SDValue(); | |||
1921 | ||||
1922 | MVT ExpectedSrcVT; | |||
1923 | switch (LHSOpcode) { | |||
1924 | case WebAssemblyISD::CONVERT_LOW_S: | |||
1925 | case WebAssemblyISD::CONVERT_LOW_U: | |||
1926 | ExpectedSrcVT = MVT::v4i32; | |||
1927 | break; | |||
1928 | case WebAssemblyISD::PROMOTE_LOW: | |||
1929 | ExpectedSrcVT = MVT::v4f32; | |||
1930 | break; | |||
1931 | } | |||
1932 | if (LHSSrcVec.getValueType() != ExpectedSrcVT) | |||
1933 | return SDValue(); | |||
1934 | ||||
1935 | auto Src = LHSSrcVec; | |||
1936 | if (LHSIndex != 0 || RHSIndex != 1 || LHSSrcVec != RHSSrcVec) { | |||
1937 | // Shuffle the source vector so that the converted lanes are the low lanes. | |||
1938 | Src = DAG.getVectorShuffle( | |||
1939 | ExpectedSrcVT, DL, LHSSrcVec, RHSSrcVec, | |||
1940 | {static_cast<int>(LHSIndex), static_cast<int>(RHSIndex) + 4, -1, -1}); | |||
1941 | } | |||
1942 | return DAG.getNode(LHSOpcode, DL, MVT::v2f64, Src); | |||
1943 | } | |||
1944 | ||||
1945 | SDValue WebAssemblyTargetLowering::LowerBUILD_VECTOR(SDValue Op, | |||
1946 | SelectionDAG &DAG) const { | |||
1947 | if (auto ConvertLow = LowerConvertLow(Op, DAG)) | |||
1948 | return ConvertLow; | |||
1949 | ||||
1950 | SDLoc DL(Op); | |||
1951 | const EVT VecT = Op.getValueType(); | |||
1952 | const EVT LaneT = Op.getOperand(0).getValueType(); | |||
1953 | const size_t Lanes = Op.getNumOperands(); | |||
1954 | bool CanSwizzle = VecT == MVT::v16i8; | |||
1955 | ||||
1956 | // BUILD_VECTORs are lowered to the instruction that initializes the highest | |||
1957 | // possible number of lanes at once followed by a sequence of replace_lane | |||
1958 | // instructions to individually initialize any remaining lanes. | |||
1959 | ||||
1960 | // TODO: Tune this. For example, lanewise swizzling is very expensive, so | |||
1961 | // swizzled lanes should be given greater weight. | |||
1962 | ||||
1963 | // TODO: Investigate looping rather than always extracting/replacing specific | |||
1964 | // lanes to fill gaps. | |||
1965 | ||||
1966 | auto IsConstant = [](const SDValue &V) { | |||
1967 | return V.getOpcode() == ISD::Constant || V.getOpcode() == ISD::ConstantFP; | |||
1968 | }; | |||
1969 | ||||
1970 | // Returns the source vector and index vector pair if they exist. Checks for: | |||
1971 | // (extract_vector_elt | |||
1972 | // $src, | |||
1973 | // (sign_extend_inreg (extract_vector_elt $indices, $i)) | |||
1974 | // ) | |||
1975 | auto GetSwizzleSrcs = [](size_t I, const SDValue &Lane) { | |||
1976 | auto Bail = std::make_pair(SDValue(), SDValue()); | |||
1977 | if (Lane->getOpcode() != ISD::EXTRACT_VECTOR_ELT) | |||
1978 | return Bail; | |||
1979 | const SDValue &SwizzleSrc = Lane->getOperand(0); | |||
1980 | const SDValue &IndexExt = Lane->getOperand(1); | |||
1981 | if (IndexExt->getOpcode() != ISD::SIGN_EXTEND_INREG) | |||
1982 | return Bail; | |||
1983 | const SDValue &Index = IndexExt->getOperand(0); | |||
1984 | if (Index->getOpcode() != ISD::EXTRACT_VECTOR_ELT) | |||
1985 | return Bail; | |||
1986 | const SDValue &SwizzleIndices = Index->getOperand(0); | |||
1987 | if (SwizzleSrc.getValueType() != MVT::v16i8 || | |||
1988 | SwizzleIndices.getValueType() != MVT::v16i8 || | |||
1989 | Index->getOperand(1)->getOpcode() != ISD::Constant || | |||
1990 | Index->getConstantOperandVal(1) != I) | |||
1991 | return Bail; | |||
1992 | return std::make_pair(SwizzleSrc, SwizzleIndices); | |||
1993 | }; | |||
1994 | ||||
1995 | // If the lane is extracted from another vector at a constant index, return | |||
1996 | // that vector. The source vector must not have more lanes than the dest | |||
1997 | // because the shufflevector indices are in terms of the destination lanes and | |||
1998 | // would not be able to address the smaller individual source lanes. | |||
1999 | auto GetShuffleSrc = [&](const SDValue &Lane) { | |||
2000 | if (Lane->getOpcode() != ISD::EXTRACT_VECTOR_ELT) | |||
2001 | return SDValue(); | |||
2002 | if (!isa<ConstantSDNode>(Lane->getOperand(1).getNode())) | |||
2003 | return SDValue(); | |||
2004 | if (Lane->getOperand(0).getValueType().getVectorNumElements() > | |||
2005 | VecT.getVectorNumElements()) | |||
2006 | return SDValue(); | |||
2007 | return Lane->getOperand(0); | |||
2008 | }; | |||
2009 | ||||
2010 | using ValueEntry = std::pair<SDValue, size_t>; | |||
2011 | SmallVector<ValueEntry, 16> SplatValueCounts; | |||
2012 | ||||
2013 | using SwizzleEntry = std::pair<std::pair<SDValue, SDValue>, size_t>; | |||
2014 | SmallVector<SwizzleEntry, 16> SwizzleCounts; | |||
2015 | ||||
2016 | using ShuffleEntry = std::pair<SDValue, size_t>; | |||
2017 | SmallVector<ShuffleEntry, 16> ShuffleCounts; | |||
2018 | ||||
2019 | auto AddCount = [](auto &Counts, const auto &Val) { | |||
2020 | auto CountIt = | |||
2021 | llvm::find_if(Counts, [&Val](auto E) { return E.first == Val; }); | |||
2022 | if (CountIt == Counts.end()) { | |||
2023 | Counts.emplace_back(Val, 1); | |||
2024 | } else { | |||
2025 | CountIt->second++; | |||
2026 | } | |||
2027 | }; | |||
2028 | ||||
2029 | auto GetMostCommon = [](auto &Counts) { | |||
2030 | auto CommonIt = | |||
2031 | std::max_element(Counts.begin(), Counts.end(), llvm::less_second()); | |||
2032 | assert(CommonIt != Counts.end() && "Unexpected all-undef build_vector")(static_cast <bool> (CommonIt != Counts.end() && "Unexpected all-undef build_vector") ? void (0) : __assert_fail ("CommonIt != Counts.end() && \"Unexpected all-undef build_vector\"" , "llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp", 2032 , __extension__ __PRETTY_FUNCTION__)); | |||
2033 | return *CommonIt; | |||
2034 | }; | |||
2035 | ||||
2036 | size_t NumConstantLanes = 0; | |||
2037 | ||||
2038 | // Count eligible lanes for each type of vector creation op | |||
2039 | for (size_t I = 0; I
| |||
2040 | const SDValue &Lane = Op->getOperand(I); | |||
2041 | if (Lane.isUndef()) | |||
2042 | continue; | |||
2043 | ||||
2044 | AddCount(SplatValueCounts, Lane); | |||
2045 | ||||
2046 | if (IsConstant(Lane)) | |||
2047 | NumConstantLanes++; | |||
2048 | if (auto ShuffleSrc = GetShuffleSrc(Lane)) | |||
2049 | AddCount(ShuffleCounts, ShuffleSrc); | |||
2050 | if (CanSwizzle
| |||
2051 | auto SwizzleSrcs = GetSwizzleSrcs(I, Lane); | |||
2052 | if (SwizzleSrcs.first) | |||
2053 | AddCount(SwizzleCounts, SwizzleSrcs); | |||
2054 | } | |||
2055 | } | |||
2056 | ||||
2057 | SDValue SplatValue; | |||
2058 | size_t NumSplatLanes; | |||
2059 | std::tie(SplatValue, NumSplatLanes) = GetMostCommon(SplatValueCounts); | |||
2060 | ||||
2061 | SDValue SwizzleSrc; | |||
2062 | SDValue SwizzleIndices; | |||
2063 | size_t NumSwizzleLanes = 0; | |||
2064 | if (SwizzleCounts.size()) | |||
2065 | std::forward_as_tuple(std::tie(SwizzleSrc, SwizzleIndices), | |||
2066 | NumSwizzleLanes) = GetMostCommon(SwizzleCounts); | |||
2067 | ||||
2068 | // Shuffles can draw from up to two vectors, so find the two most common | |||
2069 | // sources. | |||
2070 | SDValue ShuffleSrc1, ShuffleSrc2; | |||
2071 | size_t NumShuffleLanes = 0; | |||
2072 | if (ShuffleCounts.size()) { | |||
2073 | std::tie(ShuffleSrc1, NumShuffleLanes) = GetMostCommon(ShuffleCounts); | |||
2074 | llvm::erase_if(ShuffleCounts, | |||
2075 | [&](const auto &Pair) { return Pair.first == ShuffleSrc1; }); | |||
2076 | } | |||
2077 | if (ShuffleCounts.size()) { | |||
2078 | size_t AdditionalShuffleLanes; | |||
2079 | std::tie(ShuffleSrc2, AdditionalShuffleLanes) = | |||
2080 | GetMostCommon(ShuffleCounts); | |||
2081 | NumShuffleLanes += AdditionalShuffleLanes; | |||
2082 | } | |||
2083 | ||||
2084 | // Predicate returning true if the lane is properly initialized by the | |||
2085 | // original instruction | |||
2086 | std::function<bool(size_t, const SDValue &)> IsLaneConstructed; | |||
2087 | SDValue Result; | |||
2088 | // Prefer swizzles over shuffles over vector consts over splats | |||
2089 | if (NumSwizzleLanes >= NumShuffleLanes && | |||
2090 | NumSwizzleLanes >= NumConstantLanes && NumSwizzleLanes >= NumSplatLanes) { | |||
2091 | Result = DAG.getNode(WebAssemblyISD::SWIZZLE, DL, VecT, SwizzleSrc, | |||
2092 | SwizzleIndices); | |||
2093 | auto Swizzled = std::make_pair(SwizzleSrc, SwizzleIndices); | |||
2094 | IsLaneConstructed = [&, Swizzled](size_t I, const SDValue &Lane) { | |||
2095 | return Swizzled == GetSwizzleSrcs(I, Lane); | |||
2096 | }; | |||
2097 | } else if (NumShuffleLanes
| |||
2098 | NumShuffleLanes >= NumSplatLanes) { | |||
2099 | size_t DestLaneSize = VecT.getVectorElementType().getFixedSizeInBits() / 8; | |||
2100 | size_t DestLaneCount = VecT.getVectorNumElements(); | |||
2101 | size_t Scale1 = 1; | |||
2102 | size_t Scale2 = 1; | |||
2103 | SDValue Src1 = ShuffleSrc1; | |||
2104 | SDValue Src2 = ShuffleSrc2 ? ShuffleSrc2 : DAG.getUNDEF(VecT); | |||
2105 | if (Src1.getValueType() != VecT) { | |||
2106 | size_t LaneSize = | |||
2107 | Src1.getValueType().getVectorElementType().getFixedSizeInBits() / 8; | |||
2108 | assert(LaneSize > DestLaneSize)(static_cast <bool> (LaneSize > DestLaneSize) ? void (0) : __assert_fail ("LaneSize > DestLaneSize", "llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp" , 2108, __extension__ __PRETTY_FUNCTION__)); | |||
2109 | Scale1 = LaneSize / DestLaneSize; | |||
2110 | Src1 = DAG.getBitcast(VecT, Src1); | |||
2111 | } | |||
2112 | if (Src2.getValueType() != VecT) { | |||
2113 | size_t LaneSize = | |||
2114 | Src2.getValueType().getVectorElementType().getFixedSizeInBits() / 8; | |||
2115 | assert(LaneSize > DestLaneSize)(static_cast <bool> (LaneSize > DestLaneSize) ? void (0) : __assert_fail ("LaneSize > DestLaneSize", "llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp" , 2115, __extension__ __PRETTY_FUNCTION__)); | |||
2116 | Scale2 = LaneSize / DestLaneSize; | |||
2117 | Src2 = DAG.getBitcast(VecT, Src2); | |||
2118 | } | |||
2119 | ||||
2120 | int Mask[16]; | |||
2121 | assert(DestLaneCount <= 16)(static_cast <bool> (DestLaneCount <= 16) ? void (0) : __assert_fail ("DestLaneCount <= 16", "llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp" , 2121, __extension__ __PRETTY_FUNCTION__)); | |||
2122 | for (size_t I = 0; I < DestLaneCount; ++I) { | |||
2123 | const SDValue &Lane = Op->getOperand(I); | |||
2124 | SDValue Src = GetShuffleSrc(Lane); | |||
2125 | if (Src == ShuffleSrc1) { | |||
2126 | Mask[I] = Lane->getConstantOperandVal(1) * Scale1; | |||
2127 | } else if (Src && Src == ShuffleSrc2) { | |||
2128 | Mask[I] = DestLaneCount + Lane->getConstantOperandVal(1) * Scale2; | |||
2129 | } else { | |||
2130 | Mask[I] = -1; | |||
2131 | } | |||
2132 | } | |||
2133 | ArrayRef<int> MaskRef(Mask, DestLaneCount); | |||
2134 | Result = DAG.getVectorShuffle(VecT, DL, Src1, Src2, MaskRef); | |||
2135 | IsLaneConstructed = [&](size_t, const SDValue &Lane) { | |||
2136 | auto Src = GetShuffleSrc(Lane); | |||
2137 | return Src == ShuffleSrc1 || (Src && Src == ShuffleSrc2); | |||
2138 | }; | |||
2139 | } else if (NumConstantLanes >= NumSplatLanes) { | |||
2140 | SmallVector<SDValue, 16> ConstLanes; | |||
2141 | for (const SDValue &Lane : Op->op_values()) { | |||
2142 | if (IsConstant(Lane)) { | |||
2143 | // Values may need to be fixed so that they will sign extend to be | |||
2144 | // within the expected range during ISel. Check whether the value is in | |||
2145 | // bounds based on the lane bit width and if it is out of bounds, lop | |||
2146 | // off the extra bits and subtract 2^n to reflect giving the high bit | |||
2147 | // value -2^(n-1) rather than +2^(n-1). Skip the i64 case because it | |||
2148 | // cannot possibly be out of range. | |||
2149 | auto *Const = dyn_cast<ConstantSDNode>(Lane.getNode()); | |||
2150 | int64_t Val = Const
| |||
2151 | uint64_t LaneBits = 128 / Lanes; | |||
2152 | assert((LaneBits == 64 || Val >= -(1ll << (LaneBits - 1))) &&(static_cast <bool> ((LaneBits == 64 || Val >= -(1ll << (LaneBits - 1))) && "Unexpected out of bounds negative value" ) ? void (0) : __assert_fail ("(LaneBits == 64 || Val >= -(1ll << (LaneBits - 1))) && \"Unexpected out of bounds negative value\"" , "llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp", 2153 , __extension__ __PRETTY_FUNCTION__)) | |||
| ||||
2153 | "Unexpected out of bounds negative value")(static_cast <bool> ((LaneBits == 64 || Val >= -(1ll << (LaneBits - 1))) && "Unexpected out of bounds negative value" ) ? void (0) : __assert_fail ("(LaneBits == 64 || Val >= -(1ll << (LaneBits - 1))) && \"Unexpected out of bounds negative value\"" , "llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp", 2153 , __extension__ __PRETTY_FUNCTION__)); | |||
2154 | if (Const && LaneBits != 64 && Val > (1ll << (LaneBits - 1)) - 1) { | |||
2155 | uint64_t Mask = (1ll << LaneBits) - 1; | |||
2156 | auto NewVal = (((uint64_t)Val & Mask) - (1ll << LaneBits)) & Mask; | |||
2157 | ConstLanes.push_back(DAG.getConstant(NewVal, SDLoc(Lane), LaneT)); | |||
2158 | } else { | |||
2159 | ConstLanes.push_back(Lane); | |||
2160 | } | |||
2161 | } else if (LaneT.isFloatingPoint()) { | |||
2162 | ConstLanes.push_back(DAG.getConstantFP(0, DL, LaneT)); | |||
2163 | } else { | |||
2164 | ConstLanes.push_back(DAG.getConstant(0, DL, LaneT)); | |||
2165 | } | |||
2166 | } | |||
2167 | Result = DAG.getBuildVector(VecT, DL, ConstLanes); | |||
2168 | IsLaneConstructed = [&IsConstant](size_t _, const SDValue &Lane) { | |||
2169 | return IsConstant(Lane); | |||
2170 | }; | |||
2171 | } else { | |||
2172 | // Use a splat (which might be selected as a load splat) | |||
2173 | Result = DAG.getSplatBuildVector(VecT, DL, SplatValue); | |||
2174 | IsLaneConstructed = [&SplatValue](size_t _, const SDValue &Lane) { | |||
2175 | return Lane == SplatValue; | |||
2176 | }; | |||
2177 | } | |||
2178 | ||||
2179 | assert(Result)(static_cast <bool> (Result) ? void (0) : __assert_fail ("Result", "llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp" , 2179, __extension__ __PRETTY_FUNCTION__)); | |||
2180 | assert(IsLaneConstructed)(static_cast <bool> (IsLaneConstructed) ? void (0) : __assert_fail ("IsLaneConstructed", "llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp" , 2180, __extension__ __PRETTY_FUNCTION__)); | |||
2181 | ||||
2182 | // Add replace_lane instructions for any unhandled values | |||
2183 | for (size_t I = 0; I < Lanes; ++I) { | |||
2184 | const SDValue &Lane = Op->getOperand(I); | |||
2185 | if (!Lane.isUndef() && !IsLaneConstructed(I, Lane)) | |||
2186 | Result = DAG.getNode(ISD::INSERT_VECTOR_ELT, DL, VecT, Result, Lane, | |||
2187 | DAG.getConstant(I, DL, MVT::i32)); | |||
2188 | } | |||
2189 | ||||
2190 | return Result; | |||
2191 | } | |||
2192 | ||||
2193 | SDValue | |||
2194 | WebAssemblyTargetLowering::LowerVECTOR_SHUFFLE(SDValue Op, | |||
2195 | SelectionDAG &DAG) const { | |||
2196 | SDLoc DL(Op); | |||
2197 | ArrayRef<int> Mask = cast<ShuffleVectorSDNode>(Op.getNode())->getMask(); | |||
2198 | MVT VecType = Op.getOperand(0).getSimpleValueType(); | |||
2199 | assert(VecType.is128BitVector() && "Unexpected shuffle vector type")(static_cast <bool> (VecType.is128BitVector() && "Unexpected shuffle vector type") ? void (0) : __assert_fail ("VecType.is128BitVector() && \"Unexpected shuffle vector type\"" , "llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp", 2199 , __extension__ __PRETTY_FUNCTION__)); | |||
2200 | size_t LaneBytes = VecType.getVectorElementType().getSizeInBits() / 8; | |||
2201 | ||||
2202 | // Space for two vector args and sixteen mask indices | |||
2203 | SDValue Ops[18]; | |||
2204 | size_t OpIdx = 0; | |||
2205 | Ops[OpIdx++] = Op.getOperand(0); | |||
2206 | Ops[OpIdx++] = Op.getOperand(1); | |||
2207 | ||||
2208 | // Expand mask indices to byte indices and materialize them as operands | |||
2209 | for (int M : Mask) { | |||
2210 | for (size_t J = 0; J < LaneBytes; ++J) { | |||
2211 | // Lower undefs (represented by -1 in mask) to {0..J}, which use a | |||
2212 | // whole lane of vector input, to allow further reduction at VM. E.g. | |||
2213 | // match an 8x16 byte shuffle to an equivalent cheaper 32x4 shuffle. | |||
2214 | uint64_t ByteIndex = M == -1 ? J : (uint64_t)M * LaneBytes + J; | |||
2215 | Ops[OpIdx++] = DAG.getConstant(ByteIndex, DL, MVT::i32); | |||
2216 | } | |||
2217 | } | |||
2218 | ||||
2219 | return DAG.getNode(WebAssemblyISD::SHUFFLE, DL, Op.getValueType(), Ops); | |||
2220 | } | |||
2221 | ||||
2222 | SDValue WebAssemblyTargetLowering::LowerSETCC(SDValue Op, | |||
2223 | SelectionDAG &DAG) const { | |||
2224 | SDLoc DL(Op); | |||
2225 | // The legalizer does not know how to expand the unsupported comparison modes | |||
2226 | // of i64x2 vectors, so we manually unroll them here. | |||
2227 | assert(Op->getOperand(0)->getSimpleValueType(0) == MVT::v2i64)(static_cast <bool> (Op->getOperand(0)->getSimpleValueType (0) == MVT::v2i64) ? void (0) : __assert_fail ("Op->getOperand(0)->getSimpleValueType(0) == MVT::v2i64" , "llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp", 2227 , __extension__ __PRETTY_FUNCTION__)); | |||
2228 | SmallVector<SDValue, 2> LHS, RHS; | |||
2229 | DAG.ExtractVectorElements(Op->getOperand(0), LHS); | |||
2230 | DAG.ExtractVectorElements(Op->getOperand(1), RHS); | |||
2231 | const SDValue &CC = Op->getOperand(2); | |||
2232 | auto MakeLane = [&](unsigned I) { | |||
2233 | return DAG.getNode(ISD::SELECT_CC, DL, MVT::i64, LHS[I], RHS[I], | |||
2234 | DAG.getConstant(uint64_t(-1), DL, MVT::i64), | |||
2235 | DAG.getConstant(uint64_t(0), DL, MVT::i64), CC); | |||
2236 | }; | |||
2237 | return DAG.getBuildVector(Op->getValueType(0), DL, | |||
2238 | {MakeLane(0), MakeLane(1)}); | |||
2239 | } | |||
2240 | ||||
2241 | SDValue | |||
2242 | WebAssemblyTargetLowering::LowerAccessVectorElement(SDValue Op, | |||
2243 | SelectionDAG &DAG) const { | |||
2244 | // Allow constant lane indices, expand variable lane indices | |||
2245 | SDNode *IdxNode = Op.getOperand(Op.getNumOperands() - 1).getNode(); | |||
2246 | if (isa<ConstantSDNode>(IdxNode)) { | |||
2247 | // Ensure the index type is i32 to match the tablegen patterns | |||
2248 | uint64_t Idx = cast<ConstantSDNode>(IdxNode)->getZExtValue(); | |||
2249 | SmallVector<SDValue, 3> Ops(Op.getNode()->ops()); | |||
2250 | Ops[Op.getNumOperands() - 1] = | |||
2251 | DAG.getConstant(Idx, SDLoc(IdxNode), MVT::i32); | |||
2252 | return DAG.getNode(Op.getOpcode(), SDLoc(Op), Op.getValueType(), Ops); | |||
2253 | } | |||
2254 | // Perform default expansion | |||
2255 | return SDValue(); | |||
2256 | } | |||
2257 | ||||
2258 | static SDValue unrollVectorShift(SDValue Op, SelectionDAG &DAG) { | |||
2259 | EVT LaneT = Op.getSimpleValueType().getVectorElementType(); | |||
2260 | // 32-bit and 64-bit unrolled shifts will have proper semantics | |||
2261 | if (LaneT.bitsGE(MVT::i32)) | |||
2262 | return DAG.UnrollVectorOp(Op.getNode()); | |||
2263 | // Otherwise mask the shift value to get proper semantics from 32-bit shift | |||
2264 | SDLoc DL(Op); | |||
2265 | size_t NumLanes = Op.getSimpleValueType().getVectorNumElements(); | |||
2266 | SDValue Mask = DAG.getConstant(LaneT.getSizeInBits() - 1, DL, MVT::i32); | |||
2267 | unsigned ShiftOpcode = Op.getOpcode(); | |||
2268 | SmallVector<SDValue, 16> ShiftedElements; | |||
2269 | DAG.ExtractVectorElements(Op.getOperand(0), ShiftedElements, 0, 0, MVT::i32); | |||
2270 | SmallVector<SDValue, 16> ShiftElements; | |||
2271 | DAG.ExtractVectorElements(Op.getOperand(1), ShiftElements, 0, 0, MVT::i32); | |||
2272 | SmallVector<SDValue, 16> UnrolledOps; | |||
2273 | for (size_t i = 0; i < NumLanes; ++i) { | |||
2274 | SDValue MaskedShiftValue = | |||
2275 | DAG.getNode(ISD::AND, DL, MVT::i32, ShiftElements[i], Mask); | |||
2276 | SDValue ShiftedValue = ShiftedElements[i]; | |||
2277 | if (ShiftOpcode == ISD::SRA) | |||
2278 | ShiftedValue = DAG.getNode(ISD::SIGN_EXTEND_INREG, DL, MVT::i32, | |||
2279 | ShiftedValue, DAG.getValueType(LaneT)); | |||
2280 | UnrolledOps.push_back( | |||
2281 | DAG.getNode(ShiftOpcode, DL, MVT::i32, ShiftedValue, MaskedShiftValue)); | |||
2282 | } | |||
2283 | return DAG.getBuildVector(Op.getValueType(), DL, UnrolledOps); | |||
2284 | } | |||
2285 | ||||
2286 | SDValue WebAssemblyTargetLowering::LowerShift(SDValue Op, | |||
2287 | SelectionDAG &DAG) const { | |||
2288 | SDLoc DL(Op); | |||
2289 | ||||
2290 | // Only manually lower vector shifts | |||
2291 | assert(Op.getSimpleValueType().isVector())(static_cast <bool> (Op.getSimpleValueType().isVector() ) ? void (0) : __assert_fail ("Op.getSimpleValueType().isVector()" , "llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp", 2291 , __extension__ __PRETTY_FUNCTION__)); | |||
2292 | ||||
2293 | uint64_t LaneBits = Op.getValueType().getScalarSizeInBits(); | |||
2294 | auto ShiftVal = Op.getOperand(1); | |||
2295 | ||||
2296 | // Try to skip bitmask operation since it is implied inside shift instruction | |||
2297 | auto SkipImpliedMask = [](SDValue MaskOp, uint64_t MaskBits) { | |||
2298 | if (MaskOp.getOpcode() != ISD::AND) | |||
2299 | return MaskOp; | |||
2300 | SDValue LHS = MaskOp.getOperand(0); | |||
2301 | SDValue RHS = MaskOp.getOperand(1); | |||
2302 | if (MaskOp.getValueType().isVector()) { | |||
2303 | APInt MaskVal; | |||
2304 | if (!ISD::isConstantSplatVector(RHS.getNode(), MaskVal)) | |||
2305 | std::swap(LHS, RHS); | |||
2306 | ||||
2307 | if (ISD::isConstantSplatVector(RHS.getNode(), MaskVal) && | |||
2308 | MaskVal == MaskBits) | |||
2309 | MaskOp = LHS; | |||
2310 | } else { | |||
2311 | if (!isa<ConstantSDNode>(RHS.getNode())) | |||
2312 | std::swap(LHS, RHS); | |||
2313 | ||||
2314 | auto ConstantRHS = dyn_cast<ConstantSDNode>(RHS.getNode()); | |||
2315 | if (ConstantRHS && ConstantRHS->getAPIntValue() == MaskBits) | |||
2316 | MaskOp = LHS; | |||
2317 | } | |||
2318 | ||||
2319 | return MaskOp; | |||
2320 | }; | |||
2321 | ||||
2322 | // Skip vector and operation | |||
2323 | ShiftVal = SkipImpliedMask(ShiftVal, LaneBits - 1); | |||
2324 | ShiftVal = DAG.getSplatValue(ShiftVal); | |||
2325 | if (!ShiftVal) | |||
2326 | return unrollVectorShift(Op, DAG); | |||
2327 | ||||
2328 | // Skip scalar and operation | |||
2329 | ShiftVal = SkipImpliedMask(ShiftVal, LaneBits - 1); | |||
2330 | // Use anyext because none of the high bits can affect the shift | |||
2331 | ShiftVal = DAG.getAnyExtOrTrunc(ShiftVal, DL, MVT::i32); | |||
2332 | ||||
2333 | unsigned Opcode; | |||
2334 | switch (Op.getOpcode()) { | |||
2335 | case ISD::SHL: | |||
2336 | Opcode = WebAssemblyISD::VEC_SHL; | |||
2337 | break; | |||
2338 | case ISD::SRA: | |||
2339 | Opcode = WebAssemblyISD::VEC_SHR_S; | |||
2340 | break; | |||
2341 | case ISD::SRL: | |||
2342 | Opcode = WebAssemblyISD::VEC_SHR_U; | |||
2343 | break; | |||
2344 | default: | |||
2345 | llvm_unreachable("unexpected opcode")::llvm::llvm_unreachable_internal("unexpected opcode", "llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp" , 2345); | |||
2346 | } | |||
2347 | ||||
2348 | return DAG.getNode(Opcode, DL, Op.getValueType(), Op.getOperand(0), ShiftVal); | |||
2349 | } | |||
2350 | ||||
2351 | SDValue WebAssemblyTargetLowering::LowerFP_TO_INT_SAT(SDValue Op, | |||
2352 | SelectionDAG &DAG) const { | |||
2353 | SDLoc DL(Op); | |||
2354 | EVT ResT = Op.getValueType(); | |||
2355 | EVT SatVT = cast<VTSDNode>(Op.getOperand(1))->getVT(); | |||
2356 | ||||
2357 | if ((ResT == MVT::i32 || ResT == MVT::i64) && | |||
2358 | (SatVT == MVT::i32 || SatVT == MVT::i64)) | |||
2359 | return Op; | |||
2360 | ||||
2361 | if (ResT == MVT::v4i32 && SatVT == MVT::i32) | |||
2362 | return Op; | |||
2363 | ||||
2364 | return SDValue(); | |||
2365 | } | |||
2366 | ||||
2367 | //===----------------------------------------------------------------------===// | |||
2368 | // Custom DAG combine hooks | |||
2369 | //===----------------------------------------------------------------------===// | |||
2370 | static SDValue | |||
2371 | performVECTOR_SHUFFLECombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI) { | |||
2372 | auto &DAG = DCI.DAG; | |||
2373 | auto Shuffle = cast<ShuffleVectorSDNode>(N); | |||
2374 | ||||
2375 | // Hoist vector bitcasts that don't change the number of lanes out of unary | |||
2376 | // shuffles, where they are less likely to get in the way of other combines. | |||
2377 | // (shuffle (vNxT1 (bitcast (vNxT0 x))), undef, mask) -> | |||
2378 | // (vNxT1 (bitcast (vNxT0 (shuffle x, undef, mask)))) | |||
2379 | SDValue Bitcast = N->getOperand(0); | |||
2380 | if (Bitcast.getOpcode() != ISD::BITCAST) | |||
2381 | return SDValue(); | |||
2382 | if (!N->getOperand(1).isUndef()) | |||
2383 | return SDValue(); | |||
2384 | SDValue CastOp = Bitcast.getOperand(0); | |||
2385 | MVT SrcType = CastOp.getSimpleValueType(); | |||
2386 | MVT DstType = Bitcast.getSimpleValueType(); | |||
2387 | if (!SrcType.is128BitVector() || | |||
2388 | SrcType.getVectorNumElements() != DstType.getVectorNumElements()) | |||
2389 | return SDValue(); | |||
2390 | SDValue NewShuffle = DAG.getVectorShuffle( | |||
2391 | SrcType, SDLoc(N), CastOp, DAG.getUNDEF(SrcType), Shuffle->getMask()); | |||
2392 | return DAG.getBitcast(DstType, NewShuffle); | |||
2393 | } | |||
2394 | ||||
2395 | /// Convert ({u,s}itofp vec) --> ({u,s}itofp ({s,z}ext vec)) so it doesn't get | |||
2396 | /// split up into scalar instructions during legalization, and the vector | |||
2397 | /// extending instructions are selected in performVectorExtendCombine below. | |||
2398 | static SDValue | |||
2399 | performVectorExtendToFPCombine(SDNode *N, | |||
2400 | TargetLowering::DAGCombinerInfo &DCI) { | |||
2401 | auto &DAG = DCI.DAG; | |||
2402 | assert(N->getOpcode() == ISD::UINT_TO_FP ||(static_cast <bool> (N->getOpcode() == ISD::UINT_TO_FP || N->getOpcode() == ISD::SINT_TO_FP) ? void (0) : __assert_fail ("N->getOpcode() == ISD::UINT_TO_FP || N->getOpcode() == ISD::SINT_TO_FP" , "llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp", 2403 , __extension__ __PRETTY_FUNCTION__)) | |||
2403 | N->getOpcode() == ISD::SINT_TO_FP)(static_cast <bool> (N->getOpcode() == ISD::UINT_TO_FP || N->getOpcode() == ISD::SINT_TO_FP) ? void (0) : __assert_fail ("N->getOpcode() == ISD::UINT_TO_FP || N->getOpcode() == ISD::SINT_TO_FP" , "llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp", 2403 , __extension__ __PRETTY_FUNCTION__)); | |||
2404 | ||||
2405 | EVT InVT = N->getOperand(0)->getValueType(0); | |||
2406 | EVT ResVT = N->getValueType(0); | |||
2407 | MVT ExtVT; | |||
2408 | if (ResVT == MVT::v4f32 && (InVT == MVT::v4i16 || InVT == MVT::v4i8)) | |||
2409 | ExtVT = MVT::v4i32; | |||
2410 | else if (ResVT == MVT::v2f64 && (InVT == MVT::v2i16 || InVT == MVT::v2i8)) | |||
2411 | ExtVT = MVT::v2i32; | |||
2412 | else | |||
2413 | return SDValue(); | |||
2414 | ||||
2415 | unsigned Op = | |||
2416 | N->getOpcode() == ISD::UINT_TO_FP ? ISD::ZERO_EXTEND : ISD::SIGN_EXTEND; | |||
2417 | SDValue Conv = DAG.getNode(Op, SDLoc(N), ExtVT, N->getOperand(0)); | |||
2418 | return DAG.getNode(N->getOpcode(), SDLoc(N), ResVT, Conv); | |||
2419 | } | |||
2420 | ||||
2421 | static SDValue | |||
2422 | performVectorExtendCombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI) { | |||
2423 | auto &DAG = DCI.DAG; | |||
2424 | assert(N->getOpcode() == ISD::SIGN_EXTEND ||(static_cast <bool> (N->getOpcode() == ISD::SIGN_EXTEND || N->getOpcode() == ISD::ZERO_EXTEND) ? void (0) : __assert_fail ("N->getOpcode() == ISD::SIGN_EXTEND || N->getOpcode() == ISD::ZERO_EXTEND" , "llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp", 2425 , __extension__ __PRETTY_FUNCTION__)) | |||
2425 | N->getOpcode() == ISD::ZERO_EXTEND)(static_cast <bool> (N->getOpcode() == ISD::SIGN_EXTEND || N->getOpcode() == ISD::ZERO_EXTEND) ? void (0) : __assert_fail ("N->getOpcode() == ISD::SIGN_EXTEND || N->getOpcode() == ISD::ZERO_EXTEND" , "llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp", 2425 , __extension__ __PRETTY_FUNCTION__)); | |||
2426 | ||||
2427 | // Combine ({s,z}ext (extract_subvector src, i)) into a widening operation if | |||
2428 | // possible before the extract_subvector can be expanded. | |||
2429 | auto Extract = N->getOperand(0); | |||
2430 | if (Extract.getOpcode() != ISD::EXTRACT_SUBVECTOR) | |||
2431 | return SDValue(); | |||
2432 | auto Source = Extract.getOperand(0); | |||
2433 | auto *IndexNode = dyn_cast<ConstantSDNode>(Extract.getOperand(1)); | |||
2434 | if (IndexNode == nullptr) | |||
2435 | return SDValue(); | |||
2436 | auto Index = IndexNode->getZExtValue(); | |||
2437 | ||||
2438 | // Only v8i8, v4i16, and v2i32 extracts can be widened, and only if the | |||
2439 | // extracted subvector is the low or high half of its source. | |||
2440 | EVT ResVT = N->getValueType(0); | |||
2441 | if (ResVT == MVT::v8i16) { | |||
2442 | if (Extract.getValueType() != MVT::v8i8 || | |||
2443 | Source.getValueType() != MVT::v16i8 || (Index != 0 && Index != 8)) | |||
2444 | return SDValue(); | |||
2445 | } else if (ResVT == MVT::v4i32) { | |||
2446 | if (Extract.getValueType() != MVT::v4i16 || | |||
2447 | Source.getValueType() != MVT::v8i16 || (Index != 0 && Index != 4)) | |||
2448 | return SDValue(); | |||
2449 | } else if (ResVT == MVT::v2i64) { | |||
2450 | if (Extract.getValueType() != MVT::v2i32 || | |||
2451 | Source.getValueType() != MVT::v4i32 || (Index != 0 && Index != 2)) | |||
2452 | return SDValue(); | |||
2453 | } else { | |||
2454 | return SDValue(); | |||
2455 | } | |||
2456 | ||||
2457 | bool IsSext = N->getOpcode() == ISD::SIGN_EXTEND; | |||
2458 | bool IsLow = Index == 0; | |||
2459 | ||||
2460 | unsigned Op = IsSext ? (IsLow ? WebAssemblyISD::EXTEND_LOW_S | |||
2461 | : WebAssemblyISD::EXTEND_HIGH_S) | |||
2462 | : (IsLow ? WebAssemblyISD::EXTEND_LOW_U | |||
2463 | : WebAssemblyISD::EXTEND_HIGH_U); | |||
2464 | ||||
2465 | return DAG.getNode(Op, SDLoc(N), ResVT, Source); | |||
2466 | } | |||
2467 | ||||
2468 | static SDValue | |||
2469 | performVectorTruncZeroCombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI) { | |||
2470 | auto &DAG = DCI.DAG; | |||
2471 | ||||
2472 | auto GetWasmConversionOp = [](unsigned Op) { | |||
2473 | switch (Op) { | |||
2474 | case ISD::FP_TO_SINT_SAT: | |||
2475 | return WebAssemblyISD::TRUNC_SAT_ZERO_S; | |||
2476 | case ISD::FP_TO_UINT_SAT: | |||
2477 | return WebAssemblyISD::TRUNC_SAT_ZERO_U; | |||
2478 | case ISD::FP_ROUND: | |||
2479 | return WebAssemblyISD::DEMOTE_ZERO; | |||
2480 | } | |||
2481 | llvm_unreachable("unexpected op")::llvm::llvm_unreachable_internal("unexpected op", "llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp" , 2481); | |||
2482 | }; | |||
2483 | ||||
2484 | auto IsZeroSplat = [](SDValue SplatVal) { | |||
2485 | auto *Splat = dyn_cast<BuildVectorSDNode>(SplatVal.getNode()); | |||
2486 | APInt SplatValue, SplatUndef; | |||
2487 | unsigned SplatBitSize; | |||
2488 | bool HasAnyUndefs; | |||
2489 | return Splat && | |||
2490 | Splat->isConstantSplat(SplatValue, SplatUndef, SplatBitSize, | |||
2491 | HasAnyUndefs) && | |||
2492 | SplatValue == 0; | |||
2493 | }; | |||
2494 | ||||
2495 | if (N->getOpcode() == ISD::CONCAT_VECTORS) { | |||
2496 | // Combine this: | |||
2497 | // | |||
2498 | // (concat_vectors (v2i32 (fp_to_{s,u}int_sat $x, 32)), (v2i32 (splat 0))) | |||
2499 | // | |||
2500 | // into (i32x4.trunc_sat_f64x2_zero_{s,u} $x). | |||
2501 | // | |||
2502 | // Or this: | |||
2503 | // | |||
2504 | // (concat_vectors (v2f32 (fp_round (v2f64 $x))), (v2f32 (splat 0))) | |||
2505 | // | |||
2506 | // into (f32x4.demote_zero_f64x2 $x). | |||
2507 | EVT ResVT; | |||
2508 | EVT ExpectedConversionType; | |||
2509 | auto Conversion = N->getOperand(0); | |||
2510 | auto ConversionOp = Conversion.getOpcode(); | |||
2511 | switch (ConversionOp) { | |||
2512 | case ISD::FP_TO_SINT_SAT: | |||
2513 | case ISD::FP_TO_UINT_SAT: | |||
2514 | ResVT = MVT::v4i32; | |||
2515 | ExpectedConversionType = MVT::v2i32; | |||
2516 | break; | |||
2517 | case ISD::FP_ROUND: | |||
2518 | ResVT = MVT::v4f32; | |||
2519 | ExpectedConversionType = MVT::v2f32; | |||
2520 | break; | |||
2521 | default: | |||
2522 | return SDValue(); | |||
2523 | } | |||
2524 | ||||
2525 | if (N->getValueType(0) != ResVT) | |||
2526 | return SDValue(); | |||
2527 | ||||
2528 | if (Conversion.getValueType() != ExpectedConversionType) | |||
2529 | return SDValue(); | |||
2530 | ||||
2531 | auto Source = Conversion.getOperand(0); | |||
2532 | if (Source.getValueType() != MVT::v2f64) | |||
2533 | return SDValue(); | |||
2534 | ||||
2535 | if (!IsZeroSplat(N->getOperand(1)) || | |||
2536 | N->getOperand(1).getValueType() != ExpectedConversionType) | |||
2537 | return SDValue(); | |||
2538 | ||||
2539 | unsigned Op = GetWasmConversionOp(ConversionOp); | |||
2540 | return DAG.getNode(Op, SDLoc(N), ResVT, Source); | |||
2541 | } | |||
2542 | ||||
2543 | // Combine this: | |||
2544 | // | |||
2545 | // (fp_to_{s,u}int_sat (concat_vectors $x, (v2f64 (splat 0))), 32) | |||
2546 | // | |||
2547 | // into (i32x4.trunc_sat_f64x2_zero_{s,u} $x). | |||
2548 | // | |||
2549 | // Or this: | |||
2550 | // | |||
2551 | // (v4f32 (fp_round (concat_vectors $x, (v2f64 (splat 0))))) | |||
2552 | // | |||
2553 | // into (f32x4.demote_zero_f64x2 $x). | |||
2554 | EVT ResVT; | |||
2555 | auto ConversionOp = N->getOpcode(); | |||
2556 | switch (ConversionOp) { | |||
2557 | case ISD::FP_TO_SINT_SAT: | |||
2558 | case ISD::FP_TO_UINT_SAT: | |||
2559 | ResVT = MVT::v4i32; | |||
2560 | break; | |||
2561 | case ISD::FP_ROUND: | |||
2562 | ResVT = MVT::v4f32; | |||
2563 | break; | |||
2564 | default: | |||
2565 | llvm_unreachable("unexpected op")::llvm::llvm_unreachable_internal("unexpected op", "llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp" , 2565); | |||
2566 | } | |||
2567 | ||||
2568 | if (N->getValueType(0) != ResVT) | |||
2569 | return SDValue(); | |||
2570 | ||||
2571 | auto Concat = N->getOperand(0); | |||
2572 | if (Concat.getValueType() != MVT::v4f64) | |||
2573 | return SDValue(); | |||
2574 | ||||
2575 | auto Source = Concat.getOperand(0); | |||
2576 | if (Source.getValueType() != MVT::v2f64) | |||
2577 | return SDValue(); | |||
2578 | ||||
2579 | if (!IsZeroSplat(Concat.getOperand(1)) || | |||
2580 | Concat.getOperand(1).getValueType() != MVT::v2f64) | |||
2581 | return SDValue(); | |||
2582 | ||||
2583 | unsigned Op = GetWasmConversionOp(ConversionOp); | |||
2584 | return DAG.getNode(Op, SDLoc(N), ResVT, Source); | |||
2585 | } | |||
2586 | ||||
2587 | // Helper to extract VectorWidth bits from Vec, starting from IdxVal. | |||
2588 | static SDValue extractSubVector(SDValue Vec, unsigned IdxVal, SelectionDAG &DAG, | |||
2589 | const SDLoc &DL, unsigned VectorWidth) { | |||
2590 | EVT VT = Vec.getValueType(); | |||
2591 | EVT ElVT = VT.getVectorElementType(); | |||
2592 | unsigned Factor = VT.getSizeInBits() / VectorWidth; | |||
2593 | EVT ResultVT = EVT::getVectorVT(*DAG.getContext(), ElVT, | |||
2594 | VT.getVectorNumElements() / Factor); | |||
2595 | ||||
2596 | // Extract the relevant VectorWidth bits. Generate an EXTRACT_SUBVECTOR | |||
2597 | unsigned ElemsPerChunk = VectorWidth / ElVT.getSizeInBits(); | |||
2598 | assert(isPowerOf2_32(ElemsPerChunk) && "Elements per chunk not power of 2")(static_cast <bool> (isPowerOf2_32(ElemsPerChunk) && "Elements per chunk not power of 2") ? void (0) : __assert_fail ("isPowerOf2_32(ElemsPerChunk) && \"Elements per chunk not power of 2\"" , "llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp", 2598 , __extension__ __PRETTY_FUNCTION__)); | |||
2599 | ||||
2600 | // This is the index of the first element of the VectorWidth-bit chunk | |||
2601 | // we want. Since ElemsPerChunk is a power of 2 just need to clear bits. | |||
2602 | IdxVal &= ~(ElemsPerChunk - 1); | |||
2603 | ||||
2604 | // If the input is a buildvector just emit a smaller one. | |||
2605 | if (Vec.getOpcode() == ISD::BUILD_VECTOR) | |||
2606 | return DAG.getBuildVector(ResultVT, DL, | |||
2607 | Vec->ops().slice(IdxVal, ElemsPerChunk)); | |||
2608 | ||||
2609 | SDValue VecIdx = DAG.getIntPtrConstant(IdxVal, DL); | |||
2610 | return DAG.getNode(ISD::EXTRACT_SUBVECTOR, DL, ResultVT, Vec, VecIdx); | |||
2611 | } | |||
2612 | ||||
2613 | // Helper to recursively truncate vector elements in half with NARROW_U. DstVT | |||
2614 | // is the expected destination value type after recursion. In is the initial | |||
2615 | // input. Note that the input should have enough leading zero bits to prevent | |||
2616 | // NARROW_U from saturating results. | |||
2617 | static SDValue truncateVectorWithNARROW(EVT DstVT, SDValue In, const SDLoc &DL, | |||
2618 | SelectionDAG &DAG) { | |||
2619 | EVT SrcVT = In.getValueType(); | |||
2620 | ||||
2621 | // No truncation required, we might get here due to recursive calls. | |||
2622 | if (SrcVT == DstVT) | |||
2623 | return In; | |||
2624 | ||||
2625 | unsigned SrcSizeInBits = SrcVT.getSizeInBits(); | |||
2626 | unsigned NumElems = SrcVT.getVectorNumElements(); | |||
2627 | if (!isPowerOf2_32(NumElems)) | |||
2628 | return SDValue(); | |||
2629 | assert(DstVT.getVectorNumElements() == NumElems && "Illegal truncation")(static_cast <bool> (DstVT.getVectorNumElements() == NumElems && "Illegal truncation") ? void (0) : __assert_fail ( "DstVT.getVectorNumElements() == NumElems && \"Illegal truncation\"" , "llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp", 2629 , __extension__ __PRETTY_FUNCTION__)); | |||
2630 | assert(SrcSizeInBits > DstVT.getSizeInBits() && "Illegal truncation")(static_cast <bool> (SrcSizeInBits > DstVT.getSizeInBits () && "Illegal truncation") ? void (0) : __assert_fail ("SrcSizeInBits > DstVT.getSizeInBits() && \"Illegal truncation\"" , "llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp", 2630 , __extension__ __PRETTY_FUNCTION__)); | |||
2631 | ||||
2632 | LLVMContext &Ctx = *DAG.getContext(); | |||
2633 | EVT PackedSVT = EVT::getIntegerVT(Ctx, SrcVT.getScalarSizeInBits() / 2); | |||
2634 | ||||
2635 | // Narrow to the largest type possible: | |||
2636 | // vXi64/vXi32 -> i16x8.narrow_i32x4_u and vXi16 -> i8x16.narrow_i16x8_u. | |||
2637 | EVT InVT = MVT::i16, OutVT = MVT::i8; | |||
2638 | if (SrcVT.getScalarSizeInBits() > 16) { | |||
2639 | InVT = MVT::i32; | |||
2640 | OutVT = MVT::i16; | |||
2641 | } | |||
2642 | unsigned SubSizeInBits = SrcSizeInBits / 2; | |||
2643 | InVT = EVT::getVectorVT(Ctx, InVT, SubSizeInBits / InVT.getSizeInBits()); | |||
2644 | OutVT = EVT::getVectorVT(Ctx, OutVT, SubSizeInBits / OutVT.getSizeInBits()); | |||
2645 | ||||
2646 | // Split lower/upper subvectors. | |||
2647 | SDValue Lo = extractSubVector(In, 0, DAG, DL, SubSizeInBits); | |||
2648 | SDValue Hi = extractSubVector(In, NumElems / 2, DAG, DL, SubSizeInBits); | |||
2649 | ||||
2650 | // 256bit -> 128bit truncate - Narrow lower/upper 128-bit subvectors. | |||
2651 | if (SrcVT.is256BitVector() && DstVT.is128BitVector()) { | |||
2652 | Lo = DAG.getBitcast(InVT, Lo); | |||
2653 | Hi = DAG.getBitcast(InVT, Hi); | |||
2654 | SDValue Res = DAG.getNode(WebAssemblyISD::NARROW_U, DL, OutVT, Lo, Hi); | |||
2655 | return DAG.getBitcast(DstVT, Res); | |||
2656 | } | |||
2657 | ||||
2658 | // Recursively narrow lower/upper subvectors, concat result and narrow again. | |||
2659 | EVT PackedVT = EVT::getVectorVT(Ctx, PackedSVT, NumElems / 2); | |||
2660 | Lo = truncateVectorWithNARROW(PackedVT, Lo, DL, DAG); | |||
2661 | Hi = truncateVectorWithNARROW(PackedVT, Hi, DL, DAG); | |||
2662 | ||||
2663 | PackedVT = EVT::getVectorVT(Ctx, PackedSVT, NumElems); | |||
2664 | SDValue Res = DAG.getNode(ISD::CONCAT_VECTORS, DL, PackedVT, Lo, Hi); | |||
2665 | return truncateVectorWithNARROW(DstVT, Res, DL, DAG); | |||
2666 | } | |||
2667 | ||||
2668 | static SDValue performTruncateCombine(SDNode *N, | |||
2669 | TargetLowering::DAGCombinerInfo &DCI) { | |||
2670 | auto &DAG = DCI.DAG; | |||
2671 | ||||
2672 | SDValue In = N->getOperand(0); | |||
2673 | EVT InVT = In.getValueType(); | |||
2674 | if (!InVT.isSimple()) | |||
2675 | return SDValue(); | |||
2676 | ||||
2677 | EVT OutVT = N->getValueType(0); | |||
2678 | if (!OutVT.isVector()) | |||
2679 | return SDValue(); | |||
2680 | ||||
2681 | EVT OutSVT = OutVT.getVectorElementType(); | |||
2682 | EVT InSVT = InVT.getVectorElementType(); | |||
2683 | // Currently only cover truncate to v16i8 or v8i16. | |||
2684 | if (!((InSVT == MVT::i16 || InSVT == MVT::i32 || InSVT == MVT::i64) && | |||
2685 | (OutSVT == MVT::i8 || OutSVT == MVT::i16) && OutVT.is128BitVector())) | |||
2686 | return SDValue(); | |||
2687 | ||||
2688 | SDLoc DL(N); | |||
2689 | APInt Mask = APInt::getLowBitsSet(InVT.getScalarSizeInBits(), | |||
2690 | OutVT.getScalarSizeInBits()); | |||
2691 | In = DAG.getNode(ISD::AND, DL, InVT, In, DAG.getConstant(Mask, DL, InVT)); | |||
2692 | return truncateVectorWithNARROW(OutVT, In, DL, DAG); | |||
2693 | } | |||
2694 | ||||
2695 | SDValue | |||
2696 | WebAssemblyTargetLowering::PerformDAGCombine(SDNode *N, | |||
2697 | DAGCombinerInfo &DCI) const { | |||
2698 | switch (N->getOpcode()) { | |||
2699 | default: | |||
2700 | return SDValue(); | |||
2701 | case ISD::VECTOR_SHUFFLE: | |||
2702 | return performVECTOR_SHUFFLECombine(N, DCI); | |||
2703 | case ISD::SIGN_EXTEND: | |||
2704 | case ISD::ZERO_EXTEND: | |||
2705 | return performVectorExtendCombine(N, DCI); | |||
2706 | case ISD::UINT_TO_FP: | |||
2707 | case ISD::SINT_TO_FP: | |||
2708 | return performVectorExtendToFPCombine(N, DCI); | |||
2709 | case ISD::FP_TO_SINT_SAT: | |||
2710 | case ISD::FP_TO_UINT_SAT: | |||
2711 | case ISD::FP_ROUND: | |||
2712 | case ISD::CONCAT_VECTORS: | |||
2713 | return performVectorTruncZeroCombine(N, DCI); | |||
2714 | case ISD::TRUNCATE: | |||
2715 | return performTruncateCombine(N, DCI); | |||
2716 | } | |||
2717 | } |