xref: /freebsd/contrib/llvm-project/llvm/lib/Target/AArch64/GISel/AArch64GlobalISelUtils.cpp (revision 13ec1e3155c7e9bf037b12af186351b7fa9b9450)
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>
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>
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 
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 
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 
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 
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