#define DEBUG_TYPE "arm-emitter"
#include "ARM.h"
#include "ARMAddressingModes.h"
+#include "ARMFixupKinds.h"
#include "ARMInstrInfo.h"
#include "llvm/MC/MCCodeEmitter.h"
#include "llvm/MC/MCExpr.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;
-STATISTIC(MCNumEmitted, "Number of MC instructions emitted");
+STATISTIC(MCNumEmitted, "Number of MC instructions emitted.");
+STATISTIC(MCNumCPRelocations, "Number of constant pool relocations created.");
namespace {
class ARMMCCodeEmitter : public MCCodeEmitter {
~ARMMCCodeEmitter() {}
+ unsigned getNumFixupKinds() const { return 2; }
+
+ const MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const {
+ const static MCFixupKindInfo Infos[] = {
+ { "fixup_arm_pcrel_12", 2, 12, MCFixupKindInfo::FKF_IsPCRel },
+ { "fixup_arm_vfp_pcrel_12", 3, 8, MCFixupKindInfo::FKF_IsPCRel },
+ };
+
+ if (Kind < FirstTargetFixupKind)
+ return MCCodeEmitter::getFixupKindInfo(Kind);
+
+ assert(unsigned(Kind - FirstTargetFixupKind) < getNumFixupKinds() &&
+ "Invalid kind!");
+ return Infos[Kind - FirstTargetFixupKind];
+ }
unsigned getMachineSoImmOpValue(unsigned SoImm) const;
// getBinaryCodeForInstr - TableGen'erated function for getting the
uint32_t getAddrModeImm12OpValue(const MCInst &MI, unsigned OpIdx,
SmallVectorImpl<MCFixup> &Fixups) const;
+ /// getLdStSORegOpValue - Return encoding info for 'reg +/- reg shop imm'
+ /// operand as needed by load/store instructions.
+ uint32_t getLdStSORegOpValue(const MCInst &MI, unsigned OpIdx,
+ SmallVectorImpl<MCFixup> &Fixups) const;
+
+ /// getLdStmModeOpValue - Return encoding for load/store multiple mode.
+ uint32_t getLdStmModeOpValue(const MCInst &MI, unsigned OpIdx,
+ SmallVectorImpl<MCFixup> &Fixups) const {
+ ARM_AM::AMSubMode Mode = (ARM_AM::AMSubMode)MI.getOperand(OpIdx).getImm();
+ switch (Mode) {
+ default: assert(0 && "Unknown addressing sub-mode!");
+ case ARM_AM::da: return 0;
+ case ARM_AM::ia: return 1;
+ case ARM_AM::db: return 2;
+ case ARM_AM::ib: return 3;
+ }
+ }
+
/// getAddrMode5OpValue - Return encoding info for 'reg +/- imm8' operand.
uint32_t getAddrMode5OpValue(const MCInst &MI, unsigned OpIdx,
SmallVectorImpl<MCFixup> &Fixups) const;
unsigned getAddrMode6OffsetOpValue(const MCInst &MI, unsigned Op,
SmallVectorImpl<MCFixup> &Fixups) const;
- unsigned getNumFixupKinds() const {
- assert(0 && "ARMMCCodeEmitter::getNumFixupKinds() not yet implemented.");
- return 0;
- }
-
- const MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const {
- static MCFixupKindInfo rtn;
- assert(0 && "ARMMCCodeEmitter::getFixupKindInfo() not yet implemented.");
- return rtn;
- }
-
- void EmitByte(unsigned char C, unsigned &CurByte, raw_ostream &OS) const {
+ void EmitByte(unsigned char C, raw_ostream &OS) const {
OS << (char)C;
- ++CurByte;
}
- void EmitConstant(uint64_t Val, unsigned Size, unsigned &CurByte,
- raw_ostream &OS) const {
+ void EmitConstant(uint64_t Val, unsigned Size, raw_ostream &OS) const {
// Output the constant in little endian byte order.
for (unsigned i = 0; i != Size; ++i) {
- EmitByte(Val & 255, CurByte, OS);
+ EmitByte(Val & 255, OS);
Val >>= 8;
}
}
const MCOperand &MO = MI.getOperand(OpIdx);
const MCOperand &MO1 = MI.getOperand(OpIdx + 1);
- // If The first operand isn't a register, we have a label reference.
- if (!MO.isReg()) {
- Reg = ARM::PC; // Rn is PC.
- Imm = 0;
- // FIXME: Add a fixup referencing the label.
- return true;
- }
-
Reg = getARMRegisterNumbering(MO.getReg());
int32_t SImm = MO1.getImm();
// {12} = (U)nsigned (add == '1', sub == '0')
// {11-0} = imm12
unsigned Reg, Imm12;
- bool isAdd = EncodeAddrModeOpValues(MI, OpIdx, Reg, Imm12, Fixups);
+ bool isAdd = true;
+ // If The first operand isn't a register, we have a label reference.
+ const MCOperand &MO = MI.getOperand(OpIdx);
+ if (!MO.isReg()) {
+ Reg = getARMRegisterNumbering(ARM::PC); // Rn is PC.
+ Imm12 = 0;
- if (Reg == ARM::PC)
- return ARM::PC << 13; // Rn is PC;
+ assert(MO.isExpr() && "Unexpected machine operand type!");
+ const MCExpr *Expr = MO.getExpr();
+ MCFixupKind Kind = MCFixupKind(ARM::fixup_arm_pcrel_12);
+ Fixups.push_back(MCFixup::Create(0, Expr, Kind));
+
+ ++MCNumCPRelocations;
+ } else
+ isAdd = EncodeAddrModeOpValues(MI, OpIdx, Reg, Imm12, Fixups);
uint32_t Binary = Imm12 & 0xfff;
// Immediate is always encoded as positive. The 'U' bit controls add vs sub.
return Binary;
}
+uint32_t ARMMCCodeEmitter::
+getLdStSORegOpValue(const MCInst &MI, unsigned OpIdx,
+ SmallVectorImpl<MCFixup> &Fixups) const {
+ const MCOperand &MO = MI.getOperand(OpIdx);
+ const MCOperand &MO1 = MI.getOperand(OpIdx+1);
+ const MCOperand &MO2 = MI.getOperand(OpIdx+2);
+ unsigned Rn = getARMRegisterNumbering(MO.getReg());
+ unsigned Rm = getARMRegisterNumbering(MO1.getReg());
+ ARM_AM::ShiftOpc ShOp = ARM_AM::getAM2ShiftOpc(MO2.getImm());
+ unsigned ShImm = ARM_AM::getAM2Offset(MO2.getImm());
+ bool isAdd = ARM_AM::getAM2Op(MO2.getImm()) == ARM_AM::add;
+ unsigned SBits;
+ // LSL - 00
+ // LSR - 01
+ // ASR - 10
+ // ROR - 11
+ switch (ShOp) {
+ default: llvm_unreachable("Unknown shift opc!");
+ case ARM_AM::no_shift:
+ assert(ShImm == 0 && "Non-zero shift amount with no shift type!");
+ // fall through
+ case ARM_AM::lsl: SBits = 0x0; break;
+ case ARM_AM::lsr: SBits = 0x1; break;
+ case ARM_AM::asr: SBits = 0x2; break;
+ case ARM_AM::ror: SBits = 0x3; break;
+ }
+
+ // {16-13} = Rn
+ // {12} = isAdd
+ // {11-0} = shifter
+ // {3-0} = Rm
+ // {4} = 0
+ // {6-5} = type
+ // {11-7} = imm
+ int64_t Binary = Rm;
+ Binary |= Rn << 13;
+ Binary |= SBits << 5;
+ Binary |= ShImm << 7;
+ if (isAdd)
+ Binary |= 1 << 12;
+ return Binary;
+}
+
/// getAddrMode5OpValue - Return encoding info for 'reg +/- imm12' operand.
uint32_t ARMMCCodeEmitter::
getAddrMode5OpValue(const MCInst &MI, unsigned OpIdx,
// {8} = (U)nsigned (add == '1', sub == '0')
// {7-0} = imm8
unsigned Reg, Imm8;
- EncodeAddrModeOpValues(MI, OpIdx, Reg, Imm8, Fixups);
+ // If The first operand isn't a register, we have a label reference.
+ const MCOperand &MO = MI.getOperand(OpIdx);
+ if (!MO.isReg()) {
+ Reg = getARMRegisterNumbering(ARM::PC); // Rn is PC.
+ Imm8 = 0;
+
+ assert(MO.isExpr() && "Unexpected machine operand type!");
+ const MCExpr *Expr = MO.getExpr();
+ MCFixupKind Kind = MCFixupKind(ARM::fixup_arm_vfp_pcrel_12);
+ Fixups.push_back(MCFixup::Create(0, Expr, Kind));
- if (Reg == ARM::PC)
- return ARM::PC << 9; // Rn is PC;
+ ++MCNumCPRelocations;
+ } else
+ EncodeAddrModeOpValues(MI, OpIdx, Reg, Imm8, Fixups);
uint32_t Binary = ARM_AM::getAM5Offset(Imm8);
// Immediate is always encoded as positive. The 'U' bit controls add vs sub.
if ((Desc.TSFlags & ARMII::FormMask) == ARMII::Pseudo)
return;
- // Keep track of the current byte being emitted.
- unsigned CurByte = 0;
- EmitConstant(getBinaryCodeForInstr(MI, Fixups), 4, CurByte, OS);
+ EmitConstant(getBinaryCodeForInstr(MI, Fixups), 4, OS);
++MCNumEmitted; // Keep track of the # of mi's emitted.
}