xref: /openbsd-src/gnu/llvm/llvm/lib/Target/X86/X86InsertWait.cpp (revision d415bd752c734aee168c4ee86ff32e8cc249eb16)
1097a140dSpatrick //-  X86Insertwait.cpp - Strict-Fp:Insert wait instruction X87 instructions --//
2097a140dSpatrick //
3097a140dSpatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4097a140dSpatrick // See https://llvm.org/LICENSE.txt for license information.
5097a140dSpatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6097a140dSpatrick //
7097a140dSpatrick //===----------------------------------------------------------------------===//
8097a140dSpatrick //
9097a140dSpatrick // This file defines the pass which insert x86 wait instructions after each
10097a140dSpatrick // X87 instructions when strict float is enabled.
11097a140dSpatrick //
12097a140dSpatrick // The logic to insert a wait instruction after an X87 instruction is as below:
13097a140dSpatrick // 1. If the X87 instruction don't raise float exception nor is a load/store
14097a140dSpatrick //    instruction, or is a x87 control instruction, don't insert wait.
15097a140dSpatrick // 2. If the X87 instruction is an instruction which the following instruction
16097a140dSpatrick //    is an X87 exception synchronizing X87 instruction, don't insert wait.
17097a140dSpatrick // 3. For other situations, insert wait instruction.
18097a140dSpatrick //
19097a140dSpatrick //===----------------------------------------------------------------------===//
20097a140dSpatrick 
21097a140dSpatrick #include "X86.h"
22097a140dSpatrick #include "X86InstrInfo.h"
23097a140dSpatrick #include "X86Subtarget.h"
24097a140dSpatrick #include "llvm/CodeGen/MachineBasicBlock.h"
25097a140dSpatrick #include "llvm/CodeGen/MachineFunction.h"
26097a140dSpatrick #include "llvm/CodeGen/MachineFunctionPass.h"
27097a140dSpatrick #include "llvm/CodeGen/MachineInstr.h"
28097a140dSpatrick #include "llvm/CodeGen/MachineInstrBuilder.h"
29097a140dSpatrick #include "llvm/CodeGen/MachineOperand.h"
30097a140dSpatrick #include "llvm/IR/DebugLoc.h"
31097a140dSpatrick #include "llvm/Support/Debug.h"
32097a140dSpatrick 
33097a140dSpatrick using namespace llvm;
34097a140dSpatrick 
35097a140dSpatrick #define DEBUG_TYPE "x86-insert-wait"
36097a140dSpatrick 
37097a140dSpatrick namespace {
38097a140dSpatrick 
39097a140dSpatrick class WaitInsert : public MachineFunctionPass {
40097a140dSpatrick public:
41097a140dSpatrick   static char ID;
42097a140dSpatrick 
WaitInsert()43097a140dSpatrick   WaitInsert() : MachineFunctionPass(ID) {}
44097a140dSpatrick 
45097a140dSpatrick   bool runOnMachineFunction(MachineFunction &MF) override;
46097a140dSpatrick 
getPassName() const47097a140dSpatrick   StringRef getPassName() const override {
48097a140dSpatrick     return "X86 insert wait instruction";
49097a140dSpatrick   }
50097a140dSpatrick };
51097a140dSpatrick 
52097a140dSpatrick } // namespace
53097a140dSpatrick 
54097a140dSpatrick char WaitInsert::ID = 0;
55097a140dSpatrick 
createX86InsertX87waitPass()56097a140dSpatrick FunctionPass *llvm::createX86InsertX87waitPass() { return new WaitInsert(); }
57097a140dSpatrick 
isX87ControlInstruction(MachineInstr & MI)58097a140dSpatrick static bool isX87ControlInstruction(MachineInstr &MI) {
59097a140dSpatrick   switch (MI.getOpcode()) {
60097a140dSpatrick   case X86::FNINIT:
61097a140dSpatrick   case X86::FLDCW16m:
62097a140dSpatrick   case X86::FNSTCW16m:
63097a140dSpatrick   case X86::FNSTSW16r:
64097a140dSpatrick   case X86::FNSTSWm:
65097a140dSpatrick   case X86::FNCLEX:
66097a140dSpatrick   case X86::FLDENVm:
67097a140dSpatrick   case X86::FSTENVm:
68097a140dSpatrick   case X86::FRSTORm:
69097a140dSpatrick   case X86::FSAVEm:
70097a140dSpatrick   case X86::FINCSTP:
71097a140dSpatrick   case X86::FDECSTP:
72097a140dSpatrick   case X86::FFREE:
73097a140dSpatrick   case X86::FFREEP:
74097a140dSpatrick   case X86::FNOP:
75097a140dSpatrick   case X86::WAIT:
76097a140dSpatrick     return true;
77097a140dSpatrick   default:
78097a140dSpatrick     return false;
79097a140dSpatrick   }
80097a140dSpatrick }
81097a140dSpatrick 
isX87NonWaitingControlInstruction(MachineInstr & MI)82097a140dSpatrick static bool isX87NonWaitingControlInstruction(MachineInstr &MI) {
83097a140dSpatrick   // a few special control instructions don't perform a wait operation
84097a140dSpatrick   switch (MI.getOpcode()) {
85097a140dSpatrick   case X86::FNINIT:
86097a140dSpatrick   case X86::FNSTSW16r:
87097a140dSpatrick   case X86::FNSTSWm:
88097a140dSpatrick   case X86::FNSTCW16m:
89097a140dSpatrick   case X86::FNCLEX:
90097a140dSpatrick     return true;
91097a140dSpatrick   default:
92097a140dSpatrick     return false;
93097a140dSpatrick   }
94097a140dSpatrick }
95097a140dSpatrick 
runOnMachineFunction(MachineFunction & MF)96097a140dSpatrick bool WaitInsert::runOnMachineFunction(MachineFunction &MF) {
97097a140dSpatrick   if (!MF.getFunction().hasFnAttribute(Attribute::StrictFP))
98097a140dSpatrick     return false;
99097a140dSpatrick 
100097a140dSpatrick   const X86Subtarget &ST = MF.getSubtarget<X86Subtarget>();
10173471bf0Spatrick   const X86InstrInfo *TII = ST.getInstrInfo();
102097a140dSpatrick   bool Changed = false;
103097a140dSpatrick 
104097a140dSpatrick   for (MachineBasicBlock &MBB : MF) {
105097a140dSpatrick     for (MachineBasicBlock::iterator MI = MBB.begin(); MI != MBB.end(); ++MI) {
106097a140dSpatrick       // Jump non X87 instruction.
107*d415bd75Srobert       if (!X86::isX87Instruction(*MI))
108097a140dSpatrick         continue;
109097a140dSpatrick       // If the instruction instruction neither has float exception nor is
110097a140dSpatrick       // a load/store instruction, or the instruction is x87 control
111097a140dSpatrick       // instruction, do not insert wait.
112097a140dSpatrick       if (!(MI->mayRaiseFPException() || MI->mayLoadOrStore()) ||
113097a140dSpatrick           isX87ControlInstruction(*MI))
114097a140dSpatrick         continue;
115097a140dSpatrick       // If the following instruction is an X87 instruction and isn't an X87
116097a140dSpatrick       // non-waiting control instruction, we can omit insert wait instruction.
117097a140dSpatrick       MachineBasicBlock::iterator AfterMI = std::next(MI);
118*d415bd75Srobert       if (AfterMI != MBB.end() && X86::isX87Instruction(*AfterMI) &&
119097a140dSpatrick           !isX87NonWaitingControlInstruction(*AfterMI))
120097a140dSpatrick         continue;
121097a140dSpatrick 
122097a140dSpatrick       BuildMI(MBB, AfterMI, MI->getDebugLoc(), TII->get(X86::WAIT));
123097a140dSpatrick       LLVM_DEBUG(dbgs() << "\nInsert wait after:\t" << *MI);
124097a140dSpatrick       // Jump the newly inserting wait
125097a140dSpatrick       ++MI;
126097a140dSpatrick       Changed = true;
127097a140dSpatrick     }
128097a140dSpatrick   }
129097a140dSpatrick   return Changed;
130097a140dSpatrick }
131