Skip to content

Commit

Permalink
[mips] Implement the 'dins' aliases.
Browse files Browse the repository at this point in the history
Traditionally GAS has provided automatic selection between dins, dinsm and
dinsu. Binutils also disassembles all instructions in that family as 'dins'
rather than the actual instruction.

Reviewers: slthakur

Differential Revision: https://reviews.llvm.org/D34877

llvm-svn: 313267
  • Loading branch information
Simon Dardis committed Sep 14, 2017
1 parent 1863307 commit 6f83ae3
Show file tree
Hide file tree
Showing 10 changed files with 165 additions and 38 deletions.
36 changes: 36 additions & 0 deletions llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp
Expand Up @@ -463,6 +463,8 @@ class MipsAsmParser : public MCTargetAsmParser {
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
Expand Down Expand Up @@ -4977,6 +4979,28 @@ unsigned MipsAsmParser::checkTargetMatchPredicate(MCInst &Inst) {
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;
Expand Down Expand Up @@ -5169,6 +5193,18 @@ bool MipsAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
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!");
Expand Down
69 changes: 61 additions & 8 deletions llvm/lib/Target/Mips/Disassembler/MipsDisassembler.cpp
Expand Up @@ -519,6 +519,10 @@ static DecodeStatus
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);
Expand Down Expand Up @@ -1051,6 +1055,60 @@ static DecodeStatus DecodeBlezGroupBranch(MCInst &MI, InsnType insn,
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,
Expand Down Expand Up @@ -2260,15 +2318,10 @@ static DecodeStatus DecodeInsSize(MCInst &Inst,
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;
}
Expand Down
26 changes: 18 additions & 8 deletions llvm/lib/Target/Mips/MicroMips64r6InstrInfo.td
Expand Up @@ -168,8 +168,9 @@ class DINSU_MM64R6_DESC : InsBase<"dinsu", GPR64Opnd, uimm5_plus32,
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,
Expand Down Expand Up @@ -382,12 +383,14 @@ let DecoderNamespace = "MicroMipsR6" in {
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,
Expand Down Expand Up @@ -562,3 +565,10 @@ def : MipsInstAlias<"dsrl $rd, $rt",
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;
31 changes: 23 additions & 8 deletions llvm/lib/Target/Mips/Mips64InstrInfo.td
Expand Up @@ -327,14 +327,23 @@ let AdditionalPredicates = [NotInMicroMips] in {
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 {
Expand Down Expand Up @@ -825,6 +834,12 @@ let 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",
Expand Down
2 changes: 1 addition & 1 deletion llvm/lib/Target/Mips/MipsInstrInfo.td
Expand Up @@ -883,7 +883,7 @@ def uimm16_altrelaxed : Operand<i32> {
// 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;
}

Expand Down
4 changes: 2 additions & 2 deletions llvm/test/MC/Disassembler/Mips/micromips64r6/valid.txt
Expand Up @@ -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
Expand Down
1 change: 0 additions & 1 deletion llvm/test/MC/Mips/micromips64r6/invalid-wrong-error.s
Expand Up @@ -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
Expand Down
2 changes: 0 additions & 2 deletions llvm/test/MC/Mips/micromips64r6/invalid.s
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion llvm/test/MC/Mips/micromips64r6/valid.s
Expand Up @@ -198,7 +198,7 @@ a:
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]
Expand Down
30 changes: 23 additions & 7 deletions llvm/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

0 comments on commit 6f83ae3

Please sign in to comment.