| //===-- SystemZInstrInfo.cpp - SystemZ instruction information ------------===// | |
| // | |
| // 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 contains the SystemZ implementation of the TargetInstrInfo class. | |
| // | |
| //===----------------------------------------------------------------------===// | |
| #include "SystemZInstrInfo.h" | |
| #include "MCTargetDesc/SystemZMCTargetDesc.h" | |
| #include "SystemZ.h" | |
| #include "SystemZInstrBuilder.h" | |
| #include "SystemZSubtarget.h" | |
| #include "llvm/ADT/Statistic.h" | |
| #include "llvm/CodeGen/LiveInterval.h" | |
| #include "llvm/CodeGen/LiveIntervals.h" | |
| #include "llvm/CodeGen/LivePhysRegs.h" | |
| #include "llvm/CodeGen/LiveVariables.h" | |
| #include "llvm/CodeGen/MachineBasicBlock.h" | |
| #include "llvm/CodeGen/MachineFrameInfo.h" | |
| #include "llvm/CodeGen/MachineFunction.h" | |
| #include "llvm/CodeGen/MachineInstr.h" | |
| #include "llvm/CodeGen/MachineMemOperand.h" | |
| #include "llvm/CodeGen/MachineOperand.h" | |
| #include "llvm/CodeGen/MachineRegisterInfo.h" | |
| #include "llvm/CodeGen/SlotIndexes.h" | |
| #include "llvm/CodeGen/StackMaps.h" | |
| #include "llvm/CodeGen/TargetInstrInfo.h" | |
| #include "llvm/CodeGen/TargetSubtargetInfo.h" | |
| #include "llvm/CodeGen/VirtRegMap.h" | |
| #include "llvm/MC/MCInstrDesc.h" | |
| #include "llvm/MC/MCRegisterInfo.h" | |
| #include "llvm/Support/BranchProbability.h" | |
| #include "llvm/Support/ErrorHandling.h" | |
| #include "llvm/Support/MathExtras.h" | |
| #include "llvm/Target/TargetMachine.h" | |
| #include <cassert> | |
| #include <cstdint> | |
| #include <iterator> | |
| using namespace llvm; | |
| #define GET_INSTRINFO_CTOR_DTOR | |
| #define GET_INSTRMAP_INFO | |
| #include "SystemZGenInstrInfo.inc" | |
| #define DEBUG_TYPE "systemz-II" | |
| // Return a mask with Count low bits set. | |
| static uint64_t allOnes(unsigned int Count) { | |
| return Count == 0 ? 0 : (uint64_t(1) << (Count - 1) << 1) - 1; | |
| } | |
| // Pin the vtable to this file. | |
| void SystemZInstrInfo::anchor() {} | |
| SystemZInstrInfo::SystemZInstrInfo(SystemZSubtarget &sti) | |
| : SystemZGenInstrInfo(SystemZ::ADJCALLSTACKDOWN, SystemZ::ADJCALLSTACKUP), | |
| RI(sti.getSpecialRegisters()->getReturnFunctionAddressRegister()), | |
| STI(sti) {} | |
| // MI is a 128-bit load or store. Split it into two 64-bit loads or stores, | |
| // each having the opcode given by NewOpcode. | |
| void SystemZInstrInfo::splitMove(MachineBasicBlock::iterator MI, | |
| unsigned NewOpcode) const { | |
| MachineBasicBlock *MBB = MI->getParent(); | |
| MachineFunction &MF = *MBB->getParent(); | |
| // Get two load or store instructions. Use the original instruction for one | |
| // of them (arbitrarily the second here) and create a clone for the other. | |
| MachineInstr *EarlierMI = MF.CloneMachineInstr(&*MI); | |
| MBB->insert(MI, EarlierMI); | |
| // Set up the two 64-bit registers and remember super reg and its flags. | |
| MachineOperand &HighRegOp = EarlierMI->getOperand(0); | |
| MachineOperand &LowRegOp = MI->getOperand(0); | |
| Register Reg128 = LowRegOp.getReg(); | |
| unsigned Reg128Killed = getKillRegState(LowRegOp.isKill()); | |
| unsigned Reg128Undef = getUndefRegState(LowRegOp.isUndef()); | |
| HighRegOp.setReg(RI.getSubReg(HighRegOp.getReg(), SystemZ::subreg_h64)); | |
| LowRegOp.setReg(RI.getSubReg(LowRegOp.getReg(), SystemZ::subreg_l64)); | |
| if (MI->mayStore()) { | |
| // Add implicit uses of the super register in case one of the subregs is | |
| // undefined. We could track liveness and skip storing an undefined | |
| // subreg, but this is hopefully rare (discovered with llvm-stress). | |
| // If Reg128 was killed, set kill flag on MI. | |
| unsigned Reg128UndefImpl = (Reg128Undef | RegState::Implicit); | |
| MachineInstrBuilder(MF, EarlierMI).addReg(Reg128, Reg128UndefImpl); | |
| MachineInstrBuilder(MF, MI).addReg(Reg128, (Reg128UndefImpl | Reg128Killed)); | |
| } | |
| // The address in the first (high) instruction is already correct. | |
| // Adjust the offset in the second (low) instruction. | |
| MachineOperand &HighOffsetOp = EarlierMI->getOperand(2); | |
| MachineOperand &LowOffsetOp = MI->getOperand(2); | |
| LowOffsetOp.setImm(LowOffsetOp.getImm() + 8); | |
| // Clear the kill flags on the registers in the first instruction. | |
| if (EarlierMI->getOperand(0).isReg() && EarlierMI->getOperand(0).isUse()) | |
| EarlierMI->getOperand(0).setIsKill(false); | |
| EarlierMI->getOperand(1).setIsKill(false); | |
| EarlierMI->getOperand(3).setIsKill(false); | |
| // Set the opcodes. | |
| unsigned HighOpcode = getOpcodeForOffset(NewOpcode, HighOffsetOp.getImm()); | |
| unsigned LowOpcode = getOpcodeForOffset(NewOpcode, LowOffsetOp.getImm()); | |
| assert(HighOpcode && LowOpcode && "Both offsets should be in range"); | |
| EarlierMI->setDesc(get(HighOpcode)); | |
| MI->setDesc(get(LowOpcode)); | |
| } | |
| // Split ADJDYNALLOC instruction MI. | |
| void SystemZInstrInfo::splitAdjDynAlloc(MachineBasicBlock::iterator MI) const { | |
| MachineBasicBlock *MBB = MI->getParent(); | |
| MachineFunction &MF = *MBB->getParent(); | |
| MachineFrameInfo &MFFrame = MF.getFrameInfo(); | |
| MachineOperand &OffsetMO = MI->getOperand(2); | |
| SystemZCallingConventionRegisters *Regs = STI.getSpecialRegisters(); | |
| uint64_t Offset = (MFFrame.getMaxCallFrameSize() + | |
| Regs->getCallFrameSize() + | |
| Regs->getStackPointerBias() + | |
| OffsetMO.getImm()); | |
| unsigned NewOpcode = getOpcodeForOffset(SystemZ::LA, Offset); | |
| assert(NewOpcode && "No support for huge argument lists yet"); | |
| MI->setDesc(get(NewOpcode)); | |
| OffsetMO.setImm(Offset); | |
| } | |
| // MI is an RI-style pseudo instruction. Replace it with LowOpcode | |
| // if the first operand is a low GR32 and HighOpcode if the first operand | |
| // is a high GR32. ConvertHigh is true if LowOpcode takes a signed operand | |
| // and HighOpcode takes an unsigned 32-bit operand. In those cases, | |
| // MI has the same kind of operand as LowOpcode, so needs to be converted | |
| // if HighOpcode is used. | |
| void SystemZInstrInfo::expandRIPseudo(MachineInstr &MI, unsigned LowOpcode, | |
| unsigned HighOpcode, | |
| bool ConvertHigh) const { | |
| Register Reg = MI.getOperand(0).getReg(); | |
| bool IsHigh = SystemZ::isHighReg(Reg); | |
| MI.setDesc(get(IsHigh ? HighOpcode : LowOpcode)); | |
| if (IsHigh && ConvertHigh) | |
| MI.getOperand(1).setImm(uint32_t(MI.getOperand(1).getImm())); | |
| } | |
| // MI is a three-operand RIE-style pseudo instruction. Replace it with | |
| // LowOpcodeK if the registers are both low GR32s, otherwise use a move | |
| // followed by HighOpcode or LowOpcode, depending on whether the target | |
| // is a high or low GR32. | |
| void SystemZInstrInfo::expandRIEPseudo(MachineInstr &MI, unsigned LowOpcode, | |
| unsigned LowOpcodeK, | |
| unsigned HighOpcode) const { | |
| Register DestReg = MI.getOperand(0).getReg(); | |
| Register SrcReg = MI.getOperand(1).getReg(); | |
| bool DestIsHigh = SystemZ::isHighReg(DestReg); | |
| bool SrcIsHigh = SystemZ::isHighReg(SrcReg); | |
| if (!DestIsHigh && !SrcIsHigh) | |
| MI.setDesc(get(LowOpcodeK)); | |
| else { | |
| if (DestReg != SrcReg) { | |
| emitGRX32Move(*MI.getParent(), MI, MI.getDebugLoc(), DestReg, SrcReg, | |
| SystemZ::LR, 32, MI.getOperand(1).isKill(), | |
| MI.getOperand(1).isUndef()); | |
| MI.getOperand(1).setReg(DestReg); | |
| } | |
| MI.setDesc(get(DestIsHigh ? HighOpcode : LowOpcode)); | |
| MI.tieOperands(0, 1); | |
| } | |
| } | |
| // MI is an RXY-style pseudo instruction. Replace it with LowOpcode | |
| // if the first operand is a low GR32 and HighOpcode if the first operand | |
| // is a high GR32. | |
| void SystemZInstrInfo::expandRXYPseudo(MachineInstr &MI, unsigned LowOpcode, | |
| unsigned HighOpcode) const { | |
| Register Reg = MI.getOperand(0).getReg(); | |
| unsigned Opcode = getOpcodeForOffset( | |
| SystemZ::isHighReg(Reg) ? HighOpcode : LowOpcode, | |
| MI.getOperand(2).getImm()); | |
| MI.setDesc(get(Opcode)); | |
| } | |
| // MI is a load-on-condition pseudo instruction with a single register | |
| // (source or destination) operand. Replace it with LowOpcode if the | |
| // register is a low GR32 and HighOpcode if the register is a high GR32. | |
| void SystemZInstrInfo::expandLOCPseudo(MachineInstr &MI, unsigned LowOpcode, | |
| unsigned HighOpcode) const { | |
| Register Reg = MI.getOperand(0).getReg(); | |
| unsigned Opcode = SystemZ::isHighReg(Reg) ? HighOpcode : LowOpcode; | |
| MI.setDesc(get(Opcode)); | |
| } | |
| // MI is an RR-style pseudo instruction that zero-extends the low Size bits | |
| // of one GRX32 into another. Replace it with LowOpcode if both operands | |
| // are low registers, otherwise use RISB[LH]G. | |
| void SystemZInstrInfo::expandZExtPseudo(MachineInstr &MI, unsigned LowOpcode, | |
| unsigned Size) const { | |
| MachineInstrBuilder MIB = | |
| emitGRX32Move(*MI.getParent(), MI, MI.getDebugLoc(), | |
| MI.getOperand(0).getReg(), MI.getOperand(1).getReg(), LowOpcode, | |
| Size, MI.getOperand(1).isKill(), MI.getOperand(1).isUndef()); | |
| // Keep the remaining operands as-is. | |
| for (const MachineOperand &MO : llvm::drop_begin(MI.operands(), 2)) | |
| MIB.add(MO); | |
| MI.eraseFromParent(); | |
| } | |
| void SystemZInstrInfo::expandLoadStackGuard(MachineInstr *MI) const { | |
| MachineBasicBlock *MBB = MI->getParent(); | |
| MachineFunction &MF = *MBB->getParent(); | |
| const Register Reg64 = MI->getOperand(0).getReg(); | |
| const Register Reg32 = RI.getSubReg(Reg64, SystemZ::subreg_l32); | |
| // EAR can only load the low subregister so us a shift for %a0 to produce | |
| // the GR containing %a0 and %a1. | |
| // ear <reg>, %a0 | |
| BuildMI(*MBB, MI, MI->getDebugLoc(), get(SystemZ::EAR), Reg32) | |
| .addReg(SystemZ::A0) | |
| .addReg(Reg64, RegState::ImplicitDefine); | |
| // sllg <reg>, <reg>, 32 | |
| BuildMI(*MBB, MI, MI->getDebugLoc(), get(SystemZ::SLLG), Reg64) | |
| .addReg(Reg64) | |
| .addReg(0) | |
| .addImm(32); | |
| // ear <reg>, %a1 | |
| BuildMI(*MBB, MI, MI->getDebugLoc(), get(SystemZ::EAR), Reg32) | |
| .addReg(SystemZ::A1); | |
| // lg <reg>, 40(<reg>) | |
| MI->setDesc(get(SystemZ::LG)); | |
| MachineInstrBuilder(MF, MI).addReg(Reg64).addImm(40).addReg(0); | |
| } | |
| // Emit a zero-extending move from 32-bit GPR SrcReg to 32-bit GPR | |
| // DestReg before MBBI in MBB. Use LowLowOpcode when both DestReg and SrcReg | |
| // are low registers, otherwise use RISB[LH]G. Size is the number of bits | |
| // taken from the low end of SrcReg (8 for LLCR, 16 for LLHR and 32 for LR). | |
| // KillSrc is true if this move is the last use of SrcReg. | |
| MachineInstrBuilder | |
| SystemZInstrInfo::emitGRX32Move(MachineBasicBlock &MBB, | |
| MachineBasicBlock::iterator MBBI, | |
| const DebugLoc &DL, unsigned DestReg, | |
| unsigned SrcReg, unsigned LowLowOpcode, | |
| unsigned Size, bool KillSrc, | |
| bool UndefSrc) const { | |
| unsigned Opcode; | |
| bool DestIsHigh = SystemZ::isHighReg(DestReg); | |
| bool SrcIsHigh = SystemZ::isHighReg(SrcReg); | |
| if (DestIsHigh && SrcIsHigh) | |
| Opcode = SystemZ::RISBHH; | |
| else if (DestIsHigh && !SrcIsHigh) | |
| Opcode = SystemZ::RISBHL; | |
| else if (!DestIsHigh && SrcIsHigh) | |
| Opcode = SystemZ::RISBLH; | |
| else { | |
| return BuildMI(MBB, MBBI, DL, get(LowLowOpcode), DestReg) | |
| .addReg(SrcReg, getKillRegState(KillSrc) | getUndefRegState(UndefSrc)); | |
| } | |
| unsigned Rotate = (DestIsHigh != SrcIsHigh ? 32 : 0); | |
| return BuildMI(MBB, MBBI, DL, get(Opcode), DestReg) | |
| .addReg(DestReg, RegState::Undef) | |
| .addReg(SrcReg, getKillRegState(KillSrc) | getUndefRegState(UndefSrc)) | |
| .addImm(32 - Size).addImm(128 + 31).addImm(Rotate); | |
| } | |
| MachineInstr *SystemZInstrInfo::commuteInstructionImpl(MachineInstr &MI, | |
| bool NewMI, | |
| unsigned OpIdx1, | |
| unsigned OpIdx2) const { | |
| auto cloneIfNew = [NewMI](MachineInstr &MI) -> MachineInstr & { | |
| if (NewMI) | |
| return *MI.getParent()->getParent()->CloneMachineInstr(&MI); | |
| return MI; | |
| }; | |
| switch (MI.getOpcode()) { | |
| case SystemZ::SELRMux: | |
| case SystemZ::SELFHR: | |
| case SystemZ::SELR: | |
| case SystemZ::SELGR: | |
| case SystemZ::LOCRMux: | |
| case SystemZ::LOCFHR: | |
| case SystemZ::LOCR: | |
| case SystemZ::LOCGR: { | |
| auto &WorkingMI = cloneIfNew(MI); | |
| // Invert condition. | |
| unsigned CCValid = WorkingMI.getOperand(3).getImm(); | |
| unsigned CCMask = WorkingMI.getOperand(4).getImm(); | |
| WorkingMI.getOperand(4).setImm(CCMask ^ CCValid); | |
| return TargetInstrInfo::commuteInstructionImpl(WorkingMI, /*NewMI=*/false, | |
| OpIdx1, OpIdx2); | |
| } | |
| default: | |
| return TargetInstrInfo::commuteInstructionImpl(MI, NewMI, OpIdx1, OpIdx2); | |
| } | |
| } | |
| // If MI is a simple load or store for a frame object, return the register | |
| // it loads or stores and set FrameIndex to the index of the frame object. | |
| // Return 0 otherwise. | |
| // | |
| // Flag is SimpleBDXLoad for loads and SimpleBDXStore for stores. | |
| static int isSimpleMove(const MachineInstr &MI, int &FrameIndex, | |
| unsigned Flag) { | |
| const MCInstrDesc &MCID = MI.getDesc(); | |
| if ((MCID.TSFlags & Flag) && MI.getOperand(1).isFI() && | |
| MI.getOperand(2).getImm() == 0 && MI.getOperand(3).getReg() == 0) { | |
| FrameIndex = MI.getOperand(1).getIndex(); | |
| return MI.getOperand(0).getReg(); | |
| } | |
| return 0; | |
| } | |
| unsigned SystemZInstrInfo::isLoadFromStackSlot(const MachineInstr &MI, | |
| int &FrameIndex) const { | |
| return isSimpleMove(MI, FrameIndex, SystemZII::SimpleBDXLoad); | |
| } | |
| unsigned SystemZInstrInfo::isStoreToStackSlot(const MachineInstr &MI, | |
| int &FrameIndex) const { | |
| return isSimpleMove(MI, FrameIndex, SystemZII::SimpleBDXStore); | |
| } | |
| bool SystemZInstrInfo::isStackSlotCopy(const MachineInstr &MI, | |
| int &DestFrameIndex, | |
| int &SrcFrameIndex) const { | |
| // Check for MVC 0(Length,FI1),0(FI2) | |
| const MachineFrameInfo &MFI = MI.getParent()->getParent()->getFrameInfo(); | |
| if (MI.getOpcode() != SystemZ::MVC || !MI.getOperand(0).isFI() || | |
| MI.getOperand(1).getImm() != 0 || !MI.getOperand(3).isFI() || | |
| MI.getOperand(4).getImm() != 0) | |
| return false; | |
| // Check that Length covers the full slots. | |
| int64_t Length = MI.getOperand(2).getImm(); | |
| unsigned FI1 = MI.getOperand(0).getIndex(); | |
| unsigned FI2 = MI.getOperand(3).getIndex(); | |
| if (MFI.getObjectSize(FI1) != Length || | |
| MFI.getObjectSize(FI2) != Length) | |
| return false; | |
| DestFrameIndex = FI1; | |
| SrcFrameIndex = FI2; | |
| return true; | |
| } | |
| bool SystemZInstrInfo::analyzeBranch(MachineBasicBlock &MBB, | |
| MachineBasicBlock *&TBB, | |
| MachineBasicBlock *&FBB, | |
| SmallVectorImpl<MachineOperand> &Cond, | |
| bool AllowModify) const { | |
| // Most of the code and comments here are boilerplate. | |
| // Start from the bottom of the block and work up, examining the | |
| // terminator instructions. | |
| MachineBasicBlock::iterator I = MBB.end(); | |
| while (I != MBB.begin()) { | |
| --I; | |
| if (I->isDebugInstr()) | |
| continue; | |
| // Working from the bottom, when we see a non-terminator instruction, we're | |
| // done. | |
| if (!isUnpredicatedTerminator(*I)) | |
| break; | |
| // A terminator that isn't a branch can't easily be handled by this | |
| // analysis. | |
| if (!I->isBranch()) | |
| return true; | |
| // Can't handle indirect branches. | |
| SystemZII::Branch Branch(getBranchInfo(*I)); | |
| if (!Branch.hasMBBTarget()) | |
| return true; | |
| // Punt on compound branches. | |
| if (Branch.Type != SystemZII::BranchNormal) | |
| return true; | |
| if (Branch.CCMask == SystemZ::CCMASK_ANY) { | |
| // Handle unconditional branches. | |
| if (!AllowModify) { | |
| TBB = Branch.getMBBTarget(); | |
| continue; | |
| } | |
| // If the block has any instructions after a JMP, delete them. | |
| MBB.erase(std::next(I), MBB.end()); | |
| Cond.clear(); | |
| FBB = nullptr; | |
| // Delete the JMP if it's equivalent to a fall-through. | |
| if (MBB.isLayoutSuccessor(Branch.getMBBTarget())) { | |
| TBB = nullptr; | |
| I->eraseFromParent(); | |
| I = MBB.end(); | |
| continue; | |
| } | |
| // TBB is used to indicate the unconditinal destination. | |
| TBB = Branch.getMBBTarget(); | |
| continue; | |
| } | |
| // Working from the bottom, handle the first conditional branch. | |
| if (Cond.empty()) { | |
| // FIXME: add X86-style branch swap | |
| FBB = TBB; | |
| TBB = Branch.getMBBTarget(); | |
| Cond.push_back(MachineOperand::CreateImm(Branch.CCValid)); | |
| Cond.push_back(MachineOperand::CreateImm(Branch.CCMask)); | |
| continue; | |
| } | |
| // Handle subsequent conditional branches. | |
| assert(Cond.size() == 2 && TBB && "Should have seen a conditional branch"); | |
| // Only handle the case where all conditional branches branch to the same | |
| // destination. | |
| if (TBB != Branch.getMBBTarget()) | |
| return true; | |
| // If the conditions are the same, we can leave them alone. | |
| unsigned OldCCValid = Cond[0].getImm(); | |
| unsigned OldCCMask = Cond[1].getImm(); | |
| if (OldCCValid == Branch.CCValid && OldCCMask == Branch.CCMask) | |
| continue; | |
| // FIXME: Try combining conditions like X86 does. Should be easy on Z! | |
| return false; | |
| } | |
| return false; | |
| } | |
| unsigned SystemZInstrInfo::removeBranch(MachineBasicBlock &MBB, | |
| int *BytesRemoved) const { | |
| assert(!BytesRemoved && "code size not handled"); | |
| // Most of the code and comments here are boilerplate. | |
| MachineBasicBlock::iterator I = MBB.end(); | |
| unsigned Count = 0; | |
| while (I != MBB.begin()) { | |
| --I; | |
| if (I->isDebugInstr()) | |
| continue; | |
| if (!I->isBranch()) | |
| break; | |
| if (!getBranchInfo(*I).hasMBBTarget()) | |
| break; | |
| // Remove the branch. | |
| I->eraseFromParent(); | |
| I = MBB.end(); | |
| ++Count; | |
| } | |
| return Count; | |
| } | |
| bool SystemZInstrInfo:: | |
| reverseBranchCondition(SmallVectorImpl<MachineOperand> &Cond) const { | |
| assert(Cond.size() == 2 && "Invalid condition"); | |
| Cond[1].setImm(Cond[1].getImm() ^ Cond[0].getImm()); | |
| return false; | |
| } | |
| unsigned SystemZInstrInfo::insertBranch(MachineBasicBlock &MBB, | |
| MachineBasicBlock *TBB, | |
| MachineBasicBlock *FBB, | |
| ArrayRef<MachineOperand> Cond, | |
| const DebugLoc &DL, | |
| int *BytesAdded) const { | |
| // In this function we output 32-bit branches, which should always | |
| // have enough range. They can be shortened and relaxed by later code | |
| // in the pipeline, if desired. | |
| // Shouldn't be a fall through. | |
| assert(TBB && "insertBranch must not be told to insert a fallthrough"); | |
| assert((Cond.size() == 2 || Cond.size() == 0) && | |
| "SystemZ branch conditions have one component!"); | |
| assert(!BytesAdded && "code size not handled"); | |
| if (Cond.empty()) { | |
| // Unconditional branch? | |
| assert(!FBB && "Unconditional branch with multiple successors!"); | |
| BuildMI(&MBB, DL, get(SystemZ::J)).addMBB(TBB); | |
| return 1; | |
| } | |
| // Conditional branch. | |
| unsigned Count = 0; | |
| unsigned CCValid = Cond[0].getImm(); | |
| unsigned CCMask = Cond[1].getImm(); | |
| BuildMI(&MBB, DL, get(SystemZ::BRC)) | |
| .addImm(CCValid).addImm(CCMask).addMBB(TBB); | |
| ++Count; | |
| if (FBB) { | |
| // Two-way Conditional branch. Insert the second branch. | |
| BuildMI(&MBB, DL, get(SystemZ::J)).addMBB(FBB); | |
| ++Count; | |
| } | |
| return Count; | |
| } | |
| bool SystemZInstrInfo::analyzeCompare(const MachineInstr &MI, Register &SrcReg, | |
| Register &SrcReg2, int64_t &Mask, | |
| int64_t &Value) const { | |
| assert(MI.isCompare() && "Caller should have checked for a comparison"); | |
| if (MI.getNumExplicitOperands() == 2 && MI.getOperand(0).isReg() && | |
| MI.getOperand(1).isImm()) { | |
| SrcReg = MI.getOperand(0).getReg(); | |
| SrcReg2 = 0; | |
| Value = MI.getOperand(1).getImm(); | |
| Mask = ~0; | |
| return true; | |
| } | |
| return false; | |
| } | |
| bool SystemZInstrInfo::canInsertSelect(const MachineBasicBlock &MBB, | |
| ArrayRef<MachineOperand> Pred, | |
| Register DstReg, Register TrueReg, | |
| Register FalseReg, int &CondCycles, | |
| int &TrueCycles, | |
| int &FalseCycles) const { | |
| // Not all subtargets have LOCR instructions. | |
| if (!STI.hasLoadStoreOnCond()) | |
| return false; | |
| if (Pred.size() != 2) | |
| return false; | |
| // Check register classes. | |
| const MachineRegisterInfo &MRI = MBB.getParent()->getRegInfo(); | |
| const TargetRegisterClass *RC = | |
| RI.getCommonSubClass(MRI.getRegClass(TrueReg), MRI.getRegClass(FalseReg)); | |
| if (!RC) | |
| return false; | |
| // We have LOCR instructions for 32 and 64 bit general purpose registers. | |
| if ((STI.hasLoadStoreOnCond2() && | |
| SystemZ::GRX32BitRegClass.hasSubClassEq(RC)) || | |
| SystemZ::GR32BitRegClass.hasSubClassEq(RC) || | |
| SystemZ::GR64BitRegClass.hasSubClassEq(RC)) { | |
| CondCycles = 2; | |
| TrueCycles = 2; | |
| FalseCycles = 2; | |
| return true; | |
| } | |
| // Can't do anything else. | |
| return false; | |
| } | |
| void SystemZInstrInfo::insertSelect(MachineBasicBlock &MBB, | |
| MachineBasicBlock::iterator I, | |
| const DebugLoc &DL, Register DstReg, | |
| ArrayRef<MachineOperand> Pred, | |
| Register TrueReg, | |
| Register FalseReg) const { | |
| MachineRegisterInfo &MRI = MBB.getParent()->getRegInfo(); | |
| const TargetRegisterClass *RC = MRI.getRegClass(DstReg); | |
| assert(Pred.size() == 2 && "Invalid condition"); | |
| unsigned CCValid = Pred[0].getImm(); | |
| unsigned CCMask = Pred[1].getImm(); | |
| unsigned Opc; | |
| if (SystemZ::GRX32BitRegClass.hasSubClassEq(RC)) { | |
| if (STI.hasMiscellaneousExtensions3()) | |
| Opc = SystemZ::SELRMux; | |
| else if (STI.hasLoadStoreOnCond2()) | |
| Opc = SystemZ::LOCRMux; | |
| else { | |
| Opc = SystemZ::LOCR; | |
| MRI.constrainRegClass(DstReg, &SystemZ::GR32BitRegClass); | |
| Register TReg = MRI.createVirtualRegister(&SystemZ::GR32BitRegClass); | |
| Register FReg = MRI.createVirtualRegister(&SystemZ::GR32BitRegClass); | |
| BuildMI(MBB, I, DL, get(TargetOpcode::COPY), TReg).addReg(TrueReg); | |
| BuildMI(MBB, I, DL, get(TargetOpcode::COPY), FReg).addReg(FalseReg); | |
| TrueReg = TReg; | |
| FalseReg = FReg; | |
| } | |
| } else if (SystemZ::GR64BitRegClass.hasSubClassEq(RC)) { | |
| if (STI.hasMiscellaneousExtensions3()) | |
| Opc = SystemZ::SELGR; | |
| else | |
| Opc = SystemZ::LOCGR; | |
| } else | |
| llvm_unreachable("Invalid register class"); | |
| BuildMI(MBB, I, DL, get(Opc), DstReg) | |
| .addReg(FalseReg).addReg(TrueReg) | |
| .addImm(CCValid).addImm(CCMask); | |
| } | |
| bool SystemZInstrInfo::FoldImmediate(MachineInstr &UseMI, MachineInstr &DefMI, | |
| Register Reg, | |
| MachineRegisterInfo *MRI) const { | |
| unsigned DefOpc = DefMI.getOpcode(); | |
| if (DefOpc != SystemZ::LHIMux && DefOpc != SystemZ::LHI && | |
| DefOpc != SystemZ::LGHI) | |
| return false; | |
| if (DefMI.getOperand(0).getReg() != Reg) | |
| return false; | |
| int32_t ImmVal = (int32_t)DefMI.getOperand(1).getImm(); | |
| unsigned UseOpc = UseMI.getOpcode(); | |
| unsigned NewUseOpc; | |
| unsigned UseIdx; | |
| int CommuteIdx = -1; | |
| bool TieOps = false; | |
| switch (UseOpc) { | |
| case SystemZ::SELRMux: | |
| TieOps = true; | |
| [[fallthrough]]; | |
| case SystemZ::LOCRMux: | |
| if (!STI.hasLoadStoreOnCond2()) | |
| return false; | |
| NewUseOpc = SystemZ::LOCHIMux; | |
| if (UseMI.getOperand(2).getReg() == Reg) | |
| UseIdx = 2; | |
| else if (UseMI.getOperand(1).getReg() == Reg) | |
| UseIdx = 2, CommuteIdx = 1; | |
| else | |
| return false; | |
| break; | |
| case SystemZ::SELGR: | |
| TieOps = true; | |
| [[fallthrough]]; | |
| case SystemZ::LOCGR: | |
| if (!STI.hasLoadStoreOnCond2()) | |
| return false; | |
| NewUseOpc = SystemZ::LOCGHI; | |
| if (UseMI.getOperand(2).getReg() == Reg) | |
| UseIdx = 2; | |
| else if (UseMI.getOperand(1).getReg() == Reg) | |
| UseIdx = 2, CommuteIdx = 1; | |
| else | |
| return false; | |
| break; | |
| default: | |
| return false; | |
| } | |
| if (CommuteIdx != -1) | |
| if (!commuteInstruction(UseMI, false, CommuteIdx, UseIdx)) | |
| return false; | |
| bool DeleteDef = MRI->hasOneNonDBGUse(Reg); | |
| UseMI.setDesc(get(NewUseOpc)); | |
| if (TieOps) | |
| UseMI.tieOperands(0, 1); | |
| UseMI.getOperand(UseIdx).ChangeToImmediate(ImmVal); | |
| if (DeleteDef) | |
| DefMI.eraseFromParent(); | |
| return true; | |
| } | |
| bool SystemZInstrInfo::isPredicable(const MachineInstr &MI) const { | |
| unsigned Opcode = MI.getOpcode(); | |
| if (Opcode == SystemZ::Return || | |
| Opcode == SystemZ::Return_XPLINK || | |
| Opcode == SystemZ::Trap || | |
| Opcode == SystemZ::CallJG || | |
| Opcode == SystemZ::CallBR) | |
| return true; | |
| return false; | |
| } | |
| bool SystemZInstrInfo:: | |
| isProfitableToIfCvt(MachineBasicBlock &MBB, | |
| unsigned NumCycles, unsigned ExtraPredCycles, | |
| BranchProbability Probability) const { | |
| // Avoid using conditional returns at the end of a loop (since then | |
| // we'd need to emit an unconditional branch to the beginning anyway, | |
| // making the loop body longer). This doesn't apply for low-probability | |
| // loops (eg. compare-and-swap retry), so just decide based on branch | |
| // probability instead of looping structure. | |
| // However, since Compare and Trap instructions cost the same as a regular | |
| // Compare instruction, we should allow the if conversion to convert this | |
| // into a Conditional Compare regardless of the branch probability. | |
| if (MBB.getLastNonDebugInstr()->getOpcode() != SystemZ::Trap && | |
| MBB.succ_empty() && Probability < BranchProbability(1, 8)) | |
| return false; | |
| // For now only convert single instructions. | |
| return NumCycles == 1; | |
| } | |
| bool SystemZInstrInfo:: | |
| isProfitableToIfCvt(MachineBasicBlock &TMBB, | |
| unsigned NumCyclesT, unsigned ExtraPredCyclesT, | |
| MachineBasicBlock &FMBB, | |
| unsigned NumCyclesF, unsigned ExtraPredCyclesF, | |
| BranchProbability Probability) const { | |
| // For now avoid converting mutually-exclusive cases. | |
| return false; | |
| } | |
| bool SystemZInstrInfo:: | |
| isProfitableToDupForIfCvt(MachineBasicBlock &MBB, unsigned NumCycles, | |
| BranchProbability Probability) const { | |
| // For now only duplicate single instructions. | |
| return NumCycles == 1; | |
| } | |
| bool SystemZInstrInfo::PredicateInstruction( | |
| MachineInstr &MI, ArrayRef<MachineOperand> Pred) const { | |
| assert(Pred.size() == 2 && "Invalid condition"); | |
| unsigned CCValid = Pred[0].getImm(); | |
| unsigned CCMask = Pred[1].getImm(); | |
| assert(CCMask > 0 && CCMask < 15 && "Invalid predicate"); | |
| unsigned Opcode = MI.getOpcode(); | |
| if (Opcode == SystemZ::Trap) { | |
| MI.setDesc(get(SystemZ::CondTrap)); | |
| MachineInstrBuilder(*MI.getParent()->getParent(), MI) | |
| .addImm(CCValid).addImm(CCMask) | |
| .addReg(SystemZ::CC, RegState::Implicit); | |
| return true; | |
| } | |
| if (Opcode == SystemZ::Return || Opcode == SystemZ::Return_XPLINK) { | |
| MI.setDesc(get(Opcode == SystemZ::Return ? SystemZ::CondReturn | |
| : SystemZ::CondReturn_XPLINK)); | |
| MachineInstrBuilder(*MI.getParent()->getParent(), MI) | |
| .addImm(CCValid) | |
| .addImm(CCMask) | |
| .addReg(SystemZ::CC, RegState::Implicit); | |
| return true; | |
| } | |
| if (Opcode == SystemZ::CallJG) { | |
| MachineOperand FirstOp = MI.getOperand(0); | |
| const uint32_t *RegMask = MI.getOperand(1).getRegMask(); | |
| MI.removeOperand(1); | |
| MI.removeOperand(0); | |
| MI.setDesc(get(SystemZ::CallBRCL)); | |
| MachineInstrBuilder(*MI.getParent()->getParent(), MI) | |
| .addImm(CCValid) | |
| .addImm(CCMask) | |
| .add(FirstOp) | |
| .addRegMask(RegMask) | |
| .addReg(SystemZ::CC, RegState::Implicit); | |
| return true; | |
| } | |
| if (Opcode == SystemZ::CallBR) { | |
| MachineOperand Target = MI.getOperand(0); | |
| const uint32_t *RegMask = MI.getOperand(1).getRegMask(); | |
| MI.removeOperand(1); | |
| MI.removeOperand(0); | |
| MI.setDesc(get(SystemZ::CallBCR)); | |
| MachineInstrBuilder(*MI.getParent()->getParent(), MI) | |
| .addImm(CCValid).addImm(CCMask) | |
| .add(Target) | |
| .addRegMask(RegMask) | |
| .addReg(SystemZ::CC, RegState::Implicit); | |
| return true; | |
| } | |
| return false; | |
| } | |
| void SystemZInstrInfo::copyPhysReg(MachineBasicBlock &MBB, | |
| MachineBasicBlock::iterator MBBI, | |
| const DebugLoc &DL, MCRegister DestReg, | |
| MCRegister SrcReg, bool KillSrc) const { | |
| // Split 128-bit GPR moves into two 64-bit moves. Add implicit uses of the | |
| // super register in case one of the subregs is undefined. | |
| // This handles ADDR128 too. | |
| if (SystemZ::GR128BitRegClass.contains(DestReg, SrcReg)) { | |
| copyPhysReg(MBB, MBBI, DL, RI.getSubReg(DestReg, SystemZ::subreg_h64), | |
| RI.getSubReg(SrcReg, SystemZ::subreg_h64), KillSrc); | |
| MachineInstrBuilder(*MBB.getParent(), std::prev(MBBI)) | |
| .addReg(SrcReg, RegState::Implicit); | |
| copyPhysReg(MBB, MBBI, DL, RI.getSubReg(DestReg, SystemZ::subreg_l64), | |
| RI.getSubReg(SrcReg, SystemZ::subreg_l64), KillSrc); | |
| MachineInstrBuilder(*MBB.getParent(), std::prev(MBBI)) | |
| .addReg(SrcReg, (getKillRegState(KillSrc) | RegState::Implicit)); | |
| return; | |
| } | |
| if (SystemZ::GRX32BitRegClass.contains(DestReg, SrcReg)) { | |
| emitGRX32Move(MBB, MBBI, DL, DestReg, SrcReg, SystemZ::LR, 32, KillSrc, | |
| false); | |
| return; | |
| } | |
| // Move 128-bit floating-point values between VR128 and FP128. | |
| if (SystemZ::VR128BitRegClass.contains(DestReg) && | |
| SystemZ::FP128BitRegClass.contains(SrcReg)) { | |
| MCRegister SrcRegHi = | |
| RI.getMatchingSuperReg(RI.getSubReg(SrcReg, SystemZ::subreg_h64), | |
| SystemZ::subreg_h64, &SystemZ::VR128BitRegClass); | |
| MCRegister SrcRegLo = | |
| RI.getMatchingSuperReg(RI.getSubReg(SrcReg, SystemZ::subreg_l64), | |
| SystemZ::subreg_h64, &SystemZ::VR128BitRegClass); | |
| BuildMI(MBB, MBBI, DL, get(SystemZ::VMRHG), DestReg) | |
| .addReg(SrcRegHi, getKillRegState(KillSrc)) | |
| .addReg(SrcRegLo, getKillRegState(KillSrc)); | |
| return; | |
| } | |
| if (SystemZ::FP128BitRegClass.contains(DestReg) && | |
| SystemZ::VR128BitRegClass.contains(SrcReg)) { | |
| MCRegister DestRegHi = | |
| RI.getMatchingSuperReg(RI.getSubReg(DestReg, SystemZ::subreg_h64), | |
| SystemZ::subreg_h64, &SystemZ::VR128BitRegClass); | |
| MCRegister DestRegLo = | |
| RI.getMatchingSuperReg(RI.getSubReg(DestReg, SystemZ::subreg_l64), | |
| SystemZ::subreg_h64, &SystemZ::VR128BitRegClass); | |
| if (DestRegHi != SrcReg) | |
| copyPhysReg(MBB, MBBI, DL, DestRegHi, SrcReg, false); | |
| BuildMI(MBB, MBBI, DL, get(SystemZ::VREPG), DestRegLo) | |
| .addReg(SrcReg, getKillRegState(KillSrc)).addImm(1); | |
| return; | |
| } | |
| // Move CC value from a GR32. | |
| if (DestReg == SystemZ::CC) { | |
| unsigned Opcode = | |
| SystemZ::GR32BitRegClass.contains(SrcReg) ? SystemZ::TMLH : SystemZ::TMHH; | |
| BuildMI(MBB, MBBI, DL, get(Opcode)) | |
| .addReg(SrcReg, getKillRegState(KillSrc)) | |
| .addImm(3 << (SystemZ::IPM_CC - 16)); | |
| return; | |
| } | |
| // Everything else needs only one instruction. | |
| unsigned Opcode; | |
| if (SystemZ::GR64BitRegClass.contains(DestReg, SrcReg)) | |
| Opcode = SystemZ::LGR; | |
| else if (SystemZ::FP32BitRegClass.contains(DestReg, SrcReg)) | |
| // For z13 we prefer LDR over LER to avoid partial register dependencies. | |
| Opcode = STI.hasVector() ? SystemZ::LDR32 : SystemZ::LER; | |
| else if (SystemZ::FP64BitRegClass.contains(DestReg, SrcReg)) | |
| Opcode = SystemZ::LDR; | |
| else if (SystemZ::FP128BitRegClass.contains(DestReg, SrcReg)) | |
| Opcode = SystemZ::LXR; | |
| else if (SystemZ::VR32BitRegClass.contains(DestReg, SrcReg)) | |
| Opcode = SystemZ::VLR32; | |
| else if (SystemZ::VR64BitRegClass.contains(DestReg, SrcReg)) | |
| Opcode = SystemZ::VLR64; | |
| else if (SystemZ::VR128BitRegClass.contains(DestReg, SrcReg)) | |
| Opcode = SystemZ::VLR; | |
| else if (SystemZ::AR32BitRegClass.contains(DestReg, SrcReg)) | |
| Opcode = SystemZ::CPYA; | |
| else | |
| llvm_unreachable("Impossible reg-to-reg copy"); | |
| BuildMI(MBB, MBBI, DL, get(Opcode), DestReg) | |
| .addReg(SrcReg, getKillRegState(KillSrc)); | |
| } | |
| void SystemZInstrInfo::storeRegToStackSlot( | |
| MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, Register SrcReg, | |
| bool isKill, int FrameIdx, const TargetRegisterClass *RC, | |
| const TargetRegisterInfo *TRI, Register VReg) const { | |
| DebugLoc DL = MBBI != MBB.end() ? MBBI->getDebugLoc() : DebugLoc(); | |
| // Callers may expect a single instruction, so keep 128-bit moves | |
| // together for now and lower them after register allocation. | |
| unsigned LoadOpcode, StoreOpcode; | |
| getLoadStoreOpcodes(RC, LoadOpcode, StoreOpcode); | |
| addFrameReference(BuildMI(MBB, MBBI, DL, get(StoreOpcode)) | |
| .addReg(SrcReg, getKillRegState(isKill)), | |
| FrameIdx); | |
| } | |
| void SystemZInstrInfo::loadRegFromStackSlot(MachineBasicBlock &MBB, | |
| MachineBasicBlock::iterator MBBI, | |
| Register DestReg, int FrameIdx, | |
| const TargetRegisterClass *RC, | |
| const TargetRegisterInfo *TRI, | |
| Register VReg) const { | |
| DebugLoc DL = MBBI != MBB.end() ? MBBI->getDebugLoc() : DebugLoc(); | |
| // Callers may expect a single instruction, so keep 128-bit moves | |
| // together for now and lower them after register allocation. | |
| unsigned LoadOpcode, StoreOpcode; | |
| getLoadStoreOpcodes(RC, LoadOpcode, StoreOpcode); | |
| addFrameReference(BuildMI(MBB, MBBI, DL, get(LoadOpcode), DestReg), | |
| FrameIdx); | |
| } | |
| // Return true if MI is a simple load or store with a 12-bit displacement | |
| // and no index. Flag is SimpleBDXLoad for loads and SimpleBDXStore for stores. | |
| static bool isSimpleBD12Move(const MachineInstr *MI, unsigned Flag) { | |
| const MCInstrDesc &MCID = MI->getDesc(); | |
| return ((MCID.TSFlags & Flag) && | |
| isUInt<12>(MI->getOperand(2).getImm()) && | |
| MI->getOperand(3).getReg() == 0); | |
| } | |
| namespace { | |
| struct LogicOp { | |
| LogicOp() = default; | |
| LogicOp(unsigned regSize, unsigned immLSB, unsigned immSize) | |
| : RegSize(regSize), ImmLSB(immLSB), ImmSize(immSize) {} | |
| explicit operator bool() const { return RegSize; } | |
| unsigned RegSize = 0; | |
| unsigned ImmLSB = 0; | |
| unsigned ImmSize = 0; | |
| }; | |
| } // end anonymous namespace | |
| static LogicOp interpretAndImmediate(unsigned Opcode) { | |
| switch (Opcode) { | |
| case SystemZ::NILMux: return LogicOp(32, 0, 16); | |
| case SystemZ::NIHMux: return LogicOp(32, 16, 16); | |
| case SystemZ::NILL64: return LogicOp(64, 0, 16); | |
| case SystemZ::NILH64: return LogicOp(64, 16, 16); | |
| case SystemZ::NIHL64: return LogicOp(64, 32, 16); | |
| case SystemZ::NIHH64: return LogicOp(64, 48, 16); | |
| case SystemZ::NIFMux: return LogicOp(32, 0, 32); | |
| case SystemZ::NILF64: return LogicOp(64, 0, 32); | |
| case SystemZ::NIHF64: return LogicOp(64, 32, 32); | |
| default: return LogicOp(); | |
| } | |
| } | |
| static void transferDeadCC(MachineInstr *OldMI, MachineInstr *NewMI) { | |
| if (OldMI->registerDefIsDead(SystemZ::CC)) { | |
| MachineOperand *CCDef = NewMI->findRegisterDefOperand(SystemZ::CC); | |
| if (CCDef != nullptr) | |
| CCDef->setIsDead(true); | |
| } | |
| } | |
| static void transferMIFlag(MachineInstr *OldMI, MachineInstr *NewMI, | |
| MachineInstr::MIFlag Flag) { | |
| if (OldMI->getFlag(Flag)) | |
| NewMI->setFlag(Flag); | |
| } | |
| MachineInstr * | |
| SystemZInstrInfo::convertToThreeAddress(MachineInstr &MI, LiveVariables *LV, | |
| LiveIntervals *LIS) const { | |
| MachineBasicBlock *MBB = MI.getParent(); | |
| // Try to convert an AND into an RISBG-type instruction. | |
| // TODO: It might be beneficial to select RISBG and shorten to AND instead. | |
| if (LogicOp And = interpretAndImmediate(MI.getOpcode())) { | |
| uint64_t Imm = MI.getOperand(2).getImm() << And.ImmLSB; | |
| // AND IMMEDIATE leaves the other bits of the register unchanged. | |
| Imm |= allOnes(And.RegSize) & ~(allOnes(And.ImmSize) << And.ImmLSB); | |
| unsigned Start, End; | |
| if (isRxSBGMask(Imm, And.RegSize, Start, End)) { | |
| unsigned NewOpcode; | |
| if (And.RegSize == 64) { | |
| NewOpcode = SystemZ::RISBG; | |
| // Prefer RISBGN if available, since it does not clobber CC. | |
| if (STI.hasMiscellaneousExtensions()) | |
| NewOpcode = SystemZ::RISBGN; | |
| } else { | |
| NewOpcode = SystemZ::RISBMux; | |
| Start &= 31; | |
| End &= 31; | |
| } | |
| MachineOperand &Dest = MI.getOperand(0); | |
| MachineOperand &Src = MI.getOperand(1); | |
| MachineInstrBuilder MIB = | |
| BuildMI(*MBB, MI, MI.getDebugLoc(), get(NewOpcode)) | |
| .add(Dest) | |
| .addReg(0) | |
| .addReg(Src.getReg(), getKillRegState(Src.isKill()), | |
| Src.getSubReg()) | |
| .addImm(Start) | |
| .addImm(End + 128) | |
| .addImm(0); | |
| if (LV) { | |
| unsigned NumOps = MI.getNumOperands(); | |
| for (unsigned I = 1; I < NumOps; ++I) { | |
| MachineOperand &Op = MI.getOperand(I); | |
| if (Op.isReg() && Op.isKill()) | |
| LV->replaceKillInstruction(Op.getReg(), MI, *MIB); | |
| } | |
| } | |
| if (LIS) | |
| LIS->ReplaceMachineInstrInMaps(MI, *MIB); | |
| transferDeadCC(&MI, MIB); | |
| return MIB; | |
| } | |
| } | |
| return nullptr; | |
| } | |
| MachineInstr *SystemZInstrInfo::foldMemoryOperandImpl( | |
| MachineFunction &MF, MachineInstr &MI, ArrayRef<unsigned> Ops, | |
| MachineBasicBlock::iterator InsertPt, int FrameIndex, | |
| LiveIntervals *LIS, VirtRegMap *VRM) const { | |
| const TargetRegisterInfo *TRI = MF.getSubtarget().getRegisterInfo(); | |
| MachineRegisterInfo &MRI = MF.getRegInfo(); | |
| const MachineFrameInfo &MFI = MF.getFrameInfo(); | |
| unsigned Size = MFI.getObjectSize(FrameIndex); | |
| unsigned Opcode = MI.getOpcode(); | |
| // Check CC liveness if new instruction introduces a dead def of CC. | |
| MCRegUnitIterator CCUnit(MCRegister::from(SystemZ::CC), TRI); | |
| SlotIndex MISlot = SlotIndex(); | |
| LiveRange *CCLiveRange = nullptr; | |
| bool CCLiveAtMI = true; | |
| if (LIS) { | |
| MISlot = LIS->getSlotIndexes()->getInstructionIndex(MI).getRegSlot(); | |
| CCLiveRange = &LIS->getRegUnit(*CCUnit); | |
| CCLiveAtMI = CCLiveRange->liveAt(MISlot); | |
| } | |
| ++CCUnit; | |
| assert(!CCUnit.isValid() && "CC only has one reg unit."); | |
| if (Ops.size() == 2 && Ops[0] == 0 && Ops[1] == 1) { | |
| if (!CCLiveAtMI && (Opcode == SystemZ::LA || Opcode == SystemZ::LAY) && | |
| isInt<8>(MI.getOperand(2).getImm()) && !MI.getOperand(3).getReg()) { | |
| // LA(Y) %reg, CONST(%reg) -> AGSI %mem, CONST | |
| MachineInstr *BuiltMI = BuildMI(*InsertPt->getParent(), InsertPt, | |
| MI.getDebugLoc(), get(SystemZ::AGSI)) | |
| .addFrameIndex(FrameIndex) | |
| .addImm(0) | |
| .addImm(MI.getOperand(2).getImm()); | |
| BuiltMI->findRegisterDefOperand(SystemZ::CC)->setIsDead(true); | |
| CCLiveRange->createDeadDef(MISlot, LIS->getVNInfoAllocator()); | |
| return BuiltMI; | |
| } | |
| return nullptr; | |
| } | |
| // All other cases require a single operand. | |
| if (Ops.size() != 1) | |
| return nullptr; | |
| unsigned OpNum = Ops[0]; | |
| assert(Size * 8 == | |
| TRI->getRegSizeInBits(*MF.getRegInfo() | |
| .getRegClass(MI.getOperand(OpNum).getReg())) && | |
| "Invalid size combination"); | |
| if ((Opcode == SystemZ::AHI || Opcode == SystemZ::AGHI) && OpNum == 0 && | |
| isInt<8>(MI.getOperand(2).getImm())) { | |
| // A(G)HI %reg, CONST -> A(G)SI %mem, CONST | |
| Opcode = (Opcode == SystemZ::AHI ? SystemZ::ASI : SystemZ::AGSI); | |
| MachineInstr *BuiltMI = | |
| BuildMI(*InsertPt->getParent(), InsertPt, MI.getDebugLoc(), get(Opcode)) | |
| .addFrameIndex(FrameIndex) | |
| .addImm(0) | |
| .addImm(MI.getOperand(2).getImm()); | |
| transferDeadCC(&MI, BuiltMI); | |
| transferMIFlag(&MI, BuiltMI, MachineInstr::NoSWrap); | |
| return BuiltMI; | |
| } | |
| if ((Opcode == SystemZ::ALFI && OpNum == 0 && | |
| isInt<8>((int32_t)MI.getOperand(2).getImm())) || | |
| (Opcode == SystemZ::ALGFI && OpNum == 0 && | |
| isInt<8>((int64_t)MI.getOperand(2).getImm()))) { | |
| // AL(G)FI %reg, CONST -> AL(G)SI %mem, CONST | |
| Opcode = (Opcode == SystemZ::ALFI ? SystemZ::ALSI : SystemZ::ALGSI); | |
| MachineInstr *BuiltMI = | |
| BuildMI(*InsertPt->getParent(), InsertPt, MI.getDebugLoc(), get(Opcode)) | |
| .addFrameIndex(FrameIndex) | |
| .addImm(0) | |
| .addImm((int8_t)MI.getOperand(2).getImm()); | |
| transferDeadCC(&MI, BuiltMI); | |
| return BuiltMI; | |
| } | |
| if ((Opcode == SystemZ::SLFI && OpNum == 0 && | |
| isInt<8>((int32_t)-MI.getOperand(2).getImm())) || | |
| (Opcode == SystemZ::SLGFI && OpNum == 0 && | |
| isInt<8>((int64_t)-MI.getOperand(2).getImm()))) { | |
| // SL(G)FI %reg, CONST -> AL(G)SI %mem, -CONST | |
| Opcode = (Opcode == SystemZ::SLFI ? SystemZ::ALSI : SystemZ::ALGSI); | |
| MachineInstr *BuiltMI = | |
| BuildMI(*InsertPt->getParent(), InsertPt, MI.getDebugLoc(), get(Opcode)) | |
| .addFrameIndex(FrameIndex) | |
| .addImm(0) | |
| .addImm((int8_t)-MI.getOperand(2).getImm()); | |
| transferDeadCC(&MI, BuiltMI); | |
| return BuiltMI; | |
| } | |
| unsigned MemImmOpc = 0; | |
| switch (Opcode) { | |
| case SystemZ::LHIMux: | |
| case SystemZ::LHI: MemImmOpc = SystemZ::MVHI; break; | |
| case SystemZ::LGHI: MemImmOpc = SystemZ::MVGHI; break; | |
| case SystemZ::CHIMux: | |
| case SystemZ::CHI: MemImmOpc = SystemZ::CHSI; break; | |
| case SystemZ::CGHI: MemImmOpc = SystemZ::CGHSI; break; | |
| case SystemZ::CLFIMux: | |
| case SystemZ::CLFI: | |
| if (isUInt<16>(MI.getOperand(1).getImm())) | |
| MemImmOpc = SystemZ::CLFHSI; | |
| break; | |
| case SystemZ::CLGFI: | |
| if (isUInt<16>(MI.getOperand(1).getImm())) | |
| MemImmOpc = SystemZ::CLGHSI; | |
| break; | |
| default: break; | |
| } | |
| if (MemImmOpc) | |
| return BuildMI(*InsertPt->getParent(), InsertPt, MI.getDebugLoc(), | |
| get(MemImmOpc)) | |
| .addFrameIndex(FrameIndex) | |
| .addImm(0) | |
| .addImm(MI.getOperand(1).getImm()); | |
| if (Opcode == SystemZ::LGDR || Opcode == SystemZ::LDGR) { | |
| bool Op0IsGPR = (Opcode == SystemZ::LGDR); | |
| bool Op1IsGPR = (Opcode == SystemZ::LDGR); | |
| // If we're spilling the destination of an LDGR or LGDR, store the | |
| // source register instead. | |
| if (OpNum == 0) { | |
| unsigned StoreOpcode = Op1IsGPR ? SystemZ::STG : SystemZ::STD; | |
| return BuildMI(*InsertPt->getParent(), InsertPt, MI.getDebugLoc(), | |
| get(StoreOpcode)) | |
| .add(MI.getOperand(1)) | |
| .addFrameIndex(FrameIndex) | |
| .addImm(0) | |
| .addReg(0); | |
| } | |
| // If we're spilling the source of an LDGR or LGDR, load the | |
| // destination register instead. | |
| if (OpNum == 1) { | |
| unsigned LoadOpcode = Op0IsGPR ? SystemZ::LG : SystemZ::LD; | |
| return BuildMI(*InsertPt->getParent(), InsertPt, MI.getDebugLoc(), | |
| get(LoadOpcode)) | |
| .add(MI.getOperand(0)) | |
| .addFrameIndex(FrameIndex) | |
| .addImm(0) | |
| .addReg(0); | |
| } | |
| } | |
| // Look for cases where the source of a simple store or the destination | |
| // of a simple load is being spilled. Try to use MVC instead. | |
| // | |
| // Although MVC is in practice a fast choice in these cases, it is still | |
| // logically a bytewise copy. This means that we cannot use it if the | |
| // load or store is volatile. We also wouldn't be able to use MVC if | |
| // the two memories partially overlap, but that case cannot occur here, | |
| // because we know that one of the memories is a full frame index. | |
| // | |
| // For performance reasons, we also want to avoid using MVC if the addresses | |
| // might be equal. We don't worry about that case here, because spill slot | |
| // coloring happens later, and because we have special code to remove | |
| // MVCs that turn out to be redundant. | |
| if (OpNum == 0 && MI.hasOneMemOperand()) { | |
| MachineMemOperand *MMO = *MI.memoperands_begin(); | |
| if (MMO->getSize() == Size && !MMO->isVolatile() && !MMO->isAtomic()) { | |
| // Handle conversion of loads. | |
| if (isSimpleBD12Move(&MI, SystemZII::SimpleBDXLoad)) { | |
| return BuildMI(*InsertPt->getParent(), InsertPt, MI.getDebugLoc(), | |
| get(SystemZ::MVC)) | |
| .addFrameIndex(FrameIndex) | |
| .addImm(0) | |
| .addImm(Size) | |
| .add(MI.getOperand(1)) | |
| .addImm(MI.getOperand(2).getImm()) | |
| .addMemOperand(MMO); | |
| } | |
| // Handle conversion of stores. | |
| if (isSimpleBD12Move(&MI, SystemZII::SimpleBDXStore)) { | |
| return BuildMI(*InsertPt->getParent(), InsertPt, MI.getDebugLoc(), | |
| get(SystemZ::MVC)) | |
| .add(MI.getOperand(1)) | |
| .addImm(MI.getOperand(2).getImm()) | |
| .addImm(Size) | |
| .addFrameIndex(FrameIndex) | |
| .addImm(0) | |
| .addMemOperand(MMO); | |
| } | |
| } | |
| } | |
| // If the spilled operand is the final one or the instruction is | |
| // commutable, try to change <INSN>R into <INSN>. Don't introduce a def of | |
| // CC if it is live and MI does not define it. | |
| unsigned NumOps = MI.getNumExplicitOperands(); | |
| int MemOpcode = SystemZ::getMemOpcode(Opcode); | |
| if (MemOpcode == -1 || | |
| (CCLiveAtMI && !MI.definesRegister(SystemZ::CC) && | |
| get(MemOpcode).hasImplicitDefOfPhysReg(SystemZ::CC))) | |
| return nullptr; | |
| // Check if all other vregs have a usable allocation in the case of vector | |
| // to FP conversion. | |
| const MCInstrDesc &MCID = MI.getDesc(); | |
| for (unsigned I = 0, E = MCID.getNumOperands(); I != E; ++I) { | |
| const MCOperandInfo &MCOI = MCID.operands()[I]; | |
| if (MCOI.OperandType != MCOI::OPERAND_REGISTER || I == OpNum) | |
| continue; | |
| const TargetRegisterClass *RC = TRI->getRegClass(MCOI.RegClass); | |
| if (RC == &SystemZ::VR32BitRegClass || RC == &SystemZ::VR64BitRegClass) { | |
| Register Reg = MI.getOperand(I).getReg(); | |
| Register PhysReg = Reg.isVirtual() | |
| ? (VRM ? Register(VRM->getPhys(Reg)) : Register()) | |
| : Reg; | |
| if (!PhysReg || | |
| !(SystemZ::FP32BitRegClass.contains(PhysReg) || | |
| SystemZ::FP64BitRegClass.contains(PhysReg) || | |
| SystemZ::VF128BitRegClass.contains(PhysReg))) | |
| return nullptr; | |
| } | |
| } | |
| // Fused multiply and add/sub need to have the same dst and accumulator reg. | |
| bool FusedFPOp = (Opcode == SystemZ::WFMADB || Opcode == SystemZ::WFMASB || | |
| Opcode == SystemZ::WFMSDB || Opcode == SystemZ::WFMSSB); | |
| if (FusedFPOp) { | |
| Register DstReg = VRM->getPhys(MI.getOperand(0).getReg()); | |
| Register AccReg = VRM->getPhys(MI.getOperand(3).getReg()); | |
| if (OpNum == 0 || OpNum == 3 || DstReg != AccReg) | |
| return nullptr; | |
| } | |
| // Try to swap compare operands if possible. | |
| bool NeedsCommute = false; | |
| if ((MI.getOpcode() == SystemZ::CR || MI.getOpcode() == SystemZ::CGR || | |
| MI.getOpcode() == SystemZ::CLR || MI.getOpcode() == SystemZ::CLGR || | |
| MI.getOpcode() == SystemZ::WFCDB || MI.getOpcode() == SystemZ::WFCSB || | |
| MI.getOpcode() == SystemZ::WFKDB || MI.getOpcode() == SystemZ::WFKSB) && | |
| OpNum == 0 && prepareCompareSwapOperands(MI)) | |
| NeedsCommute = true; | |
| bool CCOperands = false; | |
| if (MI.getOpcode() == SystemZ::LOCRMux || MI.getOpcode() == SystemZ::LOCGR || | |
| MI.getOpcode() == SystemZ::SELRMux || MI.getOpcode() == SystemZ::SELGR) { | |
| assert(MI.getNumOperands() == 6 && NumOps == 5 && | |
| "LOCR/SELR instruction operands corrupt?"); | |
| NumOps -= 2; | |
| CCOperands = true; | |
| } | |
| // See if this is a 3-address instruction that is convertible to 2-address | |
| // and suitable for folding below. Only try this with virtual registers | |
| // and a provided VRM (during regalloc). | |
| if (NumOps == 3 && SystemZ::getTargetMemOpcode(MemOpcode) != -1) { | |
| if (VRM == nullptr) | |
| return nullptr; | |
| else { | |
| Register DstReg = MI.getOperand(0).getReg(); | |
| Register DstPhys = | |
| (DstReg.isVirtual() ? Register(VRM->getPhys(DstReg)) : DstReg); | |
| Register SrcReg = (OpNum == 2 ? MI.getOperand(1).getReg() | |
| : ((OpNum == 1 && MI.isCommutable()) | |
| ? MI.getOperand(2).getReg() | |
| : Register())); | |
| if (DstPhys && !SystemZ::GRH32BitRegClass.contains(DstPhys) && SrcReg && | |
| SrcReg.isVirtual() && DstPhys == VRM->getPhys(SrcReg)) | |
| NeedsCommute = (OpNum == 1); | |
| else | |
| return nullptr; | |
| } | |
| } | |
| if ((OpNum == NumOps - 1) || NeedsCommute || FusedFPOp) { | |
| const MCInstrDesc &MemDesc = get(MemOpcode); | |
| uint64_t AccessBytes = SystemZII::getAccessSize(MemDesc.TSFlags); | |
| assert(AccessBytes != 0 && "Size of access should be known"); | |
| assert(AccessBytes <= Size && "Access outside the frame index"); | |
| uint64_t Offset = Size - AccessBytes; | |
| MachineInstrBuilder MIB = BuildMI(*InsertPt->getParent(), InsertPt, | |
| MI.getDebugLoc(), get(MemOpcode)); | |
| if (MI.isCompare()) { | |
| assert(NumOps == 2 && "Expected 2 register operands for a compare."); | |
| MIB.add(MI.getOperand(NeedsCommute ? 1 : 0)); | |
| } | |
| else if (FusedFPOp) { | |
| MIB.add(MI.getOperand(0)); | |
| MIB.add(MI.getOperand(3)); | |
| MIB.add(MI.getOperand(OpNum == 1 ? 2 : 1)); | |
| } | |
| else { | |
| MIB.add(MI.getOperand(0)); | |
| if (NeedsCommute) | |
| MIB.add(MI.getOperand(2)); | |
| else | |
| for (unsigned I = 1; I < OpNum; ++I) | |
| MIB.add(MI.getOperand(I)); | |
| } | |
| MIB.addFrameIndex(FrameIndex).addImm(Offset); | |
| if (MemDesc.TSFlags & SystemZII::HasIndex) | |
| MIB.addReg(0); | |
| if (CCOperands) { | |
| unsigned CCValid = MI.getOperand(NumOps).getImm(); | |
| unsigned CCMask = MI.getOperand(NumOps + 1).getImm(); | |
| MIB.addImm(CCValid); | |
| MIB.addImm(NeedsCommute ? CCMask ^ CCValid : CCMask); | |
| } | |
| if (MIB->definesRegister(SystemZ::CC) && | |
| (!MI.definesRegister(SystemZ::CC) || | |
| MI.registerDefIsDead(SystemZ::CC))) { | |
| MIB->addRegisterDead(SystemZ::CC, TRI); | |
| if (CCLiveRange) | |
| CCLiveRange->createDeadDef(MISlot, LIS->getVNInfoAllocator()); | |
| } | |
| // Constrain the register classes if converted from a vector opcode. The | |
| // allocated regs are in an FP reg-class per previous check above. | |
| for (const MachineOperand &MO : MIB->operands()) | |
| if (MO.isReg() && MO.getReg().isVirtual()) { | |
| Register Reg = MO.getReg(); | |
| if (MRI.getRegClass(Reg) == &SystemZ::VR32BitRegClass) | |
| MRI.setRegClass(Reg, &SystemZ::FP32BitRegClass); | |
| else if (MRI.getRegClass(Reg) == &SystemZ::VR64BitRegClass) | |
| MRI.setRegClass(Reg, &SystemZ::FP64BitRegClass); | |
| else if (MRI.getRegClass(Reg) == &SystemZ::VR128BitRegClass) | |
| MRI.setRegClass(Reg, &SystemZ::VF128BitRegClass); | |
| } | |
| transferDeadCC(&MI, MIB); | |
| transferMIFlag(&MI, MIB, MachineInstr::NoSWrap); | |
| transferMIFlag(&MI, MIB, MachineInstr::NoFPExcept); | |
| return MIB; | |
| } | |
| return nullptr; | |
| } | |
| MachineInstr *SystemZInstrInfo::foldMemoryOperandImpl( | |
| MachineFunction &MF, MachineInstr &MI, ArrayRef<unsigned> Ops, | |
| MachineBasicBlock::iterator InsertPt, MachineInstr &LoadMI, | |
| LiveIntervals *LIS) const { | |
| return nullptr; | |
| } | |
| bool SystemZInstrInfo::expandPostRAPseudo(MachineInstr &MI) const { | |
| switch (MI.getOpcode()) { | |
| case SystemZ::L128: | |
| splitMove(MI, SystemZ::LG); | |
| return true; | |
| case SystemZ::ST128: | |
| splitMove(MI, SystemZ::STG); | |
| return true; | |
| case SystemZ::LX: | |
| splitMove(MI, SystemZ::LD); | |
| return true; | |
| case SystemZ::STX: | |
| splitMove(MI, SystemZ::STD); | |
| return true; | |
| case SystemZ::LBMux: | |
| expandRXYPseudo(MI, SystemZ::LB, SystemZ::LBH); | |
| return true; | |
| case SystemZ::LHMux: | |
| expandRXYPseudo(MI, SystemZ::LH, SystemZ::LHH); | |
| return true; | |
| case SystemZ::LLCRMux: | |
| expandZExtPseudo(MI, SystemZ::LLCR, 8); | |
| return true; | |
| case SystemZ::LLHRMux: | |
| expandZExtPseudo(MI, SystemZ::LLHR, 16); | |
| return true; | |
| case SystemZ::LLCMux: | |
| expandRXYPseudo(MI, SystemZ::LLC, SystemZ::LLCH); | |
| return true; | |
| case SystemZ::LLHMux: | |
| expandRXYPseudo(MI, SystemZ::LLH, SystemZ::LLHH); | |
| return true; | |
| case SystemZ::LMux: | |
| expandRXYPseudo(MI, SystemZ::L, SystemZ::LFH); | |
| return true; | |
| case SystemZ::LOCMux: | |
| expandLOCPseudo(MI, SystemZ::LOC, SystemZ::LOCFH); | |
| return true; | |
| case SystemZ::LOCHIMux: | |
| expandLOCPseudo(MI, SystemZ::LOCHI, SystemZ::LOCHHI); | |
| return true; | |
| case SystemZ::STCMux: | |
| expandRXYPseudo(MI, SystemZ::STC, SystemZ::STCH); | |
| return true; | |
| case SystemZ::STHMux: | |
| expandRXYPseudo(MI, SystemZ::STH, SystemZ::STHH); | |
| return true; | |
| case SystemZ::STMux: | |
| expandRXYPseudo(MI, SystemZ::ST, SystemZ::STFH); | |
| return true; | |
| case SystemZ::STOCMux: | |
| expandLOCPseudo(MI, SystemZ::STOC, SystemZ::STOCFH); | |
| return true; | |
| case SystemZ::LHIMux: | |
| expandRIPseudo(MI, SystemZ::LHI, SystemZ::IIHF, true); | |
| return true; | |
| case SystemZ::IIFMux: | |
| expandRIPseudo(MI, SystemZ::IILF, SystemZ::IIHF, false); | |
| return true; | |
| case SystemZ::IILMux: | |
| expandRIPseudo(MI, SystemZ::IILL, SystemZ::IIHL, false); | |
| return true; | |
| case SystemZ::IIHMux: | |
| expandRIPseudo(MI, SystemZ::IILH, SystemZ::IIHH, false); | |
| return true; | |
| case SystemZ::NIFMux: | |
| expandRIPseudo(MI, SystemZ::NILF, SystemZ::NIHF, false); | |
| return true; | |
| case SystemZ::NILMux: | |
| expandRIPseudo(MI, SystemZ::NILL, SystemZ::NIHL, false); | |
| return true; | |
| case SystemZ::NIHMux: | |
| expandRIPseudo(MI, SystemZ::NILH, SystemZ::NIHH, false); | |
| return true; | |
| case SystemZ::OIFMux: | |
| expandRIPseudo(MI, SystemZ::OILF, SystemZ::OIHF, false); | |
| return true; | |
| case SystemZ::OILMux: | |
| expandRIPseudo(MI, SystemZ::OILL, SystemZ::OIHL, false); | |
| return true; | |
| case SystemZ::OIHMux: | |
| expandRIPseudo(MI, SystemZ::OILH, SystemZ::OIHH, false); | |
| return true; | |
| case SystemZ::XIFMux: | |
| expandRIPseudo(MI, SystemZ::XILF, SystemZ::XIHF, false); | |
| return true; | |
| case SystemZ::TMLMux: | |
| expandRIPseudo(MI, SystemZ::TMLL, SystemZ::TMHL, false); | |
| return true; | |
| case SystemZ::TMHMux: | |
| expandRIPseudo(MI, SystemZ::TMLH, SystemZ::TMHH, false); | |
| return true; | |
| case SystemZ::AHIMux: | |
| expandRIPseudo(MI, SystemZ::AHI, SystemZ::AIH, false); | |
| return true; | |
| case SystemZ::AHIMuxK: | |
| expandRIEPseudo(MI, SystemZ::AHI, SystemZ::AHIK, SystemZ::AIH); | |
| return true; | |
| case SystemZ::AFIMux: | |
| expandRIPseudo(MI, SystemZ::AFI, SystemZ::AIH, false); | |
| return true; | |
| case SystemZ::CHIMux: | |
| expandRIPseudo(MI, SystemZ::CHI, SystemZ::CIH, false); | |
| return true; | |
| case SystemZ::CFIMux: | |
| expandRIPseudo(MI, SystemZ::CFI, SystemZ::CIH, false); | |
| return true; | |
| case SystemZ::CLFIMux: | |
| expandRIPseudo(MI, SystemZ::CLFI, SystemZ::CLIH, false); | |
| return true; | |
| case SystemZ::CMux: | |
| expandRXYPseudo(MI, SystemZ::C, SystemZ::CHF); | |
| return true; | |
| case SystemZ::CLMux: | |
| expandRXYPseudo(MI, SystemZ::CL, SystemZ::CLHF); | |
| return true; | |
| case SystemZ::RISBMux: { | |
| bool DestIsHigh = SystemZ::isHighReg(MI.getOperand(0).getReg()); | |
| bool SrcIsHigh = SystemZ::isHighReg(MI.getOperand(2).getReg()); | |
| if (SrcIsHigh == DestIsHigh) | |
| MI.setDesc(get(DestIsHigh ? SystemZ::RISBHH : SystemZ::RISBLL)); | |
| else { | |
| MI.setDesc(get(DestIsHigh ? SystemZ::RISBHL : SystemZ::RISBLH)); | |
| MI.getOperand(5).setImm(MI.getOperand(5).getImm() ^ 32); | |
| } | |
| return true; | |
| } | |
| case SystemZ::ADJDYNALLOC: | |
| splitAdjDynAlloc(MI); | |
| return true; | |
| case TargetOpcode::LOAD_STACK_GUARD: | |
| expandLoadStackGuard(&MI); | |
| return true; | |
| default: | |
| return false; | |
| } | |
| } | |
| unsigned SystemZInstrInfo::getInstSizeInBytes(const MachineInstr &MI) const { | |
| if (MI.isInlineAsm()) { | |
| const MachineFunction *MF = MI.getParent()->getParent(); | |
| const char *AsmStr = MI.getOperand(0).getSymbolName(); | |
| return getInlineAsmLength(AsmStr, *MF->getTarget().getMCAsmInfo()); | |
| } | |
| else if (MI.getOpcode() == SystemZ::PATCHPOINT) | |
| return PatchPointOpers(&MI).getNumPatchBytes(); | |
| else if (MI.getOpcode() == SystemZ::STACKMAP) | |
| return MI.getOperand(1).getImm(); | |
| else if (MI.getOpcode() == SystemZ::FENTRY_CALL) | |
| return 6; | |
| return MI.getDesc().getSize(); | |
| } | |
| SystemZII::Branch | |
| SystemZInstrInfo::getBranchInfo(const MachineInstr &MI) const { | |
| switch (MI.getOpcode()) { | |
| case SystemZ::BR: | |
| case SystemZ::BI: | |
| case SystemZ::J: | |
| case SystemZ::JG: | |
| return SystemZII::Branch(SystemZII::BranchNormal, SystemZ::CCMASK_ANY, | |
| SystemZ::CCMASK_ANY, &MI.getOperand(0)); | |
| case SystemZ::BRC: | |
| case SystemZ::BRCL: | |
| return SystemZII::Branch(SystemZII::BranchNormal, MI.getOperand(0).getImm(), | |
| MI.getOperand(1).getImm(), &MI.getOperand(2)); | |
| case SystemZ::BRCT: | |
| case SystemZ::BRCTH: | |
| return SystemZII::Branch(SystemZII::BranchCT, SystemZ::CCMASK_ICMP, | |
| SystemZ::CCMASK_CMP_NE, &MI.getOperand(2)); | |
| case SystemZ::BRCTG: | |
| return SystemZII::Branch(SystemZII::BranchCTG, SystemZ::CCMASK_ICMP, | |
| SystemZ::CCMASK_CMP_NE, &MI.getOperand(2)); | |
| case SystemZ::CIJ: | |
| case SystemZ::CRJ: | |
| return SystemZII::Branch(SystemZII::BranchC, SystemZ::CCMASK_ICMP, | |
| MI.getOperand(2).getImm(), &MI.getOperand(3)); | |
| case SystemZ::CLIJ: | |
| case SystemZ::CLRJ: | |
| return SystemZII::Branch(SystemZII::BranchCL, SystemZ::CCMASK_ICMP, | |
| MI.getOperand(2).getImm(), &MI.getOperand(3)); | |
| case SystemZ::CGIJ: | |
| case SystemZ::CGRJ: | |
| return SystemZII::Branch(SystemZII::BranchCG, SystemZ::CCMASK_ICMP, | |
| MI.getOperand(2).getImm(), &MI.getOperand(3)); | |
| case SystemZ::CLGIJ: | |
| case SystemZ::CLGRJ: | |
| return SystemZII::Branch(SystemZII::BranchCLG, SystemZ::CCMASK_ICMP, | |
| MI.getOperand(2).getImm(), &MI.getOperand(3)); | |
| case SystemZ::INLINEASM_BR: | |
| // Don't try to analyze asm goto, so pass nullptr as branch target argument. | |
| return SystemZII::Branch(SystemZII::AsmGoto, 0, 0, nullptr); | |
| default: | |
| llvm_unreachable("Unrecognized branch opcode"); | |
| } | |
| } | |
| void SystemZInstrInfo::getLoadStoreOpcodes(const TargetRegisterClass *RC, | |
| unsigned &LoadOpcode, | |
| unsigned &StoreOpcode) const { | |
| if (RC == &SystemZ::GR32BitRegClass || RC == &SystemZ::ADDR32BitRegClass) { | |
| LoadOpcode = SystemZ::L; | |
| StoreOpcode = SystemZ::ST; | |
| } else if (RC == &SystemZ::GRH32BitRegClass) { | |
| LoadOpcode = SystemZ::LFH; | |
| StoreOpcode = SystemZ::STFH; | |
| } else if (RC == &SystemZ::GRX32BitRegClass) { | |
| LoadOpcode = SystemZ::LMux; | |
| StoreOpcode = SystemZ::STMux; | |
| } else if (RC == &SystemZ::GR64BitRegClass || | |
| RC == &SystemZ::ADDR64BitRegClass) { | |
| LoadOpcode = SystemZ::LG; | |
| StoreOpcode = SystemZ::STG; | |
| } else if (RC == &SystemZ::GR128BitRegClass || | |
| RC == &SystemZ::ADDR128BitRegClass) { | |
| LoadOpcode = SystemZ::L128; | |
| StoreOpcode = SystemZ::ST128; | |
| } else if (RC == &SystemZ::FP32BitRegClass) { | |
| LoadOpcode = SystemZ::LE; | |
| StoreOpcode = SystemZ::STE; | |
| } else if (RC == &SystemZ::FP64BitRegClass) { | |
| LoadOpcode = SystemZ::LD; | |
| StoreOpcode = SystemZ::STD; | |
| } else if (RC == &SystemZ::FP128BitRegClass) { | |
| LoadOpcode = SystemZ::LX; | |
| StoreOpcode = SystemZ::STX; | |
| } else if (RC == &SystemZ::VR32BitRegClass) { | |
| LoadOpcode = SystemZ::VL32; | |
| StoreOpcode = SystemZ::VST32; | |
| } else if (RC == &SystemZ::VR64BitRegClass) { | |
| LoadOpcode = SystemZ::VL64; | |
| StoreOpcode = SystemZ::VST64; | |
| } else if (RC == &SystemZ::VF128BitRegClass || | |
| RC == &SystemZ::VR128BitRegClass) { | |
| LoadOpcode = SystemZ::VL; | |
| StoreOpcode = SystemZ::VST; | |
| } else | |
| llvm_unreachable("Unsupported regclass to load or store"); | |
| } | |
| unsigned SystemZInstrInfo::getOpcodeForOffset(unsigned Opcode, | |
| int64_t Offset, | |
| const MachineInstr *MI) const { | |
| const MCInstrDesc &MCID = get(Opcode); | |
| int64_t Offset2 = (MCID.TSFlags & SystemZII::Is128Bit ? Offset + 8 : Offset); | |
| if (isUInt<12>(Offset) && isUInt<12>(Offset2)) { | |
| // Get the instruction to use for unsigned 12-bit displacements. | |
| int Disp12Opcode = SystemZ::getDisp12Opcode(Opcode); | |
| if (Disp12Opcode >= 0) | |
| return Disp12Opcode; | |
| // All address-related instructions can use unsigned 12-bit | |
| // displacements. | |
| return Opcode; | |
| } | |
| if (isInt<20>(Offset) && isInt<20>(Offset2)) { | |
| // Get the instruction to use for signed 20-bit displacements. | |
| int Disp20Opcode = SystemZ::getDisp20Opcode(Opcode); | |
| if (Disp20Opcode >= 0) | |
| return Disp20Opcode; | |
| // Check whether Opcode allows signed 20-bit displacements. | |
| if (MCID.TSFlags & SystemZII::Has20BitOffset) | |
| return Opcode; | |
| // If a VR32/VR64 reg ended up in an FP register, use the FP opcode. | |
| if (MI && MI->getOperand(0).isReg()) { | |
| Register Reg = MI->getOperand(0).getReg(); | |
| if (Reg.isPhysical() && SystemZMC::getFirstReg(Reg) < 16) { | |
| switch (Opcode) { | |
| case SystemZ::VL32: | |
| return SystemZ::LEY; | |
| case SystemZ::VST32: | |
| return SystemZ::STEY; | |
| case SystemZ::VL64: | |
| return SystemZ::LDY; | |
| case SystemZ::VST64: | |
| return SystemZ::STDY; | |
| default: break; | |
| } | |
| } | |
| } | |
| } | |
| return 0; | |
| } | |
| bool SystemZInstrInfo::hasDisplacementPairInsn(unsigned Opcode) const { | |
| const MCInstrDesc &MCID = get(Opcode); | |
| if (MCID.TSFlags & SystemZII::Has20BitOffset) | |
| return SystemZ::getDisp12Opcode(Opcode) >= 0; | |
| return SystemZ::getDisp20Opcode(Opcode) >= 0; | |
| } | |
| unsigned SystemZInstrInfo::getLoadAndTest(unsigned Opcode) const { | |
| switch (Opcode) { | |
| case SystemZ::L: return SystemZ::LT; | |
| case SystemZ::LY: return SystemZ::LT; | |
| case SystemZ::LG: return SystemZ::LTG; | |
| case SystemZ::LGF: return SystemZ::LTGF; | |
| case SystemZ::LR: return SystemZ::LTR; | |
| case SystemZ::LGFR: return SystemZ::LTGFR; | |
| case SystemZ::LGR: return SystemZ::LTGR; | |
| case SystemZ::LER: return SystemZ::LTEBR; | |
| case SystemZ::LDR: return SystemZ::LTDBR; | |
| case SystemZ::LXR: return SystemZ::LTXBR; | |
| case SystemZ::LCDFR: return SystemZ::LCDBR; | |
| case SystemZ::LPDFR: return SystemZ::LPDBR; | |
| case SystemZ::LNDFR: return SystemZ::LNDBR; | |
| case SystemZ::LCDFR_32: return SystemZ::LCEBR; | |
| case SystemZ::LPDFR_32: return SystemZ::LPEBR; | |
| case SystemZ::LNDFR_32: return SystemZ::LNEBR; | |
| // On zEC12 we prefer to use RISBGN. But if there is a chance to | |
| // actually use the condition code, we may turn it back into RISGB. | |
| // Note that RISBG is not really a "load-and-test" instruction, | |
| // but sets the same condition code values, so is OK to use here. | |
| case SystemZ::RISBGN: return SystemZ::RISBG; | |
| default: return 0; | |
| } | |
| } | |
| bool SystemZInstrInfo::isRxSBGMask(uint64_t Mask, unsigned BitSize, | |
| unsigned &Start, unsigned &End) const { | |
| // Reject trivial all-zero masks. | |
| Mask &= allOnes(BitSize); | |
| if (Mask == 0) | |
| return false; | |
| // Handle the 1+0+ or 0+1+0* cases. Start then specifies the index of | |
| // the msb and End specifies the index of the lsb. | |
| unsigned LSB, Length; | |
| if (isShiftedMask_64(Mask, LSB, Length)) { | |
| Start = 63 - (LSB + Length - 1); | |
| End = 63 - LSB; | |
| return true; | |
| } | |
| // Handle the wrap-around 1+0+1+ cases. Start then specifies the msb | |
| // of the low 1s and End specifies the lsb of the high 1s. | |
| if (isShiftedMask_64(Mask ^ allOnes(BitSize), LSB, Length)) { | |
| assert(LSB > 0 && "Bottom bit must be set"); | |
| assert(LSB + Length < BitSize && "Top bit must be set"); | |
| Start = 63 - (LSB - 1); | |
| End = 63 - (LSB + Length); | |
| return true; | |
| } | |
| return false; | |
| } | |
| unsigned SystemZInstrInfo::getFusedCompare(unsigned Opcode, | |
| SystemZII::FusedCompareType Type, | |
| const MachineInstr *MI) const { | |
| switch (Opcode) { | |
| case SystemZ::CHI: | |
| case SystemZ::CGHI: | |
| if (!(MI && isInt<8>(MI->getOperand(1).getImm()))) | |
| return 0; | |
| break; | |
| case SystemZ::CLFI: | |
| case SystemZ::CLGFI: | |
| if (!(MI && isUInt<8>(MI->getOperand(1).getImm()))) | |
| return 0; | |
| break; | |
| case SystemZ::CL: | |
| case SystemZ::CLG: | |
| if (!STI.hasMiscellaneousExtensions()) | |
| return 0; | |
| if (!(MI && MI->getOperand(3).getReg() == 0)) | |
| return 0; | |
| break; | |
| } | |
| switch (Type) { | |
| case SystemZII::CompareAndBranch: | |
| switch (Opcode) { | |
| case SystemZ::CR: | |
| return SystemZ::CRJ; | |
| case SystemZ::CGR: | |
| return SystemZ::CGRJ; | |
| case SystemZ::CHI: | |
| return SystemZ::CIJ; | |
| case SystemZ::CGHI: | |
| return SystemZ::CGIJ; | |
| case SystemZ::CLR: | |
| return SystemZ::CLRJ; | |
| case SystemZ::CLGR: | |
| return SystemZ::CLGRJ; | |
| case SystemZ::CLFI: | |
| return SystemZ::CLIJ; | |
| case SystemZ::CLGFI: | |
| return SystemZ::CLGIJ; | |
| default: | |
| return 0; | |
| } | |
| case SystemZII::CompareAndReturn: | |
| switch (Opcode) { | |
| case SystemZ::CR: | |
| return SystemZ::CRBReturn; | |
| case SystemZ::CGR: | |
| return SystemZ::CGRBReturn; | |
| case SystemZ::CHI: | |
| return SystemZ::CIBReturn; | |
| case SystemZ::CGHI: | |
| return SystemZ::CGIBReturn; | |
| case SystemZ::CLR: | |
| return SystemZ::CLRBReturn; | |
| case SystemZ::CLGR: | |
| return SystemZ::CLGRBReturn; | |
| case SystemZ::CLFI: | |
| return SystemZ::CLIBReturn; | |
| case SystemZ::CLGFI: | |
| return SystemZ::CLGIBReturn; | |
| default: | |
| return 0; | |
| } | |
| case SystemZII::CompareAndSibcall: | |
| switch (Opcode) { | |
| case SystemZ::CR: | |
| return SystemZ::CRBCall; | |
| case SystemZ::CGR: | |
| return SystemZ::CGRBCall; | |
| case SystemZ::CHI: | |
| return SystemZ::CIBCall; | |
| case SystemZ::CGHI: | |
| return SystemZ::CGIBCall; | |
| case SystemZ::CLR: | |
| return SystemZ::CLRBCall; | |
| case SystemZ::CLGR: | |
| return SystemZ::CLGRBCall; | |
| case SystemZ::CLFI: | |
| return SystemZ::CLIBCall; | |
| case SystemZ::CLGFI: | |
| return SystemZ::CLGIBCall; | |
| default: | |
| return 0; | |
| } | |
| case SystemZII::CompareAndTrap: | |
| switch (Opcode) { | |
| case SystemZ::CR: | |
| return SystemZ::CRT; | |
| case SystemZ::CGR: | |
| return SystemZ::CGRT; | |
| case SystemZ::CHI: | |
| return SystemZ::CIT; | |
| case SystemZ::CGHI: | |
| return SystemZ::CGIT; | |
| case SystemZ::CLR: | |
| return SystemZ::CLRT; | |
| case SystemZ::CLGR: | |
| return SystemZ::CLGRT; | |
| case SystemZ::CLFI: | |
| return SystemZ::CLFIT; | |
| case SystemZ::CLGFI: | |
| return SystemZ::CLGIT; | |
| case SystemZ::CL: | |
| return SystemZ::CLT; | |
| case SystemZ::CLG: | |
| return SystemZ::CLGT; | |
| default: | |
| return 0; | |
| } | |
| } | |
| return 0; | |
| } | |
| bool SystemZInstrInfo:: | |
| prepareCompareSwapOperands(MachineBasicBlock::iterator const MBBI) const { | |
| assert(MBBI->isCompare() && MBBI->getOperand(0).isReg() && | |
| MBBI->getOperand(1).isReg() && !MBBI->mayLoad() && | |
| "Not a compare reg/reg."); | |
| MachineBasicBlock *MBB = MBBI->getParent(); | |
| bool CCLive = true; | |
| SmallVector<MachineInstr *, 4> CCUsers; | |
| for (MachineInstr &MI : llvm::make_range(std::next(MBBI), MBB->end())) { | |
| if (MI.readsRegister(SystemZ::CC)) { | |
| unsigned Flags = MI.getDesc().TSFlags; | |
| if ((Flags & SystemZII::CCMaskFirst) || (Flags & SystemZII::CCMaskLast)) | |
| CCUsers.push_back(&MI); | |
| else | |
| return false; | |
| } | |
| if (MI.definesRegister(SystemZ::CC)) { | |
| CCLive = false; | |
| break; | |
| } | |
| } | |
| if (CCLive) { | |
| LivePhysRegs LiveRegs(*MBB->getParent()->getSubtarget().getRegisterInfo()); | |
| LiveRegs.addLiveOuts(*MBB); | |
| if (LiveRegs.contains(SystemZ::CC)) | |
| return false; | |
| } | |
| // Update all CC users. | |
| for (unsigned Idx = 0; Idx < CCUsers.size(); ++Idx) { | |
| unsigned Flags = CCUsers[Idx]->getDesc().TSFlags; | |
| unsigned FirstOpNum = ((Flags & SystemZII::CCMaskFirst) ? | |
| 0 : CCUsers[Idx]->getNumExplicitOperands() - 2); | |
| MachineOperand &CCMaskMO = CCUsers[Idx]->getOperand(FirstOpNum + 1); | |
| unsigned NewCCMask = SystemZ::reverseCCMask(CCMaskMO.getImm()); | |
| CCMaskMO.setImm(NewCCMask); | |
| } | |
| return true; | |
| } | |
| unsigned SystemZ::reverseCCMask(unsigned CCMask) { | |
| return ((CCMask & SystemZ::CCMASK_CMP_EQ) | | |
| (CCMask & SystemZ::CCMASK_CMP_GT ? SystemZ::CCMASK_CMP_LT : 0) | | |
| (CCMask & SystemZ::CCMASK_CMP_LT ? SystemZ::CCMASK_CMP_GT : 0) | | |
| (CCMask & SystemZ::CCMASK_CMP_UO)); | |
| } | |
| MachineBasicBlock *SystemZ::emitBlockAfter(MachineBasicBlock *MBB) { | |
| MachineFunction &MF = *MBB->getParent(); | |
| MachineBasicBlock *NewMBB = MF.CreateMachineBasicBlock(MBB->getBasicBlock()); | |
| MF.insert(std::next(MachineFunction::iterator(MBB)), NewMBB); | |
| return NewMBB; | |
| } | |
| MachineBasicBlock *SystemZ::splitBlockAfter(MachineBasicBlock::iterator MI, | |
| MachineBasicBlock *MBB) { | |
| MachineBasicBlock *NewMBB = emitBlockAfter(MBB); | |
| NewMBB->splice(NewMBB->begin(), MBB, | |
| std::next(MachineBasicBlock::iterator(MI)), MBB->end()); | |
| NewMBB->transferSuccessorsAndUpdatePHIs(MBB); | |
| return NewMBB; | |
| } | |
| MachineBasicBlock *SystemZ::splitBlockBefore(MachineBasicBlock::iterator MI, | |
| MachineBasicBlock *MBB) { | |
| MachineBasicBlock *NewMBB = emitBlockAfter(MBB); | |
| NewMBB->splice(NewMBB->begin(), MBB, MI, MBB->end()); | |
| NewMBB->transferSuccessorsAndUpdatePHIs(MBB); | |
| return NewMBB; | |
| } | |
| unsigned SystemZInstrInfo::getLoadAndTrap(unsigned Opcode) const { | |
| if (!STI.hasLoadAndTrap()) | |
| return 0; | |
| switch (Opcode) { | |
| case SystemZ::L: | |
| case SystemZ::LY: | |
| return SystemZ::LAT; | |
| case SystemZ::LG: | |
| return SystemZ::LGAT; | |
| case SystemZ::LFH: | |
| return SystemZ::LFHAT; | |
| case SystemZ::LLGF: | |
| return SystemZ::LLGFAT; | |
| case SystemZ::LLGT: | |
| return SystemZ::LLGTAT; | |
| } | |
| return 0; | |
| } | |
| void SystemZInstrInfo::loadImmediate(MachineBasicBlock &MBB, | |
| MachineBasicBlock::iterator MBBI, | |
| unsigned Reg, uint64_t Value) const { | |
| DebugLoc DL = MBBI != MBB.end() ? MBBI->getDebugLoc() : DebugLoc(); | |
| unsigned Opcode = 0; | |
| if (isInt<16>(Value)) | |
| Opcode = SystemZ::LGHI; | |
| else if (SystemZ::isImmLL(Value)) | |
| Opcode = SystemZ::LLILL; | |
| else if (SystemZ::isImmLH(Value)) { | |
| Opcode = SystemZ::LLILH; | |
| Value >>= 16; | |
| } | |
| else if (isInt<32>(Value)) | |
| Opcode = SystemZ::LGFI; | |
| if (Opcode) { | |
| BuildMI(MBB, MBBI, DL, get(Opcode), Reg).addImm(Value); | |
| return; | |
| } | |
| MachineRegisterInfo &MRI = MBB.getParent()->getRegInfo(); | |
| assert (MRI.isSSA() && "Huge values only handled before reg-alloc ."); | |
| Register Reg0 = MRI.createVirtualRegister(&SystemZ::GR64BitRegClass); | |
| Register Reg1 = MRI.createVirtualRegister(&SystemZ::GR64BitRegClass); | |
| BuildMI(MBB, MBBI, DL, get(SystemZ::IMPLICIT_DEF), Reg0); | |
| BuildMI(MBB, MBBI, DL, get(SystemZ::IIHF64), Reg1) | |
| .addReg(Reg0).addImm(Value >> 32); | |
| BuildMI(MBB, MBBI, DL, get(SystemZ::IILF64), Reg) | |
| .addReg(Reg1).addImm(Value & ((uint64_t(1) << 32) - 1)); | |
| } | |
| bool SystemZInstrInfo::verifyInstruction(const MachineInstr &MI, | |
| StringRef &ErrInfo) const { | |
| const MCInstrDesc &MCID = MI.getDesc(); | |
| for (unsigned I = 0, E = MI.getNumOperands(); I != E; ++I) { | |
| if (I >= MCID.getNumOperands()) | |
| break; | |
| const MachineOperand &Op = MI.getOperand(I); | |
| const MCOperandInfo &MCOI = MCID.operands()[I]; | |
| // Addressing modes have register and immediate operands. Op should be a | |
| // register (or frame index) operand if MCOI.RegClass contains a valid | |
| // register class, or an immediate otherwise. | |
| if (MCOI.OperandType == MCOI::OPERAND_MEMORY && | |
| ((MCOI.RegClass != -1 && !Op.isReg() && !Op.isFI()) || | |
| (MCOI.RegClass == -1 && !Op.isImm()))) { | |
| ErrInfo = "Addressing mode operands corrupt!"; | |
| return false; | |
| } | |
| } | |
| return true; | |
| } | |
| bool SystemZInstrInfo:: | |
| areMemAccessesTriviallyDisjoint(const MachineInstr &MIa, | |
| const MachineInstr &MIb) const { | |
| if (!MIa.hasOneMemOperand() || !MIb.hasOneMemOperand()) | |
| return false; | |
| // If mem-operands show that the same address Value is used by both | |
| // instructions, check for non-overlapping offsets and widths. Not | |
| // sure if a register based analysis would be an improvement... | |
| MachineMemOperand *MMOa = *MIa.memoperands_begin(); | |
| MachineMemOperand *MMOb = *MIb.memoperands_begin(); | |
| const Value *VALa = MMOa->getValue(); | |
| const Value *VALb = MMOb->getValue(); | |
| bool SameVal = (VALa && VALb && (VALa == VALb)); | |
| if (!SameVal) { | |
| const PseudoSourceValue *PSVa = MMOa->getPseudoValue(); | |
| const PseudoSourceValue *PSVb = MMOb->getPseudoValue(); | |
| if (PSVa && PSVb && (PSVa == PSVb)) | |
| SameVal = true; | |
| } | |
| if (SameVal) { | |
| int OffsetA = MMOa->getOffset(), OffsetB = MMOb->getOffset(); | |
| int WidthA = MMOa->getSize(), WidthB = MMOb->getSize(); | |
| int LowOffset = OffsetA < OffsetB ? OffsetA : OffsetB; | |
| int HighOffset = OffsetA < OffsetB ? OffsetB : OffsetA; | |
| int LowWidth = (LowOffset == OffsetA) ? WidthA : WidthB; | |
| if (LowOffset + LowWidth <= HighOffset) | |
| return true; | |
| } | |
| return false; | |
| } |