//===-- X86FloatingPoint.cpp - Floating point Reg -> Stack converter ------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This file defines the pass which converts floating point instructions from // pseudo registers into register stack instructions. This pass uses live // variable information to indicate where the FPn registers are used and their // lifetimes. // // The x87 hardware tracks liveness of the stack registers, so it is necessary // to implement exact liveness tracking between basic blocks. The CFG edges are // partitioned into bundles where the same FP registers must be live in // identical stack positions. Instructions are inserted at the end of each basic // block to rearrange the live registers to match the outgoing bundle. // // This approach avoids splitting critical edges at the potential cost of more // live register shuffling instructions when critical edges are present. // //===----------------------------------------------------------------------===// #include "X86.h" #include "X86InstrInfo.h" #include "llvm/ADT/DepthFirstIterator.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/Statistic.h" #include "llvm/CodeGen/EdgeBundles.h" #include "llvm/CodeGen/LiveRegUnits.h" #include "llvm/CodeGen/MachineFunctionPass.h" #include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/CodeGen/Passes.h" #include "llvm/CodeGen/TargetInstrInfo.h" #include "llvm/CodeGen/TargetSubtargetInfo.h" #include "llvm/Config/llvm-config.h" #include "llvm/IR/InlineAsm.h" #include "llvm/InitializePasses.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Target/TargetMachine.h" #include <algorithm> #include <bitset> usingnamespacellvm; #define DEBUG_TYPE … STATISTIC(NumFXCH, "Number of fxch instructions inserted"); STATISTIC(NumFP , "Number of floating point instructions"); namespace { const unsigned ScratchFPReg = …; struct FPS : public MachineFunctionPass { … }; } char FPS::ID = …; INITIALIZE_PASS_BEGIN(FPS, DEBUG_TYPE, "X86 FP Stackifier", false, false) INITIALIZE_PASS_DEPENDENCY(EdgeBundles) INITIALIZE_PASS_END(FPS, DEBUG_TYPE, "X86 FP Stackifier", false, false) FunctionPass *llvm::createX86FloatingPointStackifierPass() { … } /// getFPReg - Return the X86::FPx register number for the specified operand. /// For example, this returns 3 for X86::FP3. static unsigned getFPReg(const MachineOperand &MO) { … } /// runOnMachineFunction - Loop over all of the basic blocks, transforming FP /// register references into FP stack references. /// bool FPS::runOnMachineFunction(MachineFunction &MF) { … } /// bundleCFG - Scan all the basic blocks to determine consistent live-in and /// live-out sets for the FP registers. Consistent means that the set of /// registers live-out from a block is identical to the live-in set of all /// successors. This is not enforced by the normal live-in lists since /// registers may be implicitly defined, or not used by all successors. void FPS::bundleCFGRecomputeKillFlags(MachineFunction &MF) { … } /// processBasicBlock - Loop over all of the instructions in the basic block, /// transforming FP instructions into their stack form. /// bool FPS::processBasicBlock(MachineFunction &MF, MachineBasicBlock &BB) { … } /// setupBlockStack - Use the live bundles to set up our model of the stack /// to match predecessors' live out stack. void FPS::setupBlockStack() { … } /// finishBlockStack - Revive live-outs that are implicitly defined out of /// MBB. Shuffle live registers to match the expected fixed stack of any /// predecessors, and ensure that all predecessors are expecting the same /// stack. void FPS::finishBlockStack() { … } //===----------------------------------------------------------------------===// // Efficient Lookup Table Support //===----------------------------------------------------------------------===// namespace { struct TableEntry { … }; } static int Lookup(ArrayRef<TableEntry> Table, unsigned Opcode) { … } #ifdef NDEBUG #define ASSERT_SORTED(TABLE) … #else #define ASSERT_SORTED … #endif //===----------------------------------------------------------------------===// // Register File -> Register Stack Mapping Methods //===----------------------------------------------------------------------===// // OpcodeTable - Sorted map of register instructions to their stack version. // The first element is an register file pseudo instruction, the second is the // concrete X86 instruction which uses the register stack. // static const TableEntry OpcodeTable[] = …; static unsigned getConcreteOpcode(unsigned Opcode) { … } //===----------------------------------------------------------------------===// // Helper Methods //===----------------------------------------------------------------------===// // PopTable - Sorted map of instructions to their popping version. The first // element is an instruction, the second is the version which pops. // static const TableEntry PopTable[] = …; static bool doesInstructionSetFPSW(MachineInstr &MI) { … } static MachineBasicBlock::iterator getNextFPInstruction(MachineBasicBlock::iterator I) { … } /// popStackAfter - Pop the current value off of the top of the FP stack after /// the specified instruction. This attempts to be sneaky and combine the pop /// into the instruction itself if possible. The iterator is left pointing to /// the last instruction, be it a new pop instruction inserted, or the old /// instruction if it was modified in place. /// void FPS::popStackAfter(MachineBasicBlock::iterator &I) { … } /// freeStackSlotAfter - Free the specified register from the register stack, so /// that it is no longer in a register. If the register is currently at the top /// of the stack, we just pop the current instruction, otherwise we store the /// current top-of-stack into the specified slot, then pop the top of stack. void FPS::freeStackSlotAfter(MachineBasicBlock::iterator &I, unsigned FPRegNo) { … } /// freeStackSlotBefore - Free the specified register without trying any /// folding. MachineBasicBlock::iterator FPS::freeStackSlotBefore(MachineBasicBlock::iterator I, unsigned FPRegNo) { … } /// adjustLiveRegs - Kill and revive registers such that exactly the FP /// registers with a bit in Mask are live. void FPS::adjustLiveRegs(unsigned Mask, MachineBasicBlock::iterator I) { … } /// shuffleStackTop - emit fxch instructions before I to shuffle the top /// FixCount entries into the order given by FixStack. /// FIXME: Is there a better algorithm than insertion sort? void FPS::shuffleStackTop(const unsigned char *FixStack, unsigned FixCount, MachineBasicBlock::iterator I) { … } //===----------------------------------------------------------------------===// // Instruction transformation implementation //===----------------------------------------------------------------------===// void FPS::handleCall(MachineBasicBlock::iterator &I) { … } /// If RET has an FP register use operand, pass the first one in ST(0) and /// the second one in ST(1). void FPS::handleReturn(MachineBasicBlock::iterator &I) { … } /// handleZeroArgFP - ST(0) = fld0 ST(0) = flds <mem> /// void FPS::handleZeroArgFP(MachineBasicBlock::iterator &I) { … } /// handleOneArgFP - fst <mem>, ST(0) /// void FPS::handleOneArgFP(MachineBasicBlock::iterator &I) { … } /// handleOneArgFPRW: Handle instructions that read from the top of stack and /// replace the value with a newly computed value. These instructions may have /// non-fp operands after their FP operands. /// /// Examples: /// R1 = fchs R2 /// R1 = fadd R2, [mem] /// void FPS::handleOneArgFPRW(MachineBasicBlock::iterator &I) { … } //===----------------------------------------------------------------------===// // Define tables of various ways to map pseudo instructions // // ForwardST0Table - Map: A = B op C into: ST(0) = ST(0) op ST(i) static const TableEntry ForwardST0Table[] = …; // ReverseST0Table - Map: A = B op C into: ST(0) = ST(i) op ST(0) static const TableEntry ReverseST0Table[] = …; // ForwardSTiTable - Map: A = B op C into: ST(i) = ST(0) op ST(i) static const TableEntry ForwardSTiTable[] = …; // ReverseSTiTable - Map: A = B op C into: ST(i) = ST(i) op ST(0) static const TableEntry ReverseSTiTable[] = …; /// handleTwoArgFP - Handle instructions like FADD and friends which are virtual /// instructions which need to be simplified and possibly transformed. /// /// Result: ST(0) = fsub ST(0), ST(i) /// ST(i) = fsub ST(0), ST(i) /// ST(0) = fsubr ST(0), ST(i) /// ST(i) = fsubr ST(0), ST(i) /// void FPS::handleTwoArgFP(MachineBasicBlock::iterator &I) { … } /// handleCompareFP - Handle FUCOM and FUCOMI instructions, which have two FP /// register arguments and no explicit destinations. /// void FPS::handleCompareFP(MachineBasicBlock::iterator &I) { … } /// handleCondMovFP - Handle two address conditional move instructions. These /// instructions move a st(i) register to st(0) iff a condition is true. These /// instructions require that the first operand is at the top of the stack, but /// otherwise don't modify the stack at all. void FPS::handleCondMovFP(MachineBasicBlock::iterator &I) { … } /// handleSpecialFP - Handle special instructions which behave unlike other /// floating point instructions. This is primarily intended for use by pseudo /// instructions. /// void FPS::handleSpecialFP(MachineBasicBlock::iterator &Inst) { … } void FPS::setKillFlags(MachineBasicBlock &MBB) const { … }