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