Skip to content

Commit

Permalink
[mips][ias] Range check uimm5 operands and fix several bugs this reve…
Browse files Browse the repository at this point in the history
…aled.

Summary:
The bugs were:
* append, prepend, and balign were not tested
* balign takes a uimm2 not a uimm5.
* drotr32 was correctly implemented with a uimm5 but the tests expected
  '52' to be valid.
* li/la were implemented with a uimm5 instead of simm32. simm32 isn't
  completely correct either but I'll fix that when I get to simm32.

A notable omission are some of the shift instructions. Several of these
have been implemented using a single uimm6 instruction (rather than two
uimm5 instructions and a CodeGen-only uimm6 pseudo). These will be updated
in the uimm6 patch.

Reviewers: vkalintiris

Subscribers: llvm-commits, dsanders

Differential Revision: http://reviews.llvm.org/D14712

llvm-svn: 254164
  • Loading branch information
dsandersllvm committed Nov 26, 2015
1 parent e4fbec4 commit daa4b6f
Showing 23 changed files with 312 additions and 135 deletions.
59 changes: 20 additions & 39 deletions llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp
Original file line number Diff line number Diff line change
@@ -928,12 +928,13 @@ class MipsOperand : public MCParsedAsmOperand {
Inst.addOperand(MCOperand::createReg(getHWRegsReg()));
}

template <unsigned Bits, int Offset = 0>
template <unsigned Bits, int Offset = 0, int AdjustOffset = 0>
void addConstantUImmOperands(MCInst &Inst, unsigned N) const {
assert(N == 1 && "Invalid number of operands!");
uint64_t Imm = getConstantImm() - Offset;
Imm &= (1 << Bits) - 1;
Imm += Offset;
Imm += AdjustOffset;
Inst.addOperand(MCOperand::createImm(Imm));
}

@@ -1034,8 +1035,10 @@ class MipsOperand : public MCParsedAsmOperand {
&& (getConstantMemOff() % 4 == 0) && getMemBase()->isRegIdx()
&& (getMemBase()->getGPR32Reg() == Mips::SP);
}
bool isUImm5Lsl2() const {
return (isImm() && isConstantImm() && isShiftedUInt<5, 2>(getConstantImm()));
template <unsigned Bits, unsigned ShiftLeftAmount>
bool isScaledUImm() const {
return isConstantImm() &&
isShiftedUInt<Bits, ShiftLeftAmount>(getConstantImm());
}
bool isRegList16() const {
if (!isRegList())
@@ -1620,32 +1623,6 @@ bool MipsAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc,
}
break;

case Mips::CINS:
case Mips::CINS32:
case Mips::EXTS:
case Mips::EXTS32:
assert(MCID.getNumOperands() == 4 && "unexpected number of operands");
// Check length
Opnd = Inst.getOperand(3);
if (!Opnd.isImm())
return Error(IDLoc, "expected immediate operand kind");
Imm = Opnd.getImm();
if (Imm < 0 || Imm > 31)
return Error(IDLoc, "immediate operand value out of range");
// Check position
Opnd = Inst.getOperand(2);
if (!Opnd.isImm())
return Error(IDLoc, "expected immediate operand kind");
Imm = Opnd.getImm();
if (Imm < 0 || Imm > (Opcode == Mips::CINS ||
Opcode == Mips::EXTS ? 63 : 31))
return Error(IDLoc, "immediate operand value out of range");
if (Imm > 31) {
Inst.setOpcode(Opcode == Mips::CINS ? Mips::CINS32 : Mips::EXTS32);
Inst.getOperand(2).setImm(Imm - 32);
}
break;

case Mips::SEQi:
case Mips::SNEi:
assert(MCID.getNumOperands() == 3 && "unexpected number of operands");
@@ -1909,16 +1886,6 @@ bool MipsAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc,
if (Imm < 0 || Imm > 60 || (Imm % 4 != 0))
return Error(IDLoc, "immediate operand value out of range");
break;
case Mips::PREFX_MM:
case Mips::CACHE:
case Mips::PREF:
Opnd = Inst.getOperand(2);
if (!Opnd.isImm())
return Error(IDLoc, "expected immediate operand kind");
Imm = Opnd.getImm();
if (!isUInt<5>(Imm))
return Error(IDLoc, "immediate operand value out of range");
break;
case Mips::ADDIUPC_MM:
MCOperand Opnd = Inst.getOperand(1);
if (!Opnd.isImm())
@@ -3666,6 +3633,20 @@ bool MipsAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
case Match_UImm4_0:
return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo),
"expected 4-bit unsigned immediate");
case Match_UImm5_0:
return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo),
"expected 5-bit unsigned immediate");
case Match_UImm5_32:
return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo),
"expected immediate in range 32 .. 63");
case Match_UImm5_0_Report_UImm6:
// This is used on UImm5 operands that have a corresponding UImm5_32
// operand to avoid confusing the user.
return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo),
"expected 6-bit unsigned immediate");
case Match_UImm5_Lsl2:
return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo),
"expected both 7-bit unsigned immediate and multiple of 4");
}

llvm_unreachable("Implement any new match types added!");
13 changes: 0 additions & 13 deletions llvm/lib/Target/Mips/MicroMipsInstrInfo.td
Original file line number Diff line number Diff line change
@@ -13,19 +13,6 @@ def simm12 : Operand<i32> {
let DecoderMethod = "DecodeSimm12";
}

def MipsUimm5Lsl2AsmOperand : AsmOperandClass {
let Name = "Uimm5Lsl2";
let RenderMethod = "addImmOperands";
let ParserMethod = "parseImm";
let PredicateMethod = "isUImm5Lsl2";
}

def uimm5_lsl2 : Operand<OtherVT> {
let EncoderMethod = "getUImm5Lsl2Encoding";
let DecoderMethod = "DecodeUImm5lsl2";
let ParserMatchClass = MipsUimm5Lsl2AsmOperand;
}

def uimm6_lsl2 : Operand<i32> {
let EncoderMethod = "getUImm6Lsl2Encoding";
let DecoderMethod = "DecodeUImm6Lsl2";
53 changes: 42 additions & 11 deletions llvm/lib/Target/Mips/Mips64InstrInfo.td
Original file line number Diff line number Diff line change
@@ -16,10 +16,6 @@
//===----------------------------------------------------------------------===//

// Unsigned Operand
def uimm5_64 : Operand<i64> {
let PrintMethod = "printUnsignedImm";
}

def uimm16_64 : Operand<i64> {
let PrintMethod = "printUnsignedImm";
}
@@ -343,8 +339,8 @@ class SetCC64_I<string opstr, PatFrag cond_op>:
}

class CBranchBitNum<string opstr, DAGOperand opnd, PatFrag cond_op,
RegisterOperand RO, bits<64> shift = 1> :
InstSE<(outs), (ins RO:$rs, uimm5_64:$p, opnd:$offset),
RegisterOperand RO, Operand ImmOp, bits<64> shift = 1> :
InstSE<(outs), (ins RO:$rs, ImmOp:$p, opnd:$offset),
!strconcat(opstr, "\t$rs, $p, $offset"),
[(brcond (i32 (cond_op (and RO:$rs, (shl shift, immZExt5_64:$p)), 0)),
bb:$offset)], II_BBIT, FrmI, opstr> {
@@ -365,14 +361,17 @@ def BADDu : ArithLogicR<"baddu", GPR64Opnd, 1, II_BADDU>,
ADD_FM<0x1c, 0x28>;

// Branch on Bit Clear /+32
def BBIT0 : CBranchBitNum<"bbit0", brtarget, seteq, GPR64Opnd>, BBIT_FM<0x32>;
def BBIT032: CBranchBitNum<"bbit032", brtarget, seteq, GPR64Opnd, 0x100000000>,
def BBIT0 : CBranchBitNum<"bbit0", brtarget, seteq, GPR64Opnd,
uimm5_64_report_uimm6>, BBIT_FM<0x32>;
def BBIT032: CBranchBitNum<"bbit032", brtarget, seteq, GPR64Opnd, uimm5_64,
0x100000000>,
BBIT_FM<0x36>;

// Branch on Bit Set /+32
def BBIT1 : CBranchBitNum<"bbit1", brtarget, setne, GPR64Opnd>, BBIT_FM<0x3a>;
def BBIT132: CBranchBitNum<"bbit132", brtarget, setne, GPR64Opnd, 0x100000000>,
BBIT_FM<0x3e>;
def BBIT1 : CBranchBitNum<"bbit1", brtarget, setne, GPR64Opnd,
uimm5_64_report_uimm6>, BBIT_FM<0x3a>;
def BBIT132: CBranchBitNum<"bbit132", brtarget, setne, GPR64Opnd, uimm5_64,
0x100000000>, BBIT_FM<0x3e>;

// Multiply Doubleword to GPR
let Defs = [HI0, LO0, P0, P1, P2] in
@@ -634,6 +633,38 @@ def : MipsInstAlias<"syncw", (SYNC 0x4), 0>;
def : MipsInstAlias<"syncws", (SYNC 0x5), 0>;
}

// cnMIPS Aliases.

// bbit* with $p 32-63 converted to bbit*32 with $p 0-31
def : MipsInstAlias<"bbit0 $rs, $p, $offset",
(BBIT032 GPR64Opnd:$rs, uimm5_plus32_normalize_64:$p,
brtarget:$offset), 0>,
ASE_CNMIPS;
def : MipsInstAlias<"bbit1 $rs, $p, $offset",
(BBIT132 GPR64Opnd:$rs, uimm5_plus32_normalize_64:$p,
brtarget:$offset), 0>,
ASE_CNMIPS;

// exts with $pos 32-63 in converted to exts32 with $pos 0-31
def : MipsInstAlias<"exts $rt, $rs, $pos, $lenm1",
(EXTS32 GPR64Opnd:$rt, GPR64Opnd:$rs,
uimm5_plus32_normalize:$pos, uimm5:$lenm1), 0>,
ASE_CNMIPS;
def : MipsInstAlias<"exts $rt, $pos, $lenm1",
(EXTS32 GPR64Opnd:$rt, GPR64Opnd:$rt,
uimm5_plus32_normalize:$pos, uimm5:$lenm1), 0>,
ASE_CNMIPS;

// cins with $pos 32-63 in converted to cins32 with $pos 0-31
def : MipsInstAlias<"cins $rt, $rs, $pos, $lenm1",
(CINS32 GPR64Opnd:$rt, GPR64Opnd:$rs,
uimm5_plus32_normalize:$pos, uimm5:$lenm1), 0>,
ASE_CNMIPS;
def : MipsInstAlias<"cins $rt, $pos, $lenm1",
(CINS32 GPR64Opnd:$rt, GPR64Opnd:$rt,
uimm5_plus32_normalize:$pos, uimm5:$lenm1), 0>,
ASE_CNMIPS;

//===----------------------------------------------------------------------===//
// Assembler Pseudo Instructions
//===----------------------------------------------------------------------===//
14 changes: 7 additions & 7 deletions llvm/lib/Target/Mips/MipsDSPInstrInfo.td
Original file line number Diff line number Diff line change
@@ -372,12 +372,12 @@ class ADDUH_QB_DESC_BASE<string instr_asm, SDPatternOperator OpNode,
}

class APPEND_DESC_BASE<string instr_asm, SDPatternOperator OpNode,
SDPatternOperator ImmOp, InstrItinClass itin> {
Operand ImmOp, SDPatternOperator Imm, InstrItinClass itin> {
dag OutOperandList = (outs GPR32Opnd:$rt);
dag InOperandList = (ins GPR32Opnd:$rs, uimm5:$sa, GPR32Opnd:$src);
dag InOperandList = (ins GPR32Opnd:$rs, ImmOp:$sa, GPR32Opnd:$src);
string AsmString = !strconcat(instr_asm, "\t$rt, $rs, $sa");
list<dag> Pattern = [(set GPR32Opnd:$rt,
(OpNode GPR32Opnd:$src, GPR32Opnd:$rs, ImmOp:$sa))];
(OpNode GPR32Opnd:$src, GPR32Opnd:$rs, Imm:$sa))];
InstrItinClass Itinerary = itin;
string Constraints = "$src = $rt";
}
@@ -1074,14 +1074,14 @@ class SHRLV_PH_DESC : SHLL_QB_R3_DESC_BASE<"shrlv.ph", int_mips_shrl_ph,
NoItinerary, DSPROpnd>;

// Misc
class APPEND_DESC : APPEND_DESC_BASE<"append", int_mips_append, immZExt5,
class APPEND_DESC : APPEND_DESC_BASE<"append", int_mips_append, uimm5, immZExt5,
NoItinerary>;

class BALIGN_DESC : APPEND_DESC_BASE<"balign", int_mips_balign, immZExt2,
class BALIGN_DESC : APPEND_DESC_BASE<"balign", int_mips_balign, uimm2, immZExt2,
NoItinerary>;

class PREPEND_DESC : APPEND_DESC_BASE<"prepend", int_mips_prepend, immZExt5,
NoItinerary>;
class PREPEND_DESC : APPEND_DESC_BASE<"prepend", int_mips_prepend, uimm5,
immZExt5, NoItinerary>;

// Pseudos.
def BPOSGE32_PSEUDO : BPOSGE32_PSEUDO_DESC_BASE<int_mips_bposge32,
65 changes: 58 additions & 7 deletions llvm/lib/Target/Mips/MipsInstrInfo.td
Original file line number Diff line number Diff line change
@@ -311,6 +311,10 @@ class INSN_MIPS5_32R2_NOT_32R6_64R6 {
list<Predicate> InsnPredicates = [HasMips5_32r2, NotMips32r6, NotMips64r6];
}

class ASE_CNMIPS {
list<Predicate> InsnPredicates = [HasCnMips];
}

class ASE_MSA {
list<Predicate> InsnPredicates = [HasMSA];
}
@@ -390,8 +394,29 @@ class ConstantUImmAsmOperandClass<int Bits, list<AsmOperandClass> Supers = [],
let DiagnosticType = "UImm" # Bits # "_" # Offset;
}

def ConstantUImm5Plus32NormalizeAsmOperandClass
: ConstantUImmAsmOperandClass<5, [], 32> {
// We must also subtract 32 when we render the operand.
let RenderMethod = "addConstantUImmOperands<5, 32, -32>";
}
def ConstantUImm5Lsl2AsmOperandClass : AsmOperandClass {
let Name = "UImm5Lsl2";
let RenderMethod = "addImmOperands";
let PredicateMethod = "isScaledUImm<5, 2>";
let SuperClasses = [];
let DiagnosticType = "UImm5_Lsl2";
}
def ConstantUImm5ReportUImm6AsmOperandClass
: ConstantUImmAsmOperandClass<5, []> {
let Name = "ConstantUImm5_0_Report_UImm6";
let DiagnosticType = "UImm5_0_Report_UImm6";
}
def ConstantUImm5AsmOperandClass
: ConstantUImmAsmOperandClass<5, []>;
def ConstantUImm4AsmOperandClass
: ConstantUImmAsmOperandClass<4, []>;
: ConstantUImmAsmOperandClass<
4, [ConstantUImm5AsmOperandClass,
ConstantUImm5Plus32NormalizeAsmOperandClass]>;
def ConstantUImm3AsmOperandClass
: ConstantUImmAsmOperandClass<3, [ConstantUImm4AsmOperandClass]>;
def ConstantUImm2Plus1AsmOperandClass
@@ -453,8 +478,8 @@ def simm18_lsl3 : Operand<i32> {
let ParserMatchClass = MipsJumpTargetAsmOperand;
}

def simm20 : Operand<i32> {
}
def simm20 : Operand<i32>;
def simm32 : Operand<i32>;

def uimm20 : Operand<i32> {
}
@@ -481,7 +506,7 @@ def uimmz : Operand<i32> {
}

// Unsigned Operands
foreach I = {1, 2, 3, 4} in
foreach I = {1, 2, 3, 4, 5} in
def uimm # I : Operand<i32> {
let PrintMethod = "printUnsignedImm";
let ParserMatchClass =
@@ -495,8 +520,34 @@ def uimm2_plus1 : Operand<i32> {
let ParserMatchClass = ConstantUImm2Plus1AsmOperandClass;
}

def uimm5 : Operand<i32> {
def uimm5_plus32_normalize : Operand<i32> {
let PrintMethod = "printUnsignedImm";
let ParserMatchClass = ConstantUImm5Plus32NormalizeAsmOperandClass;
}

def uimm5_lsl2 : Operand<OtherVT> {
let EncoderMethod = "getUImm5Lsl2Encoding";
let DecoderMethod = "DecodeUImm5lsl2";
let ParserMatchClass = ConstantUImm5Lsl2AsmOperandClass;
}

def uimm5_plus32_normalize_64 : Operand<i64> {
let PrintMethod = "printUnsignedImm";
let ParserMatchClass = ConstantUImm5Plus32NormalizeAsmOperandClass;
}

foreach I = {5} in
def uimm # I # _64 : Operand<i64> {
let PrintMethod = "printUnsignedImm";
let ParserMatchClass =
!cast<AsmOperandClass>("ConstantUImm" # I # "AsmOperandClass");
}

// Like uimm5_64 but reports a less confusing error for 32-63 when
// an instruction alias permits that.
def uimm5_64_report_uimm6 : Operand<i64> {
let PrintMethod = "printUnsignedImm";
let ParserMatchClass = ConstantUImm5ReportUImm6AsmOperandClass;
}

def uimm6 : Operand<i32> {
@@ -1847,7 +1898,7 @@ def : MipsInstAlias<"sync",
class LoadImmediate32<string instr_asm, Operand Od, RegisterOperand RO> :
MipsAsmPseudoInst<(outs RO:$rt), (ins Od:$imm32),
!strconcat(instr_asm, "\t$rt, $imm32")> ;
def LoadImm32 : LoadImmediate32<"li", uimm5, GPR32Opnd>;
def LoadImm32 : LoadImmediate32<"li", simm32, GPR32Opnd>;

class LoadAddressFromReg32<string instr_asm, Operand MemOpnd,
RegisterOperand RO> :
@@ -1858,7 +1909,7 @@ def LoadAddrReg32 : LoadAddressFromReg32<"la", mem, GPR32Opnd>;
class LoadAddressFromImm32<string instr_asm, Operand Od, RegisterOperand RO> :
MipsAsmPseudoInst<(outs RO:$rt), (ins Od:$imm32),
!strconcat(instr_asm, "\t$rt, $imm32")> ;
def LoadAddrImm32 : LoadAddressFromImm32<"la", uimm5, GPR32Opnd>;
def LoadAddrImm32 : LoadAddressFromImm32<"la", simm32, GPR32Opnd>;

def JalTwoReg : MipsAsmPseudoInst<(outs GPR32Opnd:$rd), (ins GPR32Opnd:$rs),
"jal\t$rd, $rs"> ;
15 changes: 15 additions & 0 deletions llvm/test/MC/Mips/cnmips/invalid.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Instructions that are invalid
#
# RUN: not llvm-mc %s -triple=mips64-unknown-linux -show-encoding -mcpu=octeon 2>%t1
# RUN: FileCheck %s < %t1

.set noat
foo:
bbit0 $19, -1, foo # CHECK: :[[@LINE]]:16: error: expected 6-bit unsigned immediate
bbit0 $19, 64, foo # CHECK: :[[@LINE]]:16: error: expected 6-bit unsigned immediate
bbit032 $19, -1, foo # CHECK: :[[@LINE]]:18: error: expected 5-bit unsigned immediate
bbit032 $19, 32, foo # CHECK: :[[@LINE]]:18: error: expected 5-bit unsigned immediate
bbit1 $19, -1, foo # CHECK: :[[@LINE]]:16: error: expected 6-bit unsigned immediate
bbit1 $19, 64, foo # CHECK: :[[@LINE]]:16: error: expected 6-bit unsigned immediate
bbit132 $19, -1, foo # CHECK: :[[@LINE]]:18: error: expected 5-bit unsigned immediate
bbit132 $19, 32, foo # CHECK: :[[@LINE]]:18: error: expected 5-bit unsigned immediate
15 changes: 13 additions & 2 deletions llvm/test/MC/Mips/dspr2/invalid.s
Original file line number Diff line number Diff line change
@@ -1,6 +1,17 @@
# RUN: not llvm-mc %s -triple=mips-unknown-unknown -show-encoding -mattr=dspr2 2>%t1
# Instructions that are invalid
#
# RUN: not llvm-mc %s -triple=mips-unknown-linux -mattr=+dspr2 -show-encoding 2>%t1
# RUN: FileCheck %s < %t1

append $2, $3, -1 # CHECK: :[[@LINE]]:18: error: expected 5-bit unsigned immediate
append $2, $3, 32 # CHECK: :[[@LINE]]:18: error: expected 5-bit unsigned immediate
balign $2, $3, -1 # CHECK: :[[@LINE]]:18: error: expected 2-bit unsigned immediate
balign $2, $3, 4 # CHECK: :[[@LINE]]:18: error: expected 2-bit unsigned immediate
precr_sra.ph.w $24, $25, -1 # CHECK: :[[@LINE]]:28: error: expected 5-bit unsigned immediate
precr_sra.ph.w $24, $25, 32 # CHECK: :[[@LINE]]:28: error: expected 5-bit unsigned immediate
precr_sra_r.ph.w $25 ,$26, -1 # CHECK: :[[@LINE]]:30: error: expected 5-bit unsigned immediate
precr_sra_r.ph.w $25 ,$26, 32 # CHECK: :[[@LINE]]:30: error: expected 5-bit unsigned immediate
prepend $2, $3, -1 # CHECK: :[[@LINE]]:19: error: expected 5-bit unsigned immediate
prepend $2, $3, 32 # CHECK: :[[@LINE]]:19: error: expected 5-bit unsigned immediate
shra.qb $3, $4, 8 # CHECK: :[[@LINE]]:19: error: expected 3-bit unsigned immediate
shra.qb $3, $4, -1 # CHECK: :[[@LINE]]:19: error: expected 3-bit unsigned immediate
shra_r.qb $3, $4, 8 # CHECK: :[[@LINE]]:21: error: expected 3-bit unsigned immediate
3 changes: 3 additions & 0 deletions llvm/test/MC/Mips/dspr2/valid.s
Original file line number Diff line number Diff line change
@@ -43,3 +43,6 @@
mflo $15 # CHECK: mflo $15 # encoding: [0x00,0x00,0x78,0x12]
mthi $16 # CHECK: mthi $16 # encoding: [0x02,0x00,0x00,0x11]
mtlo $17 # CHECK: mtlo $17 # encoding: [0x02,0x20,0x00,0x13]
append $2, $3, 3 # CHECK: append $2, $3, 3 # encoding: [0x7c,0x62,0x18,0x31]
balign $4, $5, 1 # CHECK: balign $4, $5, 1 # encoding: [0x7c,0xa4,0x0c,0x31]
prepend $6, $7, 4 # CHECK: prepend $6, $7, 4 # encoding: [0x7c,0xe6,0x20,0x71]
Loading

0 comments on commit daa4b6f

Please sign in to comment.