444 lines · cpp
1//===- ARCInstrInfo.cpp - ARC Instruction Information -----------*- C++ -*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This file contains the ARC implementation of the TargetInstrInfo class.10//11//===----------------------------------------------------------------------===//12 13#include "ARCInstrInfo.h"14#include "ARC.h"15#include "ARCMachineFunctionInfo.h"16#include "ARCSubtarget.h"17#include "MCTargetDesc/ARCInfo.h"18#include "llvm/CodeGen/MachineFrameInfo.h"19#include "llvm/CodeGen/MachineInstrBuilder.h"20#include "llvm/CodeGen/MachineMemOperand.h"21#include "llvm/MC/TargetRegistry.h"22#include "llvm/Support/Debug.h"23 24using namespace llvm;25 26#define GET_INSTRINFO_CTOR_DTOR27#include "ARCGenInstrInfo.inc"28 29#define DEBUG_TYPE "arc-inst-info"30 31enum AddrIncType {32 NoAddInc = 0,33 PreInc = 1,34 PostInc = 2,35 Scaled = 336};37 38enum TSFlagsConstants {39 TSF_AddrModeOff = 0,40 TSF_AddModeMask = 341};42 43// Pin the vtable to this file.44void ARCInstrInfo::anchor() {}45 46ARCInstrInfo::ARCInstrInfo(const ARCSubtarget &ST)47 : ARCGenInstrInfo(ST, RI, ARC::ADJCALLSTACKDOWN, ARC::ADJCALLSTACKUP),48 RI(ST) {}49 50static bool isZeroImm(const MachineOperand &Op) {51 return Op.isImm() && Op.getImm() == 0;52}53 54static bool isLoad(int Opcode) {55 return Opcode == ARC::LD_rs9 || Opcode == ARC::LDH_rs9 ||56 Opcode == ARC::LDB_rs9;57}58 59static bool isStore(int Opcode) {60 return Opcode == ARC::ST_rs9 || Opcode == ARC::STH_rs9 ||61 Opcode == ARC::STB_rs9;62}63 64/// If the specified machine instruction is a direct65/// load from a stack slot, return the virtual or physical register number of66/// the destination along with the FrameIndex of the loaded stack slot. If67/// not, return 0. This predicate must return 0 if the instruction has68/// any side effects other than loading from the stack slot.69Register ARCInstrInfo::isLoadFromStackSlot(const MachineInstr &MI,70 int &FrameIndex) const {71 int Opcode = MI.getOpcode();72 if (isLoad(Opcode)) {73 if ((MI.getOperand(1).isFI()) && // is a stack slot74 (MI.getOperand(2).isImm()) && // the imm is zero75 (isZeroImm(MI.getOperand(2)))) {76 FrameIndex = MI.getOperand(1).getIndex();77 return MI.getOperand(0).getReg();78 }79 }80 return 0;81}82 83/// If the specified machine instruction is a direct84/// store to a stack slot, return the virtual or physical register number of85/// the source reg along with the FrameIndex of the loaded stack slot. If86/// not, return 0. This predicate must return 0 if the instruction has87/// any side effects other than storing to the stack slot.88Register ARCInstrInfo::isStoreToStackSlot(const MachineInstr &MI,89 int &FrameIndex) const {90 int Opcode = MI.getOpcode();91 if (isStore(Opcode)) {92 if ((MI.getOperand(1).isFI()) && // is a stack slot93 (MI.getOperand(2).isImm()) && // the imm is zero94 (isZeroImm(MI.getOperand(2)))) {95 FrameIndex = MI.getOperand(1).getIndex();96 return MI.getOperand(0).getReg();97 }98 }99 return 0;100}101 102/// Return the inverse of passed condition, i.e. turning COND_E to COND_NE.103static ARCCC::CondCode getOppositeBranchCondition(ARCCC::CondCode CC) {104 switch (CC) {105 default:106 llvm_unreachable("Illegal condition code!");107 case ARCCC::EQ:108 return ARCCC::NE;109 case ARCCC::NE:110 return ARCCC::EQ;111 case ARCCC::LO:112 return ARCCC::HS;113 case ARCCC::HS:114 return ARCCC::LO;115 case ARCCC::GT:116 return ARCCC::LE;117 case ARCCC::GE:118 return ARCCC::LT;119 case ARCCC::VS:120 return ARCCC::VC;121 case ARCCC::VC:122 return ARCCC::VS;123 case ARCCC::LT:124 return ARCCC::GE;125 case ARCCC::LE:126 return ARCCC::GT;127 case ARCCC::HI:128 return ARCCC::LS;129 case ARCCC::LS:130 return ARCCC::HI;131 case ARCCC::NZ:132 return ARCCC::Z;133 case ARCCC::Z:134 return ARCCC::NZ;135 }136}137 138static bool isUncondBranchOpcode(int Opc) { return Opc == ARC::BR; }139 140static bool isCondBranchOpcode(int Opc) {141 return Opc == ARC::BRcc_rr_p || Opc == ARC::BRcc_ru6_p;142}143 144static bool isJumpOpcode(int Opc) { return Opc == ARC::J; }145 146/// Analyze the branching code at the end of MBB, returning147/// true if it cannot be understood (e.g. it's a switch dispatch or isn't148/// implemented for a target). Upon success, this returns false and returns149/// with the following information in various cases:150///151/// 1. If this block ends with no branches (it just falls through to its succ)152/// just return false, leaving TBB/FBB null.153/// 2. If this block ends with only an unconditional branch, it sets TBB to be154/// the destination block.155/// 3. If this block ends with a conditional branch and it falls through to a156/// successor block, it sets TBB to be the branch destination block and a157/// list of operands that evaluate the condition. These operands can be158/// passed to other TargetInstrInfo methods to create new branches.159/// 4. If this block ends with a conditional branch followed by an160/// unconditional branch, it returns the 'true' destination in TBB, the161/// 'false' destination in FBB, and a list of operands that evaluate the162/// condition. These operands can be passed to other TargetInstrInfo163/// methods to create new branches.164///165/// Note that RemoveBranch and insertBranch must be implemented to support166/// cases where this method returns success.167///168/// If AllowModify is true, then this routine is allowed to modify the basic169/// block (e.g. delete instructions after the unconditional branch).170 171bool ARCInstrInfo::analyzeBranch(MachineBasicBlock &MBB,172 MachineBasicBlock *&TBB,173 MachineBasicBlock *&FBB,174 SmallVectorImpl<MachineOperand> &Cond,175 bool AllowModify) const {176 TBB = FBB = nullptr;177 MachineBasicBlock::iterator I = MBB.end();178 if (I == MBB.begin())179 return false;180 --I;181 182 while (isPredicated(*I) || I->isTerminator() || I->isDebugValue()) {183 // Flag to be raised on unanalyzeable instructions. This is useful in cases184 // where we want to clean up on the end of the basic block before we bail185 // out.186 bool CantAnalyze = false;187 188 // Skip over DEBUG values and predicated nonterminators.189 while (I->isDebugInstr() || !I->isTerminator()) {190 if (I == MBB.begin())191 return false;192 --I;193 }194 195 if (isJumpOpcode(I->getOpcode())) {196 // Indirect branches and jump tables can't be analyzed, but we still want197 // to clean up any instructions at the tail of the basic block.198 CantAnalyze = true;199 } else if (isUncondBranchOpcode(I->getOpcode())) {200 TBB = I->getOperand(0).getMBB();201 } else if (isCondBranchOpcode(I->getOpcode())) {202 // Bail out if we encounter multiple conditional branches.203 if (!Cond.empty())204 return true;205 206 assert(!FBB && "FBB should have been null.");207 FBB = TBB;208 TBB = I->getOperand(0).getMBB();209 Cond.push_back(I->getOperand(1));210 Cond.push_back(I->getOperand(2));211 Cond.push_back(I->getOperand(3));212 } else if (I->isReturn()) {213 // Returns can't be analyzed, but we should run cleanup.214 CantAnalyze = !isPredicated(*I);215 } else {216 // We encountered other unrecognized terminator. Bail out immediately.217 return true;218 }219 220 // Cleanup code - to be run for unpredicated unconditional branches and221 // returns.222 if (!isPredicated(*I) && (isUncondBranchOpcode(I->getOpcode()) ||223 isJumpOpcode(I->getOpcode()) || I->isReturn())) {224 // Forget any previous condition branch information - it no longer225 // applies.226 Cond.clear();227 FBB = nullptr;228 229 // If we can modify the function, delete everything below this230 // unconditional branch.231 if (AllowModify) {232 MachineBasicBlock::iterator DI = std::next(I);233 while (DI != MBB.end()) {234 MachineInstr &InstToDelete = *DI;235 ++DI;236 InstToDelete.eraseFromParent();237 }238 }239 }240 241 if (CantAnalyze)242 return true;243 244 if (I == MBB.begin())245 return false;246 247 --I;248 }249 250 // We made it past the terminators without bailing out - we must have251 // analyzed this branch successfully.252 return false;253}254 255unsigned ARCInstrInfo::removeBranch(MachineBasicBlock &MBB,256 int *BytesRemoved) const {257 assert(!BytesRemoved && "Code size not handled");258 MachineBasicBlock::iterator I = MBB.getLastNonDebugInstr();259 if (I == MBB.end())260 return 0;261 262 if (!isUncondBranchOpcode(I->getOpcode()) &&263 !isCondBranchOpcode(I->getOpcode()))264 return 0;265 266 // Remove the branch.267 I->eraseFromParent();268 269 I = MBB.end();270 271 if (I == MBB.begin())272 return 1;273 --I;274 if (!isCondBranchOpcode(I->getOpcode()))275 return 1;276 277 // Remove the branch.278 I->eraseFromParent();279 return 2;280}281 282void ARCInstrInfo::copyPhysReg(MachineBasicBlock &MBB,283 MachineBasicBlock::iterator I,284 const DebugLoc &DL, Register DestReg,285 Register SrcReg, bool KillSrc,286 bool RenamableDest, bool RenamableSrc) const {287 assert(ARC::GPR32RegClass.contains(SrcReg) &&288 "Only GPR32 src copy supported.");289 assert(ARC::GPR32RegClass.contains(DestReg) &&290 "Only GPR32 dest copy supported.");291 BuildMI(MBB, I, DL, get(ARC::MOV_rr), DestReg)292 .addReg(SrcReg, getKillRegState(KillSrc));293}294 295void ARCInstrInfo::storeRegToStackSlot(296 MachineBasicBlock &MBB, MachineBasicBlock::iterator I, Register SrcReg,297 bool IsKill, int FrameIndex, const TargetRegisterClass *RC, Register VReg,298 MachineInstr::MIFlag Flags) const {299 DebugLoc DL = MBB.findDebugLoc(I);300 MachineFunction &MF = *MBB.getParent();301 MachineFrameInfo &MFI = MF.getFrameInfo();302 303 MachineMemOperand *MMO = MF.getMachineMemOperand(304 MachinePointerInfo::getFixedStack(MF, FrameIndex),305 MachineMemOperand::MOStore, MFI.getObjectSize(FrameIndex),306 MFI.getObjectAlign(FrameIndex));307 308 assert(MMO && "Couldn't get MachineMemOperand for store to stack.");309 assert(TRI.getSpillSize(*RC) == 4 &&310 "Only support 4-byte stores to stack now.");311 assert(ARC::GPR32RegClass.hasSubClassEq(RC) &&312 "Only support GPR32 stores to stack now.");313 LLVM_DEBUG(dbgs() << "Created store reg=" << printReg(SrcReg, &TRI)314 << " to FrameIndex=" << FrameIndex << "\n");315 BuildMI(MBB, I, DL, get(ARC::ST_rs9))316 .addReg(SrcReg, getKillRegState(IsKill))317 .addFrameIndex(FrameIndex)318 .addImm(0)319 .addMemOperand(MMO);320}321 322void ARCInstrInfo::loadRegFromStackSlot(MachineBasicBlock &MBB,323 MachineBasicBlock::iterator I,324 Register DestReg, int FrameIndex,325 const TargetRegisterClass *RC,326 Register VReg,327 MachineInstr::MIFlag Flags) const {328 DebugLoc DL = MBB.findDebugLoc(I);329 MachineFunction &MF = *MBB.getParent();330 MachineFrameInfo &MFI = MF.getFrameInfo();331 MachineMemOperand *MMO = MF.getMachineMemOperand(332 MachinePointerInfo::getFixedStack(MF, FrameIndex),333 MachineMemOperand::MOLoad, MFI.getObjectSize(FrameIndex),334 MFI.getObjectAlign(FrameIndex));335 336 assert(MMO && "Couldn't get MachineMemOperand for store to stack.");337 assert(TRI.getSpillSize(*RC) == 4 &&338 "Only support 4-byte loads from stack now.");339 assert(ARC::GPR32RegClass.hasSubClassEq(RC) &&340 "Only support GPR32 stores to stack now.");341 LLVM_DEBUG(dbgs() << "Created load reg=" << printReg(DestReg, &TRI)342 << " from FrameIndex=" << FrameIndex << "\n");343 BuildMI(MBB, I, DL, get(ARC::LD_rs9))344 .addReg(DestReg, RegState::Define)345 .addFrameIndex(FrameIndex)346 .addImm(0)347 .addMemOperand(MMO);348}349 350/// Return the inverse opcode of the specified Branch instruction.351bool ARCInstrInfo::reverseBranchCondition(352 SmallVectorImpl<MachineOperand> &Cond) const {353 assert((Cond.size() == 3) && "Invalid ARC branch condition!");354 Cond[2].setImm(getOppositeBranchCondition((ARCCC::CondCode)Cond[2].getImm()));355 return false;356}357 358MachineBasicBlock::iterator359ARCInstrInfo::loadImmediate(MachineBasicBlock &MBB,360 MachineBasicBlock::iterator MI, unsigned Reg,361 uint64_t Value) const {362 DebugLoc DL = MBB.findDebugLoc(MI);363 if (isInt<12>(Value)) {364 return BuildMI(MBB, MI, DL, get(ARC::MOV_rs12), Reg)365 .addImm(Value)366 .getInstr();367 }368 llvm_unreachable("Need Arc long immediate instructions.");369}370 371unsigned ARCInstrInfo::insertBranch(MachineBasicBlock &MBB,372 MachineBasicBlock *TBB,373 MachineBasicBlock *FBB,374 ArrayRef<MachineOperand> Cond,375 const DebugLoc &DL, int *BytesAdded) const {376 assert(!BytesAdded && "Code size not handled.");377 378 // Shouldn't be a fall through.379 assert(TBB && "insertBranch must not be told to insert a fallthrough");380 assert((Cond.size() == 3 || Cond.size() == 0) &&381 "ARC branch conditions have two components!");382 383 if (Cond.empty()) {384 BuildMI(&MBB, DL, get(ARC::BR)).addMBB(TBB);385 return 1;386 }387 int BccOpc = Cond[1].isImm() ? ARC::BRcc_ru6_p : ARC::BRcc_rr_p;388 MachineInstrBuilder MIB = BuildMI(&MBB, DL, get(BccOpc));389 MIB.addMBB(TBB);390 for (unsigned i = 0; i < 3; i++) {391 MIB.add(Cond[i]);392 }393 394 // One-way conditional branch.395 if (!FBB) {396 return 1;397 }398 399 // Two-way conditional branch.400 BuildMI(&MBB, DL, get(ARC::BR)).addMBB(FBB);401 return 2;402}403 404unsigned ARCInstrInfo::getInstSizeInBytes(const MachineInstr &MI) const {405 if (MI.isInlineAsm()) {406 const MachineFunction *MF = MI.getParent()->getParent();407 const char *AsmStr = MI.getOperand(0).getSymbolName();408 return getInlineAsmLength(AsmStr, *MF->getTarget().getMCAsmInfo());409 }410 return MI.getDesc().getSize();411}412 413bool ARCInstrInfo::isPostIncrement(const MachineInstr &MI) const {414 const MCInstrDesc &MID = MI.getDesc();415 const uint64_t F = MID.TSFlags;416 return ((F >> TSF_AddrModeOff) & TSF_AddModeMask) == PostInc;417}418 419bool ARCInstrInfo::isPreIncrement(const MachineInstr &MI) const {420 const MCInstrDesc &MID = MI.getDesc();421 const uint64_t F = MID.TSFlags;422 return ((F >> TSF_AddrModeOff) & TSF_AddModeMask) == PreInc;423}424 425bool ARCInstrInfo::getBaseAndOffsetPosition(const MachineInstr &MI,426 unsigned &BasePos,427 unsigned &OffsetPos) const {428 if (!MI.mayLoad() && !MI.mayStore())429 return false;430 431 BasePos = 1;432 OffsetPos = 2;433 434 if (isPostIncrement(MI) || isPreIncrement(MI)) {435 BasePos++;436 OffsetPos++;437 }438 439 if (!MI.getOperand(BasePos).isReg() || !MI.getOperand(OffsetPos).isImm())440 return false;441 442 return true;443}444