mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-07-27 12:26:08 +00:00
Teach ARM/MC/ELF to handle R_ARM_JUMP24 relocation type for conditional jumps.
(yes, this is different from R_ARM_CALL) - Adds a new method getARMBranchTargetOpValue() which handles the necessary distinction between the conditional and unconditional br/bl needed for ARM/ELF At least for ARM mode, the needed fixup for conditional versus unconditional br/bl is identical, but the ARM docs and existing ARM tools expect this reloc type... Added a few FIXME's for future naming fixups in ARMInstrInfo.td git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@124895 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
@@ -1503,7 +1503,7 @@ unsigned ARMELFObjectWriter::GetRelocType(const MCValue &Target,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ARM::fixup_arm_branch:
|
case ARM::fixup_arm_uncondbranch:
|
||||||
switch (Modifier) {
|
switch (Modifier) {
|
||||||
case MCSymbolRefExpr::VK_ARM_PLT:
|
case MCSymbolRefExpr::VK_ARM_PLT:
|
||||||
Type = ELF::R_ARM_PLT32;
|
Type = ELF::R_ARM_PLT32;
|
||||||
@@ -1513,6 +1513,9 @@ unsigned ARMELFObjectWriter::GetRelocType(const MCValue &Target,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case ARM::fixup_arm_condbranch:
|
||||||
|
Type = ELF::R_ARM_JUMP24;
|
||||||
|
break;
|
||||||
case ARM::fixup_arm_movt_hi16:
|
case ARM::fixup_arm_movt_hi16:
|
||||||
case ARM::fixup_arm_movt_hi16_pcrel:
|
case ARM::fixup_arm_movt_hi16_pcrel:
|
||||||
Type = ELF::R_ARM_MOVT_PREL;
|
Type = ELF::R_ARM_MOVT_PREL;
|
||||||
@@ -1565,11 +1568,12 @@ unsigned ARMELFObjectWriter::GetRelocType(const MCValue &Target,
|
|||||||
case ARM::fixup_arm_thumb_br:
|
case ARM::fixup_arm_thumb_br:
|
||||||
assert(0 && "Unimplemented");
|
assert(0 && "Unimplemented");
|
||||||
break;
|
break;
|
||||||
case ARM::fixup_arm_branch:
|
case ARM::fixup_arm_uncondbranch:
|
||||||
// FIXME: Differentiate between R_ARM_CALL and
|
|
||||||
// R_ARM_JUMP24 (latter used for conditional jumps)
|
|
||||||
Type = ELF::R_ARM_CALL;
|
Type = ELF::R_ARM_CALL;
|
||||||
break;
|
break;
|
||||||
|
case ARM::fixup_arm_condbranch:
|
||||||
|
Type = ELF::R_ARM_JUMP24;
|
||||||
|
break;
|
||||||
case ARM::fixup_arm_movt_hi16:
|
case ARM::fixup_arm_movt_hi16:
|
||||||
Type = ELF::R_ARM_MOVT_ABS;
|
Type = ELF::R_ARM_MOVT_ABS;
|
||||||
break;
|
break;
|
||||||
|
@@ -940,7 +940,8 @@ public:
|
|||||||
case ARM::fixup_arm_ldst_pcrel_12:
|
case ARM::fixup_arm_ldst_pcrel_12:
|
||||||
case ARM::fixup_arm_pcrel_10:
|
case ARM::fixup_arm_pcrel_10:
|
||||||
case ARM::fixup_arm_adr_pcrel_12:
|
case ARM::fixup_arm_adr_pcrel_12:
|
||||||
case ARM::fixup_arm_branch:
|
case ARM::fixup_arm_condbranch:
|
||||||
|
case ARM::fixup_arm_uncondbranch:
|
||||||
RelocType = unsigned(macho::RIT_ARM_Branch24Bit);
|
RelocType = unsigned(macho::RIT_ARM_Branch24Bit);
|
||||||
// Report as 'long', even though that is not quite accurate.
|
// Report as 'long', even though that is not quite accurate.
|
||||||
Log2Size = llvm::Log2_32(4);
|
Log2Size = llvm::Log2_32(4);
|
||||||
|
@@ -67,7 +67,8 @@ public:
|
|||||||
{ "fixup_arm_adr_pcrel_12", 1, 24, MCFixupKindInfo::FKF_IsPCRel },
|
{ "fixup_arm_adr_pcrel_12", 1, 24, MCFixupKindInfo::FKF_IsPCRel },
|
||||||
{ "fixup_t2_adr_pcrel_12", 0, 32, MCFixupKindInfo::FKF_IsPCRel |
|
{ "fixup_t2_adr_pcrel_12", 0, 32, MCFixupKindInfo::FKF_IsPCRel |
|
||||||
MCFixupKindInfo::FKF_IsAlignedDownTo32Bits},
|
MCFixupKindInfo::FKF_IsAlignedDownTo32Bits},
|
||||||
{ "fixup_arm_branch", 0, 24, MCFixupKindInfo::FKF_IsPCRel },
|
{ "fixup_arm_condbranch", 0, 24, MCFixupKindInfo::FKF_IsPCRel },
|
||||||
|
{ "fixup_arm_uncondbranch", 0, 24, MCFixupKindInfo::FKF_IsPCRel },
|
||||||
{ "fixup_t2_condbranch", 0, 32, MCFixupKindInfo::FKF_IsPCRel },
|
{ "fixup_t2_condbranch", 0, 32, MCFixupKindInfo::FKF_IsPCRel },
|
||||||
{ "fixup_t2_uncondbranch", 0, 32, MCFixupKindInfo::FKF_IsPCRel },
|
{ "fixup_t2_uncondbranch", 0, 32, MCFixupKindInfo::FKF_IsPCRel },
|
||||||
{ "fixup_arm_thumb_br", 0, 16, MCFixupKindInfo::FKF_IsPCRel },
|
{ "fixup_arm_thumb_br", 0, 16, MCFixupKindInfo::FKF_IsPCRel },
|
||||||
@@ -254,7 +255,8 @@ static unsigned adjustFixupValue(unsigned Kind, uint64_t Value) {
|
|||||||
return swapped;
|
return swapped;
|
||||||
}
|
}
|
||||||
|
|
||||||
case ARM::fixup_arm_branch:
|
case ARM::fixup_arm_condbranch:
|
||||||
|
case ARM::fixup_arm_uncondbranch:
|
||||||
// These values don't encode the low two bits since they're always zero.
|
// These values don't encode the low two bits since they're always zero.
|
||||||
// Offset by 8 just as above.
|
// Offset by 8 just as above.
|
||||||
return 0xffffff & ((Value - 8) >> 2);
|
return 0xffffff & ((Value - 8) >> 2);
|
||||||
@@ -454,7 +456,8 @@ static unsigned getFixupKindNumBytes(unsigned Kind) {
|
|||||||
case ARM::fixup_arm_ldst_pcrel_12:
|
case ARM::fixup_arm_ldst_pcrel_12:
|
||||||
case ARM::fixup_arm_pcrel_10:
|
case ARM::fixup_arm_pcrel_10:
|
||||||
case ARM::fixup_arm_adr_pcrel_12:
|
case ARM::fixup_arm_adr_pcrel_12:
|
||||||
case ARM::fixup_arm_branch:
|
case ARM::fixup_arm_condbranch:
|
||||||
|
case ARM::fixup_arm_uncondbranch:
|
||||||
return 3;
|
return 3;
|
||||||
|
|
||||||
case FK_Data_4:
|
case FK_Data_4:
|
||||||
|
@@ -187,6 +187,8 @@ namespace {
|
|||||||
const { return 0; }
|
const { return 0; }
|
||||||
unsigned getUnconditionalBranchTargetOpValue(const MachineInstr &MI,
|
unsigned getUnconditionalBranchTargetOpValue(const MachineInstr &MI,
|
||||||
unsigned Op) const { return 0; }
|
unsigned Op) const { return 0; }
|
||||||
|
unsigned getARMBranchTargetOpValue(const MachineInstr &MI, unsigned Op)
|
||||||
|
const { return 0; }
|
||||||
unsigned getCCOutOpValue(const MachineInstr &MI, unsigned Op)
|
unsigned getCCOutOpValue(const MachineInstr &MI, unsigned Op)
|
||||||
const { return 0; }
|
const { return 0; }
|
||||||
unsigned getSOImmOpValue(const MachineInstr &MI, unsigned Op)
|
unsigned getSOImmOpValue(const MachineInstr &MI, unsigned Op)
|
||||||
|
@@ -40,9 +40,12 @@ enum Fixups {
|
|||||||
// fixup_t2_adr_pcrel_12 - 12-bit PC relative relocation for the ADR
|
// fixup_t2_adr_pcrel_12 - 12-bit PC relative relocation for the ADR
|
||||||
// instruction.
|
// instruction.
|
||||||
fixup_t2_adr_pcrel_12,
|
fixup_t2_adr_pcrel_12,
|
||||||
// fixup_arm_branch - 24-bit PC relative relocation for direct branch
|
// fixup_arm_condbranch - 24-bit PC relative relocation for conditional branch
|
||||||
// instructions.
|
// instructions.
|
||||||
fixup_arm_branch,
|
fixup_arm_condbranch,
|
||||||
|
// fixup_arm_uncondbranch - 24-bit PC relative relocation for
|
||||||
|
// branch instructions. (unconditional)
|
||||||
|
fixup_arm_uncondbranch,
|
||||||
// fixup_t2_condbranch - 20-bit PC relative relocation for Thumb2 direct
|
// fixup_t2_condbranch - 20-bit PC relative relocation for Thumb2 direct
|
||||||
// uconditional branch instructions.
|
// uconditional branch instructions.
|
||||||
fixup_t2_condbranch,
|
fixup_t2_condbranch,
|
||||||
|
@@ -293,20 +293,36 @@ def fsub_mlx : PatFrag<(ops node:$lhs, node:$rhs),(fsub node:$lhs, node:$rhs),[{
|
|||||||
//
|
//
|
||||||
|
|
||||||
// Branch target.
|
// Branch target.
|
||||||
|
// FIXME: rename brtarget to t2_brtarget
|
||||||
def brtarget : Operand<OtherVT> {
|
def brtarget : Operand<OtherVT> {
|
||||||
let EncoderMethod = "getBranchTargetOpValue";
|
let EncoderMethod = "getBranchTargetOpValue";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME: get rid of this one?
|
||||||
def uncondbrtarget : Operand<OtherVT> {
|
def uncondbrtarget : Operand<OtherVT> {
|
||||||
let EncoderMethod = "getUnconditionalBranchTargetOpValue";
|
let EncoderMethod = "getUnconditionalBranchTargetOpValue";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Branch target for ARM. Handles conditional/unconditional
|
||||||
|
def br_target : Operand<OtherVT> {
|
||||||
|
let EncoderMethod = "getARMBranchTargetOpValue";
|
||||||
|
}
|
||||||
|
|
||||||
// Call target.
|
// Call target.
|
||||||
|
// FIXME: rename bltarget to t2_bl_target?
|
||||||
def bltarget : Operand<i32> {
|
def bltarget : Operand<i32> {
|
||||||
// Encoded the same as branch targets.
|
// Encoded the same as branch targets.
|
||||||
let EncoderMethod = "getBranchTargetOpValue";
|
let EncoderMethod = "getBranchTargetOpValue";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Call target for ARM. Handles conditional/unconditional
|
||||||
|
// FIXME: rename bl_target to t2_bltarget?
|
||||||
|
def bl_target : Operand<i32> {
|
||||||
|
// Encoded the same as branch targets.
|
||||||
|
let EncoderMethod = "getARMBranchTargetOpValue";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// A list of registers separated by comma. Used by load/store multiple.
|
// A list of registers separated by comma. Used by load/store multiple.
|
||||||
def RegListAsmOperand : AsmOperandClass {
|
def RegListAsmOperand : AsmOperandClass {
|
||||||
let Name = "RegList";
|
let Name = "RegList";
|
||||||
@@ -1271,7 +1287,7 @@ let isCall = 1,
|
|||||||
D16, D17, D18, D19, D20, D21, D22, D23,
|
D16, D17, D18, D19, D20, D21, D22, D23,
|
||||||
D24, D25, D26, D27, D28, D29, D30, D31, CPSR, FPSCR],
|
D24, D25, D26, D27, D28, D29, D30, D31, CPSR, FPSCR],
|
||||||
Uses = [SP] in {
|
Uses = [SP] in {
|
||||||
def BL : ABXI<0b1011, (outs), (ins bltarget:$func, variable_ops),
|
def BL : ABXI<0b1011, (outs), (ins bl_target:$func, variable_ops),
|
||||||
IIC_Br, "bl\t$func",
|
IIC_Br, "bl\t$func",
|
||||||
[(ARMcall tglobaladdr:$func)]>,
|
[(ARMcall tglobaladdr:$func)]>,
|
||||||
Requires<[IsARM, IsNotDarwin]> {
|
Requires<[IsARM, IsNotDarwin]> {
|
||||||
@@ -1280,7 +1296,7 @@ let isCall = 1,
|
|||||||
let Inst{23-0} = func;
|
let Inst{23-0} = func;
|
||||||
}
|
}
|
||||||
|
|
||||||
def BL_pred : ABI<0b1011, (outs), (ins bltarget:$func, variable_ops),
|
def BL_pred : ABI<0b1011, (outs), (ins bl_target:$func, variable_ops),
|
||||||
IIC_Br, "bl", "\t$func",
|
IIC_Br, "bl", "\t$func",
|
||||||
[(ARMcall_pred tglobaladdr:$func)]>,
|
[(ARMcall_pred tglobaladdr:$func)]>,
|
||||||
Requires<[IsARM, IsNotDarwin]> {
|
Requires<[IsARM, IsNotDarwin]> {
|
||||||
@@ -1456,7 +1472,7 @@ let isBranch = 1, isTerminator = 1 in {
|
|||||||
|
|
||||||
// FIXME: should be able to write a pattern for ARMBrcond, but can't use
|
// 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. :(
|
// a two-value operand where a dag node expects two operands. :(
|
||||||
def Bcc : ABI<0b1010, (outs), (ins brtarget:$target),
|
def Bcc : ABI<0b1010, (outs), (ins br_target:$target),
|
||||||
IIC_Br, "b", "\t$target",
|
IIC_Br, "b", "\t$target",
|
||||||
[/*(ARMbrcond bb:$target, imm:$cc, CCR:$ccr)*/]> {
|
[/*(ARMbrcond bb:$target, imm:$cc, CCR:$ccr)*/]> {
|
||||||
bits<24> target;
|
bits<24> target;
|
||||||
|
@@ -99,6 +99,10 @@ public:
|
|||||||
uint32_t getUnconditionalBranchTargetOpValue(const MCInst &MI, unsigned OpIdx,
|
uint32_t getUnconditionalBranchTargetOpValue(const MCInst &MI, unsigned OpIdx,
|
||||||
SmallVectorImpl<MCFixup> &Fixups) const;
|
SmallVectorImpl<MCFixup> &Fixups) const;
|
||||||
|
|
||||||
|
/// getARMBranchTargetOpValue - Return encoding info for 24-bit immediate
|
||||||
|
/// branch target.
|
||||||
|
uint32_t getARMBranchTargetOpValue(const MCInst &MI, unsigned OpIdx,
|
||||||
|
SmallVectorImpl<MCFixup> &Fixups) const;
|
||||||
|
|
||||||
/// getAdrLabelOpValue - Return encoding info for 12-bit immediate
|
/// getAdrLabelOpValue - Return encoding info for 12-bit immediate
|
||||||
/// ADR label target.
|
/// ADR label target.
|
||||||
@@ -473,6 +477,23 @@ getThumbCBTargetOpValue(const MCInst &MI, unsigned OpIdx,
|
|||||||
return ::getBranchTargetOpValue(MI, OpIdx, ARM::fixup_arm_thumb_cb, Fixups);
|
return ::getBranchTargetOpValue(MI, OpIdx, ARM::fixup_arm_thumb_cb, Fixups);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return true if this branch has a non-always predication
|
||||||
|
static bool HasConditionalBranch(const MCInst &MI) {
|
||||||
|
int NumOp = MI.getNumOperands();
|
||||||
|
if (NumOp >= 2) {
|
||||||
|
for (int i = 0; i < NumOp-1; ++i) {
|
||||||
|
const MCOperand &MCOp1 = MI.getOperand(i);
|
||||||
|
const MCOperand &MCOp2 = MI.getOperand(i + 1);
|
||||||
|
if (MCOp1.isImm() && MCOp2.isReg() &&
|
||||||
|
(MCOp2.getReg() == 0 || MCOp2.getReg() == ARM::CPSR)) {
|
||||||
|
if (ARMCC::CondCodes(MCOp1.getImm()) != ARMCC::AL)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/// getBranchTargetOpValue - Return encoding info for 24-bit immediate branch
|
/// getBranchTargetOpValue - Return encoding info for 24-bit immediate branch
|
||||||
/// target.
|
/// target.
|
||||||
uint32_t ARMMCCodeEmitter::
|
uint32_t ARMMCCodeEmitter::
|
||||||
@@ -483,9 +504,24 @@ getBranchTargetOpValue(const MCInst &MI, unsigned OpIdx,
|
|||||||
if (Subtarget->isThumb2())
|
if (Subtarget->isThumb2())
|
||||||
return
|
return
|
||||||
::getBranchTargetOpValue(MI, OpIdx, ARM::fixup_t2_condbranch, Fixups);
|
::getBranchTargetOpValue(MI, OpIdx, ARM::fixup_t2_condbranch, Fixups);
|
||||||
return ::getBranchTargetOpValue(MI, OpIdx, ARM::fixup_arm_branch, Fixups);
|
return getARMBranchTargetOpValue(MI, OpIdx, Fixups);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// getBranchTargetOpValue - Return encoding info for 24-bit immediate branch
|
||||||
|
/// target.
|
||||||
|
uint32_t ARMMCCodeEmitter::
|
||||||
|
getARMBranchTargetOpValue(const MCInst &MI, unsigned OpIdx,
|
||||||
|
SmallVectorImpl<MCFixup> &Fixups) const {
|
||||||
|
if (HasConditionalBranch(MI))
|
||||||
|
return ::getBranchTargetOpValue(MI, OpIdx,
|
||||||
|
ARM::fixup_arm_condbranch, Fixups);
|
||||||
|
return ::getBranchTargetOpValue(MI, OpIdx,
|
||||||
|
ARM::fixup_arm_uncondbranch, Fixups);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// getUnconditionalBranchTargetOpValue - Return encoding info for 24-bit
|
/// getUnconditionalBranchTargetOpValue - Return encoding info for 24-bit
|
||||||
/// immediate branch target.
|
/// immediate branch target.
|
||||||
uint32_t ARMMCCodeEmitter::
|
uint32_t ARMMCCodeEmitter::
|
||||||
|
@@ -2,6 +2,6 @@
|
|||||||
// RUN: FileCheck < %t %s
|
// RUN: FileCheck < %t %s
|
||||||
|
|
||||||
// CHECK: bl _printf @ encoding: [A,A,A,0xeb]
|
// CHECK: bl _printf @ encoding: [A,A,A,0xeb]
|
||||||
// CHECK: @ fixup A - offset: 0, value: _printf, kind: fixup_arm_branch
|
// CHECK: @ fixup A - offset: 0, value: _printf, kind: fixup_arm_uncondbranch
|
||||||
bl _printf
|
bl _printf
|
||||||
|
|
@@ -325,6 +325,9 @@ static int X86TypeFromOpName(LiteralConstantEmitter *type,
|
|||||||
PCR("uncondbrtarget");
|
PCR("uncondbrtarget");
|
||||||
PCR("bltarget");
|
PCR("bltarget");
|
||||||
|
|
||||||
|
// all I, ARM mode only, conditional/unconditional
|
||||||
|
PCR("br_target");
|
||||||
|
PCR("bl_target");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -600,6 +603,10 @@ static int ARMFlagFromOpName(LiteralConstantEmitter *type,
|
|||||||
MISC("t_bcctarget", "kOperandTypeARMBranchTarget"); // ?
|
MISC("t_bcctarget", "kOperandTypeARMBranchTarget"); // ?
|
||||||
MISC("t_cbtarget", "kOperandTypeARMBranchTarget"); // ?
|
MISC("t_cbtarget", "kOperandTypeARMBranchTarget"); // ?
|
||||||
MISC("bltarget", "kOperandTypeARMBranchTarget"); // ?
|
MISC("bltarget", "kOperandTypeARMBranchTarget"); // ?
|
||||||
|
|
||||||
|
MISC("br_target", "kOperandTypeARMBranchTarget"); // ?
|
||||||
|
MISC("bl_target", "kOperandTypeARMBranchTarget"); // ?
|
||||||
|
|
||||||
MISC("t_bltarget", "kOperandTypeARMBranchTarget"); // ?
|
MISC("t_bltarget", "kOperandTypeARMBranchTarget"); // ?
|
||||||
MISC("t_blxtarget", "kOperandTypeARMBranchTarget"); // ?
|
MISC("t_blxtarget", "kOperandTypeARMBranchTarget"); // ?
|
||||||
MISC("so_reg", "kOperandTypeARMSoReg"); // R, R, I
|
MISC("so_reg", "kOperandTypeARMSoReg"); // R, R, I
|
||||||
|
Reference in New Issue
Block a user