#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/ObjectCodeEmitter.h"
#include "llvm/CodeGen/MachineConstantPool.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstr.h"
namespace {
- class ARMCodeEmitter {
- public:
- /// getBinaryCodeForInstr - This function, generated by the
- /// CodeEmitterGenerator using TableGen, produces the binary encoding for
- /// machine instructions.
- unsigned getBinaryCodeForInstr(const MachineInstr &MI);
- };
-
- template<class CodeEmitter>
- class Emitter : public MachineFunctionPass, public ARMCodeEmitter {
+ class ARMCodeEmitter : public MachineFunctionPass {
ARMJITInfo *JTI;
const ARMInstrInfo *II;
const TargetData *TD;
const ARMSubtarget *Subtarget;
TargetMachine &TM;
- CodeEmitter &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 Emitter(TargetMachine &tm, CodeEmitter &mce)
- : MachineFunctionPass(&ID), JTI(0), II(0), TD(0), TM(tm),
- MCE(mce), MCPEs(0), MJTEs(0),
- IsPIC(TM.getRelocationModel() == Reloc::PIC_) {}
- Emitter(TargetMachine &tm, CodeEmitter &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);
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 MachineOperand &MO,
void emitMiscArithInstruction(const MachineInstr &MI);
+ void emitSaturateInstruction(const MachineInstr &MI);
+
void emitBranchInstruction(const MachineInstr &MI);
void emitInlineJumpTable(unsigned JTIndex);
void emitMiscInstruction(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);
return getMachineOpValue(MI, MI.getOperand(OpIdx));
}
+ /// 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);
+ unsigned getMovi32Value(const MachineInstr &MI, unsigned OpIdx,
+ unsigned Reloc) {
+ return getMovi32Value(MI, MI.getOperand(OpIdx), 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,
+ void emitGlobalAddress(const GlobalValue *GV, unsigned Reloc,
bool MayNeedFarStub, bool Indirect,
intptr_t ACPV = 0);
void emitExternalSymbolAddress(const char *ES, unsigned Reloc);
void emitMachineBasicBlock(MachineBasicBlock *BB, unsigned Reloc,
intptr_t JTBase = 0);
};
- template <class CodeEmitter>
- char Emitter<CodeEmitter>::ID = 0;
}
-/// createARMCodeEmitterPass - Return a pass that emits the collected ARM code
-/// to the specified MCE object.
+char ARMCodeEmitter::ID = 0;
-FunctionPass *llvm::createARMCodeEmitterPass(ARMBaseTargetMachine &TM,
- MachineCodeEmitter &MCE) {
- return new Emitter<MachineCodeEmitter>(TM, MCE);
-}
+/// createARMJITCodeEmitterPass - Return a pass that emits the collected ARM
+/// code to the specified MCE object.
FunctionPass *llvm::createARMJITCodeEmitterPass(ARMBaseTargetMachine &TM,
JITCodeEmitter &JCE) {
- return new Emitter<JITCodeEmitter>(TM, JCE);
-}
-FunctionPass *llvm::createARMObjectCodeEmitterPass(ARMBaseTargetMachine &TM,
- ObjectCodeEmitter &OCE) {
- return new Emitter<ObjectCodeEmitter>(TM, OCE);
+ return new ARMCodeEmitter(TM, JCE);
}
-template<class CodeEmitter>
-bool Emitter<CodeEmitter>::runOnMachineFunction(MachineFunction &MF) {
+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!");
- JTI = ((ARMTargetMachine&)MF.getTarget()).getJITInfo();
- II = ((ARMTargetMachine&)MF.getTarget()).getInstrInfo();
- TD = ((ARMTargetMachine&)MF.getTarget()).getTargetData();
+ 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 = 0;
if (MF.getJumpTableInfo()) MJTEs = &MF.getJumpTableInfo()->getJumpTables();
IsPIC = TM.getRelocationModel() == Reloc::PIC_;
+ IsThumb = MF.getInfo<ARMFunctionInfo>()->isThumbFunction();
JTI->Initialize(MF, IsPIC);
- MCE.setModuleInfo(&getAnalysis<MachineModuleInfo>());
+ MMI = &getAnalysis<MachineModuleInfo>();
+ MCE.setModuleInfo(MMI);
do {
DEBUG(errs() << "JITTing function '"
/// getShiftOp - Return the shift opcode (bit[6:5]) of the immediate value.
///
-template<class CodeEmitter>
-unsigned Emitter<CodeEmitter>::getShiftOp(unsigned Imm) const {
+unsigned ARMCodeEmitter::getShiftOp(unsigned Imm) const {
switch (ARM_AM::getAM2ShiftOpc(Imm)) {
default: llvm_unreachable("Unknown shift opc!");
case ARM_AM::asr: return 2;
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.
-template<class CodeEmitter>
-unsigned Emitter<CodeEmitter>::getMachineOpValue(const MachineInstr &MI,
- const MachineOperand &MO) {
+unsigned ARMCodeEmitter::getMachineOpValue(const MachineInstr &MI,
+ const MachineOperand &MO) {
if (MO.isReg())
return ARMRegisterInfo::getRegisterNumbering(MO.getReg());
else if (MO.isImm())
/// emitGlobalAddress - Emit the specified address to the code stream.
///
-template<class CodeEmitter>
-void Emitter<CodeEmitter>::emitGlobalAddress(GlobalValue *GV, unsigned Reloc,
- bool MayNeedFarStub, bool Indirect,
- intptr_t ACPV) {
+void ARMCodeEmitter::emitGlobalAddress(const GlobalValue *GV, unsigned Reloc,
+ bool MayNeedFarStub, bool Indirect,
+ intptr_t ACPV) {
MachineRelocation MR = Indirect
? MachineRelocation::getIndirectSymbol(MCE.getCurrentPCOffset(), Reloc,
- GV, ACPV, MayNeedFarStub)
+ const_cast<GlobalValue *>(GV),
+ ACPV, MayNeedFarStub)
: MachineRelocation::getGV(MCE.getCurrentPCOffset(), Reloc,
- GV, ACPV, MayNeedFarStub);
+ 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.
-template<class CodeEmitter>
-void Emitter<CodeEmitter>::emitExternalSymbolAddress(const char *ES,
- unsigned Reloc) {
+void ARMCodeEmitter::emitExternalSymbolAddress(const char *ES, unsigned Reloc) {
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.
-template<class CodeEmitter>
-void Emitter<CodeEmitter>::emitConstPoolAddress(unsigned CPI,
- unsigned Reloc) {
+void ARMCodeEmitter::emitConstPoolAddress(unsigned CPI, unsigned Reloc) {
// 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.
-template<class CodeEmitter>
-void Emitter<CodeEmitter>::emitJumpTableAddress(unsigned JTIndex,
- unsigned Reloc) {
+void ARMCodeEmitter::emitJumpTableAddress(unsigned JTIndex, unsigned Reloc) {
MCE.addRelocation(MachineRelocation::getJumpTable(MCE.getCurrentPCOffset(),
Reloc, JTIndex, 0, true));
}
/// emitMachineBasicBlock - Emit the specified address basic block.
-template<class CodeEmitter>
-void Emitter<CodeEmitter>::emitMachineBasicBlock(MachineBasicBlock *BB,
- unsigned Reloc, intptr_t JTBase) {
+void ARMCodeEmitter::emitMachineBasicBlock(MachineBasicBlock *BB,
+ unsigned Reloc, intptr_t JTBase) {
MCE.addRelocation(MachineRelocation::getBB(MCE.getCurrentPCOffset(),
Reloc, BB, JTBase));
}
-template<class CodeEmitter>
-void Emitter<CodeEmitter>::emitWordLE(unsigned Binary) {
+void ARMCodeEmitter::emitWordLE(unsigned Binary) {
DEBUG(errs() << " 0x";
errs().write_hex(Binary) << "\n");
MCE.emitWordLE(Binary);
}
-template<class CodeEmitter>
-void Emitter<CodeEmitter>::emitDWordLE(uint64_t Binary) {
+void ARMCodeEmitter::emitDWordLE(uint64_t Binary) {
DEBUG(errs() << " 0x";
errs().write_hex(Binary) << "\n");
MCE.emitDWordLE(Binary);
}
-template<class CodeEmitter>
-void Emitter<CodeEmitter>::emitInstruction(const MachineInstr &MI) {
+void ARMCodeEmitter::emitInstruction(const MachineInstr &MI) {
DEBUG(errs() << "JIT: " << (void*)MCE.getCurrentPCValue() << ":\t" << MI);
MCE.processDebugLoc(MI.getDebugLoc(), true);
- NumEmitted++; // Keep track of the # of mi's emitted
+ ++NumEmitted; // Keep track of the # of mi's emitted
switch (MI.getDesc().TSFlags & ARMII::FormMask) {
default: {
llvm_unreachable("Unhandled instruction encoding format!");
case ARMII::ArithMiscFrm:
emitMiscArithInstruction(MI);
break;
+ case ARMII::SatFrm:
+ emitSaturateInstruction(MI);
+ break;
case ARMII::BrFrm:
emitBranchInstruction(MI);
break;
case ARMII::VFPMiscFrm:
emitMiscInstruction(MI);
break;
+ // 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);
}
-template<class CodeEmitter>
-void Emitter<CodeEmitter>::emitConstPoolInstruction(const MachineInstr &MI) {
+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];
<< (void*)MCE.getCurrentPCValue() << " " << *ACPV << '\n');
assert(ACPV->isGlobalValue() && "unsupported constant pool value");
- GlobalValue *GV = ACPV->getGV();
+ const GlobalValue *GV = ACPV->getGV();
if (GV) {
Reloc::Model RelocM = TM.getRelocationModel();
emitGlobalAddress(GV, ARM::reloc_arm_machine_cp_entry,
}
emitWordLE(0);
} else {
- Constant *CV = MCPE.Val.ConstVal;
+ const Constant *CV = MCPE.Val.ConstVal;
DEBUG({
errs() << " ** Constant pool #" << CPI << " @ "
errs() << '\n';
});
- if (GlobalValue *GV = dyn_cast<GlobalValue>(CV)) {
+ 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)) {
}
}
-template<class CodeEmitter>
-void Emitter<CodeEmitter>::emitMOVi2piecesInstruction(const MachineInstr &MI) {
+void ARMCodeEmitter::emitMOVi32immInstruction(const MachineInstr &MI) {
const MachineOperand &MO0 = MI.getOperand(0);
const MachineOperand &MO1 = MI.getOperand(1);
- assert(MO1.isImm() && ARM_AM::getSOImmVal(MO1.isImm()) != -1 &&
- "Not a valid so_imm value!");
+
+ // 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() && 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());
emitWordLE(Binary);
}
-template<class CodeEmitter>
-void Emitter<CodeEmitter>::emitLEApcrelJTInstruction(const MachineInstr &MI) {
+void ARMCodeEmitter::emitLEApcrelJTInstruction(const MachineInstr &MI) {
// It's basically add r, pc, (LJTI - $+8)
const TargetInstrDesc &TID = MI.getDesc();
emitWordLE(Binary);
}
-template<class CodeEmitter>
-void Emitter<CodeEmitter>::emitPseudoMoveInstruction(const MachineInstr &MI) {
+void ARMCodeEmitter::emitPseudoMoveInstruction(const MachineInstr &MI) {
unsigned Opcode = MI.getDesc().Opcode;
// Part of binary is determined by TableGn.
emitWordLE(Binary);
}
-template<class CodeEmitter>
-void Emitter<CodeEmitter>::addPCLabel(unsigned LabelID) {
+void ARMCodeEmitter::addPCLabel(unsigned LabelID) {
DEBUG(errs() << " ** LPC" << LabelID << " @ "
<< (void*)MCE.getCurrentPCValue() << '\n');
JTI->addPCLabelAddr(LabelID, MCE.getCurrentPCValue());
}
-template<class CodeEmitter>
-void Emitter<CodeEmitter>::emitPseudoInstruction(const MachineInstr &MI) {
+void ARMCodeEmitter::emitPseudoInstruction(const MachineInstr &MI) {
unsigned Opcode = MI.getDesc().Opcode;
switch (Opcode) {
default:
llvm_unreachable("ARMCodeEmitter::emitPseudoInstruction");
- // FIXME: Add support for MOVimm32.
- case TargetInstrInfo::INLINEASM: {
+ case ARM::BX:
+ case ARM::BMOVPCRX:
+ case ARM::BXr9:
+ case ARM::BMOVPCRXr9: {
+ // 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]) {
- llvm_report_error("JIT does not support inline asm!");
+ report_fatal_error("JIT does not support inline asm!");
}
break;
}
- case TargetInstrInfo::DBG_LABEL:
- case TargetInstrInfo::EH_LABEL:
- MCE.emitLabel(MI.getOperand(0).getImm());
+ case TargetOpcode::PROLOG_LABEL:
+ case TargetOpcode::EH_LABEL:
+ MCE.emitLabel(MI.getOperand(0).getMCSymbol());
break;
- case TargetInstrInfo::IMPLICIT_DEF:
- case TargetInstrInfo::KILL:
+ case TargetOpcode::IMPLICIT_DEF:
+ case TargetOpcode::KILL:
// Do nothing.
break;
case ARM::CONSTPOOL_ENTRY:
emitMiscLoadStoreInstruction(MI, ARM::PC);
break;
}
+
+ case ARM::MOVi32imm:
+ emitMOVi32immInstruction(MI);
+ break;
+
case ARM::MOVi2pieces:
// Two instructions to materialize a constant.
emitMOVi2piecesInstruction(MI);
}
}
-template<class CodeEmitter>
-unsigned Emitter<CodeEmitter>::getMachineSoRegOpValue(
- const MachineInstr &MI,
+unsigned ARMCodeEmitter::getMachineSoRegOpValue(const MachineInstr &MI,
const TargetInstrDesc &TID,
const MachineOperand &MO,
unsigned OpIdx) {
return Binary | ARM_AM::getSORegOffset(MO2.getImm()) << 7;
}
-template<class CodeEmitter>
-unsigned Emitter<CodeEmitter>::getMachineSoImmOpValue(unsigned SoImm) {
+unsigned ARMCodeEmitter::getMachineSoImmOpValue(unsigned SoImm) {
int SoImmVal = ARM_AM::getSOImmVal(SoImm);
assert(SoImmVal != -1 && "Not a valid so_imm value!");
return Binary;
}
-template<class CodeEmitter>
-unsigned Emitter<CodeEmitter>::getAddrModeSBit(const MachineInstr &MI,
- const TargetInstrDesc &TID) const {
+unsigned ARMCodeEmitter::getAddrModeSBit(const MachineInstr &MI,
+ const TargetInstrDesc &TID) const {
for (unsigned i = MI.getNumOperands(), e = TID.getNumOperands(); i != e; --i){
const MachineOperand &MO = MI.getOperand(i-1);
if (MO.isReg() && MO.isDef() && MO.getReg() == ARM::CPSR)
return 0;
}
-template<class CodeEmitter>
-void Emitter<CodeEmitter>::emitDataProcessingInstruction(
- const MachineInstr &MI,
+void ARMCodeEmitter::emitDataProcessingInstruction(const MachineInstr &MI,
unsigned ImplicitRd,
unsigned ImplicitRn) {
const TargetInstrDesc &TID = MI.getDesc();
- if (TID.Opcode == ARM::BFC) {
- llvm_report_error("ARMv6t2 JIT is not yet supported.");
- }
-
// Part of binary is determined by TableGn.
unsigned Binary = getBinaryCodeForInstr(MI);
Binary |= (ARMRegisterInfo::getRegisterNumbering(ImplicitRd)
<< ARMII::RegRdShift);
+ if (TID.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(TID.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 ((TID.Opcode == ARM::BFC) || (TID.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 ((TID.Opcode == ARM::UBFX) || (TID.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)
++OpIdx;
emitWordLE(Binary);
}
-template<class CodeEmitter>
-void Emitter<CodeEmitter>::emitLoadStoreInstruction(
- const MachineInstr &MI,
+void ARMCodeEmitter::emitLoadStoreInstruction(const MachineInstr &MI,
unsigned ImplicitRd,
unsigned ImplicitRn) {
const TargetInstrDesc &TID = MI.getDesc();
emitWordLE(Binary);
}
-template<class CodeEmitter>
-void Emitter<CodeEmitter>::emitMiscLoadStoreInstruction(const MachineInstr &MI,
- unsigned ImplicitRn) {
+void ARMCodeEmitter::emitMiscLoadStoreInstruction(const MachineInstr &MI,
+ unsigned ImplicitRn) {
const TargetInstrDesc &TID = MI.getDesc();
unsigned Form = TID.TSFlags & ARMII::FormMask;
bool IsPrePost = (TID.TSFlags & ARMII::IndexModeMask) != 0;
return Binary;
}
-template<class CodeEmitter>
-void Emitter<CodeEmitter>::emitLoadStoreMultipleInstruction(
- const MachineInstr &MI) {
+void ARMCodeEmitter::emitLoadStoreMultipleInstruction(const MachineInstr &MI) {
+ const TargetInstrDesc &TID = MI.getDesc();
+ bool IsUpdating = (TID.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);
+ const MachineOperand &MO = MI.getOperand(OpIdx++);
Binary |= getAddrModeUPBits(ARM_AM::getAM4SubMode(MO.getImm()));
// Set bit W(21)
- if (ARM_AM::getAM4WBFlag(MO.getImm()))
+ if (IsUpdating)
Binary |= 0x1 << ARMII::W_BitShift;
// Set registers
- for (unsigned i = 5, 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;
emitWordLE(Binary);
}
-template<class CodeEmitter>
-void Emitter<CodeEmitter>::emitMulFrmInstruction(const MachineInstr &MI) {
+void ARMCodeEmitter::emitMulFrmInstruction(const MachineInstr &MI) {
const TargetInstrDesc &TID = MI.getDesc();
// Part of binary is determined by TableGn.
emitWordLE(Binary);
}
-template<class CodeEmitter>
-void Emitter<CodeEmitter>::emitExtendInstruction(const MachineInstr &MI) {
+void ARMCodeEmitter::emitExtendInstruction(const MachineInstr &MI) {
const TargetInstrDesc &TID = MI.getDesc();
// Part of binary is determined by TableGn.
emitWordLE(Binary);
}
-template<class CodeEmitter>
-void Emitter<CodeEmitter>::emitMiscArithInstruction(const MachineInstr &MI) {
+void ARMCodeEmitter::emitMiscArithInstruction(const MachineInstr &MI) {
const TargetInstrDesc &TID = MI.getDesc();
// Part of binary is determined by TableGn.
emitWordLE(Binary);
}
-template<class CodeEmitter>
-void Emitter<CodeEmitter>::emitBranchInstruction(const MachineInstr &MI) {
+void ARMCodeEmitter::emitSaturateInstruction(const MachineInstr &MI) {
+ const TargetInstrDesc &TID = 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 (TID.Opcode == ARM::SSATlsl ||
+ TID.Opcode == ARM::SSATasr ||
+ TID.Opcode == ARM::SSAT16)
+ Pos -= 1;
+ assert((Pos < 16 || (Pos < 32 &&
+ TID.Opcode != ARM::SSAT16 &&
+ TID.Opcode != ARM::USAT16)) &&
+ "saturate bit position out of range");
+ Binary |= Pos << 16;
+
+ // Encode Rm
+ Binary |= getMachineOpValue(MI, 2);
+
+ // Encode shift_imm.
+ if (TID.getNumOperands() == 4) {
+ unsigned ShiftAmt = MI.getOperand(3).getImm();
+ if (ShiftAmt == 32 &&
+ (TID.Opcode == ARM::SSATasr || TID.Opcode == ARM::USATasr))
+ 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();
if (TID.Opcode == ARM::TPsoft) {
emitWordLE(Binary);
}
-template<class CodeEmitter>
-void Emitter<CodeEmitter>::emitInlineJumpTable(unsigned JTIndex) {
+void ARMCodeEmitter::emitInlineJumpTable(unsigned JTIndex) {
// Remember the base address of the inline jump table.
uintptr_t JTBase = MCE.getCurrentPCValue();
JTI->addJumpTableBaseAddr(JTIndex, JTBase);
}
}
-template<class CodeEmitter>
-void Emitter<CodeEmitter>::emitMiscBranchInstruction(const MachineInstr &MI) {
+void ARMCodeEmitter::emitMiscBranchInstruction(const MachineInstr &MI) {
const TargetInstrDesc &TID = MI.getDesc();
// Handle jump tables.
// Set the conditional execution predicate
Binary |= II->getPredicate(&MI) << ARMII::CondShift;
- if (TID.Opcode == ARM::BX_RET)
+ if (TID.Opcode == ARM::BX_RET || TID.Opcode == ARM::MOVPCLR)
// The return register is LR.
Binary |= ARMRegisterInfo::getRegisterNumbering(ARM::LR);
else
return Binary;
}
-template<class CodeEmitter>
-void Emitter<CodeEmitter>::emitVFPArithInstruction(const MachineInstr &MI) {
+void ARMCodeEmitter::emitVFPArithInstruction(const MachineInstr &MI) {
const TargetInstrDesc &TID = MI.getDesc();
// Part of binary is determined by TableGn.
emitWordLE(Binary);
}
-template<class CodeEmitter>
-void Emitter<CodeEmitter>::emitVFPConversionInstruction(
- const MachineInstr &MI) {
+void ARMCodeEmitter::emitVFPConversionInstruction(const MachineInstr &MI) {
const TargetInstrDesc &TID = MI.getDesc();
unsigned Form = TID.TSFlags & ARMII::FormMask;
emitWordLE(Binary);
}
-template<class CodeEmitter>
-void Emitter<CodeEmitter>::emitVFPLoadStoreInstruction(const MachineInstr &MI) {
+void ARMCodeEmitter::emitVFPLoadStoreInstruction(const MachineInstr &MI) {
// Part of binary is determined by TableGn.
unsigned Binary = getBinaryCodeForInstr(MI);
emitWordLE(Binary);
}
-template<class CodeEmitter>
-void Emitter<CodeEmitter>::emitVFPLoadStoreMultipleInstruction(
- const MachineInstr &MI) {
+void
+ARMCodeEmitter::emitVFPLoadStoreMultipleInstruction(const MachineInstr &MI) {
+ const TargetInstrDesc &TID = MI.getDesc();
+ bool IsUpdating = (TID.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);
+ const MachineOperand &MO = MI.getOperand(OpIdx++);
Binary |= getAddrModeUPBits(ARM_AM::getAM5SubMode(MO.getImm()));
// Set bit W(21)
- if (ARM_AM::getAM5WBFlag(MO.getImm()))
+ if (IsUpdating)
Binary |= 0x1 << ARMII::W_BitShift;
// First register is encoded in Dd.
- Binary |= encodeVFPRd(MI, 5);
+ Binary |= encodeVFPRd(MI, OpIdx+2);
// Number of registers are encoded in offset field.
unsigned NumRegs = 1;
- for (unsigned i = 6, 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);
}
-template<class CodeEmitter>
-void Emitter<CodeEmitter>::emitMiscInstruction(const MachineInstr &MI) {
+void ARMCodeEmitter::emitMiscInstruction(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;
+ switch(Opcode) {
+ default:
+ llvm_unreachable("ARMCodeEmitter::emitMiscInstruction");
+
+ case ARM::FMSTAT:
+ // No further encoding needed.
+ break;
+
+ case ARM::VMRS:
+ case ARM::VMSR: {
+ const MachineOperand &MO0 = MI.getOperand(0);
+ // Encode Rt.
+ Binary |= ARMRegisterInfo::getRegisterNumbering(MO0.getReg())
+ << ARMII::RegRdShift;
+ break;
+ }
+
+ case ARM::FCONSTD:
+ case ARM::FCONSTS: {
+ // Encode Dd / Sd.
+ Binary |= encodeVFPRd(MI, 0);
+
+ // Encode imm., Table A7-18 VFP modified immediate constants
+ const MachineOperand &MO1 = MI.getOperand(1);
+ unsigned Imm = static_cast<unsigned>(MO1.getFPImm()->getValueAPF()
+ .bitcastToAPInt().getHiBits(32).getLimitedValue());
+ unsigned ModifiedImm;
+
+ if(Opcode == ARM::FCONSTS)
+ ModifiedImm = (Imm & 0x80000000) >> 24 | // a
+ (Imm & 0x03F80000) >> 19; // bcdefgh
+ else // Opcode == ARM::FCONSTD
+ ModifiedImm = (Imm & 0x80000000) >> 24 | // a
+ (Imm & 0x007F0000) >> 16; // bcdefgh
+
+ // Insts{19-16} = abcd, Insts{3-0} = efgh
+ Binary |= ((ModifiedImm & 0xF0) >> 4) << 16;
+ Binary |= (ModifiedImm & 0xF);
+ break;
+ }
+ }
+
+ emitWordLE(Binary);
+}
+
+static unsigned encodeNEONRd(const MachineInstr &MI, unsigned OpIdx) {
+ unsigned RegD = MI.getOperand(OpIdx).getReg();
+ unsigned Binary = 0;
+ RegD = ARMRegisterInfo::getRegisterNumbering(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 = ARMRegisterInfo::getRegisterNumbering(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 = ARMRegisterInfo::getRegisterNumbering(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 TargetInstrDesc &TID = MI.getDesc();
+ if ((TID.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 |= (IsThumb ? ARMCC::AL : II->getPredicate(&MI)) << ARMII::CondShift;
+
+ unsigned RegT = MI.getOperand(RegTOpIdx).getReg();
+ RegT = ARMRegisterInfo::getRegisterNumbering(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 = ARMRegisterInfo::getRegisterNumbering(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 TargetInstrDesc &TID = MI.getDesc();
+ unsigned Binary = getBinaryCodeForInstr(MI);
+ // Destination register is encoded in Dd; source register in Dm.
+ unsigned OpIdx = 0;
+ Binary |= encodeNEONRd(MI, OpIdx++);
+ if (TID.getOperandConstraint(OpIdx, TOI::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 TargetInstrDesc &TID = 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 (TID.getOperandConstraint(OpIdx, TOI::TIED_TO) != -1)
+ ++OpIdx;
+ Binary |= encodeNEONRn(MI, OpIdx++);
+ if (TID.getOperandConstraint(OpIdx, TOI::TIED_TO) != -1)
+ ++OpIdx;
+ Binary |= encodeNEONRm(MI, OpIdx);
+ if (IsThumb)
+ Binary = convertNEONDataProcToThumb(Binary);
+ // FIXME: This does not handle VMOVDneon or VMOVQ.
emitWordLE(Binary);
}