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
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;
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!");
DecodeBlezGroupBranchMMR6(MCInst &MI, InsnType insn, uint64_t Address,
const void *Decoder);
+template <typename InsnType>
+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);
return MCDisassembler::Success;
}
+// Override the generated disassembler to produce DINS all the time. This is
+// for feature / behaviour parity with binutils.
+template <typename InsnType>
+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<uint8_t> Bytes, uint64_t Address,
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;
}
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,
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,
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;
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, uimm_range_2_64,
- 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, uimm_range_2_64,
+ immZExt5, immZExtRange2To64, MipsIns>,
+ EXT_FM<5>, ISA_MIPS64R2;
+ }
}
let isCodeGenOnly = 1, AdditionalPredicates = [NotInMicroMips] in {
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",
// Like uimm5 but reports a less confusing error for 32-63 when
// an instruction alias permits that.
def uimm5_report_uimm6 : Operand<i32> {
- let PrintMethod = "printUImm<5>";
+ let PrintMethod = "printUImm<6>";
let ParserMatchClass = ConstantUImm5ReportUImm6AsmOperandClass;
}
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
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
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
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]
# 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