1 //===-- WebAssemblyFastISel.cpp - WebAssembly FastISel implementation -----===//
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
7 //===----------------------------------------------------------------------===//
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.
16 //===----------------------------------------------------------------------===//
18 #include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
19 #include "Utils/WebAssemblyTypeUtilities.h"
20 #include "WebAssembly.h"
21 #include "WebAssemblyMachineFunctionInfo.h"
22 #include "WebAssemblySubtarget.h"
23 #include "WebAssemblyTargetMachine.h"
24 #include "WebAssemblyUtilities.h"
25 #include "llvm/Analysis/BranchProbabilityInfo.h"
26 #include "llvm/CodeGen/FastISel.h"
27 #include "llvm/CodeGen/FunctionLoweringInfo.h"
28 #include "llvm/CodeGen/MachineConstantPool.h"
29 #include "llvm/CodeGen/MachineFrameInfo.h"
30 #include "llvm/CodeGen/MachineInstrBuilder.h"
31 #include "llvm/CodeGen/MachineModuleInfo.h"
32 #include "llvm/CodeGen/MachineRegisterInfo.h"
33 #include "llvm/IR/DataLayout.h"
34 #include "llvm/IR/DerivedTypes.h"
35 #include "llvm/IR/Function.h"
36 #include "llvm/IR/GetElementPtrTypeIterator.h"
37 #include "llvm/IR/GlobalAlias.h"
38 #include "llvm/IR/GlobalVariable.h"
39 #include "llvm/IR/Instructions.h"
40 #include "llvm/IR/IntrinsicInst.h"
41 #include "llvm/IR/Operator.h"
42 #include "llvm/IR/PatternMatch.h"
45 using namespace PatternMatch
;
47 #define DEBUG_TYPE "wasm-fastisel"
51 class WebAssemblyFastISel final
: public FastISel
{
52 // All possible address modes.
55 using BaseKind
= enum { RegBase
, FrameIndexBase
};
58 BaseKind Kind
= RegBase
;
64 // Whether the base has been determined yet
65 bool IsBaseSet
= false;
69 const GlobalValue
*GV
= nullptr;
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");
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");
87 unsigned getReg() const {
88 assert(isRegBase() && "Invalid base register access!");
91 void setFI(unsigned FI
) {
92 assert(isFIBase() && "Invalid base frame index access!");
93 assert(!IsBaseSet
&& "Base cannot be reset");
97 unsigned getFI() const {
98 assert(isFIBase() && "Invalid base frame index access!");
102 void setOffset(int64_t NewOffset
) {
103 assert(NewOffset
>= 0 && "Offsets must be non-negative");
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
; }
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
;
115 LLVMContext
*Context
;
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
122 : MVT::INVALID_SIMPLE_VALUE_TYPE
;
124 MVT::SimpleValueType
getLegalType(MVT::SimpleValueType VT
) {
137 if (Subtarget
->hasReferenceTypes())
141 if (Subtarget
->hasReferenceTypes() && Subtarget
->hasExceptionHandling())
152 if (Subtarget
->hasSIMD128())
158 return MVT::INVALID_SIMPLE_VALUE_TYPE
;
160 bool computeAddress(const Value
*Obj
, Address
&Addr
);
161 void materializeLoadStoreOperands(Address
&Addr
);
162 void addLoadStoreOperands(const Address
&Addr
, const MachineInstrBuilder
&MIB
,
163 MachineMemOperand
*MMO
);
164 unsigned maskI1Value(unsigned Reg
, const Value
*V
);
165 unsigned getRegForI1Value(const Value
*V
, const BasicBlock
*BB
, bool &Not
);
166 unsigned zeroExtendToI32(unsigned Reg
, const Value
*V
,
167 MVT::SimpleValueType From
);
168 unsigned signExtendToI32(unsigned Reg
, const Value
*V
,
169 MVT::SimpleValueType From
);
170 unsigned zeroExtend(unsigned Reg
, const Value
*V
, MVT::SimpleValueType From
,
171 MVT::SimpleValueType To
);
172 unsigned signExtend(unsigned Reg
, const Value
*V
, MVT::SimpleValueType From
,
173 MVT::SimpleValueType To
);
174 unsigned getRegForUnsignedValue(const Value
*V
);
175 unsigned getRegForSignedValue(const Value
*V
);
176 unsigned getRegForPromotedValue(const Value
*V
, bool IsSigned
);
177 unsigned notValue(unsigned Reg
);
178 unsigned copyValue(unsigned Reg
);
180 // Backend specific FastISel code.
181 unsigned fastMaterializeAlloca(const AllocaInst
*AI
) override
;
182 unsigned fastMaterializeConstant(const Constant
*C
) override
;
183 bool fastLowerArguments() override
;
185 // Selection routines.
186 bool selectCall(const Instruction
*I
);
187 bool selectSelect(const Instruction
*I
);
188 bool selectTrunc(const Instruction
*I
);
189 bool selectZExt(const Instruction
*I
);
190 bool selectSExt(const Instruction
*I
);
191 bool selectICmp(const Instruction
*I
);
192 bool selectFCmp(const Instruction
*I
);
193 bool selectBitCast(const Instruction
*I
);
194 bool selectLoad(const Instruction
*I
);
195 bool selectStore(const Instruction
*I
);
196 bool selectBr(const Instruction
*I
);
197 bool selectRet(const Instruction
*I
);
198 bool selectUnreachable(const Instruction
*I
);
201 // Backend specific FastISel code.
202 WebAssemblyFastISel(FunctionLoweringInfo
&FuncInfo
,
203 const TargetLibraryInfo
*LibInfo
)
204 : FastISel(FuncInfo
, LibInfo
, /*SkipTargetIndependentISel=*/true) {
205 Subtarget
= &FuncInfo
.MF
->getSubtarget
<WebAssemblySubtarget
>();
206 Context
= &FuncInfo
.Fn
->getContext();
209 bool fastSelectInstruction(const Instruction
*I
) override
;
211 #include "WebAssemblyGenFastISel.inc"
214 } // end anonymous namespace
216 bool WebAssemblyFastISel::computeAddress(const Value
*Obj
, Address
&Addr
) {
217 const User
*U
= nullptr;
218 unsigned Opcode
= Instruction::UserOp1
;
219 if (const auto *I
= dyn_cast
<Instruction
>(Obj
)) {
220 // Don't walk into other basic blocks unless the object is an alloca from
221 // another block, otherwise it may not have a virtual register assigned.
222 if (FuncInfo
.StaticAllocaMap
.count(static_cast<const AllocaInst
*>(Obj
)) ||
223 FuncInfo
.MBBMap
[I
->getParent()] == FuncInfo
.MBB
) {
224 Opcode
= I
->getOpcode();
227 } else if (const auto *C
= dyn_cast
<ConstantExpr
>(Obj
)) {
228 Opcode
= C
->getOpcode();
232 if (auto *Ty
= dyn_cast
<PointerType
>(Obj
->getType()))
233 if (Ty
->getAddressSpace() > 255)
234 // Fast instruction selection doesn't support the special
238 if (const auto *GV
= dyn_cast
<GlobalValue
>(Obj
)) {
239 if (TLI
.isPositionIndependent())
241 if (Addr
.getGlobalValue())
243 if (GV
->isThreadLocal())
245 Addr
.setGlobalValue(GV
);
252 case Instruction::BitCast
: {
253 // Look through bitcasts.
254 return computeAddress(U
->getOperand(0), Addr
);
256 case Instruction::IntToPtr
: {
257 // Look past no-op inttoptrs.
258 if (TLI
.getValueType(DL
, U
->getOperand(0)->getType()) ==
259 TLI
.getPointerTy(DL
))
260 return computeAddress(U
->getOperand(0), Addr
);
263 case Instruction::PtrToInt
: {
264 // Look past no-op ptrtoints.
265 if (TLI
.getValueType(DL
, U
->getType()) == TLI
.getPointerTy(DL
))
266 return computeAddress(U
->getOperand(0), Addr
);
269 case Instruction::GetElementPtr
: {
270 Address SavedAddr
= Addr
;
271 uint64_t TmpOffset
= Addr
.getOffset();
272 // Non-inbounds geps can wrap; wasm's offsets can't.
273 if (!cast
<GEPOperator
>(U
)->isInBounds())
274 goto unsupported_gep
;
275 // Iterate through the GEP folding the constants into offsets where
277 for (gep_type_iterator GTI
= gep_type_begin(U
), E
= gep_type_end(U
);
279 const Value
*Op
= GTI
.getOperand();
280 if (StructType
*STy
= GTI
.getStructTypeOrNull()) {
281 const StructLayout
*SL
= DL
.getStructLayout(STy
);
282 unsigned Idx
= cast
<ConstantInt
>(Op
)->getZExtValue();
283 TmpOffset
+= SL
->getElementOffset(Idx
);
285 uint64_t S
= GTI
.getSequentialElementStride(DL
);
287 if (const auto *CI
= dyn_cast
<ConstantInt
>(Op
)) {
288 // Constant-offset addressing.
289 TmpOffset
+= CI
->getSExtValue() * S
;
292 if (S
== 1 && Addr
.isRegBase() && Addr
.getReg() == 0) {
293 // An unscaled add of a register. Set it as the new base.
294 Register Reg
= getRegForValue(Op
);
300 if (canFoldAddIntoGEP(U
, Op
)) {
301 // A compatible add with a constant operand. Fold the constant.
302 auto *CI
= cast
<ConstantInt
>(cast
<AddOperator
>(Op
)->getOperand(1));
303 TmpOffset
+= CI
->getSExtValue() * S
;
304 // Iterate on the other operand.
305 Op
= cast
<AddOperator
>(Op
)->getOperand(0);
309 goto unsupported_gep
;
313 // Don't fold in negative offsets.
314 if (int64_t(TmpOffset
) >= 0) {
315 // Try to grab the base operand now.
316 Addr
.setOffset(TmpOffset
);
317 if (computeAddress(U
->getOperand(0), Addr
))
320 // We failed, restore everything and try the other options.
325 case Instruction::Alloca
: {
326 const auto *AI
= cast
<AllocaInst
>(Obj
);
327 DenseMap
<const AllocaInst
*, int>::iterator SI
=
328 FuncInfo
.StaticAllocaMap
.find(AI
);
329 if (SI
!= FuncInfo
.StaticAllocaMap
.end()) {
333 Addr
.setKind(Address::FrameIndexBase
);
334 Addr
.setFI(SI
->second
);
339 case Instruction::Add
: {
340 // Adds of constants are common and easy enough.
341 const Value
*LHS
= U
->getOperand(0);
342 const Value
*RHS
= U
->getOperand(1);
344 if (isa
<ConstantInt
>(LHS
))
347 if (const auto *CI
= dyn_cast
<ConstantInt
>(RHS
)) {
348 uint64_t TmpOffset
= Addr
.getOffset() + CI
->getSExtValue();
349 if (int64_t(TmpOffset
) >= 0) {
350 Addr
.setOffset(TmpOffset
);
351 return computeAddress(LHS
, Addr
);
355 Address Backup
= Addr
;
356 if (computeAddress(LHS
, Addr
) && computeAddress(RHS
, Addr
))
362 case Instruction::Sub
: {
363 // Subs of constants are common and easy enough.
364 const Value
*LHS
= U
->getOperand(0);
365 const Value
*RHS
= U
->getOperand(1);
367 if (const auto *CI
= dyn_cast
<ConstantInt
>(RHS
)) {
368 int64_t TmpOffset
= Addr
.getOffset() - CI
->getSExtValue();
369 if (TmpOffset
>= 0) {
370 Addr
.setOffset(TmpOffset
);
371 return computeAddress(LHS
, Addr
);
380 Register Reg
= getRegForValue(Obj
);
384 return Addr
.getReg() != 0;
387 void WebAssemblyFastISel::materializeLoadStoreOperands(Address
&Addr
) {
388 if (Addr
.isRegBase()) {
389 unsigned Reg
= Addr
.getReg();
391 Reg
= createResultReg(Subtarget
->hasAddr64() ? &WebAssembly::I64RegClass
392 : &WebAssembly::I32RegClass
);
393 unsigned Opc
= Subtarget
->hasAddr64() ? WebAssembly::CONST_I64
394 : WebAssembly::CONST_I32
;
395 BuildMI(*FuncInfo
.MBB
, FuncInfo
.InsertPt
, MIMD
, TII
.get(Opc
), Reg
)
402 void WebAssemblyFastISel::addLoadStoreOperands(const Address
&Addr
,
403 const MachineInstrBuilder
&MIB
,
404 MachineMemOperand
*MMO
) {
405 // Set the alignment operand (this is rewritten in SetP2AlignOperands).
406 // TODO: Disable SetP2AlignOperands for FastISel and just do it here.
409 if (const GlobalValue
*GV
= Addr
.getGlobalValue())
410 MIB
.addGlobalAddress(GV
, Addr
.getOffset());
412 MIB
.addImm(Addr
.getOffset());
414 if (Addr
.isRegBase())
415 MIB
.addReg(Addr
.getReg());
417 MIB
.addFrameIndex(Addr
.getFI());
419 MIB
.addMemOperand(MMO
);
422 unsigned WebAssemblyFastISel::maskI1Value(unsigned Reg
, const Value
*V
) {
423 return zeroExtendToI32(Reg
, V
, MVT::i1
);
426 unsigned WebAssemblyFastISel::getRegForI1Value(const Value
*V
,
427 const BasicBlock
*BB
,
429 if (const auto *ICmp
= dyn_cast
<ICmpInst
>(V
))
430 if (const ConstantInt
*C
= dyn_cast
<ConstantInt
>(ICmp
->getOperand(1)))
431 if (ICmp
->isEquality() && C
->isZero() && C
->getType()->isIntegerTy(32) &&
432 ICmp
->getParent() == BB
) {
433 Not
= ICmp
->isTrueWhenEqual();
434 return getRegForValue(ICmp
->getOperand(0));
438 Register Reg
= getRegForValue(V
);
441 return maskI1Value(Reg
, V
);
444 unsigned WebAssemblyFastISel::zeroExtendToI32(unsigned Reg
, const Value
*V
,
445 MVT::SimpleValueType From
) {
451 // If the value is naturally an i1, we don't need to mask it. We only know
452 // if a value is naturally an i1 if it is definitely lowered by FastISel,
453 // not a DAG ISel fallback.
454 if (V
!= nullptr && isa
<Argument
>(V
) && cast
<Argument
>(V
)->hasZExtAttr())
455 return copyValue(Reg
);
461 return copyValue(Reg
);
466 Register Imm
= createResultReg(&WebAssembly::I32RegClass
);
467 BuildMI(*FuncInfo
.MBB
, FuncInfo
.InsertPt
, MIMD
,
468 TII
.get(WebAssembly::CONST_I32
), Imm
)
469 .addImm(~(~uint64_t(0) << MVT(From
).getSizeInBits()));
471 Register Result
= createResultReg(&WebAssembly::I32RegClass
);
472 BuildMI(*FuncInfo
.MBB
, FuncInfo
.InsertPt
, MIMD
,
473 TII
.get(WebAssembly::AND_I32
), Result
)
480 unsigned WebAssemblyFastISel::signExtendToI32(unsigned Reg
, const Value
*V
,
481 MVT::SimpleValueType From
) {
491 return copyValue(Reg
);
496 Register Imm
= createResultReg(&WebAssembly::I32RegClass
);
497 BuildMI(*FuncInfo
.MBB
, FuncInfo
.InsertPt
, MIMD
,
498 TII
.get(WebAssembly::CONST_I32
), Imm
)
499 .addImm(32 - MVT(From
).getSizeInBits());
501 Register Left
= createResultReg(&WebAssembly::I32RegClass
);
502 BuildMI(*FuncInfo
.MBB
, FuncInfo
.InsertPt
, MIMD
,
503 TII
.get(WebAssembly::SHL_I32
), Left
)
507 Register Right
= createResultReg(&WebAssembly::I32RegClass
);
508 BuildMI(*FuncInfo
.MBB
, FuncInfo
.InsertPt
, MIMD
,
509 TII
.get(WebAssembly::SHR_S_I32
), Right
)
516 unsigned WebAssemblyFastISel::zeroExtend(unsigned Reg
, const Value
*V
,
517 MVT::SimpleValueType From
,
518 MVT::SimpleValueType To
) {
519 if (To
== MVT::i64
) {
520 if (From
== MVT::i64
)
521 return copyValue(Reg
);
523 Reg
= zeroExtendToI32(Reg
, V
, From
);
525 Register Result
= createResultReg(&WebAssembly::I64RegClass
);
526 BuildMI(*FuncInfo
.MBB
, FuncInfo
.InsertPt
, MIMD
,
527 TII
.get(WebAssembly::I64_EXTEND_U_I32
), Result
)
533 return zeroExtendToI32(Reg
, V
, From
);
538 unsigned WebAssemblyFastISel::signExtend(unsigned Reg
, const Value
*V
,
539 MVT::SimpleValueType From
,
540 MVT::SimpleValueType To
) {
541 if (To
== MVT::i64
) {
542 if (From
== MVT::i64
)
543 return copyValue(Reg
);
545 Reg
= signExtendToI32(Reg
, V
, From
);
547 Register Result
= createResultReg(&WebAssembly::I64RegClass
);
548 BuildMI(*FuncInfo
.MBB
, FuncInfo
.InsertPt
, MIMD
,
549 TII
.get(WebAssembly::I64_EXTEND_S_I32
), Result
)
555 return signExtendToI32(Reg
, V
, From
);
560 unsigned WebAssemblyFastISel::getRegForUnsignedValue(const Value
*V
) {
561 MVT::SimpleValueType From
= getSimpleType(V
->getType());
562 MVT::SimpleValueType To
= getLegalType(From
);
563 Register VReg
= getRegForValue(V
);
568 return zeroExtend(VReg
, V
, From
, To
);
571 unsigned WebAssemblyFastISel::getRegForSignedValue(const Value
*V
) {
572 MVT::SimpleValueType From
= getSimpleType(V
->getType());
573 MVT::SimpleValueType To
= getLegalType(From
);
574 Register VReg
= getRegForValue(V
);
579 return signExtend(VReg
, V
, From
, To
);
582 unsigned WebAssemblyFastISel::getRegForPromotedValue(const Value
*V
,
584 return IsSigned
? getRegForSignedValue(V
) : getRegForUnsignedValue(V
);
587 unsigned WebAssemblyFastISel::notValue(unsigned Reg
) {
588 assert(MRI
.getRegClass(Reg
) == &WebAssembly::I32RegClass
);
590 Register NotReg
= createResultReg(&WebAssembly::I32RegClass
);
591 BuildMI(*FuncInfo
.MBB
, FuncInfo
.InsertPt
, MIMD
,
592 TII
.get(WebAssembly::EQZ_I32
), NotReg
)
597 unsigned WebAssemblyFastISel::copyValue(unsigned Reg
) {
598 Register ResultReg
= createResultReg(MRI
.getRegClass(Reg
));
599 BuildMI(*FuncInfo
.MBB
, FuncInfo
.InsertPt
, MIMD
, TII
.get(WebAssembly::COPY
),
605 unsigned WebAssemblyFastISel::fastMaterializeAlloca(const AllocaInst
*AI
) {
606 DenseMap
<const AllocaInst
*, int>::iterator SI
=
607 FuncInfo
.StaticAllocaMap
.find(AI
);
609 if (SI
!= FuncInfo
.StaticAllocaMap
.end()) {
611 createResultReg(Subtarget
->hasAddr64() ? &WebAssembly::I64RegClass
612 : &WebAssembly::I32RegClass
);
614 Subtarget
->hasAddr64() ? WebAssembly::COPY_I64
: WebAssembly::COPY_I32
;
615 BuildMI(*FuncInfo
.MBB
, FuncInfo
.InsertPt
, MIMD
, TII
.get(Opc
), ResultReg
)
616 .addFrameIndex(SI
->second
);
623 unsigned WebAssemblyFastISel::fastMaterializeConstant(const Constant
*C
) {
624 if (const GlobalValue
*GV
= dyn_cast
<GlobalValue
>(C
)) {
625 if (TLI
.isPositionIndependent())
627 if (GV
->isThreadLocal())
630 createResultReg(Subtarget
->hasAddr64() ? &WebAssembly::I64RegClass
631 : &WebAssembly::I32RegClass
);
632 unsigned Opc
= Subtarget
->hasAddr64() ? WebAssembly::CONST_I64
633 : WebAssembly::CONST_I32
;
634 BuildMI(*FuncInfo
.MBB
, FuncInfo
.InsertPt
, MIMD
, TII
.get(Opc
), ResultReg
)
635 .addGlobalAddress(GV
);
639 // Let target-independent code handle it.
643 bool WebAssemblyFastISel::fastLowerArguments() {
644 if (!FuncInfo
.CanLowerReturn
)
647 const Function
*F
= FuncInfo
.Fn
;
651 if (FuncInfo
.Fn
->getCallingConv() == CallingConv::Swift
)
655 for (auto const &Arg
: F
->args()) {
656 const AttributeList
&Attrs
= F
->getAttributes();
657 if (Attrs
.hasParamAttr(I
, Attribute::ByVal
) ||
658 Attrs
.hasParamAttr(I
, Attribute::SwiftSelf
) ||
659 Attrs
.hasParamAttr(I
, Attribute::SwiftError
) ||
660 Attrs
.hasParamAttr(I
, Attribute::InAlloca
) ||
661 Attrs
.hasParamAttr(I
, Attribute::Nest
))
664 Type
*ArgTy
= Arg
.getType();
665 if (ArgTy
->isStructTy() || ArgTy
->isArrayTy())
667 if (!Subtarget
->hasSIMD128() && ArgTy
->isVectorTy())
671 const TargetRegisterClass
*RC
;
672 switch (getSimpleType(ArgTy
)) {
677 Opc
= WebAssembly::ARGUMENT_i32
;
678 RC
= &WebAssembly::I32RegClass
;
681 Opc
= WebAssembly::ARGUMENT_i64
;
682 RC
= &WebAssembly::I64RegClass
;
685 Opc
= WebAssembly::ARGUMENT_f32
;
686 RC
= &WebAssembly::F32RegClass
;
689 Opc
= WebAssembly::ARGUMENT_f64
;
690 RC
= &WebAssembly::F64RegClass
;
693 Opc
= WebAssembly::ARGUMENT_v16i8
;
694 RC
= &WebAssembly::V128RegClass
;
697 Opc
= WebAssembly::ARGUMENT_v8i16
;
698 RC
= &WebAssembly::V128RegClass
;
701 Opc
= WebAssembly::ARGUMENT_v4i32
;
702 RC
= &WebAssembly::V128RegClass
;
705 Opc
= WebAssembly::ARGUMENT_v2i64
;
706 RC
= &WebAssembly::V128RegClass
;
709 Opc
= WebAssembly::ARGUMENT_v4f32
;
710 RC
= &WebAssembly::V128RegClass
;
713 Opc
= WebAssembly::ARGUMENT_v2f64
;
714 RC
= &WebAssembly::V128RegClass
;
717 Opc
= WebAssembly::ARGUMENT_funcref
;
718 RC
= &WebAssembly::FUNCREFRegClass
;
721 Opc
= WebAssembly::ARGUMENT_externref
;
722 RC
= &WebAssembly::EXTERNREFRegClass
;
725 Opc
= WebAssembly::ARGUMENT_exnref
;
726 RC
= &WebAssembly::EXNREFRegClass
;
731 Register ResultReg
= createResultReg(RC
);
732 BuildMI(*FuncInfo
.MBB
, FuncInfo
.InsertPt
, MIMD
, TII
.get(Opc
), ResultReg
)
734 updateValueMap(&Arg
, ResultReg
);
739 MRI
.addLiveIn(WebAssembly::ARGUMENTS
);
741 auto *MFI
= MF
->getInfo
<WebAssemblyFunctionInfo
>();
742 for (auto const &Arg
: F
->args()) {
743 MVT::SimpleValueType ArgTy
= getLegalType(getSimpleType(Arg
.getType()));
744 if (ArgTy
== MVT::INVALID_SIMPLE_VALUE_TYPE
) {
745 MFI
->clearParamsAndResults();
748 MFI
->addParam(ArgTy
);
751 if (!F
->getReturnType()->isVoidTy()) {
752 MVT::SimpleValueType RetTy
=
753 getLegalType(getSimpleType(F
->getReturnType()));
754 if (RetTy
== MVT::INVALID_SIMPLE_VALUE_TYPE
) {
755 MFI
->clearParamsAndResults();
758 MFI
->addResult(RetTy
);
764 bool WebAssemblyFastISel::selectCall(const Instruction
*I
) {
765 const auto *Call
= cast
<CallInst
>(I
);
767 // TODO: Support tail calls in FastISel
768 if (Call
->isMustTailCall() || Call
->isInlineAsm() ||
769 Call
->getFunctionType()->isVarArg())
772 Function
*Func
= Call
->getCalledFunction();
773 if (Func
&& Func
->isIntrinsic())
776 if (Call
->getCallingConv() == CallingConv::Swift
)
779 bool IsDirect
= Func
!= nullptr;
780 if (!IsDirect
&& isa
<ConstantExpr
>(Call
->getCalledOperand()))
783 FunctionType
*FuncTy
= Call
->getFunctionType();
784 unsigned Opc
= IsDirect
? WebAssembly::CALL
: WebAssembly::CALL_INDIRECT
;
785 bool IsVoid
= FuncTy
->getReturnType()->isVoidTy();
788 if (!Subtarget
->hasSIMD128() && Call
->getType()->isVectorTy())
791 MVT::SimpleValueType RetTy
= getSimpleType(Call
->getType());
797 ResultReg
= createResultReg(&WebAssembly::I32RegClass
);
800 ResultReg
= createResultReg(&WebAssembly::I64RegClass
);
803 ResultReg
= createResultReg(&WebAssembly::F32RegClass
);
806 ResultReg
= createResultReg(&WebAssembly::F64RegClass
);
809 ResultReg
= createResultReg(&WebAssembly::V128RegClass
);
812 ResultReg
= createResultReg(&WebAssembly::V128RegClass
);
815 ResultReg
= createResultReg(&WebAssembly::V128RegClass
);
818 ResultReg
= createResultReg(&WebAssembly::V128RegClass
);
821 ResultReg
= createResultReg(&WebAssembly::V128RegClass
);
824 ResultReg
= createResultReg(&WebAssembly::V128RegClass
);
827 ResultReg
= createResultReg(&WebAssembly::FUNCREFRegClass
);
830 ResultReg
= createResultReg(&WebAssembly::EXTERNREFRegClass
);
833 ResultReg
= createResultReg(&WebAssembly::EXNREFRegClass
);
840 SmallVector
<unsigned, 8> Args
;
841 for (unsigned I
= 0, E
= Call
->arg_size(); I
< E
; ++I
) {
842 Value
*V
= Call
->getArgOperand(I
);
843 MVT::SimpleValueType ArgTy
= getSimpleType(V
->getType());
844 if (ArgTy
== MVT::INVALID_SIMPLE_VALUE_TYPE
)
847 const AttributeList
&Attrs
= Call
->getAttributes();
848 if (Attrs
.hasParamAttr(I
, Attribute::ByVal
) ||
849 Attrs
.hasParamAttr(I
, Attribute::SwiftSelf
) ||
850 Attrs
.hasParamAttr(I
, Attribute::SwiftError
) ||
851 Attrs
.hasParamAttr(I
, Attribute::InAlloca
) ||
852 Attrs
.hasParamAttr(I
, Attribute::Nest
))
857 if (Call
->paramHasAttr(I
, Attribute::SExt
))
858 Reg
= getRegForSignedValue(V
);
859 else if (Call
->paramHasAttr(I
, Attribute::ZExt
))
860 Reg
= getRegForUnsignedValue(V
);
862 Reg
= getRegForValue(V
);
870 unsigned CalleeReg
= 0;
872 CalleeReg
= getRegForValue(Call
->getCalledOperand());
877 auto MIB
= BuildMI(*FuncInfo
.MBB
, FuncInfo
.InsertPt
, MIMD
, TII
.get(Opc
));
880 MIB
.addReg(ResultReg
, RegState::Define
);
883 MIB
.addGlobalAddress(Func
);
885 // Placeholder for the type index.
887 // The table into which this call_indirect indexes.
888 MCSymbolWasm
*Table
= WebAssembly::getOrCreateFunctionTableSymbol(
889 MF
->getContext(), Subtarget
);
890 if (Subtarget
->hasReferenceTypes()) {
893 // Otherwise for the MVP there is at most one table whose number is 0, but
894 // we can't write a table symbol or issue relocations. Instead we just
895 // ensure the table is live.
901 for (unsigned ArgReg
: Args
)
905 MIB
.addReg(CalleeReg
);
908 updateValueMap(Call
, ResultReg
);
912 bool WebAssemblyFastISel::selectSelect(const Instruction
*I
) {
913 const auto *Select
= cast
<SelectInst
>(I
);
917 getRegForI1Value(Select
->getCondition(), I
->getParent(), Not
);
921 Register TrueReg
= getRegForValue(Select
->getTrueValue());
925 Register FalseReg
= getRegForValue(Select
->getFalseValue());
930 std::swap(TrueReg
, FalseReg
);
933 const TargetRegisterClass
*RC
;
934 switch (getSimpleType(Select
->getType())) {
939 Opc
= WebAssembly::SELECT_I32
;
940 RC
= &WebAssembly::I32RegClass
;
943 Opc
= WebAssembly::SELECT_I64
;
944 RC
= &WebAssembly::I64RegClass
;
947 Opc
= WebAssembly::SELECT_F32
;
948 RC
= &WebAssembly::F32RegClass
;
951 Opc
= WebAssembly::SELECT_F64
;
952 RC
= &WebAssembly::F64RegClass
;
955 Opc
= WebAssembly::SELECT_FUNCREF
;
956 RC
= &WebAssembly::FUNCREFRegClass
;
959 Opc
= WebAssembly::SELECT_EXTERNREF
;
960 RC
= &WebAssembly::EXTERNREFRegClass
;
963 Opc
= WebAssembly::SELECT_EXNREF
;
964 RC
= &WebAssembly::EXNREFRegClass
;
970 Register ResultReg
= createResultReg(RC
);
971 BuildMI(*FuncInfo
.MBB
, FuncInfo
.InsertPt
, MIMD
, TII
.get(Opc
), ResultReg
)
976 updateValueMap(Select
, ResultReg
);
980 bool WebAssemblyFastISel::selectTrunc(const Instruction
*I
) {
981 const auto *Trunc
= cast
<TruncInst
>(I
);
983 Register Reg
= getRegForValue(Trunc
->getOperand(0));
987 if (Trunc
->getOperand(0)->getType()->isIntegerTy(64)) {
988 Register Result
= createResultReg(&WebAssembly::I32RegClass
);
989 BuildMI(*FuncInfo
.MBB
, FuncInfo
.InsertPt
, MIMD
,
990 TII
.get(WebAssembly::I32_WRAP_I64
), Result
)
995 updateValueMap(Trunc
, Reg
);
999 bool WebAssemblyFastISel::selectZExt(const Instruction
*I
) {
1000 const auto *ZExt
= cast
<ZExtInst
>(I
);
1002 const Value
*Op
= ZExt
->getOperand(0);
1003 MVT::SimpleValueType From
= getSimpleType(Op
->getType());
1004 MVT::SimpleValueType To
= getLegalType(getSimpleType(ZExt
->getType()));
1005 Register In
= getRegForValue(Op
);
1008 unsigned Reg
= zeroExtend(In
, Op
, From
, To
);
1012 updateValueMap(ZExt
, Reg
);
1016 bool WebAssemblyFastISel::selectSExt(const Instruction
*I
) {
1017 const auto *SExt
= cast
<SExtInst
>(I
);
1019 const Value
*Op
= SExt
->getOperand(0);
1020 MVT::SimpleValueType From
= getSimpleType(Op
->getType());
1021 MVT::SimpleValueType To
= getLegalType(getSimpleType(SExt
->getType()));
1022 Register In
= getRegForValue(Op
);
1025 unsigned Reg
= signExtend(In
, Op
, From
, To
);
1029 updateValueMap(SExt
, Reg
);
1033 bool WebAssemblyFastISel::selectICmp(const Instruction
*I
) {
1034 const auto *ICmp
= cast
<ICmpInst
>(I
);
1036 bool I32
= getSimpleType(ICmp
->getOperand(0)->getType()) != MVT::i64
;
1038 bool IsSigned
= false;
1039 switch (ICmp
->getPredicate()) {
1040 case ICmpInst::ICMP_EQ
:
1041 Opc
= I32
? WebAssembly::EQ_I32
: WebAssembly::EQ_I64
;
1043 case ICmpInst::ICMP_NE
:
1044 Opc
= I32
? WebAssembly::NE_I32
: WebAssembly::NE_I64
;
1046 case ICmpInst::ICMP_UGT
:
1047 Opc
= I32
? WebAssembly::GT_U_I32
: WebAssembly::GT_U_I64
;
1049 case ICmpInst::ICMP_UGE
:
1050 Opc
= I32
? WebAssembly::GE_U_I32
: WebAssembly::GE_U_I64
;
1052 case ICmpInst::ICMP_ULT
:
1053 Opc
= I32
? WebAssembly::LT_U_I32
: WebAssembly::LT_U_I64
;
1055 case ICmpInst::ICMP_ULE
:
1056 Opc
= I32
? WebAssembly::LE_U_I32
: WebAssembly::LE_U_I64
;
1058 case ICmpInst::ICMP_SGT
:
1059 Opc
= I32
? WebAssembly::GT_S_I32
: WebAssembly::GT_S_I64
;
1062 case ICmpInst::ICMP_SGE
:
1063 Opc
= I32
? WebAssembly::GE_S_I32
: WebAssembly::GE_S_I64
;
1066 case ICmpInst::ICMP_SLT
:
1067 Opc
= I32
? WebAssembly::LT_S_I32
: WebAssembly::LT_S_I64
;
1070 case ICmpInst::ICMP_SLE
:
1071 Opc
= I32
? WebAssembly::LE_S_I32
: WebAssembly::LE_S_I64
;
1078 unsigned LHS
= getRegForPromotedValue(ICmp
->getOperand(0), IsSigned
);
1082 unsigned RHS
= getRegForPromotedValue(ICmp
->getOperand(1), IsSigned
);
1086 Register ResultReg
= createResultReg(&WebAssembly::I32RegClass
);
1087 BuildMI(*FuncInfo
.MBB
, FuncInfo
.InsertPt
, MIMD
, TII
.get(Opc
), ResultReg
)
1090 updateValueMap(ICmp
, ResultReg
);
1094 bool WebAssemblyFastISel::selectFCmp(const Instruction
*I
) {
1095 const auto *FCmp
= cast
<FCmpInst
>(I
);
1097 Register LHS
= getRegForValue(FCmp
->getOperand(0));
1101 Register RHS
= getRegForValue(FCmp
->getOperand(1));
1105 bool F32
= getSimpleType(FCmp
->getOperand(0)->getType()) != MVT::f64
;
1108 switch (FCmp
->getPredicate()) {
1109 case FCmpInst::FCMP_OEQ
:
1110 Opc
= F32
? WebAssembly::EQ_F32
: WebAssembly::EQ_F64
;
1112 case FCmpInst::FCMP_UNE
:
1113 Opc
= F32
? WebAssembly::NE_F32
: WebAssembly::NE_F64
;
1115 case FCmpInst::FCMP_OGT
:
1116 Opc
= F32
? WebAssembly::GT_F32
: WebAssembly::GT_F64
;
1118 case FCmpInst::FCMP_OGE
:
1119 Opc
= F32
? WebAssembly::GE_F32
: WebAssembly::GE_F64
;
1121 case FCmpInst::FCMP_OLT
:
1122 Opc
= F32
? WebAssembly::LT_F32
: WebAssembly::LT_F64
;
1124 case FCmpInst::FCMP_OLE
:
1125 Opc
= F32
? WebAssembly::LE_F32
: WebAssembly::LE_F64
;
1127 case FCmpInst::FCMP_UGT
:
1128 Opc
= F32
? WebAssembly::LE_F32
: WebAssembly::LE_F64
;
1131 case FCmpInst::FCMP_UGE
:
1132 Opc
= F32
? WebAssembly::LT_F32
: WebAssembly::LT_F64
;
1135 case FCmpInst::FCMP_ULT
:
1136 Opc
= F32
? WebAssembly::GE_F32
: WebAssembly::GE_F64
;
1139 case FCmpInst::FCMP_ULE
:
1140 Opc
= F32
? WebAssembly::GT_F32
: WebAssembly::GT_F64
;
1147 Register ResultReg
= createResultReg(&WebAssembly::I32RegClass
);
1148 BuildMI(*FuncInfo
.MBB
, FuncInfo
.InsertPt
, MIMD
, TII
.get(Opc
), ResultReg
)
1153 ResultReg
= notValue(ResultReg
);
1155 updateValueMap(FCmp
, ResultReg
);
1159 bool WebAssemblyFastISel::selectBitCast(const Instruction
*I
) {
1160 // Target-independent code can handle this, except it doesn't set the dead
1161 // flag on the ARGUMENTS clobber, so we have to do that manually in order
1162 // to satisfy code that expects this of isBitcast() instructions.
1163 EVT VT
= TLI
.getValueType(DL
, I
->getOperand(0)->getType());
1164 EVT RetVT
= TLI
.getValueType(DL
, I
->getType());
1165 if (!VT
.isSimple() || !RetVT
.isSimple())
1168 Register In
= getRegForValue(I
->getOperand(0));
1174 updateValueMap(I
, In
);
1178 Register Reg
= fastEmit_ISD_BITCAST_r(VT
.getSimpleVT(), RetVT
.getSimpleVT(),
1182 MachineBasicBlock::iterator Iter
= FuncInfo
.InsertPt
;
1184 assert(Iter
->isBitcast());
1185 Iter
->setPhysRegsDeadExcept(ArrayRef
<Register
>(), TRI
);
1186 updateValueMap(I
, Reg
);
1190 bool WebAssemblyFastISel::selectLoad(const Instruction
*I
) {
1191 const auto *Load
= cast
<LoadInst
>(I
);
1192 if (Load
->isAtomic())
1194 if (!WebAssembly::isDefaultAddressSpace(Load
->getPointerAddressSpace()))
1196 if (!Subtarget
->hasSIMD128() && Load
->getType()->isVectorTy())
1200 if (!computeAddress(Load
->getPointerOperand(), Addr
))
1203 // TODO: Fold a following sign-/zero-extend into the load instruction.
1206 const TargetRegisterClass
*RC
;
1207 bool A64
= Subtarget
->hasAddr64();
1208 switch (getSimpleType(Load
->getType())) {
1211 Opc
= A64
? WebAssembly::LOAD8_U_I32_A64
: WebAssembly::LOAD8_U_I32_A32
;
1212 RC
= &WebAssembly::I32RegClass
;
1215 Opc
= A64
? WebAssembly::LOAD16_U_I32_A64
: WebAssembly::LOAD16_U_I32_A32
;
1216 RC
= &WebAssembly::I32RegClass
;
1219 Opc
= A64
? WebAssembly::LOAD_I32_A64
: WebAssembly::LOAD_I32_A32
;
1220 RC
= &WebAssembly::I32RegClass
;
1223 Opc
= A64
? WebAssembly::LOAD_I64_A64
: WebAssembly::LOAD_I64_A32
;
1224 RC
= &WebAssembly::I64RegClass
;
1227 Opc
= A64
? WebAssembly::LOAD_F32_A64
: WebAssembly::LOAD_F32_A32
;
1228 RC
= &WebAssembly::F32RegClass
;
1231 Opc
= A64
? WebAssembly::LOAD_F64_A64
: WebAssembly::LOAD_F64_A32
;
1232 RC
= &WebAssembly::F64RegClass
;
1238 materializeLoadStoreOperands(Addr
);
1240 Register ResultReg
= createResultReg(RC
);
1241 auto MIB
= BuildMI(*FuncInfo
.MBB
, FuncInfo
.InsertPt
, MIMD
, TII
.get(Opc
),
1244 addLoadStoreOperands(Addr
, MIB
, createMachineMemOperandFor(Load
));
1246 updateValueMap(Load
, ResultReg
);
1250 bool WebAssemblyFastISel::selectStore(const Instruction
*I
) {
1251 const auto *Store
= cast
<StoreInst
>(I
);
1252 if (Store
->isAtomic())
1254 if (!WebAssembly::isDefaultAddressSpace(Store
->getPointerAddressSpace()))
1256 if (!Subtarget
->hasSIMD128() &&
1257 Store
->getValueOperand()->getType()->isVectorTy())
1261 if (!computeAddress(Store
->getPointerOperand(), Addr
))
1265 bool VTIsi1
= false;
1266 bool A64
= Subtarget
->hasAddr64();
1267 switch (getSimpleType(Store
->getValueOperand()->getType())) {
1272 Opc
= A64
? WebAssembly::STORE8_I32_A64
: WebAssembly::STORE8_I32_A32
;
1275 Opc
= A64
? WebAssembly::STORE16_I32_A64
: WebAssembly::STORE16_I32_A32
;
1278 Opc
= A64
? WebAssembly::STORE_I32_A64
: WebAssembly::STORE_I32_A32
;
1281 Opc
= A64
? WebAssembly::STORE_I64_A64
: WebAssembly::STORE_I64_A32
;
1284 Opc
= A64
? WebAssembly::STORE_F32_A64
: WebAssembly::STORE_F32_A32
;
1287 Opc
= A64
? WebAssembly::STORE_F64_A64
: WebAssembly::STORE_F64_A32
;
1293 materializeLoadStoreOperands(Addr
);
1295 Register ValueReg
= getRegForValue(Store
->getValueOperand());
1299 ValueReg
= maskI1Value(ValueReg
, Store
->getValueOperand());
1301 auto MIB
= BuildMI(*FuncInfo
.MBB
, FuncInfo
.InsertPt
, MIMD
, TII
.get(Opc
));
1303 addLoadStoreOperands(Addr
, MIB
, createMachineMemOperandFor(Store
));
1305 MIB
.addReg(ValueReg
);
1309 bool WebAssemblyFastISel::selectBr(const Instruction
*I
) {
1310 const auto *Br
= cast
<BranchInst
>(I
);
1311 if (Br
->isUnconditional()) {
1312 MachineBasicBlock
*MSucc
= FuncInfo
.MBBMap
[Br
->getSuccessor(0)];
1313 fastEmitBranch(MSucc
, Br
->getDebugLoc());
1317 MachineBasicBlock
*TBB
= FuncInfo
.MBBMap
[Br
->getSuccessor(0)];
1318 MachineBasicBlock
*FBB
= FuncInfo
.MBBMap
[Br
->getSuccessor(1)];
1321 unsigned CondReg
= getRegForI1Value(Br
->getCondition(), Br
->getParent(), Not
);
1325 unsigned Opc
= WebAssembly::BR_IF
;
1327 Opc
= WebAssembly::BR_UNLESS
;
1329 BuildMI(*FuncInfo
.MBB
, FuncInfo
.InsertPt
, MIMD
, TII
.get(Opc
))
1333 finishCondBranch(Br
->getParent(), TBB
, FBB
);
1337 bool WebAssemblyFastISel::selectRet(const Instruction
*I
) {
1338 if (!FuncInfo
.CanLowerReturn
)
1341 const auto *Ret
= cast
<ReturnInst
>(I
);
1343 if (Ret
->getNumOperands() == 0) {
1344 BuildMI(*FuncInfo
.MBB
, FuncInfo
.InsertPt
, MIMD
,
1345 TII
.get(WebAssembly::RETURN
));
1349 // TODO: support multiple return in FastISel
1350 if (Ret
->getNumOperands() > 1)
1353 Value
*RV
= Ret
->getOperand(0);
1354 if (!Subtarget
->hasSIMD128() && RV
->getType()->isVectorTy())
1357 switch (getSimpleType(RV
->getType())) {
1372 case MVT::externref
:
1380 if (FuncInfo
.Fn
->getAttributes().hasRetAttr(Attribute::SExt
))
1381 Reg
= getRegForSignedValue(RV
);
1382 else if (FuncInfo
.Fn
->getAttributes().hasRetAttr(Attribute::ZExt
))
1383 Reg
= getRegForUnsignedValue(RV
);
1385 Reg
= getRegForValue(RV
);
1390 BuildMI(*FuncInfo
.MBB
, FuncInfo
.InsertPt
, MIMD
,
1391 TII
.get(WebAssembly::RETURN
))
1396 bool WebAssemblyFastISel::selectUnreachable(const Instruction
*I
) {
1397 BuildMI(*FuncInfo
.MBB
, FuncInfo
.InsertPt
, MIMD
,
1398 TII
.get(WebAssembly::UNREACHABLE
));
1402 bool WebAssemblyFastISel::fastSelectInstruction(const Instruction
*I
) {
1403 switch (I
->getOpcode()) {
1404 case Instruction::Call
:
1408 case Instruction::Select
:
1409 return selectSelect(I
);
1410 case Instruction::Trunc
:
1411 return selectTrunc(I
);
1412 case Instruction::ZExt
:
1413 return selectZExt(I
);
1414 case Instruction::SExt
:
1415 return selectSExt(I
);
1416 case Instruction::ICmp
:
1417 return selectICmp(I
);
1418 case Instruction::FCmp
:
1419 return selectFCmp(I
);
1420 case Instruction::BitCast
:
1421 return selectBitCast(I
);
1422 case Instruction::Load
:
1423 return selectLoad(I
);
1424 case Instruction::Store
:
1425 return selectStore(I
);
1426 case Instruction::Br
:
1428 case Instruction::Ret
:
1429 return selectRet(I
);
1430 case Instruction::Unreachable
:
1431 return selectUnreachable(I
);
1436 // Fall back to target-independent instruction selection.
1437 return selectOperator(I
, I
->getOpcode());
1440 FastISel
*WebAssembly::createFastISel(FunctionLoweringInfo
&FuncInfo
,
1441 const TargetLibraryInfo
*LibInfo
) {
1442 return new WebAssemblyFastISel(FuncInfo
, LibInfo
);