131 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8//9// This file defines the pass which insert x86 wait instructions after each10// 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/store14// instruction, or is a x87 control instruction, don't insert wait.15// 2. If the X87 instruction is an instruction which the following instruction16// 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/IR/DebugLoc.h"31#include "llvm/Support/Debug.h"32 33using namespace llvm;34 35#define DEBUG_TYPE "x86-insert-wait"36 37namespace {38 39class WaitInsert : public MachineFunctionPass {40public:41 static char ID;42 43 WaitInsert() : MachineFunctionPass(ID) {}44 45 bool runOnMachineFunction(MachineFunction &MF) override;46 47 StringRef getPassName() const override {48 return "X86 insert wait instruction";49 }50};51 52} // namespace53 54char WaitInsert::ID = 0;55 56FunctionPass *llvm::createX86InsertX87waitPass() { return new WaitInsert(); }57 58static bool isX87ControlInstruction(MachineInstr &MI) {59 switch (MI.getOpcode()) {60 case X86::FNINIT:61 case X86::FLDCW16m:62 case X86::FNSTCW16m:63 case X86::FNSTSW16r:64 case X86::FNSTSWm:65 case X86::FNCLEX:66 case X86::FLDENVm:67 case X86::FSTENVm:68 case X86::FRSTORm:69 case X86::FSAVEm:70 case X86::FINCSTP:71 case X86::FDECSTP:72 case X86::FFREE:73 case X86::FFREEP:74 case X86::FNOP:75 case X86::WAIT:76 return true;77 default:78 return false;79 }80}81 82static bool isX87NonWaitingControlInstruction(MachineInstr &MI) {83 // a few special control instructions don't perform a wait operation84 switch (MI.getOpcode()) {85 case X86::FNINIT:86 case X86::FNSTSW16r:87 case X86::FNSTSWm:88 case X86::FNSTCW16m:89 case X86::FNCLEX:90 return true;91 default:92 return false;93 }94}95 96bool WaitInsert::runOnMachineFunction(MachineFunction &MF) {97 if (!MF.getFunction().hasFnAttribute(Attribute::StrictFP))98 return false;99 100 const X86Subtarget &ST = MF.getSubtarget<X86Subtarget>();101 const X86InstrInfo *TII = ST.getInstrInfo();102 bool Changed = false;103 104 for (MachineBasicBlock &MBB : MF) {105 for (MachineBasicBlock::iterator MI = MBB.begin(); MI != MBB.end(); ++MI) {106 // Jump non X87 instruction.107 if (!X86::isX87Instruction(*MI))108 continue;109 // If the instruction instruction neither has float exception nor is110 // a load/store instruction, or the instruction is x87 control111 // instruction, do not insert wait.112 if (!(MI->mayRaiseFPException() || MI->mayLoadOrStore()) ||113 isX87ControlInstruction(*MI))114 continue;115 // If the following instruction is an X87 instruction and isn't an X87116 // non-waiting control instruction, we can omit insert wait instruction.117 MachineBasicBlock::iterator AfterMI = std::next(MI);118 if (AfterMI != MBB.end() && X86::isX87Instruction(*AfterMI) &&119 !isX87NonWaitingControlInstruction(*AfterMI))120 continue;121 122 BuildMI(MBB, AfterMI, MI->getDebugLoc(), TII->get(X86::WAIT));123 LLVM_DEBUG(dbgs() << "\nInsert wait after:\t" << *MI);124 // Jump the newly inserting wait125 ++MI;126 Changed = true;127 }128 }129 return Changed;130}131