diff options
author | Kang Zhang <shkzhang@cn.ibm.com> | 2019-03-29 08:45:24 +0000 |
---|---|---|
committer | Kang Zhang <shkzhang@cn.ibm.com> | 2019-03-29 08:45:24 +0000 |
commit | 05f78b35ae82e371bfa478d02c482c6825c5fd80 (patch) | |
tree | 636b34e45539f366eab7ccb9cf6e3c7d9cdffd14 /llvm/lib/Target/PowerPC/PPCISelLowering.cpp | |
parent | 711bea9dedd81cffa4d04dc6bb9edee933e04aaf (diff) | |
download | bcm5719-llvm-05f78b35ae82e371bfa478d02c482c6825c5fd80.tar.gz bcm5719-llvm-05f78b35ae82e371bfa478d02c482c6825c5fd80.zip |
[PowerPC] Add the support for __builtin_setrnd()
Summary:
PowerPC64/PowerPC64le supports the builtin function __builtin_setrnd to set the floating point rounding mode. This function will use the least significant two bits of integer argument to set the floating point rounding mode.
double __builtin_setrnd(int mode);
The effective values for mode are:
0 - round to nearest
1 - round to zero
2 - round to +infinity
3 - round to -infinity
Note that the mode argument will modulo 4, so if the int argument is greater than 3, it will only use the least significant two bits of the mode. Namely, builtin_setrnd(102)) is equal to builtin_setrnd(2).
Reviewed By: jsji
Differential Revision: https://reviews.llvm.org/D59405
llvm-svn: 357241
Diffstat (limited to 'llvm/lib/Target/PowerPC/PPCISelLowering.cpp')
-rw-r--r-- | llvm/lib/Target/PowerPC/PPCISelLowering.cpp | 131 |
1 files changed, 131 insertions, 0 deletions
diff --git a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp index 33f46634029..9effe3d0310 100644 --- a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp +++ b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp @@ -10949,6 +10949,137 @@ PPCTargetLowering::EmitInstrWithCustomInserter(MachineInstr &MI, unsigned CRReg = RegInfo.createVirtualRegister(&PPC::CRRCRegClass); BuildMI(*BB, MI, Dl, TII->get(PPC::TCHECK), CRReg); return BB; + } else if (MI.getOpcode() == PPC::SETRNDi) { + DebugLoc dl = MI.getDebugLoc(); + unsigned OldFPSCRReg = MI.getOperand(0).getReg(); + + // Save FPSCR value. + BuildMI(*BB, MI, dl, TII->get(PPC::MFFS), OldFPSCRReg); + + // The floating point rounding mode is in the bits 62:63 of FPCSR, and has + // the following settings: + // 00 Round to nearest + // 01 Round to 0 + // 10 Round to +inf + // 11 Round to -inf + + // When the operand is immediate, using the two least significant bits of + // the immediate to set the bits 62:63 of FPSCR. + unsigned Mode = MI.getOperand(1).getImm(); + BuildMI(*BB, MI, dl, TII->get(Mode & 1 ? PPC::MTFSB1 : PPC::MTFSB0)) + .addImm(31); + + BuildMI(*BB, MI, dl, TII->get(Mode & 2 ? PPC::MTFSB1 : PPC::MTFSB0)) + .addImm(30); + } else if (MI.getOpcode() == PPC::SETRND) { + DebugLoc dl = MI.getDebugLoc(); + + // Copy register from F8RCRegClass::SrcReg to G8RCRegClass::DestReg + // or copy register from G8RCRegClass::SrcReg to F8RCRegClass::DestReg. + // If the target doesn't have DirectMove, we should use stack to do the + // conversion, because the target doesn't have the instructions like mtvsrd + // or mfvsrd to do this conversion directly. + auto copyRegFromG8RCOrF8RC = [&] (unsigned DestReg, unsigned SrcReg) { + if (Subtarget.hasDirectMove()) { + BuildMI(*BB, MI, dl, TII->get(TargetOpcode::COPY), DestReg) + .addReg(SrcReg); + } else { + // Use stack to do the register copy. + unsigned StoreOp = PPC::STD, LoadOp = PPC::LFD; + MachineRegisterInfo &RegInfo = F->getRegInfo(); + const TargetRegisterClass *RC = RegInfo.getRegClass(SrcReg); + if (RC == &PPC::F8RCRegClass) { + // Copy register from F8RCRegClass to G8RCRegclass. + assert((RegInfo.getRegClass(DestReg) == &PPC::G8RCRegClass) && + "Unsupported RegClass."); + + StoreOp = PPC::STFD; + LoadOp = PPC::LD; + } else { + // Copy register from G8RCRegClass to F8RCRegclass. + assert((RegInfo.getRegClass(SrcReg) == &PPC::G8RCRegClass) && + (RegInfo.getRegClass(DestReg) == &PPC::F8RCRegClass) && + "Unsupported RegClass."); + } + + MachineFrameInfo &MFI = F->getFrameInfo(); + int FrameIdx = MFI.CreateStackObject(8, 8, false); + + MachineMemOperand *MMOStore = F->getMachineMemOperand( + MachinePointerInfo::getFixedStack(*F, FrameIdx, 0), + MachineMemOperand::MOStore, MFI.getObjectSize(FrameIdx), + MFI.getObjectAlignment(FrameIdx)); + + // Store the SrcReg into the stack. + BuildMI(*BB, MI, dl, TII->get(StoreOp)) + .addReg(SrcReg) + .addImm(0) + .addFrameIndex(FrameIdx) + .addMemOperand(MMOStore); + + MachineMemOperand *MMOLoad = F->getMachineMemOperand( + MachinePointerInfo::getFixedStack(*F, FrameIdx, 0), + MachineMemOperand::MOLoad, MFI.getObjectSize(FrameIdx), + MFI.getObjectAlignment(FrameIdx)); + + // Load from the stack where SrcReg is stored, and save to DestReg, + // so we have done the RegClass conversion from RegClass::SrcReg to + // RegClass::DestReg. + BuildMI(*BB, MI, dl, TII->get(LoadOp), DestReg) + .addImm(0) + .addFrameIndex(FrameIdx) + .addMemOperand(MMOLoad); + } + }; + + unsigned OldFPSCRReg = MI.getOperand(0).getReg(); + + // Save FPSCR value. + BuildMI(*BB, MI, dl, TII->get(PPC::MFFS), OldFPSCRReg); + + // When the operand is gprc register, use two least significant bits of the + // register and mtfsf instruction to set the bits 62:63 of FPSCR. + // + // copy OldFPSCRTmpReg, OldFPSCRReg + // (INSERT_SUBREG ExtSrcReg, (IMPLICIT_DEF ImDefReg), SrcOp, 1) + // rldimi NewFPSCRTmpReg, ExtSrcReg, OldFPSCRReg, 0, 62 + // copy NewFPSCRReg, NewFPSCRTmpReg + // mtfsf 255, NewFPSCRReg + MachineOperand SrcOp = MI.getOperand(1); + MachineRegisterInfo &RegInfo = F->getRegInfo(); + unsigned OldFPSCRTmpReg = RegInfo.createVirtualRegister(&PPC::G8RCRegClass); + + copyRegFromG8RCOrF8RC(OldFPSCRTmpReg, OldFPSCRReg); + + unsigned ImDefReg = RegInfo.createVirtualRegister(&PPC::G8RCRegClass); + unsigned ExtSrcReg = RegInfo.createVirtualRegister(&PPC::G8RCRegClass); + + // The first operand of INSERT_SUBREG should be a register which has + // subregisters, we only care about its RegClass, so we should use an + // IMPLICIT_DEF register. + BuildMI(*BB, MI, dl, TII->get(TargetOpcode::IMPLICIT_DEF), ImDefReg); + BuildMI(*BB, MI, dl, TII->get(PPC::INSERT_SUBREG), ExtSrcReg) + .addReg(ImDefReg) + .add(SrcOp) + .addImm(1); + + unsigned NewFPSCRTmpReg = RegInfo.createVirtualRegister(&PPC::G8RCRegClass); + BuildMI(*BB, MI, dl, TII->get(PPC::RLDIMI), NewFPSCRTmpReg) + .addReg(OldFPSCRTmpReg) + .addReg(ExtSrcReg) + .addImm(0) + .addImm(62); + + unsigned NewFPSCRReg = RegInfo.createVirtualRegister(&PPC::F8RCRegClass); + copyRegFromG8RCOrF8RC(NewFPSCRReg, NewFPSCRTmpReg); + + // The mask 255 means that put the 32:63 bits of NewFPSCRReg to the 32:63 + // bits of FPSCR. + BuildMI(*BB, MI, dl, TII->get(PPC::MTFSF)) + .addImm(255) + .addReg(NewFPSCRReg) + .addImm(0) + .addImm(0); } else { llvm_unreachable("Unexpected instr type to insert"); } |