LCOV - code coverage report
Current view: top level - lib/Target/AArch64 - AArch64MacroFusion.cpp (source / functions) Hit Total Coverage
Test: llvm-toolchain.info Lines: 63 77 81.8 %
Date: 2018-06-17 00:07:59 Functions: 8 8 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : //===- AArch64MacroFusion.cpp - AArch64 Macro Fusion ----------------------===//
       2             : //
       3             : //                     The LLVM Compiler Infrastructure
       4             : //
       5             : // This file is distributed under the University of Illinois Open Source
       6             : // License. See LICENSE.TXT for details.
       7             : //
       8             : //===----------------------------------------------------------------------===//
       9             : //
      10             : /// \file This file contains the AArch64 implementation of the DAG scheduling
      11             : ///  mutation to pair instructions back to back.
      12             : //
      13             : //===----------------------------------------------------------------------===//
      14             : 
      15             : #include "AArch64Subtarget.h"
      16             : #include "llvm/CodeGen/MacroFusion.h"
      17             : #include "llvm/CodeGen/TargetInstrInfo.h"
      18             : 
      19             : using namespace llvm;
      20             : 
      21             : namespace {
      22             : 
      23             : // Fuse CMN, CMP, TST followed by Bcc.
      24        3432 : static bool isArithmeticBccPair(const MachineInstr *FirstMI,
      25             :                                 const MachineInstr &SecondMI) {
      26        6864 :   if (SecondMI.getOpcode() == AArch64::Bcc) {
      27             :     // Assume the 1st instr to be a wildcard if it is unspecified.
      28          88 :     if (!FirstMI)
      29             :       return true;
      30             : 
      31          88 :     switch (FirstMI->getOpcode()) {
      32             :     case AArch64::ADDSWri:
      33             :     case AArch64::ADDSWrr:
      34             :     case AArch64::ADDSXri:
      35             :     case AArch64::ADDSXrr:
      36             :     case AArch64::ANDSWri:
      37             :     case AArch64::ANDSWrr:
      38             :     case AArch64::ANDSXri:
      39             :     case AArch64::ANDSXrr:
      40             :     case AArch64::SUBSWri:
      41             :     case AArch64::SUBSWrr:
      42             :     case AArch64::SUBSXri:
      43             :     case AArch64::SUBSXrr:
      44             :     case AArch64::BICSWrr:
      45             :     case AArch64::BICSXrr:
      46             :       return true;
      47           0 :     case AArch64::ADDSWrs:
      48             :     case AArch64::ADDSXrs:
      49             :     case AArch64::ANDSWrs:
      50             :     case AArch64::ANDSXrs:
      51             :     case AArch64::SUBSWrs:
      52             :     case AArch64::SUBSXrs:
      53             :     case AArch64::BICSWrs:
      54             :     case AArch64::BICSXrs:
      55             :       // Shift value can be 0 making these behave like the "rr" variant...
      56           0 :       return (!AArch64InstrInfo::hasShiftedReg(*FirstMI));
      57             :     }
      58             :   }
      59             :   return false;
      60             : }
      61             : 
      62             : // Fuse ALU operations followed by CBZ/CBNZ.
      63        3337 : static bool isArithmeticCbzPair(const MachineInstr *FirstMI,
      64             :                                 const MachineInstr &SecondMI) {
      65        3337 :   unsigned SecondOpcode = SecondMI.getOpcode();
      66             : 
      67        3337 :   if (SecondOpcode == AArch64::CBNZW || SecondOpcode == AArch64::CBNZX ||
      68        3337 :       SecondOpcode == AArch64::CBZW  || SecondOpcode == AArch64::CBZX) {
      69             :     // Assume the 1st instr to be a wildcard if it is unspecified.
      70          71 :     if (!FirstMI)
      71             :       return true;
      72             : 
      73          74 :     switch (FirstMI->getOpcode()) {
      74             :     case AArch64::ADDWri:
      75             :     case AArch64::ADDWrr:
      76             :     case AArch64::ADDXri:
      77             :     case AArch64::ADDXrr:
      78             :     case AArch64::ANDWri:
      79             :     case AArch64::ANDWrr:
      80             :     case AArch64::ANDXri:
      81             :     case AArch64::ANDXrr:
      82             :     case AArch64::EORWri:
      83             :     case AArch64::EORWrr:
      84             :     case AArch64::EORXri:
      85             :     case AArch64::EORXrr:
      86             :     case AArch64::ORRWri:
      87             :     case AArch64::ORRWrr:
      88             :     case AArch64::ORRXri:
      89             :     case AArch64::ORRXrr:
      90             :     case AArch64::SUBWri:
      91             :     case AArch64::SUBWrr:
      92             :     case AArch64::SUBXri:
      93             :     case AArch64::SUBXrr:
      94             :       return true;
      95           0 :     case AArch64::ADDWrs:
      96             :     case AArch64::ADDXrs:
      97             :     case AArch64::ANDWrs:
      98             :     case AArch64::ANDXrs:
      99             :     case AArch64::SUBWrs:
     100             :     case AArch64::SUBXrs:
     101             :     case AArch64::BICWrs:
     102             :     case AArch64::BICXrs:
     103             :       // Shift value can be 0 making these behave like the "rr" variant...
     104           0 :       return (!AArch64InstrInfo::hasShiftedReg(*FirstMI));
     105             :     }
     106             :   }
     107             :   return false;
     108             : }
     109             : 
     110             : // Fuse AES crypto encoding or decoding.
     111      120939 : static bool isAESPair(const MachineInstr *FirstMI,
     112             :                       const MachineInstr &SecondMI) {
     113             :   // Assume the 1st instr to be a wildcard if it is unspecified.
     114             :   unsigned FirstOpcode =
     115      120939 :       FirstMI ? FirstMI->getOpcode()
     116             :               : static_cast<unsigned>(AArch64::INSTRUCTION_LIST_END);
     117      120939 :   unsigned SecondOpcode = SecondMI.getOpcode();
     118             : 
     119             :   // AES encode.
     120      241878 :   if ((FirstOpcode == AArch64::INSTRUCTION_LIST_END ||
     121      241296 :        FirstOpcode == AArch64::AESErr) &&
     122      120357 :       (SecondOpcode == AArch64::AESMCrr ||
     123             :        SecondOpcode == AArch64::AESMCrrTied))
     124             :     return true;
     125             :   // AES decode.
     126      120576 :   else if ((FirstOpcode == AArch64::INSTRUCTION_LIST_END ||
     127      240712 :             FirstOpcode == AArch64::AESDrr) &&
     128      120136 :            (SecondOpcode == AArch64::AESIMCrr ||
     129             :             SecondOpcode == AArch64::AESIMCrrTied))
     130             :     return true;
     131             : 
     132      120285 :   return false;
     133             : }
     134             : 
     135             : // Fuse literal generation.
     136        4655 : static bool isLiteralsPair(const MachineInstr *FirstMI,
     137             :                            const MachineInstr &SecondMI) {
     138             :   // Assume the 1st instr to be a wildcard if it is unspecified.
     139             :   unsigned FirstOpcode =
     140        4655 :       FirstMI ? FirstMI->getOpcode()
     141             :               : static_cast<unsigned>(AArch64::INSTRUCTION_LIST_END);
     142        4655 :   unsigned SecondOpcode = SecondMI.getOpcode();
     143             : 
     144             :   // PC relative address.
     145        9310 :   if ((FirstOpcode == AArch64::INSTRUCTION_LIST_END ||
     146        9032 :        FirstOpcode == AArch64::ADRP) &&
     147             :       SecondOpcode == AArch64::ADDXri)
     148             :     return true;
     149             :   // 32 bit immediate.
     150        4613 :   else if ((FirstOpcode == AArch64::INSTRUCTION_LIST_END ||
     151        9226 :             FirstOpcode == AArch64::MOVZWi) &&
     152           8 :            (SecondOpcode == AArch64::MOVKWi &&
     153           8 :             SecondMI.getOperand(3).getImm() == 16))
     154             :     return true;
     155             :   // Lower half of 64 bit immediate.
     156        4605 :   else if((FirstOpcode == AArch64::INSTRUCTION_LIST_END ||
     157        9210 :            FirstOpcode == AArch64::MOVZXi) &&
     158          16 :           (SecondOpcode == AArch64::MOVKXi &&
     159          16 :            SecondMI.getOperand(3).getImm() == 16))
     160             :     return true;
     161             :   // Upper half of 64 bit immediate.
     162         332 :   else if ((FirstOpcode == AArch64::INSTRUCTION_LIST_END ||
     163           4 :             (FirstOpcode == AArch64::MOVKXi &&
     164        8870 :              FirstMI->getOperand(3).getImm() == 32)) &&
     165          12 :            (SecondOpcode == AArch64::MOVKXi &&
     166          12 :             SecondMI.getOperand(3).getImm() == 48))
     167             :     return true;
     168             : 
     169             :   return false;
     170             : }
     171             : 
     172             : // Fuse address generation and loads or stores.
     173        3102 : static bool isAddressLdStPair(const MachineInstr *FirstMI,
     174             :                               const MachineInstr &SecondMI) {
     175        3102 :   unsigned SecondOpcode = SecondMI.getOpcode();
     176             : 
     177        3102 :   switch (SecondOpcode) {
     178         531 :   case AArch64::STRBBui:
     179             :   case AArch64::STRBui:
     180             :   case AArch64::STRDui:
     181             :   case AArch64::STRHHui:
     182             :   case AArch64::STRHui:
     183             :   case AArch64::STRQui:
     184             :   case AArch64::STRSui:
     185             :   case AArch64::STRWui:
     186             :   case AArch64::STRXui:
     187             :   case AArch64::LDRBBui:
     188             :   case AArch64::LDRBui:
     189             :   case AArch64::LDRDui:
     190             :   case AArch64::LDRHHui:
     191             :   case AArch64::LDRHui:
     192             :   case AArch64::LDRQui:
     193             :   case AArch64::LDRSui:
     194             :   case AArch64::LDRWui:
     195             :   case AArch64::LDRXui:
     196             :   case AArch64::LDRSBWui:
     197             :   case AArch64::LDRSBXui:
     198             :   case AArch64::LDRSHWui:
     199             :   case AArch64::LDRSHXui:
     200             :   case AArch64::LDRSWui:
     201             :     // Assume the 1st instr to be a wildcard if it is unspecified.
     202         531 :     if (!FirstMI)
     203             :       return true;
     204             : 
     205         688 :     switch (FirstMI->getOpcode()) {
     206           0 :     case AArch64::ADR:
     207           0 :       return (SecondMI.getOperand(2).getImm() == 0);
     208             :     case AArch64::ADRP:
     209             :       return true;
     210             :     }
     211             :   }
     212             :   return false;
     213             : }
     214             : 
     215             : // Fuse compare and conditional select.
     216        2776 : static bool isCCSelectPair(const MachineInstr *FirstMI,
     217             :                            const MachineInstr &SecondMI) {
     218        2776 :   unsigned SecondOpcode = SecondMI.getOpcode();
     219             : 
     220             :   // 32 bits
     221        2776 :   if (SecondOpcode == AArch64::CSELWr) {
     222             :     // Assume the 1st instr to be a wildcard if it is unspecified.
     223          12 :     if (!FirstMI)
     224             :       return true;
     225             : 
     226           6 :     if (FirstMI->definesRegister(AArch64::WZR))
     227          12 :       switch (FirstMI->getOpcode()) {
     228           0 :       case AArch64::SUBSWrs:
     229           0 :         return (!AArch64InstrInfo::hasShiftedReg(*FirstMI));
     230           0 :       case AArch64::SUBSWrx:
     231           0 :         return (!AArch64InstrInfo::hasExtendedReg(*FirstMI));
     232             :       case AArch64::SUBSWrr:
     233             :       case AArch64::SUBSWri:
     234             :         return true;
     235             :       }
     236             :   }
     237             :   // 64 bits
     238        2764 :   else if (SecondOpcode == AArch64::CSELXr) {
     239             :     // Assume the 1st instr to be a wildcard if it is unspecified.
     240          12 :     if (!FirstMI)
     241             :       return true;
     242             : 
     243           6 :     if (FirstMI->definesRegister(AArch64::XZR))
     244          12 :       switch (FirstMI->getOpcode()) {
     245           0 :       case AArch64::SUBSXrs:
     246           0 :         return (!AArch64InstrInfo::hasShiftedReg(*FirstMI));
     247           0 :       case AArch64::SUBSXrx:
     248             :       case AArch64::SUBSXrx64:
     249           0 :         return (!AArch64InstrInfo::hasExtendedReg(*FirstMI));
     250             :       case AArch64::SUBSXrr:
     251             :       case AArch64::SUBSXri:
     252             :         return true;
     253             :       }
     254             :   }
     255             :   return false;
     256             : }
     257             : 
     258             : /// Check if the instr pair, FirstMI and SecondMI, should be fused
     259             : /// together. Given SecondMI, when FirstMI is unspecified, then check if
     260             : /// SecondMI may be part of a fused pair at all.
     261      121076 : static bool shouldScheduleAdjacent(const TargetInstrInfo &TII,
     262             :                                    const TargetSubtargetInfo &TSI,
     263             :                                    const MachineInstr *FirstMI,
     264             :                                    const MachineInstr &SecondMI) {
     265             :   const AArch64Subtarget &ST = static_cast<const AArch64Subtarget&>(TSI);
     266             : 
     267      121076 :   if (ST.hasArithmeticBccFusion() && isArithmeticBccPair(FirstMI, SecondMI))
     268             :     return true;
     269      120997 :   if (ST.hasArithmeticCbzFusion() && isArithmeticCbzPair(FirstMI, SecondMI))
     270             :     return true;
     271      120959 :   if (ST.hasFuseAES() && isAESPair(FirstMI, SecondMI))
     272             :     return true;
     273      120305 :   if (ST.hasFuseLiterals() && isLiteralsPair(FirstMI, SecondMI))
     274             :     return true;
     275      120239 :   if (ST.hasFuseAddress() && isAddressLdStPair(FirstMI, SecondMI))
     276             :     return true;
     277      119962 :   if (ST.hasFuseCCSelect() && isCCSelectPair(FirstMI, SecondMI))
     278             :     return true;
     279             : 
     280             :   return false;
     281             : }
     282             : 
     283             : } // end namespace
     284             : 
     285             : 
     286             : namespace llvm {
     287             : 
     288       22238 : std::unique_ptr<ScheduleDAGMutation> createAArch64MacroFusionDAGMutation () {
     289       44476 :   return createMacroFusionDAGMutation(shouldScheduleAdjacent);
     290             : }
     291             : 
     292             : } // end namespace llvm

Generated by: LCOV version 1.13