RegisterBankInfo::InstructionMapping RegisterBankInfo::getInstrMapping(const MachineInstr &MI) const { RegisterBankInfo::InstructionMapping Mapping = getInstrMappingImpl(MI); if (Mapping.isValid()) return Mapping; llvm_unreachable("The target must implement this"); }
RegisterBankInfo::InstructionMapping AArch64RegisterBankInfo::getInstrMapping(const MachineInstr &MI) const { RegisterBankInfo::InstructionMapping Mapping = getInstrMappingImpl(MI); if (Mapping.isValid()) return Mapping; // As a top-level guess, vectors go in FPRs, scalars in GPRs. Obviously this // won't work for normal floating-point types (or NZCV). When such // instructions exist we'll need to look at the MI's opcode. LLT Ty = MI.getType(); unsigned BankID; if (Ty.isVector()) BankID = AArch64::FPRRegBankID; else BankID = AArch64::GPRRegBankID; Mapping = InstructionMapping{1, 1, MI.getNumOperands()}; int Size = Ty.isSized() ? Ty.getSizeInBits() : 0; for (unsigned Idx = 0; Idx < MI.getNumOperands(); ++Idx) Mapping.setOperandMapping(Idx, Size, getRegBank(BankID)); return Mapping; }
RegisterBankInfo::InstructionMapping AArch64RegisterBankInfo::getInstrMapping(const MachineInstr &MI) const { const unsigned Opc = MI.getOpcode(); const MachineFunction &MF = *MI.getParent()->getParent(); const MachineRegisterInfo &MRI = MF.getRegInfo(); // Try the default logic for non-generic instructions that are either copies // or already have some operands assigned to banks. if (!isPreISelGenericOpcode(Opc)) { RegisterBankInfo::InstructionMapping Mapping = getInstrMappingImpl(MI); if (Mapping.isValid()) return Mapping; } RegisterBankInfo::InstructionMapping Mapping = InstructionMapping{DefaultMappingID, 1, MI.getNumOperands()}; // Track the size and bank of each register. We don't do partial mappings. SmallVector<unsigned, 4> OpBaseIdx(MI.getNumOperands()); SmallVector<unsigned, 4> OpFinalIdx(MI.getNumOperands()); for (unsigned Idx = 0; Idx < MI.getNumOperands(); ++Idx) { auto &MO = MI.getOperand(Idx); if (!MO.isReg()) continue; LLT Ty = MRI.getType(MO.getReg()); unsigned RBIdx = AArch64::getRegBankBaseIdx(Ty.getSizeInBits()); OpBaseIdx[Idx] = RBIdx; // As a top-level guess, vectors go in FPRs, scalars and pointers in GPRs. // For floating-point instructions, scalars go in FPRs. if (Ty.isVector() || isPreISelGenericFloatingPointOpcode(Opc)) { assert(RBIdx < (AArch64::LastFPR - AArch64::FirstFPR) + 1 && "Index out of bound"); OpFinalIdx[Idx] = AArch64::FirstFPR + RBIdx; } else { assert(RBIdx < (AArch64::LastGPR - AArch64::FirstGPR) + 1 && "Index out of bound"); OpFinalIdx[Idx] = AArch64::FirstGPR + RBIdx; } } // Some of the floating-point instructions have mixed GPR and FPR operands: // fine-tune the computed mapping. switch (Opc) { case TargetOpcode::G_SITOFP: case TargetOpcode::G_UITOFP: { OpFinalIdx = {OpBaseIdx[0] + AArch64::FirstFPR, OpBaseIdx[1] + AArch64::FirstGPR}; break; } case TargetOpcode::G_FPTOSI: case TargetOpcode::G_FPTOUI: { OpFinalIdx = {OpBaseIdx[0] + AArch64::FirstGPR, OpBaseIdx[1] + AArch64::FirstFPR}; break; } case TargetOpcode::G_FCMP: { OpFinalIdx = {OpBaseIdx[0] + AArch64::FirstGPR, /* Predicate */ 0, OpBaseIdx[2] + AArch64::FirstFPR, OpBaseIdx[3] + AArch64::FirstFPR}; break; } } // Finally construct the computed mapping. for (unsigned Idx = 0; Idx < MI.getNumOperands(); ++Idx) if (MI.getOperand(Idx).isReg()) Mapping.setOperandMapping( Idx, ValueMapping{&AArch64::PartMappings[OpFinalIdx[Idx]], 1}); return Mapping; }
RegisterBankInfo::InstructionMapping AArch64RegisterBankInfo::getInstrMapping(const MachineInstr &MI) const { const unsigned Opc = MI.getOpcode(); const MachineFunction &MF = *MI.getParent()->getParent(); const MachineRegisterInfo &MRI = MF.getRegInfo(); // Try the default logic for non-generic instructions that are either copies // or already have some operands assigned to banks. if (!isPreISelGenericOpcode(Opc)) { RegisterBankInfo::InstructionMapping Mapping = getInstrMappingImpl(MI); if (Mapping.isValid()) return Mapping; } switch (Opc) { // G_{F|S|U}REM are not listed because they are not legal. // Arithmetic ops. case TargetOpcode::G_ADD: case TargetOpcode::G_SUB: case TargetOpcode::G_GEP: case TargetOpcode::G_MUL: case TargetOpcode::G_SDIV: case TargetOpcode::G_UDIV: // Bitwise ops. case TargetOpcode::G_AND: case TargetOpcode::G_OR: case TargetOpcode::G_XOR: // Shifts. case TargetOpcode::G_SHL: case TargetOpcode::G_LSHR: case TargetOpcode::G_ASHR: // Floating point ops. case TargetOpcode::G_FADD: case TargetOpcode::G_FSUB: case TargetOpcode::G_FMUL: case TargetOpcode::G_FDIV: return getSameKindOfOperandsMapping(MI); case TargetOpcode::G_BITCAST: { LLT DstTy = MRI.getType(MI.getOperand(0).getReg()); LLT SrcTy = MRI.getType(MI.getOperand(1).getReg()); unsigned Size = DstTy.getSizeInBits(); bool DstIsGPR = !DstTy.isVector(); bool SrcIsGPR = !SrcTy.isVector(); const RegisterBank &DstRB = DstIsGPR ? AArch64::GPRRegBank : AArch64::FPRRegBank; const RegisterBank &SrcRB = SrcIsGPR ? AArch64::GPRRegBank : AArch64::FPRRegBank; return InstructionMapping{ DefaultMappingID, copyCost(DstRB, SrcRB, Size), getCopyMapping(DstRB.getID(), SrcRB.getID(), Size), /*NumOperands*/ 2}; } case TargetOpcode::G_SEQUENCE: // FIXME: support this, but the generic code is really not going to do // anything sane. return InstructionMapping(); default: break; } unsigned NumOperands = MI.getNumOperands(); // Track the size and bank of each register. We don't do partial mappings. SmallVector<unsigned, 4> OpSize(NumOperands); SmallVector<PartialMappingIdx, 4> OpRegBankIdx(NumOperands); for (unsigned Idx = 0; Idx < NumOperands; ++Idx) { auto &MO = MI.getOperand(Idx); if (!MO.isReg() || !MO.getReg()) continue; LLT Ty = MRI.getType(MO.getReg()); OpSize[Idx] = Ty.getSizeInBits(); // As a top-level guess, vectors go in FPRs, scalars and pointers in GPRs. // For floating-point instructions, scalars go in FPRs. if (Ty.isVector() || isPreISelGenericFloatingPointOpcode(Opc)) OpRegBankIdx[Idx] = PMI_FirstFPR; else OpRegBankIdx[Idx] = PMI_FirstGPR; } unsigned Cost = 1; // Some of the floating-point instructions have mixed GPR and FPR operands: // fine-tune the computed mapping. switch (Opc) { case TargetOpcode::G_SITOFP: case TargetOpcode::G_UITOFP: OpRegBankIdx = {PMI_FirstFPR, PMI_FirstGPR}; break; case TargetOpcode::G_FPTOSI: case TargetOpcode::G_FPTOUI: OpRegBankIdx = {PMI_FirstGPR, PMI_FirstFPR}; break; case TargetOpcode::G_FCMP: OpRegBankIdx = {PMI_FirstGPR, /* Predicate */ PMI_None, PMI_FirstFPR, PMI_FirstFPR}; break; case TargetOpcode::G_BITCAST: // This is going to be a cross register bank copy and this is expensive. if (OpRegBankIdx[0] != OpRegBankIdx[1]) Cost = copyCost( *AArch64GenRegisterBankInfo::PartMappings[OpRegBankIdx[0]].RegBank, *AArch64GenRegisterBankInfo::PartMappings[OpRegBankIdx[1]].RegBank, OpSize[0]); break; case TargetOpcode::G_LOAD: // Loading in vector unit is slightly more expensive. // This is actually only true for the LD1R and co instructions, // but anyway for the fast mode this number does not matter and // for the greedy mode the cost of the cross bank copy will // offset this number. // FIXME: Should be derived from the scheduling model. if (OpRegBankIdx[0] >= PMI_FirstFPR) Cost = 2; break; } // Finally construct the computed mapping. RegisterBankInfo::InstructionMapping Mapping = InstructionMapping{DefaultMappingID, Cost, nullptr, NumOperands}; SmallVector<const ValueMapping *, 8> OpdsMapping(NumOperands); for (unsigned Idx = 0; Idx < NumOperands; ++Idx) { if (MI.getOperand(Idx).isReg() && MI.getOperand(Idx).getReg()) { auto Mapping = getValueMapping(OpRegBankIdx[Idx], OpSize[Idx]); if (!Mapping->isValid()) return InstructionMapping(); OpdsMapping[Idx] = Mapping; } } Mapping.setOperandsMapping(getOperandsMapping(OpdsMapping)); return Mapping; }