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