Line data Source code
1 : //===-- WebAssemblyFastISel.cpp - WebAssembly FastISel implementation -----===//
2 : //
3 : // The LLVM Compiler Infrastructure
4 : //
5 : // This file is distributed under the University of Illinois Open Source
6 : // License. See LICENSE.TXT for details.
7 : //
8 : //===----------------------------------------------------------------------===//
9 : ///
10 : /// \file
11 : /// This file defines the WebAssembly-specific support for the FastISel
12 : /// class. Some of the target-specific code is generated by tablegen in the file
13 : /// WebAssemblyGenFastISel.inc, which is #included here.
14 : ///
15 : /// TODO: kill flags
16 : ///
17 : //===----------------------------------------------------------------------===//
18 :
19 : #include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
20 : #include "WebAssembly.h"
21 : #include "WebAssemblyMachineFunctionInfo.h"
22 : #include "WebAssemblySubtarget.h"
23 : #include "WebAssemblyTargetMachine.h"
24 : #include "llvm/Analysis/BranchProbabilityInfo.h"
25 : #include "llvm/CodeGen/FastISel.h"
26 : #include "llvm/CodeGen/FunctionLoweringInfo.h"
27 : #include "llvm/CodeGen/MachineConstantPool.h"
28 : #include "llvm/CodeGen/MachineFrameInfo.h"
29 : #include "llvm/CodeGen/MachineInstrBuilder.h"
30 : #include "llvm/CodeGen/MachineRegisterInfo.h"
31 : #include "llvm/IR/DataLayout.h"
32 : #include "llvm/IR/DerivedTypes.h"
33 : #include "llvm/IR/Function.h"
34 : #include "llvm/IR/GetElementPtrTypeIterator.h"
35 : #include "llvm/IR/GlobalAlias.h"
36 : #include "llvm/IR/GlobalVariable.h"
37 : #include "llvm/IR/Instructions.h"
38 : #include "llvm/IR/IntrinsicInst.h"
39 : #include "llvm/IR/Operator.h"
40 : using namespace llvm;
41 :
42 : #define DEBUG_TYPE "wasm-fastisel"
43 :
44 : namespace {
45 :
46 : class WebAssemblyFastISel final : public FastISel {
47 : // All possible address modes.
48 : class Address {
49 : public:
50 : typedef enum { RegBase, FrameIndexBase } BaseKind;
51 :
52 : private:
53 : BaseKind Kind;
54 : union {
55 : unsigned Reg;
56 : int FI;
57 : } Base;
58 :
59 : int64_t Offset;
60 :
61 : const GlobalValue *GV;
62 :
63 : public:
64 : // Innocuous defaults for our address.
65 57 : Address() : Kind(RegBase), Offset(0), GV(0) { Base.Reg = 0; }
66 0 : void setKind(BaseKind K) {
67 : assert(!isSet() && "Can't change kind with non-zero base");
68 30 : Kind = K;
69 0 : }
70 : BaseKind getKind() const { return Kind; }
71 0 : bool isRegBase() const { return Kind == RegBase; }
72 : bool isFIBase() const { return Kind == FrameIndexBase; }
73 0 : void setReg(unsigned Reg) {
74 : assert(isRegBase() && "Invalid base register access!");
75 : assert(Base.Reg == 0 && "Overwriting non-zero register");
76 3 : Base.Reg = Reg;
77 0 : }
78 0 : unsigned getReg() const {
79 : assert(isRegBase() && "Invalid base register access!");
80 0 : return Base.Reg;
81 : }
82 0 : void setFI(unsigned FI) {
83 : assert(isFIBase() && "Invalid base frame index access!");
84 : assert(Base.FI == 0 && "Overwriting non-zero frame index");
85 30 : Base.FI = FI;
86 0 : }
87 0 : unsigned getFI() const {
88 : assert(isFIBase() && "Invalid base frame index access!");
89 0 : return Base.FI;
90 : }
91 :
92 0 : void setOffset(int64_t Offset_) {
93 : assert(Offset_ >= 0 && "Offsets must be non-negative");
94 7 : Offset = Offset_;
95 0 : }
96 0 : int64_t getOffset() const { return Offset; }
97 1 : void setGlobalValue(const GlobalValue *G) { GV = G; }
98 0 : const GlobalValue *getGlobalValue() const { return GV; }
99 : bool isSet() const {
100 58 : if (isRegBase()) {
101 58 : return Base.Reg != 0;
102 : } else {
103 0 : return Base.FI != 0;
104 : }
105 : }
106 : };
107 :
108 : /// Keep a pointer to the WebAssemblySubtarget around so that we can make the
109 : /// right decision when generating code for different targets.
110 : const WebAssemblySubtarget *Subtarget;
111 : LLVMContext *Context;
112 :
113 : private:
114 : // Utility helper routines
115 0 : MVT::SimpleValueType getSimpleType(Type *Ty) {
116 0 : EVT VT = TLI.getValueType(DL, Ty, /*HandleUnknown=*/true);
117 1998 : return VT.isSimple() ? VT.getSimpleVT().SimpleTy
118 0 : : MVT::INVALID_SIMPLE_VALUE_TYPE;
119 : }
120 956 : MVT::SimpleValueType getLegalType(MVT::SimpleValueType VT) {
121 956 : switch (VT) {
122 : case MVT::i1:
123 : case MVT::i8:
124 : case MVT::i16:
125 : return MVT::i32;
126 311 : case MVT::i32:
127 : case MVT::i64:
128 : case MVT::f32:
129 : case MVT::f64:
130 : case MVT::ExceptRef:
131 311 : return VT;
132 1 : case MVT::f16:
133 1 : return MVT::f32;
134 612 : case MVT::v16i8:
135 : case MVT::v8i16:
136 : case MVT::v4i32:
137 : case MVT::v2i64:
138 : case MVT::v4f32:
139 : case MVT::v2f64:
140 612 : if (Subtarget->hasSIMD128())
141 612 : return VT;
142 : break;
143 : default:
144 : break;
145 : }
146 : return MVT::INVALID_SIMPLE_VALUE_TYPE;
147 : }
148 : bool computeAddress(const Value *Obj, Address &Addr);
149 : void materializeLoadStoreOperands(Address &Addr);
150 : void addLoadStoreOperands(const Address &Addr, const MachineInstrBuilder &MIB,
151 : MachineMemOperand *MMO);
152 : unsigned maskI1Value(unsigned Reg, const Value *V);
153 : unsigned getRegForI1Value(const Value *V, bool &Not);
154 : unsigned zeroExtendToI32(unsigned Reg, const Value *V,
155 : MVT::SimpleValueType From);
156 : unsigned signExtendToI32(unsigned Reg, const Value *V,
157 : MVT::SimpleValueType From);
158 : unsigned zeroExtend(unsigned Reg, const Value *V, MVT::SimpleValueType From,
159 : MVT::SimpleValueType To);
160 : unsigned signExtend(unsigned Reg, const Value *V, MVT::SimpleValueType From,
161 : MVT::SimpleValueType To);
162 : unsigned getRegForUnsignedValue(const Value *V);
163 : unsigned getRegForSignedValue(const Value *V);
164 : unsigned getRegForPromotedValue(const Value *V, bool IsSigned);
165 : unsigned notValue(unsigned Reg);
166 : unsigned copyValue(unsigned Reg);
167 :
168 : // Backend specific FastISel code.
169 : unsigned fastMaterializeAlloca(const AllocaInst *AI) override;
170 : unsigned fastMaterializeConstant(const Constant *C) override;
171 : bool fastLowerArguments() override;
172 :
173 : // Selection routines.
174 : bool selectCall(const Instruction *I);
175 : bool selectSelect(const Instruction *I);
176 : bool selectTrunc(const Instruction *I);
177 : bool selectZExt(const Instruction *I);
178 : bool selectSExt(const Instruction *I);
179 : bool selectICmp(const Instruction *I);
180 : bool selectFCmp(const Instruction *I);
181 : bool selectBitCast(const Instruction *I);
182 : bool selectLoad(const Instruction *I);
183 : bool selectStore(const Instruction *I);
184 : bool selectBr(const Instruction *I);
185 : bool selectRet(const Instruction *I);
186 : bool selectUnreachable(const Instruction *I);
187 :
188 : public:
189 : // Backend specific FastISel code.
190 478 : WebAssemblyFastISel(FunctionLoweringInfo &FuncInfo,
191 : const TargetLibraryInfo *LibInfo)
192 478 : : FastISel(FuncInfo, LibInfo, /*SkipTargetIndependentISel=*/true) {
193 478 : Subtarget = &FuncInfo.MF->getSubtarget<WebAssemblySubtarget>();
194 478 : Context = &FuncInfo.Fn->getContext();
195 478 : }
196 :
197 : bool fastSelectInstruction(const Instruction *I) override;
198 :
199 : #include "WebAssemblyGenFastISel.inc"
200 : };
201 :
202 : } // end anonymous namespace
203 :
204 70 : bool WebAssemblyFastISel::computeAddress(const Value *Obj, Address &Addr) {
205 :
206 : const User *U = nullptr;
207 : unsigned Opcode = Instruction::UserOp1;
208 : if (const Instruction *I = dyn_cast<Instruction>(Obj)) {
209 : // Don't walk into other basic blocks unless the object is an alloca from
210 : // another block, otherwise it may not have a virtual register assigned.
211 79 : if (FuncInfo.StaticAllocaMap.count(static_cast<const AllocaInst *>(Obj)) ||
212 48 : FuncInfo.MBBMap[I->getParent()] == FuncInfo.MBB) {
213 : Opcode = I->getOpcode();
214 : U = I;
215 : }
216 : } else if (const ConstantExpr *C = dyn_cast<ConstantExpr>(Obj)) {
217 : Opcode = C->getOpcode();
218 : U = C;
219 : }
220 :
221 70 : if (auto *Ty = dyn_cast<PointerType>(Obj->getType()))
222 66 : if (Ty->getAddressSpace() > 255)
223 : // Fast instruction selection doesn't support the special
224 : // address spaces.
225 : return false;
226 :
227 : if (const GlobalValue *GV = dyn_cast<GlobalValue>(Obj)) {
228 1 : if (Addr.getGlobalValue())
229 : return false;
230 : Addr.setGlobalValue(GV);
231 1 : return true;
232 : }
233 :
234 69 : switch (Opcode) {
235 : default:
236 : break;
237 : case Instruction::BitCast: {
238 : // Look through bitcasts.
239 0 : return computeAddress(U->getOperand(0), Addr);
240 : }
241 2 : case Instruction::IntToPtr: {
242 : // Look past no-op inttoptrs.
243 8 : if (TLI.getValueType(DL, U->getOperand(0)->getType()) ==
244 : TLI.getPointerTy(DL))
245 2 : return computeAddress(U->getOperand(0), Addr);
246 : break;
247 : }
248 2 : case Instruction::PtrToInt: {
249 : // Look past no-op ptrtoints.
250 6 : if (TLI.getValueType(DL, U->getType()) == TLI.getPointerTy(DL))
251 2 : return computeAddress(U->getOperand(0), Addr);
252 : break;
253 : }
254 11 : case Instruction::GetElementPtr: {
255 11 : Address SavedAddr = Addr;
256 11 : uint64_t TmpOffset = Addr.getOffset();
257 : // Non-inbounds geps can wrap; wasm's offsets can't.
258 11 : if (!cast<GEPOperator>(U)->isInBounds())
259 : goto unsupported_gep;
260 : // Iterate through the GEP folding the constants into offsets where
261 : // we can.
262 18 : for (gep_type_iterator GTI = gep_type_begin(U), E = gep_type_end(U);
263 28 : GTI != E; ++GTI) {
264 : const Value *Op = GTI.getOperand();
265 0 : if (StructType *STy = GTI.getStructTypeOrNull()) {
266 0 : const StructLayout *SL = DL.getStructLayout(STy);
267 0 : unsigned Idx = cast<ConstantInt>(Op)->getZExtValue();
268 0 : TmpOffset += SL->getElementOffset(Idx);
269 : } else {
270 10 : uint64_t S = DL.getTypeAllocSize(GTI.getIndexedType());
271 : for (;;) {
272 : if (const ConstantInt *CI = dyn_cast<ConstantInt>(Op)) {
273 : // Constant-offset addressing.
274 7 : TmpOffset += CI->getSExtValue() * S;
275 7 : break;
276 : }
277 3 : if (S == 1 && Addr.isRegBase() && Addr.getReg() == 0) {
278 : // An unscaled add of a register. Set it as the new base.
279 3 : unsigned Reg = getRegForValue(Op);
280 3 : if (Reg == 0)
281 0 : return false;
282 : Addr.setReg(Reg);
283 : break;
284 : }
285 0 : if (canFoldAddIntoGEP(U, Op)) {
286 : // A compatible add with a constant operand. Fold the constant.
287 : ConstantInt *CI =
288 0 : cast<ConstantInt>(cast<AddOperator>(Op)->getOperand(1));
289 0 : TmpOffset += CI->getSExtValue() * S;
290 : // Iterate on the other operand.
291 : Op = cast<AddOperator>(Op)->getOperand(0);
292 : continue;
293 : }
294 : // Unsupported
295 0 : goto unsupported_gep;
296 0 : }
297 : }
298 : }
299 : // Don't fold in negative offsets.
300 8 : if (int64_t(TmpOffset) >= 0) {
301 : // Try to grab the base operand now.
302 : Addr.setOffset(TmpOffset);
303 7 : if (computeAddress(U->getOperand(0), Addr))
304 : return true;
305 : }
306 : // We failed, restore everything and try the other options.
307 3 : Addr = SavedAddr;
308 6 : unsupported_gep:
309 6 : break;
310 : }
311 : case Instruction::Alloca: {
312 : const AllocaInst *AI = cast<AllocaInst>(Obj);
313 : DenseMap<const AllocaInst *, int>::iterator SI =
314 31 : FuncInfo.StaticAllocaMap.find(AI);
315 62 : if (SI != FuncInfo.StaticAllocaMap.end()) {
316 31 : if (Addr.isSet()) {
317 31 : return false;
318 : }
319 : Addr.setKind(Address::FrameIndexBase);
320 30 : Addr.setFI(SI->second);
321 30 : return true;
322 : }
323 0 : break;
324 : }
325 : case Instruction::Add: {
326 : // Adds of constants are common and easy enough.
327 : const Value *LHS = U->getOperand(0);
328 : const Value *RHS = U->getOperand(1);
329 :
330 2 : if (isa<ConstantInt>(LHS))
331 : std::swap(LHS, RHS);
332 :
333 : if (const ConstantInt *CI = dyn_cast<ConstantInt>(RHS)) {
334 2 : uint64_t TmpOffset = Addr.getOffset() + CI->getSExtValue();
335 2 : if (int64_t(TmpOffset) >= 0) {
336 : Addr.setOffset(TmpOffset);
337 2 : return computeAddress(LHS, Addr);
338 : }
339 : }
340 :
341 0 : Address Backup = Addr;
342 0 : if (computeAddress(LHS, Addr) && computeAddress(RHS, Addr))
343 : return true;
344 0 : Addr = Backup;
345 :
346 0 : break;
347 : }
348 : case Instruction::Sub: {
349 : // Subs of constants are common and easy enough.
350 : const Value *LHS = U->getOperand(0);
351 : const Value *RHS = U->getOperand(1);
352 :
353 : if (const ConstantInt *CI = dyn_cast<ConstantInt>(RHS)) {
354 0 : int64_t TmpOffset = Addr.getOffset() - CI->getSExtValue();
355 0 : if (TmpOffset >= 0) {
356 : Addr.setOffset(TmpOffset);
357 0 : return computeAddress(LHS, Addr);
358 : }
359 : }
360 : break;
361 : }
362 : }
363 27 : if (Addr.isSet()) {
364 : return false;
365 : }
366 26 : unsigned Reg = getRegForValue(Obj);
367 26 : if (Reg == 0)
368 : return false;
369 : Addr.setReg(Reg);
370 26 : return Addr.getReg() != 0;
371 : }
372 :
373 57 : void WebAssemblyFastISel::materializeLoadStoreOperands(Address &Addr) {
374 57 : if (Addr.isRegBase()) {
375 27 : unsigned Reg = Addr.getReg();
376 27 : if (Reg == 0) {
377 0 : Reg = createResultReg(Subtarget->hasAddr64() ? &WebAssembly::I64RegClass
378 : : &WebAssembly::I32RegClass);
379 0 : unsigned Opc = Subtarget->hasAddr64() ? WebAssembly::CONST_I64
380 : : WebAssembly::CONST_I32;
381 0 : BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), Reg)
382 : .addImm(0);
383 : Addr.setReg(Reg);
384 : }
385 : }
386 57 : }
387 :
388 0 : void WebAssemblyFastISel::addLoadStoreOperands(const Address &Addr,
389 : const MachineInstrBuilder &MIB,
390 : MachineMemOperand *MMO) {
391 : // Set the alignment operand (this is rewritten in SetP2AlignOperands).
392 : // TODO: Disable SetP2AlignOperands for FastISel and just do it here.
393 : MIB.addImm(0);
394 :
395 0 : if (const GlobalValue *GV = Addr.getGlobalValue())
396 0 : MIB.addGlobalAddress(GV, Addr.getOffset());
397 : else
398 0 : MIB.addImm(Addr.getOffset());
399 :
400 0 : if (Addr.isRegBase())
401 0 : MIB.addReg(Addr.getReg());
402 : else
403 0 : MIB.addFrameIndex(Addr.getFI());
404 :
405 : MIB.addMemOperand(MMO);
406 0 : }
407 :
408 : unsigned WebAssemblyFastISel::maskI1Value(unsigned Reg, const Value *V) {
409 12 : return zeroExtendToI32(Reg, V, MVT::i1);
410 : }
411 :
412 44 : unsigned WebAssemblyFastISel::getRegForI1Value(const Value *V, bool &Not) {
413 : if (const ICmpInst *ICmp = dyn_cast<ICmpInst>(V))
414 : if (const ConstantInt *C = dyn_cast<ConstantInt>(ICmp->getOperand(1)))
415 24 : if (ICmp->isEquality() && C->isZero() && C->getType()->isIntegerTy(32)) {
416 10 : Not = ICmp->isTrueWhenEqual();
417 10 : return getRegForValue(ICmp->getOperand(0));
418 : }
419 :
420 34 : if (BinaryOperator::isNot(V) && V->getType()->isIntegerTy(32)) {
421 0 : Not = true;
422 0 : return getRegForValue(BinaryOperator::getNotArgument(V));
423 : }
424 :
425 34 : Not = false;
426 34 : unsigned Reg = getRegForValue(V);
427 34 : if (Reg == 0)
428 : return 0;
429 12 : return maskI1Value(Reg, V);
430 : }
431 :
432 50 : unsigned WebAssemblyFastISel::zeroExtendToI32(unsigned Reg, const Value *V,
433 : MVT::SimpleValueType From) {
434 50 : if (Reg == 0)
435 : return 0;
436 :
437 50 : switch (From) {
438 32 : case MVT::i1:
439 : // If the value is naturally an i1, we don't need to mask it.
440 : // TODO: Recursively examine selects, phis, and, or, xor, constants.
441 32 : if (From == MVT::i1 && V != nullptr) {
442 7 : if (isa<CmpInst>(V) ||
443 4 : (isa<Argument>(V) && cast<Argument>(V)->hasZExtAttr()))
444 29 : return copyValue(Reg);
445 : }
446 : case MVT::i8:
447 : case MVT::i16:
448 : break;
449 14 : case MVT::i32:
450 14 : return copyValue(Reg);
451 : default:
452 : return 0;
453 : }
454 :
455 7 : unsigned Imm = createResultReg(&WebAssembly::I32RegClass);
456 14 : BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
457 14 : TII.get(WebAssembly::CONST_I32), Imm)
458 7 : .addImm(~(~uint64_t(0) << MVT(From).getSizeInBits()));
459 :
460 7 : unsigned Result = createResultReg(&WebAssembly::I32RegClass);
461 14 : BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
462 14 : TII.get(WebAssembly::AND_I32), Result)
463 7 : .addReg(Reg)
464 7 : .addReg(Imm);
465 :
466 7 : return Result;
467 : }
468 :
469 12 : unsigned WebAssemblyFastISel::signExtendToI32(unsigned Reg, const Value *V,
470 : MVT::SimpleValueType From) {
471 12 : if (Reg == 0)
472 : return 0;
473 :
474 12 : switch (From) {
475 : case MVT::i1:
476 : case MVT::i8:
477 : case MVT::i16:
478 : break;
479 10 : case MVT::i32:
480 10 : return copyValue(Reg);
481 : default:
482 : return 0;
483 : }
484 :
485 2 : unsigned Imm = createResultReg(&WebAssembly::I32RegClass);
486 4 : BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
487 4 : TII.get(WebAssembly::CONST_I32), Imm)
488 2 : .addImm(32 - MVT(From).getSizeInBits());
489 :
490 2 : unsigned Left = createResultReg(&WebAssembly::I32RegClass);
491 4 : BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
492 4 : TII.get(WebAssembly::SHL_I32), Left)
493 2 : .addReg(Reg)
494 2 : .addReg(Imm);
495 :
496 2 : unsigned Right = createResultReg(&WebAssembly::I32RegClass);
497 4 : BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
498 4 : TII.get(WebAssembly::SHR_S_I32), Right)
499 2 : .addReg(Left)
500 2 : .addReg(Imm);
501 :
502 2 : return Right;
503 : }
504 :
505 50 : unsigned WebAssemblyFastISel::zeroExtend(unsigned Reg, const Value *V,
506 : MVT::SimpleValueType From,
507 : MVT::SimpleValueType To) {
508 50 : if (To == MVT::i64) {
509 12 : if (From == MVT::i64)
510 12 : return copyValue(Reg);
511 :
512 0 : Reg = zeroExtendToI32(Reg, V, From);
513 :
514 0 : unsigned Result = createResultReg(&WebAssembly::I64RegClass);
515 0 : BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
516 0 : TII.get(WebAssembly::I64_EXTEND_U_I32), Result)
517 0 : .addReg(Reg);
518 0 : return Result;
519 : }
520 :
521 38 : return zeroExtendToI32(Reg, V, From);
522 : }
523 :
524 20 : unsigned WebAssemblyFastISel::signExtend(unsigned Reg, const Value *V,
525 : MVT::SimpleValueType From,
526 : MVT::SimpleValueType To) {
527 20 : if (To == MVT::i64) {
528 8 : if (From == MVT::i64)
529 8 : return copyValue(Reg);
530 :
531 0 : Reg = signExtendToI32(Reg, V, From);
532 :
533 0 : unsigned Result = createResultReg(&WebAssembly::I64RegClass);
534 0 : BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
535 0 : TII.get(WebAssembly::I64_EXTEND_S_I32), Result)
536 0 : .addReg(Reg);
537 0 : return Result;
538 : }
539 :
540 12 : return signExtendToI32(Reg, V, From);
541 : }
542 :
543 29 : unsigned WebAssemblyFastISel::getRegForUnsignedValue(const Value *V) {
544 29 : MVT::SimpleValueType From = getSimpleType(V->getType());
545 29 : MVT::SimpleValueType To = getLegalType(From);
546 29 : unsigned VReg = getRegForValue(V);
547 29 : if (VReg == 0)
548 : return 0;
549 27 : return zeroExtend(VReg, V, From, To);
550 : }
551 :
552 21 : unsigned WebAssemblyFastISel::getRegForSignedValue(const Value *V) {
553 21 : MVT::SimpleValueType From = getSimpleType(V->getType());
554 21 : MVT::SimpleValueType To = getLegalType(From);
555 21 : unsigned VReg = getRegForValue(V);
556 21 : if (VReg == 0)
557 : return 0;
558 19 : return signExtend(VReg, V, From, To);
559 : }
560 :
561 48 : unsigned WebAssemblyFastISel::getRegForPromotedValue(const Value *V,
562 : bool IsSigned) {
563 48 : return IsSigned ? getRegForSignedValue(V) : getRegForUnsignedValue(V);
564 : }
565 :
566 0 : unsigned WebAssemblyFastISel::notValue(unsigned Reg) {
567 : assert(MRI.getRegClass(Reg) == &WebAssembly::I32RegClass);
568 :
569 0 : unsigned NotReg = createResultReg(&WebAssembly::I32RegClass);
570 0 : BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
571 0 : TII.get(WebAssembly::EQZ_I32), NotReg)
572 0 : .addReg(Reg);
573 0 : return NotReg;
574 : }
575 :
576 73 : unsigned WebAssemblyFastISel::copyValue(unsigned Reg) {
577 146 : unsigned ResultReg = createResultReg(MRI.getRegClass(Reg));
578 219 : BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(WebAssembly::COPY),
579 146 : ResultReg)
580 73 : .addReg(Reg);
581 73 : return ResultReg;
582 : }
583 :
584 1 : unsigned WebAssemblyFastISel::fastMaterializeAlloca(const AllocaInst *AI) {
585 : DenseMap<const AllocaInst *, int>::iterator SI =
586 1 : FuncInfo.StaticAllocaMap.find(AI);
587 :
588 2 : if (SI != FuncInfo.StaticAllocaMap.end()) {
589 : unsigned ResultReg =
590 2 : createResultReg(Subtarget->hasAddr64() ? &WebAssembly::I64RegClass
591 : : &WebAssembly::I32RegClass);
592 : unsigned Opc =
593 1 : Subtarget->hasAddr64() ? WebAssembly::COPY_I64 : WebAssembly::COPY_I32;
594 2 : BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg)
595 1 : .addFrameIndex(SI->second);
596 1 : return ResultReg;
597 : }
598 :
599 : return 0;
600 : }
601 :
602 108 : unsigned WebAssemblyFastISel::fastMaterializeConstant(const Constant *C) {
603 : if (const GlobalValue *GV = dyn_cast<GlobalValue>(C)) {
604 : unsigned ResultReg =
605 14 : createResultReg(Subtarget->hasAddr64() ? &WebAssembly::I64RegClass
606 : : &WebAssembly::I32RegClass);
607 7 : unsigned Opc = Subtarget->hasAddr64() ? WebAssembly::CONST_I64
608 : : WebAssembly::CONST_I32;
609 14 : BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg)
610 : .addGlobalAddress(GV);
611 7 : return ResultReg;
612 : }
613 :
614 : // Let target-independent code handle it.
615 : return 0;
616 : }
617 :
618 365 : bool WebAssemblyFastISel::fastLowerArguments() {
619 365 : if (!FuncInfo.CanLowerReturn)
620 : return false;
621 :
622 365 : const Function *F = FuncInfo.Fn;
623 365 : if (F->isVarArg())
624 : return false;
625 :
626 : unsigned i = 0;
627 917 : for (auto const &Arg : F->args()) {
628 557 : const AttributeList &Attrs = F->getAttributes();
629 1111 : if (Attrs.hasParamAttribute(i, Attribute::ByVal) ||
630 1108 : Attrs.hasParamAttribute(i, Attribute::SwiftSelf) ||
631 1108 : Attrs.hasParamAttribute(i, Attribute::SwiftError) ||
632 1665 : Attrs.hasParamAttribute(i, Attribute::InAlloca) ||
633 554 : Attrs.hasParamAttribute(i, Attribute::Nest))
634 3 : return false;
635 :
636 554 : Type *ArgTy = Arg.getType();
637 554 : if (ArgTy->isStructTy() || ArgTy->isArrayTy())
638 : return false;
639 554 : if (!Subtarget->hasSIMD128() && ArgTy->isVectorTy())
640 : return false;
641 :
642 : unsigned Opc;
643 : const TargetRegisterClass *RC;
644 1107 : switch (getSimpleType(ArgTy)) {
645 : case MVT::i1:
646 : case MVT::i8:
647 : case MVT::i16:
648 : case MVT::i32:
649 : Opc = WebAssembly::ARGUMENT_i32;
650 : RC = &WebAssembly::I32RegClass;
651 : break;
652 34 : case MVT::i64:
653 : Opc = WebAssembly::ARGUMENT_i64;
654 : RC = &WebAssembly::I64RegClass;
655 34 : break;
656 9 : case MVT::f32:
657 : Opc = WebAssembly::ARGUMENT_f32;
658 : RC = &WebAssembly::F32RegClass;
659 9 : break;
660 8 : case MVT::f64:
661 : Opc = WebAssembly::ARGUMENT_f64;
662 : RC = &WebAssembly::F64RegClass;
663 8 : break;
664 76 : case MVT::v16i8:
665 : Opc = WebAssembly::ARGUMENT_v16i8;
666 : RC = &WebAssembly::V128RegClass;
667 76 : break;
668 76 : case MVT::v8i16:
669 : Opc = WebAssembly::ARGUMENT_v8i16;
670 : RC = &WebAssembly::V128RegClass;
671 76 : break;
672 68 : case MVT::v4i32:
673 : Opc = WebAssembly::ARGUMENT_v4i32;
674 : RC = &WebAssembly::V128RegClass;
675 68 : break;
676 53 : case MVT::v2i64:
677 : Opc = WebAssembly::ARGUMENT_v2i64;
678 : RC = &WebAssembly::V128RegClass;
679 53 : break;
680 62 : case MVT::v4f32:
681 : Opc = WebAssembly::ARGUMENT_v4f32;
682 : RC = &WebAssembly::V128RegClass;
683 62 : break;
684 43 : case MVT::v2f64:
685 : Opc = WebAssembly::ARGUMENT_v2f64;
686 : RC = &WebAssembly::V128RegClass;
687 43 : break;
688 0 : case MVT::ExceptRef:
689 : Opc = WebAssembly::ARGUMENT_ExceptRef;
690 : RC = &WebAssembly::EXCEPT_REFRegClass;
691 0 : break;
692 : default:
693 : return false;
694 : }
695 552 : unsigned ResultReg = createResultReg(RC);
696 1104 : BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg)
697 552 : .addImm(i);
698 552 : updateValueMap(&Arg, ResultReg);
699 :
700 552 : ++i;
701 : }
702 :
703 360 : MRI.addLiveIn(WebAssembly::ARGUMENTS);
704 :
705 360 : auto *MFI = MF->getInfo<WebAssemblyFunctionInfo>();
706 912 : for (auto const &Arg : F->args()) {
707 552 : MVT::SimpleValueType ArgTy = getLegalType(getSimpleType(Arg.getType()));
708 552 : if (ArgTy == MVT::INVALID_SIMPLE_VALUE_TYPE) {
709 : MFI->clearParamsAndResults();
710 0 : return false;
711 : }
712 552 : MFI->addParam(ArgTy);
713 : }
714 :
715 360 : if (!F->getReturnType()->isVoidTy()) {
716 : MVT::SimpleValueType RetTy =
717 326 : getLegalType(getSimpleType(F->getReturnType()));
718 326 : if (RetTy == MVT::INVALID_SIMPLE_VALUE_TYPE) {
719 : MFI->clearParamsAndResults();
720 1 : return false;
721 : }
722 325 : MFI->addResult(RetTy);
723 : }
724 :
725 : return true;
726 : }
727 :
728 97 : bool WebAssemblyFastISel::selectCall(const Instruction *I) {
729 : const CallInst *Call = cast<CallInst>(I);
730 :
731 97 : if (Call->isMustTailCall() || Call->isInlineAsm() ||
732 97 : Call->getFunctionType()->isVarArg())
733 : return false;
734 :
735 : Function *Func = Call->getCalledFunction();
736 83 : if (Func && Func->isIntrinsic())
737 : return false;
738 :
739 : bool IsDirect = Func != nullptr;
740 39 : if (!IsDirect && isa<ConstantExpr>(Call->getCalledValue()))
741 : return false;
742 :
743 : FunctionType *FuncTy = Call->getFunctionType();
744 : unsigned Opc;
745 38 : bool IsVoid = FuncTy->getReturnType()->isVoidTy();
746 : unsigned ResultReg;
747 38 : if (IsVoid) {
748 22 : Opc = IsDirect ? WebAssembly::CALL_VOID : WebAssembly::PCALL_INDIRECT_VOID;
749 : } else {
750 16 : if (!Subtarget->hasSIMD128() && Call->getType()->isVectorTy())
751 : return false;
752 :
753 16 : MVT::SimpleValueType RetTy = getSimpleType(Call->getType());
754 16 : switch (RetTy) {
755 8 : case MVT::i1:
756 : case MVT::i8:
757 : case MVT::i16:
758 : case MVT::i32:
759 8 : Opc = IsDirect ? WebAssembly::CALL_I32 : WebAssembly::PCALL_INDIRECT_I32;
760 8 : ResultReg = createResultReg(&WebAssembly::I32RegClass);
761 8 : break;
762 2 : case MVT::i64:
763 2 : Opc = IsDirect ? WebAssembly::CALL_I64 : WebAssembly::PCALL_INDIRECT_I64;
764 2 : ResultReg = createResultReg(&WebAssembly::I64RegClass);
765 2 : break;
766 2 : case MVT::f32:
767 2 : Opc = IsDirect ? WebAssembly::CALL_F32 : WebAssembly::PCALL_INDIRECT_F32;
768 2 : ResultReg = createResultReg(&WebAssembly::F32RegClass);
769 2 : break;
770 2 : case MVT::f64:
771 2 : Opc = IsDirect ? WebAssembly::CALL_F64 : WebAssembly::PCALL_INDIRECT_F64;
772 2 : ResultReg = createResultReg(&WebAssembly::F64RegClass);
773 2 : break;
774 2 : case MVT::v16i8:
775 2 : Opc = IsDirect ? WebAssembly::CALL_v16i8
776 : : WebAssembly::PCALL_INDIRECT_v16i8;
777 2 : ResultReg = createResultReg(&WebAssembly::V128RegClass);
778 2 : break;
779 0 : case MVT::v8i16:
780 0 : Opc = IsDirect ? WebAssembly::CALL_v8i16
781 : : WebAssembly::PCALL_INDIRECT_v8i16;
782 0 : ResultReg = createResultReg(&WebAssembly::V128RegClass);
783 0 : break;
784 0 : case MVT::v4i32:
785 0 : Opc = IsDirect ? WebAssembly::CALL_v4i32
786 : : WebAssembly::PCALL_INDIRECT_v4i32;
787 0 : ResultReg = createResultReg(&WebAssembly::V128RegClass);
788 0 : break;
789 0 : case MVT::v2i64:
790 0 : Opc = IsDirect ? WebAssembly::CALL_v2i64
791 : : WebAssembly::PCALL_INDIRECT_v2i64;
792 0 : ResultReg = createResultReg(&WebAssembly::V128RegClass);
793 0 : break;
794 0 : case MVT::v4f32:
795 0 : Opc = IsDirect ? WebAssembly::CALL_v4f32
796 : : WebAssembly::PCALL_INDIRECT_v4f32;
797 0 : ResultReg = createResultReg(&WebAssembly::V128RegClass);
798 0 : break;
799 0 : case MVT::v2f64:
800 0 : Opc = IsDirect ? WebAssembly::CALL_v2f64
801 : : WebAssembly::PCALL_INDIRECT_v2f64;
802 0 : ResultReg = createResultReg(&WebAssembly::V128RegClass);
803 0 : break;
804 0 : case MVT::ExceptRef:
805 0 : Opc = IsDirect ? WebAssembly::CALL_EXCEPT_REF
806 : : WebAssembly::PCALL_INDIRECT_EXCEPT_REF;
807 0 : ResultReg = createResultReg(&WebAssembly::EXCEPT_REFRegClass);
808 0 : break;
809 0 : default:
810 0 : return false;
811 : }
812 : }
813 :
814 : SmallVector<unsigned, 8> Args;
815 92 : for (unsigned i = 0, e = Call->getNumArgOperands(); i < e; ++i) {
816 : Value *V = Call->getArgOperand(i);
817 21 : MVT::SimpleValueType ArgTy = getSimpleType(V->getType());
818 : if (ArgTy == MVT::INVALID_SIMPLE_VALUE_TYPE)
819 5 : return false;
820 :
821 21 : const AttributeList &Attrs = Call->getAttributes();
822 37 : if (Attrs.hasParamAttribute(i, Attribute::ByVal) ||
823 32 : Attrs.hasParamAttribute(i, Attribute::SwiftSelf) ||
824 32 : Attrs.hasParamAttribute(i, Attribute::SwiftError) ||
825 53 : Attrs.hasParamAttribute(i, Attribute::InAlloca) ||
826 16 : Attrs.hasParamAttribute(i, Attribute::Nest))
827 5 : return false;
828 :
829 : unsigned Reg;
830 :
831 16 : if (Attrs.hasParamAttribute(i, Attribute::SExt))
832 1 : Reg = getRegForSignedValue(V);
833 15 : else if (Attrs.hasParamAttribute(i, Attribute::ZExt))
834 0 : Reg = getRegForUnsignedValue(V);
835 : else
836 15 : Reg = getRegForValue(V);
837 :
838 16 : if (Reg == 0)
839 : return false;
840 :
841 16 : Args.push_back(Reg);
842 : }
843 :
844 66 : auto MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc));
845 :
846 33 : if (!IsVoid)
847 16 : MIB.addReg(ResultReg, RegState::Define);
848 :
849 33 : if (IsDirect)
850 : MIB.addGlobalAddress(Func);
851 : else {
852 22 : unsigned Reg = getRegForValue(Call->getCalledValue());
853 11 : if (Reg == 0)
854 : return false;
855 11 : MIB.addReg(Reg);
856 : }
857 :
858 49 : for (unsigned ArgReg : Args)
859 16 : MIB.addReg(ArgReg);
860 :
861 33 : if (!IsVoid)
862 16 : updateValueMap(Call, ResultReg);
863 : return true;
864 : }
865 :
866 32 : bool WebAssemblyFastISel::selectSelect(const Instruction *I) {
867 : const SelectInst *Select = cast<SelectInst>(I);
868 :
869 : bool Not;
870 32 : unsigned CondReg = getRegForI1Value(Select->getCondition(), Not);
871 32 : if (CondReg == 0)
872 : return false;
873 :
874 24 : unsigned TrueReg = getRegForValue(Select->getTrueValue());
875 12 : if (TrueReg == 0)
876 : return false;
877 :
878 12 : unsigned FalseReg = getRegForValue(Select->getFalseValue());
879 12 : if (FalseReg == 0)
880 : return false;
881 :
882 12 : if (Not)
883 : std::swap(TrueReg, FalseReg);
884 :
885 : unsigned Opc;
886 : const TargetRegisterClass *RC;
887 24 : switch (getSimpleType(Select->getType())) {
888 : case MVT::i1:
889 : case MVT::i8:
890 : case MVT::i16:
891 : case MVT::i32:
892 : Opc = WebAssembly::SELECT_I32;
893 : RC = &WebAssembly::I32RegClass;
894 : break;
895 3 : case MVT::i64:
896 : Opc = WebAssembly::SELECT_I64;
897 : RC = &WebAssembly::I64RegClass;
898 3 : break;
899 3 : case MVT::f32:
900 : Opc = WebAssembly::SELECT_F32;
901 : RC = &WebAssembly::F32RegClass;
902 3 : break;
903 3 : case MVT::f64:
904 : Opc = WebAssembly::SELECT_F64;
905 : RC = &WebAssembly::F64RegClass;
906 3 : break;
907 0 : case MVT::ExceptRef:
908 : Opc = WebAssembly::SELECT_EXCEPT_REF;
909 : RC = &WebAssembly::EXCEPT_REFRegClass;
910 0 : break;
911 : default:
912 : return false;
913 : }
914 :
915 12 : unsigned ResultReg = createResultReg(RC);
916 24 : BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg)
917 12 : .addReg(TrueReg)
918 12 : .addReg(FalseReg)
919 12 : .addReg(CondReg);
920 :
921 12 : updateValueMap(Select, ResultReg);
922 12 : return true;
923 : }
924 :
925 1 : bool WebAssemblyFastISel::selectTrunc(const Instruction *I) {
926 : const TruncInst *Trunc = cast<TruncInst>(I);
927 :
928 1 : unsigned Reg = getRegForValue(Trunc->getOperand(0));
929 1 : if (Reg == 0)
930 : return false;
931 :
932 1 : if (Trunc->getOperand(0)->getType()->isIntegerTy(64)) {
933 0 : unsigned Result = createResultReg(&WebAssembly::I32RegClass);
934 0 : BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
935 0 : TII.get(WebAssembly::I32_WRAP_I64), Result)
936 0 : .addReg(Reg);
937 : Reg = Result;
938 : }
939 :
940 1 : updateValueMap(Trunc, Reg);
941 1 : return true;
942 : }
943 :
944 25 : bool WebAssemblyFastISel::selectZExt(const Instruction *I) {
945 : const ZExtInst *ZExt = cast<ZExtInst>(I);
946 :
947 : const Value *Op = ZExt->getOperand(0);
948 25 : MVT::SimpleValueType From = getSimpleType(Op->getType());
949 25 : MVT::SimpleValueType To = getLegalType(getSimpleType(ZExt->getType()));
950 25 : unsigned In = getRegForValue(Op);
951 25 : if (In == 0)
952 : return false;
953 23 : unsigned Reg = zeroExtend(In, Op, From, To);
954 23 : if (Reg == 0)
955 : return false;
956 :
957 23 : updateValueMap(ZExt, Reg);
958 23 : return true;
959 : }
960 :
961 3 : bool WebAssemblyFastISel::selectSExt(const Instruction *I) {
962 : const SExtInst *SExt = cast<SExtInst>(I);
963 :
964 : const Value *Op = SExt->getOperand(0);
965 3 : MVT::SimpleValueType From = getSimpleType(Op->getType());
966 3 : MVT::SimpleValueType To = getLegalType(getSimpleType(SExt->getType()));
967 3 : unsigned In = getRegForValue(Op);
968 3 : if (In == 0)
969 : return false;
970 1 : unsigned Reg = signExtend(In, Op, From, To);
971 1 : if (Reg == 0)
972 : return false;
973 :
974 1 : updateValueMap(SExt, Reg);
975 1 : return true;
976 : }
977 :
978 26 : bool WebAssemblyFastISel::selectICmp(const Instruction *I) {
979 : const ICmpInst *ICmp = cast<ICmpInst>(I);
980 :
981 26 : bool I32 = getSimpleType(ICmp->getOperand(0)->getType()) != MVT::i64;
982 : unsigned Opc;
983 : bool isSigned = false;
984 26 : switch (ICmp->getPredicate()) {
985 3 : case ICmpInst::ICMP_EQ:
986 3 : Opc = I32 ? WebAssembly::EQ_I32 : WebAssembly::EQ_I64;
987 : break;
988 2 : case ICmpInst::ICMP_NE:
989 2 : Opc = I32 ? WebAssembly::NE_I32 : WebAssembly::NE_I64;
990 : break;
991 2 : case ICmpInst::ICMP_UGT:
992 2 : Opc = I32 ? WebAssembly::GT_U_I32 : WebAssembly::GT_U_I64;
993 : break;
994 2 : case ICmpInst::ICMP_UGE:
995 2 : Opc = I32 ? WebAssembly::GE_U_I32 : WebAssembly::GE_U_I64;
996 : break;
997 4 : case ICmpInst::ICMP_ULT:
998 4 : Opc = I32 ? WebAssembly::LT_U_I32 : WebAssembly::LT_U_I64;
999 : break;
1000 2 : case ICmpInst::ICMP_ULE:
1001 2 : Opc = I32 ? WebAssembly::LE_U_I32 : WebAssembly::LE_U_I64;
1002 : break;
1003 2 : case ICmpInst::ICMP_SGT:
1004 2 : Opc = I32 ? WebAssembly::GT_S_I32 : WebAssembly::GT_S_I64;
1005 : isSigned = true;
1006 : break;
1007 2 : case ICmpInst::ICMP_SGE:
1008 2 : Opc = I32 ? WebAssembly::GE_S_I32 : WebAssembly::GE_S_I64;
1009 : isSigned = true;
1010 : break;
1011 5 : case ICmpInst::ICMP_SLT:
1012 5 : Opc = I32 ? WebAssembly::LT_S_I32 : WebAssembly::LT_S_I64;
1013 : isSigned = true;
1014 : break;
1015 2 : case ICmpInst::ICMP_SLE:
1016 2 : Opc = I32 ? WebAssembly::LE_S_I32 : WebAssembly::LE_S_I64;
1017 : isSigned = true;
1018 : break;
1019 : default:
1020 : return false;
1021 : }
1022 :
1023 26 : unsigned LHS = getRegForPromotedValue(ICmp->getOperand(0), isSigned);
1024 26 : if (LHS == 0)
1025 : return false;
1026 :
1027 22 : unsigned RHS = getRegForPromotedValue(ICmp->getOperand(1), isSigned);
1028 22 : if (RHS == 0)
1029 : return false;
1030 :
1031 22 : unsigned ResultReg = createResultReg(&WebAssembly::I32RegClass);
1032 44 : BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg)
1033 22 : .addReg(LHS)
1034 22 : .addReg(RHS);
1035 22 : updateValueMap(ICmp, ResultReg);
1036 22 : return true;
1037 : }
1038 :
1039 0 : bool WebAssemblyFastISel::selectFCmp(const Instruction *I) {
1040 : const FCmpInst *FCmp = cast<FCmpInst>(I);
1041 :
1042 0 : unsigned LHS = getRegForValue(FCmp->getOperand(0));
1043 0 : if (LHS == 0)
1044 : return false;
1045 :
1046 0 : unsigned RHS = getRegForValue(FCmp->getOperand(1));
1047 0 : if (RHS == 0)
1048 : return false;
1049 :
1050 0 : bool F32 = getSimpleType(FCmp->getOperand(0)->getType()) != MVT::f64;
1051 : unsigned Opc;
1052 : bool Not = false;
1053 0 : switch (FCmp->getPredicate()) {
1054 0 : case FCmpInst::FCMP_OEQ:
1055 0 : Opc = F32 ? WebAssembly::EQ_F32 : WebAssembly::EQ_F64;
1056 : break;
1057 0 : case FCmpInst::FCMP_UNE:
1058 0 : Opc = F32 ? WebAssembly::NE_F32 : WebAssembly::NE_F64;
1059 : break;
1060 0 : case FCmpInst::FCMP_OGT:
1061 0 : Opc = F32 ? WebAssembly::GT_F32 : WebAssembly::GT_F64;
1062 : break;
1063 0 : case FCmpInst::FCMP_OGE:
1064 0 : Opc = F32 ? WebAssembly::GE_F32 : WebAssembly::GE_F64;
1065 : break;
1066 0 : case FCmpInst::FCMP_OLT:
1067 0 : Opc = F32 ? WebAssembly::LT_F32 : WebAssembly::LT_F64;
1068 : break;
1069 0 : case FCmpInst::FCMP_OLE:
1070 0 : Opc = F32 ? WebAssembly::LE_F32 : WebAssembly::LE_F64;
1071 : break;
1072 0 : case FCmpInst::FCMP_UGT:
1073 0 : Opc = F32 ? WebAssembly::LE_F32 : WebAssembly::LE_F64;
1074 : Not = true;
1075 : break;
1076 0 : case FCmpInst::FCMP_UGE:
1077 0 : Opc = F32 ? WebAssembly::LT_F32 : WebAssembly::LT_F64;
1078 : Not = true;
1079 : break;
1080 0 : case FCmpInst::FCMP_ULT:
1081 0 : Opc = F32 ? WebAssembly::GE_F32 : WebAssembly::GE_F64;
1082 : Not = true;
1083 : break;
1084 0 : case FCmpInst::FCMP_ULE:
1085 0 : Opc = F32 ? WebAssembly::GT_F32 : WebAssembly::GT_F64;
1086 : Not = true;
1087 : break;
1088 : default:
1089 : return false;
1090 : }
1091 :
1092 0 : unsigned ResultReg = createResultReg(&WebAssembly::I32RegClass);
1093 0 : BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg)
1094 0 : .addReg(LHS)
1095 0 : .addReg(RHS);
1096 :
1097 0 : if (Not)
1098 0 : ResultReg = notValue(ResultReg);
1099 :
1100 0 : updateValueMap(FCmp, ResultReg);
1101 0 : return true;
1102 : }
1103 :
1104 4 : bool WebAssemblyFastISel::selectBitCast(const Instruction *I) {
1105 : // Target-independent code can handle this, except it doesn't set the dead
1106 : // flag on the ARGUMENTS clobber, so we have to do that manually in order
1107 : // to satisfy code that expects this of isBitcast() instructions.
1108 8 : EVT VT = TLI.getValueType(DL, I->getOperand(0)->getType());
1109 4 : EVT RetVT = TLI.getValueType(DL, I->getType());
1110 4 : if (!VT.isSimple() || !RetVT.isSimple())
1111 : return false;
1112 :
1113 8 : unsigned In = getRegForValue(I->getOperand(0));
1114 4 : if (In == 0)
1115 : return false;
1116 :
1117 : if (VT == RetVT) {
1118 : // No-op bitcast.
1119 0 : updateValueMap(I, In);
1120 0 : return true;
1121 : }
1122 :
1123 4 : unsigned Reg = fastEmit_ISD_BITCAST_r(VT.getSimpleVT(), RetVT.getSimpleVT(),
1124 : In, I->getOperand(0)->hasOneUse());
1125 4 : if (!Reg)
1126 : return false;
1127 4 : MachineBasicBlock::iterator Iter = FuncInfo.InsertPt;
1128 : --Iter;
1129 : assert(Iter->isBitcast());
1130 4 : Iter->setPhysRegsDeadExcept(ArrayRef<unsigned>(), TRI);
1131 4 : updateValueMap(I, Reg);
1132 4 : return true;
1133 : }
1134 :
1135 25 : bool WebAssemblyFastISel::selectLoad(const Instruction *I) {
1136 : const LoadInst *Load = cast<LoadInst>(I);
1137 25 : if (Load->isAtomic())
1138 : return false;
1139 25 : if (!Subtarget->hasSIMD128() && Load->getType()->isVectorTy())
1140 : return false;
1141 :
1142 : Address Addr;
1143 25 : if (!computeAddress(Load->getPointerOperand(), Addr))
1144 : return false;
1145 :
1146 : // TODO: Fold a following sign-/zero-extend into the load instruction.
1147 :
1148 : unsigned Opc;
1149 : const TargetRegisterClass *RC;
1150 50 : switch (getSimpleType(Load->getType())) {
1151 : case MVT::i1:
1152 : case MVT::i8:
1153 : Opc = WebAssembly::LOAD8_U_I32;
1154 : RC = &WebAssembly::I32RegClass;
1155 : break;
1156 0 : case MVT::i16:
1157 : Opc = WebAssembly::LOAD16_U_I32;
1158 : RC = &WebAssembly::I32RegClass;
1159 0 : break;
1160 15 : case MVT::i32:
1161 : Opc = WebAssembly::LOAD_I32;
1162 : RC = &WebAssembly::I32RegClass;
1163 15 : break;
1164 4 : case MVT::i64:
1165 : Opc = WebAssembly::LOAD_I64;
1166 : RC = &WebAssembly::I64RegClass;
1167 4 : break;
1168 1 : case MVT::f32:
1169 : Opc = WebAssembly::LOAD_F32;
1170 : RC = &WebAssembly::F32RegClass;
1171 1 : break;
1172 1 : case MVT::f64:
1173 : Opc = WebAssembly::LOAD_F64;
1174 : RC = &WebAssembly::F64RegClass;
1175 1 : break;
1176 : default:
1177 : return false;
1178 : }
1179 :
1180 25 : materializeLoadStoreOperands(Addr);
1181 :
1182 25 : unsigned ResultReg = createResultReg(RC);
1183 50 : auto MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc),
1184 50 : ResultReg);
1185 :
1186 25 : addLoadStoreOperands(Addr, MIB, createMachineMemOperandFor(Load));
1187 :
1188 25 : updateValueMap(Load, ResultReg);
1189 25 : return true;
1190 : }
1191 :
1192 32 : bool WebAssemblyFastISel::selectStore(const Instruction *I) {
1193 : const StoreInst *Store = cast<StoreInst>(I);
1194 32 : if (Store->isAtomic())
1195 : return false;
1196 64 : if (!Subtarget->hasSIMD128() &&
1197 32 : Store->getValueOperand()->getType()->isVectorTy())
1198 : return false;
1199 :
1200 : Address Addr;
1201 32 : if (!computeAddress(Store->getPointerOperand(), Addr))
1202 : return false;
1203 :
1204 : unsigned Opc;
1205 : bool VTIsi1 = false;
1206 64 : switch (getSimpleType(Store->getValueOperand()->getType())) {
1207 0 : case MVT::i1:
1208 : VTIsi1 = true;
1209 : LLVM_FALLTHROUGH;
1210 : case MVT::i8:
1211 : Opc = WebAssembly::STORE8_I32;
1212 : break;
1213 : case MVT::i16:
1214 : Opc = WebAssembly::STORE16_I32;
1215 : break;
1216 24 : case MVT::i32:
1217 : Opc = WebAssembly::STORE_I32;
1218 24 : break;
1219 2 : case MVT::i64:
1220 : Opc = WebAssembly::STORE_I64;
1221 2 : break;
1222 1 : case MVT::f32:
1223 : Opc = WebAssembly::STORE_F32;
1224 1 : break;
1225 1 : case MVT::f64:
1226 : Opc = WebAssembly::STORE_F64;
1227 1 : break;
1228 : default:
1229 : return false;
1230 : }
1231 :
1232 32 : materializeLoadStoreOperands(Addr);
1233 :
1234 32 : unsigned ValueReg = getRegForValue(Store->getValueOperand());
1235 32 : if (ValueReg == 0)
1236 : return false;
1237 30 : if (VTIsi1)
1238 : ValueReg = maskI1Value(ValueReg, Store->getValueOperand());
1239 :
1240 60 : auto MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc));
1241 :
1242 30 : addLoadStoreOperands(Addr, MIB, createMachineMemOperandFor(Store));
1243 :
1244 30 : MIB.addReg(ValueReg);
1245 30 : return true;
1246 : }
1247 :
1248 20 : bool WebAssemblyFastISel::selectBr(const Instruction *I) {
1249 : const BranchInst *Br = cast<BranchInst>(I);
1250 20 : if (Br->isUnconditional()) {
1251 8 : MachineBasicBlock *MSucc = FuncInfo.MBBMap[Br->getSuccessor(0)];
1252 16 : fastEmitBranch(MSucc, Br->getDebugLoc());
1253 8 : return true;
1254 : }
1255 :
1256 12 : MachineBasicBlock *TBB = FuncInfo.MBBMap[Br->getSuccessor(0)];
1257 12 : MachineBasicBlock *FBB = FuncInfo.MBBMap[Br->getSuccessor(1)];
1258 :
1259 : bool Not;
1260 12 : unsigned CondReg = getRegForI1Value(Br->getCondition(), Not);
1261 12 : if (CondReg == 0)
1262 : return false;
1263 :
1264 : unsigned Opc = WebAssembly::BR_IF;
1265 10 : if (Not)
1266 : Opc = WebAssembly::BR_UNLESS;
1267 :
1268 20 : BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc))
1269 : .addMBB(TBB)
1270 10 : .addReg(CondReg);
1271 :
1272 10 : finishCondBranch(Br->getParent(), TBB, FBB);
1273 10 : return true;
1274 : }
1275 :
1276 479 : bool WebAssemblyFastISel::selectRet(const Instruction *I) {
1277 479 : if (!FuncInfo.CanLowerReturn)
1278 : return false;
1279 :
1280 : const ReturnInst *Ret = cast<ReturnInst>(I);
1281 :
1282 366 : if (Ret->getNumOperands() == 0) {
1283 38 : BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
1284 76 : TII.get(WebAssembly::RETURN_VOID));
1285 38 : return true;
1286 : }
1287 :
1288 : Value *RV = Ret->getOperand(0);
1289 328 : if (!Subtarget->hasSIMD128() && RV->getType()->isVectorTy())
1290 : return false;
1291 :
1292 : unsigned Opc;
1293 654 : switch (getSimpleType(RV->getType())) {
1294 : case MVT::i1:
1295 : case MVT::i8:
1296 : case MVT::i16:
1297 : case MVT::i32:
1298 : Opc = WebAssembly::RETURN_I32;
1299 : break;
1300 10 : case MVT::i64:
1301 : Opc = WebAssembly::RETURN_I64;
1302 10 : break;
1303 9 : case MVT::f32:
1304 : Opc = WebAssembly::RETURN_F32;
1305 9 : break;
1306 8 : case MVT::f64:
1307 : Opc = WebAssembly::RETURN_F64;
1308 8 : break;
1309 46 : case MVT::v16i8:
1310 : Opc = WebAssembly::RETURN_v16i8;
1311 46 : break;
1312 44 : case MVT::v8i16:
1313 : Opc = WebAssembly::RETURN_v8i16;
1314 44 : break;
1315 42 : case MVT::v4i32:
1316 : Opc = WebAssembly::RETURN_v4i32;
1317 42 : break;
1318 35 : case MVT::v2i64:
1319 : Opc = WebAssembly::RETURN_v2i64;
1320 35 : break;
1321 40 : case MVT::v4f32:
1322 : Opc = WebAssembly::RETURN_v4f32;
1323 40 : break;
1324 27 : case MVT::v2f64:
1325 : Opc = WebAssembly::RETURN_v2f64;
1326 27 : break;
1327 0 : case MVT::ExceptRef:
1328 : Opc = WebAssembly::RETURN_EXCEPT_REF;
1329 0 : break;
1330 : default:
1331 : return false;
1332 : }
1333 :
1334 : unsigned Reg;
1335 325 : if (FuncInfo.Fn->getAttributes().hasAttribute(0, Attribute::SExt))
1336 0 : Reg = getRegForSignedValue(RV);
1337 325 : else if (FuncInfo.Fn->getAttributes().hasAttribute(0, Attribute::ZExt))
1338 1 : Reg = getRegForUnsignedValue(RV);
1339 : else
1340 324 : Reg = getRegForValue(RV);
1341 :
1342 325 : if (Reg == 0)
1343 : return false;
1344 :
1345 646 : BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc)).addReg(Reg);
1346 323 : return true;
1347 : }
1348 :
1349 0 : bool WebAssemblyFastISel::selectUnreachable(const Instruction *I) {
1350 9 : BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
1351 18 : TII.get(WebAssembly::UNREACHABLE));
1352 0 : return true;
1353 : }
1354 :
1355 966 : bool WebAssemblyFastISel::fastSelectInstruction(const Instruction *I) {
1356 966 : switch (I->getOpcode()) {
1357 97 : case Instruction::Call:
1358 97 : if (selectCall(I))
1359 : return true;
1360 : break;
1361 32 : case Instruction::Select:
1362 32 : return selectSelect(I);
1363 1 : case Instruction::Trunc:
1364 1 : return selectTrunc(I);
1365 25 : case Instruction::ZExt:
1366 25 : return selectZExt(I);
1367 3 : case Instruction::SExt:
1368 3 : return selectSExt(I);
1369 26 : case Instruction::ICmp:
1370 26 : return selectICmp(I);
1371 0 : case Instruction::FCmp:
1372 0 : return selectFCmp(I);
1373 4 : case Instruction::BitCast:
1374 4 : return selectBitCast(I);
1375 25 : case Instruction::Load:
1376 25 : return selectLoad(I);
1377 32 : case Instruction::Store:
1378 32 : return selectStore(I);
1379 20 : case Instruction::Br:
1380 20 : return selectBr(I);
1381 479 : case Instruction::Ret:
1382 479 : return selectRet(I);
1383 : case Instruction::Unreachable:
1384 9 : return selectUnreachable(I);
1385 : default:
1386 : break;
1387 : }
1388 :
1389 : // Fall back to target-independent instruction selection.
1390 554 : return selectOperator(I, I->getOpcode());
1391 : }
1392 :
1393 478 : FastISel *WebAssembly::createFastISel(FunctionLoweringInfo &FuncInfo,
1394 : const TargetLibraryInfo *LibInfo) {
1395 478 : return new WebAssemblyFastISel(FuncInfo, LibInfo);
1396 : }
|