X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;f=lib%2FTarget%2FARM%2FARMCodeEmitter.cpp;h=089d1c51598f41c9ccfa6b2e4db36abbfc9596f3;hb=9ccaf53ada99c63737547c0235baeb8454b04e80;hp=2fdd9ce10b9d514a941469dcdab11af8e21f60c3;hpb=3f4924efffdb4bb7af408356df86bd8cb83ab89a;p=oota-llvm.git diff --git a/lib/Target/ARM/ARMCodeEmitter.cpp b/lib/Target/ARM/ARMCodeEmitter.cpp index 2fdd9ce10b9..089d1c51598 100644 --- a/lib/Target/ARM/ARMCodeEmitter.cpp +++ b/lib/Target/ARM/ARMCodeEmitter.cpp @@ -24,15 +24,17 @@ #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 #endif @@ -41,27 +43,38 @@ using namespace llvm; 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 *MCPEs; const std::vector *MJTEs; bool IsPIC; + bool IsThumb; + + void getAnalysisUsage(AnalysisUsage &AU) const { + AU.addRequired(); + 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); bool runOnMachineFunction(MachineFunction &MF); @@ -74,19 +87,14 @@ namespace { 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, @@ -132,11 +140,11 @@ namespace { 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. @@ -145,46 +153,64 @@ namespace { 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, - bool NeedStub, intptr_t ACPV = 0); + void emitGlobalAddress(const GlobalValue *GV, unsigned Reloc, + bool MayNeedFarStub, bool Indirect, + intptr_t ACPV = 0); void emitExternalSymbolAddress(const char *ES, unsigned Reloc); void emitConstPoolAddress(unsigned CPI, unsigned Reloc); void emitJumpTableAddress(unsigned JTIndex, unsigned Reloc); void emitMachineBasicBlock(MachineBasicBlock *BB, unsigned Reloc, intptr_t JTBase = 0); }; - 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(); 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()->isThumbFunction(); JTI->Initialize(MF, IsPIC); + MMI = &getAnalysis(); + 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(); @@ -200,7 +226,7 @@ bool ARMCodeEmitter::runOnMachineFunction(MachineFunction &MF) { /// 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; @@ -210,6 +236,31 @@ unsigned ARMCodeEmitter::getShiftOp(unsigned Imm) 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 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(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, @@ -219,7 +270,7 @@ unsigned ARMCodeEmitter::getMachineOpValue(const MachineInstr &MI, else if (MO.isImm()) return static_cast(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()) { @@ -233,18 +284,27 @@ unsigned ARMCodeEmitter::getMachineOpValue(const MachineInstr &MI, else if (MO.isMBB()) emitMachineBasicBlock(MO.getMBB(), ARM::reloc_arm_branch); else { - cerr << "ERROR: Unknown type of MachineOperand: " << MO << "\n"; - abort(); +#ifndef NDEBUG + errs() << MO; +#endif + llvm_unreachable(0); } 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) { + MachineRelocation MR = Indirect + ? MachineRelocation::getIndirectSymbol(MCE.getCurrentPCOffset(), Reloc, + const_cast(GV), + ACPV, MayNeedFarStub) + : MachineRelocation::getGV(MCE.getCurrentPCOffset(), Reloc, + const_cast(GV), ACPV, + MayNeedFarStub); + MCE.addRelocation(MR); } /// emitExternalSymbolAddress - Arrange for the address of an external symbol to @@ -280,31 +340,28 @@ void ARMCodeEmitter::emitMachineBasicBlock(MachineBasicBlock *BB, } 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::Pseudo: emitPseudoInstruction(MI); break; @@ -312,10 +369,12 @@ void ARMCodeEmitter::emitInstruction(const MachineInstr &MI) { case ARMII::DPSoRegFrm: emitDataProcessingInstruction(MI); break; - case ARMII::LdStFrm: + case ARMII::LdFrm: + case ARMII::StFrm: emitLoadStoreInstruction(MI); break; - case ARMII::LdStMiscFrm: + case ARMII::LdMiscFrm: + case ARMII::StMiscFrm: emitMiscLoadStoreInstruction(MI); break; case ARMII::LdStMulFrm: @@ -357,14 +416,32 @@ void ARMCodeEmitter::emitInstruction(const MachineInstr &MI) { 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); } 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()); @@ -374,56 +451,95 @@ void ARMCodeEmitter::emitConstPoolInstruction(const MachineInstr &MI) { ARMConstantPoolValue *ACPV = static_cast(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 = 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); + Reloc::Model RelocM = TM.getRelocationModel(); + emitGlobalAddress(GV, ARM::reloc_arm_machine_cp_entry, + isa(GV), + Subtarget->GVIsIndirectSymbol(GV, RelocM), + (intptr_t)ACPV); } else { - assert(!ACPV->isNonLazyPointer() && "Don't know how to deal this yet!"); emitExternalSymbolAddress(ACPV->getSymbol(), 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(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(CV)) + errs() << F->getName(); + else + errs() << *CV; + errs() << '\n'; + }); + + if (const GlobalValue *GV = dyn_cast(CV)) { + emitGlobalAddress(GV, ARM::reloc_arm_absolute, isa(GV), false); emitWordLE(0); } else if (const ConstantInt *CI = dyn_cast(CV)) { uint32_t Val = *(uint32_t*)CI->getValue().getRawData(); emitWordLE(Val); } else if (const ConstantFP *CFP = dyn_cast(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()); @@ -439,7 +555,7 @@ void ARMCodeEmitter::emitMOVi2piecesInstruction(const MachineInstr &MI) { // Encode so_imm. // Set bit I(25) to identify this is the immediate form of Binary |= 1 << ARMII::I_BitShift; - Binary |= getMachineSoImmOpValue(ARM_AM::getSOImmVal(V1)); + Binary |= getMachineSoImmOpValue(V1); emitWordLE(Binary); // Now the 'orr' instruction. @@ -457,13 +573,13 @@ void ARMCodeEmitter::emitMOVi2piecesInstruction(const MachineInstr &MI) { // Encode so_imm. // Set bit I(25) to identify this is the immediate form of 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(); // Emit the 'add' instruction. @@ -482,16 +598,54 @@ void ARMCodeEmitter::emitLEApcrelJTInstruction(const MachineInstr &MI) { Binary |= ARMRegisterInfo::getRegisterNumbering(ARM::PC) << ARMII::RegRnShift; // Encode the displacement. - // Set bit I(25) to identify this is the immediate form of . 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::MOVrx: + // 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()); } @@ -499,7 +653,36 @@ void ARMCodeEmitter::emitPseudoInstruction(const MachineInstr &MI) { unsigned Opcode = MI.getDesc().Opcode; switch (Opcode) { default: - abort(); // FIXME: + llvm_unreachable("ARMCodeEmitter::emitPseudoInstruction"); + 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]) { + 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; @@ -530,6 +713,11 @@ void ARMCodeEmitter::emitPseudoInstruction(const MachineInstr &MI) { emitMiscLoadStoreInstruction(MI, ARM::PC); break; } + + case ARM::MOVi32imm: + emitMOVi32immInstruction(MI); + break; + case ARM::MOVi2pieces: // Two instructions to materialize a constant. emitMOVi2piecesInstruction(MI); @@ -538,10 +726,14 @@ void ARMCodeEmitter::emitPseudoInstruction(const MachineInstr &MI) { // Materialize jumptable address. emitLEApcrelJTInstruction(MI); break; + case ARM::MOVrx: + case ARM::MOVsrl_flag: + case ARM::MOVsra_flag: + emitPseudoMoveInstruction(MI); + break; } } - unsigned ARMCodeEmitter::getMachineSoRegOpValue(const MachineInstr &MI, const TargetInstrDesc &TID, const MachineOperand &MO, @@ -563,7 +755,7 @@ unsigned ARMCodeEmitter::getMachineSoRegOpValue(const MachineInstr &MI, // 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; @@ -577,7 +769,7 @@ unsigned ARMCodeEmitter::getMachineSoRegOpValue(const MachineInstr &MI, // 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; @@ -601,12 +793,15 @@ unsigned ARMCodeEmitter::getMachineSoRegOpValue(const MachineInstr &MI, } 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; } @@ -644,6 +839,45 @@ void ARMCodeEmitter::emitDataProcessingInstruction(const MachineInstr &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; @@ -676,9 +910,7 @@ void ARMCodeEmitter::emitDataProcessingInstruction(const MachineInstr &MI, } // Encode so_imm. - // Set bit I(25) to identify this is the immediate form of . - Binary |= 1 << ARMII::I_BitShift; - Binary |= getMachineSoImmOpValue(MO.getImm()); + Binary |= getMachineSoImmOpValue((unsigned)MO.getImm()); emitWordLE(Binary); } @@ -687,6 +919,8 @@ void ARMCodeEmitter::emitLoadStoreInstruction(const MachineInstr &MI, unsigned ImplicitRd, unsigned ImplicitRn) { const TargetInstrDesc &TID = MI.getDesc(); + unsigned Form = TID.TSFlags & ARMII::FormMask; + bool IsPrePost = (TID.TSFlags & ARMII::IndexModeMask) != 0; // Part of binary is determined by TableGn. unsigned Binary = getBinaryCodeForInstr(MI); @@ -694,8 +928,17 @@ void ARMCodeEmitter::emitLoadStoreInstruction(const MachineInstr &MI, // 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) @@ -712,7 +955,7 @@ void ARMCodeEmitter::emitLoadStoreInstruction(const MachineInstr &MI, 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 && TID.getOperandConstraint(OpIdx, TOI::TIED_TO) != -1) ++OpIdx; const MachineOperand &MO2 = MI.getOperand(OpIdx); @@ -749,6 +992,8 @@ void ARMCodeEmitter::emitLoadStoreInstruction(const MachineInstr &MI, 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; // Part of binary is determined by TableGn. unsigned Binary = getBinaryCodeForInstr(MI); @@ -756,11 +1001,24 @@ void ARMCodeEmitter::emitMiscLoadStoreInstruction(const MachineInstr &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 (TID.Opcode == ARM::LDRD || TID.Opcode == ARM::STRD) + ++OpIdx; // Set second operand - unsigned OpIdx = 1; if (ImplicitRn) // Special handling for implicit use (e.g. PC). Binary |= (ARMRegisterInfo::getRegisterNumbering(ImplicitRn) @@ -769,7 +1027,7 @@ void ARMCodeEmitter::emitMiscLoadStoreInstruction(const MachineInstr &MI, 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 && TID.getOperandConstraint(OpIdx, TOI::TIED_TO) != -1) ++OpIdx; const MachineOperand &MO2 = MI.getOperand(OpIdx); @@ -808,8 +1066,8 @@ static unsigned getAddrModeUPBits(unsigned Mode) { // 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; @@ -819,25 +1077,33 @@ static unsigned getAddrModeUPBits(unsigned Mode) { } 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 = 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; @@ -958,15 +1224,16 @@ void ARMCodeEmitter::emitMiscArithInstruction(const MachineInstr &MI) { unsigned ShiftAmt = MI.getOperand(OpIdx).getImm(); 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) - abort(); // FIXME + if (TID.Opcode == ARM::TPsoft) { + llvm_unreachable("ARM::TPsoft FIXME"); // FIXME + } // Part of binary is determined by TableGn. unsigned Binary = getBinaryCodeForInstr(MI); @@ -982,9 +1249,10 @@ void ARMCodeEmitter::emitBranchInstruction(const MachineInstr &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 &MBBs = (*MJTEs)[JTIndex].MBBs; @@ -1008,7 +1276,8 @@ void ARMCodeEmitter::emitMiscBranchInstruction(const MachineInstr &MI) { emitDataProcessingInstruction(MI, ARM::PC); // Then emit the inline jump table. - unsigned JTIndex = (TID.Opcode == ARM::BR_JTr) + unsigned JTIndex = + (TID.Opcode == ARM::BR_JTr) ? MI.getOperand(1).getIndex() : MI.getOperand(2).getIndex(); emitInlineJumpTable(JTIndex); return; @@ -1027,10 +1296,10 @@ void ARMCodeEmitter::emitMiscBranchInstruction(const MachineInstr &MI) { // 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 + else // otherwise, set the return register Binary |= getMachineOpValue(MI, 0); @@ -1041,7 +1310,7 @@ static unsigned encodeVFPRd(const MachineInstr &MI, unsigned OpIdx) { unsigned RegD = MI.getOperand(OpIdx).getReg(); unsigned Binary = 0; bool isSPVFP = false; - RegD = ARMRegisterInfo::getRegisterNumbering(RegD, isSPVFP); + RegD = ARMRegisterInfo::getRegisterNumbering(RegD, &isSPVFP); if (!isSPVFP) Binary |= RegD << ARMII::RegRdShift; else { @@ -1055,7 +1324,7 @@ static unsigned encodeVFPRn(const MachineInstr &MI, unsigned OpIdx) { unsigned RegN = MI.getOperand(OpIdx).getReg(); unsigned Binary = 0; bool isSPVFP = false; - RegN = ARMRegisterInfo::getRegisterNumbering(RegN, isSPVFP); + RegN = ARMRegisterInfo::getRegisterNumbering(RegN, &isSPVFP); if (!isSPVFP) Binary |= RegN << ARMII::RegRnShift; else { @@ -1069,7 +1338,7 @@ static unsigned encodeVFPRm(const MachineInstr &MI, unsigned OpIdx) { unsigned RegM = MI.getOperand(OpIdx).getReg(); unsigned Binary = 0; bool isSPVFP = false; - RegM = ARMRegisterInfo::getRegisterNumbering(RegM, isSPVFP); + RegM = ARMRegisterInfo::getRegisterNumbering(RegM, &isSPVFP); if (!isSPVFP) Binary |= RegM; else { @@ -1114,7 +1383,7 @@ void ARMCodeEmitter::emitVFPArithInstruction(const MachineInstr &MI) { // Encode Dm / Sm. Binary |= encodeVFPRm(MI, OpIdx); - + emitWordLE(Binary); } @@ -1151,6 +1420,7 @@ void ARMCodeEmitter::emitVFPConversionInstruction(const MachineInstr &MI) { case ARMII::VFPConv1Frm: // Encode Dm / Sm. Binary |= encodeVFPRm(MI, 1); + break; case ARMII::VFPConv2Frm: case ARMII::VFPConv3Frm: // Encode Dn / Sn. @@ -1195,8 +1465,7 @@ void ARMCodeEmitter::emitVFPLoadStoreInstruction(const MachineInstr &MI) { 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; } @@ -1210,46 +1479,242 @@ void ARMCodeEmitter::emitVFPLoadStoreInstruction(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, 4); + Binary |= encodeVFPRd(MI, OpIdx+2); // Number of registers are encoded in offset field. 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 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) { + 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(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); }