brintos

brintos / llvm-project-archived public Read only

0
0
Text · 15.1 KiB · c9cb449 Raw
405 lines · cpp
1//===----- HexagonQFPOptimizer.cpp - Qualcomm-FP to IEEE-FP conversions2// optimizer ------------------===//3//4// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.5// See https://llvm.org/LICENSE.txt for license information.6// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception7//8//===----------------------------------------------------------------------===//9//10// Basic infrastructure for optimizing intermediate conversion instructions11// generated while performing vector floating point operations.12// Currently run at the starting of the code generation for Hexagon, cleans13// up redundant conversion instructions and replaces the uses of conversion14// with appropriate machine operand. Liveness is preserved after this pass.15//16// @note: The redundant conversion instructions are not eliminated in this pass.17// In this pass, we are only trying to replace the uses of conversion18// instructions with its appropriate QFP instruction. We are leaving the job to19// Dead instruction Elimination pass to remove redundant conversion20// instructions.21//22// Brief overview of working of this QFP optimizer.23// This version of Hexagon QFP optimizer basically iterates over each24// instruction, checks whether if it belongs to hexagon floating point HVX25// arithmetic instruction category(Add, Sub, Mul). And then it finds the unique26// definition for the machine operands corresponding to the instruction.27//28// Example:29// MachineInstruction *MI be the HVX vadd instruction30// MI -> $v0 = V6_vadd_sf $v1, $v231// MachineOperand *DefMI1 = MRI->getVRegDef(MI->getOperand(1).getReg());32// MachineOperand *DefMI2 = MRI->getVRegDef(MI->getOperand(2).getReg());33//34// In the above example, DefMI1 and DefMI2 gives the unique definitions35// corresponding to the operands($v1 and &v2 respectively) of instruction MI.36//37// If both of the definitions are not conversion instructions(V6_vconv_sf_qf32,38// V6_vconv_hf_qf16), then it will skip optimizing the current instruction and39// iterates over next instruction.40//41// If one the definitions is conversion instruction then our pass will replace42// the arithmetic instruction with its corresponding mix variant.43// In the above example, if $v1 is conversion instruction44// DefMI1 -> $v1 = V6_vconv_sf_qf32 $v345// After Transformation:46// MI -> $v0 = V6_vadd_qf32_mix $v3, $v2 ($v1 is replaced with $v3)47//48// If both the definitions are conversion instructions then the instruction will49// be replaced with its qf variant50// In the above example, if $v1 and $v2 are conversion instructions51// DefMI1 -> $v1 = V6_vconv_sf_qf32 $v352// DefMI2 -> $v2 = V6_vconv_sf_qf32 $v453// After Transformation:54// MI -> $v0 = V6_vadd_qf32 $v3, $v4 ($v1 is replaced with $v3, $v2 is replaced55// with $v4)56//57// Currently, in this pass, we are not handling the case when the definitions58// are PHI inst.59//60//===----------------------------------------------------------------------===//61 62#define HEXAGON_QFP_OPTIMIZER "QFP optimizer pass"63 64#include "Hexagon.h"65#include "HexagonInstrInfo.h"66#include "HexagonSubtarget.h"67#include "llvm/ADT/SmallVector.h"68#include "llvm/ADT/StringRef.h"69#include "llvm/CodeGen/MachineBasicBlock.h"70#include "llvm/CodeGen/MachineFunction.h"71#include "llvm/CodeGen/MachineFunctionPass.h"72#include "llvm/CodeGen/MachineInstr.h"73#include "llvm/CodeGen/MachineOperand.h"74#include "llvm/CodeGen/Passes.h"75#include "llvm/Pass.h"76#include "llvm/Support/CommandLine.h"77#include "llvm/Support/Debug.h"78#include "llvm/Support/raw_ostream.h"79#include <map>80 81#define DEBUG_TYPE "hexagon-qfp-optimizer"82 83using namespace llvm;84 85cl::opt<bool>86    DisableQFOptimizer("disable-qfp-opt", cl::init(false),87                       cl::desc("Disable optimization of Qfloat operations."));88cl::opt<bool> DisableQFOptForMul(89    "disable-qfp-opt-mul", cl::init(true),90    cl::desc("Disable optimization of Qfloat operations for multiply."));91 92namespace {93const std::map<unsigned short, unsigned short> QFPInstMap{94    {Hexagon::V6_vadd_hf, Hexagon::V6_vadd_qf16_mix},95    {Hexagon::V6_vadd_qf16_mix, Hexagon::V6_vadd_qf16},96    {Hexagon::V6_vadd_sf, Hexagon::V6_vadd_qf32_mix},97    {Hexagon::V6_vadd_qf32_mix, Hexagon::V6_vadd_qf32},98    {Hexagon::V6_vsub_hf, Hexagon::V6_vsub_qf16_mix},99    {Hexagon::V6_vsub_qf16_mix, Hexagon::V6_vsub_qf16},100    {Hexagon::V6_vsub_sf, Hexagon::V6_vsub_qf32_mix},101    {Hexagon::V6_vsub_qf32_mix, Hexagon::V6_vsub_qf32},102    {Hexagon::V6_vmpy_qf16_hf, Hexagon::V6_vmpy_qf16_mix_hf},103    {Hexagon::V6_vmpy_qf16_mix_hf, Hexagon::V6_vmpy_qf16},104    {Hexagon::V6_vmpy_qf32_hf, Hexagon::V6_vmpy_qf32_mix_hf},105    {Hexagon::V6_vmpy_qf32_mix_hf, Hexagon::V6_vmpy_qf32_qf16},106    {Hexagon::V6_vmpy_qf32_sf, Hexagon::V6_vmpy_qf32},107    {Hexagon::V6_vilog2_sf, Hexagon::V6_vilog2_qf32},108    {Hexagon::V6_vilog2_hf, Hexagon::V6_vilog2_qf16},109    {Hexagon::V6_vabs_qf32_sf, Hexagon::V6_vabs_qf32_qf32},110    {Hexagon::V6_vabs_qf16_hf, Hexagon::V6_vabs_qf16_qf16},111    {Hexagon::V6_vneg_qf32_sf, Hexagon::V6_vneg_qf32_qf32},112    {Hexagon::V6_vneg_qf16_hf, Hexagon::V6_vneg_qf16_qf16}};113} // namespace114 115namespace {116struct HexagonQFPOptimizer : public MachineFunctionPass {117public:118  static char ID;119 120  HexagonQFPOptimizer() : MachineFunctionPass(ID) {}121 122  bool runOnMachineFunction(MachineFunction &MF) override;123 124  bool optimizeQfp(MachineInstr *MI, MachineBasicBlock *MBB);125 126  bool optimizeQfpTwoOp(MachineInstr *MI, MachineBasicBlock *MBB);127 128  bool optimizeQfpOneOp(MachineInstr *MI, MachineBasicBlock *MBB);129 130  StringRef getPassName() const override { return HEXAGON_QFP_OPTIMIZER; }131 132  void getAnalysisUsage(AnalysisUsage &AU) const override {133    AU.setPreservesCFG();134    MachineFunctionPass::getAnalysisUsage(AU);135  }136 137private:138  const HexagonSubtarget *HST = nullptr;139  const HexagonInstrInfo *HII = nullptr;140  const MachineRegisterInfo *MRI = nullptr;141};142 143char HexagonQFPOptimizer::ID = 0;144} // namespace145 146INITIALIZE_PASS(HexagonQFPOptimizer, "hexagon-qfp-optimizer",147                HEXAGON_QFP_OPTIMIZER, false, false)148 149FunctionPass *llvm::createHexagonQFPOptimizer() {150  return new HexagonQFPOptimizer();151}152 153bool HexagonQFPOptimizer::optimizeQfp(MachineInstr *MI,154                                      MachineBasicBlock *MBB) {155 156  if (MI->getNumOperands() == 2)157    return optimizeQfpOneOp(MI, MBB);158  else if (MI->getNumOperands() == 3)159    return optimizeQfpTwoOp(MI, MBB);160  else161    return false;162}163 164bool HexagonQFPOptimizer::optimizeQfpOneOp(MachineInstr *MI,165                                           MachineBasicBlock *MBB) {166 167  unsigned Op0F = 0;168  auto It = QFPInstMap.find(MI->getOpcode());169  if (It == QFPInstMap.end())170    return false;171 172  unsigned short InstTy = It->second;173  // Get the reachind defs of MI174  MachineInstr *DefMI = MRI->getVRegDef(MI->getOperand(1).getReg());175  MachineOperand &Res = MI->getOperand(0);176  if (!Res.isReg())177    return false;178 179  LLVM_DEBUG(dbgs() << "\n[Reaching Defs of operands]: "; DefMI->dump());180  MachineInstr *ReachDefDef = nullptr;181 182  // Get the reaching def of the reaching def to check for W reg def183  if (DefMI->getNumOperands() > 1 && DefMI->getOperand(1).isReg() &&184      DefMI->getOperand(1).getReg().isVirtual())185    ReachDefDef = MRI->getVRegDef(DefMI->getOperand(1).getReg());186  unsigned ReachDefOp = DefMI->getOpcode();187  MachineInstrBuilder MIB;188 189  // Check if the reaching def is a conversion190  if (ReachDefOp == Hexagon::V6_vconv_sf_qf32 ||191      ReachDefOp == Hexagon::V6_vconv_hf_qf16) {192 193    // Return if the reaching def of reaching def is W type194    if (ReachDefDef && MRI->getRegClass(ReachDefDef->getOperand(0).getReg()) ==195                           &Hexagon::HvxWRRegClass)196      return false;197 198    // Analyze the use operands of the conversion to get their KILL status199    MachineOperand &SrcOp = DefMI->getOperand(1);200    Op0F = getKillRegState(SrcOp.isKill());201    SrcOp.setIsKill(false);202    MIB = BuildMI(*MBB, MI, MI->getDebugLoc(), HII->get(InstTy), Res.getReg())203              .addReg(SrcOp.getReg(), Op0F, SrcOp.getSubReg());204    LLVM_DEBUG(dbgs() << "\n[Inserting]: "; MIB.getInstr()->dump());205    return true;206  }207  return false;208}209 210bool HexagonQFPOptimizer::optimizeQfpTwoOp(MachineInstr *MI,211                                           MachineBasicBlock *MBB) {212 213  unsigned Op0F = 0;214  unsigned Op1F = 0;215  auto It = QFPInstMap.find(MI->getOpcode());216  if (It == QFPInstMap.end())217    return false;218  unsigned short InstTy = It->second;219  // Get the reaching defs of MI, DefMI1 and DefMI2220  MachineInstr *DefMI1 = nullptr;221  MachineInstr *DefMI2 = nullptr;222 223  if (MI->getOperand(1).isReg())224    DefMI1 = MRI->getVRegDef(MI->getOperand(1).getReg());225  if (MI->getOperand(2).isReg())226    DefMI2 = MRI->getVRegDef(MI->getOperand(2).getReg());227  if (!DefMI1 || !DefMI2)228    return false;229 230  MachineOperand &Res = MI->getOperand(0);231  if (!Res.isReg())232    return false;233 234  MachineInstr *Inst1 = nullptr;235  MachineInstr *Inst2 = nullptr;236  LLVM_DEBUG(dbgs() << "\n[Reaching Defs of operands]: "; DefMI1->dump();237             DefMI2->dump());238 239  // Get the reaching defs of DefMI240  if (DefMI1->getNumOperands() > 1 && DefMI1->getOperand(1).isReg() &&241      DefMI1->getOperand(1).getReg().isVirtual())242    Inst1 = MRI->getVRegDef(DefMI1->getOperand(1).getReg());243 244  if (DefMI2->getNumOperands() > 1 && DefMI2->getOperand(1).isReg() &&245      DefMI2->getOperand(1).getReg().isVirtual())246    Inst2 = MRI->getVRegDef(DefMI2->getOperand(1).getReg());247 248  unsigned Def1OP = DefMI1->getOpcode();249  unsigned Def2OP = DefMI2->getOpcode();250 251  MachineInstrBuilder MIB;252 253  // Check if the both the reaching defs of MI are qf to sf/hf conversions254  if ((Def1OP == Hexagon::V6_vconv_sf_qf32 &&255       Def2OP == Hexagon::V6_vconv_sf_qf32) ||256      (Def1OP == Hexagon::V6_vconv_hf_qf16 &&257       Def2OP == Hexagon::V6_vconv_hf_qf16)) {258 259    // If the reaching defs of DefMI are W register type, we return260    if ((Inst1 && Inst1->getNumOperands() > 0 && Inst1->getOperand(0).isReg() &&261         MRI->getRegClass(Inst1->getOperand(0).getReg()) ==262             &Hexagon::HvxWRRegClass) ||263        (Inst2 && Inst2->getNumOperands() > 0 && Inst2->getOperand(0).isReg() &&264         MRI->getRegClass(Inst2->getOperand(0).getReg()) ==265             &Hexagon::HvxWRRegClass))266      return false;267 268    // Analyze the use operands of the conversion to get their KILL status269    MachineOperand &Src1 = DefMI1->getOperand(1);270    MachineOperand &Src2 = DefMI2->getOperand(1);271 272    Op0F = getKillRegState(Src1.isKill());273    Src1.setIsKill(false);274 275    Op1F = getKillRegState(Src2.isKill());276    Src2.setIsKill(false);277 278    if (MI->getOpcode() != Hexagon::V6_vmpy_qf32_sf) {279      auto OuterIt = QFPInstMap.find(MI->getOpcode());280      if (OuterIt == QFPInstMap.end())281        return false;282      auto InnerIt = QFPInstMap.find(OuterIt->second);283      if (InnerIt == QFPInstMap.end())284        return false;285      InstTy = InnerIt->second;286    }287 288    MIB = BuildMI(*MBB, MI, MI->getDebugLoc(), HII->get(InstTy), Res.getReg())289              .addReg(Src1.getReg(), Op0F, Src1.getSubReg())290              .addReg(Src2.getReg(), Op1F, Src2.getSubReg());291    LLVM_DEBUG(dbgs() << "\n[Inserting]: "; MIB.getInstr()->dump());292    return true;293 294    // Check if left operand's reaching def is a conversion to sf/hf295  } else if (((Def1OP == Hexagon::V6_vconv_sf_qf32 &&296               Def2OP != Hexagon::V6_vconv_sf_qf32) ||297              (Def1OP == Hexagon::V6_vconv_hf_qf16 &&298               Def2OP != Hexagon::V6_vconv_hf_qf16)) &&299             !DefMI2->isPHI() &&300             (MI->getOpcode() != Hexagon::V6_vmpy_qf32_sf)) {301 302    if (Inst1 && MRI->getRegClass(Inst1->getOperand(0).getReg()) ==303                     &Hexagon::HvxWRRegClass)304      return false;305 306    MachineOperand &Src1 = DefMI1->getOperand(1);307    MachineOperand &Src2 = MI->getOperand(2);308 309    Op0F = getKillRegState(Src1.isKill());310    Src1.setIsKill(false);311    Op1F = getKillRegState(Src2.isKill());312    MIB = BuildMI(*MBB, MI, MI->getDebugLoc(), HII->get(InstTy), Res.getReg())313              .addReg(Src1.getReg(), Op0F, Src1.getSubReg())314              .addReg(Src2.getReg(), Op1F, Src2.getSubReg());315    LLVM_DEBUG(dbgs() << "\n[Inserting]: "; MIB.getInstr()->dump());316    return true;317 318    // Check if right operand's reaching def is a conversion to sf/hf319  } else if (((Def1OP != Hexagon::V6_vconv_sf_qf32 &&320               Def2OP == Hexagon::V6_vconv_sf_qf32) ||321              (Def1OP != Hexagon::V6_vconv_hf_qf16 &&322               Def2OP == Hexagon::V6_vconv_hf_qf16)) &&323             !DefMI1->isPHI() &&324             (MI->getOpcode() != Hexagon::V6_vmpy_qf32_sf)) {325    // The second operand of original instruction is converted.326    if (Inst2 && MRI->getRegClass(Inst2->getOperand(0).getReg()) ==327                     &Hexagon::HvxWRRegClass)328      return false;329 330    MachineOperand &Src1 = MI->getOperand(1);331    MachineOperand &Src2 = DefMI2->getOperand(1);332 333    Op1F = getKillRegState(Src2.isKill());334    Src2.setIsKill(false);335    Op0F = getKillRegState(Src1.isKill());336    if (InstTy == Hexagon::V6_vsub_qf16_mix ||337        InstTy == Hexagon::V6_vsub_qf32_mix) {338      if (!HST->useHVXV81Ops())339        // vsub_(hf|sf)_mix insts are only avlbl on hvx81+340        return false;341      // vsub is not commutative w.r.t. operands -> treat it as a special case342      // to choose the correct mix instruction.343      if (Def2OP == Hexagon::V6_vconv_sf_qf32)344        InstTy = Hexagon::V6_vsub_sf_mix;345      else if (Def2OP == Hexagon::V6_vconv_hf_qf16)346        InstTy = Hexagon::V6_vsub_hf_mix;347      MIB = BuildMI(*MBB, MI, MI->getDebugLoc(), HII->get(InstTy), Res.getReg())348                .addReg(Src1.getReg(), Op0F, Src1.getSubReg())349                .addReg(Src2.getReg(), Op1F, Src2.getSubReg());350    } else {351      MIB = BuildMI(*MBB, MI, MI->getDebugLoc(), HII->get(InstTy), Res.getReg())352                .addReg(Src2.getReg(), Op1F,353                        Src2.getSubReg()) // Notice the operands are flipped.354                .addReg(Src1.getReg(), Op0F, Src1.getSubReg());355    }356    LLVM_DEBUG(dbgs() << "\n[Inserting]: "; MIB.getInstr()->dump());357    return true;358  }359 360  return false;361}362 363bool HexagonQFPOptimizer::runOnMachineFunction(MachineFunction &MF) {364 365  bool Changed = false;366 367  if (DisableQFOptimizer)368    return Changed;369 370  HST = &MF.getSubtarget<HexagonSubtarget>();371  if (!HST->useHVXV68Ops() || !HST->usePackets() ||372      skipFunction(MF.getFunction()))373    return false;374  HII = HST->getInstrInfo();375  MRI = &MF.getRegInfo();376 377  MachineFunction::iterator MBBI = MF.begin();378  LLVM_DEBUG(dbgs() << "\n=== Running QFPOptimzer Pass for : " << MF.getName()379                    << " Optimize intermediate conversions ===\n");380  while (MBBI != MF.end()) {381    MachineBasicBlock *MBB = &*MBBI;382    MachineBasicBlock::iterator MII = MBBI->instr_begin();383    while (MII != MBBI->instr_end()) {384      MachineInstr *MI = &*MII;385      ++MII; // As MI might be removed.386      if (QFPInstMap.count(MI->getOpcode())) {387        auto OpC = MI->getOpcode();388        if (DisableQFOptForMul && HII->isQFPMul(MI))389          continue;390        if (OpC != Hexagon::V6_vconv_sf_qf32 &&391            OpC != Hexagon::V6_vconv_hf_qf16) {392          LLVM_DEBUG(dbgs() << "\n###Analyzing for removal: "; MI->dump());393          if (optimizeQfp(MI, MBB)) {394            MI->eraseFromParent();395            LLVM_DEBUG(dbgs() << "\t....Removing....");396            Changed = true;397          }398        }399      }400    }401    ++MBBI;402  }403  return Changed;404}405