1 //===- AArch64GlobalISelUtils.cpp --------------------------------*- C++ -*-==//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 /// \file Implementations of AArch64-specific helper functions used in the
9 /// GlobalISel pipeline.
10 //===----------------------------------------------------------------------===//
11 #include "AArch64GlobalISelUtils.h"
12 #include "AArch64InstrInfo.h"
13 #include "llvm/CodeGen/GlobalISel/Utils.h"
14 #include "llvm/CodeGen/TargetLowering.h"
15 #include "llvm/IR/InstrTypes.h"
16 #include "llvm/Support/raw_ostream.h"
17
18 using namespace llvm;
19
20 Optional<RegOrConstant>
getAArch64VectorSplat(const MachineInstr & MI,const MachineRegisterInfo & MRI)21 AArch64GISelUtils::getAArch64VectorSplat(const MachineInstr &MI,
22 const MachineRegisterInfo &MRI) {
23 if (auto Splat = getVectorSplat(MI, MRI))
24 return Splat;
25 if (MI.getOpcode() != AArch64::G_DUP)
26 return None;
27 Register Src = MI.getOperand(1).getReg();
28 if (auto ValAndVReg =
29 getConstantVRegValWithLookThrough(MI.getOperand(1).getReg(), MRI))
30 return RegOrConstant(ValAndVReg->Value.getSExtValue());
31 return RegOrConstant(Src);
32 }
33
34 Optional<int64_t>
getAArch64VectorSplatScalar(const MachineInstr & MI,const MachineRegisterInfo & MRI)35 AArch64GISelUtils::getAArch64VectorSplatScalar(const MachineInstr &MI,
36 const MachineRegisterInfo &MRI) {
37 auto Splat = getAArch64VectorSplat(MI, MRI);
38 if (!Splat || Splat->isReg())
39 return None;
40 return Splat->getCst();
41 }
42
isCMN(const MachineInstr * MaybeSub,const CmpInst::Predicate & Pred,const MachineRegisterInfo & MRI)43 bool AArch64GISelUtils::isCMN(const MachineInstr *MaybeSub,
44 const CmpInst::Predicate &Pred,
45 const MachineRegisterInfo &MRI) {
46 // Match:
47 //
48 // %sub = G_SUB 0, %y
49 // %cmp = G_ICMP eq/ne, %sub, %z
50 //
51 // Or
52 //
53 // %sub = G_SUB 0, %y
54 // %cmp = G_ICMP eq/ne, %z, %sub
55 if (!MaybeSub || MaybeSub->getOpcode() != TargetOpcode::G_SUB ||
56 !CmpInst::isEquality(Pred))
57 return false;
58 auto MaybeZero =
59 getConstantVRegValWithLookThrough(MaybeSub->getOperand(1).getReg(), MRI);
60 return MaybeZero && MaybeZero->Value.getZExtValue() == 0;
61 }
62
tryEmitBZero(MachineInstr & MI,MachineIRBuilder & MIRBuilder,bool MinSize)63 bool AArch64GISelUtils::tryEmitBZero(MachineInstr &MI,
64 MachineIRBuilder &MIRBuilder,
65 bool MinSize) {
66 assert(MI.getOpcode() == TargetOpcode::G_MEMSET);
67 MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
68 auto &TLI = *MIRBuilder.getMF().getSubtarget().getTargetLowering();
69 if (!TLI.getLibcallName(RTLIB::BZERO))
70 return false;
71 auto Zero = getConstantVRegValWithLookThrough(MI.getOperand(1).getReg(), MRI);
72 if (!Zero || Zero->Value.getSExtValue() != 0)
73 return false;
74
75 // It's not faster to use bzero rather than memset for sizes <= 256.
76 // However, it *does* save us a mov from wzr, so if we're going for
77 // minsize, use bzero even if it's slower.
78 if (!MinSize) {
79 // If the size is known, check it. If it is not known, assume using bzero is
80 // better.
81 if (auto Size =
82 getConstantVRegValWithLookThrough(MI.getOperand(2).getReg(), MRI)) {
83 if (Size->Value.getSExtValue() <= 256)
84 return false;
85 }
86 }
87
88 MIRBuilder.setInstrAndDebugLoc(MI);
89 MIRBuilder
90 .buildInstr(TargetOpcode::G_BZERO, {},
91 {MI.getOperand(0), MI.getOperand(2)})
92 .addImm(MI.getOperand(3).getImm())
93 .addMemOperand(*MI.memoperands_begin());
94 MI.eraseFromParent();
95 return true;
96 }
97
changeFCMPPredToAArch64CC(const CmpInst::Predicate P,AArch64CC::CondCode & CondCode,AArch64CC::CondCode & CondCode2)98 void AArch64GISelUtils::changeFCMPPredToAArch64CC(
99 const CmpInst::Predicate P, AArch64CC::CondCode &CondCode,
100 AArch64CC::CondCode &CondCode2) {
101 CondCode2 = AArch64CC::AL;
102 switch (P) {
103 default:
104 llvm_unreachable("Unknown FP condition!");
105 case CmpInst::FCMP_OEQ:
106 CondCode = AArch64CC::EQ;
107 break;
108 case CmpInst::FCMP_OGT:
109 CondCode = AArch64CC::GT;
110 break;
111 case CmpInst::FCMP_OGE:
112 CondCode = AArch64CC::GE;
113 break;
114 case CmpInst::FCMP_OLT:
115 CondCode = AArch64CC::MI;
116 break;
117 case CmpInst::FCMP_OLE:
118 CondCode = AArch64CC::LS;
119 break;
120 case CmpInst::FCMP_ONE:
121 CondCode = AArch64CC::MI;
122 CondCode2 = AArch64CC::GT;
123 break;
124 case CmpInst::FCMP_ORD:
125 CondCode = AArch64CC::VC;
126 break;
127 case CmpInst::FCMP_UNO:
128 CondCode = AArch64CC::VS;
129 break;
130 case CmpInst::FCMP_UEQ:
131 CondCode = AArch64CC::EQ;
132 CondCode2 = AArch64CC::VS;
133 break;
134 case CmpInst::FCMP_UGT:
135 CondCode = AArch64CC::HI;
136 break;
137 case CmpInst::FCMP_UGE:
138 CondCode = AArch64CC::PL;
139 break;
140 case CmpInst::FCMP_ULT:
141 CondCode = AArch64CC::LT;
142 break;
143 case CmpInst::FCMP_ULE:
144 CondCode = AArch64CC::LE;
145 break;
146 case CmpInst::FCMP_UNE:
147 CondCode = AArch64CC::NE;
148 break;
149 }
150 }
151
changeVectorFCMPPredToAArch64CC(const CmpInst::Predicate P,AArch64CC::CondCode & CondCode,AArch64CC::CondCode & CondCode2,bool & Invert)152 void AArch64GISelUtils::changeVectorFCMPPredToAArch64CC(
153 const CmpInst::Predicate P, AArch64CC::CondCode &CondCode,
154 AArch64CC::CondCode &CondCode2, bool &Invert) {
155 Invert = false;
156 switch (P) {
157 default:
158 // Mostly the scalar mappings work fine.
159 changeFCMPPredToAArch64CC(P, CondCode, CondCode2);
160 break;
161 case CmpInst::FCMP_UNO:
162 Invert = true;
163 LLVM_FALLTHROUGH;
164 case CmpInst::FCMP_ORD:
165 CondCode = AArch64CC::MI;
166 CondCode2 = AArch64CC::GE;
167 break;
168 case CmpInst::FCMP_UEQ:
169 case CmpInst::FCMP_ULT:
170 case CmpInst::FCMP_ULE:
171 case CmpInst::FCMP_UGT:
172 case CmpInst::FCMP_UGE:
173 // All of the compare-mask comparisons are ordered, but we can switch
174 // between the two by a double inversion. E.g. ULE == !OGT.
175 Invert = true;
176 changeFCMPPredToAArch64CC(CmpInst::getInversePredicate(P), CondCode,
177 CondCode2);
178 break;
179 }
180 }
181