#define DEBUG_TYPE "jit"
#include "ARM.h"
-#include "ARMAddressingModes.h"
#include "ARMConstantPoolValue.h"
#include "ARMInstrInfo.h"
#include "ARMRelocations.h"
#include "ARMSubtarget.h"
#include "ARMTargetMachine.h"
+#include "MCTargetDesc/ARMAddressingModes.h"
#include "llvm/Constants.h"
#include "llvm/DerivedTypes.h"
#include "llvm/Function.h"
#include "llvm/PassManager.h"
-#include "llvm/CodeGen/MachineCodeEmitter.h"
+#include "llvm/CodeGen/JITCodeEmitter.h"
#include "llvm/CodeGen/MachineConstantPool.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/MachineJumpTableInfo.h"
+#include "llvm/CodeGen/MachineModuleInfo.h"
#include "llvm/CodeGen/Passes.h"
#include "llvm/ADT/Statistic.h"
-#include "llvm/Support/Compiler.h"
#include "llvm/Support/Debug.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/raw_ostream.h"
#ifndef NDEBUG
#include <iomanip>
#endif
STATISTIC(NumEmitted, "Number of machine instructions emitted");
namespace {
- class VISIBILITY_HIDDEN ARMCodeEmitter : public MachineFunctionPass {
+
+ class ARMCodeEmitter : public MachineFunctionPass {
ARMJITInfo *JTI;
const ARMInstrInfo *II;
const TargetData *TD;
+ const ARMSubtarget *Subtarget;
TargetMachine &TM;
- MachineCodeEmitter &MCE;
+ JITCodeEmitter &MCE;
+ MachineModuleInfo *MMI;
const std::vector<MachineConstantPoolEntry> *MCPEs;
const std::vector<MachineJumpTableEntry> *MJTEs;
bool IsPIC;
+ bool IsThumb;
+
+ void getAnalysisUsage(AnalysisUsage &AU) const {
+ AU.addRequired<MachineModuleInfo>();
+ MachineFunctionPass::getAnalysisUsage(AU);
+ }
- public:
static char ID;
- explicit ARMCodeEmitter(TargetMachine &tm, MachineCodeEmitter &mce)
- : MachineFunctionPass(&ID), JTI(0), II(0), TD(0), TM(tm),
- MCE(mce), MCPEs(0), MJTEs(0),
- IsPIC(TM.getRelocationModel() == Reloc::PIC_) {}
- ARMCodeEmitter(TargetMachine &tm, MachineCodeEmitter &mce,
- const ARMInstrInfo &ii, const TargetData &td)
- : MachineFunctionPass(&ID), JTI(0), II(&ii), TD(&td), TM(tm),
- MCE(mce), MCPEs(0), MJTEs(0),
- IsPIC(TM.getRelocationModel() == Reloc::PIC_) {}
+ public:
+ ARMCodeEmitter(TargetMachine &tm, JITCodeEmitter &mce)
+ : MachineFunctionPass(ID), JTI(0),
+ II((const ARMInstrInfo *)tm.getInstrInfo()),
+ TD(tm.getTargetData()), TM(tm),
+ MCE(mce), MCPEs(0), MJTEs(0),
+ IsPIC(TM.getRelocationModel() == Reloc::PIC_), IsThumb(false) {}
+
+ /// getBinaryCodeForInstr - This function, generated by the
+ /// CodeEmitterGenerator using TableGen, produces the binary encoding for
+ /// machine instructions.
+ unsigned getBinaryCodeForInstr(const MachineInstr &MI) const;
bool runOnMachineFunction(MachineFunction &MF);
private:
void emitWordLE(unsigned Binary);
-
void emitDWordLE(uint64_t Binary);
-
void emitConstPoolInstruction(const MachineInstr &MI);
-
+ void emitMOVi32immInstruction(const MachineInstr &MI);
void emitMOVi2piecesInstruction(const MachineInstr &MI);
-
void emitLEApcrelJTInstruction(const MachineInstr &MI);
-
+ void emitPseudoMoveInstruction(const MachineInstr &MI);
void addPCLabel(unsigned LabelID);
-
void emitPseudoInstruction(const MachineInstr &MI);
-
unsigned getMachineSoRegOpValue(const MachineInstr &MI,
- const TargetInstrDesc &TID,
+ const MCInstrDesc &MCID,
const MachineOperand &MO,
unsigned OpIdx);
unsigned getMachineSoImmOpValue(unsigned SoImm);
-
unsigned getAddrModeSBit(const MachineInstr &MI,
- const TargetInstrDesc &TID) const;
+ const MCInstrDesc &MCID) const;
void emitDataProcessingInstruction(const MachineInstr &MI,
unsigned ImplicitRd = 0,
void emitMiscArithInstruction(const MachineInstr &MI);
+ void emitSaturateInstruction(const MachineInstr &MI);
+
void emitBranchInstruction(const MachineInstr &MI);
void emitInlineJumpTable(unsigned JTIndex);
void emitVFPLoadStoreMultipleInstruction(const MachineInstr &MI);
- void emitMiscInstruction(const MachineInstr &MI);
-
- /// getBinaryCodeForInstr - This function, generated by the
- /// CodeEmitterGenerator using TableGen, produces the binary encoding for
- /// machine instructions.
- ///
- unsigned getBinaryCodeForInstr(const MachineInstr &MI);
+ void emitNEONLaneInstruction(const MachineInstr &MI);
+ void emitNEONDupInstruction(const MachineInstr &MI);
+ void emitNEON1RegModImmInstruction(const MachineInstr &MI);
+ void emitNEON2RegInstruction(const MachineInstr &MI);
+ void emitNEON3RegInstruction(const MachineInstr &MI);
/// getMachineOpValue - Return binary encoding of operand. If the machine
/// operand requires relocation, record the relocation and return zero.
- unsigned getMachineOpValue(const MachineInstr &MI,const MachineOperand &MO);
- unsigned getMachineOpValue(const MachineInstr &MI, unsigned OpIdx) {
+ unsigned getMachineOpValue(const MachineInstr &MI,
+ const MachineOperand &MO) const;
+ unsigned getMachineOpValue(const MachineInstr &MI, unsigned OpIdx) const {
return getMachineOpValue(MI, MI.getOperand(OpIdx));
}
+ // FIXME: The legacy JIT ARMCodeEmitter doesn't rely on the the
+ // TableGen'erated getBinaryCodeForInstr() function to encode any
+ // operand values, instead querying getMachineOpValue() directly for
+ // each operand it needs to encode. Thus, any of the new encoder
+ // helper functions can simply return 0 as the values the return
+ // are already handled elsewhere. They are placeholders to allow this
+ // encoder to continue to function until the MC encoder is sufficiently
+ // far along that this one can be eliminated entirely.
+ unsigned NEONThumb2DataIPostEncoder(const MachineInstr &MI, unsigned Val)
+ const { return 0; }
+ unsigned NEONThumb2LoadStorePostEncoder(const MachineInstr &MI,unsigned Val)
+ const { return 0; }
+ unsigned NEONThumb2DupPostEncoder(const MachineInstr &MI,unsigned Val)
+ const { return 0; }
+ unsigned VFPThumb2PostEncoder(const MachineInstr&MI, unsigned Val)
+ const { return 0; }
+ unsigned getAdrLabelOpValue(const MachineInstr &MI, unsigned Op)
+ const { return 0; }
+ unsigned getThumbAdrLabelOpValue(const MachineInstr &MI, unsigned Op)
+ const { return 0; }
+ unsigned getThumbBLTargetOpValue(const MachineInstr &MI, unsigned Op)
+ const { return 0; }
+ unsigned getThumbBLXTargetOpValue(const MachineInstr &MI, unsigned Op)
+ const { return 0; }
+ unsigned getThumbBRTargetOpValue(const MachineInstr &MI, unsigned Op)
+ const { return 0; }
+ unsigned getThumbBCCTargetOpValue(const MachineInstr &MI, unsigned Op)
+ const { return 0; }
+ unsigned getThumbCBTargetOpValue(const MachineInstr &MI, unsigned Op)
+ const { return 0; }
+ unsigned getBranchTargetOpValue(const MachineInstr &MI, unsigned Op)
+ const { return 0; }
+ unsigned getUnconditionalBranchTargetOpValue(const MachineInstr &MI,
+ unsigned Op) const { return 0; }
+ unsigned getARMBranchTargetOpValue(const MachineInstr &MI, unsigned Op)
+ const { return 0; }
+ unsigned getARMBLXTargetOpValue(const MachineInstr &MI, unsigned Op)
+ const { return 0; }
+ unsigned getCCOutOpValue(const MachineInstr &MI, unsigned Op)
+ const { return 0; }
+ unsigned getSOImmOpValue(const MachineInstr &MI, unsigned Op)
+ const { return 0; }
+ unsigned getT2SOImmOpValue(const MachineInstr &MI, unsigned Op)
+ const { return 0; }
+ unsigned getSORegRegOpValue(const MachineInstr &MI, unsigned Op)
+ const { return 0; }
+ unsigned getSORegImmOpValue(const MachineInstr &MI, unsigned Op)
+ const { return 0; }
+ unsigned getThumbAddrModeRegRegOpValue(const MachineInstr &MI, unsigned Op)
+ const { return 0; }
+ unsigned getT2AddrModeImm12OpValue(const MachineInstr &MI, unsigned Op)
+ const { return 0; }
+ unsigned getT2AddrModeImm8OpValue(const MachineInstr &MI, unsigned Op)
+ const { return 0; }
+ unsigned getT2Imm8s4OpValue(const MachineInstr &MI, unsigned Op)
+ const { return 0; }
+ unsigned getT2AddrModeImm8s4OpValue(const MachineInstr &MI, unsigned Op)
+ const { return 0; }
+ unsigned getT2AddrModeImm0_1020s4OpValue(const MachineInstr &MI,unsigned Op)
+ const { return 0; }
+ unsigned getT2AddrModeImm8OffsetOpValue(const MachineInstr &MI, unsigned Op)
+ const { return 0; }
+ unsigned getT2AddrModeImm12OffsetOpValue(const MachineInstr &MI,unsigned Op)
+ const { return 0; }
+ unsigned getT2AddrModeSORegOpValue(const MachineInstr &MI, unsigned Op)
+ const { return 0; }
+ unsigned getT2SORegOpValue(const MachineInstr &MI, unsigned Op)
+ const { return 0; }
+ unsigned getT2AdrLabelOpValue(const MachineInstr &MI, unsigned Op)
+ const { return 0; }
+ unsigned getAddrMode6AddressOpValue(const MachineInstr &MI, unsigned Op)
+ const { return 0; }
+ unsigned getAddrMode6OneLane32AddressOpValue(const MachineInstr &MI,
+ unsigned Op)
+ const { return 0; }
+ unsigned getAddrMode6DupAddressOpValue(const MachineInstr &MI, unsigned Op)
+ const { return 0; }
+ unsigned getAddrMode6OffsetOpValue(const MachineInstr &MI, unsigned Op)
+ const { return 0; }
+ unsigned getBitfieldInvertedMaskOpValue(const MachineInstr &MI,
+ unsigned Op) const { return 0; }
+ unsigned getSsatBitPosValue(const MachineInstr &MI,
+ unsigned Op) const { return 0; }
+ uint32_t getLdStmModeOpValue(const MachineInstr &MI, unsigned OpIdx)
+ const {return 0; }
+ uint32_t getLdStSORegOpValue(const MachineInstr &MI, unsigned OpIdx)
+ const { return 0; }
+
+ unsigned getAddrModeImm12OpValue(const MachineInstr &MI, unsigned Op)
+ const {
+ // {17-13} = reg
+ // {12} = (U)nsigned (add == '1', sub == '0')
+ // {11-0} = imm12
+ const MachineOperand &MO = MI.getOperand(Op);
+ const MachineOperand &MO1 = MI.getOperand(Op + 1);
+ if (!MO.isReg()) {
+ emitConstPoolAddress(MO.getIndex(), ARM::reloc_arm_cp_entry);
+ return 0;
+ }
+ unsigned Reg = getARMRegisterNumbering(MO.getReg());
+ int32_t Imm12 = MO1.getImm();
+ uint32_t Binary;
+ Binary = Imm12 & 0xfff;
+ if (Imm12 >= 0)
+ Binary |= (1 << 12);
+ Binary |= (Reg << 13);
+ return Binary;
+ }
+
+ unsigned getHiLo16ImmOpValue(const MachineInstr &MI, unsigned Op) const {
+ return 0;
+ }
+
+ uint32_t getAddrMode2OpValue(const MachineInstr &MI, unsigned OpIdx)
+ const { return 0;}
+ uint32_t getAddrMode2OffsetOpValue(const MachineInstr &MI, unsigned OpIdx)
+ const { return 0;}
+ uint32_t getPostIdxRegOpValue(const MachineInstr &MI, unsigned OpIdx)
+ const { return 0;}
+ uint32_t getAddrMode3OffsetOpValue(const MachineInstr &MI, unsigned OpIdx)
+ const { return 0;}
+ uint32_t getAddrMode3OpValue(const MachineInstr &MI, unsigned Op)
+ const { return 0; }
+ uint32_t getAddrModeThumbSPOpValue(const MachineInstr &MI, unsigned Op)
+ const { return 0; }
+ uint32_t getAddrModeSOpValue(const MachineInstr &MI, unsigned Op)
+ const { return 0; }
+ uint32_t getAddrModeISOpValue(const MachineInstr &MI, unsigned Op)
+ const { return 0; }
+ uint32_t getAddrModePCOpValue(const MachineInstr &MI, unsigned Op)
+ const { return 0; }
+ uint32_t getAddrMode5OpValue(const MachineInstr &MI, unsigned Op) const {
+ // {17-13} = reg
+ // {12} = (U)nsigned (add == '1', sub == '0')
+ // {11-0} = imm12
+ const MachineOperand &MO = MI.getOperand(Op);
+ const MachineOperand &MO1 = MI.getOperand(Op + 1);
+ if (!MO.isReg()) {
+ emitConstPoolAddress(MO.getIndex(), ARM::reloc_arm_cp_entry);
+ return 0;
+ }
+ unsigned Reg = getARMRegisterNumbering(MO.getReg());
+ int32_t Imm12 = MO1.getImm();
+
+ // Special value for #-0
+ if (Imm12 == INT32_MIN)
+ Imm12 = 0;
+
+ // Immediate is always encoded as positive. The 'U' bit controls add vs
+ // sub.
+ bool isAdd = true;
+ if (Imm12 < 0) {
+ Imm12 = -Imm12;
+ isAdd = false;
+ }
+
+ uint32_t Binary = Imm12 & 0xfff;
+ if (isAdd)
+ Binary |= (1 << 12);
+ Binary |= (Reg << 13);
+ return Binary;
+ }
+ unsigned getNEONVcvtImm32OpValue(const MachineInstr &MI, unsigned Op)
+ const { return 0; }
+
+ unsigned getRegisterListOpValue(const MachineInstr &MI, unsigned Op)
+ const { return 0; }
+
+ unsigned getShiftRight8Imm(const MachineInstr &MI, unsigned Op)
+ const { return 0; }
+ unsigned getShiftRight16Imm(const MachineInstr &MI, unsigned Op)
+ const { return 0; }
+ unsigned getShiftRight32Imm(const MachineInstr &MI, unsigned Op)
+ const { return 0; }
+ unsigned getShiftRight64Imm(const MachineInstr &MI, unsigned Op)
+ const { return 0; }
+
+ /// getMovi32Value - Return binary encoding of operand for movw/movt. If the
+ /// machine operand requires relocation, record the relocation and return
+ /// zero.
+ unsigned getMovi32Value(const MachineInstr &MI,const MachineOperand &MO,
+ unsigned Reloc);
+
/// getShiftOp - Return the shift opcode (bit[6:5]) of the immediate value.
///
unsigned getShiftOp(unsigned Imm) const ;
/// Routines that handle operands which add machine relocations which are
/// fixed up by the relocation stage.
- void emitGlobalAddress(GlobalValue *GV, unsigned Reloc,
- bool NeedStub, intptr_t ACPV = 0);
- void emitExternalSymbolAddress(const char *ES, unsigned Reloc);
- void emitConstPoolAddress(unsigned CPI, unsigned Reloc);
- void emitJumpTableAddress(unsigned JTIndex, unsigned Reloc);
+ void emitGlobalAddress(const GlobalValue *GV, unsigned Reloc,
+ bool MayNeedFarStub, bool Indirect,
+ intptr_t ACPV = 0) const;
+ void emitExternalSymbolAddress(const char *ES, unsigned Reloc) const;
+ void emitConstPoolAddress(unsigned CPI, unsigned Reloc) const;
+ void emitJumpTableAddress(unsigned JTIndex, unsigned Reloc) const;
void emitMachineBasicBlock(MachineBasicBlock *BB, unsigned Reloc,
- intptr_t JTBase = 0);
+ intptr_t JTBase = 0) const;
};
- char ARMCodeEmitter::ID = 0;
}
-/// createARMCodeEmitterPass - Return a pass that emits the collected ARM code
-/// to the specified MCE object.
-FunctionPass *llvm::createARMCodeEmitterPass(ARMTargetMachine &TM,
- MachineCodeEmitter &MCE) {
- return new ARMCodeEmitter(TM, MCE);
+char ARMCodeEmitter::ID = 0;
+
+/// createARMJITCodeEmitterPass - Return a pass that emits the collected ARM
+/// code to the specified MCE object.
+FunctionPass *llvm::createARMJITCodeEmitterPass(ARMBaseTargetMachine &TM,
+ JITCodeEmitter &JCE) {
+ return new ARMCodeEmitter(TM, JCE);
}
bool ARMCodeEmitter::runOnMachineFunction(MachineFunction &MF) {
assert((MF.getTarget().getRelocationModel() != Reloc::Default ||
MF.getTarget().getRelocationModel() != Reloc::Static) &&
"JIT relocation model must be set to static or default!");
- II = ((ARMTargetMachine&)MF.getTarget()).getInstrInfo();
- TD = ((ARMTargetMachine&)MF.getTarget()).getTargetData();
- JTI = ((ARMTargetMachine&)MF.getTarget()).getJITInfo();
+ JTI = ((ARMTargetMachine &)MF.getTarget()).getJITInfo();
+ II = ((const ARMTargetMachine &)MF.getTarget()).getInstrInfo();
+ TD = ((const ARMTargetMachine &)MF.getTarget()).getTargetData();
+ Subtarget = &TM.getSubtarget<ARMSubtarget>();
MCPEs = &MF.getConstantPool()->getConstants();
- MJTEs = &MF.getJumpTableInfo()->getJumpTables();
+ MJTEs = 0;
+ if (MF.getJumpTableInfo()) MJTEs = &MF.getJumpTableInfo()->getJumpTables();
IsPIC = TM.getRelocationModel() == Reloc::PIC_;
+ IsThumb = MF.getInfo<ARMFunctionInfo>()->isThumbFunction();
JTI->Initialize(MF, IsPIC);
+ MMI = &getAnalysis<MachineModuleInfo>();
+ MCE.setModuleInfo(MMI);
do {
- DOUT << "JITTing function '" << MF.getFunction()->getName() << "'\n";
+ DEBUG(errs() << "JITTing function '"
+ << MF.getFunction()->getName() << "'\n");
MCE.startFunction(MF);
- for (MachineFunction::iterator MBB = MF.begin(), E = MF.end();
+ for (MachineFunction::iterator MBB = MF.begin(), E = MF.end();
MBB != E; ++MBB) {
MCE.StartMachineBasicBlock(MBB);
for (MachineBasicBlock::const_iterator I = MBB->begin(), E = MBB->end();
///
unsigned ARMCodeEmitter::getShiftOp(unsigned Imm) const {
switch (ARM_AM::getAM2ShiftOpc(Imm)) {
- default: assert(0 && "Unknown shift opc!");
+ default: llvm_unreachable("Unknown shift opc!");
case ARM_AM::asr: return 2;
case ARM_AM::lsl: return 0;
case ARM_AM::lsr: return 1;
return 0;
}
+/// getMovi32Value - Return binary encoding of operand for movw/movt. If the
+/// machine operand requires relocation, record the relocation and return zero.
+unsigned ARMCodeEmitter::getMovi32Value(const MachineInstr &MI,
+ const MachineOperand &MO,
+ unsigned Reloc) {
+ assert(((Reloc == ARM::reloc_arm_movt) || (Reloc == ARM::reloc_arm_movw))
+ && "Relocation to this function should be for movt or movw");
+
+ if (MO.isImm())
+ return static_cast<unsigned>(MO.getImm());
+ else if (MO.isGlobal())
+ emitGlobalAddress(MO.getGlobal(), Reloc, true, false);
+ else if (MO.isSymbol())
+ emitExternalSymbolAddress(MO.getSymbolName(), Reloc);
+ else if (MO.isMBB())
+ emitMachineBasicBlock(MO.getMBB(), Reloc);
+ else {
+#ifndef NDEBUG
+ errs() << MO;
+#endif
+ llvm_unreachable("Unsupported operand type for movw/movt");
+ }
+ return 0;
+}
+
/// getMachineOpValue - Return binary encoding of operand. If the machine
/// operand requires relocation, record the relocation and return zero.
unsigned ARMCodeEmitter::getMachineOpValue(const MachineInstr &MI,
- const MachineOperand &MO) {
+ const MachineOperand &MO) const {
if (MO.isReg())
- return ARMRegisterInfo::getRegisterNumbering(MO.getReg());
+ return getARMRegisterNumbering(MO.getReg());
else if (MO.isImm())
return static_cast<unsigned>(MO.getImm());
else if (MO.isGlobal())
- emitGlobalAddress(MO.getGlobal(), ARM::reloc_arm_branch, true);
+ emitGlobalAddress(MO.getGlobal(), ARM::reloc_arm_branch, true, false);
else if (MO.isSymbol())
emitExternalSymbolAddress(MO.getSymbolName(), ARM::reloc_arm_branch);
else if (MO.isCPI()) {
- const TargetInstrDesc &TID = MI.getDesc();
+ const MCInstrDesc &MCID = MI.getDesc();
// For VFP load, the immediate offset is multiplied by 4.
- unsigned Reloc = ((TID.TSFlags & ARMII::FormMask) == ARMII::VFPLdStFrm)
+ unsigned Reloc = ((MCID.TSFlags & ARMII::FormMask) == ARMII::VFPLdStFrm)
? ARM::reloc_arm_vfp_cp_entry : ARM::reloc_arm_cp_entry;
emitConstPoolAddress(MO.getIndex(), Reloc);
} else if (MO.isJTI())
emitJumpTableAddress(MO.getIndex(), ARM::reloc_arm_relative);
else if (MO.isMBB())
emitMachineBasicBlock(MO.getMBB(), ARM::reloc_arm_branch);
- else {
- cerr << "ERROR: Unknown type of MachineOperand: " << MO << "\n";
- abort();
- }
+ else
+ llvm_unreachable("Unable to encode MachineOperand!");
return 0;
}
/// emitGlobalAddress - Emit the specified address to the code stream.
///
-void ARMCodeEmitter::emitGlobalAddress(GlobalValue *GV, unsigned Reloc,
- bool NeedStub, intptr_t ACPV) {
- MCE.addRelocation(MachineRelocation::getGV(MCE.getCurrentPCOffset(),
- Reloc, GV, ACPV, NeedStub));
+void ARMCodeEmitter::emitGlobalAddress(const GlobalValue *GV, unsigned Reloc,
+ bool MayNeedFarStub, bool Indirect,
+ intptr_t ACPV) const {
+ MachineRelocation MR = Indirect
+ ? MachineRelocation::getIndirectSymbol(MCE.getCurrentPCOffset(), Reloc,
+ const_cast<GlobalValue *>(GV),
+ ACPV, MayNeedFarStub)
+ : MachineRelocation::getGV(MCE.getCurrentPCOffset(), Reloc,
+ const_cast<GlobalValue *>(GV), ACPV,
+ MayNeedFarStub);
+ MCE.addRelocation(MR);
}
/// emitExternalSymbolAddress - Arrange for the address of an external symbol to
/// be emitted to the current location in the function, and allow it to be PC
/// relative.
-void ARMCodeEmitter::emitExternalSymbolAddress(const char *ES, unsigned Reloc) {
+void ARMCodeEmitter::
+emitExternalSymbolAddress(const char *ES, unsigned Reloc) const {
MCE.addRelocation(MachineRelocation::getExtSym(MCE.getCurrentPCOffset(),
Reloc, ES));
}
/// emitConstPoolAddress - Arrange for the address of an constant pool
/// to be emitted to the current location in the function, and allow it to be PC
/// relative.
-void ARMCodeEmitter::emitConstPoolAddress(unsigned CPI, unsigned Reloc) {
+void ARMCodeEmitter::emitConstPoolAddress(unsigned CPI, unsigned Reloc) const {
// Tell JIT emitter we'll resolve the address.
MCE.addRelocation(MachineRelocation::getConstPool(MCE.getCurrentPCOffset(),
Reloc, CPI, 0, true));
/// emitJumpTableAddress - Arrange for the address of a jump table to
/// be emitted to the current location in the function, and allow it to be PC
/// relative.
-void ARMCodeEmitter::emitJumpTableAddress(unsigned JTIndex, unsigned Reloc) {
+void ARMCodeEmitter::
+emitJumpTableAddress(unsigned JTIndex, unsigned Reloc) const {
MCE.addRelocation(MachineRelocation::getJumpTable(MCE.getCurrentPCOffset(),
Reloc, JTIndex, 0, true));
}
/// emitMachineBasicBlock - Emit the specified address basic block.
void ARMCodeEmitter::emitMachineBasicBlock(MachineBasicBlock *BB,
- unsigned Reloc, intptr_t JTBase) {
+ unsigned Reloc,
+ intptr_t JTBase) const {
MCE.addRelocation(MachineRelocation::getBB(MCE.getCurrentPCOffset(),
Reloc, BB, JTBase));
}
void ARMCodeEmitter::emitWordLE(unsigned Binary) {
-#ifndef NDEBUG
- DOUT << " 0x" << std::hex << std::setw(8) << std::setfill('0')
- << Binary << std::dec << "\n";
-#endif
+ DEBUG(errs() << " 0x";
+ errs().write_hex(Binary) << "\n");
MCE.emitWordLE(Binary);
}
void ARMCodeEmitter::emitDWordLE(uint64_t Binary) {
-#ifndef NDEBUG
- DOUT << " 0x" << std::hex << std::setw(8) << std::setfill('0')
- << (unsigned)Binary << std::dec << "\n";
- DOUT << " 0x" << std::hex << std::setw(8) << std::setfill('0')
- << (unsigned)(Binary >> 32) << std::dec << "\n";
-#endif
+ DEBUG(errs() << " 0x";
+ errs().write_hex(Binary) << "\n");
MCE.emitDWordLE(Binary);
}
void ARMCodeEmitter::emitInstruction(const MachineInstr &MI) {
- DOUT << "JIT: " << (void*)MCE.getCurrentPCValue() << ":\t" << MI;
+ DEBUG(errs() << "JIT: " << (void*)MCE.getCurrentPCValue() << ":\t" << MI);
- NumEmitted++; // Keep track of the # of mi's emitted
+ MCE.processDebugLoc(MI.getDebugLoc(), true);
+
+ ++NumEmitted; // Keep track of the # of mi's emitted
switch (MI.getDesc().TSFlags & ARMII::FormMask) {
- default:
- assert(0 && "Unhandled instruction encoding format!");
+ default: {
+ llvm_unreachable("Unhandled instruction encoding format!");
+ break;
+ }
+ case ARMII::MiscFrm:
+ if (MI.getOpcode() == ARM::LEApcrelJT) {
+ // Materialize jumptable address.
+ emitLEApcrelJTInstruction(MI);
+ break;
+ }
+ llvm_unreachable("Unhandled instruction encoding!");
break;
case ARMII::Pseudo:
emitPseudoInstruction(MI);
case ARMII::StMiscFrm:
emitMiscLoadStoreInstruction(MI);
break;
- case ARMII::LdMulFrm:
- case ARMII::StMulFrm:
+ case ARMII::LdStMulFrm:
emitLoadStoreMultipleInstruction(MI);
break;
case ARMII::MulFrm:
case ARMII::ArithMiscFrm:
emitMiscArithInstruction(MI);
break;
+ case ARMII::SatFrm:
+ emitSaturateInstruction(MI);
+ break;
case ARMII::BrFrm:
emitBranchInstruction(MI);
break;
case ARMII::VFPConv1Frm:
case ARMII::VFPConv2Frm:
case ARMII::VFPConv3Frm:
+ case ARMII::VFPConv4Frm:
+ case ARMII::VFPConv5Frm:
emitVFPConversionInstruction(MI);
break;
case ARMII::VFPLdStFrm:
case ARMII::VFPLdStMulFrm:
emitVFPLoadStoreMultipleInstruction(MI);
break;
- case ARMII::VFPMiscFrm:
- emitMiscInstruction(MI);
+
+ // NEON instructions.
+ case ARMII::NGetLnFrm:
+ case ARMII::NSetLnFrm:
+ emitNEONLaneInstruction(MI);
+ break;
+ case ARMII::NDupFrm:
+ emitNEONDupInstruction(MI);
+ break;
+ case ARMII::N1RegModImmFrm:
+ emitNEON1RegModImmInstruction(MI);
+ break;
+ case ARMII::N2RegFrm:
+ emitNEON2RegInstruction(MI);
+ break;
+ case ARMII::N3RegFrm:
+ emitNEON3RegInstruction(MI);
break;
}
+ MCE.processDebugLoc(MI.getDebugLoc(), false);
}
void ARMCodeEmitter::emitConstPoolInstruction(const MachineInstr &MI) {
unsigned CPI = MI.getOperand(0).getImm(); // CP instruction index.
unsigned CPIndex = MI.getOperand(1).getIndex(); // Actual cp entry index.
const MachineConstantPoolEntry &MCPE = (*MCPEs)[CPIndex];
-
+
// Remember the CONSTPOOL_ENTRY address for later relocation.
JTI->addConstantPoolEntryAddr(CPI, MCE.getCurrentPCValue());
ARMConstantPoolValue *ACPV =
static_cast<ARMConstantPoolValue*>(MCPE.Val.MachineCPVal);
- DOUT << " ** ARM constant pool #" << CPI << " @ "
- << (void*)MCE.getCurrentPCValue() << " " << *ACPV << '\n';
+ DEBUG(errs() << " ** ARM constant pool #" << CPI << " @ "
+ << (void*)MCE.getCurrentPCValue() << " " << *ACPV << '\n');
- GlobalValue *GV = ACPV->getGV();
+ assert(ACPV->isGlobalValue() && "unsupported constant pool value");
+ const GlobalValue *GV = cast<ARMConstantPoolConstant>(ACPV)->getGV();
if (GV) {
- assert(!ACPV->isStub() && "Don't know how to deal this yet!");
- if (ACPV->isNonLazyPointer())
- MCE.addRelocation(MachineRelocation::getIndirectSymbol(
- MCE.getCurrentPCOffset(), ARM::reloc_arm_machine_cp_entry, GV,
- (intptr_t)ACPV, false));
- else
- emitGlobalAddress(GV, ARM::reloc_arm_machine_cp_entry,
- ACPV->isStub(), (intptr_t)ACPV);
- } else {
- assert(!ACPV->isNonLazyPointer() && "Don't know how to deal this yet!");
- emitExternalSymbolAddress(ACPV->getSymbol(), ARM::reloc_arm_absolute);
+ Reloc::Model RelocM = TM.getRelocationModel();
+ emitGlobalAddress(GV, ARM::reloc_arm_machine_cp_entry,
+ isa<Function>(GV),
+ Subtarget->GVIsIndirectSymbol(GV, RelocM),
+ (intptr_t)ACPV);
+ } else {
+ const char *Sym = cast<ARMConstantPoolSymbol>(ACPV)->getSymbol();
+ emitExternalSymbolAddress(Sym, ARM::reloc_arm_absolute);
}
emitWordLE(0);
} else {
- Constant *CV = MCPE.Val.ConstVal;
-
- DOUT << " ** Constant pool #" << CPI << " @ "
- << (void*)MCE.getCurrentPCValue() << " " << *CV << '\n';
-
- if (GlobalValue *GV = dyn_cast<GlobalValue>(CV)) {
- emitGlobalAddress(GV, ARM::reloc_arm_absolute, false);
+ const Constant *CV = MCPE.Val.ConstVal;
+
+ DEBUG({
+ errs() << " ** Constant pool #" << CPI << " @ "
+ << (void*)MCE.getCurrentPCValue() << " ";
+ if (const Function *F = dyn_cast<Function>(CV))
+ errs() << F->getName();
+ else
+ errs() << *CV;
+ errs() << '\n';
+ });
+
+ if (const GlobalValue *GV = dyn_cast<GlobalValue>(CV)) {
+ emitGlobalAddress(GV, ARM::reloc_arm_absolute, isa<Function>(GV), false);
emitWordLE(0);
} else if (const ConstantInt *CI = dyn_cast<ConstantInt>(CV)) {
- uint32_t Val = *(uint32_t*)CI->getValue().getRawData();
+ uint32_t Val = uint32_t(*CI->getValue().getRawData());
emitWordLE(Val);
} else if (const ConstantFP *CFP = dyn_cast<ConstantFP>(CV)) {
- if (CFP->getType() == Type::FloatTy)
+ if (CFP->getType()->isFloatTy())
emitWordLE(CFP->getValueAPF().bitcastToAPInt().getZExtValue());
- else if (CFP->getType() == Type::DoubleTy)
+ else if (CFP->getType()->isDoubleTy())
emitDWordLE(CFP->getValueAPF().bitcastToAPInt().getZExtValue());
else {
- assert(0 && "Unable to handle this constantpool entry!");
- abort();
+ llvm_unreachable("Unable to handle this constantpool entry!");
}
} else {
- assert(0 && "Unable to handle this constantpool entry!");
- abort();
+ llvm_unreachable("Unable to handle this constantpool entry!");
}
}
}
+void ARMCodeEmitter::emitMOVi32immInstruction(const MachineInstr &MI) {
+ const MachineOperand &MO0 = MI.getOperand(0);
+ const MachineOperand &MO1 = MI.getOperand(1);
+
+ // Emit the 'movw' instruction.
+ unsigned Binary = 0x30 << 20; // mov: Insts{27-20} = 0b00110000
+
+ unsigned Lo16 = getMovi32Value(MI, MO1, ARM::reloc_arm_movw) & 0xFFFF;
+
+ // Set the conditional execution predicate.
+ Binary |= II->getPredicate(&MI) << ARMII::CondShift;
+
+ // Encode Rd.
+ Binary |= getMachineOpValue(MI, MO0) << ARMII::RegRdShift;
+
+ // Encode imm16 as imm4:imm12
+ Binary |= Lo16 & 0xFFF; // Insts{11-0} = imm12
+ Binary |= ((Lo16 >> 12) & 0xF) << 16; // Insts{19-16} = imm4
+ emitWordLE(Binary);
+
+ unsigned Hi16 = getMovi32Value(MI, MO1, ARM::reloc_arm_movt) >> 16;
+ // Emit the 'movt' instruction.
+ Binary = 0x34 << 20; // movt: Insts{27-20} = 0b00110100
+
+ // Set the conditional execution predicate.
+ Binary |= II->getPredicate(&MI) << ARMII::CondShift;
+
+ // Encode Rd.
+ Binary |= getMachineOpValue(MI, MO0) << ARMII::RegRdShift;
+
+ // Encode imm16 as imm4:imm1, same as movw above.
+ Binary |= Hi16 & 0xFFF;
+ Binary |= ((Hi16 >> 12) & 0xF) << 16;
+ emitWordLE(Binary);
+}
+
void ARMCodeEmitter::emitMOVi2piecesInstruction(const MachineInstr &MI) {
const MachineOperand &MO0 = MI.getOperand(0);
const MachineOperand &MO1 = MI.getOperand(1);
- assert(MO1.isImm() && "Not a valid so_imm value!");
+ assert(MO1.isImm() && ARM_AM::isSOImmTwoPartVal(MO1.getImm()) &&
+ "Not a valid so_imm value!");
unsigned V1 = ARM_AM::getSOImmTwoPartFirst(MO1.getImm());
unsigned V2 = ARM_AM::getSOImmTwoPartSecond(MO1.getImm());
// Encode so_imm.
// Set bit I(25) to identify this is the immediate form of <shifter_op>
Binary |= 1 << ARMII::I_BitShift;
- Binary |= getMachineSoImmOpValue(ARM_AM::getSOImmVal(V1));
+ Binary |= getMachineSoImmOpValue(V1);
emitWordLE(Binary);
// Now the 'orr' instruction.
// Encode so_imm.
// Set bit I(25) to identify this is the immediate form of <shifter_op>
Binary |= 1 << ARMII::I_BitShift;
- Binary |= getMachineSoImmOpValue(ARM_AM::getSOImmVal(V2));
+ Binary |= getMachineSoImmOpValue(V2);
emitWordLE(Binary);
}
void ARMCodeEmitter::emitLEApcrelJTInstruction(const MachineInstr &MI) {
// It's basically add r, pc, (LJTI - $+8)
-
- const TargetInstrDesc &TID = MI.getDesc();
+
+ const MCInstrDesc &MCID = MI.getDesc();
// Emit the 'add' instruction.
- unsigned Binary = 0x4 << 21; // add: Insts{24-31} = 0b0100
+ unsigned Binary = 0x4 << 21; // add: Insts{24-21} = 0b0100
// Set the conditional execution predicate
Binary |= II->getPredicate(&MI) << ARMII::CondShift;
// Encode S bit if MI modifies CPSR.
- Binary |= getAddrModeSBit(MI, TID);
+ Binary |= getAddrModeSBit(MI, MCID);
// Encode Rd.
Binary |= getMachineOpValue(MI, 0) << ARMII::RegRdShift;
// Encode Rn which is PC.
- Binary |= ARMRegisterInfo::getRegisterNumbering(ARM::PC) << ARMII::RegRnShift;
+ Binary |= getARMRegisterNumbering(ARM::PC) << ARMII::RegRnShift;
// Encode the displacement.
- // Set bit I(25) to identify this is the immediate form of <shifter_op>.
Binary |= 1 << ARMII::I_BitShift;
emitJumpTableAddress(MI.getOperand(1).getIndex(), ARM::reloc_arm_jt_base);
emitWordLE(Binary);
}
+void ARMCodeEmitter::emitPseudoMoveInstruction(const MachineInstr &MI) {
+ unsigned Opcode = MI.getDesc().Opcode;
+
+ // Part of binary is determined by TableGn.
+ unsigned Binary = getBinaryCodeForInstr(MI);
+
+ // Set the conditional execution predicate
+ Binary |= II->getPredicate(&MI) << ARMII::CondShift;
+
+ // Encode S bit if MI modifies CPSR.
+ if (Opcode == ARM::MOVsrl_flag || Opcode == ARM::MOVsra_flag)
+ Binary |= 1 << ARMII::S_BitShift;
+
+ // Encode register def if there is one.
+ Binary |= getMachineOpValue(MI, 0) << ARMII::RegRdShift;
+
+ // Encode the shift operation.
+ switch (Opcode) {
+ default: break;
+ case ARM::RRX:
+ // rrx
+ Binary |= 0x6 << 4;
+ break;
+ case ARM::MOVsrl_flag:
+ // lsr #1
+ Binary |= (0x2 << 4) | (1 << 7);
+ break;
+ case ARM::MOVsra_flag:
+ // asr #1
+ Binary |= (0x4 << 4) | (1 << 7);
+ break;
+ }
+
+ // Encode register Rm.
+ Binary |= getMachineOpValue(MI, 1);
+
+ emitWordLE(Binary);
+}
+
void ARMCodeEmitter::addPCLabel(unsigned LabelID) {
- DOUT << " ** LPC" << LabelID << " @ "
- << (void*)MCE.getCurrentPCValue() << '\n';
+ DEBUG(errs() << " ** LPC" << LabelID << " @ "
+ << (void*)MCE.getCurrentPCValue() << '\n');
JTI->addPCLabelAddr(LabelID, MCE.getCurrentPCValue());
}
unsigned Opcode = MI.getDesc().Opcode;
switch (Opcode) {
default:
- abort(); // FIXME:
+ llvm_unreachable("ARMCodeEmitter::emitPseudoInstruction");
+ case ARM::BX_CALL:
+ case ARM::BMOVPCRX_CALL:
+ case ARM::BXr9_CALL:
+ case ARM::BMOVPCRXr9_CALL: {
+ // First emit mov lr, pc
+ unsigned Binary = 0x01a0e00f;
+ Binary |= II->getPredicate(&MI) << ARMII::CondShift;
+ emitWordLE(Binary);
+
+ // and then emit the branch.
+ emitMiscBranchInstruction(MI);
+ break;
+ }
+ case TargetOpcode::INLINEASM: {
+ // We allow inline assembler nodes with empty bodies - they can
+ // implicitly define registers, which is ok for JIT.
+ if (MI.getOperand(0).getSymbolName()[0]) {
+ report_fatal_error("JIT does not support inline asm!");
+ }
+ break;
+ }
+ case TargetOpcode::PROLOG_LABEL:
+ case TargetOpcode::EH_LABEL:
+ MCE.emitLabel(MI.getOperand(0).getMCSymbol());
+ break;
+ case TargetOpcode::IMPLICIT_DEF:
+ case TargetOpcode::KILL:
+ // Do nothing.
+ break;
case ARM::CONSTPOOL_ENTRY:
emitConstPoolInstruction(MI);
break;
emitMiscLoadStoreInstruction(MI, ARM::PC);
break;
}
- case ARM::MOVi2pieces:
+
+ case ARM::MOVi32imm:
// Two instructions to materialize a constant.
- emitMOVi2piecesInstruction(MI);
+ if (Subtarget->hasV6T2Ops())
+ emitMOVi32immInstruction(MI);
+ else
+ emitMOVi2piecesInstruction(MI);
break;
+
case ARM::LEApcrelJT:
// Materialize jumptable address.
emitLEApcrelJTInstruction(MI);
break;
+ case ARM::RRX:
+ case ARM::MOVsrl_flag:
+ case ARM::MOVsra_flag:
+ emitPseudoMoveInstruction(MI);
+ break;
}
}
-
unsigned ARMCodeEmitter::getMachineSoRegOpValue(const MachineInstr &MI,
- const TargetInstrDesc &TID,
+ const MCInstrDesc &MCID,
const MachineOperand &MO,
unsigned OpIdx) {
unsigned Binary = getMachineOpValue(MI, MO);
// ROR - 0111
// RRX - 0110 and bit[11:8] clear.
switch (SOpc) {
- default: assert(0 && "Unknown shift opc!");
+ default: llvm_unreachable("Unknown shift opc!");
case ARM_AM::lsl: SBits = 0x1; break;
case ARM_AM::lsr: SBits = 0x3; break;
case ARM_AM::asr: SBits = 0x5; break;
// ASR - 100
// ROR - 110
switch (SOpc) {
- default: assert(0 && "Unknown shift opc!");
+ default: llvm_unreachable("Unknown shift opc!");
case ARM_AM::lsl: SBits = 0x0; break;
case ARM_AM::lsr: SBits = 0x2; break;
case ARM_AM::asr: SBits = 0x4; break;
if (Rs) {
// Encode Rs bit[11:8].
assert(ARM_AM::getSORegOffset(MO2.getImm()) == 0);
- return Binary |
- (ARMRegisterInfo::getRegisterNumbering(Rs) << ARMII::RegRsShift);
+ return Binary | (getARMRegisterNumbering(Rs) << ARMII::RegRsShift);
}
// Encode shift_imm bit[11:7].
}
unsigned ARMCodeEmitter::getMachineSoImmOpValue(unsigned SoImm) {
+ int SoImmVal = ARM_AM::getSOImmVal(SoImm);
+ assert(SoImmVal != -1 && "Not a valid so_imm value!");
+
// Encode rotate_imm.
- unsigned Binary = (ARM_AM::getSOImmValRot(SoImm) >> 1)
+ unsigned Binary = (ARM_AM::getSOImmValRot((unsigned)SoImmVal) >> 1)
<< ARMII::SoRotImmShift;
// Encode immed_8.
- Binary |= ARM_AM::getSOImmValImm(SoImm);
+ Binary |= ARM_AM::getSOImmValImm((unsigned)SoImmVal);
return Binary;
}
unsigned ARMCodeEmitter::getAddrModeSBit(const MachineInstr &MI,
- const TargetInstrDesc &TID) const {
- for (unsigned i = MI.getNumOperands(), e = TID.getNumOperands(); i != e; --i){
+ const MCInstrDesc &MCID) const {
+ for (unsigned i = MI.getNumOperands(), e = MCID.getNumOperands(); i >= e;--i){
const MachineOperand &MO = MI.getOperand(i-1);
if (MO.isReg() && MO.isDef() && MO.getReg() == ARM::CPSR)
return 1 << ARMII::S_BitShift;
void ARMCodeEmitter::emitDataProcessingInstruction(const MachineInstr &MI,
unsigned ImplicitRd,
unsigned ImplicitRn) {
- const TargetInstrDesc &TID = MI.getDesc();
+ const MCInstrDesc &MCID = MI.getDesc();
// Part of binary is determined by TableGn.
unsigned Binary = getBinaryCodeForInstr(MI);
Binary |= II->getPredicate(&MI) << ARMII::CondShift;
// Encode S bit if MI modifies CPSR.
- Binary |= getAddrModeSBit(MI, TID);
+ Binary |= getAddrModeSBit(MI, MCID);
// Encode register def if there is one.
- unsigned NumDefs = TID.getNumDefs();
+ unsigned NumDefs = MCID.getNumDefs();
unsigned OpIdx = 0;
if (NumDefs)
Binary |= getMachineOpValue(MI, OpIdx++) << ARMII::RegRdShift;
else if (ImplicitRd)
// Special handling for implicit use (e.g. PC).
- Binary |= (ARMRegisterInfo::getRegisterNumbering(ImplicitRd)
- << ARMII::RegRdShift);
+ Binary |= (getARMRegisterNumbering(ImplicitRd) << ARMII::RegRdShift);
+
+ if (MCID.Opcode == ARM::MOVi16) {
+ // Get immediate from MI.
+ unsigned Lo16 = getMovi32Value(MI, MI.getOperand(OpIdx),
+ ARM::reloc_arm_movw);
+ // Encode imm which is the same as in emitMOVi32immInstruction().
+ Binary |= Lo16 & 0xFFF;
+ Binary |= ((Lo16 >> 12) & 0xF) << 16;
+ emitWordLE(Binary);
+ return;
+ } else if(MCID.Opcode == ARM::MOVTi16) {
+ unsigned Hi16 = (getMovi32Value(MI, MI.getOperand(OpIdx),
+ ARM::reloc_arm_movt) >> 16);
+ Binary |= Hi16 & 0xFFF;
+ Binary |= ((Hi16 >> 12) & 0xF) << 16;
+ emitWordLE(Binary);
+ return;
+ } else if ((MCID.Opcode == ARM::BFC) || (MCID.Opcode == ARM::BFI)) {
+ uint32_t v = ~MI.getOperand(2).getImm();
+ int32_t lsb = CountTrailingZeros_32(v);
+ int32_t msb = (32 - CountLeadingZeros_32(v)) - 1;
+ // Instr{20-16} = msb, Instr{11-7} = lsb
+ Binary |= (msb & 0x1F) << 16;
+ Binary |= (lsb & 0x1F) << 7;
+ emitWordLE(Binary);
+ return;
+ } else if ((MCID.Opcode == ARM::UBFX) || (MCID.Opcode == ARM::SBFX)) {
+ // Encode Rn in Instr{0-3}
+ Binary |= getMachineOpValue(MI, OpIdx++);
+
+ uint32_t lsb = MI.getOperand(OpIdx++).getImm();
+ uint32_t widthm1 = MI.getOperand(OpIdx++).getImm() - 1;
+
+ // Instr{20-16} = widthm1, Instr{11-7} = lsb
+ Binary |= (widthm1 & 0x1F) << 16;
+ Binary |= (lsb & 0x1F) << 7;
+ emitWordLE(Binary);
+ return;
+ }
// If this is a two-address operand, skip it. e.g. MOVCCr operand 1.
- if (TID.getOperandConstraint(OpIdx, TOI::TIED_TO) != -1)
+ if (MCID.getOperandConstraint(OpIdx, MCOI::TIED_TO) != -1)
++OpIdx;
// Encode first non-shifter register operand if there is one.
- bool isUnary = TID.TSFlags & ARMII::UnaryDP;
+ bool isUnary = MCID.TSFlags & ARMII::UnaryDP;
if (!isUnary) {
if (ImplicitRn)
// Special handling for implicit use (e.g. PC).
- Binary |= (ARMRegisterInfo::getRegisterNumbering(ImplicitRn)
- << ARMII::RegRnShift);
+ Binary |= (getARMRegisterNumbering(ImplicitRn) << ARMII::RegRnShift);
else {
Binary |= getMachineOpValue(MI, OpIdx) << ARMII::RegRnShift;
++OpIdx;
// Encode shifter operand.
const MachineOperand &MO = MI.getOperand(OpIdx);
- if ((TID.TSFlags & ARMII::FormMask) == ARMII::DPSoRegFrm) {
+ if ((MCID.TSFlags & ARMII::FormMask) == ARMII::DPSoRegFrm) {
// Encode SoReg.
- emitWordLE(Binary | getMachineSoRegOpValue(MI, TID, MO, OpIdx));
+ emitWordLE(Binary | getMachineSoRegOpValue(MI, MCID, MO, OpIdx));
return;
}
if (MO.isReg()) {
// Encode register Rm.
- emitWordLE(Binary | ARMRegisterInfo::getRegisterNumbering(MO.getReg()));
+ emitWordLE(Binary | getARMRegisterNumbering(MO.getReg()));
return;
}
// Encode so_imm.
- // Set bit I(25) to identify this is the immediate form of <shifter_op>.
- Binary |= 1 << ARMII::I_BitShift;
- Binary |= getMachineSoImmOpValue(MO.getImm());
+ Binary |= getMachineSoImmOpValue((unsigned)MO.getImm());
emitWordLE(Binary);
}
void ARMCodeEmitter::emitLoadStoreInstruction(const MachineInstr &MI,
unsigned ImplicitRd,
unsigned ImplicitRn) {
- const TargetInstrDesc &TID = MI.getDesc();
+ const MCInstrDesc &MCID = MI.getDesc();
+ unsigned Form = MCID.TSFlags & ARMII::FormMask;
+ bool IsPrePost = (MCID.TSFlags & ARMII::IndexModeMask) != 0;
// Part of binary is determined by TableGn.
unsigned Binary = getBinaryCodeForInstr(MI);
+ // If this is an LDRi12, STRi12 or LDRcp, nothing more needs be done.
+ if (MI.getOpcode() == ARM::LDRi12 || MI.getOpcode() == ARM::LDRcp ||
+ MI.getOpcode() == ARM::STRi12) {
+ emitWordLE(Binary);
+ return;
+ }
+
// Set the conditional execution predicate
Binary |= II->getPredicate(&MI) << ARMII::CondShift;
- // Set first operand
unsigned OpIdx = 0;
+
+ // Operand 0 of a pre- and post-indexed store is the address base
+ // writeback. Skip it.
+ bool Skipped = false;
+ if (IsPrePost && Form == ARMII::StFrm) {
+ ++OpIdx;
+ Skipped = true;
+ }
+
+ // Set first operand
if (ImplicitRd)
// Special handling for implicit use (e.g. PC).
- Binary |= (ARMRegisterInfo::getRegisterNumbering(ImplicitRd)
- << ARMII::RegRdShift);
+ Binary |= (getARMRegisterNumbering(ImplicitRd) << ARMII::RegRdShift);
else
Binary |= getMachineOpValue(MI, OpIdx++) << ARMII::RegRdShift;
// Set second operand
if (ImplicitRn)
// Special handling for implicit use (e.g. PC).
- Binary |= (ARMRegisterInfo::getRegisterNumbering(ImplicitRn)
- << ARMII::RegRnShift);
+ Binary |= (getARMRegisterNumbering(ImplicitRn) << ARMII::RegRnShift);
else
Binary |= getMachineOpValue(MI, OpIdx++) << ARMII::RegRnShift;
// If this is a two-address operand, skip it. e.g. LDR_PRE.
- if (TID.getOperandConstraint(OpIdx, TOI::TIED_TO) != -1)
+ if (!Skipped && MCID.getOperandConstraint(OpIdx, MCOI::TIED_TO) != -1)
++OpIdx;
const MachineOperand &MO2 = MI.getOperand(OpIdx);
return;
}
- // Set bit I(25), because this is not in immediate enconding.
+ // Set bit I(25), because this is not in immediate encoding.
Binary |= 1 << ARMII::I_BitShift;
assert(TargetRegisterInfo::isPhysicalRegister(MO2.getReg()));
// Set bit[3:0] to the corresponding Rm register
- Binary |= ARMRegisterInfo::getRegisterNumbering(MO2.getReg());
+ Binary |= getARMRegisterNumbering(MO2.getReg());
- // if this instr is in scaled register offset/index instruction, set
+ // If this instr is in scaled register offset/index instruction, set
// shift_immed(bit[11:7]) and shift(bit[6:5]) fields.
if (unsigned ShImm = ARM_AM::getAM2Offset(AM2Opc)) {
- Binary |= getShiftOp(AM2Opc) << 5; // shift
- Binary |= ShImm << 7; // shift_immed
+ Binary |= getShiftOp(AM2Opc) << ARMII::ShiftImmShift; // shift
+ Binary |= ShImm << ARMII::ShiftShift; // shift_immed
}
emitWordLE(Binary);
void ARMCodeEmitter::emitMiscLoadStoreInstruction(const MachineInstr &MI,
unsigned ImplicitRn) {
- const TargetInstrDesc &TID = MI.getDesc();
+ const MCInstrDesc &MCID = MI.getDesc();
+ unsigned Form = MCID.TSFlags & ARMII::FormMask;
+ bool IsPrePost = (MCID.TSFlags & ARMII::IndexModeMask) != 0;
// Part of binary is determined by TableGn.
unsigned Binary = getBinaryCodeForInstr(MI);
// Set the conditional execution predicate
Binary |= II->getPredicate(&MI) << ARMII::CondShift;
+ unsigned OpIdx = 0;
+
+ // Operand 0 of a pre- and post-indexed store is the address base
+ // writeback. Skip it.
+ bool Skipped = false;
+ if (IsPrePost && Form == ARMII::StMiscFrm) {
+ ++OpIdx;
+ Skipped = true;
+ }
+
// Set first operand
- Binary |= getMachineOpValue(MI, 0) << ARMII::RegRdShift;
+ Binary |= getMachineOpValue(MI, OpIdx++) << ARMII::RegRdShift;
+
+ // Skip LDRD and STRD's second operand.
+ if (MCID.Opcode == ARM::LDRD || MCID.Opcode == ARM::STRD)
+ ++OpIdx;
// Set second operand
- unsigned OpIdx = 1;
if (ImplicitRn)
// Special handling for implicit use (e.g. PC).
- Binary |= (ARMRegisterInfo::getRegisterNumbering(ImplicitRn)
- << ARMII::RegRnShift);
+ Binary |= (getARMRegisterNumbering(ImplicitRn) << ARMII::RegRnShift);
else
Binary |= getMachineOpValue(MI, OpIdx++) << ARMII::RegRnShift;
// If this is a two-address operand, skip it. e.g. LDRH_POST.
- if (TID.getOperandConstraint(OpIdx, TOI::TIED_TO) != -1)
+ if (!Skipped && MCID.getOperandConstraint(OpIdx, MCOI::TIED_TO) != -1)
++OpIdx;
const MachineOperand &MO2 = MI.getOperand(OpIdx);
// If this instr is in register offset/index encoding, set bit[3:0]
// to the corresponding Rm register.
if (MO2.getReg()) {
- Binary |= ARMRegisterInfo::getRegisterNumbering(MO2.getReg());
+ Binary |= getARMRegisterNumbering(MO2.getReg());
emitWordLE(Binary);
return;
}
Binary |= 1 << ARMII::AM3_I_BitShift;
if (unsigned ImmOffs = ARM_AM::getAM3Offset(AM3Opc)) {
// Set operands
- Binary |= (ImmOffs >> 4) << 8; // immedH
- Binary |= (ImmOffs & ~0xF); // immedL
+ Binary |= (ImmOffs >> 4) << ARMII::ImmHiShift; // immedH
+ Binary |= (ImmOffs & 0xF); // immedL
}
emitWordLE(Binary);
// DA - Decrement after - bit U = 0 and bit P = 0
// DB - Decrement before - bit U = 0 and bit P = 1
switch (Mode) {
- default: assert(0 && "Unknown addressing sub-mode!");
- case ARM_AM::da: break;
+ default: llvm_unreachable("Unknown addressing sub-mode!");
+ case ARM_AM::da: break;
case ARM_AM::db: Binary |= 0x1 << ARMII::P_BitShift; break;
case ARM_AM::ia: Binary |= 0x1 << ARMII::U_BitShift; break;
case ARM_AM::ib: Binary |= 0x3 << ARMII::U_BitShift; break;
}
void ARMCodeEmitter::emitLoadStoreMultipleInstruction(const MachineInstr &MI) {
+ const MCInstrDesc &MCID = MI.getDesc();
+ bool IsUpdating = (MCID.TSFlags & ARMII::IndexModeMask) != 0;
+
// Part of binary is determined by TableGn.
unsigned Binary = getBinaryCodeForInstr(MI);
// Set the conditional execution predicate
Binary |= II->getPredicate(&MI) << ARMII::CondShift;
+ // Skip operand 0 of an instruction with base register update.
+ unsigned OpIdx = 0;
+ if (IsUpdating)
+ ++OpIdx;
+
// Set base address operand
- Binary |= getMachineOpValue(MI, 0) << ARMII::RegRnShift;
+ Binary |= getMachineOpValue(MI, OpIdx++) << ARMII::RegRnShift;
// Set addressing mode by modifying bits U(23) and P(24)
- const MachineOperand &MO = MI.getOperand(1);
- Binary |= getAddrModeUPBits(ARM_AM::getAM4SubMode(MO.getImm()));
+ ARM_AM::AMSubMode Mode = ARM_AM::getLoadStoreMultipleSubMode(MI.getOpcode());
+ Binary |= getAddrModeUPBits(ARM_AM::getAM4SubMode(Mode));
// Set bit W(21)
- if (ARM_AM::getAM4WBFlag(MO.getImm()))
+ if (IsUpdating)
Binary |= 0x1 << ARMII::W_BitShift;
// Set registers
- for (unsigned i = 4, e = MI.getNumOperands(); i != e; ++i) {
+ for (unsigned i = OpIdx+2, e = MI.getNumOperands(); i != e; ++i) {
const MachineOperand &MO = MI.getOperand(i);
if (!MO.isReg() || MO.isImplicit())
break;
- unsigned RegNum = ARMRegisterInfo::getRegisterNumbering(MO.getReg());
+ unsigned RegNum = getARMRegisterNumbering(MO.getReg());
assert(TargetRegisterInfo::isPhysicalRegister(MO.getReg()) &&
RegNum < 16);
Binary |= 0x1 << RegNum;
}
void ARMCodeEmitter::emitMulFrmInstruction(const MachineInstr &MI) {
- const TargetInstrDesc &TID = MI.getDesc();
+ const MCInstrDesc &MCID = MI.getDesc();
// Part of binary is determined by TableGn.
unsigned Binary = getBinaryCodeForInstr(MI);
Binary |= II->getPredicate(&MI) << ARMII::CondShift;
// Encode S bit if MI modifies CPSR.
- Binary |= getAddrModeSBit(MI, TID);
+ Binary |= getAddrModeSBit(MI, MCID);
// 32x32->64bit operations have two destination registers. The number
// of register definitions will tell us if that's what we're dealing with.
unsigned OpIdx = 0;
- if (TID.getNumDefs() == 2)
+ if (MCID.getNumDefs() == 2)
Binary |= getMachineOpValue (MI, OpIdx++) << ARMII::RegRdLoShift;
// Encode Rd
// Many multiple instructions (e.g. MLA) have three src operands. Encode
// it as Rn (for multiply, that's in the same offset as RdLo.
- if (TID.getNumOperands() > OpIdx &&
- !TID.OpInfo[OpIdx].isPredicate() &&
- !TID.OpInfo[OpIdx].isOptionalDef())
+ if (MCID.getNumOperands() > OpIdx &&
+ !MCID.OpInfo[OpIdx].isPredicate() &&
+ !MCID.OpInfo[OpIdx].isOptionalDef())
Binary |= getMachineOpValue(MI, OpIdx) << ARMII::RegRdLoShift;
emitWordLE(Binary);
}
void ARMCodeEmitter::emitExtendInstruction(const MachineInstr &MI) {
- const TargetInstrDesc &TID = MI.getDesc();
+ const MCInstrDesc &MCID = MI.getDesc();
// Part of binary is determined by TableGn.
unsigned Binary = getBinaryCodeForInstr(MI);
// Encode rot imm (0, 8, 16, or 24) if it has a rotate immediate operand.
if (MI.getOperand(OpIdx).isImm() &&
- !TID.OpInfo[OpIdx].isPredicate() &&
- !TID.OpInfo[OpIdx].isOptionalDef())
+ !MCID.OpInfo[OpIdx].isPredicate() &&
+ !MCID.OpInfo[OpIdx].isOptionalDef())
Binary |= (getMachineOpValue(MI, OpIdx) / 8) << ARMII::ExtRotImmShift;
emitWordLE(Binary);
}
void ARMCodeEmitter::emitMiscArithInstruction(const MachineInstr &MI) {
- const TargetInstrDesc &TID = MI.getDesc();
+ const MCInstrDesc &MCID = MI.getDesc();
// Part of binary is determined by TableGn.
unsigned Binary = getBinaryCodeForInstr(MI);
// Set the conditional execution predicate
Binary |= II->getPredicate(&MI) << ARMII::CondShift;
+ // PKH instructions are finished at this point
+ if (MCID.Opcode == ARM::PKHBT || MCID.Opcode == ARM::PKHTB) {
+ emitWordLE(Binary);
+ return;
+ }
+
unsigned OpIdx = 0;
// Encode Rd
Binary |= getMachineOpValue(MI, OpIdx++) << ARMII::RegRdShift;
const MachineOperand &MO = MI.getOperand(OpIdx++);
- if (OpIdx == TID.getNumOperands() ||
- TID.OpInfo[OpIdx].isPredicate() ||
- TID.OpInfo[OpIdx].isOptionalDef()) {
+ if (OpIdx == MCID.getNumOperands() ||
+ MCID.OpInfo[OpIdx].isPredicate() ||
+ MCID.OpInfo[OpIdx].isOptionalDef()) {
// Encode Rm and it's done.
Binary |= getMachineOpValue(MI, MO);
emitWordLE(Binary);
// Encode shift_imm.
unsigned ShiftAmt = MI.getOperand(OpIdx).getImm();
+ if (MCID.Opcode == ARM::PKHTB) {
+ assert(ShiftAmt != 0 && "PKHTB shift_imm is 0!");
+ if (ShiftAmt == 32)
+ ShiftAmt = 0;
+ }
assert(ShiftAmt < 32 && "shift_imm range is 0 to 31!");
Binary |= ShiftAmt << ARMII::ShiftShift;
-
+
+ emitWordLE(Binary);
+}
+
+void ARMCodeEmitter::emitSaturateInstruction(const MachineInstr &MI) {
+ const MCInstrDesc &MCID = MI.getDesc();
+
+ // Part of binary is determined by TableGen.
+ unsigned Binary = getBinaryCodeForInstr(MI);
+
+ // Set the conditional execution predicate
+ Binary |= II->getPredicate(&MI) << ARMII::CondShift;
+
+ // Encode Rd
+ Binary |= getMachineOpValue(MI, 0) << ARMII::RegRdShift;
+
+ // Encode saturate bit position.
+ unsigned Pos = MI.getOperand(1).getImm();
+ if (MCID.Opcode == ARM::SSAT || MCID.Opcode == ARM::SSAT16)
+ Pos -= 1;
+ assert((Pos < 16 || (Pos < 32 &&
+ MCID.Opcode != ARM::SSAT16 &&
+ MCID.Opcode != ARM::USAT16)) &&
+ "saturate bit position out of range");
+ Binary |= Pos << 16;
+
+ // Encode Rm
+ Binary |= getMachineOpValue(MI, 2);
+
+ // Encode shift_imm.
+ if (MCID.getNumOperands() == 4) {
+ unsigned ShiftOp = MI.getOperand(3).getImm();
+ ARM_AM::ShiftOpc Opc = ARM_AM::getSORegShOp(ShiftOp);
+ if (Opc == ARM_AM::asr)
+ Binary |= (1 << 6);
+ unsigned ShiftAmt = MI.getOperand(3).getImm();
+ if (ShiftAmt == 32 && Opc == ARM_AM::asr)
+ ShiftAmt = 0;
+ assert(ShiftAmt < 32 && "shift_imm range is 0 to 31!");
+ Binary |= ShiftAmt << ARMII::ShiftShift;
+ }
+
emitWordLE(Binary);
}
void ARMCodeEmitter::emitBranchInstruction(const MachineInstr &MI) {
- const TargetInstrDesc &TID = MI.getDesc();
+ const MCInstrDesc &MCID = MI.getDesc();
- if (TID.Opcode == ARM::TPsoft)
- abort(); // FIXME
+ if (MCID.Opcode == ARM::TPsoft) {
+ llvm_unreachable("ARM::TPsoft FIXME"); // FIXME
+ }
// Part of binary is determined by TableGn.
unsigned Binary = getBinaryCodeForInstr(MI);
void ARMCodeEmitter::emitInlineJumpTable(unsigned JTIndex) {
// Remember the base address of the inline jump table.
- intptr_t JTBase = MCE.getCurrentPCValue();
+ uintptr_t JTBase = MCE.getCurrentPCValue();
JTI->addJumpTableBaseAddr(JTIndex, JTBase);
- DOUT << " ** Jump Table #" << JTIndex << " @ " << (void*)JTBase << '\n';
+ DEBUG(errs() << " ** Jump Table #" << JTIndex << " @ " << (void*)JTBase
+ << '\n');
// Now emit the jump table entries.
const std::vector<MachineBasicBlock*> &MBBs = (*MJTEs)[JTIndex].MBBs;
}
void ARMCodeEmitter::emitMiscBranchInstruction(const MachineInstr &MI) {
- const TargetInstrDesc &TID = MI.getDesc();
+ const MCInstrDesc &MCID = MI.getDesc();
// Handle jump tables.
- if (TID.Opcode == ARM::BR_JTr || TID.Opcode == ARM::BR_JTadd) {
+ if (MCID.Opcode == ARM::BR_JTr || MCID.Opcode == ARM::BR_JTadd) {
// First emit a ldr pc, [] instruction.
emitDataProcessingInstruction(MI, ARM::PC);
// Then emit the inline jump table.
- unsigned JTIndex = (TID.Opcode == ARM::BR_JTr)
+ unsigned JTIndex =
+ (MCID.Opcode == ARM::BR_JTr)
? MI.getOperand(1).getIndex() : MI.getOperand(2).getIndex();
emitInlineJumpTable(JTIndex);
return;
- } else if (TID.Opcode == ARM::BR_JTm) {
+ } else if (MCID.Opcode == ARM::BR_JTm) {
// First emit a ldr pc, [] instruction.
emitLoadStoreInstruction(MI, ARM::PC);
// Set the conditional execution predicate
Binary |= II->getPredicate(&MI) << ARMII::CondShift;
- if (TID.Opcode == ARM::BX_RET)
+ if (MCID.Opcode == ARM::BX_RET || MCID.Opcode == ARM::MOVPCLR)
// The return register is LR.
- Binary |= ARMRegisterInfo::getRegisterNumbering(ARM::LR);
- else
+ Binary |= getARMRegisterNumbering(ARM::LR);
+ else
// otherwise, set the return register
Binary |= getMachineOpValue(MI, 0);
emitWordLE(Binary);
}
+static unsigned encodeVFPRd(const MachineInstr &MI, unsigned OpIdx) {
+ unsigned RegD = MI.getOperand(OpIdx).getReg();
+ unsigned Binary = 0;
+ bool isSPVFP = ARM::SPRRegisterClass->contains(RegD);
+ RegD = getARMRegisterNumbering(RegD);
+ if (!isSPVFP)
+ Binary |= RegD << ARMII::RegRdShift;
+ else {
+ Binary |= ((RegD & 0x1E) >> 1) << ARMII::RegRdShift;
+ Binary |= (RegD & 0x01) << ARMII::D_BitShift;
+ }
+ return Binary;
+}
+
+static unsigned encodeVFPRn(const MachineInstr &MI, unsigned OpIdx) {
+ unsigned RegN = MI.getOperand(OpIdx).getReg();
+ unsigned Binary = 0;
+ bool isSPVFP = ARM::SPRRegisterClass->contains(RegN);
+ RegN = getARMRegisterNumbering(RegN);
+ if (!isSPVFP)
+ Binary |= RegN << ARMII::RegRnShift;
+ else {
+ Binary |= ((RegN & 0x1E) >> 1) << ARMII::RegRnShift;
+ Binary |= (RegN & 0x01) << ARMII::N_BitShift;
+ }
+ return Binary;
+}
+
+static unsigned encodeVFPRm(const MachineInstr &MI, unsigned OpIdx) {
+ unsigned RegM = MI.getOperand(OpIdx).getReg();
+ unsigned Binary = 0;
+ bool isSPVFP = ARM::SPRRegisterClass->contains(RegM);
+ RegM = getARMRegisterNumbering(RegM);
+ if (!isSPVFP)
+ Binary |= RegM;
+ else {
+ Binary |= ((RegM & 0x1E) >> 1);
+ Binary |= (RegM & 0x01) << ARMII::M_BitShift;
+ }
+ return Binary;
+}
+
void ARMCodeEmitter::emitVFPArithInstruction(const MachineInstr &MI) {
- const TargetInstrDesc &TID = MI.getDesc();
+ const MCInstrDesc &MCID = MI.getDesc();
// Part of binary is determined by TableGn.
unsigned Binary = getBinaryCodeForInstr(MI);
(Binary & ARMII::M_BitShift) == 0 && "VFP encoding bug!");
// Encode Dd / Sd.
- unsigned RegD = MI.getOperand(OpIdx++).getReg();
- bool isSPVFP = false;
- RegD = ARMRegisterInfo::getRegisterNumbering(RegD, isSPVFP);
- if (!isSPVFP)
- Binary |= RegD << ARMII::RegRdShift;
- else {
- Binary |= ((RegD & 0x1E) >> 1) << ARMII::RegRdShift;
- Binary |= (RegD & 0x01) << ARMII::D_BitShift;
- }
-
+ Binary |= encodeVFPRd(MI, OpIdx++);
// If this is a two-address operand, skip it, e.g. FMACD.
- if (TID.getOperandConstraint(OpIdx, TOI::TIED_TO) != -1)
+ if (MCID.getOperandConstraint(OpIdx, MCOI::TIED_TO) != -1)
++OpIdx;
// Encode Dn / Sn.
- if ((TID.TSFlags & ARMII::FormMask) == ARMII::VFPBinaryFrm) {
- unsigned RegN = MI.getOperand(OpIdx++).getReg();
- isSPVFP = false;
- RegN = ARMRegisterInfo::getRegisterNumbering(RegN, isSPVFP);
- if (!isSPVFP)
- Binary |= RegN << ARMII::RegRnShift;
- else {
- Binary |= ((RegN & 0x1E) >> 1) << ARMII::RegRnShift;
- Binary |= (RegN & 0x01) << ARMII::N_BitShift;
- }
+ if ((MCID.TSFlags & ARMII::FormMask) == ARMII::VFPBinaryFrm)
+ Binary |= encodeVFPRn(MI, OpIdx++);
+
+ if (OpIdx == MCID.getNumOperands() ||
+ MCID.OpInfo[OpIdx].isPredicate() ||
+ MCID.OpInfo[OpIdx].isOptionalDef()) {
+ // FCMPEZD etc. has only one operand.
+ emitWordLE(Binary);
+ return;
}
// Encode Dm / Sm.
- unsigned RegM = MI.getOperand(OpIdx++).getReg();
- isSPVFP = false;
- RegM = ARMRegisterInfo::getRegisterNumbering(RegM, isSPVFP);
- if (!isSPVFP)
- Binary |= RegM;
- else {
- Binary |= ((RegM & 0x1E) >> 1);
- Binary |= (RegM & 0x01) << ARMII::M_BitShift;
- }
-
+ Binary |= encodeVFPRm(MI, OpIdx);
+
emitWordLE(Binary);
}
void ARMCodeEmitter::emitVFPConversionInstruction(const MachineInstr &MI) {
- const TargetInstrDesc &TID = MI.getDesc();
+ const MCInstrDesc &MCID = MI.getDesc();
+ unsigned Form = MCID.TSFlags & ARMII::FormMask;
// Part of binary is determined by TableGn.
unsigned Binary = getBinaryCodeForInstr(MI);
// Set the conditional execution predicate
Binary |= II->getPredicate(&MI) << ARMII::CondShift;
- // FMDRR encodes registers in reverse order.
- unsigned Form = TID.TSFlags & ARMII::FormMask;
- unsigned OpIdx = (Form == ARMII::VFPConv2Frm)
- ? MI.findFirstPredOperandIdx()-1 : 0;
-
- // Encode Dd / Sd.
- unsigned RegD = MI.getOperand(OpIdx).getReg();
- bool isSPVFP = false;
- RegD = ARMRegisterInfo::getRegisterNumbering(RegD, isSPVFP);
- if (!isSPVFP)
- Binary |= RegD << ARMII::RegRdShift;
- else {
- Binary |= ((RegD & 0x1E) >> 1) << ARMII::RegRdShift;
- Binary |= (RegD & 0x01) << ARMII::D_BitShift;
- }
- if (Form == ARMII::VFPConv2Frm)
- --OpIdx;
- else
- ++OpIdx;
-
- if (Form == ARMII::VFPConv3Frm) {
- unsigned RegM = MI.getOperand(OpIdx).getReg();
- isSPVFP = false;
- RegM = ARMRegisterInfo::getRegisterNumbering(RegM, isSPVFP);
- if (!isSPVFP)
- Binary |= RegM;
- else {
- Binary |= ((RegM & 0x1E) >> 1);
- Binary |= (RegM & 0x01) << ARMII::M_BitShift;
- }
-
- emitWordLE(Binary);
- return;
+ switch (Form) {
+ default: break;
+ case ARMII::VFPConv1Frm:
+ case ARMII::VFPConv2Frm:
+ case ARMII::VFPConv3Frm:
+ // Encode Dd / Sd.
+ Binary |= encodeVFPRd(MI, 0);
+ break;
+ case ARMII::VFPConv4Frm:
+ // Encode Dn / Sn.
+ Binary |= encodeVFPRn(MI, 0);
+ break;
+ case ARMII::VFPConv5Frm:
+ // Encode Dm / Sm.
+ Binary |= encodeVFPRm(MI, 0);
+ break;
}
- // Encode Dn / Sn.
- unsigned RegN = MI.getOperand(OpIdx).getReg();
- isSPVFP = false;
- RegN = ARMRegisterInfo::getRegisterNumbering(RegN, isSPVFP);
- if (!isSPVFP)
- Binary |= RegN << ARMII::RegRnShift;
- else {
- Binary |= ((RegN & 0x1E) >> 1) << ARMII::RegRnShift;
- Binary |= (RegN & 0x01) << ARMII::N_BitShift;
+ switch (Form) {
+ default: break;
+ case ARMII::VFPConv1Frm:
+ // Encode Dm / Sm.
+ Binary |= encodeVFPRm(MI, 1);
+ break;
+ case ARMII::VFPConv2Frm:
+ case ARMII::VFPConv3Frm:
+ // Encode Dn / Sn.
+ Binary |= encodeVFPRn(MI, 1);
+ break;
+ case ARMII::VFPConv4Frm:
+ case ARMII::VFPConv5Frm:
+ // Encode Dd / Sd.
+ Binary |= encodeVFPRd(MI, 1);
+ break;
}
- if (Form == ARMII::VFPConv2Frm)
- --OpIdx;
- else
- ++OpIdx;
- // FMRS / FMSR do not have Rm.
- if (TID.getNumOperands() > OpIdx && MI.getOperand(OpIdx).isReg()) {
- unsigned RegM = MI.getOperand(OpIdx).getReg();
- isSPVFP = false;
- RegM = ARMRegisterInfo::getRegisterNumbering(RegM, isSPVFP);
- if (!isSPVFP)
- Binary |= RegM;
- else {
- Binary |= ((RegM & 0x1E) >> 1);
- Binary |= (RegM & 0x01) << ARMII::M_BitShift;
- }
- }
+ if (Form == ARMII::VFPConv5Frm)
+ // Encode Dn / Sn.
+ Binary |= encodeVFPRn(MI, 2);
+ else if (Form == ARMII::VFPConv3Frm)
+ // Encode Dm / Sm.
+ Binary |= encodeVFPRm(MI, 2);
emitWordLE(Binary);
}
unsigned OpIdx = 0;
// Encode Dd / Sd.
- unsigned RegD = MI.getOperand(OpIdx++).getReg();
- bool isSPVFP = false;
- RegD = ARMRegisterInfo::getRegisterNumbering(RegD, isSPVFP);
- if (!isSPVFP)
- Binary |= RegD << ARMII::RegRdShift;
- else {
- Binary |= ((RegD & 0x1E) >> 1) << ARMII::RegRdShift;
- Binary |= (RegD & 0x01) << ARMII::D_BitShift;
- }
+ Binary |= encodeVFPRd(MI, OpIdx++);
// Encode address base.
const MachineOperand &Base = MI.getOperand(OpIdx++);
if (unsigned ImmOffs = ARM_AM::getAM5Offset(Offset.getImm())) {
if (ARM_AM::getAM5Op(Offset.getImm()) == ARM_AM::add)
Binary |= 1 << ARMII::U_BitShift;
- // Immediate offset is multiplied by 4.
- Binary |= ImmOffs >> 2;
+ Binary |= ImmOffs;
emitWordLE(Binary);
return;
}
void
ARMCodeEmitter::emitVFPLoadStoreMultipleInstruction(const MachineInstr &MI) {
+ const MCInstrDesc &MCID = MI.getDesc();
+ bool IsUpdating = (MCID.TSFlags & ARMII::IndexModeMask) != 0;
+
// Part of binary is determined by TableGn.
unsigned Binary = getBinaryCodeForInstr(MI);
// Set the conditional execution predicate
Binary |= II->getPredicate(&MI) << ARMII::CondShift;
+ // Skip operand 0 of an instruction with base register update.
+ unsigned OpIdx = 0;
+ if (IsUpdating)
+ ++OpIdx;
+
// Set base address operand
- Binary |= getMachineOpValue(MI, 0) << ARMII::RegRnShift;
+ Binary |= getMachineOpValue(MI, OpIdx++) << ARMII::RegRnShift;
// Set addressing mode by modifying bits U(23) and P(24)
- const MachineOperand &MO = MI.getOperand(1);
- Binary |= getAddrModeUPBits(ARM_AM::getAM5SubMode(MO.getImm()));
+ ARM_AM::AMSubMode Mode = ARM_AM::getLoadStoreMultipleSubMode(MI.getOpcode());
+ Binary |= getAddrModeUPBits(ARM_AM::getAM4SubMode(Mode));
// Set bit W(21)
- if (ARM_AM::getAM5WBFlag(MO.getImm()))
+ if (IsUpdating)
Binary |= 0x1 << ARMII::W_BitShift;
// First register is encoded in Dd.
- unsigned RegD = MI.getOperand(4).getReg();
- bool isSPVFP = false;
- RegD = ARMRegisterInfo::getRegisterNumbering(RegD, isSPVFP);
- if (!isSPVFP)
- Binary |= RegD << ARMII::RegRdShift;
- else {
- Binary |= ((RegD & 0x1E) >> 1) << ARMII::RegRdShift;
- Binary |= (RegD & 0x01) << ARMII::D_BitShift;
- }
+ Binary |= encodeVFPRd(MI, OpIdx+2);
- // Number of registers are encoded in offset field.
+ // Count the number of registers.
unsigned NumRegs = 1;
- for (unsigned i = 5, e = MI.getNumOperands(); i != e; ++i) {
+ for (unsigned i = OpIdx+3, e = MI.getNumOperands(); i != e; ++i) {
const MachineOperand &MO = MI.getOperand(i);
if (!MO.isReg() || MO.isImplicit())
break;
++NumRegs;
}
- Binary |= NumRegs * 2;
+ // Bit 8 will be set if <list> is consecutive 64-bit registers (e.g., D0)
+ // Otherwise, it will be 0, in the case of 32-bit registers.
+ if(Binary & 0x100)
+ Binary |= NumRegs * 2;
+ else
+ Binary |= NumRegs;
emitWordLE(Binary);
}
-void ARMCodeEmitter::emitMiscInstruction(const MachineInstr &MI) {
- // Part of binary is determined by TableGn.
+static unsigned encodeNEONRd(const MachineInstr &MI, unsigned OpIdx) {
+ unsigned RegD = MI.getOperand(OpIdx).getReg();
+ unsigned Binary = 0;
+ RegD = getARMRegisterNumbering(RegD);
+ Binary |= (RegD & 0xf) << ARMII::RegRdShift;
+ Binary |= ((RegD >> 4) & 1) << ARMII::D_BitShift;
+ return Binary;
+}
+
+static unsigned encodeNEONRn(const MachineInstr &MI, unsigned OpIdx) {
+ unsigned RegN = MI.getOperand(OpIdx).getReg();
+ unsigned Binary = 0;
+ RegN = getARMRegisterNumbering(RegN);
+ Binary |= (RegN & 0xf) << ARMII::RegRnShift;
+ Binary |= ((RegN >> 4) & 1) << ARMII::N_BitShift;
+ return Binary;
+}
+
+static unsigned encodeNEONRm(const MachineInstr &MI, unsigned OpIdx) {
+ unsigned RegM = MI.getOperand(OpIdx).getReg();
+ unsigned Binary = 0;
+ RegM = getARMRegisterNumbering(RegM);
+ Binary |= (RegM & 0xf);
+ Binary |= ((RegM >> 4) & 1) << ARMII::M_BitShift;
+ return Binary;
+}
+
+/// convertNEONDataProcToThumb - Convert the ARM mode encoding for a NEON
+/// data-processing instruction to the corresponding Thumb encoding.
+static unsigned convertNEONDataProcToThumb(unsigned Binary) {
+ assert((Binary & 0xfe000000) == 0xf2000000 &&
+ "not an ARM NEON data-processing instruction");
+ unsigned UBit = (Binary >> 24) & 1;
+ return 0xef000000 | (UBit << 28) | (Binary & 0xffffff);
+}
+
+void ARMCodeEmitter::emitNEONLaneInstruction(const MachineInstr &MI) {
unsigned Binary = getBinaryCodeForInstr(MI);
+ unsigned RegTOpIdx, RegNOpIdx, LnOpIdx;
+ const MCInstrDesc &MCID = MI.getDesc();
+ if ((MCID.TSFlags & ARMII::FormMask) == ARMII::NGetLnFrm) {
+ RegTOpIdx = 0;
+ RegNOpIdx = 1;
+ LnOpIdx = 2;
+ } else { // ARMII::NSetLnFrm
+ RegTOpIdx = 2;
+ RegNOpIdx = 0;
+ LnOpIdx = 3;
+ }
+
// Set the conditional execution predicate
- Binary |= II->getPredicate(&MI) << ARMII::CondShift;
+ Binary |= (IsThumb ? ARMCC::AL : II->getPredicate(&MI)) << ARMII::CondShift;
+
+ unsigned RegT = MI.getOperand(RegTOpIdx).getReg();
+ RegT = getARMRegisterNumbering(RegT);
+ Binary |= (RegT << ARMII::RegRdShift);
+ Binary |= encodeNEONRn(MI, RegNOpIdx);
+
+ unsigned LaneShift;
+ if ((Binary & (1 << 22)) != 0)
+ LaneShift = 0; // 8-bit elements
+ else if ((Binary & (1 << 5)) != 0)
+ LaneShift = 1; // 16-bit elements
+ else
+ LaneShift = 2; // 32-bit elements
+
+ unsigned Lane = MI.getOperand(LnOpIdx).getImm() << LaneShift;
+ unsigned Opc1 = Lane >> 2;
+ unsigned Opc2 = Lane & 3;
+ assert((Opc1 & 3) == 0 && "out-of-range lane number operand");
+ Binary |= (Opc1 << 21);
+ Binary |= (Opc2 << 5);
+
+ emitWordLE(Binary);
+}
+void ARMCodeEmitter::emitNEONDupInstruction(const MachineInstr &MI) {
+ unsigned Binary = getBinaryCodeForInstr(MI);
+
+ // Set the conditional execution predicate
+ Binary |= (IsThumb ? ARMCC::AL : II->getPredicate(&MI)) << ARMII::CondShift;
+
+ unsigned RegT = MI.getOperand(1).getReg();
+ RegT = getARMRegisterNumbering(RegT);
+ Binary |= (RegT << ARMII::RegRdShift);
+ Binary |= encodeNEONRn(MI, 0);
+ emitWordLE(Binary);
+}
+
+void ARMCodeEmitter::emitNEON1RegModImmInstruction(const MachineInstr &MI) {
+ unsigned Binary = getBinaryCodeForInstr(MI);
+ // Destination register is encoded in Dd.
+ Binary |= encodeNEONRd(MI, 0);
+ // Immediate fields: Op, Cmode, I, Imm3, Imm4
+ unsigned Imm = MI.getOperand(1).getImm();
+ unsigned Op = (Imm >> 12) & 1;
+ unsigned Cmode = (Imm >> 8) & 0xf;
+ unsigned I = (Imm >> 7) & 1;
+ unsigned Imm3 = (Imm >> 4) & 0x7;
+ unsigned Imm4 = Imm & 0xf;
+ Binary |= (I << 24) | (Imm3 << 16) | (Cmode << 8) | (Op << 5) | Imm4;
+ if (IsThumb)
+ Binary = convertNEONDataProcToThumb(Binary);
+ emitWordLE(Binary);
+}
+
+void ARMCodeEmitter::emitNEON2RegInstruction(const MachineInstr &MI) {
+ const MCInstrDesc &MCID = MI.getDesc();
+ unsigned Binary = getBinaryCodeForInstr(MI);
+ // Destination register is encoded in Dd; source register in Dm.
+ unsigned OpIdx = 0;
+ Binary |= encodeNEONRd(MI, OpIdx++);
+ if (MCID.getOperandConstraint(OpIdx, MCOI::TIED_TO) != -1)
+ ++OpIdx;
+ Binary |= encodeNEONRm(MI, OpIdx);
+ if (IsThumb)
+ Binary = convertNEONDataProcToThumb(Binary);
+ // FIXME: This does not handle VDUPfdf or VDUPfqf.
+ emitWordLE(Binary);
+}
+
+void ARMCodeEmitter::emitNEON3RegInstruction(const MachineInstr &MI) {
+ const MCInstrDesc &MCID = MI.getDesc();
+ unsigned Binary = getBinaryCodeForInstr(MI);
+ // Destination register is encoded in Dd; source registers in Dn and Dm.
+ unsigned OpIdx = 0;
+ Binary |= encodeNEONRd(MI, OpIdx++);
+ if (MCID.getOperandConstraint(OpIdx, MCOI::TIED_TO) != -1)
+ ++OpIdx;
+ Binary |= encodeNEONRn(MI, OpIdx++);
+ if (MCID.getOperandConstraint(OpIdx, MCOI::TIED_TO) != -1)
+ ++OpIdx;
+ Binary |= encodeNEONRm(MI, OpIdx);
+ if (IsThumb)
+ Binary = convertNEONDataProcToThumb(Binary);
+ // FIXME: This does not handle VMOVDneon or VMOVQ.
emitWordLE(Binary);
}