diff --git a/lib/Target/ARM/ARMCodeEmitter.cpp b/lib/Target/ARM/ARMCodeEmitter.cpp index f786df97b8a..026727607e6 100644 --- a/lib/Target/ARM/ARMCodeEmitter.cpp +++ b/lib/Target/ARM/ARMCodeEmitter.cpp @@ -28,10 +28,14 @@ #include "llvm/CodeGen/MachineConstantPool.h" #include "llvm/CodeGen/MachineFunctionPass.h" #include "llvm/CodeGen/MachineInstr.h" +#include "llvm/CodeGen/MachineJumpTableInfo.h" #include "llvm/CodeGen/Passes.h" #include "llvm/ADT/Statistic.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/Debug.h" +#ifndef NDEBUG +#include +#endif using namespace llvm; STATISTIC(NumEmitted, "Number of machine instructions emitted"); @@ -44,16 +48,20 @@ namespace { TargetMachine &TM; MachineCodeEmitter &MCE; const std::vector *MCPEs; - + const std::vector *MJTEs; + bool IsPIC; + public: static char ID; explicit ARMCodeEmitter(TargetMachine &tm, MachineCodeEmitter &mce) : MachineFunctionPass(&ID), JTI(0), II(0), TD(0), TM(tm), - MCE(mce), MCPEs(0) {} + 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) {} + MCE(mce), MCPEs(0), MJTEs(0), + IsPIC(TM.getRelocationModel() == Reloc::PIC_) {} bool runOnMachineFunction(MachineFunction &MF); @@ -71,6 +79,8 @@ namespace { void emitMOVi2piecesInstruction(const MachineInstr &MI); + void emitLEApcrelJTInstruction(const MachineInstr &MI); + void addPCLabel(unsigned LabelID); void emitPseudoInstruction(const MachineInstr &MI); @@ -89,6 +99,7 @@ namespace { unsigned ImplicitRn = 0); void emitLoadStoreInstruction(const MachineInstr &MI, + unsigned ImplicitRd = 0, unsigned ImplicitRn = 0); void emitMiscLoadStoreInstruction(const MachineInstr &MI, @@ -104,6 +115,8 @@ namespace { void emitBranchInstruction(const MachineInstr &MI); + void emitInlineJumpTable(unsigned JTIndex, intptr_t JTBase); + void emitMiscBranchInstruction(const MachineInstr &MI); /// getBinaryCodeForInstr - This function, generated by the @@ -133,7 +146,7 @@ namespace { void emitJumpTableAddress(unsigned JTIndex, unsigned Reloc, unsigned PCAdj = 0); void emitGlobalConstant(const Constant *CV); - void emitMachineBasicBlock(MachineBasicBlock *BB); + void emitMachineBasicBlock(MachineBasicBlock *BB, unsigned Reloc); }; char ARMCodeEmitter::ID = 0; } @@ -153,7 +166,9 @@ bool ARMCodeEmitter::runOnMachineFunction(MachineFunction &MF) { TD = ((ARMTargetMachine&)MF.getTarget()).getTargetData(); JTI = ((ARMTargetMachine&)MF.getTarget()).getJITInfo(); MCPEs = &MF.getConstantPool()->getConstants(); - JTI->Initialize(MCPEs); + MJTEs = &MF.getJumpTableInfo()->getJumpTables(); + IsPIC = TM.getRelocationModel() == Reloc::PIC_; + JTI->Initialize(MF); do { DOUT << "JITTing function '" << MF.getFunction()->getName() << "'\n"; @@ -201,7 +216,7 @@ unsigned ARMCodeEmitter::getMachineOpValue(const MachineInstr &MI, else if (MO.isJTI()) emitJumpTableAddress(MO.getIndex(), ARM::reloc_arm_relative); else if (MO.isMBB()) - emitMachineBasicBlock(MO.getMBB()); + emitMachineBasicBlock(MO.getMBB(), ARM::reloc_arm_branch); else { cerr << "ERROR: Unknown type of MachineOperand: " << MO << "\n"; abort(); @@ -242,17 +257,21 @@ void ARMCodeEmitter::emitConstPoolAddress(unsigned CPI, unsigned Reloc, void ARMCodeEmitter::emitJumpTableAddress(unsigned JTIndex, unsigned Reloc, unsigned PCAdj /* = 0 */) { MCE.addRelocation(MachineRelocation::getJumpTable(MCE.getCurrentPCOffset(), - Reloc, JTIndex, PCAdj)); + Reloc, JTIndex, PCAdj, true)); } /// emitMachineBasicBlock - Emit the specified address basic block. -void ARMCodeEmitter::emitMachineBasicBlock(MachineBasicBlock *BB) { +void ARMCodeEmitter::emitMachineBasicBlock(MachineBasicBlock *BB, + unsigned Reloc) { MCE.addRelocation(MachineRelocation::getBB(MCE.getCurrentPCOffset(), - ARM::reloc_arm_branch, BB)); + Reloc, BB)); } void ARMCodeEmitter::emitWordLE(unsigned Binary) { - DOUT << " " << (void*)Binary << "\n"; +#ifndef NDEBUG + DOUT << " 0x" << std::hex << std::setw(8) << std::setfill('0') + << Binary << std::dec << "\n"; +#endif MCE.emitWordLE(Binary); } @@ -389,6 +408,34 @@ void ARMCodeEmitter::emitMOVi2piecesInstruction(const MachineInstr &MI) { 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. + unsigned Binary = 0x4 << 21; // add: Insts{24-31} = 0b0100 + + // Set the conditional execution predicate + Binary |= II->getPredicate(&MI) << ARMII::CondShift; + + // Encode S bit if MI modifies CPSR. + Binary |= getAddrModeSBit(MI, TID); + + // Encode Rd. + Binary |= getMachineOpValue(MI, 0) << ARMII::RegRdShift; + + // Encode Rn which is PC. + 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::addPCLabel(unsigned LabelID) { DOUT << " ** LPC" << LabelID << " @ " << (void*)MCE.getCurrentPCValue() << '\n'; @@ -417,7 +464,7 @@ void ARMCodeEmitter::emitPseudoInstruction(const MachineInstr &MI) { // Remember of the address of the PC label for relocation later. addPCLabel(MI.getOperand(2).getImm()); // These are just load / store instructions that implicitly read pc. - emitLoadStoreInstruction(MI, ARM::PC); + emitLoadStoreInstruction(MI, 0, ARM::PC); break; } case ARM::PICLDRH: @@ -434,6 +481,10 @@ void ARMCodeEmitter::emitPseudoInstruction(const MachineInstr &MI) { // Two instructions to materialize a constant. emitMOVi2piecesInstruction(MI); break; + case ARM::LEApcrelJT: + // Materialize jumptable address. + emitLEApcrelJTInstruction(MI); + break; } } @@ -569,7 +620,7 @@ void ARMCodeEmitter::emitDataProcessingInstruction(const MachineInstr &MI, } // Encode so_imm. - // Set bit I(25) to identify this is the immediate form of + // Set bit I(25) to identify this is the immediate form of . Binary |= 1 << ARMII::I_BitShift; Binary |= getMachineSoImmOpValue(MO.getImm()); @@ -577,6 +628,7 @@ void ARMCodeEmitter::emitDataProcessingInstruction(const MachineInstr &MI, } void ARMCodeEmitter::emitLoadStoreInstruction(const MachineInstr &MI, + unsigned ImplicitRd, unsigned ImplicitRn) { // Part of binary is determined by TableGn. unsigned Binary = getBinaryCodeForInstr(MI); @@ -585,18 +637,21 @@ void ARMCodeEmitter::emitLoadStoreInstruction(const MachineInstr &MI, Binary |= II->getPredicate(&MI) << ARMII::CondShift; // Set first operand - Binary |= getMachineOpValue(MI, 0) << ARMII::RegRdShift; + unsigned OpIdx = 0; + if (ImplicitRd) + // Special handling for implicit use (e.g. PC). + Binary |= (ARMRegisterInfo::getRegisterNumbering(ImplicitRd) + << ARMII::RegRdShift); + else + Binary |= getMachineOpValue(MI, OpIdx++) << ARMII::RegRdShift; // Set second operand - unsigned OpIdx = 1; if (ImplicitRn) // Special handling for implicit use (e.g. PC). Binary |= (ARMRegisterInfo::getRegisterNumbering(ImplicitRn) << ARMII::RegRnShift); - else { - Binary |= getMachineOpValue(MI, OpIdx) << ARMII::RegRnShift; - ++OpIdx; - } + else + Binary |= getMachineOpValue(MI, OpIdx++) << ARMII::RegRnShift; const MachineOperand &MO2 = MI.getOperand(OpIdx); unsigned AM2Opc = (ImplicitRn == ARM::PC) @@ -646,10 +701,8 @@ void ARMCodeEmitter::emitMiscLoadStoreInstruction(const MachineInstr &MI, // Special handling for implicit use (e.g. PC). Binary |= (ARMRegisterInfo::getRegisterNumbering(ImplicitRn) << ARMII::RegRnShift); - else { - Binary |= getMachineOpValue(MI, OpIdx) << ARMII::RegRnShift; - ++OpIdx; - } + else + Binary |= getMachineOpValue(MI, OpIdx++) << ARMII::RegRnShift; const MachineOperand &MO2 = MI.getOperand(OpIdx); unsigned AM3Opc = (ImplicitRn == ARM::PC) @@ -851,14 +904,40 @@ void ARMCodeEmitter::emitBranchInstruction(const MachineInstr &MI) { emitWordLE(Binary); } +void ARMCodeEmitter::emitInlineJumpTable(unsigned JTIndex, intptr_t JTBase) { + // Remember the base address of the inline jump table. + JTI->addJumpTableBaseAddr(JTIndex, MCE.getCurrentPCValue()); + + // Now emit the jump table entries. + const std::vector &MBBs = (*MJTEs)[JTIndex].MBBs; + for (unsigned i = 0, e = MBBs.size(); i != e; ++i) { + if (IsPIC) + // DestBB address - JT base. + MCE.addRelocation(MachineRelocation::getBB(JTBase, ARM::reloc_arm_pic_jt, + MBBs[i])); + else + // Absolute DestBB address. + emitMachineBasicBlock(MBBs[i], ARM::reloc_arm_absolute); + emitWordLE(0); + } +} + void ARMCodeEmitter::emitMiscBranchInstruction(const MachineInstr &MI) { const TargetInstrDesc &TID = MI.getDesc(); if (TID.Opcode == ARM::BX || TID.Opcode == ARM::BR_JTr || - TID.Opcode == ARM::BR_JTm || TID.Opcode == ARM::BR_JTadd) abort(); // FIXME + if (TID.Opcode == ARM::BR_JTm) { + // First emit a ldr pc, [] instruction. + emitLoadStoreInstruction(MI, ARM::PC); + + // Then emit the inline jump table. + emitInlineJumpTable(MI.getOperand(3).getIndex(), MCE.getCurrentPCOffset()); + return; + } + // Part of binary is determined by TableGn. unsigned Binary = getBinaryCodeForInstr(MI); diff --git a/lib/Target/ARM/ARMInstrFormats.td b/lib/Target/ARM/ARMInstrFormats.td index 90e27fa94d8..9fe56d79d26 100644 --- a/lib/Target/ARM/ARMInstrFormats.td +++ b/lib/Target/ARM/ARMInstrFormats.td @@ -151,33 +151,9 @@ class ABXIx2 pattern> "", pattern>; // BR_JT instructions -// == mov pc -class JTI opcod, dag oops, dag iops, string asm, list pattern> +class JTI pattern> : XI { - let Inst{20} = 0; // S Bit - let Inst{24-21} = opcod; - let Inst{27-26} = {0,0}; -} -// == add pc -class JTI1 opcod, dag oops, dag iops, string asm, list pattern> - : XI { - let Inst{20} = 0; // S bit - let Inst{24-21} = opcod; - let Inst{27-26} = {0,0}; -} -// == ldr pc -class JTI2 opcod, dag oops, dag iops, string asm, list pattern> - : XI { - let Inst{20} = 1; // L bit - let Inst{21} = 0; // W bit - let Inst{22} = 0; // B bit - let Inst{24} = 1; // P bit - let Inst{27-26} = {0,1}; -} - + asm, "", pattern>; // addrmode1 instructions class AI1 opcod, dag oops, dag iops, Format f, string opc, diff --git a/lib/Target/ARM/ARMInstrInfo.td b/lib/Target/ARM/ARMInstrInfo.td index 45cee486d8e..b4677f09bc3 100644 --- a/lib/Target/ARM/ARMInstrInfo.td +++ b/lib/Target/ARM/ARMInstrInfo.td @@ -572,23 +572,35 @@ let isBranch = 1, isTerminator = 1 in { [(br bb:$target)]>; let isNotDuplicable = 1, isIndirectBranch = 1 in { - def BR_JTr : JTI<0b1101, (outs), - (ins GPR:$target, jtblock_operand:$jt, i32imm:$id), + def BR_JTr : JTI<(outs), (ins GPR:$target, jtblock_operand:$jt, i32imm:$id), "mov pc, $target \n$jt", - [(ARMbrjt GPR:$target, tjumptable:$jt, imm:$id)]>; - def BR_JTm : JTI2<0, (outs), - (ins addrmode2:$target, jtblock_operand:$jt, i32imm:$id), - "ldr pc, $target \n$jt", - [(ARMbrjt (i32 (load addrmode2:$target)), tjumptable:$jt, - imm:$id)]>; - def BR_JTadd : JTI1<0b0100, (outs), - (ins GPR:$target, GPR:$idx, jtblock_operand:$jt, - i32imm:$id), - "add pc, $target, $idx \n$jt", - [(ARMbrjt (add GPR:$target, GPR:$idx), tjumptable:$jt, - imm:$id)]>; + [(ARMbrjt GPR:$target, tjumptable:$jt, imm:$id)]> { + let Inst{20} = 0; // S Bit + let Inst{24-21} = 0b1101; + let Inst{27-26} = {0,0}; } + def BR_JTm : JTI<(outs), + (ins addrmode2:$target, jtblock_operand:$jt, i32imm:$id), + "ldr pc, $target \n$jt", + [(ARMbrjt (i32 (load addrmode2:$target)), tjumptable:$jt, + imm:$id)]> { + let Inst{20} = 1; // L bit + let Inst{21} = 0; // W bit + let Inst{22} = 0; // B bit + let Inst{24} = 1; // P bit + let Inst{27-26} = {0,1}; } + def BR_JTadd : JTI<(outs), + (ins GPR:$target, GPR:$idx, jtblock_operand:$jt, i32imm:$id), + "add pc, $target, $idx \n$jt", + [(ARMbrjt (add GPR:$target, GPR:$idx), tjumptable:$jt, + imm:$id)]> { + let Inst{20} = 0; // S bit + let Inst{24-21} = 0b0100; + let Inst{27-26} = {0,0}; + } + } // isNotDuplicable = 1, isIndirectBranch = 1 + } // isBarrier = 1 // FIXME: should be able to write a pattern for ARMBrcond, but can't use // a two-value operand where a dag node expects two operands. :( diff --git a/lib/Target/ARM/ARMJITInfo.cpp b/lib/Target/ARM/ARMJITInfo.cpp index c57477baf4d..96918fd3259 100644 --- a/lib/Target/ARM/ARMJITInfo.cpp +++ b/lib/Target/ARM/ARMJITInfo.cpp @@ -168,9 +168,11 @@ void *ARMJITInfo::emitFunctionStub(const Function* F, void *Fn, return MCE.finishFunctionStub(F); } -intptr_t ARMJITInfo::resolveRelocationAddr(MachineRelocation *MR) const { +intptr_t ARMJITInfo::resolveRelocDestAddr(MachineRelocation *MR) const { ARM::RelocationType RT = (ARM::RelocationType)MR->getRelocationType(); - if (RT == ARM::reloc_arm_cp_entry) + if (RT == ARM::reloc_arm_jt_base) + return getJumpTableBaseAddr(MR->getJumpTableIndex()); + else if (RT == ARM::reloc_arm_cp_entry) return getConstantPoolEntryAddr(MR->getConstantPoolIndex()); else if (RT == ARM::reloc_arm_machine_cp_entry) { const MachineConstantPoolEntry &MCPE = (*MCPEs)[MR->getConstantVal()]; @@ -196,7 +198,7 @@ void ARMJITInfo::relocate(void *Function, MachineRelocation *MR, void *RelocPos = (char*)Function + MR->getMachineCodeOffset(); // If this is a constpool relocation, get the address of the // constpool_entry instruction. - intptr_t ResultPtr = resolveRelocationAddr(MR); + intptr_t ResultPtr = resolveRelocDestAddr(MR); switch ((ARM::RelocationType)MR->getRelocationType()) { case ARM::reloc_arm_cp_entry: case ARM::reloc_arm_relative: { @@ -221,7 +223,7 @@ void ARMJITInfo::relocate(void *Function, MachineRelocation *MR, case ARM::reloc_arm_machine_cp_entry: case ARM::reloc_arm_absolute: { // These addresses have already been resolved. - *((unsigned*)RelocPos) += (unsigned)ResultPtr; + *((unsigned*)RelocPos) |= (unsigned)ResultPtr; break; } case ARM::reloc_arm_branch: { @@ -230,12 +232,24 @@ void ARMJITInfo::relocate(void *Function, MachineRelocation *MR, // byte offset, which must be inside the range -33554432 and +33554428. // Then, we set the signed_immed_24 field of the instruction to bits // [25:2] of the byte offset. More details ARM-ARM p. A4-11. - ResultPtr = ResultPtr-(intptr_t)RelocPos-8; + ResultPtr = ResultPtr - (intptr_t)RelocPos - 8; ResultPtr = (ResultPtr & 0x03FFFFFC) >> 2; assert(ResultPtr >= -33554432 && ResultPtr <= 33554428); *((unsigned*)RelocPos) |= ResultPtr; break; } + case ARM::reloc_arm_jt_base: { + // JT base - (instruction addr + 8) + ResultPtr = ResultPtr - (intptr_t)RelocPos - 8; + *((unsigned*)RelocPos) |= ResultPtr; + break; + } + case ARM::reloc_arm_pic_jt: { + // PIC JT entry is destination - JT base. + ResultPtr = ResultPtr - (intptr_t)RelocPos; + *((unsigned*)RelocPos) |= ResultPtr; + break; + } } } } diff --git a/lib/Target/ARM/ARMJITInfo.h b/lib/Target/ARM/ARMJITInfo.h index 2a3a7f8f37c..4b94f3ef795 100644 --- a/lib/Target/ARM/ARMJITInfo.h +++ b/lib/Target/ARM/ARMJITInfo.h @@ -16,6 +16,8 @@ #include "llvm/Target/TargetJITInfo.h" #include "llvm/CodeGen/MachineConstantPool.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineJumpTableInfo.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallVector.h" @@ -31,7 +33,11 @@ namespace llvm { // ConstPoolId2AddrMap - A map from constant pool ids to the corresponding // CONSTPOOL_ENTRY addresses. - SmallVector ConstPoolId2AddrMap; + SmallVector ConstPoolId2AddrMap; + + // JumpTableId2AddrMap - A map from inline jumptable ids to the + // corresponding inline jump table bases. + SmallVector JumpTableId2AddrMap; // PCLabelMap - A map from PC labels to addresses. DenseMap PCLabelMap; @@ -65,6 +71,10 @@ namespace llvm { /// pool address resolution is handled by the target. virtual bool hasCustomConstantPool() const { return true; } + /// hasCustomJumpTables - Allows a target to specify that jumptables + /// are emitted by the target. + virtual bool hasCustomJumpTables() const { return true; } + /// allocateSeparateGVMemory - If true, globals should be placed in /// separately allocated heap memory rather than in the same /// code memory allocated by MachineCodeEmitter. @@ -78,20 +88,21 @@ namespace llvm { /// Initialize - Initialize internal stage. Get the list of constant pool /// Resize constant pool ids to CONSTPOOL_ENTRY addresses map. - void Initialize(const std::vector *mcpes) { - MCPEs = mcpes; + void Initialize(const MachineFunction &MF) { + MCPEs = &MF.getConstantPool()->getConstants(); ConstPoolId2AddrMap.resize(MCPEs->size()); + JumpTableId2AddrMap.resize(MF.getJumpTableInfo()->getJumpTables().size()); } /// getConstantPoolEntryAddr - The ARM target puts all constant - /// pool entries into constant islands. Resolve the constant pool index - /// into the address where the constant is stored. + /// pool entries into constant islands. This returns the address of the + /// constant pool entry of the specified index. intptr_t getConstantPoolEntryAddr(unsigned CPI) const { assert(CPI < ConstPoolId2AddrMap.size()); return ConstPoolId2AddrMap[CPI]; } - /// addConstantPoolEntryAddr - Map a Constant Pool Index (CPI) to the address + /// addConstantPoolEntryAddr - Map a Constant Pool Index to the address /// where its associated value is stored. When relocations are processed, /// this value will be used to resolve references to the constant. void addConstantPoolEntryAddr(unsigned CPI, intptr_t Addr) { @@ -99,6 +110,23 @@ namespace llvm { ConstPoolId2AddrMap[CPI] = Addr; } + /// getJumpTableBaseAddr - The ARM target inline all jump tables within + /// text section of the function. This returns the address of the base of + /// the jump table of the specified index. + intptr_t getJumpTableBaseAddr(unsigned JTI) const { + assert(JTI < JumpTableId2AddrMap.size()); + return JumpTableId2AddrMap[JTI]; + } + + /// addJumpTableBaseAddr - Map a jump table index to the address where + /// the corresponding inline jump table is emitted. When relocations are + /// processed, this value will be used to resolve references to the + /// jump table. + void addJumpTableBaseAddr(unsigned JTI, intptr_t Addr) { + assert(JTI < JumpTableId2AddrMap.size()); + JumpTableId2AddrMap[JTI] = Addr; + } + /// getPCLabelAddr - Retrieve the address of the PC label of the specified id. intptr_t getPCLabelAddr(unsigned Id) const { DenseMap::const_iterator I = PCLabelMap.find(Id); @@ -112,10 +140,10 @@ namespace llvm { } private: - /// resolveRelocationAddr - Resolve the resulting address of the relocation + /// resolveRelocDestAddr - Resolve the resulting address of the relocation /// if it's not already solved. Constantpool entries must be resolved by /// ARM target. - intptr_t resolveRelocationAddr(MachineRelocation *MR) const; + intptr_t resolveRelocDestAddr(MachineRelocation *MR) const; }; } diff --git a/lib/Target/ARM/ARMRelocations.h b/lib/Target/ARM/ARMRelocations.h index 2c1a98990a2..8424386916d 100644 --- a/lib/Target/ARM/ARMRelocations.h +++ b/lib/Target/ARM/ARMRelocations.h @@ -35,6 +35,13 @@ namespace llvm { // entry. reloc_arm_machine_cp_entry, + // reloc_arm_jt_base - PC relative relocation for jump tables whose + // addresses are kept locally in a map. + reloc_arm_jt_base, + + // reloc_arm_pic_jt - PIC jump table entry relocation: dest bb - jt base. + reloc_arm_pic_jt, + // reloc_arm_branch - Branch address relocation. reloc_arm_branch };