LLVM 19.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
20#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.
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 // 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 if (From == To)
563 return VReg;
564 return zeroExtend(VReg, V, From, To);
565}
566
567unsigned WebAssemblyFastISel::getRegForSignedValue(const Value *V) {
568 MVT::SimpleValueType From = getSimpleType(V->getType());
569 MVT::SimpleValueType To = getLegalType(From);
570 Register VReg = getRegForValue(V);
571 if (VReg == 0)
572 return 0;
573 if (From == To)
574 return VReg;
575 return signExtend(VReg, V, From, To);
576}
577
578unsigned WebAssemblyFastISel::getRegForPromotedValue(const Value *V,
579 bool IsSigned) {
580 return IsSigned ? getRegForSignedValue(V) : getRegForUnsignedValue(V);
581}
582
583unsigned WebAssemblyFastISel::notValue(unsigned Reg) {
584 assert(MRI.getRegClass(Reg) == &WebAssembly::I32RegClass);
585
586 Register NotReg = createResultReg(&WebAssembly::I32RegClass);
587 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
588 TII.get(WebAssembly::EQZ_I32), NotReg)
589 .addReg(Reg);
590 return NotReg;
591}
592
593unsigned WebAssemblyFastISel::copyValue(unsigned Reg) {
594 Register ResultReg = createResultReg(MRI.getRegClass(Reg));
595 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(WebAssembly::COPY),
596 ResultReg)
597 .addReg(Reg);
598 return ResultReg;
599}
600
601unsigned WebAssemblyFastISel::fastMaterializeAlloca(const AllocaInst *AI) {
603 FuncInfo.StaticAllocaMap.find(AI);
604
605 if (SI != FuncInfo.StaticAllocaMap.end()) {
606 Register ResultReg =
607 createResultReg(Subtarget->hasAddr64() ? &WebAssembly::I64RegClass
608 : &WebAssembly::I32RegClass);
609 unsigned Opc =
610 Subtarget->hasAddr64() ? WebAssembly::COPY_I64 : WebAssembly::COPY_I32;
611 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc), ResultReg)
612 .addFrameIndex(SI->second);
613 return ResultReg;
614 }
615
616 return 0;
617}
618
619unsigned WebAssemblyFastISel::fastMaterializeConstant(const Constant *C) {
620 if (const GlobalValue *GV = dyn_cast<GlobalValue>(C)) {
621 if (TLI.isPositionIndependent())
622 return 0;
623 if (GV->isThreadLocal())
624 return 0;
625 Register ResultReg =
626 createResultReg(Subtarget->hasAddr64() ? &WebAssembly::I64RegClass
627 : &WebAssembly::I32RegClass);
628 unsigned Opc = Subtarget->hasAddr64() ? WebAssembly::CONST_I64
629 : WebAssembly::CONST_I32;
630 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc), ResultReg)
631 .addGlobalAddress(GV);
632 return ResultReg;
633 }
634
635 // Let target-independent code handle it.
636 return 0;
637}
638
639bool WebAssemblyFastISel::fastLowerArguments() {
640 if (!FuncInfo.CanLowerReturn)
641 return false;
642
643 const Function *F = FuncInfo.Fn;
644 if (F->isVarArg())
645 return false;
646
647 if (FuncInfo.Fn->getCallingConv() == CallingConv::Swift)
648 return false;
649
650 unsigned I = 0;
651 for (auto const &Arg : F->args()) {
652 const AttributeList &Attrs = F->getAttributes();
653 if (Attrs.hasParamAttr(I, Attribute::ByVal) ||
654 Attrs.hasParamAttr(I, Attribute::SwiftSelf) ||
655 Attrs.hasParamAttr(I, Attribute::SwiftError) ||
656 Attrs.hasParamAttr(I, Attribute::InAlloca) ||
657 Attrs.hasParamAttr(I, Attribute::Nest))
658 return false;
659
660 Type *ArgTy = Arg.getType();
661 if (ArgTy->isStructTy() || ArgTy->isArrayTy())
662 return false;
663 if (!Subtarget->hasSIMD128() && ArgTy->isVectorTy())
664 return false;
665
666 unsigned Opc;
667 const TargetRegisterClass *RC;
668 switch (getSimpleType(ArgTy)) {
669 case MVT::i1:
670 case MVT::i8:
671 case MVT::i16:
672 case MVT::i32:
673 Opc = WebAssembly::ARGUMENT_i32;
674 RC = &WebAssembly::I32RegClass;
675 break;
676 case MVT::i64:
677 Opc = WebAssembly::ARGUMENT_i64;
678 RC = &WebAssembly::I64RegClass;
679 break;
680 case MVT::f32:
681 Opc = WebAssembly::ARGUMENT_f32;
682 RC = &WebAssembly::F32RegClass;
683 break;
684 case MVT::f64:
685 Opc = WebAssembly::ARGUMENT_f64;
686 RC = &WebAssembly::F64RegClass;
687 break;
688 case MVT::v16i8:
689 Opc = WebAssembly::ARGUMENT_v16i8;
690 RC = &WebAssembly::V128RegClass;
691 break;
692 case MVT::v8i16:
693 Opc = WebAssembly::ARGUMENT_v8i16;
694 RC = &WebAssembly::V128RegClass;
695 break;
696 case MVT::v4i32:
697 Opc = WebAssembly::ARGUMENT_v4i32;
698 RC = &WebAssembly::V128RegClass;
699 break;
700 case MVT::v2i64:
701 Opc = WebAssembly::ARGUMENT_v2i64;
702 RC = &WebAssembly::V128RegClass;
703 break;
704 case MVT::v4f32:
705 Opc = WebAssembly::ARGUMENT_v4f32;
706 RC = &WebAssembly::V128RegClass;
707 break;
708 case MVT::v2f64:
709 Opc = WebAssembly::ARGUMENT_v2f64;
710 RC = &WebAssembly::V128RegClass;
711 break;
712 case MVT::funcref:
713 Opc = WebAssembly::ARGUMENT_funcref;
714 RC = &WebAssembly::FUNCREFRegClass;
715 break;
716 case MVT::externref:
717 Opc = WebAssembly::ARGUMENT_externref;
718 RC = &WebAssembly::EXTERNREFRegClass;
719 break;
720 default:
721 return false;
722 }
723 Register ResultReg = createResultReg(RC);
724 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc), ResultReg)
725 .addImm(I);
726 updateValueMap(&Arg, ResultReg);
727
728 ++I;
729 }
730
731 MRI.addLiveIn(WebAssembly::ARGUMENTS);
732
733 auto *MFI = MF->getInfo<WebAssemblyFunctionInfo>();
734 for (auto const &Arg : F->args()) {
735 MVT::SimpleValueType ArgTy = getLegalType(getSimpleType(Arg.getType()));
736 if (ArgTy == MVT::INVALID_SIMPLE_VALUE_TYPE) {
737 MFI->clearParamsAndResults();
738 return false;
739 }
740 MFI->addParam(ArgTy);
741 }
742
743 if (!F->getReturnType()->isVoidTy()) {
745 getLegalType(getSimpleType(F->getReturnType()));
747 MFI->clearParamsAndResults();
748 return false;
749 }
750 MFI->addResult(RetTy);
751 }
752
753 return true;
754}
755
756bool WebAssemblyFastISel::selectCall(const Instruction *I) {
757 const auto *Call = cast<CallInst>(I);
758
759 // TODO: Support tail calls in FastISel
760 if (Call->isMustTailCall() || Call->isInlineAsm() ||
761 Call->getFunctionType()->isVarArg())
762 return false;
763
764 Function *Func = Call->getCalledFunction();
765 if (Func && Func->isIntrinsic())
766 return false;
767
768 if (Call->getCallingConv() == CallingConv::Swift)
769 return false;
770
771 bool IsDirect = Func != nullptr;
772 if (!IsDirect && isa<ConstantExpr>(Call->getCalledOperand()))
773 return false;
774
775 FunctionType *FuncTy = Call->getFunctionType();
776 unsigned Opc = IsDirect ? WebAssembly::CALL : WebAssembly::CALL_INDIRECT;
777 bool IsVoid = FuncTy->getReturnType()->isVoidTy();
778 unsigned ResultReg;
779 if (!IsVoid) {
780 if (!Subtarget->hasSIMD128() && Call->getType()->isVectorTy())
781 return false;
782
783 MVT::SimpleValueType RetTy = getSimpleType(Call->getType());
784 switch (RetTy) {
785 case MVT::i1:
786 case MVT::i8:
787 case MVT::i16:
788 case MVT::i32:
789 ResultReg = createResultReg(&WebAssembly::I32RegClass);
790 break;
791 case MVT::i64:
792 ResultReg = createResultReg(&WebAssembly::I64RegClass);
793 break;
794 case MVT::f32:
795 ResultReg = createResultReg(&WebAssembly::F32RegClass);
796 break;
797 case MVT::f64:
798 ResultReg = createResultReg(&WebAssembly::F64RegClass);
799 break;
800 case MVT::v16i8:
801 ResultReg = createResultReg(&WebAssembly::V128RegClass);
802 break;
803 case MVT::v8i16:
804 ResultReg = createResultReg(&WebAssembly::V128RegClass);
805 break;
806 case MVT::v4i32:
807 ResultReg = createResultReg(&WebAssembly::V128RegClass);
808 break;
809 case MVT::v2i64:
810 ResultReg = createResultReg(&WebAssembly::V128RegClass);
811 break;
812 case MVT::v4f32:
813 ResultReg = createResultReg(&WebAssembly::V128RegClass);
814 break;
815 case MVT::v2f64:
816 ResultReg = createResultReg(&WebAssembly::V128RegClass);
817 break;
818 case MVT::funcref:
819 ResultReg = createResultReg(&WebAssembly::FUNCREFRegClass);
820 break;
821 case MVT::externref:
822 ResultReg = createResultReg(&WebAssembly::EXTERNREFRegClass);
823 break;
824 default:
825 return false;
826 }
827 }
828
830 for (unsigned I = 0, E = Call->arg_size(); I < E; ++I) {
831 Value *V = Call->getArgOperand(I);
832 MVT::SimpleValueType ArgTy = getSimpleType(V->getType());
834 return false;
835
836 const AttributeList &Attrs = Call->getAttributes();
837 if (Attrs.hasParamAttr(I, Attribute::ByVal) ||
838 Attrs.hasParamAttr(I, Attribute::SwiftSelf) ||
839 Attrs.hasParamAttr(I, Attribute::SwiftError) ||
840 Attrs.hasParamAttr(I, Attribute::InAlloca) ||
841 Attrs.hasParamAttr(I, Attribute::Nest))
842 return false;
843
844 unsigned Reg;
845
846 if (Call->paramHasAttr(I, Attribute::SExt))
847 Reg = getRegForSignedValue(V);
848 else if (Call->paramHasAttr(I, Attribute::ZExt))
849 Reg = getRegForUnsignedValue(V);
850 else
851 Reg = getRegForValue(V);
852
853 if (Reg == 0)
854 return false;
855
856 Args.push_back(Reg);
857 }
858
859 unsigned CalleeReg = 0;
860 if (!IsDirect) {
861 CalleeReg = getRegForValue(Call->getCalledOperand());
862 if (!CalleeReg)
863 return false;
864 }
865
866 auto MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc));
867
868 if (!IsVoid)
869 MIB.addReg(ResultReg, RegState::Define);
870
871 if (IsDirect) {
872 MIB.addGlobalAddress(Func);
873 } else {
874 // Placeholder for the type index.
875 MIB.addImm(0);
876 // The table into which this call_indirect indexes.
878 MF->getMMI().getContext(), Subtarget);
879 if (Subtarget->hasReferenceTypes()) {
880 MIB.addSym(Table);
881 } else {
882 // Otherwise for the MVP there is at most one table whose number is 0, but
883 // we can't write a table symbol or issue relocations. Instead we just
884 // ensure the table is live.
885 Table->setNoStrip();
886 MIB.addImm(0);
887 }
888 // See if we must truncate the function pointer.
889 // CALL_INDIRECT takes an i32, but in wasm64 we represent function pointers
890 // as 64-bit for uniformity with other pointer types.
891 // See also: WebAssemblyISelLowering.cpp: LowerCallResults
892 if (Subtarget->hasAddr64()) {
893 auto Wrap = BuildMI(*FuncInfo.MBB, std::prev(FuncInfo.InsertPt), MIMD,
894 TII.get(WebAssembly::I32_WRAP_I64));
895 Register Reg32 = createResultReg(&WebAssembly::I32RegClass);
896 Wrap.addReg(Reg32, RegState::Define);
897 Wrap.addReg(CalleeReg);
898 CalleeReg = Reg32;
899 }
900 }
901
902 for (unsigned ArgReg : Args)
903 MIB.addReg(ArgReg);
904
905 if (!IsDirect)
906 MIB.addReg(CalleeReg);
907
908 if (!IsVoid)
909 updateValueMap(Call, ResultReg);
910 return true;
911}
912
913bool WebAssemblyFastISel::selectSelect(const Instruction *I) {
914 const auto *Select = cast<SelectInst>(I);
915
916 bool Not;
917 unsigned CondReg =
918 getRegForI1Value(Select->getCondition(), I->getParent(), Not);
919 if (CondReg == 0)
920 return false;
921
922 Register TrueReg = getRegForValue(Select->getTrueValue());
923 if (TrueReg == 0)
924 return false;
925
926 Register FalseReg = getRegForValue(Select->getFalseValue());
927 if (FalseReg == 0)
928 return false;
929
930 if (Not)
931 std::swap(TrueReg, FalseReg);
932
933 unsigned Opc;
934 const TargetRegisterClass *RC;
935 switch (getSimpleType(Select->getType())) {
936 case MVT::i1:
937 case MVT::i8:
938 case MVT::i16:
939 case MVT::i32:
940 Opc = WebAssembly::SELECT_I32;
941 RC = &WebAssembly::I32RegClass;
942 break;
943 case MVT::i64:
944 Opc = WebAssembly::SELECT_I64;
945 RC = &WebAssembly::I64RegClass;
946 break;
947 case MVT::f32:
948 Opc = WebAssembly::SELECT_F32;
949 RC = &WebAssembly::F32RegClass;
950 break;
951 case MVT::f64:
952 Opc = WebAssembly::SELECT_F64;
953 RC = &WebAssembly::F64RegClass;
954 break;
955 case MVT::funcref:
956 Opc = WebAssembly::SELECT_FUNCREF;
957 RC = &WebAssembly::FUNCREFRegClass;
958 break;
959 case MVT::externref:
960 Opc = WebAssembly::SELECT_EXTERNREF;
961 RC = &WebAssembly::EXTERNREFRegClass;
962 break;
963 default:
964 return false;
965 }
966
967 Register ResultReg = createResultReg(RC);
968 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc), ResultReg)
969 .addReg(TrueReg)
970 .addReg(FalseReg)
971 .addReg(CondReg);
972
973 updateValueMap(Select, ResultReg);
974 return true;
975}
976
977bool WebAssemblyFastISel::selectTrunc(const Instruction *I) {
978 const auto *Trunc = cast<TruncInst>(I);
979
980 Register Reg = getRegForValue(Trunc->getOperand(0));
981 if (Reg == 0)
982 return false;
983
984 if (Trunc->getOperand(0)->getType()->isIntegerTy(64)) {
985 Register Result = createResultReg(&WebAssembly::I32RegClass);
986 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
987 TII.get(WebAssembly::I32_WRAP_I64), Result)
988 .addReg(Reg);
989 Reg = Result;
990 }
991
992 updateValueMap(Trunc, Reg);
993 return true;
994}
995
996bool WebAssemblyFastISel::selectZExt(const Instruction *I) {
997 const auto *ZExt = cast<ZExtInst>(I);
998
999 const Value *Op = ZExt->getOperand(0);
1000 MVT::SimpleValueType From = getSimpleType(Op->getType());
1001 MVT::SimpleValueType To = getLegalType(getSimpleType(ZExt->getType()));
1002 Register In = getRegForValue(Op);
1003 if (In == 0)
1004 return false;
1005 unsigned Reg = zeroExtend(In, Op, From, To);
1006 if (Reg == 0)
1007 return false;
1008
1009 updateValueMap(ZExt, Reg);
1010 return true;
1011}
1012
1013bool WebAssemblyFastISel::selectSExt(const Instruction *I) {
1014 const auto *SExt = cast<SExtInst>(I);
1015
1016 const Value *Op = SExt->getOperand(0);
1017 MVT::SimpleValueType From = getSimpleType(Op->getType());
1018 MVT::SimpleValueType To = getLegalType(getSimpleType(SExt->getType()));
1019 Register In = getRegForValue(Op);
1020 if (In == 0)
1021 return false;
1022 unsigned Reg = signExtend(In, Op, From, To);
1023 if (Reg == 0)
1024 return false;
1025
1026 updateValueMap(SExt, Reg);
1027 return true;
1028}
1029
1030bool WebAssemblyFastISel::selectICmp(const Instruction *I) {
1031 const auto *ICmp = cast<ICmpInst>(I);
1032
1033 bool I32 = getSimpleType(ICmp->getOperand(0)->getType()) != MVT::i64;
1034 unsigned Opc;
1035 bool IsSigned = false;
1036 switch (ICmp->getPredicate()) {
1037 case ICmpInst::ICMP_EQ:
1038 Opc = I32 ? WebAssembly::EQ_I32 : WebAssembly::EQ_I64;
1039 break;
1040 case ICmpInst::ICMP_NE:
1041 Opc = I32 ? WebAssembly::NE_I32 : WebAssembly::NE_I64;
1042 break;
1043 case ICmpInst::ICMP_UGT:
1044 Opc = I32 ? WebAssembly::GT_U_I32 : WebAssembly::GT_U_I64;
1045 break;
1046 case ICmpInst::ICMP_UGE:
1047 Opc = I32 ? WebAssembly::GE_U_I32 : WebAssembly::GE_U_I64;
1048 break;
1049 case ICmpInst::ICMP_ULT:
1050 Opc = I32 ? WebAssembly::LT_U_I32 : WebAssembly::LT_U_I64;
1051 break;
1052 case ICmpInst::ICMP_ULE:
1053 Opc = I32 ? WebAssembly::LE_U_I32 : WebAssembly::LE_U_I64;
1054 break;
1055 case ICmpInst::ICMP_SGT:
1056 Opc = I32 ? WebAssembly::GT_S_I32 : WebAssembly::GT_S_I64;
1057 IsSigned = true;
1058 break;
1059 case ICmpInst::ICMP_SGE:
1060 Opc = I32 ? WebAssembly::GE_S_I32 : WebAssembly::GE_S_I64;
1061 IsSigned = true;
1062 break;
1063 case ICmpInst::ICMP_SLT:
1064 Opc = I32 ? WebAssembly::LT_S_I32 : WebAssembly::LT_S_I64;
1065 IsSigned = true;
1066 break;
1067 case ICmpInst::ICMP_SLE:
1068 Opc = I32 ? WebAssembly::LE_S_I32 : WebAssembly::LE_S_I64;
1069 IsSigned = true;
1070 break;
1071 default:
1072 return false;
1073 }
1074
1075 unsigned LHS = getRegForPromotedValue(ICmp->getOperand(0), IsSigned);
1076 if (LHS == 0)
1077 return false;
1078
1079 unsigned RHS = getRegForPromotedValue(ICmp->getOperand(1), IsSigned);
1080 if (RHS == 0)
1081 return false;
1082
1083 Register ResultReg = createResultReg(&WebAssembly::I32RegClass);
1084 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc), ResultReg)
1085 .addReg(LHS)
1086 .addReg(RHS);
1087 updateValueMap(ICmp, ResultReg);
1088 return true;
1089}
1090
1091bool WebAssemblyFastISel::selectFCmp(const Instruction *I) {
1092 const auto *FCmp = cast<FCmpInst>(I);
1093
1094 Register LHS = getRegForValue(FCmp->getOperand(0));
1095 if (LHS == 0)
1096 return false;
1097
1098 Register RHS = getRegForValue(FCmp->getOperand(1));
1099 if (RHS == 0)
1100 return false;
1101
1102 bool F32 = getSimpleType(FCmp->getOperand(0)->getType()) != MVT::f64;
1103 unsigned Opc;
1104 bool Not = false;
1105 switch (FCmp->getPredicate()) {
1106 case FCmpInst::FCMP_OEQ:
1107 Opc = F32 ? WebAssembly::EQ_F32 : WebAssembly::EQ_F64;
1108 break;
1109 case FCmpInst::FCMP_UNE:
1110 Opc = F32 ? WebAssembly::NE_F32 : WebAssembly::NE_F64;
1111 break;
1112 case FCmpInst::FCMP_OGT:
1113 Opc = F32 ? WebAssembly::GT_F32 : WebAssembly::GT_F64;
1114 break;
1115 case FCmpInst::FCMP_OGE:
1116 Opc = F32 ? WebAssembly::GE_F32 : WebAssembly::GE_F64;
1117 break;
1118 case FCmpInst::FCMP_OLT:
1119 Opc = F32 ? WebAssembly::LT_F32 : WebAssembly::LT_F64;
1120 break;
1121 case FCmpInst::FCMP_OLE:
1122 Opc = F32 ? WebAssembly::LE_F32 : WebAssembly::LE_F64;
1123 break;
1124 case FCmpInst::FCMP_UGT:
1125 Opc = F32 ? WebAssembly::LE_F32 : WebAssembly::LE_F64;
1126 Not = true;
1127 break;
1128 case FCmpInst::FCMP_UGE:
1129 Opc = F32 ? WebAssembly::LT_F32 : WebAssembly::LT_F64;
1130 Not = true;
1131 break;
1132 case FCmpInst::FCMP_ULT:
1133 Opc = F32 ? WebAssembly::GE_F32 : WebAssembly::GE_F64;
1134 Not = true;
1135 break;
1136 case FCmpInst::FCMP_ULE:
1137 Opc = F32 ? WebAssembly::GT_F32 : WebAssembly::GT_F64;
1138 Not = true;
1139 break;
1140 default:
1141 return false;
1142 }
1143
1144 Register ResultReg = createResultReg(&WebAssembly::I32RegClass);
1145 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc), ResultReg)
1146 .addReg(LHS)
1147 .addReg(RHS);
1148
1149 if (Not)
1150 ResultReg = notValue(ResultReg);
1151
1152 updateValueMap(FCmp, ResultReg);
1153 return true;
1154}
1155
1156bool WebAssemblyFastISel::selectBitCast(const Instruction *I) {
1157 // Target-independent code can handle this, except it doesn't set the dead
1158 // flag on the ARGUMENTS clobber, so we have to do that manually in order
1159 // to satisfy code that expects this of isBitcast() instructions.
1160 EVT VT = TLI.getValueType(DL, I->getOperand(0)->getType());
1161 EVT RetVT = TLI.getValueType(DL, I->getType());
1162 if (!VT.isSimple() || !RetVT.isSimple())
1163 return false;
1164
1165 Register In = getRegForValue(I->getOperand(0));
1166 if (In == 0)
1167 return false;
1168
1169 if (VT == RetVT) {
1170 // No-op bitcast.
1171 updateValueMap(I, In);
1172 return true;
1173 }
1174
1175 Register Reg = fastEmit_ISD_BITCAST_r(VT.getSimpleVT(), RetVT.getSimpleVT(),
1176 In);
1177 if (!Reg)
1178 return false;
1179 MachineBasicBlock::iterator Iter = FuncInfo.InsertPt;
1180 --Iter;
1181 assert(Iter->isBitcast());
1182 Iter->setPhysRegsDeadExcept(ArrayRef<Register>(), TRI);
1183 updateValueMap(I, Reg);
1184 return true;
1185}
1186
1187bool WebAssemblyFastISel::selectLoad(const Instruction *I) {
1188 const auto *Load = cast<LoadInst>(I);
1189 if (Load->isAtomic())
1190 return false;
1191 if (!WebAssembly::isDefaultAddressSpace(Load->getPointerAddressSpace()))
1192 return false;
1193 if (!Subtarget->hasSIMD128() && Load->getType()->isVectorTy())
1194 return false;
1195
1196 Address Addr;
1197 if (!computeAddress(Load->getPointerOperand(), Addr))
1198 return false;
1199
1200 // TODO: Fold a following sign-/zero-extend into the load instruction.
1201
1202 unsigned Opc;
1203 const TargetRegisterClass *RC;
1204 bool A64 = Subtarget->hasAddr64();
1205 switch (getSimpleType(Load->getType())) {
1206 case MVT::i1:
1207 case MVT::i8:
1208 Opc = A64 ? WebAssembly::LOAD8_U_I32_A64 : WebAssembly::LOAD8_U_I32_A32;
1209 RC = &WebAssembly::I32RegClass;
1210 break;
1211 case MVT::i16:
1212 Opc = A64 ? WebAssembly::LOAD16_U_I32_A64 : WebAssembly::LOAD16_U_I32_A32;
1213 RC = &WebAssembly::I32RegClass;
1214 break;
1215 case MVT::i32:
1216 Opc = A64 ? WebAssembly::LOAD_I32_A64 : WebAssembly::LOAD_I32_A32;
1217 RC = &WebAssembly::I32RegClass;
1218 break;
1219 case MVT::i64:
1220 Opc = A64 ? WebAssembly::LOAD_I64_A64 : WebAssembly::LOAD_I64_A32;
1221 RC = &WebAssembly::I64RegClass;
1222 break;
1223 case MVT::f32:
1224 Opc = A64 ? WebAssembly::LOAD_F32_A64 : WebAssembly::LOAD_F32_A32;
1225 RC = &WebAssembly::F32RegClass;
1226 break;
1227 case MVT::f64:
1228 Opc = A64 ? WebAssembly::LOAD_F64_A64 : WebAssembly::LOAD_F64_A32;
1229 RC = &WebAssembly::F64RegClass;
1230 break;
1231 default:
1232 return false;
1233 }
1234
1235 materializeLoadStoreOperands(Addr);
1236
1237 Register ResultReg = createResultReg(RC);
1238 auto MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc),
1239 ResultReg);
1240
1241 addLoadStoreOperands(Addr, MIB, createMachineMemOperandFor(Load));
1242
1243 updateValueMap(Load, ResultReg);
1244 return true;
1245}
1246
1247bool WebAssemblyFastISel::selectStore(const Instruction *I) {
1248 const auto *Store = cast<StoreInst>(I);
1249 if (Store->isAtomic())
1250 return false;
1251 if (!WebAssembly::isDefaultAddressSpace(Store->getPointerAddressSpace()))
1252 return false;
1253 if (!Subtarget->hasSIMD128() &&
1254 Store->getValueOperand()->getType()->isVectorTy())
1255 return false;
1256
1257 Address Addr;
1258 if (!computeAddress(Store->getPointerOperand(), Addr))
1259 return false;
1260
1261 unsigned Opc;
1262 bool VTIsi1 = false;
1263 bool A64 = Subtarget->hasAddr64();
1264 switch (getSimpleType(Store->getValueOperand()->getType())) {
1265 case MVT::i1:
1266 VTIsi1 = true;
1267 [[fallthrough]];
1268 case MVT::i8:
1269 Opc = A64 ? WebAssembly::STORE8_I32_A64 : WebAssembly::STORE8_I32_A32;
1270 break;
1271 case MVT::i16:
1272 Opc = A64 ? WebAssembly::STORE16_I32_A64 : WebAssembly::STORE16_I32_A32;
1273 break;
1274 case MVT::i32:
1275 Opc = A64 ? WebAssembly::STORE_I32_A64 : WebAssembly::STORE_I32_A32;
1276 break;
1277 case MVT::i64:
1278 Opc = A64 ? WebAssembly::STORE_I64_A64 : WebAssembly::STORE_I64_A32;
1279 break;
1280 case MVT::f32:
1281 Opc = A64 ? WebAssembly::STORE_F32_A64 : WebAssembly::STORE_F32_A32;
1282 break;
1283 case MVT::f64:
1284 Opc = A64 ? WebAssembly::STORE_F64_A64 : WebAssembly::STORE_F64_A32;
1285 break;
1286 default:
1287 return false;
1288 }
1289
1290 materializeLoadStoreOperands(Addr);
1291
1292 Register ValueReg = getRegForValue(Store->getValueOperand());
1293 if (ValueReg == 0)
1294 return false;
1295 if (VTIsi1)
1296 ValueReg = maskI1Value(ValueReg, Store->getValueOperand());
1297
1298 auto MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc));
1299
1300 addLoadStoreOperands(Addr, MIB, createMachineMemOperandFor(Store));
1301
1302 MIB.addReg(ValueReg);
1303 return true;
1304}
1305
1306bool WebAssemblyFastISel::selectBr(const Instruction *I) {
1307 const auto *Br = cast<BranchInst>(I);
1308 if (Br->isUnconditional()) {
1309 MachineBasicBlock *MSucc = FuncInfo.MBBMap[Br->getSuccessor(0)];
1310 fastEmitBranch(MSucc, Br->getDebugLoc());
1311 return true;
1312 }
1313
1314 MachineBasicBlock *TBB = FuncInfo.MBBMap[Br->getSuccessor(0)];
1315 MachineBasicBlock *FBB = FuncInfo.MBBMap[Br->getSuccessor(1)];
1316
1317 bool Not;
1318 unsigned CondReg = getRegForI1Value(Br->getCondition(), Br->getParent(), Not);
1319 if (CondReg == 0)
1320 return false;
1321
1322 unsigned Opc = WebAssembly::BR_IF;
1323 if (Not)
1324 Opc = WebAssembly::BR_UNLESS;
1325
1326 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc))
1327 .addMBB(TBB)
1328 .addReg(CondReg);
1329
1330 finishCondBranch(Br->getParent(), TBB, FBB);
1331 return true;
1332}
1333
1334bool WebAssemblyFastISel::selectRet(const Instruction *I) {
1335 if (!FuncInfo.CanLowerReturn)
1336 return false;
1337
1338 const auto *Ret = cast<ReturnInst>(I);
1339
1340 if (Ret->getNumOperands() == 0) {
1341 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
1342 TII.get(WebAssembly::RETURN));
1343 return true;
1344 }
1345
1346 // TODO: support multiple return in FastISel
1347 if (Ret->getNumOperands() > 1)
1348 return false;
1349
1350 Value *RV = Ret->getOperand(0);
1351 if (!Subtarget->hasSIMD128() && RV->getType()->isVectorTy())
1352 return false;
1353
1354 switch (getSimpleType(RV->getType())) {
1355 case MVT::i1:
1356 case MVT::i8:
1357 case MVT::i16:
1358 case MVT::i32:
1359 case MVT::i64:
1360 case MVT::f32:
1361 case MVT::f64:
1362 case MVT::v16i8:
1363 case MVT::v8i16:
1364 case MVT::v4i32:
1365 case MVT::v2i64:
1366 case MVT::v4f32:
1367 case MVT::v2f64:
1368 case MVT::funcref:
1369 case MVT::externref:
1370 break;
1371 default:
1372 return false;
1373 }
1374
1375 unsigned Reg;
1376 if (FuncInfo.Fn->getAttributes().hasRetAttr(Attribute::SExt))
1377 Reg = getRegForSignedValue(RV);
1378 else if (FuncInfo.Fn->getAttributes().hasRetAttr(Attribute::ZExt))
1379 Reg = getRegForUnsignedValue(RV);
1380 else
1381 Reg = getRegForValue(RV);
1382
1383 if (Reg == 0)
1384 return false;
1385
1386 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
1387 TII.get(WebAssembly::RETURN))
1388 .addReg(Reg);
1389 return true;
1390}
1391
1392bool WebAssemblyFastISel::selectUnreachable(const Instruction *I) {
1393 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
1394 TII.get(WebAssembly::UNREACHABLE));
1395 return true;
1396}
1397
1398bool WebAssemblyFastISel::fastSelectInstruction(const Instruction *I) {
1399 switch (I->getOpcode()) {
1400 case Instruction::Call:
1401 if (selectCall(I))
1402 return true;
1403 break;
1404 case Instruction::Select:
1405 return selectSelect(I);
1406 case Instruction::Trunc:
1407 return selectTrunc(I);
1408 case Instruction::ZExt:
1409 return selectZExt(I);
1410 case Instruction::SExt:
1411 return selectSExt(I);
1412 case Instruction::ICmp:
1413 return selectICmp(I);
1414 case Instruction::FCmp:
1415 return selectFCmp(I);
1416 case Instruction::BitCast:
1417 return selectBitCast(I);
1418 case Instruction::Load:
1419 return selectLoad(I);
1420 case Instruction::Store:
1421 return selectStore(I);
1422 case Instruction::Br:
1423 return selectBr(I);
1424 case Instruction::Ret:
1425 return selectRet(I);
1426 case Instruction::Unreachable:
1427 return selectUnreachable(I);
1428 default:
1429 break;
1430 }
1431
1432 // Fall back to target-independent instruction selection.
1433 return selectOperator(I, I->getOpcode());
1434}
1435
1437 const TargetLibraryInfo *LibInfo) {
1438 return new WebAssemblyFastISel(FuncInfo, LibInfo);
1439}
unsigned const MachineRegisterInfo * MRI
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
amdgpu AMDGPU Register Bank Select
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)
LLVMContext & Context
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 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:59
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:60
This is the shared class of boolean and integer constants.
Definition: Constants.h:80
This is an important base class in LLVM.
Definition: Constant.h:41
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:1935
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:1519
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:350
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 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:1209
Used to lazily calculate structure layout information for a target machine, based on the DataLayout s...
Definition: DataLayout.h:622
TypeSize getElementOffset(unsigned Idx) const
Definition: DataLayout.h:651
Class to represent struct types.
Definition: DerivedTypes.h:216
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:252
bool isStructTy() const
True if this is an instance of StructType.
Definition: Type.h:249
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.
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:34
bool isSimple() const
Test if the given EVT is simple (as opposed to being extended).
Definition: ValueTypes.h:136
MVT getSimpleVT() const
Return the SimpleValueType held in the specified simple EVT.
Definition: ValueTypes.h:306