| //===-- PTXFPRoundingModePass.cpp - Assign rounding modes pass ------------===// | |
| // | |
| // The LLVM Compiler Infrastructure | |
| // | |
| // This file is distributed under the University of Illinois Open Source | |
| // License. See LICENSE.TXT for details. | |
| // | |
| //===----------------------------------------------------------------------===// | |
| // | |
| // This file defines a machine function pass that sets appropriate FP rounding | |
| // modes for all relevant instructions. | |
| // | |
| //===----------------------------------------------------------------------===// | |
| #define DEBUG_TYPE "ptx-fp-rounding-mode" | |
| #include "PTX.h" | |
| #include "PTXTargetMachine.h" | |
| #include "llvm/ADT/DenseMap.h" | |
| #include "llvm/CodeGen/MachineFunctionPass.h" | |
| #include "llvm/CodeGen/MachineRegisterInfo.h" | |
| #include "llvm/Support/Debug.h" | |
| #include "llvm/Support/ErrorHandling.h" | |
| #include "llvm/Support/raw_ostream.h" | |
| // NOTE: PTXFPRoundingModePass should be executed just before emission. | |
| namespace llvm { | |
| /// PTXFPRoundingModePass - Pass to assign appropriate FP rounding modes to | |
| /// all FP instructions. Essentially, this pass just looks for all FP | |
| /// instructions that have a rounding mode set to RndDefault, and sets an | |
| /// appropriate rounding mode based on the target device. | |
| /// | |
| class PTXFPRoundingModePass : public MachineFunctionPass { | |
| private: | |
| static char ID; | |
| typedef std::pair<unsigned, unsigned> RndModeDesc; | |
| PTXTargetMachine& TargetMachine; | |
| DenseMap<unsigned, RndModeDesc> Instrs; | |
| public: | |
| PTXFPRoundingModePass(PTXTargetMachine &TM, CodeGenOpt::Level OptLevel) | |
| : MachineFunctionPass(ID), | |
| TargetMachine(TM) { | |
| initializeMap(); | |
| } | |
| virtual bool runOnMachineFunction(MachineFunction &MF); | |
| virtual const char *getPassName() const { | |
| return "PTX FP Rounding Mode Pass"; | |
| } | |
| private: | |
| void initializeMap(); | |
| void processInstruction(MachineInstr &MI); | |
| }; // class PTXFPRoundingModePass | |
| } // namespace llvm | |
| using namespace llvm; | |
| char PTXFPRoundingModePass::ID = 0; | |
| bool PTXFPRoundingModePass::runOnMachineFunction(MachineFunction &MF) { | |
| // Look at each basic block | |
| for (MachineFunction::iterator bbi = MF.begin(), bbe = MF.end(); bbi != bbe; | |
| ++bbi) { | |
| MachineBasicBlock &MBB = *bbi; | |
| // Look at each instruction | |
| for (MachineBasicBlock::iterator ii = MBB.begin(), ie = MBB.end(); | |
| ii != ie; ++ii) { | |
| MachineInstr &MI = *ii; | |
| processInstruction(MI); | |
| } | |
| } | |
| return false; | |
| } | |
| void PTXFPRoundingModePass::initializeMap() { | |
| using namespace PTXRoundingMode; | |
| const PTXSubtarget& ST = TargetMachine.getSubtarget<PTXSubtarget>(); | |
| // Build a map of default rounding mode for all instructions that need a | |
| // rounding mode. | |
| Instrs[PTX::FADDrr32] = std::make_pair(1U, (unsigned)RndNearestEven); | |
| Instrs[PTX::FADDri32] = std::make_pair(1U, (unsigned)RndNearestEven); | |
| Instrs[PTX::FADDrr64] = std::make_pair(1U, (unsigned)RndNearestEven); | |
| Instrs[PTX::FADDri64] = std::make_pair(1U, (unsigned)RndNearestEven); | |
| Instrs[PTX::FSUBrr32] = std::make_pair(1U, (unsigned)RndNearestEven); | |
| Instrs[PTX::FSUBri32] = std::make_pair(1U, (unsigned)RndNearestEven); | |
| Instrs[PTX::FSUBrr64] = std::make_pair(1U, (unsigned)RndNearestEven); | |
| Instrs[PTX::FSUBri64] = std::make_pair(1U, (unsigned)RndNearestEven); | |
| Instrs[PTX::FMULrr32] = std::make_pair(1U, (unsigned)RndNearestEven); | |
| Instrs[PTX::FMULri32] = std::make_pair(1U, (unsigned)RndNearestEven); | |
| Instrs[PTX::FMULrr64] = std::make_pair(1U, (unsigned)RndNearestEven); | |
| Instrs[PTX::FMULri64] = std::make_pair(1U, (unsigned)RndNearestEven); | |
| Instrs[PTX::FNEGrr32] = std::make_pair(1U, (unsigned)RndNone); | |
| Instrs[PTX::FNEGri32] = std::make_pair(1U, (unsigned)RndNone); | |
| Instrs[PTX::FNEGrr64] = std::make_pair(1U, (unsigned)RndNone); | |
| Instrs[PTX::FNEGri64] = std::make_pair(1U, (unsigned)RndNone); | |
| unsigned FDivRndMode = ST.fdivNeedsRoundingMode() ? RndNearestEven : RndNone; | |
| Instrs[PTX::FDIVrr32] = std::make_pair(1U, FDivRndMode); | |
| Instrs[PTX::FDIVri32] = std::make_pair(1U, FDivRndMode); | |
| Instrs[PTX::FDIVrr64] = std::make_pair(1U, FDivRndMode); | |
| Instrs[PTX::FDIVri64] = std::make_pair(1U, FDivRndMode); | |
| unsigned FMADRndMode = ST.fmadNeedsRoundingMode() ? RndNearestEven : RndNone; | |
| Instrs[PTX::FMADrrr32] = std::make_pair(1U, FMADRndMode); | |
| Instrs[PTX::FMADrri32] = std::make_pair(1U, FMADRndMode); | |
| Instrs[PTX::FMADrii32] = std::make_pair(1U, FMADRndMode); | |
| Instrs[PTX::FMADrrr64] = std::make_pair(1U, FMADRndMode); | |
| Instrs[PTX::FMADrri64] = std::make_pair(1U, FMADRndMode); | |
| Instrs[PTX::FMADrii64] = std::make_pair(1U, FMADRndMode); | |
| Instrs[PTX::FSQRTrr32] = std::make_pair(1U, (unsigned)RndNearestEven); | |
| Instrs[PTX::FSQRTri32] = std::make_pair(1U, (unsigned)RndNearestEven); | |
| Instrs[PTX::FSQRTrr64] = std::make_pair(1U, (unsigned)RndNearestEven); | |
| Instrs[PTX::FSQRTri64] = std::make_pair(1U, (unsigned)RndNearestEven); | |
| Instrs[PTX::FSINrr32] = std::make_pair(1U, (unsigned)RndApprox); | |
| Instrs[PTX::FSINri32] = std::make_pair(1U, (unsigned)RndApprox); | |
| Instrs[PTX::FSINrr64] = std::make_pair(1U, (unsigned)RndApprox); | |
| Instrs[PTX::FSINri64] = std::make_pair(1U, (unsigned)RndApprox); | |
| Instrs[PTX::FCOSrr32] = std::make_pair(1U, (unsigned)RndApprox); | |
| Instrs[PTX::FCOSri32] = std::make_pair(1U, (unsigned)RndApprox); | |
| Instrs[PTX::FCOSrr64] = std::make_pair(1U, (unsigned)RndApprox); | |
| Instrs[PTX::FCOSri64] = std::make_pair(1U, (unsigned)RndApprox); | |
| Instrs[PTX::CVTu16f32] = std::make_pair(1U, (unsigned)RndTowardsZeroInt); | |
| Instrs[PTX::CVTs16f32] = std::make_pair(1U, (unsigned)RndTowardsZeroInt); | |
| Instrs[PTX::CVTu16f64] = std::make_pair(1U, (unsigned)RndTowardsZeroInt); | |
| Instrs[PTX::CVTs16f64] = std::make_pair(1U, (unsigned)RndTowardsZeroInt); | |
| Instrs[PTX::CVTu32f32] = std::make_pair(1U, (unsigned)RndTowardsZeroInt); | |
| Instrs[PTX::CVTs32f32] = std::make_pair(1U, (unsigned)RndTowardsZeroInt); | |
| Instrs[PTX::CVTu32f64] = std::make_pair(1U, (unsigned)RndTowardsZeroInt); | |
| Instrs[PTX::CVTs32f64] = std::make_pair(1U, (unsigned)RndTowardsZeroInt); | |
| Instrs[PTX::CVTu64f32] = std::make_pair(1U, (unsigned)RndTowardsZeroInt); | |
| Instrs[PTX::CVTs64f32] = std::make_pair(1U, (unsigned)RndTowardsZeroInt); | |
| Instrs[PTX::CVTu64f64] = std::make_pair(1U, (unsigned)RndTowardsZeroInt); | |
| Instrs[PTX::CVTs64f64] = std::make_pair(1U, (unsigned)RndTowardsZeroInt); | |
| Instrs[PTX::CVTf32u16] = std::make_pair(1U, (unsigned)RndNearestEven); | |
| Instrs[PTX::CVTf32s16] = std::make_pair(1U, (unsigned)RndNearestEven); | |
| Instrs[PTX::CVTf32u32] = std::make_pair(1U, (unsigned)RndNearestEven); | |
| Instrs[PTX::CVTf32s32] = std::make_pair(1U, (unsigned)RndNearestEven); | |
| Instrs[PTX::CVTf32u64] = std::make_pair(1U, (unsigned)RndNearestEven); | |
| Instrs[PTX::CVTf32s64] = std::make_pair(1U, (unsigned)RndNearestEven); | |
| Instrs[PTX::CVTf32f64] = std::make_pair(1U, (unsigned)RndNearestEven); | |
| Instrs[PTX::CVTf64u16] = std::make_pair(1U, (unsigned)RndNearestEven); | |
| Instrs[PTX::CVTf64s16] = std::make_pair(1U, (unsigned)RndNearestEven); | |
| Instrs[PTX::CVTf64u32] = std::make_pair(1U, (unsigned)RndNearestEven); | |
| Instrs[PTX::CVTf64s32] = std::make_pair(1U, (unsigned)RndNearestEven); | |
| Instrs[PTX::CVTf64u64] = std::make_pair(1U, (unsigned)RndNearestEven); | |
| Instrs[PTX::CVTf64s64] = std::make_pair(1U, (unsigned)RndNearestEven); | |
| } | |
| void PTXFPRoundingModePass::processInstruction(MachineInstr &MI) { | |
| // Is this an instruction that needs a rounding mode? | |
| if (Instrs.count(MI.getOpcode())) { | |
| const RndModeDesc &Desc = Instrs[MI.getOpcode()]; | |
| // Get the rounding mode operand | |
| MachineOperand &Op = MI.getOperand(Desc.first); | |
| // Update the rounding mode if needed | |
| if (Op.getImm() == PTXRoundingMode::RndDefault) { | |
| Op.setImm(Desc.second); | |
| } | |
| } | |
| } | |
| FunctionPass *llvm::createPTXFPRoundingModePass(PTXTargetMachine &TM, | |
| CodeGenOpt::Level OptLevel) { | |
| return new PTXFPRoundingModePass(TM, OptLevel); | |
| } | |