Bug Summary

File:build/source/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
Warning:line 2152, column 9
The result of the left shift is undefined due to shifting by '127', which is greater or equal to the width of type 'long long'

Annotated Source Code

Press '?' to see keyboard shortcuts

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