Index: include/llvm/Support/ELF.h =================================================================== --- include/llvm/Support/ELF.h +++ include/llvm/Support/ELF.h @@ -890,6 +890,7 @@ R_MICROMIPS_HI16 = 134, R_MICROMIPS_LO16 = 135, R_MICROMIPS_GOT16 = 138, + R_MICROMIPS_PC10_S1 = 140, R_MICROMIPS_PC16_S1 = 141, R_MICROMIPS_CALL16 = 142, R_MICROMIPS_GOT_DISP = 145, Index: lib/Object/ELF.cpp =================================================================== --- lib/Object/ELF.cpp +++ lib/Object/ELF.cpp @@ -165,6 +165,7 @@ 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); + LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_MICROMIPS_PC10_S1); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_MICROMIPS_PC16_S1); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_MICROMIPS_CALL16); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_MICROMIPS_GOT_DISP); Index: lib/Target/Mips/AsmParser/MipsAsmParser.cpp =================================================================== --- lib/Target/Mips/AsmParser/MipsAsmParser.cpp +++ lib/Target/Mips/AsmParser/MipsAsmParser.cpp @@ -835,6 +835,16 @@ if (OffsetToAlignment(Offset.getImm(), 1LL << (isMicroMips() ? 1 : 2))) return Error(IDLoc, "branch to misaligned address"); break; + case Mips::B16_MM: + assert(MCID.getNumOperands() == 1 && "unexpected number of operands"); + Offset = Inst.getOperand(0); + if (!Offset.isImm()) + break; // We'll deal with this situation later on when applying fixups. + if (!isIntN(11, Offset.getImm())) + return Error(IDLoc, "branch target out of range"); + if (OffsetToAlignment(Offset.getImm(), 1LL << 1)) + return Error(IDLoc, "branch to misaligned address"); + break; case Mips::BGEZ: case Mips::BGTZ: case Mips::BLEZ: Index: lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp =================================================================== --- lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp +++ lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp @@ -94,6 +94,14 @@ case Mips::fixup_MICROMIPS_26_S1: Value >>= 1; break; + case Mips::fixup_MICROMIPS_PC10_S1: + Value -= 2; + // Forcing a signed division because Value can be negative. + Value = (int64_t) Value / 2; + // We now check if Value can be encoded as a 10-bit signed immediate. + if (!isIntN(10, Value) && Ctx) + Ctx->FatalError(Fixup.getLoc(), "out of range PC10 fixup"); + break; case Mips::fixup_MICROMIPS_PC16_S1: Value -= 4; // Forcing a signed division because Value can be negative. @@ -167,6 +175,14 @@ bool microMipsLEByteOrder = needsMMLEByteOrder((unsigned) Kind); + if ((unsigned) Kind == Mips::fixup_MICROMIPS_PC10_S1) { + // We have 16-bit unconditional branch instruction. + FullSize = 2; + // We don't want microMIPS specific little-endian byte ordering + // for 16-bit instructions. + microMipsLEByteOrder = false; + } + for (unsigned i = 0; i != NumBytes; ++i) { unsigned Idx = IsLittle ? (microMipsLEByteOrder ? calculateMMLEIndex(i) : i) @@ -233,6 +249,7 @@ { "fixup_MICROMIPS_HI16", 0, 16, 0 }, { "fixup_MICROMIPS_LO16", 0, 16, 0 }, { "fixup_MICROMIPS_GOT16", 0, 16, 0 }, + { "fixup_MICROMIPS_PC10_S1", 0, 10, MCFixupKindInfo::FKF_IsPCRel }, { "fixup_MICROMIPS_PC16_S1", 0, 16, MCFixupKindInfo::FKF_IsPCRel }, { "fixup_MICROMIPS_CALL16", 0, 16, 0 }, { "fixup_MICROMIPS_GOT_DISP", 0, 16, 0 }, Index: lib/Target/Mips/MCTargetDesc/MipsELFObjectWriter.cpp =================================================================== --- lib/Target/Mips/MCTargetDesc/MipsELFObjectWriter.cpp +++ lib/Target/Mips/MCTargetDesc/MipsELFObjectWriter.cpp @@ -160,6 +160,9 @@ case Mips::fixup_MICROMIPS_GOT16: Type = ELF::R_MICROMIPS_GOT16; break; + case Mips::fixup_MICROMIPS_PC10_S1: + Type = ELF::R_MICROMIPS_PC10_S1; + break; case Mips::fixup_MICROMIPS_PC16_S1: Type = ELF::R_MICROMIPS_PC16_S1; break; Index: lib/Target/Mips/MCTargetDesc/MipsFixupKinds.h =================================================================== --- lib/Target/Mips/MCTargetDesc/MipsFixupKinds.h +++ lib/Target/Mips/MCTargetDesc/MipsFixupKinds.h @@ -140,6 +140,9 @@ // resulting in - R_MICROMIPS_GOT16 fixup_MICROMIPS_GOT16, + // resulting in - R_MICROMIPS_PC10_S1 + fixup_MICROMIPS_PC10_S1, + // resulting in - R_MICROMIPS_PC16_S1 fixup_MICROMIPS_PC16_S1, Index: lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.h =================================================================== --- lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.h +++ lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.h @@ -81,6 +81,10 @@ SmallVectorImpl &Fixups, const MCSubtargetInfo &STI) const; + unsigned getBranchTargetOpValueMMPC10(const MCInst &MI, unsigned OpNo, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const; + // getBranchTargetOpValue - Return binary encoding of the microMIPS branch // target operand. If the machine operand requires relocation, // record the relocation and return zero. Index: lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.cpp =================================================================== --- lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.cpp +++ lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.cpp @@ -219,6 +219,25 @@ return 0; } +unsigned MipsMCCodeEmitter:: +getBranchTargetOpValueMMPC10(const MCInst &MI, unsigned OpNo, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) 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() && + "getBranchTargetOpValuePC10 expects only expressions or immediates"); + + const MCExpr *Expr = MO.getExpr(); + Fixups.push_back(MCFixup::Create(0, Expr, + MCFixupKind(Mips::fixup_MICROMIPS_PC10_S1))); + return 0; +} + /// getBranchTargetOpValue - Return binary encoding of the microMIPS branch /// target operand. If the machine operand requires relocation, /// record the relocation and return zero. Index: lib/Target/Mips/MicroMipsInstrFormats.td =================================================================== --- lib/Target/Mips/MicroMipsInstrFormats.td +++ lib/Target/Mips/MicroMipsInstrFormats.td @@ -72,6 +72,15 @@ let Inst{4-0} = rd; } +class B16_FM { + bits<10> offset; + + bits<16> Inst; + + let Inst{15-10} = 0x33; + let Inst{9-0} = offset; +} + //===----------------------------------------------------------------------===// // MicroMIPS 32-bit Instruction Formats //===----------------------------------------------------------------------===// Index: lib/Target/Mips/MicroMipsInstrInfo.td =================================================================== --- lib/Target/Mips/MicroMipsInstrInfo.td +++ lib/Target/Mips/MicroMipsInstrInfo.td @@ -16,6 +16,11 @@ let EncoderMethod = "getJumpTargetOpValueMM"; } +def brtarget10_mm : Operand { + let EncoderMethod = "getBranchTargetOpValueMMPC10"; + let OperandType = "OPERAND_PCREL"; +} + def calltarget_mm : Operand { let EncoderMethod = "getJumpTargetOpValueMM"; } @@ -94,10 +99,25 @@ let Defs = [RA]; } +class UncondBranchMM16 : + MicroMipsInst16<(outs), (ins brtarget10_mm:$offset), + !strconcat(opstr, "\t$offset"), + [], IIBranch, FrmI> { + let isBranch = 1; + let isTerminator = 1; + let isBarrier = 1; + let hasDelaySlot = 1; + let Predicates = [RelocPIC]; + let Defs = [AT]; +} + +let Predicates = [InMicroMips] in { def MFHI16_MM : MoveFromHILOMM<"mfhi", GPR32Opnd, AC0>, MFHILO_FM_MM16<0x10>; def MFLO16_MM : MoveFromHILOMM<"mflo", GPR32Opnd, AC0>, MFHILO_FM_MM16<0x12>; def MOVE16_MM : MoveMM16<"move", GPR32Opnd>, MOVE_FM_MM16<0x03>; def JALR16_MM : JumpLinkRegMM16<"jalr", GPR32Opnd>, JALR_FM_MM16<0x0e>; +def B16_MM : UncondBranchMM16<"b">, B16_FM; +} class WaitMM : InstSE<(outs), (ins uimm10:$code_), !strconcat(opstr, "\t$code_"), [], Index: lib/Target/Mips/MipsCodeEmitter.cpp =================================================================== --- lib/Target/Mips/MipsCodeEmitter.cpp +++ lib/Target/Mips/MipsCodeEmitter.cpp @@ -107,6 +107,8 @@ unsigned getJumpTargetOpValue(const MachineInstr &MI, unsigned OpNo) const; unsigned getJumpTargetOpValueMM(const MachineInstr &MI, unsigned OpNo) const; + unsigned getBranchTargetOpValueMMPC10(const MachineInstr &MI, + unsigned OpNo) const; unsigned getBranchTargetOpValueMM(const MachineInstr &MI, unsigned OpNo) const; @@ -196,6 +198,12 @@ return 0; } +unsigned MipsCodeEmitter::getBranchTargetOpValueMMPC10(const MachineInstr &MI, + unsigned OpNo) const { + llvm_unreachable("Unimplemented function."); + return 0; +} + unsigned MipsCodeEmitter::getBranchTargetOpValueMM(const MachineInstr &MI, unsigned OpNo) const { llvm_unreachable("Unimplemented function."); Index: lib/Target/Mips/MipsLongBranch.cpp =================================================================== --- lib/Target/Mips/MipsLongBranch.cpp +++ lib/Target/Mips/MipsLongBranch.cpp @@ -82,6 +82,7 @@ void replaceBranch(MachineBasicBlock &MBB, Iter Br, DebugLoc DL, MachineBasicBlock *MBBOpnd); void expandToLongBranch(MBBInfo &Info); + bool buildMMUncondBranchInst(MBBInfo &Info); const TargetMachine &TM; MachineFunction *MF; @@ -408,6 +409,26 @@ MBB.removeLiveIn(Mips::V0); } +bool MipsLongBranch::buildMMUncondBranchInst(MBBInfo &I) { + MachineBasicBlock::iterator Pos; + MachineBasicBlock *MBB = I.Br->getParent(); + MachineBasicBlock *TgtMBB = getTargetMBB(*I.Br); + DebugLoc DL = I.Br->getDebugLoc(); + const MipsInstrInfo *TII = + static_cast(TM.getInstrInfo()); + + Pos = MBB->begin(); + if (Pos->getOpcode() == (unsigned) Mips::B) { + BuildMI(*MBB, Pos, DL, TII->get(Mips::B16_MM)).addMBB(TgtMBB); + + MachineBasicBlock::instr_iterator II(Pos); + MIBundleBuilder(*MBB, Pos).append((++II)->removeFromBundle()); + Pos->eraseFromParent(); + } + + return true; +} + bool MipsLongBranch::runOnMachineFunction(MachineFunction &F) { const MipsInstrInfo *TII = static_cast(TM.getInstrInfo()); @@ -437,7 +458,15 @@ if (!I->Br || I->HasLongBranch) continue; - int ShVal = TM.getSubtarget().inMicroMipsMode() ? 2 : 4; + bool IsMicroMips = TM.getSubtarget().inMicroMipsMode(); + int ShVal = IsMicroMips ? 2 : 4; + + // Check if offset fits into 16-bit immediate field of branches. + if (IsMicroMips && !ForceLongBranch && I->Br->isUnconditionalBranch() && + isInt<10>(computeOffset(I->Br) / ShVal)) { + if (buildMMUncondBranchInst(*I)) + continue; + } // Check if offset fits into 16-bit immediate field of branches. if (!ForceLongBranch && isInt<16>(computeOffset(I->Br) / ShVal)) Index: test/MC/Mips/micromips-16-bit-instructions.s =================================================================== --- test/MC/Mips/micromips-16-bit-instructions.s +++ test/MC/Mips/micromips-16-bit-instructions.s @@ -13,6 +13,7 @@ # CHECK-EL: mflo $9 # encoding: [0x49,0x46] # CHECK-EL: move $25, $1 # encoding: [0x21,0x0f] # CHECK-EL: jalr $9 # encoding: [0xc9,0x45] +# CHECK-EL: b 132 # encoding: [0x42,0xcc] #------------------------------------------------------------------------------ # Big endian #------------------------------------------------------------------------------ @@ -20,8 +21,13 @@ # CHECK-EB: mflo $9 # encoding: [0x46,0x49] # CHECK-EB: move $25, $1 # encoding: [0x0f,0x21] # CHECK-EB: jalr $9 # encoding: [0x45,0xc9] +# CHECK-EB: b 132 # encoding: [0xcc,0x42] + + .text + .set noat mfhi $9 mflo $9 move $25, $1 jalr $9 + b 132 Index: test/MC/Mips/micromips-bad-branches.s =================================================================== --- test/MC/Mips/micromips-bad-branches.s +++ test/MC/Mips/micromips-bad-branches.s @@ -1,11 +1,11 @@ # RUN: not llvm-mc %s -triple=mipsel-unknown-linux -mcpu=mips32r2 -mattr=+msa -arch=mips -mattr=+micromips 2>&1 | FileCheck %s # # CHECK: error: branch to misaligned address -# CHECK: b -65535 +# CHECK: b -535 # CHECK: error: branch target out of range -# CHECK: b -65537 +# CHECK: b -65536 # CHECK: error: branch to misaligned address -# CHECK: b 65535 +# CHECK: b 535 # CHECK: error: branch target out of range # CHECK: b 65536 @@ -126,11 +126,11 @@ # CHECK: error: branch target out of range # CHECK: bc1t $fcc0, 65536 - b -65535 + b -535 b -65536 - b -65537 + b -537 b 65534 - b 65535 + b 535 b 65536 beq $1, $1, -65535 Index: test/MC/Mips/micromips-branch-instructions.s =================================================================== --- test/MC/Mips/micromips-branch-instructions.s +++ test/MC/Mips/micromips-branch-instructions.s @@ -9,8 +9,6 @@ #------------------------------------------------------------------------------ # Little endian #------------------------------------------------------------------------------ -# CHECK-EL: b 1332 # encoding: [0x00,0x94,0x9a,0x02] -# CHECK-EL: nop # encoding: [0x00,0x00,0x00,0x00] # CHECK-EL: beq $9, $6, 1332 # encoding: [0xc9,0x94,0x9a,0x02] # CHECK-EL: nop # encoding: [0x00,0x00,0x00,0x00] # CHECK-EL: bgez $6, 1332 # encoding: [0x46,0x40,0x9a,0x02] @@ -32,8 +30,6 @@ #------------------------------------------------------------------------------ # Big endian #------------------------------------------------------------------------------ -# CHECK-EB: b 1332 # encoding: [0x94,0x00,0x02,0x9a] -# CHECK-EB: nop # encoding: [0x00,0x00,0x00,0x00] # CHECK-EB: beq $9, $6, 1332 # encoding: [0x94,0xc9,0x02,0x9a] # CHECK-EB: nop # encoding: [0x00,0x00,0x00,0x00] # CHECK-EB: bgez $6, 1332 # encoding: [0x40,0x46,0x02,0x9a] @@ -53,7 +49,6 @@ # CHECK-EB: bltz $6, 1332 # encoding: [0x40,0x06,0x02,0x9a] # CHECK-EB: nop # encoding: [0x00,0x00,0x00,0x00] - b 1332 beq $9,$6,1332 bgez $6,1332 bgezal $6,1332 Index: test/MC/Mips/micromips-branch10.s =================================================================== --- /dev/null +++ test/MC/Mips/micromips-branch10.s @@ -0,0 +1,21 @@ +# 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: b bar # encoding: [A,0b110011AA] +# CHECK-FIXUP: # fixup A - offset: 0, +# CHECK-FIXUP: value: bar, kind: fixup_MICROMIPS_PC10_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_PC10_S1 +# CHECK-ELF: ] + + b bar Index: test/MC/Mips/micromips-branch16.s =================================================================== --- test/MC/Mips/micromips-branch16.s +++ test/MC/Mips/micromips-branch16.s @@ -7,10 +7,6 @@ # Check that the assembler can handle the documented syntax # for relocations. #------------------------------------------------------------------------------ -# CHECK-FIXUP: b bar # encoding: [A,0x94'A',0x00,0x00] -# CHECK-FIXUP: # fixup A - offset: 0, -# CHECK-FIXUP: value: bar, kind: fixup_MICROMIPS_PC16_S1 -# CHECK-FIXUP: nop # encoding: [0x00,0x00,0x00,0x00] # CHECK-FIXUP: beq $3, $4, bar # encoding: [0x83'A',0x94'A',0x00,0x00] # CHECK-FIXUP: # fixup A - offset: 0, # CHECK-FIXUP: value: bar, kind: fixup_MICROMIPS_PC16_S1 @@ -55,10 +51,8 @@ # CHECK-ELF: 0x{{[0-9,A-F]+}} R_MICROMIPS_PC16_S1 # CHECK-ELF: 0x{{[0-9,A-F]+}} R_MICROMIPS_PC16_S1 # CHECK-ELF: 0x{{[0-9,A-F]+}} R_MICROMIPS_PC16_S1 -# CHECK-ELF: 0x{{[0-9,A-F]+}} R_MICROMIPS_PC16_S1 # CHECK-ELF: ] - b bar beq $3, $4, bar bne $3, $4, bar bgez $4, bar Index: test/MC/Mips/micromips-diagnostic-fixup.s =================================================================== --- test/MC/Mips/micromips-diagnostic-fixup.s +++ test/MC/Mips/micromips-diagnostic-fixup.s @@ -1,6 +1,6 @@ # RUN: not llvm-mc %s -triple=mipsel-unknown-linux -mcpu=mips32r2 -arch=mips -mattr=+micromips 2>&1 -filetype=obj | FileCheck %s # -# CHECK: LLVM ERROR: out of range PC16 fixup +# CHECK: LLVM ERROR: out of range PC10 fixup .text b foo Index: test/MC/Mips/micromips-pc16-fixup.s =================================================================== --- test/MC/Mips/micromips-pc16-fixup.s +++ test/MC/Mips/micromips-pc16-fixup.s @@ -3,7 +3,7 @@ # CHECK-NOT: LLVM ERROR: out of range PC16 fixup .text - b foo + beq $0, $0, foo .space 65536 - 8, 1 # -8 = size of b instr plus size of automatically inserted nop foo: add $0,$0,$0