62#define HEXAGON_QFP_OPTIMIZER "QFP optimizer pass"
80#define DEBUG_TYPE "hexagon-qfp-optimizer"
86 cl::desc(
"Disable optimization of Qfloat operations."));
88 "disable-qfp-opt-mul",
cl::init(
true),
89 cl::desc(
"Disable optimization of Qfloat operations for multiply."));
92const std::map<unsigned short, unsigned short> QFPInstMap{
93 {Hexagon::V6_vadd_hf, Hexagon::V6_vadd_qf16_mix},
94 {Hexagon::V6_vadd_qf16_mix, Hexagon::V6_vadd_qf16},
95 {Hexagon::V6_vadd_sf, Hexagon::V6_vadd_qf32_mix},
96 {Hexagon::V6_vadd_qf32_mix, Hexagon::V6_vadd_qf32},
97 {Hexagon::V6_vsub_hf, Hexagon::V6_vsub_qf16_mix},
98 {Hexagon::V6_vsub_qf16_mix, Hexagon::V6_vsub_qf16},
99 {Hexagon::V6_vsub_sf, Hexagon::V6_vsub_qf32_mix},
100 {Hexagon::V6_vsub_qf32_mix, Hexagon::V6_vsub_qf32},
101 {Hexagon::V6_vmpy_qf16_hf, Hexagon::V6_vmpy_qf16_mix_hf},
102 {Hexagon::V6_vmpy_qf16_mix_hf, Hexagon::V6_vmpy_qf16},
103 {Hexagon::V6_vmpy_qf32_hf, Hexagon::V6_vmpy_qf32_mix_hf},
104 {Hexagon::V6_vmpy_qf32_mix_hf, Hexagon::V6_vmpy_qf32_qf16},
105 {Hexagon::V6_vmpy_qf32_sf, Hexagon::V6_vmpy_qf32},
106 {Hexagon::V6_vilog2_sf, Hexagon::V6_vilog2_qf32},
107 {Hexagon::V6_vilog2_hf, Hexagon::V6_vilog2_qf16},
108 {Hexagon::V6_vabs_qf32_sf, Hexagon::V6_vabs_qf32_qf32},
109 {Hexagon::V6_vabs_qf16_hf, Hexagon::V6_vabs_qf16_qf16},
110 {Hexagon::V6_vneg_qf32_sf, Hexagon::V6_vneg_qf32_qf32},
111 {Hexagon::V6_vneg_qf16_hf, Hexagon::V6_vneg_qf16_qf16}};
119 HexagonQFPOptimizer() : MachineFunctionPass(ID) {}
123 bool optimizeQfp(MachineInstr *
MI, MachineBasicBlock *
MBB);
125 bool optimizeQfpTwoOp(MachineInstr *
MI, MachineBasicBlock *
MBB);
127 bool optimizeQfpOneOp(MachineInstr *
MI, MachineBasicBlock *
MBB);
131 void getAnalysisUsage(AnalysisUsage &AU)
const override {
137 const HexagonSubtarget *HST =
nullptr;
138 const HexagonInstrInfo *HII =
nullptr;
139 const MachineRegisterInfo *MRI =
nullptr;
142char HexagonQFPOptimizer::ID = 0;
149 return new HexagonQFPOptimizer();
155 if (
MI->getNumOperands() == 2)
156 return optimizeQfpOneOp(
MI,
MBB);
157 else if (
MI->getNumOperands() == 3)
158 return optimizeQfpTwoOp(
MI,
MBB);
163bool HexagonQFPOptimizer::optimizeQfpOneOp(MachineInstr *
MI,
164 MachineBasicBlock *
MBB) {
167 auto It = QFPInstMap.find(
MI->getOpcode());
168 if (It == QFPInstMap.end())
171 unsigned short InstTy = It->second;
179 MachineInstr *ReachDefDef =
nullptr;
186 MachineInstrBuilder MIB;
189 if (ReachDefOp == Hexagon::V6_vconv_sf_qf32 ||
190 ReachDefOp == Hexagon::V6_vconv_hf_qf16) {
194 &Hexagon::HvxWRRegClass)
209bool HexagonQFPOptimizer::optimizeQfpTwoOp(MachineInstr *
MI,
210 MachineBasicBlock *
MBB) {
214 auto It = QFPInstMap.find(
MI->getOpcode());
215 if (It == QFPInstMap.end())
217 unsigned short InstTy = It->second;
219 MachineInstr *DefMI1 =
nullptr;
220 MachineInstr *DefMI2 =
nullptr;
222 if (
MI->getOperand(1).isReg())
224 if (
MI->getOperand(2).isReg())
226 if (!DefMI1 || !DefMI2)
229 MachineOperand &Res =
MI->getOperand(0);
233 MachineInstr *Inst1 =
nullptr;
234 MachineInstr *Inst2 =
nullptr;
250 MachineInstrBuilder MIB;
253 if ((Def1OP == Hexagon::V6_vconv_sf_qf32 &&
254 Def2OP == Hexagon::V6_vconv_sf_qf32) ||
255 (Def1OP == Hexagon::V6_vconv_hf_qf16 &&
256 Def2OP == Hexagon::V6_vconv_hf_qf16)) {
261 &Hexagon::HvxWRRegClass) ||
264 &Hexagon::HvxWRRegClass))
277 if (
MI->getOpcode() != Hexagon::V6_vmpy_qf32_sf) {
278 auto OuterIt = QFPInstMap.find(
MI->getOpcode());
279 if (OuterIt == QFPInstMap.end())
281 auto InnerIt = QFPInstMap.find(OuterIt->second);
282 if (InnerIt == QFPInstMap.end())
284 InstTy = InnerIt->second;
294 }
else if (((Def1OP == Hexagon::V6_vconv_sf_qf32 &&
295 Def2OP != Hexagon::V6_vconv_sf_qf32) ||
296 (Def1OP == Hexagon::V6_vconv_hf_qf16 &&
297 Def2OP != Hexagon::V6_vconv_hf_qf16)) &&
299 (
MI->getOpcode() != Hexagon::V6_vmpy_qf32_sf)) {
302 &Hexagon::HvxWRRegClass)
306 MachineOperand &Src2 =
MI->getOperand(2);
318 }
else if (((Def1OP != Hexagon::V6_vconv_sf_qf32 &&
319 Def2OP == Hexagon::V6_vconv_sf_qf32) ||
320 (Def1OP != Hexagon::V6_vconv_hf_qf16 &&
321 Def2OP == Hexagon::V6_vconv_hf_qf16)) &&
323 (
MI->getOpcode() != Hexagon::V6_vmpy_qf32_sf)) {
326 &Hexagon::HvxWRRegClass)
329 MachineOperand &Src1 =
MI->getOperand(1);
335 if (InstTy == Hexagon::V6_vsub_qf16_mix ||
336 InstTy == Hexagon::V6_vsub_qf32_mix) {
342 if (Def2OP == Hexagon::V6_vconv_sf_qf32)
343 InstTy = Hexagon::V6_vsub_sf_mix;
344 else if (Def2OP == Hexagon::V6_vconv_hf_qf16)
345 InstTy = Hexagon::V6_vsub_hf_mix;
378 <<
" Optimize intermediate conversions ===\n");
380 MachineBasicBlock *
MBB = &*
MBBI;
383 MachineInstr *
MI = &*MII;
385 if (QFPInstMap.count(
MI->getOpcode())) {
386 auto OpC =
MI->getOpcode();
389 if (OpC != Hexagon::V6_vconv_sf_qf32 &&
390 OpC != Hexagon::V6_vconv_hf_qf16) {
392 if (optimizeQfp(
MI,
MBB)) {
393 MI->eraseFromParent();
MachineInstrBuilder MachineInstrBuilder & DefMI
MachineBasicBlock MachineBasicBlock::iterator MBBI
cl::opt< bool > DisableQFOptimizer("disable-qfp-opt", cl::init(false), cl::desc("Disable optimization of Qfloat operations."))
cl::opt< bool > DisableQFOptForMul("disable-qfp-opt-mul", cl::init(true), cl::desc("Disable optimization of Qfloat operations for multiply."))
#define HEXAGON_QFP_OPTIMIZER
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
LLVM_ABI void setPreservesCFG()
This function should be called by the pass, iff they do not:
FunctionPass class - This class is used to implement most global optimizations.
bool isQFPMul(const MachineInstr *MF) const
const HexagonInstrInfo * getInstrInfo() const override
bool useHVXV81Ops() const
bool useHVXV68Ops() const
instr_iterator instr_begin()
instr_iterator instr_end()
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.
StringRef getName() const
getName - Return the name of the corresponding LLVM function.
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
Function & getFunction()
Return the LLVM function that this machine code represents.
BasicBlockListType::iterator iterator
const MachineInstrBuilder & addReg(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a new virtual register operand.
MachineInstr * getInstr() const
If conversion operators fail, use this method to get the MachineInstr explicitly.
Representation of each machine instruction.
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
unsigned getNumOperands() const
Retuns the total number of operands.
LLVM_ABI void dump() const
const MachineOperand & getOperand(unsigned i) const
unsigned getSubReg() const
bool isReg() const
isReg - Tests if this is a MO_Register operand.
void setIsKill(bool Val=true)
Register getReg() const
getReg - Returns the register number.
const TargetRegisterClass * getRegClass(Register Reg) const
Return the register class of the specified virtual register.
LLVM_ABI LLVM_READONLY MachineInstr * getVRegDef(Register Reg) const
getVRegDef - Return the machine instr that defines the specified virtual register or null if none is ...
constexpr bool isVirtual() const
Return true if the specified register number is in the virtual register namespace.
initializer< Ty > init(const Ty &Val)
This is an optimization pass for GlobalISel generic memory operations.
void dump(const SparseBitVector< ElementSize > &LHS, raw_ostream &out)
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)
FunctionPass * createHexagonQFPOptimizer()
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.