Path: blob/main/contrib/llvm-project/llvm/lib/Target/ARC/ARCInstrInfo.cpp
35266 views
//===- ARCInstrInfo.cpp - ARC Instruction Information -----------*- C++ -*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This file contains the ARC implementation of the TargetInstrInfo class.9//10//===----------------------------------------------------------------------===//1112#include "ARCInstrInfo.h"13#include "ARC.h"14#include "ARCMachineFunctionInfo.h"15#include "ARCSubtarget.h"16#include "MCTargetDesc/ARCInfo.h"17#include "llvm/CodeGen/MachineFrameInfo.h"18#include "llvm/CodeGen/MachineInstrBuilder.h"19#include "llvm/CodeGen/MachineMemOperand.h"20#include "llvm/MC/TargetRegistry.h"21#include "llvm/Support/Debug.h"2223using namespace llvm;2425#define GET_INSTRINFO_CTOR_DTOR26#include "ARCGenInstrInfo.inc"2728#define DEBUG_TYPE "arc-inst-info"2930enum AddrIncType {31NoAddInc = 0,32PreInc = 1,33PostInc = 2,34Scaled = 335};3637enum TSFlagsConstants {38TSF_AddrModeOff = 0,39TSF_AddModeMask = 340};4142// Pin the vtable to this file.43void ARCInstrInfo::anchor() {}4445ARCInstrInfo::ARCInstrInfo(const ARCSubtarget &ST)46: ARCGenInstrInfo(ARC::ADJCALLSTACKDOWN, ARC::ADJCALLSTACKUP), RI(ST) {}4748static bool isZeroImm(const MachineOperand &Op) {49return Op.isImm() && Op.getImm() == 0;50}5152static bool isLoad(int Opcode) {53return Opcode == ARC::LD_rs9 || Opcode == ARC::LDH_rs9 ||54Opcode == ARC::LDB_rs9;55}5657static bool isStore(int Opcode) {58return Opcode == ARC::ST_rs9 || Opcode == ARC::STH_rs9 ||59Opcode == ARC::STB_rs9;60}6162/// If the specified machine instruction is a direct63/// load from a stack slot, return the virtual or physical register number of64/// the destination along with the FrameIndex of the loaded stack slot. If65/// not, return 0. This predicate must return 0 if the instruction has66/// any side effects other than loading from the stack slot.67Register ARCInstrInfo::isLoadFromStackSlot(const MachineInstr &MI,68int &FrameIndex) const {69int Opcode = MI.getOpcode();70if (isLoad(Opcode)) {71if ((MI.getOperand(1).isFI()) && // is a stack slot72(MI.getOperand(2).isImm()) && // the imm is zero73(isZeroImm(MI.getOperand(2)))) {74FrameIndex = MI.getOperand(1).getIndex();75return MI.getOperand(0).getReg();76}77}78return 0;79}8081/// If the specified machine instruction is a direct82/// store to a stack slot, return the virtual or physical register number of83/// the source reg along with the FrameIndex of the loaded stack slot. If84/// not, return 0. This predicate must return 0 if the instruction has85/// any side effects other than storing to the stack slot.86Register ARCInstrInfo::isStoreToStackSlot(const MachineInstr &MI,87int &FrameIndex) const {88int Opcode = MI.getOpcode();89if (isStore(Opcode)) {90if ((MI.getOperand(1).isFI()) && // is a stack slot91(MI.getOperand(2).isImm()) && // the imm is zero92(isZeroImm(MI.getOperand(2)))) {93FrameIndex = MI.getOperand(1).getIndex();94return MI.getOperand(0).getReg();95}96}97return 0;98}99100/// Return the inverse of passed condition, i.e. turning COND_E to COND_NE.101static ARCCC::CondCode getOppositeBranchCondition(ARCCC::CondCode CC) {102switch (CC) {103default:104llvm_unreachable("Illegal condition code!");105case ARCCC::EQ:106return ARCCC::NE;107case ARCCC::NE:108return ARCCC::EQ;109case ARCCC::LO:110return ARCCC::HS;111case ARCCC::HS:112return ARCCC::LO;113case ARCCC::GT:114return ARCCC::LE;115case ARCCC::GE:116return ARCCC::LT;117case ARCCC::VS:118return ARCCC::VC;119case ARCCC::VC:120return ARCCC::VS;121case ARCCC::LT:122return ARCCC::GE;123case ARCCC::LE:124return ARCCC::GT;125case ARCCC::HI:126return ARCCC::LS;127case ARCCC::LS:128return ARCCC::HI;129case ARCCC::NZ:130return ARCCC::Z;131case ARCCC::Z:132return ARCCC::NZ;133}134}135136static bool isUncondBranchOpcode(int Opc) { return Opc == ARC::BR; }137138static bool isCondBranchOpcode(int Opc) {139return Opc == ARC::BRcc_rr_p || Opc == ARC::BRcc_ru6_p;140}141142static bool isJumpOpcode(int Opc) { return Opc == ARC::J; }143144/// Analyze the branching code at the end of MBB, returning145/// true if it cannot be understood (e.g. it's a switch dispatch or isn't146/// implemented for a target). Upon success, this returns false and returns147/// with the following information in various cases:148///149/// 1. If this block ends with no branches (it just falls through to its succ)150/// just return false, leaving TBB/FBB null.151/// 2. If this block ends with only an unconditional branch, it sets TBB to be152/// the destination block.153/// 3. If this block ends with a conditional branch and it falls through to a154/// successor block, it sets TBB to be the branch destination block and a155/// list of operands that evaluate the condition. These operands can be156/// passed to other TargetInstrInfo methods to create new branches.157/// 4. If this block ends with a conditional branch followed by an158/// unconditional branch, it returns the 'true' destination in TBB, the159/// 'false' destination in FBB, and a list of operands that evaluate the160/// condition. These operands can be passed to other TargetInstrInfo161/// methods to create new branches.162///163/// Note that RemoveBranch and insertBranch must be implemented to support164/// cases where this method returns success.165///166/// If AllowModify is true, then this routine is allowed to modify the basic167/// block (e.g. delete instructions after the unconditional branch).168169bool ARCInstrInfo::analyzeBranch(MachineBasicBlock &MBB,170MachineBasicBlock *&TBB,171MachineBasicBlock *&FBB,172SmallVectorImpl<MachineOperand> &Cond,173bool AllowModify) const {174TBB = FBB = nullptr;175MachineBasicBlock::iterator I = MBB.end();176if (I == MBB.begin())177return false;178--I;179180while (isPredicated(*I) || I->isTerminator() || I->isDebugValue()) {181// Flag to be raised on unanalyzeable instructions. This is useful in cases182// where we want to clean up on the end of the basic block before we bail183// out.184bool CantAnalyze = false;185186// Skip over DEBUG values and predicated nonterminators.187while (I->isDebugInstr() || !I->isTerminator()) {188if (I == MBB.begin())189return false;190--I;191}192193if (isJumpOpcode(I->getOpcode())) {194// Indirect branches and jump tables can't be analyzed, but we still want195// to clean up any instructions at the tail of the basic block.196CantAnalyze = true;197} else if (isUncondBranchOpcode(I->getOpcode())) {198TBB = I->getOperand(0).getMBB();199} else if (isCondBranchOpcode(I->getOpcode())) {200// Bail out if we encounter multiple conditional branches.201if (!Cond.empty())202return true;203204assert(!FBB && "FBB should have been null.");205FBB = TBB;206TBB = I->getOperand(0).getMBB();207Cond.push_back(I->getOperand(1));208Cond.push_back(I->getOperand(2));209Cond.push_back(I->getOperand(3));210} else if (I->isReturn()) {211// Returns can't be analyzed, but we should run cleanup.212CantAnalyze = !isPredicated(*I);213} else {214// We encountered other unrecognized terminator. Bail out immediately.215return true;216}217218// Cleanup code - to be run for unpredicated unconditional branches and219// returns.220if (!isPredicated(*I) && (isUncondBranchOpcode(I->getOpcode()) ||221isJumpOpcode(I->getOpcode()) || I->isReturn())) {222// Forget any previous condition branch information - it no longer223// applies.224Cond.clear();225FBB = nullptr;226227// If we can modify the function, delete everything below this228// unconditional branch.229if (AllowModify) {230MachineBasicBlock::iterator DI = std::next(I);231while (DI != MBB.end()) {232MachineInstr &InstToDelete = *DI;233++DI;234InstToDelete.eraseFromParent();235}236}237}238239if (CantAnalyze)240return true;241242if (I == MBB.begin())243return false;244245--I;246}247248// We made it past the terminators without bailing out - we must have249// analyzed this branch successfully.250return false;251}252253unsigned ARCInstrInfo::removeBranch(MachineBasicBlock &MBB,254int *BytesRemoved) const {255assert(!BytesRemoved && "Code size not handled");256MachineBasicBlock::iterator I = MBB.getLastNonDebugInstr();257if (I == MBB.end())258return 0;259260if (!isUncondBranchOpcode(I->getOpcode()) &&261!isCondBranchOpcode(I->getOpcode()))262return 0;263264// Remove the branch.265I->eraseFromParent();266267I = MBB.end();268269if (I == MBB.begin())270return 1;271--I;272if (!isCondBranchOpcode(I->getOpcode()))273return 1;274275// Remove the branch.276I->eraseFromParent();277return 2;278}279280void ARCInstrInfo::copyPhysReg(MachineBasicBlock &MBB,281MachineBasicBlock::iterator I,282const DebugLoc &DL, MCRegister DestReg,283MCRegister SrcReg, bool KillSrc) const {284assert(ARC::GPR32RegClass.contains(SrcReg) &&285"Only GPR32 src copy supported.");286assert(ARC::GPR32RegClass.contains(DestReg) &&287"Only GPR32 dest copy supported.");288BuildMI(MBB, I, DL, get(ARC::MOV_rr), DestReg)289.addReg(SrcReg, getKillRegState(KillSrc));290}291292void ARCInstrInfo::storeRegToStackSlot(293MachineBasicBlock &MBB, MachineBasicBlock::iterator I, Register SrcReg,294bool IsKill, int FrameIndex, const TargetRegisterClass *RC,295const TargetRegisterInfo *TRI, Register VReg) const {296DebugLoc DL = MBB.findDebugLoc(I);297MachineFunction &MF = *MBB.getParent();298MachineFrameInfo &MFI = MF.getFrameInfo();299300MachineMemOperand *MMO = MF.getMachineMemOperand(301MachinePointerInfo::getFixedStack(MF, FrameIndex),302MachineMemOperand::MOStore, MFI.getObjectSize(FrameIndex),303MFI.getObjectAlign(FrameIndex));304305assert(MMO && "Couldn't get MachineMemOperand for store to stack.");306assert(TRI->getSpillSize(*RC) == 4 &&307"Only support 4-byte stores to stack now.");308assert(ARC::GPR32RegClass.hasSubClassEq(RC) &&309"Only support GPR32 stores to stack now.");310LLVM_DEBUG(dbgs() << "Created store reg=" << printReg(SrcReg, TRI)311<< " to FrameIndex=" << FrameIndex << "\n");312BuildMI(MBB, I, DL, get(ARC::ST_rs9))313.addReg(SrcReg, getKillRegState(IsKill))314.addFrameIndex(FrameIndex)315.addImm(0)316.addMemOperand(MMO);317}318319void ARCInstrInfo::loadRegFromStackSlot(MachineBasicBlock &MBB,320MachineBasicBlock::iterator I,321Register DestReg, int FrameIndex,322const TargetRegisterClass *RC,323const TargetRegisterInfo *TRI,324Register VReg) const {325DebugLoc DL = MBB.findDebugLoc(I);326MachineFunction &MF = *MBB.getParent();327MachineFrameInfo &MFI = MF.getFrameInfo();328MachineMemOperand *MMO = MF.getMachineMemOperand(329MachinePointerInfo::getFixedStack(MF, FrameIndex),330MachineMemOperand::MOLoad, MFI.getObjectSize(FrameIndex),331MFI.getObjectAlign(FrameIndex));332333assert(MMO && "Couldn't get MachineMemOperand for store to stack.");334assert(TRI->getSpillSize(*RC) == 4 &&335"Only support 4-byte loads from stack now.");336assert(ARC::GPR32RegClass.hasSubClassEq(RC) &&337"Only support GPR32 stores to stack now.");338LLVM_DEBUG(dbgs() << "Created load reg=" << printReg(DestReg, TRI)339<< " from FrameIndex=" << FrameIndex << "\n");340BuildMI(MBB, I, DL, get(ARC::LD_rs9))341.addReg(DestReg, RegState::Define)342.addFrameIndex(FrameIndex)343.addImm(0)344.addMemOperand(MMO);345}346347/// Return the inverse opcode of the specified Branch instruction.348bool ARCInstrInfo::reverseBranchCondition(349SmallVectorImpl<MachineOperand> &Cond) const {350assert((Cond.size() == 3) && "Invalid ARC branch condition!");351Cond[2].setImm(getOppositeBranchCondition((ARCCC::CondCode)Cond[2].getImm()));352return false;353}354355MachineBasicBlock::iterator356ARCInstrInfo::loadImmediate(MachineBasicBlock &MBB,357MachineBasicBlock::iterator MI, unsigned Reg,358uint64_t Value) const {359DebugLoc DL = MBB.findDebugLoc(MI);360if (isInt<12>(Value)) {361return BuildMI(MBB, MI, DL, get(ARC::MOV_rs12), Reg)362.addImm(Value)363.getInstr();364}365llvm_unreachable("Need Arc long immediate instructions.");366}367368unsigned ARCInstrInfo::insertBranch(MachineBasicBlock &MBB,369MachineBasicBlock *TBB,370MachineBasicBlock *FBB,371ArrayRef<MachineOperand> Cond,372const DebugLoc &DL, int *BytesAdded) const {373assert(!BytesAdded && "Code size not handled.");374375// Shouldn't be a fall through.376assert(TBB && "insertBranch must not be told to insert a fallthrough");377assert((Cond.size() == 3 || Cond.size() == 0) &&378"ARC branch conditions have two components!");379380if (Cond.empty()) {381BuildMI(&MBB, DL, get(ARC::BR)).addMBB(TBB);382return 1;383}384int BccOpc = Cond[1].isImm() ? ARC::BRcc_ru6_p : ARC::BRcc_rr_p;385MachineInstrBuilder MIB = BuildMI(&MBB, DL, get(BccOpc));386MIB.addMBB(TBB);387for (unsigned i = 0; i < 3; i++) {388MIB.add(Cond[i]);389}390391// One-way conditional branch.392if (!FBB) {393return 1;394}395396// Two-way conditional branch.397BuildMI(&MBB, DL, get(ARC::BR)).addMBB(FBB);398return 2;399}400401unsigned ARCInstrInfo::getInstSizeInBytes(const MachineInstr &MI) const {402if (MI.isInlineAsm()) {403const MachineFunction *MF = MI.getParent()->getParent();404const char *AsmStr = MI.getOperand(0).getSymbolName();405return getInlineAsmLength(AsmStr, *MF->getTarget().getMCAsmInfo());406}407return MI.getDesc().getSize();408}409410bool ARCInstrInfo::isPostIncrement(const MachineInstr &MI) const {411const MCInstrDesc &MID = MI.getDesc();412const uint64_t F = MID.TSFlags;413return ((F >> TSF_AddrModeOff) & TSF_AddModeMask) == PostInc;414}415416bool ARCInstrInfo::isPreIncrement(const MachineInstr &MI) const {417const MCInstrDesc &MID = MI.getDesc();418const uint64_t F = MID.TSFlags;419return ((F >> TSF_AddrModeOff) & TSF_AddModeMask) == PreInc;420}421422bool ARCInstrInfo::getBaseAndOffsetPosition(const MachineInstr &MI,423unsigned &BasePos,424unsigned &OffsetPos) const {425if (!MI.mayLoad() && !MI.mayStore())426return false;427428BasePos = 1;429OffsetPos = 2;430431if (isPostIncrement(MI) || isPreIncrement(MI)) {432BasePos++;433OffsetPos++;434}435436if (!MI.getOperand(BasePos).isReg() || !MI.getOperand(OffsetPos).isImm())437return false;438439return true;440}441442443