| //===- PPCInstructionSelector.cpp --------------------------------*- C++ -*-==// | |
| // | |
| // 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 | |
| // | |
| //===----------------------------------------------------------------------===// | |
| /// \file | |
| /// This file implements the targeting of the InstructionSelector class for | |
| /// PowerPC. | |
| //===----------------------------------------------------------------------===// | |
| #include "PPC.h" | |
| #include "PPCInstrInfo.h" | |
| #include "PPCRegisterBankInfo.h" | |
| #include "PPCSubtarget.h" | |
| #include "PPCTargetMachine.h" | |
| #include "llvm/CodeGen/GlobalISel/GenericMachineInstrs.h" | |
| #include "llvm/CodeGen/GlobalISel/InstructionSelector.h" | |
| #include "llvm/CodeGen/GlobalISel/InstructionSelectorImpl.h" | |
| #include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h" | |
| #include "llvm/CodeGen/MachineConstantPool.h" | |
| #include "llvm/CodeGen/MachineFunction.h" | |
| #include "llvm/IR/IntrinsicsPowerPC.h" | |
| #include "llvm/Support/Debug.h" | |
| #define DEBUG_TYPE "ppc-gisel" | |
| using namespace llvm; | |
| namespace { | |
| #define GET_GLOBALISEL_PREDICATE_BITSET | |
| #include "PPCGenGlobalISel.inc" | |
| #undef GET_GLOBALISEL_PREDICATE_BITSET | |
| class PPCInstructionSelector : public InstructionSelector { | |
| public: | |
| PPCInstructionSelector(const PPCTargetMachine &TM, const PPCSubtarget &STI, | |
| const PPCRegisterBankInfo &RBI); | |
| bool select(MachineInstr &I) override; | |
| static const char *getName() { return DEBUG_TYPE; } | |
| private: | |
| /// tblgen generated 'select' implementation that is used as the initial | |
| /// selector for the patterns that do not require complex C++. | |
| bool selectImpl(MachineInstr &I, CodeGenCoverage &CoverageInfo) const; | |
| bool selectFPToInt(MachineInstr &I, MachineBasicBlock &MBB, | |
| MachineRegisterInfo &MRI) const; | |
| bool selectIntToFP(MachineInstr &I, MachineBasicBlock &MBB, | |
| MachineRegisterInfo &MRI) const; | |
| bool selectZExt(MachineInstr &I, MachineBasicBlock &MBB, | |
| MachineRegisterInfo &MRI) const; | |
| std::optional<bool> selectI64ImmDirect(MachineInstr &I, | |
| MachineBasicBlock &MBB, | |
| MachineRegisterInfo &MRI, Register Reg, | |
| uint64_t Imm) const; | |
| bool selectI64Imm(MachineInstr &I, MachineBasicBlock &MBB, | |
| MachineRegisterInfo &MRI) const; | |
| const PPCSubtarget &STI; | |
| const PPCInstrInfo &TII; | |
| const PPCRegisterInfo &TRI; | |
| const PPCRegisterBankInfo &RBI; | |
| #define GET_GLOBALISEL_PREDICATES_DECL | |
| #include "PPCGenGlobalISel.inc" | |
| #undef GET_GLOBALISEL_PREDICATES_DECL | |
| #define GET_GLOBALISEL_TEMPORARIES_DECL | |
| #include "PPCGenGlobalISel.inc" | |
| #undef GET_GLOBALISEL_TEMPORARIES_DECL | |
| }; | |
| } // end anonymous namespace | |
| #define GET_GLOBALISEL_IMPL | |
| #include "PPCGenGlobalISel.inc" | |
| #undef GET_GLOBALISEL_IMPL | |
| PPCInstructionSelector::PPCInstructionSelector(const PPCTargetMachine &TM, | |
| const PPCSubtarget &STI, | |
| const PPCRegisterBankInfo &RBI) | |
| : STI(STI), TII(*STI.getInstrInfo()), TRI(*STI.getRegisterInfo()), RBI(RBI), | |
| #define GET_GLOBALISEL_PREDICATES_INIT | |
| #include "PPCGenGlobalISel.inc" | |
| #undef GET_GLOBALISEL_PREDICATES_INIT | |
| #define GET_GLOBALISEL_TEMPORARIES_INIT | |
| #include "PPCGenGlobalISel.inc" | |
| #undef GET_GLOBALISEL_TEMPORARIES_INIT | |
| { | |
| } | |
| static const TargetRegisterClass *getRegClass(LLT Ty, const RegisterBank *RB) { | |
| if (RB->getID() == PPC::GPRRegBankID) { | |
| if (Ty.getSizeInBits() == 64) | |
| return &PPC::G8RCRegClass; | |
| if (Ty.getSizeInBits() <= 32) | |
| return &PPC::GPRCRegClass; | |
| } | |
| if (RB->getID() == PPC::FPRRegBankID) { | |
| if (Ty.getSizeInBits() == 32) | |
| return &PPC::F4RCRegClass; | |
| if (Ty.getSizeInBits() == 64) | |
| return &PPC::F8RCRegClass; | |
| } | |
| if (RB->getID() == PPC::CRRegBankID) { | |
| if (Ty.getSizeInBits() == 1) | |
| return &PPC::CRBITRCRegClass; | |
| if (Ty.getSizeInBits() == 4) | |
| return &PPC::CRRCRegClass; | |
| } | |
| llvm_unreachable("Unknown RegBank!"); | |
| } | |
| static bool selectCopy(MachineInstr &I, const TargetInstrInfo &TII, | |
| MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI, | |
| const RegisterBankInfo &RBI) { | |
| Register DstReg = I.getOperand(0).getReg(); | |
| if (DstReg.isPhysical()) | |
| return true; | |
| const RegisterBank *DstRegBank = RBI.getRegBank(DstReg, MRI, TRI); | |
| const TargetRegisterClass *DstRC = | |
| getRegClass(MRI.getType(DstReg), DstRegBank); | |
| // No need to constrain SrcReg. It will get constrained when we hit another of | |
| // its use or its defs. | |
| // Copies do not have constraints. | |
| if (!RBI.constrainGenericRegister(DstReg, *DstRC, MRI)) { | |
| LLVM_DEBUG(dbgs() << "Failed to constrain " << TII.getName(I.getOpcode()) | |
| << " operand\n"); | |
| return false; | |
| } | |
| return true; | |
| } | |
| static unsigned selectLoadStoreOp(unsigned GenericOpc, unsigned RegBankID, | |
| unsigned OpSize) { | |
| const bool IsStore = GenericOpc == TargetOpcode::G_STORE; | |
| switch (RegBankID) { | |
| case PPC::GPRRegBankID: | |
| switch (OpSize) { | |
| case 32: | |
| return IsStore ? PPC::STW : PPC::LWZ; | |
| case 64: | |
| return IsStore ? PPC::STD : PPC::LD; | |
| default: | |
| llvm_unreachable("Unexpected size!"); | |
| } | |
| break; | |
| case PPC::FPRRegBankID: | |
| switch (OpSize) { | |
| case 32: | |
| return IsStore ? PPC::STFS : PPC::LFS; | |
| case 64: | |
| return IsStore ? PPC::STFD : PPC::LFD; | |
| default: | |
| llvm_unreachable("Unexpected size!"); | |
| } | |
| break; | |
| default: | |
| llvm_unreachable("Unexpected register bank!"); | |
| } | |
| return GenericOpc; | |
| } | |
| bool PPCInstructionSelector::selectIntToFP(MachineInstr &I, | |
| MachineBasicBlock &MBB, | |
| MachineRegisterInfo &MRI) const { | |
| if (!STI.hasDirectMove() || !STI.isPPC64() || !STI.hasFPCVT()) | |
| return false; | |
| const DebugLoc &DbgLoc = I.getDebugLoc(); | |
| const Register DstReg = I.getOperand(0).getReg(); | |
| const Register SrcReg = I.getOperand(1).getReg(); | |
| Register MoveReg = MRI.createVirtualRegister(&PPC::VSFRCRegClass); | |
| // For now, only handle the case for 64 bit integer. | |
| BuildMI(MBB, I, DbgLoc, TII.get(PPC::MTVSRD), MoveReg).addReg(SrcReg); | |
| bool IsSingle = MRI.getType(DstReg).getSizeInBits() == 32; | |
| bool IsSigned = I.getOpcode() == TargetOpcode::G_SITOFP; | |
| unsigned ConvOp = IsSingle ? (IsSigned ? PPC::XSCVSXDSP : PPC::XSCVUXDSP) | |
| : (IsSigned ? PPC::XSCVSXDDP : PPC::XSCVUXDDP); | |
| MachineInstr *MI = | |
| BuildMI(MBB, I, DbgLoc, TII.get(ConvOp), DstReg).addReg(MoveReg); | |
| I.eraseFromParent(); | |
| return constrainSelectedInstRegOperands(*MI, TII, TRI, RBI); | |
| } | |
| bool PPCInstructionSelector::selectFPToInt(MachineInstr &I, | |
| MachineBasicBlock &MBB, | |
| MachineRegisterInfo &MRI) const { | |
| if (!STI.hasDirectMove() || !STI.isPPC64() || !STI.hasFPCVT()) | |
| return false; | |
| const DebugLoc &DbgLoc = I.getDebugLoc(); | |
| const Register DstReg = I.getOperand(0).getReg(); | |
| const Register SrcReg = I.getOperand(1).getReg(); | |
| Register CopyReg = MRI.createVirtualRegister(&PPC::VSFRCRegClass); | |
| BuildMI(MBB, I, DbgLoc, TII.get(TargetOpcode::COPY), CopyReg).addReg(SrcReg); | |
| Register ConvReg = MRI.createVirtualRegister(&PPC::VSFRCRegClass); | |
| bool IsSigned = I.getOpcode() == TargetOpcode::G_FPTOSI; | |
| // single-precision is stored as double-precision on PPC in registers, so | |
| // always use double-precision convertions. | |
| unsigned ConvOp = IsSigned ? PPC::XSCVDPSXDS : PPC::XSCVDPUXDS; | |
| BuildMI(MBB, I, DbgLoc, TII.get(ConvOp), ConvReg).addReg(CopyReg); | |
| MachineInstr *MI = | |
| BuildMI(MBB, I, DbgLoc, TII.get(PPC::MFVSRD), DstReg).addReg(ConvReg); | |
| I.eraseFromParent(); | |
| return constrainSelectedInstRegOperands(*MI, TII, TRI, RBI); | |
| } | |
| bool PPCInstructionSelector::selectZExt(MachineInstr &I, MachineBasicBlock &MBB, | |
| MachineRegisterInfo &MRI) const { | |
| const Register DstReg = I.getOperand(0).getReg(); | |
| const LLT DstTy = MRI.getType(DstReg); | |
| const RegisterBank *DstRegBank = RBI.getRegBank(DstReg, MRI, TRI); | |
| const Register SrcReg = I.getOperand(1).getReg(); | |
| assert(DstTy.getSizeInBits() == 64 && "Unexpected dest size!"); | |
| assert(MRI.getType(SrcReg).getSizeInBits() == 32 && "Unexpected src size!"); | |
| Register ImpDefReg = | |
| MRI.createVirtualRegister(getRegClass(DstTy, DstRegBank)); | |
| BuildMI(MBB, I, I.getDebugLoc(), TII.get(TargetOpcode::IMPLICIT_DEF), | |
| ImpDefReg); | |
| Register NewDefReg = | |
| MRI.createVirtualRegister(getRegClass(DstTy, DstRegBank)); | |
| BuildMI(MBB, I, I.getDebugLoc(), TII.get(TargetOpcode::INSERT_SUBREG), | |
| NewDefReg) | |
| .addReg(ImpDefReg) | |
| .addReg(SrcReg) | |
| .addImm(PPC::sub_32); | |
| MachineInstr *MI = | |
| BuildMI(MBB, I, I.getDebugLoc(), TII.get(PPC::RLDICL), DstReg) | |
| .addReg(NewDefReg) | |
| .addImm(0) | |
| .addImm(32); | |
| I.eraseFromParent(); | |
| return constrainSelectedInstRegOperands(*MI, TII, TRI, RBI); | |
| } | |
| // For any 32 < Num < 64, check if the Imm contains at least Num consecutive | |
| // zeros and return the number of bits by the left of these consecutive zeros. | |
| static uint32_t findContiguousZerosAtLeast(uint64_t Imm, unsigned Num) { | |
| uint32_t HiTZ = countTrailingZeros<uint32_t>(Hi_32(Imm)); | |
| uint32_t LoLZ = countLeadingZeros<uint32_t>(Lo_32(Imm)); | |
| if ((HiTZ + LoLZ) >= Num) | |
| return (32 + HiTZ); | |
| return 0; | |
| } | |
| // Direct materialization of 64-bit constants by enumerated patterns. | |
| // Similar to PPCISelDAGToDAG::selectI64ImmDirect(). | |
| std::optional<bool> PPCInstructionSelector::selectI64ImmDirect(MachineInstr &I, | |
| MachineBasicBlock &MBB, | |
| MachineRegisterInfo &MRI, | |
| Register Reg, | |
| uint64_t Imm) const { | |
| unsigned TZ = countTrailingZeros<uint64_t>(Imm); | |
| unsigned LZ = countLeadingZeros<uint64_t>(Imm); | |
| unsigned TO = countTrailingOnes<uint64_t>(Imm); | |
| unsigned LO = countLeadingOnes<uint64_t>(Imm); | |
| uint32_t Hi32 = Hi_32(Imm); | |
| uint32_t Lo32 = Lo_32(Imm); | |
| uint32_t Shift = 0; | |
| // Following patterns use 1 instructions to materialize the Imm. | |
| // 1-1) Patterns : {zeros}{15-bit valve} | |
| // {ones}{15-bit valve} | |
| if (isInt<16>(Imm)) | |
| return BuildMI(MBB, I, I.getDebugLoc(), TII.get(PPC::LI8), Reg) | |
| .addImm(Imm) | |
| .constrainAllUses(TII, TRI, RBI); | |
| // 1-2) Patterns : {zeros}{15-bit valve}{16 zeros} | |
| // {ones}{15-bit valve}{16 zeros} | |
| if (TZ > 15 && (LZ > 32 || LO > 32)) | |
| return BuildMI(MBB, I, I.getDebugLoc(), TII.get(PPC::LIS8), Reg) | |
| .addImm((Imm >> 16) & 0xffff) | |
| .constrainAllUses(TII, TRI, RBI); | |
| // Following patterns use 2 instructions to materialize the Imm. | |
| assert(LZ < 64 && "Unexpected leading zeros here."); | |
| // Count of ones follwing the leading zeros. | |
| unsigned FO = countLeadingOnes<uint64_t>(Imm << LZ); | |
| // 2-1) Patterns : {zeros}{31-bit value} | |
| // {ones}{31-bit value} | |
| if (isInt<32>(Imm)) { | |
| uint64_t ImmHi16 = (Imm >> 16) & 0xffff; | |
| unsigned Opcode = ImmHi16 ? PPC::LIS8 : PPC::LI8; | |
| Register TmpReg = MRI.createVirtualRegister(&PPC::G8RCRegClass); | |
| if (!BuildMI(MBB, I, I.getDebugLoc(), TII.get(Opcode), TmpReg) | |
| .addImm((Imm >> 16) & 0xffff) | |
| .constrainAllUses(TII, TRI, RBI)) | |
| return false; | |
| return BuildMI(MBB, I, I.getDebugLoc(), TII.get(PPC::ORI8), Reg) | |
| .addReg(TmpReg, RegState::Kill) | |
| .addImm(Imm & 0xffff) | |
| .constrainAllUses(TII, TRI, RBI); | |
| } | |
| // 2-2) Patterns : {zeros}{ones}{15-bit value}{zeros} | |
| // {zeros}{15-bit value}{zeros} | |
| // {zeros}{ones}{15-bit value} | |
| // {ones}{15-bit value}{zeros} | |
| // We can take advantage of LI's sign-extension semantics to generate leading | |
| // ones, and then use RLDIC to mask off the ones in both sides after rotation. | |
| if ((LZ + FO + TZ) > 48) { | |
| Register TmpReg = MRI.createVirtualRegister(&PPC::G8RCRegClass); | |
| if (!BuildMI(MBB, I, I.getDebugLoc(), TII.get(PPC::LI8), TmpReg) | |
| .addImm((Imm >> TZ) & 0xffff) | |
| .constrainAllUses(TII, TRI, RBI)) | |
| return false; | |
| return BuildMI(MBB, I, I.getDebugLoc(), TII.get(PPC::RLDIC), Reg) | |
| .addReg(TmpReg, RegState::Kill) | |
| .addImm(TZ) | |
| .addImm(LZ) | |
| .constrainAllUses(TII, TRI, RBI); | |
| } | |
| // 2-3) Pattern : {zeros}{15-bit value}{ones} | |
| // Shift right the Imm by (48 - LZ) bits to construct a negtive 16 bits value, | |
| // therefore we can take advantage of LI's sign-extension semantics, and then | |
| // mask them off after rotation. | |
| // | |
| // +--LZ--||-15-bit-||--TO--+ +-------------|--16-bit--+ | |
| // |00000001bbbbbbbbb1111111| -> |00000000000001bbbbbbbbb1| | |
| // +------------------------+ +------------------------+ | |
| // 63 0 63 0 | |
| // Imm (Imm >> (48 - LZ) & 0xffff) | |
| // +----sext-----|--16-bit--+ +clear-|-----------------+ | |
| // |11111111111111bbbbbbbbb1| -> |00000001bbbbbbbbb1111111| | |
| // +------------------------+ +------------------------+ | |
| // 63 0 63 0 | |
| // LI8: sext many leading zeros RLDICL: rotate left (48 - LZ), clear left LZ | |
| if ((LZ + TO) > 48) { | |
| // Since the immediates with (LZ > 32) have been handled by previous | |
| // patterns, here we have (LZ <= 32) to make sure we will not shift right | |
| // the Imm by a negative value. | |
| assert(LZ <= 32 && "Unexpected shift value."); | |
| Register TmpReg = MRI.createVirtualRegister(&PPC::G8RCRegClass); | |
| if (!BuildMI(MBB, I, I.getDebugLoc(), TII.get(PPC::LI8), TmpReg) | |
| .addImm(Imm >> (48 - LZ) & 0xffff) | |
| .constrainAllUses(TII, TRI, RBI)) | |
| return false; | |
| return BuildMI(MBB, I, I.getDebugLoc(), TII.get(PPC::RLDICL), Reg) | |
| .addReg(TmpReg, RegState::Kill) | |
| .addImm(48 - LZ) | |
| .addImm(LZ) | |
| .constrainAllUses(TII, TRI, RBI); | |
| } | |
| // 2-4) Patterns : {zeros}{ones}{15-bit value}{ones} | |
| // {ones}{15-bit value}{ones} | |
| // We can take advantage of LI's sign-extension semantics to generate leading | |
| // ones, and then use RLDICL to mask off the ones in left sides (if required) | |
| // after rotation. | |
| // | |
| // +-LZ-FO||-15-bit-||--TO--+ +-------------|--16-bit--+ | |
| // |00011110bbbbbbbbb1111111| -> |000000000011110bbbbbbbbb| | |
| // +------------------------+ +------------------------+ | |
| // 63 0 63 0 | |
| // Imm (Imm >> TO) & 0xffff | |
| // +----sext-----|--16-bit--+ +LZ|---------------------+ | |
| // |111111111111110bbbbbbbbb| -> |00011110bbbbbbbbb1111111| | |
| // +------------------------+ +------------------------+ | |
| // 63 0 63 0 | |
| // LI8: sext many leading zeros RLDICL: rotate left TO, clear left LZ | |
| if ((LZ + FO + TO) > 48) { | |
| Register TmpReg = MRI.createVirtualRegister(&PPC::G8RCRegClass); | |
| if (!BuildMI(MBB, I, I.getDebugLoc(), TII.get(PPC::LI8), TmpReg) | |
| .addImm((Imm >> TO) & 0xffff) | |
| .constrainAllUses(TII, TRI, RBI)) | |
| return false; | |
| return BuildMI(MBB, I, I.getDebugLoc(), TII.get(PPC::RLDICL), Reg) | |
| .addReg(TmpReg, RegState::Kill) | |
| .addImm(TO) | |
| .addImm(LZ) | |
| .constrainAllUses(TII, TRI, RBI); | |
| } | |
| // 2-5) Pattern : {32 zeros}{****}{0}{15-bit value} | |
| // If Hi32 is zero and the Lo16(in Lo32) can be presented as a positive 16 bit | |
| // value, we can use LI for Lo16 without generating leading ones then add the | |
| // Hi16(in Lo32). | |
| if (LZ == 32 && ((Lo32 & 0x8000) == 0)) { | |
| Register TmpReg = MRI.createVirtualRegister(&PPC::G8RCRegClass); | |
| if (!BuildMI(MBB, I, I.getDebugLoc(), TII.get(PPC::LI8), TmpReg) | |
| .addImm(Lo32 & 0xffff) | |
| .constrainAllUses(TII, TRI, RBI)) | |
| return false; | |
| return BuildMI(MBB, I, I.getDebugLoc(), TII.get(PPC::ORIS8), Reg) | |
| .addReg(TmpReg, RegState::Kill) | |
| .addImm(Lo32 >> 16) | |
| .constrainAllUses(TII, TRI, RBI); | |
| } | |
| // 2-6) Patterns : {******}{49 zeros}{******} | |
| // {******}{49 ones}{******} | |
| // If the Imm contains 49 consecutive zeros/ones, it means that a total of 15 | |
| // bits remain on both sides. Rotate right the Imm to construct an int<16> | |
| // value, use LI for int<16> value and then use RLDICL without mask to rotate | |
| // it back. | |
| // | |
| // 1) findContiguousZerosAtLeast(Imm, 49) | |
| // +------|--zeros-|------+ +---ones--||---15 bit--+ | |
| // |bbbbbb0000000000aaaaaa| -> |0000000000aaaaaabbbbbb| | |
| // +----------------------+ +----------------------+ | |
| // 63 0 63 0 | |
| // | |
| // 2) findContiguousZerosAtLeast(~Imm, 49) | |
| // +------|--ones--|------+ +---ones--||---15 bit--+ | |
| // |bbbbbb1111111111aaaaaa| -> |1111111111aaaaaabbbbbb| | |
| // +----------------------+ +----------------------+ | |
| // 63 0 63 0 | |
| if ((Shift = findContiguousZerosAtLeast(Imm, 49)) || | |
| (Shift = findContiguousZerosAtLeast(~Imm, 49))) { | |
| uint64_t RotImm = APInt(64, Imm).rotr(Shift).getZExtValue(); | |
| Register TmpReg = MRI.createVirtualRegister(&PPC::G8RCRegClass); | |
| if (!BuildMI(MBB, I, I.getDebugLoc(), TII.get(PPC::LI8), TmpReg) | |
| .addImm(RotImm & 0xffff) | |
| .constrainAllUses(TII, TRI, RBI)) | |
| return false; | |
| return BuildMI(MBB, I, I.getDebugLoc(), TII.get(PPC::RLDICL), Reg) | |
| .addReg(TmpReg, RegState::Kill) | |
| .addImm(Shift) | |
| .addImm(0) | |
| .constrainAllUses(TII, TRI, RBI); | |
| } | |
| // Following patterns use 3 instructions to materialize the Imm. | |
| // 3-1) Patterns : {zeros}{ones}{31-bit value}{zeros} | |
| // {zeros}{31-bit value}{zeros} | |
| // {zeros}{ones}{31-bit value} | |
| // {ones}{31-bit value}{zeros} | |
| // We can take advantage of LIS's sign-extension semantics to generate leading | |
| // ones, add the remaining bits with ORI, and then use RLDIC to mask off the | |
| // ones in both sides after rotation. | |
| if ((LZ + FO + TZ) > 32) { | |
| uint64_t ImmHi16 = (Imm >> (TZ + 16)) & 0xffff; | |
| unsigned Opcode = ImmHi16 ? PPC::LIS8 : PPC::LI8; | |
| Register TmpReg = MRI.createVirtualRegister(&PPC::G8RCRegClass); | |
| Register Tmp2Reg = MRI.createVirtualRegister(&PPC::G8RCRegClass); | |
| if (!BuildMI(MBB, I, I.getDebugLoc(), TII.get(Opcode), TmpReg) | |
| .addImm(ImmHi16) | |
| .constrainAllUses(TII, TRI, RBI)) | |
| return false; | |
| if (!BuildMI(MBB, I, I.getDebugLoc(), TII.get(PPC::ORI8), Tmp2Reg) | |
| .addReg(TmpReg, RegState::Kill) | |
| .addImm((Imm >> TZ) & 0xffff) | |
| .constrainAllUses(TII, TRI, RBI)) | |
| return false; | |
| return BuildMI(MBB, I, I.getDebugLoc(), TII.get(PPC::RLDIC), Reg) | |
| .addReg(Tmp2Reg, RegState::Kill) | |
| .addImm(TZ) | |
| .addImm(LZ) | |
| .constrainAllUses(TII, TRI, RBI); | |
| } | |
| // 3-2) Pattern : {zeros}{31-bit value}{ones} | |
| // Shift right the Imm by (32 - LZ) bits to construct a negative 32 bits | |
| // value, therefore we can take advantage of LIS's sign-extension semantics, | |
| // add the remaining bits with ORI, and then mask them off after rotation. | |
| // This is similar to Pattern 2-3, please refer to the diagram there. | |
| if ((LZ + TO) > 32) { | |
| // Since the immediates with (LZ > 32) have been handled by previous | |
| // patterns, here we have (LZ <= 32) to make sure we will not shift right | |
| // the Imm by a negative value. | |
| assert(LZ <= 32 && "Unexpected shift value."); | |
| Register TmpReg = MRI.createVirtualRegister(&PPC::G8RCRegClass); | |
| Register Tmp2Reg = MRI.createVirtualRegister(&PPC::G8RCRegClass); | |
| if (!BuildMI(MBB, I, I.getDebugLoc(), TII.get(PPC::LIS8), TmpReg) | |
| .addImm((Imm >> (48 - LZ)) & 0xffff) | |
| .constrainAllUses(TII, TRI, RBI)) | |
| return false; | |
| if (!BuildMI(MBB, I, I.getDebugLoc(), TII.get(PPC::ORI8), Tmp2Reg) | |
| .addReg(TmpReg, RegState::Kill) | |
| .addImm((Imm >> (32 - LZ)) & 0xffff) | |
| .constrainAllUses(TII, TRI, RBI)) | |
| return false; | |
| return BuildMI(MBB, I, I.getDebugLoc(), TII.get(PPC::RLDICL), Reg) | |
| .addReg(Tmp2Reg, RegState::Kill) | |
| .addImm(32 - LZ) | |
| .addImm(LZ) | |
| .constrainAllUses(TII, TRI, RBI); | |
| } | |
| // 3-3) Patterns : {zeros}{ones}{31-bit value}{ones} | |
| // {ones}{31-bit value}{ones} | |
| // We can take advantage of LIS's sign-extension semantics to generate leading | |
| // ones, add the remaining bits with ORI, and then use RLDICL to mask off the | |
| // ones in left sides (if required) after rotation. | |
| // This is similar to Pattern 2-4, please refer to the diagram there. | |
| if ((LZ + FO + TO) > 32) { | |
| Register TmpReg = MRI.createVirtualRegister(&PPC::G8RCRegClass); | |
| Register Tmp2Reg = MRI.createVirtualRegister(&PPC::G8RCRegClass); | |
| if (!BuildMI(MBB, I, I.getDebugLoc(), TII.get(PPC::LIS8), TmpReg) | |
| .addImm((Imm >> (TO + 16)) & 0xffff) | |
| .constrainAllUses(TII, TRI, RBI)) | |
| return false; | |
| if (!BuildMI(MBB, I, I.getDebugLoc(), TII.get(PPC::ORI8), Tmp2Reg) | |
| .addReg(TmpReg, RegState::Kill) | |
| .addImm((Imm >> TO) & 0xffff) | |
| .constrainAllUses(TII, TRI, RBI)) | |
| return false; | |
| return BuildMI(MBB, I, I.getDebugLoc(), TII.get(PPC::RLDICL), Reg) | |
| .addReg(Tmp2Reg, RegState::Kill) | |
| .addImm(TO) | |
| .addImm(LZ) | |
| .constrainAllUses(TII, TRI, RBI); | |
| } | |
| // 3-4) Patterns : High word == Low word | |
| if (Hi32 == Lo32) { | |
| // Handle the first 32 bits. | |
| uint64_t ImmHi16 = (Lo32 >> 16) & 0xffff; | |
| unsigned Opcode = ImmHi16 ? PPC::LIS8 : PPC::LI8; | |
| Register TmpReg = MRI.createVirtualRegister(&PPC::G8RCRegClass); | |
| Register Tmp2Reg = MRI.createVirtualRegister(&PPC::G8RCRegClass); | |
| if (!BuildMI(MBB, I, I.getDebugLoc(), TII.get(Opcode), TmpReg) | |
| .addImm(ImmHi16) | |
| .constrainAllUses(TII, TRI, RBI)) | |
| return false; | |
| if (!BuildMI(MBB, I, I.getDebugLoc(), TII.get(PPC::ORI8), Tmp2Reg) | |
| .addReg(TmpReg, RegState::Kill) | |
| .addImm(Lo32 & 0xffff) | |
| .constrainAllUses(TII, TRI, RBI)) | |
| return false; | |
| return BuildMI(MBB, I, I.getDebugLoc(), TII.get(PPC::RLDIMI), Reg) | |
| .addReg(Tmp2Reg) | |
| .addReg(Tmp2Reg, RegState::Kill) | |
| .addImm(32) | |
| .addImm(0) | |
| .constrainAllUses(TII, TRI, RBI); | |
| } | |
| // 3-5) Patterns : {******}{33 zeros}{******} | |
| // {******}{33 ones}{******} | |
| // If the Imm contains 33 consecutive zeros/ones, it means that a total of 31 | |
| // bits remain on both sides. Rotate right the Imm to construct an int<32> | |
| // value, use LIS + ORI for int<32> value and then use RLDICL without mask to | |
| // rotate it back. | |
| // This is similar to Pattern 2-6, please refer to the diagram there. | |
| if ((Shift = findContiguousZerosAtLeast(Imm, 33)) || | |
| (Shift = findContiguousZerosAtLeast(~Imm, 33))) { | |
| uint64_t RotImm = APInt(64, Imm).rotr(Shift).getZExtValue(); | |
| uint64_t ImmHi16 = (RotImm >> 16) & 0xffff; | |
| unsigned Opcode = ImmHi16 ? PPC::LIS8 : PPC::LI8; | |
| Register TmpReg = MRI.createVirtualRegister(&PPC::G8RCRegClass); | |
| Register Tmp2Reg = MRI.createVirtualRegister(&PPC::G8RCRegClass); | |
| if (!BuildMI(MBB, I, I.getDebugLoc(), TII.get(Opcode), TmpReg) | |
| .addImm(ImmHi16) | |
| .constrainAllUses(TII, TRI, RBI)) | |
| return false; | |
| if (!BuildMI(MBB, I, I.getDebugLoc(), TII.get(PPC::ORI8), Tmp2Reg) | |
| .addReg(TmpReg, RegState::Kill) | |
| .addImm(RotImm & 0xffff) | |
| .constrainAllUses(TII, TRI, RBI)) | |
| return false; | |
| return BuildMI(MBB, I, I.getDebugLoc(), TII.get(PPC::RLDICL), Reg) | |
| .addReg(Tmp2Reg, RegState::Kill) | |
| .addImm(Shift) | |
| .addImm(0) | |
| .constrainAllUses(TII, TRI, RBI); | |
| } | |
| // If we end up here then no instructions were inserted. | |
| return std::nullopt; | |
| } | |
| // Derived from PPCISelDAGToDAG::selectI64Imm(). | |
| // TODO: Add support for prefixed instructions. | |
| bool PPCInstructionSelector::selectI64Imm(MachineInstr &I, | |
| MachineBasicBlock &MBB, | |
| MachineRegisterInfo &MRI) const { | |
| assert(I.getOpcode() == TargetOpcode::G_CONSTANT && "Unexpected G code"); | |
| Register DstReg = I.getOperand(0).getReg(); | |
| int64_t Imm = I.getOperand(1).getCImm()->getValue().getZExtValue(); | |
| // No more than 3 instructions are used if we can select the i64 immediate | |
| // directly. | |
| if (std::optional<bool> Res = selectI64ImmDirect(I, MBB, MRI, DstReg, Imm)) { | |
| I.eraseFromParent(); | |
| return *Res; | |
| } | |
| // Calculate the last bits as required. | |
| uint32_t Hi16 = (Lo_32(Imm) >> 16) & 0xffff; | |
| uint32_t Lo16 = Lo_32(Imm) & 0xffff; | |
| Register Reg = | |
| (Hi16 || Lo16) ? MRI.createVirtualRegister(&PPC::G8RCRegClass) : DstReg; | |
| // Handle the upper 32 bit value. | |
| std::optional<bool> Res = | |
| selectI64ImmDirect(I, MBB, MRI, Reg, Imm & 0xffffffff00000000); | |
| if (!Res || !*Res) | |
| return false; | |
| // Add in the last bits as required. | |
| if (Hi16) { | |
| Register TmpReg = | |
| Lo16 ? MRI.createVirtualRegister(&PPC::G8RCRegClass) : DstReg; | |
| if (!BuildMI(MBB, I, I.getDebugLoc(), TII.get(PPC::ORIS8), TmpReg) | |
| .addReg(Reg, RegState::Kill) | |
| .addImm(Hi16) | |
| .constrainAllUses(TII, TRI, RBI)) | |
| return false; | |
| Reg = TmpReg; | |
| } | |
| if (Lo16) { | |
| if (!BuildMI(MBB, I, I.getDebugLoc(), TII.get(PPC::ORI8), DstReg) | |
| .addReg(Reg, RegState::Kill) | |
| .addImm(Lo16) | |
| .constrainAllUses(TII, TRI, RBI)) | |
| return false; | |
| } | |
| I.eraseFromParent(); | |
| return true; | |
| } | |
| bool PPCInstructionSelector::select(MachineInstr &I) { | |
| auto &MBB = *I.getParent(); | |
| auto &MF = *MBB.getParent(); | |
| auto &MRI = MF.getRegInfo(); | |
| if (!isPreISelGenericOpcode(I.getOpcode())) { | |
| if (I.isCopy()) | |
| return selectCopy(I, TII, MRI, TRI, RBI); | |
| return true; | |
| } | |
| if (selectImpl(I, *CoverageInfo)) | |
| return true; | |
| unsigned Opcode = I.getOpcode(); | |
| switch (Opcode) { | |
| default: | |
| return false; | |
| case TargetOpcode::G_LOAD: | |
| case TargetOpcode::G_STORE: { | |
| GLoadStore &LdSt = cast<GLoadStore>(I); | |
| LLT PtrTy = MRI.getType(LdSt.getPointerReg()); | |
| if (PtrTy != LLT::pointer(0, 64)) { | |
| LLVM_DEBUG(dbgs() << "Load/Store pointer has type: " << PtrTy | |
| << ", expected: " << LLT::pointer(0, 64) << '\n'); | |
| return false; | |
| } | |
| auto SelectLoadStoreAddressingMode = [&]() -> MachineInstr * { | |
| const unsigned NewOpc = selectLoadStoreOp( | |
| I.getOpcode(), RBI.getRegBank(LdSt.getReg(0), MRI, TRI)->getID(), | |
| LdSt.getMemSizeInBits()); | |
| if (NewOpc == I.getOpcode()) | |
| return nullptr; | |
| // For now, simply use DForm with load/store addr as base and 0 as imm. | |
| // FIXME: optimize load/store with some specific address patterns. | |
| I.setDesc(TII.get(NewOpc)); | |
| Register AddrReg = I.getOperand(1).getReg(); | |
| bool IsKill = I.getOperand(1).isKill(); | |
| I.getOperand(1).ChangeToImmediate(0); | |
| I.addOperand(*I.getParent()->getParent(), | |
| MachineOperand::CreateReg(AddrReg, /* isDef */ false, | |
| /* isImp */ false, IsKill)); | |
| return &I; | |
| }; | |
| MachineInstr *LoadStore = SelectLoadStoreAddressingMode(); | |
| if (!LoadStore) | |
| return false; | |
| return constrainSelectedInstRegOperands(*LoadStore, TII, TRI, RBI); | |
| } | |
| case TargetOpcode::G_SITOFP: | |
| case TargetOpcode::G_UITOFP: | |
| return selectIntToFP(I, MBB, MRI); | |
| case TargetOpcode::G_FPTOSI: | |
| case TargetOpcode::G_FPTOUI: | |
| return selectFPToInt(I, MBB, MRI); | |
| // G_SEXT will be selected in tb-gen pattern. | |
| case TargetOpcode::G_ZEXT: | |
| return selectZExt(I, MBB, MRI); | |
| case TargetOpcode::G_CONSTANT: | |
| return selectI64Imm(I, MBB, MRI); | |
| } | |
| return false; | |
| } | |
| namespace llvm { | |
| InstructionSelector * | |
| createPPCInstructionSelector(const PPCTargetMachine &TM, | |
| const PPCSubtarget &Subtarget, | |
| const PPCRegisterBankInfo &RBI) { | |
| return new PPCInstructionSelector(TM, Subtarget, RBI); | |
| } | |
| } // end namespace llvm |