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
, /*HandleUnknown=*/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
) {
211 const User
*U
= nullptr;
212 unsigned Opcode
= Instruction::UserOp1
;
213 if (const auto *I
= dyn_cast
<Instruction
>(Obj
)) {
214 // Don't walk into other basic blocks unless the object is an alloca from
215 // another block, otherwise it may not have a virtual register assigned.
216 if (FuncInfo
.StaticAllocaMap
.count(static_cast<const AllocaInst
*>(Obj
)) ||
217 FuncInfo
.MBBMap
[I
->getParent()] == FuncInfo
.MBB
) {
218 Opcode
= I
->getOpcode();
221 } else if (const auto *C
= dyn_cast
<ConstantExpr
>(Obj
)) {
222 Opcode
= C
->getOpcode();
226 if (auto *Ty
= dyn_cast
<PointerType
>(Obj
->getType()))
227 if (Ty
->getAddressSpace() > 255)
228 // Fast instruction selection doesn't support the special
232 if (const auto *GV
= dyn_cast
<GlobalValue
>(Obj
)) {
233 if (Addr
.getGlobalValue())
235 Addr
.setGlobalValue(GV
);
242 case Instruction::BitCast
: {
243 // Look through bitcasts.
244 return computeAddress(U
->getOperand(0), Addr
);
246 case Instruction::IntToPtr
: {
247 // Look past no-op inttoptrs.
248 if (TLI
.getValueType(DL
, U
->getOperand(0)->getType()) ==
249 TLI
.getPointerTy(DL
))
250 return computeAddress(U
->getOperand(0), Addr
);
253 case Instruction::PtrToInt
: {
254 // Look past no-op ptrtoints.
255 if (TLI
.getValueType(DL
, U
->getType()) == TLI
.getPointerTy(DL
))
256 return computeAddress(U
->getOperand(0), Addr
);
259 case Instruction::GetElementPtr
: {
260 Address SavedAddr
= Addr
;
261 uint64_t TmpOffset
= Addr
.getOffset();
262 // Non-inbounds geps can wrap; wasm's offsets can't.
263 if (!cast
<GEPOperator
>(U
)->isInBounds())
264 goto unsupported_gep
;
265 // Iterate through the GEP folding the constants into offsets where
267 for (gep_type_iterator GTI
= gep_type_begin(U
), E
= gep_type_end(U
);
269 const Value
*Op
= GTI
.getOperand();
270 if (StructType
*STy
= GTI
.getStructTypeOrNull()) {
271 const StructLayout
*SL
= DL
.getStructLayout(STy
);
272 unsigned Idx
= cast
<ConstantInt
>(Op
)->getZExtValue();
273 TmpOffset
+= SL
->getElementOffset(Idx
);
275 uint64_t S
= DL
.getTypeAllocSize(GTI
.getIndexedType());
277 if (const auto *CI
= dyn_cast
<ConstantInt
>(Op
)) {
278 // Constant-offset addressing.
279 TmpOffset
+= CI
->getSExtValue() * S
;
282 if (S
== 1 && Addr
.isRegBase() && Addr
.getReg() == 0) {
283 // An unscaled add of a register. Set it as the new base.
284 unsigned Reg
= getRegForValue(Op
);
290 if (canFoldAddIntoGEP(U
, Op
)) {
291 // A compatible add with a constant operand. Fold the constant.
292 auto *CI
= cast
<ConstantInt
>(cast
<AddOperator
>(Op
)->getOperand(1));
293 TmpOffset
+= CI
->getSExtValue() * S
;
294 // Iterate on the other operand.
295 Op
= cast
<AddOperator
>(Op
)->getOperand(0);
299 goto unsupported_gep
;
303 // Don't fold in negative offsets.
304 if (int64_t(TmpOffset
) >= 0) {
305 // Try to grab the base operand now.
306 Addr
.setOffset(TmpOffset
);
307 if (computeAddress(U
->getOperand(0), Addr
))
310 // We failed, restore everything and try the other options.
315 case Instruction::Alloca
: {
316 const auto *AI
= cast
<AllocaInst
>(Obj
);
317 DenseMap
<const AllocaInst
*, int>::iterator SI
=
318 FuncInfo
.StaticAllocaMap
.find(AI
);
319 if (SI
!= FuncInfo
.StaticAllocaMap
.end()) {
323 Addr
.setKind(Address::FrameIndexBase
);
324 Addr
.setFI(SI
->second
);
329 case Instruction::Add
: {
330 // Adds of constants are common and easy enough.
331 const Value
*LHS
= U
->getOperand(0);
332 const Value
*RHS
= U
->getOperand(1);
334 if (isa
<ConstantInt
>(LHS
))
337 if (const auto *CI
= dyn_cast
<ConstantInt
>(RHS
)) {
338 uint64_t TmpOffset
= Addr
.getOffset() + CI
->getSExtValue();
339 if (int64_t(TmpOffset
) >= 0) {
340 Addr
.setOffset(TmpOffset
);
341 return computeAddress(LHS
, Addr
);
345 Address Backup
= Addr
;
346 if (computeAddress(LHS
, Addr
) && computeAddress(RHS
, Addr
))
352 case Instruction::Sub
: {
353 // Subs of constants are common and easy enough.
354 const Value
*LHS
= U
->getOperand(0);
355 const Value
*RHS
= U
->getOperand(1);
357 if (const auto *CI
= dyn_cast
<ConstantInt
>(RHS
)) {
358 int64_t TmpOffset
= Addr
.getOffset() - CI
->getSExtValue();
359 if (TmpOffset
>= 0) {
360 Addr
.setOffset(TmpOffset
);
361 return computeAddress(LHS
, Addr
);
370 unsigned Reg
= getRegForValue(Obj
);
374 return Addr
.getReg() != 0;
377 void WebAssemblyFastISel::materializeLoadStoreOperands(Address
&Addr
) {
378 if (Addr
.isRegBase()) {
379 unsigned Reg
= Addr
.getReg();
381 Reg
= createResultReg(Subtarget
->hasAddr64() ? &WebAssembly::I64RegClass
382 : &WebAssembly::I32RegClass
);
383 unsigned Opc
= Subtarget
->hasAddr64() ? WebAssembly::CONST_I64
384 : WebAssembly::CONST_I32
;
385 BuildMI(*FuncInfo
.MBB
, FuncInfo
.InsertPt
, DbgLoc
, TII
.get(Opc
), Reg
)
392 void WebAssemblyFastISel::addLoadStoreOperands(const Address
&Addr
,
393 const MachineInstrBuilder
&MIB
,
394 MachineMemOperand
*MMO
) {
395 // Set the alignment operand (this is rewritten in SetP2AlignOperands).
396 // TODO: Disable SetP2AlignOperands for FastISel and just do it here.
399 if (const GlobalValue
*GV
= Addr
.getGlobalValue())
400 MIB
.addGlobalAddress(GV
, Addr
.getOffset());
402 MIB
.addImm(Addr
.getOffset());
404 if (Addr
.isRegBase())
405 MIB
.addReg(Addr
.getReg());
407 MIB
.addFrameIndex(Addr
.getFI());
409 MIB
.addMemOperand(MMO
);
412 unsigned WebAssemblyFastISel::maskI1Value(unsigned Reg
, const Value
*V
) {
413 return zeroExtendToI32(Reg
, V
, MVT::i1
);
416 unsigned WebAssemblyFastISel::getRegForI1Value(const Value
*V
, bool &Not
) {
417 if (const auto *ICmp
= dyn_cast
<ICmpInst
>(V
))
418 if (const ConstantInt
*C
= dyn_cast
<ConstantInt
>(ICmp
->getOperand(1)))
419 if (ICmp
->isEquality() && C
->isZero() && C
->getType()->isIntegerTy(32)) {
420 Not
= ICmp
->isTrueWhenEqual();
421 return getRegForValue(ICmp
->getOperand(0));
425 if (match(V
, m_Not(m_Value(NotV
))) && V
->getType()->isIntegerTy(32)) {
427 return getRegForValue(NotV
);
431 unsigned Reg
= getRegForValue(V
);
434 return maskI1Value(Reg
, V
);
437 unsigned WebAssemblyFastISel::zeroExtendToI32(unsigned Reg
, const Value
*V
,
438 MVT::SimpleValueType From
) {
444 // If the value is naturally an i1, we don't need to mask it. We only know
445 // if a value is naturally an i1 if it is definitely lowered by FastISel,
446 // not a DAG ISel fallback.
447 if (V
!= nullptr && isa
<Argument
>(V
) && cast
<Argument
>(V
)->hasZExtAttr())
448 return copyValue(Reg
);
454 return copyValue(Reg
);
459 unsigned Imm
= createResultReg(&WebAssembly::I32RegClass
);
460 BuildMI(*FuncInfo
.MBB
, FuncInfo
.InsertPt
, DbgLoc
,
461 TII
.get(WebAssembly::CONST_I32
), Imm
)
462 .addImm(~(~uint64_t(0) << MVT(From
).getSizeInBits()));
464 unsigned Result
= createResultReg(&WebAssembly::I32RegClass
);
465 BuildMI(*FuncInfo
.MBB
, FuncInfo
.InsertPt
, DbgLoc
,
466 TII
.get(WebAssembly::AND_I32
), Result
)
473 unsigned WebAssemblyFastISel::signExtendToI32(unsigned Reg
, const Value
*V
,
474 MVT::SimpleValueType From
) {
484 return copyValue(Reg
);
489 unsigned Imm
= createResultReg(&WebAssembly::I32RegClass
);
490 BuildMI(*FuncInfo
.MBB
, FuncInfo
.InsertPt
, DbgLoc
,
491 TII
.get(WebAssembly::CONST_I32
), Imm
)
492 .addImm(32 - MVT(From
).getSizeInBits());
494 unsigned Left
= createResultReg(&WebAssembly::I32RegClass
);
495 BuildMI(*FuncInfo
.MBB
, FuncInfo
.InsertPt
, DbgLoc
,
496 TII
.get(WebAssembly::SHL_I32
), Left
)
500 unsigned Right
= createResultReg(&WebAssembly::I32RegClass
);
501 BuildMI(*FuncInfo
.MBB
, FuncInfo
.InsertPt
, DbgLoc
,
502 TII
.get(WebAssembly::SHR_S_I32
), Right
)
509 unsigned WebAssemblyFastISel::zeroExtend(unsigned Reg
, const Value
*V
,
510 MVT::SimpleValueType From
,
511 MVT::SimpleValueType To
) {
512 if (To
== MVT::i64
) {
513 if (From
== MVT::i64
)
514 return copyValue(Reg
);
516 Reg
= zeroExtendToI32(Reg
, V
, From
);
518 unsigned Result
= createResultReg(&WebAssembly::I64RegClass
);
519 BuildMI(*FuncInfo
.MBB
, FuncInfo
.InsertPt
, DbgLoc
,
520 TII
.get(WebAssembly::I64_EXTEND_U_I32
), Result
)
525 return zeroExtendToI32(Reg
, V
, From
);
528 unsigned WebAssemblyFastISel::signExtend(unsigned Reg
, const Value
*V
,
529 MVT::SimpleValueType From
,
530 MVT::SimpleValueType To
) {
531 if (To
== MVT::i64
) {
532 if (From
== MVT::i64
)
533 return copyValue(Reg
);
535 Reg
= signExtendToI32(Reg
, V
, From
);
537 unsigned Result
= createResultReg(&WebAssembly::I64RegClass
);
538 BuildMI(*FuncInfo
.MBB
, FuncInfo
.InsertPt
, DbgLoc
,
539 TII
.get(WebAssembly::I64_EXTEND_S_I32
), Result
)
544 return signExtendToI32(Reg
, V
, From
);
547 unsigned WebAssemblyFastISel::getRegForUnsignedValue(const Value
*V
) {
548 MVT::SimpleValueType From
= getSimpleType(V
->getType());
549 MVT::SimpleValueType To
= getLegalType(From
);
550 unsigned VReg
= getRegForValue(V
);
553 return zeroExtend(VReg
, V
, From
, To
);
556 unsigned WebAssemblyFastISel::getRegForSignedValue(const Value
*V
) {
557 MVT::SimpleValueType From
= getSimpleType(V
->getType());
558 MVT::SimpleValueType To
= getLegalType(From
);
559 unsigned VReg
= getRegForValue(V
);
562 return signExtend(VReg
, V
, From
, To
);
565 unsigned WebAssemblyFastISel::getRegForPromotedValue(const Value
*V
,
567 return IsSigned
? getRegForSignedValue(V
) : getRegForUnsignedValue(V
);
570 unsigned WebAssemblyFastISel::notValue(unsigned Reg
) {
571 assert(MRI
.getRegClass(Reg
) == &WebAssembly::I32RegClass
);
573 unsigned NotReg
= createResultReg(&WebAssembly::I32RegClass
);
574 BuildMI(*FuncInfo
.MBB
, FuncInfo
.InsertPt
, DbgLoc
,
575 TII
.get(WebAssembly::EQZ_I32
), NotReg
)
580 unsigned WebAssemblyFastISel::copyValue(unsigned Reg
) {
581 unsigned ResultReg
= createResultReg(MRI
.getRegClass(Reg
));
582 BuildMI(*FuncInfo
.MBB
, FuncInfo
.InsertPt
, DbgLoc
, TII
.get(WebAssembly::COPY
),
588 unsigned WebAssemblyFastISel::fastMaterializeAlloca(const AllocaInst
*AI
) {
589 DenseMap
<const AllocaInst
*, int>::iterator SI
=
590 FuncInfo
.StaticAllocaMap
.find(AI
);
592 if (SI
!= FuncInfo
.StaticAllocaMap
.end()) {
594 createResultReg(Subtarget
->hasAddr64() ? &WebAssembly::I64RegClass
595 : &WebAssembly::I32RegClass
);
597 Subtarget
->hasAddr64() ? WebAssembly::COPY_I64
: WebAssembly::COPY_I32
;
598 BuildMI(*FuncInfo
.MBB
, FuncInfo
.InsertPt
, DbgLoc
, TII
.get(Opc
), ResultReg
)
599 .addFrameIndex(SI
->second
);
606 unsigned WebAssemblyFastISel::fastMaterializeConstant(const Constant
*C
) {
607 if (const auto *GV
= dyn_cast
<GlobalValue
>(C
)) {
609 createResultReg(Subtarget
->hasAddr64() ? &WebAssembly::I64RegClass
610 : &WebAssembly::I32RegClass
);
611 unsigned Opc
= Subtarget
->hasAddr64() ? WebAssembly::CONST_I64
612 : WebAssembly::CONST_I32
;
613 BuildMI(*FuncInfo
.MBB
, FuncInfo
.InsertPt
, DbgLoc
, TII
.get(Opc
), ResultReg
)
614 .addGlobalAddress(GV
);
618 // Let target-independent code handle it.
622 bool WebAssemblyFastISel::fastLowerArguments() {
623 if (!FuncInfo
.CanLowerReturn
)
626 const Function
*F
= FuncInfo
.Fn
;
631 for (auto const &Arg
: F
->args()) {
632 const AttributeList
&Attrs
= F
->getAttributes();
633 if (Attrs
.hasParamAttribute(I
, Attribute::ByVal
) ||
634 Attrs
.hasParamAttribute(I
, Attribute::SwiftSelf
) ||
635 Attrs
.hasParamAttribute(I
, Attribute::SwiftError
) ||
636 Attrs
.hasParamAttribute(I
, Attribute::InAlloca
) ||
637 Attrs
.hasParamAttribute(I
, Attribute::Nest
))
640 Type
*ArgTy
= Arg
.getType();
641 if (ArgTy
->isStructTy() || ArgTy
->isArrayTy())
643 if (!Subtarget
->hasSIMD128() && ArgTy
->isVectorTy())
647 const TargetRegisterClass
*RC
;
648 switch (getSimpleType(ArgTy
)) {
653 Opc
= WebAssembly::ARGUMENT_i32
;
654 RC
= &WebAssembly::I32RegClass
;
657 Opc
= WebAssembly::ARGUMENT_i64
;
658 RC
= &WebAssembly::I64RegClass
;
661 Opc
= WebAssembly::ARGUMENT_f32
;
662 RC
= &WebAssembly::F32RegClass
;
665 Opc
= WebAssembly::ARGUMENT_f64
;
666 RC
= &WebAssembly::F64RegClass
;
669 Opc
= WebAssembly::ARGUMENT_v16i8
;
670 RC
= &WebAssembly::V128RegClass
;
673 Opc
= WebAssembly::ARGUMENT_v8i16
;
674 RC
= &WebAssembly::V128RegClass
;
677 Opc
= WebAssembly::ARGUMENT_v4i32
;
678 RC
= &WebAssembly::V128RegClass
;
681 Opc
= WebAssembly::ARGUMENT_v2i64
;
682 RC
= &WebAssembly::V128RegClass
;
685 Opc
= WebAssembly::ARGUMENT_v4f32
;
686 RC
= &WebAssembly::V128RegClass
;
689 Opc
= WebAssembly::ARGUMENT_v2f64
;
690 RC
= &WebAssembly::V128RegClass
;
693 Opc
= WebAssembly::ARGUMENT_ExceptRef
;
694 RC
= &WebAssembly::EXCEPT_REFRegClass
;
699 unsigned ResultReg
= createResultReg(RC
);
700 BuildMI(*FuncInfo
.MBB
, FuncInfo
.InsertPt
, DbgLoc
, TII
.get(Opc
), ResultReg
)
702 updateValueMap(&Arg
, ResultReg
);
707 MRI
.addLiveIn(WebAssembly::ARGUMENTS
);
709 auto *MFI
= MF
->getInfo
<WebAssemblyFunctionInfo
>();
710 for (auto const &Arg
: F
->args()) {
711 MVT::SimpleValueType ArgTy
= getLegalType(getSimpleType(Arg
.getType()));
712 if (ArgTy
== MVT::INVALID_SIMPLE_VALUE_TYPE
) {
713 MFI
->clearParamsAndResults();
716 MFI
->addParam(ArgTy
);
719 if (!F
->getReturnType()->isVoidTy()) {
720 MVT::SimpleValueType RetTy
=
721 getLegalType(getSimpleType(F
->getReturnType()));
722 if (RetTy
== MVT::INVALID_SIMPLE_VALUE_TYPE
) {
723 MFI
->clearParamsAndResults();
726 MFI
->addResult(RetTy
);
732 bool WebAssemblyFastISel::selectCall(const Instruction
*I
) {
733 const auto *Call
= cast
<CallInst
>(I
);
735 if (Call
->isMustTailCall() || Call
->isInlineAsm() ||
736 Call
->getFunctionType()->isVarArg())
739 Function
*Func
= Call
->getCalledFunction();
740 if (Func
&& Func
->isIntrinsic())
743 bool IsDirect
= Func
!= nullptr;
744 if (!IsDirect
&& isa
<ConstantExpr
>(Call
->getCalledValue()))
747 FunctionType
*FuncTy
= Call
->getFunctionType();
749 bool IsVoid
= FuncTy
->getReturnType()->isVoidTy();
752 Opc
= IsDirect
? WebAssembly::CALL_VOID
: WebAssembly::PCALL_INDIRECT_VOID
;
754 if (!Subtarget
->hasSIMD128() && Call
->getType()->isVectorTy())
757 MVT::SimpleValueType RetTy
= getSimpleType(Call
->getType());
763 Opc
= IsDirect
? WebAssembly::CALL_I32
: WebAssembly::PCALL_INDIRECT_I32
;
764 ResultReg
= createResultReg(&WebAssembly::I32RegClass
);
767 Opc
= IsDirect
? WebAssembly::CALL_I64
: WebAssembly::PCALL_INDIRECT_I64
;
768 ResultReg
= createResultReg(&WebAssembly::I64RegClass
);
771 Opc
= IsDirect
? WebAssembly::CALL_F32
: WebAssembly::PCALL_INDIRECT_F32
;
772 ResultReg
= createResultReg(&WebAssembly::F32RegClass
);
775 Opc
= IsDirect
? WebAssembly::CALL_F64
: WebAssembly::PCALL_INDIRECT_F64
;
776 ResultReg
= createResultReg(&WebAssembly::F64RegClass
);
779 Opc
= IsDirect
? WebAssembly::CALL_v16i8
780 : WebAssembly::PCALL_INDIRECT_v16i8
;
781 ResultReg
= createResultReg(&WebAssembly::V128RegClass
);
784 Opc
= IsDirect
? WebAssembly::CALL_v8i16
785 : WebAssembly::PCALL_INDIRECT_v8i16
;
786 ResultReg
= createResultReg(&WebAssembly::V128RegClass
);
789 Opc
= IsDirect
? WebAssembly::CALL_v4i32
790 : WebAssembly::PCALL_INDIRECT_v4i32
;
791 ResultReg
= createResultReg(&WebAssembly::V128RegClass
);
794 Opc
= IsDirect
? WebAssembly::CALL_v2i64
795 : WebAssembly::PCALL_INDIRECT_v2i64
;
796 ResultReg
= createResultReg(&WebAssembly::V128RegClass
);
799 Opc
= IsDirect
? WebAssembly::CALL_v4f32
800 : WebAssembly::PCALL_INDIRECT_v4f32
;
801 ResultReg
= createResultReg(&WebAssembly::V128RegClass
);
804 Opc
= IsDirect
? WebAssembly::CALL_v2f64
805 : WebAssembly::PCALL_INDIRECT_v2f64
;
806 ResultReg
= createResultReg(&WebAssembly::V128RegClass
);
809 Opc
= IsDirect
? WebAssembly::CALL_EXCEPT_REF
810 : WebAssembly::PCALL_INDIRECT_EXCEPT_REF
;
811 ResultReg
= createResultReg(&WebAssembly::EXCEPT_REFRegClass
);
818 SmallVector
<unsigned, 8> Args
;
819 for (unsigned I
= 0, E
= Call
->getNumArgOperands(); I
< E
; ++I
) {
820 Value
*V
= Call
->getArgOperand(I
);
821 MVT::SimpleValueType ArgTy
= getSimpleType(V
->getType());
822 if (ArgTy
== MVT::INVALID_SIMPLE_VALUE_TYPE
)
825 const AttributeList
&Attrs
= Call
->getAttributes();
826 if (Attrs
.hasParamAttribute(I
, Attribute::ByVal
) ||
827 Attrs
.hasParamAttribute(I
, Attribute::SwiftSelf
) ||
828 Attrs
.hasParamAttribute(I
, Attribute::SwiftError
) ||
829 Attrs
.hasParamAttribute(I
, Attribute::InAlloca
) ||
830 Attrs
.hasParamAttribute(I
, Attribute::Nest
))
835 if (Attrs
.hasParamAttribute(I
, Attribute::SExt
))
836 Reg
= getRegForSignedValue(V
);
837 else if (Attrs
.hasParamAttribute(I
, Attribute::ZExt
))
838 Reg
= getRegForUnsignedValue(V
);
840 Reg
= getRegForValue(V
);
848 auto MIB
= BuildMI(*FuncInfo
.MBB
, FuncInfo
.InsertPt
, DbgLoc
, TII
.get(Opc
));
851 MIB
.addReg(ResultReg
, RegState::Define
);
854 MIB
.addGlobalAddress(Func
);
856 unsigned Reg
= getRegForValue(Call
->getCalledValue());
862 for (unsigned ArgReg
: Args
)
866 updateValueMap(Call
, ResultReg
);
870 bool WebAssemblyFastISel::selectSelect(const Instruction
*I
) {
871 const auto *Select
= cast
<SelectInst
>(I
);
874 unsigned CondReg
= getRegForI1Value(Select
->getCondition(), Not
);
878 unsigned TrueReg
= getRegForValue(Select
->getTrueValue());
882 unsigned FalseReg
= getRegForValue(Select
->getFalseValue());
887 std::swap(TrueReg
, FalseReg
);
890 const TargetRegisterClass
*RC
;
891 switch (getSimpleType(Select
->getType())) {
896 Opc
= WebAssembly::SELECT_I32
;
897 RC
= &WebAssembly::I32RegClass
;
900 Opc
= WebAssembly::SELECT_I64
;
901 RC
= &WebAssembly::I64RegClass
;
904 Opc
= WebAssembly::SELECT_F32
;
905 RC
= &WebAssembly::F32RegClass
;
908 Opc
= WebAssembly::SELECT_F64
;
909 RC
= &WebAssembly::F64RegClass
;
912 Opc
= WebAssembly::SELECT_EXCEPT_REF
;
913 RC
= &WebAssembly::EXCEPT_REFRegClass
;
919 unsigned ResultReg
= createResultReg(RC
);
920 BuildMI(*FuncInfo
.MBB
, FuncInfo
.InsertPt
, DbgLoc
, TII
.get(Opc
), ResultReg
)
925 updateValueMap(Select
, ResultReg
);
929 bool WebAssemblyFastISel::selectTrunc(const Instruction
*I
) {
930 const auto *Trunc
= cast
<TruncInst
>(I
);
932 unsigned Reg
= getRegForValue(Trunc
->getOperand(0));
936 if (Trunc
->getOperand(0)->getType()->isIntegerTy(64)) {
937 unsigned Result
= createResultReg(&WebAssembly::I32RegClass
);
938 BuildMI(*FuncInfo
.MBB
, FuncInfo
.InsertPt
, DbgLoc
,
939 TII
.get(WebAssembly::I32_WRAP_I64
), Result
)
944 updateValueMap(Trunc
, Reg
);
948 bool WebAssemblyFastISel::selectZExt(const Instruction
*I
) {
949 const auto *ZExt
= cast
<ZExtInst
>(I
);
951 const Value
*Op
= ZExt
->getOperand(0);
952 MVT::SimpleValueType From
= getSimpleType(Op
->getType());
953 MVT::SimpleValueType To
= getLegalType(getSimpleType(ZExt
->getType()));
954 unsigned In
= getRegForValue(Op
);
957 unsigned Reg
= zeroExtend(In
, Op
, From
, To
);
961 updateValueMap(ZExt
, Reg
);
965 bool WebAssemblyFastISel::selectSExt(const Instruction
*I
) {
966 const auto *SExt
= cast
<SExtInst
>(I
);
968 const Value
*Op
= SExt
->getOperand(0);
969 MVT::SimpleValueType From
= getSimpleType(Op
->getType());
970 MVT::SimpleValueType To
= getLegalType(getSimpleType(SExt
->getType()));
971 unsigned In
= getRegForValue(Op
);
974 unsigned Reg
= signExtend(In
, Op
, From
, To
);
978 updateValueMap(SExt
, Reg
);
982 bool WebAssemblyFastISel::selectICmp(const Instruction
*I
) {
983 const auto *ICmp
= cast
<ICmpInst
>(I
);
985 bool I32
= getSimpleType(ICmp
->getOperand(0)->getType()) != MVT::i64
;
987 bool IsSigned
= false;
988 switch (ICmp
->getPredicate()) {
989 case ICmpInst::ICMP_EQ
:
990 Opc
= I32
? WebAssembly::EQ_I32
: WebAssembly::EQ_I64
;
992 case ICmpInst::ICMP_NE
:
993 Opc
= I32
? WebAssembly::NE_I32
: WebAssembly::NE_I64
;
995 case ICmpInst::ICMP_UGT
:
996 Opc
= I32
? WebAssembly::GT_U_I32
: WebAssembly::GT_U_I64
;
998 case ICmpInst::ICMP_UGE
:
999 Opc
= I32
? WebAssembly::GE_U_I32
: WebAssembly::GE_U_I64
;
1001 case ICmpInst::ICMP_ULT
:
1002 Opc
= I32
? WebAssembly::LT_U_I32
: WebAssembly::LT_U_I64
;
1004 case ICmpInst::ICMP_ULE
:
1005 Opc
= I32
? WebAssembly::LE_U_I32
: WebAssembly::LE_U_I64
;
1007 case ICmpInst::ICMP_SGT
:
1008 Opc
= I32
? WebAssembly::GT_S_I32
: WebAssembly::GT_S_I64
;
1011 case ICmpInst::ICMP_SGE
:
1012 Opc
= I32
? WebAssembly::GE_S_I32
: WebAssembly::GE_S_I64
;
1015 case ICmpInst::ICMP_SLT
:
1016 Opc
= I32
? WebAssembly::LT_S_I32
: WebAssembly::LT_S_I64
;
1019 case ICmpInst::ICMP_SLE
:
1020 Opc
= I32
? WebAssembly::LE_S_I32
: WebAssembly::LE_S_I64
;
1027 unsigned LHS
= getRegForPromotedValue(ICmp
->getOperand(0), IsSigned
);
1031 unsigned RHS
= getRegForPromotedValue(ICmp
->getOperand(1), IsSigned
);
1035 unsigned ResultReg
= createResultReg(&WebAssembly::I32RegClass
);
1036 BuildMI(*FuncInfo
.MBB
, FuncInfo
.InsertPt
, DbgLoc
, TII
.get(Opc
), ResultReg
)
1039 updateValueMap(ICmp
, ResultReg
);
1043 bool WebAssemblyFastISel::selectFCmp(const Instruction
*I
) {
1044 const auto *FCmp
= cast
<FCmpInst
>(I
);
1046 unsigned LHS
= getRegForValue(FCmp
->getOperand(0));
1050 unsigned RHS
= getRegForValue(FCmp
->getOperand(1));
1054 bool F32
= getSimpleType(FCmp
->getOperand(0)->getType()) != MVT::f64
;
1057 switch (FCmp
->getPredicate()) {
1058 case FCmpInst::FCMP_OEQ
:
1059 Opc
= F32
? WebAssembly::EQ_F32
: WebAssembly::EQ_F64
;
1061 case FCmpInst::FCMP_UNE
:
1062 Opc
= F32
? WebAssembly::NE_F32
: WebAssembly::NE_F64
;
1064 case FCmpInst::FCMP_OGT
:
1065 Opc
= F32
? WebAssembly::GT_F32
: WebAssembly::GT_F64
;
1067 case FCmpInst::FCMP_OGE
:
1068 Opc
= F32
? WebAssembly::GE_F32
: WebAssembly::GE_F64
;
1070 case FCmpInst::FCMP_OLT
:
1071 Opc
= F32
? WebAssembly::LT_F32
: WebAssembly::LT_F64
;
1073 case FCmpInst::FCMP_OLE
:
1074 Opc
= F32
? WebAssembly::LE_F32
: WebAssembly::LE_F64
;
1076 case FCmpInst::FCMP_UGT
:
1077 Opc
= F32
? WebAssembly::LE_F32
: WebAssembly::LE_F64
;
1080 case FCmpInst::FCMP_UGE
:
1081 Opc
= F32
? WebAssembly::LT_F32
: WebAssembly::LT_F64
;
1084 case FCmpInst::FCMP_ULT
:
1085 Opc
= F32
? WebAssembly::GE_F32
: WebAssembly::GE_F64
;
1088 case FCmpInst::FCMP_ULE
:
1089 Opc
= F32
? WebAssembly::GT_F32
: WebAssembly::GT_F64
;
1096 unsigned ResultReg
= createResultReg(&WebAssembly::I32RegClass
);
1097 BuildMI(*FuncInfo
.MBB
, FuncInfo
.InsertPt
, DbgLoc
, TII
.get(Opc
), ResultReg
)
1102 ResultReg
= notValue(ResultReg
);
1104 updateValueMap(FCmp
, ResultReg
);
1108 bool WebAssemblyFastISel::selectBitCast(const Instruction
*I
) {
1109 // Target-independent code can handle this, except it doesn't set the dead
1110 // flag on the ARGUMENTS clobber, so we have to do that manually in order
1111 // to satisfy code that expects this of isBitcast() instructions.
1112 EVT VT
= TLI
.getValueType(DL
, I
->getOperand(0)->getType());
1113 EVT RetVT
= TLI
.getValueType(DL
, I
->getType());
1114 if (!VT
.isSimple() || !RetVT
.isSimple())
1117 unsigned In
= getRegForValue(I
->getOperand(0));
1123 updateValueMap(I
, In
);
1127 unsigned Reg
= fastEmit_ISD_BITCAST_r(VT
.getSimpleVT(), RetVT
.getSimpleVT(),
1128 In
, I
->getOperand(0)->hasOneUse());
1131 MachineBasicBlock::iterator Iter
= FuncInfo
.InsertPt
;
1133 assert(Iter
->isBitcast());
1134 Iter
->setPhysRegsDeadExcept(ArrayRef
<unsigned>(), TRI
);
1135 updateValueMap(I
, Reg
);
1139 bool WebAssemblyFastISel::selectLoad(const Instruction
*I
) {
1140 const auto *Load
= cast
<LoadInst
>(I
);
1141 if (Load
->isAtomic())
1143 if (!Subtarget
->hasSIMD128() && Load
->getType()->isVectorTy())
1147 if (!computeAddress(Load
->getPointerOperand(), Addr
))
1150 // TODO: Fold a following sign-/zero-extend into the load instruction.
1153 const TargetRegisterClass
*RC
;
1154 switch (getSimpleType(Load
->getType())) {
1157 Opc
= WebAssembly::LOAD8_U_I32
;
1158 RC
= &WebAssembly::I32RegClass
;
1161 Opc
= WebAssembly::LOAD16_U_I32
;
1162 RC
= &WebAssembly::I32RegClass
;
1165 Opc
= WebAssembly::LOAD_I32
;
1166 RC
= &WebAssembly::I32RegClass
;
1169 Opc
= WebAssembly::LOAD_I64
;
1170 RC
= &WebAssembly::I64RegClass
;
1173 Opc
= WebAssembly::LOAD_F32
;
1174 RC
= &WebAssembly::F32RegClass
;
1177 Opc
= WebAssembly::LOAD_F64
;
1178 RC
= &WebAssembly::F64RegClass
;
1184 materializeLoadStoreOperands(Addr
);
1186 unsigned ResultReg
= createResultReg(RC
);
1187 auto MIB
= BuildMI(*FuncInfo
.MBB
, FuncInfo
.InsertPt
, DbgLoc
, TII
.get(Opc
),
1190 addLoadStoreOperands(Addr
, MIB
, createMachineMemOperandFor(Load
));
1192 updateValueMap(Load
, ResultReg
);
1196 bool WebAssemblyFastISel::selectStore(const Instruction
*I
) {
1197 const auto *Store
= cast
<StoreInst
>(I
);
1198 if (Store
->isAtomic())
1200 if (!Subtarget
->hasSIMD128() &&
1201 Store
->getValueOperand()->getType()->isVectorTy())
1205 if (!computeAddress(Store
->getPointerOperand(), Addr
))
1209 bool VTIsi1
= false;
1210 switch (getSimpleType(Store
->getValueOperand()->getType())) {
1215 Opc
= WebAssembly::STORE8_I32
;
1218 Opc
= WebAssembly::STORE16_I32
;
1221 Opc
= WebAssembly::STORE_I32
;
1224 Opc
= WebAssembly::STORE_I64
;
1227 Opc
= WebAssembly::STORE_F32
;
1230 Opc
= WebAssembly::STORE_F64
;
1236 materializeLoadStoreOperands(Addr
);
1238 unsigned ValueReg
= getRegForValue(Store
->getValueOperand());
1242 ValueReg
= maskI1Value(ValueReg
, Store
->getValueOperand());
1244 auto MIB
= BuildMI(*FuncInfo
.MBB
, FuncInfo
.InsertPt
, DbgLoc
, TII
.get(Opc
));
1246 addLoadStoreOperands(Addr
, MIB
, createMachineMemOperandFor(Store
));
1248 MIB
.addReg(ValueReg
);
1252 bool WebAssemblyFastISel::selectBr(const Instruction
*I
) {
1253 const auto *Br
= cast
<BranchInst
>(I
);
1254 if (Br
->isUnconditional()) {
1255 MachineBasicBlock
*MSucc
= FuncInfo
.MBBMap
[Br
->getSuccessor(0)];
1256 fastEmitBranch(MSucc
, Br
->getDebugLoc());
1260 MachineBasicBlock
*TBB
= FuncInfo
.MBBMap
[Br
->getSuccessor(0)];
1261 MachineBasicBlock
*FBB
= FuncInfo
.MBBMap
[Br
->getSuccessor(1)];
1264 unsigned CondReg
= getRegForI1Value(Br
->getCondition(), Not
);
1268 unsigned Opc
= WebAssembly::BR_IF
;
1270 Opc
= WebAssembly::BR_UNLESS
;
1272 BuildMI(*FuncInfo
.MBB
, FuncInfo
.InsertPt
, DbgLoc
, TII
.get(Opc
))
1276 finishCondBranch(Br
->getParent(), TBB
, FBB
);
1280 bool WebAssemblyFastISel::selectRet(const Instruction
*I
) {
1281 if (!FuncInfo
.CanLowerReturn
)
1284 const auto *Ret
= cast
<ReturnInst
>(I
);
1286 if (Ret
->getNumOperands() == 0) {
1287 BuildMI(*FuncInfo
.MBB
, FuncInfo
.InsertPt
, DbgLoc
,
1288 TII
.get(WebAssembly::RETURN_VOID
));
1292 Value
*RV
= Ret
->getOperand(0);
1293 if (!Subtarget
->hasSIMD128() && RV
->getType()->isVectorTy())
1297 switch (getSimpleType(RV
->getType())) {
1302 Opc
= WebAssembly::RETURN_I32
;
1305 Opc
= WebAssembly::RETURN_I64
;
1308 Opc
= WebAssembly::RETURN_F32
;
1311 Opc
= WebAssembly::RETURN_F64
;
1314 Opc
= WebAssembly::RETURN_v16i8
;
1317 Opc
= WebAssembly::RETURN_v8i16
;
1320 Opc
= WebAssembly::RETURN_v4i32
;
1323 Opc
= WebAssembly::RETURN_v2i64
;
1326 Opc
= WebAssembly::RETURN_v4f32
;
1329 Opc
= WebAssembly::RETURN_v2f64
;
1331 case MVT::ExceptRef
:
1332 Opc
= WebAssembly::RETURN_EXCEPT_REF
;
1339 if (FuncInfo
.Fn
->getAttributes().hasAttribute(0, Attribute::SExt
))
1340 Reg
= getRegForSignedValue(RV
);
1341 else if (FuncInfo
.Fn
->getAttributes().hasAttribute(0, Attribute::ZExt
))
1342 Reg
= getRegForUnsignedValue(RV
);
1344 Reg
= getRegForValue(RV
);
1349 BuildMI(*FuncInfo
.MBB
, FuncInfo
.InsertPt
, DbgLoc
, TII
.get(Opc
)).addReg(Reg
);
1353 bool WebAssemblyFastISel::selectUnreachable(const Instruction
*I
) {
1354 BuildMI(*FuncInfo
.MBB
, FuncInfo
.InsertPt
, DbgLoc
,
1355 TII
.get(WebAssembly::UNREACHABLE
));
1359 bool WebAssemblyFastISel::fastSelectInstruction(const Instruction
*I
) {
1360 switch (I
->getOpcode()) {
1361 case Instruction::Call
:
1365 case Instruction::Select
:
1366 return selectSelect(I
);
1367 case Instruction::Trunc
:
1368 return selectTrunc(I
);
1369 case Instruction::ZExt
:
1370 return selectZExt(I
);
1371 case Instruction::SExt
:
1372 return selectSExt(I
);
1373 case Instruction::ICmp
:
1374 return selectICmp(I
);
1375 case Instruction::FCmp
:
1376 return selectFCmp(I
);
1377 case Instruction::BitCast
:
1378 return selectBitCast(I
);
1379 case Instruction::Load
:
1380 return selectLoad(I
);
1381 case Instruction::Store
:
1382 return selectStore(I
);
1383 case Instruction::Br
:
1385 case Instruction::Ret
:
1386 return selectRet(I
);
1387 case Instruction::Unreachable
:
1388 return selectUnreachable(I
);
1393 // Fall back to target-independent instruction selection.
1394 return selectOperator(I
, I
->getOpcode());
1397 FastISel
*WebAssembly::createFastISel(FunctionLoweringInfo
&FuncInfo
,
1398 const TargetLibraryInfo
*LibInfo
) {
1399 return new WebAssemblyFastISel(FuncInfo
, LibInfo
);