brintos

brintos / llvm-project-archived public Read only

0
0
Text · 6.0 KiB · eae7e86 Raw
173 lines · cpp
1//===------- RISCVPushPopOptimizer.cpp - RISC-V Push/Pop opt. pass --------===//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//9// This file contains a pass that replaces Zcmp POP instructions with10// POPRET[Z] where possible.11//12//===----------------------------------------------------------------------===//13 14#include "RISCVInstrInfo.h"15#include "RISCVMachineFunctionInfo.h"16#include "llvm/CodeGen/MachineInstr.h"17 18using namespace llvm;19 20#define RISCV_PUSH_POP_OPT_NAME "RISC-V Zcmp Push/Pop optimization pass"21 22namespace {23struct RISCVPushPopOpt : public MachineFunctionPass {24  static char ID;25 26  RISCVPushPopOpt() : MachineFunctionPass(ID) {}27 28  const RISCVInstrInfo *TII;29  const TargetRegisterInfo *TRI;30 31  // Track which register units have been modified and used.32  LiveRegUnits ModifiedRegUnits, UsedRegUnits;33 34  bool usePopRet(MachineBasicBlock::iterator &MBBI,35                 MachineBasicBlock::iterator &NextI, bool IsReturnZero);36  bool adjustRetVal(MachineBasicBlock::iterator &MBBI);37  bool runOnMachineFunction(MachineFunction &Fn) override;38 39  StringRef getPassName() const override { return RISCV_PUSH_POP_OPT_NAME; }40};41 42char RISCVPushPopOpt::ID = 0;43 44} // end of anonymous namespace45 46INITIALIZE_PASS(RISCVPushPopOpt, "riscv-push-pop-opt", RISCV_PUSH_POP_OPT_NAME,47                false, false)48 49static bool isPop(unsigned Opcode) {50  switch (Opcode) {51  case RISCV::CM_POP:52  case RISCV::QC_CM_POP:53    return true;54  default:55    return false;56  }57}58 59static unsigned getPopRetOpcode(unsigned PopOpcode, bool IsReturnZero) {60  assert(isPop(PopOpcode) && "Unexpected Pop Opcode");61 62  switch (PopOpcode) {63  case RISCV::CM_POP:64    return IsReturnZero ? RISCV::CM_POPRETZ : RISCV::CM_POPRET;65  case RISCV::QC_CM_POP:66    return IsReturnZero ? RISCV::QC_CM_POPRETZ : RISCV::QC_CM_POPRET;67  default:68    llvm_unreachable("Unhandled Pop Opcode");69  }70}71 72bool RISCVPushPopOpt::usePopRet(MachineBasicBlock::iterator &MBBI,73                                MachineBasicBlock::iterator &NextI,74                                bool IsReturnZero) {75  // Since Pseudo instruction lowering happen later in the pipeline,76  // this will detect all ret instruction.77  DebugLoc DL = NextI->getDebugLoc();78  unsigned Opc = getPopRetOpcode(MBBI->getOpcode(), IsReturnZero);79  MachineInstrBuilder PopRetBuilder =80      BuildMI(*NextI->getParent(), NextI, DL, TII->get(Opc))81          .add(MBBI->getOperand(0))82          .add(MBBI->getOperand(1))83          .setMIFlag(MachineInstr::FrameDestroy);84 85  // Copy over the variable implicit uses and defs from the CM_POP. They depend86  // on what register list has been picked during frame lowering.87  const MCInstrDesc &PopDesc = MBBI->getDesc();88  unsigned FirstNonDeclaredOp = PopDesc.getNumOperands() +89                                PopDesc.NumImplicitUses +90                                PopDesc.NumImplicitDefs;91  for (unsigned i = FirstNonDeclaredOp; i < MBBI->getNumOperands(); ++i)92    PopRetBuilder.add(MBBI->getOperand(i));93 94  MBBI->eraseFromParent();95  NextI->eraseFromParent();96  return true;97}98 99// Search for last assignment to a0 and if possible use ret_val slot of POP to100// store return value.101bool RISCVPushPopOpt::adjustRetVal(MachineBasicBlock::iterator &MBBI) {102  MachineBasicBlock::reverse_iterator RE = MBBI->getParent()->rend();103  // Track which register units have been modified and used between the POP104  // insn and the last assignment to register a0.105  ModifiedRegUnits.clear();106  UsedRegUnits.clear();107  // Since POP instruction is in Epilogue no normal instructions will follow108  // after it. Therefore search only previous ones to find the return value.109  for (MachineBasicBlock::reverse_iterator I =110           next_nodbg(MBBI.getReverse(), RE);111       I != RE; I = next_nodbg(I, RE)) {112    MachineInstr &MI = *I;113    if (auto OperandPair = TII->isCopyInstrImpl(MI)) {114      Register DestReg = OperandPair->Destination->getReg();115      Register Source = OperandPair->Source->getReg();116      if (DestReg == RISCV::X10 && Source == RISCV::X0) {117        MI.removeFromParent();118        return true;119      }120    }121    // Update modified / used register units.122    LiveRegUnits::accumulateUsedDefed(MI, ModifiedRegUnits, UsedRegUnits, TRI);123    // If a0 was modified or used, there is no possibility124    // of using ret_val slot of POP instruction.125    if (!ModifiedRegUnits.available(RISCV::X10) ||126        !UsedRegUnits.available(RISCV::X10))127      return false;128  }129  return false;130}131 132bool RISCVPushPopOpt::runOnMachineFunction(MachineFunction &Fn) {133  if (skipFunction(Fn.getFunction()))134    return false;135 136  // If Zcmp extension is not supported, abort.137  const RISCVSubtarget *Subtarget = &Fn.getSubtarget<RISCVSubtarget>();138  if (!Subtarget->hasStdExtZcmp() && !Subtarget->hasVendorXqccmp())139    return false;140 141  TII = Subtarget->getInstrInfo();142  TRI = Subtarget->getRegisterInfo();143 144  // Resize the modified and used register unit trackers.  We do this once145  // per function and then clear the register units each time we determine146  // correct return value for the POP.147  ModifiedRegUnits.init(*TRI);148  UsedRegUnits.init(*TRI);149 150  bool Modified = false;151  for (auto &MBB : Fn) {152    // RET should be the only terminator.153    auto RetMBBI = MBB.getFirstTerminator();154    if (RetMBBI == MBB.end() || RetMBBI->getOpcode() != RISCV::PseudoRET ||155        RetMBBI == MBB.begin())156      continue;157 158    // The previous instruction should be a POP.159    auto PopMBBI = prev_nodbg(RetMBBI, MBB.begin());160    if (isPop(PopMBBI->getOpcode()) &&161        PopMBBI->getFlag(MachineInstr::FrameDestroy))162      Modified |= usePopRet(PopMBBI, RetMBBI, adjustRetVal(PopMBBI));163  }164 165  return Modified;166}167 168/// createRISCVPushPopOptimizationPass - returns an instance of the169/// Push/Pop optimization pass.170FunctionPass *llvm::createRISCVPushPopOptimizationPass() {171  return new RISCVPushPopOpt();172}173