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