57#include "llvm/IR/IntrinsicsAArch64.h"
81class AArch64FastISel final :
public FastISel {
84 using BaseKind =
enum {
90 BaseKind
Kind = RegBase;
96 unsigned OffsetReg = 0;
104 void setKind(BaseKind K) {
Kind =
K; }
105 BaseKind getKind()
const {
return Kind; }
108 bool isRegBase()
const {
return Kind == RegBase; }
109 bool isFIBase()
const {
return Kind == FrameIndexBase; }
111 void setReg(
unsigned Reg) {
112 assert(isRegBase() &&
"Invalid base register access!");
117 assert(isRegBase() &&
"Invalid base register access!");
121 void setOffsetReg(
unsigned Reg) {
125 unsigned getOffsetReg()
const {
129 void setFI(
unsigned FI) {
130 assert(isFIBase() &&
"Invalid base frame index access!");
134 unsigned getFI()
const {
135 assert(isFIBase() &&
"Invalid base frame index access!");
139 void setOffset(int64_t O) {
Offset =
O; }
141 void setShift(
unsigned S) { Shift = S; }
142 unsigned getShift() {
return Shift; }
171 bool selectRem(
const Instruction *
I,
unsigned ISDOpcode);
184 bool isTypeLegal(
Type *Ty,
MVT &VT);
185 bool isTypeSupported(
Type *Ty,
MVT &VT,
bool IsVectorAllowed =
false);
186 bool isValueAvailable(
const Value *V)
const;
187 bool computeAddress(
const Value *Obj, Address &
Addr,
Type *Ty =
nullptr);
188 bool computeCallAddress(
const Value *V, Address &
Addr);
189 bool simplifyAddress(Address &
Addr,
MVT VT);
194 bool tryEmitSmallMemCpy(Address Dest, Address Src,
uint64_t Len,
203 unsigned emitAddSub(
bool UseAdd,
MVT RetVT,
const Value *LHS,
204 const Value *RHS,
bool SetFlags =
false,
205 bool WantResult =
true,
bool IsZExt =
false);
206 unsigned emitAddSub_rr(
bool UseAdd,
MVT RetVT,
unsigned LHSReg,
207 unsigned RHSReg,
bool SetFlags =
false,
208 bool WantResult =
true);
209 unsigned emitAddSub_ri(
bool UseAdd,
MVT RetVT,
unsigned LHSReg,
210 uint64_t Imm,
bool SetFlags =
false,
211 bool WantResult =
true);
212 unsigned emitAddSub_rs(
bool UseAdd,
MVT RetVT,
unsigned LHSReg,
214 uint64_t ShiftImm,
bool SetFlags =
false,
215 bool WantResult =
true);
216 unsigned emitAddSub_rx(
bool UseAdd,
MVT RetVT,
unsigned LHSReg,
218 uint64_t ShiftImm,
bool SetFlags =
false,
219 bool WantResult =
true);
222 bool emitCompareAndBranch(
const BranchInst *BI);
224 bool emitICmp(
MVT RetVT,
const Value *LHS,
const Value *RHS,
bool IsZExt);
225 bool emitICmp_ri(
MVT RetVT,
unsigned LHSReg,
uint64_t Imm);
226 bool emitFCmp(
MVT RetVT,
const Value *LHS,
const Value *RHS);
231 bool emitStoreRelease(
MVT VT,
unsigned SrcReg,
unsigned AddrReg,
233 unsigned emitIntExt(
MVT SrcVT,
unsigned SrcReg,
MVT DestVT,
bool isZExt);
234 unsigned emiti1Ext(
unsigned SrcReg,
MVT DestVT,
bool isZExt);
235 unsigned emitAdd(
MVT RetVT,
const Value *LHS,
const Value *RHS,
236 bool SetFlags =
false,
bool WantResult =
true,
237 bool IsZExt =
false);
238 unsigned emitAdd_ri_(
MVT VT,
unsigned Op0, int64_t Imm);
239 unsigned emitSub(
MVT RetVT,
const Value *LHS,
const Value *RHS,
240 bool SetFlags =
false,
bool WantResult =
true,
241 bool IsZExt =
false);
242 unsigned emitSubs_rr(
MVT RetVT,
unsigned LHSReg,
unsigned RHSReg,
243 bool WantResult =
true);
244 unsigned emitSubs_rs(
MVT RetVT,
unsigned LHSReg,
unsigned RHSReg,
246 bool WantResult =
true);
247 unsigned emitLogicalOp(
unsigned ISDOpc,
MVT RetVT,
const Value *LHS,
249 unsigned emitLogicalOp_ri(
unsigned ISDOpc,
MVT RetVT,
unsigned LHSReg,
251 unsigned emitLogicalOp_rs(
unsigned ISDOpc,
MVT RetVT,
unsigned LHSReg,
252 unsigned RHSReg,
uint64_t ShiftImm);
253 unsigned emitAnd_ri(
MVT RetVT,
unsigned LHSReg,
uint64_t Imm);
254 unsigned emitMul_rr(
MVT RetVT,
unsigned Op0,
unsigned Op1);
255 unsigned emitSMULL_rr(
MVT RetVT,
unsigned Op0,
unsigned Op1);
256 unsigned emitUMULL_rr(
MVT RetVT,
unsigned Op0,
unsigned Op1);
257 unsigned emitLSL_rr(
MVT RetVT,
unsigned Op0Reg,
unsigned Op1Reg);
258 unsigned emitLSL_ri(
MVT RetVT,
MVT SrcVT,
unsigned Op0Reg,
uint64_t Imm,
260 unsigned emitLSR_rr(
MVT RetVT,
unsigned Op0Reg,
unsigned Op1Reg);
261 unsigned emitLSR_ri(
MVT RetVT,
MVT SrcVT,
unsigned Op0Reg,
uint64_t Imm,
263 unsigned emitASR_rr(
MVT RetVT,
unsigned Op0Reg,
unsigned Op1Reg);
264 unsigned emitASR_ri(
MVT RetVT,
MVT SrcVT,
unsigned Op0Reg,
uint64_t Imm,
265 bool IsZExt =
false);
276 bool finishCall(CallLoweringInfo &CLI,
unsigned NumBytes);
293#include "AArch64GenFastISel.inc"
300 assert((isa<ZExtInst>(
I) || isa<SExtInst>(
I)) &&
301 "Unexpected integer extend instruction.");
302 assert(!
I->getType()->isVectorTy() &&
I->getType()->isIntegerTy() &&
303 "Unexpected value type.");
304 bool IsZExt = isa<ZExtInst>(
I);
306 if (
const auto *LI = dyn_cast<LoadInst>(
I->getOperand(0)))
310 if (
const auto *Arg = dyn_cast<Argument>(
I->getOperand(0)))
311 if ((IsZExt && Arg->hasZExtAttr()) || (!IsZExt && Arg->hasSExtAttr()))
342 if (Subtarget->isTargetDarwin())
344 if (Subtarget->isTargetWindows())
349unsigned AArch64FastISel::fastMaterializeAlloca(
const AllocaInst *AI) {
351 "Alloca should always return a pointer.");
354 if (!FuncInfo.StaticAllocaMap.count(AI))
358 FuncInfo.StaticAllocaMap.find(AI);
360 if (SI != FuncInfo.StaticAllocaMap.end()) {
361 Register ResultReg = createResultReg(&AArch64::GPR64spRegClass);
362 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(AArch64::ADDXri),
373unsigned AArch64FastISel::materializeInt(
const ConstantInt *CI,
MVT VT) {
382 : &AArch64::GPR32RegClass;
383 unsigned ZeroReg = (VT == MVT::i64) ? AArch64::XZR : AArch64::WZR;
384 Register ResultReg = createResultReg(RC);
385 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(TargetOpcode::COPY),
390unsigned AArch64FastISel::materializeFP(
const ConstantFP *CFP,
MVT VT) {
394 return fastMaterializeFloatZero(CFP);
396 if (VT != MVT::f32 && VT != MVT::f64)
400 bool Is64Bit = (VT == MVT::f64);
406 unsigned Opc = Is64Bit ? AArch64::FMOVDi : AArch64::FMOVSi;
407 return fastEmitInst_i(Opc, TLI.getRegClassFor(VT), Imm);
412 unsigned Opc1 = Is64Bit ? AArch64::MOVi64imm : AArch64::MOVi32imm;
414 &AArch64::GPR64RegClass : &AArch64::GPR32RegClass;
416 Register TmpReg = createResultReg(RC);
417 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(Opc1), TmpReg)
420 Register ResultReg = createResultReg(TLI.getRegClassFor(VT));
421 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
422 TII.get(TargetOpcode::COPY), ResultReg)
432 unsigned CPI = MCP.getConstantPoolIndex(cast<Constant>(CFP), Alignment);
433 Register ADRPReg = createResultReg(&AArch64::GPR64commonRegClass);
434 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(AArch64::ADRP),
437 unsigned Opc = Is64Bit ? AArch64::LDRDui : AArch64::LDRSui;
438 Register ResultReg = createResultReg(TLI.getRegClassFor(VT));
439 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(Opc), ResultReg)
445unsigned AArch64FastISel::materializeGV(
const GlobalValue *GV) {
452 if (!Subtarget->useSmallAddressing() && !Subtarget->isTargetMachO())
458 unsigned OpFlags = Subtarget->ClassifyGlobalReference(GV, TM);
460 EVT DestEVT = TLI.getValueType(
DL, GV->
getType(),
true);
464 Register ADRPReg = createResultReg(&AArch64::GPR64commonRegClass);
469 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(AArch64::ADRP),
474 if (Subtarget->isTargetILP32()) {
475 ResultReg = createResultReg(&AArch64::GPR32RegClass);
476 LdrOpc = AArch64::LDRWui;
478 ResultReg = createResultReg(&AArch64::GPR64RegClass);
479 LdrOpc = AArch64::LDRXui;
481 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(LdrOpc),
486 if (!Subtarget->isTargetILP32())
491 Register Result64 = createResultReg(&AArch64::GPR64RegClass);
492 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
493 TII.get(TargetOpcode::SUBREG_TO_REG))
501 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(AArch64::ADRP),
519 unsigned DstReg = createResultReg(&AArch64::GPR64commonRegClass);
520 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(AArch64::MOVKXi),
529 ResultReg = createResultReg(&AArch64::GPR64spRegClass);
530 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(AArch64::ADDXri),
540unsigned AArch64FastISel::fastMaterializeConstant(
const Constant *
C) {
541 EVT CEVT = TLI.getValueType(
DL,
C->getType(),
true);
549 if (isa<ConstantPointerNull>(
C)) {
550 assert(VT == MVT::i64 &&
"Expected 64-bit pointers");
554 if (
const auto *CI = dyn_cast<ConstantInt>(
C))
555 return materializeInt(CI, VT);
556 else if (
const ConstantFP *CFP = dyn_cast<ConstantFP>(
C))
557 return materializeFP(CFP, VT);
558 else if (
const GlobalValue *GV = dyn_cast<GlobalValue>(
C))
559 return materializeGV(GV);
564unsigned AArch64FastISel::fastMaterializeFloatZero(
const ConstantFP* CFP) {
566 "Floating-point constant is not a positive zero.");
568 if (!isTypeLegal(CFP->
getType(), VT))
571 if (VT != MVT::f32 && VT != MVT::f64)
574 bool Is64Bit = (VT == MVT::f64);
575 unsigned ZReg = Is64Bit ? AArch64::XZR : AArch64::WZR;
576 unsigned Opc = Is64Bit ? AArch64::FMOVXDr : AArch64::FMOVWSr;
577 return fastEmitInst_r(Opc, TLI.getRegClassFor(VT), ZReg);
582 if (
const auto *
MI = dyn_cast<MulOperator>(
I)) {
583 if (
const auto *
C = dyn_cast<ConstantInt>(
MI->getOperand(0)))
584 if (
C->getValue().isPowerOf2())
586 if (
const auto *
C = dyn_cast<ConstantInt>(
MI->getOperand(1)))
587 if (
C->getValue().isPowerOf2())
594bool AArch64FastISel::computeAddress(
const Value *Obj, Address &
Addr,
Type *Ty)
596 const User *
U =
nullptr;
597 unsigned Opcode = Instruction::UserOp1;
598 if (
const Instruction *
I = dyn_cast<Instruction>(Obj)) {
601 if (FuncInfo.StaticAllocaMap.count(
static_cast<const AllocaInst *
>(Obj)) ||
602 FuncInfo.getMBB(
I->getParent()) == FuncInfo.MBB) {
603 Opcode =
I->getOpcode();
606 }
else if (
const ConstantExpr *
C = dyn_cast<ConstantExpr>(Obj)) {
607 Opcode =
C->getOpcode();
611 if (
auto *Ty = dyn_cast<PointerType>(Obj->
getType()))
612 if (Ty->getAddressSpace() > 255)
620 case Instruction::BitCast:
622 return computeAddress(
U->getOperand(0),
Addr, Ty);
624 case Instruction::IntToPtr:
626 if (TLI.getValueType(
DL,
U->getOperand(0)->getType()) ==
627 TLI.getPointerTy(
DL))
628 return computeAddress(
U->getOperand(0),
Addr, Ty);
631 case Instruction::PtrToInt:
633 if (TLI.getValueType(
DL,
U->getType()) == TLI.getPointerTy(
DL))
634 return computeAddress(
U->getOperand(0),
Addr, Ty);
637 case Instruction::GetElementPtr: {
645 const Value *
Op = GTI.getOperand();
646 if (
StructType *STy = GTI.getStructTypeOrNull()) {
648 unsigned Idx = cast<ConstantInt>(
Op)->getZExtValue();
651 uint64_t S = GTI.getSequentialElementStride(
DL);
658 if (canFoldAddIntoGEP(U,
Op)) {
661 cast<ConstantInt>(cast<AddOperator>(
Op)->getOperand(1));
664 Op = cast<AddOperator>(
Op)->getOperand(0);
668 goto unsupported_gep;
674 Addr.setOffset(TmpOffset);
675 if (computeAddress(
U->getOperand(0),
Addr, Ty))
684 case Instruction::Alloca: {
687 FuncInfo.StaticAllocaMap.find(AI);
688 if (SI != FuncInfo.StaticAllocaMap.end()) {
689 Addr.setKind(Address::FrameIndexBase);
695 case Instruction::Add: {
700 if (isa<ConstantInt>(LHS))
703 if (
const ConstantInt *CI = dyn_cast<ConstantInt>(RHS)) {
705 return computeAddress(LHS,
Addr, Ty);
709 if (computeAddress(LHS,
Addr, Ty) && computeAddress(RHS,
Addr, Ty))
715 case Instruction::Sub: {
720 if (
const ConstantInt *CI = dyn_cast<ConstantInt>(RHS)) {
722 return computeAddress(LHS,
Addr, Ty);
726 case Instruction::Shl: {
727 if (
Addr.getOffsetReg())
730 const auto *CI = dyn_cast<ConstantInt>(
U->getOperand(1));
735 if (Val < 1 || Val > 3)
741 NumBytes = NumBits / 8;
746 if (NumBytes != (1ULL << Val))
752 const Value *Src =
U->getOperand(0);
753 if (
const auto *
I = dyn_cast<Instruction>(Src)) {
754 if (FuncInfo.getMBB(
I->getParent()) == FuncInfo.MBB) {
756 if (
const auto *ZE = dyn_cast<ZExtInst>(
I)) {
758 ZE->getOperand(0)->getType()->isIntegerTy(32)) {
760 Src = ZE->getOperand(0);
762 }
else if (
const auto *SE = dyn_cast<SExtInst>(
I)) {
764 SE->getOperand(0)->getType()->isIntegerTy(32)) {
766 Src = SE->getOperand(0);
772 if (
const auto *AI = dyn_cast<BinaryOperator>(Src))
773 if (AI->
getOpcode() == Instruction::And) {
777 if (
const auto *
C = dyn_cast<ConstantInt>(LHS))
778 if (
C->getValue() == 0xffffffff)
781 if (
const auto *
C = dyn_cast<ConstantInt>(RHS))
782 if (
C->getValue() == 0xffffffff) {
787 Reg = fastEmitInst_extractsubreg(MVT::i32, Reg, AArch64::sub_32);
788 Addr.setOffsetReg(Reg);
796 Addr.setOffsetReg(Reg);
799 case Instruction::Mul: {
800 if (
Addr.getOffsetReg())
810 if (
const auto *
C = dyn_cast<ConstantInt>(LHS))
811 if (
C->getValue().isPowerOf2())
814 assert(isa<ConstantInt>(RHS) &&
"Expected an ConstantInt.");
815 const auto *
C = cast<ConstantInt>(RHS);
816 unsigned Val =
C->getValue().logBase2();
817 if (Val < 1 || Val > 3)
823 NumBytes = NumBits / 8;
828 if (NumBytes != (1ULL << Val))
835 if (
const auto *
I = dyn_cast<Instruction>(Src)) {
836 if (FuncInfo.getMBB(
I->getParent()) == FuncInfo.MBB) {
838 if (
const auto *ZE = dyn_cast<ZExtInst>(
I)) {
840 ZE->getOperand(0)->getType()->isIntegerTy(32)) {
842 Src = ZE->getOperand(0);
844 }
else if (
const auto *SE = dyn_cast<SExtInst>(
I)) {
846 SE->getOperand(0)->getType()->isIntegerTy(32)) {
848 Src = SE->getOperand(0);
857 Addr.setOffsetReg(Reg);
860 case Instruction::And: {
861 if (
Addr.getOffsetReg())
864 if (!Ty ||
DL.getTypeSizeInBits(Ty) != 8)
870 if (
const auto *
C = dyn_cast<ConstantInt>(LHS))
871 if (
C->getValue() == 0xffffffff)
874 if (
const auto *
C = dyn_cast<ConstantInt>(RHS))
875 if (
C->getValue() == 0xffffffff) {
883 Reg = fastEmitInst_extractsubreg(MVT::i32, Reg, AArch64::sub_32);
884 Addr.setOffsetReg(Reg);
889 case Instruction::SExt:
890 case Instruction::ZExt: {
891 if (!
Addr.getReg() ||
Addr.getOffsetReg())
894 const Value *Src =
nullptr;
896 if (
const auto *ZE = dyn_cast<ZExtInst>(U)) {
897 if (!
isIntExtFree(ZE) && ZE->getOperand(0)->getType()->isIntegerTy(32)) {
899 Src = ZE->getOperand(0);
901 }
else if (
const auto *SE = dyn_cast<SExtInst>(U)) {
902 if (!
isIntExtFree(SE) && SE->getOperand(0)->getType()->isIntegerTy(32)) {
904 Src = SE->getOperand(0);
915 Addr.setOffsetReg(Reg);
920 if (
Addr.isRegBase() && !
Addr.getReg()) {
928 if (!
Addr.getOffsetReg()) {
932 Addr.setOffsetReg(Reg);
939bool AArch64FastISel::computeCallAddress(
const Value *V, Address &
Addr) {
940 const User *
U =
nullptr;
941 unsigned Opcode = Instruction::UserOp1;
944 if (
const auto *
I = dyn_cast<Instruction>(V)) {
945 Opcode =
I->getOpcode();
947 InMBB =
I->getParent() == FuncInfo.MBB->getBasicBlock();
948 }
else if (
const auto *
C = dyn_cast<ConstantExpr>(V)) {
949 Opcode =
C->getOpcode();
955 case Instruction::BitCast:
958 return computeCallAddress(
U->getOperand(0),
Addr);
960 case Instruction::IntToPtr:
963 TLI.getValueType(
DL,
U->getOperand(0)->getType()) ==
964 TLI.getPointerTy(
DL))
965 return computeCallAddress(
U->getOperand(0),
Addr);
967 case Instruction::PtrToInt:
969 if (InMBB && TLI.getValueType(
DL,
U->getType()) == TLI.getPointerTy(
DL))
970 return computeCallAddress(
U->getOperand(0),
Addr);
974 if (
const GlobalValue *GV = dyn_cast<GlobalValue>(V)) {
975 Addr.setGlobalValue(GV);
980 if (!
Addr.getGlobalValue()) {
981 Addr.setReg(getRegForValue(V));
982 return Addr.getReg() != 0;
988bool AArch64FastISel::isTypeLegal(
Type *Ty,
MVT &VT) {
989 EVT evt = TLI.getValueType(
DL, Ty,
true);
991 if (Subtarget->isTargetILP32() && Ty->
isPointerTy())
995 if (evt == MVT::Other || !evt.
isSimple())
1000 if (VT == MVT::f128)
1005 return TLI.isTypeLegal(VT);
1012bool AArch64FastISel::isTypeSupported(
Type *Ty,
MVT &VT,
bool IsVectorAllowed) {
1016 if (isTypeLegal(Ty, VT))
1021 if (VT == MVT::i1 || VT == MVT::i8 || VT == MVT::i16)
1027bool AArch64FastISel::isValueAvailable(
const Value *V)
const {
1028 if (!isa<Instruction>(V))
1031 const auto *
I = cast<Instruction>(V);
1032 return FuncInfo.getMBB(
I->getParent()) == FuncInfo.MBB;
1035bool AArch64FastISel::simplifyAddress(Address &
Addr,
MVT VT) {
1036 if (Subtarget->isTargetILP32())
1043 bool ImmediateOffsetNeedsLowering =
false;
1044 bool RegisterOffsetNeedsLowering =
false;
1047 ImmediateOffsetNeedsLowering =
true;
1048 else if (
Offset > 0 && !(
Offset & (ScaleFactor - 1)) &&
1049 !isUInt<12>(
Offset / ScaleFactor))
1050 ImmediateOffsetNeedsLowering =
true;
1055 if (!ImmediateOffsetNeedsLowering &&
Addr.getOffset() &&
Addr.getOffsetReg())
1056 RegisterOffsetNeedsLowering =
true;
1059 if (
Addr.isRegBase() &&
Addr.getOffsetReg() && !
Addr.getReg())
1060 RegisterOffsetNeedsLowering =
true;
1065 if ((ImmediateOffsetNeedsLowering ||
Addr.getOffsetReg()) &&
Addr.isFIBase())
1067 Register ResultReg = createResultReg(&AArch64::GPR64spRegClass);
1068 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(AArch64::ADDXri),
1073 Addr.setKind(Address::RegBase);
1074 Addr.setReg(ResultReg);
1077 if (RegisterOffsetNeedsLowering) {
1078 unsigned ResultReg = 0;
1079 if (
Addr.getReg()) {
1082 ResultReg = emitAddSub_rx(
true, MVT::i64,
Addr.getReg(),
1083 Addr.getOffsetReg(),
Addr.getExtendType(),
1086 ResultReg = emitAddSub_rs(
true, MVT::i64,
Addr.getReg(),
1091 ResultReg = emitLSL_ri(MVT::i64, MVT::i32,
Addr.getOffsetReg(),
1092 Addr.getShift(),
true);
1094 ResultReg = emitLSL_ri(MVT::i64, MVT::i32,
Addr.getOffsetReg(),
1095 Addr.getShift(),
false);
1097 ResultReg = emitLSL_ri(MVT::i64, MVT::i64,
Addr.getOffsetReg(),
1103 Addr.setReg(ResultReg);
1104 Addr.setOffsetReg(0);
1111 if (ImmediateOffsetNeedsLowering) {
1115 ResultReg = emitAdd_ri_(MVT::i64,
Addr.getReg(),
Offset);
1121 Addr.setReg(ResultReg);
1127void AArch64FastISel::addLoadStoreOperands(Address &
Addr,
1130 unsigned ScaleFactor,
1132 int64_t
Offset =
Addr.getOffset() / ScaleFactor;
1134 if (
Addr.isFIBase()) {
1135 int FI =
Addr.getFI();
1138 MMO = FuncInfo.MF->getMachineMemOperand(
1140 MFI.getObjectSize(FI), MFI.getObjectAlign(FI));
1144 assert(
Addr.isRegBase() &&
"Unexpected address kind.");
1151 if (
Addr.getOffsetReg()) {
1152 assert(
Addr.getOffset() == 0 &&
"Unexpected offset");
1167unsigned AArch64FastISel::emitAddSub(
bool UseAdd,
MVT RetVT,
const Value *LHS,
1168 const Value *RHS,
bool SetFlags,
1169 bool WantResult,
bool IsZExt) {
1171 bool NeedExtend =
false;
1194 if (UseAdd && isa<Constant>(LHS) && !isa<Constant>(RHS))
1198 if (UseAdd &&
LHS->
hasOneUse() && isValueAvailable(LHS))
1203 if (UseAdd &&
LHS->
hasOneUse() && isValueAvailable(LHS))
1204 if (
const auto *SI = dyn_cast<BinaryOperator>(LHS))
1205 if (isa<ConstantInt>(
SI->getOperand(1)))
1206 if (
SI->getOpcode() == Instruction::Shl ||
1207 SI->getOpcode() == Instruction::LShr ||
1208 SI->getOpcode() == Instruction::AShr )
1211 Register LHSReg = getRegForValue(LHS);
1216 LHSReg = emitIntExt(SrcVT, LHSReg, RetVT, IsZExt);
1218 unsigned ResultReg = 0;
1219 if (
const auto *
C = dyn_cast<ConstantInt>(RHS)) {
1220 uint64_t Imm = IsZExt ?
C->getZExtValue() :
C->getSExtValue();
1221 if (
C->isNegative())
1222 ResultReg = emitAddSub_ri(!UseAdd, RetVT, LHSReg, -Imm, SetFlags,
1225 ResultReg = emitAddSub_ri(UseAdd, RetVT, LHSReg, Imm, SetFlags,
1227 }
else if (
const auto *
C = dyn_cast<Constant>(RHS))
1228 if (
C->isNullValue())
1229 ResultReg = emitAddSub_ri(UseAdd, RetVT, LHSReg, 0, SetFlags, WantResult);
1236 isValueAvailable(RHS)) {
1237 Register RHSReg = getRegForValue(RHS);
1240 return emitAddSub_rx(UseAdd, RetVT, LHSReg, RHSReg, ExtendType, 0,
1241 SetFlags, WantResult);
1247 const Value *MulLHS = cast<MulOperator>(RHS)->getOperand(0);
1248 const Value *MulRHS = cast<MulOperator>(RHS)->getOperand(1);
1250 if (
const auto *
C = dyn_cast<ConstantInt>(MulLHS))
1251 if (
C->getValue().isPowerOf2())
1254 assert(isa<ConstantInt>(MulRHS) &&
"Expected a ConstantInt.");
1255 uint64_t ShiftVal = cast<ConstantInt>(MulRHS)->getValue().logBase2();
1256 Register RHSReg = getRegForValue(MulLHS);
1259 ResultReg = emitAddSub_rs(UseAdd, RetVT, LHSReg, RHSReg,
AArch64_AM::LSL,
1260 ShiftVal, SetFlags, WantResult);
1268 if (
const auto *SI = dyn_cast<BinaryOperator>(RHS)) {
1269 if (
const auto *
C = dyn_cast<ConstantInt>(
SI->getOperand(1))) {
1271 switch (
SI->getOpcode()) {
1279 Register RHSReg = getRegForValue(
SI->getOperand(0));
1282 ResultReg = emitAddSub_rs(UseAdd, RetVT, LHSReg, RHSReg, ShiftType,
1283 ShiftVal, SetFlags, WantResult);
1291 Register RHSReg = getRegForValue(RHS);
1296 RHSReg = emitIntExt(SrcVT, RHSReg, RetVT, IsZExt);
1298 return emitAddSub_rr(UseAdd, RetVT, LHSReg, RHSReg, SetFlags, WantResult);
1301unsigned AArch64FastISel::emitAddSub_rr(
bool UseAdd,
MVT RetVT,
unsigned LHSReg,
1302 unsigned RHSReg,
bool SetFlags,
1304 assert(LHSReg && RHSReg &&
"Invalid register number.");
1306 if (LHSReg == AArch64::SP || LHSReg == AArch64::WSP ||
1307 RHSReg == AArch64::SP || RHSReg == AArch64::WSP)
1310 if (RetVT != MVT::i32 && RetVT != MVT::i64)
1313 static const unsigned OpcTable[2][2][2] = {
1314 { { AArch64::SUBWrr, AArch64::SUBXrr },
1315 { AArch64::ADDWrr, AArch64::ADDXrr } },
1316 { { AArch64::SUBSWrr, AArch64::SUBSXrr },
1317 { AArch64::ADDSWrr, AArch64::ADDSXrr } }
1319 bool Is64Bit = RetVT == MVT::i64;
1320 unsigned Opc = OpcTable[SetFlags][UseAdd][Is64Bit];
1322 Is64Bit ? &AArch64::GPR64RegClass : &AArch64::GPR32RegClass;
1325 ResultReg = createResultReg(RC);
1327 ResultReg = Is64Bit ? AArch64::XZR : AArch64::WZR;
1332 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
II, ResultReg)
1338unsigned AArch64FastISel::emitAddSub_ri(
bool UseAdd,
MVT RetVT,
unsigned LHSReg,
1341 assert(LHSReg &&
"Invalid register number.");
1343 if (RetVT != MVT::i32 && RetVT != MVT::i64)
1347 if (isUInt<12>(Imm))
1349 else if ((Imm & 0xfff000) == Imm) {
1355 static const unsigned OpcTable[2][2][2] = {
1356 { { AArch64::SUBWri, AArch64::SUBXri },
1357 { AArch64::ADDWri, AArch64::ADDXri } },
1358 { { AArch64::SUBSWri, AArch64::SUBSXri },
1359 { AArch64::ADDSWri, AArch64::ADDSXri } }
1361 bool Is64Bit = RetVT == MVT::i64;
1362 unsigned Opc = OpcTable[SetFlags][UseAdd][Is64Bit];
1365 RC = Is64Bit ? &AArch64::GPR64RegClass : &AArch64::GPR32RegClass;
1367 RC = Is64Bit ? &AArch64::GPR64spRegClass : &AArch64::GPR32spRegClass;
1370 ResultReg = createResultReg(RC);
1372 ResultReg = Is64Bit ? AArch64::XZR : AArch64::WZR;
1376 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
II, ResultReg)
1383unsigned AArch64FastISel::emitAddSub_rs(
bool UseAdd,
MVT RetVT,
unsigned LHSReg,
1388 assert(LHSReg && RHSReg &&
"Invalid register number.");
1389 assert(LHSReg != AArch64::SP && LHSReg != AArch64::WSP &&
1390 RHSReg != AArch64::SP && RHSReg != AArch64::WSP);
1392 if (RetVT != MVT::i32 && RetVT != MVT::i64)
1399 static const unsigned OpcTable[2][2][2] = {
1400 { { AArch64::SUBWrs, AArch64::SUBXrs },
1401 { AArch64::ADDWrs, AArch64::ADDXrs } },
1402 { { AArch64::SUBSWrs, AArch64::SUBSXrs },
1403 { AArch64::ADDSWrs, AArch64::ADDSXrs } }
1405 bool Is64Bit = RetVT == MVT::i64;
1406 unsigned Opc = OpcTable[SetFlags][UseAdd][Is64Bit];
1408 Is64Bit ? &AArch64::GPR64RegClass : &AArch64::GPR32RegClass;
1411 ResultReg = createResultReg(RC);
1413 ResultReg = Is64Bit ? AArch64::XZR : AArch64::WZR;
1418 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
II, ResultReg)
1421 .
addImm(getShifterImm(ShiftType, ShiftImm));
1425unsigned AArch64FastISel::emitAddSub_rx(
bool UseAdd,
MVT RetVT,
unsigned LHSReg,
1430 assert(LHSReg && RHSReg &&
"Invalid register number.");
1431 assert(LHSReg != AArch64::XZR && LHSReg != AArch64::WZR &&
1432 RHSReg != AArch64::XZR && RHSReg != AArch64::WZR);
1434 if (RetVT != MVT::i32 && RetVT != MVT::i64)
1440 static const unsigned OpcTable[2][2][2] = {
1441 { { AArch64::SUBWrx, AArch64::SUBXrx },
1442 { AArch64::ADDWrx, AArch64::ADDXrx } },
1443 { { AArch64::SUBSWrx, AArch64::SUBSXrx },
1444 { AArch64::ADDSWrx, AArch64::ADDSXrx } }
1446 bool Is64Bit = RetVT == MVT::i64;
1447 unsigned Opc = OpcTable[SetFlags][UseAdd][Is64Bit];
1450 RC = Is64Bit ? &AArch64::GPR64RegClass : &AArch64::GPR32RegClass;
1452 RC = Is64Bit ? &AArch64::GPR64spRegClass : &AArch64::GPR32spRegClass;
1455 ResultReg = createResultReg(RC);
1457 ResultReg = Is64Bit ? AArch64::XZR : AArch64::WZR;
1462 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
II, ResultReg)
1465 .
addImm(getArithExtendImm(ExtType, ShiftImm));
1469bool AArch64FastISel::emitCmp(
const Value *LHS,
const Value *RHS,
bool IsZExt) {
1471 EVT EVT = TLI.getValueType(
DL, Ty,
true);
1484 return emitICmp(VT, LHS, RHS, IsZExt);
1487 return emitFCmp(VT, LHS, RHS);
1491bool AArch64FastISel::emitICmp(
MVT RetVT,
const Value *LHS,
const Value *RHS,
1493 return emitSub(RetVT, LHS, RHS,
true,
false,
1497bool AArch64FastISel::emitICmp_ri(
MVT RetVT,
unsigned LHSReg,
uint64_t Imm) {
1498 return emitAddSub_ri(
false, RetVT, LHSReg, Imm,
1502bool AArch64FastISel::emitFCmp(
MVT RetVT,
const Value *LHS,
const Value *RHS) {
1503 if (RetVT != MVT::f32 && RetVT != MVT::f64)
1508 bool UseImm =
false;
1509 if (
const auto *CFP = dyn_cast<ConstantFP>(RHS))
1513 Register LHSReg = getRegForValue(LHS);
1518 unsigned Opc = (RetVT == MVT::f64) ? AArch64::FCMPDri : AArch64::FCMPSri;
1519 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(Opc))
1524 Register RHSReg = getRegForValue(RHS);
1528 unsigned Opc = (RetVT == MVT::f64) ? AArch64::FCMPDrr : AArch64::FCMPSrr;
1529 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(Opc))
1535unsigned AArch64FastISel::emitAdd(
MVT RetVT,
const Value *LHS,
const Value *RHS,
1536 bool SetFlags,
bool WantResult,
bool IsZExt) {
1537 return emitAddSub(
true, RetVT, LHS, RHS, SetFlags, WantResult,
1546unsigned AArch64FastISel::emitAdd_ri_(
MVT VT,
unsigned Op0, int64_t Imm) {
1549 ResultReg = emitAddSub_ri(
false, VT, Op0, -Imm);
1551 ResultReg = emitAddSub_ri(
true, VT, Op0, Imm);
1560 ResultReg = emitAddSub_rr(
true, VT, Op0, CReg);
1564unsigned AArch64FastISel::emitSub(
MVT RetVT,
const Value *LHS,
const Value *RHS,
1565 bool SetFlags,
bool WantResult,
bool IsZExt) {
1566 return emitAddSub(
false, RetVT, LHS, RHS, SetFlags, WantResult,
1570unsigned AArch64FastISel::emitSubs_rr(
MVT RetVT,
unsigned LHSReg,
1571 unsigned RHSReg,
bool WantResult) {
1572 return emitAddSub_rr(
false, RetVT, LHSReg, RHSReg,
1576unsigned AArch64FastISel::emitSubs_rs(
MVT RetVT,
unsigned LHSReg,
1579 uint64_t ShiftImm,
bool WantResult) {
1580 return emitAddSub_rs(
false, RetVT, LHSReg, RHSReg, ShiftType,
1581 ShiftImm,
true, WantResult);
1584unsigned AArch64FastISel::emitLogicalOp(
unsigned ISDOpc,
MVT RetVT,
1587 if (isa<ConstantInt>(LHS) && !isa<ConstantInt>(RHS))
1597 if (
const auto *SI = dyn_cast<ShlOperator>(LHS))
1598 if (isa<ConstantInt>(
SI->getOperand(1)))
1601 Register LHSReg = getRegForValue(LHS);
1605 unsigned ResultReg = 0;
1606 if (
const auto *
C = dyn_cast<ConstantInt>(RHS)) {
1608 ResultReg = emitLogicalOp_ri(ISDOpc, RetVT, LHSReg, Imm);
1616 const Value *MulLHS = cast<MulOperator>(RHS)->getOperand(0);
1617 const Value *MulRHS = cast<MulOperator>(RHS)->getOperand(1);
1619 if (
const auto *
C = dyn_cast<ConstantInt>(MulLHS))
1620 if (
C->getValue().isPowerOf2())
1623 assert(isa<ConstantInt>(MulRHS) &&
"Expected a ConstantInt.");
1624 uint64_t ShiftVal = cast<ConstantInt>(MulRHS)->getValue().logBase2();
1626 Register RHSReg = getRegForValue(MulLHS);
1629 ResultReg = emitLogicalOp_rs(ISDOpc, RetVT, LHSReg, RHSReg, ShiftVal);
1637 if (
const auto *SI = dyn_cast<ShlOperator>(RHS))
1638 if (
const auto *
C = dyn_cast<ConstantInt>(
SI->getOperand(1))) {
1640 Register RHSReg = getRegForValue(
SI->getOperand(0));
1643 ResultReg = emitLogicalOp_rs(ISDOpc, RetVT, LHSReg, RHSReg, ShiftVal);
1649 Register RHSReg = getRegForValue(RHS);
1654 ResultReg = fastEmit_rr(VT, VT, ISDOpc, LHSReg, RHSReg);
1655 if (RetVT >= MVT::i8 && RetVT <= MVT::i16) {
1657 ResultReg = emitAnd_ri(MVT::i32, ResultReg, Mask);
1662unsigned AArch64FastISel::emitLogicalOp_ri(
unsigned ISDOpc,
MVT RetVT,
1665 "ISD nodes are not consecutive!");
1666 static const unsigned OpcTable[3][2] = {
1667 { AArch64::ANDWri, AArch64::ANDXri },
1668 { AArch64::ORRWri, AArch64::ORRXri },
1669 { AArch64::EORWri, AArch64::EORXri }
1682 Opc = OpcTable[
Idx][0];
1683 RC = &AArch64::GPR32spRegClass;
1688 Opc = OpcTable[ISDOpc -
ISD::AND][1];
1689 RC = &AArch64::GPR64spRegClass;
1698 fastEmitInst_ri(Opc, RC, LHSReg,
1700 if (RetVT >= MVT::i8 && RetVT <= MVT::i16 && ISDOpc !=
ISD::AND) {
1702 ResultReg = emitAnd_ri(MVT::i32, ResultReg, Mask);
1707unsigned AArch64FastISel::emitLogicalOp_rs(
unsigned ISDOpc,
MVT RetVT,
1708 unsigned LHSReg,
unsigned RHSReg,
1711 "ISD nodes are not consecutive!");
1712 static const unsigned OpcTable[3][2] = {
1713 { AArch64::ANDWrs, AArch64::ANDXrs },
1714 { AArch64::ORRWrs, AArch64::ORRXrs },
1715 { AArch64::EORWrs, AArch64::EORXrs }
1731 Opc = OpcTable[ISDOpc -
ISD::AND][0];
1732 RC = &AArch64::GPR32RegClass;
1735 Opc = OpcTable[ISDOpc -
ISD::AND][1];
1736 RC = &AArch64::GPR64RegClass;
1740 fastEmitInst_rri(Opc, RC, LHSReg, RHSReg,
1742 if (RetVT >= MVT::i8 && RetVT <= MVT::i16) {
1744 ResultReg = emitAnd_ri(MVT::i32, ResultReg, Mask);
1749unsigned AArch64FastISel::emitAnd_ri(
MVT RetVT,
unsigned LHSReg,
1751 return emitLogicalOp_ri(
ISD::AND, RetVT, LHSReg, Imm);
1754unsigned AArch64FastISel::emitLoad(
MVT VT,
MVT RetVT, Address
Addr,
1756 if (!TLI.allowsMisalignedMemoryAccesses(VT))
1760 if (!simplifyAddress(
Addr, VT))
1769 bool UseScaled =
true;
1770 if ((
Addr.getOffset() < 0) || (
Addr.getOffset() & (ScaleFactor - 1))) {
1775 static const unsigned GPOpcTable[2][8][4] = {
1777 { { AArch64::LDURSBWi, AArch64::LDURSHWi, AArch64::LDURWi,
1779 { AArch64::LDURSBXi, AArch64::LDURSHXi, AArch64::LDURSWi,
1781 { AArch64::LDRSBWui, AArch64::LDRSHWui, AArch64::LDRWui,
1783 { AArch64::LDRSBXui, AArch64::LDRSHXui, AArch64::LDRSWui,
1785 { AArch64::LDRSBWroX, AArch64::LDRSHWroX, AArch64::LDRWroX,
1787 { AArch64::LDRSBXroX, AArch64::LDRSHXroX, AArch64::LDRSWroX,
1789 { AArch64::LDRSBWroW, AArch64::LDRSHWroW, AArch64::LDRWroW,
1791 { AArch64::LDRSBXroW, AArch64::LDRSHXroW, AArch64::LDRSWroW,
1795 { { AArch64::LDURBBi, AArch64::LDURHHi, AArch64::LDURWi,
1797 { AArch64::LDURBBi, AArch64::LDURHHi, AArch64::LDURWi,
1799 { AArch64::LDRBBui, AArch64::LDRHHui, AArch64::LDRWui,
1801 { AArch64::LDRBBui, AArch64::LDRHHui, AArch64::LDRWui,
1803 { AArch64::LDRBBroX, AArch64::LDRHHroX, AArch64::LDRWroX,
1805 { AArch64::LDRBBroX, AArch64::LDRHHroX, AArch64::LDRWroX,
1807 { AArch64::LDRBBroW, AArch64::LDRHHroW, AArch64::LDRWroW,
1809 { AArch64::LDRBBroW, AArch64::LDRHHroW, AArch64::LDRWroW,
1814 static const unsigned FPOpcTable[4][2] = {
1815 { AArch64::LDURSi, AArch64::LDURDi },
1816 { AArch64::LDRSui, AArch64::LDRDui },
1817 { AArch64::LDRSroX, AArch64::LDRDroX },
1818 { AArch64::LDRSroW, AArch64::LDRDroW }
1823 bool UseRegOffset =
Addr.isRegBase() && !
Addr.getOffset() &&
Addr.getReg() &&
1824 Addr.getOffsetReg();
1825 unsigned Idx = UseRegOffset ? 2 : UseScaled ? 1 : 0;
1830 bool IsRet64Bit = RetVT == MVT::i64;
1836 Opc = GPOpcTable[WantZExt][2 *
Idx + IsRet64Bit][0];
1837 RC = (IsRet64Bit && !WantZExt) ?
1838 &AArch64::GPR64RegClass: &AArch64::GPR32RegClass;
1841 Opc = GPOpcTable[WantZExt][2 *
Idx + IsRet64Bit][1];
1842 RC = (IsRet64Bit && !WantZExt) ?
1843 &AArch64::GPR64RegClass: &AArch64::GPR32RegClass;
1846 Opc = GPOpcTable[WantZExt][2 *
Idx + IsRet64Bit][2];
1847 RC = (IsRet64Bit && !WantZExt) ?
1848 &AArch64::GPR64RegClass: &AArch64::GPR32RegClass;
1851 Opc = GPOpcTable[WantZExt][2 *
Idx + IsRet64Bit][3];
1852 RC = &AArch64::GPR64RegClass;
1855 Opc = FPOpcTable[
Idx][0];
1856 RC = &AArch64::FPR32RegClass;
1859 Opc = FPOpcTable[
Idx][1];
1860 RC = &AArch64::FPR64RegClass;
1865 Register ResultReg = createResultReg(RC);
1867 TII.get(Opc), ResultReg);
1871 if (VT == MVT::i1) {
1872 unsigned ANDReg = emitAnd_ri(MVT::i32, ResultReg, 1);
1873 assert(ANDReg &&
"Unexpected AND instruction emission failure.");
1879 if (WantZExt && RetVT == MVT::i64 && VT <= MVT::i32) {
1880 Register Reg64 = createResultReg(&AArch64::GPR64RegClass);
1881 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
1882 TII.get(AArch64::SUBREG_TO_REG), Reg64)
1885 .
addImm(AArch64::sub_32);
1891bool AArch64FastISel::selectAddSub(
const Instruction *
I) {
1893 if (!isTypeSupported(
I->getType(), VT,
true))
1897 return selectOperator(
I,
I->getOpcode());
1900 switch (
I->getOpcode()) {
1903 case Instruction::Add:
1904 ResultReg = emitAdd(VT,
I->getOperand(0),
I->getOperand(1));
1906 case Instruction::Sub:
1907 ResultReg = emitSub(VT,
I->getOperand(0),
I->getOperand(1));
1913 updateValueMap(
I, ResultReg);
1917bool AArch64FastISel::selectLogicalOp(
const Instruction *
I) {
1919 if (!isTypeSupported(
I->getType(), VT,
true))
1923 return selectOperator(
I,
I->getOpcode());
1926 switch (
I->getOpcode()) {
1929 case Instruction::And:
1930 ResultReg = emitLogicalOp(
ISD::AND, VT,
I->getOperand(0),
I->getOperand(1));
1932 case Instruction::Or:
1933 ResultReg = emitLogicalOp(
ISD::OR, VT,
I->getOperand(0),
I->getOperand(1));
1935 case Instruction::Xor:
1936 ResultReg = emitLogicalOp(
ISD::XOR, VT,
I->getOperand(0),
I->getOperand(1));
1942 updateValueMap(
I, ResultReg);
1946bool AArch64FastISel::selectLoad(
const Instruction *
I) {
1951 if (!isTypeSupported(
I->getType(), VT,
true) ||
1952 cast<LoadInst>(
I)->isAtomic())
1955 const Value *SV =
I->getOperand(0);
1956 if (TLI.supportSwiftError()) {
1959 if (
const Argument *Arg = dyn_cast<Argument>(SV)) {
1960 if (Arg->hasSwiftErrorAttr())
1964 if (
const AllocaInst *Alloca = dyn_cast<AllocaInst>(SV)) {
1965 if (Alloca->isSwiftError())
1972 if (!computeAddress(
I->getOperand(0),
Addr,
I->getType()))
1976 bool WantZExt =
true;
1978 const Value *IntExtVal =
nullptr;
1979 if (
I->hasOneUse()) {
1980 if (
const auto *ZE = dyn_cast<ZExtInst>(
I->use_begin()->getUser())) {
1981 if (isTypeSupported(ZE->getType(), RetVT))
1985 }
else if (
const auto *SE = dyn_cast<SExtInst>(
I->use_begin()->getUser())) {
1986 if (isTypeSupported(SE->getType(), RetVT))
1994 unsigned ResultReg =
1995 emitLoad(VT, RetVT,
Addr, WantZExt, createMachineMemOperandFor(
I));
2016 auto *
MI =
MRI.getUniqueVRegDef(Reg);
2018 if (RetVT == MVT::i64 && VT <= MVT::i32) {
2022 ResultReg = std::prev(
I)->getOperand(0).getReg();
2023 removeDeadCode(
I, std::next(
I));
2025 ResultReg = fastEmitInst_extractsubreg(MVT::i32, ResultReg,
2028 updateValueMap(
I, ResultReg);
2037 for (
auto &Opnd :
MI->uses()) {
2039 Reg = Opnd.getReg();
2044 removeDeadCode(
I, std::next(
I));
2047 MI =
MRI.getUniqueVRegDef(Reg);
2049 updateValueMap(IntExtVal, ResultReg);
2053 updateValueMap(
I, ResultReg);
2057bool AArch64FastISel::emitStoreRelease(
MVT VT,
unsigned SrcReg,
2062 default:
return false;
2063 case MVT::i8: Opc = AArch64::STLRB;
break;
2064 case MVT::i16: Opc = AArch64::STLRH;
break;
2065 case MVT::i32: Opc = AArch64::STLRW;
break;
2066 case MVT::i64: Opc = AArch64::STLRX;
break;
2072 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
II)
2079bool AArch64FastISel::emitStore(
MVT VT,
unsigned SrcReg, Address
Addr,
2081 if (!TLI.allowsMisalignedMemoryAccesses(VT))
2085 if (!simplifyAddress(
Addr, VT))
2094 bool UseScaled =
true;
2095 if ((
Addr.getOffset() < 0) || (
Addr.getOffset() & (ScaleFactor - 1))) {
2100 static const unsigned OpcTable[4][6] = {
2101 { AArch64::STURBBi, AArch64::STURHHi, AArch64::STURWi, AArch64::STURXi,
2102 AArch64::STURSi, AArch64::STURDi },
2103 { AArch64::STRBBui, AArch64::STRHHui, AArch64::STRWui, AArch64::STRXui,
2104 AArch64::STRSui, AArch64::STRDui },
2105 { AArch64::STRBBroX, AArch64::STRHHroX, AArch64::STRWroX, AArch64::STRXroX,
2106 AArch64::STRSroX, AArch64::STRDroX },
2107 { AArch64::STRBBroW, AArch64::STRHHroW, AArch64::STRWroW, AArch64::STRXroW,
2108 AArch64::STRSroW, AArch64::STRDroW }
2112 bool VTIsi1 =
false;
2113 bool UseRegOffset =
Addr.isRegBase() && !
Addr.getOffset() &&
Addr.getReg() &&
2114 Addr.getOffsetReg();
2115 unsigned Idx = UseRegOffset ? 2 : UseScaled ? 1 : 0;
2122 case MVT::i1: VTIsi1 =
true; [[fallthrough]];
2123 case MVT::i8: Opc = OpcTable[
Idx][0];
break;
2124 case MVT::i16: Opc = OpcTable[
Idx][1];
break;
2125 case MVT::i32: Opc = OpcTable[
Idx][2];
break;
2126 case MVT::i64: Opc = OpcTable[
Idx][3];
break;
2127 case MVT::f32: Opc = OpcTable[
Idx][4];
break;
2128 case MVT::f64: Opc = OpcTable[
Idx][5];
break;
2132 if (VTIsi1 && SrcReg != AArch64::WZR) {
2133 unsigned ANDReg = emitAnd_ri(MVT::i32, SrcReg, 1);
2134 assert(ANDReg &&
"Unexpected AND instruction emission failure.");
2147bool AArch64FastISel::selectStore(
const Instruction *
I) {
2149 const Value *Op0 =
I->getOperand(0);
2153 if (!isTypeSupported(Op0->
getType(), VT,
true))
2156 const Value *PtrV =
I->getOperand(1);
2157 if (TLI.supportSwiftError()) {
2160 if (
const Argument *Arg = dyn_cast<Argument>(PtrV)) {
2161 if (Arg->hasSwiftErrorAttr())
2165 if (
const AllocaInst *Alloca = dyn_cast<AllocaInst>(PtrV)) {
2166 if (Alloca->isSwiftError())
2173 unsigned SrcReg = 0;
2174 if (
const auto *CI = dyn_cast<ConstantInt>(Op0)) {
2176 SrcReg = (VT == MVT::i64) ? AArch64::XZR : AArch64::WZR;
2177 }
else if (
const auto *CF = dyn_cast<ConstantFP>(Op0)) {
2178 if (CF->isZero() && !CF->isNegative()) {
2180 SrcReg = (VT == MVT::i64) ? AArch64::XZR : AArch64::WZR;
2185 SrcReg = getRegForValue(Op0);
2190 auto *
SI = cast<StoreInst>(
I);
2193 if (
SI->isAtomic()) {
2198 Register AddrReg = getRegForValue(PtrV);
2199 return emitStoreRelease(VT, SrcReg, AddrReg,
2200 createMachineMemOperandFor(
I));
2261bool AArch64FastISel::emitCompareAndBranch(
const BranchInst *BI) {
2265 if (FuncInfo.MF->getFunction().hasFnAttribute(
2266 Attribute::SpeculativeLoadHardening))
2288 if (FuncInfo.MBB->isLayoutSuccessor(
TBB)) {
2295 switch (Predicate) {
2300 if (isa<Constant>(LHS) && cast<Constant>(LHS)->isNullValue())
2303 if (!isa<Constant>(RHS) || !cast<Constant>(RHS)->isNullValue())
2306 if (
const auto *AI = dyn_cast<BinaryOperator>(LHS))
2307 if (AI->
getOpcode() == Instruction::And && isValueAvailable(AI)) {
2311 if (
const auto *
C = dyn_cast<ConstantInt>(AndLHS))
2312 if (
C->getValue().isPowerOf2())
2315 if (
const auto *
C = dyn_cast<ConstantInt>(AndRHS))
2316 if (
C->getValue().isPowerOf2()) {
2317 TestBit =
C->getValue().logBase2();
2329 if (!isa<Constant>(RHS) || !cast<Constant>(RHS)->isNullValue())
2337 if (!isa<ConstantInt>(RHS))
2340 if (cast<ConstantInt>(RHS)->getValue() !=
APInt(BW, -1,
true))
2348 static const unsigned OpcTable[2][2][2] = {
2349 { {AArch64::CBZW, AArch64::CBZX },
2350 {AArch64::CBNZW, AArch64::CBNZX} },
2351 { {AArch64::TBZW, AArch64::TBZX },
2352 {AArch64::TBNZW, AArch64::TBNZX} }
2355 bool IsBitTest = TestBit != -1;
2356 bool Is64Bit = BW == 64;
2357 if (TestBit < 32 && TestBit >= 0)
2360 unsigned Opc = OpcTable[IsBitTest][IsCmpNE][Is64Bit];
2363 Register SrcReg = getRegForValue(LHS);
2367 if (BW == 64 && !Is64Bit)
2368 SrcReg = fastEmitInst_extractsubreg(MVT::i32, SrcReg, AArch64::sub_32);
2370 if ((BW < 32) && !IsBitTest)
2371 SrcReg = emitIntExt(VT, SrcReg, MVT::i32,
true);
2376 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(Opc))
2386bool AArch64FastISel::selectBranch(
const Instruction *
I) {
2398 if (CI->
hasOneUse() && isValueAvailable(CI)) {
2401 switch (Predicate) {
2405 fastEmitBranch(FBB, MIMD.getDL());
2408 fastEmitBranch(
TBB, MIMD.getDL());
2413 if (emitCompareAndBranch(BI))
2417 if (FuncInfo.MBB->isLayoutSuccessor(
TBB)) {
2430 switch (Predicate) {
2446 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(AArch64::Bcc))
2452 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(AArch64::Bcc))
2459 }
else if (
const auto *CI = dyn_cast<ConstantInt>(BI->
getCondition())) {
2462 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(AArch64::B))
2471 FuncInfo.MBB->addSuccessorWithoutProb(
Target);
2483 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(AArch64::Bcc))
2497 unsigned Opcode = AArch64::TBNZW;
2498 if (FuncInfo.MBB->isLayoutSuccessor(
TBB)) {
2500 Opcode = AArch64::TBZW;
2506 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
II)
2507 .
addReg(ConstrainedCondReg)
2515bool AArch64FastISel::selectIndirectBr(
const Instruction *
I) {
2522 if (FuncInfo.MF->getFunction().hasFnAttribute(
"ptrauth-indirect-gotos"))
2532 FuncInfo.MBB->addSuccessor(FuncInfo.getMBB(Succ));
2538 const CmpInst *CI = cast<CmpInst>(
I);
2546 unsigned ResultReg = 0;
2547 switch (Predicate) {
2551 ResultReg = createResultReg(&AArch64::GPR32RegClass);
2552 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
2553 TII.get(TargetOpcode::COPY), ResultReg)
2557 ResultReg = fastEmit_i(MVT::i32, MVT::i32,
ISD::Constant, 1);
2562 updateValueMap(
I, ResultReg);
2570 ResultReg = createResultReg(&AArch64::GPR32RegClass);
2574 static unsigned CondCodeTable[2][2] = {
2579 switch (Predicate) {
2591 Register TmpReg1 = createResultReg(&AArch64::GPR32RegClass);
2592 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(AArch64::CSINCWr),
2597 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(AArch64::CSINCWr),
2603 updateValueMap(
I, ResultReg);
2611 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(AArch64::CSINCWr),
2617 updateValueMap(
I, ResultReg);
2623bool AArch64FastISel::optimizeSelect(
const SelectInst *SI) {
2624 if (!
SI->getType()->isIntegerTy(1))
2627 const Value *Src1Val, *Src2Val;
2629 bool NeedExtraOp =
false;
2630 if (
auto *CI = dyn_cast<ConstantInt>(
SI->getTrueValue())) {
2632 Src1Val =
SI->getCondition();
2633 Src2Val =
SI->getFalseValue();
2634 Opc = AArch64::ORRWrr;
2637 Src1Val =
SI->getFalseValue();
2638 Src2Val =
SI->getCondition();
2639 Opc = AArch64::BICWrr;
2641 }
else if (
auto *CI = dyn_cast<ConstantInt>(
SI->getFalseValue())) {
2643 Src1Val =
SI->getCondition();
2644 Src2Val =
SI->getTrueValue();
2645 Opc = AArch64::ORRWrr;
2649 Src1Val =
SI->getCondition();
2650 Src2Val =
SI->getTrueValue();
2651 Opc = AArch64::ANDWrr;
2658 Register Src1Reg = getRegForValue(Src1Val);
2662 Register Src2Reg = getRegForValue(Src2Val);
2667 Src1Reg = emitLogicalOp_ri(
ISD::XOR, MVT::i32, Src1Reg, 1);
2669 Register ResultReg = fastEmitInst_rr(Opc, &AArch64::GPR32RegClass, Src1Reg,
2671 updateValueMap(SI, ResultReg);
2675bool AArch64FastISel::selectSelect(
const Instruction *
I) {
2676 assert(isa<SelectInst>(
I) &&
"Expected a select instruction.");
2678 if (!isTypeSupported(
I->getType(), VT))
2690 Opc = AArch64::CSELWr;
2691 RC = &AArch64::GPR32RegClass;
2694 Opc = AArch64::CSELXr;
2695 RC = &AArch64::GPR64RegClass;
2698 Opc = AArch64::FCSELSrrr;
2699 RC = &AArch64::FPR32RegClass;
2702 Opc = AArch64::FCSELDrrr;
2703 RC = &AArch64::FPR64RegClass;
2712 if (optimizeSelect(SI))
2716 if (foldXALUIntrinsic(
CC,
I,
Cond)) {
2721 }
else if (isa<CmpInst>(
Cond) && cast<CmpInst>(
Cond)->hasOneUse() &&
2722 isValueAvailable(
Cond)) {
2723 const auto *
Cmp = cast<CmpInst>(
Cond);
2726 const Value *FoldSelect =
nullptr;
2727 switch (Predicate) {
2731 FoldSelect =
SI->getFalseValue();
2734 FoldSelect =
SI->getTrueValue();
2739 Register SrcReg = getRegForValue(FoldSelect);
2743 updateValueMap(
I, SrcReg);
2753 switch (Predicate) {
2775 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
II,
2781 Register Src1Reg = getRegForValue(
SI->getTrueValue());
2782 Register Src2Reg = getRegForValue(
SI->getFalseValue());
2784 if (!Src1Reg || !Src2Reg)
2788 Src2Reg = fastEmitInst_rri(Opc, RC, Src1Reg, Src2Reg, ExtraCC);
2790 Register ResultReg = fastEmitInst_rri(Opc, RC, Src1Reg, Src2Reg,
CC);
2791 updateValueMap(
I, ResultReg);
2795bool AArch64FastISel::selectFPExt(
const Instruction *
I) {
2797 if (!
I->getType()->isDoubleTy() || !
V->getType()->isFloatTy())
2804 Register ResultReg = createResultReg(&AArch64::FPR64RegClass);
2805 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(AArch64::FCVTDSr),
2807 updateValueMap(
I, ResultReg);
2811bool AArch64FastISel::selectFPTrunc(
const Instruction *
I) {
2813 if (!
I->getType()->isFloatTy() || !
V->getType()->isDoubleTy())
2820 Register ResultReg = createResultReg(&AArch64::FPR32RegClass);
2821 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(AArch64::FCVTSDr),
2823 updateValueMap(
I, ResultReg);
2830 if (!isTypeLegal(
I->getType(), DestVT) || DestVT.
isVector())
2833 Register SrcReg = getRegForValue(
I->getOperand(0));
2837 EVT SrcVT = TLI.getValueType(
DL,
I->getOperand(0)->getType(),
true);
2838 if (SrcVT == MVT::f128 || SrcVT == MVT::f16 || SrcVT == MVT::bf16)
2842 if (SrcVT == MVT::f64) {
2844 Opc = (DestVT == MVT::i32) ? AArch64::FCVTZSUWDr : AArch64::FCVTZSUXDr;
2846 Opc = (DestVT == MVT::i32) ? AArch64::FCVTZUUWDr : AArch64::FCVTZUUXDr;
2849 Opc = (DestVT == MVT::i32) ? AArch64::FCVTZSUWSr : AArch64::FCVTZSUXSr;
2851 Opc = (DestVT == MVT::i32) ? AArch64::FCVTZUUWSr : AArch64::FCVTZUUXSr;
2853 Register ResultReg = createResultReg(
2854 DestVT == MVT::i32 ? &AArch64::GPR32RegClass : &AArch64::GPR64RegClass);
2855 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(Opc), ResultReg)
2857 updateValueMap(
I, ResultReg);
2863 if (!isTypeLegal(
I->getType(), DestVT) || DestVT.
isVector())
2866 if (DestVT == MVT::f16 || DestVT == MVT::bf16)
2869 assert((DestVT == MVT::f32 || DestVT == MVT::f64) &&
2870 "Unexpected value type.");
2872 Register SrcReg = getRegForValue(
I->getOperand(0));
2876 EVT SrcVT = TLI.getValueType(
DL,
I->getOperand(0)->getType(),
true);
2879 if (SrcVT == MVT::i16 || SrcVT == MVT::i8 || SrcVT == MVT::i1) {
2887 if (SrcVT == MVT::i64) {
2889 Opc = (DestVT == MVT::f32) ? AArch64::SCVTFUXSri : AArch64::SCVTFUXDri;
2891 Opc = (DestVT == MVT::f32) ? AArch64::UCVTFUXSri : AArch64::UCVTFUXDri;
2894 Opc = (DestVT == MVT::f32) ? AArch64::SCVTFUWSri : AArch64::SCVTFUWDri;
2896 Opc = (DestVT == MVT::f32) ? AArch64::UCVTFUWSri : AArch64::UCVTFUWDri;
2899 Register ResultReg = fastEmitInst_r(Opc, TLI.getRegClassFor(DestVT), SrcReg);
2900 updateValueMap(
I, ResultReg);
2904bool AArch64FastISel::fastLowerArguments() {
2905 if (!FuncInfo.CanLowerReturn)
2916 if (Subtarget->hasCustomCallingConv())
2920 unsigned GPRCnt = 0;
2921 unsigned FPRCnt = 0;
2922 for (
auto const &Arg :
F->args()) {
2923 if (Arg.hasAttribute(Attribute::ByVal) ||
2924 Arg.hasAttribute(Attribute::InReg) ||
2925 Arg.hasAttribute(Attribute::StructRet) ||
2926 Arg.hasAttribute(Attribute::SwiftSelf) ||
2927 Arg.hasAttribute(Attribute::SwiftAsync) ||
2928 Arg.hasAttribute(Attribute::SwiftError) ||
2929 Arg.hasAttribute(Attribute::Nest))
2932 Type *ArgTy = Arg.getType();
2936 EVT ArgVT = TLI.getValueType(
DL, ArgTy);
2945 (!Subtarget->hasNEON() || !Subtarget->isLittleEndian()))
2948 if (VT >= MVT::i1 && VT <= MVT::i64)
2950 else if ((VT >= MVT::f16 && VT <= MVT::f64) || VT.
is64BitVector() ||
2956 if (GPRCnt > 8 || FPRCnt > 8)
2961 { AArch64::W0, AArch64::W1, AArch64::W2, AArch64::W3, AArch64::W4,
2962 AArch64::W5, AArch64::W6, AArch64::W7 },
2963 { AArch64::X0, AArch64::X1, AArch64::X2, AArch64::X3, AArch64::X4,
2964 AArch64::X5, AArch64::X6, AArch64::X7 },
2965 { AArch64::H0, AArch64::H1, AArch64::H2, AArch64::H3, AArch64::H4,
2966 AArch64::H5, AArch64::H6, AArch64::H7 },
2967 { AArch64::S0, AArch64::S1, AArch64::S2, AArch64::S3, AArch64::S4,
2968 AArch64::S5, AArch64::S6, AArch64::S7 },
2969 { AArch64::D0, AArch64::D1, AArch64::D2, AArch64::D3, AArch64::D4,
2970 AArch64::D5, AArch64::D6, AArch64::D7 },
2971 { AArch64::Q0, AArch64::Q1, AArch64::Q2, AArch64::Q3, AArch64::Q4,
2972 AArch64::Q5, AArch64::Q6, AArch64::Q7 }
2976 unsigned FPRIdx = 0;
2977 for (
auto const &Arg :
F->args()) {
2978 MVT VT = TLI.getSimpleValueType(
DL, Arg.getType());
2981 if (VT >= MVT::i1 && VT <= MVT::i32) {
2983 RC = &AArch64::GPR32RegClass;
2985 }
else if (VT == MVT::i64) {
2987 RC = &AArch64::GPR64RegClass;
2988 }
else if (VT == MVT::f16 || VT == MVT::bf16) {
2990 RC = &AArch64::FPR16RegClass;
2991 }
else if (VT == MVT::f32) {
2993 RC = &AArch64::FPR32RegClass;
2996 RC = &AArch64::FPR64RegClass;
2999 RC = &AArch64::FPR128RegClass;
3003 Register DstReg = FuncInfo.MF->addLiveIn(SrcReg, RC);
3007 Register ResultReg = createResultReg(RC);
3008 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
3009 TII.get(TargetOpcode::COPY), ResultReg)
3011 updateValueMap(&Arg, ResultReg);
3016bool AArch64FastISel::processCallArgs(CallLoweringInfo &CLI,
3018 unsigned &NumBytes) {
3021 CCState CCInfo(
CC,
false, *FuncInfo.MF, ArgLocs, *Context);
3022 CCInfo.AnalyzeCallOperands(OutVTs, CLI.OutFlags, CCAssignFnForCall(
CC));
3025 NumBytes = CCInfo.getStackSize();
3028 unsigned AdjStackDown =
TII.getCallFrameSetupOpcode();
3029 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(AdjStackDown))
3034 const Value *ArgVal = CLI.OutVals[VA.getValNo()];
3035 MVT ArgVT = OutVTs[VA.getValNo()];
3037 Register ArgReg = getRegForValue(ArgVal);
3042 switch (VA.getLocInfo()) {
3046 MVT DestVT = VA.getLocVT();
3048 ArgReg = emitIntExt(SrcVT, ArgReg, DestVT,
false);
3056 MVT DestVT = VA.getLocVT();
3058 ArgReg = emitIntExt(SrcVT, ArgReg, DestVT,
true);
3068 if (VA.isRegLoc() && !VA.needsCustom()) {
3069 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
3070 TII.get(TargetOpcode::COPY), VA.getLocReg()).
addReg(ArgReg);
3071 CLI.OutRegs.push_back(VA.getLocReg());
3072 }
else if (VA.needsCustom()) {
3076 assert(VA.isMemLoc() &&
"Assuming store on stack.");
3079 if (isa<UndefValue>(ArgVal))
3085 unsigned BEAlign = 0;
3086 if (ArgSize < 8 && !Subtarget->isLittleEndian())
3087 BEAlign = 8 - ArgSize;
3090 Addr.setKind(Address::RegBase);
3091 Addr.setReg(AArch64::SP);
3092 Addr.setOffset(VA.getLocMemOffset() + BEAlign);
3106bool AArch64FastISel::finishCall(CallLoweringInfo &CLI,
unsigned NumBytes) {
3110 unsigned AdjStackUp =
TII.getCallFrameDestroyOpcode();
3111 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(AdjStackUp))
3116 CCState CCInfo(
CC,
false, *FuncInfo.MF, RVLocs, *Context);
3117 CCInfo.AnalyzeCallResult(CLI.Ins, CCAssignFnForCall(
CC));
3119 Register ResultReg = FuncInfo.CreateRegs(CLI.RetTy);
3120 for (
unsigned i = 0; i != RVLocs.
size(); ++i) {
3123 unsigned CopyReg = ResultReg + i;
3126 if (CopyVT.
isVector() && !Subtarget->isLittleEndian())
3130 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(TargetOpcode::COPY),
3136 CLI.ResultReg = ResultReg;
3137 CLI.NumResultRegs = RVLocs.
size();
3142bool AArch64FastISel::fastLowerCall(CallLoweringInfo &CLI) {
3144 bool IsTailCall = CLI.IsTailCall;
3145 bool IsVarArg = CLI.IsVarArg;
3149 if (!Callee && !Symbol)
3154 if (CLI.CB && CLI.CB->hasFnAttr(Attribute::ReturnsTwice) &&
3155 !Subtarget->noBTIAtReturnTwice() &&
3160 if (CLI.CB && CLI.CB->isIndirectCall() &&
3170 if (Subtarget->isTargetILP32())
3184 if (MF->getFunction().getParent()->getRtLibUseGOT())
3191 if (Subtarget->isWindowsArm64EC())
3194 for (
auto Flag : CLI.OutFlags)
3196 Flag.isSwiftSelf() ||
Flag.isSwiftAsync() ||
Flag.isSwiftError())
3201 OutVTs.
reserve(CLI.OutVals.size());
3203 for (
auto *Val : CLI.OutVals) {
3205 if (!isTypeLegal(Val->getType(), VT) &&
3206 !(VT == MVT::i1 || VT == MVT::i8 || VT == MVT::i16))
3217 if (Callee && !computeCallAddress(Callee,
Addr))
3223 if (Subtarget->isTargetWindows() &&
Addr.getGlobalValue() &&
3224 Addr.getGlobalValue()->hasExternalWeakLinkage())
3229 if (!processCallArgs(CLI, OutVTs, NumBytes))
3233 if (
RegInfo->isAnyArgRegReserved(*MF))
3234 RegInfo->emitReservedArgRegCallError(*MF);
3238 if (Subtarget->useSmallAddressing()) {
3241 MIB =
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
II);
3244 else if (
Addr.getGlobalValue())
3246 else if (
Addr.getReg()) {
3252 unsigned CallReg = 0;
3254 Register ADRPReg = createResultReg(&AArch64::GPR64commonRegClass);
3255 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(AArch64::ADRP),
3259 CallReg = createResultReg(&AArch64::GPR64RegClass);
3260 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
3261 TII.get(AArch64::LDRXui), CallReg)
3265 }
else if (
Addr.getGlobalValue())
3266 CallReg = materializeGV(
Addr.getGlobalValue());
3267 else if (
Addr.getReg())
3268 CallReg =
Addr.getReg();
3275 MIB =
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
II).
addReg(CallReg);
3279 for (
auto Reg : CLI.OutRegs)
3289 return finishCall(CLI, NumBytes);
3294 return Len / Alignment->value() <= 4;
3299bool AArch64FastISel::tryEmitSmallMemCpy(Address Dest, Address Src,
3302 if (!isMemCpySmall(Len, Alignment))
3305 int64_t UnscaledOffset = 0;
3311 if (!Alignment || *Alignment >= 8) {
3322 assert(Alignment &&
"Alignment is set in this branch");
3324 if (Len >= 4 && *Alignment == 4)
3326 else if (Len >= 2 && *Alignment == 2)
3333 unsigned ResultReg =
emitLoad(VT, VT, Src);
3342 UnscaledOffset +=
Size;
3345 Dest.setOffset(OrigDest.getOffset() + UnscaledOffset);
3346 Src.setOffset(OrigSrc.getOffset() + UnscaledOffset);
3357 if (!isa<ExtractValueInst>(
Cond))
3360 const auto *EV = cast<ExtractValueInst>(
Cond);
3361 if (!isa<IntrinsicInst>(EV->getAggregateOperand()))
3364 const auto *
II = cast<IntrinsicInst>(EV->getAggregateOperand());
3368 cast<StructType>(
Callee->getReturnType())->getTypeAtIndex(0U);
3369 if (!isTypeLegal(
RetTy, RetVT))
3372 if (RetVT != MVT::i32 && RetVT != MVT::i64)
3379 if (isa<ConstantInt>(LHS) && !isa<ConstantInt>(RHS) &&
II->isCommutative())
3387 case Intrinsic::smul_with_overflow:
3388 if (
const auto *
C = dyn_cast<ConstantInt>(RHS))
3389 if (
C->getValue() == 2)
3390 IID = Intrinsic::sadd_with_overflow;
3392 case Intrinsic::umul_with_overflow:
3393 if (
const auto *
C = dyn_cast<ConstantInt>(RHS))
3394 if (
C->getValue() == 2)
3395 IID = Intrinsic::uadd_with_overflow;
3403 case Intrinsic::sadd_with_overflow:
3404 case Intrinsic::ssub_with_overflow:
3407 case Intrinsic::uadd_with_overflow:
3410 case Intrinsic::usub_with_overflow:
3413 case Intrinsic::smul_with_overflow:
3414 case Intrinsic::umul_with_overflow:
3420 if (!isValueAvailable(
II))
3426 for (
auto Itr = std::prev(Start); Itr !=
End; --Itr) {
3429 if (!isa<ExtractValueInst>(Itr))
3433 const auto *EVI = cast<ExtractValueInst>(Itr);
3434 if (EVI->getAggregateOperand() !=
II)
3442bool AArch64FastISel::fastLowerIntrinsicCall(
const IntrinsicInst *
II) {
3444 switch (
II->getIntrinsicID()) {
3445 default:
return false;
3446 case Intrinsic::frameaddress: {
3452 Register SrcReg =
MRI.createVirtualRegister(&AArch64::GPR64RegClass);
3453 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
3461 unsigned Depth = cast<ConstantInt>(
II->getOperand(0))->getZExtValue();
3463 DestReg = fastEmitInst_ri(AArch64::LDRXui, &AArch64::GPR64RegClass,
3465 assert(DestReg &&
"Unexpected LDR instruction emission failure.");
3469 updateValueMap(
II, SrcReg);
3472 case Intrinsic::sponentry: {
3477 Register ResultReg = createResultReg(&AArch64::GPR64spRegClass);
3478 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
3479 TII.get(AArch64::ADDXri), ResultReg)
3484 updateValueMap(
II, ResultReg);
3487 case Intrinsic::memcpy:
3488 case Intrinsic::memmove: {
3489 const auto *MTI = cast<MemTransferInst>(
II);
3491 if (MTI->isVolatile())
3496 bool IsMemCpy = (
II->getIntrinsicID() == Intrinsic::memcpy);
3497 if (isa<ConstantInt>(MTI->getLength()) && IsMemCpy) {
3500 uint64_t Len = cast<ConstantInt>(MTI->getLength())->getZExtValue();
3502 if (MTI->getDestAlign() || MTI->getSourceAlign())
3503 Alignment = std::min(MTI->getDestAlign().valueOrOne(),
3504 MTI->getSourceAlign().valueOrOne());
3505 if (isMemCpySmall(Len, Alignment)) {
3507 if (!computeAddress(MTI->getRawDest(), Dest) ||
3508 !computeAddress(MTI->getRawSource(), Src))
3510 if (tryEmitSmallMemCpy(Dest, Src, Len, Alignment))
3515 if (!MTI->getLength()->getType()->isIntegerTy(64))
3518 if (MTI->getSourceAddressSpace() > 255 || MTI->getDestAddressSpace() > 255)
3523 const char *IntrMemName = isa<MemCpyInst>(
II) ?
"memcpy" :
"memmove";
3524 return lowerCallTo(
II, IntrMemName,
II->arg_size() - 1);
3526 case Intrinsic::memset: {
3540 return lowerCallTo(
II,
"memset",
II->arg_size() - 1);
3542 case Intrinsic::sin:
3543 case Intrinsic::cos:
3544 case Intrinsic::tan:
3545 case Intrinsic::pow: {
3547 if (!isTypeLegal(
II->getType(), RetVT))
3550 if (RetVT != MVT::f32 && RetVT != MVT::f64)
3554 {RTLIB::SIN_F32, RTLIB::SIN_F64},
3555 {RTLIB::COS_F32, RTLIB::COS_F64},
3556 {RTLIB::TAN_F32, RTLIB::TAN_F64},
3557 {RTLIB::POW_F32, RTLIB::POW_F64}};
3559 bool Is64Bit = RetVT == MVT::f64;
3560 switch (
II->getIntrinsicID()) {
3563 case Intrinsic::sin:
3564 LC = LibCallTable[0][Is64Bit];
3566 case Intrinsic::cos:
3567 LC = LibCallTable[1][Is64Bit];
3569 case Intrinsic::tan:
3570 LC = LibCallTable[2][Is64Bit];
3572 case Intrinsic::pow:
3573 LC = LibCallTable[3][Is64Bit];
3578 Args.reserve(
II->arg_size());
3581 for (
auto &Arg :
II->args()) {
3584 Entry.Ty = Arg->getType();
3585 Args.push_back(Entry);
3588 CallLoweringInfo CLI;
3590 CLI.setCallee(
DL, Ctx, TLI.getLibcallCallingConv(LC),
II->getType(),
3591 TLI.getLibcallName(LC), std::move(Args));
3592 if (!lowerCallTo(CLI))
3594 updateValueMap(
II, CLI.ResultReg);
3597 case Intrinsic::fabs: {
3599 if (!isTypeLegal(
II->getType(), VT))
3607 Opc = AArch64::FABSSr;
3610 Opc = AArch64::FABSDr;
3613 Register SrcReg = getRegForValue(
II->getOperand(0));
3616 Register ResultReg = createResultReg(TLI.getRegClassFor(VT));
3617 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(Opc), ResultReg)
3619 updateValueMap(
II, ResultReg);
3622 case Intrinsic::trap:
3623 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(AArch64::BRK))
3626 case Intrinsic::debugtrap:
3627 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(AArch64::BRK))
3631 case Intrinsic::sqrt: {
3632 Type *
RetTy =
II->getCalledFunction()->getReturnType();
3635 if (!isTypeLegal(
RetTy, VT))
3638 Register Op0Reg = getRegForValue(
II->getOperand(0));
3642 unsigned ResultReg = fastEmit_r(VT, VT,
ISD::FSQRT, Op0Reg);
3646 updateValueMap(
II, ResultReg);
3649 case Intrinsic::sadd_with_overflow:
3650 case Intrinsic::uadd_with_overflow:
3651 case Intrinsic::ssub_with_overflow:
3652 case Intrinsic::usub_with_overflow:
3653 case Intrinsic::smul_with_overflow:
3654 case Intrinsic::umul_with_overflow: {
3657 auto *Ty = cast<StructType>(
Callee->getReturnType());
3661 if (!isTypeLegal(
RetTy, VT))
3664 if (VT != MVT::i32 && VT != MVT::i64)
3670 if (isa<ConstantInt>(LHS) && !isa<ConstantInt>(RHS) &&
II->isCommutative())
3678 case Intrinsic::smul_with_overflow:
3679 if (
const auto *
C = dyn_cast<ConstantInt>(RHS))
3680 if (
C->getValue() == 2) {
3681 IID = Intrinsic::sadd_with_overflow;
3685 case Intrinsic::umul_with_overflow:
3686 if (
const auto *
C = dyn_cast<ConstantInt>(RHS))
3687 if (
C->getValue() == 2) {
3688 IID = Intrinsic::uadd_with_overflow;
3694 unsigned ResultReg1 = 0, ResultReg2 = 0, MulReg = 0;
3698 case Intrinsic::sadd_with_overflow:
3699 ResultReg1 = emitAdd(VT, LHS, RHS,
true);
3702 case Intrinsic::uadd_with_overflow:
3703 ResultReg1 = emitAdd(VT, LHS, RHS,
true);
3706 case Intrinsic::ssub_with_overflow:
3707 ResultReg1 = emitSub(VT, LHS, RHS,
true);
3710 case Intrinsic::usub_with_overflow:
3711 ResultReg1 = emitSub(VT, LHS, RHS,
true);
3714 case Intrinsic::smul_with_overflow: {
3716 Register LHSReg = getRegForValue(LHS);
3720 Register RHSReg = getRegForValue(RHS);
3724 if (VT == MVT::i32) {
3725 MulReg = emitSMULL_rr(MVT::i64, LHSReg, RHSReg);
3727 fastEmitInst_extractsubreg(VT, MulReg, AArch64::sub_32);
3729 emitAddSub_rx(
false, MVT::i64, MulReg, MulSubReg,
3734 assert(VT == MVT::i64 &&
"Unexpected value type.");
3737 MulReg = emitMul_rr(VT, LHSReg, RHSReg);
3738 unsigned SMULHReg = fastEmit_rr(VT, VT,
ISD::MULHS, LHSReg, RHSReg);
3744 case Intrinsic::umul_with_overflow: {
3746 Register LHSReg = getRegForValue(LHS);
3750 Register RHSReg = getRegForValue(RHS);
3754 if (VT == MVT::i32) {
3755 MulReg = emitUMULL_rr(MVT::i64, LHSReg, RHSReg);
3757 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
3758 TII.get(AArch64::ANDSXri), AArch64::XZR)
3761 MulReg = fastEmitInst_extractsubreg(VT, MulReg, AArch64::sub_32);
3763 assert(VT == MVT::i64 &&
"Unexpected value type.");
3766 MulReg = emitMul_rr(VT, LHSReg, RHSReg);
3767 unsigned UMULHReg = fastEmit_rr(VT, VT,
ISD::MULHU, LHSReg, RHSReg);
3768 emitSubs_rr(VT, AArch64::XZR, UMULHReg,
false);
3775 ResultReg1 = createResultReg(TLI.getRegClassFor(VT));
3776 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
3777 TII.get(TargetOpcode::COPY), ResultReg1).
addReg(MulReg);
3783 ResultReg2 = fastEmitInst_rri(AArch64::CSINCWr, &AArch64::GPR32RegClass,
3784 AArch64::WZR, AArch64::WZR,
3785 getInvertedCondCode(
CC));
3787 assert((ResultReg1 + 1) == ResultReg2 &&
3788 "Nonconsecutive result registers.");
3789 updateValueMap(
II, ResultReg1, 2);
3792 case Intrinsic::aarch64_crc32b:
3793 case Intrinsic::aarch64_crc32h:
3794 case Intrinsic::aarch64_crc32w:
3795 case Intrinsic::aarch64_crc32x:
3796 case Intrinsic::aarch64_crc32cb:
3797 case Intrinsic::aarch64_crc32ch:
3798 case Intrinsic::aarch64_crc32cw:
3799 case Intrinsic::aarch64_crc32cx: {
3800 if (!Subtarget->hasCRC())
3804 switch (
II->getIntrinsicID()) {
3807 case Intrinsic::aarch64_crc32b:
3808 Opc = AArch64::CRC32Brr;
3810 case Intrinsic::aarch64_crc32h:
3811 Opc = AArch64::CRC32Hrr;
3813 case Intrinsic::aarch64_crc32w:
3814 Opc = AArch64::CRC32Wrr;
3816 case Intrinsic::aarch64_crc32x:
3817 Opc = AArch64::CRC32Xrr;
3819 case Intrinsic::aarch64_crc32cb:
3820 Opc = AArch64::CRC32CBrr;
3822 case Intrinsic::aarch64_crc32ch:
3823 Opc = AArch64::CRC32CHrr;
3825 case Intrinsic::aarch64_crc32cw:
3826 Opc = AArch64::CRC32CWrr;
3828 case Intrinsic::aarch64_crc32cx:
3829 Opc = AArch64::CRC32CXrr;
3833 Register LHSReg = getRegForValue(
II->getArgOperand(0));
3834 Register RHSReg = getRegForValue(
II->getArgOperand(1));
3835 if (!LHSReg || !RHSReg)
3839 fastEmitInst_rr(Opc, &AArch64::GPR32RegClass, LHSReg, RHSReg);
3840 updateValueMap(
II, ResultReg);
3849 const Function &
F = *
I->getParent()->getParent();
3851 if (!FuncInfo.CanLowerReturn)
3857 if (TLI.supportSwiftError() &&
3858 F.getAttributes().hasAttrSomewhere(Attribute::SwiftError))
3861 if (TLI.supportSplitCSR(FuncInfo.MF))
3867 if (
Ret->getNumOperands() > 0) {
3874 CCState CCInfo(
CC,
F.isVarArg(), *FuncInfo.MF, ValLocs,
I->getContext());
3878 if (ValLocs.
size() != 1)
3882 const Value *RV =
Ret->getOperand(0);
3900 if (!
MRI.getRegClass(SrcReg)->contains(DestReg))
3909 !Subtarget->isLittleEndian())
3913 if (RVVT == MVT::f128)
3918 if (RVVT != DestVT) {
3919 if (RVVT != MVT::i1 && RVVT != MVT::i8 && RVVT != MVT::i16)
3922 if (!Outs[0].
Flags.isZExt() && !Outs[0].Flags.isSExt())
3925 bool IsZExt = Outs[0].Flags.isZExt();
3926 SrcReg = emitIntExt(RVVT, SrcReg, DestVT, IsZExt);
3934 SrcReg = emitAnd_ri(MVT::i64, SrcReg, 0xffffffff);
3937 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
3938 TII.get(TargetOpcode::COPY), DestReg).
addReg(SrcReg);
3945 TII.get(AArch64::RET_ReallyLR));
3946 for (
unsigned RetReg : RetRegs)
3951bool AArch64FastISel::selectTrunc(
const Instruction *
I) {
3952 Type *DestTy =
I->getType();
3954 Type *SrcTy =
Op->getType();
3956 EVT SrcEVT = TLI.getValueType(
DL, SrcTy,
true);
3957 EVT DestEVT = TLI.getValueType(
DL, DestTy,
true);
3966 if (SrcVT != MVT::i64 && SrcVT != MVT::i32 && SrcVT != MVT::i16 &&
3969 if (DestVT != MVT::i32 && DestVT != MVT::i16 && DestVT != MVT::i8 &&
3983 if (SrcVT == MVT::i64) {
4000 Register Reg32 = fastEmitInst_extractsubreg(MVT::i32, SrcReg,
4003 ResultReg = emitAnd_ri(MVT::i32, Reg32, Mask);
4004 assert(ResultReg &&
"Unexpected AND instruction emission failure.");
4006 ResultReg = createResultReg(&AArch64::GPR32RegClass);
4007 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
4008 TII.get(TargetOpcode::COPY), ResultReg)
4012 updateValueMap(
I, ResultReg);
4016unsigned AArch64FastISel::emiti1Ext(
unsigned SrcReg,
MVT DestVT,
bool IsZExt) {
4017 assert((DestVT == MVT::i8 || DestVT == MVT::i16 || DestVT == MVT::i32 ||
4018 DestVT == MVT::i64) &&
4019 "Unexpected value type.");
4021 if (DestVT == MVT::i8 || DestVT == MVT::i16)
4025 unsigned ResultReg = emitAnd_ri(MVT::i32, SrcReg, 1);
4026 assert(ResultReg &&
"Unexpected AND instruction emission failure.");
4027 if (DestVT == MVT::i64) {
4030 Register Reg64 =
MRI.createVirtualRegister(&AArch64::GPR64RegClass);
4031 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
4032 TII.get(AArch64::SUBREG_TO_REG), Reg64)
4035 .
addImm(AArch64::sub_32);
4040 if (DestVT == MVT::i64) {
4044 return fastEmitInst_rii(AArch64::SBFMWri, &AArch64::GPR32RegClass, SrcReg,
4049unsigned AArch64FastISel::emitMul_rr(
MVT RetVT,
unsigned Op0,
unsigned Op1) {
4057 Opc = AArch64::MADDWrrr; ZReg = AArch64::WZR;
break;
4059 Opc = AArch64::MADDXrrr; ZReg = AArch64::XZR;
break;
4063 (RetVT == MVT::i64) ? &AArch64::GPR64RegClass : &AArch64::GPR32RegClass;
4064 return fastEmitInst_rrr(Opc, RC, Op0, Op1, ZReg);
4067unsigned AArch64FastISel::emitSMULL_rr(
MVT RetVT,
unsigned Op0,
unsigned Op1) {
4068 if (RetVT != MVT::i64)
4071 return fastEmitInst_rrr(AArch64::SMADDLrrr, &AArch64::GPR64RegClass,
4072 Op0, Op1, AArch64::XZR);
4075unsigned AArch64FastISel::emitUMULL_rr(
MVT RetVT,
unsigned Op0,
unsigned Op1) {
4076 if (RetVT != MVT::i64)
4079 return fastEmitInst_rrr(AArch64::UMADDLrrr, &AArch64::GPR64RegClass,
4080 Op0, Op1, AArch64::XZR);
4083unsigned AArch64FastISel::emitLSL_rr(
MVT RetVT,
unsigned Op0Reg,
4086 bool NeedTrunc =
false;
4090 case MVT::i8: Opc = AArch64::LSLVWr; NeedTrunc =
true;
Mask = 0xff;
break;
4091 case MVT::i16: Opc = AArch64::LSLVWr; NeedTrunc =
true;
Mask = 0xffff;
break;
4092 case MVT::i32: Opc = AArch64::LSLVWr;
break;
4093 case MVT::i64: Opc = AArch64::LSLVXr;
break;
4097 (RetVT == MVT::i64) ? &AArch64::GPR64RegClass : &AArch64::GPR32RegClass;
4099 Op1Reg = emitAnd_ri(MVT::i32, Op1Reg, Mask);
4101 Register ResultReg = fastEmitInst_rr(Opc, RC, Op0Reg, Op1Reg);
4103 ResultReg = emitAnd_ri(MVT::i32, ResultReg, Mask);
4107unsigned AArch64FastISel::emitLSL_ri(
MVT RetVT,
MVT SrcVT,
unsigned Op0,
4110 "Unexpected source/return type pair.");
4111 assert((SrcVT == MVT::i1 || SrcVT == MVT::i8 || SrcVT == MVT::i16 ||
4112 SrcVT == MVT::i32 || SrcVT == MVT::i64) &&
4113 "Unexpected source value type.");
4114 assert((RetVT == MVT::i8 || RetVT == MVT::i16 || RetVT == MVT::i32 ||
4115 RetVT == MVT::i64) &&
"Unexpected return value type.");
4117 bool Is64Bit = (RetVT == MVT::i64);
4118 unsigned RegSize = Is64Bit ? 64 : 32;
4122 Is64Bit ? &AArch64::GPR64RegClass : &AArch64::GPR32RegClass;
4126 if (RetVT == SrcVT) {
4127 Register ResultReg = createResultReg(RC);
4128 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
4129 TII.get(TargetOpcode::COPY), ResultReg)
4133 return emitIntExt(SrcVT, Op0, RetVT, IsZExt);
4137 if (Shift >= DstBits)
4165 unsigned ImmR =
RegSize - Shift;
4167 unsigned ImmS = std::min<unsigned>(SrcBits - 1, DstBits - 1 - Shift);
4168 static const unsigned OpcTable[2][2] = {
4169 {AArch64::SBFMWri, AArch64::SBFMXri},
4170 {AArch64::UBFMWri, AArch64::UBFMXri}
4172 unsigned Opc = OpcTable[IsZExt][Is64Bit];
4173 if (SrcVT.
SimpleTy <= MVT::i32 && RetVT == MVT::i64) {
4175 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
4176 TII.get(AArch64::SUBREG_TO_REG), TmpReg)
4179 .
addImm(AArch64::sub_32);
4182 return fastEmitInst_rii(Opc, RC, Op0, ImmR, ImmS);
4185unsigned AArch64FastISel::emitLSR_rr(
MVT RetVT,
unsigned Op0Reg,
4188 bool NeedTrunc =
false;
4192 case MVT::i8: Opc = AArch64::LSRVWr; NeedTrunc =
true;
Mask = 0xff;
break;
4193 case MVT::i16: Opc = AArch64::LSRVWr; NeedTrunc =
true;
Mask = 0xffff;
break;
4194 case MVT::i32: Opc = AArch64::LSRVWr;
break;
4195 case MVT::i64: Opc = AArch64::LSRVXr;
break;
4199 (RetVT == MVT::i64) ? &AArch64::GPR64RegClass : &AArch64::GPR32RegClass;
4201 Op0Reg = emitAnd_ri(MVT::i32, Op0Reg, Mask);
4202 Op1Reg = emitAnd_ri(MVT::i32, Op1Reg, Mask);
4204 Register ResultReg = fastEmitInst_rr(Opc, RC, Op0Reg, Op1Reg);
4206 ResultReg = emitAnd_ri(MVT::i32, ResultReg, Mask);
4210unsigned AArch64FastISel::emitLSR_ri(
MVT RetVT,
MVT SrcVT,
unsigned Op0,
4213 "Unexpected source/return type pair.");
4214 assert((SrcVT == MVT::i1 || SrcVT == MVT::i8 || SrcVT == MVT::i16 ||
4215 SrcVT == MVT::i32 || SrcVT == MVT::i64) &&
4216 "Unexpected source value type.");
4217 assert((RetVT == MVT::i8 || RetVT == MVT::i16 || RetVT == MVT::i32 ||
4218 RetVT == MVT::i64) &&
"Unexpected return value type.");
4220 bool Is64Bit = (RetVT == MVT::i64);
4221 unsigned RegSize = Is64Bit ? 64 : 32;
4225 Is64Bit ? &AArch64::GPR64RegClass : &AArch64::GPR32RegClass;
4229 if (RetVT == SrcVT) {
4230 Register ResultReg = createResultReg(RC);
4231 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
4232 TII.get(TargetOpcode::COPY), ResultReg)
4236 return emitIntExt(SrcVT, Op0, RetVT, IsZExt);
4240 if (Shift >= DstBits)
4268 if (Shift >= SrcBits && IsZExt)
4269 return materializeInt(ConstantInt::get(*Context,
APInt(
RegSize, 0)), RetVT);
4274 Op0 = emitIntExt(SrcVT, Op0, RetVT, IsZExt);
4282 unsigned ImmR = std::min<unsigned>(SrcBits - 1, Shift);
4283 unsigned ImmS = SrcBits - 1;
4284 static const unsigned OpcTable[2][2] = {
4285 {AArch64::SBFMWri, AArch64::SBFMXri},
4286 {AArch64::UBFMWri, AArch64::UBFMXri}
4288 unsigned Opc = OpcTable[IsZExt][Is64Bit];
4289 if (SrcVT.
SimpleTy <= MVT::i32 && RetVT == MVT::i64) {
4291 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
4292 TII.get(AArch64::SUBREG_TO_REG), TmpReg)
4295 .
addImm(AArch64::sub_32);
4298 return fastEmitInst_rii(Opc, RC, Op0, ImmR, ImmS);
4301unsigned AArch64FastISel::emitASR_rr(
MVT RetVT,
unsigned Op0Reg,
4304 bool NeedTrunc =
false;
4308 case MVT::i8: Opc = AArch64::ASRVWr; NeedTrunc =
true;
Mask = 0xff;
break;
4309 case MVT::i16: Opc = AArch64::ASRVWr; NeedTrunc =
true;
Mask = 0xffff;
break;
4310 case MVT::i32: Opc = AArch64::ASRVWr;
break;
4311 case MVT::i64: Opc = AArch64::ASRVXr;
break;
4315 (RetVT == MVT::i64) ? &AArch64::GPR64RegClass : &AArch64::GPR32RegClass;
4317 Op0Reg = emitIntExt(RetVT, Op0Reg, MVT::i32,
false);
4318 Op1Reg = emitAnd_ri(MVT::i32, Op1Reg, Mask);
4320 Register ResultReg = fastEmitInst_rr(Opc, RC, Op0Reg, Op1Reg);
4322 ResultReg = emitAnd_ri(MVT::i32, ResultReg, Mask);
4326unsigned AArch64FastISel::emitASR_ri(
MVT RetVT,
MVT SrcVT,
unsigned Op0,
4329 "Unexpected source/return type pair.");
4330 assert((SrcVT == MVT::i1 || SrcVT == MVT::i8 || SrcVT == MVT::i16 ||
4331 SrcVT == MVT::i32 || SrcVT == MVT::i64) &&
4332 "Unexpected source value type.");
4333 assert((RetVT == MVT::i8 || RetVT == MVT::i16 || RetVT == MVT::i32 ||
4334 RetVT == MVT::i64) &&
"Unexpected return value type.");
4336 bool Is64Bit = (RetVT == MVT::i64);
4337 unsigned RegSize = Is64Bit ? 64 : 32;
4341 Is64Bit ? &AArch64::GPR64RegClass : &AArch64::GPR32RegClass;
4345 if (RetVT == SrcVT) {
4346 Register ResultReg = createResultReg(RC);
4347 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
4348 TII.get(TargetOpcode::COPY), ResultReg)
4352 return emitIntExt(SrcVT, Op0, RetVT, IsZExt);
4356 if (Shift >= DstBits)
4384 if (Shift >= SrcBits && IsZExt)
4385 return materializeInt(ConstantInt::get(*Context,
APInt(
RegSize, 0)), RetVT);
4387 unsigned ImmR = std::min<unsigned>(SrcBits - 1, Shift);
4388 unsigned ImmS = SrcBits - 1;
4389 static const unsigned OpcTable[2][2] = {
4390 {AArch64::SBFMWri, AArch64::SBFMXri},
4391 {AArch64::UBFMWri, AArch64::UBFMXri}
4393 unsigned Opc = OpcTable[IsZExt][Is64Bit];
4394 if (SrcVT.
SimpleTy <= MVT::i32 && RetVT == MVT::i64) {
4396 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
4397 TII.get(AArch64::SUBREG_TO_REG), TmpReg)
4400 .
addImm(AArch64::sub_32);
4403 return fastEmitInst_rii(Opc, RC, Op0, ImmR, ImmS);
4406unsigned AArch64FastISel::emitIntExt(
MVT SrcVT,
unsigned SrcReg,
MVT DestVT,
4408 assert(DestVT != MVT::i1 &&
"ZeroExt/SignExt an i1?");
4414 if (((DestVT != MVT::i8) && (DestVT != MVT::i16) &&
4415 (DestVT != MVT::i32) && (DestVT != MVT::i64)) ||
4416 ((SrcVT != MVT::i1) && (SrcVT != MVT::i8) &&
4417 (SrcVT != MVT::i16) && (SrcVT != MVT::i32)))
4427 return emiti1Ext(SrcReg, DestVT, IsZExt);
4429 if (DestVT == MVT::i64)
4430 Opc = IsZExt ? AArch64::UBFMXri : AArch64::SBFMXri;
4432 Opc = IsZExt ? AArch64::UBFMWri : AArch64::SBFMWri;
4436 if (DestVT == MVT::i64)
4437 Opc = IsZExt ? AArch64::UBFMXri : AArch64::SBFMXri;
4439 Opc = IsZExt ? AArch64::UBFMWri : AArch64::SBFMWri;
4443 assert(DestVT == MVT::i64 &&
"IntExt i32 to i32?!?");
4444 Opc = IsZExt ? AArch64::UBFMXri : AArch64::SBFMXri;
4450 if (DestVT == MVT::i8 || DestVT == MVT::i16)
4452 else if (DestVT == MVT::i64) {
4453 Register Src64 =
MRI.createVirtualRegister(&AArch64::GPR64RegClass);
4454 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
4455 TII.get(AArch64::SUBREG_TO_REG), Src64)
4458 .
addImm(AArch64::sub_32);
4463 (DestVT == MVT::i64) ? &AArch64::GPR64RegClass : &AArch64::GPR32RegClass;
4464 return fastEmitInst_rii(Opc, RC, SrcReg, 0, Imm);
4471 case AArch64::LDURBBi:
4472 case AArch64::LDURHHi:
4473 case AArch64::LDURWi:
4474 case AArch64::LDRBBui:
4475 case AArch64::LDRHHui:
4476 case AArch64::LDRWui:
4477 case AArch64::LDRBBroX:
4478 case AArch64::LDRHHroX:
4479 case AArch64::LDRWroX:
4480 case AArch64::LDRBBroW:
4481 case AArch64::LDRHHroW:
4482 case AArch64::LDRWroW:
4491 case AArch64::LDURSBWi:
4492 case AArch64::LDURSHWi:
4493 case AArch64::LDURSBXi:
4494 case AArch64::LDURSHXi:
4495 case AArch64::LDURSWi:
4496 case AArch64::LDRSBWui:
4497 case AArch64::LDRSHWui:
4498 case AArch64::LDRSBXui:
4499 case AArch64::LDRSHXui:
4500 case AArch64::LDRSWui:
4501 case AArch64::LDRSBWroX:
4502 case AArch64::LDRSHWroX:
4503 case AArch64::LDRSBXroX:
4504 case AArch64::LDRSHXroX:
4505 case AArch64::LDRSWroX:
4506 case AArch64::LDRSBWroW:
4507 case AArch64::LDRSHWroW:
4508 case AArch64::LDRSBXroW:
4509 case AArch64::LDRSHXroW:
4510 case AArch64::LDRSWroW:
4515bool AArch64FastISel::optimizeIntExtLoad(
const Instruction *
I,
MVT RetVT,
4517 const auto *LI = dyn_cast<LoadInst>(
I->getOperand(0));
4518 if (!LI || !LI->hasOneUse())
4532 bool IsZExt = isa<ZExtInst>(
I);
4533 const auto *LoadMI =
MI;
4534 if (LoadMI->getOpcode() == TargetOpcode::COPY &&
4535 LoadMI->getOperand(1).getSubReg() == AArch64::sub_32) {
4536 Register LoadReg =
MI->getOperand(1).getReg();
4537 LoadMI =
MRI.getUniqueVRegDef(LoadReg);
4538 assert(LoadMI &&
"Expected valid instruction");
4544 if (RetVT != MVT::i64 || SrcVT > MVT::i32) {
4545 updateValueMap(
I, Reg);
4550 Register Reg64 = createResultReg(&AArch64::GPR64RegClass);
4551 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
4552 TII.get(AArch64::SUBREG_TO_REG), Reg64)
4555 .
addImm(AArch64::sub_32);
4558 assert((
MI->getOpcode() == TargetOpcode::COPY &&
4559 MI->getOperand(1).getSubReg() == AArch64::sub_32) &&
4560 "Expected copy instruction");
4561 Reg =
MI->getOperand(1).getReg();
4563 removeDeadCode(
I, std::next(
I));
4565 updateValueMap(
I, Reg);
4569bool AArch64FastISel::selectIntExt(
const Instruction *
I) {
4570 assert((isa<ZExtInst>(
I) || isa<SExtInst>(
I)) &&
4571 "Unexpected integer extend instruction.");
4574 if (!isTypeSupported(
I->getType(), RetVT))
4577 if (!isTypeSupported(
I->getOperand(0)->getType(), SrcVT))
4581 if (optimizeIntExtLoad(
I, RetVT, SrcVT))
4584 Register SrcReg = getRegForValue(
I->getOperand(0));
4589 bool IsZExt = isa<ZExtInst>(
I);
4590 if (
const auto *Arg = dyn_cast<Argument>(
I->getOperand(0))) {
4591 if ((IsZExt && Arg->hasZExtAttr()) || (!IsZExt && Arg->hasSExtAttr())) {
4592 if (RetVT == MVT::i64 && SrcVT != MVT::i64) {
4593 Register ResultReg = createResultReg(&AArch64::GPR64RegClass);
4594 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
4595 TII.get(AArch64::SUBREG_TO_REG), ResultReg)
4598 .
addImm(AArch64::sub_32);
4602 updateValueMap(
I, SrcReg);
4607 unsigned ResultReg = emitIntExt(SrcVT, SrcReg, RetVT, IsZExt);
4611 updateValueMap(
I, ResultReg);
4615bool AArch64FastISel::selectRem(
const Instruction *
I,
unsigned ISDOpcode) {
4616 EVT DestEVT = TLI.getValueType(
DL,
I->getType(),
true);
4621 if (DestVT != MVT::i64 && DestVT != MVT::i32)
4625 bool Is64bit = (DestVT == MVT::i64);
4626 switch (ISDOpcode) {
4630 DivOpc = Is64bit ? AArch64::SDIVXr : AArch64::SDIVWr;
4633 DivOpc = Is64bit ? AArch64::UDIVXr : AArch64::UDIVWr;
4636 unsigned MSubOpc = Is64bit ? AArch64::MSUBXrrr : AArch64::MSUBWrrr;
4637 Register Src0Reg = getRegForValue(
I->getOperand(0));
4641 Register Src1Reg = getRegForValue(
I->getOperand(1));
4646 (DestVT == MVT::i64) ? &AArch64::GPR64RegClass : &AArch64::GPR32RegClass;
4647 Register QuotReg = fastEmitInst_rr(DivOpc, RC, Src0Reg, Src1Reg);
4648 assert(QuotReg &&
"Unexpected DIV instruction emission failure.");
4651 Register ResultReg = fastEmitInst_rrr(MSubOpc, RC, QuotReg, Src1Reg, Src0Reg);
4652 updateValueMap(
I, ResultReg);
4658 if (!isTypeSupported(
I->getType(), VT,
true))
4664 const Value *Src0 =
I->getOperand(0);
4665 const Value *Src1 =
I->getOperand(1);
4666 if (
const auto *
C = dyn_cast<ConstantInt>(Src0))
4667 if (
C->getValue().isPowerOf2())
4671 if (
const auto *
C = dyn_cast<ConstantInt>(Src1))
4672 if (
C->getValue().isPowerOf2()) {
4673 uint64_t ShiftVal =
C->getValue().logBase2();
4676 if (
const auto *ZExt = dyn_cast<ZExtInst>(Src0)) {
4679 if (isValueAvailable(ZExt) && isTypeSupported(ZExt->getSrcTy(), VT)) {
4682 Src0 = ZExt->getOperand(0);
4685 }
else if (
const auto *SExt = dyn_cast<SExtInst>(Src0)) {
4688 if (isValueAvailable(SExt) && isTypeSupported(SExt->getSrcTy(), VT)) {
4691 Src0 = SExt->getOperand(0);
4696 Register Src0Reg = getRegForValue(Src0);
4700 unsigned ResultReg =
4701 emitLSL_ri(VT, SrcVT, Src0Reg, ShiftVal, IsZExt);
4704 updateValueMap(
I, ResultReg);
4709 Register Src0Reg = getRegForValue(
I->getOperand(0));
4713 Register Src1Reg = getRegForValue(
I->getOperand(1));
4717 unsigned ResultReg = emitMul_rr(VT, Src0Reg, Src1Reg);
4722 updateValueMap(
I, ResultReg);
4726bool AArch64FastISel::selectShift(
const Instruction *
I) {
4728 if (!isTypeSupported(
I->getType(), RetVT,
true))
4732 return selectOperator(
I,
I->getOpcode());
4734 if (
const auto *
C = dyn_cast<ConstantInt>(
I->getOperand(1))) {
4735 unsigned ResultReg = 0;
4738 bool IsZExt =
I->getOpcode() != Instruction::AShr;
4739 const Value *Op0 =
I->getOperand(0);
4740 if (
const auto *ZExt = dyn_cast<ZExtInst>(Op0)) {
4743 if (isValueAvailable(ZExt) && isTypeSupported(ZExt->getSrcTy(), TmpVT)) {
4746 Op0 = ZExt->getOperand(0);
4749 }
else if (
const auto *SExt = dyn_cast<SExtInst>(Op0)) {
4752 if (isValueAvailable(SExt) && isTypeSupported(SExt->getSrcTy(), TmpVT)) {
4755 Op0 = SExt->getOperand(0);
4760 Register Op0Reg = getRegForValue(Op0);
4764 switch (
I->getOpcode()) {
4766 case Instruction::Shl:
4767 ResultReg = emitLSL_ri(RetVT, SrcVT, Op0Reg, ShiftVal, IsZExt);
4769 case Instruction::AShr:
4770 ResultReg = emitASR_ri(RetVT, SrcVT, Op0Reg, ShiftVal, IsZExt);
4772 case Instruction::LShr:
4773 ResultReg = emitLSR_ri(RetVT, SrcVT, Op0Reg, ShiftVal, IsZExt);
4779 updateValueMap(
I, ResultReg);
4783 Register Op0Reg = getRegForValue(
I->getOperand(0));
4787 Register Op1Reg = getRegForValue(
I->getOperand(1));
4791 unsigned ResultReg = 0;
4792 switch (
I->getOpcode()) {
4794 case Instruction::Shl:
4795 ResultReg = emitLSL_rr(RetVT, Op0Reg, Op1Reg);
4797 case Instruction::AShr:
4798 ResultReg = emitASR_rr(RetVT, Op0Reg, Op1Reg);
4800 case Instruction::LShr:
4801 ResultReg = emitLSR_rr(RetVT, Op0Reg, Op1Reg);
4808 updateValueMap(
I, ResultReg);
4812bool AArch64FastISel::selectBitCast(
const Instruction *
I) {
4815 if (!isTypeLegal(
I->getOperand(0)->getType(), SrcVT))
4817 if (!isTypeLegal(
I->getType(), RetVT))
4821 if (RetVT == MVT::f32 && SrcVT == MVT::i32)
4822 Opc = AArch64::FMOVWSr;
4823 else if (RetVT == MVT::f64 && SrcVT == MVT::i64)
4824 Opc = AArch64::FMOVXDr;
4825 else if (RetVT == MVT::i32 && SrcVT == MVT::f32)
4826 Opc = AArch64::FMOVSWr;
4827 else if (RetVT == MVT::i64 && SrcVT == MVT::f64)
4828 Opc = AArch64::FMOVDXr;
4835 case MVT::i32: RC = &AArch64::GPR32RegClass;
break;
4836 case MVT::i64: RC = &AArch64::GPR64RegClass;
break;
4837 case MVT::f32: RC = &AArch64::FPR32RegClass;
break;
4838 case MVT::f64: RC = &AArch64::FPR64RegClass;
break;
4840 Register Op0Reg = getRegForValue(
I->getOperand(0));
4844 Register ResultReg = fastEmitInst_r(Opc, RC, Op0Reg);
4848 updateValueMap(
I, ResultReg);
4852bool AArch64FastISel::selectFRem(
const Instruction *
I) {
4854 if (!isTypeLegal(
I->getType(), RetVT))
4862 LC = RTLIB::REM_F32;
4865 LC = RTLIB::REM_F64;
4870 Args.reserve(
I->getNumOperands());
4873 for (
auto &Arg :
I->operands()) {
4876 Entry.Ty = Arg->getType();
4877 Args.push_back(Entry);
4880 CallLoweringInfo CLI;
4882 CLI.setCallee(
DL, Ctx, TLI.getLibcallCallingConv(LC),
I->getType(),
4883 TLI.getLibcallName(LC), std::move(Args));
4884 if (!lowerCallTo(CLI))
4886 updateValueMap(
I, CLI.ResultReg);
4890bool AArch64FastISel::selectSDiv(
const Instruction *
I) {
4892 if (!isTypeLegal(
I->getType(), VT))
4895 if (!isa<ConstantInt>(
I->getOperand(1)))
4898 const APInt &
C = cast<ConstantInt>(
I->getOperand(1))->getValue();
4899 if ((VT != MVT::i32 && VT != MVT::i64) || !
C ||
4900 !(
C.isPowerOf2() ||
C.isNegatedPowerOf2()))
4903 unsigned Lg2 =
C.countr_zero();
4904 Register Src0Reg = getRegForValue(
I->getOperand(0));
4908 if (cast<BinaryOperator>(
I)->isExact()) {
4909 unsigned ResultReg = emitASR_ri(VT, VT, Src0Reg, Lg2);
4912 updateValueMap(
I, ResultReg);
4916 int64_t Pow2MinusOne = (1ULL << Lg2) - 1;
4917 unsigned AddReg = emitAdd_ri_(VT, Src0Reg, Pow2MinusOne);
4922 if (!emitICmp_ri(VT, Src0Reg, 0))
4927 if (VT == MVT::i64) {
4928 SelectOpc = AArch64::CSELXr;
4929 RC = &AArch64::GPR64RegClass;
4931 SelectOpc = AArch64::CSELWr;
4932 RC = &AArch64::GPR32RegClass;
4934 Register SelectReg = fastEmitInst_rri(SelectOpc, RC, AddReg, Src0Reg,
4941 unsigned ZeroReg = (VT == MVT::i64) ? AArch64::XZR : AArch64::WZR;
4944 ResultReg = emitAddSub_rs(
false, VT, ZeroReg, SelectReg,
4947 ResultReg = emitASR_ri(VT, VT, SelectReg, Lg2);
4952 updateValueMap(
I, ResultReg);
4959unsigned AArch64FastISel::getRegForGEPIndex(
const Value *
Idx) {
4966 MVT PtrVT = TLI.getPointerTy(
DL);
4968 if (IdxVT.
bitsLT(PtrVT)) {
4969 IdxN = emitIntExt(IdxVT.
getSimpleVT(), IdxN, PtrVT,
false);
4970 }
else if (IdxVT.
bitsGT(PtrVT))
4971 llvm_unreachable(
"AArch64 FastISel doesn't support types larger than i64");
4979bool AArch64FastISel::selectGetElementPtr(
const Instruction *
I) {
4980 if (Subtarget->isTargetILP32())
4983 Register N = getRegForValue(
I->getOperand(0));
4990 MVT VT = TLI.getPointerTy(
DL);
4993 const Value *
Idx = GTI.getOperand();
4994 if (
auto *StTy = GTI.getStructTypeOrNull()) {
4995 unsigned Field = cast<ConstantInt>(
Idx)->getZExtValue();
4998 TotalOffs +=
DL.getStructLayout(StTy)->getElementOffset(
Field);
5001 if (
const auto *CI = dyn_cast<ConstantInt>(
Idx)) {
5005 TotalOffs += GTI.getSequentialElementStride(
DL) *
5006 cast<ConstantInt>(CI)->getSExtValue();
5010 N = emitAdd_ri_(VT,
N, TotalOffs);
5017 uint64_t ElementSize = GTI.getSequentialElementStride(
DL);
5018 unsigned IdxN = getRegForGEPIndex(
Idx);
5022 if (ElementSize != 1) {
5026 IdxN = emitMul_rr(VT, IdxN,
C);
5036 N = emitAdd_ri_(VT,
N, TotalOffs);
5040 updateValueMap(
I,
N);
5045 assert(
TM.getOptLevel() == CodeGenOptLevel::None &&
5046 "cmpxchg survived AtomicExpand at optlevel > -O0");
5048 auto *RetPairTy = cast<StructType>(
I->getType());
5049 Type *
RetTy = RetPairTy->getTypeAtIndex(0U);
5050 assert(RetPairTy->getTypeAtIndex(1U)->isIntegerTy(1) &&
5051 "cmpxchg has a non-i1 status result");
5054 if (!isTypeLegal(
RetTy, VT))
5058 unsigned Opc, CmpOpc;
5061 if (VT == MVT::i32) {
5062 Opc = AArch64::CMP_SWAP_32;
5063 CmpOpc = AArch64::SUBSWrs;
5064 ResRC = &AArch64::GPR32RegClass;
5065 }
else if (VT == MVT::i64) {
5066 Opc = AArch64::CMP_SWAP_64;
5067 CmpOpc = AArch64::SUBSXrs;
5068 ResRC = &AArch64::GPR64RegClass;
5076 II, getRegForValue(
I->getPointerOperand()),
II.getNumDefs());
5078 II, getRegForValue(
I->getCompareOperand()),
II.getNumDefs() + 1);
5080 II, getRegForValue(
I->getNewValOperand()),
II.getNumDefs() + 2);
5082 const Register ResultReg1 = createResultReg(ResRC);
5083 const Register ResultReg2 = createResultReg(&AArch64::GPR32RegClass);
5084 const Register ScratchReg = createResultReg(&AArch64::GPR32RegClass);
5087 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
II)
5094 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(CmpOpc))
5095 .
addDef(VT == MVT::i32 ? AArch64::WZR : AArch64::XZR)
5100 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(AArch64::CSINCWr))
5106 assert((ResultReg1 + 1) == ResultReg2 &&
"Nonconsecutive result registers.");
5107 updateValueMap(
I, ResultReg1, 2);
5111bool AArch64FastISel::fastSelectInstruction(
const Instruction *
I) {
5112 if (TLI.fallBackToDAGISel(*
I))
5114 switch (
I->getOpcode()) {
5117 case Instruction::Add:
5118 case Instruction::Sub:
5119 return selectAddSub(
I);
5120 case Instruction::Mul:
5121 return selectMul(
I);
5122 case Instruction::SDiv:
5123 return selectSDiv(
I);
5124 case Instruction::SRem:
5128 case Instruction::URem:
5132 case Instruction::Shl:
5133 case Instruction::LShr:
5134 case Instruction::AShr:
5135 return selectShift(
I);
5136 case Instruction::And:
5137 case Instruction::Or:
5138 case Instruction::Xor:
5139 return selectLogicalOp(
I);
5140 case Instruction::Br:
5141 return selectBranch(
I);
5142 case Instruction::IndirectBr:
5143 return selectIndirectBr(
I);
5144 case Instruction::BitCast:
5146 return selectBitCast(
I);
5148 case Instruction::FPToSI:
5150 return selectFPToInt(
I,
true);
5152 case Instruction::FPToUI:
5153 return selectFPToInt(
I,
false);
5154 case Instruction::ZExt:
5155 case Instruction::SExt:
5156 return selectIntExt(
I);
5157 case Instruction::Trunc:
5159 return selectTrunc(
I);
5161 case Instruction::FPExt:
5162 return selectFPExt(
I);
5163 case Instruction::FPTrunc:
5164 return selectFPTrunc(
I);
5165 case Instruction::SIToFP:
5167 return selectIntToFP(
I,
true);
5169 case Instruction::UIToFP:
5170 return selectIntToFP(
I,
false);
5171 case Instruction::Load:
5172 return selectLoad(
I);
5173 case Instruction::Store:
5174 return selectStore(
I);
5175 case Instruction::FCmp:
5176 case Instruction::ICmp:
5177 return selectCmp(
I);
5178 case Instruction::Select:
5179 return selectSelect(
I);
5180 case Instruction::Ret:
5181 return selectRet(
I);
5182 case Instruction::FRem:
5183 return selectFRem(
I);
5184 case Instruction::GetElementPtr:
5185 return selectGetElementPtr(
I);
5186 case Instruction::AtomicCmpXchg:
5187 return selectAtomicCmpXchg(cast<AtomicCmpXchgInst>(
I));
5191 return selectOperator(
I,
I->getOpcode());
5202 return new AArch64FastISel(FuncInfo, LibInfo);
unsigned const MachineRegisterInfo * MRI
static bool isIntExtFree(const Instruction *I)
Check if the sign-/zero-extend will be a noop.
static bool isSExtLoad(const MachineInstr *LI)
static AArch64CC::CondCode getCompareCC(CmpInst::Predicate Pred)
static bool isMulPowOf2(const Value *I)
Check if the multiply is by a power-of-2 constant.
static unsigned getImplicitScaleFactor(MVT VT)
Determine the implicit scale factor that is applied by a memory operation for a given value type.
static bool isZExtLoad(const MachineInstr *LI)
static unsigned selectBinaryOp(unsigned GenericOpc, unsigned RegBankID, unsigned OpSize)
Select the AArch64 opcode for the basic binary operation GenericOpc (such as G_OR or G_SDIV),...
static void emitLoad(MachineFunction &MF, MachineBasicBlock &MBB, MachineBasicBlock::iterator Pos, const TargetInstrInfo &TII, unsigned Reg1, unsigned Reg2, int Offset, bool IsPostDec)
Emit a load-pair instruction for frame-destroy.
static void emitStore(MachineFunction &MF, MachineBasicBlock &MBB, MachineBasicBlock::iterator Pos, const TargetInstrInfo &TII, unsigned Reg1, unsigned Reg2, int Offset, bool IsPreDec)
Emit a store-pair instruction for frame-setup.
This file declares a class to represent arbitrary precision floating point values and provide a varie...
This file implements a class to represent arbitrary precision integral constant values and operations...
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
Atomic ordering constants.
This file contains the simple types necessary to represent the attributes associated with functions a...
This file contains the declarations for the subclasses of Constant, which represent the different fla...
Returns the sub type a function will return at a given Idx Should correspond to the result type of an ExtractValue instruction executed with just that one unsigned Idx
This file defines the DenseMap class.
This file defines the FastISel class.
const HexagonInstrInfo * TII
Module.h This file contains the declarations for the Module class.
This file declares the MachineConstantPool class which is an abstract constant pool to keep track of ...
unsigned const TargetRegisterInfo * TRI
static unsigned getReg(const MCDisassembler *D, unsigned RC, unsigned RegNo)
uint64_t IntrinsicInst * II
const SmallVectorImpl< MachineOperand > MachineBasicBlock * TBB
const SmallVectorImpl< MachineOperand > & Cond
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
SI Pre allocate WWM Registers
This file defines the SmallVector class.
static SDValue emitCmp(SelectionDAG &DAG, const SDLoc &DL, Comparison &C)
static const unsigned FramePtr
AArch64FunctionInfo - This class is derived from MachineFunctionInfo and contains private AArch64-spe...
bool branchTargetEnforcement() const
bool hasELFSignedGOT() const
APInt bitcastToAPInt() const
Class for arbitrary precision integers.
uint64_t getZExtValue() const
Get zero extended value.
an instruction to allocate memory on the stack
PointerType * getType() const
Overload to return most specific pointer type.
This class represents an incoming formal argument to a Function.
An instruction that atomically checks whether a specified value is in a memory location,...
InstListType::const_iterator const_iterator
Conditional or Unconditional Branch instruction.
BasicBlock * getSuccessor(unsigned i) const
bool isUnconditional() const
Value * getCondition() const
CCState - This class holds information needed while lowering arguments and return values.
CCValAssign - Represent assignment of one arg/retval to a location.
Register getLocReg() const
LocInfo getLocInfo() const
unsigned getValNo() const
This class is the base class for the comparison instructions.
Predicate
This enumeration lists the possible predicates for CmpInst subclasses.
@ FCMP_OEQ
0 0 0 1 True if ordered and equal
@ FCMP_TRUE
1 1 1 1 Always true (always folded)
@ ICMP_SLT
signed less than
@ ICMP_SLE
signed less or equal
@ FCMP_OLT
0 1 0 0 True if ordered and less than
@ FCMP_ULE
1 1 0 1 True if unordered, less than, or equal
@ FCMP_OGT
0 0 1 0 True if ordered and greater than
@ FCMP_OGE
0 0 1 1 True if ordered and greater than or equal
@ ICMP_UGE
unsigned greater or equal
@ ICMP_UGT
unsigned greater than
@ ICMP_SGT
signed greater than
@ FCMP_ULT
1 1 0 0 True if unordered or less than
@ FCMP_ONE
0 1 1 0 True if ordered and operands are unequal
@ FCMP_UEQ
1 0 0 1 True if unordered or equal
@ ICMP_ULT
unsigned less than
@ FCMP_UGT
1 0 1 0 True if unordered or greater than
@ FCMP_OLE
0 1 0 1 True if ordered and less than or equal
@ FCMP_ORD
0 1 1 1 True if ordered (no nans)
@ ICMP_SGE
signed greater or equal
@ FCMP_UNE
1 1 1 0 True if unordered or not equal
@ ICMP_ULE
unsigned less or equal
@ FCMP_UGE
1 0 1 1 True if unordered, greater than, or equal
@ FCMP_FALSE
0 0 0 0 Always false (always folded)
@ FCMP_UNO
1 0 0 0 True if unordered: isnan(X) | isnan(Y)
Predicate getInversePredicate() const
For example, EQ -> NE, UGT -> ULE, SLT -> SGE, OEQ -> UNE, UGT -> OLE, OLT -> UGE,...
A constant value that is initialized with an expression using other constant values.
ConstantFP - Floating Point Values [float, double].
const APFloat & getValueAPF() const
bool isNegative() const
Return true if the sign bit is set.
bool isZero() const
Return true if the value is positive or negative zero.
This is the shared class of boolean and integer constants.
bool isZero() const
This is just a convenience method to make client code smaller for a common code.
int64_t getSExtValue() const
Return the constant as a 64-bit integer value after it has been sign extended as appropriate for the ...
uint64_t getZExtValue() const
Return the constant as a 64-bit unsigned integer value after it has been zero extended as appropriate...
This is an important base class in LLVM.
bool isNullValue() const
Return true if this is the value that would be returned by getNullValue.
This class represents an Operation in the Expression.
constexpr bool isVector() const
One or more elements.
This is a fast-path instruction selection class that generates poor code and doesn't support illegal ...
bool selectGetElementPtr(const User *I)
virtual unsigned fastMaterializeFloatZero(const ConstantFP *CF)
Emit the floating-point constant +0.0 in a register using target- specific logic.
virtual bool fastLowerIntrinsicCall(const IntrinsicInst *II)
This method is called by target-independent code to do target- specific intrinsic lowering.
Register getRegForGEPIndex(MVT PtrVT, const Value *Idx)
This is a wrapper around getRegForValue that also takes care of truncating or sign-extending the give...
virtual unsigned fastMaterializeConstant(const Constant *C)
Emit a constant in a register using target-specific logic, such as constant pool loads.
virtual bool fastLowerCall(CallLoweringInfo &CLI)
This method is called by target-independent code to do target- specific call lowering.
virtual bool fastLowerArguments()
This method is called by target-independent code to do target- specific argument lowering.
virtual bool fastSelectInstruction(const Instruction *I)=0
This method is called by target-independent code when the normal FastISel process fails to select an ...
bool selectBitCast(const User *I)
virtual unsigned fastMaterializeAlloca(const AllocaInst *C)
Emit an alloca address in a register using target-specific logic.
FunctionLoweringInfo - This contains information that is global to a function that is used when lower...
LLVMContext & getContext() const
getContext - Return a reference to the LLVMContext associated with this function.
bool isThreadLocal() const
If the value is "Thread Local", its value isn't shared by the threads.
PointerType * getType() const
Global values are always pointers.
Indirect Branch Instruction.
iterator_range< succ_op_iterator > successors()
const DebugLoc & getDebugLoc() const
Return the debug location for this node as a DebugLoc.
unsigned getOpcode() const
Returns a member of one of the enums like Instruction::Add.
A wrapper class for inspecting calls to intrinsic functions.
This is an important class for using LLVM in a threaded context.
Context object for machine code objects.
Describe properties that are true of each instruction in the target description file.
MCSymbol - Instances of this class represent a symbol name in the MC file, and MCSymbols are created ...
bool is128BitVector() const
Return true if this is a 128-bit vector type.
bool isVector() const
Return true if this is a vector value type.
TypeSize getSizeInBits() const
Returns the size of the specified MVT in bits.
TypeSize getStoreSize() const
Return the number of bytes overwritten by a store of the specified value type.
bool isFloatingPoint() const
Return true if this is a FP or a vector FP type.
static MVT getIntegerVT(unsigned BitWidth)
bool is64BitVector() const
Return true if this is a 64-bit vector type.
The MachineFrameInfo class represents an abstract stack frame until prolog/epilog code is inserted.
int CreateFixedObject(uint64_t Size, int64_t SPOffset, bool IsImmutable, bool isAliased=false)
Create a new object at a fixed location on the stack.
void setFrameAddressIsTaken(bool T)
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
const MachineInstrBuilder & addSym(MCSymbol *Sym, unsigned char TargetFlags=0) const
const MachineInstrBuilder & addFrameIndex(int Idx) const
const MachineInstrBuilder & addConstantPoolIndex(unsigned Idx, int Offset=0, unsigned TargetFlags=0) const
const MachineInstrBuilder & addRegMask(const uint32_t *Mask) const
const MachineInstrBuilder & addGlobalAddress(const GlobalValue *GV, int64_t Offset=0, unsigned TargetFlags=0) const
const MachineInstrBuilder & addReg(Register RegNo, unsigned flags=0, unsigned SubReg=0) const
Add a new virtual register operand.
const MachineInstrBuilder & addMBB(MachineBasicBlock *MBB, unsigned TargetFlags=0) const
const MachineInstrBuilder & addUse(Register RegNo, unsigned Flags=0, unsigned SubReg=0) const
Add a virtual register use operand.
const MachineInstrBuilder & addMemOperand(MachineMemOperand *MMO) const
const MachineInstrBuilder & addDef(Register RegNo, unsigned Flags=0, unsigned SubReg=0) const
Add a virtual register definition operand.
Representation of each machine instruction.
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
const MCInstrDesc & getDesc() const
Returns the target instruction descriptor of this MachineInstr.
A description of a memory reference used in the backend.
Flags
Flags values. These may be or'd together.
@ MOLoad
The memory access reads data.
@ MOStore
The memory access writes data.
Value * getLength() const
unsigned getDestAddressSpace() const
This class wraps the llvm.memset and llvm.memset.inline intrinsics.
Wrapper class representing virtual and physical registers.
Return a value (possibly void), from a function.
SMEAttrs is a utility class to parse the SME ACLE attributes on functions.
bool hasStreamingCompatibleInterface() const
bool hasStreamingInterfaceOrBody() const
This class represents the LLVM 'select' instruction.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
void reserve(size_type N)
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Used to lazily calculate structure layout information for a target machine, based on the DataLayout s...
TypeSize getElementOffset(unsigned Idx) const
Class to represent struct types.
Provides information about what library functions are available for the current target.
Target - Wrapper for Target specific information.
The instances of the Type class are immutable: once they are created, they are never changed.
bool isVectorTy() const
True if this is an instance of VectorType.
bool isArrayTy() const
True if this is an instance of ArrayType.
bool isPointerTy() const
True if this is an instance of PointerType.
bool isStructTy() const
True if this is an instance of StructType.
bool isSized(SmallPtrSetImpl< Type * > *Visited=nullptr) const
Return true if it makes sense to take the size of this type.
static IntegerType * getInt64Ty(LLVMContext &C)
bool isIntegerTy() const
True if this is an instance of IntegerType.
Value * getOperand(unsigned i) const
LLVM Value Representation.
Type * getType() const
All values are typed, get the type of this value.
bool hasOneUse() const
Return true if there is exactly one use of this value.
const ParentTy * getParent() const
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
@ MO_NC
MO_NC - Indicates whether the linker is expected to check the symbol reference for overflow.
@ MO_PAGEOFF
MO_PAGEOFF - A symbol operand with this flag represents the offset of that symbol within a 4K page.
@ MO_GOT
MO_GOT - This flag indicates that a symbol operand represents the address of the GOT entry for the sy...
@ MO_PREL
MO_PREL - Indicates that the bits of the symbol operand represented by MO_G0 etc are PC relative.
@ MO_PAGE
MO_PAGE - A symbol operand with this flag represents the pc-relative offset of the 4K page containing...
@ MO_TAGGED
MO_TAGGED - With MO_PAGE, indicates that the page includes a memory tag in bits 56-63.
@ MO_G3
MO_G3 - A symbol operand with this flag (granule 3) represents the high 16-bits of a 64-bit address,...
static bool isLogicalImmediate(uint64_t imm, unsigned regSize)
isLogicalImmediate - Return true if the immediate is valid for a logical immediate instruction of the...
static uint64_t encodeLogicalImmediate(uint64_t imm, unsigned regSize)
encodeLogicalImmediate - Return the encoded immediate value for a logical immediate instruction of th...
static int getFP64Imm(const APInt &Imm)
getFP64Imm - Return an 8-bit floating-point version of the 64-bit floating-point value.
static unsigned getShifterImm(AArch64_AM::ShiftExtendType ST, unsigned Imm)
getShifterImm - Encode the shift type and amount: imm: 6-bit shift amount shifter: 000 ==> lsl 001 ==...
FastISel * createFastISel(FunctionLoweringInfo &funcInfo, const TargetLibraryInfo *libInfo)
constexpr char Args[]
Key for Kernel::Metadata::mArgs.
int getFP32Imm(const APInt &Imm)
getFP32Imm - Return an 8-bit floating-point version of the 32-bit floating-point value.
constexpr std::underlying_type_t< E > Mask()
Get a bitmask with 1s in all places up to the high-order bit of E's largest value.
@ Swift
Calling convention for Swift.
@ CFGuard_Check
Special calling convention on Windows for calling the Control Guard Check ICall funtion.
@ GHC
Used by the Glasgow Haskell Compiler (GHC).
@ C
The default llvm calling convention, compatible with C.
@ ADD
Simple integer binary arithmetic operators.
@ SINT_TO_FP
[SU]INT_TO_FP - These operators convert integers (whose interpreted sign depends on the first letter)...
@ MULHU
MULHU/MULHS - Multiply high - Multiply two integers of type iN, producing an unsigned/signed value of...
@ FP_TO_SINT
FP_TO_[US]INT - Convert a floating point value to a signed or unsigned integer.
@ AND
Bitwise operators - logical and, logical or, logical xor.
@ TRUNCATE
TRUNCATE - Completely drop the high bits.
Flag
These should be considered private to the implementation of the MCInstrDesc class.
Predicate
Predicate - These are "(BI << 5) | BO" for various predicates.
Libcall
RTLIB::Libcall enum - This enum defines all of the runtime library calls the backend can emit.
@ Implicit
Not emitted register (e.g. carry, or temporary result).
@ Kill
The last use of a register.
Reg
All possible values of the reg field in the ModR/M byte.
This is an optimization pass for GlobalISel generic memory operations.
bool RetCC_AArch64_AAPCS(unsigned ValNo, MVT ValVT, MVT LocVT, CCValAssign::LocInfo LocInfo, ISD::ArgFlagsTy ArgFlags, CCState &State)
bool CC_AArch64_GHC(unsigned ValNo, MVT ValVT, MVT LocVT, CCValAssign::LocInfo LocInfo, ISD::ArgFlagsTy ArgFlags, CCState &State)
Register constrainOperandRegClass(const MachineFunction &MF, const TargetRegisterInfo &TRI, MachineRegisterInfo &MRI, const TargetInstrInfo &TII, const RegisterBankInfo &RBI, MachineInstr &InsertPt, const TargetRegisterClass &RegClass, MachineOperand &RegMO)
Constrain the Register operand OpIdx, so that it is now constrained to the TargetRegisterClass passed...
void GetReturnInfo(CallingConv::ID CC, Type *ReturnType, AttributeList attr, SmallVectorImpl< ISD::OutputArg > &Outs, const TargetLowering &TLI, const DataLayout &DL)
Given an LLVM IR type and return type attributes, compute the return value EVTs and flags,...
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
bool CC_AArch64_Win64PCS(unsigned ValNo, MVT ValVT, MVT LocVT, CCValAssign::LocInfo LocInfo, ISD::ArgFlagsTy ArgFlags, CCState &State)
bool CC_AArch64_Win64_CFGuard_Check(unsigned ValNo, MVT ValVT, MVT LocVT, CCValAssign::LocInfo LocInfo, ISD::ArgFlagsTy ArgFlags, CCState &State)
unsigned getBLRCallOpcode(const MachineFunction &MF)
Return opcode to be used for indirect calls.
constexpr bool isPowerOf2_64(uint64_t Value)
Return true if the argument is a power of two > 0 (64 bit edition.)
gep_type_iterator gep_type_end(const User *GEP)
bool isReleaseOrStronger(AtomicOrdering AO)
static Error getOffset(const SymbolRef &Sym, SectionRef Sec, uint64_t &Result)
bool CC_AArch64_AAPCS(unsigned ValNo, MVT ValVT, MVT LocVT, CCValAssign::LocInfo LocInfo, ISD::ArgFlagsTy ArgFlags, CCState &State)
AtomicOrdering
Atomic ordering for LLVM's memory model.
bool CCAssignFn(unsigned ValNo, MVT ValVT, MVT LocVT, CCValAssign::LocInfo LocInfo, ISD::ArgFlagsTy ArgFlags, CCState &State)
CCAssignFn - This function assigns a location for Val, updating State to reflect the change.
unsigned getKillRegState(bool B)
bool CC_AArch64_DarwinPCS(unsigned ValNo, MVT ValVT, MVT LocVT, CCValAssign::LocInfo LocInfo, ISD::ArgFlagsTy ArgFlags, CCState &State)
gep_type_iterator gep_type_begin(const User *GEP)
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
This struct is a compact representation of a valid (non-zero power of two) alignment.
bool isSimple() const
Test if the given EVT is simple (as opposed to being extended).
bool bitsGT(EVT VT) const
Return true if this has more bits than VT.
bool bitsLT(EVT VT) const
Return true if this has less bits than VT.
ElementCount getVectorElementCount() const
static EVT getEVT(Type *Ty, bool HandleUnknown=false)
Return the value type corresponding to the specified type.
MVT getSimpleVT() const
Return the SimpleValueType held in the specified simple EVT.
bool isVector() const
Return true if this is a vector value type.
static MachinePointerInfo getStack(MachineFunction &MF, int64_t Offset, uint8_t ID=0)
Stack pointer relative access.
static MachinePointerInfo getFixedStack(MachineFunction &MF, int FI, int64_t Offset=0)
Return a MachinePointerInfo record that refers to the specified FrameIndex.
This struct is a compact representation of a valid (power of two) or undefined (0) alignment.