brintos

brintos / llvm-project-archived public Read only

0
0
Text · 6.9 KiB · 1a15075 Raw
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