15ffd83dbSDimitry Andric //- X86Insertwait.cpp - Strict-Fp:Insert wait instruction X87 instructions --// 25ffd83dbSDimitry Andric // 35ffd83dbSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 45ffd83dbSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 55ffd83dbSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 65ffd83dbSDimitry Andric // 75ffd83dbSDimitry Andric //===----------------------------------------------------------------------===// 85ffd83dbSDimitry Andric // 95ffd83dbSDimitry Andric // This file defines the pass which insert x86 wait instructions after each 105ffd83dbSDimitry Andric // X87 instructions when strict float is enabled. 115ffd83dbSDimitry Andric // 125ffd83dbSDimitry Andric // The logic to insert a wait instruction after an X87 instruction is as below: 135ffd83dbSDimitry Andric // 1. If the X87 instruction don't raise float exception nor is a load/store 145ffd83dbSDimitry Andric // instruction, or is a x87 control instruction, don't insert wait. 155ffd83dbSDimitry Andric // 2. If the X87 instruction is an instruction which the following instruction 165ffd83dbSDimitry Andric // is an X87 exception synchronizing X87 instruction, don't insert wait. 175ffd83dbSDimitry Andric // 3. For other situations, insert wait instruction. 185ffd83dbSDimitry Andric // 195ffd83dbSDimitry Andric //===----------------------------------------------------------------------===// 205ffd83dbSDimitry Andric 215ffd83dbSDimitry Andric #include "X86.h" 225ffd83dbSDimitry Andric #include "X86InstrInfo.h" 235ffd83dbSDimitry Andric #include "X86Subtarget.h" 245ffd83dbSDimitry Andric #include "llvm/CodeGen/MachineBasicBlock.h" 255ffd83dbSDimitry Andric #include "llvm/CodeGen/MachineFunction.h" 265ffd83dbSDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h" 275ffd83dbSDimitry Andric #include "llvm/CodeGen/MachineInstr.h" 285ffd83dbSDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h" 295ffd83dbSDimitry Andric #include "llvm/CodeGen/MachineOperand.h" 305ffd83dbSDimitry Andric #include "llvm/IR/DebugLoc.h" 315ffd83dbSDimitry Andric #include "llvm/Support/Debug.h" 325ffd83dbSDimitry Andric 335ffd83dbSDimitry Andric using namespace llvm; 345ffd83dbSDimitry Andric 355ffd83dbSDimitry Andric #define DEBUG_TYPE "x86-insert-wait" 365ffd83dbSDimitry Andric 375ffd83dbSDimitry Andric namespace { 385ffd83dbSDimitry Andric 395ffd83dbSDimitry Andric class WaitInsert : public MachineFunctionPass { 405ffd83dbSDimitry Andric public: 415ffd83dbSDimitry Andric static char ID; 425ffd83dbSDimitry Andric 435ffd83dbSDimitry Andric WaitInsert() : MachineFunctionPass(ID) {} 445ffd83dbSDimitry Andric 455ffd83dbSDimitry Andric bool runOnMachineFunction(MachineFunction &MF) override; 465ffd83dbSDimitry Andric 475ffd83dbSDimitry Andric StringRef getPassName() const override { 485ffd83dbSDimitry Andric return "X86 insert wait instruction"; 495ffd83dbSDimitry Andric } 505ffd83dbSDimitry Andric }; 515ffd83dbSDimitry Andric 525ffd83dbSDimitry Andric } // namespace 535ffd83dbSDimitry Andric 545ffd83dbSDimitry Andric char WaitInsert::ID = 0; 555ffd83dbSDimitry Andric 565ffd83dbSDimitry Andric FunctionPass *llvm::createX86InsertX87waitPass() { return new WaitInsert(); } 575ffd83dbSDimitry Andric 585ffd83dbSDimitry Andric /// Return true if the Reg is X87 register. 595ffd83dbSDimitry Andric static bool isX87Reg(unsigned Reg) { 605ffd83dbSDimitry Andric return (Reg == X86::FPCW || Reg == X86::FPSW || 615ffd83dbSDimitry Andric (Reg >= X86::ST0 && Reg <= X86::ST7)); 625ffd83dbSDimitry Andric } 635ffd83dbSDimitry Andric 645ffd83dbSDimitry Andric /// check if the instruction is X87 instruction 655ffd83dbSDimitry Andric static bool isX87Instruction(MachineInstr &MI) { 665ffd83dbSDimitry Andric for (const MachineOperand &MO : MI.operands()) { 675ffd83dbSDimitry Andric if (!MO.isReg()) 685ffd83dbSDimitry Andric continue; 695ffd83dbSDimitry Andric if (isX87Reg(MO.getReg())) 705ffd83dbSDimitry Andric return true; 715ffd83dbSDimitry Andric } 725ffd83dbSDimitry Andric return false; 735ffd83dbSDimitry Andric } 745ffd83dbSDimitry Andric 755ffd83dbSDimitry Andric static bool isX87ControlInstruction(MachineInstr &MI) { 765ffd83dbSDimitry Andric switch (MI.getOpcode()) { 775ffd83dbSDimitry Andric case X86::FNINIT: 785ffd83dbSDimitry Andric case X86::FLDCW16m: 795ffd83dbSDimitry Andric case X86::FNSTCW16m: 805ffd83dbSDimitry Andric case X86::FNSTSW16r: 815ffd83dbSDimitry Andric case X86::FNSTSWm: 825ffd83dbSDimitry Andric case X86::FNCLEX: 835ffd83dbSDimitry Andric case X86::FLDENVm: 845ffd83dbSDimitry Andric case X86::FSTENVm: 855ffd83dbSDimitry Andric case X86::FRSTORm: 865ffd83dbSDimitry Andric case X86::FSAVEm: 875ffd83dbSDimitry Andric case X86::FINCSTP: 885ffd83dbSDimitry Andric case X86::FDECSTP: 895ffd83dbSDimitry Andric case X86::FFREE: 905ffd83dbSDimitry Andric case X86::FFREEP: 915ffd83dbSDimitry Andric case X86::FNOP: 925ffd83dbSDimitry Andric case X86::WAIT: 935ffd83dbSDimitry Andric return true; 945ffd83dbSDimitry Andric default: 955ffd83dbSDimitry Andric return false; 965ffd83dbSDimitry Andric } 975ffd83dbSDimitry Andric } 985ffd83dbSDimitry Andric 995ffd83dbSDimitry Andric static bool isX87NonWaitingControlInstruction(MachineInstr &MI) { 1005ffd83dbSDimitry Andric // a few special control instructions don't perform a wait operation 1015ffd83dbSDimitry Andric switch (MI.getOpcode()) { 1025ffd83dbSDimitry Andric case X86::FNINIT: 1035ffd83dbSDimitry Andric case X86::FNSTSW16r: 1045ffd83dbSDimitry Andric case X86::FNSTSWm: 1055ffd83dbSDimitry Andric case X86::FNSTCW16m: 1065ffd83dbSDimitry Andric case X86::FNCLEX: 1075ffd83dbSDimitry Andric return true; 1085ffd83dbSDimitry Andric default: 1095ffd83dbSDimitry Andric return false; 1105ffd83dbSDimitry Andric } 1115ffd83dbSDimitry Andric } 1125ffd83dbSDimitry Andric 1135ffd83dbSDimitry Andric bool WaitInsert::runOnMachineFunction(MachineFunction &MF) { 1145ffd83dbSDimitry Andric if (!MF.getFunction().hasFnAttribute(Attribute::StrictFP)) 1155ffd83dbSDimitry Andric return false; 1165ffd83dbSDimitry Andric 1175ffd83dbSDimitry Andric const X86Subtarget &ST = MF.getSubtarget<X86Subtarget>(); 118*e8d8bef9SDimitry Andric const X86InstrInfo *TII = ST.getInstrInfo(); 1195ffd83dbSDimitry Andric bool Changed = false; 1205ffd83dbSDimitry Andric 1215ffd83dbSDimitry Andric for (MachineBasicBlock &MBB : MF) { 1225ffd83dbSDimitry Andric for (MachineBasicBlock::iterator MI = MBB.begin(); MI != MBB.end(); ++MI) { 1235ffd83dbSDimitry Andric // Jump non X87 instruction. 1245ffd83dbSDimitry Andric if (!isX87Instruction(*MI)) 1255ffd83dbSDimitry Andric continue; 1265ffd83dbSDimitry Andric // If the instruction instruction neither has float exception nor is 1275ffd83dbSDimitry Andric // a load/store instruction, or the instruction is x87 control 1285ffd83dbSDimitry Andric // instruction, do not insert wait. 1295ffd83dbSDimitry Andric if (!(MI->mayRaiseFPException() || MI->mayLoadOrStore()) || 1305ffd83dbSDimitry Andric isX87ControlInstruction(*MI)) 1315ffd83dbSDimitry Andric continue; 1325ffd83dbSDimitry Andric // If the following instruction is an X87 instruction and isn't an X87 1335ffd83dbSDimitry Andric // non-waiting control instruction, we can omit insert wait instruction. 1345ffd83dbSDimitry Andric MachineBasicBlock::iterator AfterMI = std::next(MI); 1355ffd83dbSDimitry Andric if (AfterMI != MBB.end() && isX87Instruction(*AfterMI) && 1365ffd83dbSDimitry Andric !isX87NonWaitingControlInstruction(*AfterMI)) 1375ffd83dbSDimitry Andric continue; 1385ffd83dbSDimitry Andric 1395ffd83dbSDimitry Andric BuildMI(MBB, AfterMI, MI->getDebugLoc(), TII->get(X86::WAIT)); 1405ffd83dbSDimitry Andric LLVM_DEBUG(dbgs() << "\nInsert wait after:\t" << *MI); 1415ffd83dbSDimitry Andric // Jump the newly inserting wait 1425ffd83dbSDimitry Andric ++MI; 1435ffd83dbSDimitry Andric Changed = true; 1445ffd83dbSDimitry Andric } 1455ffd83dbSDimitry Andric } 1465ffd83dbSDimitry Andric return Changed; 1475ffd83dbSDimitry Andric } 148