60#define DEBUG_TYPE "aarch64-simd-instr-opt"
63 "Number of SIMD instructions modified");
65#define AARCH64_VECTOR_BY_ELEMENT_OPT_NAME \
66 "AArch64 SIMD instructions optimization pass"
72constexpr unsigned MaxNumRepl = 10;
74class AArch64SIMDInstrOptImpl {
80 using SIMDInstrTableMap = std::map<std::pair<unsigned, std::string>,
bool>;
90 SIMDInstrTableMap &SIMDInstrTable;
94 InterlEarlyExitMap &InterlEarlyExit;
102 struct InstReplInfo {
104 unsigned ReplOpc[MaxNumRepl];
109#define RuleST2(OpcOrg, OpcR0, OpcR1, OpcR2, RC) \
110 {OpcOrg, {OpcR0, OpcR1, OpcR2}, 3, &RC}
111#define RuleST4(OpcOrg, OpcR0, OpcR1, OpcR2, OpcR3, OpcR4, OpcR5, OpcR6, \
112 OpcR7, OpcR8, OpcR9, RC) \
114 {OpcR0, OpcR1, OpcR2, OpcR3, OpcR4, OpcR5, OpcR6, OpcR7, OpcR8, OpcR9}, \
118 AArch64SIMDInstrOptImpl(SIMDInstrTableMap &SIMDInstrTable,
119 InterlEarlyExitMap &InterlEarlyExit)
120 : SIMDInstrTable(SIMDInstrTable), InterlEarlyExit(InterlEarlyExit) {}
126 bool shouldReplaceInst(MachineFunction *MF,
const MCInstrDesc *InstDesc,
127 SmallVectorImpl<const MCInstrDesc*> &ReplInstrMCID);
133 bool shouldExitEarly(MachineFunction *MF, Subpass SP);
139 bool reuseDUP(MachineInstr &
MI,
unsigned DupOpcode,
unsigned SrcReg,
140 unsigned LaneNumber,
unsigned *DestReg)
const;
146 bool optimizeVectElement(MachineInstr &
MI);
153 bool processSeqRegInst(MachineInstr *DefiningMI,
unsigned *StReg,
154 RegState *StRegKill,
unsigned NumArg)
const;
159 bool optimizeLdStInterleave(MachineInstr &
MI);
163 unsigned determineSrcReg(MachineInstr &
MI)
const;
165 bool run(MachineFunction &MF);
171 AArch64SIMDInstrOptImpl::SIMDInstrTableMap SIMDInstrTable;
172 AArch64SIMDInstrOptImpl::InterlEarlyExitMap InterlEarlyExit;
174 AArch64SIMDInstrOptLegacy() : MachineFunctionPass(ID) {}
176 bool runOnMachineFunction(MachineFunction &Fn)
override;
178 StringRef getPassName()
const override {
182 void getAnalysisUsage(AnalysisUsage &AU)
const override {
188char AArch64SIMDInstrOptLegacy::ID = 0;
191constexpr AArch64SIMDInstrOptImpl::InstReplInfo IRT[] = {
193 RuleST2(AArch64::ST2Twov2d, AArch64::ZIP1v2i64, AArch64::ZIP2v2i64,
194 AArch64::STPQi, AArch64::FPR128RegClass),
195 RuleST2(AArch64::ST2Twov4s, AArch64::ZIP1v4i32, AArch64::ZIP2v4i32,
196 AArch64::STPQi, AArch64::FPR128RegClass),
197 RuleST2(AArch64::ST2Twov2s, AArch64::ZIP1v2i32, AArch64::ZIP2v2i32,
198 AArch64::STPDi, AArch64::FPR64RegClass),
199 RuleST2(AArch64::ST2Twov8h, AArch64::ZIP1v8i16, AArch64::ZIP2v8i16,
200 AArch64::STPQi, AArch64::FPR128RegClass),
201 RuleST2(AArch64::ST2Twov4h, AArch64::ZIP1v4i16, AArch64::ZIP2v4i16,
202 AArch64::STPDi, AArch64::FPR64RegClass),
203 RuleST2(AArch64::ST2Twov16b, AArch64::ZIP1v16i8, AArch64::ZIP2v16i8,
204 AArch64::STPQi, AArch64::FPR128RegClass),
205 RuleST2(AArch64::ST2Twov8b, AArch64::ZIP1v8i8, AArch64::ZIP2v8i8,
206 AArch64::STPDi, AArch64::FPR64RegClass),
208 RuleST4(AArch64::ST4Fourv2d, AArch64::ZIP1v2i64, AArch64::ZIP2v2i64,
209 AArch64::ZIP1v2i64, AArch64::ZIP2v2i64, AArch64::ZIP1v2i64,
210 AArch64::ZIP2v2i64, AArch64::ZIP1v2i64, AArch64::ZIP2v2i64,
211 AArch64::STPQi, AArch64::STPQi, AArch64::FPR128RegClass),
212 RuleST4(AArch64::ST4Fourv4s, AArch64::ZIP1v4i32, AArch64::ZIP2v4i32,
213 AArch64::ZIP1v4i32, AArch64::ZIP2v4i32, AArch64::ZIP1v4i32,
214 AArch64::ZIP2v4i32, AArch64::ZIP1v4i32, AArch64::ZIP2v4i32,
215 AArch64::STPQi, AArch64::STPQi, AArch64::FPR128RegClass),
216 RuleST4(AArch64::ST4Fourv2s, AArch64::ZIP1v2i32, AArch64::ZIP2v2i32,
217 AArch64::ZIP1v2i32, AArch64::ZIP2v2i32, AArch64::ZIP1v2i32,
218 AArch64::ZIP2v2i32, AArch64::ZIP1v2i32, AArch64::ZIP2v2i32,
219 AArch64::STPDi, AArch64::STPDi, AArch64::FPR64RegClass),
220 RuleST4(AArch64::ST4Fourv8h, AArch64::ZIP1v8i16, AArch64::ZIP2v8i16,
221 AArch64::ZIP1v8i16, AArch64::ZIP2v8i16, AArch64::ZIP1v8i16,
222 AArch64::ZIP2v8i16, AArch64::ZIP1v8i16, AArch64::ZIP2v8i16,
223 AArch64::STPQi, AArch64::STPQi, AArch64::FPR128RegClass),
224 RuleST4(AArch64::ST4Fourv4h, AArch64::ZIP1v4i16, AArch64::ZIP2v4i16,
225 AArch64::ZIP1v4i16, AArch64::ZIP2v4i16, AArch64::ZIP1v4i16,
226 AArch64::ZIP2v4i16, AArch64::ZIP1v4i16, AArch64::ZIP2v4i16,
227 AArch64::STPDi, AArch64::STPDi, AArch64::FPR64RegClass),
228 RuleST4(AArch64::ST4Fourv16b, AArch64::ZIP1v16i8, AArch64::ZIP2v16i8,
229 AArch64::ZIP1v16i8, AArch64::ZIP2v16i8, AArch64::ZIP1v16i8,
230 AArch64::ZIP2v16i8, AArch64::ZIP1v16i8, AArch64::ZIP2v16i8,
231 AArch64::STPQi, AArch64::STPQi, AArch64::FPR128RegClass),
232 RuleST4(AArch64::ST4Fourv8b, AArch64::ZIP1v8i8, AArch64::ZIP2v8i8,
233 AArch64::ZIP1v8i8, AArch64::ZIP2v8i8, AArch64::ZIP1v8i8,
234 AArch64::ZIP2v8i8, AArch64::ZIP1v8i8, AArch64::ZIP2v8i8,
235 AArch64::STPDi, AArch64::STPDi, AArch64::FPR64RegClass)};
246bool AArch64SIMDInstrOptImpl::shouldReplaceInst(
251 std::string Subtarget = std::string(SchedModel.getSubtargetInfo()->getCPU());
252 auto InstID = std::make_pair(InstDesc->getOpcode(), Subtarget);
253 auto It = SIMDInstrTable.find(InstID);
254 if (It != SIMDInstrTable.end())
257 unsigned SCIdx = InstDesc->getSchedClass();
259 SchedModel.getMCSchedModel()->getSchedClassDesc(SCIdx);
266 SIMDInstrTable[InstID] =
false;
269 for (
const auto *IDesc : InstDescRepl)
271 SCDescRepl = SchedModel.getMCSchedModel()->getSchedClassDesc(
272 IDesc->getSchedClass());
275 SIMDInstrTable[InstID] =
false;
281 unsigned ReplCost = 0;
282 for (
const auto *IDesc :InstDescRepl)
283 ReplCost += SchedModel.computeInstrLatency(IDesc->getOpcode());
285 if (SchedModel.computeInstrLatency(InstDesc->getOpcode()) > ReplCost)
287 SIMDInstrTable[InstID] =
true;
292 SIMDInstrTable[InstID] =
false;
303bool AArch64SIMDInstrOptImpl::shouldExitEarly(
MachineFunction *MF, Subpass SP) {
304 const MCInstrDesc *OriginalMCID;
312 OriginalMCID = &
TII->get(AArch64::FMLAv4i32_indexed);
313 ReplInstrMCID.
push_back(&
TII->get(AArch64::DUPv4i32lane));
315 if (shouldReplaceInst(MF, OriginalMCID, ReplInstrMCID))
321 std::string Subtarget =
323 auto It = InterlEarlyExit.
find(Subtarget);
324 if (It != InterlEarlyExit.
end())
327 for (
const auto &
I : IRT) {
328 OriginalMCID = &
TII->get(
I.OrigOpc);
329 for (
unsigned J = 0; J <
I.NumRepl; ++J)
331 if (shouldReplaceInst(MF, OriginalMCID, ReplInstrMCID)) {
332 InterlEarlyExit[Subtarget] =
false;
335 ReplInstrMCID.
clear();
337 InterlEarlyExit[Subtarget] =
true;
348bool AArch64SIMDInstrOptImpl::reuseDUP(MachineInstr &
MI,
unsigned DupOpcode,
349 unsigned SrcReg,
unsigned LaneNumber,
350 unsigned *DestReg)
const {
354 MachineInstr *CurrentMI = &*MII;
356 if (CurrentMI->
getOpcode() == DupOpcode &&
382bool AArch64SIMDInstrOptImpl::optimizeVectElement(MachineInstr &
MI) {
383 const MCInstrDesc *MulMCID, *DupMCID;
386 switch (
MI.getOpcode()) {
391 case AArch64::FMLAv4i32_indexed:
392 DupMCID = &
TII->get(AArch64::DUPv4i32lane);
393 MulMCID = &
TII->get(AArch64::FMLAv4f32);
395 case AArch64::FMLSv4i32_indexed:
396 DupMCID = &
TII->get(AArch64::DUPv4i32lane);
397 MulMCID = &
TII->get(AArch64::FMLSv4f32);
399 case AArch64::FMULXv4i32_indexed:
400 DupMCID = &
TII->get(AArch64::DUPv4i32lane);
401 MulMCID = &
TII->get(AArch64::FMULXv4f32);
403 case AArch64::FMULv4i32_indexed:
404 DupMCID = &
TII->get(AArch64::DUPv4i32lane);
405 MulMCID = &
TII->get(AArch64::FMULv4f32);
409 case AArch64::FMLAv2i64_indexed:
410 DupMCID = &
TII->get(AArch64::DUPv2i64lane);
411 MulMCID = &
TII->get(AArch64::FMLAv2f64);
413 case AArch64::FMLSv2i64_indexed:
414 DupMCID = &
TII->get(AArch64::DUPv2i64lane);
415 MulMCID = &
TII->get(AArch64::FMLSv2f64);
417 case AArch64::FMULXv2i64_indexed:
418 DupMCID = &
TII->get(AArch64::DUPv2i64lane);
419 MulMCID = &
TII->get(AArch64::FMULXv2f64);
421 case AArch64::FMULv2i64_indexed:
422 DupMCID = &
TII->get(AArch64::DUPv2i64lane);
423 MulMCID = &
TII->get(AArch64::FMULv2f64);
427 case AArch64::FMLAv2i32_indexed:
428 RC = &AArch64::FPR64RegClass;
429 DupMCID = &
TII->get(AArch64::DUPv2i32lane);
430 MulMCID = &
TII->get(AArch64::FMLAv2f32);
432 case AArch64::FMLSv2i32_indexed:
433 RC = &AArch64::FPR64RegClass;
434 DupMCID = &
TII->get(AArch64::DUPv2i32lane);
435 MulMCID = &
TII->get(AArch64::FMLSv2f32);
437 case AArch64::FMULXv2i32_indexed:
438 RC = &AArch64::FPR64RegClass;
439 DupMCID = &
TII->get(AArch64::DUPv2i32lane);
440 MulMCID = &
TII->get(AArch64::FMULXv2f32);
442 case AArch64::FMULv2i32_indexed:
443 RC = &AArch64::FPR64RegClass;
444 DupMCID = &
TII->get(AArch64::DUPv2i32lane);
445 MulMCID = &
TII->get(AArch64::FMULv2f32);
452 if (!shouldReplaceInst(
MI.getParent()->getParent(), &
TII->get(
MI.getOpcode()),
457 MachineBasicBlock &
MBB = *
MI.getParent();
469 if (
MI.getNumOperands() == 5) {
472 unsigned LaneNumber =
MI.getOperand(4).getImm();
476 if (!reuseDUP(
MI, DupMCID->
getOpcode(), SrcReg2, LaneNumber, &DupDest)) {
479 .
addReg(SrcReg2, Src2IsKill)
483 .
addReg(SrcReg0, Src0IsKill)
484 .
addReg(SrcReg1, Src1IsKill)
485 .
addReg(DupDest, Src2IsKill);
486 }
else if (
MI.getNumOperands() == 4) {
487 unsigned LaneNumber =
MI.getOperand(3).getImm();
488 if (!reuseDUP(
MI, DupMCID->
getOpcode(), SrcReg1, LaneNumber, &DupDest)) {
491 .
addReg(SrcReg1, Src1IsKill)
495 .
addReg(SrcReg0, Src0IsKill)
496 .
addReg(DupDest, Src1IsKill);
534bool AArch64SIMDInstrOptImpl::optimizeLdStInterleave(MachineInstr &
MI) {
536 unsigned SeqReg, AddrReg;
539 MachineInstr *DefiningMI;
541 MachineBasicBlock &
MBB = *
MI.getParent();
548 for (
const auto &
I : IRT) {
549 if (
MI.getOpcode() ==
I.OrigOpc) {
550 SeqReg =
MI.getOperand(0).getReg();
551 AddrReg =
MI.getOperand(1).getReg();
553 unsigned NumReg = determineSrcReg(
MI);
554 if (!processSeqRegInst(DefiningMI, StReg, StRegKill, NumReg))
557 for (
unsigned J = 0; J <
I.NumRepl; ++J) {
558 unsigned Repl =
I.ReplOpc[J];
561 if (Repl != AArch64::STPQi && Repl != AArch64::STPDi)
574 if (!shouldReplaceInst(
MI.getParent()->getParent(), &
TII->get(
MI.getOpcode()),
584 switch (
MI.getOpcode()) {
588 case AArch64::ST2Twov16b:
589 case AArch64::ST2Twov8b:
590 case AArch64::ST2Twov8h:
591 case AArch64::ST2Twov4h:
592 case AArch64::ST2Twov4s:
593 case AArch64::ST2Twov2s:
594 case AArch64::ST2Twov2d:
600 .
addReg(StReg[0], StRegKill[0])
601 .
addReg(StReg[1], StRegKill[1]);
610 case AArch64::ST4Fourv16b:
611 case AArch64::ST4Fourv8b:
612 case AArch64::ST4Fourv8h:
613 case AArch64::ST4Fourv4h:
614 case AArch64::ST4Fourv4s:
615 case AArch64::ST4Fourv2s:
616 case AArch64::ST4Fourv2d:
622 .
addReg(StReg[0], StRegKill[0])
623 .
addReg(StReg[2], StRegKill[2]);
628 .
addReg(StReg[1], StRegKill[1])
629 .
addReg(StReg[3], StRegKill[3]);
665bool AArch64SIMDInstrOptImpl::processSeqRegInst(MachineInstr *DefiningMI,
668 unsigned NumArg)
const {
669 assert(DefiningMI !=
nullptr);
670 if (DefiningMI->
getOpcode() != AArch64::REG_SEQUENCE)
673 for (
unsigned i=0; i<NumArg; i++) {
702unsigned AArch64SIMDInstrOptImpl::determineSrcReg(MachineInstr &
MI)
const {
703 switch (
MI.getOpcode()) {
707 case AArch64::ST2Twov16b:
708 case AArch64::ST2Twov8b:
709 case AArch64::ST2Twov8h:
710 case AArch64::ST2Twov4h:
711 case AArch64::ST2Twov4s:
712 case AArch64::ST2Twov2s:
713 case AArch64::ST2Twov2d:
716 case AArch64::ST4Fourv16b:
717 case AArch64::ST4Fourv8b:
718 case AArch64::ST4Fourv8h:
719 case AArch64::ST4Fourv4h:
720 case AArch64::ST4Fourv4s:
721 case AArch64::ST4Fourv2s:
722 case AArch64::ST4Fourv2d:
727bool AArch64SIMDInstrOptImpl::run(MachineFunction &MF) {
730 TII =
ST.getInstrInfo();
731 SchedModel.
init(&ST);
736 for (
auto OptimizationKind : {VectorElem, Interleave}) {
737 if (!shouldExitEarly(&MF, OptimizationKind)) {
738 SmallVector<MachineInstr *, 8> RemoveMIs;
739 for (MachineBasicBlock &
MBB : MF) {
740 for (MachineInstr &
MI :
MBB) {
742 if (OptimizationKind == VectorElem)
743 InstRewrite = optimizeVectElement(
MI) ;
745 InstRewrite = optimizeLdStInterleave(
MI);
754 for (MachineInstr *
MI : RemoveMIs)
755 MI->eraseFromParent();
762bool AArch64SIMDInstrOptLegacy::runOnMachineFunction(MachineFunction &MF) {
766 return AArch64SIMDInstrOptImpl(SIMDInstrTable, InterlEarlyExit).run(MF);
773 AArch64SIMDInstrOptImpl(SIMDInstrTable, InterlEarlyExit).run(MF);
785 return new AArch64SIMDInstrOptLegacy();
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
#define RuleST4(OpcOrg, OpcR0, OpcR1, OpcR2, OpcR3, OpcR4, OpcR5, OpcR6, OpcR7, OpcR8, OpcR9, RC)
#define RuleST2(OpcOrg, OpcR0, OpcR1, OpcR2, RC)
#define AARCH64_VECTOR_BY_ELEMENT_OPT_NAME
This file defines the StringMap class.
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
const HexagonInstrInfo * TII
Promote Memory to Register
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
This file defines the SmallVector class.
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
PreservedAnalyses run(MachineFunction &MF, MachineFunctionAnalysisManager &MFAM)
AnalysisUsage & addPreserved()
Add the specified Pass class to the set of analyses preserved by this pass.
Represents analyses that only rely on functions' control flow.
FunctionPass class - This class is used to implement most global optimizations.
Describe properties that are true of each instruction in the target description file.
unsigned getOpcode() const
Return the opcode number for this descriptor.
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
MachineInstrBundleIterator< MachineInstr > iterator
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
void getAnalysisUsage(AnalysisUsage &AU) const override
getAnalysisUsage - Subclasses that override getAnalysisUsage must call this.
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
Function & getFunction()
Return the LLVM function that this machine code represents.
const MachineInstrBuilder & addReg(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a new virtual register operand.
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
unsigned getNumOperands() const
Retuns the total number of operands.
const MachineOperand & getOperand(unsigned i) const
bool isImm() const
isImm - Tests if this is a MO_Immediate operand.
Register getReg() const
getReg - Returns the register number.
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
LLVM_ABI Register createVirtualRegister(const TargetRegisterClass *RegClass, StringRef Name="")
createVirtualRegister - Create and return a new virtual register in the function with the specified r...
LLVM_ABI MachineInstr * getUniqueVRegDef(Register Reg) const
getUniqueVRegDef - Return the unique machine instr that defines the specified virtual register or nul...
A set of analyses that are preserved following a run of a transformation pass.
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
PreservedAnalyses & preserveSet()
Mark an analysis set as preserved.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
void push_back(const T &Elt)
StringMap - This is an unconventional map that is specialized for handling keys that are "strings",...
iterator find(StringRef Key)
Provide an instruction scheduling machine model to CodeGen passes.
LLVM_ABI bool hasInstrSchedModel() const
Return true if this machine model includes an instruction-level scheduling model.
LLVM_ABI void init(const TargetSubtargetInfo *TSInfo, bool EnableSModel=true, bool EnableSItins=true)
Initialize the machine model for instruction scheduling.
const TargetSubtargetInfo * getSubtargetInfo() const
TargetSubtargetInfo getter.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
DXILDebugInfoMap run(Module &M)
This is an optimization pass for GlobalISel generic memory operations.
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
RegState
Flags to represent properties of register accesses.
constexpr RegState getKillRegState(bool B)
AnalysisManager< MachineFunction > MachineFunctionAnalysisManager
LLVM_ABI PreservedAnalyses getMachineFunctionPassPreservedAnalyses()
Returns the minimum set of Analyses that all machine function passes must preserve.
FunctionPass * createAArch64SIMDInstrOptPass()
Returns an instance of the high cost ASIMD instruction replacement optimization pass.
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
MCRegisterClass TargetRegisterClass
Summarize the scheduling resources required for an instruction of a particular scheduling class.