1 //===- PPCMacroFusion.cpp - PowerPC Macro Fusion --------------------------===//
2 //
3 // 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
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 /// \file This file contains the PowerPC implementation of the DAG scheduling
10 /// mutation to pair instructions back to back.
11 //
12 //===----------------------------------------------------------------------===//
13
14 #include "PPC.h"
15 #include "PPCSubtarget.h"
16 #include "llvm/ADT/DenseSet.h"
17 #include "llvm/CodeGen/MacroFusion.h"
18
19 using namespace llvm;
20 namespace {
21
22 class FusionFeature {
23 public:
24 typedef SmallDenseSet<unsigned> FusionOpSet;
25
26 enum FusionKind {
27 #define FUSION_KIND(KIND) FK_##KIND
28 #define FUSION_FEATURE(KIND, HAS_FEATURE, DEP_OP_IDX, OPSET1, OPSET2) \
29 FUSION_KIND(KIND),
30 #include "PPCMacroFusion.def"
31 FUSION_KIND(END)
32 };
33 private:
34 // Each fusion feature is assigned with one fusion kind. All the
35 // instructions with the same fusion kind have the same fusion characteristic.
36 FusionKind Kd;
37 // True if this feature is enabled.
38 bool Supported;
39 // li rx, si
40 // load rt, ra, rx
41 // The dependent operand index in the second op(load). And the negative means
42 // it could be any one.
43 int DepOpIdx;
44 // The first fusion op set.
45 FusionOpSet OpSet1;
46 // The second fusion op set.
47 FusionOpSet OpSet2;
48 public:
FusionFeature(FusionKind Kind,bool HasFeature,int Index,const FusionOpSet & First,const FusionOpSet & Second)49 FusionFeature(FusionKind Kind, bool HasFeature, int Index,
50 const FusionOpSet &First, const FusionOpSet &Second) :
51 Kd(Kind), Supported(HasFeature), DepOpIdx(Index), OpSet1(First),
52 OpSet2(Second) {}
53
hasOp1(unsigned Opc) const54 bool hasOp1(unsigned Opc) const { return OpSet1.count(Opc) != 0; }
hasOp2(unsigned Opc) const55 bool hasOp2(unsigned Opc) const { return OpSet2.count(Opc) != 0; }
isSupported() const56 bool isSupported() const { return Supported; }
depOpIdx() const57 Optional<unsigned> depOpIdx() const {
58 if (DepOpIdx < 0)
59 return None;
60 return DepOpIdx;
61 }
62
getKind() const63 FusionKind getKind() const { return Kd; }
64 };
65
matchingRegOps(const MachineInstr & FirstMI,int FirstMIOpIndex,const MachineInstr & SecondMI,int SecondMIOpIndex)66 static bool matchingRegOps(const MachineInstr &FirstMI,
67 int FirstMIOpIndex,
68 const MachineInstr &SecondMI,
69 int SecondMIOpIndex) {
70 const MachineOperand &Op1 = FirstMI.getOperand(FirstMIOpIndex);
71 const MachineOperand &Op2 = SecondMI.getOperand(SecondMIOpIndex);
72 if (!Op1.isReg() || !Op2.isReg())
73 return false;
74
75 return Op1.getReg() == Op2.getReg();
76 }
77
78 // Return true if the FirstMI meets the constraints of SecondMI according to
79 // fusion specification.
checkOpConstraints(FusionFeature::FusionKind Kd,const MachineInstr & FirstMI,const MachineInstr & SecondMI)80 static bool checkOpConstraints(FusionFeature::FusionKind Kd,
81 const MachineInstr &FirstMI,
82 const MachineInstr &SecondMI) {
83 switch (Kd) {
84 // The hardware didn't require any specific check for the fused instructions'
85 // operands. Therefore, return true to indicate that, it is fusable.
86 default: return true;
87 // [addi rt,ra,si - lxvd2x xt,ra,rb] etc.
88 case FusionFeature::FK_AddiLoad: {
89 // lxvd2x(ra) cannot be zero
90 const MachineOperand &RA = SecondMI.getOperand(1);
91 if (!RA.isReg())
92 return true;
93
94 return Register::isVirtualRegister(RA.getReg()) ||
95 (RA.getReg() != PPC::ZERO && RA.getReg() != PPC::ZERO8);
96 }
97 // [addis rt,ra,si - ld rt,ds(ra)] etc.
98 case FusionFeature::FK_AddisLoad: {
99 const MachineOperand &RT = SecondMI.getOperand(0);
100 if (!RT.isReg())
101 return true;
102
103 // Only check it for non-virtual register.
104 if (!Register::isVirtualRegister(RT.getReg()))
105 // addis(rt) = ld(ra) = ld(rt)
106 // ld(rt) cannot be zero
107 if (!matchingRegOps(SecondMI, 0, SecondMI, 2) ||
108 (RT.getReg() == PPC::ZERO || RT.getReg() == PPC::ZERO8))
109 return false;
110
111 // addis(si) first 12 bits must be all 1s or all 0s
112 const MachineOperand &SI = FirstMI.getOperand(2);
113 if (!SI.isImm())
114 return true;
115 int64_t Imm = SI.getImm();
116 if (((Imm & 0xFFF0) != 0) && ((Imm & 0xFFF0) != 0xFFF0))
117 return false;
118
119 // If si = 1111111111110000 and the msb of the d/ds field of the load equals
120 // 1, then fusion does not occur.
121 if ((Imm & 0xFFF0) == 0xFFF0) {
122 const MachineOperand &D = SecondMI.getOperand(1);
123 if (!D.isImm())
124 return true;
125
126 // 14 bit for DS field, while 16 bit for D field.
127 int MSB = 15;
128 if (SecondMI.getOpcode() == PPC::LD)
129 MSB = 13;
130
131 return (D.getImm() & (1ULL << MSB)) == 0;
132 }
133 return true;
134 }
135 }
136
137 llvm_unreachable("All the cases should have been handled");
138 return true;
139 }
140
141 /// Check if the instr pair, FirstMI and SecondMI, should be fused together.
142 /// Given SecondMI, when FirstMI is unspecified, then check if SecondMI may be
143 /// part of a fused pair at all.
shouldScheduleAdjacent(const TargetInstrInfo & TII,const TargetSubtargetInfo & TSI,const MachineInstr * FirstMI,const MachineInstr & SecondMI)144 static bool shouldScheduleAdjacent(const TargetInstrInfo &TII,
145 const TargetSubtargetInfo &TSI,
146 const MachineInstr *FirstMI,
147 const MachineInstr &SecondMI) {
148 // We use the PPC namespace to avoid the need to prefix opcodes with PPC:: in
149 // the def file.
150 using namespace PPC;
151
152 const PPCSubtarget &ST = static_cast<const PPCSubtarget&>(TSI);
153 static const FusionFeature FusionFeatures[] = {
154 #define FUSION_FEATURE(KIND, HAS_FEATURE, DEP_OP_IDX, OPSET1, OPSET2) { \
155 FusionFeature::FUSION_KIND(KIND), ST.HAS_FEATURE(), DEP_OP_IDX, { OPSET1 },\
156 { OPSET2 } },
157 #include "PPCMacroFusion.def"
158 };
159 #undef FUSION_KIND
160
161 for (auto &Feature : FusionFeatures) {
162 // Skip if the feature is not supported.
163 if (!Feature.isSupported())
164 continue;
165
166 // Only when the SecondMI is fusable, we are starting to look for the
167 // fusable FirstMI.
168 if (Feature.hasOp2(SecondMI.getOpcode())) {
169 // If FirstMI == nullptr, that means, we're only checking whether SecondMI
170 // can be fused at all.
171 if (!FirstMI)
172 return true;
173
174 // Checking if the FirstMI is fusable with the SecondMI.
175 if (!Feature.hasOp1(FirstMI->getOpcode()))
176 continue;
177
178 auto DepOpIdx = Feature.depOpIdx();
179 if (DepOpIdx.hasValue()) {
180 // Checking if the result of the FirstMI is the desired operand of the
181 // SecondMI if the DepOpIdx is set. Otherwise, ignore it.
182 if (!matchingRegOps(*FirstMI, 0, SecondMI, *DepOpIdx))
183 return false;
184 }
185
186 // Checking more on the instruction operands.
187 if (checkOpConstraints(Feature.getKind(), *FirstMI, SecondMI))
188 return true;
189 }
190 }
191
192 return false;
193 }
194
195 } // end anonymous namespace
196
197 namespace llvm {
198
createPowerPCMacroFusionDAGMutation()199 std::unique_ptr<ScheduleDAGMutation> createPowerPCMacroFusionDAGMutation () {
200 return createMacroFusionDAGMutation(shouldScheduleAdjacent);
201 }
202
203 } // end namespace llvm
204