From 7602e11c3298ca740deb04a246c70560f1743dbd Mon Sep 17 00:00:00 2001 From: Evan Cheng Date: Tue, 2 Sep 2008 06:52:38 +0000 Subject: [PATCH] Revamp ARM JIT. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@55624 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Target/ARM/ARMCodeEmitter.cpp | 865 +++++++++++++----------------- 1 file changed, 375 insertions(+), 490 deletions(-) diff --git a/lib/Target/ARM/ARMCodeEmitter.cpp b/lib/Target/ARM/ARMCodeEmitter.cpp index f4ee6b0f649..16b00417b35 100644 --- a/lib/Target/ARM/ARMCodeEmitter.cpp +++ b/lib/Target/ARM/ARMCodeEmitter.cpp @@ -13,18 +13,17 @@ //===----------------------------------------------------------------------===// #define DEBUG_TYPE "arm-emitter" +#include "ARM.h" +#include "ARMAddressingModes.h" #include "ARMInstrInfo.h" +#include "ARMRelocations.h" #include "ARMSubtarget.h" #include "ARMTargetMachine.h" -#include "ARMRelocations.h" -#include "ARMAddressingModes.h" -#include "ARM.h" #include "llvm/PassManager.h" #include "llvm/CodeGen/MachineCodeEmitter.h" #include "llvm/CodeGen/MachineFunctionPass.h" #include "llvm/CodeGen/MachineInstr.h" #include "llvm/CodeGen/Passes.h" -#include "llvm/Function.h" #include "llvm/ADT/Statistic.h" #include "llvm/Support/Compiler.h" using namespace llvm; @@ -32,19 +31,19 @@ using namespace llvm; STATISTIC(NumEmitted, "Number of machine instructions emitted"); namespace { - class VISIBILITY_HIDDEN Emitter : public MachineFunctionPass { + class VISIBILITY_HIDDEN ARMCodeEmitter : public MachineFunctionPass { const ARMInstrInfo *II; const TargetData *TD; TargetMachine &TM; MachineCodeEmitter &MCE; public: static char ID; - explicit Emitter(TargetMachine &tm, MachineCodeEmitter &mce) - : MachineFunctionPass((intptr_t)&ID), II(0), TD(0), TM(tm), + explicit ARMCodeEmitter(TargetMachine &tm, MachineCodeEmitter &mce) + : MachineFunctionPass((intptr_t)&ID), II(0), TD(0), TM(tm), MCE(mce) {} - Emitter(TargetMachine &tm, MachineCodeEmitter &mce, + ARMCodeEmitter(TargetMachine &tm, MachineCodeEmitter &mce, const ARMInstrInfo &ii, const TargetData &td) - : MachineFunctionPass((intptr_t)&ID), II(&ii), TD(&td), TM(tm), + : MachineFunctionPass((intptr_t)&ID), II(&ii), TD(&td), TM(tm), MCE(mce) {} bool runOnMachineFunction(MachineFunction &MF); @@ -54,10 +53,54 @@ namespace { } void emitInstruction(const MachineInstr &MI); - int getMachineOpValue(const MachineInstr &MI, unsigned OpIndex); - unsigned getBaseOpcodeFor(const TargetInstrDesc &TID); + + private: + unsigned getAddrModeNoneInstrBinary(const MachineInstr &MI, + const TargetInstrDesc &Desc, + unsigned Binary) ; + unsigned getAddrMode1InstrBinary(const MachineInstr &MI, + const TargetInstrDesc &Desc, + unsigned Binary); + unsigned getAddrMode2InstrBinary(const MachineInstr &MI, + const TargetInstrDesc &Desc, + unsigned Binary); + unsigned getAddrMode3InstrBinary(const MachineInstr &MI, + const TargetInstrDesc &Desc, + unsigned Binary); + unsigned getAddrMode4InstrBinary(const MachineInstr &MI, + const TargetInstrDesc &Desc, + unsigned Binary); + + /// getInstrBinary - Return binary encoding for the specified + /// machine instruction. + unsigned getInstrBinary(const MachineInstr &MI); + + /// getBinaryCodeForInstr - This function, generated by the + /// CodeEmitterGenerator using TableGen, produces the binary encoding for + /// machine instructions. + /// unsigned getBinaryCodeForInstr(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, unsigned OpIdx) { + return getMachineOpValue(MI, MI.getOperand(OpIdx)); + } + unsigned getMachineOpValue(const MachineInstr &MI, + const MachineOperand &MO); + + /// getBaseOpcodeFor - Return the opcode value. + /// + unsigned getBaseOpcodeFor(const TargetInstrDesc &TID) const { + return (TID.TSFlags & ARMII::OpcodeMask) >> ARMII::OpcodeShift; + } + + /// getShiftOp - Return the shift opcode (bit[6:5]) of the machine operand. + /// + unsigned getShiftOp(const MachineOperand &MO) const ; + + /// Routines that handle operands which add machine relocations which are + /// fixed up by the JIT fixup stage. void emitGlobalAddressForCall(GlobalValue *GV, bool DoesntNeedStub); void emitExternalSymbolAddress(const char *ES, unsigned Reloc); void emitConstPoolAddress(unsigned CPI, unsigned Reloc, @@ -66,22 +109,18 @@ namespace { unsigned PCAdj = 0); void emitGlobalConstant(const Constant *CV); void emitMachineBasicBlock(MachineBasicBlock *BB); - - private: - int getShiftOp(const MachineOperand &MO); - }; - char Emitter::ID = 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 Emitter(TM, MCE); + return new ARMCodeEmitter(TM, MCE); } -bool Emitter::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!"); @@ -102,70 +141,57 @@ bool Emitter::runOnMachineFunction(MachineFunction &MF) { return false; } -/// getBaseOpcodeFor - Return the opcode value -unsigned Emitter::getBaseOpcodeFor(const TargetInstrDesc &TID) { - return (TID.TSFlags & ARMII::OpcodeMask) >> ARMII::OpcodeShift; -} - -/// getShiftOp - Verify which is the shift opcode (bit[6:5]) of the -/// machine operand. -int Emitter::getShiftOp(const MachineOperand &MO) { - unsigned ShiftOp = 0x0; - switch(ARM_AM::getAM2ShiftOpc(MO.getImm())) { +/// getShiftOp - Return the shift opcode (bit[6:5]) of the machine operand. +/// +unsigned ARMCodeEmitter::getShiftOp(const MachineOperand &MO) const { + switch (ARM_AM::getAM2ShiftOpc(MO.getImm())) { default: assert(0 && "Unknown shift opc!"); - case ARM_AM::asr: - ShiftOp = 0X2; - break; - case ARM_AM::lsl: - ShiftOp = 0X0; - break; - case ARM_AM::lsr: - ShiftOp = 0X1; - break; + case ARM_AM::asr: return 2; + case ARM_AM::lsl: return 0; + case ARM_AM::lsr: return 1; case ARM_AM::ror: - case ARM_AM::rrx: - ShiftOp = 0X3; - break; + case ARM_AM::rrx: return 3; } - return ShiftOp; + return 0; } -int Emitter::getMachineOpValue(const MachineInstr &MI, unsigned OpIndex) { - intptr_t rv = 0; - const MachineOperand &MO = MI.getOperand(OpIndex); - if (MO.isRegister()) { - assert(TargetRegisterInfo::isPhysicalRegister(MO.getReg())); - rv = ARMRegisterInfo::getRegisterNumbering(MO.getReg()); - } else if (MO.isImmediate()) { - rv = MO.getImm(); - } else if (MO.isGlobalAddress()) { +/// 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) { + if (MO.isRegister()) + return ARMRegisterInfo::getRegisterNumbering(MO.getReg()); + else if (MO.isImmediate()) + return static_cast(MO.getImm()); + else if (MO.isGlobalAddress()) emitGlobalAddressForCall(MO.getGlobal(), false); - } else if (MO.isExternalSymbol()) { + else if (MO.isExternalSymbol()) emitExternalSymbolAddress(MO.getSymbolName(), ARM::reloc_arm_relative); - } else if (MO.isConstantPoolIndex()) { + else if (MO.isConstantPoolIndex()) emitConstPoolAddress(MO.getIndex(), ARM::reloc_arm_relative); - } else if (MO.isJumpTableIndex()) { + else if (MO.isJumpTableIndex()) emitJumpTableAddress(MO.getIndex(), ARM::reloc_arm_relative); - } else if (MO.isMachineBasicBlock()) { + else if (MO.isMachineBasicBlock()) emitMachineBasicBlock(MO.getMBB()); - } - return rv; + abort(); + return 0; } /// emitGlobalAddressForCall - Emit the specified address to the code stream /// assuming this is part of a function call, which is PC relative. /// -void Emitter::emitGlobalAddressForCall(GlobalValue *GV, bool DoesntNeedStub) { +void ARMCodeEmitter::emitGlobalAddressForCall(GlobalValue *GV, + bool DoesntNeedStub) { MCE.addRelocation(MachineRelocation::getGV(MCE.getCurrentPCOffset(), - ARM::reloc_arm_branch, GV, 0, - DoesntNeedStub)); + ARM::reloc_arm_branch, GV, 0, + DoesntNeedStub)); } /// 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 Emitter::emitExternalSymbolAddress(const char *ES, unsigned Reloc) { +void ARMCodeEmitter::emitExternalSymbolAddress(const char *ES, unsigned Reloc) { MCE.addRelocation(MachineRelocation::getExtSym(MCE.getCurrentPCOffset(), Reloc, ES)); } @@ -173,9 +199,9 @@ void Emitter::emitExternalSymbolAddress(const char *ES, unsigned Reloc) { /// 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 Emitter::emitConstPoolAddress(unsigned CPI, unsigned Reloc, - int Disp /* = 0 */, - unsigned PCAdj /* = 0 */) { +void ARMCodeEmitter::emitConstPoolAddress(unsigned CPI, unsigned Reloc, + int Disp /* = 0 */, + unsigned PCAdj /* = 0 */) { MCE.addRelocation(MachineRelocation::getConstPool(MCE.getCurrentPCOffset(), Reloc, CPI, PCAdj)); } @@ -183,472 +209,331 @@ void Emitter::emitConstPoolAddress(unsigned CPI, unsigned Reloc, /// 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 Emitter::emitJumpTableAddress(unsigned JTI, unsigned Reloc, - unsigned PCAdj /* = 0 */) { +void ARMCodeEmitter::emitJumpTableAddress(unsigned JTI, unsigned Reloc, + unsigned PCAdj /* = 0 */) { MCE.addRelocation(MachineRelocation::getJumpTable(MCE.getCurrentPCOffset(), Reloc, JTI, PCAdj)); } /// emitMachineBasicBlock - Emit the specified address basic block. -void Emitter::emitMachineBasicBlock(MachineBasicBlock *BB) { +void ARMCodeEmitter::emitMachineBasicBlock(MachineBasicBlock *BB) { MCE.addRelocation(MachineRelocation::getBB(MCE.getCurrentPCOffset(), - ARM::reloc_arm_branch, BB)); + ARM::reloc_arm_branch, BB)); } -void Emitter::emitInstruction(const MachineInstr &MI) { +void ARMCodeEmitter::emitInstruction(const MachineInstr &MI) { NumEmitted++; // Keep track of the # of mi's emitted - MCE.emitWordLE(getBinaryCodeForInstr(MI)); + MCE.emitWordLE(getInstrBinary(MI)); } -unsigned Emitter::getBinaryCodeForInstr(const MachineInstr &MI) { - const TargetInstrDesc &Desc = MI.getDesc(); - unsigned opcode = Desc.Opcode; - // initial instruction mask - unsigned Value = 0xE0000000; - unsigned op; - - switch (Desc.TSFlags & ARMII::AddrModeMask) { - case ARMII::AddrModeNone: { - switch(Desc.TSFlags & ARMII::FormMask) { - default: { - assert(0 && "Unknown instruction subtype!"); - // treat special instruction CLZ - if(opcode == ARM::CLZ) { - // set first operand - op = getMachineOpValue(MI,0); - Value |= op << ARMII::RegRdShift; - - // set second operand - op = getMachineOpValue(MI,1); - Value |= op; - } - break; - } - case ARMII::MulSMLAW: - case ARMII::MulSMULW: - // set bit W(21) - Value |= 1 << 21; - case ARMII::MulSMLA: - case ARMII::MulSMUL: { - // set bit W(21) - Value |= 1 << 24; - - // set opcode (bit[7:4]). For more information, see ARM-ARM page A3-31 - // SMLA - 1yx0 - // SMLAW - 1y00 - // SMULW - 1y10 - // SMUL - 1yx0 - unsigned char BaseOpcode = getBaseOpcodeFor(Desc); - Value |= BaseOpcode << 4; - - unsigned Format = (Desc.TSFlags & ARMII::FormMask); - if (Format == ARMII::MulSMUL) - Value |= 1 << 22; - - // set first operand - op = getMachineOpValue(MI,0); - Value |= op << ARMII::RegRnShift; - - // set second operand - op = getMachineOpValue(MI,1); - Value |= op; - - // set third operand - op = getMachineOpValue(MI,2); - Value |= op << ARMII::RegRsShift; - - // instructions SMLA and SMLAW have a fourth operand - if (Format != ARMII::MulSMULW && Format != ARMII::MulSMUL) { - op = getMachineOpValue(MI,3); - Value |= op << ARMII::RegRdShift; - } - - break; +unsigned ARMCodeEmitter::getAddrModeNoneInstrBinary(const MachineInstr &MI, + const TargetInstrDesc &Desc, + unsigned Binary) { + switch (Desc.TSFlags & ARMII::FormMask) { + default: + assert(0 && "Unknown instruction subtype!"); + break; + case ARMII::Branch: { + // Set signed_immed_24 field + Binary |= getMachineOpValue(MI, 0); + + // if it is a conditional branch, set cond field + if (Desc.Opcode == ARM::Bcc) { + Binary &= 0x0FFFFFFF; // clear conditional field + Binary |= getMachineOpValue(MI, 1) << 28; // set conditional field } - case ARMII::MulFrm: { - // bit[7:4] is always 9 - Value |= 9 << 4; - // set opcode (bit[23:20]) - unsigned char BaseOpcode = getBaseOpcodeFor(Desc); - Value |= BaseOpcode << 20; - - bool isMUL = opcode == ARM::MUL; - bool isMLA = opcode == ARM::MLA; - - // set first operand - op = getMachineOpValue(MI,0); - Value |= op << (isMUL || isMLA ? ARMII::RegRnShift : ARMII::RegRdShift); - - // set second operand - op = getMachineOpValue(MI,1); - Value |= op << (isMUL || isMLA ? 0 : ARMII::RegRnShift); - - // set third operand - op = getMachineOpValue(MI,2); - Value |= op << (isMUL || isMLA ? ARMII::RegRsShift : 0); - - // multiply instructions (except MUL), have a fourth operand - if (!isMUL) { - op = getMachineOpValue(MI,3); - Value |= op << (isMLA ? ARMII::RegRdShift : ARMII::RegRsShift); - } + break; + } + case ARMII::BranchMisc: { + // Set bit[19:8] to 0xFFF + Binary |= 0xfff << 8; + if (Desc.Opcode == ARM::BX_RET) + Binary |= 0xe; // the return register is LR + else + // otherwise, set the return register + Binary |= getMachineOpValue(MI, 0); + break; + } + } - break; - } - case ARMII::Branch: { - // set opcode (bit[27:24]) - unsigned BaseOpcode = getBaseOpcodeFor(Desc); - Value |= BaseOpcode << 24; - - // set signed_immed_24 field - op = getMachineOpValue(MI,0); - Value |= op; - - // if it is a conditional branch, set cond field - if (opcode == ARM::Bcc) { - op = getMachineOpValue(MI,1); - Value &= 0x0FFFFFFF; // clear conditional field - Value |= op << 28; // set conditional field - } + return Binary; +} +unsigned ARMCodeEmitter::getAddrMode1InstrBinary(const MachineInstr &MI, + const TargetInstrDesc &Desc, + unsigned Binary) { + // FIXME: Clean up. + // Treat 3 special instructions: MOVsra_flag, MOVsrl_flag and MOVrx. + unsigned Format = Desc.TSFlags & ARMII::FormMask; + if (Format == ARMII::DPRdMisc) { + Binary |= getMachineOpValue(MI, 0) << ARMII::RegRdShift; + Binary |= getMachineOpValue(MI, 1); + switch (Desc.Opcode) { + case ARM::MOVsra_flag: + Binary |= 0x1 << 6; + Binary |= 0x1 << 7; break; - } - case ARMII::BranchMisc: { - // set opcode (bit[7:4]) - unsigned char BaseOpcode = getBaseOpcodeFor(Desc); - Value |= BaseOpcode << 4; - // set bit[27:24] to 1, set bit[23:20] to 2 and set bit[19:8] to 0xFFF - Value |= 0x12fff << 8; - - if (opcode == ARM::BX_RET) - op = 0xe; // the return register is LR - else - // otherwise, set the return register - op = getMachineOpValue(MI,0); - Value |= op; - + case ARM::MOVsrl_flag: + Binary |= 0x1 << 5; + Binary |= 0x1 << 7; break; - } - case ARMII::Pseudo: + case ARM::MOVrx: + Binary |= 0x3 << 5; break; } - - break; + return Binary; } - case ARMII::AddrMode1: { - // set opcode (bit[24:21]) of data-processing instructions - unsigned char BaseOpcode = getBaseOpcodeFor(Desc); - Value |= BaseOpcode << 21; - - // treat 3 special instructions: MOVsra_flag, MOVsrl_flag and - // MOVrx. - unsigned Format = Desc.TSFlags & ARMII::FormMask; - if (Format == ARMII::DPRdMisc) { - Value |= getMachineOpValue(MI,0) << ARMII::RegRdShift; - Value |= getMachineOpValue(MI,1); - switch(opcode) { - case ARM::MOVsra_flag: { - Value |= 0x1 << 6; - Value |= 0x1 << 7; - break; - } - case ARM::MOVsrl_flag: { - Value |= 0x1 << 5; - Value |= 0x1 << 7; - break; - } - case ARM::MOVrx: { - Value |= 0x3 << 5; - break; - } - } - break; - } - - // Data processing operand instructions has 3 possible encodings (for more - // information, see ARM-ARM page A3-10): - // 1. , - // 2. , - // 3. ,, - bool IsDataProcessing1 = Format == ARMII::DPRdIm || - Format == ARMII::DPRdReg || - Format == ARMII::DPRdSoReg; - bool IsDataProcessing2 = Format == ARMII::DPRnIm || - Format == ARMII::DPRnReg || - Format == ARMII::DPRnSoReg; - bool IsDataProcessing3 = false; - - // set bit S(20) - if (Format == ARMII::DPRImS || Format == ARMII::DPRRegS || - Format == ARMII::DPRSoRegS || IsDataProcessing2) { - Value |= 1 << ARMII::S_BitShift; - IsDataProcessing3 = !IsDataProcessing2; - } - - IsDataProcessing3 = Format == ARMII::DPRIm || - Format == ARMII::DPRReg || - Format == ARMII::DPRSoReg || - IsDataProcessing3; - - // set first operand - op = getMachineOpValue(MI,0); - if (IsDataProcessing1 || IsDataProcessing3) { - Value |= op << ARMII::RegRdShift; - } else if (IsDataProcessing2) { - Value |= op << ARMII::RegRnShift; - } - // set second operand of data processing #3 instructions - if (IsDataProcessing3) { - op = getMachineOpValue(MI,1); - Value |= op << ARMII::RegRnShift; - } + // FIXME: Clean up this part. + // Data processing operand instructions has 3 possible encodings (for more + // information, see ARM-ARM page A3-10): + // 1. , + // 2. , + // 3. ,, + bool IsDataProcessing1 = Format == ARMII::DPRdIm || + Format == ARMII::DPRdReg || + Format == ARMII::DPRdSoReg; + bool IsDataProcessing2 = Format == ARMII::DPRnIm || + Format == ARMII::DPRnReg || + Format == ARMII::DPRnSoReg; + bool IsDataProcessing3 = false; + + if (Format == ARMII::DPRImS || Format == ARMII::DPRRegS || + Format == ARMII::DPRSoRegS || IsDataProcessing2) + IsDataProcessing3 = !IsDataProcessing2; + + IsDataProcessing3 = Format == ARMII::DPRIm || + Format == ARMII::DPRReg || + Format == ARMII::DPRSoReg || + IsDataProcessing3; + + // Set first operand + if (IsDataProcessing1 || IsDataProcessing3) { + Binary |= getMachineOpValue(MI, 0) << ARMII::RegRdShift; + } else if (IsDataProcessing2) { + Binary |= getMachineOpValue(MI, 0) << ARMII::RegRnShift; + } - unsigned OperandIndex = IsDataProcessing3 ? 2 : 1; - switch (Format) { - case ARMII::DPRdIm: case ARMII::DPRnIm: - case ARMII::DPRIm: case ARMII::DPRImS: { - // set bit I(25) to identify this is the immediate form of - Value |= 1 << ARMII::I_BitShift; - // set immed_8 field - const MachineOperand &MO = MI.getOperand(OperandIndex); - op = ARM_AM::getSOImmVal(MO.getImm()); - Value |= op; + // Set second operand of data processing #3 instructions + if (IsDataProcessing3) + Binary |= getMachineOpValue(MI, 1) << ARMII::RegRnShift; + unsigned OpIdx = IsDataProcessing3 ? 2 : 1; + switch (Format) { + default: + assert(false && "Unknown operand type!"); + break; + case ARMII::DPRdIm: case ARMII::DPRnIm: + case ARMII::DPRIm: case ARMII::DPRImS: { + // Set bit I(25) to identify this is the immediate form of + Binary |= 1 << ARMII::I_BitShift; + // Set immed_8 field + const MachineOperand &MO = MI.getOperand(OpIdx); + Binary |= ARM_AM::getSOImmVal(MO.getImm()); + break; + } + case ARMII::DPRdReg: case ARMII::DPRnReg: + case ARMII::DPRReg: case ARMII::DPRRegS: { + // Set last operand (register Rm) + Binary |= getMachineOpValue(MI, OpIdx); + break; + } + case ARMII::DPRdSoReg: case ARMII::DPRnSoReg: + case ARMII::DPRSoReg: case ARMII::DPRSoRegS: { + // Set last operand (register Rm) + Binary |= getMachineOpValue(MI, OpIdx); + + const MachineOperand &MO1 = MI.getOperand(OpIdx + 1); + const MachineOperand &MO2 = MI.getOperand(OpIdx + 2); + + // Identify it the instr is in immed or register shifts encoding + bool IsShiftByRegister = MO1.getReg() > 0; + // Set shift operand (bit[6:4]). + // ASR - 101 if it is in register shifts encoding; 100, otherwise. + // LSL - 001 if it is in register shifts encoding; 000, otherwise. + // LSR - 011 if it is in register shifts encoding; 010, otherwise. + // ROR - 111 if it is in register shifts encoding; 110, otherwise. + // RRX - 110 and bit[11:7] clear. + switch (ARM_AM::getSORegShOp(MO2.getImm())) { + default: assert(0 && "Unknown shift opc!"); + case ARM_AM::asr: + if (IsShiftByRegister) + Binary |= 0x5 << 4; + else + Binary |= 0x1 << 6; break; - } - case ARMII::DPRdReg: case ARMII::DPRnReg: - case ARMII::DPRReg: case ARMII::DPRRegS: { - // set last operand (register Rm) - op = getMachineOpValue(MI,OperandIndex); - Value |= op; - + case ARM_AM::lsl: + if (IsShiftByRegister) + Binary |= 0x1 << 4; break; - } - case ARMII::DPRdSoReg: case ARMII::DPRnSoReg: - case ARMII::DPRSoReg: case ARMII::DPRSoRegS: { - // set last operand (register Rm) - op = getMachineOpValue(MI,OperandIndex); - Value |= op; - - const MachineOperand &MO1 = MI.getOperand(OperandIndex + 1); - const MachineOperand &MO2 = MI.getOperand(OperandIndex + 2); - // identify it the instr is in immed or register shifts encoding - bool IsShiftByRegister = MO1.getReg() > 0; - // set shift operand (bit[6:4]). - // ASR - 101 if it is in register shifts encoding; 100, otherwise. - // LSL - 001 if it is in register shifts encoding; 000, otherwise. - // LSR - 011 if it is in register shifts encoding; 010, otherwise. - // ROR - 111 if it is in register shifts encoding; 110, otherwise. - // RRX - 110 and bit[11:7] clear. - switch(ARM_AM::getSORegShOp(MO2.getImm())) { - default: assert(0 && "Unknown shift opc!"); - case ARM_AM::asr: { - if(IsShiftByRegister) - Value |= 0x5 << 4; - else - Value |= 0x1 << 6; - break; - } - case ARM_AM::lsl: { - if(IsShiftByRegister) - Value |= 0x1 << 4; - break; - } - case ARM_AM::lsr: { - if(IsShiftByRegister) - Value |= 0x3 << 4; - else - Value |= 0x1 << 5; - break; - } - case ARM_AM::ror: { - if(IsShiftByRegister) - Value |= 0x7 << 4; - else - Value |= 0x3 << 5; - break; - } - case ARM_AM::rrx: { - Value |= 0x3 << 5; - break; - } - } - // set the field related to shift operations (except rrx). - if (ARM_AM::getSORegShOp(MO2.getImm()) != ARM_AM::rrx) { - if (IsShiftByRegister) { - // set the value of bit[11:8] (register Rs). - assert(TargetRegisterInfo::isPhysicalRegister(MO1.getReg())); - op = ARMRegisterInfo::getRegisterNumbering(MO1.getReg()); - assert(ARM_AM::getSORegOffset(MO2.getImm()) == 0); - Value |= op << ARMII::RegRsShift; - } else { - // set the value of bit [11:7] (shift_immed field). - op = ARM_AM::getSORegOffset(MO2.getImm()); - Value |= op << 7; - } - } + case ARM_AM::lsr: + if (IsShiftByRegister) + Binary |= 0x3 << 4; + else + Binary |= 0x1 << 5; break; - } - default: assert(false && "Unknown operand type!"); + case ARM_AM::ror: + if (IsShiftByRegister) + Binary |= 0x7 << 4; + else + Binary |= 0x3 << 5; + break; + case ARM_AM::rrx: + Binary |= 0x3 << 5; break; } + // Set the field related to shift operations (except rrx). + if (ARM_AM::getSORegShOp(MO2.getImm()) != ARM_AM::rrx) { + if (IsShiftByRegister) { + // Set the value of bit[11:8] (register Rs). + assert(ARM_AM::getSORegOffset(MO2.getImm()) == 0); + Binary |= (ARMRegisterInfo::getRegisterNumbering(MO1.getReg()) << + ARMII::RegRsShift); + } else + // Set the value of bit [11:7] (shift_immed field). + Binary |= ARM_AM::getSORegOffset(MO2.getImm()) << 7; + } break; } - case ARMII::AddrMode2: { - // bit 26 is always 1 - Value |= 1 << 26; - - unsigned Index = Desc.TSFlags & ARMII::IndexModeMask; - // if the instruction uses offset addressing or pre-indexed addressing, - // set bit P(24) to 1 - if (Index == ARMII::IndexModePre || Index == 0) - Value |= 1 << ARMII::IndexShift; - // if the instruction uses post-indexed addressing, set bit W(21) to 1 - if (Index == ARMII::IndexModePre) - Value |= 1 << 21; - - unsigned Format = Desc.TSFlags & ARMII::FormMask; - // If it is a load instruction (except LDRD), set bit L(20) to 1 - if (Format == ARMII::LdFrm) - Value |= 1 << ARMII::L_BitShift; - - // set bit B(22) - unsigned BitByte = getBaseOpcodeFor(Desc); - Value |= BitByte << 22; - - // set first operand - op = getMachineOpValue(MI,0); - Value |= op << ARMII::RegRdShift; - - // set second operand - op = getMachineOpValue(MI,1); - Value |= op << ARMII::RegRnShift; - - const MachineOperand &MO2 = MI.getOperand(2); - const MachineOperand &MO3 = MI.getOperand(3); - - // set bit U(23) according to signal of immed value (positive or negative) - Value |= (ARM_AM::getAM2Op(MO3.getImm()) == ARM_AM::add ? 1 : 0) << - ARMII::U_BitShift; - if (!MO2.getReg()) { // is immediate - if (ARM_AM::getAM2Offset(MO3.getImm())) - // set the value of offset_12 field - Value |= ARM_AM::getAM2Offset(MO3.getImm()); - break; - } + } - // set bit I(25), because this is not in immediate enconding. - Value |= 1 << ARMII::I_BitShift; - assert(TargetRegisterInfo::isPhysicalRegister(MO2.getReg())); - // set bit[3:0] to the corresponding Rm register - Value |= ARMRegisterInfo::getRegisterNumbering(MO2.getReg()); - - // 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(MO3.getImm())) { - unsigned ShiftOp = getShiftOp(MO3); - Value |= ShiftOp << 5; // shift - Value |= ShImm << 7; // shift_immed - } + return Binary; +} - break; +unsigned ARMCodeEmitter::getAddrMode2InstrBinary(const MachineInstr &MI, + const TargetInstrDesc &Desc, + unsigned Binary) { + // Set first operand + Binary |= getMachineOpValue(MI, 0) << ARMII::RegRdShift; + + // Set second operand + Binary |= getMachineOpValue(MI, 1) << ARMII::RegRnShift; + + const MachineOperand &MO2 = MI.getOperand(2); + const MachineOperand &MO3 = MI.getOperand(3); + + // Set bit U(23) according to signal of immed value (positive or negative). + Binary |= ((ARM_AM::getAM2Op(MO3.getImm()) == ARM_AM::add ? 1 : 0) << + ARMII::U_BitShift); + if (!MO2.getReg()) { // is immediate + if (ARM_AM::getAM2Offset(MO3.getImm())) + // Set the value of offset_12 field + Binary |= ARM_AM::getAM2Offset(MO3.getImm()); + return Binary; } - case ARMII::AddrMode3: { - unsigned Index = Desc.TSFlags & ARMII::IndexModeMask; - // if the instruction uses offset addressing or pre-indexed addressing, - // set bit P(24) to 1 - if (Index == ARMII::IndexModePre || Index == 0) - Value |= 1 << ARMII::IndexShift; - - unsigned Format = Desc.TSFlags & ARMII::FormMask; - // If it is a load instruction (except LDRD), set bit L(20) to 1 - if (Format == ARMII::LdFrm && opcode != ARM::LDRD) - Value |= 1 << ARMII::L_BitShift; - - // bit[7:4] is the opcode of this instruction class (bits S and H). - unsigned char BaseOpcode = getBaseOpcodeFor(Desc); - Value |= BaseOpcode << 4; - - // set first operand - op = getMachineOpValue(MI,0); - Value |= op << ARMII::RegRdShift; - - // set second operand - op = getMachineOpValue(MI,1); - Value |= op << ARMII::RegRnShift; - - const MachineOperand &MO2 = MI.getOperand(2); - const MachineOperand &MO3 = MI.getOperand(3); - - // set bit U(23) according to signal of immed value (positive or negative) - Value |= (ARM_AM::getAM2Op(MO3.getImm()) == ARM_AM::add ? 1 : 0) << - ARMII::U_BitShift; - - // if this instr is in register offset/index encoding, set bit[3:0] - // to the corresponding Rm register. - if (MO2.getReg()) { - Value |= ARMRegisterInfo::getRegisterNumbering(MO2.getReg()); - break; - } - // if this instr is in immediate offset/index encoding, set bit 22 to 1 - if (unsigned ImmOffs = ARM_AM::getAM3Offset(MO3.getImm())) { - Value |= 1 << 22; - // set operands - Value |= (ImmOffs >> 4) << 8; // immedH - Value |= (ImmOffs & ~0xF); // immedL - } + // Set bit I(25), because this is not in immediate enconding. + Binary |= 1 << ARMII::I_BitShift; + assert(TargetRegisterInfo::isPhysicalRegister(MO2.getReg())); + // Set bit[3:0] to the corresponding Rm register + Binary |= ARMRegisterInfo::getRegisterNumbering(MO2.getReg()); + + // 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(MO3.getImm())) { + Binary |= getShiftOp(MO3) << 5; // shift + Binary |= ShImm << 7; // shift_immed + } - break; + return Binary; +} + +unsigned ARMCodeEmitter::getAddrMode3InstrBinary(const MachineInstr &MI, + const TargetInstrDesc &Desc, + unsigned Binary) { + // Set first operand + Binary |= getMachineOpValue(MI, 0) << ARMII::RegRdShift; + + // Set second operand + Binary |= getMachineOpValue(MI, 1) << ARMII::RegRnShift; + + const MachineOperand &MO2 = MI.getOperand(2); + const MachineOperand &MO3 = MI.getOperand(3); + + // Set bit U(23) according to signal of immed value (positive or negative) + Binary |= ((ARM_AM::getAM2Op(MO3.getImm()) == ARM_AM::add ? 1 : 0) << + ARMII::U_BitShift); + + // 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()); + return Binary; } - case ARMII::AddrMode4: { - // bit 27 is always 1 - Value |= 1 << 27; - - unsigned Format = Desc.TSFlags & ARMII::FormMask; - // if it is a load instr, set bit L(20) to 1 - if (Format == ARMII::LdFrm) - Value |= 1 << ARMII::L_BitShift; - - unsigned OpIndex = 0; - - // set first operand - op = getMachineOpValue(MI,OpIndex); - Value |= op << ARMII::RegRnShift; - - // set addressing mode by modifying bits U(23) and P(24) - // IA - Increment after - bit U = 1 and bit P = 0 - // IB - Increment before - bit U = 1 and bit P = 1 - // DA - Decrement after - bit U = 0 and bit P = 0 - // DB - Decrement before - bit U = 0 and bit P = 1 - const MachineOperand &MO = MI.getOperand(OpIndex + 1); - ARM_AM::AMSubMode Mode = ARM_AM::getAM4SubMode(MO.getImm()); - switch(Mode) { - default: assert(0 && "Unknown addressing sub-mode!"); - case ARM_AM::ia: Value |= 0x1 << 23; break; - case ARM_AM::ib: Value |= 0x3 << 23; break; - case ARM_AM::da: break; - case ARM_AM::db: Value |= 0x1 << 24; break; - } - // set bit W(21) - if (ARM_AM::getAM4WBFlag(MO.getImm())) - Value |= 0x1 << 21; - - // set registers - for (unsigned i = OpIndex + 4, e = MI.getNumOperands(); i != e; ++i) { - const MachineOperand &MOR = MI.getOperand(i); - unsigned RegNumber = ARMRegisterInfo::getRegisterNumbering(MOR.getReg()); - assert(TargetRegisterInfo::isPhysicalRegister(MOR.getReg()) && - RegNumber < 16); - Value |= 0x1 << RegNumber; - } + // if this instr is in immediate offset/index encoding, set bit 22 to 1 + if (unsigned ImmOffs = ARM_AM::getAM3Offset(MO3.getImm())) { + Binary |= 1 << 22; + // Set operands + Binary |= (ImmOffs >> 4) << 8; // immedH + Binary |= (ImmOffs & ~0xF); // immedL + } - break; + return Binary; +} + +unsigned ARMCodeEmitter::getAddrMode4InstrBinary(const MachineInstr &MI, + const TargetInstrDesc &Desc, + unsigned Binary) { + // Set first operand + Binary |= getMachineOpValue(MI, 0) << ARMII::RegRnShift; + + // Set addressing mode by modifying bits U(23) and P(24) + // IA - Increment after - bit U = 1 and bit P = 0 + // IB - Increment before - bit U = 1 and bit P = 1 + // DA - Decrement after - bit U = 0 and bit P = 0 + // DB - Decrement before - bit U = 0 and bit P = 1 + const MachineOperand &MO = MI.getOperand(1); + ARM_AM::AMSubMode Mode = ARM_AM::getAM4SubMode(MO.getImm()); + switch (Mode) { + default: assert(0 && "Unknown addressing sub-mode!"); + case ARM_AM::da: break; + case ARM_AM::db: Binary |= 0x1 << 24; break; + case ARM_AM::ia: Binary |= 0x1 << 23; break; + case ARM_AM::ib: Binary |= 0x3 << 23; break; } + + // Set bit W(21) + if (ARM_AM::getAM4WBFlag(MO.getImm())) + Binary |= 0x1 << 21; + + // Set registers + for (unsigned i = 4, e = MI.getNumOperands(); i != e; ++i) { + const MachineOperand &MO = MI.getOperand(i); + if (MO.isRegister() && MO.isImplicit()) + continue; + unsigned RegNum = ARMRegisterInfo::getRegisterNumbering(MO.getReg()); + assert(TargetRegisterInfo::isPhysicalRegister(MO.getReg()) && + RegNum < 16); + Binary |= 0x1 << RegNum; + } + + return Binary; +} + +/// getInstrBinary - Return binary encoding for the specified +/// machine instruction. +unsigned ARMCodeEmitter::getInstrBinary(const MachineInstr &MI) { + // Part of binary is determined by TableGn. + unsigned Binary = getBinaryCodeForInstr(MI); + + const TargetInstrDesc &Desc = MI.getDesc(); + switch (Desc.TSFlags & ARMII::AddrModeMask) { + case ARMII::AddrModeNone: + return getAddrModeNoneInstrBinary(MI, Desc, Binary); + case ARMII::AddrMode1: + return getAddrMode1InstrBinary(MI, Desc, Binary); + case ARMII::AddrMode2: + return getAddrMode2InstrBinary(MI, Desc, Binary); + case ARMII::AddrMode3: + return getAddrMode3InstrBinary(MI, Desc, Binary); + case ARMII::AddrMode4: + return getAddrMode4InstrBinary(MI, Desc, Binary); } - return Value; + abort(); + return 0; } + +#include "ARMGenCodeEmitter.inc" -- 2.34.1