brintos

brintos / llvm-project-archived public Read only

0
0
Text · 7.8 KiB · 4ff49a6 Raw
203 lines · cpp
1//==-- AArch64DeadRegisterDefinitions.cpp - Replace dead defs w/ zero reg --==//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 When allowed by the instruction, replace a dead definition of a GPR9/// with the zero register. This makes the code a bit friendlier towards the10/// hardware's register renamer.11//===----------------------------------------------------------------------===//12 13#include "AArch64.h"14#include "AArch64RegisterInfo.h"15#include "AArch64Subtarget.h"16#include "llvm/ADT/Statistic.h"17#include "llvm/CodeGen/MachineFunction.h"18#include "llvm/CodeGen/MachineFunctionPass.h"19#include "llvm/CodeGen/MachineInstr.h"20#include "llvm/CodeGen/MachineRegisterInfo.h"21#include "llvm/CodeGen/TargetInstrInfo.h"22#include "llvm/CodeGen/TargetSubtargetInfo.h"23#include "llvm/Support/Debug.h"24#include "llvm/Support/raw_ostream.h"25using namespace llvm;26 27#define DEBUG_TYPE "aarch64-dead-defs"28 29STATISTIC(NumDeadDefsReplaced, "Number of dead definitions replaced");30 31#define AARCH64_DEAD_REG_DEF_NAME "AArch64 Dead register definitions"32 33namespace {34class AArch64DeadRegisterDefinitions : public MachineFunctionPass {35private:36  const TargetRegisterInfo *TRI;37  const MachineRegisterInfo *MRI;38  const TargetInstrInfo *TII;39  bool Changed;40  void processMachineBasicBlock(MachineBasicBlock &MBB);41public:42  static char ID; // Pass identification, replacement for typeid.43  AArch64DeadRegisterDefinitions() : MachineFunctionPass(ID) {}44 45  bool runOnMachineFunction(MachineFunction &F) override;46 47  StringRef getPassName() const override { return AARCH64_DEAD_REG_DEF_NAME; }48 49  void getAnalysisUsage(AnalysisUsage &AU) const override {50    AU.setPreservesCFG();51    MachineFunctionPass::getAnalysisUsage(AU);52  }53};54char AArch64DeadRegisterDefinitions::ID = 0;55} // end anonymous namespace56 57INITIALIZE_PASS(AArch64DeadRegisterDefinitions, "aarch64-dead-defs",58                AARCH64_DEAD_REG_DEF_NAME, false, false)59 60static bool usesFrameIndex(const MachineInstr &MI) {61  for (const MachineOperand &MO : MI.uses())62    if (MO.isFI())63      return true;64  return false;65}66 67// Instructions that lose their 'read' operation for a subsequent fence acquire68// (DMB LD) once the zero register is used.69//70// WARNING: The acquire variants of the instructions are also affected, but they71// are split out into `atomicBarrierDroppedOnZero()` to support annotations on72// assembly.73static bool atomicReadDroppedOnZero(unsigned Opcode) {74  switch (Opcode) {75    case AArch64::LDADDB:     case AArch64::LDADDH:76    case AArch64::LDADDW:     case AArch64::LDADDX:77    case AArch64::LDADDLB:    case AArch64::LDADDLH:78    case AArch64::LDADDLW:    case AArch64::LDADDLX:79    case AArch64::LDCLRB:     case AArch64::LDCLRH:80    case AArch64::LDCLRW:     case AArch64::LDCLRX:81    case AArch64::LDCLRLB:    case AArch64::LDCLRLH:82    case AArch64::LDCLRLW:    case AArch64::LDCLRLX:83    case AArch64::LDEORB:     case AArch64::LDEORH:84    case AArch64::LDEORW:     case AArch64::LDEORX:85    case AArch64::LDEORLB:    case AArch64::LDEORLH:86    case AArch64::LDEORLW:    case AArch64::LDEORLX:87    case AArch64::LDSETB:     case AArch64::LDSETH:88    case AArch64::LDSETW:     case AArch64::LDSETX:89    case AArch64::LDSETLB:    case AArch64::LDSETLH:90    case AArch64::LDSETLW:    case AArch64::LDSETLX:91    case AArch64::LDSMAXB:    case AArch64::LDSMAXH:92    case AArch64::LDSMAXW:    case AArch64::LDSMAXX:93    case AArch64::LDSMAXLB:   case AArch64::LDSMAXLH:94    case AArch64::LDSMAXLW:   case AArch64::LDSMAXLX:95    case AArch64::LDSMINB:    case AArch64::LDSMINH:96    case AArch64::LDSMINW:    case AArch64::LDSMINX:97    case AArch64::LDSMINLB:   case AArch64::LDSMINLH:98    case AArch64::LDSMINLW:   case AArch64::LDSMINLX:99    case AArch64::LDUMAXB:    case AArch64::LDUMAXH:100    case AArch64::LDUMAXW:    case AArch64::LDUMAXX:101    case AArch64::LDUMAXLB:   case AArch64::LDUMAXLH:102    case AArch64::LDUMAXLW:   case AArch64::LDUMAXLX:103    case AArch64::LDUMINB:    case AArch64::LDUMINH:104    case AArch64::LDUMINW:    case AArch64::LDUMINX:105    case AArch64::LDUMINLB:   case AArch64::LDUMINLH:106    case AArch64::LDUMINLW:   case AArch64::LDUMINLX:107    case AArch64::SWPB:       case AArch64::SWPH:108    case AArch64::SWPW:       case AArch64::SWPX:109    case AArch64::SWPLB:      case AArch64::SWPLH:110    case AArch64::SWPLW:      case AArch64::SWPLX:111    return true;112  }113  return false;114}115 116void AArch64DeadRegisterDefinitions::processMachineBasicBlock(117    MachineBasicBlock &MBB) {118  for (MachineInstr &MI : MBB) {119    if (usesFrameIndex(MI)) {120      // We need to skip this instruction because while it appears to have a121      // dead def it uses a frame index which might expand into a multi122      // instruction sequence during EPI.123      LLVM_DEBUG(dbgs() << "    Ignoring, operand is frame index\n");124      continue;125    }126    if (MI.definesRegister(AArch64::XZR, /*TRI=*/nullptr) ||127        MI.definesRegister(AArch64::WZR, /*TRI=*/nullptr)) {128      // It is not allowed to write to the same register (not even the zero129      // register) twice in a single instruction.130      LLVM_DEBUG(131          dbgs()132          << "    Ignoring, XZR or WZR already used by the instruction\n");133      continue;134    }135 136    if (atomicBarrierDroppedOnZero(MI.getOpcode()) || atomicReadDroppedOnZero(MI.getOpcode())) {137      LLVM_DEBUG(dbgs() << "    Ignoring, semantics change with xzr/wzr.\n");138      continue;139    }140 141    const MCInstrDesc &Desc = MI.getDesc();142    for (int I = 0, E = Desc.getNumDefs(); I != E; ++I) {143      MachineOperand &MO = MI.getOperand(I);144      if (!MO.isReg() || !MO.isDef())145        continue;146      // We should not have any relevant physreg defs that are replacable by147      // zero before register allocation. So we just check for dead vreg defs.148      Register Reg = MO.getReg();149      if (!Reg.isVirtual() || (!MO.isDead() && !MRI->use_nodbg_empty(Reg)))150        continue;151      assert(!MO.isImplicit() && "Unexpected implicit def!");152      LLVM_DEBUG(dbgs() << "  Dead def operand #" << I << " in:\n    ";153                 MI.print(dbgs()));154      // Be careful not to change the register if it's a tied operand.155      if (MI.isRegTiedToUseOperand(I)) {156        LLVM_DEBUG(dbgs() << "    Ignoring, def is tied operand.\n");157        continue;158      }159      const TargetRegisterClass *RC = TII->getRegClass(Desc, I);160      unsigned NewReg;161      if (RC == nullptr) {162        LLVM_DEBUG(dbgs() << "    Ignoring, register is not a GPR.\n");163        continue;164      } else if (RC->contains(AArch64::WZR))165        NewReg = AArch64::WZR;166      else if (RC->contains(AArch64::XZR))167        NewReg = AArch64::XZR;168      else {169        LLVM_DEBUG(dbgs() << "    Ignoring, register is not a GPR.\n");170        continue;171      }172      LLVM_DEBUG(dbgs() << "    Replacing with zero register. New:\n      ");173      MO.setReg(NewReg);174      MO.setIsDead();175      LLVM_DEBUG(MI.print(dbgs()));176      ++NumDeadDefsReplaced;177      Changed = true;178      // Only replace one dead register, see check for zero register above.179      break;180    }181  }182}183 184// Scan the function for instructions that have a dead definition of a185// register. Replace that register with the zero register when possible.186bool AArch64DeadRegisterDefinitions::runOnMachineFunction(MachineFunction &MF) {187  if (skipFunction(MF.getFunction()))188    return false;189 190  TRI = MF.getSubtarget().getRegisterInfo();191  TII = MF.getSubtarget().getInstrInfo();192  MRI = &MF.getRegInfo();193  LLVM_DEBUG(dbgs() << "***** AArch64DeadRegisterDefinitions *****\n");194  Changed = false;195  for (auto &MBB : MF)196    processMachineBasicBlock(MBB);197  return Changed;198}199 200FunctionPass *llvm::createAArch64DeadRegisterDefinitions() {201  return new AArch64DeadRegisterDefinitions();202}203