217 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8/// \file Implementations of AArch64-specific helper functions used in the9/// GlobalISel pipeline.10//===----------------------------------------------------------------------===//11#include "AArch64GlobalISelUtils.h"12#include "llvm/CodeGen/GlobalISel/Utils.h"13#include "llvm/CodeGen/TargetLowering.h"14#include "llvm/IR/InstrTypes.h"15 16using namespace llvm;17 18std::optional<RegOrConstant>19AArch64GISelUtils::getAArch64VectorSplat(const MachineInstr &MI,20 const MachineRegisterInfo &MRI) {21 if (auto Splat = getVectorSplat(MI, MRI))22 return Splat;23 if (MI.getOpcode() != AArch64::G_DUP)24 return std::nullopt;25 Register Src = MI.getOperand(1).getReg();26 if (auto ValAndVReg =27 getAnyConstantVRegValWithLookThrough(MI.getOperand(1).getReg(), MRI))28 return RegOrConstant(ValAndVReg->Value.getSExtValue());29 return RegOrConstant(Src);30}31 32std::optional<int64_t>33AArch64GISelUtils::getAArch64VectorSplatScalar(const MachineInstr &MI,34 const MachineRegisterInfo &MRI) {35 auto Splat = getAArch64VectorSplat(MI, MRI);36 if (!Splat || Splat->isReg())37 return std::nullopt;38 return Splat->getCst();39}40 41bool AArch64GISelUtils::isCMN(const MachineInstr *MaybeSub,42 const CmpInst::Predicate &Pred,43 const MachineRegisterInfo &MRI) {44 // Match:45 //46 // %sub = G_SUB 0, %y47 // %cmp = G_ICMP eq/ne, %sub, %z48 //49 // Or50 //51 // %sub = G_SUB 0, %y52 // %cmp = G_ICMP eq/ne, %z, %sub53 // or with signed comparisons with the no-signed-wrap flag set54 if (!MaybeSub || MaybeSub->getOpcode() != TargetOpcode::G_SUB ||55 (!CmpInst::isEquality(Pred) &&56 !(CmpInst::isSigned(Pred) && MaybeSub->getFlag(MachineInstr::NoSWrap))))57 return false;58 auto MaybeZero =59 getIConstantVRegValWithLookThrough(MaybeSub->getOperand(1).getReg(), MRI);60 return MaybeZero && MaybeZero->Value.getZExtValue() == 0;61}62 63bool 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 =72 getIConstantVRegValWithLookThrough(MI.getOperand(1).getReg(), MRI);73 if (!Zero || Zero->Value.getSExtValue() != 0)74 return false;75 76 // It's not faster to use bzero rather than memset for sizes <= 256.77 // However, it *does* save us a mov from wzr, so if we're going for78 // minsize, use bzero even if it's slower.79 if (!MinSize) {80 // If the size is known, check it. If it is not known, assume using bzero is81 // better.82 if (auto Size = getIConstantVRegValWithLookThrough(83 MI.getOperand(2).getReg(), MRI)) {84 if (Size->Value.getSExtValue() <= 256)85 return false;86 }87 }88 89 MIRBuilder.setInstrAndDebugLoc(MI);90 MIRBuilder91 .buildInstr(TargetOpcode::G_BZERO, {},92 {MI.getOperand(0), MI.getOperand(2)})93 .addImm(MI.getOperand(3).getImm())94 .addMemOperand(*MI.memoperands_begin());95 MI.eraseFromParent();96 return true;97}98 99std::tuple<uint16_t, Register>100AArch64GISelUtils::extractPtrauthBlendDiscriminators(Register Disc,101 MachineRegisterInfo &MRI) {102 Register AddrDisc = Disc;103 uint16_t ConstDisc = 0;104 105 if (auto ConstDiscVal = getIConstantVRegVal(Disc, MRI)) {106 if (isUInt<16>(ConstDiscVal->getZExtValue())) {107 ConstDisc = ConstDiscVal->getZExtValue();108 AddrDisc = AArch64::NoRegister;109 }110 return std::make_tuple(ConstDisc, AddrDisc);111 }112 113 const MachineInstr *DiscMI = MRI.getVRegDef(Disc);114 if (!DiscMI || DiscMI->getOpcode() != TargetOpcode::G_INTRINSIC ||115 DiscMI->getOperand(1).getIntrinsicID() != Intrinsic::ptrauth_blend)116 return std::make_tuple(ConstDisc, AddrDisc);117 118 if (auto ConstDiscVal =119 getIConstantVRegVal(DiscMI->getOperand(3).getReg(), MRI)) {120 if (isUInt<16>(ConstDiscVal->getZExtValue())) {121 ConstDisc = ConstDiscVal->getZExtValue();122 AddrDisc = DiscMI->getOperand(2).getReg();123 }124 }125 return std::make_tuple(ConstDisc, AddrDisc);126}127 128void AArch64GISelUtils::changeFCMPPredToAArch64CC(129 const CmpInst::Predicate P, AArch64CC::CondCode &CondCode,130 AArch64CC::CondCode &CondCode2) {131 CondCode2 = AArch64CC::AL;132 switch (P) {133 default:134 llvm_unreachable("Unknown FP condition!");135 case CmpInst::FCMP_OEQ:136 CondCode = AArch64CC::EQ;137 break;138 case CmpInst::FCMP_OGT:139 CondCode = AArch64CC::GT;140 break;141 case CmpInst::FCMP_OGE:142 CondCode = AArch64CC::GE;143 break;144 case CmpInst::FCMP_OLT:145 CondCode = AArch64CC::MI;146 break;147 case CmpInst::FCMP_OLE:148 CondCode = AArch64CC::LS;149 break;150 case CmpInst::FCMP_ONE:151 CondCode = AArch64CC::MI;152 CondCode2 = AArch64CC::GT;153 break;154 case CmpInst::FCMP_ORD:155 CondCode = AArch64CC::VC;156 break;157 case CmpInst::FCMP_UNO:158 CondCode = AArch64CC::VS;159 break;160 case CmpInst::FCMP_UEQ:161 CondCode = AArch64CC::EQ;162 CondCode2 = AArch64CC::VS;163 break;164 case CmpInst::FCMP_UGT:165 CondCode = AArch64CC::HI;166 break;167 case CmpInst::FCMP_UGE:168 CondCode = AArch64CC::PL;169 break;170 case CmpInst::FCMP_ULT:171 CondCode = AArch64CC::LT;172 break;173 case CmpInst::FCMP_ULE:174 CondCode = AArch64CC::LE;175 break;176 case CmpInst::FCMP_UNE:177 CondCode = AArch64CC::NE;178 break;179 case CmpInst::FCMP_TRUE:180 CondCode = AArch64CC::AL;181 break;182 case CmpInst::FCMP_FALSE:183 CondCode = AArch64CC::NV;184 break;185 }186}187 188void AArch64GISelUtils::changeVectorFCMPPredToAArch64CC(189 const CmpInst::Predicate P, AArch64CC::CondCode &CondCode,190 AArch64CC::CondCode &CondCode2, bool &Invert) {191 Invert = false;192 switch (P) {193 default:194 // Mostly the scalar mappings work fine.195 changeFCMPPredToAArch64CC(P, CondCode, CondCode2);196 break;197 case CmpInst::FCMP_UNO:198 Invert = true;199 [[fallthrough]];200 case CmpInst::FCMP_ORD:201 CondCode = AArch64CC::MI;202 CondCode2 = AArch64CC::GE;203 break;204 case CmpInst::FCMP_UEQ:205 case CmpInst::FCMP_ULT:206 case CmpInst::FCMP_ULE:207 case CmpInst::FCMP_UGT:208 case CmpInst::FCMP_UGE:209 // All of the compare-mask comparisons are ordered, but we can switch210 // between the two by a double inversion. E.g. ULE == !OGT.211 Invert = true;212 changeFCMPPredToAArch64CC(CmpInst::getInversePredicate(P), CondCode,213 CondCode2);214 break;215 }216}217