xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/X86/X86InsertWait.cpp (revision e8d8bef961a50d4dc22501cde4fb9fb0be1b2532)
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