blob: 9a2103579a6ab355d41faeac70a81a95d9b98e8f [file] [log] [blame]
Evandro Menezes94edf022017-02-01 02:54:34 +00001//===- AArch64MacroFusion.cpp - AArch64 Macro Fusion ----------------------===//
2//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// 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-exception
Evandro Menezes94edf022017-02-01 02:54:34 +00006//
7//===----------------------------------------------------------------------===//
8//
Florian Hahn5f746c82017-06-19 12:53:31 +00009/// \file This file contains the AArch64 implementation of the DAG scheduling
10/// mutation to pair instructions back to back.
Evandro Menezes94edf022017-02-01 02:54:34 +000011//
12//===----------------------------------------------------------------------===//
13
Evandro Menezes94edf022017-02-01 02:54:34 +000014#include "AArch64Subtarget.h"
Florian Hahn5f746c82017-06-19 12:53:31 +000015#include "llvm/CodeGen/MacroFusion.h"
David Blaikie3f833ed2017-11-08 01:01:31 +000016#include "llvm/CodeGen/TargetInstrInfo.h"
Evandro Menezes94edf022017-02-01 02:54:34 +000017
Evandro Menezes94edf022017-02-01 02:54:34 +000018using namespace llvm;
19
Evandro Menezes94edf022017-02-01 02:54:34 +000020namespace {
21
Matthias Braun934be5f2018-09-19 00:23:37 +000022/// CMN, CMP, TST followed by Bcc
Evandro Menezesde655c62018-10-16 17:19:28 +000023static bool isArithmeticBccPair(const MachineInstr *FirstMI,
24 const MachineInstr &SecondMI) {
25 if (SecondMI.getOpcode() != AArch64::Bcc)
Matthias Braun934be5f2018-09-19 00:23:37 +000026 return false;
Evandro Menezes5c986b02018-02-23 00:14:39 +000027
Evandro Menezesde655c62018-10-16 17:19:28 +000028 // Assume the 1st instr to be a wildcard if it is unspecified.
29 if (FirstMI == nullptr)
Matthias Braun934be5f2018-09-19 00:23:37 +000030 return true;
Evandro Menezesde655c62018-10-16 17:19:28 +000031
32 switch (FirstMI->getOpcode()) {
Matthias Braun934be5f2018-09-19 00:23:37 +000033 case AArch64::ADDSWri:
34 case AArch64::ADDSWrr:
35 case AArch64::ADDSXri:
36 case AArch64::ADDSXrr:
37 case AArch64::ANDSWri:
38 case AArch64::ANDSWrr:
39 case AArch64::ANDSXri:
40 case AArch64::ANDSXrr:
41 case AArch64::SUBSWri:
42 case AArch64::SUBSWrr:
43 case AArch64::SUBSXri:
44 case AArch64::SUBSXrr:
45 case AArch64::BICSWrr:
46 case AArch64::BICSXrr:
47 return true;
48 case AArch64::ADDSWrs:
49 case AArch64::ADDSXrs:
50 case AArch64::ANDSWrs:
51 case AArch64::ANDSXrs:
52 case AArch64::SUBSWrs:
53 case AArch64::SUBSXrs:
54 case AArch64::BICSWrs:
55 case AArch64::BICSXrs:
56 // Shift value can be 0 making these behave like the "rr" variant...
57 return !AArch64InstrInfo::hasShiftedReg(*FirstMI);
Evandro Menezes5c986b02018-02-23 00:14:39 +000058 }
Evandro Menezesde655c62018-10-16 17:19:28 +000059
Evandro Menezes5c986b02018-02-23 00:14:39 +000060 return false;
61}
62
Matthias Braun934be5f2018-09-19 00:23:37 +000063/// ALU operations followed by CBZ/CBNZ.
Evandro Menezesde655c62018-10-16 17:19:28 +000064static bool isArithmeticCbzPair(const MachineInstr *FirstMI,
65 const MachineInstr &SecondMI) {
Evandro Menezesc98decf2018-10-16 17:41:45 +000066 if (SecondMI.getOpcode() != AArch64::CBZW &&
67 SecondMI.getOpcode() != AArch64::CBZX &&
68 SecondMI.getOpcode() != AArch64::CBNZW &&
69 SecondMI.getOpcode() != AArch64::CBNZX)
Matthias Braun934be5f2018-09-19 00:23:37 +000070 return false;
Evandro Menezes5c986b02018-02-23 00:14:39 +000071
Evandro Menezesde655c62018-10-16 17:19:28 +000072 // Assume the 1st instr to be a wildcard if it is unspecified.
73 if (FirstMI == nullptr)
Matthias Braun934be5f2018-09-19 00:23:37 +000074 return true;
Evandro Menezesde655c62018-10-16 17:19:28 +000075
76 switch (FirstMI->getOpcode()) {
Matthias Braun934be5f2018-09-19 00:23:37 +000077 case AArch64::ADDWri:
78 case AArch64::ADDWrr:
79 case AArch64::ADDXri:
80 case AArch64::ADDXrr:
81 case AArch64::ANDWri:
82 case AArch64::ANDWrr:
83 case AArch64::ANDXri:
84 case AArch64::ANDXrr:
85 case AArch64::EORWri:
86 case AArch64::EORWrr:
87 case AArch64::EORXri:
88 case AArch64::EORXrr:
89 case AArch64::ORRWri:
90 case AArch64::ORRWrr:
91 case AArch64::ORRXri:
92 case AArch64::ORRXrr:
93 case AArch64::SUBWri:
94 case AArch64::SUBWrr:
95 case AArch64::SUBXri:
96 case AArch64::SUBXrr:
97 return true;
98 case AArch64::ADDWrs:
99 case AArch64::ADDXrs:
100 case AArch64::ANDWrs:
101 case AArch64::ANDXrs:
102 case AArch64::SUBWrs:
103 case AArch64::SUBXrs:
104 case AArch64::BICWrs:
105 case AArch64::BICXrs:
106 // Shift value can be 0 making these behave like the "rr" variant...
107 return !AArch64InstrInfo::hasShiftedReg(*FirstMI);
Evandro Menezes5c986b02018-02-23 00:14:39 +0000108 }
Evandro Menezesde655c62018-10-16 17:19:28 +0000109
Evandro Menezes5c986b02018-02-23 00:14:39 +0000110 return false;
111}
112
Matthias Braun934be5f2018-09-19 00:23:37 +0000113/// AES crypto encoding or decoding.
Evandro Menezesde655c62018-10-16 17:19:28 +0000114static bool isAESPair(const MachineInstr *FirstMI,
115 const MachineInstr &SecondMI) {
116 // Assume the 1st instr to be a wildcard if it is unspecified.
117 switch (SecondMI.getOpcode()) {
Evandro Menezes5c986b02018-02-23 00:14:39 +0000118 // AES encode.
Evandro Menezesde655c62018-10-16 17:19:28 +0000119 case AArch64::AESMCrr:
120 case AArch64::AESMCrrTied:
121 return FirstMI == nullptr || FirstMI->getOpcode() == AArch64::AESErr;
Evandro Menezes5c986b02018-02-23 00:14:39 +0000122 // AES decode.
Evandro Menezesde655c62018-10-16 17:19:28 +0000123 case AArch64::AESIMCrr:
124 case AArch64::AESIMCrrTied:
125 return FirstMI == nullptr || FirstMI->getOpcode() == AArch64::AESDrr;
126 }
Evandro Menezes5c986b02018-02-23 00:14:39 +0000127
128 return false;
129}
130
Matthias Braun28d6a4a2018-09-19 20:50:51 +0000131/// AESE/AESD/PMULL + EOR.
Evandro Menezesde655c62018-10-16 17:19:28 +0000132static bool isCryptoEORPair(const MachineInstr *FirstMI,
133 const MachineInstr &SecondMI) {
134 if (SecondMI.getOpcode() != AArch64::EORv16i8)
Matthias Braun28d6a4a2018-09-19 20:50:51 +0000135 return false;
136
Evandro Menezesde655c62018-10-16 17:19:28 +0000137 // Assume the 1st instr to be a wildcard if it is unspecified.
138 if (FirstMI == nullptr)
139 return true;
140
141 switch (FirstMI->getOpcode()) {
Matthias Braun28d6a4a2018-09-19 20:50:51 +0000142 case AArch64::AESErr:
143 case AArch64::AESDrr:
144 case AArch64::PMULLv16i8:
145 case AArch64::PMULLv8i8:
146 case AArch64::PMULLv1i64:
147 case AArch64::PMULLv2i64:
148 return true;
149 }
Evandro Menezesde655c62018-10-16 17:19:28 +0000150
Matthias Braun28d6a4a2018-09-19 20:50:51 +0000151 return false;
152}
153
Matthias Braun934be5f2018-09-19 00:23:37 +0000154/// Literal generation.
Evandro Menezesde655c62018-10-16 17:19:28 +0000155static bool isLiteralsPair(const MachineInstr *FirstMI,
Evandro Menezes5c986b02018-02-23 00:14:39 +0000156 const MachineInstr &SecondMI) {
Evandro Menezesde655c62018-10-16 17:19:28 +0000157 // Assume the 1st instr to be a wildcard if it is unspecified.
158
Evandro Menezes5c986b02018-02-23 00:14:39 +0000159 // PC relative address.
Evandro Menezesde655c62018-10-16 17:19:28 +0000160 if ((FirstMI == nullptr || FirstMI->getOpcode() == AArch64::ADRP) &&
161 SecondMI.getOpcode() == AArch64::ADDXri)
Evandro Menezes5c986b02018-02-23 00:14:39 +0000162 return true;
Evandro Menezesde655c62018-10-16 17:19:28 +0000163
Evandro Menezes5c986b02018-02-23 00:14:39 +0000164 // 32 bit immediate.
Evandro Menezesde655c62018-10-16 17:19:28 +0000165 if ((FirstMI == nullptr || FirstMI->getOpcode() == AArch64::MOVZWi) &&
166 (SecondMI.getOpcode() == AArch64::MOVKWi &&
167 SecondMI.getOperand(3).getImm() == 16))
Evandro Menezes5c986b02018-02-23 00:14:39 +0000168 return true;
Evandro Menezesde655c62018-10-16 17:19:28 +0000169
Evandro Menezes5c986b02018-02-23 00:14:39 +0000170 // Lower half of 64 bit immediate.
Evandro Menezesde655c62018-10-16 17:19:28 +0000171 if((FirstMI == nullptr || FirstMI->getOpcode() == AArch64::MOVZXi) &&
172 (SecondMI.getOpcode() == AArch64::MOVKXi &&
173 SecondMI.getOperand(3).getImm() == 16))
Evandro Menezes5c986b02018-02-23 00:14:39 +0000174 return true;
Evandro Menezesde655c62018-10-16 17:19:28 +0000175
Evandro Menezes5c986b02018-02-23 00:14:39 +0000176 // Upper half of 64 bit immediate.
Evandro Menezesde655c62018-10-16 17:19:28 +0000177 if ((FirstMI == nullptr ||
178 (FirstMI->getOpcode() == AArch64::MOVKXi &&
179 FirstMI->getOperand(3).getImm() == 32)) &&
180 (SecondMI.getOpcode() == AArch64::MOVKXi &&
181 SecondMI.getOperand(3).getImm() == 48))
Evandro Menezes5c986b02018-02-23 00:14:39 +0000182 return true;
183
184 return false;
185}
186
Evandro Menezesde655c62018-10-16 17:19:28 +0000187/// Fuse address generation and loads or stores.
188static bool isAddressLdStPair(const MachineInstr *FirstMI,
Evandro Menezes5c986b02018-02-23 00:14:39 +0000189 const MachineInstr &SecondMI) {
Evandro Menezesde655c62018-10-16 17:19:28 +0000190 switch (SecondMI.getOpcode()) {
Evandro Menezes5c986b02018-02-23 00:14:39 +0000191 case AArch64::STRBBui:
192 case AArch64::STRBui:
193 case AArch64::STRDui:
194 case AArch64::STRHHui:
195 case AArch64::STRHui:
196 case AArch64::STRQui:
197 case AArch64::STRSui:
198 case AArch64::STRWui:
199 case AArch64::STRXui:
200 case AArch64::LDRBBui:
201 case AArch64::LDRBui:
202 case AArch64::LDRDui:
203 case AArch64::LDRHHui:
204 case AArch64::LDRHui:
205 case AArch64::LDRQui:
206 case AArch64::LDRSui:
207 case AArch64::LDRWui:
208 case AArch64::LDRXui:
209 case AArch64::LDRSBWui:
210 case AArch64::LDRSBXui:
211 case AArch64::LDRSHWui:
212 case AArch64::LDRSHXui:
213 case AArch64::LDRSWui:
Evandro Menezesde655c62018-10-16 17:19:28 +0000214 // Assume the 1st instr to be a wildcard if it is unspecified.
215 if (FirstMI == nullptr)
Evandro Menezes5c986b02018-02-23 00:14:39 +0000216 return true;
Evandro Menezesde655c62018-10-16 17:19:28 +0000217
218 switch (FirstMI->getOpcode()) {
Evandro Menezes5c986b02018-02-23 00:14:39 +0000219 case AArch64::ADR:
Matthias Braun934be5f2018-09-19 00:23:37 +0000220 return SecondMI.getOperand(2).getImm() == 0;
Evandro Menezes5c986b02018-02-23 00:14:39 +0000221 case AArch64::ADRP:
222 return true;
223 }
224 }
Evandro Menezesde655c62018-10-16 17:19:28 +0000225
Evandro Menezes5c986b02018-02-23 00:14:39 +0000226 return false;
227}
228
Evandro Menezesde655c62018-10-16 17:19:28 +0000229/// Compare and conditional select.
230static bool isCCSelectPair(const MachineInstr *FirstMI,
231 const MachineInstr &SecondMI) {
Evandro Menezes1afffac2018-02-23 19:27:43 +0000232 // 32 bits
Evandro Menezesde655c62018-10-16 17:19:28 +0000233 if (SecondMI.getOpcode() == AArch64::CSELWr) {
Evandro Menezes1afffac2018-02-23 19:27:43 +0000234 // Assume the 1st instr to be a wildcard if it is unspecified.
Evandro Menezesde655c62018-10-16 17:19:28 +0000235 if (FirstMI == nullptr)
Evandro Menezes1afffac2018-02-23 19:27:43 +0000236 return true;
237
238 if (FirstMI->definesRegister(AArch64::WZR))
Evandro Menezesde655c62018-10-16 17:19:28 +0000239 switch (FirstMI->getOpcode()) {
Evandro Menezes1afffac2018-02-23 19:27:43 +0000240 case AArch64::SUBSWrs:
Matthias Braun934be5f2018-09-19 00:23:37 +0000241 return !AArch64InstrInfo::hasShiftedReg(*FirstMI);
Evandro Menezes1afffac2018-02-23 19:27:43 +0000242 case AArch64::SUBSWrx:
Matthias Braun934be5f2018-09-19 00:23:37 +0000243 return !AArch64InstrInfo::hasExtendedReg(*FirstMI);
Evandro Menezes1afffac2018-02-23 19:27:43 +0000244 case AArch64::SUBSWrr:
245 case AArch64::SUBSWri:
246 return true;
247 }
248 }
Evandro Menezesde655c62018-10-16 17:19:28 +0000249
Evandro Menezes1afffac2018-02-23 19:27:43 +0000250 // 64 bits
Evandro Menezesde655c62018-10-16 17:19:28 +0000251 if (SecondMI.getOpcode() == AArch64::CSELXr) {
Evandro Menezes1afffac2018-02-23 19:27:43 +0000252 // Assume the 1st instr to be a wildcard if it is unspecified.
Evandro Menezesde655c62018-10-16 17:19:28 +0000253 if (FirstMI == nullptr)
Evandro Menezes1afffac2018-02-23 19:27:43 +0000254 return true;
255
256 if (FirstMI->definesRegister(AArch64::XZR))
Evandro Menezesde655c62018-10-16 17:19:28 +0000257 switch (FirstMI->getOpcode()) {
Evandro Menezes1afffac2018-02-23 19:27:43 +0000258 case AArch64::SUBSXrs:
Matthias Braun934be5f2018-09-19 00:23:37 +0000259 return !AArch64InstrInfo::hasShiftedReg(*FirstMI);
Evandro Menezes1afffac2018-02-23 19:27:43 +0000260 case AArch64::SUBSXrx:
261 case AArch64::SUBSXrx64:
Matthias Braun934be5f2018-09-19 00:23:37 +0000262 return !AArch64InstrInfo::hasExtendedReg(*FirstMI);
Evandro Menezes1afffac2018-02-23 19:27:43 +0000263 case AArch64::SUBSXrr:
264 case AArch64::SUBSXri:
265 return true;
266 }
267 }
Evandro Menezesde655c62018-10-16 17:19:28 +0000268
Evandro Menezes1afffac2018-02-23 19:27:43 +0000269 return false;
270}
271
Evandro Menezesbf59cb02019-01-14 23:54:36 +0000272// Arithmetic and logic.
273static bool isArithmeticLogicPair(const MachineInstr *FirstMI,
274 const MachineInstr &SecondMI) {
275 if (AArch64InstrInfo::hasShiftedReg(SecondMI))
276 return false;
277
278 switch (SecondMI.getOpcode()) {
279 // Arithmetic
280 case AArch64::ADDWrr:
281 case AArch64::ADDXrr:
282 case AArch64::SUBWrr:
283 case AArch64::SUBXrr:
284 case AArch64::ADDWrs:
285 case AArch64::ADDXrs:
286 case AArch64::SUBWrs:
287 case AArch64::SUBXrs:
288 // Logic
289 case AArch64::ANDWrr:
290 case AArch64::ANDXrr:
291 case AArch64::BICWrr:
292 case AArch64::BICXrr:
293 case AArch64::EONWrr:
294 case AArch64::EONXrr:
295 case AArch64::EORWrr:
296 case AArch64::EORXrr:
297 case AArch64::ORNWrr:
298 case AArch64::ORNXrr:
299 case AArch64::ORRWrr:
300 case AArch64::ORRXrr:
301 case AArch64::ANDWrs:
302 case AArch64::ANDXrs:
303 case AArch64::BICWrs:
304 case AArch64::BICXrs:
305 case AArch64::EONWrs:
306 case AArch64::EONXrs:
307 case AArch64::EORWrs:
308 case AArch64::EORXrs:
309 case AArch64::ORNWrs:
310 case AArch64::ORNXrs:
311 case AArch64::ORRWrs:
312 case AArch64::ORRXrs:
313 // Assume the 1st instr to be a wildcard if it is unspecified.
314 if (FirstMI == nullptr)
315 return true;
316
317 // Arithmetic
318 switch (FirstMI->getOpcode()) {
319 case AArch64::ADDWrr:
320 case AArch64::ADDXrr:
321 case AArch64::ADDSWrr:
322 case AArch64::ADDSXrr:
323 case AArch64::SUBWrr:
324 case AArch64::SUBXrr:
325 case AArch64::SUBSWrr:
326 case AArch64::SUBSXrr:
327 return true;
328 case AArch64::ADDWrs:
329 case AArch64::ADDXrs:
330 case AArch64::ADDSWrs:
331 case AArch64::ADDSXrs:
332 case AArch64::SUBWrs:
333 case AArch64::SUBXrs:
334 case AArch64::SUBSWrs:
335 case AArch64::SUBSXrs:
336 return !AArch64InstrInfo::hasShiftedReg(*FirstMI);
337 }
338 break;
339
340 // Arithmetic, setting flags.
341 case AArch64::ADDSWrr:
342 case AArch64::ADDSXrr:
343 case AArch64::SUBSWrr:
344 case AArch64::SUBSXrr:
345 case AArch64::ADDSWrs:
346 case AArch64::ADDSXrs:
347 case AArch64::SUBSWrs:
348 case AArch64::SUBSXrs:
349 // Assume the 1st instr to be a wildcard if it is unspecified.
350 if (FirstMI == nullptr)
351 return true;
352
353 // Arithmetic, not setting flags.
354 switch (FirstMI->getOpcode()) {
355 case AArch64::ADDWrr:
356 case AArch64::ADDXrr:
357 case AArch64::SUBWrr:
358 case AArch64::SUBXrr:
359 return true;
360 case AArch64::ADDWrs:
361 case AArch64::ADDXrs:
362 case AArch64::SUBWrs:
363 case AArch64::SUBXrs:
364 return !AArch64InstrInfo::hasShiftedReg(*FirstMI);
365 }
366 break;
367 }
368
369 return false;
370}
371
372/// \brief Check if the instr pair, FirstMI and SecondMI, should be fused
Florian Hahn5f746c82017-06-19 12:53:31 +0000373/// together. Given SecondMI, when FirstMI is unspecified, then check if
374/// SecondMI may be part of a fused pair at all.
Evandro Menezes203eef02017-04-11 19:13:11 +0000375static bool shouldScheduleAdjacent(const TargetInstrInfo &TII,
376 const TargetSubtargetInfo &TSI,
377 const MachineInstr *FirstMI,
Florian Hahn5f746c82017-06-19 12:53:31 +0000378 const MachineInstr &SecondMI) {
Evandro Menezes203eef02017-04-11 19:13:11 +0000379 const AArch64Subtarget &ST = static_cast<const AArch64Subtarget&>(TSI);
380
Evandro Menezesde655c62018-10-16 17:19:28 +0000381 // All checking functions assume that the 1st instr is a wildcard if it is
382 // unspecified.
383 if (ST.hasArithmeticBccFusion() && isArithmeticBccPair(FirstMI, SecondMI))
Evandro Menezes5c986b02018-02-23 00:14:39 +0000384 return true;
Evandro Menezesde655c62018-10-16 17:19:28 +0000385 if (ST.hasArithmeticCbzFusion() && isArithmeticCbzPair(FirstMI, SecondMI))
Evandro Menezes5c986b02018-02-23 00:14:39 +0000386 return true;
Evandro Menezesde655c62018-10-16 17:19:28 +0000387 if (ST.hasFuseAES() && isAESPair(FirstMI, SecondMI))
Evandro Menezes5c986b02018-02-23 00:14:39 +0000388 return true;
Evandro Menezesde655c62018-10-16 17:19:28 +0000389 if (ST.hasFuseCryptoEOR() && isCryptoEORPair(FirstMI, SecondMI))
Matthias Braun28d6a4a2018-09-19 20:50:51 +0000390 return true;
Evandro Menezesde655c62018-10-16 17:19:28 +0000391 if (ST.hasFuseLiterals() && isLiteralsPair(FirstMI, SecondMI))
Evandro Menezes5c986b02018-02-23 00:14:39 +0000392 return true;
Evandro Menezesde655c62018-10-16 17:19:28 +0000393 if (ST.hasFuseAddress() && isAddressLdStPair(FirstMI, SecondMI))
Evandro Menezes5c986b02018-02-23 00:14:39 +0000394 return true;
Evandro Menezesde655c62018-10-16 17:19:28 +0000395 if (ST.hasFuseCCSelect() && isCCSelectPair(FirstMI, SecondMI))
Evandro Menezes1afffac2018-02-23 19:27:43 +0000396 return true;
Evandro Menezesbf59cb02019-01-14 23:54:36 +0000397 if (ST.hasFuseArithmeticLogic() && isArithmeticLogicPair(FirstMI, SecondMI))
398 return true;
Evandro Menezesf1d01642018-01-30 16:28:01 +0000399
Evandro Menezes94edf022017-02-01 02:54:34 +0000400 return false;
401}
402
Evandro Menezes94edf022017-02-01 02:54:34 +0000403} // end namespace
404
405
406namespace llvm {
407
408std::unique_ptr<ScheduleDAGMutation> createAArch64MacroFusionDAGMutation () {
Florian Hahn5f746c82017-06-19 12:53:31 +0000409 return createMacroFusionDAGMutation(shouldScheduleAdjacent);
Evandro Menezes94edf022017-02-01 02:54:34 +0000410}
411
412} // end namespace llvm