Support for microMIPS jump instructions

llvm-svn: 193623
This commit is contained in:
Zoran Jovanovic 2013-10-29 16:38:59 +00:00
parent 08ded12ffb
commit 507e084a18
18 changed files with 253 additions and 21 deletions

View File

@ -881,6 +881,7 @@ enum {
R_MIPS_GLOB_DAT = 51,
R_MIPS_COPY = 126,
R_MIPS_JUMP_SLOT = 127,
R_MICROMIPS_26_S1 = 133,
R_MICROMIPS_HI16 = 134,
R_MICROMIPS_LO16 = 135,
R_MICROMIPS_GOT16 = 138,

View File

@ -161,6 +161,7 @@ StringRef getELFRelocationTypeName(uint32_t Machine, uint32_t Type) {
LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_MIPS_GLOB_DAT);
LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_MIPS_COPY);
LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_MIPS_JUMP_SLOT);
LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_MICROMIPS_26_S1);
LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_MICROMIPS_HI16);
LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_MICROMIPS_LO16);
LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_MICROMIPS_GOT16);

View File

@ -205,6 +205,13 @@ static DecodeStatus DecodeJumpTarget(MCInst &Inst,
uint64_t Address,
const void *Decoder);
// DecodeJumpTargetMM - Decode microMIPS jump target, which is
// shifted left by 1 bit.
static DecodeStatus DecodeJumpTargetMM(MCInst &Inst,
unsigned Insn,
uint64_t Address,
const void *Decoder);
static DecodeStatus DecodeMem(MCInst &Inst,
unsigned Insn,
uint64_t Address,
@ -744,6 +751,14 @@ static DecodeStatus DecodeJumpTarget(MCInst &Inst,
return MCDisassembler::Success;
}
static DecodeStatus DecodeJumpTargetMM(MCInst &Inst,
unsigned Insn,
uint64_t Address,
const void *Decoder) {
unsigned JumpOffset = fieldFromInstruction(Insn, 0, 26) << 1;
Inst.addOperand(MCOperand::CreateImm(JumpOffset));
return MCDisassembler::Success;
}
static DecodeStatus DecodeSimm16(MCInst &Inst,
unsigned Insn,

View File

@ -81,6 +81,9 @@ static unsigned adjustFixupValue(unsigned Kind, uint64_t Value) {
// Get the 4th 16-bits.
Value = ((Value + 0x800080008000LL) >> 48) & 0xffff;
break;
case Mips::fixup_MICROMIPS_26_S1:
Value >>= 1;
break;
}
return Value;
@ -194,6 +197,7 @@ public:
{ "fixup_Mips_GOT_LO16", 0, 16, 0 },
{ "fixup_Mips_CALL_HI16", 0, 16, 0 },
{ "fixup_Mips_CALL_LO16", 0, 16, 0 },
{ "fixup_MICROMIPS_26_S1", 0, 26, 0 },
{ "fixup_MICROMIPS_HI16", 0, 16, 0 },
{ "fixup_MICROMIPS_LO16", 0, 16, 0 },
{ "fixup_MICROMIPS_GOT16", 0, 16, 0 },

View File

@ -183,6 +183,9 @@ unsigned MipsELFObjectWriter::GetRelocType(const MCValue &Target,
case Mips::fixup_Mips_CALL_LO16:
Type = ELF::R_MIPS_CALL_LO16;
break;
case Mips::fixup_MICROMIPS_26_S1:
Type = ELF::R_MICROMIPS_26_S1;
break;
case Mips::fixup_MICROMIPS_HI16:
Type = ELF::R_MICROMIPS_HI16;
break;

View File

@ -128,6 +128,9 @@ namespace Mips {
// resulting in - R_MIPS_CALL_LO16
fixup_Mips_CALL_LO16,
// resulting in - R_MICROMIPS_26_S1
fixup_MICROMIPS_26_S1,
// resulting in - R_MICROMIPS_HI16
fixup_MICROMIPS_HI16,

View File

@ -84,6 +84,12 @@ public:
unsigned getJumpTargetOpValue(const MCInst &MI, unsigned OpNo,
SmallVectorImpl<MCFixup> &Fixups) const;
// getBranchJumpOpValueMM - Return binary encoding of the microMIPS jump
// target operand. If the machine operand requires relocation,
// record the relocation and return zero.
unsigned getJumpTargetOpValueMM(const MCInst &MI, unsigned OpNo,
SmallVectorImpl<MCFixup> &Fixups) const;
// getBranchTargetOpValue - Return binary encoding of the branch
// target operand. If the machine operand requires relocation,
// record the relocation and return zero.
@ -290,6 +296,23 @@ getJumpTargetOpValue(const MCInst &MI, unsigned OpNo,
return 0;
}
unsigned MipsMCCodeEmitter::
getJumpTargetOpValueMM(const MCInst &MI, unsigned OpNo,
SmallVectorImpl<MCFixup> &Fixups) const {
const MCOperand &MO = MI.getOperand(OpNo);
// If the destination is an immediate, divide by 2.
if (MO.isImm()) return MO.getImm() >> 1;
assert(MO.isExpr() &&
"getJumpTargetOpValueMM expects only expressions or an immediate");
const MCExpr *Expr = MO.getExpr();
Fixups.push_back(MCFixup::Create(0, Expr,
MCFixupKind(Mips::fixup_MICROMIPS_26_S1)));
return 0;
}
unsigned MipsMCCodeEmitter::
getExprOpValue(const MCExpr *Expr,SmallVectorImpl<MCFixup> &Fixups) const {
int64_t Res;

View File

@ -204,3 +204,37 @@ class EXT_FM_MM<bits<6> funct> : MMArch {
let Inst{10-6} = pos;
let Inst{5-0} = funct;
}
class J_FM_MM<bits<6> op> : MMArch {
bits<26> target;
bits<32> Inst;
let Inst{31-26} = op;
let Inst{25-0} = target;
}
class JR_FM_MM<bits<8> funct> : MMArch {
bits<5> rs;
bits<32> Inst;
let Inst{31-21} = 0x00;
let Inst{20-16} = rs;
let Inst{15-14} = 0x0;
let Inst{13-6} = funct;
let Inst{5-0} = 0x3c;
}
class JALR_FM_MM<bits<10> funct> : MMArch {
bits<5> rs;
bits<5> rd;
bits<32> Inst;
let Inst{31-26} = 0x00;
let Inst{25-21} = rd;
let Inst{20-16} = rs;
let Inst{15-6} = funct;
let Inst{5-0} = 0x3c;
}

View File

@ -12,6 +12,14 @@ def mem_mm_12 : Operand<i32> {
let OperandType = "OPERAND_MEMORY";
}
def jmptarget_mm : Operand<OtherVT> {
let EncoderMethod = "getJumpTargetOpValueMM";
}
def calltarget_mm : Operand<iPTR> {
let EncoderMethod = "getJumpTargetOpValueMM";
}
let canFoldAsLoad = 1 in
class LoadLeftRightMM<string opstr, SDNode OpNode, RegisterOperand RO,
Operand MemOpnd> :
@ -155,4 +163,18 @@ let DecoderNamespace = "MicroMips", Predicates = [InMicroMips] in {
EXT_FM_MM<0x2c>;
def INS_MM : MMRel, InsBase<"ins", GPR32Opnd, uimm5, MipsIns>,
EXT_FM_MM<0x0c>;
/// Jump Instructions
let DecoderMethod = "DecodeJumpTargetMM" in {
def J_MM : MMRel, JumpFJ<jmptarget_mm, "j", br, bb, "j">,
J_FM_MM<0x35>;
def JAL_MM : MMRel, JumpLink<"jal", calltarget_mm>, J_FM_MM<0x3d>;
def TAILCALL_MM : MMRel, JumpFJ<calltarget_mm, "j", MipsTailCall, imm,
"tcall">, J_FM_MM<0x3d>, IsTailCall;
}
def JR_MM : MMRel, IndirectBranch<"jr", GPR32Opnd>, JR_FM_MM<0x3c>;
def JALR_MM : MMRel, JumpLinkReg<"jalr", GPR32Opnd>, JALR_FM_MM<0x03c>;
def TAILCALL_R_MM : MMRel, JumpFR<"tcallr", GPR32Opnd, MipsTailCall>,
JR_FM_MM<0x3c>, IsTailCall;
def RET_MM : MMRel, RetBase<"ret", GPR32Opnd>, JR_FM_MM<0x3c>;
}

View File

@ -150,7 +150,7 @@ def SCD : SCBase<"scd", GPR64Opnd>, LW_FM<0x3c>;
/// Jump and Branch Instructions
let isCodeGenOnly = 1 in {
def JR64 : IndirectBranch<GPR64Opnd>, MTLO_FM<8>;
def JR64 : IndirectBranch<"jr", GPR64Opnd>, MTLO_FM<8>;
def BEQ64 : CBranch<"beq", seteq, GPR64Opnd>, BEQ_FM<4>;
def BNE64 : CBranch<"bne", setne, GPR64Opnd>, BEQ_FM<5>;
def BGEZ64 : CBranchZero<"bgez", setge, GPR64Opnd>, BGEZ_FM<1, 1>;
@ -159,7 +159,8 @@ def BLEZ64 : CBranchZero<"blez", setle, GPR64Opnd>, BGEZ_FM<6, 0>;
def BLTZ64 : CBranchZero<"bltz", setlt, GPR64Opnd>, BGEZ_FM<1, 0>;
def JALR64 : JumpLinkReg<"jalr", GPR64Opnd>, JALR_FM;
def JALR64Pseudo : JumpLinkRegPseudo<GPR64Opnd, JALR, RA, GPR32Opnd>;
def TAILCALL64_R : JumpFR<GPR64Opnd, MipsTailCall>, MTLO_FM<8>, IsTailCall;
def TAILCALL64_R : JumpFR<"tcallr", GPR64Opnd, MipsTailCall>,
MTLO_FM<8>, IsTailCall;
}
/// Multiply and Divide Instructions.

View File

@ -105,6 +105,7 @@ private:
const MachineOperand &MO) const;
unsigned getJumpTargetOpValue(const MachineInstr &MI, unsigned OpNo) const;
unsigned getJumpTargetOpValueMM(const MachineInstr &MI, unsigned OpNo) const;
unsigned getBranchTargetOpValue(const MachineInstr &MI, unsigned OpNo) const;
unsigned getMemEncoding(const MachineInstr &MI, unsigned OpNo) const;
@ -187,6 +188,12 @@ unsigned MipsCodeEmitter::getJumpTargetOpValue(const MachineInstr &MI,
return 0;
}
unsigned MipsCodeEmitter::getJumpTargetOpValueMM(const MachineInstr &MI,
unsigned OpNo) const {
llvm_unreachable("Unimplemented function.");
return 0;
}
unsigned MipsCodeEmitter::getBranchTargetOpValue(const MachineInstr &MI,
unsigned OpNo) const {
MachineOperand MO = MI.getOperand(OpNo);

View File

@ -183,7 +183,7 @@ class BranchBase<bits<6> op, dag outs, dag ins, string asmstr,
// Format J instruction class in Mips : <|opcode|address|>
//===----------------------------------------------------------------------===//
class FJ<bits<6> op>
class FJ<bits<6> op> : StdArch
{
bits<26> target;
@ -375,7 +375,7 @@ class LUI_FM : StdArch {
let Inst{15-0} = imm16;
}
class JALR_FM {
class JALR_FM : StdArch {
bits<5> rd;
bits<5> rs;

View File

@ -541,9 +541,9 @@ class SetCC_I<string opstr, PatFrag cond_op, Operand Od, PatLeaf imm_type,
// Jump
class JumpFJ<DAGOperand opnd, string opstr, SDPatternOperator operator,
SDPatternOperator targetoperator> :
SDPatternOperator targetoperator, string bopstr> :
InstSE<(outs), (ins opnd:$target), !strconcat(opstr, "\t$target"),
[(operator targetoperator:$target)], IIBranch, FrmJ> {
[(operator targetoperator:$target)], IIBranch, FrmJ, bopstr> {
let isTerminator=1;
let isBarrier=1;
let hasDelaySlot = 1;
@ -565,17 +565,20 @@ class UncondBranch<Instruction BEQInst> :
// Base class for indirect branch and return instruction classes.
let isTerminator=1, isBarrier=1, hasDelaySlot = 1 in
class JumpFR<RegisterOperand RO, SDPatternOperator operator = null_frag>:
InstSE<(outs), (ins RO:$rs), "jr\t$rs", [(operator RO:$rs)], IIBranch, FrmR>;
class JumpFR<string opstr, RegisterOperand RO,
SDPatternOperator operator = null_frag>:
InstSE<(outs), (ins RO:$rs), "jr\t$rs", [(operator RO:$rs)], IIBranch,
FrmR, opstr>;
// Indirect branch
class IndirectBranch<RegisterOperand RO>: JumpFR<RO, brind> {
class IndirectBranch<string opstr, RegisterOperand RO> :
JumpFR<opstr, RO, brind> {
let isBranch = 1;
let isIndirectBranch = 1;
}
// Return instruction
class RetBase<RegisterOperand RO>: JumpFR<RO> {
class RetBase<string opstr, RegisterOperand RO>: JumpFR<opstr, RO> {
let isReturn = 1;
let isCodeGenOnly = 1;
let hasCtrlDep = 1;
@ -584,9 +587,9 @@ class RetBase<RegisterOperand RO>: JumpFR<RO> {
// Jump and Link (Call)
let isCall=1, hasDelaySlot=1, Defs = [RA] in {
class JumpLink<string opstr> :
InstSE<(outs), (ins calltarget:$target), !strconcat(opstr, "\t$target"),
[(MipsJmpLink imm:$target)], IIBranch, FrmJ> {
class JumpLink<string opstr, DAGOperand opnd> :
InstSE<(outs), (ins opnd:$target), !strconcat(opstr, "\t$target"),
[(MipsJmpLink imm:$target)], IIBranch, FrmJ, opstr> {
let DecoderMethod = "DecodeJumpTarget";
}
@ -597,7 +600,7 @@ let isCall=1, hasDelaySlot=1, Defs = [RA] in {
class JumpLinkReg<string opstr, RegisterOperand RO>:
InstSE<(outs RO:$rd), (ins RO:$rs), !strconcat(opstr, "\t$rd, $rs"),
[], IIBranch, FrmR>;
[], IIBranch, FrmR, opstr>;
class BGEZAL_FT<string opstr, RegisterOperand RO> :
InstSE<(outs), (ins RO:$rs, brtarget:$offset),
@ -988,9 +991,9 @@ def LL : LLBase<"ll", GPR32Opnd>, LW_FM<0x30>;
def SC : SCBase<"sc", GPR32Opnd>, LW_FM<0x38>;
/// Jump and Branch Instructions
def J : JumpFJ<jmptarget, "j", br, bb>, FJ<2>,
def J : MMRel, JumpFJ<jmptarget, "j", br, bb, "j">, FJ<2>,
Requires<[RelocStatic, HasStdEnc]>, IsBranch;
def JR : IndirectBranch<GPR32Opnd>, MTLO_FM<8>;
def JR : MMRel, IndirectBranch<"jr", GPR32Opnd>, MTLO_FM<8>;
def BEQ : CBranch<"beq", seteq, GPR32Opnd>, BEQ_FM<4>;
def BNE : CBranch<"bne", setne, GPR32Opnd>, BEQ_FM<5>;
def BGEZ : CBranchZero<"bgez", setge, GPR32Opnd>, BGEZ_FM<1, 1>;
@ -999,16 +1002,18 @@ def BLEZ : CBranchZero<"blez", setle, GPR32Opnd>, BGEZ_FM<6, 0>;
def BLTZ : CBranchZero<"bltz", setlt, GPR32Opnd>, BGEZ_FM<1, 0>;
def B : UncondBranch<BEQ>;
def JAL : JumpLink<"jal">, FJ<3>;
def JALR : JumpLinkReg<"jalr", GPR32Opnd>, JALR_FM;
def JAL : MMRel, JumpLink<"jal", calltarget>, FJ<3>;
def JALR : MMRel, JumpLinkReg<"jalr", GPR32Opnd>, JALR_FM;
def JALRPseudo : JumpLinkRegPseudo<GPR32Opnd, JALR, RA>;
def BGEZAL : BGEZAL_FT<"bgezal", GPR32Opnd>, BGEZAL_FM<0x11>;
def BLTZAL : BGEZAL_FT<"bltzal", GPR32Opnd>, BGEZAL_FM<0x10>;
def BAL_BR : BAL_BR_Pseudo<BGEZAL>;
def TAILCALL : JumpFJ<calltarget, "j", MipsTailCall, imm>, FJ<2>, IsTailCall;
def TAILCALL_R : JumpFR<GPR32Opnd, MipsTailCall>, MTLO_FM<8>, IsTailCall;
def TAILCALL : MMRel, JumpFJ<calltarget, "j", MipsTailCall, imm, "tcall">,
FJ<2>, IsTailCall;
def TAILCALL_R : MMRel, JumpFR<"tcallr", GPR32Opnd, MipsTailCall>, MTLO_FM<8>,
IsTailCall;
def RET : RetBase<GPR32Opnd>, MTLO_FM<8>;
def RET : MMRel, RetBase<"ret", GPR32Opnd>, MTLO_FM<8>;
// Exception handling related node and instructions.
// The conversion sequence is:

View File

@ -213,3 +213,15 @@
# CHECK: ins $9, $6, 3, 7
0x01 0x26 0x48 0xcc
# CHECK: j 1328
0xd4 0x00 0x02 0x98
# CHECK: jal 1328
0xf4 0x00 0x02 0x98
# CHECK: jalr $ra, $6
0x03 0xe6 0x0f 0x3c
# CHECK: jr $7
0x00 0x07 0x0f 0x3c

View File

@ -213,3 +213,15 @@
# CHECK: ins $9, $6, 3, 7
0x26 0x01 0xcc 0x48
# CHECK: j 1328
0x00 0xd4 0x98 0x02
# CHECK: jal 1328
0x00 0xf4 0x98 0x02
# CHECK: jalr $ra, $6
0xe6 0x03 0x3c 0x0f
# CHECK: jr $7
0x07 0x00 0x3c 0x0f

View File

@ -0,0 +1,40 @@
# RUN: llvm-mc %s -triple=mipsel -show-encoding -mattr=micromips \
# RUN: | FileCheck %s -check-prefix=CHECK-EL
# RUN: llvm-mc %s -triple=mips -show-encoding -mattr=micromips \
# RUN: | FileCheck %s -check-prefix=CHECK-EB
# Check that the assembler can handle the documented syntax
# for jump and branch instructions.
#------------------------------------------------------------------------------
# Jump instructions
#------------------------------------------------------------------------------
# Little endian
#------------------------------------------------------------------------------
# CHECK-EL: j 1328 # encoding: [0x00,0xd4,0x98,0x02]
# CHECK-EL: nop # encoding: [0x00,0x00,0x00,0x00]
# CHECK-EL: jal 1328 # encoding: [0x00,0xf4,0x98,0x02]
# CHECK-EL: nop # encoding: [0x00,0x00,0x00,0x00]
# CHECK-EL: jalr $6 # encoding: [0xe6,0x03,0x3c,0x0f]
# CHECK-EL: nop # encoding: [0x00,0x00,0x00,0x00]
# CHECK-EL: jr $7 # encoding: [0x07,0x00,0x3c,0x0f]
# CHECK-EL: nop # encoding: [0x00,0x00,0x00,0x00]
# CHECK-EL: jr $7 # encoding: [0x07,0x00,0x3c,0x0f]
# CHECK-EL: nop # encoding: [0x00,0x00,0x00,0x00]
#------------------------------------------------------------------------------
# Big endian
#------------------------------------------------------------------------------
# CHECK-EB: j 1328 # encoding: [0xd4,0x00,0x02,0x98]
# CHECK-EB: nop # encoding: [0x00,0x00,0x00,0x00]
# CHECK-EB: jal 1328 # encoding: [0xf4,0x00,0x02,0x98]
# CHECK-EB: nop # encoding: [0x00,0x00,0x00,0x00]
# CHECK-EB: jalr $6 # encoding: [0x03,0xe6,0x0f,0x3c]
# CHECK-EB: nop # encoding: [0x00,0x00,0x00,0x00]
# CHECK-EB: jr $7 # encoding: [0x00,0x07,0x0f,0x3c]
# CHECK-EB: nop # encoding: [0x00,0x00,0x00,0x00]
# CHECK-EB: jr $7 # encoding: [0x00,0x07,0x0f,0x3c]
# CHECK-EB: nop # encoding: [0x00,0x00,0x00,0x00]
j 1328
jal 1328
jalr $6
jr $7
j $7

View File

@ -0,0 +1,23 @@
# RUN: llvm-mc %s -triple=mipsel-unknown-linux -show-encoding \
# RUN: -mattr=micromips | FileCheck %s -check-prefix=CHECK-FIXUP
# RUN: llvm-mc %s -filetype=obj -triple=mipsel-unknown-linux \
# RUN: -mattr=micromips | llvm-readobj -r \
# RUN: | FileCheck %s -check-prefix=CHECK-ELF
#------------------------------------------------------------------------------
# Check that the assembler can handle the documented syntax
# for relocations.
#------------------------------------------------------------------------------
# CHECK-FIXUP: foo:
# CHECK-FIXUP: jal bar # encoding: [A,0xf4'A',A,0b000000AA]
# CHECK-FIXUP: # fixup A - offset: 0,
# CHECK-FIXUP: value: bar, kind: fixup_MICROMIPS_26_S1
# CHECK-FIXUP: nop # encoding: [0x00,0x00,0x00,0x00]
#------------------------------------------------------------------------------
# Check that the appropriate relocations were created.
#------------------------------------------------------------------------------
# CHECK-ELF: Relocations [
# CHECK-ELF: 0x{{[0-9,A-F]+}} R_MICROMIPS_26_S1
# CHECK-ELF: ]
foo:
jal bar

View File

@ -0,0 +1,26 @@
# RUN: llvm-mc %s -triple=mipsel-unknown-linux -show-encoding \
# RUN: -mattr=micromips | FileCheck %s -check-prefix=CHECK-FIXUP
# RUN: llvm-mc %s -filetype=obj -triple=mipsel-unknown-linux \
# RUN: -mattr=micromips | llvm-readobj -r \
# RUN: | FileCheck %s -check-prefix=CHECK-ELF
#------------------------------------------------------------------------------
# Check that the assembler can handle the documented syntax
# for relocations.
#------------------------------------------------------------------------------
# CHECK-FIXUP: foo:
# CHECK-FIXUP: addiu $2, $zero, 1332
# CHECK-FIXUP: # encoding: [0x40,0x30,0x34,0x05]
# CHECK-FIXUP: j foo # encoding: [A,0xd4'A',A,0b000000AA]
# CHECK-FIXUP: # fixup A - offset: 0,
# CHECK-FIXUP: value: foo, kind: fixup_MICROMIPS_26_S1
# CHECK-FIXUP: nop # encoding: [0x00,0x00,0x00,0x00]
#------------------------------------------------------------------------------
# Check that the appropriate relocations were created.
#------------------------------------------------------------------------------
# CHECK-ELF: Relocations [
# CHECK-ELF: 0x{{[0-9,A-F]+}} R_MICROMIPS_26_S1
# CHECK-ELF: ]
foo:
addiu $2, $0, 1332
j foo