Files
clang-p2996/llvm/lib/Target/ARM/MCTargetDesc/ARMMCTargetDesc.cpp
Reid Kleckner 89b57061f7 Move TargetRegistry.(h|cpp) from Support to MC
This moves the registry higher in the LLVM library dependency stack.
Every client of the target registry needs to link against MC anyway to
actually use the target, so we might as well move this out of Support.

This allows us to ensure that Support doesn't have includes from MC/*.

Differential Revision: https://reviews.llvm.org/D111454
2021-10-08 14:51:48 -07:00

705 lines
26 KiB
C++

//===-- ARMMCTargetDesc.cpp - ARM Target Descriptions ---------------------===//
//
// 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 provides ARM specific target descriptions.
//
//===----------------------------------------------------------------------===//
#include "ARMMCTargetDesc.h"
#include "ARMAddressingModes.h"
#include "ARMBaseInfo.h"
#include "ARMInstPrinter.h"
#include "ARMMCAsmInfo.h"
#include "TargetInfo/ARMTargetInfo.h"
#include "llvm/ADT/Triple.h"
#include "llvm/DebugInfo/CodeView/CodeView.h"
#include "llvm/MC/MCAsmBackend.h"
#include "llvm/MC/MCCodeEmitter.h"
#include "llvm/MC/MCELFStreamer.h"
#include "llvm/MC/MCInstrAnalysis.h"
#include "llvm/MC/MCInstrInfo.h"
#include "llvm/MC/MCObjectWriter.h"
#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/MC/MCStreamer.h"
#include "llvm/MC/MCSubtargetInfo.h"
#include "llvm/MC/TargetRegistry.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/TargetParser.h"
using namespace llvm;
#define GET_REGINFO_MC_DESC
#include "ARMGenRegisterInfo.inc"
static bool getMCRDeprecationInfo(MCInst &MI, const MCSubtargetInfo &STI,
std::string &Info) {
if (STI.getFeatureBits()[llvm::ARM::HasV7Ops] &&
(MI.getOperand(0).isImm() && MI.getOperand(0).getImm() == 15) &&
(MI.getOperand(1).isImm() && MI.getOperand(1).getImm() == 0) &&
// Checks for the deprecated CP15ISB encoding:
// mcr p15, #0, rX, c7, c5, #4
(MI.getOperand(3).isImm() && MI.getOperand(3).getImm() == 7)) {
if ((MI.getOperand(5).isImm() && MI.getOperand(5).getImm() == 4)) {
if (MI.getOperand(4).isImm() && MI.getOperand(4).getImm() == 5) {
Info = "deprecated since v7, use 'isb'";
return true;
}
// Checks for the deprecated CP15DSB encoding:
// mcr p15, #0, rX, c7, c10, #4
if (MI.getOperand(4).isImm() && MI.getOperand(4).getImm() == 10) {
Info = "deprecated since v7, use 'dsb'";
return true;
}
}
// Checks for the deprecated CP15DMB encoding:
// mcr p15, #0, rX, c7, c10, #5
if (MI.getOperand(4).isImm() && MI.getOperand(4).getImm() == 10 &&
(MI.getOperand(5).isImm() && MI.getOperand(5).getImm() == 5)) {
Info = "deprecated since v7, use 'dmb'";
return true;
}
}
if (STI.getFeatureBits()[llvm::ARM::HasV7Ops] &&
((MI.getOperand(0).isImm() && MI.getOperand(0).getImm() == 10) ||
(MI.getOperand(0).isImm() && MI.getOperand(0).getImm() == 11))) {
Info = "since v7, cp10 and cp11 are reserved for advanced SIMD or floating "
"point instructions";
return true;
}
return false;
}
static bool getMRCDeprecationInfo(MCInst &MI, const MCSubtargetInfo &STI,
std::string &Info) {
if (STI.getFeatureBits()[llvm::ARM::HasV7Ops] &&
((MI.getOperand(0).isImm() && MI.getOperand(0).getImm() == 10) ||
(MI.getOperand(0).isImm() && MI.getOperand(0).getImm() == 11))) {
Info = "since v7, cp10 and cp11 are reserved for advanced SIMD or floating "
"point instructions";
return true;
}
return false;
}
static bool getITDeprecationInfo(MCInst &MI, const MCSubtargetInfo &STI,
std::string &Info) {
if (STI.getFeatureBits()[llvm::ARM::HasV8Ops] && MI.getOperand(1).isImm() &&
MI.getOperand(1).getImm() != 8) {
Info = "applying IT instruction to more than one subsequent instruction is "
"deprecated";
return true;
}
return false;
}
static bool getARMStoreDeprecationInfo(MCInst &MI, const MCSubtargetInfo &STI,
std::string &Info) {
assert(!STI.getFeatureBits()[llvm::ARM::ModeThumb] &&
"cannot predicate thumb instructions");
assert(MI.getNumOperands() >= 4 && "expected >= 4 arguments");
for (unsigned OI = 4, OE = MI.getNumOperands(); OI < OE; ++OI) {
assert(MI.getOperand(OI).isReg() && "expected register");
if (MI.getOperand(OI).getReg() == ARM::PC) {
Info = "use of PC in the list is deprecated";
return true;
}
}
return false;
}
static bool getARMLoadDeprecationInfo(MCInst &MI, const MCSubtargetInfo &STI,
std::string &Info) {
assert(!STI.getFeatureBits()[llvm::ARM::ModeThumb] &&
"cannot predicate thumb instructions");
assert(MI.getNumOperands() >= 4 && "expected >= 4 arguments");
bool ListContainsPC = false, ListContainsLR = false;
for (unsigned OI = 4, OE = MI.getNumOperands(); OI < OE; ++OI) {
assert(MI.getOperand(OI).isReg() && "expected register");
switch (MI.getOperand(OI).getReg()) {
default:
break;
case ARM::LR:
ListContainsLR = true;
break;
case ARM::PC:
ListContainsPC = true;
break;
}
}
if (ListContainsPC && ListContainsLR) {
Info = "use of LR and PC simultaneously in the list is deprecated";
return true;
}
return false;
}
#define GET_INSTRINFO_MC_DESC
#include "ARMGenInstrInfo.inc"
#define GET_SUBTARGETINFO_MC_DESC
#include "ARMGenSubtargetInfo.inc"
std::string ARM_MC::ParseARMTriple(const Triple &TT, StringRef CPU) {
std::string ARMArchFeature;
ARM::ArchKind ArchID = ARM::parseArch(TT.getArchName());
if (ArchID != ARM::ArchKind::INVALID && (CPU.empty() || CPU == "generic"))
ARMArchFeature = (ARMArchFeature + "+" + ARM::getArchName(ArchID)).str();
if (TT.isThumb()) {
if (!ARMArchFeature.empty())
ARMArchFeature += ",";
ARMArchFeature += "+thumb-mode,+v4t";
}
if (TT.isOSNaCl()) {
if (!ARMArchFeature.empty())
ARMArchFeature += ",";
ARMArchFeature += "+nacl-trap";
}
if (TT.isOSWindows()) {
if (!ARMArchFeature.empty())
ARMArchFeature += ",";
ARMArchFeature += "+noarm";
}
return ARMArchFeature;
}
bool ARM_MC::isPredicated(const MCInst &MI, const MCInstrInfo *MCII) {
const MCInstrDesc &Desc = MCII->get(MI.getOpcode());
int PredOpIdx = Desc.findFirstPredOperandIdx();
return PredOpIdx != -1 && MI.getOperand(PredOpIdx).getImm() != ARMCC::AL;
}
bool ARM_MC::isCPSRDefined(const MCInst &MI, const MCInstrInfo *MCII) {
const MCInstrDesc &Desc = MCII->get(MI.getOpcode());
for (unsigned I = 0; I < MI.getNumOperands(); ++I) {
const MCOperand &MO = MI.getOperand(I);
if (MO.isReg() && MO.getReg() == ARM::CPSR &&
Desc.OpInfo[I].isOptionalDef())
return true;
}
return false;
}
uint64_t ARM_MC::evaluateBranchTarget(const MCInstrDesc &InstDesc,
uint64_t Addr, int64_t Imm) {
// For ARM instructions the PC offset is 8 bytes, for Thumb instructions it
// is 4 bytes.
uint64_t Offset =
((InstDesc.TSFlags & ARMII::FormMask) == ARMII::ThumbFrm) ? 4 : 8;
// A Thumb instruction BLX(i) can be 16-bit aligned while targets Arm code
// which is 32-bit aligned. The target address for the case is calculated as
// targetAddress = Align(PC,4) + imm32;
// where
// Align(x, y) = y * (x DIV y);
if (InstDesc.getOpcode() == ARM::tBLXi)
Addr &= ~0x3;
return Addr + Imm + Offset;
}
MCSubtargetInfo *ARM_MC::createARMMCSubtargetInfo(const Triple &TT,
StringRef CPU, StringRef FS) {
std::string ArchFS = ARM_MC::ParseARMTriple(TT, CPU);
if (!FS.empty()) {
if (!ArchFS.empty())
ArchFS = (Twine(ArchFS) + "," + FS).str();
else
ArchFS = std::string(FS);
}
return createARMMCSubtargetInfoImpl(TT, CPU, /*TuneCPU*/ CPU, ArchFS);
}
static MCInstrInfo *createARMMCInstrInfo() {
MCInstrInfo *X = new MCInstrInfo();
InitARMMCInstrInfo(X);
return X;
}
void ARM_MC::initLLVMToCVRegMapping(MCRegisterInfo *MRI) {
// Mapping from CodeView to MC register id.
static const struct {
codeview::RegisterId CVReg;
MCPhysReg Reg;
} RegMap[] = {
{codeview::RegisterId::ARM_R0, ARM::R0},
{codeview::RegisterId::ARM_R1, ARM::R1},
{codeview::RegisterId::ARM_R2, ARM::R2},
{codeview::RegisterId::ARM_R3, ARM::R3},
{codeview::RegisterId::ARM_R4, ARM::R4},
{codeview::RegisterId::ARM_R5, ARM::R5},
{codeview::RegisterId::ARM_R6, ARM::R6},
{codeview::RegisterId::ARM_R7, ARM::R7},
{codeview::RegisterId::ARM_R8, ARM::R8},
{codeview::RegisterId::ARM_R9, ARM::R9},
{codeview::RegisterId::ARM_R10, ARM::R10},
{codeview::RegisterId::ARM_R11, ARM::R11},
{codeview::RegisterId::ARM_R12, ARM::R12},
{codeview::RegisterId::ARM_SP, ARM::SP},
{codeview::RegisterId::ARM_LR, ARM::LR},
{codeview::RegisterId::ARM_PC, ARM::PC},
{codeview::RegisterId::ARM_CPSR, ARM::CPSR},
{codeview::RegisterId::ARM_FPSCR, ARM::FPSCR},
{codeview::RegisterId::ARM_FPEXC, ARM::FPEXC},
{codeview::RegisterId::ARM_FS0, ARM::S0},
{codeview::RegisterId::ARM_FS1, ARM::S1},
{codeview::RegisterId::ARM_FS2, ARM::S2},
{codeview::RegisterId::ARM_FS3, ARM::S3},
{codeview::RegisterId::ARM_FS4, ARM::S4},
{codeview::RegisterId::ARM_FS5, ARM::S5},
{codeview::RegisterId::ARM_FS6, ARM::S6},
{codeview::RegisterId::ARM_FS7, ARM::S7},
{codeview::RegisterId::ARM_FS8, ARM::S8},
{codeview::RegisterId::ARM_FS9, ARM::S9},
{codeview::RegisterId::ARM_FS10, ARM::S10},
{codeview::RegisterId::ARM_FS11, ARM::S11},
{codeview::RegisterId::ARM_FS12, ARM::S12},
{codeview::RegisterId::ARM_FS13, ARM::S13},
{codeview::RegisterId::ARM_FS14, ARM::S14},
{codeview::RegisterId::ARM_FS15, ARM::S15},
{codeview::RegisterId::ARM_FS16, ARM::S16},
{codeview::RegisterId::ARM_FS17, ARM::S17},
{codeview::RegisterId::ARM_FS18, ARM::S18},
{codeview::RegisterId::ARM_FS19, ARM::S19},
{codeview::RegisterId::ARM_FS20, ARM::S20},
{codeview::RegisterId::ARM_FS21, ARM::S21},
{codeview::RegisterId::ARM_FS22, ARM::S22},
{codeview::RegisterId::ARM_FS23, ARM::S23},
{codeview::RegisterId::ARM_FS24, ARM::S24},
{codeview::RegisterId::ARM_FS25, ARM::S25},
{codeview::RegisterId::ARM_FS26, ARM::S26},
{codeview::RegisterId::ARM_FS27, ARM::S27},
{codeview::RegisterId::ARM_FS28, ARM::S28},
{codeview::RegisterId::ARM_FS29, ARM::S29},
{codeview::RegisterId::ARM_FS30, ARM::S30},
{codeview::RegisterId::ARM_FS31, ARM::S31},
{codeview::RegisterId::ARM_ND0, ARM::D0},
{codeview::RegisterId::ARM_ND1, ARM::D1},
{codeview::RegisterId::ARM_ND2, ARM::D2},
{codeview::RegisterId::ARM_ND3, ARM::D3},
{codeview::RegisterId::ARM_ND4, ARM::D4},
{codeview::RegisterId::ARM_ND5, ARM::D5},
{codeview::RegisterId::ARM_ND6, ARM::D6},
{codeview::RegisterId::ARM_ND7, ARM::D7},
{codeview::RegisterId::ARM_ND8, ARM::D8},
{codeview::RegisterId::ARM_ND9, ARM::D9},
{codeview::RegisterId::ARM_ND10, ARM::D10},
{codeview::RegisterId::ARM_ND11, ARM::D11},
{codeview::RegisterId::ARM_ND12, ARM::D12},
{codeview::RegisterId::ARM_ND13, ARM::D13},
{codeview::RegisterId::ARM_ND14, ARM::D14},
{codeview::RegisterId::ARM_ND15, ARM::D15},
{codeview::RegisterId::ARM_ND16, ARM::D16},
{codeview::RegisterId::ARM_ND17, ARM::D17},
{codeview::RegisterId::ARM_ND18, ARM::D18},
{codeview::RegisterId::ARM_ND19, ARM::D19},
{codeview::RegisterId::ARM_ND20, ARM::D20},
{codeview::RegisterId::ARM_ND21, ARM::D21},
{codeview::RegisterId::ARM_ND22, ARM::D22},
{codeview::RegisterId::ARM_ND23, ARM::D23},
{codeview::RegisterId::ARM_ND24, ARM::D24},
{codeview::RegisterId::ARM_ND25, ARM::D25},
{codeview::RegisterId::ARM_ND26, ARM::D26},
{codeview::RegisterId::ARM_ND27, ARM::D27},
{codeview::RegisterId::ARM_ND28, ARM::D28},
{codeview::RegisterId::ARM_ND29, ARM::D29},
{codeview::RegisterId::ARM_ND30, ARM::D30},
{codeview::RegisterId::ARM_ND31, ARM::D31},
{codeview::RegisterId::ARM_NQ0, ARM::Q0},
{codeview::RegisterId::ARM_NQ1, ARM::Q1},
{codeview::RegisterId::ARM_NQ2, ARM::Q2},
{codeview::RegisterId::ARM_NQ3, ARM::Q3},
{codeview::RegisterId::ARM_NQ4, ARM::Q4},
{codeview::RegisterId::ARM_NQ5, ARM::Q5},
{codeview::RegisterId::ARM_NQ6, ARM::Q6},
{codeview::RegisterId::ARM_NQ7, ARM::Q7},
{codeview::RegisterId::ARM_NQ8, ARM::Q8},
{codeview::RegisterId::ARM_NQ9, ARM::Q9},
{codeview::RegisterId::ARM_NQ10, ARM::Q10},
{codeview::RegisterId::ARM_NQ11, ARM::Q11},
{codeview::RegisterId::ARM_NQ12, ARM::Q12},
{codeview::RegisterId::ARM_NQ13, ARM::Q13},
{codeview::RegisterId::ARM_NQ14, ARM::Q14},
{codeview::RegisterId::ARM_NQ15, ARM::Q15},
};
for (unsigned I = 0; I < array_lengthof(RegMap); ++I)
MRI->mapLLVMRegToCVReg(RegMap[I].Reg, static_cast<int>(RegMap[I].CVReg));
}
static MCRegisterInfo *createARMMCRegisterInfo(const Triple &Triple) {
MCRegisterInfo *X = new MCRegisterInfo();
InitARMMCRegisterInfo(X, ARM::LR, 0, 0, ARM::PC);
ARM_MC::initLLVMToCVRegMapping(X);
return X;
}
static MCAsmInfo *createARMMCAsmInfo(const MCRegisterInfo &MRI,
const Triple &TheTriple,
const MCTargetOptions &Options) {
MCAsmInfo *MAI;
if (TheTriple.isOSDarwin() || TheTriple.isOSBinFormatMachO())
MAI = new ARMMCAsmInfoDarwin(TheTriple);
else if (TheTriple.isWindowsMSVCEnvironment())
MAI = new ARMCOFFMCAsmInfoMicrosoft();
else if (TheTriple.isOSWindows())
MAI = new ARMCOFFMCAsmInfoGNU();
else
MAI = new ARMELFMCAsmInfo(TheTriple);
unsigned Reg = MRI.getDwarfRegNum(ARM::SP, true);
MAI->addInitialFrameState(MCCFIInstruction::cfiDefCfa(nullptr, Reg, 0));
return MAI;
}
static MCStreamer *createELFStreamer(const Triple &T, MCContext &Ctx,
std::unique_ptr<MCAsmBackend> &&MAB,
std::unique_ptr<MCObjectWriter> &&OW,
std::unique_ptr<MCCodeEmitter> &&Emitter,
bool RelaxAll) {
return createARMELFStreamer(
Ctx, std::move(MAB), std::move(OW), std::move(Emitter), false,
(T.getArch() == Triple::thumb || T.getArch() == Triple::thumbeb),
T.isAndroid());
}
static MCStreamer *
createARMMachOStreamer(MCContext &Ctx, std::unique_ptr<MCAsmBackend> &&MAB,
std::unique_ptr<MCObjectWriter> &&OW,
std::unique_ptr<MCCodeEmitter> &&Emitter, bool RelaxAll,
bool DWARFMustBeAtTheEnd) {
return createMachOStreamer(Ctx, std::move(MAB), std::move(OW),
std::move(Emitter), false, DWARFMustBeAtTheEnd);
}
static MCInstPrinter *createARMMCInstPrinter(const Triple &T,
unsigned SyntaxVariant,
const MCAsmInfo &MAI,
const MCInstrInfo &MII,
const MCRegisterInfo &MRI) {
if (SyntaxVariant == 0)
return new ARMInstPrinter(MAI, MII, MRI);
return nullptr;
}
static MCRelocationInfo *createARMMCRelocationInfo(const Triple &TT,
MCContext &Ctx) {
if (TT.isOSBinFormatMachO())
return createARMMachORelocationInfo(Ctx);
// Default to the stock relocation info.
return llvm::createMCRelocationInfo(TT, Ctx);
}
namespace {
class ARMMCInstrAnalysis : public MCInstrAnalysis {
public:
ARMMCInstrAnalysis(const MCInstrInfo *Info) : MCInstrAnalysis(Info) {}
bool isUnconditionalBranch(const MCInst &Inst) const override {
// BCCs with the "always" predicate are unconditional branches.
if (Inst.getOpcode() == ARM::Bcc && Inst.getOperand(1).getImm()==ARMCC::AL)
return true;
return MCInstrAnalysis::isUnconditionalBranch(Inst);
}
bool isConditionalBranch(const MCInst &Inst) const override {
// BCCs with the "always" predicate are unconditional branches.
if (Inst.getOpcode() == ARM::Bcc && Inst.getOperand(1).getImm()==ARMCC::AL)
return false;
return MCInstrAnalysis::isConditionalBranch(Inst);
}
bool evaluateBranch(const MCInst &Inst, uint64_t Addr, uint64_t Size,
uint64_t &Target) const override {
const MCInstrDesc &Desc = Info->get(Inst.getOpcode());
// Find the PC-relative immediate operand in the instruction.
for (unsigned OpNum = 0; OpNum < Desc.getNumOperands(); ++OpNum) {
if (Inst.getOperand(OpNum).isImm() &&
Desc.OpInfo[OpNum].OperandType == MCOI::OPERAND_PCREL) {
int64_t Imm = Inst.getOperand(OpNum).getImm();
Target = ARM_MC::evaluateBranchTarget(Desc, Addr, Imm);
return true;
}
}
return false;
}
Optional<uint64_t> evaluateMemoryOperandAddress(const MCInst &Inst,
const MCSubtargetInfo *STI,
uint64_t Addr,
uint64_t Size) const override;
};
} // namespace
static Optional<uint64_t>
// NOLINTNEXTLINE(readability-identifier-naming)
evaluateMemOpAddrForAddrMode_i12(const MCInst &Inst, const MCInstrDesc &Desc,
unsigned MemOpIndex, uint64_t Addr) {
if (MemOpIndex + 1 >= Desc.getNumOperands())
return None;
const MCOperand &MO1 = Inst.getOperand(MemOpIndex);
const MCOperand &MO2 = Inst.getOperand(MemOpIndex + 1);
if (!MO1.isReg() || MO1.getReg() != ARM::PC || !MO2.isImm())
return None;
int32_t OffImm = (int32_t)MO2.getImm();
// Special value for #-0. All others are normal.
if (OffImm == INT32_MIN)
OffImm = 0;
return Addr + OffImm;
}
static Optional<uint64_t> evaluateMemOpAddrForAddrMode3(const MCInst &Inst,
const MCInstrDesc &Desc,
unsigned MemOpIndex,
uint64_t Addr) {
if (MemOpIndex + 2 >= Desc.getNumOperands())
return None;
const MCOperand &MO1 = Inst.getOperand(MemOpIndex);
const MCOperand &MO2 = Inst.getOperand(MemOpIndex + 1);
const MCOperand &MO3 = Inst.getOperand(MemOpIndex + 2);
if (!MO1.isReg() || MO1.getReg() != ARM::PC || MO2.getReg() || !MO3.isImm())
return None;
unsigned ImmOffs = ARM_AM::getAM3Offset(MO3.getImm());
ARM_AM::AddrOpc Op = ARM_AM::getAM3Op(MO3.getImm());
if (Op == ARM_AM::sub)
return Addr - ImmOffs;
return Addr + ImmOffs;
}
static Optional<uint64_t> evaluateMemOpAddrForAddrMode5(const MCInst &Inst,
const MCInstrDesc &Desc,
unsigned MemOpIndex,
uint64_t Addr) {
if (MemOpIndex + 1 >= Desc.getNumOperands())
return None;
const MCOperand &MO1 = Inst.getOperand(MemOpIndex);
const MCOperand &MO2 = Inst.getOperand(MemOpIndex + 1);
if (!MO1.isReg() || MO1.getReg() != ARM::PC || !MO2.isImm())
return None;
unsigned ImmOffs = ARM_AM::getAM5Offset(MO2.getImm());
ARM_AM::AddrOpc Op = ARM_AM::getAM5Op(MO2.getImm());
if (Op == ARM_AM::sub)
return Addr - ImmOffs * 4;
return Addr + ImmOffs * 4;
}
static Optional<uint64_t>
evaluateMemOpAddrForAddrMode5FP16(const MCInst &Inst, const MCInstrDesc &Desc,
unsigned MemOpIndex, uint64_t Addr) {
if (MemOpIndex + 1 >= Desc.getNumOperands())
return None;
const MCOperand &MO1 = Inst.getOperand(MemOpIndex);
const MCOperand &MO2 = Inst.getOperand(MemOpIndex + 1);
if (!MO1.isReg() || MO1.getReg() != ARM::PC || !MO2.isImm())
return None;
unsigned ImmOffs = ARM_AM::getAM5FP16Offset(MO2.getImm());
ARM_AM::AddrOpc Op = ARM_AM::getAM5FP16Op(MO2.getImm());
if (Op == ARM_AM::sub)
return Addr - ImmOffs * 2;
return Addr + ImmOffs * 2;
}
static Optional<uint64_t>
// NOLINTNEXTLINE(readability-identifier-naming)
evaluateMemOpAddrForAddrModeT2_i8s4(const MCInst &Inst, const MCInstrDesc &Desc,
unsigned MemOpIndex, uint64_t Addr) {
if (MemOpIndex + 1 >= Desc.getNumOperands())
return None;
const MCOperand &MO1 = Inst.getOperand(MemOpIndex);
const MCOperand &MO2 = Inst.getOperand(MemOpIndex + 1);
if (!MO1.isReg() || MO1.getReg() != ARM::PC || !MO2.isImm())
return None;
int32_t OffImm = (int32_t)MO2.getImm();
assert(((OffImm & 0x3) == 0) && "Not a valid immediate!");
// Special value for #-0. All others are normal.
if (OffImm == INT32_MIN)
OffImm = 0;
return Addr + OffImm;
}
static Optional<uint64_t>
// NOLINTNEXTLINE(readability-identifier-naming)
evaluateMemOpAddrForAddrModeT2_pc(const MCInst &Inst, const MCInstrDesc &Desc,
unsigned MemOpIndex, uint64_t Addr) {
const MCOperand &MO1 = Inst.getOperand(MemOpIndex);
if (!MO1.isImm())
return None;
int32_t OffImm = (int32_t)MO1.getImm();
// Special value for #-0. All others are normal.
if (OffImm == INT32_MIN)
OffImm = 0;
return Addr + OffImm;
}
static Optional<uint64_t>
// NOLINTNEXTLINE(readability-identifier-naming)
evaluateMemOpAddrForAddrModeT1_s(const MCInst &Inst, const MCInstrDesc &Desc,
unsigned MemOpIndex, uint64_t Addr) {
return evaluateMemOpAddrForAddrModeT2_pc(Inst, Desc, MemOpIndex, Addr);
}
Optional<uint64_t> ARMMCInstrAnalysis::evaluateMemoryOperandAddress(
const MCInst &Inst, const MCSubtargetInfo *STI, uint64_t Addr,
uint64_t Size) const {
const MCInstrDesc &Desc = Info->get(Inst.getOpcode());
// Only load instructions can have PC-relative memory addressing.
if (!Desc.mayLoad())
return None;
// PC-relative addressing does not update the base register.
uint64_t TSFlags = Desc.TSFlags;
unsigned IndexMode =
(TSFlags & ARMII::IndexModeMask) >> ARMII::IndexModeShift;
if (IndexMode != ARMII::IndexModeNone)
return None;
// Find the memory addressing operand in the instruction.
unsigned OpIndex = Desc.NumDefs;
while (OpIndex < Desc.getNumOperands() &&
Desc.OpInfo[OpIndex].OperandType != MCOI::OPERAND_MEMORY)
++OpIndex;
if (OpIndex == Desc.getNumOperands())
return None;
// Base address for PC-relative addressing is always 32-bit aligned.
Addr &= ~0x3;
// For ARM instructions the PC offset is 8 bytes, for Thumb instructions it
// is 4 bytes.
switch (Desc.TSFlags & ARMII::FormMask) {
default:
Addr += 8;
break;
case ARMII::ThumbFrm:
Addr += 4;
break;
// VLDR* instructions share the same opcode (and thus the same form) for Arm
// and Thumb. Use a bit longer route through STI in that case.
case ARMII::VFPLdStFrm:
Addr += STI->getFeatureBits()[ARM::ModeThumb] ? 4 : 8;
break;
}
// Eveluate the address depending on the addressing mode
unsigned AddrMode = (TSFlags & ARMII::AddrModeMask);
switch (AddrMode) {
default:
return None;
case ARMII::AddrMode_i12:
return evaluateMemOpAddrForAddrMode_i12(Inst, Desc, OpIndex, Addr);
case ARMII::AddrMode3:
return evaluateMemOpAddrForAddrMode3(Inst, Desc, OpIndex, Addr);
case ARMII::AddrMode5:
return evaluateMemOpAddrForAddrMode5(Inst, Desc, OpIndex, Addr);
case ARMII::AddrMode5FP16:
return evaluateMemOpAddrForAddrMode5FP16(Inst, Desc, OpIndex, Addr);
case ARMII::AddrModeT2_i8s4:
return evaluateMemOpAddrForAddrModeT2_i8s4(Inst, Desc, OpIndex, Addr);
case ARMII::AddrModeT2_pc:
return evaluateMemOpAddrForAddrModeT2_pc(Inst, Desc, OpIndex, Addr);
case ARMII::AddrModeT1_s:
return evaluateMemOpAddrForAddrModeT1_s(Inst, Desc, OpIndex, Addr);
}
}
static MCInstrAnalysis *createARMMCInstrAnalysis(const MCInstrInfo *Info) {
return new ARMMCInstrAnalysis(Info);
}
bool ARM::isCDECoproc(size_t Coproc, const MCSubtargetInfo &STI) {
// Unfortunately we don't have ARMTargetInfo in the disassembler, so we have
// to rely on feature bits.
if (Coproc >= 8)
return false;
return STI.getFeatureBits()[ARM::FeatureCoprocCDE0 + Coproc];
}
// Force static initialization.
extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeARMTargetMC() {
for (Target *T : {&getTheARMLETarget(), &getTheARMBETarget(),
&getTheThumbLETarget(), &getTheThumbBETarget()}) {
// Register the MC asm info.
RegisterMCAsmInfoFn X(*T, createARMMCAsmInfo);
// Register the MC instruction info.
TargetRegistry::RegisterMCInstrInfo(*T, createARMMCInstrInfo);
// Register the MC register info.
TargetRegistry::RegisterMCRegInfo(*T, createARMMCRegisterInfo);
// Register the MC subtarget info.
TargetRegistry::RegisterMCSubtargetInfo(*T,
ARM_MC::createARMMCSubtargetInfo);
TargetRegistry::RegisterELFStreamer(*T, createELFStreamer);
TargetRegistry::RegisterCOFFStreamer(*T, createARMWinCOFFStreamer);
TargetRegistry::RegisterMachOStreamer(*T, createARMMachOStreamer);
// Register the obj target streamer.
TargetRegistry::RegisterObjectTargetStreamer(*T,
createARMObjectTargetStreamer);
// Register the asm streamer.
TargetRegistry::RegisterAsmTargetStreamer(*T, createARMTargetAsmStreamer);
// Register the null TargetStreamer.
TargetRegistry::RegisterNullTargetStreamer(*T, createARMNullTargetStreamer);
// Register the MCInstPrinter.
TargetRegistry::RegisterMCInstPrinter(*T, createARMMCInstPrinter);
// Register the MC relocation info.
TargetRegistry::RegisterMCRelocationInfo(*T, createARMMCRelocationInfo);
}
// Register the MC instruction analyzer.
for (Target *T : {&getTheARMLETarget(), &getTheARMBETarget(),
&getTheThumbLETarget(), &getTheThumbBETarget()})
TargetRegistry::RegisterMCInstrAnalysis(*T, createARMMCInstrAnalysis);
for (Target *T : {&getTheARMLETarget(), &getTheThumbLETarget()}) {
TargetRegistry::RegisterMCCodeEmitter(*T, createARMLEMCCodeEmitter);
TargetRegistry::RegisterMCAsmBackend(*T, createARMLEAsmBackend);
}
for (Target *T : {&getTheARMBETarget(), &getTheThumbBETarget()}) {
TargetRegistry::RegisterMCCodeEmitter(*T, createARMBEMCCodeEmitter);
TargetRegistry::RegisterMCAsmBackend(*T, createARMBEAsmBackend);
}
}