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 "WebAssembly.h"
20 #include "WebAssemblyMachineFunctionInfo.h"
21 #include "WebAssemblySubtarget.h"
22 #include "WebAssemblyTargetMachine.h"
23 #include "llvm/Analysis/BranchProbabilityInfo.h"
24 #include "llvm/CodeGen/FastISel.h"
25 #include "llvm/CodeGen/FunctionLoweringInfo.h"
26 #include "llvm/CodeGen/MachineConstantPool.h"
27 #include "llvm/CodeGen/MachineFrameInfo.h"
28 #include "llvm/CodeGen/MachineInstrBuilder.h"
29 #include "llvm/CodeGen/MachineRegisterInfo.h"
30 #include "llvm/IR/DataLayout.h"
31 #include "llvm/IR/DerivedTypes.h"
32 #include "llvm/IR/Function.h"
33 #include "llvm/IR/GetElementPtrTypeIterator.h"
34 #include "llvm/IR/GlobalAlias.h"
35 #include "llvm/IR/GlobalVariable.h"
36 #include "llvm/IR/Instructions.h"
37 #include "llvm/IR/IntrinsicInst.h"
38 #include "llvm/IR/Operator.h"
39 #include "llvm/IR/PatternMatch.h"
42 using namespace PatternMatch
;
44 #define DEBUG_TYPE "wasm-fastisel"
48 class WebAssemblyFastISel final
: public FastISel
{
49 // All possible address modes.
52 using BaseKind
= enum { RegBase
, FrameIndexBase
};
55 BaseKind Kind
= RegBase
;
63 const GlobalValue
*GV
= nullptr;
66 // Innocuous defaults for our address.
67 Address() { Base
.Reg
= 0; }
68 void setKind(BaseKind K
) {
69 assert(!isSet() && "Can't change kind with non-zero base");
72 BaseKind
getKind() const { return Kind
; }
73 bool isRegBase() const { return Kind
== RegBase
; }
74 bool isFIBase() const { return Kind
== FrameIndexBase
; }
75 void setReg(unsigned Reg
) {
76 assert(isRegBase() && "Invalid base register access!");
77 assert(Base
.Reg
== 0 && "Overwriting non-zero register");
80 unsigned getReg() const {
81 assert(isRegBase() && "Invalid base register access!");
84 void setFI(unsigned FI
) {
85 assert(isFIBase() && "Invalid base frame index access!");
86 assert(Base
.FI
== 0 && "Overwriting non-zero frame index");
89 unsigned getFI() const {
90 assert(isFIBase() && "Invalid base frame index access!");
94 void setOffset(int64_t NewOffset
) {
95 assert(NewOffset
>= 0 && "Offsets must be non-negative");
98 int64_t getOffset() const { return Offset
; }
99 void setGlobalValue(const GlobalValue
*G
) { GV
= G
; }
100 const GlobalValue
*getGlobalValue() const { return GV
; }
103 return Base
.Reg
!= 0;
110 /// Keep a pointer to the WebAssemblySubtarget around so that we can make the
111 /// right decision when generating code for different targets.
112 const WebAssemblySubtarget
*Subtarget
;
113 LLVMContext
*Context
;
116 // Utility helper routines
117 MVT::SimpleValueType
getSimpleType(Type
*Ty
) {
118 EVT VT
= TLI
.getValueType(DL
, Ty
, /*AllowUnknown=*/true);
119 return VT
.isSimple() ? VT
.getSimpleVT().SimpleTy
120 : MVT::INVALID_SIMPLE_VALUE_TYPE
;
122 MVT::SimpleValueType
getLegalType(MVT::SimpleValueType VT
) {
140 if (Subtarget
->hasSIMD128())
145 if (Subtarget
->hasUnimplementedSIMD128())
151 return MVT::INVALID_SIMPLE_VALUE_TYPE
;
153 bool computeAddress(const Value
*Obj
, Address
&Addr
);
154 void materializeLoadStoreOperands(Address
&Addr
);
155 void addLoadStoreOperands(const Address
&Addr
, const MachineInstrBuilder
&MIB
,
156 MachineMemOperand
*MMO
);
157 unsigned maskI1Value(unsigned Reg
, const Value
*V
);
158 unsigned getRegForI1Value(const Value
*V
, bool &Not
);
159 unsigned zeroExtendToI32(unsigned Reg
, const Value
*V
,
160 MVT::SimpleValueType From
);
161 unsigned signExtendToI32(unsigned Reg
, const Value
*V
,
162 MVT::SimpleValueType From
);
163 unsigned zeroExtend(unsigned Reg
, const Value
*V
, MVT::SimpleValueType From
,
164 MVT::SimpleValueType To
);
165 unsigned signExtend(unsigned Reg
, const Value
*V
, MVT::SimpleValueType From
,
166 MVT::SimpleValueType To
);
167 unsigned getRegForUnsignedValue(const Value
*V
);
168 unsigned getRegForSignedValue(const Value
*V
);
169 unsigned getRegForPromotedValue(const Value
*V
, bool IsSigned
);
170 unsigned notValue(unsigned Reg
);
171 unsigned copyValue(unsigned Reg
);
173 // Backend specific FastISel code.
174 unsigned fastMaterializeAlloca(const AllocaInst
*AI
) override
;
175 unsigned fastMaterializeConstant(const Constant
*C
) override
;
176 bool fastLowerArguments() override
;
178 // Selection routines.
179 bool selectCall(const Instruction
*I
);
180 bool selectSelect(const Instruction
*I
);
181 bool selectTrunc(const Instruction
*I
);
182 bool selectZExt(const Instruction
*I
);
183 bool selectSExt(const Instruction
*I
);
184 bool selectICmp(const Instruction
*I
);
185 bool selectFCmp(const Instruction
*I
);
186 bool selectBitCast(const Instruction
*I
);
187 bool selectLoad(const Instruction
*I
);
188 bool selectStore(const Instruction
*I
);
189 bool selectBr(const Instruction
*I
);
190 bool selectRet(const Instruction
*I
);
191 bool selectUnreachable(const Instruction
*I
);
194 // Backend specific FastISel code.
195 WebAssemblyFastISel(FunctionLoweringInfo
&FuncInfo
,
196 const TargetLibraryInfo
*LibInfo
)
197 : FastISel(FuncInfo
, LibInfo
, /*SkipTargetIndependentISel=*/true) {
198 Subtarget
= &FuncInfo
.MF
->getSubtarget
<WebAssemblySubtarget
>();
199 Context
= &FuncInfo
.Fn
->getContext();
202 bool fastSelectInstruction(const Instruction
*I
) override
;
204 #include "WebAssemblyGenFastISel.inc"
207 } // end anonymous namespace
209 bool WebAssemblyFastISel::computeAddress(const Value
*Obj
, Address
&Addr
) {
210 const User
*U
= nullptr;
211 unsigned Opcode
= Instruction::UserOp1
;
212 if (const auto *I
= dyn_cast
<Instruction
>(Obj
)) {
213 // Don't walk into other basic blocks unless the object is an alloca from
214 // another block, otherwise it may not have a virtual register assigned.
215 if (FuncInfo
.StaticAllocaMap
.count(static_cast<const AllocaInst
*>(Obj
)) ||
216 FuncInfo
.MBBMap
[I
->getParent()] == FuncInfo
.MBB
) {
217 Opcode
= I
->getOpcode();
220 } else if (const auto *C
= dyn_cast
<ConstantExpr
>(Obj
)) {
221 Opcode
= C
->getOpcode();
225 if (auto *Ty
= dyn_cast
<PointerType
>(Obj
->getType()))
226 if (Ty
->getAddressSpace() > 255)
227 // Fast instruction selection doesn't support the special
231 if (const auto *GV
= dyn_cast
<GlobalValue
>(Obj
)) {
232 if (TLI
.isPositionIndependent())
234 if (Addr
.getGlobalValue())
236 if (GV
->isThreadLocal())
238 Addr
.setGlobalValue(GV
);
245 case Instruction::BitCast
: {
246 // Look through bitcasts.
247 return computeAddress(U
->getOperand(0), Addr
);
249 case Instruction::IntToPtr
: {
250 // Look past no-op inttoptrs.
251 if (TLI
.getValueType(DL
, U
->getOperand(0)->getType()) ==
252 TLI
.getPointerTy(DL
))
253 return computeAddress(U
->getOperand(0), Addr
);
256 case Instruction::PtrToInt
: {
257 // Look past no-op ptrtoints.
258 if (TLI
.getValueType(DL
, U
->getType()) == TLI
.getPointerTy(DL
))
259 return computeAddress(U
->getOperand(0), Addr
);
262 case Instruction::GetElementPtr
: {
263 Address SavedAddr
= Addr
;
264 uint64_t TmpOffset
= Addr
.getOffset();
265 // Non-inbounds geps can wrap; wasm's offsets can't.
266 if (!cast
<GEPOperator
>(U
)->isInBounds())
267 goto unsupported_gep
;
268 // Iterate through the GEP folding the constants into offsets where
270 for (gep_type_iterator GTI
= gep_type_begin(U
), E
= gep_type_end(U
);
272 const Value
*Op
= GTI
.getOperand();
273 if (StructType
*STy
= GTI
.getStructTypeOrNull()) {
274 const StructLayout
*SL
= DL
.getStructLayout(STy
);
275 unsigned Idx
= cast
<ConstantInt
>(Op
)->getZExtValue();
276 TmpOffset
+= SL
->getElementOffset(Idx
);
278 uint64_t S
= DL
.getTypeAllocSize(GTI
.getIndexedType());
280 if (const auto *CI
= dyn_cast
<ConstantInt
>(Op
)) {
281 // Constant-offset addressing.
282 TmpOffset
+= CI
->getSExtValue() * S
;
285 if (S
== 1 && Addr
.isRegBase() && Addr
.getReg() == 0) {
286 // An unscaled add of a register. Set it as the new base.
287 unsigned Reg
= getRegForValue(Op
);
293 if (canFoldAddIntoGEP(U
, Op
)) {
294 // A compatible add with a constant operand. Fold the constant.
295 auto *CI
= cast
<ConstantInt
>(cast
<AddOperator
>(Op
)->getOperand(1));
296 TmpOffset
+= CI
->getSExtValue() * S
;
297 // Iterate on the other operand.
298 Op
= cast
<AddOperator
>(Op
)->getOperand(0);
302 goto unsupported_gep
;
306 // Don't fold in negative offsets.
307 if (int64_t(TmpOffset
) >= 0) {
308 // Try to grab the base operand now.
309 Addr
.setOffset(TmpOffset
);
310 if (computeAddress(U
->getOperand(0), Addr
))
313 // We failed, restore everything and try the other options.
318 case Instruction::Alloca
: {
319 const auto *AI
= cast
<AllocaInst
>(Obj
);
320 DenseMap
<const AllocaInst
*, int>::iterator SI
=
321 FuncInfo
.StaticAllocaMap
.find(AI
);
322 if (SI
!= FuncInfo
.StaticAllocaMap
.end()) {
326 Addr
.setKind(Address::FrameIndexBase
);
327 Addr
.setFI(SI
->second
);
332 case Instruction::Add
: {
333 // Adds of constants are common and easy enough.
334 const Value
*LHS
= U
->getOperand(0);
335 const Value
*RHS
= U
->getOperand(1);
337 if (isa
<ConstantInt
>(LHS
))
340 if (const auto *CI
= dyn_cast
<ConstantInt
>(RHS
)) {
341 uint64_t TmpOffset
= Addr
.getOffset() + CI
->getSExtValue();
342 if (int64_t(TmpOffset
) >= 0) {
343 Addr
.setOffset(TmpOffset
);
344 return computeAddress(LHS
, Addr
);
348 Address Backup
= Addr
;
349 if (computeAddress(LHS
, Addr
) && computeAddress(RHS
, Addr
))
355 case Instruction::Sub
: {
356 // Subs of constants are common and easy enough.
357 const Value
*LHS
= U
->getOperand(0);
358 const Value
*RHS
= U
->getOperand(1);
360 if (const auto *CI
= dyn_cast
<ConstantInt
>(RHS
)) {
361 int64_t TmpOffset
= Addr
.getOffset() - CI
->getSExtValue();
362 if (TmpOffset
>= 0) {
363 Addr
.setOffset(TmpOffset
);
364 return computeAddress(LHS
, Addr
);
373 unsigned Reg
= getRegForValue(Obj
);
377 return Addr
.getReg() != 0;
380 void WebAssemblyFastISel::materializeLoadStoreOperands(Address
&Addr
) {
381 if (Addr
.isRegBase()) {
382 unsigned Reg
= Addr
.getReg();
384 Reg
= createResultReg(Subtarget
->hasAddr64() ? &WebAssembly::I64RegClass
385 : &WebAssembly::I32RegClass
);
386 unsigned Opc
= Subtarget
->hasAddr64() ? WebAssembly::CONST_I64
387 : WebAssembly::CONST_I32
;
388 BuildMI(*FuncInfo
.MBB
, FuncInfo
.InsertPt
, DbgLoc
, TII
.get(Opc
), Reg
)
395 void WebAssemblyFastISel::addLoadStoreOperands(const Address
&Addr
,
396 const MachineInstrBuilder
&MIB
,
397 MachineMemOperand
*MMO
) {
398 // Set the alignment operand (this is rewritten in SetP2AlignOperands).
399 // TODO: Disable SetP2AlignOperands for FastISel and just do it here.
402 if (const GlobalValue
*GV
= Addr
.getGlobalValue())
403 MIB
.addGlobalAddress(GV
, Addr
.getOffset());
405 MIB
.addImm(Addr
.getOffset());
407 if (Addr
.isRegBase())
408 MIB
.addReg(Addr
.getReg());
410 MIB
.addFrameIndex(Addr
.getFI());
412 MIB
.addMemOperand(MMO
);
415 unsigned WebAssemblyFastISel::maskI1Value(unsigned Reg
, const Value
*V
) {
416 return zeroExtendToI32(Reg
, V
, MVT::i1
);
419 unsigned WebAssemblyFastISel::getRegForI1Value(const Value
*V
, bool &Not
) {
420 if (const auto *ICmp
= dyn_cast
<ICmpInst
>(V
))
421 if (const ConstantInt
*C
= dyn_cast
<ConstantInt
>(ICmp
->getOperand(1)))
422 if (ICmp
->isEquality() && C
->isZero() && C
->getType()->isIntegerTy(32)) {
423 Not
= ICmp
->isTrueWhenEqual();
424 return getRegForValue(ICmp
->getOperand(0));
428 if (match(V
, m_Not(m_Value(NotV
))) && V
->getType()->isIntegerTy(32)) {
430 return getRegForValue(NotV
);
434 unsigned Reg
= getRegForValue(V
);
437 return maskI1Value(Reg
, V
);
440 unsigned WebAssemblyFastISel::zeroExtendToI32(unsigned Reg
, const Value
*V
,
441 MVT::SimpleValueType From
) {
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
);
457 return copyValue(Reg
);
462 unsigned Imm
= createResultReg(&WebAssembly::I32RegClass
);
463 BuildMI(*FuncInfo
.MBB
, FuncInfo
.InsertPt
, DbgLoc
,
464 TII
.get(WebAssembly::CONST_I32
), Imm
)
465 .addImm(~(~uint64_t(0) << MVT(From
).getSizeInBits()));
467 unsigned Result
= createResultReg(&WebAssembly::I32RegClass
);
468 BuildMI(*FuncInfo
.MBB
, FuncInfo
.InsertPt
, DbgLoc
,
469 TII
.get(WebAssembly::AND_I32
), Result
)
476 unsigned WebAssemblyFastISel::signExtendToI32(unsigned Reg
, const Value
*V
,
477 MVT::SimpleValueType From
) {
487 return copyValue(Reg
);
492 unsigned Imm
= createResultReg(&WebAssembly::I32RegClass
);
493 BuildMI(*FuncInfo
.MBB
, FuncInfo
.InsertPt
, DbgLoc
,
494 TII
.get(WebAssembly::CONST_I32
), Imm
)
495 .addImm(32 - MVT(From
).getSizeInBits());
497 unsigned Left
= createResultReg(&WebAssembly::I32RegClass
);
498 BuildMI(*FuncInfo
.MBB
, FuncInfo
.InsertPt
, DbgLoc
,
499 TII
.get(WebAssembly::SHL_I32
), Left
)
503 unsigned Right
= createResultReg(&WebAssembly::I32RegClass
);
504 BuildMI(*FuncInfo
.MBB
, FuncInfo
.InsertPt
, DbgLoc
,
505 TII
.get(WebAssembly::SHR_S_I32
), Right
)
512 unsigned WebAssemblyFastISel::zeroExtend(unsigned Reg
, const Value
*V
,
513 MVT::SimpleValueType From
,
514 MVT::SimpleValueType To
) {
515 if (To
== MVT::i64
) {
516 if (From
== MVT::i64
)
517 return copyValue(Reg
);
519 Reg
= zeroExtendToI32(Reg
, V
, From
);
521 unsigned Result
= createResultReg(&WebAssembly::I64RegClass
);
522 BuildMI(*FuncInfo
.MBB
, FuncInfo
.InsertPt
, DbgLoc
,
523 TII
.get(WebAssembly::I64_EXTEND_U_I32
), Result
)
529 return zeroExtendToI32(Reg
, V
, From
);
534 unsigned WebAssemblyFastISel::signExtend(unsigned Reg
, const Value
*V
,
535 MVT::SimpleValueType From
,
536 MVT::SimpleValueType To
) {
537 if (To
== MVT::i64
) {
538 if (From
== MVT::i64
)
539 return copyValue(Reg
);
541 Reg
= signExtendToI32(Reg
, V
, From
);
543 unsigned Result
= createResultReg(&WebAssembly::I64RegClass
);
544 BuildMI(*FuncInfo
.MBB
, FuncInfo
.InsertPt
, DbgLoc
,
545 TII
.get(WebAssembly::I64_EXTEND_S_I32
), Result
)
551 return signExtendToI32(Reg
, V
, From
);
556 unsigned WebAssemblyFastISel::getRegForUnsignedValue(const Value
*V
) {
557 MVT::SimpleValueType From
= getSimpleType(V
->getType());
558 MVT::SimpleValueType To
= getLegalType(From
);
559 unsigned VReg
= getRegForValue(V
);
562 return zeroExtend(VReg
, V
, From
, To
);
565 unsigned WebAssemblyFastISel::getRegForSignedValue(const Value
*V
) {
566 MVT::SimpleValueType From
= getSimpleType(V
->getType());
567 MVT::SimpleValueType To
= getLegalType(From
);
568 unsigned VReg
= getRegForValue(V
);
571 return signExtend(VReg
, V
, From
, To
);
574 unsigned WebAssemblyFastISel::getRegForPromotedValue(const Value
*V
,
576 return IsSigned
? getRegForSignedValue(V
) : getRegForUnsignedValue(V
);
579 unsigned WebAssemblyFastISel::notValue(unsigned Reg
) {
580 assert(MRI
.getRegClass(Reg
) == &WebAssembly::I32RegClass
);
582 unsigned NotReg
= createResultReg(&WebAssembly::I32RegClass
);
583 BuildMI(*FuncInfo
.MBB
, FuncInfo
.InsertPt
, DbgLoc
,
584 TII
.get(WebAssembly::EQZ_I32
), NotReg
)
589 unsigned WebAssemblyFastISel::copyValue(unsigned Reg
) {
590 unsigned ResultReg
= createResultReg(MRI
.getRegClass(Reg
));
591 BuildMI(*FuncInfo
.MBB
, FuncInfo
.InsertPt
, DbgLoc
, TII
.get(WebAssembly::COPY
),
597 unsigned WebAssemblyFastISel::fastMaterializeAlloca(const AllocaInst
*AI
) {
598 DenseMap
<const AllocaInst
*, int>::iterator SI
=
599 FuncInfo
.StaticAllocaMap
.find(AI
);
601 if (SI
!= FuncInfo
.StaticAllocaMap
.end()) {
603 createResultReg(Subtarget
->hasAddr64() ? &WebAssembly::I64RegClass
604 : &WebAssembly::I32RegClass
);
606 Subtarget
->hasAddr64() ? WebAssembly::COPY_I64
: WebAssembly::COPY_I32
;
607 BuildMI(*FuncInfo
.MBB
, FuncInfo
.InsertPt
, DbgLoc
, TII
.get(Opc
), ResultReg
)
608 .addFrameIndex(SI
->second
);
615 unsigned WebAssemblyFastISel::fastMaterializeConstant(const Constant
*C
) {
616 if (const GlobalValue
*GV
= dyn_cast
<GlobalValue
>(C
)) {
617 if (TLI
.isPositionIndependent())
619 if (GV
->isThreadLocal())
622 createResultReg(Subtarget
->hasAddr64() ? &WebAssembly::I64RegClass
623 : &WebAssembly::I32RegClass
);
624 unsigned Opc
= Subtarget
->hasAddr64() ? WebAssembly::CONST_I64
625 : WebAssembly::CONST_I32
;
626 BuildMI(*FuncInfo
.MBB
, FuncInfo
.InsertPt
, DbgLoc
, TII
.get(Opc
), ResultReg
)
627 .addGlobalAddress(GV
);
631 // Let target-independent code handle it.
635 bool WebAssemblyFastISel::fastLowerArguments() {
636 if (!FuncInfo
.CanLowerReturn
)
639 const Function
*F
= FuncInfo
.Fn
;
644 for (auto const &Arg
: F
->args()) {
645 const AttributeList
&Attrs
= F
->getAttributes();
646 if (Attrs
.hasParamAttribute(I
, Attribute::ByVal
) ||
647 Attrs
.hasParamAttribute(I
, Attribute::SwiftSelf
) ||
648 Attrs
.hasParamAttribute(I
, Attribute::SwiftError
) ||
649 Attrs
.hasParamAttribute(I
, Attribute::InAlloca
) ||
650 Attrs
.hasParamAttribute(I
, Attribute::Nest
))
653 Type
*ArgTy
= Arg
.getType();
654 if (ArgTy
->isStructTy() || ArgTy
->isArrayTy())
656 if (!Subtarget
->hasSIMD128() && ArgTy
->isVectorTy())
660 const TargetRegisterClass
*RC
;
661 switch (getSimpleType(ArgTy
)) {
666 Opc
= WebAssembly::ARGUMENT_i32
;
667 RC
= &WebAssembly::I32RegClass
;
670 Opc
= WebAssembly::ARGUMENT_i64
;
671 RC
= &WebAssembly::I64RegClass
;
674 Opc
= WebAssembly::ARGUMENT_f32
;
675 RC
= &WebAssembly::F32RegClass
;
678 Opc
= WebAssembly::ARGUMENT_f64
;
679 RC
= &WebAssembly::F64RegClass
;
682 Opc
= WebAssembly::ARGUMENT_v16i8
;
683 RC
= &WebAssembly::V128RegClass
;
686 Opc
= WebAssembly::ARGUMENT_v8i16
;
687 RC
= &WebAssembly::V128RegClass
;
690 Opc
= WebAssembly::ARGUMENT_v4i32
;
691 RC
= &WebAssembly::V128RegClass
;
694 Opc
= WebAssembly::ARGUMENT_v2i64
;
695 RC
= &WebAssembly::V128RegClass
;
698 Opc
= WebAssembly::ARGUMENT_v4f32
;
699 RC
= &WebAssembly::V128RegClass
;
702 Opc
= WebAssembly::ARGUMENT_v2f64
;
703 RC
= &WebAssembly::V128RegClass
;
706 Opc
= WebAssembly::ARGUMENT_exnref
;
707 RC
= &WebAssembly::EXNREFRegClass
;
712 unsigned ResultReg
= createResultReg(RC
);
713 BuildMI(*FuncInfo
.MBB
, FuncInfo
.InsertPt
, DbgLoc
, TII
.get(Opc
), ResultReg
)
715 updateValueMap(&Arg
, ResultReg
);
720 MRI
.addLiveIn(WebAssembly::ARGUMENTS
);
722 auto *MFI
= MF
->getInfo
<WebAssemblyFunctionInfo
>();
723 for (auto const &Arg
: F
->args()) {
724 MVT::SimpleValueType ArgTy
= getLegalType(getSimpleType(Arg
.getType()));
725 if (ArgTy
== MVT::INVALID_SIMPLE_VALUE_TYPE
) {
726 MFI
->clearParamsAndResults();
729 MFI
->addParam(ArgTy
);
732 if (!F
->getReturnType()->isVoidTy()) {
733 MVT::SimpleValueType RetTy
=
734 getLegalType(getSimpleType(F
->getReturnType()));
735 if (RetTy
== MVT::INVALID_SIMPLE_VALUE_TYPE
) {
736 MFI
->clearParamsAndResults();
739 MFI
->addResult(RetTy
);
745 bool WebAssemblyFastISel::selectCall(const Instruction
*I
) {
746 const auto *Call
= cast
<CallInst
>(I
);
748 // TODO: Support tail calls in FastISel
749 if (Call
->isMustTailCall() || Call
->isInlineAsm() ||
750 Call
->getFunctionType()->isVarArg())
753 Function
*Func
= Call
->getCalledFunction();
754 if (Func
&& Func
->isIntrinsic())
757 bool IsDirect
= Func
!= nullptr;
758 if (!IsDirect
&& isa
<ConstantExpr
>(Call
->getCalledValue()))
761 FunctionType
*FuncTy
= Call
->getFunctionType();
763 bool IsVoid
= FuncTy
->getReturnType()->isVoidTy();
766 Opc
= IsDirect
? WebAssembly::CALL_VOID
: WebAssembly::PCALL_INDIRECT_VOID
;
768 if (!Subtarget
->hasSIMD128() && Call
->getType()->isVectorTy())
771 MVT::SimpleValueType RetTy
= getSimpleType(Call
->getType());
777 Opc
= IsDirect
? WebAssembly::CALL_i32
: WebAssembly::PCALL_INDIRECT_i32
;
778 ResultReg
= createResultReg(&WebAssembly::I32RegClass
);
781 Opc
= IsDirect
? WebAssembly::CALL_i64
: WebAssembly::PCALL_INDIRECT_i64
;
782 ResultReg
= createResultReg(&WebAssembly::I64RegClass
);
785 Opc
= IsDirect
? WebAssembly::CALL_f32
: WebAssembly::PCALL_INDIRECT_f32
;
786 ResultReg
= createResultReg(&WebAssembly::F32RegClass
);
789 Opc
= IsDirect
? WebAssembly::CALL_f64
: WebAssembly::PCALL_INDIRECT_f64
;
790 ResultReg
= createResultReg(&WebAssembly::F64RegClass
);
793 Opc
= IsDirect
? WebAssembly::CALL_v16i8
794 : WebAssembly::PCALL_INDIRECT_v16i8
;
795 ResultReg
= createResultReg(&WebAssembly::V128RegClass
);
798 Opc
= IsDirect
? WebAssembly::CALL_v8i16
799 : WebAssembly::PCALL_INDIRECT_v8i16
;
800 ResultReg
= createResultReg(&WebAssembly::V128RegClass
);
803 Opc
= IsDirect
? WebAssembly::CALL_v4i32
804 : WebAssembly::PCALL_INDIRECT_v4i32
;
805 ResultReg
= createResultReg(&WebAssembly::V128RegClass
);
808 Opc
= IsDirect
? WebAssembly::CALL_v2i64
809 : WebAssembly::PCALL_INDIRECT_v2i64
;
810 ResultReg
= createResultReg(&WebAssembly::V128RegClass
);
813 Opc
= IsDirect
? WebAssembly::CALL_v4f32
814 : WebAssembly::PCALL_INDIRECT_v4f32
;
815 ResultReg
= createResultReg(&WebAssembly::V128RegClass
);
818 Opc
= IsDirect
? WebAssembly::CALL_v2f64
819 : WebAssembly::PCALL_INDIRECT_v2f64
;
820 ResultReg
= createResultReg(&WebAssembly::V128RegClass
);
823 Opc
= IsDirect
? WebAssembly::CALL_exnref
824 : WebAssembly::PCALL_INDIRECT_exnref
;
825 ResultReg
= createResultReg(&WebAssembly::EXNREFRegClass
);
832 SmallVector
<unsigned, 8> Args
;
833 for (unsigned I
= 0, E
= Call
->getNumArgOperands(); I
< E
; ++I
) {
834 Value
*V
= Call
->getArgOperand(I
);
835 MVT::SimpleValueType ArgTy
= getSimpleType(V
->getType());
836 if (ArgTy
== MVT::INVALID_SIMPLE_VALUE_TYPE
)
839 const AttributeList
&Attrs
= Call
->getAttributes();
840 if (Attrs
.hasParamAttribute(I
, Attribute::ByVal
) ||
841 Attrs
.hasParamAttribute(I
, Attribute::SwiftSelf
) ||
842 Attrs
.hasParamAttribute(I
, Attribute::SwiftError
) ||
843 Attrs
.hasParamAttribute(I
, Attribute::InAlloca
) ||
844 Attrs
.hasParamAttribute(I
, Attribute::Nest
))
849 if (Attrs
.hasParamAttribute(I
, Attribute::SExt
))
850 Reg
= getRegForSignedValue(V
);
851 else if (Attrs
.hasParamAttribute(I
, Attribute::ZExt
))
852 Reg
= getRegForUnsignedValue(V
);
854 Reg
= getRegForValue(V
);
862 unsigned CalleeReg
= 0;
864 CalleeReg
= getRegForValue(Call
->getCalledValue());
869 auto MIB
= BuildMI(*FuncInfo
.MBB
, FuncInfo
.InsertPt
, DbgLoc
, TII
.get(Opc
));
872 MIB
.addReg(ResultReg
, RegState::Define
);
875 MIB
.addGlobalAddress(Func
);
877 MIB
.addReg(CalleeReg
);
879 for (unsigned ArgReg
: Args
)
883 updateValueMap(Call
, ResultReg
);
887 bool WebAssemblyFastISel::selectSelect(const Instruction
*I
) {
888 const auto *Select
= cast
<SelectInst
>(I
);
891 unsigned CondReg
= getRegForI1Value(Select
->getCondition(), Not
);
895 unsigned TrueReg
= getRegForValue(Select
->getTrueValue());
899 unsigned FalseReg
= getRegForValue(Select
->getFalseValue());
904 std::swap(TrueReg
, FalseReg
);
907 const TargetRegisterClass
*RC
;
908 switch (getSimpleType(Select
->getType())) {
913 Opc
= WebAssembly::SELECT_I32
;
914 RC
= &WebAssembly::I32RegClass
;
917 Opc
= WebAssembly::SELECT_I64
;
918 RC
= &WebAssembly::I64RegClass
;
921 Opc
= WebAssembly::SELECT_F32
;
922 RC
= &WebAssembly::F32RegClass
;
925 Opc
= WebAssembly::SELECT_F64
;
926 RC
= &WebAssembly::F64RegClass
;
929 Opc
= WebAssembly::SELECT_EXNREF
;
930 RC
= &WebAssembly::EXNREFRegClass
;
936 unsigned ResultReg
= createResultReg(RC
);
937 BuildMI(*FuncInfo
.MBB
, FuncInfo
.InsertPt
, DbgLoc
, TII
.get(Opc
), ResultReg
)
942 updateValueMap(Select
, ResultReg
);
946 bool WebAssemblyFastISel::selectTrunc(const Instruction
*I
) {
947 const auto *Trunc
= cast
<TruncInst
>(I
);
949 unsigned Reg
= getRegForValue(Trunc
->getOperand(0));
953 if (Trunc
->getOperand(0)->getType()->isIntegerTy(64)) {
954 unsigned Result
= createResultReg(&WebAssembly::I32RegClass
);
955 BuildMI(*FuncInfo
.MBB
, FuncInfo
.InsertPt
, DbgLoc
,
956 TII
.get(WebAssembly::I32_WRAP_I64
), Result
)
961 updateValueMap(Trunc
, Reg
);
965 bool WebAssemblyFastISel::selectZExt(const Instruction
*I
) {
966 const auto *ZExt
= cast
<ZExtInst
>(I
);
968 const Value
*Op
= ZExt
->getOperand(0);
969 MVT::SimpleValueType From
= getSimpleType(Op
->getType());
970 MVT::SimpleValueType To
= getLegalType(getSimpleType(ZExt
->getType()));
971 unsigned In
= getRegForValue(Op
);
974 unsigned Reg
= zeroExtend(In
, Op
, From
, To
);
978 updateValueMap(ZExt
, Reg
);
982 bool WebAssemblyFastISel::selectSExt(const Instruction
*I
) {
983 const auto *SExt
= cast
<SExtInst
>(I
);
985 const Value
*Op
= SExt
->getOperand(0);
986 MVT::SimpleValueType From
= getSimpleType(Op
->getType());
987 MVT::SimpleValueType To
= getLegalType(getSimpleType(SExt
->getType()));
988 unsigned In
= getRegForValue(Op
);
991 unsigned Reg
= signExtend(In
, Op
, From
, To
);
995 updateValueMap(SExt
, Reg
);
999 bool WebAssemblyFastISel::selectICmp(const Instruction
*I
) {
1000 const auto *ICmp
= cast
<ICmpInst
>(I
);
1002 bool I32
= getSimpleType(ICmp
->getOperand(0)->getType()) != MVT::i64
;
1004 bool IsSigned
= false;
1005 switch (ICmp
->getPredicate()) {
1006 case ICmpInst::ICMP_EQ
:
1007 Opc
= I32
? WebAssembly::EQ_I32
: WebAssembly::EQ_I64
;
1009 case ICmpInst::ICMP_NE
:
1010 Opc
= I32
? WebAssembly::NE_I32
: WebAssembly::NE_I64
;
1012 case ICmpInst::ICMP_UGT
:
1013 Opc
= I32
? WebAssembly::GT_U_I32
: WebAssembly::GT_U_I64
;
1015 case ICmpInst::ICMP_UGE
:
1016 Opc
= I32
? WebAssembly::GE_U_I32
: WebAssembly::GE_U_I64
;
1018 case ICmpInst::ICMP_ULT
:
1019 Opc
= I32
? WebAssembly::LT_U_I32
: WebAssembly::LT_U_I64
;
1021 case ICmpInst::ICMP_ULE
:
1022 Opc
= I32
? WebAssembly::LE_U_I32
: WebAssembly::LE_U_I64
;
1024 case ICmpInst::ICMP_SGT
:
1025 Opc
= I32
? WebAssembly::GT_S_I32
: WebAssembly::GT_S_I64
;
1028 case ICmpInst::ICMP_SGE
:
1029 Opc
= I32
? WebAssembly::GE_S_I32
: WebAssembly::GE_S_I64
;
1032 case ICmpInst::ICMP_SLT
:
1033 Opc
= I32
? WebAssembly::LT_S_I32
: WebAssembly::LT_S_I64
;
1036 case ICmpInst::ICMP_SLE
:
1037 Opc
= I32
? WebAssembly::LE_S_I32
: WebAssembly::LE_S_I64
;
1044 unsigned LHS
= getRegForPromotedValue(ICmp
->getOperand(0), IsSigned
);
1048 unsigned RHS
= getRegForPromotedValue(ICmp
->getOperand(1), IsSigned
);
1052 unsigned ResultReg
= createResultReg(&WebAssembly::I32RegClass
);
1053 BuildMI(*FuncInfo
.MBB
, FuncInfo
.InsertPt
, DbgLoc
, TII
.get(Opc
), ResultReg
)
1056 updateValueMap(ICmp
, ResultReg
);
1060 bool WebAssemblyFastISel::selectFCmp(const Instruction
*I
) {
1061 const auto *FCmp
= cast
<FCmpInst
>(I
);
1063 unsigned LHS
= getRegForValue(FCmp
->getOperand(0));
1067 unsigned RHS
= getRegForValue(FCmp
->getOperand(1));
1071 bool F32
= getSimpleType(FCmp
->getOperand(0)->getType()) != MVT::f64
;
1074 switch (FCmp
->getPredicate()) {
1075 case FCmpInst::FCMP_OEQ
:
1076 Opc
= F32
? WebAssembly::EQ_F32
: WebAssembly::EQ_F64
;
1078 case FCmpInst::FCMP_UNE
:
1079 Opc
= F32
? WebAssembly::NE_F32
: WebAssembly::NE_F64
;
1081 case FCmpInst::FCMP_OGT
:
1082 Opc
= F32
? WebAssembly::GT_F32
: WebAssembly::GT_F64
;
1084 case FCmpInst::FCMP_OGE
:
1085 Opc
= F32
? WebAssembly::GE_F32
: WebAssembly::GE_F64
;
1087 case FCmpInst::FCMP_OLT
:
1088 Opc
= F32
? WebAssembly::LT_F32
: WebAssembly::LT_F64
;
1090 case FCmpInst::FCMP_OLE
:
1091 Opc
= F32
? WebAssembly::LE_F32
: WebAssembly::LE_F64
;
1093 case FCmpInst::FCMP_UGT
:
1094 Opc
= F32
? WebAssembly::LE_F32
: WebAssembly::LE_F64
;
1097 case FCmpInst::FCMP_UGE
:
1098 Opc
= F32
? WebAssembly::LT_F32
: WebAssembly::LT_F64
;
1101 case FCmpInst::FCMP_ULT
:
1102 Opc
= F32
? WebAssembly::GE_F32
: WebAssembly::GE_F64
;
1105 case FCmpInst::FCMP_ULE
:
1106 Opc
= F32
? WebAssembly::GT_F32
: WebAssembly::GT_F64
;
1113 unsigned ResultReg
= createResultReg(&WebAssembly::I32RegClass
);
1114 BuildMI(*FuncInfo
.MBB
, FuncInfo
.InsertPt
, DbgLoc
, TII
.get(Opc
), ResultReg
)
1119 ResultReg
= notValue(ResultReg
);
1121 updateValueMap(FCmp
, ResultReg
);
1125 bool WebAssemblyFastISel::selectBitCast(const Instruction
*I
) {
1126 // Target-independent code can handle this, except it doesn't set the dead
1127 // flag on the ARGUMENTS clobber, so we have to do that manually in order
1128 // to satisfy code that expects this of isBitcast() instructions.
1129 EVT VT
= TLI
.getValueType(DL
, I
->getOperand(0)->getType());
1130 EVT RetVT
= TLI
.getValueType(DL
, I
->getType());
1131 if (!VT
.isSimple() || !RetVT
.isSimple())
1134 unsigned In
= getRegForValue(I
->getOperand(0));
1140 updateValueMap(I
, In
);
1144 Register Reg
= fastEmit_ISD_BITCAST_r(VT
.getSimpleVT(), RetVT
.getSimpleVT(),
1145 In
, I
->getOperand(0)->hasOneUse());
1148 MachineBasicBlock::iterator Iter
= FuncInfo
.InsertPt
;
1150 assert(Iter
->isBitcast());
1151 Iter
->setPhysRegsDeadExcept(ArrayRef
<Register
>(), TRI
);
1152 updateValueMap(I
, Reg
);
1156 bool WebAssemblyFastISel::selectLoad(const Instruction
*I
) {
1157 const auto *Load
= cast
<LoadInst
>(I
);
1158 if (Load
->isAtomic())
1160 if (!Subtarget
->hasSIMD128() && Load
->getType()->isVectorTy())
1164 if (!computeAddress(Load
->getPointerOperand(), Addr
))
1167 // TODO: Fold a following sign-/zero-extend into the load instruction.
1170 const TargetRegisterClass
*RC
;
1171 switch (getSimpleType(Load
->getType())) {
1174 Opc
= WebAssembly::LOAD8_U_I32
;
1175 RC
= &WebAssembly::I32RegClass
;
1178 Opc
= WebAssembly::LOAD16_U_I32
;
1179 RC
= &WebAssembly::I32RegClass
;
1182 Opc
= WebAssembly::LOAD_I32
;
1183 RC
= &WebAssembly::I32RegClass
;
1186 Opc
= WebAssembly::LOAD_I64
;
1187 RC
= &WebAssembly::I64RegClass
;
1190 Opc
= WebAssembly::LOAD_F32
;
1191 RC
= &WebAssembly::F32RegClass
;
1194 Opc
= WebAssembly::LOAD_F64
;
1195 RC
= &WebAssembly::F64RegClass
;
1201 materializeLoadStoreOperands(Addr
);
1203 unsigned ResultReg
= createResultReg(RC
);
1204 auto MIB
= BuildMI(*FuncInfo
.MBB
, FuncInfo
.InsertPt
, DbgLoc
, TII
.get(Opc
),
1207 addLoadStoreOperands(Addr
, MIB
, createMachineMemOperandFor(Load
));
1209 updateValueMap(Load
, ResultReg
);
1213 bool WebAssemblyFastISel::selectStore(const Instruction
*I
) {
1214 const auto *Store
= cast
<StoreInst
>(I
);
1215 if (Store
->isAtomic())
1217 if (!Subtarget
->hasSIMD128() &&
1218 Store
->getValueOperand()->getType()->isVectorTy())
1222 if (!computeAddress(Store
->getPointerOperand(), Addr
))
1226 bool VTIsi1
= false;
1227 switch (getSimpleType(Store
->getValueOperand()->getType())) {
1232 Opc
= WebAssembly::STORE8_I32
;
1235 Opc
= WebAssembly::STORE16_I32
;
1238 Opc
= WebAssembly::STORE_I32
;
1241 Opc
= WebAssembly::STORE_I64
;
1244 Opc
= WebAssembly::STORE_F32
;
1247 Opc
= WebAssembly::STORE_F64
;
1253 materializeLoadStoreOperands(Addr
);
1255 unsigned ValueReg
= getRegForValue(Store
->getValueOperand());
1259 ValueReg
= maskI1Value(ValueReg
, Store
->getValueOperand());
1261 auto MIB
= BuildMI(*FuncInfo
.MBB
, FuncInfo
.InsertPt
, DbgLoc
, TII
.get(Opc
));
1263 addLoadStoreOperands(Addr
, MIB
, createMachineMemOperandFor(Store
));
1265 MIB
.addReg(ValueReg
);
1269 bool WebAssemblyFastISel::selectBr(const Instruction
*I
) {
1270 const auto *Br
= cast
<BranchInst
>(I
);
1271 if (Br
->isUnconditional()) {
1272 MachineBasicBlock
*MSucc
= FuncInfo
.MBBMap
[Br
->getSuccessor(0)];
1273 fastEmitBranch(MSucc
, Br
->getDebugLoc());
1277 MachineBasicBlock
*TBB
= FuncInfo
.MBBMap
[Br
->getSuccessor(0)];
1278 MachineBasicBlock
*FBB
= FuncInfo
.MBBMap
[Br
->getSuccessor(1)];
1281 unsigned CondReg
= getRegForI1Value(Br
->getCondition(), Not
);
1285 unsigned Opc
= WebAssembly::BR_IF
;
1287 Opc
= WebAssembly::BR_UNLESS
;
1289 BuildMI(*FuncInfo
.MBB
, FuncInfo
.InsertPt
, DbgLoc
, TII
.get(Opc
))
1293 finishCondBranch(Br
->getParent(), TBB
, FBB
);
1297 bool WebAssemblyFastISel::selectRet(const Instruction
*I
) {
1298 if (!FuncInfo
.CanLowerReturn
)
1301 const auto *Ret
= cast
<ReturnInst
>(I
);
1303 if (Ret
->getNumOperands() == 0) {
1304 BuildMI(*FuncInfo
.MBB
, FuncInfo
.InsertPt
, DbgLoc
,
1305 TII
.get(WebAssembly::RETURN
));
1309 // TODO: support multiple return in FastISel
1310 if (Ret
->getNumOperands() > 1)
1313 Value
*RV
= Ret
->getOperand(0);
1314 if (!Subtarget
->hasSIMD128() && RV
->getType()->isVectorTy())
1317 switch (getSimpleType(RV
->getType())) {
1338 if (FuncInfo
.Fn
->getAttributes().hasAttribute(0, Attribute::SExt
))
1339 Reg
= getRegForSignedValue(RV
);
1340 else if (FuncInfo
.Fn
->getAttributes().hasAttribute(0, Attribute::ZExt
))
1341 Reg
= getRegForUnsignedValue(RV
);
1343 Reg
= getRegForValue(RV
);
1348 BuildMI(*FuncInfo
.MBB
, FuncInfo
.InsertPt
, DbgLoc
,
1349 TII
.get(WebAssembly::RETURN
))
1354 bool WebAssemblyFastISel::selectUnreachable(const Instruction
*I
) {
1355 BuildMI(*FuncInfo
.MBB
, FuncInfo
.InsertPt
, DbgLoc
,
1356 TII
.get(WebAssembly::UNREACHABLE
));
1360 bool WebAssemblyFastISel::fastSelectInstruction(const Instruction
*I
) {
1361 switch (I
->getOpcode()) {
1362 case Instruction::Call
:
1366 case Instruction::Select
:
1367 return selectSelect(I
);
1368 case Instruction::Trunc
:
1369 return selectTrunc(I
);
1370 case Instruction::ZExt
:
1371 return selectZExt(I
);
1372 case Instruction::SExt
:
1373 return selectSExt(I
);
1374 case Instruction::ICmp
:
1375 return selectICmp(I
);
1376 case Instruction::FCmp
:
1377 return selectFCmp(I
);
1378 case Instruction::BitCast
:
1379 return selectBitCast(I
);
1380 case Instruction::Load
:
1381 return selectLoad(I
);
1382 case Instruction::Store
:
1383 return selectStore(I
);
1384 case Instruction::Br
:
1386 case Instruction::Ret
:
1387 return selectRet(I
);
1388 case Instruction::Unreachable
:
1389 return selectUnreachable(I
);
1394 // Fall back to target-independent instruction selection.
1395 return selectOperator(I
, I
->getOpcode());
1398 FastISel
*WebAssembly::createFastISel(FunctionLoweringInfo
&FuncInfo
,
1399 const TargetLibraryInfo
*LibInfo
) {
1400 return new WebAssemblyFastISel(FuncInfo
, LibInfo
);