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/WebAssemblyUtilities.h"
20 #include "WebAssembly.h"
21 #include "WebAssemblyMachineFunctionInfo.h"
22 #include "WebAssemblySubtarget.h"
23 #include "WebAssemblyTargetMachine.h"
24 #include "llvm/Analysis/BranchProbabilityInfo.h"
25 #include "llvm/CodeGen/FastISel.h"
26 #include "llvm/CodeGen/FunctionLoweringInfo.h"
27 #include "llvm/CodeGen/MachineConstantPool.h"
28 #include "llvm/CodeGen/MachineFrameInfo.h"
29 #include "llvm/CodeGen/MachineInstrBuilder.h"
30 #include "llvm/CodeGen/MachineModuleInfo.h"
31 #include "llvm/CodeGen/MachineRegisterInfo.h"
32 #include "llvm/IR/DataLayout.h"
33 #include "llvm/IR/DerivedTypes.h"
34 #include "llvm/IR/Function.h"
35 #include "llvm/IR/GetElementPtrTypeIterator.h"
36 #include "llvm/IR/GlobalAlias.h"
37 #include "llvm/IR/GlobalVariable.h"
38 #include "llvm/IR/Instructions.h"
39 #include "llvm/IR/IntrinsicInst.h"
40 #include "llvm/IR/Operator.h"
41 #include "llvm/IR/PatternMatch.h"
44 using namespace PatternMatch
;
46 #define DEBUG_TYPE "wasm-fastisel"
50 class WebAssemblyFastISel final
: public FastISel
{
51 // All possible address modes.
54 using BaseKind
= enum { RegBase
, FrameIndexBase
};
57 BaseKind Kind
= RegBase
;
63 // Whether the base has been determined yet
64 bool IsBaseSet
= false;
68 const GlobalValue
*GV
= nullptr;
71 // Innocuous defaults for our address.
72 Address() { Base
.Reg
= 0; }
73 void setKind(BaseKind K
) {
74 assert(!isSet() && "Can't change kind with non-zero base");
77 BaseKind
getKind() const { return Kind
; }
78 bool isRegBase() const { return Kind
== RegBase
; }
79 bool isFIBase() const { return Kind
== FrameIndexBase
; }
80 void setReg(unsigned Reg
) {
81 assert(isRegBase() && "Invalid base register access!");
82 assert(!IsBaseSet
&& "Base cannot be reset");
86 unsigned getReg() const {
87 assert(isRegBase() && "Invalid base register access!");
90 void setFI(unsigned FI
) {
91 assert(isFIBase() && "Invalid base frame index access!");
92 assert(!IsBaseSet
&& "Base cannot be reset");
96 unsigned getFI() const {
97 assert(isFIBase() && "Invalid base frame index access!");
101 void setOffset(int64_t NewOffset
) {
102 assert(NewOffset
>= 0 && "Offsets must be non-negative");
105 int64_t getOffset() const { return Offset
; }
106 void setGlobalValue(const GlobalValue
*G
) { GV
= G
; }
107 const GlobalValue
*getGlobalValue() const { return GV
; }
108 bool isSet() const { return IsBaseSet
; }
111 /// Keep a pointer to the WebAssemblySubtarget around so that we can make the
112 /// right decision when generating code for different targets.
113 const WebAssemblySubtarget
*Subtarget
;
114 LLVMContext
*Context
;
117 // Utility helper routines
118 MVT::SimpleValueType
getSimpleType(Type
*Ty
) {
119 EVT VT
= TLI
.getValueType(DL
, Ty
, /*AllowUnknown=*/true);
120 return VT
.isSimple() ? VT
.getSimpleVT().SimpleTy
121 : MVT::INVALID_SIMPLE_VALUE_TYPE
;
123 MVT::SimpleValueType
getLegalType(MVT::SimpleValueType VT
) {
136 if (Subtarget
->hasReferenceTypes())
147 if (Subtarget
->hasSIMD128())
153 return MVT::INVALID_SIMPLE_VALUE_TYPE
;
155 bool computeAddress(const Value
*Obj
, Address
&Addr
);
156 void materializeLoadStoreOperands(Address
&Addr
);
157 void addLoadStoreOperands(const Address
&Addr
, const MachineInstrBuilder
&MIB
,
158 MachineMemOperand
*MMO
);
159 unsigned maskI1Value(unsigned Reg
, const Value
*V
);
160 unsigned getRegForI1Value(const Value
*V
, bool &Not
);
161 unsigned zeroExtendToI32(unsigned Reg
, const Value
*V
,
162 MVT::SimpleValueType From
);
163 unsigned signExtendToI32(unsigned Reg
, const Value
*V
,
164 MVT::SimpleValueType From
);
165 unsigned zeroExtend(unsigned Reg
, const Value
*V
, MVT::SimpleValueType From
,
166 MVT::SimpleValueType To
);
167 unsigned signExtend(unsigned Reg
, const Value
*V
, MVT::SimpleValueType From
,
168 MVT::SimpleValueType To
);
169 unsigned getRegForUnsignedValue(const Value
*V
);
170 unsigned getRegForSignedValue(const Value
*V
);
171 unsigned getRegForPromotedValue(const Value
*V
, bool IsSigned
);
172 unsigned notValue(unsigned Reg
);
173 unsigned copyValue(unsigned Reg
);
175 // Backend specific FastISel code.
176 unsigned fastMaterializeAlloca(const AllocaInst
*AI
) override
;
177 unsigned fastMaterializeConstant(const Constant
*C
) override
;
178 bool fastLowerArguments() override
;
180 // Selection routines.
181 bool selectCall(const Instruction
*I
);
182 bool selectSelect(const Instruction
*I
);
183 bool selectTrunc(const Instruction
*I
);
184 bool selectZExt(const Instruction
*I
);
185 bool selectSExt(const Instruction
*I
);
186 bool selectICmp(const Instruction
*I
);
187 bool selectFCmp(const Instruction
*I
);
188 bool selectBitCast(const Instruction
*I
);
189 bool selectLoad(const Instruction
*I
);
190 bool selectStore(const Instruction
*I
);
191 bool selectBr(const Instruction
*I
);
192 bool selectRet(const Instruction
*I
);
193 bool selectUnreachable(const Instruction
*I
);
196 // Backend specific FastISel code.
197 WebAssemblyFastISel(FunctionLoweringInfo
&FuncInfo
,
198 const TargetLibraryInfo
*LibInfo
)
199 : FastISel(FuncInfo
, LibInfo
, /*SkipTargetIndependentISel=*/true) {
200 Subtarget
= &FuncInfo
.MF
->getSubtarget
<WebAssemblySubtarget
>();
201 Context
= &FuncInfo
.Fn
->getContext();
204 bool fastSelectInstruction(const Instruction
*I
) override
;
206 #include "WebAssemblyGenFastISel.inc"
209 } // end anonymous namespace
211 bool WebAssemblyFastISel::computeAddress(const Value
*Obj
, Address
&Addr
) {
212 const User
*U
= nullptr;
213 unsigned Opcode
= Instruction::UserOp1
;
214 if (const auto *I
= dyn_cast
<Instruction
>(Obj
)) {
215 // Don't walk into other basic blocks unless the object is an alloca from
216 // another block, otherwise it may not have a virtual register assigned.
217 if (FuncInfo
.StaticAllocaMap
.count(static_cast<const AllocaInst
*>(Obj
)) ||
218 FuncInfo
.MBBMap
[I
->getParent()] == FuncInfo
.MBB
) {
219 Opcode
= I
->getOpcode();
222 } else if (const auto *C
= dyn_cast
<ConstantExpr
>(Obj
)) {
223 Opcode
= C
->getOpcode();
227 if (auto *Ty
= dyn_cast
<PointerType
>(Obj
->getType()))
228 if (Ty
->getAddressSpace() > 255)
229 // Fast instruction selection doesn't support the special
233 if (const auto *GV
= dyn_cast
<GlobalValue
>(Obj
)) {
234 if (TLI
.isPositionIndependent())
236 if (Addr
.getGlobalValue())
238 if (GV
->isThreadLocal())
240 Addr
.setGlobalValue(GV
);
247 case Instruction::BitCast
: {
248 // Look through bitcasts.
249 return computeAddress(U
->getOperand(0), Addr
);
251 case Instruction::IntToPtr
: {
252 // Look past no-op inttoptrs.
253 if (TLI
.getValueType(DL
, U
->getOperand(0)->getType()) ==
254 TLI
.getPointerTy(DL
))
255 return computeAddress(U
->getOperand(0), Addr
);
258 case Instruction::PtrToInt
: {
259 // Look past no-op ptrtoints.
260 if (TLI
.getValueType(DL
, U
->getType()) == TLI
.getPointerTy(DL
))
261 return computeAddress(U
->getOperand(0), Addr
);
264 case Instruction::GetElementPtr
: {
265 Address SavedAddr
= Addr
;
266 uint64_t TmpOffset
= Addr
.getOffset();
267 // Non-inbounds geps can wrap; wasm's offsets can't.
268 if (!cast
<GEPOperator
>(U
)->isInBounds())
269 goto unsupported_gep
;
270 // Iterate through the GEP folding the constants into offsets where
272 for (gep_type_iterator GTI
= gep_type_begin(U
), E
= gep_type_end(U
);
274 const Value
*Op
= GTI
.getOperand();
275 if (StructType
*STy
= GTI
.getStructTypeOrNull()) {
276 const StructLayout
*SL
= DL
.getStructLayout(STy
);
277 unsigned Idx
= cast
<ConstantInt
>(Op
)->getZExtValue();
278 TmpOffset
+= SL
->getElementOffset(Idx
);
280 uint64_t S
= DL
.getTypeAllocSize(GTI
.getIndexedType());
282 if (const auto *CI
= dyn_cast
<ConstantInt
>(Op
)) {
283 // Constant-offset addressing.
284 TmpOffset
+= CI
->getSExtValue() * S
;
287 if (S
== 1 && Addr
.isRegBase() && Addr
.getReg() == 0) {
288 // An unscaled add of a register. Set it as the new base.
289 unsigned Reg
= getRegForValue(Op
);
295 if (canFoldAddIntoGEP(U
, Op
)) {
296 // A compatible add with a constant operand. Fold the constant.
297 auto *CI
= cast
<ConstantInt
>(cast
<AddOperator
>(Op
)->getOperand(1));
298 TmpOffset
+= CI
->getSExtValue() * S
;
299 // Iterate on the other operand.
300 Op
= cast
<AddOperator
>(Op
)->getOperand(0);
304 goto unsupported_gep
;
308 // Don't fold in negative offsets.
309 if (int64_t(TmpOffset
) >= 0) {
310 // Try to grab the base operand now.
311 Addr
.setOffset(TmpOffset
);
312 if (computeAddress(U
->getOperand(0), Addr
))
315 // We failed, restore everything and try the other options.
320 case Instruction::Alloca
: {
321 const auto *AI
= cast
<AllocaInst
>(Obj
);
322 DenseMap
<const AllocaInst
*, int>::iterator SI
=
323 FuncInfo
.StaticAllocaMap
.find(AI
);
324 if (SI
!= FuncInfo
.StaticAllocaMap
.end()) {
328 Addr
.setKind(Address::FrameIndexBase
);
329 Addr
.setFI(SI
->second
);
334 case Instruction::Add
: {
335 // Adds of constants are common and easy enough.
336 const Value
*LHS
= U
->getOperand(0);
337 const Value
*RHS
= U
->getOperand(1);
339 if (isa
<ConstantInt
>(LHS
))
342 if (const auto *CI
= dyn_cast
<ConstantInt
>(RHS
)) {
343 uint64_t TmpOffset
= Addr
.getOffset() + CI
->getSExtValue();
344 if (int64_t(TmpOffset
) >= 0) {
345 Addr
.setOffset(TmpOffset
);
346 return computeAddress(LHS
, Addr
);
350 Address Backup
= Addr
;
351 if (computeAddress(LHS
, Addr
) && computeAddress(RHS
, Addr
))
357 case Instruction::Sub
: {
358 // Subs of constants are common and easy enough.
359 const Value
*LHS
= U
->getOperand(0);
360 const Value
*RHS
= U
->getOperand(1);
362 if (const auto *CI
= dyn_cast
<ConstantInt
>(RHS
)) {
363 int64_t TmpOffset
= Addr
.getOffset() - CI
->getSExtValue();
364 if (TmpOffset
>= 0) {
365 Addr
.setOffset(TmpOffset
);
366 return computeAddress(LHS
, Addr
);
375 unsigned Reg
= getRegForValue(Obj
);
379 return Addr
.getReg() != 0;
382 void WebAssemblyFastISel::materializeLoadStoreOperands(Address
&Addr
) {
383 if (Addr
.isRegBase()) {
384 unsigned Reg
= Addr
.getReg();
386 Reg
= createResultReg(Subtarget
->hasAddr64() ? &WebAssembly::I64RegClass
387 : &WebAssembly::I32RegClass
);
388 unsigned Opc
= Subtarget
->hasAddr64() ? WebAssembly::CONST_I64
389 : WebAssembly::CONST_I32
;
390 BuildMI(*FuncInfo
.MBB
, FuncInfo
.InsertPt
, DbgLoc
, TII
.get(Opc
), Reg
)
397 void WebAssemblyFastISel::addLoadStoreOperands(const Address
&Addr
,
398 const MachineInstrBuilder
&MIB
,
399 MachineMemOperand
*MMO
) {
400 // Set the alignment operand (this is rewritten in SetP2AlignOperands).
401 // TODO: Disable SetP2AlignOperands for FastISel and just do it here.
404 if (const GlobalValue
*GV
= Addr
.getGlobalValue())
405 MIB
.addGlobalAddress(GV
, Addr
.getOffset());
407 MIB
.addImm(Addr
.getOffset());
409 if (Addr
.isRegBase())
410 MIB
.addReg(Addr
.getReg());
412 MIB
.addFrameIndex(Addr
.getFI());
414 MIB
.addMemOperand(MMO
);
417 unsigned WebAssemblyFastISel::maskI1Value(unsigned Reg
, const Value
*V
) {
418 return zeroExtendToI32(Reg
, V
, MVT::i1
);
421 unsigned WebAssemblyFastISel::getRegForI1Value(const Value
*V
, bool &Not
) {
422 if (const auto *ICmp
= dyn_cast
<ICmpInst
>(V
))
423 if (const ConstantInt
*C
= dyn_cast
<ConstantInt
>(ICmp
->getOperand(1)))
424 if (ICmp
->isEquality() && C
->isZero() && C
->getType()->isIntegerTy(32)) {
425 Not
= ICmp
->isTrueWhenEqual();
426 return getRegForValue(ICmp
->getOperand(0));
430 if (match(V
, m_Not(m_Value(NotV
))) && V
->getType()->isIntegerTy(32)) {
432 return getRegForValue(NotV
);
436 unsigned Reg
= getRegForValue(V
);
439 return maskI1Value(Reg
, V
);
442 unsigned WebAssemblyFastISel::zeroExtendToI32(unsigned Reg
, const Value
*V
,
443 MVT::SimpleValueType From
) {
449 // If the value is naturally an i1, we don't need to mask it. We only know
450 // if a value is naturally an i1 if it is definitely lowered by FastISel,
451 // not a DAG ISel fallback.
452 if (V
!= nullptr && isa
<Argument
>(V
) && cast
<Argument
>(V
)->hasZExtAttr())
453 return copyValue(Reg
);
459 return copyValue(Reg
);
464 unsigned Imm
= createResultReg(&WebAssembly::I32RegClass
);
465 BuildMI(*FuncInfo
.MBB
, FuncInfo
.InsertPt
, DbgLoc
,
466 TII
.get(WebAssembly::CONST_I32
), Imm
)
467 .addImm(~(~uint64_t(0) << MVT(From
).getSizeInBits()));
469 unsigned Result
= createResultReg(&WebAssembly::I32RegClass
);
470 BuildMI(*FuncInfo
.MBB
, FuncInfo
.InsertPt
, DbgLoc
,
471 TII
.get(WebAssembly::AND_I32
), Result
)
478 unsigned WebAssemblyFastISel::signExtendToI32(unsigned Reg
, const Value
*V
,
479 MVT::SimpleValueType From
) {
489 return copyValue(Reg
);
494 unsigned Imm
= createResultReg(&WebAssembly::I32RegClass
);
495 BuildMI(*FuncInfo
.MBB
, FuncInfo
.InsertPt
, DbgLoc
,
496 TII
.get(WebAssembly::CONST_I32
), Imm
)
497 .addImm(32 - MVT(From
).getSizeInBits());
499 unsigned Left
= createResultReg(&WebAssembly::I32RegClass
);
500 BuildMI(*FuncInfo
.MBB
, FuncInfo
.InsertPt
, DbgLoc
,
501 TII
.get(WebAssembly::SHL_I32
), Left
)
505 unsigned Right
= createResultReg(&WebAssembly::I32RegClass
);
506 BuildMI(*FuncInfo
.MBB
, FuncInfo
.InsertPt
, DbgLoc
,
507 TII
.get(WebAssembly::SHR_S_I32
), Right
)
514 unsigned WebAssemblyFastISel::zeroExtend(unsigned Reg
, const Value
*V
,
515 MVT::SimpleValueType From
,
516 MVT::SimpleValueType To
) {
517 if (To
== MVT::i64
) {
518 if (From
== MVT::i64
)
519 return copyValue(Reg
);
521 Reg
= zeroExtendToI32(Reg
, V
, From
);
523 unsigned Result
= createResultReg(&WebAssembly::I64RegClass
);
524 BuildMI(*FuncInfo
.MBB
, FuncInfo
.InsertPt
, DbgLoc
,
525 TII
.get(WebAssembly::I64_EXTEND_U_I32
), Result
)
531 return zeroExtendToI32(Reg
, V
, From
);
536 unsigned WebAssemblyFastISel::signExtend(unsigned Reg
, const Value
*V
,
537 MVT::SimpleValueType From
,
538 MVT::SimpleValueType To
) {
539 if (To
== MVT::i64
) {
540 if (From
== MVT::i64
)
541 return copyValue(Reg
);
543 Reg
= signExtendToI32(Reg
, V
, From
);
545 unsigned Result
= createResultReg(&WebAssembly::I64RegClass
);
546 BuildMI(*FuncInfo
.MBB
, FuncInfo
.InsertPt
, DbgLoc
,
547 TII
.get(WebAssembly::I64_EXTEND_S_I32
), Result
)
553 return signExtendToI32(Reg
, V
, From
);
558 unsigned WebAssemblyFastISel::getRegForUnsignedValue(const Value
*V
) {
559 MVT::SimpleValueType From
= getSimpleType(V
->getType());
560 MVT::SimpleValueType To
= getLegalType(From
);
561 unsigned VReg
= getRegForValue(V
);
564 return zeroExtend(VReg
, V
, From
, To
);
567 unsigned WebAssemblyFastISel::getRegForSignedValue(const Value
*V
) {
568 MVT::SimpleValueType From
= getSimpleType(V
->getType());
569 MVT::SimpleValueType To
= getLegalType(From
);
570 unsigned VReg
= getRegForValue(V
);
573 return signExtend(VReg
, V
, From
, To
);
576 unsigned WebAssemblyFastISel::getRegForPromotedValue(const Value
*V
,
578 return IsSigned
? getRegForSignedValue(V
) : getRegForUnsignedValue(V
);
581 unsigned WebAssemblyFastISel::notValue(unsigned Reg
) {
582 assert(MRI
.getRegClass(Reg
) == &WebAssembly::I32RegClass
);
584 unsigned NotReg
= createResultReg(&WebAssembly::I32RegClass
);
585 BuildMI(*FuncInfo
.MBB
, FuncInfo
.InsertPt
, DbgLoc
,
586 TII
.get(WebAssembly::EQZ_I32
), NotReg
)
591 unsigned WebAssemblyFastISel::copyValue(unsigned Reg
) {
592 unsigned ResultReg
= createResultReg(MRI
.getRegClass(Reg
));
593 BuildMI(*FuncInfo
.MBB
, FuncInfo
.InsertPt
, DbgLoc
, TII
.get(WebAssembly::COPY
),
599 unsigned WebAssemblyFastISel::fastMaterializeAlloca(const AllocaInst
*AI
) {
600 DenseMap
<const AllocaInst
*, int>::iterator SI
=
601 FuncInfo
.StaticAllocaMap
.find(AI
);
603 if (SI
!= FuncInfo
.StaticAllocaMap
.end()) {
605 createResultReg(Subtarget
->hasAddr64() ? &WebAssembly::I64RegClass
606 : &WebAssembly::I32RegClass
);
608 Subtarget
->hasAddr64() ? WebAssembly::COPY_I64
: WebAssembly::COPY_I32
;
609 BuildMI(*FuncInfo
.MBB
, FuncInfo
.InsertPt
, DbgLoc
, TII
.get(Opc
), ResultReg
)
610 .addFrameIndex(SI
->second
);
617 unsigned WebAssemblyFastISel::fastMaterializeConstant(const Constant
*C
) {
618 if (const GlobalValue
*GV
= dyn_cast
<GlobalValue
>(C
)) {
619 if (TLI
.isPositionIndependent())
621 if (GV
->isThreadLocal())
624 createResultReg(Subtarget
->hasAddr64() ? &WebAssembly::I64RegClass
625 : &WebAssembly::I32RegClass
);
626 unsigned Opc
= Subtarget
->hasAddr64() ? WebAssembly::CONST_I64
627 : WebAssembly::CONST_I32
;
628 BuildMI(*FuncInfo
.MBB
, FuncInfo
.InsertPt
, DbgLoc
, TII
.get(Opc
), ResultReg
)
629 .addGlobalAddress(GV
);
633 // Let target-independent code handle it.
637 bool WebAssemblyFastISel::fastLowerArguments() {
638 if (!FuncInfo
.CanLowerReturn
)
641 const Function
*F
= FuncInfo
.Fn
;
645 if (FuncInfo
.Fn
->getCallingConv() == CallingConv::Swift
)
649 for (auto const &Arg
: F
->args()) {
650 const AttributeList
&Attrs
= F
->getAttributes();
651 if (Attrs
.hasParamAttr(I
, Attribute::ByVal
) ||
652 Attrs
.hasParamAttr(I
, Attribute::SwiftSelf
) ||
653 Attrs
.hasParamAttr(I
, Attribute::SwiftError
) ||
654 Attrs
.hasParamAttr(I
, Attribute::InAlloca
) ||
655 Attrs
.hasParamAttr(I
, Attribute::Nest
))
658 Type
*ArgTy
= Arg
.getType();
659 if (ArgTy
->isStructTy() || ArgTy
->isArrayTy())
661 if (!Subtarget
->hasSIMD128() && ArgTy
->isVectorTy())
665 const TargetRegisterClass
*RC
;
666 switch (getSimpleType(ArgTy
)) {
671 Opc
= WebAssembly::ARGUMENT_i32
;
672 RC
= &WebAssembly::I32RegClass
;
675 Opc
= WebAssembly::ARGUMENT_i64
;
676 RC
= &WebAssembly::I64RegClass
;
679 Opc
= WebAssembly::ARGUMENT_f32
;
680 RC
= &WebAssembly::F32RegClass
;
683 Opc
= WebAssembly::ARGUMENT_f64
;
684 RC
= &WebAssembly::F64RegClass
;
687 Opc
= WebAssembly::ARGUMENT_v16i8
;
688 RC
= &WebAssembly::V128RegClass
;
691 Opc
= WebAssembly::ARGUMENT_v8i16
;
692 RC
= &WebAssembly::V128RegClass
;
695 Opc
= WebAssembly::ARGUMENT_v4i32
;
696 RC
= &WebAssembly::V128RegClass
;
699 Opc
= WebAssembly::ARGUMENT_v2i64
;
700 RC
= &WebAssembly::V128RegClass
;
703 Opc
= WebAssembly::ARGUMENT_v4f32
;
704 RC
= &WebAssembly::V128RegClass
;
707 Opc
= WebAssembly::ARGUMENT_v2f64
;
708 RC
= &WebAssembly::V128RegClass
;
711 Opc
= WebAssembly::ARGUMENT_funcref
;
712 RC
= &WebAssembly::FUNCREFRegClass
;
715 Opc
= WebAssembly::ARGUMENT_externref
;
716 RC
= &WebAssembly::EXTERNREFRegClass
;
721 unsigned ResultReg
= createResultReg(RC
);
722 BuildMI(*FuncInfo
.MBB
, FuncInfo
.InsertPt
, DbgLoc
, TII
.get(Opc
), ResultReg
)
724 updateValueMap(&Arg
, ResultReg
);
729 MRI
.addLiveIn(WebAssembly::ARGUMENTS
);
731 auto *MFI
= MF
->getInfo
<WebAssemblyFunctionInfo
>();
732 for (auto const &Arg
: F
->args()) {
733 MVT::SimpleValueType ArgTy
= getLegalType(getSimpleType(Arg
.getType()));
734 if (ArgTy
== MVT::INVALID_SIMPLE_VALUE_TYPE
) {
735 MFI
->clearParamsAndResults();
738 MFI
->addParam(ArgTy
);
741 if (!F
->getReturnType()->isVoidTy()) {
742 MVT::SimpleValueType RetTy
=
743 getLegalType(getSimpleType(F
->getReturnType()));
744 if (RetTy
== MVT::INVALID_SIMPLE_VALUE_TYPE
) {
745 MFI
->clearParamsAndResults();
748 MFI
->addResult(RetTy
);
754 bool WebAssemblyFastISel::selectCall(const Instruction
*I
) {
755 const auto *Call
= cast
<CallInst
>(I
);
757 // TODO: Support tail calls in FastISel
758 if (Call
->isMustTailCall() || Call
->isInlineAsm() ||
759 Call
->getFunctionType()->isVarArg())
762 Function
*Func
= Call
->getCalledFunction();
763 if (Func
&& Func
->isIntrinsic())
766 if (Call
->getCallingConv() == CallingConv::Swift
)
769 bool IsDirect
= Func
!= nullptr;
770 if (!IsDirect
&& isa
<ConstantExpr
>(Call
->getCalledOperand()))
773 FunctionType
*FuncTy
= Call
->getFunctionType();
774 unsigned Opc
= IsDirect
? WebAssembly::CALL
: WebAssembly::CALL_INDIRECT
;
775 bool IsVoid
= FuncTy
->getReturnType()->isVoidTy();
778 if (!Subtarget
->hasSIMD128() && Call
->getType()->isVectorTy())
781 MVT::SimpleValueType RetTy
= getSimpleType(Call
->getType());
787 ResultReg
= createResultReg(&WebAssembly::I32RegClass
);
790 ResultReg
= createResultReg(&WebAssembly::I64RegClass
);
793 ResultReg
= createResultReg(&WebAssembly::F32RegClass
);
796 ResultReg
= createResultReg(&WebAssembly::F64RegClass
);
799 ResultReg
= createResultReg(&WebAssembly::V128RegClass
);
802 ResultReg
= createResultReg(&WebAssembly::V128RegClass
);
805 ResultReg
= createResultReg(&WebAssembly::V128RegClass
);
808 ResultReg
= createResultReg(&WebAssembly::V128RegClass
);
811 ResultReg
= createResultReg(&WebAssembly::V128RegClass
);
814 ResultReg
= createResultReg(&WebAssembly::V128RegClass
);
817 ResultReg
= createResultReg(&WebAssembly::FUNCREFRegClass
);
820 ResultReg
= createResultReg(&WebAssembly::EXTERNREFRegClass
);
827 SmallVector
<unsigned, 8> Args
;
828 for (unsigned I
= 0, E
= Call
->getNumArgOperands(); I
< E
; ++I
) {
829 Value
*V
= Call
->getArgOperand(I
);
830 MVT::SimpleValueType ArgTy
= getSimpleType(V
->getType());
831 if (ArgTy
== MVT::INVALID_SIMPLE_VALUE_TYPE
)
834 const AttributeList
&Attrs
= Call
->getAttributes();
835 if (Attrs
.hasParamAttr(I
, Attribute::ByVal
) ||
836 Attrs
.hasParamAttr(I
, Attribute::SwiftSelf
) ||
837 Attrs
.hasParamAttr(I
, Attribute::SwiftError
) ||
838 Attrs
.hasParamAttr(I
, Attribute::InAlloca
) ||
839 Attrs
.hasParamAttr(I
, Attribute::Nest
))
844 if (Attrs
.hasParamAttr(I
, Attribute::SExt
))
845 Reg
= getRegForSignedValue(V
);
846 else if (Attrs
.hasParamAttr(I
, Attribute::ZExt
))
847 Reg
= getRegForUnsignedValue(V
);
849 Reg
= getRegForValue(V
);
857 unsigned CalleeReg
= 0;
859 CalleeReg
= getRegForValue(Call
->getCalledOperand());
864 auto MIB
= BuildMI(*FuncInfo
.MBB
, FuncInfo
.InsertPt
, DbgLoc
, TII
.get(Opc
));
867 MIB
.addReg(ResultReg
, RegState::Define
);
870 MIB
.addGlobalAddress(Func
);
872 // Placeholder for the type index.
874 // The table into which this call_indirect indexes.
875 MCSymbolWasm
*Table
= WebAssembly::getOrCreateFunctionTableSymbol(
876 MF
->getMMI().getContext(), Subtarget
);
877 if (Subtarget
->hasReferenceTypes()) {
880 // Otherwise for the MVP there is at most one table whose number is 0, but
881 // we can't write a table symbol or issue relocations. Instead we just
882 // ensure the table is live.
886 // See if we must truncate the function pointer.
887 // CALL_INDIRECT takes an i32, but in wasm64 we represent function pointers
888 // as 64-bit for uniformity with other pointer types.
889 // See also: WebAssemblyISelLowering.cpp: LowerCallResults
890 if (Subtarget
->hasAddr64()) {
891 auto Wrap
= BuildMI(*FuncInfo
.MBB
, std::prev(FuncInfo
.InsertPt
), DbgLoc
,
892 TII
.get(WebAssembly::I32_WRAP_I64
));
893 unsigned Reg32
= createResultReg(&WebAssembly::I32RegClass
);
894 Wrap
.addReg(Reg32
, RegState::Define
);
895 Wrap
.addReg(CalleeReg
);
900 for (unsigned ArgReg
: Args
)
904 MIB
.addReg(CalleeReg
);
907 updateValueMap(Call
, ResultReg
);
911 bool WebAssemblyFastISel::selectSelect(const Instruction
*I
) {
912 const auto *Select
= cast
<SelectInst
>(I
);
915 unsigned CondReg
= getRegForI1Value(Select
->getCondition(), Not
);
919 unsigned TrueReg
= getRegForValue(Select
->getTrueValue());
923 unsigned FalseReg
= getRegForValue(Select
->getFalseValue());
928 std::swap(TrueReg
, FalseReg
);
931 const TargetRegisterClass
*RC
;
932 switch (getSimpleType(Select
->getType())) {
937 Opc
= WebAssembly::SELECT_I32
;
938 RC
= &WebAssembly::I32RegClass
;
941 Opc
= WebAssembly::SELECT_I64
;
942 RC
= &WebAssembly::I64RegClass
;
945 Opc
= WebAssembly::SELECT_F32
;
946 RC
= &WebAssembly::F32RegClass
;
949 Opc
= WebAssembly::SELECT_F64
;
950 RC
= &WebAssembly::F64RegClass
;
953 Opc
= WebAssembly::SELECT_FUNCREF
;
954 RC
= &WebAssembly::FUNCREFRegClass
;
957 Opc
= WebAssembly::SELECT_EXTERNREF
;
958 RC
= &WebAssembly::EXTERNREFRegClass
;
964 unsigned ResultReg
= createResultReg(RC
);
965 BuildMI(*FuncInfo
.MBB
, FuncInfo
.InsertPt
, DbgLoc
, TII
.get(Opc
), ResultReg
)
970 updateValueMap(Select
, ResultReg
);
974 bool WebAssemblyFastISel::selectTrunc(const Instruction
*I
) {
975 const auto *Trunc
= cast
<TruncInst
>(I
);
977 unsigned Reg
= getRegForValue(Trunc
->getOperand(0));
981 if (Trunc
->getOperand(0)->getType()->isIntegerTy(64)) {
982 unsigned Result
= createResultReg(&WebAssembly::I32RegClass
);
983 BuildMI(*FuncInfo
.MBB
, FuncInfo
.InsertPt
, DbgLoc
,
984 TII
.get(WebAssembly::I32_WRAP_I64
), Result
)
989 updateValueMap(Trunc
, Reg
);
993 bool WebAssemblyFastISel::selectZExt(const Instruction
*I
) {
994 const auto *ZExt
= cast
<ZExtInst
>(I
);
996 const Value
*Op
= ZExt
->getOperand(0);
997 MVT::SimpleValueType From
= getSimpleType(Op
->getType());
998 MVT::SimpleValueType To
= getLegalType(getSimpleType(ZExt
->getType()));
999 unsigned In
= getRegForValue(Op
);
1002 unsigned Reg
= zeroExtend(In
, Op
, From
, To
);
1006 updateValueMap(ZExt
, Reg
);
1010 bool WebAssemblyFastISel::selectSExt(const Instruction
*I
) {
1011 const auto *SExt
= cast
<SExtInst
>(I
);
1013 const Value
*Op
= SExt
->getOperand(0);
1014 MVT::SimpleValueType From
= getSimpleType(Op
->getType());
1015 MVT::SimpleValueType To
= getLegalType(getSimpleType(SExt
->getType()));
1016 unsigned In
= getRegForValue(Op
);
1019 unsigned Reg
= signExtend(In
, Op
, From
, To
);
1023 updateValueMap(SExt
, Reg
);
1027 bool WebAssemblyFastISel::selectICmp(const Instruction
*I
) {
1028 const auto *ICmp
= cast
<ICmpInst
>(I
);
1030 bool I32
= getSimpleType(ICmp
->getOperand(0)->getType()) != MVT::i64
;
1032 bool IsSigned
= false;
1033 switch (ICmp
->getPredicate()) {
1034 case ICmpInst::ICMP_EQ
:
1035 Opc
= I32
? WebAssembly::EQ_I32
: WebAssembly::EQ_I64
;
1037 case ICmpInst::ICMP_NE
:
1038 Opc
= I32
? WebAssembly::NE_I32
: WebAssembly::NE_I64
;
1040 case ICmpInst::ICMP_UGT
:
1041 Opc
= I32
? WebAssembly::GT_U_I32
: WebAssembly::GT_U_I64
;
1043 case ICmpInst::ICMP_UGE
:
1044 Opc
= I32
? WebAssembly::GE_U_I32
: WebAssembly::GE_U_I64
;
1046 case ICmpInst::ICMP_ULT
:
1047 Opc
= I32
? WebAssembly::LT_U_I32
: WebAssembly::LT_U_I64
;
1049 case ICmpInst::ICMP_ULE
:
1050 Opc
= I32
? WebAssembly::LE_U_I32
: WebAssembly::LE_U_I64
;
1052 case ICmpInst::ICMP_SGT
:
1053 Opc
= I32
? WebAssembly::GT_S_I32
: WebAssembly::GT_S_I64
;
1056 case ICmpInst::ICMP_SGE
:
1057 Opc
= I32
? WebAssembly::GE_S_I32
: WebAssembly::GE_S_I64
;
1060 case ICmpInst::ICMP_SLT
:
1061 Opc
= I32
? WebAssembly::LT_S_I32
: WebAssembly::LT_S_I64
;
1064 case ICmpInst::ICMP_SLE
:
1065 Opc
= I32
? WebAssembly::LE_S_I32
: WebAssembly::LE_S_I64
;
1072 unsigned LHS
= getRegForPromotedValue(ICmp
->getOperand(0), IsSigned
);
1076 unsigned RHS
= getRegForPromotedValue(ICmp
->getOperand(1), IsSigned
);
1080 unsigned ResultReg
= createResultReg(&WebAssembly::I32RegClass
);
1081 BuildMI(*FuncInfo
.MBB
, FuncInfo
.InsertPt
, DbgLoc
, TII
.get(Opc
), ResultReg
)
1084 updateValueMap(ICmp
, ResultReg
);
1088 bool WebAssemblyFastISel::selectFCmp(const Instruction
*I
) {
1089 const auto *FCmp
= cast
<FCmpInst
>(I
);
1091 unsigned LHS
= getRegForValue(FCmp
->getOperand(0));
1095 unsigned RHS
= getRegForValue(FCmp
->getOperand(1));
1099 bool F32
= getSimpleType(FCmp
->getOperand(0)->getType()) != MVT::f64
;
1102 switch (FCmp
->getPredicate()) {
1103 case FCmpInst::FCMP_OEQ
:
1104 Opc
= F32
? WebAssembly::EQ_F32
: WebAssembly::EQ_F64
;
1106 case FCmpInst::FCMP_UNE
:
1107 Opc
= F32
? WebAssembly::NE_F32
: WebAssembly::NE_F64
;
1109 case FCmpInst::FCMP_OGT
:
1110 Opc
= F32
? WebAssembly::GT_F32
: WebAssembly::GT_F64
;
1112 case FCmpInst::FCMP_OGE
:
1113 Opc
= F32
? WebAssembly::GE_F32
: WebAssembly::GE_F64
;
1115 case FCmpInst::FCMP_OLT
:
1116 Opc
= F32
? WebAssembly::LT_F32
: WebAssembly::LT_F64
;
1118 case FCmpInst::FCMP_OLE
:
1119 Opc
= F32
? WebAssembly::LE_F32
: WebAssembly::LE_F64
;
1121 case FCmpInst::FCMP_UGT
:
1122 Opc
= F32
? WebAssembly::LE_F32
: WebAssembly::LE_F64
;
1125 case FCmpInst::FCMP_UGE
:
1126 Opc
= F32
? WebAssembly::LT_F32
: WebAssembly::LT_F64
;
1129 case FCmpInst::FCMP_ULT
:
1130 Opc
= F32
? WebAssembly::GE_F32
: WebAssembly::GE_F64
;
1133 case FCmpInst::FCMP_ULE
:
1134 Opc
= F32
? WebAssembly::GT_F32
: WebAssembly::GT_F64
;
1141 unsigned ResultReg
= createResultReg(&WebAssembly::I32RegClass
);
1142 BuildMI(*FuncInfo
.MBB
, FuncInfo
.InsertPt
, DbgLoc
, TII
.get(Opc
), ResultReg
)
1147 ResultReg
= notValue(ResultReg
);
1149 updateValueMap(FCmp
, ResultReg
);
1153 bool WebAssemblyFastISel::selectBitCast(const Instruction
*I
) {
1154 // Target-independent code can handle this, except it doesn't set the dead
1155 // flag on the ARGUMENTS clobber, so we have to do that manually in order
1156 // to satisfy code that expects this of isBitcast() instructions.
1157 EVT VT
= TLI
.getValueType(DL
, I
->getOperand(0)->getType());
1158 EVT RetVT
= TLI
.getValueType(DL
, I
->getType());
1159 if (!VT
.isSimple() || !RetVT
.isSimple())
1162 unsigned In
= getRegForValue(I
->getOperand(0));
1168 updateValueMap(I
, In
);
1172 Register Reg
= fastEmit_ISD_BITCAST_r(VT
.getSimpleVT(), RetVT
.getSimpleVT(),
1176 MachineBasicBlock::iterator Iter
= FuncInfo
.InsertPt
;
1178 assert(Iter
->isBitcast());
1179 Iter
->setPhysRegsDeadExcept(ArrayRef
<Register
>(), TRI
);
1180 updateValueMap(I
, Reg
);
1184 bool WebAssemblyFastISel::selectLoad(const Instruction
*I
) {
1185 const auto *Load
= cast
<LoadInst
>(I
);
1186 if (Load
->isAtomic())
1188 if (!WebAssembly::isDefaultAddressSpace(Load
->getPointerAddressSpace()))
1190 if (!Subtarget
->hasSIMD128() && Load
->getType()->isVectorTy())
1194 if (!computeAddress(Load
->getPointerOperand(), Addr
))
1197 // TODO: Fold a following sign-/zero-extend into the load instruction.
1200 const TargetRegisterClass
*RC
;
1201 bool A64
= Subtarget
->hasAddr64();
1202 switch (getSimpleType(Load
->getType())) {
1205 Opc
= A64
? WebAssembly::LOAD8_U_I32_A64
: WebAssembly::LOAD8_U_I32_A32
;
1206 RC
= &WebAssembly::I32RegClass
;
1209 Opc
= A64
? WebAssembly::LOAD16_U_I32_A64
: WebAssembly::LOAD16_U_I32_A32
;
1210 RC
= &WebAssembly::I32RegClass
;
1213 Opc
= A64
? WebAssembly::LOAD_I32_A64
: WebAssembly::LOAD_I32_A32
;
1214 RC
= &WebAssembly::I32RegClass
;
1217 Opc
= A64
? WebAssembly::LOAD_I64_A64
: WebAssembly::LOAD_I64_A32
;
1218 RC
= &WebAssembly::I64RegClass
;
1221 Opc
= A64
? WebAssembly::LOAD_F32_A64
: WebAssembly::LOAD_F32_A32
;
1222 RC
= &WebAssembly::F32RegClass
;
1225 Opc
= A64
? WebAssembly::LOAD_F64_A64
: WebAssembly::LOAD_F64_A32
;
1226 RC
= &WebAssembly::F64RegClass
;
1232 materializeLoadStoreOperands(Addr
);
1234 unsigned ResultReg
= createResultReg(RC
);
1235 auto MIB
= BuildMI(*FuncInfo
.MBB
, FuncInfo
.InsertPt
, DbgLoc
, TII
.get(Opc
),
1238 addLoadStoreOperands(Addr
, MIB
, createMachineMemOperandFor(Load
));
1240 updateValueMap(Load
, ResultReg
);
1244 bool WebAssemblyFastISel::selectStore(const Instruction
*I
) {
1245 const auto *Store
= cast
<StoreInst
>(I
);
1246 if (Store
->isAtomic())
1248 if (!WebAssembly::isDefaultAddressSpace(Store
->getPointerAddressSpace()))
1250 if (!Subtarget
->hasSIMD128() &&
1251 Store
->getValueOperand()->getType()->isVectorTy())
1255 if (!computeAddress(Store
->getPointerOperand(), Addr
))
1259 bool VTIsi1
= false;
1260 bool A64
= Subtarget
->hasAddr64();
1261 switch (getSimpleType(Store
->getValueOperand()->getType())) {
1266 Opc
= A64
? WebAssembly::STORE8_I32_A64
: WebAssembly::STORE8_I32_A32
;
1269 Opc
= A64
? WebAssembly::STORE16_I32_A64
: WebAssembly::STORE16_I32_A32
;
1272 Opc
= A64
? WebAssembly::STORE_I32_A64
: WebAssembly::STORE_I32_A32
;
1275 Opc
= A64
? WebAssembly::STORE_I64_A64
: WebAssembly::STORE_I64_A32
;
1278 Opc
= A64
? WebAssembly::STORE_F32_A64
: WebAssembly::STORE_F32_A32
;
1281 Opc
= A64
? WebAssembly::STORE_F64_A64
: WebAssembly::STORE_F64_A32
;
1287 materializeLoadStoreOperands(Addr
);
1289 unsigned ValueReg
= getRegForValue(Store
->getValueOperand());
1293 ValueReg
= maskI1Value(ValueReg
, Store
->getValueOperand());
1295 auto MIB
= BuildMI(*FuncInfo
.MBB
, FuncInfo
.InsertPt
, DbgLoc
, TII
.get(Opc
));
1297 addLoadStoreOperands(Addr
, MIB
, createMachineMemOperandFor(Store
));
1299 MIB
.addReg(ValueReg
);
1303 bool WebAssemblyFastISel::selectBr(const Instruction
*I
) {
1304 const auto *Br
= cast
<BranchInst
>(I
);
1305 if (Br
->isUnconditional()) {
1306 MachineBasicBlock
*MSucc
= FuncInfo
.MBBMap
[Br
->getSuccessor(0)];
1307 fastEmitBranch(MSucc
, Br
->getDebugLoc());
1311 MachineBasicBlock
*TBB
= FuncInfo
.MBBMap
[Br
->getSuccessor(0)];
1312 MachineBasicBlock
*FBB
= FuncInfo
.MBBMap
[Br
->getSuccessor(1)];
1315 unsigned CondReg
= getRegForI1Value(Br
->getCondition(), Not
);
1319 unsigned Opc
= WebAssembly::BR_IF
;
1321 Opc
= WebAssembly::BR_UNLESS
;
1323 BuildMI(*FuncInfo
.MBB
, FuncInfo
.InsertPt
, DbgLoc
, TII
.get(Opc
))
1327 finishCondBranch(Br
->getParent(), TBB
, FBB
);
1331 bool WebAssemblyFastISel::selectRet(const Instruction
*I
) {
1332 if (!FuncInfo
.CanLowerReturn
)
1335 const auto *Ret
= cast
<ReturnInst
>(I
);
1337 if (Ret
->getNumOperands() == 0) {
1338 BuildMI(*FuncInfo
.MBB
, FuncInfo
.InsertPt
, DbgLoc
,
1339 TII
.get(WebAssembly::RETURN
));
1343 // TODO: support multiple return in FastISel
1344 if (Ret
->getNumOperands() > 1)
1347 Value
*RV
= Ret
->getOperand(0);
1348 if (!Subtarget
->hasSIMD128() && RV
->getType()->isVectorTy())
1351 switch (getSimpleType(RV
->getType())) {
1366 case MVT::externref
:
1373 if (FuncInfo
.Fn
->getAttributes().hasRetAttr(Attribute::SExt
))
1374 Reg
= getRegForSignedValue(RV
);
1375 else if (FuncInfo
.Fn
->getAttributes().hasRetAttr(Attribute::ZExt
))
1376 Reg
= getRegForUnsignedValue(RV
);
1378 Reg
= getRegForValue(RV
);
1383 BuildMI(*FuncInfo
.MBB
, FuncInfo
.InsertPt
, DbgLoc
,
1384 TII
.get(WebAssembly::RETURN
))
1389 bool WebAssemblyFastISel::selectUnreachable(const Instruction
*I
) {
1390 BuildMI(*FuncInfo
.MBB
, FuncInfo
.InsertPt
, DbgLoc
,
1391 TII
.get(WebAssembly::UNREACHABLE
));
1395 bool WebAssemblyFastISel::fastSelectInstruction(const Instruction
*I
) {
1396 switch (I
->getOpcode()) {
1397 case Instruction::Call
:
1401 case Instruction::Select
:
1402 return selectSelect(I
);
1403 case Instruction::Trunc
:
1404 return selectTrunc(I
);
1405 case Instruction::ZExt
:
1406 return selectZExt(I
);
1407 case Instruction::SExt
:
1408 return selectSExt(I
);
1409 case Instruction::ICmp
:
1410 return selectICmp(I
);
1411 case Instruction::FCmp
:
1412 return selectFCmp(I
);
1413 case Instruction::BitCast
:
1414 return selectBitCast(I
);
1415 case Instruction::Load
:
1416 return selectLoad(I
);
1417 case Instruction::Store
:
1418 return selectStore(I
);
1419 case Instruction::Br
:
1421 case Instruction::Ret
:
1422 return selectRet(I
);
1423 case Instruction::Unreachable
:
1424 return selectUnreachable(I
);
1429 // Fall back to target-independent instruction selection.
1430 return selectOperator(I
, I
->getOpcode());
1433 FastISel
*WebAssembly::createFastISel(FunctionLoweringInfo
&FuncInfo
,
1434 const TargetLibraryInfo
*LibInfo
) {
1435 return new WebAssemblyFastISel(FuncInfo
, LibInfo
);