Files
clang-p2996/llvm/lib/Target/ARM/MCTargetDesc/ARMMCTargetDesc.cpp
David Green 3e0bf1c7a9 [CodeGen] Move instruction predicate verification to emitInstruction
D25618 added a method to verify the instruction predicates for an
emitted instruction, through verifyInstructionPredicates added into
<Target>MCCodeEmitter::encodeInstruction. This is a very useful idea,
but the implementation inside MCCodeEmitter made it only fire for object
files, not assembly which most of the llvm test suite uses.

This patch moves the code into the <Target>_MC::verifyInstructionPredicates
method, inside the InstrInfo.  The allows it to be called from other
places, such as in this patch where it is called from the
<Target>AsmPrinter::emitInstruction methods which should trigger for
both assembly and object files. It can also be called from other places
such as verifyInstruction, but that is not done here (it tends to catch
errors earlier, but in reality just shows all the mir tests that have
incorrect feature predicates). The interface was also simplified
slightly, moving computeAvailableFeatures into the function so that it
does not need to be called externally.

The ARM, AMDGPU (but not R600), AVR, Mips and X86 backends all currently
show errors in the test-suite, so have been disabled with FIXME
comments.

Recommitted with some fixes for the leftover MCII variables in release
builds.

Differential Revision: https://reviews.llvm.org/D129506
2022-07-14 09:33:28 +01:00

694 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 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
#define ENABLE_INSTR_PREDICATE_VERIFIER
#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 (const auto &I : RegMap)
MRI->mapLLVMRegToCVReg(I.Reg, static_cast<int>(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);
}
}