LLVM 23.0.0git
WebAssemblyFastISel.cpp
Go to the documentation of this file.
1//===-- WebAssemblyFastISel.cpp - WebAssembly FastISel 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 defines the WebAssembly-specific support for the FastISel
11/// class. Some of the target-specific code is generated by tablegen in the file
12/// WebAssemblyGenFastISel.inc, which is #included here.
13///
14/// TODO: kill flags
15///
16//===----------------------------------------------------------------------===//
17
32#include "llvm/IR/DataLayout.h"
34#include "llvm/IR/Function.h"
38#include "llvm/IR/Operator.h"
39
40using namespace llvm;
41
42#define DEBUG_TYPE "wasm-fastisel"
43
44namespace {
45
46class WebAssemblyFastISel final : public FastISel {
47 // All possible address modes.
48 class Address {
49 public:
50 enum BaseKind { RegBase, FrameIndexBase };
51
52 private:
53 BaseKind Kind = RegBase;
54 union {
55 unsigned Reg;
56 int FI;
57 } Base;
58
59 // Whether the base has been determined yet
60 bool IsBaseSet = false;
61
62 int64_t Offset = 0;
63
64 const GlobalValue *GV = nullptr;
65
66 public:
67 // Innocuous defaults for our address.
68 Address() { Base.Reg = 0; }
69 void setKind(BaseKind K) {
70 assert(!isSet() && "Can't change kind with non-zero base");
71 Kind = K;
72 }
73 BaseKind getKind() const { return Kind; }
74 bool isRegBase() const { return Kind == RegBase; }
75 bool isFIBase() const { return Kind == FrameIndexBase; }
76 void setReg(unsigned Reg) {
77 assert(isRegBase() && "Invalid base register access!");
78 assert(!IsBaseSet && "Base cannot be reset");
79 Base.Reg = Reg;
80 IsBaseSet = true;
81 }
82 unsigned getReg() const {
83 assert(isRegBase() && "Invalid base register access!");
84 return Base.Reg;
85 }
86 void setFI(unsigned FI) {
87 assert(isFIBase() && "Invalid base frame index access!");
88 assert(!IsBaseSet && "Base cannot be reset");
89 Base.FI = FI;
90 IsBaseSet = true;
91 }
92 unsigned getFI() const {
93 assert(isFIBase() && "Invalid base frame index access!");
94 return Base.FI;
95 }
96
97 void setOffset(int64_t NewOffset) {
98 assert(NewOffset >= 0 && "Offsets must be non-negative");
99 Offset = NewOffset;
100 }
101 int64_t getOffset() const { return Offset; }
102 void setGlobalValue(const GlobalValue *G) { GV = G; }
103 const GlobalValue *getGlobalValue() const { return GV; }
104 bool isSet() const { return IsBaseSet; }
105 };
106
107 /// Keep a pointer to the WebAssemblySubtarget around so that we can make the
108 /// right decision when generating code for different targets.
109 const WebAssemblySubtarget *Subtarget;
110 LLVMContext *Context;
111
112private:
113 // Utility helper routines
114 MVT::SimpleValueType getSimpleType(Type *Ty) {
115 EVT VT = TLI.getValueType(DL, Ty, /*AllowUnknown=*/true);
116 return VT.isSimple() ? VT.getSimpleVT().SimpleTy
118 }
120 switch (VT) {
121 case MVT::i1:
122 case MVT::i8:
123 case MVT::i16:
124 return MVT::i32;
125 case MVT::i32:
126 case MVT::i64:
127 case MVT::f32:
128 case MVT::f64:
129 return VT;
130 case MVT::funcref:
131 case MVT::externref:
132 if (Subtarget->hasReferenceTypes())
133 return VT;
134 break;
135 case MVT::exnref:
136 if (Subtarget->hasReferenceTypes() && Subtarget->hasExceptionHandling())
137 return VT;
138 break;
139 case MVT::f16:
140 return MVT::f32;
141 case MVT::v16i8:
142 case MVT::v8i16:
143 case MVT::v4i32:
144 case MVT::v4f32:
145 case MVT::v2i64:
146 case MVT::v2f64:
147 if (Subtarget->hasSIMD128())
148 return VT;
149 break;
150 default:
151 break;
152 }
154 }
155 bool computeAddress(const Value *Obj, Address &Addr);
156 void materializeLoadStoreOperands(Address &Addr);
157 void addLoadStoreOperands(const Address &Addr, const MachineInstrBuilder &MIB,
158 MachineMemOperand *MMO);
159 bool emitLoad(Register ResultReg, unsigned Opc, const LoadInst *LoadInst);
160 unsigned maskI1Value(unsigned Reg, const Value *V);
161 unsigned getRegForI1Value(const Value *V, const BasicBlock *BB, bool &Not);
162 unsigned zeroExtendToI32(unsigned Reg, const Value *V,
164 unsigned signExtendToI32(unsigned Reg, const Value *V,
166 unsigned zeroExtend(unsigned Reg, const Value *V, MVT::SimpleValueType From,
168 unsigned signExtend(unsigned Reg, const Value *V, MVT::SimpleValueType From,
170 unsigned getRegForUnsignedValue(const Value *V);
171 unsigned getRegForSignedValue(const Value *V);
172 unsigned getRegForPromotedValue(const Value *V, bool IsSigned);
173 unsigned notValue(unsigned Reg);
174 unsigned copyValue(unsigned Reg);
175
176 // Backend specific FastISel code.
177 Register fastMaterializeAlloca(const AllocaInst *AI) override;
178 Register fastMaterializeConstant(const Constant *C) override;
179 bool fastLowerArguments() override;
180
181 // Selection routines.
182 bool selectCall(const Instruction *I);
183 bool selectSelect(const Instruction *I);
184 bool selectTrunc(const Instruction *I);
185 bool selectZExt(const Instruction *I);
186 bool selectSExt(const Instruction *I);
187 bool selectICmp(const Instruction *I);
188 bool selectFCmp(const Instruction *I);
189 bool selectBitCast(const Instruction *I);
190 bool selectLoad(const Instruction *I);
191 bool selectStore(const Instruction *I);
192 bool selectBr(const Instruction *I);
193 bool selectRet(const Instruction *I);
194 bool selectUnreachable(const Instruction *I);
195
196public:
197 // Backend specific FastISel code.
198 WebAssemblyFastISel(FunctionLoweringInfo &FuncInfo,
199 const TargetLibraryInfo *LibInfo,
200 const LibcallLoweringInfo *LibcallLowering)
201 : FastISel(FuncInfo, LibInfo, LibcallLowering,
202 /*SkipTargetIndependentISel=*/true) {
203 Subtarget = &FuncInfo.MF->getSubtarget<WebAssemblySubtarget>();
204 Context = &FuncInfo.Fn->getContext();
205 }
206
207 bool fastSelectInstruction(const Instruction *I) override;
208 bool tryToFoldLoadIntoMI(MachineInstr *MI, unsigned OpNo,
209 const LoadInst *LI) override;
210
211#include "WebAssemblyGenFastISel.inc"
212};
213
214} // end anonymous namespace
215
216bool WebAssemblyFastISel::computeAddress(const Value *Obj, Address &Addr) {
217 const User *U = nullptr;
218 unsigned Opcode = Instruction::UserOp1;
219 if (const auto *I = dyn_cast<Instruction>(Obj)) {
220 // Don't walk into other basic blocks unless the object is an alloca from
221 // another block, otherwise it may not have a virtual register assigned.
222 if (FuncInfo.StaticAllocaMap.count(static_cast<const AllocaInst *>(Obj)) ||
223 FuncInfo.getMBB(I->getParent()) == FuncInfo.MBB) {
224 Opcode = I->getOpcode();
225 U = I;
226 }
227 } else if (const auto *C = dyn_cast<ConstantExpr>(Obj)) {
228 Opcode = C->getOpcode();
229 U = C;
230 }
231
232 if (auto *Ty = dyn_cast<PointerType>(Obj->getType()))
233 if (Ty->getAddressSpace() > 255)
234 // Fast instruction selection doesn't support the special
235 // address spaces.
236 return false;
237
238 if (const auto *GV = dyn_cast<GlobalValue>(Obj)) {
239 if (TLI.isPositionIndependent())
240 return false;
241 if (Addr.getGlobalValue())
242 return false;
243 if (GV->isThreadLocal())
244 return false;
245 Addr.setGlobalValue(GV);
246 return true;
247 }
248
249 switch (Opcode) {
250 default:
251 break;
252 case Instruction::BitCast: {
253 // Look through bitcasts.
254 return computeAddress(U->getOperand(0), Addr);
255 }
256 case Instruction::IntToPtr: {
257 // Look past no-op inttoptrs.
258 if (TLI.getValueType(DL, U->getOperand(0)->getType()) ==
259 TLI.getPointerTy(DL))
260 return computeAddress(U->getOperand(0), Addr);
261 break;
262 }
263 case Instruction::PtrToInt: {
264 // Look past no-op ptrtoints.
265 if (TLI.getValueType(DL, U->getType()) == TLI.getPointerTy(DL))
266 return computeAddress(U->getOperand(0), Addr);
267 break;
268 }
269 case Instruction::GetElementPtr: {
270 Address SavedAddr = Addr;
271 uint64_t TmpOffset = Addr.getOffset();
272 // Non-inbounds geps can wrap; wasm's offsets can't.
273 if (!cast<GEPOperator>(U)->isInBounds())
274 goto unsupported_gep;
275 // Iterate through the GEP folding the constants into offsets where
276 // we can.
278 GTI != E; ++GTI) {
279 const Value *Op = GTI.getOperand();
280 if (StructType *STy = GTI.getStructTypeOrNull()) {
281 const StructLayout *SL = DL.getStructLayout(STy);
282 unsigned Idx = cast<ConstantInt>(Op)->getZExtValue();
283 TmpOffset += SL->getElementOffset(Idx);
284 } else {
285 uint64_t S = GTI.getSequentialElementStride(DL);
286 for (;;) {
287 if (const auto *CI = dyn_cast<ConstantInt>(Op)) {
288 // Constant-offset addressing.
289 TmpOffset += CI->getSExtValue() * S;
290 break;
291 }
292 if (S == 1 && Addr.isRegBase() && Addr.getReg() == 0) {
293 // An unscaled add of a register. Set it as the new base.
294 Register Reg = getRegForValue(Op);
295 if (Reg == 0)
296 return false;
297 Addr.setReg(Reg);
298 break;
299 }
300 if (canFoldAddIntoGEP(U, Op)) {
301 // A compatible add with a constant operand. Fold the constant.
302 auto *CI = cast<ConstantInt>(cast<AddOperator>(Op)->getOperand(1));
303 TmpOffset += CI->getSExtValue() * S;
304 // Iterate on the other operand.
305 Op = cast<AddOperator>(Op)->getOperand(0);
306 continue;
307 }
308 // Unsupported
309 goto unsupported_gep;
310 }
311 }
312 }
313 // Don't fold in negative offsets.
314 if (int64_t(TmpOffset) >= 0) {
315 // Try to grab the base operand now.
316 Addr.setOffset(TmpOffset);
317 if (computeAddress(U->getOperand(0), Addr))
318 return true;
319 }
320 // We failed, restore everything and try the other options.
321 Addr = SavedAddr;
322 unsupported_gep:
323 break;
324 }
325 case Instruction::Alloca: {
326 const auto *AI = cast<AllocaInst>(Obj);
327 DenseMap<const AllocaInst *, int>::iterator SI =
328 FuncInfo.StaticAllocaMap.find(AI);
329 if (SI != FuncInfo.StaticAllocaMap.end()) {
330 if (Addr.isSet()) {
331 return false;
332 }
333 Addr.setKind(Address::FrameIndexBase);
334 Addr.setFI(SI->second);
335 return true;
336 }
337 break;
338 }
339 case Instruction::Add: {
340 // We should not fold operands into an offset when 'nuw' (no unsigned wrap)
341 // is not present, because the address calculation does not wrap.
342 if (auto *OFBinOp = dyn_cast<OverflowingBinaryOperator>(U))
343 if (!OFBinOp->hasNoUnsignedWrap())
344 break;
345
346 // Adds of constants are common and easy enough.
347 const Value *LHS = U->getOperand(0);
348 const Value *RHS = U->getOperand(1);
349
351 std::swap(LHS, RHS);
352
353 if (const auto *CI = dyn_cast<ConstantInt>(RHS)) {
354 uint64_t TmpOffset = Addr.getOffset() + CI->getSExtValue();
355 if (int64_t(TmpOffset) >= 0) {
356 Addr.setOffset(TmpOffset);
357 return computeAddress(LHS, Addr);
358 }
359 }
360
361 Address Backup = Addr;
362 if (computeAddress(LHS, Addr) && computeAddress(RHS, Addr))
363 return true;
364 Addr = Backup;
365
366 break;
367 }
368 case Instruction::Sub: {
369 // We should not fold operands into an offset when 'nuw' (no unsigned wrap)
370 // is not present, because the address calculation does not wrap.
371 if (auto *OFBinOp = dyn_cast<OverflowingBinaryOperator>(U))
372 if (!OFBinOp->hasNoUnsignedWrap())
373 break;
374
375 // Subs of constants are common and easy enough.
376 const Value *LHS = U->getOperand(0);
377 const Value *RHS = U->getOperand(1);
378
379 if (const auto *CI = dyn_cast<ConstantInt>(RHS)) {
380 int64_t TmpOffset = Addr.getOffset() - CI->getSExtValue();
381 if (TmpOffset >= 0) {
382 Addr.setOffset(TmpOffset);
383 return computeAddress(LHS, Addr);
384 }
385 }
386 break;
387 }
388 }
389 if (Addr.isSet()) {
390 return false;
391 }
392 Register Reg = getRegForValue(Obj);
393 if (Reg == 0)
394 return false;
395 Addr.setReg(Reg);
396 return Addr.getReg() != 0;
397}
398
399void WebAssemblyFastISel::materializeLoadStoreOperands(Address &Addr) {
400 if (Addr.isRegBase()) {
401 unsigned Reg = Addr.getReg();
402 if (Reg == 0) {
403 Reg = createResultReg(Subtarget->hasAddr64() ? &WebAssembly::I64RegClass
404 : &WebAssembly::I32RegClass);
405 unsigned Opc = Subtarget->hasAddr64() ? WebAssembly::CONST_I64
406 : WebAssembly::CONST_I32;
407 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc), Reg)
408 .addImm(0);
409 Addr.setReg(Reg);
410 }
411 }
412}
413
414void WebAssemblyFastISel::addLoadStoreOperands(const Address &Addr,
415 const MachineInstrBuilder &MIB,
416 MachineMemOperand *MMO) {
417 // Set the alignment operand (this is rewritten in SetP2AlignOperands).
418 // TODO: Disable SetP2AlignOperands for FastISel and just do it here.
419 MIB.addImm(0);
420
421 if (const GlobalValue *GV = Addr.getGlobalValue())
422 MIB.addGlobalAddress(GV, Addr.getOffset());
423 else
424 MIB.addImm(Addr.getOffset());
425
426 if (Addr.isRegBase())
427 MIB.addReg(Addr.getReg());
428 else
429 MIB.addFrameIndex(Addr.getFI());
430
431 MIB.addMemOperand(MMO);
432}
433
434bool WebAssemblyFastISel::emitLoad(Register ResultReg, unsigned Opc,
435 const LoadInst *Load) {
436 Address Addr;
437 if (!computeAddress(Load->getPointerOperand(), Addr))
438 return false;
439
440 materializeLoadStoreOperands(Addr);
441 auto MIB =
442 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc), ResultReg);
443 addLoadStoreOperands(Addr, MIB, createMachineMemOperandFor(Load));
444
445 return true;
446}
447
448unsigned WebAssemblyFastISel::maskI1Value(unsigned Reg, const Value *V) {
449 return zeroExtendToI32(Reg, V, MVT::i1);
450}
451
452unsigned WebAssemblyFastISel::getRegForI1Value(const Value *V,
453 const BasicBlock *BB,
454 bool &Not) {
455 if (const auto *ICmp = dyn_cast<ICmpInst>(V))
456 if (const ConstantInt *C = dyn_cast<ConstantInt>(ICmp->getOperand(1)))
457 if (ICmp->isEquality() && C->isZero() && C->getType()->isIntegerTy(32) &&
458 ICmp->getParent() == BB) {
459 Not = ICmp->isTrueWhenEqual();
460 return getRegForValue(ICmp->getOperand(0));
461 }
462
463 Not = false;
464 Register Reg = getRegForValue(V);
465 if (Reg == 0)
466 return 0;
467 return maskI1Value(Reg, V);
468}
469
470unsigned WebAssemblyFastISel::zeroExtendToI32(unsigned Reg, const Value *V,
472 if (Reg == 0)
473 return 0;
474
475 switch (From) {
476 case MVT::i1:
477 // If the value is naturally an i1, we don't need to mask it. We only know
478 // if a value is naturally an i1 if it is definitely lowered by FastISel,
479 // not a DAG ISel fallback.
480 if (V != nullptr && isa<Argument>(V) && cast<Argument>(V)->hasZExtAttr())
481 return copyValue(Reg);
482 break;
483 case MVT::i8:
484 case MVT::i16:
485 break;
486 case MVT::i32:
487 return copyValue(Reg);
488 default:
489 return 0;
490 }
491
492 Register Imm = createResultReg(&WebAssembly::I32RegClass);
493 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
494 TII.get(WebAssembly::CONST_I32), Imm)
495 .addImm(~(~uint64_t(0) << MVT(From).getSizeInBits()));
496
497 Register Result = createResultReg(&WebAssembly::I32RegClass);
498 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(WebAssembly::AND_I32),
499 Result)
500 .addReg(Reg)
501 .addReg(Imm);
502
503 return Result;
504}
505
506unsigned WebAssemblyFastISel::signExtendToI32(unsigned Reg, const Value *V,
508 if (Reg == 0)
509 return 0;
510
511 switch (From) {
512 case MVT::i1:
513 case MVT::i8:
514 case MVT::i16:
515 break;
516 case MVT::i32:
517 return copyValue(Reg);
518 default:
519 return 0;
520 }
521
522 if (Subtarget->hasSignExt()) {
523 if (From == MVT::i8 || From == MVT::i16) {
524 Register Result = createResultReg(&WebAssembly::I32RegClass);
525 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
526 TII.get(From == MVT::i16 ? WebAssembly::I32_EXTEND16_S_I32
527 : WebAssembly::I32_EXTEND8_S_I32),
528 Result)
529 .addReg(Reg);
530 return Result;
531 }
532 }
533
534 Register Imm = createResultReg(&WebAssembly::I32RegClass);
535 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
536 TII.get(WebAssembly::CONST_I32), Imm)
537 .addImm(32 - MVT(From).getSizeInBits());
538
539 Register Left = createResultReg(&WebAssembly::I32RegClass);
540 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(WebAssembly::SHL_I32),
541 Left)
542 .addReg(Reg)
543 .addReg(Imm);
544
545 Register Right = createResultReg(&WebAssembly::I32RegClass);
546 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
547 TII.get(WebAssembly::SHR_S_I32), Right)
548 .addReg(Left)
549 .addReg(Imm);
550
551 return Right;
552}
553
554unsigned WebAssemblyFastISel::zeroExtend(unsigned Reg, const Value *V,
557 if (To == MVT::i64) {
558 if (From == MVT::i64)
559 return copyValue(Reg);
560
561 Reg = zeroExtendToI32(Reg, V, From);
562
563 Register Result = createResultReg(&WebAssembly::I64RegClass);
564 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
565 TII.get(WebAssembly::I64_EXTEND_U_I32), Result)
566 .addReg(Reg);
567 return Result;
568 }
569
570 if (To == MVT::i32)
571 return zeroExtendToI32(Reg, V, From);
572
573 return 0;
574}
575
576unsigned WebAssemblyFastISel::signExtend(unsigned Reg, const Value *V,
579 if (To == MVT::i64) {
580 if (From == MVT::i64)
581 return copyValue(Reg);
582
583 Register Result = createResultReg(&WebAssembly::I64RegClass);
584
585 if (Subtarget->hasSignExt()) {
586 if (From != MVT::i32) {
587 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
588 TII.get(WebAssembly::I64_EXTEND_U_I32), Result)
589 .addReg(Reg);
590
591 Reg = Result;
592 Result = createResultReg(&WebAssembly::I64RegClass);
593 }
594
595 switch (From) {
596 case MVT::i8:
597 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
598 TII.get(WebAssembly::I64_EXTEND8_S_I64), Result)
599 .addReg(Reg);
600 return Result;
601 case MVT::i16:
602 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
603 TII.get(WebAssembly::I64_EXTEND16_S_I64), Result)
604 .addReg(Reg);
605 return Result;
606 case MVT::i32:
607 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
608 TII.get(WebAssembly::I64_EXTEND_S_I32), Result)
609 .addReg(Reg);
610 return Result;
611 default:
612 break;
613 }
614 } else {
615 Reg = signExtendToI32(Reg, V, From);
616
617 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
618 TII.get(WebAssembly::I64_EXTEND_S_I32), Result)
619 .addReg(Reg);
620 }
621
622 return Result;
623 }
624
625 if (To == MVT::i32)
626 return signExtendToI32(Reg, V, From);
627
628 return 0;
629}
630
631unsigned WebAssemblyFastISel::getRegForUnsignedValue(const Value *V) {
632 MVT::SimpleValueType From = getSimpleType(V->getType());
633 MVT::SimpleValueType To = getLegalType(From);
634 Register VReg = getRegForValue(V);
635 if (VReg == 0)
636 return 0;
637 if (From == To)
638 return VReg;
639 return zeroExtend(VReg, V, From, To);
640}
641
642unsigned WebAssemblyFastISel::getRegForSignedValue(const Value *V) {
643 MVT::SimpleValueType From = getSimpleType(V->getType());
644 MVT::SimpleValueType To = getLegalType(From);
645 Register VReg = getRegForValue(V);
646 if (VReg == 0)
647 return 0;
648 if (From == To)
649 return VReg;
650 return signExtend(VReg, V, From, To);
651}
652
653unsigned WebAssemblyFastISel::getRegForPromotedValue(const Value *V,
654 bool IsSigned) {
655 return IsSigned ? getRegForSignedValue(V) : getRegForUnsignedValue(V);
656}
657
658unsigned WebAssemblyFastISel::notValue(unsigned Reg) {
659 assert(MRI.getRegClass(Reg) == &WebAssembly::I32RegClass);
660
661 Register NotReg = createResultReg(&WebAssembly::I32RegClass);
662 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(WebAssembly::EQZ_I32),
663 NotReg)
664 .addReg(Reg);
665 return NotReg;
666}
667
668unsigned WebAssemblyFastISel::copyValue(unsigned Reg) {
669 Register ResultReg = createResultReg(MRI.getRegClass(Reg));
670 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(WebAssembly::COPY),
671 ResultReg)
672 .addReg(Reg);
673 return ResultReg;
674}
675
676Register WebAssemblyFastISel::fastMaterializeAlloca(const AllocaInst *AI) {
677 DenseMap<const AllocaInst *, int>::iterator SI =
678 FuncInfo.StaticAllocaMap.find(AI);
679
680 if (SI != FuncInfo.StaticAllocaMap.end()) {
681 Register ResultReg =
682 createResultReg(Subtarget->hasAddr64() ? &WebAssembly::I64RegClass
683 : &WebAssembly::I32RegClass);
684 unsigned Opc =
685 Subtarget->hasAddr64() ? WebAssembly::COPY_I64 : WebAssembly::COPY_I32;
686 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc), ResultReg)
687 .addFrameIndex(SI->second);
688 return ResultReg;
689 }
690
691 return Register();
692}
693
694Register WebAssemblyFastISel::fastMaterializeConstant(const Constant *C) {
695 if (const GlobalValue *GV = dyn_cast<GlobalValue>(C)) {
696 if (TLI.isPositionIndependent())
697 return Register();
698 if (GV->isThreadLocal())
699 return Register();
700 Register ResultReg =
701 createResultReg(Subtarget->hasAddr64() ? &WebAssembly::I64RegClass
702 : &WebAssembly::I32RegClass);
703 unsigned Opc = Subtarget->hasAddr64() ? WebAssembly::CONST_I64
704 : WebAssembly::CONST_I32;
705 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc), ResultReg)
706 .addGlobalAddress(GV);
707 return ResultReg;
708 }
709
710 // Let target-independent code handle it.
711 return Register();
712}
713
714bool WebAssemblyFastISel::fastLowerArguments() {
715 if (!FuncInfo.CanLowerReturn)
716 return false;
717
718 const Function *F = FuncInfo.Fn;
719 if (F->isVarArg())
720 return false;
721
722 if (FuncInfo.Fn->getCallingConv() == CallingConv::Swift)
723 return false;
724
725 unsigned I = 0;
726 for (auto const &Arg : F->args()) {
727 const AttributeList &Attrs = F->getAttributes();
728 if (Attrs.hasParamAttr(I, Attribute::ByVal) ||
729 Attrs.hasParamAttr(I, Attribute::SwiftSelf) ||
730 Attrs.hasParamAttr(I, Attribute::SwiftError) ||
731 Attrs.hasParamAttr(I, Attribute::InAlloca) ||
732 Attrs.hasParamAttr(I, Attribute::Nest))
733 return false;
734
735 Type *ArgTy = Arg.getType();
736 if (ArgTy->isStructTy() || ArgTy->isArrayTy())
737 return false;
738 if (!Subtarget->hasSIMD128() && ArgTy->isVectorTy())
739 return false;
740
741 unsigned Opc;
742 const TargetRegisterClass *RC;
743 switch (getSimpleType(ArgTy)) {
744 case MVT::i1:
745 case MVT::i8:
746 case MVT::i16:
747 case MVT::i32:
748 Opc = WebAssembly::ARGUMENT_i32;
749 RC = &WebAssembly::I32RegClass;
750 break;
751 case MVT::i64:
752 Opc = WebAssembly::ARGUMENT_i64;
753 RC = &WebAssembly::I64RegClass;
754 break;
755 case MVT::f32:
756 Opc = WebAssembly::ARGUMENT_f32;
757 RC = &WebAssembly::F32RegClass;
758 break;
759 case MVT::f64:
760 Opc = WebAssembly::ARGUMENT_f64;
761 RC = &WebAssembly::F64RegClass;
762 break;
763 case MVT::v16i8:
764 Opc = WebAssembly::ARGUMENT_v16i8;
765 RC = &WebAssembly::V128RegClass;
766 break;
767 case MVT::v8i16:
768 Opc = WebAssembly::ARGUMENT_v8i16;
769 RC = &WebAssembly::V128RegClass;
770 break;
771 case MVT::v4i32:
772 Opc = WebAssembly::ARGUMENT_v4i32;
773 RC = &WebAssembly::V128RegClass;
774 break;
775 case MVT::v2i64:
776 Opc = WebAssembly::ARGUMENT_v2i64;
777 RC = &WebAssembly::V128RegClass;
778 break;
779 case MVT::v4f32:
780 Opc = WebAssembly::ARGUMENT_v4f32;
781 RC = &WebAssembly::V128RegClass;
782 break;
783 case MVT::v2f64:
784 Opc = WebAssembly::ARGUMENT_v2f64;
785 RC = &WebAssembly::V128RegClass;
786 break;
787 case MVT::funcref:
788 Opc = WebAssembly::ARGUMENT_funcref;
789 RC = &WebAssembly::FUNCREFRegClass;
790 break;
791 case MVT::externref:
792 Opc = WebAssembly::ARGUMENT_externref;
793 RC = &WebAssembly::EXTERNREFRegClass;
794 break;
795 case MVT::exnref:
796 Opc = WebAssembly::ARGUMENT_exnref;
797 RC = &WebAssembly::EXNREFRegClass;
798 break;
799 default:
800 return false;
801 }
802 Register ResultReg = createResultReg(RC);
803 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc), ResultReg)
804 .addImm(I);
805 updateValueMap(&Arg, ResultReg);
806
807 ++I;
808 }
809
810 MRI.addLiveIn(WebAssembly::ARGUMENTS);
811
812 auto *MFI = MF->getInfo<WebAssemblyFunctionInfo>();
813 for (auto const &Arg : F->args()) {
814 MVT::SimpleValueType ArgTy = getLegalType(getSimpleType(Arg.getType()));
815 if (ArgTy == MVT::INVALID_SIMPLE_VALUE_TYPE) {
816 MFI->clearParamsAndResults();
817 return false;
818 }
819 MFI->addParam(ArgTy);
820 }
821
822 if (!F->getReturnType()->isVoidTy()) {
824 getLegalType(getSimpleType(F->getReturnType()));
825 if (RetTy == MVT::INVALID_SIMPLE_VALUE_TYPE) {
826 MFI->clearParamsAndResults();
827 return false;
828 }
829 MFI->addResult(RetTy);
830 }
831
832 return true;
833}
834
835bool WebAssemblyFastISel::selectCall(const Instruction *I) {
836 const auto *Call = cast<CallInst>(I);
837
838 // FastISel does not support calls through funcref
840 WebAssembly::WasmAddressSpace::WASM_ADDRESS_SPACE_DEFAULT)
841 return false;
842
843 // TODO: Support tail calls in FastISel
844 if (Call->isMustTailCall() || Call->isInlineAsm() ||
846 return false;
847
849 if (Func && Func->isIntrinsic())
850 return false;
851
852 if (Call->getCallingConv() == CallingConv::Swift)
853 return false;
854
855 bool IsDirect = Func != nullptr;
856 if (!IsDirect && isa<ConstantExpr>(Call->getCalledOperand()))
857 return false;
858
859 FunctionType *FuncTy = Call->getFunctionType();
860 unsigned Opc = IsDirect ? WebAssembly::CALL : WebAssembly::CALL_INDIRECT;
861 bool IsVoid = FuncTy->getReturnType()->isVoidTy();
862 unsigned ResultReg;
863 if (!IsVoid) {
864 if (!Subtarget->hasSIMD128() && Call->getType()->isVectorTy())
865 return false;
866
867 MVT::SimpleValueType RetTy = getSimpleType(Call->getType());
868 switch (RetTy) {
869 case MVT::i1:
870 case MVT::i8:
871 case MVT::i16:
872 case MVT::i32:
873 ResultReg = createResultReg(&WebAssembly::I32RegClass);
874 break;
875 case MVT::i64:
876 ResultReg = createResultReg(&WebAssembly::I64RegClass);
877 break;
878 case MVT::f32:
879 ResultReg = createResultReg(&WebAssembly::F32RegClass);
880 break;
881 case MVT::f64:
882 ResultReg = createResultReg(&WebAssembly::F64RegClass);
883 break;
884 case MVT::v16i8:
885 ResultReg = createResultReg(&WebAssembly::V128RegClass);
886 break;
887 case MVT::v8i16:
888 ResultReg = createResultReg(&WebAssembly::V128RegClass);
889 break;
890 case MVT::v4i32:
891 ResultReg = createResultReg(&WebAssembly::V128RegClass);
892 break;
893 case MVT::v2i64:
894 ResultReg = createResultReg(&WebAssembly::V128RegClass);
895 break;
896 case MVT::v4f32:
897 ResultReg = createResultReg(&WebAssembly::V128RegClass);
898 break;
899 case MVT::v2f64:
900 ResultReg = createResultReg(&WebAssembly::V128RegClass);
901 break;
902 case MVT::funcref:
903 ResultReg = createResultReg(&WebAssembly::FUNCREFRegClass);
904 break;
905 case MVT::externref:
906 ResultReg = createResultReg(&WebAssembly::EXTERNREFRegClass);
907 break;
908 case MVT::exnref:
909 ResultReg = createResultReg(&WebAssembly::EXNREFRegClass);
910 break;
911 default:
912 return false;
913 }
914 }
915
916 SmallVector<unsigned, 8> Args;
917 for (unsigned I = 0, E = Call->arg_size(); I < E; ++I) {
919 MVT::SimpleValueType ArgTy = getSimpleType(V->getType());
921 return false;
922
923 const AttributeList &Attrs = Call->getAttributes();
924 if (Attrs.hasParamAttr(I, Attribute::ByVal) ||
925 Attrs.hasParamAttr(I, Attribute::SwiftSelf) ||
926 Attrs.hasParamAttr(I, Attribute::SwiftError) ||
927 Attrs.hasParamAttr(I, Attribute::InAlloca) ||
928 Attrs.hasParamAttr(I, Attribute::Nest))
929 return false;
930
931 unsigned Reg;
932
933 if (Call->paramHasAttr(I, Attribute::SExt))
934 Reg = getRegForSignedValue(V);
935 else if (Call->paramHasAttr(I, Attribute::ZExt))
936 Reg = getRegForUnsignedValue(V);
937 else
938 Reg = getRegForValue(V);
939
940 if (Reg == 0)
941 return false;
942
943 Args.push_back(Reg);
944 }
945
946 unsigned CalleeReg = 0;
947 if (!IsDirect) {
948 CalleeReg = getRegForValue(Call->getCalledOperand());
949 if (!CalleeReg)
950 return false;
951 }
952
953 auto MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc));
954
955 if (!IsVoid)
956 MIB.addReg(ResultReg, RegState::Define);
957
958 if (IsDirect) {
959 MIB.addGlobalAddress(Func);
960 } else {
961 // Placeholder for the type index.
962 MIB.addImm(0);
963 // The table into which this call_indirect indexes.
965 MF->getContext(), Subtarget);
966 if (Subtarget->hasCallIndirectOverlong()) {
967 MIB.addSym(Table);
968 } else {
969 // Otherwise for the MVP there is at most one table whose number is 0, but
970 // we can't write a table symbol or issue relocations. Instead we just
971 // ensure the table is live.
972 Table->setNoStrip();
973 MIB.addImm(0);
974 }
975 }
976
977 for (unsigned ArgReg : Args)
978 MIB.addReg(ArgReg);
979
980 if (!IsDirect)
981 MIB.addReg(CalleeReg);
982
983 if (!IsVoid)
984 updateValueMap(Call, ResultReg);
985
987 return true;
988}
989
990bool WebAssemblyFastISel::selectSelect(const Instruction *I) {
991 const auto *Select = cast<SelectInst>(I);
992
993 bool Not;
994 unsigned CondReg =
995 getRegForI1Value(Select->getCondition(), I->getParent(), Not);
996 if (CondReg == 0)
997 return false;
998
999 Register TrueReg = getRegForValue(Select->getTrueValue());
1000 if (TrueReg == 0)
1001 return false;
1002
1003 Register FalseReg = getRegForValue(Select->getFalseValue());
1004 if (FalseReg == 0)
1005 return false;
1006
1007 if (Not)
1008 std::swap(TrueReg, FalseReg);
1009
1010 unsigned Opc;
1011 const TargetRegisterClass *RC;
1012 switch (getSimpleType(Select->getType())) {
1013 case MVT::i1:
1014 case MVT::i8:
1015 case MVT::i16:
1016 case MVT::i32:
1017 Opc = WebAssembly::SELECT_I32;
1018 RC = &WebAssembly::I32RegClass;
1019 break;
1020 case MVT::i64:
1021 Opc = WebAssembly::SELECT_I64;
1022 RC = &WebAssembly::I64RegClass;
1023 break;
1024 case MVT::f32:
1025 Opc = WebAssembly::SELECT_F32;
1026 RC = &WebAssembly::F32RegClass;
1027 break;
1028 case MVT::f64:
1029 Opc = WebAssembly::SELECT_F64;
1030 RC = &WebAssembly::F64RegClass;
1031 break;
1032 case MVT::funcref:
1033 Opc = WebAssembly::SELECT_FUNCREF;
1034 RC = &WebAssembly::FUNCREFRegClass;
1035 break;
1036 case MVT::externref:
1037 Opc = WebAssembly::SELECT_EXTERNREF;
1038 RC = &WebAssembly::EXTERNREFRegClass;
1039 break;
1040 case MVT::exnref:
1041 Opc = WebAssembly::SELECT_EXNREF;
1042 RC = &WebAssembly::EXNREFRegClass;
1043 break;
1044 default:
1045 return false;
1046 }
1047
1048 Register ResultReg = createResultReg(RC);
1049 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc), ResultReg)
1050 .addReg(TrueReg)
1051 .addReg(FalseReg)
1052 .addReg(CondReg);
1053
1054 updateValueMap(Select, ResultReg);
1055 return true;
1056}
1057
1058bool WebAssemblyFastISel::selectTrunc(const Instruction *I) {
1059 const auto *Trunc = cast<TruncInst>(I);
1060
1061 const Value *Op = Trunc->getOperand(0);
1062 MVT::SimpleValueType From = getSimpleType(Op->getType());
1063 MVT::SimpleValueType To = getLegalType(getSimpleType(Trunc->getType()));
1064 Register In = getRegForValue(Op);
1065 if (In == 0)
1066 return false;
1067
1068 auto Truncate = [&](Register Reg) -> unsigned {
1069 if (From == MVT::i64) {
1070 if (To == MVT::i64)
1071 return copyValue(Reg);
1072
1073 if (To == MVT::i1 || To == MVT::i8 || To == MVT::i16 || To == MVT::i32) {
1074 Register Result = createResultReg(&WebAssembly::I32RegClass);
1075 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
1076 TII.get(WebAssembly::I32_WRAP_I64), Result)
1077 .addReg(Reg);
1078 return Result;
1079 }
1080 }
1081
1082 if (From == MVT::i32)
1083 return copyValue(Reg);
1084
1085 return 0;
1086 };
1087
1088 unsigned Reg = Truncate(In);
1089 if (Reg == 0)
1090 return false;
1091
1092 updateValueMap(Trunc, Reg);
1093 return true;
1094}
1095
1096bool WebAssemblyFastISel::selectZExt(const Instruction *I) {
1097 const auto *ZExt = cast<ZExtInst>(I);
1098
1099 const Value *Op = ZExt->getOperand(0);
1100 MVT::SimpleValueType From = getSimpleType(Op->getType());
1101 MVT::SimpleValueType To = getLegalType(getSimpleType(ZExt->getType()));
1102 Register In = getRegForValue(Op);
1103 if (In == 0)
1104 return false;
1105 unsigned Reg = zeroExtend(In, Op, From, To);
1106 if (Reg == 0)
1107 return false;
1108
1109 updateValueMap(ZExt, Reg);
1110 return true;
1111}
1112
1113bool WebAssemblyFastISel::selectSExt(const Instruction *I) {
1114 const auto *SExt = cast<SExtInst>(I);
1115
1116 const Value *Op = SExt->getOperand(0);
1117 MVT::SimpleValueType From = getSimpleType(Op->getType());
1118 MVT::SimpleValueType To = getLegalType(getSimpleType(SExt->getType()));
1119 Register In = getRegForValue(Op);
1120 if (In == 0)
1121 return false;
1122 unsigned Reg = signExtend(In, Op, From, To);
1123 if (Reg == 0)
1124 return false;
1125
1126 updateValueMap(SExt, Reg);
1127 return true;
1128}
1129
1130bool WebAssemblyFastISel::selectICmp(const Instruction *I) {
1131 const auto *ICmp = cast<ICmpInst>(I);
1132
1133 bool I32 = getSimpleType(ICmp->getOperand(0)->getType()) != MVT::i64;
1134 unsigned Opc;
1135 bool IsSigned = false;
1136 switch (ICmp->getPredicate()) {
1137 case ICmpInst::ICMP_EQ:
1138 Opc = I32 ? WebAssembly::EQ_I32 : WebAssembly::EQ_I64;
1139 break;
1140 case ICmpInst::ICMP_NE:
1141 Opc = I32 ? WebAssembly::NE_I32 : WebAssembly::NE_I64;
1142 break;
1143 case ICmpInst::ICMP_UGT:
1144 Opc = I32 ? WebAssembly::GT_U_I32 : WebAssembly::GT_U_I64;
1145 break;
1146 case ICmpInst::ICMP_UGE:
1147 Opc = I32 ? WebAssembly::GE_U_I32 : WebAssembly::GE_U_I64;
1148 break;
1149 case ICmpInst::ICMP_ULT:
1150 Opc = I32 ? WebAssembly::LT_U_I32 : WebAssembly::LT_U_I64;
1151 break;
1152 case ICmpInst::ICMP_ULE:
1153 Opc = I32 ? WebAssembly::LE_U_I32 : WebAssembly::LE_U_I64;
1154 break;
1155 case ICmpInst::ICMP_SGT:
1156 Opc = I32 ? WebAssembly::GT_S_I32 : WebAssembly::GT_S_I64;
1157 IsSigned = true;
1158 break;
1159 case ICmpInst::ICMP_SGE:
1160 Opc = I32 ? WebAssembly::GE_S_I32 : WebAssembly::GE_S_I64;
1161 IsSigned = true;
1162 break;
1163 case ICmpInst::ICMP_SLT:
1164 Opc = I32 ? WebAssembly::LT_S_I32 : WebAssembly::LT_S_I64;
1165 IsSigned = true;
1166 break;
1167 case ICmpInst::ICMP_SLE:
1168 Opc = I32 ? WebAssembly::LE_S_I32 : WebAssembly::LE_S_I64;
1169 IsSigned = true;
1170 break;
1171 default:
1172 return false;
1173 }
1174
1175 unsigned LHS = getRegForPromotedValue(ICmp->getOperand(0), IsSigned);
1176 if (LHS == 0)
1177 return false;
1178
1179 unsigned RHS = getRegForPromotedValue(ICmp->getOperand(1), IsSigned);
1180 if (RHS == 0)
1181 return false;
1182
1183 Register ResultReg = createResultReg(&WebAssembly::I32RegClass);
1184 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc), ResultReg)
1185 .addReg(LHS)
1186 .addReg(RHS);
1187 updateValueMap(ICmp, ResultReg);
1188 return true;
1189}
1190
1191bool WebAssemblyFastISel::selectFCmp(const Instruction *I) {
1192 const auto *FCmp = cast<FCmpInst>(I);
1193
1194 Register LHS = getRegForValue(FCmp->getOperand(0));
1195 if (LHS == 0)
1196 return false;
1197
1198 Register RHS = getRegForValue(FCmp->getOperand(1));
1199 if (RHS == 0)
1200 return false;
1201
1202 bool F32 = getSimpleType(FCmp->getOperand(0)->getType()) != MVT::f64;
1203 unsigned Opc;
1204 bool Not = false;
1205 switch (FCmp->getPredicate()) {
1206 case FCmpInst::FCMP_OEQ:
1207 Opc = F32 ? WebAssembly::EQ_F32 : WebAssembly::EQ_F64;
1208 break;
1209 case FCmpInst::FCMP_UNE:
1210 Opc = F32 ? WebAssembly::NE_F32 : WebAssembly::NE_F64;
1211 break;
1212 case FCmpInst::FCMP_OGT:
1213 Opc = F32 ? WebAssembly::GT_F32 : WebAssembly::GT_F64;
1214 break;
1215 case FCmpInst::FCMP_OGE:
1216 Opc = F32 ? WebAssembly::GE_F32 : WebAssembly::GE_F64;
1217 break;
1218 case FCmpInst::FCMP_OLT:
1219 Opc = F32 ? WebAssembly::LT_F32 : WebAssembly::LT_F64;
1220 break;
1221 case FCmpInst::FCMP_OLE:
1222 Opc = F32 ? WebAssembly::LE_F32 : WebAssembly::LE_F64;
1223 break;
1224 case FCmpInst::FCMP_UGT:
1225 Opc = F32 ? WebAssembly::LE_F32 : WebAssembly::LE_F64;
1226 Not = true;
1227 break;
1228 case FCmpInst::FCMP_UGE:
1229 Opc = F32 ? WebAssembly::LT_F32 : WebAssembly::LT_F64;
1230 Not = true;
1231 break;
1232 case FCmpInst::FCMP_ULT:
1233 Opc = F32 ? WebAssembly::GE_F32 : WebAssembly::GE_F64;
1234 Not = true;
1235 break;
1236 case FCmpInst::FCMP_ULE:
1237 Opc = F32 ? WebAssembly::GT_F32 : WebAssembly::GT_F64;
1238 Not = true;
1239 break;
1240 default:
1241 return false;
1242 }
1243
1244 Register ResultReg = createResultReg(&WebAssembly::I32RegClass);
1245 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc), ResultReg)
1246 .addReg(LHS)
1247 .addReg(RHS);
1248
1249 if (Not)
1250 ResultReg = notValue(ResultReg);
1251
1252 updateValueMap(FCmp, ResultReg);
1253 return true;
1254}
1255
1256bool WebAssemblyFastISel::selectBitCast(const Instruction *I) {
1257 // Target-independent code can handle this, except it doesn't set the dead
1258 // flag on the ARGUMENTS clobber, so we have to do that manually in order
1259 // to satisfy code that expects this of isBitcast() instructions.
1260 EVT VT = TLI.getValueType(DL, I->getOperand(0)->getType());
1261 EVT RetVT = TLI.getValueType(DL, I->getType());
1262 if (!VT.isSimple() || !RetVT.isSimple())
1263 return false;
1264
1265 Register In = getRegForValue(I->getOperand(0));
1266 if (In == 0)
1267 return false;
1268
1269 if (VT == RetVT) {
1270 // No-op bitcast.
1271 updateValueMap(I, In);
1272 return true;
1273 }
1274
1275 Register Reg =
1276 fastEmit_ISD_BITCAST_r(VT.getSimpleVT(), RetVT.getSimpleVT(), In);
1277 if (!Reg)
1278 return false;
1279 MachineBasicBlock::iterator Iter = FuncInfo.InsertPt;
1280 --Iter;
1281 assert(Iter->isBitcast());
1282 Iter->setPhysRegsDeadExcept(ArrayRef<Register>(), TRI);
1283 updateValueMap(I, Reg);
1284 return true;
1285}
1286
1287static unsigned getSExtLoadOpcode(unsigned Opc, bool A64) {
1288 switch (Opc) {
1289 default:
1290 return WebAssembly::INSTRUCTION_LIST_END;
1291 case WebAssembly::I32_EXTEND8_S_I32:
1292 Opc = A64 ? WebAssembly::LOAD8_S_I32_A64 : WebAssembly::LOAD8_S_I32_A32;
1293 break;
1294 case WebAssembly::I32_EXTEND16_S_I32:
1295 Opc = A64 ? WebAssembly::LOAD16_S_I32_A64 : WebAssembly::LOAD16_S_I32_A32;
1296 break;
1297 case WebAssembly::I64_EXTEND8_S_I64:
1298 Opc = A64 ? WebAssembly::LOAD8_S_I64_A64 : WebAssembly::LOAD8_S_I64_A32;
1299 break;
1300 case WebAssembly::I64_EXTEND16_S_I64:
1301 Opc = A64 ? WebAssembly::LOAD16_S_I64_A64 : WebAssembly::LOAD16_S_I64_A32;
1302 break;
1303 case WebAssembly::I64_EXTEND32_S_I64:
1304 case WebAssembly::I64_EXTEND_S_I32:
1305 Opc = A64 ? WebAssembly::LOAD32_S_I64_A64 : WebAssembly::LOAD32_S_I64_A32;
1306 break;
1307 }
1308
1309 return Opc;
1310}
1311
1312bool WebAssemblyFastISel::tryToFoldLoadIntoMI(MachineInstr *MI, unsigned OpNo,
1313 const LoadInst *LI) {
1314 bool A64 = Subtarget->hasAddr64();
1315 unsigned NewOpc;
1316 if ((NewOpc = getSExtLoadOpcode(MI->getOpcode(), A64)) ==
1317 WebAssembly::INSTRUCTION_LIST_END)
1318 return false;
1319
1320 Register ResultReg = MI->getOperand(0).getReg();
1321 if (!emitLoad(ResultReg, NewOpc, LI))
1322 return false;
1323
1325 removeDeadCode(Iter, std::next(Iter));
1326 return true;
1327}
1328
1329bool WebAssemblyFastISel::selectLoad(const Instruction *I) {
1330 const auto *Load = cast<LoadInst>(I);
1331 if (Load->isAtomic())
1332 return false;
1333 if (!WebAssembly::isDefaultAddressSpace(Load->getPointerAddressSpace()))
1334 return false;
1335 if (!Subtarget->hasSIMD128() && Load->getType()->isVectorTy())
1336 return false;
1337
1338 // TODO: Fold a following sign-/zero-extend into the load instruction.
1339
1340 unsigned Opc;
1341 const TargetRegisterClass *RC;
1342 bool A64 = Subtarget->hasAddr64();
1343 switch (getSimpleType(Load->getType())) {
1344 case MVT::i1:
1345 case MVT::i8:
1346 Opc = A64 ? WebAssembly::LOAD8_U_I32_A64 : WebAssembly::LOAD8_U_I32_A32;
1347 RC = &WebAssembly::I32RegClass;
1348 break;
1349 case MVT::i16:
1350 Opc = A64 ? WebAssembly::LOAD16_U_I32_A64 : WebAssembly::LOAD16_U_I32_A32;
1351 RC = &WebAssembly::I32RegClass;
1352 break;
1353 case MVT::i32:
1354 Opc = A64 ? WebAssembly::LOAD_I32_A64 : WebAssembly::LOAD_I32_A32;
1355 RC = &WebAssembly::I32RegClass;
1356 break;
1357 case MVT::i64:
1358 Opc = A64 ? WebAssembly::LOAD_I64_A64 : WebAssembly::LOAD_I64_A32;
1359 RC = &WebAssembly::I64RegClass;
1360 break;
1361 case MVT::f32:
1362 Opc = A64 ? WebAssembly::LOAD_F32_A64 : WebAssembly::LOAD_F32_A32;
1363 RC = &WebAssembly::F32RegClass;
1364 break;
1365 case MVT::f64:
1366 Opc = A64 ? WebAssembly::LOAD_F64_A64 : WebAssembly::LOAD_F64_A32;
1367 RC = &WebAssembly::F64RegClass;
1368 break;
1369 default:
1370 return false;
1371 }
1372
1373 Register ResultReg = createResultReg(RC);
1374 if (!emitLoad(ResultReg, Opc, Load))
1375 return false;
1376
1377 updateValueMap(Load, ResultReg);
1378 return true;
1379}
1380
1381bool WebAssemblyFastISel::selectStore(const Instruction *I) {
1382 const auto *Store = cast<StoreInst>(I);
1383 if (Store->isAtomic())
1384 return false;
1385 if (!WebAssembly::isDefaultAddressSpace(Store->getPointerAddressSpace()))
1386 return false;
1387 if (!Subtarget->hasSIMD128() &&
1388 Store->getValueOperand()->getType()->isVectorTy())
1389 return false;
1390
1391 Address Addr;
1392 if (!computeAddress(Store->getPointerOperand(), Addr))
1393 return false;
1394
1395 unsigned Opc;
1396 bool VTIsi1 = false;
1397 bool A64 = Subtarget->hasAddr64();
1398 switch (getSimpleType(Store->getValueOperand()->getType())) {
1399 case MVT::i1:
1400 VTIsi1 = true;
1401 [[fallthrough]];
1402 case MVT::i8:
1403 Opc = A64 ? WebAssembly::STORE8_I32_A64 : WebAssembly::STORE8_I32_A32;
1404 break;
1405 case MVT::i16:
1406 Opc = A64 ? WebAssembly::STORE16_I32_A64 : WebAssembly::STORE16_I32_A32;
1407 break;
1408 case MVT::i32:
1409 Opc = A64 ? WebAssembly::STORE_I32_A64 : WebAssembly::STORE_I32_A32;
1410 break;
1411 case MVT::i64:
1412 Opc = A64 ? WebAssembly::STORE_I64_A64 : WebAssembly::STORE_I64_A32;
1413 break;
1414 case MVT::f32:
1415 Opc = A64 ? WebAssembly::STORE_F32_A64 : WebAssembly::STORE_F32_A32;
1416 break;
1417 case MVT::f64:
1418 Opc = A64 ? WebAssembly::STORE_F64_A64 : WebAssembly::STORE_F64_A32;
1419 break;
1420 default:
1421 return false;
1422 }
1423
1424 materializeLoadStoreOperands(Addr);
1425
1426 Register ValueReg = getRegForValue(Store->getValueOperand());
1427 if (ValueReg == 0)
1428 return false;
1429 if (VTIsi1)
1430 ValueReg = maskI1Value(ValueReg, Store->getValueOperand());
1431
1432 auto MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc));
1433
1434 addLoadStoreOperands(Addr, MIB, createMachineMemOperandFor(Store));
1435
1436 MIB.addReg(ValueReg);
1437 return true;
1438}
1439
1440bool WebAssemblyFastISel::selectBr(const Instruction *I) {
1441 const auto *Br = cast<BranchInst>(I);
1442 if (Br->isUnconditional()) {
1443 MachineBasicBlock *MSucc = FuncInfo.getMBB(Br->getSuccessor(0));
1444 fastEmitBranch(MSucc, Br->getDebugLoc());
1445 return true;
1446 }
1447
1448 MachineBasicBlock *TBB = FuncInfo.getMBB(Br->getSuccessor(0));
1449 MachineBasicBlock *FBB = FuncInfo.getMBB(Br->getSuccessor(1));
1450
1451 bool Not;
1452 unsigned CondReg = getRegForI1Value(Br->getCondition(), Br->getParent(), Not);
1453 if (CondReg == 0)
1454 return false;
1455
1456 unsigned Opc = WebAssembly::BR_IF;
1457 if (Not)
1458 Opc = WebAssembly::BR_UNLESS;
1459
1460 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc))
1461 .addMBB(TBB)
1462 .addReg(CondReg);
1463
1464 finishCondBranch(Br->getParent(), TBB, FBB);
1465 return true;
1466}
1467
1468bool WebAssemblyFastISel::selectRet(const Instruction *I) {
1469 if (!FuncInfo.CanLowerReturn)
1470 return false;
1471
1472 const auto *Ret = cast<ReturnInst>(I);
1473
1474 if (Ret->getNumOperands() == 0) {
1475 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
1476 TII.get(WebAssembly::RETURN));
1477 return true;
1478 }
1479
1480 // TODO: support multiple return in FastISel
1481 if (Ret->getNumOperands() > 1)
1482 return false;
1483
1484 Value *RV = Ret->getOperand(0);
1485 if (!Subtarget->hasSIMD128() && RV->getType()->isVectorTy())
1486 return false;
1487
1488 switch (getSimpleType(RV->getType())) {
1489 case MVT::i1:
1490 case MVT::i8:
1491 case MVT::i16:
1492 case MVT::i32:
1493 case MVT::i64:
1494 case MVT::f32:
1495 case MVT::f64:
1496 case MVT::v16i8:
1497 case MVT::v8i16:
1498 case MVT::v4i32:
1499 case MVT::v2i64:
1500 case MVT::v4f32:
1501 case MVT::v2f64:
1502 case MVT::funcref:
1503 case MVT::externref:
1504 case MVT::exnref:
1505 break;
1506 default:
1507 return false;
1508 }
1509
1510 unsigned Reg;
1511 if (FuncInfo.Fn->getAttributes().hasRetAttr(Attribute::SExt))
1512 Reg = getRegForSignedValue(RV);
1513 else if (FuncInfo.Fn->getAttributes().hasRetAttr(Attribute::ZExt))
1514 Reg = getRegForUnsignedValue(RV);
1515 else
1516 Reg = getRegForValue(RV);
1517
1518 if (Reg == 0)
1519 return false;
1520
1521 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(WebAssembly::RETURN))
1522 .addReg(Reg);
1523 return true;
1524}
1525
1526bool WebAssemblyFastISel::selectUnreachable(const Instruction *I) {
1527 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
1528 TII.get(WebAssembly::UNREACHABLE));
1529 return true;
1530}
1531
1532bool WebAssemblyFastISel::fastSelectInstruction(const Instruction *I) {
1533 switch (I->getOpcode()) {
1534 case Instruction::Call:
1535 if (selectCall(I))
1536 return true;
1537 break;
1538 case Instruction::Select:
1539 return selectSelect(I);
1540 case Instruction::Trunc:
1541 return selectTrunc(I);
1542 case Instruction::ZExt:
1543 return selectZExt(I);
1544 case Instruction::SExt:
1545 return selectSExt(I);
1546 case Instruction::ICmp:
1547 return selectICmp(I);
1548 case Instruction::FCmp:
1549 return selectFCmp(I);
1550 case Instruction::BitCast:
1551 return selectBitCast(I);
1552 case Instruction::Load:
1553 return selectLoad(I);
1554 case Instruction::Store:
1555 return selectStore(I);
1556 case Instruction::Br:
1557 return selectBr(I);
1558 case Instruction::Ret:
1559 return selectRet(I);
1560 case Instruction::Unreachable:
1561 return selectUnreachable(I);
1562 default:
1563 break;
1564 }
1565
1566 // Fall back to target-independent instruction selection.
1567 return selectOperator(I, I->getOpcode());
1568}
1569
1570FastISel *
1572 const TargetLibraryInfo *LibInfo,
1573 const LibcallLoweringInfo *LibcallLowering) {
1574 return new WebAssemblyFastISel(FuncInfo, LibInfo, LibcallLowering);
1575}
static void emitLoad(MachineFunction &MF, MachineBasicBlock &MBB, MachineBasicBlock::iterator Pos, const TargetInstrInfo &TII, unsigned Reg1, unsigned Reg2, int Offset, bool IsPostDec)
Emit a load-pair instruction for frame-destroy.
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
constexpr LLT F32
AMDGPU Register Bank Select
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
This file defines the FastISel class.
const HexagonInstrInfo * TII
IRTranslator LLVM IR MI
#define F(x, y, z)
Definition MD5.cpp:54
#define I(x, y, z)
Definition MD5.cpp:57
#define G(x, y, z)
Definition MD5.cpp:55
This file declares the MachineConstantPool class which is an abstract constant pool to keep track of ...
Register Reg
Register const TargetRegisterInfo * TRI
Promote Memory to Register
Definition Mem2Reg.cpp:110
static MCRegister getReg(const MCDisassembler *D, unsigned RC, unsigned RegNo)
const SmallVectorImpl< MachineOperand > MachineBasicBlock * TBB
static unsigned getSExtLoadOpcode(unsigned Opc, bool A64)
This file provides WebAssembly-specific target descriptions.
This file declares WebAssembly-specific per-machine-function information.
This file declares the WebAssembly-specific subclass of TargetSubtarget.
This file contains the declaration of the WebAssembly-specific type parsing utility functions.
This file contains the declaration of the WebAssembly-specific utility functions.
Value * RHS
Value * LHS
an instruction to allocate memory on the stack
LLVM Basic Block Representation.
Definition BasicBlock.h:62
bool isInlineAsm() const
Check if this call is an inline asm statement.
Function * getCalledFunction() const
Returns the function called, or null if this is an indirect function invocation or the function signa...
CallingConv::ID getCallingConv() const
LLVM_ABI bool paramHasAttr(unsigned ArgNo, Attribute::AttrKind Kind) const
Determine whether the argument or parameter has the given attribute.
Value * getCalledOperand() const
Value * getArgOperand(unsigned i) const
FunctionType * getFunctionType() const
unsigned arg_size() const
AttributeList getAttributes() const
Return the attributes for this call.
bool isMustTailCall() const
This is an important base class in LLVM.
Definition Constant.h:43
This is a fast-path instruction selection class that generates poor code and doesn't support illegal ...
Definition FastISel.h:66
FunctionLoweringInfo - This contains information that is global to a function that is used when lower...
bool isVarArg() const
LLVMContext & getContext() const
getContext - Return a reference to the LLVMContext associated with this function.
Definition Function.cpp:358
This is an important class for using LLVM in a threaded context.
Definition LLVMContext.h:68
Tracks which library functions to use for a particular subtarget.
An instruction for reading from memory.
void setNoStrip() const
@ INVALID_SIMPLE_VALUE_TYPE
SimpleValueType SimpleTy
MachineInstrBundleIterator< MachineInstr > iterator
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
const MachineInstrBuilder & addReg(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a new virtual register operand.
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
const MachineInstrBuilder & addSym(MCSymbol *Sym, unsigned char TargetFlags=0) const
const MachineInstrBuilder & addFrameIndex(int Idx) const
const MachineInstrBuilder & addGlobalAddress(const GlobalValue *GV, int64_t Offset=0, unsigned TargetFlags=0) const
const MachineInstrBuilder & addMBB(MachineBasicBlock *MBB, unsigned TargetFlags=0) const
const MachineInstrBuilder & addMemOperand(MachineMemOperand *MMO) const
Representation of each machine instruction.
A description of a memory reference used in the backend.
Wrapper class representing virtual and physical registers.
Definition Register.h:20
TypeSize getElementOffset(unsigned Idx) const
Definition DataLayout.h:754
Provides information about what library functions are available for the current target.
The instances of the Type class are immutable: once they are created, they are never changed.
Definition Type.h:45
bool isVectorTy() const
True if this is an instance of VectorType.
Definition Type.h:273
bool isArrayTy() const
True if this is an instance of ArrayType.
Definition Type.h:264
LLVM_ABI unsigned getPointerAddressSpace() const
Get the address space of this pointer or pointer vector type.
bool isStructTy() const
True if this is an instance of StructType.
Definition Type.h:261
LLVM Value Representation.
Definition Value.h:75
Type * getType() const
All values are typed, get the type of this value.
Definition Value.h:256
CallInst * Call
constexpr char Args[]
Key for Kernel::Metadata::mArgs.
constexpr char Attrs[]
Key for Kernel::Metadata::mAttrs.
@ C
The default llvm calling convention, compatible with C.
Definition CallingConv.h:34
Not(const Pred &P) -> Not< Pred >
bool isDefaultAddressSpace(unsigned AS)
MCSymbolWasm * getOrCreateFunctionTableSymbol(MCContext &Ctx, const WebAssemblySubtarget *Subtarget)
Returns the __indirect_function_table, for use in call_indirect and in function bitcasts.
FastISel * createFastISel(FunctionLoweringInfo &funcInfo, const TargetLibraryInfo *libInfo, const LibcallLoweringInfo *libcallLowering)
@ User
could "use" a pointer
NodeAddr< FuncNode * > Func
Definition RDFGraph.h:393
This is an optimization pass for GlobalISel generic memory operations.
Definition Types.h:26
@ Offset
Definition DWP.cpp:532
FunctionAddr VTableAddr Value
Definition InstrProf.h:137
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
LLVM_ABI void diagnoseDontCall(const CallInst &CI)
gep_type_iterator gep_type_end(const User *GEP)
static Error getOffset(const SymbolRef &Sym, SectionRef Sec, uint64_t &Result)
generic_gep_type_iterator<> gep_type_iterator
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
Definition Casting.h:547
DWARFExpression::Operation Op
ArrayRef(const T &OneElt) -> ArrayRef< T >
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559
gep_type_iterator gep_type_begin(const User *GEP)
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
Definition BitVector.h:872
Extended Value Type.
Definition ValueTypes.h:35
bool isSimple() const
Test if the given EVT is simple (as opposed to being extended).
Definition ValueTypes.h:145
MVT getSimpleVT() const
Return the SimpleValueType held in the specified simple EVT.
Definition ValueTypes.h:324