LLVM 17.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
21#include "WebAssembly.h"
33#include "llvm/IR/DataLayout.h"
35#include "llvm/IR/Function.h"
37#include "llvm/IR/GlobalAlias.h"
41#include "llvm/IR/Operator.h"
43
44using namespace llvm;
45using namespace PatternMatch;
46
47#define DEBUG_TYPE "wasm-fastisel"
48
49namespace {
50
51class WebAssemblyFastISel final : public FastISel {
52 // All possible address modes.
53 class Address {
54 public:
55 using BaseKind = enum { RegBase, FrameIndexBase };
56
57 private:
58 BaseKind Kind = RegBase;
59 union {
60 unsigned Reg;
61 int FI;
62 } Base;
63
64 // Whether the base has been determined yet
65 bool IsBaseSet = false;
66
67 int64_t Offset = 0;
68
69 const GlobalValue *GV = nullptr;
70
71 public:
72 // Innocuous defaults for our address.
73 Address() { Base.Reg = 0; }
74 void setKind(BaseKind K) {
75 assert(!isSet() && "Can't change kind with non-zero base");
76 Kind = K;
77 }
78 BaseKind getKind() const { return Kind; }
79 bool isRegBase() const { return Kind == RegBase; }
80 bool isFIBase() const { return Kind == FrameIndexBase; }
81 void setReg(unsigned Reg) {
82 assert(isRegBase() && "Invalid base register access!");
83 assert(!IsBaseSet && "Base cannot be reset");
84 Base.Reg = Reg;
85 IsBaseSet = true;
86 }
87 unsigned getReg() const {
88 assert(isRegBase() && "Invalid base register access!");
89 return Base.Reg;
90 }
91 void setFI(unsigned FI) {
92 assert(isFIBase() && "Invalid base frame index access!");
93 assert(!IsBaseSet && "Base cannot be reset");
94 Base.FI = FI;
95 IsBaseSet = true;
96 }
97 unsigned getFI() const {
98 assert(isFIBase() && "Invalid base frame index access!");
99 return Base.FI;
100 }
101
102 void setOffset(int64_t NewOffset) {
103 assert(NewOffset >= 0 && "Offsets must be non-negative");
104 Offset = NewOffset;
105 }
106 int64_t getOffset() const { return Offset; }
107 void setGlobalValue(const GlobalValue *G) { GV = G; }
108 const GlobalValue *getGlobalValue() const { return GV; }
109 bool isSet() const { return IsBaseSet; }
110 };
111
112 /// Keep a pointer to the WebAssemblySubtarget around so that we can make the
113 /// right decision when generating code for different targets.
114 const WebAssemblySubtarget *Subtarget;
116
117private:
118 // Utility helper routines
119 MVT::SimpleValueType getSimpleType(Type *Ty) {
120 EVT VT = TLI.getValueType(DL, Ty, /*AllowUnknown=*/true);
121 return VT.isSimple() ? VT.getSimpleVT().SimpleTy
123 }
125 switch (VT) {
126 case MVT::i1:
127 case MVT::i8:
128 case MVT::i16:
129 return MVT::i32;
130 case MVT::i32:
131 case MVT::i64:
132 case MVT::f32:
133 case MVT::f64:
134 return VT;
135 case MVT::funcref:
136 case MVT::externref:
137 if (Subtarget->hasReferenceTypes())
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.MBBMap[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.
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 = DL.getTypeAllocSize(GTI.getIndexedType());
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 // Adds of constants are common and easy enough.
337 const Value *LHS = U->getOperand(0);
338 const Value *RHS = U->getOperand(1);
339
340 if (isa<ConstantInt>(LHS))
341 std::swap(LHS, RHS);
342
343 if (const auto *CI = dyn_cast<ConstantInt>(RHS)) {
344 uint64_t TmpOffset = Addr.getOffset() + CI->getSExtValue();
345 if (int64_t(TmpOffset) >= 0) {
346 Addr.setOffset(TmpOffset);
347 return computeAddress(LHS, Addr);
348 }
349 }
350
351 Address Backup = Addr;
352 if (computeAddress(LHS, Addr) && computeAddress(RHS, Addr))
353 return true;
354 Addr = Backup;
355
356 break;
357 }
358 case Instruction::Sub: {
359 // Subs of constants are common and easy enough.
360 const Value *LHS = U->getOperand(0);
361 const Value *RHS = U->getOperand(1);
362
363 if (const auto *CI = dyn_cast<ConstantInt>(RHS)) {
364 int64_t TmpOffset = Addr.getOffset() - CI->getSExtValue();
365 if (TmpOffset >= 0) {
366 Addr.setOffset(TmpOffset);
367 return computeAddress(LHS, Addr);
368 }
369 }
370 break;
371 }
372 }
373 if (Addr.isSet()) {
374 return false;
375 }
376 Register Reg = getRegForValue(Obj);
377 if (Reg == 0)
378 return false;
379 Addr.setReg(Reg);
380 return Addr.getReg() != 0;
381}
382
383void WebAssemblyFastISel::materializeLoadStoreOperands(Address &Addr) {
384 if (Addr.isRegBase()) {
385 unsigned Reg = Addr.getReg();
386 if (Reg == 0) {
387 Reg = createResultReg(Subtarget->hasAddr64() ? &WebAssembly::I64RegClass
388 : &WebAssembly::I32RegClass);
389 unsigned Opc = Subtarget->hasAddr64() ? WebAssembly::CONST_I64
390 : WebAssembly::CONST_I32;
391 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc), Reg)
392 .addImm(0);
393 Addr.setReg(Reg);
394 }
395 }
396}
397
398void WebAssemblyFastISel::addLoadStoreOperands(const Address &Addr,
399 const MachineInstrBuilder &MIB,
400 MachineMemOperand *MMO) {
401 // Set the alignment operand (this is rewritten in SetP2AlignOperands).
402 // TODO: Disable SetP2AlignOperands for FastISel and just do it here.
403 MIB.addImm(0);
404
405 if (const GlobalValue *GV = Addr.getGlobalValue())
406 MIB.addGlobalAddress(GV, Addr.getOffset());
407 else
408 MIB.addImm(Addr.getOffset());
409
410 if (Addr.isRegBase())
411 MIB.addReg(Addr.getReg());
412 else
413 MIB.addFrameIndex(Addr.getFI());
414
415 MIB.addMemOperand(MMO);
416}
417
418unsigned WebAssemblyFastISel::maskI1Value(unsigned Reg, const Value *V) {
419 return zeroExtendToI32(Reg, V, MVT::i1);
420}
421
422unsigned WebAssemblyFastISel::getRegForI1Value(const Value *V,
423 const BasicBlock *BB,
424 bool &Not) {
425 if (const auto *ICmp = dyn_cast<ICmpInst>(V))
426 if (const ConstantInt *C = dyn_cast<ConstantInt>(ICmp->getOperand(1)))
427 if (ICmp->isEquality() && C->isZero() && C->getType()->isIntegerTy(32) &&
428 ICmp->getParent() == BB) {
429 Not = ICmp->isTrueWhenEqual();
430 return getRegForValue(ICmp->getOperand(0));
431 }
432
433 Not = false;
434 Register Reg = getRegForValue(V);
435 if (Reg == 0)
436 return 0;
437 return maskI1Value(Reg, V);
438}
439
440unsigned WebAssemblyFastISel::zeroExtendToI32(unsigned Reg, const Value *V,
442 if (Reg == 0)
443 return 0;
444
445 switch (From) {
446 case MVT::i1:
447 // If the value is naturally an i1, we don't need to mask it. We only know
448 // if a value is naturally an i1 if it is definitely lowered by FastISel,
449 // not a DAG ISel fallback.
450 if (V != nullptr && isa<Argument>(V) && cast<Argument>(V)->hasZExtAttr())
451 return copyValue(Reg);
452 break;
453 case MVT::i8:
454 case MVT::i16:
455 break;
456 case MVT::i32:
457 return copyValue(Reg);
458 default:
459 return 0;
460 }
461
462 Register Imm = createResultReg(&WebAssembly::I32RegClass);
463 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
464 TII.get(WebAssembly::CONST_I32), Imm)
465 .addImm(~(~uint64_t(0) << MVT(From).getSizeInBits()));
466
467 Register Result = createResultReg(&WebAssembly::I32RegClass);
468 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
469 TII.get(WebAssembly::AND_I32), Result)
470 .addReg(Reg)
471 .addReg(Imm);
472
473 return Result;
474}
475
476unsigned WebAssemblyFastISel::signExtendToI32(unsigned Reg, const Value *V,
478 if (Reg == 0)
479 return 0;
480
481 switch (From) {
482 case MVT::i1:
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(32 - MVT(From).getSizeInBits());
496
497 Register Left = createResultReg(&WebAssembly::I32RegClass);
498 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
499 TII.get(WebAssembly::SHL_I32), Left)
500 .addReg(Reg)
501 .addReg(Imm);
502
503 Register Right = createResultReg(&WebAssembly::I32RegClass);
504 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
505 TII.get(WebAssembly::SHR_S_I32), Right)
506 .addReg(Left)
507 .addReg(Imm);
508
509 return Right;
510}
511
512unsigned WebAssemblyFastISel::zeroExtend(unsigned Reg, const Value *V,
515 if (To == MVT::i64) {
516 if (From == MVT::i64)
517 return copyValue(Reg);
518
519 Reg = zeroExtendToI32(Reg, V, From);
520
521 Register Result = createResultReg(&WebAssembly::I64RegClass);
522 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
523 TII.get(WebAssembly::I64_EXTEND_U_I32), Result)
524 .addReg(Reg);
525 return Result;
526 }
527
528 if (To == MVT::i32)
529 return zeroExtendToI32(Reg, V, From);
530
531 return 0;
532}
533
534unsigned WebAssemblyFastISel::signExtend(unsigned Reg, const Value *V,
537 if (To == MVT::i64) {
538 if (From == MVT::i64)
539 return copyValue(Reg);
540
541 Reg = signExtendToI32(Reg, V, From);
542
543 Register Result = createResultReg(&WebAssembly::I64RegClass);
544 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
545 TII.get(WebAssembly::I64_EXTEND_S_I32), Result)
546 .addReg(Reg);
547 return Result;
548 }
549
550 if (To == MVT::i32)
551 return signExtendToI32(Reg, V, From);
552
553 return 0;
554}
555
556unsigned WebAssemblyFastISel::getRegForUnsignedValue(const Value *V) {
557 MVT::SimpleValueType From = getSimpleType(V->getType());
558 MVT::SimpleValueType To = getLegalType(From);
559 Register VReg = getRegForValue(V);
560 if (VReg == 0)
561 return 0;
562 return zeroExtend(VReg, V, From, To);
563}
564
565unsigned WebAssemblyFastISel::getRegForSignedValue(const Value *V) {
566 MVT::SimpleValueType From = getSimpleType(V->getType());
567 MVT::SimpleValueType To = getLegalType(From);
568 Register VReg = getRegForValue(V);
569 if (VReg == 0)
570 return 0;
571 return signExtend(VReg, V, From, To);
572}
573
574unsigned WebAssemblyFastISel::getRegForPromotedValue(const Value *V,
575 bool IsSigned) {
576 return IsSigned ? getRegForSignedValue(V) : getRegForUnsignedValue(V);
577}
578
579unsigned WebAssemblyFastISel::notValue(unsigned Reg) {
580 assert(MRI.getRegClass(Reg) == &WebAssembly::I32RegClass);
581
582 Register NotReg = createResultReg(&WebAssembly::I32RegClass);
583 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
584 TII.get(WebAssembly::EQZ_I32), NotReg)
585 .addReg(Reg);
586 return NotReg;
587}
588
589unsigned WebAssemblyFastISel::copyValue(unsigned Reg) {
590 Register ResultReg = createResultReg(MRI.getRegClass(Reg));
591 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(WebAssembly::COPY),
592 ResultReg)
593 .addReg(Reg);
594 return ResultReg;
595}
596
597unsigned WebAssemblyFastISel::fastMaterializeAlloca(const AllocaInst *AI) {
599 FuncInfo.StaticAllocaMap.find(AI);
600
601 if (SI != FuncInfo.StaticAllocaMap.end()) {
602 Register ResultReg =
603 createResultReg(Subtarget->hasAddr64() ? &WebAssembly::I64RegClass
604 : &WebAssembly::I32RegClass);
605 unsigned Opc =
606 Subtarget->hasAddr64() ? WebAssembly::COPY_I64 : WebAssembly::COPY_I32;
607 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc), ResultReg)
608 .addFrameIndex(SI->second);
609 return ResultReg;
610 }
611
612 return 0;
613}
614
615unsigned WebAssemblyFastISel::fastMaterializeConstant(const Constant *C) {
616 if (const GlobalValue *GV = dyn_cast<GlobalValue>(C)) {
617 if (TLI.isPositionIndependent())
618 return 0;
619 if (GV->isThreadLocal())
620 return 0;
621 Register ResultReg =
622 createResultReg(Subtarget->hasAddr64() ? &WebAssembly::I64RegClass
623 : &WebAssembly::I32RegClass);
624 unsigned Opc = Subtarget->hasAddr64() ? WebAssembly::CONST_I64
625 : WebAssembly::CONST_I32;
626 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc), ResultReg)
627 .addGlobalAddress(GV);
628 return ResultReg;
629 }
630
631 // Let target-independent code handle it.
632 return 0;
633}
634
635bool WebAssemblyFastISel::fastLowerArguments() {
636 if (!FuncInfo.CanLowerReturn)
637 return false;
638
639 const Function *F = FuncInfo.Fn;
640 if (F->isVarArg())
641 return false;
642
643 if (FuncInfo.Fn->getCallingConv() == CallingConv::Swift)
644 return false;
645
646 unsigned I = 0;
647 for (auto const &Arg : F->args()) {
648 const AttributeList &Attrs = F->getAttributes();
649 if (Attrs.hasParamAttr(I, Attribute::ByVal) ||
650 Attrs.hasParamAttr(I, Attribute::SwiftSelf) ||
651 Attrs.hasParamAttr(I, Attribute::SwiftError) ||
652 Attrs.hasParamAttr(I, Attribute::InAlloca) ||
653 Attrs.hasParamAttr(I, Attribute::Nest))
654 return false;
655
656 Type *ArgTy = Arg.getType();
657 if (ArgTy->isStructTy() || ArgTy->isArrayTy())
658 return false;
659 if (!Subtarget->hasSIMD128() && ArgTy->isVectorTy())
660 return false;
661
662 unsigned Opc;
663 const TargetRegisterClass *RC;
664 switch (getSimpleType(ArgTy)) {
665 case MVT::i1:
666 case MVT::i8:
667 case MVT::i16:
668 case MVT::i32:
669 Opc = WebAssembly::ARGUMENT_i32;
670 RC = &WebAssembly::I32RegClass;
671 break;
672 case MVT::i64:
673 Opc = WebAssembly::ARGUMENT_i64;
674 RC = &WebAssembly::I64RegClass;
675 break;
676 case MVT::f32:
677 Opc = WebAssembly::ARGUMENT_f32;
678 RC = &WebAssembly::F32RegClass;
679 break;
680 case MVT::f64:
681 Opc = WebAssembly::ARGUMENT_f64;
682 RC = &WebAssembly::F64RegClass;
683 break;
684 case MVT::v16i8:
685 Opc = WebAssembly::ARGUMENT_v16i8;
686 RC = &WebAssembly::V128RegClass;
687 break;
688 case MVT::v8i16:
689 Opc = WebAssembly::ARGUMENT_v8i16;
690 RC = &WebAssembly::V128RegClass;
691 break;
692 case MVT::v4i32:
693 Opc = WebAssembly::ARGUMENT_v4i32;
694 RC = &WebAssembly::V128RegClass;
695 break;
696 case MVT::v2i64:
697 Opc = WebAssembly::ARGUMENT_v2i64;
698 RC = &WebAssembly::V128RegClass;
699 break;
700 case MVT::v4f32:
701 Opc = WebAssembly::ARGUMENT_v4f32;
702 RC = &WebAssembly::V128RegClass;
703 break;
704 case MVT::v2f64:
705 Opc = WebAssembly::ARGUMENT_v2f64;
706 RC = &WebAssembly::V128RegClass;
707 break;
708 case MVT::funcref:
709 Opc = WebAssembly::ARGUMENT_funcref;
710 RC = &WebAssembly::FUNCREFRegClass;
711 break;
712 case MVT::externref:
713 Opc = WebAssembly::ARGUMENT_externref;
714 RC = &WebAssembly::EXTERNREFRegClass;
715 break;
716 default:
717 return false;
718 }
719 Register ResultReg = createResultReg(RC);
720 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc), ResultReg)
721 .addImm(I);
722 updateValueMap(&Arg, ResultReg);
723
724 ++I;
725 }
726
727 MRI.addLiveIn(WebAssembly::ARGUMENTS);
728
729 auto *MFI = MF->getInfo<WebAssemblyFunctionInfo>();
730 for (auto const &Arg : F->args()) {
731 MVT::SimpleValueType ArgTy = getLegalType(getSimpleType(Arg.getType()));
732 if (ArgTy == MVT::INVALID_SIMPLE_VALUE_TYPE) {
733 MFI->clearParamsAndResults();
734 return false;
735 }
736 MFI->addParam(ArgTy);
737 }
738
739 if (!F->getReturnType()->isVoidTy()) {
741 getLegalType(getSimpleType(F->getReturnType()));
743 MFI->clearParamsAndResults();
744 return false;
745 }
746 MFI->addResult(RetTy);
747 }
748
749 return true;
750}
751
752bool WebAssemblyFastISel::selectCall(const Instruction *I) {
753 const auto *Call = cast<CallInst>(I);
754
755 // TODO: Support tail calls in FastISel
756 if (Call->isMustTailCall() || Call->isInlineAsm() ||
757 Call->getFunctionType()->isVarArg())
758 return false;
759
760 Function *Func = Call->getCalledFunction();
761 if (Func && Func->isIntrinsic())
762 return false;
763
764 if (Call->getCallingConv() == CallingConv::Swift)
765 return false;
766
767 bool IsDirect = Func != nullptr;
768 if (!IsDirect && isa<ConstantExpr>(Call->getCalledOperand()))
769 return false;
770
771 FunctionType *FuncTy = Call->getFunctionType();
772 unsigned Opc = IsDirect ? WebAssembly::CALL : WebAssembly::CALL_INDIRECT;
773 bool IsVoid = FuncTy->getReturnType()->isVoidTy();
774 unsigned ResultReg;
775 if (!IsVoid) {
776 if (!Subtarget->hasSIMD128() && Call->getType()->isVectorTy())
777 return false;
778
779 MVT::SimpleValueType RetTy = getSimpleType(Call->getType());
780 switch (RetTy) {
781 case MVT::i1:
782 case MVT::i8:
783 case MVT::i16:
784 case MVT::i32:
785 ResultReg = createResultReg(&WebAssembly::I32RegClass);
786 break;
787 case MVT::i64:
788 ResultReg = createResultReg(&WebAssembly::I64RegClass);
789 break;
790 case MVT::f32:
791 ResultReg = createResultReg(&WebAssembly::F32RegClass);
792 break;
793 case MVT::f64:
794 ResultReg = createResultReg(&WebAssembly::F64RegClass);
795 break;
796 case MVT::v16i8:
797 ResultReg = createResultReg(&WebAssembly::V128RegClass);
798 break;
799 case MVT::v8i16:
800 ResultReg = createResultReg(&WebAssembly::V128RegClass);
801 break;
802 case MVT::v4i32:
803 ResultReg = createResultReg(&WebAssembly::V128RegClass);
804 break;
805 case MVT::v2i64:
806 ResultReg = createResultReg(&WebAssembly::V128RegClass);
807 break;
808 case MVT::v4f32:
809 ResultReg = createResultReg(&WebAssembly::V128RegClass);
810 break;
811 case MVT::v2f64:
812 ResultReg = createResultReg(&WebAssembly::V128RegClass);
813 break;
814 case MVT::funcref:
815 ResultReg = createResultReg(&WebAssembly::FUNCREFRegClass);
816 break;
817 case MVT::externref:
818 ResultReg = createResultReg(&WebAssembly::EXTERNREFRegClass);
819 break;
820 default:
821 return false;
822 }
823 }
824
826 for (unsigned I = 0, E = Call->arg_size(); I < E; ++I) {
827 Value *V = Call->getArgOperand(I);
828 MVT::SimpleValueType ArgTy = getSimpleType(V->getType());
830 return false;
831
832 const AttributeList &Attrs = Call->getAttributes();
833 if (Attrs.hasParamAttr(I, Attribute::ByVal) ||
834 Attrs.hasParamAttr(I, Attribute::SwiftSelf) ||
835 Attrs.hasParamAttr(I, Attribute::SwiftError) ||
836 Attrs.hasParamAttr(I, Attribute::InAlloca) ||
837 Attrs.hasParamAttr(I, Attribute::Nest))
838 return false;
839
840 unsigned Reg;
841
842 if (Attrs.hasParamAttr(I, Attribute::SExt))
843 Reg = getRegForSignedValue(V);
844 else if (Attrs.hasParamAttr(I, Attribute::ZExt))
845 Reg = getRegForUnsignedValue(V);
846 else
847 Reg = getRegForValue(V);
848
849 if (Reg == 0)
850 return false;
851
852 Args.push_back(Reg);
853 }
854
855 unsigned CalleeReg = 0;
856 if (!IsDirect) {
857 CalleeReg = getRegForValue(Call->getCalledOperand());
858 if (!CalleeReg)
859 return false;
860 }
861
862 auto MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc));
863
864 if (!IsVoid)
865 MIB.addReg(ResultReg, RegState::Define);
866
867 if (IsDirect) {
868 MIB.addGlobalAddress(Func);
869 } else {
870 // Placeholder for the type index.
871 MIB.addImm(0);
872 // The table into which this call_indirect indexes.
874 MF->getMMI().getContext(), Subtarget);
875 if (Subtarget->hasReferenceTypes()) {
876 MIB.addSym(Table);
877 } else {
878 // Otherwise for the MVP there is at most one table whose number is 0, but
879 // we can't write a table symbol or issue relocations. Instead we just
880 // ensure the table is live.
881 Table->setNoStrip();
882 MIB.addImm(0);
883 }
884 // See if we must truncate the function pointer.
885 // CALL_INDIRECT takes an i32, but in wasm64 we represent function pointers
886 // as 64-bit for uniformity with other pointer types.
887 // See also: WebAssemblyISelLowering.cpp: LowerCallResults
888 if (Subtarget->hasAddr64()) {
889 auto Wrap = BuildMI(*FuncInfo.MBB, std::prev(FuncInfo.InsertPt), MIMD,
890 TII.get(WebAssembly::I32_WRAP_I64));
891 Register Reg32 = createResultReg(&WebAssembly::I32RegClass);
892 Wrap.addReg(Reg32, RegState::Define);
893 Wrap.addReg(CalleeReg);
894 CalleeReg = Reg32;
895 }
896 }
897
898 for (unsigned ArgReg : Args)
899 MIB.addReg(ArgReg);
900
901 if (!IsDirect)
902 MIB.addReg(CalleeReg);
903
904 if (!IsVoid)
905 updateValueMap(Call, ResultReg);
906 return true;
907}
908
909bool WebAssemblyFastISel::selectSelect(const Instruction *I) {
910 const auto *Select = cast<SelectInst>(I);
911
912 bool Not;
913 unsigned CondReg =
914 getRegForI1Value(Select->getCondition(), I->getParent(), Not);
915 if (CondReg == 0)
916 return false;
917
918 Register TrueReg = getRegForValue(Select->getTrueValue());
919 if (TrueReg == 0)
920 return false;
921
922 Register FalseReg = getRegForValue(Select->getFalseValue());
923 if (FalseReg == 0)
924 return false;
925
926 if (Not)
927 std::swap(TrueReg, FalseReg);
928
929 unsigned Opc;
930 const TargetRegisterClass *RC;
931 switch (getSimpleType(Select->getType())) {
932 case MVT::i1:
933 case MVT::i8:
934 case MVT::i16:
935 case MVT::i32:
936 Opc = WebAssembly::SELECT_I32;
937 RC = &WebAssembly::I32RegClass;
938 break;
939 case MVT::i64:
940 Opc = WebAssembly::SELECT_I64;
941 RC = &WebAssembly::I64RegClass;
942 break;
943 case MVT::f32:
944 Opc = WebAssembly::SELECT_F32;
945 RC = &WebAssembly::F32RegClass;
946 break;
947 case MVT::f64:
948 Opc = WebAssembly::SELECT_F64;
949 RC = &WebAssembly::F64RegClass;
950 break;
951 case MVT::funcref:
952 Opc = WebAssembly::SELECT_FUNCREF;
953 RC = &WebAssembly::FUNCREFRegClass;
954 break;
955 case MVT::externref:
956 Opc = WebAssembly::SELECT_EXTERNREF;
957 RC = &WebAssembly::EXTERNREFRegClass;
958 break;
959 default:
960 return false;
961 }
962
963 Register ResultReg = createResultReg(RC);
964 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc), ResultReg)
965 .addReg(TrueReg)
966 .addReg(FalseReg)
967 .addReg(CondReg);
968
969 updateValueMap(Select, ResultReg);
970 return true;
971}
972
973bool WebAssemblyFastISel::selectTrunc(const Instruction *I) {
974 const auto *Trunc = cast<TruncInst>(I);
975
976 Register Reg = getRegForValue(Trunc->getOperand(0));
977 if (Reg == 0)
978 return false;
979
980 if (Trunc->getOperand(0)->getType()->isIntegerTy(64)) {
981 Register Result = createResultReg(&WebAssembly::I32RegClass);
982 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
983 TII.get(WebAssembly::I32_WRAP_I64), Result)
984 .addReg(Reg);
985 Reg = Result;
986 }
987
988 updateValueMap(Trunc, Reg);
989 return true;
990}
991
992bool WebAssemblyFastISel::selectZExt(const Instruction *I) {
993 const auto *ZExt = cast<ZExtInst>(I);
994
995 const Value *Op = ZExt->getOperand(0);
996 MVT::SimpleValueType From = getSimpleType(Op->getType());
997 MVT::SimpleValueType To = getLegalType(getSimpleType(ZExt->getType()));
998 Register In = getRegForValue(Op);
999 if (In == 0)
1000 return false;
1001 unsigned Reg = zeroExtend(In, Op, From, To);
1002 if (Reg == 0)
1003 return false;
1004
1005 updateValueMap(ZExt, Reg);
1006 return true;
1007}
1008
1009bool WebAssemblyFastISel::selectSExt(const Instruction *I) {
1010 const auto *SExt = cast<SExtInst>(I);
1011
1012 const Value *Op = SExt->getOperand(0);
1013 MVT::SimpleValueType From = getSimpleType(Op->getType());
1014 MVT::SimpleValueType To = getLegalType(getSimpleType(SExt->getType()));
1015 Register In = getRegForValue(Op);
1016 if (In == 0)
1017 return false;
1018 unsigned Reg = signExtend(In, Op, From, To);
1019 if (Reg == 0)
1020 return false;
1021
1022 updateValueMap(SExt, Reg);
1023 return true;
1024}
1025
1026bool WebAssemblyFastISel::selectICmp(const Instruction *I) {
1027 const auto *ICmp = cast<ICmpInst>(I);
1028
1029 bool I32 = getSimpleType(ICmp->getOperand(0)->getType()) != MVT::i64;
1030 unsigned Opc;
1031 bool IsSigned = false;
1032 switch (ICmp->getPredicate()) {
1033 case ICmpInst::ICMP_EQ:
1034 Opc = I32 ? WebAssembly::EQ_I32 : WebAssembly::EQ_I64;
1035 break;
1036 case ICmpInst::ICMP_NE:
1037 Opc = I32 ? WebAssembly::NE_I32 : WebAssembly::NE_I64;
1038 break;
1039 case ICmpInst::ICMP_UGT:
1040 Opc = I32 ? WebAssembly::GT_U_I32 : WebAssembly::GT_U_I64;
1041 break;
1042 case ICmpInst::ICMP_UGE:
1043 Opc = I32 ? WebAssembly::GE_U_I32 : WebAssembly::GE_U_I64;
1044 break;
1045 case ICmpInst::ICMP_ULT:
1046 Opc = I32 ? WebAssembly::LT_U_I32 : WebAssembly::LT_U_I64;
1047 break;
1048 case ICmpInst::ICMP_ULE:
1049 Opc = I32 ? WebAssembly::LE_U_I32 : WebAssembly::LE_U_I64;
1050 break;
1051 case ICmpInst::ICMP_SGT:
1052 Opc = I32 ? WebAssembly::GT_S_I32 : WebAssembly::GT_S_I64;
1053 IsSigned = true;
1054 break;
1055 case ICmpInst::ICMP_SGE:
1056 Opc = I32 ? WebAssembly::GE_S_I32 : WebAssembly::GE_S_I64;
1057 IsSigned = true;
1058 break;
1059 case ICmpInst::ICMP_SLT:
1060 Opc = I32 ? WebAssembly::LT_S_I32 : WebAssembly::LT_S_I64;
1061 IsSigned = true;
1062 break;
1063 case ICmpInst::ICMP_SLE:
1064 Opc = I32 ? WebAssembly::LE_S_I32 : WebAssembly::LE_S_I64;
1065 IsSigned = true;
1066 break;
1067 default:
1068 return false;
1069 }
1070
1071 unsigned LHS = getRegForPromotedValue(ICmp->getOperand(0), IsSigned);
1072 if (LHS == 0)
1073 return false;
1074
1075 unsigned RHS = getRegForPromotedValue(ICmp->getOperand(1), IsSigned);
1076 if (RHS == 0)
1077 return false;
1078
1079 Register ResultReg = createResultReg(&WebAssembly::I32RegClass);
1080 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc), ResultReg)
1081 .addReg(LHS)
1082 .addReg(RHS);
1083 updateValueMap(ICmp, ResultReg);
1084 return true;
1085}
1086
1087bool WebAssemblyFastISel::selectFCmp(const Instruction *I) {
1088 const auto *FCmp = cast<FCmpInst>(I);
1089
1090 Register LHS = getRegForValue(FCmp->getOperand(0));
1091 if (LHS == 0)
1092 return false;
1093
1094 Register RHS = getRegForValue(FCmp->getOperand(1));
1095 if (RHS == 0)
1096 return false;
1097
1098 bool F32 = getSimpleType(FCmp->getOperand(0)->getType()) != MVT::f64;
1099 unsigned Opc;
1100 bool Not = false;
1101 switch (FCmp->getPredicate()) {
1102 case FCmpInst::FCMP_OEQ:
1103 Opc = F32 ? WebAssembly::EQ_F32 : WebAssembly::EQ_F64;
1104 break;
1105 case FCmpInst::FCMP_UNE:
1106 Opc = F32 ? WebAssembly::NE_F32 : WebAssembly::NE_F64;
1107 break;
1108 case FCmpInst::FCMP_OGT:
1109 Opc = F32 ? WebAssembly::GT_F32 : WebAssembly::GT_F64;
1110 break;
1111 case FCmpInst::FCMP_OGE:
1112 Opc = F32 ? WebAssembly::GE_F32 : WebAssembly::GE_F64;
1113 break;
1114 case FCmpInst::FCMP_OLT:
1115 Opc = F32 ? WebAssembly::LT_F32 : WebAssembly::LT_F64;
1116 break;
1117 case FCmpInst::FCMP_OLE:
1118 Opc = F32 ? WebAssembly::LE_F32 : WebAssembly::LE_F64;
1119 break;
1120 case FCmpInst::FCMP_UGT:
1121 Opc = F32 ? WebAssembly::LE_F32 : WebAssembly::LE_F64;
1122 Not = true;
1123 break;
1124 case FCmpInst::FCMP_UGE:
1125 Opc = F32 ? WebAssembly::LT_F32 : WebAssembly::LT_F64;
1126 Not = true;
1127 break;
1128 case FCmpInst::FCMP_ULT:
1129 Opc = F32 ? WebAssembly::GE_F32 : WebAssembly::GE_F64;
1130 Not = true;
1131 break;
1132 case FCmpInst::FCMP_ULE:
1133 Opc = F32 ? WebAssembly::GT_F32 : WebAssembly::GT_F64;
1134 Not = true;
1135 break;
1136 default:
1137 return false;
1138 }
1139
1140 Register ResultReg = createResultReg(&WebAssembly::I32RegClass);
1141 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc), ResultReg)
1142 .addReg(LHS)
1143 .addReg(RHS);
1144
1145 if (Not)
1146 ResultReg = notValue(ResultReg);
1147
1148 updateValueMap(FCmp, ResultReg);
1149 return true;
1150}
1151
1152bool WebAssemblyFastISel::selectBitCast(const Instruction *I) {
1153 // Target-independent code can handle this, except it doesn't set the dead
1154 // flag on the ARGUMENTS clobber, so we have to do that manually in order
1155 // to satisfy code that expects this of isBitcast() instructions.
1156 EVT VT = TLI.getValueType(DL, I->getOperand(0)->getType());
1157 EVT RetVT = TLI.getValueType(DL, I->getType());
1158 if (!VT.isSimple() || !RetVT.isSimple())
1159 return false;
1160
1161 Register In = getRegForValue(I->getOperand(0));
1162 if (In == 0)
1163 return false;
1164
1165 if (VT == RetVT) {
1166 // No-op bitcast.
1167 updateValueMap(I, In);
1168 return true;
1169 }
1170
1171 Register Reg = fastEmit_ISD_BITCAST_r(VT.getSimpleVT(), RetVT.getSimpleVT(),
1172 In);
1173 if (!Reg)
1174 return false;
1175 MachineBasicBlock::iterator Iter = FuncInfo.InsertPt;
1176 --Iter;
1177 assert(Iter->isBitcast());
1178 Iter->setPhysRegsDeadExcept(ArrayRef<Register>(), TRI);
1179 updateValueMap(I, Reg);
1180 return true;
1181}
1182
1183bool WebAssemblyFastISel::selectLoad(const Instruction *I) {
1184 const auto *Load = cast<LoadInst>(I);
1185 if (Load->isAtomic())
1186 return false;
1187 if (!WebAssembly::isDefaultAddressSpace(Load->getPointerAddressSpace()))
1188 return false;
1189 if (!Subtarget->hasSIMD128() && Load->getType()->isVectorTy())
1190 return false;
1191
1192 Address Addr;
1193 if (!computeAddress(Load->getPointerOperand(), Addr))
1194 return false;
1195
1196 // TODO: Fold a following sign-/zero-extend into the load instruction.
1197
1198 unsigned Opc;
1199 const TargetRegisterClass *RC;
1200 bool A64 = Subtarget->hasAddr64();
1201 switch (getSimpleType(Load->getType())) {
1202 case MVT::i1:
1203 case MVT::i8:
1204 Opc = A64 ? WebAssembly::LOAD8_U_I32_A64 : WebAssembly::LOAD8_U_I32_A32;
1205 RC = &WebAssembly::I32RegClass;
1206 break;
1207 case MVT::i16:
1208 Opc = A64 ? WebAssembly::LOAD16_U_I32_A64 : WebAssembly::LOAD16_U_I32_A32;
1209 RC = &WebAssembly::I32RegClass;
1210 break;
1211 case MVT::i32:
1212 Opc = A64 ? WebAssembly::LOAD_I32_A64 : WebAssembly::LOAD_I32_A32;
1213 RC = &WebAssembly::I32RegClass;
1214 break;
1215 case MVT::i64:
1216 Opc = A64 ? WebAssembly::LOAD_I64_A64 : WebAssembly::LOAD_I64_A32;
1217 RC = &WebAssembly::I64RegClass;
1218 break;
1219 case MVT::f32:
1220 Opc = A64 ? WebAssembly::LOAD_F32_A64 : WebAssembly::LOAD_F32_A32;
1221 RC = &WebAssembly::F32RegClass;
1222 break;
1223 case MVT::f64:
1224 Opc = A64 ? WebAssembly::LOAD_F64_A64 : WebAssembly::LOAD_F64_A32;
1225 RC = &WebAssembly::F64RegClass;
1226 break;
1227 default:
1228 return false;
1229 }
1230
1231 materializeLoadStoreOperands(Addr);
1232
1233 Register ResultReg = createResultReg(RC);
1234 auto MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc),
1235 ResultReg);
1236
1237 addLoadStoreOperands(Addr, MIB, createMachineMemOperandFor(Load));
1238
1239 updateValueMap(Load, ResultReg);
1240 return true;
1241}
1242
1243bool WebAssemblyFastISel::selectStore(const Instruction *I) {
1244 const auto *Store = cast<StoreInst>(I);
1245 if (Store->isAtomic())
1246 return false;
1247 if (!WebAssembly::isDefaultAddressSpace(Store->getPointerAddressSpace()))
1248 return false;
1249 if (!Subtarget->hasSIMD128() &&
1250 Store->getValueOperand()->getType()->isVectorTy())
1251 return false;
1252
1253 Address Addr;
1254 if (!computeAddress(Store->getPointerOperand(), Addr))
1255 return false;
1256
1257 unsigned Opc;
1258 bool VTIsi1 = false;
1259 bool A64 = Subtarget->hasAddr64();
1260 switch (getSimpleType(Store->getValueOperand()->getType())) {
1261 case MVT::i1:
1262 VTIsi1 = true;
1263 [[fallthrough]];
1264 case MVT::i8:
1265 Opc = A64 ? WebAssembly::STORE8_I32_A64 : WebAssembly::STORE8_I32_A32;
1266 break;
1267 case MVT::i16:
1268 Opc = A64 ? WebAssembly::STORE16_I32_A64 : WebAssembly::STORE16_I32_A32;
1269 break;
1270 case MVT::i32:
1271 Opc = A64 ? WebAssembly::STORE_I32_A64 : WebAssembly::STORE_I32_A32;
1272 break;
1273 case MVT::i64:
1274 Opc = A64 ? WebAssembly::STORE_I64_A64 : WebAssembly::STORE_I64_A32;
1275 break;
1276 case MVT::f32:
1277 Opc = A64 ? WebAssembly::STORE_F32_A64 : WebAssembly::STORE_F32_A32;
1278 break;
1279 case MVT::f64:
1280 Opc = A64 ? WebAssembly::STORE_F64_A64 : WebAssembly::STORE_F64_A32;
1281 break;
1282 default:
1283 return false;
1284 }
1285
1286 materializeLoadStoreOperands(Addr);
1287
1288 Register ValueReg = getRegForValue(Store->getValueOperand());
1289 if (ValueReg == 0)
1290 return false;
1291 if (VTIsi1)
1292 ValueReg = maskI1Value(ValueReg, Store->getValueOperand());
1293
1294 auto MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc));
1295
1296 addLoadStoreOperands(Addr, MIB, createMachineMemOperandFor(Store));
1297
1298 MIB.addReg(ValueReg);
1299 return true;
1300}
1301
1302bool WebAssemblyFastISel::selectBr(const Instruction *I) {
1303 const auto *Br = cast<BranchInst>(I);
1304 if (Br->isUnconditional()) {
1305 MachineBasicBlock *MSucc = FuncInfo.MBBMap[Br->getSuccessor(0)];
1306 fastEmitBranch(MSucc, Br->getDebugLoc());
1307 return true;
1308 }
1309
1310 MachineBasicBlock *TBB = FuncInfo.MBBMap[Br->getSuccessor(0)];
1311 MachineBasicBlock *FBB = FuncInfo.MBBMap[Br->getSuccessor(1)];
1312
1313 bool Not;
1314 unsigned CondReg = getRegForI1Value(Br->getCondition(), Br->getParent(), Not);
1315 if (CondReg == 0)
1316 return false;
1317
1318 unsigned Opc = WebAssembly::BR_IF;
1319 if (Not)
1320 Opc = WebAssembly::BR_UNLESS;
1321
1322 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc))
1323 .addMBB(TBB)
1324 .addReg(CondReg);
1325
1326 finishCondBranch(Br->getParent(), TBB, FBB);
1327 return true;
1328}
1329
1330bool WebAssemblyFastISel::selectRet(const Instruction *I) {
1331 if (!FuncInfo.CanLowerReturn)
1332 return false;
1333
1334 const auto *Ret = cast<ReturnInst>(I);
1335
1336 if (Ret->getNumOperands() == 0) {
1337 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
1338 TII.get(WebAssembly::RETURN));
1339 return true;
1340 }
1341
1342 // TODO: support multiple return in FastISel
1343 if (Ret->getNumOperands() > 1)
1344 return false;
1345
1346 Value *RV = Ret->getOperand(0);
1347 if (!Subtarget->hasSIMD128() && RV->getType()->isVectorTy())
1348 return false;
1349
1350 switch (getSimpleType(RV->getType())) {
1351 case MVT::i1:
1352 case MVT::i8:
1353 case MVT::i16:
1354 case MVT::i32:
1355 case MVT::i64:
1356 case MVT::f32:
1357 case MVT::f64:
1358 case MVT::v16i8:
1359 case MVT::v8i16:
1360 case MVT::v4i32:
1361 case MVT::v2i64:
1362 case MVT::v4f32:
1363 case MVT::v2f64:
1364 case MVT::funcref:
1365 case MVT::externref:
1366 break;
1367 default:
1368 return false;
1369 }
1370
1371 unsigned Reg;
1372 if (FuncInfo.Fn->getAttributes().hasRetAttr(Attribute::SExt))
1373 Reg = getRegForSignedValue(RV);
1374 else if (FuncInfo.Fn->getAttributes().hasRetAttr(Attribute::ZExt))
1375 Reg = getRegForUnsignedValue(RV);
1376 else
1377 Reg = getRegForValue(RV);
1378
1379 if (Reg == 0)
1380 return false;
1381
1382 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
1383 TII.get(WebAssembly::RETURN))
1384 .addReg(Reg);
1385 return true;
1386}
1387
1388bool WebAssemblyFastISel::selectUnreachable(const Instruction *I) {
1389 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
1390 TII.get(WebAssembly::UNREACHABLE));
1391 return true;
1392}
1393
1394bool WebAssemblyFastISel::fastSelectInstruction(const Instruction *I) {
1395 switch (I->getOpcode()) {
1396 case Instruction::Call:
1397 if (selectCall(I))
1398 return true;
1399 break;
1400 case Instruction::Select:
1401 return selectSelect(I);
1402 case Instruction::Trunc:
1403 return selectTrunc(I);
1404 case Instruction::ZExt:
1405 return selectZExt(I);
1406 case Instruction::SExt:
1407 return selectSExt(I);
1408 case Instruction::ICmp:
1409 return selectICmp(I);
1410 case Instruction::FCmp:
1411 return selectFCmp(I);
1412 case Instruction::BitCast:
1413 return selectBitCast(I);
1414 case Instruction::Load:
1415 return selectLoad(I);
1416 case Instruction::Store:
1417 return selectStore(I);
1418 case Instruction::Br:
1419 return selectBr(I);
1420 case Instruction::Ret:
1421 return selectRet(I);
1422 case Instruction::Unreachable:
1423 return selectUnreachable(I);
1424 default:
1425 break;
1426 }
1427
1428 // Fall back to target-independent instruction selection.
1429 return selectOperator(I, I->getOpcode());
1430}
1431
1433 const TargetLibraryInfo *LibInfo) {
1434 return new WebAssemblyFastISel(FuncInfo, LibInfo);
1435}
unsigned const MachineRegisterInfo * MRI
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
amdgpu Simplify well known AMD library false FunctionCallee Value * Arg
amdgpu AMDGPU Register Bank Select
BlockVerifier::State From
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
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
typename CallsiteContextGraph< DerivedCCG, FuncTy, CallTy >::FuncInfo FuncInfo
static unsigned getReg(const MCDisassembler *D, unsigned RC, unsigned RegNo)
LLVMContext & Context
const SmallVectorImpl< MachineOperand > MachineBasicBlock * TBB
@ SI
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 declares the WebAssembly-specific subclass of TargetMachine.
This file contains the declaration of the WebAssembly-specific type parsing utility functions.
This file contains the declaration of the WebAssembly-specific utility functions.
This file contains the entry points for global functions defined in the LLVM WebAssembly back-end.
Value * RHS
Value * LHS
an instruction to allocate memory on the stack
Definition: Instructions.h:58
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:56
This is the shared class of boolean and integer constants.
Definition: Constants.h:78
This is an important base class in LLVM.
Definition: Constant.h:41
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:469
virtual bool fastLowerArguments()
This method is called by target-independent code to do target- specific argument lowering.
Definition: FastISel.cpp:1845
bool selectCall(const User *I)
Definition: FastISel.cpp:1149
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:1429
virtual unsigned fastMaterializeAlloca(const AllocaInst *C)
Emit an alloca address in a register using target-specific logic.
Definition: FastISel.h:472
FunctionLoweringInfo - This contains information that is global to a function that is used when lower...
This is an important class for using LLVM in a threaded context.
Definition: LLVMContext.h:67
void setNoStrip() const
Definition: MCSymbolWasm.h:65
Machine Value Type.
SimpleValueType SimpleTy
@ INVALID_SIMPLE_VALUE_TYPE
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:1200
Used to lazily calculate structure layout information for a target machine, based on the DataLayout s...
Definition: DataLayout.h:623
TypeSize getElementOffset(unsigned Idx) const
Definition: DataLayout.h:652
Class to represent struct types.
Definition: DerivedTypes.h:213
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:265
bool isArrayTy() const
True if this is an instance of ArrayType.
Definition: Type.h:253
bool isStructTy() const
True if this is an instance of StructType.
Definition: Type.h:250
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.
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.
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:34
bool isSimple() const
Test if the given EVT is simple (as opposed to being extended).
Definition: ValueTypes.h:129
MVT getSimpleVT() const
Return the SimpleValueType held in the specified simple EVT.
Definition: ValueTypes.h:299