diff --git a/lib/MC/ELFObjectWriter.cpp b/lib/MC/ELFObjectWriter.cpp index 549288773bb..4daab49089a 100644 --- a/lib/MC/ELFObjectWriter.cpp +++ b/lib/MC/ELFObjectWriter.cpp @@ -1546,6 +1546,7 @@ unsigned ARMELFObjectWriter::GetRelocType(const MCValue &Target, case ARM::fixup_arm_ldst_pcrel_12: case ARM::fixup_arm_pcrel_10: case ARM::fixup_arm_adr_pcrel_12: + case ARM::fixup_arm_thumb_bl: assert(0 && "Unimplemented"); break; case ARM::fixup_arm_branch: return ELF::R_ARM_CALL; break; diff --git a/lib/Target/ARM/ARMAsmBackend.cpp b/lib/Target/ARM/ARMAsmBackend.cpp index 536923e47bf..7b9e59f9a9d 100644 --- a/lib/Target/ARM/ARMAsmBackend.cpp +++ b/lib/Target/ARM/ARMAsmBackend.cpp @@ -103,7 +103,18 @@ static unsigned adjustFixupValue(unsigned Kind, uint64_t Value) { case ARM::fixup_arm_branch: // These values don't encode the low two bits since they're always zero. // Offset by 8 just as above. - return 0xFFFFFF & ((Value - 8) >> 2); + return 0xffffff & ((Value - 8) >> 2); + case ARM::fixup_arm_thumb_bl: { + // The value doesn't encode the low bit (always zero) and is offset by + // four. The value is encoded into disjoint bit positions in the destination + // opcode. x = unchanged, I = immediate value bit, S = sign extension bit + // xxxxxSIIIIIIIIII xxxxxIIIIIIIIIII + // Note that the halfwords are stored high first, low second; so we need + // to transpose the fixup value here to map properly. + uint32_t Binary = 0x3fffff & ((Value - 4) >> 1); + Binary = ((Binary & 0x7ff) << 16) | (Binary >> 11); + return Binary; + } case ARM::fixup_arm_pcrel_10: { // Offset by 8 just as above. Value = Value - 8; @@ -198,12 +209,17 @@ public: static unsigned getFixupKindNumBytes(unsigned Kind) { switch (Kind) { - default: llvm_unreachable("Unknown fixup kind!"); - case FK_Data_4: return 4; - case ARM::fixup_arm_ldst_pcrel_12: return 3; - case ARM::fixup_arm_pcrel_10: return 3; - case ARM::fixup_arm_adr_pcrel_12: return 3; - case ARM::fixup_arm_branch: return 3; + default: + llvm_unreachable("Unknown fixup kind!"); + case FK_Data_4: + return 4; + case ARM::fixup_arm_ldst_pcrel_12: + case ARM::fixup_arm_pcrel_10: + case ARM::fixup_arm_adr_pcrel_12: + case ARM::fixup_arm_branch: + return 3; + case ARM::fixup_arm_thumb_bl: + return 4; } } diff --git a/lib/Target/ARM/ARMCodeEmitter.cpp b/lib/Target/ARM/ARMCodeEmitter.cpp index e253a865a08..4424f775b10 100644 --- a/lib/Target/ARM/ARMCodeEmitter.cpp +++ b/lib/Target/ARM/ARMCodeEmitter.cpp @@ -171,6 +171,8 @@ namespace { const { return 0; } unsigned getAdrLabelOpValue(const MachineInstr &MI, unsigned Op) const { return 0; } + unsigned getThumbBLTargetOpValue(const MachineInstr &MI, unsigned Op) + const { return 0; } unsigned getBranchTargetOpValue(const MachineInstr &MI, unsigned Op) const { return 0; } unsigned getCCOutOpValue(const MachineInstr &MI, unsigned Op) diff --git a/lib/Target/ARM/ARMFixupKinds.h b/lib/Target/ARM/ARMFixupKinds.h index 1ec0ba42435..c905611906f 100644 --- a/lib/Target/ARM/ARMFixupKinds.h +++ b/lib/Target/ARM/ARMFixupKinds.h @@ -25,9 +25,11 @@ enum Fixups { // fixup_arm_adr_pcrel_12 - 12-bit PC relative relocation for the ADR // instruction. fixup_arm_adr_pcrel_12, - // fixup_arm_brnach - 24-bit PC relative relocation for direct branch + // fixup_arm_branch - 24-bit PC relative relocation for direct branch // instructions. fixup_arm_branch, + // fixup_arm_thumb_bl - Fixup for Thumb BL/BLX instructions. + fixup_arm_thumb_bl, // The next two are for the movt/movw pair // the 16bit imm field are split into imm{15-12} and imm{11-0} diff --git a/lib/Target/ARM/ARMInstrThumb.td b/lib/Target/ARM/ARMInstrThumb.td index a8681aef3c8..67f7da64ddf 100644 --- a/lib/Target/ARM/ARMInstrThumb.td +++ b/lib/Target/ARM/ARMInstrThumb.td @@ -74,6 +74,10 @@ def t_imm_s4 : Operand { // Define Thumb specific addressing modes. +def t_bltarget : Operand { + let EncoderMethod = "getThumbBLTargetOpValue"; +} + def MemModeThumbAsmOperand : AsmOperandClass { let Name = "MemModeThumb"; let SuperClasses = []; @@ -366,22 +370,29 @@ let isCall = 1, Uses = [SP] in { // Also used for Thumb2 def tBL : TIx2<0b11110, 0b11, 1, - (outs), (ins i32imm:$func, variable_ops), IIC_Br, + (outs), (ins t_bltarget:$func, variable_ops), IIC_Br, "bl\t$func", [(ARMtcall tglobaladdr:$func)]>, Requires<[IsThumb, IsNotDarwin]> { + bits<21> func; + let Inst{25-16} = func{20-11}; let Inst{13} = 1; let Inst{11} = 1; + let Inst{10-0} = func{10-0}; } // ARMv5T and above, also used for Thumb2 def tBLXi : TIx2<0b11110, 0b11, 0, - (outs), (ins i32imm:$func, variable_ops), IIC_Br, + (outs), (ins t_bltarget:$func, variable_ops), IIC_Br, "blx\t$func", [(ARMcall tglobaladdr:$func)]>, Requires<[IsThumb, HasV5T, IsNotDarwin]> { + bits<21> func; + let Inst{25-16} = func{20-11}; let Inst{13} = 1; let Inst{11} = 1; + let Inst{10-1} = func{10-1}; + let Inst{0} = 0; // func{0} is assumed zero } // Also used for Thumb2 @@ -412,23 +423,29 @@ let isCall = 1, Uses = [R7, SP] in { // Also used for Thumb2 def tBLr9 : TIx2<0b11110, 0b11, 1, - (outs), (ins pred:$p, i32imm:$func, variable_ops), IIC_Br, - "bl${p}\t$func", + (outs), (ins pred:$p, t_bltarget:$func, variable_ops), + IIC_Br, "bl${p}\t$func", [(ARMtcall tglobaladdr:$func)]>, Requires<[IsThumb, IsDarwin]> { - let Inst{13} = 1; - let Inst{11} = 1; + bits<21> func; + let Inst{25-16} = func{20-11}; + let Inst{13} = 1; + let Inst{11} = 1; + let Inst{10-0} = func{10-0}; } // ARMv5T and above, also used for Thumb2 def tBLXi_r9 : TIx2<0b11110, 0b11, 0, - (outs), (ins pred:$p, i32imm:$func, variable_ops), - IIC_Br, - "blx${p}\t$func", + (outs), (ins pred:$p, t_bltarget:$func, variable_ops), + IIC_Br, "blx${p}\t$func", [(ARMcall tglobaladdr:$func)]>, Requires<[IsThumb, HasV5T, IsDarwin]> { + bits<21> func; + let Inst{25-16} = func{20-11}; let Inst{13} = 1; let Inst{11} = 1; + let Inst{10-1} = func{10-1}; + let Inst{0} = 0; // func{0} is assumed zero } // Also used for Thumb2 diff --git a/lib/Target/ARM/ARMMCCodeEmitter.cpp b/lib/Target/ARM/ARMMCCodeEmitter.cpp index bdac5adf4cd..b8939a1531c 100644 --- a/lib/Target/ARM/ARMMCCodeEmitter.cpp +++ b/lib/Target/ARM/ARMMCCodeEmitter.cpp @@ -50,6 +50,7 @@ public: { "fixup_arm_pcrel_10", 1, 24, MCFixupKindInfo::FKF_IsPCRel }, { "fixup_arm_adr_pcrel_12", 1, 24, MCFixupKindInfo::FKF_IsPCRel }, { "fixup_arm_branch", 1, 24, MCFixupKindInfo::FKF_IsPCRel }, + { "fixup_arm_thumb_bl", 0, 32, MCFixupKindInfo::FKF_IsPCRel }, { "fixup_arm_movt_hi16", 0, 16, 0 }, { "fixup_arm_movw_lo16", 0, 16, 0 }, }; @@ -81,6 +82,11 @@ public: unsigned &Reg, unsigned &Imm, SmallVectorImpl &Fixups) const; + /// getThumbBLTargetOpValue - Return encoding info for Thumb immediate + /// branch target. + uint32_t getThumbBLTargetOpValue(const MCInst &MI, unsigned OpIdx, + SmallVectorImpl &Fixups) const; + /// getBranchTargetOpValue - Return encoding info for 24-bit immediate /// branch target. uint32_t getBranchTargetOpValue(const MCInst &MI, unsigned OpIdx, @@ -395,6 +401,24 @@ EncodeAddrModeOpValues(const MCInst &MI, unsigned OpIdx, unsigned &Reg, return isAdd; } +/// getThumbBLTargetOpValue - Return encoding info for immediate +/// branch target. +uint32_t ARMMCCodeEmitter:: +getThumbBLTargetOpValue(const MCInst &MI, unsigned OpIdx, + SmallVectorImpl &Fixups) const { + const MCOperand &MO = MI.getOperand(OpIdx); + + // If the destination is an immediate, we have nothing to do. + if (MO.isImm()) return MO.getImm(); + assert (MO.isExpr() && "Unexpected branch target type!"); + const MCExpr *Expr = MO.getExpr(); + MCFixupKind Kind = MCFixupKind(ARM::fixup_arm_thumb_bl); + Fixups.push_back(MCFixup::Create(0, Expr, Kind)); + + // All of the information is in the fixup. + return 0; +} + /// getBranchTargetOpValue - Return encoding info for 24-bit immediate /// branch target. uint32_t ARMMCCodeEmitter:: diff --git a/utils/TableGen/EDEmitter.cpp b/utils/TableGen/EDEmitter.cpp index f3056e05317..68568c8df54 100644 --- a/utils/TableGen/EDEmitter.cpp +++ b/utils/TableGen/EDEmitter.cpp @@ -587,6 +587,7 @@ static int ARMFlagFromOpName(LiteralConstantEmitter *type, IMM("neon_vcvt_imm32"); MISC("brtarget", "kOperandTypeARMBranchTarget"); // ? + MISC("t_bltarget", "kOperandTypeARMBranchTarget"); // ? MISC("bltarget", "kOperandTypeARMBranchTarget"); // ? MISC("so_reg", "kOperandTypeARMSoReg"); // R, R, I MISC("shift_so_reg", "kOperandTypeARMSoReg"); // R, R, I