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