Index: lib/Target/Mips/AsmParser/MipsAsmParser.cpp =================================================================== --- lib/Target/Mips/AsmParser/MipsAsmParser.cpp +++ lib/Target/Mips/AsmParser/MipsAsmParser.cpp @@ -461,6 +461,8 @@ Match_RequiresSameSrcAndDst, Match_NoFCCRegisterForCurrentISA, Match_NonZeroOperandForSync, + Match_RequiresPosSizeRange0_32, + Match_RequiresPosSizeRange33_64, #define GET_OPERAND_DIAGNOSTIC_TYPES #include "MipsGenAsmMatcher.inc" #undef GET_OPERAND_DIAGNOSTIC_TYPES @@ -4891,6 +4893,28 @@ if (Inst.getOperand(0).getReg() == Inst.getOperand(1).getReg()) return Match_RequiresDifferentOperands; return Match_Success; + case Mips::DINS: + case Mips::DINS_MM64R6: { + assert(Inst.getOperand(2).isImm() && Inst.getOperand(3).isImm() && + "Operands must be immediates for dins!"); + const signed Pos = Inst.getOperand(2).getImm(); + const signed Size = Inst.getOperand(3).getImm(); + if ((0 > (Pos + Size)) || ((Pos + Size) > 32)) + return Match_RequiresPosSizeRange0_32; + return Match_Success; + } + case Mips::DINSM: + case Mips::DINSM_MM64R6: + case Mips::DINSU: + case Mips::DINSU_MM64R6: { + assert(Inst.getOperand(2).isImm() && Inst.getOperand(3).isImm() && + "Operands must be immediates for dinsm/dinsu!"); + const signed Pos = Inst.getOperand(2).getImm(); + const signed Size = Inst.getOperand(3).getImm(); + if ((32 >= (Pos + Size)) || ((Pos + Size) > 64)) + return Match_RequiresPosSizeRange33_64; + return Match_Success; + } } uint64_t TSFlags = getInstDesc(Inst.getOpcode()).TSFlags; @@ -5082,6 +5106,18 @@ case Match_MemSImm16: return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), "expected memory with 16-bit signed offset"); + case Match_RequiresPosSizeRange0_32: { + SMLoc ErrorStart = Operands[3]->getStartLoc(); + SMLoc ErrorEnd = Operands[4]->getEndLoc(); + return Error(ErrorStart, "size plus position are not in the range 0 .. 32", + SMRange(ErrorStart, ErrorEnd)); + } + case Match_RequiresPosSizeRange33_64: { + SMLoc ErrorStart = Operands[3]->getStartLoc(); + SMLoc ErrorEnd = Operands[4]->getEndLoc(); + return Error(ErrorStart, "size plus position are not in the range 33 .. 64", + SMRange(ErrorStart, ErrorEnd)); + } } llvm_unreachable("Implement any new match types added!"); Index: lib/Target/Mips/Disassembler/MipsDisassembler.cpp =================================================================== --- lib/Target/Mips/Disassembler/MipsDisassembler.cpp +++ lib/Target/Mips/Disassembler/MipsDisassembler.cpp @@ -523,6 +523,10 @@ DecodeBlezGroupBranchMMR6(MCInst &MI, InsnType insn, uint64_t Address, const void *Decoder); +template +static DecodeStatus DecodeDINS(MCInst &MI, InsnType Insn, uint64_t Address, + const void *Decoder); + static DecodeStatus DecodeRegListOperand(MCInst &Inst, unsigned Insn, uint64_t Address, const void *Decoder); @@ -1054,6 +1058,60 @@ return MCDisassembler::Success; } +// Override the generated disassembler to produce DINS all the time. This is +// for feature / behaviour parity with binutils. +template +static DecodeStatus DecodeDINS(MCInst &MI, InsnType Insn, uint64_t Address, + const void *Decoder) { + unsigned Msbd = fieldFromInstruction(Insn, 11, 5); + unsigned Lsb = fieldFromInstruction(Insn, 6, 5); + unsigned Size = 0; + unsigned Pos = 0; + bool IsMicroMips = false; + + switch (MI.getOpcode()) { + case Mips::DINS_MM64R6: + IsMicroMips = true; + LLVM_FALLTHROUGH; + case Mips::DINS: + Pos = Lsb; + Size = Msbd + 1 - Pos; + break; + case Mips::DINSM_MM64R6: + IsMicroMips = true; + LLVM_FALLTHROUGH; + case Mips::DINSM: + Pos = Lsb; + Size = Msbd + 33 - Pos; + break; + case Mips::DINSU_MM64R6: + IsMicroMips = true; + LLVM_FALLTHROUGH; + case Mips::DINSU: + Pos = Lsb + 32; + // mbsd = pos + size - 33 + // mbsd - pos + 33 = size + Size = Msbd + 33 - Pos; + break; + default: + llvm_unreachable("Unknown DINS instruction!"); + } + + // Although the format of the instruction is similar, rs and rt are swapped + // for microMIPS64R6. + InsnType Rs = fieldFromInstruction(Insn, 21, 5); + InsnType Rt = fieldFromInstruction(Insn, 16, 5); + if (IsMicroMips) + std::swap(Rs, Rt); + + MI.setOpcode(IsMicroMips ? Mips::DINS_MM64R6 : Mips::DINS); + MI.addOperand(MCOperand::createReg(getReg(Decoder, Mips::GPR64RegClassID, Rt))); + MI.addOperand(MCOperand::createReg(getReg(Decoder, Mips::GPR64RegClassID, Rs))); + MI.addOperand(MCOperand::createImm(Pos)); + MI.addOperand(MCOperand::createImm(Size)); + + return MCDisassembler::Success; +} /// Read two bytes from the ArrayRef and return 16 bit halfword sorted /// according to the given endianness. static DecodeStatus readInstruction16(ArrayRef Bytes, uint64_t Address, @@ -2263,15 +2321,10 @@ uint64_t Address, const void *Decoder) { // First we need to grab the pos(lsb) from MCInst. + // This function only handles the 32 bit variants of ins, as dins + // variants are handled differently. int Pos = Inst.getOperand(2).getImm(); - if (Inst.getOpcode() == Mips::DINSU) - Pos += 32; - int Size; - if (Inst.getOpcode() == Mips::DINSM || - Inst.getOpcode() == Mips::DINSU) - Size = (int) Insn - Pos + 33; - else - Size = (int) Insn - Pos + 1; + int Size = (int) Insn - Pos + 1; Inst.addOperand(MCOperand::createImm(SignExtend32<16>(Size))); return MCDisassembler::Success; } Index: lib/Target/Mips/MicroMips64r6InstrInfo.td =================================================================== --- lib/Target/Mips/MicroMips64r6InstrInfo.td +++ lib/Target/Mips/MicroMips64r6InstrInfo.td @@ -168,8 +168,9 @@ immZExt5Plus1, MipsIns>; class DINSM_MM64R6_DESC : InsBase<"dinsm", GPR64Opnd, uimm5, uimm_range_2_64, immZExt5, immZExtRange2To64, MipsIns>; -class DINS_MM64R6_DESC : InsBase<"dins", GPR64Opnd, uimm5, uimm5_inssize_plus1, - immZExt5, immZExt5Plus1, MipsIns>; +class DINS_MM64R6_DESC : InsBase<"dins", GPR64Opnd, uimm5_report_uimm6, + uimm5_inssize_plus1, immZExt5, immZExt5Plus1, + MipsIns>; class DMTC0_MM64R6_DESC : MTC0_MMR6_DESC_BASE<"dmtc0", COP0Opnd, GPR64Opnd, II_DMTC0>; class DMTC1_MM64R6_DESC : MTC1_MMR6_DESC_BASE<"dmtc1", FGR64Opnd, GPR64Opnd, @@ -382,12 +383,14 @@ ISA_MICROMIPS64R6; def DMODU_MM64R6 : R6MMR6Rel, DMODU_MM64R6_DESC, DMODU_MM64R6_ENC, ISA_MICROMIPS64R6; - def DINSU_MM64R6: R6MMR6Rel, DINSU_MM64R6_DESC, DINSU_MM64R6_ENC, - ISA_MICROMIPS64R6; - def DINSM_MM64R6: R6MMR6Rel, DINSM_MM64R6_DESC, DINSM_MM64R6_ENC, - ISA_MICROMIPS64R6; - def DINS_MM64R6: R6MMR6Rel, DINS_MM64R6_DESC, DINS_MM64R6_ENC, - ISA_MICROMIPS64R6; + let DecoderMethod = "DecodeDINS" in { + def DINSU_MM64R6: R6MMR6Rel, DINSU_MM64R6_DESC, DINSU_MM64R6_ENC, + ISA_MICROMIPS64R6; + def DINSM_MM64R6: R6MMR6Rel, DINSM_MM64R6_DESC, DINSM_MM64R6_ENC, + ISA_MICROMIPS64R6; + def DINS_MM64R6: R6MMR6Rel, DINS_MM64R6_DESC, DINS_MM64R6_ENC, + ISA_MICROMIPS64R6; + } def DMTC0_MM64R6 : StdMMR6Rel, DMTC0_MM64R6_ENC, DMTC0_MM64R6_DESC, ISA_MICROMIPS64R6; def DMTC1_MM64R6 : StdMMR6Rel, DMTC1_MM64R6_DESC, DMTC1_MM64R6_ENC, @@ -562,3 +565,10 @@ def : MipsInstAlias<"dsll $rd, $rt", (DSLLV_MM64R6 GPR64Opnd:$rd, GPR64Opnd:$rd, GPR32Opnd:$rt), 0>, ISA_MICROMIPS64R6; +def : MipsInstAlias<"dins $rt, $rs, $pos, $size", + (DINSM_MM64R6 GPR64Opnd:$rt, GPR64Opnd:$rs, uimm5:$pos, + uimm_range_2_64:$size), 0>, ISA_MICROMIPS64R6; +def : MipsInstAlias<"dins $rt, $rs, $pos, $size", + (DINSU_MM64R6 GPR64Opnd:$rt, GPR64Opnd:$rs, + uimm5_plus32:$pos, uimm5_plus1:$size), 0>, + ISA_MICROMIPS64R6; Index: lib/Target/Mips/Mips64InstrInfo.td =================================================================== --- lib/Target/Mips/Mips64InstrInfo.td +++ lib/Target/Mips/Mips64InstrInfo.td @@ -318,14 +318,23 @@ def DEXTU : ExtBase<"dextu", GPR64Opnd, uimm5_plus32, uimm5_plus1, immZExt5Plus32, immZExt5Plus1, MipsExt>, EXT_FM<2>, ISA_MIPS64R2; - def DINS : InsBase<"dins", GPR64Opnd, uimm6, uimm5_inssize_plus1, immZExt5, - immZExt5Plus1, MipsIns>, EXT_FM<7>, ISA_MIPS64R2; - def DINSU : InsBase<"dinsu", GPR64Opnd, uimm5_plus32, uimm5_inssize_plus1, - immZExt5Plus32, immZExt5Plus1, MipsIns>, - EXT_FM<6>, ISA_MIPS64R2; - def DINSM : InsBase<"dinsm", GPR64Opnd, uimm5, uimm5_inssize_plus1, - immZExt5, immZExtRange2To64, MipsIns>, - EXT_FM<5>, ISA_MIPS64R2; + // The 'pos + size' constraints for code generation are enforced by the + // code that lowers into MipsISD::Ins. + // For assembly parsing, we alias dinsu and dinsm to dins, and match by + // operand were possible then check the 'pos + size' in MipsAsmParser. + // We override the generated decoder to enforce that dins always comes out + // for dinsm and dinsu like binutils. + let DecoderMethod = "DecodeDINS" in { + def DINS : InsBase<"dins", GPR64Opnd, uimm6, uimm5_inssize_plus1, + immZExt5, immZExt5Plus1, MipsIns>, EXT_FM<7>, + ISA_MIPS64R2; + def DINSU : InsBase<"dinsu", GPR64Opnd, uimm5_plus32, uimm5_inssize_plus1, + immZExt5Plus32, immZExt5Plus1, MipsIns>, + EXT_FM<6>, ISA_MIPS64R2; + def DINSM : InsBase<"dinsm", GPR64Opnd, uimm5, uimm5_inssize_plus1, + immZExt5, immZExtRange2To64, MipsIns>, + EXT_FM<5>, ISA_MIPS64R2; + } } let isCodeGenOnly = 1, AdditionalPredicates = [NotInMicroMips] in { @@ -804,6 +813,12 @@ def : MipsInstAlias<"dsll $rd, $rt", (DSLLV GPR64Opnd:$rd, GPR64Opnd:$rd, GPR32Opnd:$rt), 0>, ISA_MIPS3; + def : MipsInstAlias<"dins $rt, $rs, $pos, $size", + (DINSM GPR64Opnd:$rt, GPR64Opnd:$rs, uimm5:$pos, + uimm_range_2_64:$size), 0>, ISA_MIPS64R2; + def : MipsInstAlias<"dins $rt, $rs, $pos, $size", + (DINSU GPR64Opnd:$rt, GPR64Opnd:$rs, uimm5_plus32:$pos, + uimm5_plus1:$size), 0>, ISA_MIPS64R2; // Two operand (implicit 0 selector) versions: def : MipsInstAlias<"dmtc0 $rt, $rd", Index: lib/Target/Mips/MipsInstrInfo.td =================================================================== --- lib/Target/Mips/MipsInstrInfo.td +++ lib/Target/Mips/MipsInstrInfo.td @@ -866,7 +866,7 @@ // Like uimm5 but reports a less confusing error for 32-63 when // an instruction alias permits that. def uimm5_report_uimm6 : Operand { - let PrintMethod = "printUImm<5>"; + let PrintMethod = "printUImm<6>"; let ParserMatchClass = ConstantUImm5ReportUImm6AsmOperandClass; } Index: test/MC/Disassembler/Mips/micromips64r6/valid.txt =================================================================== --- test/MC/Disassembler/Mips/micromips64r6/valid.txt +++ test/MC/Disassembler/Mips/micromips64r6/valid.txt @@ -189,8 +189,8 @@ 0x00 0x00 0x39 0x7c # CHECK: evp $zero 0x00 0x00 0x43 0x7c # CHECK: tlbinv 0x00 0x00 0x53 0x7c # CHECK: tlbinvf -0x58 0x82 0x20 0x34 # CHECK: dinsu $4, $2, 32, 5 -0x58 0x82 0x38 0xc4 # CHECK: dinsm $4, $2, 3, 5 +0x58 0x82 0x20 0x34 # CHECK: dins $4, $2, 32, 5 +0x58 0x82 0x48 0xc4 # CHECK: dins $4, $2, 3, 39 0x58 0x82 0x38 0xcc # CHECK: dins $4, $2, 3, 5 0x00 0xa9 0x02 0xfc # CHECK: mtc0 $5, $9, 0 0x00 0xa9 0x02 0xfc # CHECK: mtc0 $5, $9 Index: test/MC/Mips/micromips64r6/invalid-wrong-error.s =================================================================== --- test/MC/Mips/micromips64r6/invalid-wrong-error.s +++ test/MC/Mips/micromips64r6/invalid-wrong-error.s @@ -34,7 +34,6 @@ tne $8, $9, -1 # CHECK: :[[@LINE]]:15: error: expected 10-bit unsigned immediate tne $8, $9, 16 # CHECK: :[[@LINE]]:3: error: instruction requires a CPU feature not currently enabled dins $2, $3, -1, 1 # CHECK: :[[@LINE]]:16: error: expected 6-bit unsigned immediate - dins $2, $3, 32, 1 # CHECK: :[[@LINE]]:3: error: instruction requires a CPU feature not currently enabled syscall -1 # CHECK: :[[@LINE]]:11: error: expected 20-bit unsigned immediate syscall $4 # CHECK: :[[@LINE]]:11: error: expected 20-bit unsigned immediate syscall 1024 # CHECK: :[[@LINE]]:3: error: instruction requires a CPU feature not currently enabled Index: test/MC/Mips/micromips64r6/invalid.s =================================================================== --- test/MC/Mips/micromips64r6/invalid.s +++ test/MC/Mips/micromips64r6/invalid.s @@ -45,9 +45,7 @@ dextu $2, $3, 64, 1 # CHECK: :[[@LINE]]:17: error: expected immediate in range 32 .. 63 dextu $2, $3, 32, 0 # CHECK: :[[@LINE]]:21: error: expected immediate in range 1 .. 32 dextu $2, $3, 32, 33 # CHECK: :[[@LINE]]:21: error: expected immediate in range 1 .. 32 - dins $2, $3, 31, 33 # CHECK: :[[@LINE]]:20: error: expected immediate in range 1 .. 32 dins $2, $3, 31, 0 # CHECK: :[[@LINE]]:20: error: expected immediate in range 1 .. 32 - # FIXME: Check '32 <= pos + size <= 64' constraint on dinsm dinsm $2, $3, -1, 1 # CHECK: :[[@LINE]]:17: error: expected 5-bit unsigned immediate dinsm $2, $3, 32, 1 # CHECK: :[[@LINE]]:17: error: expected 5-bit unsigned immediate dinsm $2, $3, 31, 0 # CHECK: :[[@LINE]]:21: error: expected immediate in range 2 .. 64 Index: test/MC/Mips/micromips64r6/valid.s =================================================================== --- test/MC/Mips/micromips64r6/valid.s +++ test/MC/Mips/micromips64r6/valid.s @@ -198,7 +198,7 @@ tlbinv # CHECK: tlbinv # encoding: [0x00,0x00,0x43,0x7c] tlbinvf # CHECK: tlbinvf # encoding: [0x00,0x00,0x53,0x7c] dinsu $4, $2, 32, 5 # CHECK: dinsu $4, $2, 32, 5 # encoding: [0x58,0x82,0x20,0x34] - dinsm $4, $2, 3, 5 # CHECK: dinsm $4, $2, 3, 5 # encoding: [0x58,0x82,0x38,0xc4] + dinsm $4, $2, 31, 5 # CHECK: dinsm $4, $2, 31, 5 # encoding: [0x58,0x82,0x1f,0xc4] dins $4, $2, 3, 5 # CHECK: dins $4, $2, 3, 5 # encoding: [0x58,0x82,0x38,0xcc] lh $2, 8($4) # CHECK: lh $2, 8($4) # encoding: [0x3c,0x44,0x00,0x08] lhe $4, 8($2) # CHECK: lhe $4, 8($2) # encoding: [0x60,0x82,0x6a,0x08] Index: test/MC/Mips/mips64extins.s =================================================================== --- test/MC/Mips/mips64extins.s +++ test/MC/Mips/mips64extins.s @@ -1,9 +1,25 @@ # RUN: llvm-mc -arch=mips64el -filetype=obj -mcpu=mips64r2 -target-abi=n64 %s -o - \ -# RUN: | llvm-objdump -disassemble - | FileCheck %s +# RUN: | llvm-objdump -disassemble - | FileCheck --check-prefix=OBJ %s +# RUN: llvm-mc -arch=mips64el -filetype=obj -mcpu=mips64r6 -mattr=+micromips \ +# RUN: -target-abi=n64 %s -o - | llvm-objdump -disassemble - \ +# RUN: | FileCheck --check-prefix=OBJ %s - dext $2, $4, 5, 10 # CHECK: dext ${{[0-9]+}}, ${{[0-9]+}}, 5, 10 - dextu $2, $4, 34, 6 # CHECK: dextu ${{[0-9]+}}, ${{[0-9]+}}, 34, 6 - dextm $2, $4, 5, 34 # CHECK: dextm ${{[0-9]+}}, ${{[0-9]+}}, 5, 34 - dins $4, $5, 8, 10 # CHECK: dins ${{[0-9]+}}, ${{[0-9]+}}, 8, 10 - dinsm $4, $5, 30, 6 # CHECK: dinsm ${{[0-9]+}}, ${{[0-9]+}}, 30, 6 - dinsu $4, $5, 40, 13 # CHECK: dinsu ${{[0-9]+}}, ${{[0-9]+}}, 40, 13 +# RUN: llvm-mc -arch=mips64el -mcpu=mips64r2 -target-abi=n64 %s -o - \ +# RUN: | FileCheck --check-prefix=ASM %s +# RUN: llvm-mc -arch=mips64el -mcpu=mips64r6 -mattr=+micromips -target-abi=n64 \ +# RUN: %s -o - | FileCheck --check-prefix=ASM %s + + dext $2, $4, 5, 10 # OBJ: dext ${{[0-9]+}}, ${{[0-9]+}}, 5, 10 + dextu $2, $4, 34, 6 # OBJ: dextu ${{[0-9]+}}, ${{[0-9]+}}, 34, 6 + dextm $2, $4, 5, 34 # OBJ: dextm ${{[0-9]+}}, ${{[0-9]+}}, 5, 34 + dins $4, $5, 8, 10 # OBJ: dins ${{[0-9]+}}, ${{[0-9]+}}, 8, 10 + dinsm $4, $5, 30, 6 # OBJ: dins ${{[0-9]+}}, ${{[0-9]+}}, 30, 6 + dinsu $4, $5, 40, 13 # OBJ: dins ${{[0-9]+}}, ${{[0-9]+}}, 40, 13 + # check the aliases + dins $2, $4, 5, 10 # OBJ: dins ${{[0-9]+}}, ${{[0-9]+}}, 5, 10 + dins $2, $4, 34, 6 # OBJ: dins ${{[0-9]+}}, ${{[0-9]+}}, 34, 6 + dins $2, $4, 5, 34 # OBJ: dins ${{[0-9]+}}, ${{[0-9]+}}, 5, 34 + # check the edge values + dins $3, $4, 31, 1 # ASM: dins $3, $4, 31, 1 + dins $3, $4, 31, 33 # ASM: dinsm $3, $4, 31, 33 + dins $3, $4, 32, 32 # ASM: dinsu $3, $4, 32, 32