Path: blob/main/contrib/llvm-project/llvm/lib/Target/AArch64/AArch64MacroFusion.cpp
35294 views
//===- AArch64MacroFusion.cpp - AArch64 Macro Fusion ----------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8/// \file This file contains the AArch64 implementation of the DAG scheduling9/// mutation to pair instructions back to back.10//11//===----------------------------------------------------------------------===//1213#include "AArch64MacroFusion.h"14#include "AArch64Subtarget.h"15#include "llvm/CodeGen/MacroFusion.h"16#include "llvm/CodeGen/TargetInstrInfo.h"1718using namespace llvm;1920/// CMN, CMP, TST followed by Bcc21static bool isArithmeticBccPair(const MachineInstr *FirstMI,22const MachineInstr &SecondMI, bool CmpOnly) {23if (SecondMI.getOpcode() != AArch64::Bcc)24return false;2526// Assume the 1st instr to be a wildcard if it is unspecified.27if (FirstMI == nullptr)28return true;2930// If we're in CmpOnly mode, we only fuse arithmetic instructions that31// discard their result.32if (CmpOnly && FirstMI->getOperand(0).isReg() &&33!(FirstMI->getOperand(0).getReg() == AArch64::XZR ||34FirstMI->getOperand(0).getReg() == AArch64::WZR)) {35return false;36}3738switch (FirstMI->getOpcode()) {39case AArch64::ADDSWri:40case AArch64::ADDSWrr:41case AArch64::ADDSXri:42case AArch64::ADDSXrr:43case AArch64::ANDSWri:44case AArch64::ANDSWrr:45case AArch64::ANDSXri:46case AArch64::ANDSXrr:47case AArch64::SUBSWri:48case AArch64::SUBSWrr:49case AArch64::SUBSXri:50case AArch64::SUBSXrr:51case AArch64::BICSWrr:52case AArch64::BICSXrr:53return true;54case AArch64::ADDSWrs:55case AArch64::ADDSXrs:56case AArch64::ANDSWrs:57case AArch64::ANDSXrs:58case AArch64::SUBSWrs:59case AArch64::SUBSXrs:60case AArch64::BICSWrs:61case AArch64::BICSXrs:62// Shift value can be 0 making these behave like the "rr" variant...63return !AArch64InstrInfo::hasShiftedReg(*FirstMI);64}6566return false;67}6869/// ALU operations followed by CBZ/CBNZ.70static bool isArithmeticCbzPair(const MachineInstr *FirstMI,71const MachineInstr &SecondMI) {72if (SecondMI.getOpcode() != AArch64::CBZW &&73SecondMI.getOpcode() != AArch64::CBZX &&74SecondMI.getOpcode() != AArch64::CBNZW &&75SecondMI.getOpcode() != AArch64::CBNZX)76return false;7778// Assume the 1st instr to be a wildcard if it is unspecified.79if (FirstMI == nullptr)80return true;8182switch (FirstMI->getOpcode()) {83case AArch64::ADDWri:84case AArch64::ADDWrr:85case AArch64::ADDXri:86case AArch64::ADDXrr:87case AArch64::ANDWri:88case AArch64::ANDWrr:89case AArch64::ANDXri:90case AArch64::ANDXrr:91case AArch64::EORWri:92case AArch64::EORWrr:93case AArch64::EORXri:94case AArch64::EORXrr:95case AArch64::ORRWri:96case AArch64::ORRWrr:97case AArch64::ORRXri:98case AArch64::ORRXrr:99case AArch64::SUBWri:100case AArch64::SUBWrr:101case AArch64::SUBXri:102case AArch64::SUBXrr:103return true;104case AArch64::ADDWrs:105case AArch64::ADDXrs:106case AArch64::ANDWrs:107case AArch64::ANDXrs:108case AArch64::SUBWrs:109case AArch64::SUBXrs:110case AArch64::BICWrs:111case AArch64::BICXrs:112// Shift value can be 0 making these behave like the "rr" variant...113return !AArch64InstrInfo::hasShiftedReg(*FirstMI);114}115116return false;117}118119/// AES crypto encoding or decoding.120static bool isAESPair(const MachineInstr *FirstMI,121const MachineInstr &SecondMI) {122// Assume the 1st instr to be a wildcard if it is unspecified.123switch (SecondMI.getOpcode()) {124// AES encode.125case AArch64::AESMCrr:126case AArch64::AESMCrrTied:127return FirstMI == nullptr || FirstMI->getOpcode() == AArch64::AESErr;128// AES decode.129case AArch64::AESIMCrr:130case AArch64::AESIMCrrTied:131return FirstMI == nullptr || FirstMI->getOpcode() == AArch64::AESDrr;132}133134return false;135}136137/// AESE/AESD/PMULL + EOR.138static bool isCryptoEORPair(const MachineInstr *FirstMI,139const MachineInstr &SecondMI) {140if (SecondMI.getOpcode() != AArch64::EORv16i8)141return false;142143// Assume the 1st instr to be a wildcard if it is unspecified.144if (FirstMI == nullptr)145return true;146147switch (FirstMI->getOpcode()) {148case AArch64::AESErr:149case AArch64::AESDrr:150case AArch64::PMULLv16i8:151case AArch64::PMULLv8i8:152case AArch64::PMULLv1i64:153case AArch64::PMULLv2i64:154return true;155}156157return false;158}159160static bool isAdrpAddPair(const MachineInstr *FirstMI,161const MachineInstr &SecondMI) {162// Assume the 1st instr to be a wildcard if it is unspecified.163if ((FirstMI == nullptr || FirstMI->getOpcode() == AArch64::ADRP) &&164SecondMI.getOpcode() == AArch64::ADDXri)165return true;166return false;167}168169/// Literal generation.170static bool isLiteralsPair(const MachineInstr *FirstMI,171const MachineInstr &SecondMI) {172// Assume the 1st instr to be a wildcard if it is unspecified.173// 32 bit immediate.174if ((FirstMI == nullptr || FirstMI->getOpcode() == AArch64::MOVZWi) &&175(SecondMI.getOpcode() == AArch64::MOVKWi &&176SecondMI.getOperand(3).getImm() == 16))177return true;178179// Lower half of 64 bit immediate.180if((FirstMI == nullptr || FirstMI->getOpcode() == AArch64::MOVZXi) &&181(SecondMI.getOpcode() == AArch64::MOVKXi &&182SecondMI.getOperand(3).getImm() == 16))183return true;184185// Upper half of 64 bit immediate.186if ((FirstMI == nullptr ||187(FirstMI->getOpcode() == AArch64::MOVKXi &&188FirstMI->getOperand(3).getImm() == 32)) &&189(SecondMI.getOpcode() == AArch64::MOVKXi &&190SecondMI.getOperand(3).getImm() == 48))191return true;192193return false;194}195196/// Fuse address generation and loads or stores.197static bool isAddressLdStPair(const MachineInstr *FirstMI,198const MachineInstr &SecondMI) {199switch (SecondMI.getOpcode()) {200case AArch64::STRBBui:201case AArch64::STRBui:202case AArch64::STRDui:203case AArch64::STRHHui:204case AArch64::STRHui:205case AArch64::STRQui:206case AArch64::STRSui:207case AArch64::STRWui:208case AArch64::STRXui:209case AArch64::LDRBBui:210case AArch64::LDRBui:211case AArch64::LDRDui:212case AArch64::LDRHHui:213case AArch64::LDRHui:214case AArch64::LDRQui:215case AArch64::LDRSui:216case AArch64::LDRWui:217case AArch64::LDRXui:218case AArch64::LDRSBWui:219case AArch64::LDRSBXui:220case AArch64::LDRSHWui:221case AArch64::LDRSHXui:222case AArch64::LDRSWui:223// Assume the 1st instr to be a wildcard if it is unspecified.224if (FirstMI == nullptr)225return true;226227switch (FirstMI->getOpcode()) {228case AArch64::ADR:229return SecondMI.getOperand(2).getImm() == 0;230case AArch64::ADRP:231return true;232}233}234235return false;236}237238/// Compare and conditional select.239static bool isCCSelectPair(const MachineInstr *FirstMI,240const MachineInstr &SecondMI) {241// 32 bits242if (SecondMI.getOpcode() == AArch64::CSELWr) {243// Assume the 1st instr to be a wildcard if it is unspecified.244if (FirstMI == nullptr)245return true;246247if (FirstMI->definesRegister(AArch64::WZR, /*TRI=*/nullptr))248switch (FirstMI->getOpcode()) {249case AArch64::SUBSWrs:250return !AArch64InstrInfo::hasShiftedReg(*FirstMI);251case AArch64::SUBSWrx:252return !AArch64InstrInfo::hasExtendedReg(*FirstMI);253case AArch64::SUBSWrr:254case AArch64::SUBSWri:255return true;256}257}258259// 64 bits260if (SecondMI.getOpcode() == AArch64::CSELXr) {261// Assume the 1st instr to be a wildcard if it is unspecified.262if (FirstMI == nullptr)263return true;264265if (FirstMI->definesRegister(AArch64::XZR, /*TRI=*/nullptr))266switch (FirstMI->getOpcode()) {267case AArch64::SUBSXrs:268return !AArch64InstrInfo::hasShiftedReg(*FirstMI);269case AArch64::SUBSXrx:270case AArch64::SUBSXrx64:271return !AArch64InstrInfo::hasExtendedReg(*FirstMI);272case AArch64::SUBSXrr:273case AArch64::SUBSXri:274return true;275}276}277278return false;279}280281// Arithmetic and logic.282static bool isArithmeticLogicPair(const MachineInstr *FirstMI,283const MachineInstr &SecondMI) {284if (AArch64InstrInfo::hasShiftedReg(SecondMI))285return false;286287switch (SecondMI.getOpcode()) {288// Arithmetic289case AArch64::ADDWrr:290case AArch64::ADDXrr:291case AArch64::SUBWrr:292case AArch64::SUBXrr:293case AArch64::ADDWrs:294case AArch64::ADDXrs:295case AArch64::SUBWrs:296case AArch64::SUBXrs:297// Logic298case AArch64::ANDWrr:299case AArch64::ANDXrr:300case AArch64::BICWrr:301case AArch64::BICXrr:302case AArch64::EONWrr:303case AArch64::EONXrr:304case AArch64::EORWrr:305case AArch64::EORXrr:306case AArch64::ORNWrr:307case AArch64::ORNXrr:308case AArch64::ORRWrr:309case AArch64::ORRXrr:310case AArch64::ANDWrs:311case AArch64::ANDXrs:312case AArch64::BICWrs:313case AArch64::BICXrs:314case AArch64::EONWrs:315case AArch64::EONXrs:316case AArch64::EORWrs:317case AArch64::EORXrs:318case AArch64::ORNWrs:319case AArch64::ORNXrs:320case AArch64::ORRWrs:321case AArch64::ORRXrs:322// Assume the 1st instr to be a wildcard if it is unspecified.323if (FirstMI == nullptr)324return true;325326// Arithmetic327switch (FirstMI->getOpcode()) {328case AArch64::ADDWrr:329case AArch64::ADDXrr:330case AArch64::ADDSWrr:331case AArch64::ADDSXrr:332case AArch64::SUBWrr:333case AArch64::SUBXrr:334case AArch64::SUBSWrr:335case AArch64::SUBSXrr:336return true;337case AArch64::ADDWrs:338case AArch64::ADDXrs:339case AArch64::ADDSWrs:340case AArch64::ADDSXrs:341case AArch64::SUBWrs:342case AArch64::SUBXrs:343case AArch64::SUBSWrs:344case AArch64::SUBSXrs:345return !AArch64InstrInfo::hasShiftedReg(*FirstMI);346}347break;348349// Arithmetic, setting flags.350case AArch64::ADDSWrr:351case AArch64::ADDSXrr:352case AArch64::SUBSWrr:353case AArch64::SUBSXrr:354case AArch64::ADDSWrs:355case AArch64::ADDSXrs:356case AArch64::SUBSWrs:357case AArch64::SUBSXrs:358// Assume the 1st instr to be a wildcard if it is unspecified.359if (FirstMI == nullptr)360return true;361362// Arithmetic, not setting flags.363switch (FirstMI->getOpcode()) {364case AArch64::ADDWrr:365case AArch64::ADDXrr:366case AArch64::SUBWrr:367case AArch64::SUBXrr:368return true;369case AArch64::ADDWrs:370case AArch64::ADDXrs:371case AArch64::SUBWrs:372case AArch64::SUBXrs:373return !AArch64InstrInfo::hasShiftedReg(*FirstMI);374}375break;376}377378return false;379}380381// "(A + B) + 1" or "(A - B) - 1"382static bool isAddSub2RegAndConstOnePair(const MachineInstr *FirstMI,383const MachineInstr &SecondMI) {384bool NeedsSubtract = false;385386// The 2nd instr must be an add-immediate or subtract-immediate.387switch (SecondMI.getOpcode()) {388case AArch64::SUBWri:389case AArch64::SUBXri:390NeedsSubtract = true;391[[fallthrough]];392case AArch64::ADDWri:393case AArch64::ADDXri:394break;395396default:397return false;398}399400// The immediate in the 2nd instr must be "1".401if (!SecondMI.getOperand(2).isImm() || SecondMI.getOperand(2).getImm() != 1) {402return false;403}404405// Assume the 1st instr to be a wildcard if it is unspecified.406if (FirstMI == nullptr) {407return true;408}409410switch (FirstMI->getOpcode()) {411case AArch64::SUBWrs:412case AArch64::SUBXrs:413if (AArch64InstrInfo::hasShiftedReg(*FirstMI))414return false;415[[fallthrough]];416case AArch64::SUBWrr:417case AArch64::SUBXrr:418if (NeedsSubtract) {419return true;420}421break;422423case AArch64::ADDWrs:424case AArch64::ADDXrs:425if (AArch64InstrInfo::hasShiftedReg(*FirstMI))426return false;427[[fallthrough]];428case AArch64::ADDWrr:429case AArch64::ADDXrr:430if (!NeedsSubtract) {431return true;432}433break;434}435436return false;437}438439/// \brief Check if the instr pair, FirstMI and SecondMI, should be fused440/// together. Given SecondMI, when FirstMI is unspecified, then check if441/// SecondMI may be part of a fused pair at all.442static bool shouldScheduleAdjacent(const TargetInstrInfo &TII,443const TargetSubtargetInfo &TSI,444const MachineInstr *FirstMI,445const MachineInstr &SecondMI) {446const AArch64Subtarget &ST = static_cast<const AArch64Subtarget&>(TSI);447448// All checking functions assume that the 1st instr is a wildcard if it is449// unspecified.450if (ST.hasCmpBccFusion() || ST.hasArithmeticBccFusion()) {451bool CmpOnly = !ST.hasArithmeticBccFusion();452if (isArithmeticBccPair(FirstMI, SecondMI, CmpOnly))453return true;454}455if (ST.hasArithmeticCbzFusion() && isArithmeticCbzPair(FirstMI, SecondMI))456return true;457if (ST.hasFuseAES() && isAESPair(FirstMI, SecondMI))458return true;459if (ST.hasFuseCryptoEOR() && isCryptoEORPair(FirstMI, SecondMI))460return true;461if (ST.hasFuseAdrpAdd() && isAdrpAddPair(FirstMI, SecondMI))462return true;463if (ST.hasFuseLiterals() && isLiteralsPair(FirstMI, SecondMI))464return true;465if (ST.hasFuseAddress() && isAddressLdStPair(FirstMI, SecondMI))466return true;467if (ST.hasFuseCCSelect() && isCCSelectPair(FirstMI, SecondMI))468return true;469if (ST.hasFuseArithmeticLogic() && isArithmeticLogicPair(FirstMI, SecondMI))470return true;471if (ST.hasFuseAddSub2RegAndConstOne() &&472isAddSub2RegAndConstOnePair(FirstMI, SecondMI))473return true;474475return false;476}477478std::unique_ptr<ScheduleDAGMutation>479llvm::createAArch64MacroFusionDAGMutation() {480return createMacroFusionDAGMutation(shouldScheduleAdjacent);481}482483484