From ea4f653d18e74439f0abefe5861d05fea9ddf5d0 Mon Sep 17 00:00:00 2001 From: Daniel Sanders Date: Fri, 6 Nov 2015 12:22:31 +0000 Subject: [mips][ias] Range check uimm2 operands and fix a bug this revealed. Summary: The bug was that the MIPS32R6/MIPS64R6/microMIPS32R6 versions of LSA and DLSA (unlike the MSA version) failed to account for the off-by-one encoding of the immediate. The range is actually 1..4 rather than 0..3. Reviewers: vkalintiris Subscribers: atanasyan, dsanders, llvm-commits Differential Revision: http://reviews.llvm.org/D14015 llvm-svn: 252295 --- llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp | 16 +++++++++--- .../Target/Mips/Disassembler/MipsDisassembler.cpp | 21 +++++++--------- .../Target/Mips/MCTargetDesc/MipsMCCodeEmitter.cpp | 12 +++++---- .../Target/Mips/MCTargetDesc/MipsMCCodeEmitter.h | 9 ++++--- llvm/lib/Target/Mips/MicroMips32r6InstrInfo.td | 2 +- llvm/lib/Target/Mips/Mips32r6InstrInfo.td | 2 +- llvm/lib/Target/Mips/Mips64r6InstrInfo.td | 2 +- llvm/lib/Target/Mips/MipsInstrInfo.td | 29 +++++++++++++++++++--- llvm/lib/Target/Mips/MipsMSAInstrInfo.td | 17 +------------ 9 files changed, 64 insertions(+), 46 deletions(-) (limited to 'llvm/lib') diff --git a/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp b/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp index 09ae6a5d43c..aea022a336f 100644 --- a/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp +++ b/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp @@ -387,7 +387,6 @@ public: #define GET_OPERAND_DIAGNOSTIC_TYPES #include "MipsGenAsmMatcher.inc" #undef GET_OPERAND_DIAGNOSTIC_TYPES - }; MipsAsmParser(MCSubtargetInfo &sti, MCAsmParser &parser, @@ -894,10 +893,12 @@ public: Inst.addOperand(MCOperand::createReg(getHWRegsReg())); } - template + template void addConstantUImmOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); - uint64_t Imm = getConstantImm() & ((1 << Bits) - 1); + uint64_t Imm = getConstantImm() - Offset; + Imm &= (1 << Bits) - 1; + Imm += Offset; Inst.addOperand(MCOperand::createImm(Imm)); } @@ -963,6 +964,9 @@ public: bool isConstantImmz() const { return isConstantImm() && getConstantImm() == 0; } + template bool isConstantUImm() const { + return isConstantImm() && isUInt(getConstantImm() - Offset); + } template bool isUImm() const { return isImm() && isConstantImm() && isUInt(getConstantImm()); } @@ -3296,6 +3300,12 @@ bool MipsAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, return Error(IDLoc, "source and destination must be different"); case Match_Immz: return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), "expected '0'"); + case Match_UImm2_0: + return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), + "expected 2-bit unsigned immediate"); + case Match_UImm2_1: + return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), + "expected immediate in range 1 .. 4"); } llvm_unreachable("Implement any new match types added!"); diff --git a/llvm/lib/Target/Mips/Disassembler/MipsDisassembler.cpp b/llvm/lib/Target/Mips/Disassembler/MipsDisassembler.cpp index 121b49c8691..6332e1d52c4 100644 --- a/llvm/lib/Target/Mips/Disassembler/MipsDisassembler.cpp +++ b/llvm/lib/Target/Mips/Disassembler/MipsDisassembler.cpp @@ -380,12 +380,9 @@ static DecodeStatus DecodeSimm16(MCInst &Inst, uint64_t Address, const void *Decoder); -// Decode the immediate field of an LSA instruction which -// is off by one. -static DecodeStatus DecodeLSAImm(MCInst &Inst, - unsigned Insn, - uint64_t Address, - const void *Decoder); +template +static DecodeStatus DecodeUImmWithOffset(MCInst &Inst, unsigned Value, + uint64_t Address, const void *Decoder); static DecodeStatus DecodeInsSize(MCInst &Inst, unsigned Insn, @@ -1908,12 +1905,12 @@ static DecodeStatus DecodeSimm16(MCInst &Inst, return MCDisassembler::Success; } -static DecodeStatus DecodeLSAImm(MCInst &Inst, - unsigned Insn, - uint64_t Address, - const void *Decoder) { - // We add one to the immediate field as it was encoded as 'imm - 1'. - Inst.addOperand(MCOperand::createImm(Insn + 1)); +template +static DecodeStatus DecodeUImmWithOffset(MCInst &Inst, unsigned Value, + uint64_t Address, + const void *Decoder) { + Value &= ((1 << Bits) - 1); + Inst.addOperand(MCOperand::createImm(Value + Offset)); return MCDisassembler::Success; } diff --git a/llvm/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.cpp b/llvm/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.cpp index bd6afcb1fe1..861049f000f 100644 --- a/llvm/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.cpp +++ b/llvm/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.cpp @@ -869,13 +869,15 @@ MipsMCCodeEmitter::getSizeInsEncoding(const MCInst &MI, unsigned OpNo, return Position + Size - 1; } +template unsigned -MipsMCCodeEmitter::getLSAImmEncoding(const MCInst &MI, unsigned OpNo, - SmallVectorImpl &Fixups, - const MCSubtargetInfo &STI) const { +MipsMCCodeEmitter::getUImmWithOffsetEncoding(const MCInst &MI, unsigned OpNo, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const { assert(MI.getOperand(OpNo).isImm()); - // The immediate is encoded as 'immediate - 1'. - return getMachineOpValue(MI, MI.getOperand(OpNo), Fixups, STI) - 1; + unsigned Value = getMachineOpValue(MI, MI.getOperand(OpNo), Fixups, STI); + Value -= Offset; + return Value; } unsigned diff --git a/llvm/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.h b/llvm/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.h index 56f286ab3d9..c2f4b6a72bb 100644 --- a/llvm/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.h +++ b/llvm/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.h @@ -191,10 +191,11 @@ public: SmallVectorImpl &Fixups, const MCSubtargetInfo &STI) const; - // getLSAImmEncoding - Return binary encoding of LSA immediate. - unsigned getLSAImmEncoding(const MCInst &MI, unsigned OpNo, - SmallVectorImpl &Fixups, - const MCSubtargetInfo &STI) const; + /// Subtract Offset then encode as a N-bit unsigned integer. + template + unsigned getUImmWithOffsetEncoding(const MCInst &MI, unsigned OpNo, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const; unsigned getSimm19Lsl2Encoding(const MCInst &MI, unsigned OpNo, SmallVectorImpl &Fixups, diff --git a/llvm/lib/Target/Mips/MicroMips32r6InstrInfo.td b/llvm/lib/Target/Mips/MicroMips32r6InstrInfo.td index f33ccf29543..572ba784c0d 100644 --- a/llvm/lib/Target/Mips/MicroMips32r6InstrInfo.td +++ b/llvm/lib/Target/Mips/MicroMips32r6InstrInfo.td @@ -426,7 +426,7 @@ class LSA_MMR6_DESC_BASE Pattern = []; } -class LSA_MMR6_DESC : LSA_MMR6_DESC_BASE<"lsa", GPR32Opnd, uimm2>; +class LSA_MMR6_DESC : LSA_MMR6_DESC_BASE<"lsa", GPR32Opnd, uimm2_plus1>; class PCREL_MMR6_DESC_BASE : MMR6Arch { diff --git a/llvm/lib/Target/Mips/Mips32r6InstrInfo.td b/llvm/lib/Target/Mips/Mips32r6InstrInfo.td index 8a6ae21e52e..9dd4d1e034e 100644 --- a/llvm/lib/Target/Mips/Mips32r6InstrInfo.td +++ b/llvm/lib/Target/Mips/Mips32r6InstrInfo.td @@ -597,7 +597,7 @@ class LSA_R6_DESC_BASE Pattern = []; } -class LSA_R6_DESC : LSA_R6_DESC_BASE<"lsa", GPR32Opnd, uimm2>; +class LSA_R6_DESC : LSA_R6_DESC_BASE<"lsa", GPR32Opnd, uimm2_plus1>; class LL_R6_DESC_BASE { dag OutOperandList = (outs GPROpnd:$rt); diff --git a/llvm/lib/Target/Mips/Mips64r6InstrInfo.td b/llvm/lib/Target/Mips/Mips64r6InstrInfo.td index 3102849721d..6f34dbe28d3 100644 --- a/llvm/lib/Target/Mips/Mips64r6InstrInfo.td +++ b/llvm/lib/Target/Mips/Mips64r6InstrInfo.td @@ -62,7 +62,7 @@ class DCLO_R6_DESC : CLO_R6_DESC_BASE<"dclo", GPR64Opnd>; class DCLZ_R6_DESC : CLZ_R6_DESC_BASE<"dclz", GPR64Opnd>; class DDIV_DESC : DIVMOD_DESC_BASE<"ddiv", GPR64Opnd, sdiv>; class DDIVU_DESC : DIVMOD_DESC_BASE<"ddivu", GPR64Opnd, udiv>; -class DLSA_R6_DESC : LSA_R6_DESC_BASE<"dlsa", GPR64Opnd, uimm2>; +class DLSA_R6_DESC : LSA_R6_DESC_BASE<"dlsa", GPR64Opnd, uimm2_plus1>; class DMOD_DESC : DIVMOD_DESC_BASE<"dmod", GPR64Opnd, srem>; class DMODU_DESC : DIVMOD_DESC_BASE<"dmodu", GPR64Opnd, urem>; class DMUH_DESC : MUL_R6_DESC_BASE<"dmuh", GPR64Opnd, mulhs>; diff --git a/llvm/lib/Target/Mips/MipsInstrInfo.td b/llvm/lib/Target/Mips/MipsInstrInfo.td index 0a32967b515..c0e62a56781 100644 --- a/llvm/lib/Target/Mips/MipsInstrInfo.td +++ b/llvm/lib/Target/Mips/MipsInstrInfo.td @@ -381,11 +381,24 @@ include "MipsInstrFormats.td" // Mips Operand, Complex Patterns and Transformations Definitions. //===----------------------------------------------------------------------===// +class ConstantUImmAsmOperandClass Supers = [], + int Offset = 0> : AsmOperandClass { + let Name = "ConstantUImm" # Bits # "_" # Offset; + let RenderMethod = "addConstantUImmOperands<" # Bits # ", " # Offset # ">"; + let PredicateMethod = "isConstantUImm<" # Bits # ", " # Offset # ">"; + let SuperClasses = Supers; + let DiagnosticType = "UImm" # Bits # "_" # Offset; +} + +def ConstantUImm2Plus1AsmOperandClass + : ConstantUImmAsmOperandClass<2, [], 1>; +def ConstantUImm2AsmOperandClass + : ConstantUImmAsmOperandClass<2>; def ConstantImmzAsmOperandClass : AsmOperandClass { let Name = "ConstantImmz"; let RenderMethod = "addConstantUImmOperands<1>"; let PredicateMethod = "isConstantImmz"; - let SuperClasses = []; + let SuperClasses = [ConstantUImm2AsmOperandClass]; let DiagnosticType = "Immz"; } @@ -461,9 +474,19 @@ def uimmz : Operand { let ParserMatchClass = ConstantImmzAsmOperandClass; } -// Unsigned Operand -def uimm2 : Operand { +// Unsigned Operands +foreach I = {2} in + def uimm # I : Operand { + let PrintMethod = "printUnsignedImm"; + let ParserMatchClass = + !cast("ConstantUImm" # I # "AsmOperandClass"); + } + +def uimm2_plus1 : Operand { let PrintMethod = "printUnsignedImm"; + let EncoderMethod = "getUImmWithOffsetEncoding<2, 1>"; + let DecoderMethod = "DecodeUImmWithOffset<2, 1>"; + let ParserMatchClass = ConstantUImm2Plus1AsmOperandClass; } def uimm3 : Operand { diff --git a/llvm/lib/Target/Mips/MipsMSAInstrInfo.td b/llvm/lib/Target/Mips/MipsMSAInstrInfo.td index 64bae3b5417..f3e08499bf9 100644 --- a/llvm/lib/Target/Mips/MipsMSAInstrInfo.td +++ b/llvm/lib/Target/Mips/MipsMSAInstrInfo.td @@ -70,21 +70,6 @@ def immZExt6Ptr : ImmLeaf(Imm);}]>; // Operands -// The immediate of an LSA instruction needs special handling -// as the encoded value should be subtracted by one. -def uimm2LSAAsmOperand : AsmOperandClass { - let Name = "LSAImm"; - let ParserMethod = "parseLSAImm"; - let RenderMethod = "addImmOperands"; -} - -def LSAImm : Operand { - let PrintMethod = "printUnsignedImm"; - let EncoderMethod = "getLSAImmEncoding"; - let DecoderMethod = "DecodeLSAImm"; - let ParserMatchClass = uimm2LSAAsmOperand; -} - def uimm4 : Operand { let PrintMethod = "printUnsignedImm8"; } @@ -2380,7 +2365,7 @@ class LSA_DESC_BASE { dag OutOperandList = (outs RORD:$rd); - dag InOperandList = (ins RORS:$rs, RORT:$rt, LSAImm:$sa); + dag InOperandList = (ins RORS:$rs, RORT:$rt, uimm2_plus1:$sa); string AsmString = !strconcat(instr_asm, "\t$rd, $rs, $rt, $sa"); list Pattern = [(set RORD:$rd, (add RORT:$rt, (shl RORS:$rs, -- cgit v1.2.3