blob: 7e97b6ccb4805144c42c65836a8021668db96054 [file] [log] [blame]
Evandro Menezes94edf022017-02-01 02:54:34 +00001//===- 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//
Florian Hahn5f746c82017-06-19 12:53:31 +000010/// \file This file contains the AArch64 implementation of the DAG scheduling
11/// mutation to pair instructions back to back.
Evandro Menezes94edf022017-02-01 02:54:34 +000012//
13//===----------------------------------------------------------------------===//
14
15#include "AArch64MacroFusion.h"
16#include "AArch64Subtarget.h"
Florian Hahn5f746c82017-06-19 12:53:31 +000017#include "llvm/CodeGen/MacroFusion.h"
Evandro Menezes94edf022017-02-01 02:54:34 +000018#include "llvm/Target/TargetInstrInfo.h"
19
Evandro Menezes94edf022017-02-01 02:54:34 +000020using namespace llvm;
21
Evandro Menezes94edf022017-02-01 02:54:34 +000022namespace {
23
Florian Hahn5f746c82017-06-19 12:53:31 +000024/// \brief Check if the instr pair, FirstMI and SecondMI, should be fused
25/// together. Given SecondMI, when FirstMI is unspecified, then check if
26/// SecondMI may be part of a fused pair at all.
Evandro Menezes203eef02017-04-11 19:13:11 +000027static bool shouldScheduleAdjacent(const TargetInstrInfo &TII,
28 const TargetSubtargetInfo &TSI,
29 const MachineInstr *FirstMI,
Florian Hahn5f746c82017-06-19 12:53:31 +000030 const MachineInstr &SecondMI) {
Evandro Menezes203eef02017-04-11 19:13:11 +000031 const AArch64InstrInfo &II = static_cast<const AArch64InstrInfo&>(TII);
32 const AArch64Subtarget &ST = static_cast<const AArch64Subtarget&>(TSI);
33
34 // Assume wildcards for unspecified instrs.
Simon Pilgrimb0921662017-02-18 22:50:28 +000035 unsigned FirstOpcode =
Evandro Menezes203eef02017-04-11 19:13:11 +000036 FirstMI ? FirstMI->getOpcode()
37 : static_cast<unsigned>(AArch64::INSTRUCTION_LIST_END);
Florian Hahn5f746c82017-06-19 12:53:31 +000038 unsigned SecondOpcode = SecondMI.getOpcode();
Evandro Menezes94edf022017-02-01 02:54:34 +000039
40 if (ST.hasArithmeticBccFusion())
41 // Fuse CMN, CMP, TST followed by Bcc.
42 if (SecondOpcode == AArch64::Bcc)
43 switch (FirstOpcode) {
44 default:
45 return false;
46 case AArch64::ADDSWri:
47 case AArch64::ADDSWrr:
48 case AArch64::ADDSXri:
49 case AArch64::ADDSXrr:
50 case AArch64::ANDSWri:
51 case AArch64::ANDSWrr:
52 case AArch64::ANDSXri:
53 case AArch64::ANDSXrr:
54 case AArch64::SUBSWri:
55 case AArch64::SUBSWrr:
56 case AArch64::SUBSXri:
57 case AArch64::SUBSXrr:
58 case AArch64::BICSWrr:
59 case AArch64::BICSXrr:
60 return true;
61 case AArch64::ADDSWrs:
62 case AArch64::ADDSXrs:
63 case AArch64::ANDSWrs:
64 case AArch64::ANDSXrs:
65 case AArch64::SUBSWrs:
66 case AArch64::SUBSXrs:
67 case AArch64::BICSWrs:
68 case AArch64::BICSXrs:
69 // Shift value can be 0 making these behave like the "rr" variant...
Evandro Menezes203eef02017-04-11 19:13:11 +000070 return !II.hasShiftedReg(*FirstMI);
Evandro Menezes94edf022017-02-01 02:54:34 +000071 case AArch64::INSTRUCTION_LIST_END:
72 return true;
73 }
74
75 if (ST.hasArithmeticCbzFusion())
76 // Fuse ALU operations followed by CBZ/CBNZ.
77 if (SecondOpcode == AArch64::CBNZW || SecondOpcode == AArch64::CBNZX ||
78 SecondOpcode == AArch64::CBZW || SecondOpcode == AArch64::CBZX)
79 switch (FirstOpcode) {
80 default:
81 return false;
82 case AArch64::ADDWri:
83 case AArch64::ADDWrr:
84 case AArch64::ADDXri:
85 case AArch64::ADDXrr:
86 case AArch64::ANDWri:
87 case AArch64::ANDWrr:
88 case AArch64::ANDXri:
89 case AArch64::ANDXrr:
90 case AArch64::EORWri:
91 case AArch64::EORWrr:
92 case AArch64::EORXri:
93 case AArch64::EORXrr:
94 case AArch64::ORRWri:
95 case AArch64::ORRWrr:
96 case AArch64::ORRXri:
97 case AArch64::ORRXrr:
98 case AArch64::SUBWri:
99 case AArch64::SUBWrr:
100 case AArch64::SUBXri:
101 case AArch64::SUBXrr:
102 return true;
103 case AArch64::ADDWrs:
104 case AArch64::ADDXrs:
105 case AArch64::ANDWrs:
106 case AArch64::ANDXrs:
107 case AArch64::SUBWrs:
108 case AArch64::SUBXrs:
109 case AArch64::BICWrs:
110 case AArch64::BICXrs:
111 // Shift value can be 0 making these behave like the "rr" variant...
Evandro Menezes203eef02017-04-11 19:13:11 +0000112 return !II.hasShiftedReg(*FirstMI);
Evandro Menezes94edf022017-02-01 02:54:34 +0000113 case AArch64::INSTRUCTION_LIST_END:
114 return true;
115 }
116
Evandro Menezesb21fb292017-02-01 02:54:39 +0000117 if (ST.hasFuseAES())
118 // Fuse AES crypto operations.
Florian Hahn5f746c82017-06-19 12:53:31 +0000119 switch(SecondOpcode) {
Evandro Menezesb21fb292017-02-01 02:54:39 +0000120 // AES encode.
Florian Hahn5f746c82017-06-19 12:53:31 +0000121 case AArch64::AESMCrr :
122 return FirstOpcode == AArch64::AESErr ||
123 FirstOpcode == AArch64::INSTRUCTION_LIST_END;
Evandro Menezesb21fb292017-02-01 02:54:39 +0000124 // AES decode.
Florian Hahn5f746c82017-06-19 12:53:31 +0000125 case AArch64::AESIMCrr:
126 return FirstOpcode == AArch64::AESDrr ||
127 FirstOpcode == AArch64::INSTRUCTION_LIST_END;
Evandro Menezesb21fb292017-02-01 02:54:39 +0000128 }
129
Evandro Menezes455382e2017-02-01 02:54:42 +0000130 if (ST.hasFuseLiterals())
131 // Fuse literal generation operations.
Florian Hahn5f746c82017-06-19 12:53:31 +0000132 switch (SecondOpcode) {
Evandro Menezes455382e2017-02-01 02:54:42 +0000133 // PC relative address.
Florian Hahn5f746c82017-06-19 12:53:31 +0000134 case AArch64::ADDXri:
135 return FirstOpcode == AArch64::ADRP ||
136 FirstOpcode == AArch64::INSTRUCTION_LIST_END;
Evandro Menezes455382e2017-02-01 02:54:42 +0000137 // 32 bit immediate.
Florian Hahn5f746c82017-06-19 12:53:31 +0000138 case AArch64::MOVKWi:
139 return (FirstOpcode == AArch64::MOVZWi &&
140 SecondMI.getOperand(3).getImm() == 16) ||
141 FirstOpcode == AArch64::INSTRUCTION_LIST_END;
142 // Lower and upper half of 64 bit immediate.
Evandro Menezes455382e2017-02-01 02:54:42 +0000143 case AArch64::MOVKXi:
Florian Hahn5f746c82017-06-19 12:53:31 +0000144 return FirstOpcode == AArch64::INSTRUCTION_LIST_END ||
145 (FirstOpcode == AArch64::MOVZXi &&
146 SecondMI.getOperand(3).getImm() == 16) ||
147 (FirstMI->getOperand(3).getImm() == 32 &&
148 FirstOpcode == AArch64::MOVKXi &&
149 SecondMI.getOperand(3).getImm() == 48);
Evandro Menezes455382e2017-02-01 02:54:42 +0000150 }
151
Evandro Menezes94edf022017-02-01 02:54:34 +0000152 return false;
153}
154
Evandro Menezes94edf022017-02-01 02:54:34 +0000155} // end namespace
156
157
158namespace llvm {
159
160std::unique_ptr<ScheduleDAGMutation> createAArch64MacroFusionDAGMutation () {
Florian Hahn5f746c82017-06-19 12:53:31 +0000161 return createMacroFusionDAGMutation(shouldScheduleAdjacent);
Evandro Menezes94edf022017-02-01 02:54:34 +0000162}
163
164} // end namespace llvm