xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/X86/X86InsertWait.cpp (revision 5ffd83dbcc34f10e07f6d3e968ae6365869615f4)
1*5ffd83dbSDimitry Andric //-  X86Insertwait.cpp - Strict-Fp:Insert wait instruction X87 instructions --//
2*5ffd83dbSDimitry Andric //
3*5ffd83dbSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*5ffd83dbSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*5ffd83dbSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*5ffd83dbSDimitry Andric //
7*5ffd83dbSDimitry Andric //===----------------------------------------------------------------------===//
8*5ffd83dbSDimitry Andric //
9*5ffd83dbSDimitry Andric // This file defines the pass which insert x86 wait instructions after each
10*5ffd83dbSDimitry Andric // X87 instructions when strict float is enabled.
11*5ffd83dbSDimitry Andric //
12*5ffd83dbSDimitry Andric // The logic to insert a wait instruction after an X87 instruction is as below:
13*5ffd83dbSDimitry Andric // 1. If the X87 instruction don't raise float exception nor is a load/store
14*5ffd83dbSDimitry Andric //    instruction, or is a x87 control instruction, don't insert wait.
15*5ffd83dbSDimitry Andric // 2. If the X87 instruction is an instruction which the following instruction
16*5ffd83dbSDimitry Andric //    is an X87 exception synchronizing X87 instruction, don't insert wait.
17*5ffd83dbSDimitry Andric // 3. For other situations, insert wait instruction.
18*5ffd83dbSDimitry Andric //
19*5ffd83dbSDimitry Andric //===----------------------------------------------------------------------===//
20*5ffd83dbSDimitry Andric 
21*5ffd83dbSDimitry Andric #include "X86.h"
22*5ffd83dbSDimitry Andric #include "X86InstrInfo.h"
23*5ffd83dbSDimitry Andric #include "X86Subtarget.h"
24*5ffd83dbSDimitry Andric #include "llvm/CodeGen/MachineBasicBlock.h"
25*5ffd83dbSDimitry Andric #include "llvm/CodeGen/MachineFunction.h"
26*5ffd83dbSDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h"
27*5ffd83dbSDimitry Andric #include "llvm/CodeGen/MachineInstr.h"
28*5ffd83dbSDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h"
29*5ffd83dbSDimitry Andric #include "llvm/CodeGen/MachineOperand.h"
30*5ffd83dbSDimitry Andric #include "llvm/CodeGen/TargetInstrInfo.h"
31*5ffd83dbSDimitry Andric #include "llvm/IR/DebugLoc.h"
32*5ffd83dbSDimitry Andric #include "llvm/Support/Debug.h"
33*5ffd83dbSDimitry Andric 
34*5ffd83dbSDimitry Andric using namespace llvm;
35*5ffd83dbSDimitry Andric 
36*5ffd83dbSDimitry Andric #define DEBUG_TYPE "x86-insert-wait"
37*5ffd83dbSDimitry Andric 
38*5ffd83dbSDimitry Andric namespace {
39*5ffd83dbSDimitry Andric 
40*5ffd83dbSDimitry Andric class WaitInsert : public MachineFunctionPass {
41*5ffd83dbSDimitry Andric public:
42*5ffd83dbSDimitry Andric   static char ID;
43*5ffd83dbSDimitry Andric 
44*5ffd83dbSDimitry Andric   WaitInsert() : MachineFunctionPass(ID) {}
45*5ffd83dbSDimitry Andric 
46*5ffd83dbSDimitry Andric   bool runOnMachineFunction(MachineFunction &MF) override;
47*5ffd83dbSDimitry Andric 
48*5ffd83dbSDimitry Andric   StringRef getPassName() const override {
49*5ffd83dbSDimitry Andric     return "X86 insert wait instruction";
50*5ffd83dbSDimitry Andric   }
51*5ffd83dbSDimitry Andric 
52*5ffd83dbSDimitry Andric private:
53*5ffd83dbSDimitry Andric   const TargetInstrInfo *TII; // Machine instruction info.
54*5ffd83dbSDimitry Andric };
55*5ffd83dbSDimitry Andric 
56*5ffd83dbSDimitry Andric } // namespace
57*5ffd83dbSDimitry Andric 
58*5ffd83dbSDimitry Andric char WaitInsert::ID = 0;
59*5ffd83dbSDimitry Andric 
60*5ffd83dbSDimitry Andric FunctionPass *llvm::createX86InsertX87waitPass() { return new WaitInsert(); }
61*5ffd83dbSDimitry Andric 
62*5ffd83dbSDimitry Andric /// Return true if the Reg is X87 register.
63*5ffd83dbSDimitry Andric static bool isX87Reg(unsigned Reg) {
64*5ffd83dbSDimitry Andric   return (Reg == X86::FPCW || Reg == X86::FPSW ||
65*5ffd83dbSDimitry Andric           (Reg >= X86::ST0 && Reg <= X86::ST7));
66*5ffd83dbSDimitry Andric }
67*5ffd83dbSDimitry Andric 
68*5ffd83dbSDimitry Andric /// check if the instruction is X87 instruction
69*5ffd83dbSDimitry Andric static bool isX87Instruction(MachineInstr &MI) {
70*5ffd83dbSDimitry Andric   for (const MachineOperand &MO : MI.operands()) {
71*5ffd83dbSDimitry Andric     if (!MO.isReg())
72*5ffd83dbSDimitry Andric       continue;
73*5ffd83dbSDimitry Andric     if (isX87Reg(MO.getReg()))
74*5ffd83dbSDimitry Andric       return true;
75*5ffd83dbSDimitry Andric   }
76*5ffd83dbSDimitry Andric   return false;
77*5ffd83dbSDimitry Andric }
78*5ffd83dbSDimitry Andric 
79*5ffd83dbSDimitry Andric static bool isX87ControlInstruction(MachineInstr &MI) {
80*5ffd83dbSDimitry Andric   switch (MI.getOpcode()) {
81*5ffd83dbSDimitry Andric   case X86::FNINIT:
82*5ffd83dbSDimitry Andric   case X86::FLDCW16m:
83*5ffd83dbSDimitry Andric   case X86::FNSTCW16m:
84*5ffd83dbSDimitry Andric   case X86::FNSTSW16r:
85*5ffd83dbSDimitry Andric   case X86::FNSTSWm:
86*5ffd83dbSDimitry Andric   case X86::FNCLEX:
87*5ffd83dbSDimitry Andric   case X86::FLDENVm:
88*5ffd83dbSDimitry Andric   case X86::FSTENVm:
89*5ffd83dbSDimitry Andric   case X86::FRSTORm:
90*5ffd83dbSDimitry Andric   case X86::FSAVEm:
91*5ffd83dbSDimitry Andric   case X86::FINCSTP:
92*5ffd83dbSDimitry Andric   case X86::FDECSTP:
93*5ffd83dbSDimitry Andric   case X86::FFREE:
94*5ffd83dbSDimitry Andric   case X86::FFREEP:
95*5ffd83dbSDimitry Andric   case X86::FNOP:
96*5ffd83dbSDimitry Andric   case X86::WAIT:
97*5ffd83dbSDimitry Andric     return true;
98*5ffd83dbSDimitry Andric   default:
99*5ffd83dbSDimitry Andric     return false;
100*5ffd83dbSDimitry Andric   }
101*5ffd83dbSDimitry Andric }
102*5ffd83dbSDimitry Andric 
103*5ffd83dbSDimitry Andric static bool isX87NonWaitingControlInstruction(MachineInstr &MI) {
104*5ffd83dbSDimitry Andric   // a few special control instructions don't perform a wait operation
105*5ffd83dbSDimitry Andric   switch (MI.getOpcode()) {
106*5ffd83dbSDimitry Andric   case X86::FNINIT:
107*5ffd83dbSDimitry Andric   case X86::FNSTSW16r:
108*5ffd83dbSDimitry Andric   case X86::FNSTSWm:
109*5ffd83dbSDimitry Andric   case X86::FNSTCW16m:
110*5ffd83dbSDimitry Andric   case X86::FNCLEX:
111*5ffd83dbSDimitry Andric     return true;
112*5ffd83dbSDimitry Andric   default:
113*5ffd83dbSDimitry Andric     return false;
114*5ffd83dbSDimitry Andric   }
115*5ffd83dbSDimitry Andric }
116*5ffd83dbSDimitry Andric 
117*5ffd83dbSDimitry Andric bool WaitInsert::runOnMachineFunction(MachineFunction &MF) {
118*5ffd83dbSDimitry Andric   if (!MF.getFunction().hasFnAttribute(Attribute::StrictFP))
119*5ffd83dbSDimitry Andric     return false;
120*5ffd83dbSDimitry Andric 
121*5ffd83dbSDimitry Andric   const X86Subtarget &ST = MF.getSubtarget<X86Subtarget>();
122*5ffd83dbSDimitry Andric   TII = ST.getInstrInfo();
123*5ffd83dbSDimitry Andric   bool Changed = false;
124*5ffd83dbSDimitry Andric 
125*5ffd83dbSDimitry Andric   for (MachineBasicBlock &MBB : MF) {
126*5ffd83dbSDimitry Andric     for (MachineBasicBlock::iterator MI = MBB.begin(); MI != MBB.end(); ++MI) {
127*5ffd83dbSDimitry Andric       // Jump non X87 instruction.
128*5ffd83dbSDimitry Andric       if (!isX87Instruction(*MI))
129*5ffd83dbSDimitry Andric         continue;
130*5ffd83dbSDimitry Andric       // If the instruction instruction neither has float exception nor is
131*5ffd83dbSDimitry Andric       // a load/store instruction, or the instruction is x87 control
132*5ffd83dbSDimitry Andric       // instruction, do not insert wait.
133*5ffd83dbSDimitry Andric       if (!(MI->mayRaiseFPException() || MI->mayLoadOrStore()) ||
134*5ffd83dbSDimitry Andric           isX87ControlInstruction(*MI))
135*5ffd83dbSDimitry Andric         continue;
136*5ffd83dbSDimitry Andric       // If the following instruction is an X87 instruction and isn't an X87
137*5ffd83dbSDimitry Andric       // non-waiting control instruction, we can omit insert wait instruction.
138*5ffd83dbSDimitry Andric       MachineBasicBlock::iterator AfterMI = std::next(MI);
139*5ffd83dbSDimitry Andric       if (AfterMI != MBB.end() && isX87Instruction(*AfterMI) &&
140*5ffd83dbSDimitry Andric           !isX87NonWaitingControlInstruction(*AfterMI))
141*5ffd83dbSDimitry Andric         continue;
142*5ffd83dbSDimitry Andric 
143*5ffd83dbSDimitry Andric       BuildMI(MBB, AfterMI, MI->getDebugLoc(), TII->get(X86::WAIT));
144*5ffd83dbSDimitry Andric       LLVM_DEBUG(dbgs() << "\nInsert wait after:\t" << *MI);
145*5ffd83dbSDimitry Andric       // Jump the newly inserting wait
146*5ffd83dbSDimitry Andric       ++MI;
147*5ffd83dbSDimitry Andric       Changed = true;
148*5ffd83dbSDimitry Andric     }
149*5ffd83dbSDimitry Andric   }
150*5ffd83dbSDimitry Andric   return Changed;
151*5ffd83dbSDimitry Andric }
152