Index: lib/Target/Mips/AsmParser/MipsAsmParser.cpp =================================================================== --- lib/Target/Mips/AsmParser/MipsAsmParser.cpp +++ lib/Target/Mips/AsmParser/MipsAsmParser.cpp @@ -1207,6 +1207,17 @@ 1LL << (inMicroMipsMode() ? 1 : 2))) return Error(IDLoc, "branch to misaligned address"); break; + case Mips::BEQZ16_MM: + case Mips::BNEZ16_MM: + assert(MCID.getNumOperands() == 2 && "unexpected number of operands"); + Offset = Inst.getOperand(1); + if (!Offset.isImm()) + break; // We'll deal with this situation later on when applying fixups. + if (!isIntN(8, Offset.getImm())) + return Error(IDLoc, "branch target out of range"); + if (OffsetToAlignment(Offset.getImm(), 2LL)) + return Error(IDLoc, "branch to misaligned address"); + break; } } Index: lib/Target/Mips/Disassembler/MipsDisassembler.cpp =================================================================== --- lib/Target/Mips/Disassembler/MipsDisassembler.cpp +++ lib/Target/Mips/Disassembler/MipsDisassembler.cpp @@ -228,6 +228,13 @@ uint64_t Address, const void *Decoder); +// DecodeBranchTarget7MM - Decode microMIPS branch offset, which is +// shifted left by 1 bit. +static DecodeStatus DecodeBranchTarget7MM(MCInst &Inst, + unsigned Offset, + uint64_t Address, + const void *Decoder); + // DecodeBranchTargetMM - Decode microMIPS branch offset, which is // shifted left by 1 bit. static DecodeStatus DecodeBranchTargetMM(MCInst &Inst, @@ -1540,6 +1547,15 @@ return MCDisassembler::Success; } +static DecodeStatus DecodeBranchTarget7MM(MCInst &Inst, + unsigned Offset, + uint64_t Address, + const void *Decoder) { + int32_t BranchOffset = SignExtend32<7>(Offset) << 1; + Inst.addOperand(MCOperand::CreateImm(BranchOffset)); + return MCDisassembler::Success; +} + static DecodeStatus DecodeBranchTargetMM(MCInst &Inst, unsigned Offset, uint64_t Address, Index: lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp =================================================================== --- lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp +++ lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp @@ -103,6 +103,14 @@ case Mips::fixup_MICROMIPS_26_S1: Value >>= 1; break; + case Mips::fixup_MICROMIPS_PC7_S1: + Value -= 4; + // Forcing a signed division because Value can be negative. + Value = (int64_t) Value / 2; + // We now check if Value can be encoded as a 7-bit signed immediate. + if (!isIntN(7, Value) && Ctx) + Ctx->FatalError(Fixup.getLoc(), "out of range PC7 fixup"); + break; case Mips::fixup_MICROMIPS_PC16_S1: Value -= 4; // Forcing a signed division because Value can be negative. @@ -271,6 +279,7 @@ { "fixup_MICROMIPS_HI16", 0, 16, 0 }, { "fixup_MICROMIPS_LO16", 0, 16, 0 }, { "fixup_MICROMIPS_GOT16", 0, 16, 0 }, + { "fixup_MICROMIPS_PC7_S1", 0, 7, 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 }, @@ -334,6 +343,7 @@ { "fixup_MICROMIPS_HI16", 16, 16, 0 }, { "fixup_MICROMIPS_LO16", 16, 16, 0 }, { "fixup_MICROMIPS_GOT16", 16, 16, 0 }, + { "fixup_MICROMIPS_PC7_S1", 9, 7, MCFixupKindInfo::FKF_IsPCRel }, { "fixup_MICROMIPS_PC16_S1",16, 16, MCFixupKindInfo::FKF_IsPCRel }, { "fixup_MICROMIPS_CALL16", 16, 16, 0 }, { "fixup_MICROMIPS_GOT_DISP", 16, 16, 0 }, Index: lib/Target/Mips/MCTargetDesc/MipsELFObjectWriter.cpp =================================================================== --- lib/Target/Mips/MCTargetDesc/MipsELFObjectWriter.cpp +++ lib/Target/Mips/MCTargetDesc/MipsELFObjectWriter.cpp @@ -162,6 +162,9 @@ case Mips::fixup_MICROMIPS_GOT16: Type = ELF::R_MICROMIPS_GOT16; break; + case Mips::fixup_MICROMIPS_PC7_S1: + Type = ELF::R_MICROMIPS_PC7_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 @@ -158,6 +158,9 @@ // resulting in - R_MICROMIPS_GOT16 fixup_MICROMIPS_GOT16, + // resulting in - R_MICROMIPS_PC7_S1 + fixup_MICROMIPS_PC7_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 @@ -101,6 +101,13 @@ SmallVectorImpl &Fixups, const MCSubtargetInfo &STI) const; + // getBranchTarget7OpValue - Return binary encoding of the microMIPS branch + // target operand. If the machine operand requires relocation, + // record the relocation and return zero. + unsigned getBranchTarget7OpValueMM(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 @@ -220,6 +220,28 @@ return 0; } +/// getBranchTarget7OpValueMM - Return binary encoding of the microMIPS branch +/// target operand. If the machine operand requires relocation, +/// record the relocation and return zero. +unsigned MipsMCCodeEmitter:: +getBranchTarget7OpValueMM(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() && + "getBranchTargetOpValueMM expects only expressions or immediates"); + + const MCExpr *Expr = MO.getExpr(); + Fixups.push_back(MCFixup::Create(0, Expr, + MCFixupKind(Mips::fixup_MICROMIPS_PC7_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 @@ -227,6 +227,17 @@ let Inst{3-0} = code_; } +class BEQNEZ_FM_MM16 op> { + bits<3> rs; + bits<7> offset; + + bits<16> Inst; + + let Inst{15-10} = op; + let Inst{9-7} = rs; + let Inst{6-0} = offset; +} + //===----------------------------------------------------------------------===// // MicroMIPS 32-bit Instruction Formats //===----------------------------------------------------------------------===// Index: lib/Target/Mips/MicroMipsInstrInfo.td =================================================================== --- lib/Target/Mips/MicroMipsInstrInfo.td +++ lib/Target/Mips/MicroMipsInstrInfo.td @@ -128,6 +128,13 @@ let EncoderMethod = "getJumpTargetOpValueMM"; } +def brtarget7_mm : Operand { + let EncoderMethod = "getBranchTarget7OpValueMM"; + let OperandType = "OPERAND_PCREL"; + let DecoderMethod = "DecodeBranchTarget7MM"; + let ParserMatchClass = MipsJumpTargetAsmOperand; +} + def brtarget_mm : Operand { let EncoderMethod = "getBranchTargetOpValueMM"; let OperandType = "OPERAND_PCREL"; @@ -382,6 +389,15 @@ !strconcat(opstr, "\t$code_"), [], NoItinerary, FrmOther>; +class CBranchZeroMM : + MicroMipsInst16<(outs), (ins RO:$rs, opnd:$offset), + !strconcat(opstr, "\t$rs, $offset"), [], IIBranch, FrmI> { + let isBranch = 1; + let isTerminator = 1; + let hasDelaySlot = 1; + let Defs = [AT]; +} + // MicroMIPS Jump and Link (Call) - Short Delay Slot let isCall = 1, hasDelaySlot = 1, Defs = [RA] in { class JumpLinkMM : @@ -512,6 +528,10 @@ def JRC16_MM : JumpRegCMM16<"jrc", GPR32Opnd>, JALR_FM_MM16<0x0d>; def JRADDIUSP : JumpRAddiuStackMM16, JRADDIUSP_FM_MM16<0x18>; def JR16_MM : JumpRegMM16<"jr16", GPR32Opnd>, JALR_FM_MM16<0x0c>; +def BEQZ16_MM : CBranchZeroMM<"beqz16", brtarget7_mm, GPRMM16Opnd>, + BEQNEZ_FM_MM16<0x23>; +def BNEZ16_MM : CBranchZeroMM<"bnez16", brtarget7_mm, GPRMM16Opnd>, + BEQNEZ_FM_MM16<0x2b>; def BREAK16_MM : BrkSdbbp16MM<"break16">, BRKSDBBP16_FM_MM<0x28>; def SDBBP16_MM : BrkSdbbp16MM<"sdbbp16">, BRKSDBBP16_FM_MM<0x2C>; Index: lib/Target/Mips/MipsLongBranch.cpp =================================================================== --- lib/Target/Mips/MipsLongBranch.cpp +++ lib/Target/Mips/MipsLongBranch.cpp @@ -247,6 +247,10 @@ } // Expand branch instructions to long branches. +// TODO: This function has to be fixed for beqz16 and bnez16, because it +// currently assumes that all branches have 16-bit offsets, and will produce +// wrong code if branches whose allowed offsets are [-128, -126, ..., 126] +// are present. void MipsLongBranch::expandToLongBranch(MBBInfo &I) { MachineBasicBlock::iterator Pos; MachineBasicBlock *MBB = I.Br->getParent(), *TgtMBB = getTargetMBB(*I.Br); Index: test/MC/Disassembler/Mips/micromips.txt =================================================================== --- test/MC/Disassembler/Mips/micromips.txt +++ test/MC/Disassembler/Mips/micromips.txt @@ -468,3 +468,9 @@ # CHECK: sw $4, 124($sp) 0xc8 0x9f + +# CHECK: beqz16 $6, 20 +0x8f 0x0a + +# CHECK: bnez16 $6, 20 +0xaf 0x0a Index: test/MC/Disassembler/Mips/micromips_le.txt =================================================================== --- test/MC/Disassembler/Mips/micromips_le.txt +++ test/MC/Disassembler/Mips/micromips_le.txt @@ -468,3 +468,9 @@ # CHECK: sw $4, 124($sp) 0x9f 0xc8 + +# CHECK: beqz16 $6, 20 +0x0a 0x8f + +# CHECK: bnez16 $6, 20 +0x0a 0xaf 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 @@ -49,6 +49,10 @@ # CHECK-EL: nop # encoding: [0x00,0x0c] # CHECK-EL: jr16 $9 # encoding: [0x89,0x45] # CHECK-EL: nop # encoding: [0x00,0x00,0x00,0x00] +# CHECK-EL: beqz16 $6, 20 # encoding: [0x0a,0x8f] +# CHECK-EL: nop # encoding: [0x00,0x00,0x00,0x00] +# CHECK-EL: bnez16 $6, 20 # encoding: [0x0a,0xaf] +# CHECK-EL: nop # encoding: [0x00,0x00,0x00,0x00] # CHECK-EL: break16 8 # encoding: [0x88,0x46] # CHECK-EL: sdbbp16 14 # encoding: [0xce,0x46] #------------------------------------------------------------------------------ @@ -94,6 +98,10 @@ # CHECK-EB: nop # encoding: [0x0c,0x00] # CHECK-EB: jr16 $9 # encoding: [0x45,0x89] # CHECK-EB: nop # encoding: [0x00,0x00,0x00,0x00] +# CHECK-EB: beqz16 $6, 20 # encoding: [0x8f,0x0a] +# CHECK-EB: nop # encoding: [0x00,0x00,0x00,0x00] +# CHECK-EB: bnez16 $6, 20 # encoding: [0xaf,0x0a] +# CHECK-EB: nop # encoding: [0x00,0x00,0x00,0x00] # CHECK-EB: break16 8 # encoding: [0x46,0x88] # CHECK-EB: sdbbp16 14 # encoding: [0x46,0xce] @@ -135,5 +143,7 @@ jraddiusp 20 jalrs16 $9 jr16 $9 + beqz16 $6, 20 + bnez16 $6, 20 break16 8 sdbbp16 14 Index: test/MC/Mips/micromips-bad-branches.s =================================================================== --- test/MC/Mips/micromips-bad-branches.s +++ test/MC/Mips/micromips-bad-branches.s @@ -126,6 +126,11 @@ # CHECK: error: branch target out of range # CHECK: bc1t $fcc0, 65536 +# CHECK: error: branch to misaligned address +# CHECK: beqz16 $6, 31 +# CHECK: error: branch target out of range +# CHECK: beqz16 $6, 130 + b -65535 b -65536 b -65537 @@ -223,3 +228,6 @@ bc1t $fcc0, 65534 bc1t $fcc0, 65535 bc1t $fcc0, 65536 + + beqz16 $6, 31 + beqz16 $6, 130 Index: test/MC/Mips/micromips-branch7.s =================================================================== --- /dev/null +++ test/MC/Mips/micromips-branch7.s @@ -0,0 +1,27 @@ +# 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: beqz16 $6, bar # encoding: [0b0AAAAAAA,0x8f] +# CHECK-FIXUP: # fixup A - offset: 0, +# CHECK-FIXUP: value: bar, kind: fixup_MICROMIPS_PC7_S1 +# CHECK-FIXUP: nop # encoding: [0x00,0x00,0x00,0x00] +# CHECK-FIXUP: bnez16 $6, bar # encoding: [0b0AAAAAAA,0xaf] +# CHECK-FIXUP: # fixup A - offset: 0, +# CHECK-FIXUP: value: bar, kind: fixup_MICROMIPS_PC7_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_PC7_S1 +# CHECK-ELF: 0x{{[0-9,A-F]+}} R_MICROMIPS_PC7_S1 +# CHECK-ELF: ] + + beqz16 $6, bar + bnez16 $6, bar Index: test/MC/Mips/micromips-invalid.s =================================================================== --- test/MC/Mips/micromips-invalid.s +++ test/MC/Mips/micromips-invalid.s @@ -64,3 +64,5 @@ sw16 $7, 4($10) # CHECK: :[[@LINE]]:{{[0-9]+}}: error: invalid operand for instruction cache 256, 8($5) # CHECK: :[[@LINE]]:{{[0-9]+}}: error: immediate operand value out of range pref 256, 8($5) # CHECK: :[[@LINE]]:{{[0-9]+}}: error: immediate operand value out of range + beqz16 $9, 20 # CHECK: :[[@LINE]]:{{[0-9]+}}: error: invalid operand for instruction + bnez16 $9, 20 # CHECK: :[[@LINE]]:{{[0-9]+}}: error: invalid operand for instruction