File: | llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp |
Warning: | line 2112, 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/MachineInstrBuilder.h" | ||||
23 | #include "llvm/CodeGen/MachineJumpTableInfo.h" | ||||
24 | #include "llvm/CodeGen/MachineModuleInfo.h" | ||||
25 | #include "llvm/CodeGen/MachineRegisterInfo.h" | ||||
26 | #include "llvm/CodeGen/SelectionDAG.h" | ||||
27 | #include "llvm/CodeGen/SelectionDAGNodes.h" | ||||
28 | #include "llvm/IR/DiagnosticInfo.h" | ||||
29 | #include "llvm/IR/DiagnosticPrinter.h" | ||||
30 | #include "llvm/IR/Function.h" | ||||
31 | #include "llvm/IR/Intrinsics.h" | ||||
32 | #include "llvm/IR/IntrinsicsWebAssembly.h" | ||||
33 | #include "llvm/Support/Debug.h" | ||||
34 | #include "llvm/Support/ErrorHandling.h" | ||||
35 | #include "llvm/Support/KnownBits.h" | ||||
36 | #include "llvm/Support/MathExtras.h" | ||||
37 | #include "llvm/Support/raw_ostream.h" | ||||
38 | #include "llvm/Target/TargetOptions.h" | ||||
39 | using namespace llvm; | ||||
40 | |||||
41 | #define DEBUG_TYPE"wasm-lower" "wasm-lower" | ||||
42 | |||||
43 | WebAssemblyTargetLowering::WebAssemblyTargetLowering( | ||||
44 | const TargetMachine &TM, const WebAssemblySubtarget &STI) | ||||
45 | : TargetLowering(TM), Subtarget(&STI) { | ||||
46 | auto MVTPtr = Subtarget->hasAddr64() ? MVT::i64 : MVT::i32; | ||||
47 | |||||
48 | // Booleans always contain 0 or 1. | ||||
49 | setBooleanContents(ZeroOrOneBooleanContent); | ||||
50 | // Except in SIMD vectors | ||||
51 | setBooleanVectorContents(ZeroOrNegativeOneBooleanContent); | ||||
52 | // We don't know the microarchitecture here, so just reduce register pressure. | ||||
53 | setSchedulingPreference(Sched::RegPressure); | ||||
54 | // Tell ISel that we have a stack pointer. | ||||
55 | setStackPointerRegisterToSaveRestore( | ||||
56 | Subtarget->hasAddr64() ? WebAssembly::SP64 : WebAssembly::SP32); | ||||
57 | // Set up the register classes. | ||||
58 | addRegisterClass(MVT::i32, &WebAssembly::I32RegClass); | ||||
59 | addRegisterClass(MVT::i64, &WebAssembly::I64RegClass); | ||||
60 | addRegisterClass(MVT::f32, &WebAssembly::F32RegClass); | ||||
61 | addRegisterClass(MVT::f64, &WebAssembly::F64RegClass); | ||||
62 | if (Subtarget->hasSIMD128()) { | ||||
63 | addRegisterClass(MVT::v16i8, &WebAssembly::V128RegClass); | ||||
64 | addRegisterClass(MVT::v8i16, &WebAssembly::V128RegClass); | ||||
65 | addRegisterClass(MVT::v4i32, &WebAssembly::V128RegClass); | ||||
66 | addRegisterClass(MVT::v4f32, &WebAssembly::V128RegClass); | ||||
67 | addRegisterClass(MVT::v2i64, &WebAssembly::V128RegClass); | ||||
68 | addRegisterClass(MVT::v2f64, &WebAssembly::V128RegClass); | ||||
69 | } | ||||
70 | if (Subtarget->hasReferenceTypes()) { | ||||
71 | addRegisterClass(MVT::externref, &WebAssembly::EXTERNREFRegClass); | ||||
72 | addRegisterClass(MVT::funcref, &WebAssembly::FUNCREFRegClass); | ||||
73 | } | ||||
74 | // Compute derived properties from the register classes. | ||||
75 | computeRegisterProperties(Subtarget->getRegisterInfo()); | ||||
76 | |||||
77 | // Transform loads and stores to pointers in address space 1 to loads and | ||||
78 | // stores to WebAssembly global variables, outside linear memory. | ||||
79 | for (auto T : {MVT::i32, MVT::i64, MVT::f32, MVT::f64}) { | ||||
80 | setOperationAction(ISD::LOAD, T, Custom); | ||||
81 | setOperationAction(ISD::STORE, T, Custom); | ||||
82 | } | ||||
83 | if (Subtarget->hasSIMD128()) { | ||||
84 | for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v4f32, MVT::v2i64, | ||||
85 | MVT::v2f64}) { | ||||
86 | setOperationAction(ISD::LOAD, T, Custom); | ||||
87 | setOperationAction(ISD::STORE, T, Custom); | ||||
88 | } | ||||
89 | } | ||||
90 | if (Subtarget->hasReferenceTypes()) { | ||||
91 | for (auto T : {MVT::externref, MVT::funcref}) { | ||||
92 | setOperationAction(ISD::LOAD, T, Custom); | ||||
93 | setOperationAction(ISD::STORE, T, Custom); | ||||
94 | } | ||||
95 | } | ||||
96 | |||||
97 | setOperationAction(ISD::GlobalAddress, MVTPtr, Custom); | ||||
98 | setOperationAction(ISD::GlobalTLSAddress, MVTPtr, Custom); | ||||
99 | setOperationAction(ISD::ExternalSymbol, MVTPtr, Custom); | ||||
100 | setOperationAction(ISD::JumpTable, MVTPtr, Custom); | ||||
101 | setOperationAction(ISD::BlockAddress, MVTPtr, Custom); | ||||
102 | setOperationAction(ISD::BRIND, MVT::Other, Custom); | ||||
103 | |||||
104 | // Take the default expansion for va_arg, va_copy, and va_end. There is no | ||||
105 | // default action for va_start, so we do that custom. | ||||
106 | setOperationAction(ISD::VASTART, MVT::Other, Custom); | ||||
107 | setOperationAction(ISD::VAARG, MVT::Other, Expand); | ||||
108 | setOperationAction(ISD::VACOPY, MVT::Other, Expand); | ||||
109 | setOperationAction(ISD::VAEND, MVT::Other, Expand); | ||||
110 | |||||
111 | for (auto T : {MVT::f32, MVT::f64, MVT::v4f32, MVT::v2f64}) { | ||||
112 | // Don't expand the floating-point types to constant pools. | ||||
113 | setOperationAction(ISD::ConstantFP, T, Legal); | ||||
114 | // Expand floating-point comparisons. | ||||
115 | for (auto CC : {ISD::SETO, ISD::SETUO, ISD::SETUEQ, ISD::SETONE, | ||||
116 | ISD::SETULT, ISD::SETULE, ISD::SETUGT, ISD::SETUGE}) | ||||
117 | setCondCodeAction(CC, T, Expand); | ||||
118 | // Expand floating-point library function operators. | ||||
119 | for (auto Op : | ||||
120 | {ISD::FSIN, ISD::FCOS, ISD::FSINCOS, ISD::FPOW, ISD::FREM, ISD::FMA}) | ||||
121 | setOperationAction(Op, T, Expand); | ||||
122 | // Note supported floating-point library function operators that otherwise | ||||
123 | // default to expand. | ||||
124 | for (auto Op : | ||||
125 | {ISD::FCEIL, ISD::FFLOOR, ISD::FTRUNC, ISD::FNEARBYINT, ISD::FRINT}) | ||||
126 | setOperationAction(Op, T, Legal); | ||||
127 | // Support minimum and maximum, which otherwise default to expand. | ||||
128 | setOperationAction(ISD::FMINIMUM, T, Legal); | ||||
129 | setOperationAction(ISD::FMAXIMUM, T, Legal); | ||||
130 | // WebAssembly currently has no builtin f16 support. | ||||
131 | setOperationAction(ISD::FP16_TO_FP, T, Expand); | ||||
132 | setOperationAction(ISD::FP_TO_FP16, T, Expand); | ||||
133 | setLoadExtAction(ISD::EXTLOAD, T, MVT::f16, Expand); | ||||
134 | setTruncStoreAction(T, MVT::f16, Expand); | ||||
135 | } | ||||
136 | |||||
137 | // Expand unavailable integer operations. | ||||
138 | for (auto Op : | ||||
139 | {ISD::BSWAP, ISD::SMUL_LOHI, ISD::UMUL_LOHI, ISD::MULHS, ISD::MULHU, | ||||
140 | ISD::SDIVREM, ISD::UDIVREM, ISD::SHL_PARTS, ISD::SRA_PARTS, | ||||
141 | ISD::SRL_PARTS, ISD::ADDC, ISD::ADDE, ISD::SUBC, ISD::SUBE}) { | ||||
142 | for (auto T : {MVT::i32, MVT::i64}) | ||||
143 | setOperationAction(Op, T, Expand); | ||||
144 | if (Subtarget->hasSIMD128()) | ||||
145 | for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v2i64}) | ||||
146 | setOperationAction(Op, T, Expand); | ||||
147 | } | ||||
148 | |||||
149 | if (Subtarget->hasNontrappingFPToInt()) | ||||
150 | for (auto Op : {ISD::FP_TO_SINT_SAT, ISD::FP_TO_UINT_SAT}) | ||||
151 | for (auto T : {MVT::i32, MVT::i64}) | ||||
152 | setOperationAction(Op, T, Custom); | ||||
153 | |||||
154 | // SIMD-specific configuration | ||||
155 | if (Subtarget->hasSIMD128()) { | ||||
156 | // Hoist bitcasts out of shuffles | ||||
157 | setTargetDAGCombine(ISD::VECTOR_SHUFFLE); | ||||
158 | |||||
159 | // Combine extends of extract_subvectors into widening ops | ||||
160 | setTargetDAGCombine(ISD::SIGN_EXTEND); | ||||
161 | setTargetDAGCombine(ISD::ZERO_EXTEND); | ||||
162 | |||||
163 | // Combine int_to_fp or fp_extend of extract_vectors and vice versa into | ||||
164 | // conversions ops | ||||
165 | setTargetDAGCombine(ISD::SINT_TO_FP); | ||||
166 | setTargetDAGCombine(ISD::UINT_TO_FP); | ||||
167 | setTargetDAGCombine(ISD::FP_EXTEND); | ||||
168 | setTargetDAGCombine(ISD::EXTRACT_SUBVECTOR); | ||||
169 | |||||
170 | // Combine fp_to_{s,u}int_sat or fp_round of concat_vectors or vice versa | ||||
171 | // into conversion ops | ||||
172 | setTargetDAGCombine(ISD::FP_TO_SINT_SAT); | ||||
173 | setTargetDAGCombine(ISD::FP_TO_UINT_SAT); | ||||
174 | setTargetDAGCombine(ISD::FP_ROUND); | ||||
175 | setTargetDAGCombine(ISD::CONCAT_VECTORS); | ||||
176 | |||||
177 | // Support saturating add for i8x16 and i16x8 | ||||
178 | for (auto Op : {ISD::SADDSAT, ISD::UADDSAT}) | ||||
179 | for (auto T : {MVT::v16i8, MVT::v8i16}) | ||||
180 | setOperationAction(Op, T, Legal); | ||||
181 | |||||
182 | // Support integer abs | ||||
183 | for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v2i64}) | ||||
184 | setOperationAction(ISD::ABS, T, Legal); | ||||
185 | |||||
186 | // Custom lower BUILD_VECTORs to minimize number of replace_lanes | ||||
187 | for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v4f32, MVT::v2i64, | ||||
188 | MVT::v2f64}) | ||||
189 | setOperationAction(ISD::BUILD_VECTOR, T, Custom); | ||||
190 | |||||
191 | // We have custom shuffle lowering to expose the shuffle mask | ||||
192 | for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v4f32, MVT::v2i64, | ||||
193 | MVT::v2f64}) | ||||
194 | setOperationAction(ISD::VECTOR_SHUFFLE, T, Custom); | ||||
195 | |||||
196 | // Custom lowering since wasm shifts must have a scalar shift amount | ||||
197 | for (auto Op : {ISD::SHL, ISD::SRA, ISD::SRL}) | ||||
198 | for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v2i64}) | ||||
199 | setOperationAction(Op, T, Custom); | ||||
200 | |||||
201 | // Custom lower lane accesses to expand out variable indices | ||||
202 | for (auto Op : {ISD::EXTRACT_VECTOR_ELT, ISD::INSERT_VECTOR_ELT}) | ||||
203 | for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v4f32, MVT::v2i64, | ||||
204 | MVT::v2f64}) | ||||
205 | setOperationAction(Op, T, Custom); | ||||
206 | |||||
207 | // There is no i8x16.mul instruction | ||||
208 | setOperationAction(ISD::MUL, MVT::v16i8, Expand); | ||||
209 | |||||
210 | // There is no vector conditional select instruction | ||||
211 | for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v4f32, MVT::v2i64, | ||||
212 | MVT::v2f64}) | ||||
213 | setOperationAction(ISD::SELECT_CC, T, Expand); | ||||
214 | |||||
215 | // Expand integer operations supported for scalars but not SIMD | ||||
216 | for (auto Op : {ISD::CTLZ, ISD::CTTZ, ISD::CTPOP, ISD::SDIV, ISD::UDIV, | ||||
217 | ISD::SREM, ISD::UREM, ISD::ROTL, ISD::ROTR}) | ||||
218 | for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v2i64}) | ||||
219 | setOperationAction(Op, T, Expand); | ||||
220 | |||||
221 | // But we do have integer min and max operations | ||||
222 | for (auto Op : {ISD::SMIN, ISD::SMAX, ISD::UMIN, ISD::UMAX}) | ||||
223 | for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32}) | ||||
224 | setOperationAction(Op, T, Legal); | ||||
225 | |||||
226 | // And we have popcnt for i8x16 | ||||
227 | setOperationAction(ISD::CTPOP, MVT::v16i8, Legal); | ||||
228 | |||||
229 | // Expand float operations supported for scalars but not SIMD | ||||
230 | for (auto Op : {ISD::FCOPYSIGN, ISD::FLOG, ISD::FLOG2, ISD::FLOG10, | ||||
231 | ISD::FEXP, ISD::FEXP2, ISD::FRINT}) | ||||
232 | for (auto T : {MVT::v4f32, MVT::v2f64}) | ||||
233 | setOperationAction(Op, T, Expand); | ||||
234 | |||||
235 | // Unsigned comparison operations are unavailable for i64x2 vectors. | ||||
236 | for (auto CC : {ISD::SETUGT, ISD::SETUGE, ISD::SETULT, ISD::SETULE}) | ||||
237 | setCondCodeAction(CC, MVT::v2i64, Custom); | ||||
238 | |||||
239 | // 64x2 conversions are not in the spec | ||||
240 | for (auto Op : | ||||
241 | {ISD::SINT_TO_FP, ISD::UINT_TO_FP, ISD::FP_TO_SINT, ISD::FP_TO_UINT}) | ||||
242 | for (auto T : {MVT::v2i64, MVT::v2f64}) | ||||
243 | setOperationAction(Op, T, Expand); | ||||
244 | |||||
245 | // But saturating fp_to_int converstions are | ||||
246 | for (auto Op : {ISD::FP_TO_SINT_SAT, ISD::FP_TO_UINT_SAT}) | ||||
247 | setOperationAction(Op, MVT::v4i32, Custom); | ||||
248 | } | ||||
249 | |||||
250 | // As a special case, these operators use the type to mean the type to | ||||
251 | // sign-extend from. | ||||
252 | setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i1, Expand); | ||||
253 | if (!Subtarget->hasSignExt()) { | ||||
254 | // Sign extends are legal only when extending a vector extract | ||||
255 | auto Action = Subtarget->hasSIMD128() ? Custom : Expand; | ||||
256 | for (auto T : {MVT::i8, MVT::i16, MVT::i32}) | ||||
257 | setOperationAction(ISD::SIGN_EXTEND_INREG, T, Action); | ||||
258 | } | ||||
259 | for (auto T : MVT::integer_fixedlen_vector_valuetypes()) | ||||
260 | setOperationAction(ISD::SIGN_EXTEND_INREG, T, Expand); | ||||
261 | |||||
262 | // Dynamic stack allocation: use the default expansion. | ||||
263 | setOperationAction(ISD::STACKSAVE, MVT::Other, Expand); | ||||
264 | setOperationAction(ISD::STACKRESTORE, MVT::Other, Expand); | ||||
265 | setOperationAction(ISD::DYNAMIC_STACKALLOC, MVTPtr, Expand); | ||||
266 | |||||
267 | setOperationAction(ISD::FrameIndex, MVT::i32, Custom); | ||||
268 | setOperationAction(ISD::FrameIndex, MVT::i64, Custom); | ||||
269 | setOperationAction(ISD::CopyToReg, MVT::Other, Custom); | ||||
270 | |||||
271 | // Expand these forms; we pattern-match the forms that we can handle in isel. | ||||
272 | for (auto T : {MVT::i32, MVT::i64, MVT::f32, MVT::f64}) | ||||
273 | for (auto Op : {ISD::BR_CC, ISD::SELECT_CC}) | ||||
274 | setOperationAction(Op, T, Expand); | ||||
275 | |||||
276 | // We have custom switch handling. | ||||
277 | setOperationAction(ISD::BR_JT, MVT::Other, Custom); | ||||
278 | |||||
279 | // WebAssembly doesn't have: | ||||
280 | // - Floating-point extending loads. | ||||
281 | // - Floating-point truncating stores. | ||||
282 | // - i1 extending loads. | ||||
283 | // - truncating SIMD stores and most extending loads | ||||
284 | setLoadExtAction(ISD::EXTLOAD, MVT::f64, MVT::f32, Expand); | ||||
285 | setTruncStoreAction(MVT::f64, MVT::f32, Expand); | ||||
286 | for (auto T : MVT::integer_valuetypes()) | ||||
287 | for (auto Ext : {ISD::EXTLOAD, ISD::ZEXTLOAD, ISD::SEXTLOAD}) | ||||
288 | setLoadExtAction(Ext, T, MVT::i1, Promote); | ||||
289 | if (Subtarget->hasSIMD128()) { | ||||
290 | for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v2i64, MVT::v4f32, | ||||
291 | MVT::v2f64}) { | ||||
292 | for (auto MemT : MVT::fixedlen_vector_valuetypes()) { | ||||
293 | if (MVT(T) != MemT) { | ||||
294 | setTruncStoreAction(T, MemT, Expand); | ||||
295 | for (auto Ext : {ISD::EXTLOAD, ISD::ZEXTLOAD, ISD::SEXTLOAD}) | ||||
296 | setLoadExtAction(Ext, T, MemT, Expand); | ||||
297 | } | ||||
298 | } | ||||
299 | } | ||||
300 | // But some vector extending loads are legal | ||||
301 | for (auto Ext : {ISD::EXTLOAD, ISD::SEXTLOAD, ISD::ZEXTLOAD}) { | ||||
302 | setLoadExtAction(Ext, MVT::v8i16, MVT::v8i8, Legal); | ||||
303 | setLoadExtAction(Ext, MVT::v4i32, MVT::v4i16, Legal); | ||||
304 | setLoadExtAction(Ext, MVT::v2i64, MVT::v2i32, Legal); | ||||
305 | } | ||||
306 | setLoadExtAction(ISD::EXTLOAD, MVT::v2f64, MVT::v2f32, Legal); | ||||
307 | } | ||||
308 | |||||
309 | // Don't do anything clever with build_pairs | ||||
310 | setOperationAction(ISD::BUILD_PAIR, MVT::i64, Expand); | ||||
311 | |||||
312 | // Trap lowers to wasm unreachable | ||||
313 | setOperationAction(ISD::TRAP, MVT::Other, Legal); | ||||
314 | setOperationAction(ISD::DEBUGTRAP, MVT::Other, Legal); | ||||
315 | |||||
316 | // Exception handling intrinsics | ||||
317 | setOperationAction(ISD::INTRINSIC_WO_CHAIN, MVT::Other, Custom); | ||||
318 | setOperationAction(ISD::INTRINSIC_W_CHAIN, MVT::Other, Custom); | ||||
319 | setOperationAction(ISD::INTRINSIC_VOID, MVT::Other, Custom); | ||||
320 | |||||
321 | setMaxAtomicSizeInBitsSupported(64); | ||||
322 | |||||
323 | // Override the __gnu_f2h_ieee/__gnu_h2f_ieee names so that the f32 name is | ||||
324 | // consistent with the f64 and f128 names. | ||||
325 | setLibcallName(RTLIB::FPEXT_F16_F32, "__extendhfsf2"); | ||||
326 | setLibcallName(RTLIB::FPROUND_F32_F16, "__truncsfhf2"); | ||||
327 | |||||
328 | // Define the emscripten name for return address helper. | ||||
329 | // TODO: when implementing other Wasm backends, make this generic or only do | ||||
330 | // this on emscripten depending on what they end up doing. | ||||
331 | setLibcallName(RTLIB::RETURN_ADDRESS, "emscripten_return_address"); | ||||
332 | |||||
333 | // Always convert switches to br_tables unless there is only one case, which | ||||
334 | // is equivalent to a simple branch. This reduces code size for wasm, and we | ||||
335 | // defer possible jump table optimizations to the VM. | ||||
336 | setMinimumJumpTableEntries(2); | ||||
337 | } | ||||
338 | |||||
339 | MVT WebAssemblyTargetLowering::getPointerTy(const DataLayout &DL, | ||||
340 | uint32_t AS) const { | ||||
341 | if (AS == WebAssembly::WasmAddressSpace::WASM_ADDRESS_SPACE_EXTERNREF) | ||||
342 | return MVT::externref; | ||||
343 | if (AS == WebAssembly::WasmAddressSpace::WASM_ADDRESS_SPACE_FUNCREF) | ||||
344 | return MVT::funcref; | ||||
345 | return TargetLowering::getPointerTy(DL, AS); | ||||
346 | } | ||||
347 | |||||
348 | MVT WebAssemblyTargetLowering::getPointerMemTy(const DataLayout &DL, | ||||
349 | uint32_t AS) const { | ||||
350 | if (AS == WebAssembly::WasmAddressSpace::WASM_ADDRESS_SPACE_EXTERNREF) | ||||
351 | return MVT::externref; | ||||
352 | if (AS == WebAssembly::WasmAddressSpace::WASM_ADDRESS_SPACE_FUNCREF) | ||||
353 | return MVT::funcref; | ||||
354 | return TargetLowering::getPointerMemTy(DL, AS); | ||||
355 | } | ||||
356 | |||||
357 | TargetLowering::AtomicExpansionKind | ||||
358 | WebAssemblyTargetLowering::shouldExpandAtomicRMWInIR(AtomicRMWInst *AI) const { | ||||
359 | // We have wasm instructions for these | ||||
360 | switch (AI->getOperation()) { | ||||
361 | case AtomicRMWInst::Add: | ||||
362 | case AtomicRMWInst::Sub: | ||||
363 | case AtomicRMWInst::And: | ||||
364 | case AtomicRMWInst::Or: | ||||
365 | case AtomicRMWInst::Xor: | ||||
366 | case AtomicRMWInst::Xchg: | ||||
367 | return AtomicExpansionKind::None; | ||||
368 | default: | ||||
369 | break; | ||||
370 | } | ||||
371 | return AtomicExpansionKind::CmpXChg; | ||||
372 | } | ||||
373 | |||||
374 | bool WebAssemblyTargetLowering::shouldScalarizeBinop(SDValue VecOp) const { | ||||
375 | // Implementation copied from X86TargetLowering. | ||||
376 | unsigned Opc = VecOp.getOpcode(); | ||||
377 | |||||
378 | // Assume target opcodes can't be scalarized. | ||||
379 | // TODO - do we have any exceptions? | ||||
380 | if (Opc >= ISD::BUILTIN_OP_END) | ||||
381 | return false; | ||||
382 | |||||
383 | // If the vector op is not supported, try to convert to scalar. | ||||
384 | EVT VecVT = VecOp.getValueType(); | ||||
385 | if (!isOperationLegalOrCustomOrPromote(Opc, VecVT)) | ||||
386 | return true; | ||||
387 | |||||
388 | // If the vector op is supported, but the scalar op is not, the transform may | ||||
389 | // not be worthwhile. | ||||
390 | EVT ScalarVT = VecVT.getScalarType(); | ||||
391 | return isOperationLegalOrCustomOrPromote(Opc, ScalarVT); | ||||
392 | } | ||||
393 | |||||
394 | FastISel *WebAssemblyTargetLowering::createFastISel( | ||||
395 | FunctionLoweringInfo &FuncInfo, const TargetLibraryInfo *LibInfo) const { | ||||
396 | return WebAssembly::createFastISel(FuncInfo, LibInfo); | ||||
397 | } | ||||
398 | |||||
399 | MVT WebAssemblyTargetLowering::getScalarShiftAmountTy(const DataLayout & /*DL*/, | ||||
400 | EVT VT) const { | ||||
401 | unsigned BitWidth = NextPowerOf2(VT.getSizeInBits() - 1); | ||||
402 | if (BitWidth > 1 && BitWidth < 8) | ||||
403 | BitWidth = 8; | ||||
404 | |||||
405 | if (BitWidth > 64) { | ||||
406 | // The shift will be lowered to a libcall, and compiler-rt libcalls expect | ||||
407 | // the count to be an i32. | ||||
408 | BitWidth = 32; | ||||
409 | 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\"" , "/build/llvm-toolchain-snapshot-14~++20211017100700+d245f2e8597b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp" , 410, __extension__ __PRETTY_FUNCTION__)) | ||||
410 | "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\"" , "/build/llvm-toolchain-snapshot-14~++20211017100700+d245f2e8597b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp" , 410, __extension__ __PRETTY_FUNCTION__)); | ||||
411 | } | ||||
412 | |||||
413 | MVT Result = MVT::getIntegerVT(BitWidth); | ||||
414 | 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\"" , "/build/llvm-toolchain-snapshot-14~++20211017100700+d245f2e8597b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp" , 415, __extension__ __PRETTY_FUNCTION__)) | ||||
415 | "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\"" , "/build/llvm-toolchain-snapshot-14~++20211017100700+d245f2e8597b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp" , 415, __extension__ __PRETTY_FUNCTION__)); | ||||
416 | return Result; | ||||
417 | } | ||||
418 | |||||
419 | // Lower an fp-to-int conversion operator from the LLVM opcode, which has an | ||||
420 | // undefined result on invalid/overflow, to the WebAssembly opcode, which | ||||
421 | // traps on invalid/overflow. | ||||
422 | static MachineBasicBlock *LowerFPToInt(MachineInstr &MI, DebugLoc DL, | ||||
423 | MachineBasicBlock *BB, | ||||
424 | const TargetInstrInfo &TII, | ||||
425 | bool IsUnsigned, bool Int64, | ||||
426 | bool Float64, unsigned LoweredOpcode) { | ||||
427 | MachineRegisterInfo &MRI = BB->getParent()->getRegInfo(); | ||||
428 | |||||
429 | Register OutReg = MI.getOperand(0).getReg(); | ||||
430 | Register InReg = MI.getOperand(1).getReg(); | ||||
431 | |||||
432 | unsigned Abs = Float64 ? WebAssembly::ABS_F64 : WebAssembly::ABS_F32; | ||||
433 | unsigned FConst = Float64 ? WebAssembly::CONST_F64 : WebAssembly::CONST_F32; | ||||
434 | unsigned LT = Float64 ? WebAssembly::LT_F64 : WebAssembly::LT_F32; | ||||
435 | unsigned GE = Float64 ? WebAssembly::GE_F64 : WebAssembly::GE_F32; | ||||
436 | unsigned IConst = Int64 ? WebAssembly::CONST_I64 : WebAssembly::CONST_I32; | ||||
437 | unsigned Eqz = WebAssembly::EQZ_I32; | ||||
438 | unsigned And = WebAssembly::AND_I32; | ||||
439 | int64_t Limit = Int64 ? INT64_MIN(-9223372036854775807L -1) : INT32_MIN(-2147483647-1); | ||||
440 | int64_t Substitute = IsUnsigned ? 0 : Limit; | ||||
441 | double CmpVal = IsUnsigned ? -(double)Limit * 2.0 : -(double)Limit; | ||||
442 | auto &Context = BB->getParent()->getFunction().getContext(); | ||||
443 | Type *Ty = Float64 ? Type::getDoubleTy(Context) : Type::getFloatTy(Context); | ||||
444 | |||||
445 | const BasicBlock *LLVMBB = BB->getBasicBlock(); | ||||
446 | MachineFunction *F = BB->getParent(); | ||||
447 | MachineBasicBlock *TrueMBB = F->CreateMachineBasicBlock(LLVMBB); | ||||
448 | MachineBasicBlock *FalseMBB = F->CreateMachineBasicBlock(LLVMBB); | ||||
449 | MachineBasicBlock *DoneMBB = F->CreateMachineBasicBlock(LLVMBB); | ||||
450 | |||||
451 | MachineFunction::iterator It = ++BB->getIterator(); | ||||
452 | F->insert(It, FalseMBB); | ||||
453 | F->insert(It, TrueMBB); | ||||
454 | F->insert(It, DoneMBB); | ||||
455 | |||||
456 | // Transfer the remainder of BB and its successor edges to DoneMBB. | ||||
457 | DoneMBB->splice(DoneMBB->begin(), BB, std::next(MI.getIterator()), BB->end()); | ||||
458 | DoneMBB->transferSuccessorsAndUpdatePHIs(BB); | ||||
459 | |||||
460 | BB->addSuccessor(TrueMBB); | ||||
461 | BB->addSuccessor(FalseMBB); | ||||
462 | TrueMBB->addSuccessor(DoneMBB); | ||||
463 | FalseMBB->addSuccessor(DoneMBB); | ||||
464 | |||||
465 | unsigned Tmp0, Tmp1, CmpReg, EqzReg, FalseReg, TrueReg; | ||||
466 | Tmp0 = MRI.createVirtualRegister(MRI.getRegClass(InReg)); | ||||
467 | Tmp1 = MRI.createVirtualRegister(MRI.getRegClass(InReg)); | ||||
468 | CmpReg = MRI.createVirtualRegister(&WebAssembly::I32RegClass); | ||||
469 | EqzReg = MRI.createVirtualRegister(&WebAssembly::I32RegClass); | ||||
470 | FalseReg = MRI.createVirtualRegister(MRI.getRegClass(OutReg)); | ||||
471 | TrueReg = MRI.createVirtualRegister(MRI.getRegClass(OutReg)); | ||||
472 | |||||
473 | MI.eraseFromParent(); | ||||
474 | // For signed numbers, we can do a single comparison to determine whether | ||||
475 | // fabs(x) is within range. | ||||
476 | if (IsUnsigned) { | ||||
477 | Tmp0 = InReg; | ||||
478 | } else { | ||||
479 | BuildMI(BB, DL, TII.get(Abs), Tmp0).addReg(InReg); | ||||
480 | } | ||||
481 | BuildMI(BB, DL, TII.get(FConst), Tmp1) | ||||
482 | .addFPImm(cast<ConstantFP>(ConstantFP::get(Ty, CmpVal))); | ||||
483 | BuildMI(BB, DL, TII.get(LT), CmpReg).addReg(Tmp0).addReg(Tmp1); | ||||
484 | |||||
485 | // For unsigned numbers, we have to do a separate comparison with zero. | ||||
486 | if (IsUnsigned) { | ||||
487 | Tmp1 = MRI.createVirtualRegister(MRI.getRegClass(InReg)); | ||||
488 | Register SecondCmpReg = | ||||
489 | MRI.createVirtualRegister(&WebAssembly::I32RegClass); | ||||
490 | Register AndReg = MRI.createVirtualRegister(&WebAssembly::I32RegClass); | ||||
491 | BuildMI(BB, DL, TII.get(FConst), Tmp1) | ||||
492 | .addFPImm(cast<ConstantFP>(ConstantFP::get(Ty, 0.0))); | ||||
493 | BuildMI(BB, DL, TII.get(GE), SecondCmpReg).addReg(Tmp0).addReg(Tmp1); | ||||
494 | BuildMI(BB, DL, TII.get(And), AndReg).addReg(CmpReg).addReg(SecondCmpReg); | ||||
495 | CmpReg = AndReg; | ||||
496 | } | ||||
497 | |||||
498 | BuildMI(BB, DL, TII.get(Eqz), EqzReg).addReg(CmpReg); | ||||
499 | |||||
500 | // Create the CFG diamond to select between doing the conversion or using | ||||
501 | // the substitute value. | ||||
502 | BuildMI(BB, DL, TII.get(WebAssembly::BR_IF)).addMBB(TrueMBB).addReg(EqzReg); | ||||
503 | BuildMI(FalseMBB, DL, TII.get(LoweredOpcode), FalseReg).addReg(InReg); | ||||
504 | BuildMI(FalseMBB, DL, TII.get(WebAssembly::BR)).addMBB(DoneMBB); | ||||
505 | BuildMI(TrueMBB, DL, TII.get(IConst), TrueReg).addImm(Substitute); | ||||
506 | BuildMI(*DoneMBB, DoneMBB->begin(), DL, TII.get(TargetOpcode::PHI), OutReg) | ||||
507 | .addReg(FalseReg) | ||||
508 | .addMBB(FalseMBB) | ||||
509 | .addReg(TrueReg) | ||||
510 | .addMBB(TrueMBB); | ||||
511 | |||||
512 | return DoneMBB; | ||||
513 | } | ||||
514 | |||||
515 | static MachineBasicBlock * | ||||
516 | LowerCallResults(MachineInstr &CallResults, DebugLoc DL, MachineBasicBlock *BB, | ||||
517 | const WebAssemblySubtarget *Subtarget, | ||||
518 | const TargetInstrInfo &TII) { | ||||
519 | MachineInstr &CallParams = *CallResults.getPrevNode(); | ||||
520 | assert(CallParams.getOpcode() == WebAssembly::CALL_PARAMS)(static_cast <bool> (CallParams.getOpcode() == WebAssembly ::CALL_PARAMS) ? void (0) : __assert_fail ("CallParams.getOpcode() == WebAssembly::CALL_PARAMS" , "/build/llvm-toolchain-snapshot-14~++20211017100700+d245f2e8597b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp" , 520, __extension__ __PRETTY_FUNCTION__)); | ||||
521 | 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" , "/build/llvm-toolchain-snapshot-14~++20211017100700+d245f2e8597b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp" , 522, __extension__ __PRETTY_FUNCTION__)) | ||||
522 | 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" , "/build/llvm-toolchain-snapshot-14~++20211017100700+d245f2e8597b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp" , 522, __extension__ __PRETTY_FUNCTION__)); | ||||
523 | |||||
524 | bool IsIndirect = CallParams.getOperand(0).isReg(); | ||||
525 | bool IsRetCall = CallResults.getOpcode() == WebAssembly::RET_CALL_RESULTS; | ||||
526 | |||||
527 | bool IsFuncrefCall = false; | ||||
528 | if (IsIndirect) { | ||||
529 | Register Reg = CallParams.getOperand(0).getReg(); | ||||
530 | const MachineFunction *MF = BB->getParent(); | ||||
531 | const MachineRegisterInfo &MRI = MF->getRegInfo(); | ||||
532 | const TargetRegisterClass *TRC = MRI.getRegClass(Reg); | ||||
533 | IsFuncrefCall = (TRC == &WebAssembly::FUNCREFRegClass); | ||||
534 | assert(!IsFuncrefCall || Subtarget->hasReferenceTypes())(static_cast <bool> (!IsFuncrefCall || Subtarget->hasReferenceTypes ()) ? void (0) : __assert_fail ("!IsFuncrefCall || Subtarget->hasReferenceTypes()" , "/build/llvm-toolchain-snapshot-14~++20211017100700+d245f2e8597b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp" , 534, __extension__ __PRETTY_FUNCTION__)); | ||||
535 | } | ||||
536 | |||||
537 | unsigned CallOp; | ||||
538 | if (IsIndirect && IsRetCall) { | ||||
539 | CallOp = WebAssembly::RET_CALL_INDIRECT; | ||||
540 | } else if (IsIndirect) { | ||||
541 | CallOp = WebAssembly::CALL_INDIRECT; | ||||
542 | } else if (IsRetCall) { | ||||
543 | CallOp = WebAssembly::RET_CALL; | ||||
544 | } else { | ||||
545 | CallOp = WebAssembly::CALL; | ||||
546 | } | ||||
547 | |||||
548 | MachineFunction &MF = *BB->getParent(); | ||||
549 | const MCInstrDesc &MCID = TII.get(CallOp); | ||||
550 | MachineInstrBuilder MIB(MF, MF.CreateMachineInstr(MCID, DL)); | ||||
551 | |||||
552 | // See if we must truncate the function pointer. | ||||
553 | // CALL_INDIRECT takes an i32, but in wasm64 we represent function pointers | ||||
554 | // as 64-bit for uniformity with other pointer types. | ||||
555 | // See also: WebAssemblyFastISel::selectCall | ||||
556 | if (IsIndirect && MF.getSubtarget<WebAssemblySubtarget>().hasAddr64()) { | ||||
557 | Register Reg32 = | ||||
558 | MF.getRegInfo().createVirtualRegister(&WebAssembly::I32RegClass); | ||||
559 | auto &FnPtr = CallParams.getOperand(0); | ||||
560 | BuildMI(*BB, CallResults.getIterator(), DL, | ||||
561 | TII.get(WebAssembly::I32_WRAP_I64), Reg32) | ||||
562 | .addReg(FnPtr.getReg()); | ||||
563 | FnPtr.setReg(Reg32); | ||||
564 | } | ||||
565 | |||||
566 | // Move the function pointer to the end of the arguments for indirect calls | ||||
567 | if (IsIndirect) { | ||||
568 | auto FnPtr = CallParams.getOperand(0); | ||||
569 | CallParams.RemoveOperand(0); | ||||
570 | |||||
571 | // For funcrefs, call_indirect is done through __funcref_call_table and the | ||||
572 | // funcref is always installed in slot 0 of the table, therefore instead of having | ||||
573 | // the function pointer added at the end of the params list, a zero (the index in | ||||
574 | // __funcref_call_table is added). | ||||
575 | if (IsFuncrefCall) { | ||||
576 | Register RegZero = | ||||
577 | MF.getRegInfo().createVirtualRegister(&WebAssembly::I32RegClass); | ||||
578 | MachineInstrBuilder MIBC0 = | ||||
579 | BuildMI(MF, DL, TII.get(WebAssembly::CONST_I32), RegZero).addImm(0); | ||||
580 | |||||
581 | BB->insert(CallResults.getIterator(), MIBC0); | ||||
582 | MachineInstrBuilder(MF, CallParams).addReg(RegZero); | ||||
583 | } else | ||||
584 | CallParams.addOperand(FnPtr); | ||||
585 | } | ||||
586 | |||||
587 | for (auto Def : CallResults.defs()) | ||||
588 | MIB.add(Def); | ||||
589 | |||||
590 | if (IsIndirect) { | ||||
591 | // Placeholder for the type index. | ||||
592 | MIB.addImm(0); | ||||
593 | // The table into which this call_indirect indexes. | ||||
594 | MCSymbolWasm *Table = IsFuncrefCall | ||||
595 | ? WebAssembly::getOrCreateFuncrefCallTableSymbol( | ||||
596 | MF.getContext(), Subtarget) | ||||
597 | : WebAssembly::getOrCreateFunctionTableSymbol( | ||||
598 | MF.getContext(), Subtarget); | ||||
599 | if (Subtarget->hasReferenceTypes()) { | ||||
600 | MIB.addSym(Table); | ||||
601 | } else { | ||||
602 | // For the MVP there is at most one table whose number is 0, but we can't | ||||
603 | // write a table symbol or issue relocations. Instead we just ensure the | ||||
604 | // table is live and write a zero. | ||||
605 | Table->setNoStrip(); | ||||
606 | MIB.addImm(0); | ||||
607 | } | ||||
608 | } | ||||
609 | |||||
610 | for (auto Use : CallParams.uses()) | ||||
611 | MIB.add(Use); | ||||
612 | |||||
613 | BB->insert(CallResults.getIterator(), MIB); | ||||
614 | CallParams.eraseFromParent(); | ||||
615 | CallResults.eraseFromParent(); | ||||
616 | |||||
617 | // If this is a funcref call, to avoid hidden GC roots, we need to clear the | ||||
618 | // table slot with ref.null upon call_indirect return. | ||||
619 | // | ||||
620 | // This generates the following code, which comes right after a call_indirect | ||||
621 | // of a funcref: | ||||
622 | // | ||||
623 | // i32.const 0 | ||||
624 | // ref.null func | ||||
625 | // table.set __funcref_call_table | ||||
626 | if (IsIndirect && IsFuncrefCall) { | ||||
627 | MCSymbolWasm *Table = WebAssembly::getOrCreateFuncrefCallTableSymbol( | ||||
628 | MF.getContext(), Subtarget); | ||||
629 | Register RegZero = | ||||
630 | MF.getRegInfo().createVirtualRegister(&WebAssembly::I32RegClass); | ||||
631 | MachineInstr *Const0 = | ||||
632 | BuildMI(MF, DL, TII.get(WebAssembly::CONST_I32), RegZero).addImm(0); | ||||
633 | BB->insertAfter(MIB.getInstr()->getIterator(), Const0); | ||||
634 | |||||
635 | Register RegFuncref = | ||||
636 | MF.getRegInfo().createVirtualRegister(&WebAssembly::FUNCREFRegClass); | ||||
637 | MachineInstr *RefNull = | ||||
638 | BuildMI(MF, DL, TII.get(WebAssembly::REF_NULL_FUNCREF), RegFuncref) | ||||
639 | .addImm(static_cast<int32_t>(WebAssembly::HeapType::Funcref)); | ||||
640 | BB->insertAfter(Const0->getIterator(), RefNull); | ||||
641 | |||||
642 | MachineInstr *TableSet = | ||||
643 | BuildMI(MF, DL, TII.get(WebAssembly::TABLE_SET_FUNCREF)) | ||||
644 | .addSym(Table) | ||||
645 | .addReg(RegZero) | ||||
646 | .addReg(RegFuncref); | ||||
647 | BB->insertAfter(RefNull->getIterator(), TableSet); | ||||
648 | } | ||||
649 | |||||
650 | return BB; | ||||
651 | } | ||||
652 | |||||
653 | MachineBasicBlock *WebAssemblyTargetLowering::EmitInstrWithCustomInserter( | ||||
654 | MachineInstr &MI, MachineBasicBlock *BB) const { | ||||
655 | const TargetInstrInfo &TII = *Subtarget->getInstrInfo(); | ||||
656 | DebugLoc DL = MI.getDebugLoc(); | ||||
657 | |||||
658 | switch (MI.getOpcode()) { | ||||
659 | default: | ||||
660 | llvm_unreachable("Unexpected instr type to insert")::llvm::llvm_unreachable_internal("Unexpected instr type to insert" , "/build/llvm-toolchain-snapshot-14~++20211017100700+d245f2e8597b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp" , 660); | ||||
661 | case WebAssembly::FP_TO_SINT_I32_F32: | ||||
662 | return LowerFPToInt(MI, DL, BB, TII, false, false, false, | ||||
663 | WebAssembly::I32_TRUNC_S_F32); | ||||
664 | case WebAssembly::FP_TO_UINT_I32_F32: | ||||
665 | return LowerFPToInt(MI, DL, BB, TII, true, false, false, | ||||
666 | WebAssembly::I32_TRUNC_U_F32); | ||||
667 | case WebAssembly::FP_TO_SINT_I64_F32: | ||||
668 | return LowerFPToInt(MI, DL, BB, TII, false, true, false, | ||||
669 | WebAssembly::I64_TRUNC_S_F32); | ||||
670 | case WebAssembly::FP_TO_UINT_I64_F32: | ||||
671 | return LowerFPToInt(MI, DL, BB, TII, true, true, false, | ||||
672 | WebAssembly::I64_TRUNC_U_F32); | ||||
673 | case WebAssembly::FP_TO_SINT_I32_F64: | ||||
674 | return LowerFPToInt(MI, DL, BB, TII, false, false, true, | ||||
675 | WebAssembly::I32_TRUNC_S_F64); | ||||
676 | case WebAssembly::FP_TO_UINT_I32_F64: | ||||
677 | return LowerFPToInt(MI, DL, BB, TII, true, false, true, | ||||
678 | WebAssembly::I32_TRUNC_U_F64); | ||||
679 | case WebAssembly::FP_TO_SINT_I64_F64: | ||||
680 | return LowerFPToInt(MI, DL, BB, TII, false, true, true, | ||||
681 | WebAssembly::I64_TRUNC_S_F64); | ||||
682 | case WebAssembly::FP_TO_UINT_I64_F64: | ||||
683 | return LowerFPToInt(MI, DL, BB, TII, true, true, true, | ||||
684 | WebAssembly::I64_TRUNC_U_F64); | ||||
685 | case WebAssembly::CALL_RESULTS: | ||||
686 | case WebAssembly::RET_CALL_RESULTS: | ||||
687 | return LowerCallResults(MI, DL, BB, Subtarget, TII); | ||||
688 | } | ||||
689 | } | ||||
690 | |||||
691 | const char * | ||||
692 | WebAssemblyTargetLowering::getTargetNodeName(unsigned Opcode) const { | ||||
693 | switch (static_cast<WebAssemblyISD::NodeType>(Opcode)) { | ||||
694 | case WebAssemblyISD::FIRST_NUMBER: | ||||
695 | case WebAssemblyISD::FIRST_MEM_OPCODE: | ||||
696 | break; | ||||
697 | #define HANDLE_NODETYPE(NODE) \ | ||||
698 | case WebAssemblyISD::NODE: \ | ||||
699 | return "WebAssemblyISD::" #NODE; | ||||
700 | #define HANDLE_MEM_NODETYPE(NODE) HANDLE_NODETYPE(NODE) | ||||
701 | #include "WebAssemblyISD.def" | ||||
702 | #undef HANDLE_MEM_NODETYPE | ||||
703 | #undef HANDLE_NODETYPE | ||||
704 | } | ||||
705 | return nullptr; | ||||
706 | } | ||||
707 | |||||
708 | std::pair<unsigned, const TargetRegisterClass *> | ||||
709 | WebAssemblyTargetLowering::getRegForInlineAsmConstraint( | ||||
710 | const TargetRegisterInfo *TRI, StringRef Constraint, MVT VT) const { | ||||
711 | // First, see if this is a constraint that directly corresponds to a | ||||
712 | // WebAssembly register class. | ||||
713 | if (Constraint.size() == 1) { | ||||
714 | switch (Constraint[0]) { | ||||
715 | case 'r': | ||||
716 | 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\"" , "/build/llvm-toolchain-snapshot-14~++20211017100700+d245f2e8597b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp" , 716, __extension__ __PRETTY_FUNCTION__)); | ||||
717 | if (Subtarget->hasSIMD128() && VT.isVector()) { | ||||
718 | if (VT.getSizeInBits() == 128) | ||||
719 | return std::make_pair(0U, &WebAssembly::V128RegClass); | ||||
720 | } | ||||
721 | if (VT.isInteger() && !VT.isVector()) { | ||||
722 | if (VT.getSizeInBits() <= 32) | ||||
723 | return std::make_pair(0U, &WebAssembly::I32RegClass); | ||||
724 | if (VT.getSizeInBits() <= 64) | ||||
725 | return std::make_pair(0U, &WebAssembly::I64RegClass); | ||||
726 | } | ||||
727 | if (VT.isFloatingPoint() && !VT.isVector()) { | ||||
728 | switch (VT.getSizeInBits()) { | ||||
729 | case 32: | ||||
730 | return std::make_pair(0U, &WebAssembly::F32RegClass); | ||||
731 | case 64: | ||||
732 | return std::make_pair(0U, &WebAssembly::F64RegClass); | ||||
733 | default: | ||||
734 | break; | ||||
735 | } | ||||
736 | } | ||||
737 | break; | ||||
738 | default: | ||||
739 | break; | ||||
740 | } | ||||
741 | } | ||||
742 | |||||
743 | return TargetLowering::getRegForInlineAsmConstraint(TRI, Constraint, VT); | ||||
744 | } | ||||
745 | |||||
746 | bool WebAssemblyTargetLowering::isCheapToSpeculateCttz() const { | ||||
747 | // Assume ctz is a relatively cheap operation. | ||||
748 | return true; | ||||
749 | } | ||||
750 | |||||
751 | bool WebAssemblyTargetLowering::isCheapToSpeculateCtlz() const { | ||||
752 | // Assume clz is a relatively cheap operation. | ||||
753 | return true; | ||||
754 | } | ||||
755 | |||||
756 | bool WebAssemblyTargetLowering::isLegalAddressingMode(const DataLayout &DL, | ||||
757 | const AddrMode &AM, | ||||
758 | Type *Ty, unsigned AS, | ||||
759 | Instruction *I) const { | ||||
760 | // WebAssembly offsets are added as unsigned without wrapping. The | ||||
761 | // isLegalAddressingMode gives us no way to determine if wrapping could be | ||||
762 | // happening, so we approximate this by accepting only non-negative offsets. | ||||
763 | if (AM.BaseOffs < 0) | ||||
764 | return false; | ||||
765 | |||||
766 | // WebAssembly has no scale register operands. | ||||
767 | if (AM.Scale != 0) | ||||
768 | return false; | ||||
769 | |||||
770 | // Everything else is legal. | ||||
771 | return true; | ||||
772 | } | ||||
773 | |||||
774 | bool WebAssemblyTargetLowering::allowsMisalignedMemoryAccesses( | ||||
775 | EVT /*VT*/, unsigned /*AddrSpace*/, Align /*Align*/, | ||||
776 | MachineMemOperand::Flags /*Flags*/, bool *Fast) const { | ||||
777 | // WebAssembly supports unaligned accesses, though it should be declared | ||||
778 | // with the p2align attribute on loads and stores which do so, and there | ||||
779 | // may be a performance impact. We tell LLVM they're "fast" because | ||||
780 | // for the kinds of things that LLVM uses this for (merging adjacent stores | ||||
781 | // of constants, etc.), WebAssembly implementations will either want the | ||||
782 | // unaligned access or they'll split anyway. | ||||
783 | if (Fast) | ||||
784 | *Fast = true; | ||||
785 | return true; | ||||
786 | } | ||||
787 | |||||
788 | bool WebAssemblyTargetLowering::isIntDivCheap(EVT VT, | ||||
789 | AttributeList Attr) const { | ||||
790 | // The current thinking is that wasm engines will perform this optimization, | ||||
791 | // so we can save on code size. | ||||
792 | return true; | ||||
793 | } | ||||
794 | |||||
795 | bool WebAssemblyTargetLowering::isVectorLoadExtDesirable(SDValue ExtVal) const { | ||||
796 | EVT ExtT = ExtVal.getValueType(); | ||||
797 | EVT MemT = cast<LoadSDNode>(ExtVal->getOperand(0))->getValueType(0); | ||||
798 | return (ExtT == MVT::v8i16 && MemT == MVT::v8i8) || | ||||
799 | (ExtT == MVT::v4i32 && MemT == MVT::v4i16) || | ||||
800 | (ExtT == MVT::v2i64 && MemT == MVT::v2i32); | ||||
801 | } | ||||
802 | |||||
803 | bool WebAssemblyTargetLowering::isOffsetFoldingLegal( | ||||
804 | const GlobalAddressSDNode *GA) const { | ||||
805 | // Wasm doesn't support function addresses with offsets | ||||
806 | const GlobalValue *GV = GA->getGlobal(); | ||||
807 | return isa<Function>(GV) ? false : TargetLowering::isOffsetFoldingLegal(GA); | ||||
808 | } | ||||
809 | |||||
810 | EVT WebAssemblyTargetLowering::getSetCCResultType(const DataLayout &DL, | ||||
811 | LLVMContext &C, | ||||
812 | EVT VT) const { | ||||
813 | if (VT.isVector()) | ||||
814 | return VT.changeVectorElementTypeToInteger(); | ||||
815 | |||||
816 | // So far, all branch instructions in Wasm take an I32 condition. | ||||
817 | // The default TargetLowering::getSetCCResultType returns the pointer size, | ||||
818 | // which would be useful to reduce instruction counts when testing | ||||
819 | // against 64-bit pointers/values if at some point Wasm supports that. | ||||
820 | return EVT::getIntegerVT(C, 32); | ||||
821 | } | ||||
822 | |||||
823 | bool WebAssemblyTargetLowering::getTgtMemIntrinsic(IntrinsicInfo &Info, | ||||
824 | const CallInst &I, | ||||
825 | MachineFunction &MF, | ||||
826 | unsigned Intrinsic) const { | ||||
827 | switch (Intrinsic) { | ||||
828 | case Intrinsic::wasm_memory_atomic_notify: | ||||
829 | Info.opc = ISD::INTRINSIC_W_CHAIN; | ||||
830 | Info.memVT = MVT::i32; | ||||
831 | Info.ptrVal = I.getArgOperand(0); | ||||
832 | Info.offset = 0; | ||||
833 | Info.align = Align(4); | ||||
834 | // atomic.notify instruction does not really load the memory specified with | ||||
835 | // this argument, but MachineMemOperand should either be load or store, so | ||||
836 | // we set this to a load. | ||||
837 | // FIXME Volatile isn't really correct, but currently all LLVM atomic | ||||
838 | // instructions are treated as volatiles in the backend, so we should be | ||||
839 | // consistent. The same applies for wasm_atomic_wait intrinsics too. | ||||
840 | Info.flags = MachineMemOperand::MOVolatile | MachineMemOperand::MOLoad; | ||||
841 | return true; | ||||
842 | case Intrinsic::wasm_memory_atomic_wait32: | ||||
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 | Info.flags = MachineMemOperand::MOVolatile | MachineMemOperand::MOLoad; | ||||
849 | return true; | ||||
850 | case Intrinsic::wasm_memory_atomic_wait64: | ||||
851 | Info.opc = ISD::INTRINSIC_W_CHAIN; | ||||
852 | Info.memVT = MVT::i64; | ||||
853 | Info.ptrVal = I.getArgOperand(0); | ||||
854 | Info.offset = 0; | ||||
855 | Info.align = Align(8); | ||||
856 | Info.flags = MachineMemOperand::MOVolatile | MachineMemOperand::MOLoad; | ||||
857 | return true; | ||||
858 | default: | ||||
859 | return false; | ||||
860 | } | ||||
861 | } | ||||
862 | |||||
863 | void WebAssemblyTargetLowering::computeKnownBitsForTargetNode( | ||||
864 | const SDValue Op, KnownBits &Known, const APInt &DemandedElts, | ||||
865 | const SelectionDAG &DAG, unsigned Depth) const { | ||||
866 | switch (Op.getOpcode()) { | ||||
867 | default: | ||||
868 | break; | ||||
869 | case ISD::INTRINSIC_WO_CHAIN: { | ||||
870 | unsigned IntNo = Op.getConstantOperandVal(0); | ||||
871 | switch (IntNo) { | ||||
872 | default: | ||||
873 | break; | ||||
874 | case Intrinsic::wasm_bitmask: { | ||||
875 | unsigned BitWidth = Known.getBitWidth(); | ||||
876 | EVT VT = Op.getOperand(1).getSimpleValueType(); | ||||
877 | unsigned PossibleBits = VT.getVectorNumElements(); | ||||
878 | APInt ZeroMask = APInt::getHighBitsSet(BitWidth, BitWidth - PossibleBits); | ||||
879 | Known.Zero |= ZeroMask; | ||||
880 | break; | ||||
881 | } | ||||
882 | } | ||||
883 | } | ||||
884 | } | ||||
885 | } | ||||
886 | |||||
887 | TargetLoweringBase::LegalizeTypeAction | ||||
888 | WebAssemblyTargetLowering::getPreferredVectorAction(MVT VT) const { | ||||
889 | if (VT.isFixedLengthVector()) { | ||||
890 | MVT EltVT = VT.getVectorElementType(); | ||||
891 | // We have legal vector types with these lane types, so widening the | ||||
892 | // vector would let us use some of the lanes directly without having to | ||||
893 | // extend or truncate values. | ||||
894 | if (EltVT == MVT::i8 || EltVT == MVT::i16 || EltVT == MVT::i32 || | ||||
895 | EltVT == MVT::i64 || EltVT == MVT::f32 || EltVT == MVT::f64) | ||||
896 | return TypeWidenVector; | ||||
897 | } | ||||
898 | |||||
899 | return TargetLoweringBase::getPreferredVectorAction(VT); | ||||
900 | } | ||||
901 | |||||
902 | //===----------------------------------------------------------------------===// | ||||
903 | // WebAssembly Lowering private implementation. | ||||
904 | //===----------------------------------------------------------------------===// | ||||
905 | |||||
906 | //===----------------------------------------------------------------------===// | ||||
907 | // Lowering Code | ||||
908 | //===----------------------------------------------------------------------===// | ||||
909 | |||||
910 | static void fail(const SDLoc &DL, SelectionDAG &DAG, const char *Msg) { | ||||
911 | MachineFunction &MF = DAG.getMachineFunction(); | ||||
912 | DAG.getContext()->diagnose( | ||||
913 | DiagnosticInfoUnsupported(MF.getFunction(), Msg, DL.getDebugLoc())); | ||||
914 | } | ||||
915 | |||||
916 | // Test whether the given calling convention is supported. | ||||
917 | static bool callingConvSupported(CallingConv::ID CallConv) { | ||||
918 | // We currently support the language-independent target-independent | ||||
919 | // conventions. We don't yet have a way to annotate calls with properties like | ||||
920 | // "cold", and we don't have any call-clobbered registers, so these are mostly | ||||
921 | // all handled the same. | ||||
922 | return CallConv == CallingConv::C || CallConv == CallingConv::Fast || | ||||
923 | CallConv == CallingConv::Cold || | ||||
924 | CallConv == CallingConv::PreserveMost || | ||||
925 | CallConv == CallingConv::PreserveAll || | ||||
926 | CallConv == CallingConv::CXX_FAST_TLS || | ||||
927 | CallConv == CallingConv::WASM_EmscriptenInvoke || | ||||
928 | CallConv == CallingConv::Swift; | ||||
929 | } | ||||
930 | |||||
931 | SDValue | ||||
932 | WebAssemblyTargetLowering::LowerCall(CallLoweringInfo &CLI, | ||||
933 | SmallVectorImpl<SDValue> &InVals) const { | ||||
934 | SelectionDAG &DAG = CLI.DAG; | ||||
935 | SDLoc DL = CLI.DL; | ||||
936 | SDValue Chain = CLI.Chain; | ||||
937 | SDValue Callee = CLI.Callee; | ||||
938 | MachineFunction &MF = DAG.getMachineFunction(); | ||||
939 | auto Layout = MF.getDataLayout(); | ||||
940 | |||||
941 | CallingConv::ID CallConv = CLI.CallConv; | ||||
942 | if (!callingConvSupported(CallConv)) | ||||
943 | fail(DL, DAG, | ||||
944 | "WebAssembly doesn't support language-specific or target-specific " | ||||
945 | "calling conventions yet"); | ||||
946 | if (CLI.IsPatchPoint) | ||||
947 | fail(DL, DAG, "WebAssembly doesn't support patch point yet"); | ||||
948 | |||||
949 | if (CLI.IsTailCall) { | ||||
950 | auto NoTail = [&](const char *Msg) { | ||||
951 | if (CLI.CB && CLI.CB->isMustTailCall()) | ||||
952 | fail(DL, DAG, Msg); | ||||
953 | CLI.IsTailCall = false; | ||||
954 | }; | ||||
955 | |||||
956 | if (!Subtarget->hasTailCall()) | ||||
957 | NoTail("WebAssembly 'tail-call' feature not enabled"); | ||||
958 | |||||
959 | // Varargs calls cannot be tail calls because the buffer is on the stack | ||||
960 | if (CLI.IsVarArg) | ||||
961 | NoTail("WebAssembly does not support varargs tail calls"); | ||||
962 | |||||
963 | // Do not tail call unless caller and callee return types match | ||||
964 | const Function &F = MF.getFunction(); | ||||
965 | const TargetMachine &TM = getTargetMachine(); | ||||
966 | Type *RetTy = F.getReturnType(); | ||||
967 | SmallVector<MVT, 4> CallerRetTys; | ||||
968 | SmallVector<MVT, 4> CalleeRetTys; | ||||
969 | computeLegalValueVTs(F, TM, RetTy, CallerRetTys); | ||||
970 | computeLegalValueVTs(F, TM, CLI.RetTy, CalleeRetTys); | ||||
971 | bool TypesMatch = CallerRetTys.size() == CalleeRetTys.size() && | ||||
972 | std::equal(CallerRetTys.begin(), CallerRetTys.end(), | ||||
973 | CalleeRetTys.begin()); | ||||
974 | if (!TypesMatch) | ||||
975 | NoTail("WebAssembly tail call requires caller and callee return types to " | ||||
976 | "match"); | ||||
977 | |||||
978 | // If pointers to local stack values are passed, we cannot tail call | ||||
979 | if (CLI.CB) { | ||||
980 | for (auto &Arg : CLI.CB->args()) { | ||||
981 | Value *Val = Arg.get(); | ||||
982 | // Trace the value back through pointer operations | ||||
983 | while (true) { | ||||
984 | Value *Src = Val->stripPointerCastsAndAliases(); | ||||
985 | if (auto *GEP = dyn_cast<GetElementPtrInst>(Src)) | ||||
986 | Src = GEP->getPointerOperand(); | ||||
987 | if (Val == Src) | ||||
988 | break; | ||||
989 | Val = Src; | ||||
990 | } | ||||
991 | if (isa<AllocaInst>(Val)) { | ||||
992 | NoTail( | ||||
993 | "WebAssembly does not support tail calling with stack arguments"); | ||||
994 | break; | ||||
995 | } | ||||
996 | } | ||||
997 | } | ||||
998 | } | ||||
999 | |||||
1000 | SmallVectorImpl<ISD::InputArg> &Ins = CLI.Ins; | ||||
1001 | SmallVectorImpl<ISD::OutputArg> &Outs = CLI.Outs; | ||||
1002 | SmallVectorImpl<SDValue> &OutVals = CLI.OutVals; | ||||
1003 | |||||
1004 | // The generic code may have added an sret argument. If we're lowering an | ||||
1005 | // invoke function, the ABI requires that the function pointer be the first | ||||
1006 | // argument, so we may have to swap the arguments. | ||||
1007 | if (CallConv == CallingConv::WASM_EmscriptenInvoke && Outs.size() >= 2 && | ||||
1008 | Outs[0].Flags.isSRet()) { | ||||
1009 | std::swap(Outs[0], Outs[1]); | ||||
1010 | std::swap(OutVals[0], OutVals[1]); | ||||
1011 | } | ||||
1012 | |||||
1013 | bool HasSwiftSelfArg = false; | ||||
1014 | bool HasSwiftErrorArg = false; | ||||
1015 | unsigned NumFixedArgs = 0; | ||||
1016 | for (unsigned I = 0; I < Outs.size(); ++I) { | ||||
1017 | const ISD::OutputArg &Out = Outs[I]; | ||||
1018 | SDValue &OutVal = OutVals[I]; | ||||
1019 | HasSwiftSelfArg |= Out.Flags.isSwiftSelf(); | ||||
1020 | HasSwiftErrorArg |= Out.Flags.isSwiftError(); | ||||
1021 | if (Out.Flags.isNest()) | ||||
1022 | fail(DL, DAG, "WebAssembly hasn't implemented nest arguments"); | ||||
1023 | if (Out.Flags.isInAlloca()) | ||||
1024 | fail(DL, DAG, "WebAssembly hasn't implemented inalloca arguments"); | ||||
1025 | if (Out.Flags.isInConsecutiveRegs()) | ||||
1026 | fail(DL, DAG, "WebAssembly hasn't implemented cons regs arguments"); | ||||
1027 | if (Out.Flags.isInConsecutiveRegsLast()) | ||||
1028 | fail(DL, DAG, "WebAssembly hasn't implemented cons regs last arguments"); | ||||
1029 | if (Out.Flags.isByVal() && Out.Flags.getByValSize() != 0) { | ||||
1030 | auto &MFI = MF.getFrameInfo(); | ||||
1031 | int FI = MFI.CreateStackObject(Out.Flags.getByValSize(), | ||||
1032 | Out.Flags.getNonZeroByValAlign(), | ||||
1033 | /*isSS=*/false); | ||||
1034 | SDValue SizeNode = | ||||
1035 | DAG.getConstant(Out.Flags.getByValSize(), DL, MVT::i32); | ||||
1036 | SDValue FINode = DAG.getFrameIndex(FI, getPointerTy(Layout)); | ||||
1037 | Chain = DAG.getMemcpy( | ||||
1038 | Chain, DL, FINode, OutVal, SizeNode, Out.Flags.getNonZeroByValAlign(), | ||||
1039 | /*isVolatile*/ false, /*AlwaysInline=*/false, | ||||
1040 | /*isTailCall*/ false, MachinePointerInfo(), MachinePointerInfo()); | ||||
1041 | OutVal = FINode; | ||||
1042 | } | ||||
1043 | // Count the number of fixed args *after* legalization. | ||||
1044 | NumFixedArgs += Out.IsFixed; | ||||
1045 | } | ||||
1046 | |||||
1047 | bool IsVarArg = CLI.IsVarArg; | ||||
1048 | auto PtrVT = getPointerTy(Layout); | ||||
1049 | |||||
1050 | // For swiftcc, emit additional swiftself and swifterror arguments | ||||
1051 | // if there aren't. These additional arguments are also added for callee | ||||
1052 | // signature They are necessary to match callee and caller signature for | ||||
1053 | // indirect call. | ||||
1054 | if (CallConv == CallingConv::Swift) { | ||||
1055 | if (!HasSwiftSelfArg) { | ||||
1056 | NumFixedArgs++; | ||||
1057 | ISD::OutputArg Arg; | ||||
1058 | Arg.Flags.setSwiftSelf(); | ||||
1059 | CLI.Outs.push_back(Arg); | ||||
1060 | SDValue ArgVal = DAG.getUNDEF(PtrVT); | ||||
1061 | CLI.OutVals.push_back(ArgVal); | ||||
1062 | } | ||||
1063 | if (!HasSwiftErrorArg) { | ||||
1064 | NumFixedArgs++; | ||||
1065 | ISD::OutputArg Arg; | ||||
1066 | Arg.Flags.setSwiftError(); | ||||
1067 | CLI.Outs.push_back(Arg); | ||||
1068 | SDValue ArgVal = DAG.getUNDEF(PtrVT); | ||||
1069 | CLI.OutVals.push_back(ArgVal); | ||||
1070 | } | ||||
1071 | } | ||||
1072 | |||||
1073 | // Analyze operands of the call, assigning locations to each operand. | ||||
1074 | SmallVector<CCValAssign, 16> ArgLocs; | ||||
1075 | CCState CCInfo(CallConv, IsVarArg, MF, ArgLocs, *DAG.getContext()); | ||||
1076 | |||||
1077 | if (IsVarArg) { | ||||
1078 | // Outgoing non-fixed arguments are placed in a buffer. First | ||||
1079 | // compute their offsets and the total amount of buffer space needed. | ||||
1080 | for (unsigned I = NumFixedArgs; I < Outs.size(); ++I) { | ||||
1081 | const ISD::OutputArg &Out = Outs[I]; | ||||
1082 | SDValue &Arg = OutVals[I]; | ||||
1083 | EVT VT = Arg.getValueType(); | ||||
1084 | 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\"" , "/build/llvm-toolchain-snapshot-14~++20211017100700+d245f2e8597b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp" , 1084, __extension__ __PRETTY_FUNCTION__)); | ||||
1085 | Type *Ty = VT.getTypeForEVT(*DAG.getContext()); | ||||
1086 | Align Alignment = | ||||
1087 | std::max(Out.Flags.getNonZeroOrigAlign(), Layout.getABITypeAlign(Ty)); | ||||
1088 | unsigned Offset = | ||||
1089 | CCInfo.AllocateStack(Layout.getTypeAllocSize(Ty), Alignment); | ||||
1090 | CCInfo.addLoc(CCValAssign::getMem(ArgLocs.size(), VT.getSimpleVT(), | ||||
1091 | Offset, VT.getSimpleVT(), | ||||
1092 | CCValAssign::Full)); | ||||
1093 | } | ||||
1094 | } | ||||
1095 | |||||
1096 | unsigned NumBytes = CCInfo.getAlignedCallFrameSize(); | ||||
1097 | |||||
1098 | SDValue FINode; | ||||
1099 | if (IsVarArg && NumBytes) { | ||||
1100 | // For non-fixed arguments, next emit stores to store the argument values | ||||
1101 | // to the stack buffer at the offsets computed above. | ||||
1102 | int FI = MF.getFrameInfo().CreateStackObject(NumBytes, | ||||
1103 | Layout.getStackAlignment(), | ||||
1104 | /*isSS=*/false); | ||||
1105 | unsigned ValNo = 0; | ||||
1106 | SmallVector<SDValue, 8> Chains; | ||||
1107 | for (SDValue Arg : drop_begin(OutVals, NumFixedArgs)) { | ||||
1108 | 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\"" , "/build/llvm-toolchain-snapshot-14~++20211017100700+d245f2e8597b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp" , 1109, __extension__ __PRETTY_FUNCTION__)) | ||||
1109 | "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\"" , "/build/llvm-toolchain-snapshot-14~++20211017100700+d245f2e8597b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp" , 1109, __extension__ __PRETTY_FUNCTION__)); | ||||
1110 | unsigned Offset = ArgLocs[ValNo++].getLocMemOffset(); | ||||
1111 | FINode = DAG.getFrameIndex(FI, getPointerTy(Layout)); | ||||
1112 | SDValue Add = DAG.getNode(ISD::ADD, DL, PtrVT, FINode, | ||||
1113 | DAG.getConstant(Offset, DL, PtrVT)); | ||||
1114 | Chains.push_back( | ||||
1115 | DAG.getStore(Chain, DL, Arg, Add, | ||||
1116 | MachinePointerInfo::getFixedStack(MF, FI, Offset))); | ||||
1117 | } | ||||
1118 | if (!Chains.empty()) | ||||
1119 | Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, Chains); | ||||
1120 | } else if (IsVarArg) { | ||||
1121 | FINode = DAG.getIntPtrConstant(0, DL); | ||||
1122 | } | ||||
1123 | |||||
1124 | if (Callee->getOpcode() == ISD::GlobalAddress) { | ||||
1125 | // If the callee is a GlobalAddress node (quite common, every direct call | ||||
1126 | // is) turn it into a TargetGlobalAddress node so that LowerGlobalAddress | ||||
1127 | // doesn't at MO_GOT which is not needed for direct calls. | ||||
1128 | GlobalAddressSDNode* GA = cast<GlobalAddressSDNode>(Callee); | ||||
1129 | Callee = DAG.getTargetGlobalAddress(GA->getGlobal(), DL, | ||||
1130 | getPointerTy(DAG.getDataLayout()), | ||||
1131 | GA->getOffset()); | ||||
1132 | Callee = DAG.getNode(WebAssemblyISD::Wrapper, DL, | ||||
1133 | getPointerTy(DAG.getDataLayout()), Callee); | ||||
1134 | } | ||||
1135 | |||||
1136 | // Compute the operands for the CALLn node. | ||||
1137 | SmallVector<SDValue, 16> Ops; | ||||
1138 | Ops.push_back(Chain); | ||||
1139 | Ops.push_back(Callee); | ||||
1140 | |||||
1141 | // Add all fixed arguments. Note that for non-varargs calls, NumFixedArgs | ||||
1142 | // isn't reliable. | ||||
1143 | Ops.append(OutVals.begin(), | ||||
1144 | IsVarArg ? OutVals.begin() + NumFixedArgs : OutVals.end()); | ||||
1145 | // Add a pointer to the vararg buffer. | ||||
1146 | if (IsVarArg) | ||||
1147 | Ops.push_back(FINode); | ||||
1148 | |||||
1149 | SmallVector<EVT, 8> InTys; | ||||
1150 | for (const auto &In : Ins) { | ||||
1151 | 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\"" , "/build/llvm-toolchain-snapshot-14~++20211017100700+d245f2e8597b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp" , 1151, __extension__ __PRETTY_FUNCTION__)); | ||||
1152 | 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\"" , "/build/llvm-toolchain-snapshot-14~++20211017100700+d245f2e8597b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp" , 1152, __extension__ __PRETTY_FUNCTION__)); | ||||
1153 | if (In.Flags.isInAlloca()) | ||||
1154 | fail(DL, DAG, "WebAssembly hasn't implemented inalloca return values"); | ||||
1155 | if (In.Flags.isInConsecutiveRegs()) | ||||
1156 | fail(DL, DAG, "WebAssembly hasn't implemented cons regs return values"); | ||||
1157 | if (In.Flags.isInConsecutiveRegsLast()) | ||||
1158 | fail(DL, DAG, | ||||
1159 | "WebAssembly hasn't implemented cons regs last return values"); | ||||
1160 | // Ignore In.getNonZeroOrigAlign() because all our arguments are passed in | ||||
1161 | // registers. | ||||
1162 | InTys.push_back(In.VT); | ||||
1163 | } | ||||
1164 | |||||
1165 | // Lastly, if this is a call to a funcref we need to add an instruction | ||||
1166 | // table.set to the chain and transform the call. | ||||
1167 | if (CLI.CB && | ||||
1168 | WebAssembly::isFuncrefType(CLI.CB->getCalledOperand()->getType())) { | ||||
1169 | // In the absence of function references proposal where a funcref call is | ||||
1170 | // lowered to call_ref, using reference types we generate a table.set to set | ||||
1171 | // the funcref to a special table used solely for this purpose, followed by | ||||
1172 | // a call_indirect. Here we just generate the table set, and return the | ||||
1173 | // SDValue of the table.set so that LowerCall can finalize the lowering by | ||||
1174 | // generating the call_indirect. | ||||
1175 | SDValue Chain = Ops[0]; | ||||
1176 | |||||
1177 | MCSymbolWasm *Table = WebAssembly::getOrCreateFuncrefCallTableSymbol( | ||||
1178 | MF.getContext(), Subtarget); | ||||
1179 | SDValue Sym = DAG.getMCSymbol(Table, PtrVT); | ||||
1180 | SDValue TableSlot = DAG.getConstant(0, DL, MVT::i32); | ||||
1181 | SDValue TableSetOps[] = {Chain, Sym, TableSlot, Callee}; | ||||
1182 | SDValue TableSet = DAG.getMemIntrinsicNode( | ||||
1183 | WebAssemblyISD::TABLE_SET, DL, DAG.getVTList(MVT::Other), TableSetOps, | ||||
1184 | MVT::funcref, | ||||
1185 | // Machine Mem Operand args | ||||
1186 | MachinePointerInfo( | ||||
1187 | WebAssembly::WasmAddressSpace::WASM_ADDRESS_SPACE_FUNCREF), | ||||
1188 | CLI.CB->getCalledOperand()->getPointerAlignment(DAG.getDataLayout()), | ||||
1189 | MachineMemOperand::MOStore); | ||||
1190 | |||||
1191 | Ops[0] = TableSet; // The new chain is the TableSet itself | ||||
1192 | } | ||||
1193 | |||||
1194 | if (CLI.IsTailCall) { | ||||
1195 | // ret_calls do not return values to the current frame | ||||
1196 | SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue); | ||||
1197 | return DAG.getNode(WebAssemblyISD::RET_CALL, DL, NodeTys, Ops); | ||||
1198 | } | ||||
1199 | |||||
1200 | InTys.push_back(MVT::Other); | ||||
1201 | SDVTList InTyList = DAG.getVTList(InTys); | ||||
1202 | SDValue Res = DAG.getNode(WebAssemblyISD::CALL, DL, InTyList, Ops); | ||||
1203 | |||||
1204 | for (size_t I = 0; I < Ins.size(); ++I) | ||||
1205 | InVals.push_back(Res.getValue(I)); | ||||
1206 | |||||
1207 | // Return the chain | ||||
1208 | return Res.getValue(Ins.size()); | ||||
1209 | } | ||||
1210 | |||||
1211 | bool WebAssemblyTargetLowering::CanLowerReturn( | ||||
1212 | CallingConv::ID /*CallConv*/, MachineFunction & /*MF*/, bool /*IsVarArg*/, | ||||
1213 | const SmallVectorImpl<ISD::OutputArg> &Outs, | ||||
1214 | LLVMContext & /*Context*/) const { | ||||
1215 | // WebAssembly can only handle returning tuples with multivalue enabled | ||||
1216 | return Subtarget->hasMultivalue() || Outs.size() <= 1; | ||||
1217 | } | ||||
1218 | |||||
1219 | SDValue WebAssemblyTargetLowering::LowerReturn( | ||||
1220 | SDValue Chain, CallingConv::ID CallConv, bool /*IsVarArg*/, | ||||
1221 | const SmallVectorImpl<ISD::OutputArg> &Outs, | ||||
1222 | const SmallVectorImpl<SDValue> &OutVals, const SDLoc &DL, | ||||
1223 | SelectionDAG &DAG) const { | ||||
1224 | 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\"" , "/build/llvm-toolchain-snapshot-14~++20211017100700+d245f2e8597b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp" , 1225, __extension__ __PRETTY_FUNCTION__)) | ||||
1225 | "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\"" , "/build/llvm-toolchain-snapshot-14~++20211017100700+d245f2e8597b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp" , 1225, __extension__ __PRETTY_FUNCTION__)); | ||||
1226 | if (!callingConvSupported(CallConv)) | ||||
1227 | fail(DL, DAG, "WebAssembly doesn't support non-C calling conventions"); | ||||
1228 | |||||
1229 | SmallVector<SDValue, 4> RetOps(1, Chain); | ||||
1230 | RetOps.append(OutVals.begin(), OutVals.end()); | ||||
1231 | Chain = DAG.getNode(WebAssemblyISD::RETURN, DL, MVT::Other, RetOps); | ||||
1232 | |||||
1233 | // Record the number and types of the return values. | ||||
1234 | for (const ISD::OutputArg &Out : Outs) { | ||||
1235 | 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\"" , "/build/llvm-toolchain-snapshot-14~++20211017100700+d245f2e8597b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp" , 1235, __extension__ __PRETTY_FUNCTION__)); | ||||
1236 | 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\"" , "/build/llvm-toolchain-snapshot-14~++20211017100700+d245f2e8597b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp" , 1236, __extension__ __PRETTY_FUNCTION__)); | ||||
1237 | 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\"" , "/build/llvm-toolchain-snapshot-14~++20211017100700+d245f2e8597b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp" , 1237, __extension__ __PRETTY_FUNCTION__)); | ||||
1238 | if (Out.Flags.isInAlloca()) | ||||
1239 | fail(DL, DAG, "WebAssembly hasn't implemented inalloca results"); | ||||
1240 | if (Out.Flags.isInConsecutiveRegs()) | ||||
1241 | fail(DL, DAG, "WebAssembly hasn't implemented cons regs results"); | ||||
1242 | if (Out.Flags.isInConsecutiveRegsLast()) | ||||
1243 | fail(DL, DAG, "WebAssembly hasn't implemented cons regs last results"); | ||||
1244 | } | ||||
1245 | |||||
1246 | return Chain; | ||||
1247 | } | ||||
1248 | |||||
1249 | SDValue WebAssemblyTargetLowering::LowerFormalArguments( | ||||
1250 | SDValue Chain, CallingConv::ID CallConv, bool IsVarArg, | ||||
1251 | const SmallVectorImpl<ISD::InputArg> &Ins, const SDLoc &DL, | ||||
1252 | SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals) const { | ||||
1253 | if (!callingConvSupported(CallConv)) | ||||
1254 | fail(DL, DAG, "WebAssembly doesn't support non-C calling conventions"); | ||||
1255 | |||||
1256 | MachineFunction &MF = DAG.getMachineFunction(); | ||||
1257 | auto *MFI = MF.getInfo<WebAssemblyFunctionInfo>(); | ||||
1258 | |||||
1259 | // Set up the incoming ARGUMENTS value, which serves to represent the liveness | ||||
1260 | // of the incoming values before they're represented by virtual registers. | ||||
1261 | MF.getRegInfo().addLiveIn(WebAssembly::ARGUMENTS); | ||||
1262 | |||||
1263 | bool HasSwiftErrorArg = false; | ||||
1264 | bool HasSwiftSelfArg = false; | ||||
1265 | for (const ISD::InputArg &In : Ins) { | ||||
1266 | HasSwiftSelfArg |= In.Flags.isSwiftSelf(); | ||||
1267 | HasSwiftErrorArg |= In.Flags.isSwiftError(); | ||||
1268 | if (In.Flags.isInAlloca()) | ||||
1269 | fail(DL, DAG, "WebAssembly hasn't implemented inalloca arguments"); | ||||
1270 | if (In.Flags.isNest()) | ||||
1271 | fail(DL, DAG, "WebAssembly hasn't implemented nest arguments"); | ||||
1272 | if (In.Flags.isInConsecutiveRegs()) | ||||
1273 | fail(DL, DAG, "WebAssembly hasn't implemented cons regs arguments"); | ||||
1274 | if (In.Flags.isInConsecutiveRegsLast()) | ||||
1275 | fail(DL, DAG, "WebAssembly hasn't implemented cons regs last arguments"); | ||||
1276 | // Ignore In.getNonZeroOrigAlign() because all our arguments are passed in | ||||
1277 | // registers. | ||||
1278 | InVals.push_back(In.Used ? DAG.getNode(WebAssemblyISD::ARGUMENT, DL, In.VT, | ||||
1279 | DAG.getTargetConstant(InVals.size(), | ||||
1280 | DL, MVT::i32)) | ||||
1281 | : DAG.getUNDEF(In.VT)); | ||||
1282 | |||||
1283 | // Record the number and types of arguments. | ||||
1284 | MFI->addParam(In.VT); | ||||
1285 | } | ||||
1286 | |||||
1287 | // For swiftcc, emit additional swiftself and swifterror arguments | ||||
1288 | // if there aren't. These additional arguments are also added for callee | ||||
1289 | // signature They are necessary to match callee and caller signature for | ||||
1290 | // indirect call. | ||||
1291 | auto PtrVT = getPointerTy(MF.getDataLayout()); | ||||
1292 | if (CallConv == CallingConv::Swift) { | ||||
1293 | if (!HasSwiftSelfArg) { | ||||
1294 | MFI->addParam(PtrVT); | ||||
1295 | } | ||||
1296 | if (!HasSwiftErrorArg) { | ||||
1297 | MFI->addParam(PtrVT); | ||||
1298 | } | ||||
1299 | } | ||||
1300 | // Varargs are copied into a buffer allocated by the caller, and a pointer to | ||||
1301 | // the buffer is passed as an argument. | ||||
1302 | if (IsVarArg) { | ||||
1303 | MVT PtrVT = getPointerTy(MF.getDataLayout()); | ||||
1304 | Register VarargVreg = | ||||
1305 | MF.getRegInfo().createVirtualRegister(getRegClassFor(PtrVT)); | ||||
1306 | MFI->setVarargBufferVreg(VarargVreg); | ||||
1307 | Chain = DAG.getCopyToReg( | ||||
1308 | Chain, DL, VarargVreg, | ||||
1309 | DAG.getNode(WebAssemblyISD::ARGUMENT, DL, PtrVT, | ||||
1310 | DAG.getTargetConstant(Ins.size(), DL, MVT::i32))); | ||||
1311 | MFI->addParam(PtrVT); | ||||
1312 | } | ||||
1313 | |||||
1314 | // Record the number and types of arguments and results. | ||||
1315 | SmallVector<MVT, 4> Params; | ||||
1316 | SmallVector<MVT, 4> Results; | ||||
1317 | computeSignatureVTs(MF.getFunction().getFunctionType(), &MF.getFunction(), | ||||
1318 | MF.getFunction(), DAG.getTarget(), Params, Results); | ||||
1319 | for (MVT VT : Results) | ||||
1320 | MFI->addResult(VT); | ||||
1321 | // TODO: Use signatures in WebAssemblyMachineFunctionInfo too and unify | ||||
1322 | // the param logic here with ComputeSignatureVTs | ||||
1323 | 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())" , "/build/llvm-toolchain-snapshot-14~++20211017100700+d245f2e8597b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp" , 1325, __extension__ __PRETTY_FUNCTION__)) | ||||
1324 | 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())" , "/build/llvm-toolchain-snapshot-14~++20211017100700+d245f2e8597b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp" , 1325, __extension__ __PRETTY_FUNCTION__)) | ||||
1325 | 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())" , "/build/llvm-toolchain-snapshot-14~++20211017100700+d245f2e8597b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp" , 1325, __extension__ __PRETTY_FUNCTION__)); | ||||
1326 | |||||
1327 | return Chain; | ||||
1328 | } | ||||
1329 | |||||
1330 | void WebAssemblyTargetLowering::ReplaceNodeResults( | ||||
1331 | SDNode *N, SmallVectorImpl<SDValue> &Results, SelectionDAG &DAG) const { | ||||
1332 | switch (N->getOpcode()) { | ||||
1333 | case ISD::SIGN_EXTEND_INREG: | ||||
1334 | // Do not add any results, signifying that N should not be custom lowered | ||||
1335 | // after all. This happens because simd128 turns on custom lowering for | ||||
1336 | // SIGN_EXTEND_INREG, but for non-vector sign extends the result might be an | ||||
1337 | // illegal type. | ||||
1338 | break; | ||||
1339 | default: | ||||
1340 | llvm_unreachable(::llvm::llvm_unreachable_internal("ReplaceNodeResults not implemented for this op for WebAssembly!" , "/build/llvm-toolchain-snapshot-14~++20211017100700+d245f2e8597b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp" , 1341) | ||||
1341 | "ReplaceNodeResults not implemented for this op for WebAssembly!")::llvm::llvm_unreachable_internal("ReplaceNodeResults not implemented for this op for WebAssembly!" , "/build/llvm-toolchain-snapshot-14~++20211017100700+d245f2e8597b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp" , 1341); | ||||
1342 | } | ||||
1343 | } | ||||
1344 | |||||
1345 | //===----------------------------------------------------------------------===// | ||||
1346 | // Custom lowering hooks. | ||||
1347 | //===----------------------------------------------------------------------===// | ||||
1348 | |||||
1349 | SDValue WebAssemblyTargetLowering::LowerOperation(SDValue Op, | ||||
1350 | SelectionDAG &DAG) const { | ||||
1351 | SDLoc DL(Op); | ||||
1352 | switch (Op.getOpcode()) { | ||||
| |||||
1353 | default: | ||||
1354 | llvm_unreachable("unimplemented operation lowering")::llvm::llvm_unreachable_internal("unimplemented operation lowering" , "/build/llvm-toolchain-snapshot-14~++20211017100700+d245f2e8597b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp" , 1354); | ||||
1355 | return SDValue(); | ||||
1356 | case ISD::FrameIndex: | ||||
1357 | return LowerFrameIndex(Op, DAG); | ||||
1358 | case ISD::GlobalAddress: | ||||
1359 | return LowerGlobalAddress(Op, DAG); | ||||
1360 | case ISD::GlobalTLSAddress: | ||||
1361 | return LowerGlobalTLSAddress(Op, DAG); | ||||
1362 | case ISD::ExternalSymbol: | ||||
1363 | return LowerExternalSymbol(Op, DAG); | ||||
1364 | case ISD::JumpTable: | ||||
1365 | return LowerJumpTable(Op, DAG); | ||||
1366 | case ISD::BR_JT: | ||||
1367 | return LowerBR_JT(Op, DAG); | ||||
1368 | case ISD::VASTART: | ||||
1369 | return LowerVASTART(Op, DAG); | ||||
1370 | case ISD::BlockAddress: | ||||
1371 | case ISD::BRIND: | ||||
1372 | fail(DL, DAG, "WebAssembly hasn't implemented computed gotos"); | ||||
1373 | return SDValue(); | ||||
1374 | case ISD::RETURNADDR: | ||||
1375 | return LowerRETURNADDR(Op, DAG); | ||||
1376 | case ISD::FRAMEADDR: | ||||
1377 | return LowerFRAMEADDR(Op, DAG); | ||||
1378 | case ISD::CopyToReg: | ||||
1379 | return LowerCopyToReg(Op, DAG); | ||||
1380 | case ISD::EXTRACT_VECTOR_ELT: | ||||
1381 | case ISD::INSERT_VECTOR_ELT: | ||||
1382 | return LowerAccessVectorElement(Op, DAG); | ||||
1383 | case ISD::INTRINSIC_VOID: | ||||
1384 | case ISD::INTRINSIC_WO_CHAIN: | ||||
1385 | case ISD::INTRINSIC_W_CHAIN: | ||||
1386 | return LowerIntrinsic(Op, DAG); | ||||
1387 | case ISD::SIGN_EXTEND_INREG: | ||||
1388 | return LowerSIGN_EXTEND_INREG(Op, DAG); | ||||
1389 | case ISD::BUILD_VECTOR: | ||||
1390 | return LowerBUILD_VECTOR(Op, DAG); | ||||
1391 | case ISD::VECTOR_SHUFFLE: | ||||
1392 | return LowerVECTOR_SHUFFLE(Op, DAG); | ||||
1393 | case ISD::SETCC: | ||||
1394 | return LowerSETCC(Op, DAG); | ||||
1395 | case ISD::SHL: | ||||
1396 | case ISD::SRA: | ||||
1397 | case ISD::SRL: | ||||
1398 | return LowerShift(Op, DAG); | ||||
1399 | case ISD::FP_TO_SINT_SAT: | ||||
1400 | case ISD::FP_TO_UINT_SAT: | ||||
1401 | return LowerFP_TO_INT_SAT(Op, DAG); | ||||
1402 | case ISD::LOAD: | ||||
1403 | return LowerLoad(Op, DAG); | ||||
1404 | case ISD::STORE: | ||||
1405 | return LowerStore(Op, DAG); | ||||
1406 | } | ||||
1407 | } | ||||
1408 | |||||
1409 | static bool IsWebAssemblyGlobal(SDValue Op) { | ||||
1410 | if (const GlobalAddressSDNode *GA = dyn_cast<GlobalAddressSDNode>(Op)) | ||||
1411 | return WebAssembly::isWasmVarAddressSpace(GA->getAddressSpace()); | ||||
1412 | |||||
1413 | return false; | ||||
1414 | } | ||||
1415 | |||||
1416 | static Optional<unsigned> IsWebAssemblyLocal(SDValue Op, SelectionDAG &DAG) { | ||||
1417 | const FrameIndexSDNode *FI = dyn_cast<FrameIndexSDNode>(Op); | ||||
1418 | if (!FI) | ||||
1419 | return None; | ||||
1420 | |||||
1421 | auto &MF = DAG.getMachineFunction(); | ||||
1422 | return WebAssemblyFrameLowering::getLocalForStackObject(MF, FI->getIndex()); | ||||
1423 | } | ||||
1424 | |||||
1425 | SDValue WebAssemblyTargetLowering::LowerStore(SDValue Op, | ||||
1426 | SelectionDAG &DAG) const { | ||||
1427 | SDLoc DL(Op); | ||||
1428 | StoreSDNode *SN = cast<StoreSDNode>(Op.getNode()); | ||||
1429 | const SDValue &Value = SN->getValue(); | ||||
1430 | const SDValue &Base = SN->getBasePtr(); | ||||
1431 | const SDValue &Offset = SN->getOffset(); | ||||
1432 | |||||
1433 | if (IsWebAssemblyGlobal(Base)) { | ||||
1434 | if (!Offset->isUndef()) | ||||
1435 | report_fatal_error("unexpected offset when storing to webassembly global", | ||||
1436 | false); | ||||
1437 | |||||
1438 | SDVTList Tys = DAG.getVTList(MVT::Other); | ||||
1439 | SDValue Ops[] = {SN->getChain(), Value, Base}; | ||||
1440 | return DAG.getMemIntrinsicNode(WebAssemblyISD::GLOBAL_SET, DL, Tys, Ops, | ||||
1441 | SN->getMemoryVT(), SN->getMemOperand()); | ||||
1442 | } | ||||
1443 | |||||
1444 | if (Optional<unsigned> Local = IsWebAssemblyLocal(Base, DAG)) { | ||||
1445 | if (!Offset->isUndef()) | ||||
1446 | report_fatal_error("unexpected offset when storing to webassembly local", | ||||
1447 | false); | ||||
1448 | |||||
1449 | SDValue Idx = DAG.getTargetConstant(*Local, Base, MVT::i32); | ||||
1450 | SDVTList Tys = DAG.getVTList(MVT::Other); // The chain. | ||||
1451 | SDValue Ops[] = {SN->getChain(), Idx, Value}; | ||||
1452 | return DAG.getNode(WebAssemblyISD::LOCAL_SET, DL, Tys, Ops); | ||||
1453 | } | ||||
1454 | |||||
1455 | return Op; | ||||
1456 | } | ||||
1457 | |||||
1458 | SDValue WebAssemblyTargetLowering::LowerLoad(SDValue Op, | ||||
1459 | SelectionDAG &DAG) const { | ||||
1460 | SDLoc DL(Op); | ||||
1461 | LoadSDNode *LN = cast<LoadSDNode>(Op.getNode()); | ||||
1462 | const SDValue &Base = LN->getBasePtr(); | ||||
1463 | const SDValue &Offset = LN->getOffset(); | ||||
1464 | |||||
1465 | if (IsWebAssemblyGlobal(Base)) { | ||||
1466 | if (!Offset->isUndef()) | ||||
1467 | report_fatal_error( | ||||
1468 | "unexpected offset when loading from webassembly global", false); | ||||
1469 | |||||
1470 | SDVTList Tys = DAG.getVTList(LN->getValueType(0), MVT::Other); | ||||
1471 | SDValue Ops[] = {LN->getChain(), Base}; | ||||
1472 | return DAG.getMemIntrinsicNode(WebAssemblyISD::GLOBAL_GET, DL, Tys, Ops, | ||||
1473 | LN->getMemoryVT(), LN->getMemOperand()); | ||||
1474 | } | ||||
1475 | |||||
1476 | if (Optional<unsigned> Local = IsWebAssemblyLocal(Base, DAG)) { | ||||
1477 | if (!Offset->isUndef()) | ||||
1478 | report_fatal_error( | ||||
1479 | "unexpected offset when loading from webassembly local", false); | ||||
1480 | |||||
1481 | SDValue Idx = DAG.getTargetConstant(*Local, Base, MVT::i32); | ||||
1482 | EVT LocalVT = LN->getValueType(0); | ||||
1483 | SDValue LocalGet = DAG.getNode(WebAssemblyISD::LOCAL_GET, DL, LocalVT, | ||||
1484 | {LN->getChain(), Idx}); | ||||
1485 | SDValue Result = DAG.getMergeValues({LocalGet, LN->getChain()}, DL); | ||||
1486 | 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!\"" , "/build/llvm-toolchain-snapshot-14~++20211017100700+d245f2e8597b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp" , 1486, __extension__ __PRETTY_FUNCTION__)); | ||||
1487 | return Result; | ||||
1488 | } | ||||
1489 | |||||
1490 | return Op; | ||||
1491 | } | ||||
1492 | |||||
1493 | SDValue WebAssemblyTargetLowering::LowerCopyToReg(SDValue Op, | ||||
1494 | SelectionDAG &DAG) const { | ||||
1495 | SDValue Src = Op.getOperand(2); | ||||
1496 | if (isa<FrameIndexSDNode>(Src.getNode())) { | ||||
1497 | // CopyToReg nodes don't support FrameIndex operands. Other targets select | ||||
1498 | // the FI to some LEA-like instruction, but since we don't have that, we | ||||
1499 | // need to insert some kind of instruction that can take an FI operand and | ||||
1500 | // produces a value usable by CopyToReg (i.e. in a vreg). So insert a dummy | ||||
1501 | // local.copy between Op and its FI operand. | ||||
1502 | SDValue Chain = Op.getOperand(0); | ||||
1503 | SDLoc DL(Op); | ||||
1504 | unsigned Reg = cast<RegisterSDNode>(Op.getOperand(1))->getReg(); | ||||
1505 | EVT VT = Src.getValueType(); | ||||
1506 | SDValue Copy(DAG.getMachineNode(VT == MVT::i32 ? WebAssembly::COPY_I32 | ||||
1507 | : WebAssembly::COPY_I64, | ||||
1508 | DL, VT, Src), | ||||
1509 | 0); | ||||
1510 | return Op.getNode()->getNumValues() == 1 | ||||
1511 | ? DAG.getCopyToReg(Chain, DL, Reg, Copy) | ||||
1512 | : DAG.getCopyToReg(Chain, DL, Reg, Copy, | ||||
1513 | Op.getNumOperands() == 4 ? Op.getOperand(3) | ||||
1514 | : SDValue()); | ||||
1515 | } | ||||
1516 | return SDValue(); | ||||
1517 | } | ||||
1518 | |||||
1519 | SDValue WebAssemblyTargetLowering::LowerFrameIndex(SDValue Op, | ||||
1520 | SelectionDAG &DAG) const { | ||||
1521 | int FI = cast<FrameIndexSDNode>(Op)->getIndex(); | ||||
1522 | return DAG.getTargetFrameIndex(FI, Op.getValueType()); | ||||
1523 | } | ||||
1524 | |||||
1525 | SDValue WebAssemblyTargetLowering::LowerRETURNADDR(SDValue Op, | ||||
1526 | SelectionDAG &DAG) const { | ||||
1527 | SDLoc DL(Op); | ||||
1528 | |||||
1529 | if (!Subtarget->getTargetTriple().isOSEmscripten()) { | ||||
1530 | fail(DL, DAG, | ||||
1531 | "Non-Emscripten WebAssembly hasn't implemented " | ||||
1532 | "__builtin_return_address"); | ||||
1533 | return SDValue(); | ||||
1534 | } | ||||
1535 | |||||
1536 | if (verifyReturnAddressArgumentIsConstant(Op, DAG)) | ||||
1537 | return SDValue(); | ||||
1538 | |||||
1539 | unsigned Depth = Op.getConstantOperandVal(0); | ||||
1540 | MakeLibCallOptions CallOptions; | ||||
1541 | return makeLibCall(DAG, RTLIB::RETURN_ADDRESS, Op.getValueType(), | ||||
1542 | {DAG.getConstant(Depth, DL, MVT::i32)}, CallOptions, DL) | ||||
1543 | .first; | ||||
1544 | } | ||||
1545 | |||||
1546 | SDValue WebAssemblyTargetLowering::LowerFRAMEADDR(SDValue Op, | ||||
1547 | SelectionDAG &DAG) const { | ||||
1548 | // Non-zero depths are not supported by WebAssembly currently. Use the | ||||
1549 | // legalizer's default expansion, which is to return 0 (what this function is | ||||
1550 | // documented to do). | ||||
1551 | if (Op.getConstantOperandVal(0) > 0) | ||||
1552 | return SDValue(); | ||||
1553 | |||||
1554 | DAG.getMachineFunction().getFrameInfo().setFrameAddressIsTaken(true); | ||||
1555 | EVT VT = Op.getValueType(); | ||||
1556 | Register FP = | ||||
1557 | Subtarget->getRegisterInfo()->getFrameRegister(DAG.getMachineFunction()); | ||||
1558 | return DAG.getCopyFromReg(DAG.getEntryNode(), SDLoc(Op), FP, VT); | ||||
1559 | } | ||||
1560 | |||||
1561 | SDValue | ||||
1562 | WebAssemblyTargetLowering::LowerGlobalTLSAddress(SDValue Op, | ||||
1563 | SelectionDAG &DAG) const { | ||||
1564 | SDLoc DL(Op); | ||||
1565 | const auto *GA = cast<GlobalAddressSDNode>(Op); | ||||
1566 | |||||
1567 | MachineFunction &MF = DAG.getMachineFunction(); | ||||
1568 | if (!MF.getSubtarget<WebAssemblySubtarget>().hasBulkMemory()) | ||||
1569 | report_fatal_error("cannot use thread-local storage without bulk memory", | ||||
1570 | false); | ||||
1571 | |||||
1572 | const GlobalValue *GV = GA->getGlobal(); | ||||
1573 | |||||
1574 | // Currently Emscripten does not support dynamic linking with threads. | ||||
1575 | // Therefore, if we have thread-local storage, only the local-exec model | ||||
1576 | // is possible. | ||||
1577 | // TODO: remove this and implement proper TLS models once Emscripten | ||||
1578 | // supports dynamic linking with threads. | ||||
1579 | if (GV->getThreadLocalMode() != GlobalValue::LocalExecTLSModel && | ||||
1580 | !Subtarget->getTargetTriple().isOSEmscripten()) { | ||||
1581 | report_fatal_error("only -ftls-model=local-exec is supported for now on " | ||||
1582 | "non-Emscripten OSes: variable " + | ||||
1583 | GV->getName(), | ||||
1584 | false); | ||||
1585 | } | ||||
1586 | |||||
1587 | auto model = GV->getThreadLocalMode(); | ||||
1588 | |||||
1589 | // Unsupported TLS modes | ||||
1590 | assert(model != GlobalValue::NotThreadLocal)(static_cast <bool> (model != GlobalValue::NotThreadLocal ) ? void (0) : __assert_fail ("model != GlobalValue::NotThreadLocal" , "/build/llvm-toolchain-snapshot-14~++20211017100700+d245f2e8597b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp" , 1590, __extension__ __PRETTY_FUNCTION__)); | ||||
1591 | assert(model != GlobalValue::InitialExecTLSModel)(static_cast <bool> (model != GlobalValue::InitialExecTLSModel ) ? void (0) : __assert_fail ("model != GlobalValue::InitialExecTLSModel" , "/build/llvm-toolchain-snapshot-14~++20211017100700+d245f2e8597b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp" , 1591, __extension__ __PRETTY_FUNCTION__)); | ||||
1592 | |||||
1593 | if (model == GlobalValue::LocalExecTLSModel || | ||||
1594 | model == GlobalValue::LocalDynamicTLSModel || | ||||
1595 | (model == GlobalValue::GeneralDynamicTLSModel && | ||||
1596 | getTargetMachine().shouldAssumeDSOLocal(*GV->getParent(), GV))) { | ||||
1597 | // For DSO-local TLS variables we use offset from __tls_base | ||||
1598 | |||||
1599 | MVT PtrVT = getPointerTy(DAG.getDataLayout()); | ||||
1600 | auto GlobalGet = PtrVT == MVT::i64 ? WebAssembly::GLOBAL_GET_I64 | ||||
1601 | : WebAssembly::GLOBAL_GET_I32; | ||||
1602 | const char *BaseName = MF.createExternalSymbolName("__tls_base"); | ||||
1603 | |||||
1604 | SDValue BaseAddr( | ||||
1605 | DAG.getMachineNode(GlobalGet, DL, PtrVT, | ||||
1606 | DAG.getTargetExternalSymbol(BaseName, PtrVT)), | ||||
1607 | 0); | ||||
1608 | |||||
1609 | SDValue TLSOffset = DAG.getTargetGlobalAddress( | ||||
1610 | GV, DL, PtrVT, GA->getOffset(), WebAssemblyII::MO_TLS_BASE_REL); | ||||
1611 | SDValue SymOffset = | ||||
1612 | DAG.getNode(WebAssemblyISD::WrapperREL, DL, PtrVT, TLSOffset); | ||||
1613 | |||||
1614 | return DAG.getNode(ISD::ADD, DL, PtrVT, BaseAddr, SymOffset); | ||||
1615 | } | ||||
1616 | |||||
1617 | assert(model == GlobalValue::GeneralDynamicTLSModel)(static_cast <bool> (model == GlobalValue::GeneralDynamicTLSModel ) ? void (0) : __assert_fail ("model == GlobalValue::GeneralDynamicTLSModel" , "/build/llvm-toolchain-snapshot-14~++20211017100700+d245f2e8597b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp" , 1617, __extension__ __PRETTY_FUNCTION__)); | ||||
1618 | |||||
1619 | EVT VT = Op.getValueType(); | ||||
1620 | return DAG.getNode(WebAssemblyISD::Wrapper, DL, VT, | ||||
1621 | DAG.getTargetGlobalAddress(GA->getGlobal(), DL, VT, | ||||
1622 | GA->getOffset(), | ||||
1623 | WebAssemblyII::MO_GOT_TLS)); | ||||
1624 | } | ||||
1625 | |||||
1626 | SDValue WebAssemblyTargetLowering::LowerGlobalAddress(SDValue Op, | ||||
1627 | SelectionDAG &DAG) const { | ||||
1628 | SDLoc DL(Op); | ||||
1629 | const auto *GA = cast<GlobalAddressSDNode>(Op); | ||||
1630 | EVT VT = Op.getValueType(); | ||||
1631 | 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\"" , "/build/llvm-toolchain-snapshot-14~++20211017100700+d245f2e8597b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp" , 1632, __extension__ __PRETTY_FUNCTION__)) | ||||
1632 | "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\"" , "/build/llvm-toolchain-snapshot-14~++20211017100700+d245f2e8597b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp" , 1632, __extension__ __PRETTY_FUNCTION__)); | ||||
1633 | if (!WebAssembly::isValidAddressSpace(GA->getAddressSpace())) | ||||
1634 | fail(DL, DAG, "Invalid address space for WebAssembly target"); | ||||
1635 | |||||
1636 | unsigned OperandFlags = 0; | ||||
1637 | if (isPositionIndependent()) { | ||||
1638 | const GlobalValue *GV = GA->getGlobal(); | ||||
1639 | if (getTargetMachine().shouldAssumeDSOLocal(*GV->getParent(), GV)) { | ||||
1640 | MachineFunction &MF = DAG.getMachineFunction(); | ||||
1641 | MVT PtrVT = getPointerTy(MF.getDataLayout()); | ||||
1642 | const char *BaseName; | ||||
1643 | if (GV->getValueType()->isFunctionTy()) { | ||||
1644 | BaseName = MF.createExternalSymbolName("__table_base"); | ||||
1645 | OperandFlags = WebAssemblyII::MO_TABLE_BASE_REL; | ||||
1646 | } | ||||
1647 | else { | ||||
1648 | BaseName = MF.createExternalSymbolName("__memory_base"); | ||||
1649 | OperandFlags = WebAssemblyII::MO_MEMORY_BASE_REL; | ||||
1650 | } | ||||
1651 | SDValue BaseAddr = | ||||
1652 | DAG.getNode(WebAssemblyISD::Wrapper, DL, PtrVT, | ||||
1653 | DAG.getTargetExternalSymbol(BaseName, PtrVT)); | ||||
1654 | |||||
1655 | SDValue SymAddr = DAG.getNode( | ||||
1656 | WebAssemblyISD::WrapperREL, DL, VT, | ||||
1657 | DAG.getTargetGlobalAddress(GA->getGlobal(), DL, VT, GA->getOffset(), | ||||
1658 | OperandFlags)); | ||||
1659 | |||||
1660 | return DAG.getNode(ISD::ADD, DL, VT, BaseAddr, SymAddr); | ||||
1661 | } | ||||
1662 | OperandFlags = WebAssemblyII::MO_GOT; | ||||
1663 | } | ||||
1664 | |||||
1665 | return DAG.getNode(WebAssemblyISD::Wrapper, DL, VT, | ||||
1666 | DAG.getTargetGlobalAddress(GA->getGlobal(), DL, VT, | ||||
1667 | GA->getOffset(), OperandFlags)); | ||||
1668 | } | ||||
1669 | |||||
1670 | SDValue | ||||
1671 | WebAssemblyTargetLowering::LowerExternalSymbol(SDValue Op, | ||||
1672 | SelectionDAG &DAG) const { | ||||
1673 | SDLoc DL(Op); | ||||
1674 | const auto *ES = cast<ExternalSymbolSDNode>(Op); | ||||
1675 | EVT VT = Op.getValueType(); | ||||
1676 | 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\"" , "/build/llvm-toolchain-snapshot-14~++20211017100700+d245f2e8597b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp" , 1677, __extension__ __PRETTY_FUNCTION__)) | ||||
1677 | "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\"" , "/build/llvm-toolchain-snapshot-14~++20211017100700+d245f2e8597b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp" , 1677, __extension__ __PRETTY_FUNCTION__)); | ||||
1678 | return DAG.getNode(WebAssemblyISD::Wrapper, DL, VT, | ||||
1679 | DAG.getTargetExternalSymbol(ES->getSymbol(), VT)); | ||||
1680 | } | ||||
1681 | |||||
1682 | SDValue WebAssemblyTargetLowering::LowerJumpTable(SDValue Op, | ||||
1683 | SelectionDAG &DAG) const { | ||||
1684 | // There's no need for a Wrapper node because we always incorporate a jump | ||||
1685 | // table operand into a BR_TABLE instruction, rather than ever | ||||
1686 | // materializing it in a register. | ||||
1687 | const JumpTableSDNode *JT = cast<JumpTableSDNode>(Op); | ||||
1688 | return DAG.getTargetJumpTable(JT->getIndex(), Op.getValueType(), | ||||
1689 | JT->getTargetFlags()); | ||||
1690 | } | ||||
1691 | |||||
1692 | SDValue WebAssemblyTargetLowering::LowerBR_JT(SDValue Op, | ||||
1693 | SelectionDAG &DAG) const { | ||||
1694 | SDLoc DL(Op); | ||||
1695 | SDValue Chain = Op.getOperand(0); | ||||
1696 | const auto *JT = cast<JumpTableSDNode>(Op.getOperand(1)); | ||||
1697 | SDValue Index = Op.getOperand(2); | ||||
1698 | 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\"" , "/build/llvm-toolchain-snapshot-14~++20211017100700+d245f2e8597b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp" , 1698, __extension__ __PRETTY_FUNCTION__)); | ||||
1699 | |||||
1700 | SmallVector<SDValue, 8> Ops; | ||||
1701 | Ops.push_back(Chain); | ||||
1702 | Ops.push_back(Index); | ||||
1703 | |||||
1704 | MachineJumpTableInfo *MJTI = DAG.getMachineFunction().getJumpTableInfo(); | ||||
1705 | const auto &MBBs = MJTI->getJumpTables()[JT->getIndex()].MBBs; | ||||
1706 | |||||
1707 | // Add an operand for each case. | ||||
1708 | for (auto MBB : MBBs) | ||||
1709 | Ops.push_back(DAG.getBasicBlock(MBB)); | ||||
1710 | |||||
1711 | // Add the first MBB as a dummy default target for now. This will be replaced | ||||
1712 | // with the proper default target (and the preceding range check eliminated) | ||||
1713 | // if possible by WebAssemblyFixBrTableDefaults. | ||||
1714 | Ops.push_back(DAG.getBasicBlock(*MBBs.begin())); | ||||
1715 | return DAG.getNode(WebAssemblyISD::BR_TABLE, DL, MVT::Other, Ops); | ||||
1716 | } | ||||
1717 | |||||
1718 | SDValue WebAssemblyTargetLowering::LowerVASTART(SDValue Op, | ||||
1719 | SelectionDAG &DAG) const { | ||||
1720 | SDLoc DL(Op); | ||||
1721 | EVT PtrVT = getPointerTy(DAG.getMachineFunction().getDataLayout()); | ||||
1722 | |||||
1723 | auto *MFI = DAG.getMachineFunction().getInfo<WebAssemblyFunctionInfo>(); | ||||
1724 | const Value *SV = cast<SrcValueSDNode>(Op.getOperand(2))->getValue(); | ||||
1725 | |||||
1726 | SDValue ArgN = DAG.getCopyFromReg(DAG.getEntryNode(), DL, | ||||
1727 | MFI->getVarargBufferVreg(), PtrVT); | ||||
1728 | return DAG.getStore(Op.getOperand(0), DL, ArgN, Op.getOperand(1), | ||||
1729 | MachinePointerInfo(SV)); | ||||
1730 | } | ||||
1731 | |||||
1732 | SDValue WebAssemblyTargetLowering::LowerIntrinsic(SDValue Op, | ||||
1733 | SelectionDAG &DAG) const { | ||||
1734 | MachineFunction &MF = DAG.getMachineFunction(); | ||||
1735 | unsigned IntNo; | ||||
1736 | switch (Op.getOpcode()) { | ||||
1737 | case ISD::INTRINSIC_VOID: | ||||
1738 | case ISD::INTRINSIC_W_CHAIN: | ||||
1739 | IntNo = Op.getConstantOperandVal(1); | ||||
1740 | break; | ||||
1741 | case ISD::INTRINSIC_WO_CHAIN: | ||||
1742 | IntNo = Op.getConstantOperandVal(0); | ||||
1743 | break; | ||||
1744 | default: | ||||
1745 | llvm_unreachable("Invalid intrinsic")::llvm::llvm_unreachable_internal("Invalid intrinsic", "/build/llvm-toolchain-snapshot-14~++20211017100700+d245f2e8597b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp" , 1745); | ||||
1746 | } | ||||
1747 | SDLoc DL(Op); | ||||
1748 | |||||
1749 | switch (IntNo) { | ||||
1750 | default: | ||||
1751 | return SDValue(); // Don't custom lower most intrinsics. | ||||
1752 | |||||
1753 | case Intrinsic::wasm_lsda: { | ||||
1754 | auto PtrVT = getPointerTy(MF.getDataLayout()); | ||||
1755 | const char *SymName = MF.createExternalSymbolName( | ||||
1756 | "GCC_except_table" + std::to_string(MF.getFunctionNumber())); | ||||
1757 | if (isPositionIndependent()) { | ||||
1758 | SDValue Node = DAG.getTargetExternalSymbol( | ||||
1759 | SymName, PtrVT, WebAssemblyII::MO_MEMORY_BASE_REL); | ||||
1760 | const char *BaseName = MF.createExternalSymbolName("__memory_base"); | ||||
1761 | SDValue BaseAddr = | ||||
1762 | DAG.getNode(WebAssemblyISD::Wrapper, DL, PtrVT, | ||||
1763 | DAG.getTargetExternalSymbol(BaseName, PtrVT)); | ||||
1764 | SDValue SymAddr = | ||||
1765 | DAG.getNode(WebAssemblyISD::WrapperREL, DL, PtrVT, Node); | ||||
1766 | return DAG.getNode(ISD::ADD, DL, PtrVT, BaseAddr, SymAddr); | ||||
1767 | } | ||||
1768 | SDValue Node = DAG.getTargetExternalSymbol(SymName, PtrVT); | ||||
1769 | return DAG.getNode(WebAssemblyISD::Wrapper, DL, PtrVT, Node); | ||||
1770 | } | ||||
1771 | |||||
1772 | case Intrinsic::wasm_shuffle: { | ||||
1773 | // Drop in-chain and replace undefs, but otherwise pass through unchanged | ||||
1774 | SDValue Ops[18]; | ||||
1775 | size_t OpIdx = 0; | ||||
1776 | Ops[OpIdx++] = Op.getOperand(1); | ||||
1777 | Ops[OpIdx++] = Op.getOperand(2); | ||||
1778 | while (OpIdx < 18) { | ||||
1779 | const SDValue &MaskIdx = Op.getOperand(OpIdx + 1); | ||||
1780 | if (MaskIdx.isUndef() || | ||||
1781 | cast<ConstantSDNode>(MaskIdx.getNode())->getZExtValue() >= 32) { | ||||
1782 | Ops[OpIdx++] = DAG.getConstant(0, DL, MVT::i32); | ||||
1783 | } else { | ||||
1784 | Ops[OpIdx++] = MaskIdx; | ||||
1785 | } | ||||
1786 | } | ||||
1787 | return DAG.getNode(WebAssemblyISD::SHUFFLE, DL, Op.getValueType(), Ops); | ||||
1788 | } | ||||
1789 | } | ||||
1790 | } | ||||
1791 | |||||
1792 | SDValue | ||||
1793 | WebAssemblyTargetLowering::LowerSIGN_EXTEND_INREG(SDValue Op, | ||||
1794 | SelectionDAG &DAG) const { | ||||
1795 | SDLoc DL(Op); | ||||
1796 | // If sign extension operations are disabled, allow sext_inreg only if operand | ||||
1797 | // is a vector extract of an i8 or i16 lane. SIMD does not depend on sign | ||||
1798 | // extension operations, but allowing sext_inreg in this context lets us have | ||||
1799 | // simple patterns to select extract_lane_s instructions. Expanding sext_inreg | ||||
1800 | // everywhere would be simpler in this file, but would necessitate large and | ||||
1801 | // brittle patterns to undo the expansion and select extract_lane_s | ||||
1802 | // instructions. | ||||
1803 | assert(!Subtarget->hasSignExt() && Subtarget->hasSIMD128())(static_cast <bool> (!Subtarget->hasSignExt() && Subtarget->hasSIMD128()) ? void (0) : __assert_fail ("!Subtarget->hasSignExt() && Subtarget->hasSIMD128()" , "/build/llvm-toolchain-snapshot-14~++20211017100700+d245f2e8597b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp" , 1803, __extension__ __PRETTY_FUNCTION__)); | ||||
1804 | if (Op.getOperand(0).getOpcode() != ISD::EXTRACT_VECTOR_ELT) | ||||
1805 | return SDValue(); | ||||
1806 | |||||
1807 | const SDValue &Extract = Op.getOperand(0); | ||||
1808 | MVT VecT = Extract.getOperand(0).getSimpleValueType(); | ||||
1809 | if (VecT.getVectorElementType().getSizeInBits() > 32) | ||||
1810 | return SDValue(); | ||||
1811 | MVT ExtractedLaneT = | ||||
1812 | cast<VTSDNode>(Op.getOperand(1).getNode())->getVT().getSimpleVT(); | ||||
1813 | MVT ExtractedVecT = | ||||
1814 | MVT::getVectorVT(ExtractedLaneT, 128 / ExtractedLaneT.getSizeInBits()); | ||||
1815 | if (ExtractedVecT == VecT) | ||||
1816 | return Op; | ||||
1817 | |||||
1818 | // Bitcast vector to appropriate type to ensure ISel pattern coverage | ||||
1819 | const SDNode *Index = Extract.getOperand(1).getNode(); | ||||
1820 | if (!isa<ConstantSDNode>(Index)) | ||||
1821 | return SDValue(); | ||||
1822 | unsigned IndexVal = cast<ConstantSDNode>(Index)->getZExtValue(); | ||||
1823 | unsigned Scale = | ||||
1824 | ExtractedVecT.getVectorNumElements() / VecT.getVectorNumElements(); | ||||
1825 | assert(Scale > 1)(static_cast <bool> (Scale > 1) ? void (0) : __assert_fail ("Scale > 1", "/build/llvm-toolchain-snapshot-14~++20211017100700+d245f2e8597b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp" , 1825, __extension__ __PRETTY_FUNCTION__)); | ||||
1826 | SDValue NewIndex = | ||||
1827 | DAG.getConstant(IndexVal * Scale, DL, Index->getValueType(0)); | ||||
1828 | SDValue NewExtract = DAG.getNode( | ||||
1829 | ISD::EXTRACT_VECTOR_ELT, DL, Extract.getValueType(), | ||||
1830 | DAG.getBitcast(ExtractedVecT, Extract.getOperand(0)), NewIndex); | ||||
1831 | return DAG.getNode(ISD::SIGN_EXTEND_INREG, DL, Op.getValueType(), NewExtract, | ||||
1832 | Op.getOperand(1)); | ||||
1833 | } | ||||
1834 | |||||
1835 | static SDValue LowerConvertLow(SDValue Op, SelectionDAG &DAG) { | ||||
1836 | SDLoc DL(Op); | ||||
1837 | if (Op.getValueType() != MVT::v2f64) | ||||
1838 | return SDValue(); | ||||
1839 | |||||
1840 | auto GetConvertedLane = [](SDValue Op, unsigned &Opcode, SDValue &SrcVec, | ||||
1841 | unsigned &Index) -> bool { | ||||
1842 | switch (Op.getOpcode()) { | ||||
1843 | case ISD::SINT_TO_FP: | ||||
1844 | Opcode = WebAssemblyISD::CONVERT_LOW_S; | ||||
1845 | break; | ||||
1846 | case ISD::UINT_TO_FP: | ||||
1847 | Opcode = WebAssemblyISD::CONVERT_LOW_U; | ||||
1848 | break; | ||||
1849 | case ISD::FP_EXTEND: | ||||
1850 | Opcode = WebAssemblyISD::PROMOTE_LOW; | ||||
1851 | break; | ||||
1852 | default: | ||||
1853 | return false; | ||||
1854 | } | ||||
1855 | |||||
1856 | auto ExtractVector = Op.getOperand(0); | ||||
1857 | if (ExtractVector.getOpcode() != ISD::EXTRACT_VECTOR_ELT) | ||||
1858 | return false; | ||||
1859 | |||||
1860 | if (!isa<ConstantSDNode>(ExtractVector.getOperand(1).getNode())) | ||||
1861 | return false; | ||||
1862 | |||||
1863 | SrcVec = ExtractVector.getOperand(0); | ||||
1864 | Index = ExtractVector.getConstantOperandVal(1); | ||||
1865 | return true; | ||||
1866 | }; | ||||
1867 | |||||
1868 | unsigned LHSOpcode, RHSOpcode, LHSIndex, RHSIndex; | ||||
1869 | SDValue LHSSrcVec, RHSSrcVec; | ||||
1870 | if (!GetConvertedLane(Op.getOperand(0), LHSOpcode, LHSSrcVec, LHSIndex) || | ||||
1871 | !GetConvertedLane(Op.getOperand(1), RHSOpcode, RHSSrcVec, RHSIndex)) | ||||
1872 | return SDValue(); | ||||
1873 | |||||
1874 | if (LHSOpcode != RHSOpcode) | ||||
1875 | return SDValue(); | ||||
1876 | |||||
1877 | MVT ExpectedSrcVT; | ||||
1878 | switch (LHSOpcode) { | ||||
1879 | case WebAssemblyISD::CONVERT_LOW_S: | ||||
1880 | case WebAssemblyISD::CONVERT_LOW_U: | ||||
1881 | ExpectedSrcVT = MVT::v4i32; | ||||
1882 | break; | ||||
1883 | case WebAssemblyISD::PROMOTE_LOW: | ||||
1884 | ExpectedSrcVT = MVT::v4f32; | ||||
1885 | break; | ||||
1886 | } | ||||
1887 | if (LHSSrcVec.getValueType() != ExpectedSrcVT) | ||||
1888 | return SDValue(); | ||||
1889 | |||||
1890 | auto Src = LHSSrcVec; | ||||
1891 | if (LHSIndex != 0 || RHSIndex != 1 || LHSSrcVec != RHSSrcVec) { | ||||
1892 | // Shuffle the source vector so that the converted lanes are the low lanes. | ||||
1893 | Src = DAG.getVectorShuffle( | ||||
1894 | ExpectedSrcVT, DL, LHSSrcVec, RHSSrcVec, | ||||
1895 | {static_cast<int>(LHSIndex), static_cast<int>(RHSIndex) + 4, -1, -1}); | ||||
1896 | } | ||||
1897 | return DAG.getNode(LHSOpcode, DL, MVT::v2f64, Src); | ||||
1898 | } | ||||
1899 | |||||
1900 | SDValue WebAssemblyTargetLowering::LowerBUILD_VECTOR(SDValue Op, | ||||
1901 | SelectionDAG &DAG) const { | ||||
1902 | if (auto ConvertLow = LowerConvertLow(Op, DAG)) | ||||
1903 | return ConvertLow; | ||||
1904 | |||||
1905 | SDLoc DL(Op); | ||||
1906 | const EVT VecT = Op.getValueType(); | ||||
1907 | const EVT LaneT = Op.getOperand(0).getValueType(); | ||||
1908 | const size_t Lanes = Op.getNumOperands(); | ||||
1909 | bool CanSwizzle = VecT == MVT::v16i8; | ||||
1910 | |||||
1911 | // BUILD_VECTORs are lowered to the instruction that initializes the highest | ||||
1912 | // possible number of lanes at once followed by a sequence of replace_lane | ||||
1913 | // instructions to individually initialize any remaining lanes. | ||||
1914 | |||||
1915 | // TODO: Tune this. For example, lanewise swizzling is very expensive, so | ||||
1916 | // swizzled lanes should be given greater weight. | ||||
1917 | |||||
1918 | // TODO: Investigate looping rather than always extracting/replacing specific | ||||
1919 | // lanes to fill gaps. | ||||
1920 | |||||
1921 | auto IsConstant = [](const SDValue &V) { | ||||
1922 | return V.getOpcode() == ISD::Constant || V.getOpcode() == ISD::ConstantFP; | ||||
1923 | }; | ||||
1924 | |||||
1925 | // Returns the source vector and index vector pair if they exist. Checks for: | ||||
1926 | // (extract_vector_elt | ||||
1927 | // $src, | ||||
1928 | // (sign_extend_inreg (extract_vector_elt $indices, $i)) | ||||
1929 | // ) | ||||
1930 | auto GetSwizzleSrcs = [](size_t I, const SDValue &Lane) { | ||||
1931 | auto Bail = std::make_pair(SDValue(), SDValue()); | ||||
1932 | if (Lane->getOpcode() != ISD::EXTRACT_VECTOR_ELT) | ||||
1933 | return Bail; | ||||
1934 | const SDValue &SwizzleSrc = Lane->getOperand(0); | ||||
1935 | const SDValue &IndexExt = Lane->getOperand(1); | ||||
1936 | if (IndexExt->getOpcode() != ISD::SIGN_EXTEND_INREG) | ||||
1937 | return Bail; | ||||
1938 | const SDValue &Index = IndexExt->getOperand(0); | ||||
1939 | if (Index->getOpcode() != ISD::EXTRACT_VECTOR_ELT) | ||||
1940 | return Bail; | ||||
1941 | const SDValue &SwizzleIndices = Index->getOperand(0); | ||||
1942 | if (SwizzleSrc.getValueType() != MVT::v16i8 || | ||||
1943 | SwizzleIndices.getValueType() != MVT::v16i8 || | ||||
1944 | Index->getOperand(1)->getOpcode() != ISD::Constant || | ||||
1945 | Index->getConstantOperandVal(1) != I) | ||||
1946 | return Bail; | ||||
1947 | return std::make_pair(SwizzleSrc, SwizzleIndices); | ||||
1948 | }; | ||||
1949 | |||||
1950 | // If the lane is extracted from another vector at a constant index, return | ||||
1951 | // that vector. The source vector must not have more lanes than the dest | ||||
1952 | // because the shufflevector indices are in terms of the destination lanes and | ||||
1953 | // would not be able to address the smaller individual source lanes. | ||||
1954 | auto GetShuffleSrc = [&](const SDValue &Lane) { | ||||
1955 | if (Lane->getOpcode() != ISD::EXTRACT_VECTOR_ELT) | ||||
1956 | return SDValue(); | ||||
1957 | if (!isa<ConstantSDNode>(Lane->getOperand(1).getNode())) | ||||
1958 | return SDValue(); | ||||
1959 | if (Lane->getOperand(0).getValueType().getVectorNumElements() > | ||||
1960 | VecT.getVectorNumElements()) | ||||
1961 | return SDValue(); | ||||
1962 | return Lane->getOperand(0); | ||||
1963 | }; | ||||
1964 | |||||
1965 | using ValueEntry = std::pair<SDValue, size_t>; | ||||
1966 | SmallVector<ValueEntry, 16> SplatValueCounts; | ||||
1967 | |||||
1968 | using SwizzleEntry = std::pair<std::pair<SDValue, SDValue>, size_t>; | ||||
1969 | SmallVector<SwizzleEntry, 16> SwizzleCounts; | ||||
1970 | |||||
1971 | using ShuffleEntry = std::pair<SDValue, size_t>; | ||||
1972 | SmallVector<ShuffleEntry, 16> ShuffleCounts; | ||||
1973 | |||||
1974 | auto AddCount = [](auto &Counts, const auto &Val) { | ||||
1975 | auto CountIt = | ||||
1976 | llvm::find_if(Counts, [&Val](auto E) { return E.first == Val; }); | ||||
1977 | if (CountIt == Counts.end()) { | ||||
1978 | Counts.emplace_back(Val, 1); | ||||
1979 | } else { | ||||
1980 | CountIt->second++; | ||||
1981 | } | ||||
1982 | }; | ||||
1983 | |||||
1984 | auto GetMostCommon = [](auto &Counts) { | ||||
1985 | auto CommonIt = | ||||
1986 | std::max_element(Counts.begin(), Counts.end(), | ||||
1987 | [](auto A, auto B) { return A.second < B.second; }); | ||||
1988 | 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\"" , "/build/llvm-toolchain-snapshot-14~++20211017100700+d245f2e8597b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp" , 1988, __extension__ __PRETTY_FUNCTION__)); | ||||
1989 | return *CommonIt; | ||||
1990 | }; | ||||
1991 | |||||
1992 | size_t NumConstantLanes = 0; | ||||
1993 | |||||
1994 | // Count eligible lanes for each type of vector creation op | ||||
1995 | for (size_t I = 0; I
| ||||
1996 | const SDValue &Lane = Op->getOperand(I); | ||||
1997 | if (Lane.isUndef()) | ||||
1998 | continue; | ||||
1999 | |||||
2000 | AddCount(SplatValueCounts, Lane); | ||||
2001 | |||||
2002 | if (IsConstant(Lane)) | ||||
2003 | NumConstantLanes++; | ||||
2004 | if (auto ShuffleSrc = GetShuffleSrc(Lane)) | ||||
2005 | AddCount(ShuffleCounts, ShuffleSrc); | ||||
2006 | if (CanSwizzle
| ||||
2007 | auto SwizzleSrcs = GetSwizzleSrcs(I, Lane); | ||||
2008 | if (SwizzleSrcs.first) | ||||
2009 | AddCount(SwizzleCounts, SwizzleSrcs); | ||||
2010 | } | ||||
2011 | } | ||||
2012 | |||||
2013 | SDValue SplatValue; | ||||
2014 | size_t NumSplatLanes; | ||||
2015 | std::tie(SplatValue, NumSplatLanes) = GetMostCommon(SplatValueCounts); | ||||
2016 | |||||
2017 | SDValue SwizzleSrc; | ||||
2018 | SDValue SwizzleIndices; | ||||
2019 | size_t NumSwizzleLanes = 0; | ||||
2020 | if (SwizzleCounts.size()) | ||||
2021 | std::forward_as_tuple(std::tie(SwizzleSrc, SwizzleIndices), | ||||
2022 | NumSwizzleLanes) = GetMostCommon(SwizzleCounts); | ||||
2023 | |||||
2024 | // Shuffles can draw from up to two vectors, so find the two most common | ||||
2025 | // sources. | ||||
2026 | SDValue ShuffleSrc1, ShuffleSrc2; | ||||
2027 | size_t NumShuffleLanes = 0; | ||||
2028 | if (ShuffleCounts.size()) { | ||||
2029 | std::tie(ShuffleSrc1, NumShuffleLanes) = GetMostCommon(ShuffleCounts); | ||||
2030 | ShuffleCounts.erase(std::remove_if(ShuffleCounts.begin(), | ||||
2031 | ShuffleCounts.end(), | ||||
2032 | [&](const auto &Pair) { | ||||
2033 | return Pair.first == ShuffleSrc1; | ||||
2034 | }), | ||||
2035 | ShuffleCounts.end()); | ||||
2036 | } | ||||
2037 | if (ShuffleCounts.size()) { | ||||
2038 | size_t AdditionalShuffleLanes; | ||||
2039 | std::tie(ShuffleSrc2, AdditionalShuffleLanes) = | ||||
2040 | GetMostCommon(ShuffleCounts); | ||||
2041 | NumShuffleLanes += AdditionalShuffleLanes; | ||||
2042 | } | ||||
2043 | |||||
2044 | // Predicate returning true if the lane is properly initialized by the | ||||
2045 | // original instruction | ||||
2046 | std::function<bool(size_t, const SDValue &)> IsLaneConstructed; | ||||
2047 | SDValue Result; | ||||
2048 | // Prefer swizzles over shuffles over vector consts over splats | ||||
2049 | if (NumSwizzleLanes >= NumShuffleLanes && | ||||
2050 | NumSwizzleLanes >= NumConstantLanes && NumSwizzleLanes >= NumSplatLanes) { | ||||
2051 | Result = DAG.getNode(WebAssemblyISD::SWIZZLE, DL, VecT, SwizzleSrc, | ||||
2052 | SwizzleIndices); | ||||
2053 | auto Swizzled = std::make_pair(SwizzleSrc, SwizzleIndices); | ||||
2054 | IsLaneConstructed = [&, Swizzled](size_t I, const SDValue &Lane) { | ||||
2055 | return Swizzled == GetSwizzleSrcs(I, Lane); | ||||
2056 | }; | ||||
2057 | } else if (NumShuffleLanes
| ||||
2058 | NumShuffleLanes >= NumSplatLanes) { | ||||
2059 | size_t DestLaneSize = VecT.getVectorElementType().getFixedSizeInBits() / 8; | ||||
2060 | size_t DestLaneCount = VecT.getVectorNumElements(); | ||||
2061 | size_t Scale1 = 1; | ||||
2062 | size_t Scale2 = 1; | ||||
2063 | SDValue Src1 = ShuffleSrc1; | ||||
2064 | SDValue Src2 = ShuffleSrc2 ? ShuffleSrc2 : DAG.getUNDEF(VecT); | ||||
2065 | if (Src1.getValueType() != VecT) { | ||||
2066 | size_t LaneSize = | ||||
2067 | Src1.getValueType().getVectorElementType().getFixedSizeInBits() / 8; | ||||
2068 | assert(LaneSize > DestLaneSize)(static_cast <bool> (LaneSize > DestLaneSize) ? void (0) : __assert_fail ("LaneSize > DestLaneSize", "/build/llvm-toolchain-snapshot-14~++20211017100700+d245f2e8597b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp" , 2068, __extension__ __PRETTY_FUNCTION__)); | ||||
2069 | Scale1 = LaneSize / DestLaneSize; | ||||
2070 | Src1 = DAG.getBitcast(VecT, Src1); | ||||
2071 | } | ||||
2072 | if (Src2.getValueType() != VecT) { | ||||
2073 | size_t LaneSize = | ||||
2074 | Src2.getValueType().getVectorElementType().getFixedSizeInBits() / 8; | ||||
2075 | assert(LaneSize > DestLaneSize)(static_cast <bool> (LaneSize > DestLaneSize) ? void (0) : __assert_fail ("LaneSize > DestLaneSize", "/build/llvm-toolchain-snapshot-14~++20211017100700+d245f2e8597b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp" , 2075, __extension__ __PRETTY_FUNCTION__)); | ||||
2076 | Scale2 = LaneSize / DestLaneSize; | ||||
2077 | Src2 = DAG.getBitcast(VecT, Src2); | ||||
2078 | } | ||||
2079 | |||||
2080 | int Mask[16]; | ||||
2081 | assert(DestLaneCount <= 16)(static_cast <bool> (DestLaneCount <= 16) ? void (0) : __assert_fail ("DestLaneCount <= 16", "/build/llvm-toolchain-snapshot-14~++20211017100700+d245f2e8597b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp" , 2081, __extension__ __PRETTY_FUNCTION__)); | ||||
2082 | for (size_t I = 0; I < DestLaneCount; ++I) { | ||||
2083 | const SDValue &Lane = Op->getOperand(I); | ||||
2084 | SDValue Src = GetShuffleSrc(Lane); | ||||
2085 | if (Src == ShuffleSrc1) { | ||||
2086 | Mask[I] = Lane->getConstantOperandVal(1) * Scale1; | ||||
2087 | } else if (Src && Src == ShuffleSrc2) { | ||||
2088 | Mask[I] = DestLaneCount + Lane->getConstantOperandVal(1) * Scale2; | ||||
2089 | } else { | ||||
2090 | Mask[I] = -1; | ||||
2091 | } | ||||
2092 | } | ||||
2093 | ArrayRef<int> MaskRef(Mask, DestLaneCount); | ||||
2094 | Result = DAG.getVectorShuffle(VecT, DL, Src1, Src2, MaskRef); | ||||
2095 | IsLaneConstructed = [&](size_t, const SDValue &Lane) { | ||||
2096 | auto Src = GetShuffleSrc(Lane); | ||||
2097 | return Src == ShuffleSrc1 || (Src && Src == ShuffleSrc2); | ||||
2098 | }; | ||||
2099 | } else if (NumConstantLanes >= NumSplatLanes) { | ||||
2100 | SmallVector<SDValue, 16> ConstLanes; | ||||
2101 | for (const SDValue &Lane : Op->op_values()) { | ||||
2102 | if (IsConstant(Lane)) { | ||||
2103 | // Values may need to be fixed so that they will sign extend to be | ||||
2104 | // within the expected range during ISel. Check whether the value is in | ||||
2105 | // bounds based on the lane bit width and if it is out of bounds, lop | ||||
2106 | // off the extra bits and subtract 2^n to reflect giving the high bit | ||||
2107 | // value -2^(n-1) rather than +2^(n-1). Skip the i64 case because it | ||||
2108 | // cannot possibly be out of range. | ||||
2109 | auto *Const = dyn_cast<ConstantSDNode>(Lane.getNode()); | ||||
2110 | int64_t Val = Const
| ||||
2111 | uint64_t LaneBits = 128 / Lanes; | ||||
2112 | 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\"" , "/build/llvm-toolchain-snapshot-14~++20211017100700+d245f2e8597b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp" , 2113, __extension__ __PRETTY_FUNCTION__)) | ||||
| |||||
2113 | "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\"" , "/build/llvm-toolchain-snapshot-14~++20211017100700+d245f2e8597b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp" , 2113, __extension__ __PRETTY_FUNCTION__)); | ||||
2114 | if (Const && LaneBits != 64 && Val > (1ll << (LaneBits - 1)) - 1) { | ||||
2115 | auto NewVal = ((uint64_t)Val % (1ll << LaneBits)) - (1ll << LaneBits); | ||||
2116 | ConstLanes.push_back(DAG.getConstant(NewVal, SDLoc(Lane), LaneT)); | ||||
2117 | } else { | ||||
2118 | ConstLanes.push_back(Lane); | ||||
2119 | } | ||||
2120 | } else if (LaneT.isFloatingPoint()) { | ||||
2121 | ConstLanes.push_back(DAG.getConstantFP(0, DL, LaneT)); | ||||
2122 | } else { | ||||
2123 | ConstLanes.push_back(DAG.getConstant(0, DL, LaneT)); | ||||
2124 | } | ||||
2125 | } | ||||
2126 | Result = DAG.getBuildVector(VecT, DL, ConstLanes); | ||||
2127 | IsLaneConstructed = [&IsConstant](size_t _, const SDValue &Lane) { | ||||
2128 | return IsConstant(Lane); | ||||
2129 | }; | ||||
2130 | } else { | ||||
2131 | // Use a splat, but possibly a load_splat | ||||
2132 | LoadSDNode *SplattedLoad; | ||||
2133 | if ((SplattedLoad = dyn_cast<LoadSDNode>(SplatValue)) && | ||||
2134 | SplattedLoad->getMemoryVT() == VecT.getVectorElementType()) { | ||||
2135 | Result = DAG.getMemIntrinsicNode( | ||||
2136 | WebAssemblyISD::LOAD_SPLAT, DL, DAG.getVTList(VecT), | ||||
2137 | {SplattedLoad->getChain(), SplattedLoad->getBasePtr(), | ||||
2138 | SplattedLoad->getOffset()}, | ||||
2139 | SplattedLoad->getMemoryVT(), SplattedLoad->getMemOperand()); | ||||
2140 | } else { | ||||
2141 | Result = DAG.getSplatBuildVector(VecT, DL, SplatValue); | ||||
2142 | } | ||||
2143 | IsLaneConstructed = [&SplatValue](size_t _, const SDValue &Lane) { | ||||
2144 | return Lane == SplatValue; | ||||
2145 | }; | ||||
2146 | } | ||||
2147 | |||||
2148 | assert(Result)(static_cast <bool> (Result) ? void (0) : __assert_fail ("Result", "/build/llvm-toolchain-snapshot-14~++20211017100700+d245f2e8597b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp" , 2148, __extension__ __PRETTY_FUNCTION__)); | ||||
2149 | assert(IsLaneConstructed)(static_cast <bool> (IsLaneConstructed) ? void (0) : __assert_fail ("IsLaneConstructed", "/build/llvm-toolchain-snapshot-14~++20211017100700+d245f2e8597b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp" , 2149, __extension__ __PRETTY_FUNCTION__)); | ||||
2150 | |||||
2151 | // Add replace_lane instructions for any unhandled values | ||||
2152 | for (size_t I = 0; I < Lanes; ++I) { | ||||
2153 | const SDValue &Lane = Op->getOperand(I); | ||||
2154 | if (!Lane.isUndef() && !IsLaneConstructed(I, Lane)) | ||||
2155 | Result = DAG.getNode(ISD::INSERT_VECTOR_ELT, DL, VecT, Result, Lane, | ||||
2156 | DAG.getConstant(I, DL, MVT::i32)); | ||||
2157 | } | ||||
2158 | |||||
2159 | return Result; | ||||
2160 | } | ||||
2161 | |||||
2162 | SDValue | ||||
2163 | WebAssemblyTargetLowering::LowerVECTOR_SHUFFLE(SDValue Op, | ||||
2164 | SelectionDAG &DAG) const { | ||||
2165 | SDLoc DL(Op); | ||||
2166 | ArrayRef<int> Mask = cast<ShuffleVectorSDNode>(Op.getNode())->getMask(); | ||||
2167 | MVT VecType = Op.getOperand(0).getSimpleValueType(); | ||||
2168 | 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\"" , "/build/llvm-toolchain-snapshot-14~++20211017100700+d245f2e8597b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp" , 2168, __extension__ __PRETTY_FUNCTION__)); | ||||
2169 | size_t LaneBytes = VecType.getVectorElementType().getSizeInBits() / 8; | ||||
2170 | |||||
2171 | // Space for two vector args and sixteen mask indices | ||||
2172 | SDValue Ops[18]; | ||||
2173 | size_t OpIdx = 0; | ||||
2174 | Ops[OpIdx++] = Op.getOperand(0); | ||||
2175 | Ops[OpIdx++] = Op.getOperand(1); | ||||
2176 | |||||
2177 | // Expand mask indices to byte indices and materialize them as operands | ||||
2178 | for (int M : Mask) { | ||||
2179 | for (size_t J = 0; J < LaneBytes; ++J) { | ||||
2180 | // Lower undefs (represented by -1 in mask) to zero | ||||
2181 | uint64_t ByteIndex = M == -1 ? 0 : (uint64_t)M * LaneBytes + J; | ||||
2182 | Ops[OpIdx++] = DAG.getConstant(ByteIndex, DL, MVT::i32); | ||||
2183 | } | ||||
2184 | } | ||||
2185 | |||||
2186 | return DAG.getNode(WebAssemblyISD::SHUFFLE, DL, Op.getValueType(), Ops); | ||||
2187 | } | ||||
2188 | |||||
2189 | SDValue WebAssemblyTargetLowering::LowerSETCC(SDValue Op, | ||||
2190 | SelectionDAG &DAG) const { | ||||
2191 | SDLoc DL(Op); | ||||
2192 | // The legalizer does not know how to expand the unsupported comparison modes | ||||
2193 | // of i64x2 vectors, so we manually unroll them here. | ||||
2194 | 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" , "/build/llvm-toolchain-snapshot-14~++20211017100700+d245f2e8597b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp" , 2194, __extension__ __PRETTY_FUNCTION__)); | ||||
2195 | SmallVector<SDValue, 2> LHS, RHS; | ||||
2196 | DAG.ExtractVectorElements(Op->getOperand(0), LHS); | ||||
2197 | DAG.ExtractVectorElements(Op->getOperand(1), RHS); | ||||
2198 | const SDValue &CC = Op->getOperand(2); | ||||
2199 | auto MakeLane = [&](unsigned I) { | ||||
2200 | return DAG.getNode(ISD::SELECT_CC, DL, MVT::i64, LHS[I], RHS[I], | ||||
2201 | DAG.getConstant(uint64_t(-1), DL, MVT::i64), | ||||
2202 | DAG.getConstant(uint64_t(0), DL, MVT::i64), CC); | ||||
2203 | }; | ||||
2204 | return DAG.getBuildVector(Op->getValueType(0), DL, | ||||
2205 | {MakeLane(0), MakeLane(1)}); | ||||
2206 | } | ||||
2207 | |||||
2208 | SDValue | ||||
2209 | WebAssemblyTargetLowering::LowerAccessVectorElement(SDValue Op, | ||||
2210 | SelectionDAG &DAG) const { | ||||
2211 | // Allow constant lane indices, expand variable lane indices | ||||
2212 | SDNode *IdxNode = Op.getOperand(Op.getNumOperands() - 1).getNode(); | ||||
2213 | if (isa<ConstantSDNode>(IdxNode) || IdxNode->isUndef()) | ||||
2214 | return Op; | ||||
2215 | else | ||||
2216 | // Perform default expansion | ||||
2217 | return SDValue(); | ||||
2218 | } | ||||
2219 | |||||
2220 | static SDValue unrollVectorShift(SDValue Op, SelectionDAG &DAG) { | ||||
2221 | EVT LaneT = Op.getSimpleValueType().getVectorElementType(); | ||||
2222 | // 32-bit and 64-bit unrolled shifts will have proper semantics | ||||
2223 | if (LaneT.bitsGE(MVT::i32)) | ||||
2224 | return DAG.UnrollVectorOp(Op.getNode()); | ||||
2225 | // Otherwise mask the shift value to get proper semantics from 32-bit shift | ||||
2226 | SDLoc DL(Op); | ||||
2227 | size_t NumLanes = Op.getSimpleValueType().getVectorNumElements(); | ||||
2228 | SDValue Mask = DAG.getConstant(LaneT.getSizeInBits() - 1, DL, MVT::i32); | ||||
2229 | unsigned ShiftOpcode = Op.getOpcode(); | ||||
2230 | SmallVector<SDValue, 16> ShiftedElements; | ||||
2231 | DAG.ExtractVectorElements(Op.getOperand(0), ShiftedElements, 0, 0, MVT::i32); | ||||
2232 | SmallVector<SDValue, 16> ShiftElements; | ||||
2233 | DAG.ExtractVectorElements(Op.getOperand(1), ShiftElements, 0, 0, MVT::i32); | ||||
2234 | SmallVector<SDValue, 16> UnrolledOps; | ||||
2235 | for (size_t i = 0; i < NumLanes; ++i) { | ||||
2236 | SDValue MaskedShiftValue = | ||||
2237 | DAG.getNode(ISD::AND, DL, MVT::i32, ShiftElements[i], Mask); | ||||
2238 | SDValue ShiftedValue = ShiftedElements[i]; | ||||
2239 | if (ShiftOpcode == ISD::SRA) | ||||
2240 | ShiftedValue = DAG.getNode(ISD::SIGN_EXTEND_INREG, DL, MVT::i32, | ||||
2241 | ShiftedValue, DAG.getValueType(LaneT)); | ||||
2242 | UnrolledOps.push_back( | ||||
2243 | DAG.getNode(ShiftOpcode, DL, MVT::i32, ShiftedValue, MaskedShiftValue)); | ||||
2244 | } | ||||
2245 | return DAG.getBuildVector(Op.getValueType(), DL, UnrolledOps); | ||||
2246 | } | ||||
2247 | |||||
2248 | SDValue WebAssemblyTargetLowering::LowerShift(SDValue Op, | ||||
2249 | SelectionDAG &DAG) const { | ||||
2250 | SDLoc DL(Op); | ||||
2251 | |||||
2252 | // Only manually lower vector shifts | ||||
2253 | assert(Op.getSimpleValueType().isVector())(static_cast <bool> (Op.getSimpleValueType().isVector() ) ? void (0) : __assert_fail ("Op.getSimpleValueType().isVector()" , "/build/llvm-toolchain-snapshot-14~++20211017100700+d245f2e8597b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp" , 2253, __extension__ __PRETTY_FUNCTION__)); | ||||
2254 | |||||
2255 | auto ShiftVal = DAG.getSplatValue(Op.getOperand(1)); | ||||
2256 | if (!ShiftVal) | ||||
2257 | return unrollVectorShift(Op, DAG); | ||||
2258 | |||||
2259 | // Use anyext because none of the high bits can affect the shift | ||||
2260 | ShiftVal = DAG.getAnyExtOrTrunc(ShiftVal, DL, MVT::i32); | ||||
2261 | |||||
2262 | unsigned Opcode; | ||||
2263 | switch (Op.getOpcode()) { | ||||
2264 | case ISD::SHL: | ||||
2265 | Opcode = WebAssemblyISD::VEC_SHL; | ||||
2266 | break; | ||||
2267 | case ISD::SRA: | ||||
2268 | Opcode = WebAssemblyISD::VEC_SHR_S; | ||||
2269 | break; | ||||
2270 | case ISD::SRL: | ||||
2271 | Opcode = WebAssemblyISD::VEC_SHR_U; | ||||
2272 | break; | ||||
2273 | default: | ||||
2274 | llvm_unreachable("unexpected opcode")::llvm::llvm_unreachable_internal("unexpected opcode", "/build/llvm-toolchain-snapshot-14~++20211017100700+d245f2e8597b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp" , 2274); | ||||
2275 | } | ||||
2276 | |||||
2277 | return DAG.getNode(Opcode, DL, Op.getValueType(), Op.getOperand(0), ShiftVal); | ||||
2278 | } | ||||
2279 | |||||
2280 | SDValue WebAssemblyTargetLowering::LowerFP_TO_INT_SAT(SDValue Op, | ||||
2281 | SelectionDAG &DAG) const { | ||||
2282 | SDLoc DL(Op); | ||||
2283 | EVT ResT = Op.getValueType(); | ||||
2284 | EVT SatVT = cast<VTSDNode>(Op.getOperand(1))->getVT(); | ||||
2285 | |||||
2286 | if ((ResT == MVT::i32 || ResT == MVT::i64) && | ||||
2287 | (SatVT == MVT::i32 || SatVT == MVT::i64)) | ||||
2288 | return Op; | ||||
2289 | |||||
2290 | if (ResT == MVT::v4i32 && SatVT == MVT::i32) | ||||
2291 | return Op; | ||||
2292 | |||||
2293 | return SDValue(); | ||||
2294 | } | ||||
2295 | |||||
2296 | //===----------------------------------------------------------------------===// | ||||
2297 | // Custom DAG combine hooks | ||||
2298 | //===----------------------------------------------------------------------===// | ||||
2299 | static SDValue | ||||
2300 | performVECTOR_SHUFFLECombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI) { | ||||
2301 | auto &DAG = DCI.DAG; | ||||
2302 | auto Shuffle = cast<ShuffleVectorSDNode>(N); | ||||
2303 | |||||
2304 | // Hoist vector bitcasts that don't change the number of lanes out of unary | ||||
2305 | // shuffles, where they are less likely to get in the way of other combines. | ||||
2306 | // (shuffle (vNxT1 (bitcast (vNxT0 x))), undef, mask) -> | ||||
2307 | // (vNxT1 (bitcast (vNxT0 (shuffle x, undef, mask)))) | ||||
2308 | SDValue Bitcast = N->getOperand(0); | ||||
2309 | if (Bitcast.getOpcode() != ISD::BITCAST) | ||||
2310 | return SDValue(); | ||||
2311 | if (!N->getOperand(1).isUndef()) | ||||
2312 | return SDValue(); | ||||
2313 | SDValue CastOp = Bitcast.getOperand(0); | ||||
2314 | MVT SrcType = CastOp.getSimpleValueType(); | ||||
2315 | MVT DstType = Bitcast.getSimpleValueType(); | ||||
2316 | if (!SrcType.is128BitVector() || | ||||
2317 | SrcType.getVectorNumElements() != DstType.getVectorNumElements()) | ||||
2318 | return SDValue(); | ||||
2319 | SDValue NewShuffle = DAG.getVectorShuffle( | ||||
2320 | SrcType, SDLoc(N), CastOp, DAG.getUNDEF(SrcType), Shuffle->getMask()); | ||||
2321 | return DAG.getBitcast(DstType, NewShuffle); | ||||
2322 | } | ||||
2323 | |||||
2324 | static SDValue | ||||
2325 | performVectorExtendCombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI) { | ||||
2326 | auto &DAG = DCI.DAG; | ||||
2327 | 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" , "/build/llvm-toolchain-snapshot-14~++20211017100700+d245f2e8597b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp" , 2328, __extension__ __PRETTY_FUNCTION__)) | ||||
2328 | 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" , "/build/llvm-toolchain-snapshot-14~++20211017100700+d245f2e8597b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp" , 2328, __extension__ __PRETTY_FUNCTION__)); | ||||
2329 | |||||
2330 | // Combine ({s,z}ext (extract_subvector src, i)) into a widening operation if | ||||
2331 | // possible before the extract_subvector can be expanded. | ||||
2332 | auto Extract = N->getOperand(0); | ||||
2333 | if (Extract.getOpcode() != ISD::EXTRACT_SUBVECTOR) | ||||
2334 | return SDValue(); | ||||
2335 | auto Source = Extract.getOperand(0); | ||||
2336 | auto *IndexNode = dyn_cast<ConstantSDNode>(Extract.getOperand(1)); | ||||
2337 | if (IndexNode == nullptr) | ||||
2338 | return SDValue(); | ||||
2339 | auto Index = IndexNode->getZExtValue(); | ||||
2340 | |||||
2341 | // Only v8i8, v4i16, and v2i32 extracts can be widened, and only if the | ||||
2342 | // extracted subvector is the low or high half of its source. | ||||
2343 | EVT ResVT = N->getValueType(0); | ||||
2344 | if (ResVT == MVT::v8i16) { | ||||
2345 | if (Extract.getValueType() != MVT::v8i8 || | ||||
2346 | Source.getValueType() != MVT::v16i8 || (Index != 0 && Index != 8)) | ||||
2347 | return SDValue(); | ||||
2348 | } else if (ResVT == MVT::v4i32) { | ||||
2349 | if (Extract.getValueType() != MVT::v4i16 || | ||||
2350 | Source.getValueType() != MVT::v8i16 || (Index != 0 && Index != 4)) | ||||
2351 | return SDValue(); | ||||
2352 | } else if (ResVT == MVT::v2i64) { | ||||
2353 | if (Extract.getValueType() != MVT::v2i32 || | ||||
2354 | Source.getValueType() != MVT::v4i32 || (Index != 0 && Index != 2)) | ||||
2355 | return SDValue(); | ||||
2356 | } else { | ||||
2357 | return SDValue(); | ||||
2358 | } | ||||
2359 | |||||
2360 | bool IsSext = N->getOpcode() == ISD::SIGN_EXTEND; | ||||
2361 | bool IsLow = Index == 0; | ||||
2362 | |||||
2363 | unsigned Op = IsSext ? (IsLow ? WebAssemblyISD::EXTEND_LOW_S | ||||
2364 | : WebAssemblyISD::EXTEND_HIGH_S) | ||||
2365 | : (IsLow ? WebAssemblyISD::EXTEND_LOW_U | ||||
2366 | : WebAssemblyISD::EXTEND_HIGH_U); | ||||
2367 | |||||
2368 | return DAG.getNode(Op, SDLoc(N), ResVT, Source); | ||||
2369 | } | ||||
2370 | |||||
2371 | static SDValue | ||||
2372 | performVectorTruncZeroCombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI) { | ||||
2373 | auto &DAG = DCI.DAG; | ||||
2374 | |||||
2375 | auto GetWasmConversionOp = [](unsigned Op) { | ||||
2376 | switch (Op) { | ||||
2377 | case ISD::FP_TO_SINT_SAT: | ||||
2378 | return WebAssemblyISD::TRUNC_SAT_ZERO_S; | ||||
2379 | case ISD::FP_TO_UINT_SAT: | ||||
2380 | return WebAssemblyISD::TRUNC_SAT_ZERO_U; | ||||
2381 | case ISD::FP_ROUND: | ||||
2382 | return WebAssemblyISD::DEMOTE_ZERO; | ||||
2383 | } | ||||
2384 | llvm_unreachable("unexpected op")::llvm::llvm_unreachable_internal("unexpected op", "/build/llvm-toolchain-snapshot-14~++20211017100700+d245f2e8597b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp" , 2384); | ||||
2385 | }; | ||||
2386 | |||||
2387 | auto IsZeroSplat = [](SDValue SplatVal) { | ||||
2388 | auto *Splat = dyn_cast<BuildVectorSDNode>(SplatVal.getNode()); | ||||
2389 | APInt SplatValue, SplatUndef; | ||||
2390 | unsigned SplatBitSize; | ||||
2391 | bool HasAnyUndefs; | ||||
2392 | return Splat && | ||||
2393 | Splat->isConstantSplat(SplatValue, SplatUndef, SplatBitSize, | ||||
2394 | HasAnyUndefs) && | ||||
2395 | SplatValue == 0; | ||||
2396 | }; | ||||
2397 | |||||
2398 | if (N->getOpcode() == ISD::CONCAT_VECTORS) { | ||||
2399 | // Combine this: | ||||
2400 | // | ||||
2401 | // (concat_vectors (v2i32 (fp_to_{s,u}int_sat $x, 32)), (v2i32 (splat 0))) | ||||
2402 | // | ||||
2403 | // into (i32x4.trunc_sat_f64x2_zero_{s,u} $x). | ||||
2404 | // | ||||
2405 | // Or this: | ||||
2406 | // | ||||
2407 | // (concat_vectors (v2f32 (fp_round (v2f64 $x))), (v2f32 (splat 0))) | ||||
2408 | // | ||||
2409 | // into (f32x4.demote_zero_f64x2 $x). | ||||
2410 | EVT ResVT; | ||||
2411 | EVT ExpectedConversionType; | ||||
2412 | auto Conversion = N->getOperand(0); | ||||
2413 | auto ConversionOp = Conversion.getOpcode(); | ||||
2414 | switch (ConversionOp) { | ||||
2415 | case ISD::FP_TO_SINT_SAT: | ||||
2416 | case ISD::FP_TO_UINT_SAT: | ||||
2417 | ResVT = MVT::v4i32; | ||||
2418 | ExpectedConversionType = MVT::v2i32; | ||||
2419 | break; | ||||
2420 | case ISD::FP_ROUND: | ||||
2421 | ResVT = MVT::v4f32; | ||||
2422 | ExpectedConversionType = MVT::v2f32; | ||||
2423 | break; | ||||
2424 | default: | ||||
2425 | return SDValue(); | ||||
2426 | } | ||||
2427 | |||||
2428 | if (N->getValueType(0) != ResVT) | ||||
2429 | return SDValue(); | ||||
2430 | |||||
2431 | if (Conversion.getValueType() != ExpectedConversionType) | ||||
2432 | return SDValue(); | ||||
2433 | |||||
2434 | auto Source = Conversion.getOperand(0); | ||||
2435 | if (Source.getValueType() != MVT::v2f64) | ||||
2436 | return SDValue(); | ||||
2437 | |||||
2438 | if (!IsZeroSplat(N->getOperand(1)) || | ||||
2439 | N->getOperand(1).getValueType() != ExpectedConversionType) | ||||
2440 | return SDValue(); | ||||
2441 | |||||
2442 | unsigned Op = GetWasmConversionOp(ConversionOp); | ||||
2443 | return DAG.getNode(Op, SDLoc(N), ResVT, Source); | ||||
2444 | } | ||||
2445 | |||||
2446 | // Combine this: | ||||
2447 | // | ||||
2448 | // (fp_to_{s,u}int_sat (concat_vectors $x, (v2f64 (splat 0))), 32) | ||||
2449 | // | ||||
2450 | // into (i32x4.trunc_sat_f64x2_zero_{s,u} $x). | ||||
2451 | // | ||||
2452 | // Or this: | ||||
2453 | // | ||||
2454 | // (v4f32 (fp_round (concat_vectors $x, (v2f64 (splat 0))))) | ||||
2455 | // | ||||
2456 | // into (f32x4.demote_zero_f64x2 $x). | ||||
2457 | EVT ResVT; | ||||
2458 | auto ConversionOp = N->getOpcode(); | ||||
2459 | switch (ConversionOp) { | ||||
2460 | case ISD::FP_TO_SINT_SAT: | ||||
2461 | case ISD::FP_TO_UINT_SAT: | ||||
2462 | ResVT = MVT::v4i32; | ||||
2463 | break; | ||||
2464 | case ISD::FP_ROUND: | ||||
2465 | ResVT = MVT::v4f32; | ||||
2466 | break; | ||||
2467 | default: | ||||
2468 | llvm_unreachable("unexpected op")::llvm::llvm_unreachable_internal("unexpected op", "/build/llvm-toolchain-snapshot-14~++20211017100700+d245f2e8597b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp" , 2468); | ||||
2469 | } | ||||
2470 | |||||
2471 | if (N->getValueType(0) != ResVT) | ||||
2472 | return SDValue(); | ||||
2473 | |||||
2474 | auto Concat = N->getOperand(0); | ||||
2475 | if (Concat.getValueType() != MVT::v4f64) | ||||
2476 | return SDValue(); | ||||
2477 | |||||
2478 | auto Source = Concat.getOperand(0); | ||||
2479 | if (Source.getValueType() != MVT::v2f64) | ||||
2480 | return SDValue(); | ||||
2481 | |||||
2482 | if (!IsZeroSplat(Concat.getOperand(1)) || | ||||
2483 | Concat.getOperand(1).getValueType() != MVT::v2f64) | ||||
2484 | return SDValue(); | ||||
2485 | |||||
2486 | unsigned Op = GetWasmConversionOp(ConversionOp); | ||||
2487 | return DAG.getNode(Op, SDLoc(N), ResVT, Source); | ||||
2488 | } | ||||
2489 | |||||
2490 | SDValue | ||||
2491 | WebAssemblyTargetLowering::PerformDAGCombine(SDNode *N, | ||||
2492 | DAGCombinerInfo &DCI) const { | ||||
2493 | switch (N->getOpcode()) { | ||||
2494 | default: | ||||
2495 | return SDValue(); | ||||
2496 | case ISD::VECTOR_SHUFFLE: | ||||
2497 | return performVECTOR_SHUFFLECombine(N, DCI); | ||||
2498 | case ISD::SIGN_EXTEND: | ||||
2499 | case ISD::ZERO_EXTEND: | ||||
2500 | return performVectorExtendCombine(N, DCI); | ||||
2501 | case ISD::FP_TO_SINT_SAT: | ||||
2502 | case ISD::FP_TO_UINT_SAT: | ||||
2503 | case ISD::FP_ROUND: | ||||
2504 | case ISD::CONCAT_VECTORS: | ||||
2505 | return performVectorTruncZeroCombine(N, DCI); | ||||
2506 | } | ||||
2507 | } |
1 | //===- llvm/CodeGen/SelectionDAGNodes.h - SelectionDAG Nodes ----*- C++ -*-===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | // |
9 | // This file declares the SDNode class and derived classes, which are used to |
10 | // represent the nodes and operations present in a SelectionDAG. These nodes |
11 | // and operations are machine code level operations, with some similarities to |
12 | // the GCC RTL representation. |
13 | // |
14 | // Clients should include the SelectionDAG.h file instead of this file directly. |
15 | // |
16 | //===----------------------------------------------------------------------===// |
17 | |
18 | #ifndef LLVM_CODEGEN_SELECTIONDAGNODES_H |
19 | #define LLVM_CODEGEN_SELECTIONDAGNODES_H |
20 | |
21 | #include "llvm/ADT/APFloat.h" |
22 | #include "llvm/ADT/ArrayRef.h" |
23 | #include "llvm/ADT/BitVector.h" |
24 | #include "llvm/ADT/FoldingSet.h" |
25 | #include "llvm/ADT/GraphTraits.h" |
26 | #include "llvm/ADT/SmallPtrSet.h" |
27 | #include "llvm/ADT/SmallVector.h" |
28 | #include "llvm/ADT/ilist_node.h" |
29 | #include "llvm/ADT/iterator.h" |
30 | #include "llvm/ADT/iterator_range.h" |
31 | #include "llvm/CodeGen/ISDOpcodes.h" |
32 | #include "llvm/CodeGen/MachineMemOperand.h" |
33 | #include "llvm/CodeGen/Register.h" |
34 | #include "llvm/CodeGen/ValueTypes.h" |
35 | #include "llvm/IR/Constants.h" |
36 | #include "llvm/IR/DebugLoc.h" |
37 | #include "llvm/IR/Instruction.h" |
38 | #include "llvm/IR/Instructions.h" |
39 | #include "llvm/IR/Metadata.h" |
40 | #include "llvm/IR/Operator.h" |
41 | #include "llvm/Support/AlignOf.h" |
42 | #include "llvm/Support/AtomicOrdering.h" |
43 | #include "llvm/Support/Casting.h" |
44 | #include "llvm/Support/ErrorHandling.h" |
45 | #include "llvm/Support/MachineValueType.h" |
46 | #include "llvm/Support/TypeSize.h" |
47 | #include <algorithm> |
48 | #include <cassert> |
49 | #include <climits> |
50 | #include <cstddef> |
51 | #include <cstdint> |
52 | #include <cstring> |
53 | #include <iterator> |
54 | #include <string> |
55 | #include <tuple> |
56 | |
57 | namespace llvm { |
58 | |
59 | class APInt; |
60 | class Constant; |
61 | template <typename T> struct DenseMapInfo; |
62 | class GlobalValue; |
63 | class MachineBasicBlock; |
64 | class MachineConstantPoolValue; |
65 | class MCSymbol; |
66 | class raw_ostream; |
67 | class SDNode; |
68 | class SelectionDAG; |
69 | class Type; |
70 | class Value; |
71 | |
72 | void checkForCycles(const SDNode *N, const SelectionDAG *DAG = nullptr, |
73 | bool force = false); |
74 | |
75 | /// This represents a list of ValueType's that has been intern'd by |
76 | /// a SelectionDAG. Instances of this simple value class are returned by |
77 | /// SelectionDAG::getVTList(...). |
78 | /// |
79 | struct SDVTList { |
80 | const EVT *VTs; |
81 | unsigned int NumVTs; |
82 | }; |
83 | |
84 | namespace ISD { |
85 | |
86 | /// Node predicates |
87 | |
88 | /// If N is a BUILD_VECTOR or SPLAT_VECTOR node whose elements are all the |
89 | /// same constant or undefined, return true and return the constant value in |
90 | /// \p SplatValue. |
91 | bool isConstantSplatVector(const SDNode *N, APInt &SplatValue); |
92 | |
93 | /// Return true if the specified node is a BUILD_VECTOR or SPLAT_VECTOR where |
94 | /// all of the elements are ~0 or undef. If \p BuildVectorOnly is set to |
95 | /// true, it only checks BUILD_VECTOR. |
96 | bool isConstantSplatVectorAllOnes(const SDNode *N, |
97 | bool BuildVectorOnly = false); |
98 | |
99 | /// Return true if the specified node is a BUILD_VECTOR or SPLAT_VECTOR where |
100 | /// all of the elements are 0 or undef. If \p BuildVectorOnly is set to true, it |
101 | /// only checks BUILD_VECTOR. |
102 | bool isConstantSplatVectorAllZeros(const SDNode *N, |
103 | bool BuildVectorOnly = false); |
104 | |
105 | /// Return true if the specified node is a BUILD_VECTOR where all of the |
106 | /// elements are ~0 or undef. |
107 | bool isBuildVectorAllOnes(const SDNode *N); |
108 | |
109 | /// Return true if the specified node is a BUILD_VECTOR where all of the |
110 | /// elements are 0 or undef. |
111 | bool isBuildVectorAllZeros(const SDNode *N); |
112 | |
113 | /// Return true if the specified node is a BUILD_VECTOR node of all |
114 | /// ConstantSDNode or undef. |
115 | bool isBuildVectorOfConstantSDNodes(const SDNode *N); |
116 | |
117 | /// Return true if the specified node is a BUILD_VECTOR node of all |
118 | /// ConstantFPSDNode or undef. |
119 | bool isBuildVectorOfConstantFPSDNodes(const SDNode *N); |
120 | |
121 | /// Return true if the node has at least one operand and all operands of the |
122 | /// specified node are ISD::UNDEF. |
123 | bool allOperandsUndef(const SDNode *N); |
124 | |
125 | } // end namespace ISD |
126 | |
127 | //===----------------------------------------------------------------------===// |
128 | /// Unlike LLVM values, Selection DAG nodes may return multiple |
129 | /// values as the result of a computation. Many nodes return multiple values, |
130 | /// from loads (which define a token and a return value) to ADDC (which returns |
131 | /// a result and a carry value), to calls (which may return an arbitrary number |
132 | /// of values). |
133 | /// |
134 | /// As such, each use of a SelectionDAG computation must indicate the node that |
135 | /// computes it as well as which return value to use from that node. This pair |
136 | /// of information is represented with the SDValue value type. |
137 | /// |
138 | class SDValue { |
139 | friend struct DenseMapInfo<SDValue>; |
140 | |
141 | SDNode *Node = nullptr; // The node defining the value we are using. |
142 | unsigned ResNo = 0; // Which return value of the node we are using. |
143 | |
144 | public: |
145 | SDValue() = default; |
146 | SDValue(SDNode *node, unsigned resno); |
147 | |
148 | /// get the index which selects a specific result in the SDNode |
149 | unsigned getResNo() const { return ResNo; } |
150 | |
151 | /// get the SDNode which holds the desired result |
152 | SDNode *getNode() const { return Node; } |
153 | |
154 | /// set the SDNode |
155 | void setNode(SDNode *N) { Node = N; } |
156 | |
157 | inline SDNode *operator->() const { return Node; } |
158 | |
159 | bool operator==(const SDValue &O) const { |
160 | return Node == O.Node && ResNo == O.ResNo; |
161 | } |
162 | bool operator!=(const SDValue &O) const { |
163 | return !operator==(O); |
164 | } |
165 | bool operator<(const SDValue &O) const { |
166 | return std::tie(Node, ResNo) < std::tie(O.Node, O.ResNo); |
167 | } |
168 | explicit operator bool() const { |
169 | return Node != nullptr; |
170 | } |
171 | |
172 | SDValue getValue(unsigned R) const { |
173 | return SDValue(Node, R); |
174 | } |
175 | |
176 | /// Return true if this node is an operand of N. |
177 | bool isOperandOf(const SDNode *N) const; |
178 | |
179 | /// Return the ValueType of the referenced return value. |
180 | inline EVT getValueType() const; |
181 | |
182 | /// Return the simple ValueType of the referenced return value. |
183 | MVT getSimpleValueType() const { |
184 | return getValueType().getSimpleVT(); |
185 | } |
186 | |
187 | /// Returns the size of the value in bits. |
188 | /// |
189 | /// If the value type is a scalable vector type, the scalable property will |
190 | /// be set and the runtime size will be a positive integer multiple of the |
191 | /// base size. |
192 | TypeSize getValueSizeInBits() const { |
193 | return getValueType().getSizeInBits(); |
194 | } |
195 | |
196 | uint64_t getScalarValueSizeInBits() const { |
197 | return getValueType().getScalarType().getFixedSizeInBits(); |
198 | } |
199 | |
200 | // Forwarding methods - These forward to the corresponding methods in SDNode. |
201 | inline unsigned getOpcode() const; |
202 | inline unsigned getNumOperands() const; |
203 | inline const SDValue &getOperand(unsigned i) const; |
204 | inline uint64_t getConstantOperandVal(unsigned i) const; |
205 | inline const APInt &getConstantOperandAPInt(unsigned i) const; |
206 | inline bool isTargetMemoryOpcode() const; |
207 | inline bool isTargetOpcode() const; |
208 | inline bool isMachineOpcode() const; |
209 | inline bool isUndef() const; |
210 | inline unsigned getMachineOpcode() const; |
211 | inline const DebugLoc &getDebugLoc() const; |
212 | inline void dump() const; |
213 | inline void dump(const SelectionDAG *G) const; |
214 | inline void dumpr() const; |
215 | inline void dumpr(const SelectionDAG *G) const; |
216 | |
217 | /// Return true if this operand (which must be a chain) reaches the |
218 | /// specified operand without crossing any side-effecting instructions. |
219 | /// In practice, this looks through token factors and non-volatile loads. |
220 | /// In order to remain efficient, this only |
221 | /// looks a couple of nodes in, it does not do an exhaustive search. |
222 | bool reachesChainWithoutSideEffects(SDValue Dest, |
223 | unsigned Depth = 2) const; |
224 | |
225 | /// Return true if there are no nodes using value ResNo of Node. |
226 | inline bool use_empty() const; |
227 | |
228 | /// Return true if there is exactly one node using value ResNo of Node. |
229 | inline bool hasOneUse() const; |
230 | }; |
231 | |
232 | template<> struct DenseMapInfo<SDValue> { |
233 | static inline SDValue getEmptyKey() { |
234 | SDValue V; |
235 | V.ResNo = -1U; |
236 | return V; |
237 | } |
238 | |
239 | static inline SDValue getTombstoneKey() { |
240 | SDValue V; |
241 | V.ResNo = -2U; |
242 | return V; |
243 | } |
244 | |
245 | static unsigned getHashValue(const SDValue &Val) { |
246 | return ((unsigned)((uintptr_t)Val.getNode() >> 4) ^ |
247 | (unsigned)((uintptr_t)Val.getNode() >> 9)) + Val.getResNo(); |
248 | } |
249 | |
250 | static bool isEqual(const SDValue &LHS, const SDValue &RHS) { |
251 | return LHS == RHS; |
252 | } |
253 | }; |
254 | |
255 | /// Allow casting operators to work directly on |
256 | /// SDValues as if they were SDNode*'s. |
257 | template<> struct simplify_type<SDValue> { |
258 | using SimpleType = SDNode *; |
259 | |
260 | static SimpleType getSimplifiedValue(SDValue &Val) { |
261 | return Val.getNode(); |
262 | } |
263 | }; |
264 | template<> struct simplify_type<const SDValue> { |
265 | using SimpleType = /*const*/ SDNode *; |
266 | |
267 | static SimpleType getSimplifiedValue(const SDValue &Val) { |
268 | return Val.getNode(); |
269 | } |
270 | }; |
271 | |
272 | /// Represents a use of a SDNode. This class holds an SDValue, |
273 | /// which records the SDNode being used and the result number, a |
274 | /// pointer to the SDNode using the value, and Next and Prev pointers, |
275 | /// which link together all the uses of an SDNode. |
276 | /// |
277 | class SDUse { |
278 | /// Val - The value being used. |
279 | SDValue Val; |
280 | /// User - The user of this value. |
281 | SDNode *User = nullptr; |
282 | /// Prev, Next - Pointers to the uses list of the SDNode referred by |
283 | /// this operand. |
284 | SDUse **Prev = nullptr; |
285 | SDUse *Next = nullptr; |
286 | |
287 | public: |
288 | SDUse() = default; |
289 | SDUse(const SDUse &U) = delete; |
290 | SDUse &operator=(const SDUse &) = delete; |
291 | |
292 | /// Normally SDUse will just implicitly convert to an SDValue that it holds. |
293 | operator const SDValue&() const { return Val; } |
294 | |
295 | /// If implicit conversion to SDValue doesn't work, the get() method returns |
296 | /// the SDValue. |
297 | const SDValue &get() const { return Val; } |
298 | |
299 | /// This returns the SDNode that contains this Use. |
300 | SDNode *getUser() { return User; } |
301 | |
302 | /// Get the next SDUse in the use list. |
303 | SDUse *getNext() const { return Next; } |
304 | |
305 | /// Convenience function for get().getNode(). |
306 | SDNode *getNode() const { return Val.getNode(); } |
307 | /// Convenience function for get().getResNo(). |
308 | unsigned getResNo() const { return Val.getResNo(); } |
309 | /// Convenience function for get().getValueType(). |
310 | EVT getValueType() const { return Val.getValueType(); } |
311 | |
312 | /// Convenience function for get().operator== |
313 | bool operator==(const SDValue &V) const { |
314 | return Val == V; |
315 | } |
316 | |
317 | /// Convenience function for get().operator!= |
318 | bool operator!=(const SDValue &V) const { |
319 | return Val != V; |
320 | } |
321 | |
322 | /// Convenience function for get().operator< |
323 | bool operator<(const SDValue &V) const { |
324 | return Val < V; |
325 | } |
326 | |
327 | private: |
328 | friend class SelectionDAG; |
329 | friend class SDNode; |
330 | // TODO: unfriend HandleSDNode once we fix its operand handling. |
331 | friend class HandleSDNode; |
332 | |
333 | void setUser(SDNode *p) { User = p; } |
334 | |
335 | /// Remove this use from its existing use list, assign it the |
336 | /// given value, and add it to the new value's node's use list. |
337 | inline void set(const SDValue &V); |
338 | /// Like set, but only supports initializing a newly-allocated |
339 | /// SDUse with a non-null value. |
340 | inline void setInitial(const SDValue &V); |
341 | /// Like set, but only sets the Node portion of the value, |
342 | /// leaving the ResNo portion unmodified. |
343 | inline void setNode(SDNode *N); |
344 | |
345 | void addToList(SDUse **List) { |
346 | Next = *List; |
347 | if (Next) Next->Prev = &Next; |
348 | Prev = List; |
349 | *List = this; |
350 | } |
351 | |
352 | void removeFromList() { |
353 | *Prev = Next; |
354 | if (Next) Next->Prev = Prev; |
355 | } |
356 | }; |
357 | |
358 | /// simplify_type specializations - Allow casting operators to work directly on |
359 | /// SDValues as if they were SDNode*'s. |
360 | template<> struct simplify_type<SDUse> { |
361 | using SimpleType = SDNode *; |
362 | |
363 | static SimpleType getSimplifiedValue(SDUse &Val) { |
364 | return Val.getNode(); |
365 | } |
366 | }; |
367 | |
368 | /// These are IR-level optimization flags that may be propagated to SDNodes. |
369 | /// TODO: This data structure should be shared by the IR optimizer and the |
370 | /// the backend. |
371 | struct SDNodeFlags { |
372 | private: |
373 | bool NoUnsignedWrap : 1; |
374 | bool NoSignedWrap : 1; |
375 | bool Exact : 1; |
376 | bool NoNaNs : 1; |
377 | bool NoInfs : 1; |
378 | bool NoSignedZeros : 1; |
379 | bool AllowReciprocal : 1; |
380 | bool AllowContract : 1; |
381 | bool ApproximateFuncs : 1; |
382 | bool AllowReassociation : 1; |
383 | |
384 | // We assume instructions do not raise floating-point exceptions by default, |
385 | // and only those marked explicitly may do so. We could choose to represent |
386 | // this via a positive "FPExcept" flags like on the MI level, but having a |
387 | // negative "NoFPExcept" flag here (that defaults to true) makes the flag |
388 | // intersection logic more straightforward. |
389 | bool NoFPExcept : 1; |
390 | |
391 | public: |
392 | /// Default constructor turns off all optimization flags. |
393 | SDNodeFlags() |
394 | : NoUnsignedWrap(false), NoSignedWrap(false), Exact(false), NoNaNs(false), |
395 | NoInfs(false), NoSignedZeros(false), AllowReciprocal(false), |
396 | AllowContract(false), ApproximateFuncs(false), |
397 | AllowReassociation(false), NoFPExcept(false) {} |
398 | |
399 | /// Propagate the fast-math-flags from an IR FPMathOperator. |
400 | void copyFMF(const FPMathOperator &FPMO) { |
401 | setNoNaNs(FPMO.hasNoNaNs()); |
402 | setNoInfs(FPMO.hasNoInfs()); |
403 | setNoSignedZeros(FPMO.hasNoSignedZeros()); |
404 | setAllowReciprocal(FPMO.hasAllowReciprocal()); |
405 | setAllowContract(FPMO.hasAllowContract()); |
406 | setApproximateFuncs(FPMO.hasApproxFunc()); |
407 | setAllowReassociation(FPMO.hasAllowReassoc()); |
408 | } |
409 | |
410 | // These are mutators for each flag. |
411 | void setNoUnsignedWrap(bool b) { NoUnsignedWrap = b; } |
412 | void setNoSignedWrap(bool b) { NoSignedWrap = b; } |
413 | void setExact(bool b) { Exact = b; } |
414 | void setNoNaNs(bool b) { NoNaNs = b; } |
415 | void setNoInfs(bool b) { NoInfs = b; } |
416 | void setNoSignedZeros(bool b) { NoSignedZeros = b; } |
417 | void setAllowReciprocal(bool b) { AllowReciprocal = b; } |
418 | void setAllowContract(bool b) { AllowContract = b; } |
419 | void setApproximateFuncs(bool b) { ApproximateFuncs = b; } |
420 | void setAllowReassociation(bool b) { AllowReassociation = b; } |
421 | void setNoFPExcept(bool b) { NoFPExcept = b; } |
422 | |
423 | // These are accessors for each flag. |
424 | bool hasNoUnsignedWrap() const { return NoUnsignedWrap; } |
425 | bool hasNoSignedWrap() const { return NoSignedWrap; } |
426 | bool hasExact() const { return Exact; } |
427 | bool hasNoNaNs() const { return NoNaNs; } |
428 | bool hasNoInfs() const { return NoInfs; } |
429 | bool hasNoSignedZeros() const { return NoSignedZeros; } |
430 | bool hasAllowReciprocal() const { return AllowReciprocal; } |
431 | bool hasAllowContract() const { return AllowContract; } |
432 | bool hasApproximateFuncs() const { return ApproximateFuncs; } |
433 | bool hasAllowReassociation() const { return AllowReassociation; } |
434 | bool hasNoFPExcept() const { return NoFPExcept; } |
435 | |
436 | /// Clear any flags in this flag set that aren't also set in Flags. All |
437 | /// flags will be cleared if Flags are undefined. |
438 | void intersectWith(const SDNodeFlags Flags) { |
439 | NoUnsignedWrap &= Flags.NoUnsignedWrap; |
440 | NoSignedWrap &= Flags.NoSignedWrap; |
441 | Exact &= Flags.Exact; |
442 | NoNaNs &= Flags.NoNaNs; |
443 | NoInfs &= Flags.NoInfs; |
444 | NoSignedZeros &= Flags.NoSignedZeros; |
445 | AllowReciprocal &= Flags.AllowReciprocal; |
446 | AllowContract &= Flags.AllowContract; |
447 | ApproximateFuncs &= Flags.ApproximateFuncs; |
448 | AllowReassociation &= Flags.AllowReassociation; |
449 | NoFPExcept &= Flags.NoFPExcept; |
450 | } |
451 | }; |
452 | |
453 | /// Represents one node in the SelectionDAG. |
454 | /// |
455 | class SDNode : public FoldingSetNode, public ilist_node<SDNode> { |
456 | private: |
457 | /// The operation that this node performs. |
458 | int16_t NodeType; |
459 | |
460 | protected: |
461 | // We define a set of mini-helper classes to help us interpret the bits in our |
462 | // SubclassData. These are designed to fit within a uint16_t so they pack |
463 | // with NodeType. |
464 | |
465 | #if defined(_AIX) && (!defined(__GNUC__4) || defined(__clang__1)) |
466 | // Except for GCC; by default, AIX compilers store bit-fields in 4-byte words |
467 | // and give the `pack` pragma push semantics. |
468 | #define BEGIN_TWO_BYTE_PACK() _Pragma("pack(2)")pack(2) |
469 | #define END_TWO_BYTE_PACK() _Pragma("pack(pop)")pack(pop) |
470 | #else |
471 | #define BEGIN_TWO_BYTE_PACK() |
472 | #define END_TWO_BYTE_PACK() |
473 | #endif |
474 | |
475 | BEGIN_TWO_BYTE_PACK() |
476 | class SDNodeBitfields { |
477 | friend class SDNode; |
478 | friend class MemIntrinsicSDNode; |
479 | friend class MemSDNode; |
480 | friend class SelectionDAG; |
481 | |
482 | uint16_t HasDebugValue : 1; |
483 | uint16_t IsMemIntrinsic : 1; |
484 | uint16_t IsDivergent : 1; |
485 | }; |
486 | enum { NumSDNodeBits = 3 }; |
487 | |
488 | class ConstantSDNodeBitfields { |
489 | friend class ConstantSDNode; |
490 | |
491 | uint16_t : NumSDNodeBits; |
492 | |
493 | uint16_t IsOpaque : 1; |
494 | }; |
495 | |
496 | class MemSDNodeBitfields { |
497 | friend class MemSDNode; |
498 | friend class MemIntrinsicSDNode; |
499 | friend class AtomicSDNode; |
500 | |
501 | uint16_t : NumSDNodeBits; |
502 | |
503 | uint16_t IsVolatile : 1; |
504 | uint16_t IsNonTemporal : 1; |
505 | uint16_t IsDereferenceable : 1; |
506 | uint16_t IsInvariant : 1; |
507 | }; |
508 | enum { NumMemSDNodeBits = NumSDNodeBits + 4 }; |
509 | |
510 | class LSBaseSDNodeBitfields { |
511 | friend class LSBaseSDNode; |
512 | friend class VPLoadStoreSDNode; |
513 | friend class MaskedLoadStoreSDNode; |
514 | friend class MaskedGatherScatterSDNode; |
515 | friend class VPGatherScatterSDNode; |
516 | |
517 | uint16_t : NumMemSDNodeBits; |
518 | |
519 | // This storage is shared between disparate class hierarchies to hold an |
520 | // enumeration specific to the class hierarchy in use. |
521 | // LSBaseSDNode => enum ISD::MemIndexedMode |
522 | // VPLoadStoreBaseSDNode => enum ISD::MemIndexedMode |
523 | // MaskedLoadStoreBaseSDNode => enum ISD::MemIndexedMode |
524 | // VPGatherScatterSDNode => enum ISD::MemIndexType |
525 | // MaskedGatherScatterSDNode => enum ISD::MemIndexType |
526 | uint16_t AddressingMode : 3; |
527 | }; |
528 | enum { NumLSBaseSDNodeBits = NumMemSDNodeBits + 3 }; |
529 | |
530 | class LoadSDNodeBitfields { |
531 | friend class LoadSDNode; |
532 | friend class VPLoadSDNode; |
533 | friend class MaskedLoadSDNode; |
534 | friend class MaskedGatherSDNode; |
535 | friend class VPGatherSDNode; |
536 | |
537 | uint16_t : NumLSBaseSDNodeBits; |
538 | |
539 | uint16_t ExtTy : 2; // enum ISD::LoadExtType |
540 | uint16_t IsExpanding : 1; |
541 | }; |
542 | |
543 | class StoreSDNodeBitfields { |
544 | friend class StoreSDNode; |
545 | friend class VPStoreSDNode; |
546 | friend class MaskedStoreSDNode; |
547 | friend class MaskedScatterSDNode; |
548 | friend class VPScatterSDNode; |
549 | |
550 | uint16_t : NumLSBaseSDNodeBits; |
551 | |
552 | uint16_t IsTruncating : 1; |
553 | uint16_t IsCompressing : 1; |
554 | }; |
555 | |
556 | union { |
557 | char RawSDNodeBits[sizeof(uint16_t)]; |
558 | SDNodeBitfields SDNodeBits; |
559 | ConstantSDNodeBitfields ConstantSDNodeBits; |
560 | MemSDNodeBitfields MemSDNodeBits; |
561 | LSBaseSDNodeBitfields LSBaseSDNodeBits; |
562 | LoadSDNodeBitfields LoadSDNodeBits; |
563 | StoreSDNodeBitfields StoreSDNodeBits; |
564 | }; |
565 | END_TWO_BYTE_PACK() |
566 | #undef BEGIN_TWO_BYTE_PACK |
567 | #undef END_TWO_BYTE_PACK |
568 | |
569 | // RawSDNodeBits must cover the entirety of the union. This means that all of |
570 | // the union's members must have size <= RawSDNodeBits. We write the RHS as |
571 | // "2" instead of sizeof(RawSDNodeBits) because MSVC can't handle the latter. |
572 | static_assert(sizeof(SDNodeBitfields) <= 2, "field too wide"); |
573 | static_assert(sizeof(ConstantSDNodeBitfields) <= 2, "field too wide"); |
574 | static_assert(sizeof(MemSDNodeBitfields) <= 2, "field too wide"); |
575 | static_assert(sizeof(LSBaseSDNodeBitfields) <= 2, "field too wide"); |
576 | static_assert(sizeof(LoadSDNodeBitfields) <= 2, "field too wide"); |
577 | static_assert(sizeof(StoreSDNodeBitfields) <= 2, "field too wide"); |
578 | |
579 | private: |
580 | friend class SelectionDAG; |
581 | // TODO: unfriend HandleSDNode once we fix its operand handling. |
582 | friend class HandleSDNode; |
583 | |
584 | /// Unique id per SDNode in the DAG. |
585 | int NodeId = -1; |
586 | |
587 | /// The values that are used by this operation. |
588 | SDUse *OperandList = nullptr; |
589 | |
590 | /// The types of the values this node defines. SDNode's may |
591 | /// define multiple values simultaneously. |
592 | const EVT *ValueList; |
593 | |
594 | /// List of uses for this SDNode. |
595 | SDUse *UseList = nullptr; |
596 | |
597 | /// The number of entries in the Operand/Value list. |
598 | unsigned short NumOperands = 0; |
599 | unsigned short NumValues; |
600 | |
601 | // The ordering of the SDNodes. It roughly corresponds to the ordering of the |
602 | // original LLVM instructions. |
603 | // This is used for turning off scheduling, because we'll forgo |
604 | // the normal scheduling algorithms and output the instructions according to |
605 | // this ordering. |
606 | unsigned IROrder; |
607 | |
608 | /// Source line information. |
609 | DebugLoc debugLoc; |
610 | |
611 | /// Return a pointer to the specified value type. |
612 | static const EVT *getValueTypeList(EVT VT); |
613 | |
614 | SDNodeFlags Flags; |
615 | |
616 | public: |
617 | /// Unique and persistent id per SDNode in the DAG. |
618 | /// Used for debug printing. |
619 | uint16_t PersistentId; |
620 | |
621 | //===--------------------------------------------------------------------===// |
622 | // Accessors |
623 | // |
624 | |
625 | /// Return the SelectionDAG opcode value for this node. For |
626 | /// pre-isel nodes (those for which isMachineOpcode returns false), these |
627 | /// are the opcode values in the ISD and <target>ISD namespaces. For |
628 | /// post-isel opcodes, see getMachineOpcode. |
629 | unsigned getOpcode() const { return (unsigned short)NodeType; } |
630 | |
631 | /// Test if this node has a target-specific opcode (in the |
632 | /// \<target\>ISD namespace). |
633 | bool isTargetOpcode() const { return NodeType >= ISD::BUILTIN_OP_END; } |
634 | |
635 | /// Test if this node has a target-specific opcode that may raise |
636 | /// FP exceptions (in the \<target\>ISD namespace and greater than |
637 | /// FIRST_TARGET_STRICTFP_OPCODE). Note that all target memory |
638 | /// opcode are currently automatically considered to possibly raise |
639 | /// FP exceptions as well. |
640 | bool isTargetStrictFPOpcode() const { |
641 | return NodeType >= ISD::FIRST_TARGET_STRICTFP_OPCODE; |
642 | } |
643 | |
644 | /// Test if this node has a target-specific |
645 | /// memory-referencing opcode (in the \<target\>ISD namespace and |
646 | /// greater than FIRST_TARGET_MEMORY_OPCODE). |
647 | bool isTargetMemoryOpcode() const { |
648 | return NodeType >= ISD::FIRST_TARGET_MEMORY_OPCODE; |
649 | } |
650 | |
651 | /// Return true if the type of the node type undefined. |
652 | bool isUndef() const { return NodeType == ISD::UNDEF; } |
653 | |
654 | /// Test if this node is a memory intrinsic (with valid pointer information). |
655 | /// INTRINSIC_W_CHAIN and INTRINSIC_VOID nodes are sometimes created for |
656 | /// non-memory intrinsics (with chains) that are not really instances of |
657 | /// MemSDNode. For such nodes, we need some extra state to determine the |
658 | /// proper classof relationship. |
659 | bool isMemIntrinsic() const { |
660 | return (NodeType == ISD::INTRINSIC_W_CHAIN || |
661 | NodeType == ISD::INTRINSIC_VOID) && |
662 | SDNodeBits.IsMemIntrinsic; |
663 | } |
664 | |
665 | /// Test if this node is a strict floating point pseudo-op. |
666 | bool isStrictFPOpcode() { |
667 | switch (NodeType) { |
668 | default: |
669 | return false; |
670 | case ISD::STRICT_FP16_TO_FP: |
671 | case ISD::STRICT_FP_TO_FP16: |
672 | #define DAG_INSTRUCTION(NAME, NARG, ROUND_MODE, INTRINSIC, DAGN) \ |
673 | case ISD::STRICT_##DAGN: |
674 | #include "llvm/IR/ConstrainedOps.def" |
675 | return true; |
676 | } |
677 | } |
678 | |
679 | /// Test if this node has a post-isel opcode, directly |
680 | /// corresponding to a MachineInstr opcode. |
681 | bool isMachineOpcode() const { return NodeType < 0; } |
682 | |
683 | /// This may only be called if isMachineOpcode returns |
684 | /// true. It returns the MachineInstr opcode value that the node's opcode |
685 | /// corresponds to. |
686 | unsigned getMachineOpcode() const { |
687 | assert(isMachineOpcode() && "Not a MachineInstr opcode!")(static_cast <bool> (isMachineOpcode() && "Not a MachineInstr opcode!" ) ? void (0) : __assert_fail ("isMachineOpcode() && \"Not a MachineInstr opcode!\"" , "/build/llvm-toolchain-snapshot-14~++20211017100700+d245f2e8597b/llvm/include/llvm/CodeGen/SelectionDAGNodes.h" , 687, __extension__ __PRETTY_FUNCTION__)); |
688 | return ~NodeType; |
689 | } |
690 | |
691 | bool getHasDebugValue() const { return SDNodeBits.HasDebugValue; } |
692 | void setHasDebugValue(bool b) { SDNodeBits.HasDebugValue = b; } |
693 | |
694 | bool isDivergent() const { return SDNodeBits.IsDivergent; } |
695 | |
696 | /// Return true if there are no uses of this node. |
697 | bool use_empty() const { return UseList == nullptr; } |
698 | |
699 | /// Return true if there is exactly one use of this node. |
700 | bool hasOneUse() const { return hasSingleElement(uses()); } |
701 | |
702 | /// Return the number of uses of this node. This method takes |
703 | /// time proportional to the number of uses. |
704 | size_t use_size() const { return std::distance(use_begin(), use_end()); } |
705 | |
706 | /// Return the unique node id. |
707 | int getNodeId() const { return NodeId; } |
708 | |
709 | /// Set unique node id. |
710 | void setNodeId(int Id) { NodeId = Id; } |
711 | |
712 | /// Return the node ordering. |
713 | unsigned getIROrder() const { return IROrder; } |
714 | |
715 | /// Set the node ordering. |
716 | void setIROrder(unsigned Order) { IROrder = Order; } |
717 | |
718 | /// Return the source location info. |
719 | const DebugLoc &getDebugLoc() const { return debugLoc; } |
720 | |
721 | /// Set source location info. Try to avoid this, putting |
722 | /// it in the constructor is preferable. |
723 | void setDebugLoc(DebugLoc dl) { debugLoc = std::move(dl); } |
724 | |
725 | /// This class provides iterator support for SDUse |
726 | /// operands that use a specific SDNode. |
727 | class use_iterator { |
728 | friend class SDNode; |
729 | |
730 | SDUse *Op = nullptr; |
731 | |
732 | explicit use_iterator(SDUse *op) : Op(op) {} |
733 | |
734 | public: |
735 | using iterator_category = std::forward_iterator_tag; |
736 | using value_type = SDUse; |
737 | using difference_type = std::ptrdiff_t; |
738 | using pointer = value_type *; |
739 | using reference = value_type &; |
740 | |
741 | use_iterator() = default; |
742 | use_iterator(const use_iterator &I) : Op(I.Op) {} |
743 | |
744 | bool operator==(const use_iterator &x) const { |
745 | return Op == x.Op; |
746 | } |
747 | bool operator!=(const use_iterator &x) const { |
748 | return !operator==(x); |
749 | } |
750 | |
751 | /// Return true if this iterator is at the end of uses list. |
752 | bool atEnd() const { return Op == nullptr; } |
753 | |
754 | // Iterator traversal: forward iteration only. |
755 | use_iterator &operator++() { // Preincrement |
756 | assert(Op && "Cannot increment end iterator!")(static_cast <bool> (Op && "Cannot increment end iterator!" ) ? void (0) : __assert_fail ("Op && \"Cannot increment end iterator!\"" , "/build/llvm-toolchain-snapshot-14~++20211017100700+d245f2e8597b/llvm/include/llvm/CodeGen/SelectionDAGNodes.h" , 756, __extension__ __PRETTY_FUNCTION__)); |
757 | Op = Op->getNext(); |
758 | return *this; |
759 | } |
760 | |
761 | use_iterator operator++(int) { // Postincrement |
762 | use_iterator tmp = *this; ++*this; return tmp; |
763 | } |
764 | |
765 | /// Retrieve a pointer to the current user node. |
766 | SDNode *operator*() const { |
767 | assert(Op && "Cannot dereference end iterator!")(static_cast <bool> (Op && "Cannot dereference end iterator!" ) ? void (0) : __assert_fail ("Op && \"Cannot dereference end iterator!\"" , "/build/llvm-toolchain-snapshot-14~++20211017100700+d245f2e8597b/llvm/include/llvm/CodeGen/SelectionDAGNodes.h" , 767, __extension__ __PRETTY_FUNCTION__)); |
768 | return Op->getUser(); |
769 | } |
770 | |
771 | SDNode *operator->() const { return operator*(); } |
772 | |
773 | SDUse &getUse() const { return *Op; } |
774 | |
775 | /// Retrieve the operand # of this use in its user. |
776 | unsigned getOperandNo() const { |
777 | assert(Op && "Cannot dereference end iterator!")(static_cast <bool> (Op && "Cannot dereference end iterator!" ) ? void (0) : __assert_fail ("Op && \"Cannot dereference end iterator!\"" , "/build/llvm-toolchain-snapshot-14~++20211017100700+d245f2e8597b/llvm/include/llvm/CodeGen/SelectionDAGNodes.h" , 777, __extension__ __PRETTY_FUNCTION__)); |
778 | return (unsigned)(Op - Op->getUser()->OperandList); |
779 | } |
780 | }; |
781 | |
782 | /// Provide iteration support to walk over all uses of an SDNode. |
783 | use_iterator use_begin() const { |
784 | return use_iterator(UseList); |
785 | } |
786 | |
787 | static use_iterator use_end() { return use_iterator(nullptr); } |
788 | |
789 | inline iterator_range<use_iterator> uses() { |
790 | return make_range(use_begin(), use_end()); |
791 | } |
792 | inline iterator_range<use_iterator> uses() const { |
793 | return make_range(use_begin(), use_end()); |
794 | } |
795 | |
796 | /// Return true if there are exactly NUSES uses of the indicated value. |
797 | /// This method ignores uses of other values defined by this operation. |
798 | bool hasNUsesOfValue(unsigned NUses, unsigned Value) const; |
799 | |
800 | /// Return true if there are any use of the indicated value. |
801 | /// This method ignores uses of other values defined by this operation. |
802 | bool hasAnyUseOfValue(unsigned Value) const; |
803 | |
804 | /// Return true if this node is the only use of N. |
805 | bool isOnlyUserOf(const SDNode *N) const; |
806 | |
807 | /// Return true if this node is an operand of N. |
808 | bool isOperandOf(const SDNode *N) const; |
809 | |
810 | /// Return true if this node is a predecessor of N. |
811 | /// NOTE: Implemented on top of hasPredecessor and every bit as |
812 | /// expensive. Use carefully. |
813 | bool isPredecessorOf(const SDNode *N) const { |
814 | return N->hasPredecessor(this); |
815 | } |
816 | |
817 | /// Return true if N is a predecessor of this node. |
818 | /// N is either an operand of this node, or can be reached by recursively |
819 | /// traversing up the operands. |
820 | /// NOTE: This is an expensive method. Use it carefully. |
821 | bool hasPredecessor(const SDNode *N) const; |
822 | |
823 | /// Returns true if N is a predecessor of any node in Worklist. This |
824 | /// helper keeps Visited and Worklist sets externally to allow unions |
825 | /// searches to be performed in parallel, caching of results across |
826 | /// queries and incremental addition to Worklist. Stops early if N is |
827 | /// found but will resume. Remember to clear Visited and Worklists |
828 | /// if DAG changes. MaxSteps gives a maximum number of nodes to visit before |
829 | /// giving up. The TopologicalPrune flag signals that positive NodeIds are |
830 | /// topologically ordered (Operands have strictly smaller node id) and search |
831 | /// can be pruned leveraging this. |
832 | static bool hasPredecessorHelper(const SDNode *N, |
833 | SmallPtrSetImpl<const SDNode *> &Visited, |
834 | SmallVectorImpl<const SDNode *> &Worklist, |
835 | unsigned int MaxSteps = 0, |
836 | bool TopologicalPrune = false) { |
837 | SmallVector<const SDNode *, 8> DeferredNodes; |
838 | if (Visited.count(N)) |
839 | return true; |
840 | |
841 | // Node Id's are assigned in three places: As a topological |
842 | // ordering (> 0), during legalization (results in values set to |
843 | // 0), new nodes (set to -1). If N has a topolgical id then we |
844 | // know that all nodes with ids smaller than it cannot be |
845 | // successors and we need not check them. Filter out all node |
846 | // that can't be matches. We add them to the worklist before exit |
847 | // in case of multiple calls. Note that during selection the topological id |
848 | // may be violated if a node's predecessor is selected before it. We mark |
849 | // this at selection negating the id of unselected successors and |
850 | // restricting topological pruning to positive ids. |
851 | |
852 | int NId = N->getNodeId(); |
853 | // If we Invalidated the Id, reconstruct original NId. |
854 | if (NId < -1) |
855 | NId = -(NId + 1); |
856 | |
857 | bool Found = false; |
858 | while (!Worklist.empty()) { |
859 | const SDNode *M = Worklist.pop_back_val(); |
860 | int MId = M->getNodeId(); |
861 | if (TopologicalPrune && M->getOpcode() != ISD::TokenFactor && (NId > 0) && |
862 | (MId > 0) && (MId < NId)) { |
863 | DeferredNodes.push_back(M); |
864 | continue; |
865 | } |
866 | for (const SDValue &OpV : M->op_values()) { |
867 | SDNode *Op = OpV.getNode(); |
868 | if (Visited.insert(Op).second) |
869 | Worklist.push_back(Op); |
870 | if (Op == N) |
871 | Found = true; |
872 | } |
873 | if (Found) |
874 | break; |
875 | if (MaxSteps != 0 && Visited.size() >= MaxSteps) |
876 | break; |
877 | } |
878 | // Push deferred nodes back on worklist. |
879 | Worklist.append(DeferredNodes.begin(), DeferredNodes.end()); |
880 | // If we bailed early, conservatively return found. |
881 | if (MaxSteps != 0 && Visited.size() >= MaxSteps) |
882 | return true; |
883 | return Found; |
884 | } |
885 | |
886 | /// Return true if all the users of N are contained in Nodes. |
887 | /// NOTE: Requires at least one match, but doesn't require them all. |
888 | static bool areOnlyUsersOf(ArrayRef<const SDNode *> Nodes, const SDNode *N); |
889 | |
890 | /// Return the number of values used by this operation. |
891 | unsigned getNumOperands() const { return NumOperands; } |
892 | |
893 | /// Return the maximum number of operands that a SDNode can hold. |
894 | static constexpr size_t getMaxNumOperands() { |
895 | return std::numeric_limits<decltype(SDNode::NumOperands)>::max(); |
896 | } |
897 | |
898 | /// Helper method returns the integer value of a ConstantSDNode operand. |
899 | inline uint64_t getConstantOperandVal(unsigned Num) const; |
900 | |
901 | /// Helper method returns the APInt of a ConstantSDNode operand. |
902 | inline const APInt &getConstantOperandAPInt(unsigned Num) const; |
903 | |
904 | const SDValue &getOperand(unsigned Num) const { |
905 | assert(Num < NumOperands && "Invalid child # of SDNode!")(static_cast <bool> (Num < NumOperands && "Invalid child # of SDNode!" ) ? void (0) : __assert_fail ("Num < NumOperands && \"Invalid child # of SDNode!\"" , "/build/llvm-toolchain-snapshot-14~++20211017100700+d245f2e8597b/llvm/include/llvm/CodeGen/SelectionDAGNodes.h" , 905, __extension__ __PRETTY_FUNCTION__)); |
906 | return OperandList[Num]; |
907 | } |
908 | |
909 | using op_iterator = SDUse *; |
910 | |
911 | op_iterator op_begin() const { return OperandList; } |
912 | op_iterator op_end() const { return OperandList+NumOperands; } |
913 | ArrayRef<SDUse> ops() const { return makeArrayRef(op_begin(), op_end()); } |
914 | |
915 | /// Iterator for directly iterating over the operand SDValue's. |
916 | struct value_op_iterator |
917 | : iterator_adaptor_base<value_op_iterator, op_iterator, |
918 | std::random_access_iterator_tag, SDValue, |
919 | ptrdiff_t, value_op_iterator *, |
920 | value_op_iterator *> { |
921 | explicit value_op_iterator(SDUse *U = nullptr) |
922 | : iterator_adaptor_base(U) {} |
923 | |
924 | const SDValue &operator*() const { return I->get(); } |
925 | }; |
926 | |
927 | iterator_range<value_op_iterator> op_values() const { |
928 | return make_range(value_op_iterator(op_begin()), |
929 | value_op_iterator(op_end())); |
930 | } |
931 | |
932 | SDVTList getVTList() const { |
933 | SDVTList X = { ValueList, NumValues }; |
934 | return X; |
935 | } |
936 | |
937 | /// If this node has a glue operand, return the node |
938 | /// to which the glue operand points. Otherwise return NULL. |
939 | SDNode *getGluedNode() const { |
940 | if (getNumOperands() != 0 && |
941 | getOperand(getNumOperands()-1).getValueType() == MVT::Glue) |
942 | return getOperand(getNumOperands()-1).getNode(); |
943 | return nullptr; |
944 | } |
945 | |
946 | /// If this node has a glue value with a user, return |
947 | /// the user (there is at most one). Otherwise return NULL. |
948 | SDNode *getGluedUser() const { |
949 | for (use_iterator UI = use_begin(), UE = use_end(); UI != UE; ++UI) |
950 | if (UI.getUse().get().getValueType() == MVT::Glue) |
951 | return *UI; |
952 | return nullptr; |
953 | } |
954 | |
955 | SDNodeFlags getFlags() const { return Flags; } |
956 | void setFlags(SDNodeFlags NewFlags) { Flags = NewFlags; } |
957 | |
958 | /// Clear any flags in this node that aren't also set in Flags. |
959 | /// If Flags is not in a defined state then this has no effect. |
960 | void intersectFlagsWith(const SDNodeFlags Flags); |
961 | |
962 | /// Return the number of values defined/returned by this operator. |
963 | unsigned getNumValues() const { return NumValues; } |
964 | |
965 | /// Return the type of a specified result. |
966 | EVT getValueType(unsigned ResNo) const { |
967 | assert(ResNo < NumValues && "Illegal result number!")(static_cast <bool> (ResNo < NumValues && "Illegal result number!" ) ? void (0) : __assert_fail ("ResNo < NumValues && \"Illegal result number!\"" , "/build/llvm-toolchain-snapshot-14~++20211017100700+d245f2e8597b/llvm/include/llvm/CodeGen/SelectionDAGNodes.h" , 967, __extension__ __PRETTY_FUNCTION__)); |
968 | return ValueList[ResNo]; |
969 | } |
970 | |
971 | /// Return the type of a specified result as a simple type. |
972 | MVT getSimpleValueType(unsigned ResNo) const { |
973 | return getValueType(ResNo).getSimpleVT(); |
974 | } |
975 | |
976 | /// Returns MVT::getSizeInBits(getValueType(ResNo)). |
977 | /// |
978 | /// If the value type is a scalable vector type, the scalable property will |
979 | /// be set and the runtime size will be a positive integer multiple of the |
980 | /// base size. |
981 | TypeSize getValueSizeInBits(unsigned ResNo) const { |
982 | return getValueType(ResNo).getSizeInBits(); |
983 | } |
984 | |
985 | using value_iterator = const EVT *; |
986 | |
987 | value_iterator value_begin() const { return ValueList; } |
988 | value_iterator value_end() const { return ValueList+NumValues; } |
989 | iterator_range<value_iterator> values() const { |
990 | return llvm::make_range(value_begin(), value_end()); |
991 | } |
992 | |
993 | /// Return the opcode of this operation for printing. |
994 | std::string getOperationName(const SelectionDAG *G = nullptr) const; |
995 | static const char* getIndexedModeName(ISD::MemIndexedMode AM); |
996 | void print_types(raw_ostream &OS, const SelectionDAG *G) const; |
997 | void print_details(raw_ostream &OS, const SelectionDAG *G) const; |
998 | void print(raw_ostream &OS, const SelectionDAG *G = nullptr) const; |
999 | void printr(raw_ostream &OS, const SelectionDAG *G = nullptr) const; |
1000 | |
1001 | /// Print a SelectionDAG node and all children down to |
1002 | /// the leaves. The given SelectionDAG allows target-specific nodes |
1003 | /// to be printed in human-readable form. Unlike printr, this will |
1004 | /// print the whole DAG, including children that appear multiple |
1005 | /// times. |
1006 | /// |
1007 | void printrFull(raw_ostream &O, const SelectionDAG *G = nullptr) const; |
1008 | |
1009 | /// Print a SelectionDAG node and children up to |
1010 | /// depth "depth." The given SelectionDAG allows target-specific |
1011 | /// nodes to be printed in human-readable form. Unlike printr, this |
1012 | /// will print children that appear multiple times wherever they are |
1013 | /// used. |
1014 | /// |
1015 | void printrWithDepth(raw_ostream &O, const SelectionDAG *G = nullptr, |
1016 | unsigned depth = 100) const; |
1017 | |
1018 | /// Dump this node, for debugging. |
1019 | void dump() const; |
1020 | |
1021 | /// Dump (recursively) this node and its use-def subgraph. |
1022 | void dumpr() const; |
1023 | |
1024 | /// Dump this node, for debugging. |
1025 | /// The given SelectionDAG allows target-specific nodes to be printed |
1026 | /// in human-readable form. |
1027 | void dump(const SelectionDAG *G) const; |
1028 | |
1029 | /// Dump (recursively) this node and its use-def subgraph. |
1030 | /// The given SelectionDAG allows target-specific nodes to be printed |
1031 | /// in human-readable form. |
1032 | void dumpr(const SelectionDAG *G) const; |
1033 | |
1034 | /// printrFull to dbgs(). The given SelectionDAG allows |
1035 | /// target-specific nodes to be printed in human-readable form. |
1036 | /// Unlike dumpr, this will print the whole DAG, including children |
1037 | /// that appear multiple times. |
1038 | void dumprFull(const SelectionDAG *G = nullptr) const; |
1039 | |
1040 | /// printrWithDepth to dbgs(). The given |
1041 | /// SelectionDAG allows target-specific nodes to be printed in |
1042 | /// human-readable form. Unlike dumpr, this will print children |
1043 | /// that appear multiple times wherever they are used. |
1044 | /// |
1045 | void dumprWithDepth(const SelectionDAG *G = nullptr, |
1046 | unsigned depth = 100) const; |
1047 | |
1048 | /// Gather unique data for the node. |
1049 | void Profile(FoldingSetNodeID &ID) const; |
1050 | |
1051 | /// This method should only be used by the SDUse class. |
1052 | void addUse(SDUse &U) { U.addToList(&UseList); } |
1053 | |
1054 | protected: |
1055 | static SDVTList getSDVTList(EVT VT) { |
1056 | SDVTList Ret = { getValueTypeList(VT), 1 }; |
1057 | return Ret; |
1058 | } |
1059 | |
1060 | /// Create an SDNode. |
1061 | /// |
1062 | /// SDNodes are created without any operands, and never own the operand |
1063 | /// storage. To add operands, see SelectionDAG::createOperands. |
1064 | SDNode(unsigned Opc, unsigned Order, DebugLoc dl, SDVTList VTs) |
1065 | : NodeType(Opc), ValueList(VTs.VTs), NumValues(VTs.NumVTs), |
1066 | IROrder(Order), debugLoc(std::move(dl)) { |
1067 | memset(&RawSDNodeBits, 0, sizeof(RawSDNodeBits)); |
1068 | assert(debugLoc.hasTrivialDestructor() && "Expected trivial destructor")(static_cast <bool> (debugLoc.hasTrivialDestructor() && "Expected trivial destructor") ? void (0) : __assert_fail ("debugLoc.hasTrivialDestructor() && \"Expected trivial destructor\"" , "/build/llvm-toolchain-snapshot-14~++20211017100700+d245f2e8597b/llvm/include/llvm/CodeGen/SelectionDAGNodes.h" , 1068, __extension__ __PRETTY_FUNCTION__)); |
1069 | assert(NumValues == VTs.NumVTs &&(static_cast <bool> (NumValues == VTs.NumVTs && "NumValues wasn't wide enough for its operands!") ? void (0) : __assert_fail ("NumValues == VTs.NumVTs && \"NumValues wasn't wide enough for its operands!\"" , "/build/llvm-toolchain-snapshot-14~++20211017100700+d245f2e8597b/llvm/include/llvm/CodeGen/SelectionDAGNodes.h" , 1070, __extension__ __PRETTY_FUNCTION__)) |
1070 | "NumValues wasn't wide enough for its operands!")(static_cast <bool> (NumValues == VTs.NumVTs && "NumValues wasn't wide enough for its operands!") ? void (0) : __assert_fail ("NumValues == VTs.NumVTs && \"NumValues wasn't wide enough for its operands!\"" , "/build/llvm-toolchain-snapshot-14~++20211017100700+d245f2e8597b/llvm/include/llvm/CodeGen/SelectionDAGNodes.h" , 1070, __extension__ __PRETTY_FUNCTION__)); |
1071 | } |
1072 | |
1073 | /// Release the operands and set this node to have zero operands. |
1074 | void DropOperands(); |
1075 | }; |
1076 | |
1077 | /// Wrapper class for IR location info (IR ordering and DebugLoc) to be passed |
1078 | /// into SDNode creation functions. |
1079 | /// When an SDNode is created from the DAGBuilder, the DebugLoc is extracted |
1080 | /// from the original Instruction, and IROrder is the ordinal position of |
1081 | /// the instruction. |
1082 | /// When an SDNode is created after the DAG is being built, both DebugLoc and |
1083 | /// the IROrder are propagated from the original SDNode. |
1084 | /// So SDLoc class provides two constructors besides the default one, one to |
1085 | /// be used by the DAGBuilder, the other to be used by others. |
1086 | class SDLoc { |
1087 | private: |
1088 | DebugLoc DL; |
1089 | int IROrder = 0; |
1090 | |
1091 | public: |
1092 | SDLoc() = default; |
1093 | SDLoc(const SDNode *N) : DL(N->getDebugLoc()), IROrder(N->getIROrder()) {} |
1094 | SDLoc(const SDValue V) : SDLoc(V.getNode()) {} |
1095 | SDLoc(const Instruction *I, int Order) : IROrder(Order) { |
1096 | assert(Order >= 0 && "bad IROrder")(static_cast <bool> (Order >= 0 && "bad IROrder" ) ? void (0) : __assert_fail ("Order >= 0 && \"bad IROrder\"" , "/build/llvm-toolchain-snapshot-14~++20211017100700+d245f2e8597b/llvm/include/llvm/CodeGen/SelectionDAGNodes.h" , 1096, __extension__ __PRETTY_FUNCTION__)); |
1097 | if (I) |
1098 | DL = I->getDebugLoc(); |
1099 | } |
1100 | |
1101 | unsigned getIROrder() const { return IROrder; } |
1102 | const DebugLoc &getDebugLoc() const { return DL; } |
1103 | }; |
1104 | |
1105 | // Define inline functions from the SDValue class. |
1106 | |
1107 | inline SDValue::SDValue(SDNode *node, unsigned resno) |
1108 | : Node(node), ResNo(resno) { |
1109 | // Explicitly check for !ResNo to avoid use-after-free, because there are |
1110 | // callers that use SDValue(N, 0) with a deleted N to indicate successful |
1111 | // combines. |
1112 | assert((!Node || !ResNo || ResNo < Node->getNumValues()) &&(static_cast <bool> ((!Node || !ResNo || ResNo < Node ->getNumValues()) && "Invalid result number for the given node!" ) ? void (0) : __assert_fail ("(!Node || !ResNo || ResNo < Node->getNumValues()) && \"Invalid result number for the given node!\"" , "/build/llvm-toolchain-snapshot-14~++20211017100700+d245f2e8597b/llvm/include/llvm/CodeGen/SelectionDAGNodes.h" , 1113, __extension__ __PRETTY_FUNCTION__)) |
1113 | "Invalid result number for the given node!")(static_cast <bool> ((!Node || !ResNo || ResNo < Node ->getNumValues()) && "Invalid result number for the given node!" ) ? void (0) : __assert_fail ("(!Node || !ResNo || ResNo < Node->getNumValues()) && \"Invalid result number for the given node!\"" , "/build/llvm-toolchain-snapshot-14~++20211017100700+d245f2e8597b/llvm/include/llvm/CodeGen/SelectionDAGNodes.h" , 1113, __extension__ __PRETTY_FUNCTION__)); |
1114 | assert(ResNo < -2U && "Cannot use result numbers reserved for DenseMaps.")(static_cast <bool> (ResNo < -2U && "Cannot use result numbers reserved for DenseMaps." ) ? void (0) : __assert_fail ("ResNo < -2U && \"Cannot use result numbers reserved for DenseMaps.\"" , "/build/llvm-toolchain-snapshot-14~++20211017100700+d245f2e8597b/llvm/include/llvm/CodeGen/SelectionDAGNodes.h" , 1114, __extension__ __PRETTY_FUNCTION__)); |
1115 | } |
1116 | |
1117 | inline unsigned SDValue::getOpcode() const { |
1118 | return Node->getOpcode(); |
1119 | } |
1120 | |
1121 | inline EVT SDValue::getValueType() const { |
1122 | return Node->getValueType(ResNo); |
1123 | } |
1124 | |
1125 | inline unsigned SDValue::getNumOperands() const { |
1126 | return Node->getNumOperands(); |
1127 | } |
1128 | |
1129 | inline const SDValue &SDValue::getOperand(unsigned i) const { |
1130 | return Node->getOperand(i); |
1131 | } |
1132 | |
1133 | inline uint64_t SDValue::getConstantOperandVal(unsigned i) const { |
1134 | return Node->getConstantOperandVal(i); |
1135 | } |
1136 | |
1137 | inline const APInt &SDValue::getConstantOperandAPInt(unsigned i) const { |
1138 | return Node->getConstantOperandAPInt(i); |
1139 | } |
1140 | |
1141 | inline bool SDValue::isTargetOpcode() const { |
1142 | return Node->isTargetOpcode(); |
1143 | } |
1144 | |
1145 | inline bool SDValue::isTargetMemoryOpcode() const { |
1146 | return Node->isTargetMemoryOpcode(); |
1147 | } |
1148 | |
1149 | inline bool SDValue::isMachineOpcode() const { |
1150 | return Node->isMachineOpcode(); |
1151 | } |
1152 | |
1153 | inline unsigned SDValue::getMachineOpcode() const { |
1154 | return Node->getMachineOpcode(); |
1155 | } |
1156 | |
1157 | inline bool SDValue::isUndef() const { |
1158 | return Node->isUndef(); |
1159 | } |
1160 | |
1161 | inline bool SDValue::use_empty() const { |
1162 | return !Node->hasAnyUseOfValue(ResNo); |
1163 | } |
1164 | |
1165 | inline bool SDValue::hasOneUse() const { |
1166 | return Node->hasNUsesOfValue(1, ResNo); |
1167 | } |
1168 | |
1169 | inline const DebugLoc &SDValue::getDebugLoc() const { |
1170 | return Node->getDebugLoc(); |
1171 | } |
1172 | |
1173 | inline void SDValue::dump() const { |
1174 | return Node->dump(); |
1175 | } |
1176 | |
1177 | inline void SDValue::dump(const SelectionDAG *G) const { |
1178 | return Node->dump(G); |
1179 | } |
1180 | |
1181 | inline void SDValue::dumpr() const { |
1182 | return Node->dumpr(); |
1183 | } |
1184 | |
1185 | inline void SDValue::dumpr(const SelectionDAG *G) const { |
1186 | return Node->dumpr(G); |
1187 | } |
1188 | |
1189 | // Define inline functions from the SDUse class. |
1190 | |
1191 | inline void SDUse::set(const SDValue &V) { |
1192 | if (Val.getNode()) removeFromList(); |
1193 | Val = V; |
1194 | if (V.getNode()) V.getNode()->addUse(*this); |
1195 | } |
1196 | |
1197 | inline void SDUse::setInitial(const SDValue &V) { |
1198 | Val = V; |
1199 | V.getNode()->addUse(*this); |
1200 | } |
1201 | |
1202 | inline void SDUse::setNode(SDNode *N) { |
1203 | if (Val.getNode()) removeFromList(); |
1204 | Val.setNode(N); |
1205 | if (N) N->addUse(*this); |
1206 | } |
1207 | |
1208 | /// This class is used to form a handle around another node that |
1209 | /// is persistent and is updated across invocations of replaceAllUsesWith on its |
1210 | /// operand. This node should be directly created by end-users and not added to |
1211 | /// the AllNodes list. |
1212 | class HandleSDNode : public SDNode { |
1213 | SDUse Op; |
1214 | |
1215 | public: |
1216 | explicit HandleSDNode(SDValue X) |
1217 | : SDNode(ISD::HANDLENODE, 0, DebugLoc(), getSDVTList(MVT::Other)) { |
1218 | // HandleSDNodes are never inserted into the DAG, so they won't be |
1219 | // auto-numbered. Use ID 65535 as a sentinel. |
1220 | PersistentId = 0xffff; |
1221 | |
1222 | // Manually set up the operand list. This node type is special in that it's |
1223 | // always stack allocated and SelectionDAG does not manage its operands. |
1224 | // TODO: This should either (a) not be in the SDNode hierarchy, or (b) not |
1225 | // be so special. |
1226 | Op.setUser(this); |
1227 | Op.setInitial(X); |
1228 | NumOperands = 1; |
1229 | OperandList = &Op; |
1230 | } |
1231 | ~HandleSDNode(); |
1232 | |
1233 | const SDValue &getValue() const { return Op; } |
1234 | }; |
1235 | |
1236 | class AddrSpaceCastSDNode : public SDNode { |
1237 | private: |
1238 | unsigned SrcAddrSpace; |
1239 | unsigned DestAddrSpace; |
1240 | |
1241 | public: |
1242 | AddrSpaceCastSDNode(unsigned Order, const DebugLoc &dl, EVT VT, |
1243 | unsigned SrcAS, unsigned DestAS); |
1244 | |
1245 | unsigned getSrcAddressSpace() const { return SrcAddrSpace; } |
1246 | unsigned getDestAddressSpace() const { return DestAddrSpace; } |
1247 | |
1248 | static bool classof(const SDNode *N) { |
1249 | return N->getOpcode() == ISD::ADDRSPACECAST; |
1250 | } |
1251 | }; |
1252 | |
1253 | /// This is an abstract virtual class for memory operations. |
1254 | class MemSDNode : public SDNode { |
1255 | private: |
1256 | // VT of in-memory value. |
1257 | EVT MemoryVT; |
1258 | |
1259 | protected: |
1260 | /// Memory reference information. |
1261 | MachineMemOperand *MMO; |
1262 | |
1263 | public: |
1264 | MemSDNode(unsigned Opc, unsigned Order, const DebugLoc &dl, SDVTList VTs, |
1265 | EVT memvt, MachineMemOperand *MMO); |
1266 | |
1267 | bool readMem() const { return MMO->isLoad(); } |
1268 | bool writeMem() const { return MMO->isStore(); } |
1269 | |
1270 | /// Returns alignment and volatility of the memory access |
1271 | Align getOriginalAlign() const { return MMO->getBaseAlign(); } |
1272 | Align getAlign() const { return MMO->getAlign(); } |
1273 | // FIXME: Remove once transition to getAlign is over. |
1274 | unsigned getAlignment() const { return MMO->getAlign().value(); } |
1275 | |
1276 | /// Return the SubclassData value, without HasDebugValue. This contains an |
1277 | /// encoding of the volatile flag, as well as bits used by subclasses. This |
1278 | /// function should only be used to compute a FoldingSetNodeID value. |
1279 | /// The HasDebugValue bit is masked out because CSE map needs to match |
1280 | /// nodes with debug info with nodes without debug info. Same is about |
1281 | /// isDivergent bit. |
1282 | unsigned getRawSubclassData() const { |
1283 | uint16_t Data; |
1284 | union { |
1285 | char RawSDNodeBits[sizeof(uint16_t)]; |
1286 | SDNodeBitfields SDNodeBits; |
1287 | }; |
1288 | memcpy(&RawSDNodeBits, &this->RawSDNodeBits, sizeof(this->RawSDNodeBits)); |
1289 | SDNodeBits.HasDebugValue = 0; |
1290 | SDNodeBits.IsDivergent = false; |
1291 | memcpy(&Data, &RawSDNodeBits, sizeof(RawSDNodeBits)); |
1292 | return Data; |
1293 | } |
1294 | |
1295 | bool isVolatile() const { return MemSDNodeBits.IsVolatile; } |
1296 | bool isNonTemporal() const { return MemSDNodeBits.IsNonTemporal; } |
1297 | bool isDereferenceable() const { return MemSDNodeBits.IsDereferenceable; } |
1298 | bool isInvariant() const { return MemSDNodeBits.IsInvariant; } |
1299 | |
1300 | // Returns the offset from the location of the access. |
1301 | int64_t getSrcValueOffset() const { return MMO->getOffset(); } |
1302 | |
1303 | /// Returns the AA info that describes the dereference. |
1304 | AAMDNodes getAAInfo() const { return MMO->getAAInfo(); } |
1305 | |
1306 | /// Returns the Ranges that describes the dereference. |
1307 | const MDNode *getRanges() const { return MMO->getRanges(); } |
1308 | |
1309 | /// Returns the synchronization scope ID for this memory operation. |
1310 | SyncScope::ID getSyncScopeID() const { return MMO->getSyncScopeID(); } |
1311 | |
1312 | /// Return the atomic ordering requirements for this memory operation. For |
1313 | /// cmpxchg atomic operations, return the atomic ordering requirements when |
1314 | /// store occurs. |
1315 | AtomicOrdering getSuccessOrdering() const { |
1316 | return MMO->getSuccessOrdering(); |
1317 | } |
1318 | |
1319 | /// Return a single atomic ordering that is at least as strong as both the |
1320 | /// success and failure orderings for an atomic operation. (For operations |
1321 | /// other than cmpxchg, this is equivalent to getSuccessOrdering().) |
1322 | AtomicOrdering getMergedOrdering() const { return MMO->getMergedOrdering(); } |
1323 | |
1324 | /// Return true if the memory operation ordering is Unordered or higher. |
1325 | bool isAtomic() const { return MMO->isAtomic(); } |
1326 | |
1327 | /// Returns true if the memory operation doesn't imply any ordering |
1328 | /// constraints on surrounding memory operations beyond the normal memory |
1329 | /// aliasing rules. |
1330 | bool isUnordered() const { return MMO->isUnordered(); } |
1331 | |
1332 | /// Returns true if the memory operation is neither atomic or volatile. |
1333 | bool isSimple() const { return !isAtomic() && !isVolatile(); } |
1334 | |
1335 | /// Return the type of the in-memory value. |
1336 | EVT getMemoryVT() const { return MemoryVT; } |
1337 | |
1338 | /// Return a MachineMemOperand object describing the memory |
1339 | /// reference performed by operation. |
1340 | MachineMemOperand *getMemOperand() const { return MMO; } |
1341 | |
1342 | const MachinePointerInfo &getPointerInfo() const { |
1343 | return MMO->getPointerInfo(); |
1344 | } |
1345 | |
1346 | /// Return the address space for the associated pointer |
1347 | unsigned getAddressSpace() const { |
1348 | return getPointerInfo().getAddrSpace(); |
1349 | } |
1350 | |
1351 | /// Update this MemSDNode's MachineMemOperand information |
1352 | /// to reflect the alignment of NewMMO, if it has a greater alignment. |
1353 | /// This must only be used when the new alignment applies to all users of |
1354 | /// this MachineMemOperand. |
1355 | void refineAlignment(const MachineMemOperand *NewMMO) { |
1356 | MMO->refineAlignment(NewMMO); |
1357 | } |
1358 | |
1359 | const SDValue &getChain() const { return getOperand(0); } |
1360 | |
1361 | const SDValue &getBasePtr() const { |
1362 | switch (getOpcode()) { |
1363 | case ISD::STORE: |
1364 | case ISD::VP_STORE: |
1365 | case ISD::MSTORE: |
1366 | case ISD::VP_SCATTER: |
1367 | return getOperand(2); |
1368 | case ISD::MGATHER: |
1369 | case ISD::MSCATTER: |
1370 | return getOperand(3); |
1371 | default: |
1372 | return getOperand(1); |
1373 | } |
1374 | } |
1375 | |
1376 | // Methods to support isa and dyn_cast |
1377 | static bool classof(const SDNode *N) { |
1378 | // For some targets, we lower some target intrinsics to a MemIntrinsicNode |
1379 | // with either an intrinsic or a target opcode. |
1380 | switch (N->getOpcode()) { |
1381 | case ISD::LOAD: |
1382 | case ISD::STORE: |
1383 | case ISD::PREFETCH: |
1384 | case ISD::ATOMIC_CMP_SWAP: |
1385 | case ISD::ATOMIC_CMP_SWAP_WITH_SUCCESS: |
1386 | case ISD::ATOMIC_SWAP: |
1387 | case ISD::ATOMIC_LOAD_ADD: |
1388 | case ISD::ATOMIC_LOAD_SUB: |
1389 | case ISD::ATOMIC_LOAD_AND: |
1390 | case ISD::ATOMIC_LOAD_CLR: |
1391 | case ISD::ATOMIC_LOAD_OR: |
1392 | case ISD::ATOMIC_LOAD_XOR: |
1393 | case ISD::ATOMIC_LOAD_NAND: |
1394 | case ISD::ATOMIC_LOAD_MIN: |
1395 | case ISD::ATOMIC_LOAD_MAX: |
1396 | case ISD::ATOMIC_LOAD_UMIN: |
1397 | case ISD::ATOMIC_LOAD_UMAX: |
1398 | case ISD::ATOMIC_LOAD_FADD: |
1399 | case ISD::ATOMIC_LOAD_FSUB: |
1400 | case ISD::ATOMIC_LOAD: |
1401 | case ISD::ATOMIC_STORE: |
1402 | case ISD::MLOAD: |
1403 | case ISD::MSTORE: |
1404 | case ISD::MGATHER: |
1405 | case ISD::MSCATTER: |
1406 | case ISD::VP_LOAD: |
1407 | case ISD::VP_STORE: |
1408 | case ISD::VP_GATHER: |
1409 | case ISD::VP_SCATTER: |
1410 | return true; |
1411 | default: |
1412 | return N->isMemIntrinsic() || N->isTargetMemoryOpcode(); |
1413 | } |
1414 | } |
1415 | }; |
1416 | |
1417 | /// This is an SDNode representing atomic operations. |
1418 | class AtomicSDNode : public MemSDNode { |
1419 | public: |
1420 | AtomicSDNode(unsigned Opc, unsigned Order, const DebugLoc &dl, SDVTList VTL, |
1421 | EVT MemVT, MachineMemOperand *MMO) |
1422 | : MemSDNode(Opc, Order, dl, VTL, MemVT, MMO) { |
1423 | assert(((Opc != ISD::ATOMIC_LOAD && Opc != ISD::ATOMIC_STORE) ||(static_cast <bool> (((Opc != ISD::ATOMIC_LOAD && Opc != ISD::ATOMIC_STORE) || MMO->isAtomic()) && "then why are we using an AtomicSDNode?" ) ? void (0) : __assert_fail ("((Opc != ISD::ATOMIC_LOAD && Opc != ISD::ATOMIC_STORE) || MMO->isAtomic()) && \"then why are we using an AtomicSDNode?\"" , "/build/llvm-toolchain-snapshot-14~++20211017100700+d245f2e8597b/llvm/include/llvm/CodeGen/SelectionDAGNodes.h" , 1424, __extension__ __PRETTY_FUNCTION__)) |
1424 | MMO->isAtomic()) && "then why are we using an AtomicSDNode?")(static_cast <bool> (((Opc != ISD::ATOMIC_LOAD && Opc != ISD::ATOMIC_STORE) || MMO->isAtomic()) && "then why are we using an AtomicSDNode?" ) ? void (0) : __assert_fail ("((Opc != ISD::ATOMIC_LOAD && Opc != ISD::ATOMIC_STORE) || MMO->isAtomic()) && \"then why are we using an AtomicSDNode?\"" , "/build/llvm-toolchain-snapshot-14~++20211017100700+d245f2e8597b/llvm/include/llvm/CodeGen/SelectionDAGNodes.h" , 1424, __extension__ __PRETTY_FUNCTION__)); |
1425 | } |
1426 | |
1427 | const SDValue &getBasePtr() const { return getOperand(1); } |
1428 | const SDValue &getVal() const { return getOperand(2); } |
1429 | |
1430 | /// Returns true if this SDNode represents cmpxchg atomic operation, false |
1431 | /// otherwise. |
1432 | bool isCompareAndSwap() const { |
1433 | unsigned Op = getOpcode(); |
1434 | return Op == ISD::ATOMIC_CMP_SWAP || |
1435 | Op == ISD::ATOMIC_CMP_SWAP_WITH_SUCCESS; |
1436 | } |
1437 | |
1438 | /// For cmpxchg atomic operations, return the atomic ordering requirements |
1439 | /// when store does not occur. |
1440 | AtomicOrdering getFailureOrdering() const { |
1441 | assert(isCompareAndSwap() && "Must be cmpxchg operation")(static_cast <bool> (isCompareAndSwap() && "Must be cmpxchg operation" ) ? void (0) : __assert_fail ("isCompareAndSwap() && \"Must be cmpxchg operation\"" , "/build/llvm-toolchain-snapshot-14~++20211017100700+d245f2e8597b/llvm/include/llvm/CodeGen/SelectionDAGNodes.h" , 1441, __extension__ __PRETTY_FUNCTION__)); |
1442 | return MMO->getFailureOrdering(); |
1443 | } |
1444 | |
1445 | // Methods to support isa and dyn_cast |
1446 | static bool classof(const SDNode *N) { |
1447 | return N->getOpcode() == ISD::ATOMIC_CMP_SWAP || |
1448 | N->getOpcode() == ISD::ATOMIC_CMP_SWAP_WITH_SUCCESS || |
1449 | N->getOpcode() == ISD::ATOMIC_SWAP || |
1450 | N->getOpcode() == ISD::ATOMIC_LOAD_ADD || |
1451 | N->getOpcode() == ISD::ATOMIC_LOAD_SUB || |
1452 | N->getOpcode() == ISD::ATOMIC_LOAD_AND || |
1453 | N->getOpcode() == ISD::ATOMIC_LOAD_CLR || |
1454 | N->getOpcode() == ISD::ATOMIC_LOAD_OR || |
1455 | N->getOpcode() == ISD::ATOMIC_LOAD_XOR || |
1456 | N->getOpcode() == ISD::ATOMIC_LOAD_NAND || |
1457 | N->getOpcode() == ISD::ATOMIC_LOAD_MIN || |
1458 | N->getOpcode() == ISD::ATOMIC_LOAD_MAX || |
1459 | N->getOpcode() == ISD::ATOMIC_LOAD_UMIN || |
1460 | N->getOpcode() == ISD::ATOMIC_LOAD_UMAX || |
1461 | N->getOpcode() == ISD::ATOMIC_LOAD_FADD || |
1462 | N->getOpcode() == ISD::ATOMIC_LOAD_FSUB || |
1463 | N->getOpcode() == ISD::ATOMIC_LOAD || |
1464 | N->getOpcode() == ISD::ATOMIC_STORE; |
1465 | } |
1466 | }; |
1467 | |
1468 | /// This SDNode is used for target intrinsics that touch |
1469 | /// memory and need an associated MachineMemOperand. Its opcode may be |
1470 | /// INTRINSIC_VOID, INTRINSIC_W_CHAIN, PREFETCH, or a target-specific opcode |
1471 | /// with a value not less than FIRST_TARGET_MEMORY_OPCODE. |
1472 | class MemIntrinsicSDNode : public MemSDNode { |
1473 | public: |
1474 | MemIntrinsicSDNode(unsigned Opc, unsigned Order, const DebugLoc &dl, |
1475 | SDVTList VTs, EVT MemoryVT, MachineMemOperand *MMO) |
1476 | : MemSDNode(Opc, Order, dl, VTs, MemoryVT, MMO) { |
1477 | SDNodeBits.IsMemIntrinsic = true; |
1478 | } |
1479 | |
1480 | // Methods to support isa and dyn_cast |
1481 | static bool classof(const SDNode *N) { |
1482 | // We lower some target intrinsics to their target opcode |
1483 | // early a node with a target opcode can be of this class |
1484 | return N->isMemIntrinsic() || |
1485 | N->getOpcode() == ISD::PREFETCH || |
1486 | N->isTargetMemoryOpcode(); |
1487 | } |
1488 | }; |
1489 | |
1490 | /// This SDNode is used to implement the code generator |
1491 | /// support for the llvm IR shufflevector instruction. It combines elements |
1492 | /// from two input vectors into a new input vector, with the selection and |
1493 | /// ordering of elements determined by an array of integers, referred to as |
1494 | /// the shuffle mask. For input vectors of width N, mask indices of 0..N-1 |
1495 | /// refer to elements from the LHS input, and indices from N to 2N-1 the RHS. |
1496 | /// An index of -1 is treated as undef, such that the code generator may put |
1497 | /// any value in the corresponding element of the result. |
1498 | class ShuffleVectorSDNode : public SDNode { |
1499 | // The memory for Mask is owned by the SelectionDAG's OperandAllocator, and |
1500 | // is freed when the SelectionDAG object is destroyed. |
1501 | const int *Mask; |
1502 | |
1503 | protected: |
1504 | friend class SelectionDAG; |
1505 | |
1506 | ShuffleVectorSDNode(EVT VT, unsigned Order, const DebugLoc &dl, const int *M) |
1507 | : SDNode(ISD::VECTOR_SHUFFLE, Order, dl, getSDVTList(VT)), Mask(M) {} |
1508 | |
1509 | public: |
1510 | ArrayRef<int> getMask() const { |
1511 | EVT VT = getValueType(0); |
1512 | return makeArrayRef(Mask, VT.getVectorNumElements()); |
1513 | } |
1514 | |
1515 | int getMaskElt(unsigned Idx) const { |
1516 | assert(Idx < getValueType(0).getVectorNumElements() && "Idx out of range!")(static_cast <bool> (Idx < getValueType(0).getVectorNumElements () && "Idx out of range!") ? void (0) : __assert_fail ("Idx < getValueType(0).getVectorNumElements() && \"Idx out of range!\"" , "/build/llvm-toolchain-snapshot-14~++20211017100700+d245f2e8597b/llvm/include/llvm/CodeGen/SelectionDAGNodes.h" , 1516, __extension__ __PRETTY_FUNCTION__)); |
1517 | return Mask[Idx]; |
1518 | } |
1519 | |
1520 | bool isSplat() const { return isSplatMask(Mask, getValueType(0)); } |
1521 | |
1522 | int getSplatIndex() const { |
1523 | assert(isSplat() && "Cannot get splat index for non-splat!")(static_cast <bool> (isSplat() && "Cannot get splat index for non-splat!" ) ? void (0) : __assert_fail ("isSplat() && \"Cannot get splat index for non-splat!\"" , "/build/llvm-toolchain-snapshot-14~++20211017100700+d245f2e8597b/llvm/include/llvm/CodeGen/SelectionDAGNodes.h" , 1523, __extension__ __PRETTY_FUNCTION__)); |
1524 | EVT VT = getValueType(0); |
1525 | for (unsigned i = 0, e = VT.getVectorNumElements(); i != e; ++i) |
1526 | if (Mask[i] >= 0) |
1527 | return Mask[i]; |
1528 | |
1529 | // We can choose any index value here and be correct because all elements |
1530 | // are undefined. Return 0 for better potential for callers to simplify. |
1531 | return 0; |
1532 | } |
1533 | |
1534 | static bool isSplatMask(const int *Mask, EVT VT); |
1535 | |
1536 | /// Change values in a shuffle permute mask assuming |
1537 | /// the two vector operands have swapped position. |
1538 | static void commuteMask(MutableArrayRef<int> Mask) { |
1539 | unsigned NumElems = Mask.size(); |
1540 | for (unsigned i = 0; i != NumElems; ++i) { |
1541 | int idx = Mask[i]; |
1542 | if (idx < 0) |
1543 | continue; |
1544 | else if (idx < (int)NumElems) |
1545 | Mask[i] = idx + NumElems; |
1546 | else |
1547 | Mask[i] = idx - NumElems; |
1548 | } |
1549 | } |
1550 | |
1551 | static bool classof(const SDNode *N) { |
1552 | return N->getOpcode() == ISD::VECTOR_SHUFFLE; |
1553 | } |
1554 | }; |
1555 | |
1556 | class ConstantSDNode : public SDNode { |
1557 | friend class SelectionDAG; |
1558 | |
1559 | const ConstantInt *Value; |
1560 | |
1561 | ConstantSDNode(bool isTarget, bool isOpaque, const ConstantInt *val, EVT VT) |
1562 | : SDNode(isTarget ? ISD::TargetConstant : ISD::Constant, 0, DebugLoc(), |
1563 | getSDVTList(VT)), |
1564 | Value(val) { |
1565 | ConstantSDNodeBits.IsOpaque = isOpaque; |
1566 | } |
1567 | |
1568 | public: |
1569 | const ConstantInt *getConstantIntValue() const { return Value; } |
1570 | const APInt &getAPIntValue() const { return Value->getValue(); } |
1571 | uint64_t getZExtValue() const { return Value->getZExtValue(); } |
1572 | int64_t getSExtValue() const { return Value->getSExtValue(); } |
1573 | uint64_t getLimitedValue(uint64_t Limit = UINT64_MAX(18446744073709551615UL)) { |
1574 | return Value->getLimitedValue(Limit); |
1575 | } |
1576 | MaybeAlign getMaybeAlignValue() const { return Value->getMaybeAlignValue(); } |
1577 | Align getAlignValue() const { return Value->getAlignValue(); } |
1578 | |
1579 | bool isOne() const { return Value->isOne(); } |
1580 | bool isZero() const { return Value->isZero(); } |
1581 | // NOTE: This is soft-deprecated. Please use `isZero()` instead. |
1582 | bool isNullValue() const { return isZero(); } |
1583 | bool isAllOnes() const { return Value->isMinusOne(); } |
1584 | // NOTE: This is soft-deprecated. Please use `isAllOnes()` instead. |
1585 | bool isAllOnesValue() const { return isAllOnes(); } |
1586 | bool isMaxSignedValue() const { return Value->isMaxValue(true); } |
1587 | bool isMinSignedValue() const { return Value->isMinValue(true); } |
1588 | |
1589 | bool isOpaque() const { return ConstantSDNodeBits.IsOpaque; } |
1590 | |
1591 | static bool classof(const SDNode *N) { |
1592 | return N->getOpcode() == ISD::Constant || |
1593 | N->getOpcode() == ISD::TargetConstant; |
1594 | } |
1595 | }; |
1596 | |
1597 | uint64_t SDNode::getConstantOperandVal(unsigned Num) const { |
1598 | return cast<ConstantSDNode>(getOperand(Num))->getZExtValue(); |
1599 | } |
1600 | |
1601 | const APInt &SDNode::getConstantOperandAPInt(unsigned Num) const { |
1602 | return cast<ConstantSDNode>(getOperand(Num))->getAPIntValue(); |
1603 | } |
1604 | |
1605 | class ConstantFPSDNode : public SDNode { |
1606 | friend class SelectionDAG; |
1607 | |
1608 | const ConstantFP *Value; |
1609 | |
1610 | ConstantFPSDNode(bool isTarget, const ConstantFP *val, EVT VT) |
1611 | : SDNode(isTarget ? ISD::TargetConstantFP : ISD::ConstantFP, 0, |
1612 | DebugLoc(), getSDVTList(VT)), |
1613 | Value(val) {} |
1614 | |
1615 | public: |
1616 | const APFloat& getValueAPF() const { return Value->getValueAPF(); } |
1617 | const ConstantFP *getConstantFPValue() const { return Value; } |
1618 | |
1619 | /// Return true if the value is positive or negative zero. |
1620 | bool isZero() const { return Value->isZero(); } |
1621 | |
1622 | /// Return true if the value is a NaN. |
1623 | bool isNaN() const { return Value->isNaN(); } |
1624 | |
1625 | /// Return true if the value is an infinity |
1626 | bool isInfinity() const { return Value->isInfinity(); } |
1627 | |
1628 | /// Return true if the value is negative. |
1629 | bool isNegative() const { return Value->isNegative(); } |
1630 | |
1631 | /// We don't rely on operator== working on double values, as |
1632 | /// it returns true for things that are clearly not equal, like -0.0 and 0.0. |
1633 | /// As such, this method can be used to do an exact bit-for-bit comparison of |
1634 | /// two floating point values. |
1635 | |
1636 | /// We leave the version with the double argument here because it's just so |
1637 | /// convenient to write "2.0" and the like. Without this function we'd |
1638 | /// have to duplicate its logic everywhere it's called. |
1639 | bool isExactlyValue(double V) const { |
1640 | return Value->getValueAPF().isExactlyValue(V); |
1641 | } |
1642 | bool isExactlyValue(const APFloat& V) const; |
1643 | |
1644 | static bool isValueValidForType(EVT VT, const APFloat& Val); |
1645 | |
1646 | static bool classof(const SDNode *N) { |
1647 | return N->getOpcode() == ISD::ConstantFP || |
1648 | N->getOpcode() == ISD::TargetConstantFP; |
1649 | } |
1650 | }; |
1651 | |
1652 | /// Returns true if \p V is a constant integer zero. |
1653 | bool isNullConstant(SDValue V); |
1654 | |
1655 | /// Returns true if \p V is an FP constant with a value of positive zero. |
1656 | bool isNullFPConstant(SDValue V); |
1657 | |
1658 | /// Returns true if \p V is an integer constant with all bits set. |
1659 | bool isAllOnesConstant(SDValue V); |
1660 | |
1661 | /// Returns true if \p V is a constant integer one. |
1662 | bool isOneConstant(SDValue V); |
1663 | |
1664 | /// Return the non-bitcasted source operand of \p V if it exists. |
1665 | /// If \p V is not a bitcasted value, it is returned as-is. |
1666 | SDValue peekThroughBitcasts(SDValue V); |
1667 | |
1668 | /// Return the non-bitcasted and one-use source operand of \p V if it exists. |
1669 | /// If \p V is not a bitcasted one-use value, it is returned as-is. |
1670 | SDValue peekThroughOneUseBitcasts(SDValue V); |
1671 | |
1672 | /// Return the non-extracted vector source operand of \p V if it exists. |
1673 | /// If \p V is not an extracted subvector, it is returned as-is. |
1674 | SDValue peekThroughExtractSubvectors(SDValue V); |
1675 | |
1676 | /// Returns true if \p V is a bitwise not operation. Assumes that an all ones |
1677 | /// constant is canonicalized to be operand 1. |
1678 | bool isBitwiseNot(SDValue V, bool AllowUndefs = false); |
1679 | |
1680 | /// Returns the SDNode if it is a constant splat BuildVector or constant int. |
1681 | ConstantSDNode *isConstOrConstSplat(SDValue N, bool AllowUndefs = false, |
1682 | bool AllowTruncation = false); |
1683 | |
1684 | /// Returns the SDNode if it is a demanded constant splat BuildVector or |
1685 | /// constant int. |
1686 | ConstantSDNode *isConstOrConstSplat(SDValue N, const APInt &DemandedElts, |
1687 | bool AllowUndefs = false, |
1688 | bool AllowTruncation = false); |
1689 | |
1690 | /// Returns the SDNode if it is a constant splat BuildVector or constant float. |
1691 | ConstantFPSDNode *isConstOrConstSplatFP(SDValue N, bool AllowUndefs = false); |
1692 | |
1693 | /// Returns the SDNode if it is a demanded constant splat BuildVector or |
1694 | /// constant float. |
1695 | ConstantFPSDNode *isConstOrConstSplatFP(SDValue N, const APInt &DemandedElts, |
1696 | bool AllowUndefs = false); |
1697 | |
1698 | /// Return true if the value is a constant 0 integer or a splatted vector of |
1699 | /// a constant 0 integer (with no undefs by default). |
1700 | /// Build vector implicit truncation is not an issue for null values. |
1701 | bool isNullOrNullSplat(SDValue V, bool AllowUndefs = false); |
1702 | |
1703 | /// Return true if the value is a constant 1 integer or a splatted vector of a |
1704 | /// constant 1 integer (with no undefs). |
1705 | /// Does not permit build vector implicit truncation. |
1706 | bool isOneOrOneSplat(SDValue V, bool AllowUndefs = false); |
1707 | |
1708 | /// Return true if the value is a constant -1 integer or a splatted vector of a |
1709 | /// constant -1 integer (with no undefs). |
1710 | /// Does not permit build vector implicit truncation. |
1711 | bool isAllOnesOrAllOnesSplat(SDValue V, bool AllowUndefs = false); |
1712 | |
1713 | /// Return true if \p V is either a integer or FP constant. |
1714 | inline bool isIntOrFPConstant(SDValue V) { |
1715 | return isa<ConstantSDNode>(V) || isa<ConstantFPSDNode>(V); |
1716 | } |
1717 | |
1718 | class GlobalAddressSDNode : public SDNode { |
1719 | friend class SelectionDAG; |
1720 | |
1721 | const GlobalValue *TheGlobal; |
1722 | int64_t Offset; |
1723 | unsigned TargetFlags; |
1724 | |
1725 | GlobalAddressSDNode(unsigned Opc, unsigned Order, const DebugLoc &DL, |
1726 | const GlobalValue *GA, EVT VT, int64_t o, |
1727 | unsigned TF); |
1728 | |
1729 | public: |
1730 | const GlobalValue *getGlobal() const { return TheGlobal; } |
1731 | int64_t getOffset() const { return Offset; } |
1732 | unsigned getTargetFlags() const { return TargetFlags; } |
1733 | // Return the address space this GlobalAddress belongs to. |
1734 | unsigned getAddressSpace() const; |
1735 | |
1736 | static bool classof(const SDNode *N) { |
1737 | return N->getOpcode() == ISD::GlobalAddress || |
1738 | N->getOpcode() == ISD::TargetGlobalAddress || |
1739 | N->getOpcode() == ISD::GlobalTLSAddress || |
1740 | N->getOpcode() == ISD::TargetGlobalTLSAddress; |
1741 | } |
1742 | }; |
1743 | |
1744 | class FrameIndexSDNode : public SDNode { |
1745 | friend class SelectionDAG; |
1746 | |
1747 | int FI; |
1748 | |
1749 | FrameIndexSDNode(int fi, EVT VT, bool isTarg) |
1750 | : SDNode(isTarg ? ISD::TargetFrameIndex : ISD::FrameIndex, |
1751 | 0, DebugLoc(), getSDVTList(VT)), FI(fi) { |
1752 | } |
1753 | |
1754 | public: |
1755 | int getIndex() const { return FI; } |
1756 | |
1757 | static bool classof(const SDNode *N) { |
1758 | return N->getOpcode() == ISD::FrameIndex || |
1759 | N->getOpcode() == ISD::TargetFrameIndex; |
1760 | } |
1761 | }; |
1762 | |
1763 | /// This SDNode is used for LIFETIME_START/LIFETIME_END values, which indicate |
1764 | /// the offet and size that are started/ended in the underlying FrameIndex. |
1765 | class LifetimeSDNode : public SDNode { |
1766 | friend class SelectionDAG; |
1767 | int64_t Size; |
1768 | int64_t Offset; // -1 if offset is unknown. |
1769 | |
1770 | LifetimeSDNode(unsigned Opcode, unsigned Order, const DebugLoc &dl, |
1771 | SDVTList VTs, int64_t Size, int64_t Offset) |
1772 | : SDNode(Opcode, Order, dl, VTs), Size(Size), Offset(Offset) {} |
1773 | public: |
1774 | int64_t getFrameIndex() const { |
1775 | return cast<FrameIndexSDNode>(getOperand(1))->getIndex(); |
1776 | } |
1777 | |
1778 | bool hasOffset() const { return Offset >= 0; } |
1779 | int64_t getOffset() const { |
1780 | assert(hasOffset() && "offset is unknown")(static_cast <bool> (hasOffset() && "offset is unknown" ) ? void (0) : __assert_fail ("hasOffset() && \"offset is unknown\"" , "/build/llvm-toolchain-snapshot-14~++20211017100700+d245f2e8597b/llvm/include/llvm/CodeGen/SelectionDAGNodes.h" , 1780, __extension__ __PRETTY_FUNCTION__)); |
1781 | return Offset; |
1782 | } |
1783 | int64_t getSize() const { |
1784 | assert(hasOffset() && "offset is unknown")(static_cast <bool> (hasOffset() && "offset is unknown" ) ? void (0) : __assert_fail ("hasOffset() && \"offset is unknown\"" , "/build/llvm-toolchain-snapshot-14~++20211017100700+d245f2e8597b/llvm/include/llvm/CodeGen/SelectionDAGNodes.h" , 1784, __extension__ __PRETTY_FUNCTION__)); |
1785 | return Size; |
1786 | } |
1787 | |
1788 | // Methods to support isa and dyn_cast |
1789 | static bool classof(const SDNode *N) { |
1790 | return N->getOpcode() == ISD::LIFETIME_START || |
1791 | N->getOpcode() == ISD::LIFETIME_END; |
1792 | } |
1793 | }; |
1794 | |
1795 | /// This SDNode is used for PSEUDO_PROBE values, which are the function guid and |
1796 | /// the index of the basic block being probed. A pseudo probe serves as a place |
1797 | /// holder and will be removed at the end of compilation. It does not have any |
1798 | /// operand because we do not want the instruction selection to deal with any. |
1799 | class PseudoProbeSDNode : public SDNode { |
1800 | friend class SelectionDAG; |
1801 | uint64_t Guid; |
1802 | uint64_t Index; |
1803 | uint32_t Attributes; |
1804 | |
1805 | PseudoProbeSDNode(unsigned Opcode, unsigned Order, const DebugLoc &Dl, |
1806 | SDVTList VTs, uint64_t Guid, uint64_t Index, uint32_t Attr) |
1807 | : SDNode(Opcode, Order, Dl, VTs), Guid(Guid), Index(Index), |
1808 | Attributes(Attr) {} |
1809 | |
1810 | public: |
1811 | uint64_t getGuid() const { return Guid; } |
1812 | uint64_t getIndex() const { return Index; } |
1813 | uint32_t getAttributes() const { return Attributes; } |
1814 | |
1815 | // Methods to support isa and dyn_cast |
1816 | static bool classof(const SDNode *N) { |
1817 | return N->getOpcode() == ISD::PSEUDO_PROBE; |
1818 | } |
1819 | }; |
1820 | |
1821 | class JumpTableSDNode : public SDNode { |
1822 | friend class SelectionDAG; |
1823 | |
1824 | int JTI; |
1825 | unsigned TargetFlags; |
1826 | |
1827 | JumpTableSDNode(int jti, EVT VT, bool isTarg, unsigned TF) |
1828 | : SDNode(isTarg ? ISD::TargetJumpTable : ISD::JumpTable, |
1829 | 0, DebugLoc(), getSDVTList(VT)), JTI(jti), TargetFlags(TF) { |
1830 | } |
1831 | |
1832 | public: |
1833 | int getIndex() const { return JTI; } |
1834 | unsigned getTargetFlags() const { return TargetFlags; } |
1835 | |
1836 | static bool classof(const SDNode *N) { |
1837 | return N->getOpcode() == ISD::JumpTable || |
1838 | N->getOpcode() == ISD::TargetJumpTable; |
1839 | } |
1840 | }; |
1841 | |
1842 | class ConstantPoolSDNode : public SDNode { |
1843 | friend class SelectionDAG; |
1844 | |
1845 | union { |
1846 | const Constant *ConstVal; |
1847 | MachineConstantPoolValue *MachineCPVal; |
1848 | } Val; |
1849 | int Offset; // It's a MachineConstantPoolValue if top bit is set. |
1850 | Align Alignment; // Minimum alignment requirement of CP. |
1851 | unsigned TargetFlags; |
1852 | |
1853 | ConstantPoolSDNode(bool isTarget, const Constant *c, EVT VT, int o, |
1854 | Align Alignment, unsigned TF) |
1855 | : SDNode(isTarget ? ISD::TargetConstantPool : ISD::ConstantPool, 0, |
1856 | DebugLoc(), getSDVTList(VT)), |
1857 | Offset(o), Alignment(Alignment), TargetFlags(TF) { |
1858 | assert(Offset >= 0 && "Offset is too large")(static_cast <bool> (Offset >= 0 && "Offset is too large" ) ? void (0) : __assert_fail ("Offset >= 0 && \"Offset is too large\"" , "/build/llvm-toolchain-snapshot-14~++20211017100700+d245f2e8597b/llvm/include/llvm/CodeGen/SelectionDAGNodes.h" , 1858, __extension__ __PRETTY_FUNCTION__)); |
1859 | Val.ConstVal = c; |
1860 | } |
1861 | |
1862 | ConstantPoolSDNode(bool isTarget, MachineConstantPoolValue *v, EVT VT, int o, |
1863 | Align Alignment, unsigned TF) |
1864 | : SDNode(isTarget ? ISD::TargetConstantPool : ISD::ConstantPool, 0, |
1865 | DebugLoc(), getSDVTList(VT)), |
1866 | Offset(o), Alignment(Alignment), TargetFlags(TF) { |
1867 | assert(Offset >= 0 && "Offset is too large")(static_cast <bool> (Offset >= 0 && "Offset is too large" ) ? void (0) : __assert_fail ("Offset >= 0 && \"Offset is too large\"" , "/build/llvm-toolchain-snapshot-14~++20211017100700+d245f2e8597b/llvm/include/llvm/CodeGen/SelectionDAGNodes.h" , 1867, __extension__ __PRETTY_FUNCTION__)); |
1868 | Val.MachineCPVal = v; |
1869 | Offset |= 1 << (sizeof(unsigned)*CHAR_BIT8-1); |
1870 | } |
1871 | |
1872 | public: |
1873 | bool isMachineConstantPoolEntry() const { |
1874 | return Offset < 0; |
1875 | } |
1876 | |
1877 | const Constant *getConstVal() const { |
1878 | assert(!isMachineConstantPoolEntry() && "Wrong constantpool type")(static_cast <bool> (!isMachineConstantPoolEntry() && "Wrong constantpool type") ? void (0) : __assert_fail ("!isMachineConstantPoolEntry() && \"Wrong constantpool type\"" , "/build/llvm-toolchain-snapshot-14~++20211017100700+d245f2e8597b/llvm/include/llvm/CodeGen/SelectionDAGNodes.h" , 1878, __extension__ __PRETTY_FUNCTION__)); |
1879 | return Val.ConstVal; |
1880 | } |
1881 | |
1882 | MachineConstantPoolValue *getMachineCPVal() const { |
1883 | assert(isMachineConstantPoolEntry() && "Wrong constantpool type")(static_cast <bool> (isMachineConstantPoolEntry() && "Wrong constantpool type") ? void (0) : __assert_fail ("isMachineConstantPoolEntry() && \"Wrong constantpool type\"" , "/build/llvm-toolchain-snapshot-14~++20211017100700+d245f2e8597b/llvm/include/llvm/CodeGen/SelectionDAGNodes.h" , 1883, __extension__ __PRETTY_FUNCTION__)); |
1884 | return Val.MachineCPVal; |
1885 | } |
1886 | |
1887 | int getOffset() const { |
1888 | return Offset & ~(1 << (sizeof(unsigned)*CHAR_BIT8-1)); |
1889 | } |
1890 | |
1891 | // Return the alignment of this constant pool object, which is either 0 (for |
1892 | // default alignment) or the desired value. |
1893 | Align getAlign() const { return Alignment; } |
1894 | unsigned getTargetFlags() const { return TargetFlags; } |
1895 | |
1896 | Type *getType() const; |
1897 | |
1898 | static bool classof(const SDNode *N) { |
1899 | return N->getOpcode() == ISD::ConstantPool || |
1900 | N->getOpcode() == ISD::TargetConstantPool; |
1901 | } |
1902 | }; |
1903 | |
1904 | /// Completely target-dependent object reference. |
1905 | class TargetIndexSDNode : public SDNode { |
1906 | friend class SelectionDAG; |
1907 | |
1908 | unsigned TargetFlags; |
1909 | int Index; |
1910 | int64_t Offset; |
1911 | |
1912 | public: |
1913 | TargetIndexSDNode(int Idx, EVT VT, int64_t Ofs, unsigned TF) |
1914 | : SDNode(ISD::TargetIndex, 0, DebugLoc(), getSDVTList(VT)), |
1915 | TargetFlags(TF), Index(Idx), Offset(Ofs) {} |
1916 | |
1917 | unsigned getTargetFlags() const { return TargetFlags; } |
1918 | int getIndex() const { return Index; } |
1919 | int64_t getOffset() const { return Offset; } |
1920 | |
1921 | static bool classof(const SDNode *N) { |
1922 | return N->getOpcode() == ISD::TargetIndex; |
1923 | } |
1924 | }; |
1925 | |
1926 | class BasicBlockSDNode : public SDNode { |
1927 | friend class SelectionDAG; |
1928 | |
1929 | MachineBasicBlock *MBB; |
1930 | |
1931 | /// Debug info is meaningful and potentially useful here, but we create |
1932 | /// blocks out of order when they're jumped to, which makes it a bit |
1933 | /// harder. Let's see if we need it first. |
1934 | explicit BasicBlockSDNode(MachineBasicBlock *mbb) |
1935 | : SDNode(ISD::BasicBlock, 0, DebugLoc(), getSDVTList(MVT::Other)), MBB(mbb) |
1936 | {} |
1937 | |
1938 | public: |
1939 | MachineBasicBlock *getBasicBlock() const { return MBB; } |
1940 | |
1941 | static bool classof(const SDNode *N) { |
1942 | return N->getOpcode() == ISD::BasicBlock; |
1943 | } |
1944 | }; |
1945 | |
1946 | /// A "pseudo-class" with methods for operating on BUILD_VECTORs. |
1947 | class BuildVectorSDNode : public SDNode { |
1948 | public: |
1949 | // These are constructed as SDNodes and then cast to BuildVectorSDNodes. |
1950 | explicit BuildVectorSDNode() = delete; |
1951 | |
1952 | /// Check if this is a constant splat, and if so, find the |
1953 | /// smallest element size that splats the vector. If MinSplatBits is |
1954 | /// nonzero, the element size must be at least that large. Note that the |
1955 | /// splat element may be the entire vector (i.e., a one element vector). |
1956 | /// Returns the splat element value in SplatValue. Any undefined bits in |
1957 | /// that value are zero, and the corresponding bits in the SplatUndef mask |
1958 | /// are set. The SplatBitSize value is set to the splat element size in |
1959 | /// bits. HasAnyUndefs is set to true if any bits in the vector are |
1960 | /// undefined. isBigEndian describes the endianness of the target. |
1961 | bool isConstantSplat(APInt &SplatValue, APInt &SplatUndef, |
1962 | unsigned &SplatBitSize, bool &HasAnyUndefs, |
1963 | unsigned MinSplatBits = 0, |
1964 | bool isBigEndian = false) const; |
1965 | |
1966 | /// Returns the demanded splatted value or a null value if this is not a |
1967 | /// splat. |
1968 | /// |
1969 | /// The DemandedElts mask indicates the elements that must be in the splat. |
1970 | /// If passed a non-null UndefElements bitvector, it will resize it to match |
1971 | /// the vector width and set the bits where elements are undef. |
1972 | SDValue getSplatValue(const APInt &DemandedElts, |
1973 | BitVector *UndefElements = nullptr) const; |
1974 | |
1975 | /// Returns the splatted value or a null value if this is not a splat. |
1976 | /// |
1977 | /// If passed a non-null UndefElements bitvector, it will resize it to match |
1978 | /// the vector width and set the bits where elements are undef. |
1979 | SDValue getSplatValue(BitVector *UndefElements = nullptr) const; |
1980 | |
1981 | /// Find the shortest repeating sequence of values in the build vector. |
1982 | /// |
1983 | /// e.g. { u, X, u, X, u, u, X, u } -> { X } |
1984 | /// { X, Y, u, Y, u, u, X, u } -> { X, Y } |
1985 | /// |
1986 | /// Currently this must be a power-of-2 build vector. |
1987 | /// The DemandedElts mask indicates the elements that must be present, |
1988 | /// undemanded elements in Sequence may be null (SDValue()). If passed a |
1989 | /// non-null UndefElements bitvector, it will resize it to match the original |
1990 | /// vector width and set the bits where elements are undef. If result is |
1991 | /// false, Sequence will be empty. |
1992 | bool getRepeatedSequence(const APInt &DemandedElts, |
1993 | SmallVectorImpl<SDValue> &Sequence, |
1994 | BitVector *UndefElements = nullptr) const; |
1995 | |
1996 | /// Find the shortest repeating sequence of values in the build vector. |
1997 | /// |
1998 | /// e.g. { u, X, u, X, u, u, X, u } -> { X } |
1999 | /// { X, Y, u, Y, u, u, X, u } -> { X, Y } |
2000 | /// |
2001 | /// Currently this must be a power-of-2 build vector. |
2002 | /// If passed a non-null UndefElements bitvector, it will resize it to match |
2003 | /// the original vector width and set the bits where elements are undef. |
2004 | /// If result is false, Sequence will be empty. |
2005 | bool getRepeatedSequence(SmallVectorImpl<SDValue> &Sequence, |
2006 | BitVector *UndefElements = nullptr) const; |
2007 | |
2008 | /// Returns the demanded splatted constant or null if this is not a constant |
2009 | /// splat. |
2010 | /// |
2011 | /// The DemandedElts mask indicates the elements that must be in the splat. |
2012 | /// If passed a non-null UndefElements bitvector, it will resize it to match |
2013 | /// the vector width and set the bits where elements are undef. |
2014 | ConstantSDNode * |
2015 | getConstantSplatNode(const APInt &DemandedElts, |
2016 | BitVector *UndefElements = nullptr) const; |
2017 | |
2018 | /// Returns the splatted constant or null if this is not a constant |
2019 | /// splat. |
2020 | /// |
2021 | /// If passed a non-null UndefElements bitvector, it will resize it to match |
2022 | /// the vector width and set the bits where elements are undef. |
2023 | ConstantSDNode * |
2024 | getConstantSplatNode(BitVector *UndefElements = nullptr) const; |
2025 | |
2026 | /// Returns the demanded splatted constant FP or null if this is not a |
2027 | /// constant FP splat. |
2028 | /// |
2029 | /// The DemandedElts mask indicates the elements that must be in the splat. |
2030 | /// If passed a non-null UndefElements bitvector, it will resize it to match |
2031 | /// the vector width and set the bits where elements are undef. |
2032 | ConstantFPSDNode * |
2033 | getConstantFPSplatNode(const APInt &DemandedElts, |
2034 | BitVector *UndefElements = nullptr) const; |
2035 | |
2036 | /// Returns the splatted constant FP or null if this is not a constant |
2037 | /// FP splat. |
2038 | /// |
2039 | /// If passed a non-null UndefElements bitvector, it will resize it to match |
2040 | /// the vector width and set the bits where elements are undef. |
2041 | ConstantFPSDNode * |
2042 | getConstantFPSplatNode(BitVector *UndefElements = nullptr) const; |
2043 | |
2044 | /// If this is a constant FP splat and the splatted constant FP is an |
2045 | /// exact power or 2, return the log base 2 integer value. Otherwise, |
2046 | /// return -1. |
2047 | /// |
2048 | /// The BitWidth specifies the necessary bit precision. |
2049 | int32_t getConstantFPSplatPow2ToLog2Int(BitVector *UndefElements, |
2050 | uint32_t BitWidth) const; |
2051 | |
2052 | bool isConstant() const; |
2053 | |
2054 | static bool classof(const SDNode *N) { |
2055 | return N->getOpcode() == ISD::BUILD_VECTOR; |
2056 | } |
2057 | }; |
2058 | |
2059 | /// An SDNode that holds an arbitrary LLVM IR Value. This is |
2060 | /// used when the SelectionDAG needs to make a simple reference to something |
2061 | /// in the LLVM IR representation. |
2062 | /// |
2063 | class SrcValueSDNode : public SDNode { |
2064 | friend class SelectionDAG; |
2065 | |
2066 | const Value *V; |
2067 | |
2068 | /// Create a SrcValue for a general value. |
2069 | explicit SrcValueSDNode(const Value *v) |
2070 | : SDNode(ISD::SRCVALUE, 0, DebugLoc(), getSDVTList(MVT::Other)), V(v) {} |
2071 | |
2072 | public: |
2073 | /// Return the contained Value. |
2074 | const Value *getValue() const { return V; } |
2075 | |
2076 | static bool classof(const SDNode *N) { |
2077 | return N->getOpcode() == ISD::SRCVALUE; |
2078 | } |
2079 | }; |
2080 | |
2081 | class MDNodeSDNode : public SDNode { |
2082 | friend class SelectionDAG; |
2083 | |
2084 | const MDNode *MD; |
2085 | |
2086 | explicit MDNodeSDNode(const MDNode *md) |
2087 | : SDNode(ISD::MDNODE_SDNODE, 0, DebugLoc(), getSDVTList(MVT::Other)), MD(md) |
2088 | {} |
2089 | |
2090 | public: |
2091 | const MDNode *getMD() const { return MD; } |
2092 | |
2093 | static bool classof(const SDNode *N) { |
2094 | return N->getOpcode() == ISD::MDNODE_SDNODE; |
2095 | } |
2096 | }; |
2097 | |
2098 | class RegisterSDNode : public SDNode { |
2099 | friend class SelectionDAG; |
2100 | |
2101 | Register Reg; |
2102 | |
2103 | RegisterSDNode(Register reg, EVT VT) |
2104 | : SDNode(ISD::Register, 0, DebugLoc(), getSDVTList(VT)), Reg(reg) {} |
2105 | |
2106 | public: |
2107 | Register getReg() const { return Reg; } |
2108 | |
2109 | static bool classof(const SDNode *N) { |
2110 | return N->getOpcode() == ISD::Register; |
2111 | } |
2112 | }; |
2113 | |
2114 | class RegisterMaskSDNode : public SDNode { |
2115 | friend class SelectionDAG; |
2116 | |
2117 | // The memory for RegMask is not owned by the node. |
2118 | const uint32_t *RegMask; |
2119 | |
2120 | RegisterMaskSDNode(const uint32_t *mask) |
2121 | : SDNode(ISD::RegisterMask, 0, DebugLoc(), getSDVTList(MVT::Untyped)), |
2122 | RegMask(mask) {} |
2123 | |
2124 | public: |
2125 | const uint32_t *getRegMask() const { return RegMask; } |
2126 | |
2127 | static bool classof(const SDNode *N) { |
2128 | return N->getOpcode() == ISD::RegisterMask; |
2129 | } |
2130 | }; |
2131 | |
2132 | class BlockAddressSDNode : public SDNode { |
2133 | friend class SelectionDAG; |
2134 | |
2135 | const BlockAddress *BA; |
2136 | int64_t Offset; |
2137 | unsigned TargetFlags; |
2138 | |
2139 | BlockAddressSDNode(unsigned NodeTy, EVT VT, const BlockAddress *ba, |
2140 | int64_t o, unsigned Flags) |
2141 | : SDNode(NodeTy, 0, DebugLoc(), getSDVTList(VT)), |
2142 | BA(ba), Offset(o), TargetFlags(Flags) {} |
2143 | |
2144 | public: |
2145 | const BlockAddress *getBlockAddress() const { return BA; } |
2146 | int64_t getOffset() const { return Offset; } |
2147 | unsigned getTargetFlags() const { return TargetFlags; } |
2148 | |
2149 | static bool classof(const SDNode *N) { |
2150 | return N->getOpcode() == ISD::BlockAddress || |
2151 | N->getOpcode() == ISD::TargetBlockAddress; |
2152 | } |
2153 | }; |
2154 | |
2155 | class LabelSDNode : public SDNode { |
2156 | friend class SelectionDAG; |
2157 | |
2158 | MCSymbol *Label; |
2159 | |
2160 | LabelSDNode(unsigned Opcode, unsigned Order, const DebugLoc &dl, MCSymbol *L) |
2161 | : SDNode(Opcode, Order, dl, getSDVTList(MVT::Other)), Label(L) { |
2162 | assert(LabelSDNode::classof(this) && "not a label opcode")(static_cast <bool> (LabelSDNode::classof(this) && "not a label opcode") ? void (0) : __assert_fail ("LabelSDNode::classof(this) && \"not a label opcode\"" , "/build/llvm-toolchain-snapshot-14~++20211017100700+d245f2e8597b/llvm/include/llvm/CodeGen/SelectionDAGNodes.h" , 2162, __extension__ __PRETTY_FUNCTION__)); |
2163 | } |
2164 | |
2165 | public: |
2166 | MCSymbol *getLabel() const { return Label; } |
2167 | |
2168 | static bool classof(const SDNode *N) { |
2169 | return N->getOpcode() == ISD::EH_LABEL || |
2170 | N->getOpcode() == ISD::ANNOTATION_LABEL; |
2171 | } |
2172 | }; |
2173 | |
2174 | class ExternalSymbolSDNode : public SDNode { |
2175 | friend class SelectionDAG; |
2176 | |
2177 | const char *Symbol; |
2178 | unsigned TargetFlags; |
2179 | |
2180 | ExternalSymbolSDNode(bool isTarget, const char *Sym, unsigned TF, EVT VT) |
2181 | : SDNode(isTarget ? ISD::TargetExternalSymbol : ISD::ExternalSymbol, 0, |
2182 | DebugLoc(), getSDVTList(VT)), |
2183 | Symbol(Sym), TargetFlags(TF) {} |
2184 | |
2185 | public: |
2186 | const char *getSymbol() const { return Symbol; } |
2187 | unsigned getTargetFlags() const { return TargetFlags; } |
2188 | |
2189 | static bool classof(const SDNode *N) { |
2190 | return N->getOpcode() == ISD::ExternalSymbol || |
2191 | N->getOpcode() == ISD::TargetExternalSymbol; |
2192 | } |
2193 | }; |
2194 | |
2195 | class MCSymbolSDNode : public SDNode { |
2196 | friend class SelectionDAG; |
2197 | |
2198 | MCSymbol *Symbol; |
2199 | |
2200 | MCSymbolSDNode(MCSymbol *Symbol, EVT VT) |
2201 | : SDNode(ISD::MCSymbol, 0, DebugLoc(), getSDVTList(VT)), Symbol(Symbol) {} |
2202 | |
2203 | public: |
2204 | MCSymbol *getMCSymbol() const { return Symbol; } |
2205 | |
2206 | static bool classof(const SDNode *N) { |
2207 | return N->getOpcode() == ISD::MCSymbol; |
2208 | } |
2209 | }; |
2210 | |
2211 | class CondCodeSDNode : public SDNode { |
2212 | friend class SelectionDAG; |
2213 | |
2214 | ISD::CondCode Condition; |
2215 | |
2216 | explicit CondCodeSDNode(ISD::CondCode Cond) |
2217 | : SDNode(ISD::CONDCODE, 0, DebugLoc(), getSDVTList(MVT::Other)), |
2218 | Condition(Cond) {} |
2219 | |
2220 | public: |
2221 | ISD::CondCode get() const { return Condition; } |
2222 | |
2223 | static bool classof(const SDNode *N) { |
2224 | return N->getOpcode() == ISD::CONDCODE; |
2225 | } |
2226 | }; |
2227 | |
2228 | /// This class is used to represent EVT's, which are used |
2229 | /// to parameterize some operations. |
2230 | class VTSDNode : public SDNode { |
2231 | friend class SelectionDAG; |
2232 | |
2233 | EVT ValueType; |
2234 | |
2235 | explicit VTSDNode(EVT VT) |
2236 | : SDNode(ISD::VALUETYPE, 0, DebugLoc(), getSDVTList(MVT::Other)), |
2237 | ValueType(VT) {} |
2238 | |
2239 | public: |
2240 | EVT getVT() const { return ValueType; } |
2241 | |
2242 | static bool classof(const SDNode *N) { |
2243 | return N->getOpcode() == ISD::VALUETYPE; |
2244 | } |
2245 | }; |
2246 | |
2247 | /// Base class for LoadSDNode and StoreSDNode |
2248 | class LSBaseSDNode : public MemSDNode { |
2249 | public: |
2250 | LSBaseSDNode(ISD::NodeType NodeTy, unsigned Order, const DebugLoc &dl, |
2251 | SDVTList VTs, ISD::MemIndexedMode AM, EVT MemVT, |
2252 | MachineMemOperand *MMO) |
2253 | : MemSDNode(NodeTy, Order, dl, VTs, MemVT, MMO) { |
2254 | LSBaseSDNodeBits.AddressingMode = AM; |
2255 | assert(getAddressingMode() == AM && "Value truncated")(static_cast <bool> (getAddressingMode() == AM && "Value truncated") ? void (0) : __assert_fail ("getAddressingMode() == AM && \"Value truncated\"" , "/build/llvm-toolchain-snapshot-14~++20211017100700+d245f2e8597b/llvm/include/llvm/CodeGen/SelectionDAGNodes.h" , 2255, __extension__ __PRETTY_FUNCTION__)); |
2256 | } |
2257 | |
2258 | const SDValue &getOffset() const { |
2259 | return getOperand(getOpcode() == ISD::LOAD ? 2 : 3); |
2260 | } |
2261 | |
2262 | /// Return the addressing mode for this load or store: |
2263 | /// unindexed, pre-inc, pre-dec, post-inc, or post-dec. |
2264 | ISD::MemIndexedMode getAddressingMode() const { |
2265 | return static_cast<ISD::MemIndexedMode>(LSBaseSDNodeBits.AddressingMode); |
2266 | } |
2267 | |
2268 | /// Return true if this is a pre/post inc/dec load/store. |
2269 | bool isIndexed() const { return getAddressingMode() != ISD::UNINDEXED; } |
2270 | |
2271 | /// Return true if this is NOT a pre/post inc/dec load/store. |
2272 | bool isUnindexed() const { return getAddressingMode() == ISD::UNINDEXED; } |
2273 | |
2274 | static bool classof(const SDNode *N) { |
2275 | return N->getOpcode() == ISD::LOAD || |
2276 | N->getOpcode() == ISD::STORE; |
2277 | } |
2278 | }; |
2279 | |
2280 | /// This class is used to represent ISD::LOAD nodes. |
2281 | class LoadSDNode : public LSBaseSDNode { |
2282 | friend class SelectionDAG; |
2283 | |
2284 | LoadSDNode(unsigned Order, const DebugLoc &dl, SDVTList VTs, |
2285 | ISD::MemIndexedMode AM, ISD::LoadExtType ETy, EVT MemVT, |
2286 | MachineMemOperand *MMO) |
2287 | : LSBaseSDNode(ISD::LOAD, Order, dl, VTs, AM, MemVT, MMO) { |
2288 | LoadSDNodeBits.ExtTy = ETy; |
2289 | assert(readMem() && "Load MachineMemOperand is not a load!")(static_cast <bool> (readMem() && "Load MachineMemOperand is not a load!" ) ? void (0) : __assert_fail ("readMem() && \"Load MachineMemOperand is not a load!\"" , "/build/llvm-toolchain-snapshot-14~++20211017100700+d245f2e8597b/llvm/include/llvm/CodeGen/SelectionDAGNodes.h" , 2289, __extension__ __PRETTY_FUNCTION__)); |
2290 | assert(!writeMem() && "Load MachineMemOperand is a store!")(static_cast <bool> (!writeMem() && "Load MachineMemOperand is a store!" ) ? void (0) : __assert_fail ("!writeMem() && \"Load MachineMemOperand is a store!\"" , "/build/llvm-toolchain-snapshot-14~++20211017100700+d245f2e8597b/llvm/include/llvm/CodeGen/SelectionDAGNodes.h" , 2290, __extension__ __PRETTY_FUNCTION__)); |
2291 | } |
2292 | |
2293 | public: |
2294 | /// Return whether this is a plain node, |
2295 | /// or one of the varieties of value-extending loads. |
2296 | ISD::LoadExtType getExtensionType() const { |
2297 | return static_cast<ISD::LoadExtType>(LoadSDNodeBits.ExtTy); |
2298 | } |
2299 | |
2300 | const SDValue &getBasePtr() const { return getOperand(1); } |
2301 | const SDValue &getOffset() const { return getOperand(2); } |
2302 | |
2303 | static bool classof(const SDNode *N) { |
2304 | return N->getOpcode() == ISD::LOAD; |
2305 | } |
2306 | }; |
2307 | |
2308 | /// This class is used to represent ISD::STORE nodes. |
2309 | class StoreSDNode : public LSBaseSDNode { |
2310 | friend class SelectionDAG; |
2311 | |
2312 | StoreSDNode(unsigned Order, const DebugLoc &dl, SDVTList VTs, |
2313 | ISD::MemIndexedMode AM, bool isTrunc, EVT MemVT, |
2314 | MachineMemOperand *MMO) |
2315 | : LSBaseSDNode(ISD::STORE, Order, dl, VTs, AM, MemVT, MMO) { |
2316 | StoreSDNodeBits.IsTruncating = isTrunc; |
2317 | assert(!readMem() && "Store MachineMemOperand is a load!")(static_cast <bool> (!readMem() && "Store MachineMemOperand is a load!" ) ? void (0) : __assert_fail ("!readMem() && \"Store MachineMemOperand is a load!\"" , "/build/llvm-toolchain-snapshot-14~++20211017100700+d245f2e8597b/llvm/include/llvm/CodeGen/SelectionDAGNodes.h" , 2317, __extension__ __PRETTY_FUNCTION__)); |
2318 | assert(writeMem() && "Store MachineMemOperand is not a store!")(static_cast <bool> (writeMem() && "Store MachineMemOperand is not a store!" ) ? void (0) : __assert_fail ("writeMem() && \"Store MachineMemOperand is not a store!\"" , "/build/llvm-toolchain-snapshot-14~++20211017100700+d245f2e8597b/llvm/include/llvm/CodeGen/SelectionDAGNodes.h" , 2318, __extension__ __PRETTY_FUNCTION__)); |
2319 | } |
2320 | |
2321 | public: |
2322 | /// Return true if the op does a truncation before store. |
2323 | /// For integers this is the same as doing a TRUNCATE and storing the result. |
2324 | /// For floats, it is the same as doing an FP_ROUND and storing the result. |
2325 | bool isTruncatingStore() const { return StoreSDNodeBits.IsTruncating; } |
2326 | void setTruncatingStore(bool Truncating) { |
2327 | StoreSDNodeBits.IsTruncating = Truncating; |
2328 | } |
2329 | |
2330 | const SDValue &getValue() const { return getOperand(1); } |
2331 | const SDValue &getBasePtr() const { return getOperand(2); } |
2332 | const SDValue &getOffset() const { return getOperand(3); } |
2333 | |
2334 | static bool classof(const SDNode *N) { |
2335 | return N->getOpcode() == ISD::STORE; |
2336 | } |
2337 | }; |
2338 | |
2339 | /// This base class is used to represent VP_LOAD and VP_STORE nodes |
2340 | class VPLoadStoreSDNode : public MemSDNode { |
2341 | public: |
2342 | friend class SelectionDAG; |
2343 | |
2344 | VPLoadStoreSDNode(ISD::NodeType NodeTy, unsigned Order, const DebugLoc &dl, |
2345 | SDVTList VTs, ISD::MemIndexedMode AM, EVT MemVT, |
2346 | MachineMemOperand *MMO) |
2347 | : MemSDNode(NodeTy, Order, dl, VTs, MemVT, MMO) { |
2348 | LSBaseSDNodeBits.AddressingMode = AM; |
2349 | assert(getAddressingMode() == AM && "Value truncated")(static_cast <bool> (getAddressingMode() == AM && "Value truncated") ? void (0) : __assert_fail ("getAddressingMode() == AM && \"Value truncated\"" , "/build/llvm-toolchain-snapshot-14~++20211017100700+d245f2e8597b/llvm/include/llvm/CodeGen/SelectionDAGNodes.h" , 2349, __extension__ __PRETTY_FUNCTION__)); |
2350 | } |
2351 | |
2352 | // VPLoadSDNode (Chain, Ptr, Offset, Mask, EVL) |
2353 | // VPStoreSDNode (Chain, Data, Ptr, Offset, Mask, EVL) |
2354 | // Mask is a vector of i1 elements; |
2355 | // the type of EVL is TLI.getVPExplicitVectorLengthTy(). |
2356 | const SDValue &getOffset() const { |
2357 | return getOperand(getOpcode() == ISD::VP_LOAD ? 2 : 3); |
2358 | } |
2359 | const SDValue &getBasePtr() const { |
2360 | return getOperand(getOpcode() == ISD::VP_LOAD ? 1 : 2); |
2361 | } |
2362 | const SDValue &getMask() const { |
2363 | return getOperand(getOpcode() == ISD::VP_LOAD ? 3 : 4); |
2364 | } |
2365 | const SDValue &getVectorLength() const { |
2366 | return getOperand(getOpcode() == ISD::VP_LOAD ? 4 : 5); |
2367 | } |
2368 | |
2369 | /// Return the addressing mode for this load or store: |
2370 | /// unindexed, pre-inc, pre-dec, post-inc, or post-dec. |
2371 | ISD::MemIndexedMode getAddressingMode() const { |
2372 | return static_cast<ISD::MemIndexedMode>(LSBaseSDNodeBits.AddressingMode); |
2373 | } |
2374 | |
2375 | /// Return true if this is a pre/post inc/dec load/store. |
2376 | bool isIndexed() const { return getAddressingMode() != ISD::UNINDEXED; } |
2377 | |
2378 | /// Return true if this is NOT a pre/post inc/dec load/store. |
2379 | bool isUnindexed() const { return getAddressingMode() == ISD::UNINDEXED; } |
2380 | |
2381 | static bool classof(const SDNode *N) { |
2382 | return N->getOpcode() == ISD::VP_LOAD || N->getOpcode() == ISD::VP_STORE; |
2383 | } |
2384 | }; |
2385 | |
2386 | /// This class is used to represent a VP_LOAD node |
2387 | class VPLoadSDNode : public VPLoadStoreSDNode { |
2388 | public: |
2389 | friend class SelectionDAG; |
2390 | |
2391 | VPLoadSDNode(unsigned Order, const DebugLoc &dl, SDVTList VTs, |
2392 | ISD::MemIndexedMode AM, ISD::LoadExtType ETy, bool isExpanding, |
2393 | EVT MemVT, MachineMemOperand *MMO) |
2394 | : VPLoadStoreSDNode(ISD::VP_LOAD, Order, dl, VTs, AM, MemVT, MMO) { |
2395 | LoadSDNodeBits.ExtTy = ETy; |
2396 | LoadSDNodeBits.IsExpanding = isExpanding; |
2397 | } |
2398 | |
2399 | ISD::LoadExtType getExtensionType() const { |
2400 | return static_cast<ISD::LoadExtType>(LoadSDNodeBits.ExtTy); |
2401 | } |
2402 | |
2403 | const SDValue &getBasePtr() const { return getOperand(1); } |
2404 | const SDValue &getOffset() const { return getOperand(2); } |
2405 | const SDValue &getMask() const { return getOperand(3); } |
2406 | const SDValue &getVectorLength() const { return getOperand(4); } |
2407 | |
2408 | static bool classof(const SDNode *N) { |
2409 | return N->getOpcode() == ISD::VP_LOAD; |
2410 | } |
2411 | bool isExpandingLoad() const { return LoadSDNodeBits.IsExpanding; } |
2412 | }; |
2413 | |
2414 | /// This class is used to represent a VP_STORE node |
2415 | class VPStoreSDNode : public VPLoadStoreSDNode { |
2416 | public: |
2417 | friend class SelectionDAG; |
2418 | |
2419 | VPStoreSDNode(unsigned Order, const DebugLoc &dl, SDVTList VTs, |
2420 | ISD::MemIndexedMode AM, bool isTrunc, bool isCompressing, |
2421 | EVT MemVT, MachineMemOperand *MMO) |
2422 | : VPLoadStoreSDNode(ISD::VP_STORE, Order, dl, VTs, AM, MemVT, MMO) { |
2423 | StoreSDNodeBits.IsTruncating = isTrunc; |
2424 | StoreSDNodeBits.IsCompressing = isCompressing; |
2425 | } |
2426 | |
2427 | /// Return true if this is a truncating store. |
2428 | /// For integers this is the same as doing a TRUNCATE and storing the result. |
2429 | /// For floats, it is the same as doing an FP_ROUND and storing the result. |
2430 | bool isTruncatingStore() const { return StoreSDNodeBits.IsTruncating; } |
2431 | |
2432 | /// Returns true if the op does a compression to the vector before storing. |
2433 | /// The node contiguously stores the active elements (integers or floats) |
2434 | /// in src (those with their respective bit set in writemask k) to unaligned |
2435 | /// memory at base_addr. |
2436 | bool isCompressingStore() const { return StoreSDNodeBits.IsCompressing; } |
2437 | |
2438 | const SDValue &getValue() const { return getOperand(1); } |
2439 | const SDValue &getBasePtr() const { return getOperand(2); } |
2440 | const SDValue &getOffset() const { return getOperand(3); } |
2441 | const SDValue &getMask() const { return getOperand(4); } |
2442 | const SDValue &getVectorLength() const { return getOperand(5); } |
2443 | |
2444 | static bool classof(const SDNode *N) { |
2445 | return N->getOpcode() == ISD::VP_STORE; |
2446 | } |
2447 | }; |
2448 | |
2449 | /// This base class is used to represent MLOAD and MSTORE nodes |
2450 | class MaskedLoadStoreSDNode : public MemSDNode { |
2451 | public: |
2452 | friend class SelectionDAG; |
2453 | |
2454 | MaskedLoadStoreSDNode(ISD::NodeType NodeTy, unsigned Order, |
2455 | const DebugLoc &dl, SDVTList VTs, |
2456 | ISD::MemIndexedMode AM, EVT MemVT, |
2457 | MachineMemOperand *MMO) |
2458 | : MemSDNode(NodeTy, Order, dl, VTs, MemVT, MMO) { |
2459 | LSBaseSDNodeBits.AddressingMode = AM; |
2460 | assert(getAddressingMode() == AM && "Value truncated")(static_cast <bool> (getAddressingMode() == AM && "Value truncated") ? void (0) : __assert_fail ("getAddressingMode() == AM && \"Value truncated\"" , "/build/llvm-toolchain-snapshot-14~++20211017100700+d245f2e8597b/llvm/include/llvm/CodeGen/SelectionDAGNodes.h" , 2460, __extension__ __PRETTY_FUNCTION__)); |
2461 | } |
2462 | |
2463 | // MaskedLoadSDNode (Chain, ptr, offset, mask, passthru) |
2464 | // MaskedStoreSDNode (Chain, data, ptr, offset, mask) |
2465 | // Mask is a vector of i1 elements |
2466 | const SDValue &getOffset() const { |
2467 | return getOperand(getOpcode() == ISD::MLOAD ? 2 : 3); |
2468 | } |
2469 | const SDValue &getMask() const { |
2470 | return getOperand(getOpcode() == ISD::MLOAD ? 3 : 4); |
2471 | } |
2472 | |
2473 | /// Return the addressing mode for this load or store: |
2474 | /// unindexed, pre-inc, pre-dec, post-inc, or post-dec. |
2475 | ISD::MemIndexedMode getAddressingMode() const { |
2476 | return static_cast<ISD::MemIndexedMode>(LSBaseSDNodeBits.AddressingMode); |
2477 | } |
2478 | |
2479 | /// Return true if this is a pre/post inc/dec load/store. |
2480 | bool isIndexed() const { return getAddressingMode() != ISD::UNINDEXED; } |
2481 | |
2482 | /// Return true if this is NOT a pre/post inc/dec load/store. |
2483 | bool isUnindexed() const { return getAddressingMode() == ISD::UNINDEXED; } |
2484 | |
2485 | static bool classof(const SDNode *N) { |
2486 | return N->getOpcode() == ISD::MLOAD || |
2487 | N->getOpcode() == ISD::MSTORE; |
2488 | } |
2489 | }; |
2490 | |
2491 | /// This class is used to represent an MLOAD node |
2492 | class MaskedLoadSDNode : public MaskedLoadStoreSDNode { |
2493 | public: |
2494 | friend class SelectionDAG; |
2495 | |
2496 | MaskedLoadSDNode(unsigned Order, const DebugLoc &dl, SDVTList VTs, |
2497 | ISD::MemIndexedMode AM, ISD::LoadExtType ETy, |
2498 | bool IsExpanding, EVT MemVT, MachineMemOperand *MMO) |
2499 | : MaskedLoadStoreSDNode(ISD::MLOAD, Order, dl, VTs, AM, MemVT, MMO) { |
2500 | LoadSDNodeBits.ExtTy = ETy; |
2501 | LoadSDNodeBits.IsExpanding = IsExpanding; |
2502 | } |
2503 | |
2504 | ISD::LoadExtType getExtensionType() const { |
2505 | return static_cast<ISD::LoadExtType>(LoadSDNodeBits.ExtTy); |
2506 | } |
2507 | |
2508 | const SDValue &getBasePtr() const { return getOperand(1); } |
2509 | const SDValue &getOffset() const { return getOperand(2); } |
2510 | const SDValue &getMask() const { return getOperand(3); } |
2511 | const SDValue &getPassThru() const { return getOperand(4); } |
2512 | |
2513 | static bool classof(const SDNode *N) { |
2514 | return N->getOpcode() == ISD::MLOAD; |
2515 | } |
2516 | |
2517 | bool isExpandingLoad() const { return LoadSDNodeBits.IsExpanding; } |
2518 | }; |
2519 | |
2520 | /// This class is used to represent an MSTORE node |
2521 | class MaskedStoreSDNode : public MaskedLoadStoreSDNode { |
2522 | public: |
2523 | friend class SelectionDAG; |
2524 | |
2525 | MaskedStoreSDNode(unsigned Order, const DebugLoc &dl, SDVTList VTs, |
2526 | ISD::MemIndexedMode AM, bool isTrunc, bool isCompressing, |
2527 | EVT MemVT, MachineMemOperand *MMO) |
2528 | : MaskedLoadStoreSDNode(ISD::MSTORE, Order, dl, VTs, AM, MemVT, MMO) { |
2529 | StoreSDNodeBits.IsTruncating = isTrunc; |
2530 | StoreSDNodeBits.IsCompressing = isCompressing; |
2531 | } |
2532 | |
2533 | /// Return true if the op does a truncation before store. |
2534 | /// For integers this is the same as doing a TRUNCATE and storing the result. |
2535 | /// For floats, it is the same as doing an FP_ROUND and storing the result. |
2536 | bool isTruncatingStore() const { return StoreSDNodeBits.IsTruncating; } |
2537 | |
2538 | /// Returns true if the op does a compression to the vector before storing. |
2539 | /// The node contiguously stores the active elements (integers or floats) |
2540 | /// in src (those with their respective bit set in writemask k) to unaligned |
2541 | /// memory at base_addr. |
2542 | bool isCompressingStore() const { return StoreSDNodeBits.IsCompressing; } |
2543 | |
2544 | const SDValue &getValue() const { return getOperand(1); } |
2545 | const SDValue &getBasePtr() const { return getOperand(2); } |
2546 | const SDValue &getOffset() const { return getOperand(3); } |
2547 | const SDValue &getMask() const { return getOperand(4); } |
2548 | |
2549 | static bool classof(const SDNode *N) { |
2550 | return N->getOpcode() == ISD::MSTORE; |
2551 | } |
2552 | }; |
2553 | |
2554 | /// This is a base class used to represent |
2555 | /// VP_GATHER and VP_SCATTER nodes |
2556 | /// |
2557 | class VPGatherScatterSDNode : public MemSDNode { |
2558 | public: |
2559 | friend class SelectionDAG; |
2560 | |
2561 | VPGatherScatterSDNode(ISD::NodeType NodeTy, unsigned Order, |
2562 | const DebugLoc &dl, SDVTList VTs, EVT MemVT, |
2563 | MachineMemOperand *MMO, ISD::MemIndexType IndexType) |
2564 | : MemSDNode(NodeTy, Order, dl, VTs, MemVT, MMO) { |
2565 | LSBaseSDNodeBits.AddressingMode = IndexType; |
2566 | assert(getIndexType() == IndexType && "Value truncated")(static_cast <bool> (getIndexType() == IndexType && "Value truncated") ? void (0) : __assert_fail ("getIndexType() == IndexType && \"Value truncated\"" , "/build/llvm-toolchain-snapshot-14~++20211017100700+d245f2e8597b/llvm/include/llvm/CodeGen/SelectionDAGNodes.h" , 2566, __extension__ __PRETTY_FUNCTION__)); |
2567 | } |
2568 | |
2569 | /// How is Index applied to BasePtr when computing addresses. |
2570 | ISD::MemIndexType getIndexType() const { |
2571 | return static_cast<ISD::MemIndexType>(LSBaseSDNodeBits.AddressingMode); |
2572 | } |
2573 | bool isIndexScaled() const { |
2574 | return (getIndexType() == ISD::SIGNED_SCALED) || |
2575 | (getIndexType() == ISD::UNSIGNED_SCALED); |
2576 | } |
2577 | bool isIndexSigned() const { |
2578 | return (getIndexType() == ISD::SIGNED_SCALED) || |
2579 | (getIndexType() == ISD::SIGNED_UNSCALED); |
2580 | } |
2581 | |
2582 | // In the both nodes address is Op1, mask is Op2: |
2583 | // VPGatherSDNode (Chain, base, index, scale, mask, vlen) |
2584 | // VPScatterSDNode (Chain, value, base, index, scale, mask, vlen) |
2585 | // Mask is a vector of i1 elements |
2586 | const SDValue &getBasePtr() const { |
2587 | return getOperand((getOpcode() == ISD::VP_GATHER) ? 1 : 2); |
2588 | } |
2589 | const SDValue &getIndex() const { |
2590 | return getOperand((getOpcode() == ISD::VP_GATHER) ? 2 : 3); |
2591 | } |
2592 | const SDValue &getScale() const { |
2593 | return getOperand((getOpcode() == ISD::VP_GATHER) ? 3 : 4); |
2594 | } |
2595 | const SDValue &getMask() const { |
2596 | return getOperand((getOpcode() == ISD::VP_GATHER) ? 4 : 5); |
2597 | } |
2598 | const SDValue &getVectorLength() const { |
2599 | return getOperand((getOpcode() == ISD::VP_GATHER) ? 5 : 6); |
2600 | } |
2601 | |
2602 | static bool classof(const SDNode *N) { |
2603 | return N->getOpcode() == ISD::VP_GATHER || |
2604 | N->getOpcode() == ISD::VP_SCATTER; |
2605 | } |
2606 | }; |
2607 | |
2608 | /// This class is used to represent an VP_GATHER node |
2609 | /// |
2610 | class VPGatherSDNode : public VPGatherScatterSDNode { |
2611 | public: |
2612 | friend class SelectionDAG; |
2613 | |
2614 | VPGatherSDNode(unsigned Order, const DebugLoc &dl, SDVTList VTs, EVT MemVT, |
2615 | MachineMemOperand *MMO, ISD::MemIndexType IndexType) |
2616 | : VPGatherScatterSDNode(ISD::VP_GATHER, Order, dl, VTs, MemVT, MMO, |
2617 | IndexType) {} |
2618 | |
2619 | static bool classof(const SDNode *N) { |
2620 | return N->getOpcode() == ISD::VP_GATHER; |
2621 | } |
2622 | }; |
2623 | |
2624 | /// This class is used to represent an VP_SCATTER node |
2625 | /// |
2626 | class VPScatterSDNode : public VPGatherScatterSDNode { |
2627 | public: |
2628 | friend class SelectionDAG; |
2629 | |
2630 | VPScatterSDNode(unsigned Order, const DebugLoc &dl, SDVTList VTs, EVT MemVT, |
2631 | MachineMemOperand *MMO, ISD::MemIndexType IndexType) |
2632 | : VPGatherScatterSDNode(ISD::VP_SCATTER, Order, dl, VTs, MemVT, MMO, |
2633 | IndexType) {} |
2634 | |
2635 | const SDValue &getValue() const { return getOperand(1); } |
2636 | |
2637 | static bool classof(const SDNode *N) { |
2638 | return N->getOpcode() == ISD::VP_SCATTER; |
2639 | } |
2640 | }; |
2641 | |
2642 | /// This is a base class used to represent |
2643 | /// MGATHER and MSCATTER nodes |
2644 | /// |
2645 | class MaskedGatherScatterSDNode : public MemSDNode { |
2646 | public: |
2647 | friend class SelectionDAG; |
2648 | |
2649 | MaskedGatherScatterSDNode(ISD::NodeType NodeTy, unsigned Order, |
2650 | const DebugLoc &dl, SDVTList VTs, EVT MemVT, |
2651 | MachineMemOperand *MMO, ISD::MemIndexType IndexType) |
2652 | : MemSDNode(NodeTy, Order, dl, VTs, MemVT, MMO) { |
2653 | LSBaseSDNodeBits.AddressingMode = IndexType; |
2654 | assert(getIndexType() == IndexType && "Value truncated")(static_cast <bool> (getIndexType() == IndexType && "Value truncated") ? void (0) : __assert_fail ("getIndexType() == IndexType && \"Value truncated\"" , "/build/llvm-toolchain-snapshot-14~++20211017100700+d245f2e8597b/llvm/include/llvm/CodeGen/SelectionDAGNodes.h" , 2654, __extension__ __PRETTY_FUNCTION__)); |
2655 | } |
2656 | |
2657 | /// How is Index applied to BasePtr when computing addresses. |
2658 | ISD::MemIndexType getIndexType() const { |
2659 | return static_cast<ISD::MemIndexType>(LSBaseSDNodeBits.AddressingMode); |
2660 | } |
2661 | void setIndexType(ISD::MemIndexType IndexType) { |
2662 | LSBaseSDNodeBits.AddressingMode = IndexType; |
2663 | } |
2664 | bool isIndexScaled() const { |
2665 | return (getIndexType() == ISD::SIGNED_SCALED) || |
2666 | (getIndexType() == ISD::UNSIGNED_SCALED); |
2667 | } |
2668 | bool isIndexSigned() const { |
2669 | return (getIndexType() == ISD::SIGNED_SCALED) || |
2670 | (getIndexType() == ISD::SIGNED_UNSCALED); |
2671 | } |
2672 | |
2673 | // In the both nodes address is Op1, mask is Op2: |
2674 | // MaskedGatherSDNode (Chain, passthru, mask, base, index, scale) |
2675 | // MaskedScatterSDNode (Chain, value, mask, base, index, scale) |
2676 | // Mask is a vector of i1 elements |
2677 | const SDValue &getBasePtr() const { return getOperand(3); } |
2678 | const SDValue &getIndex() const { return getOperand(4); } |
2679 | const SDValue &getMask() const { return getOperand(2); } |
2680 | const SDValue &getScale() const { return getOperand(5); } |
2681 | |
2682 | static bool classof(const SDNode *N) { |
2683 | return N->getOpcode() == ISD::MGATHER || |
2684 | N->getOpcode() == ISD::MSCATTER; |
2685 | } |
2686 | }; |
2687 | |
2688 | /// This class is used to represent an MGATHER node |
2689 | /// |
2690 | class MaskedGatherSDNode : public MaskedGatherScatterSDNode { |
2691 | public: |
2692 | friend class SelectionDAG; |
2693 | |
2694 | MaskedGatherSDNode(unsigned Order, const DebugLoc &dl, SDVTList VTs, |
2695 | EVT MemVT, MachineMemOperand *MMO, |
2696 | ISD::MemIndexType IndexType, ISD::LoadExtType ETy) |
2697 | : MaskedGatherScatterSDNode(ISD::MGATHER, Order, dl, VTs, MemVT, MMO, |
2698 | IndexType) { |
2699 | LoadSDNodeBits.ExtTy = ETy; |
2700 | } |
2701 | |
2702 | const SDValue &getPassThru() const { return getOperand(1); } |
2703 | |
2704 | ISD::LoadExtType getExtensionType() const { |
2705 | return ISD::LoadExtType(LoadSDNodeBits.ExtTy); |
2706 | } |
2707 | |
2708 | static bool classof(const SDNode *N) { |
2709 | return N->getOpcode() == ISD::MGATHER; |
2710 | } |
2711 | }; |
2712 | |
2713 | /// This class is used to represent an MSCATTER node |
2714 | /// |
2715 | class MaskedScatterSDNode : public MaskedGatherScatterSDNode { |
2716 | public: |
2717 | friend class SelectionDAG; |
2718 | |
2719 | MaskedScatterSDNode(unsigned Order, const DebugLoc &dl, SDVTList VTs, |
2720 | EVT MemVT, MachineMemOperand *MMO, |
2721 | ISD::MemIndexType IndexType, bool IsTrunc) |
2722 | : MaskedGatherScatterSDNode(ISD::MSCATTER, Order, dl, VTs, MemVT, MMO, |
2723 | IndexType) { |
2724 | StoreSDNodeBits.IsTruncating = IsTrunc; |
2725 | } |
2726 | |
2727 | /// Return true if the op does a truncation before store. |
2728 | /// For integers this is the same as doing a TRUNCATE and storing the result. |
2729 | /// For floats, it is the same as doing an FP_ROUND and storing the result. |
2730 | bool isTruncatingStore() const { return StoreSDNodeBits.IsTruncating; } |
2731 | |
2732 | const SDValue &getValue() const { return getOperand(1); } |
2733 | |
2734 | static bool classof(const SDNode *N) { |
2735 | return N->getOpcode() == ISD::MSCATTER; |
2736 | } |
2737 | }; |
2738 | |
2739 | /// An SDNode that represents everything that will be needed |
2740 | /// to construct a MachineInstr. These nodes are created during the |
2741 | /// instruction selection proper phase. |
2742 | /// |
2743 | /// Note that the only supported way to set the `memoperands` is by calling the |
2744 | /// `SelectionDAG::setNodeMemRefs` function as the memory management happens |
2745 | /// inside the DAG rather than in the node. |
2746 | class MachineSDNode : public SDNode { |
2747 | private: |
2748 | friend class SelectionDAG; |
2749 | |
2750 | MachineSDNode(unsigned Opc, unsigned Order, const DebugLoc &DL, SDVTList VTs) |
2751 | : SDNode(Opc, Order, DL, VTs) {} |
2752 | |
2753 | // We use a pointer union between a single `MachineMemOperand` pointer and |
2754 | // a pointer to an array of `MachineMemOperand` pointers. This is null when |
2755 | // the number of these is zero, the single pointer variant used when the |
2756 | // number is one, and the array is used for larger numbers. |
2757 | // |
2758 | // The array is allocated via the `SelectionDAG`'s allocator and so will |
2759 | // always live until the DAG is cleaned up and doesn't require ownership here. |
2760 | // |
2761 | // We can't use something simpler like `TinyPtrVector` here because `SDNode` |
2762 | // subclasses aren't managed in a conforming C++ manner. See the comments on |
2763 | // `SelectionDAG::MorphNodeTo` which details what all goes on, but the |
2764 | // constraint here is that these don't manage memory with their constructor or |
2765 | // destructor and can be initialized to a good state even if they start off |
2766 | // uninitialized. |
2767 | PointerUnion<MachineMemOperand *, MachineMemOperand **> MemRefs = {}; |
2768 | |
2769 | // Note that this could be folded into the above `MemRefs` member if doing so |
2770 | // is advantageous at some point. We don't need to store this in most cases. |
2771 | // However, at the moment this doesn't appear to make the allocation any |
2772 | // smaller and makes the code somewhat simpler to read. |
2773 | int NumMemRefs = 0; |
2774 | |
2775 | public: |
2776 | using mmo_iterator = ArrayRef<MachineMemOperand *>::const_iterator; |
2777 | |
2778 | ArrayRef<MachineMemOperand *> memoperands() const { |
2779 | // Special case the common cases. |
2780 | if (NumMemRefs == 0) |
2781 | return {}; |
2782 | if (NumMemRefs == 1) |
2783 | return makeArrayRef(MemRefs.getAddrOfPtr1(), 1); |
2784 | |
2785 | // Otherwise we have an actual array. |
2786 | return makeArrayRef(MemRefs.get<MachineMemOperand **>(), NumMemRefs); |
2787 | } |
2788 | mmo_iterator memoperands_begin() const { return memoperands().begin(); } |
2789 | mmo_iterator memoperands_end() const { return memoperands().end(); } |
2790 | bool memoperands_empty() const { return memoperands().empty(); } |
2791 | |
2792 | /// Clear out the memory reference descriptor list. |
2793 | void clearMemRefs() { |
2794 | MemRefs = nullptr; |
2795 | NumMemRefs = 0; |
2796 | } |
2797 | |
2798 | static bool classof(const SDNode *N) { |
2799 | return N->isMachineOpcode(); |
2800 | } |
2801 | }; |
2802 | |
2803 | /// An SDNode that records if a register contains a value that is guaranteed to |
2804 | /// be aligned accordingly. |
2805 | class AssertAlignSDNode : public SDNode { |
2806 | Align Alignment; |
2807 | |
2808 | public: |
2809 | AssertAlignSDNode(unsigned Order, const DebugLoc &DL, EVT VT, Align A) |
2810 | : SDNode(ISD::AssertAlign, Order, DL, getSDVTList(VT)), Alignment(A) {} |
2811 | |
2812 | Align getAlign() const { return Alignment; } |
2813 | |
2814 | static bool classof(const SDNode *N) { |
2815 | return N->getOpcode() == ISD::AssertAlign; |
2816 | } |
2817 | }; |
2818 | |
2819 | class SDNodeIterator { |
2820 | const SDNode *Node; |
2821 | unsigned Operand; |
2822 | |
2823 | SDNodeIterator(const SDNode *N, unsigned Op) : Node(N), Operand(Op) {} |
2824 | |
2825 | public: |
2826 | using iterator_category = std::forward_iterator_tag; |
2827 | using value_type = SDNode; |
2828 | using difference_type = std::ptrdiff_t; |
2829 | using pointer = value_type *; |
2830 | using reference = value_type &; |
2831 | |
2832 | bool operator==(const SDNodeIterator& x) const { |
2833 | return Operand == x.Operand; |
2834 | } |
2835 | bool operator!=(const SDNodeIterator& x) const { return !operator==(x); } |
2836 | |
2837 | pointer operator*() const { |
2838 | return Node->getOperand(Operand).getNode(); |
2839 | } |
2840 | pointer operator->() const { return operator*(); } |
2841 | |
2842 | SDNodeIterator& operator++() { // Preincrement |
2843 | ++Operand; |
2844 | return *this; |
2845 | } |
2846 | SDNodeIterator operator++(int) { // Postincrement |
2847 | SDNodeIterator tmp = *this; ++*this; return tmp; |
2848 | } |
2849 | size_t operator-(SDNodeIterator Other) const { |
2850 | assert(Node == Other.Node &&(static_cast <bool> (Node == Other.Node && "Cannot compare iterators of two different nodes!" ) ? void (0) : __assert_fail ("Node == Other.Node && \"Cannot compare iterators of two different nodes!\"" , "/build/llvm-toolchain-snapshot-14~++20211017100700+d245f2e8597b/llvm/include/llvm/CodeGen/SelectionDAGNodes.h" , 2851, __extension__ __PRETTY_FUNCTION__)) |
2851 | "Cannot compare iterators of two different nodes!")(static_cast <bool> (Node == Other.Node && "Cannot compare iterators of two different nodes!" ) ? void (0) : __assert_fail ("Node == Other.Node && \"Cannot compare iterators of two different nodes!\"" , "/build/llvm-toolchain-snapshot-14~++20211017100700+d245f2e8597b/llvm/include/llvm/CodeGen/SelectionDAGNodes.h" , 2851, __extension__ __PRETTY_FUNCTION__)); |
2852 | return Operand - Other.Operand; |
2853 | } |
2854 | |
2855 | static SDNodeIterator begin(const SDNode *N) { return SDNodeIterator(N, 0); } |
2856 | static SDNodeIterator end (const SDNode *N) { |
2857 | return SDNodeIterator(N, N->getNumOperands()); |
2858 | } |
2859 | |
2860 | unsigned getOperand() const { return Operand; } |
2861 | const SDNode *getNode() const { return Node; } |
2862 | }; |
2863 | |
2864 | template <> struct GraphTraits<SDNode*> { |
2865 | using NodeRef = SDNode *; |
2866 | using ChildIteratorType = SDNodeIterator; |
2867 | |
2868 | static NodeRef getEntryNode(SDNode *N) { return N; } |
2869 | |
2870 | static ChildIteratorType child_begin(NodeRef N) { |
2871 | return SDNodeIterator::begin(N); |
2872 | } |
2873 | |
2874 | static ChildIteratorType child_end(NodeRef N) { |
2875 | return SDNodeIterator::end(N); |
2876 | } |
2877 | }; |
2878 | |
2879 | /// A representation of the largest SDNode, for use in sizeof(). |
2880 | /// |
2881 | /// This needs to be a union because the largest node differs on 32 bit systems |
2882 | /// with 4 and 8 byte pointer alignment, respectively. |
2883 | using LargestSDNode = AlignedCharArrayUnion<AtomicSDNode, TargetIndexSDNode, |
2884 | BlockAddressSDNode, |
2885 | GlobalAddressSDNode, |
2886 | PseudoProbeSDNode>; |
2887 | |
2888 | /// The SDNode class with the greatest alignment requirement. |
2889 | using MostAlignedSDNode = GlobalAddressSDNode; |
2890 | |
2891 | namespace ISD { |
2892 | |
2893 | /// Returns true if the specified node is a non-extending and unindexed load. |
2894 | inline bool isNormalLoad(const SDNode *N) { |
2895 | const LoadSDNode *Ld = dyn_cast<LoadSDNode>(N); |
2896 | return Ld && Ld->getExtensionType() == ISD::NON_EXTLOAD && |
2897 | Ld->getAddressingMode() == ISD::UNINDEXED; |
2898 | } |
2899 | |
2900 | /// Returns true if the specified node is a non-extending load. |
2901 | inline bool isNON_EXTLoad(const SDNode *N) { |
2902 | return isa<LoadSDNode>(N) && |
2903 | cast<LoadSDNode>(N)->getExtensionType() == ISD::NON_EXTLOAD; |
2904 | } |
2905 | |
2906 | /// Returns true if the specified node is a EXTLOAD. |
2907 | inline bool isEXTLoad(const SDNode *N) { |
2908 | return isa<LoadSDNode>(N) && |
2909 | cast<LoadSDNode>(N)->getExtensionType() == ISD::EXTLOAD; |
2910 | } |
2911 | |
2912 | /// Returns true if the specified node is a SEXTLOAD. |
2913 | inline bool isSEXTLoad(const SDNode *N) { |
2914 | return isa<LoadSDNode>(N) && |
2915 | cast<LoadSDNode>(N)->getExtensionType() == ISD::SEXTLOAD; |
2916 | } |
2917 | |
2918 | /// Returns true if the specified node is a ZEXTLOAD. |
2919 | inline bool isZEXTLoad(const SDNode *N) { |
2920 | return isa<LoadSDNode>(N) && |
2921 | cast<LoadSDNode>(N)->getExtensionType() == ISD::ZEXTLOAD; |
2922 | } |
2923 | |
2924 | /// Returns true if the specified node is an unindexed load. |
2925 | inline bool isUNINDEXEDLoad(const SDNode *N) { |
2926 | return isa<LoadSDNode>(N) && |
2927 | cast<LoadSDNode>(N)->getAddressingMode() == ISD::UNINDEXED; |
2928 | } |
2929 | |
2930 | /// Returns true if the specified node is a non-truncating |
2931 | /// and unindexed store. |
2932 | inline bool isNormalStore(const SDNode *N) { |
2933 | const StoreSDNode *St = dyn_cast<StoreSDNode>(N); |
2934 | return St && !St->isTruncatingStore() && |
2935 | St->getAddressingMode() == ISD::UNINDEXED; |
2936 | } |
2937 | |
2938 | /// Returns true if the specified node is an unindexed store. |
2939 | inline bool isUNINDEXEDStore(const SDNode *N) { |
2940 | return isa<StoreSDNode>(N) && |
2941 | cast<StoreSDNode>(N)->getAddressingMode() == ISD::UNINDEXED; |
2942 | } |
2943 | |
2944 | /// Attempt to match a unary predicate against a scalar/splat constant or |
2945 | /// every element of a constant BUILD_VECTOR. |
2946 | /// If AllowUndef is true, then UNDEF elements will pass nullptr to Match. |
2947 | bool matchUnaryPredicate(SDValue Op, |
2948 | std::function<bool(ConstantSDNode *)> Match, |
2949 | bool AllowUndefs = false); |
2950 | |
2951 | /// Attempt to match a binary predicate against a pair of scalar/splat |
2952 | /// constants or every element of a pair of constant BUILD_VECTORs. |
2953 | /// If AllowUndef is true, then UNDEF elements will pass nullptr to Match. |
2954 | /// If AllowTypeMismatch is true then RetType + ArgTypes don't need to match. |
2955 | bool matchBinaryPredicate( |
2956 | SDValue LHS, SDValue RHS, |
2957 | std::function<bool(ConstantSDNode *, ConstantSDNode *)> Match, |
2958 | bool AllowUndefs = false, bool AllowTypeMismatch = false); |
2959 | |
2960 | /// Returns true if the specified value is the overflow result from one |
2961 | /// of the overflow intrinsic nodes. |
2962 | inline bool isOverflowIntrOpRes(SDValue Op) { |
2963 | unsigned Opc = Op.getOpcode(); |
2964 | return (Op.getResNo() == 1 && |
2965 | (Opc == ISD::SADDO || Opc == ISD::UADDO || Opc == ISD::SSUBO || |
2966 | Opc == ISD::USUBO || Opc == ISD::SMULO || Opc == ISD::UMULO)); |
2967 | } |
2968 | |
2969 | } // end namespace ISD |
2970 | |
2971 | } // end namespace llvm |
2972 | |
2973 | #endif // LLVM_CODEGEN_SELECTIONDAGNODES_H |