diff --git a/lib/Target/Mips/AsmParser/MipsAsmParser.cpp b/lib/Target/Mips/AsmParser/MipsAsmParser.cpp index ae9d2764fb2..16260857c24 100644 --- a/lib/Target/Mips/AsmParser/MipsAsmParser.cpp +++ b/lib/Target/Mips/AsmParser/MipsAsmParser.cpp @@ -236,6 +236,12 @@ class MipsAsmParser : public MCTargetAsmParser { bool processInstruction(MCInst &Inst, SMLoc IDLoc, SmallVectorImpl &Instructions); + + // Helper function that checks if the value of a vector index is within the + // boundaries of accepted values for each RegisterKind + // Example: INSERT.B $w0[n], $1 => 16 > n >= 0 + bool validateMSAIndex(int Val, int RegKind); + public: MipsAsmParser(MCSubtargetInfo &sti, MCAsmParser &parser, const MCInstrInfo &MII) @@ -1547,6 +1553,26 @@ MipsAsmParser::parseRegs(SmallVectorImpl &Operands, return MatchOperand_NoMatch; } +bool MipsAsmParser::validateMSAIndex(int Val, int RegKind) { + MipsOperand::RegisterKind Kind = (MipsOperand::RegisterKind)RegKind; + + if (Val < 0) + return false; + + switch (Kind) { + default: + return false; + case MipsOperand::Kind_MSA128BRegs: + return Val < 16; + case MipsOperand::Kind_MSA128HRegs: + return Val < 8; + case MipsOperand::Kind_MSA128WRegs: + return Val < 4; + case MipsOperand::Kind_MSA128DRegs: + return Val < 2; + } +} + MipsAsmParser::OperandMatchResultTy MipsAsmParser::parseMSARegs(SmallVectorImpl &Operands, int RegKind) { @@ -1589,6 +1615,102 @@ MipsAsmParser::parseMSARegs(SmallVectorImpl &Operands, Parser.Lex(); // Eat the register identifier. + // MSA registers may be suffixed with an index in the form of: + // 1) Immediate expression. + // 2) General Purpose Register. + // Examples: + // 1) copy_s.b $29,$w0[0] + // 2) sld.b $w0,$w1[$1] + + if (Parser.getTok().isNot(AsmToken::LBrac)) + return MatchOperand_Success; + + MipsOperand *Mnemonic = static_cast(Operands[0]); + + Operands.push_back(MipsOperand::CreateToken("[", Parser.getTok().getLoc())); + Parser.Lex(); // Parse the '[' token. + + if (Parser.getTok().is(AsmToken::Dollar)) { + // This must be a GPR. + MipsOperand *RegOp; + SMLoc VIdx = Parser.getTok().getLoc(); + Parser.Lex(); // Parse the '$' token. + + // GPR have aliases and we must account for that. Example: $30 == $fp + if (getLexer().getKind() == AsmToken::Integer) { + unsigned RegNum = Parser.getTok().getIntVal(); + int Reg = matchRegisterByNumber( + RegNum, regKindToRegClass(MipsOperand::Kind_GPR32)); + if (Reg == -1) { + Error(VIdx, "invalid general purpose register"); + return MatchOperand_ParseFail; + } + + RegOp = MipsOperand::CreateReg(Reg, VIdx, Parser.getTok().getLoc()); + } else if (getLexer().getKind() == AsmToken::Identifier) { + int RegNum = -1; + std::string RegName = Parser.getTok().getString().lower(); + + RegNum = matchCPURegisterName(RegName); + if (RegNum == -1) { + Error(VIdx, "general purpose register expected"); + return MatchOperand_ParseFail; + } + RegNum = getReg(regKindToRegClass(MipsOperand::Kind_GPR32), RegNum); + RegOp = MipsOperand::CreateReg(RegNum, VIdx, Parser.getTok().getLoc()); + } else + return MatchOperand_ParseFail; + + RegOp->setRegKind(MipsOperand::Kind_GPR32); + Operands.push_back(RegOp); + Parser.Lex(); // Eat the register identifier. + + if (Parser.getTok().isNot(AsmToken::RBrac)) + return MatchOperand_ParseFail; + + Operands.push_back(MipsOperand::CreateToken("]", Parser.getTok().getLoc())); + Parser.Lex(); // Parse the ']' token. + + return MatchOperand_Success; + } + + // The index must be a constant expression then. + SMLoc VIdx = Parser.getTok().getLoc(); + const MCExpr *ImmVal; + + if (getParser().parseExpression(ImmVal)) + return MatchOperand_ParseFail; + + const MCConstantExpr *expr = dyn_cast(ImmVal); + if (!expr || !validateMSAIndex((int)expr->getValue(), Kind)) { + Error(VIdx, "invalid immediate value"); + return MatchOperand_ParseFail; + } + + SMLoc E = Parser.getTok().getEndLoc(); + + if (Parser.getTok().isNot(AsmToken::RBrac)) + return MatchOperand_ParseFail; + + bool insve = Mnemonic->getToken() == "insve.b" || + Mnemonic->getToken() == "insve.h" || + Mnemonic->getToken() == "insve.w" || + Mnemonic->getToken() == "insve.d"; + + // The second vector index of insve instructions is always 0. + if (insve && Operands.size() > 6) { + if (expr->getValue() != 0) { + Error(VIdx, "immediate value must be 0"); + return MatchOperand_ParseFail; + } + Operands.push_back(MipsOperand::CreateToken("0", VIdx)); + } else + Operands.push_back(MipsOperand::CreateImm(expr, VIdx, E)); + + Operands.push_back(MipsOperand::CreateToken("]", Parser.getTok().getLoc())); + + Parser.Lex(); // Parse the ']' token. + return MatchOperand_Success; } diff --git a/lib/Target/Mips/MipsMSAInstrFormats.td b/lib/Target/Mips/MipsMSAInstrFormats.td index 2744c90d841..579e6e3ad17 100644 --- a/lib/Target/Mips/MipsMSAInstrFormats.td +++ b/lib/Target/Mips/MipsMSAInstrFormats.td @@ -133,6 +133,45 @@ class MSA_ELM_D_FMT major, bits<6> minor>: MSAInst { let Inst{5-0} = minor; } +class MSA_ELM_INSERT_B_FMT major, bits<6> minor>: MSAInst { + bits<6> n; + bits<5> rs; + bits<5> wd; + + let Inst{25-22} = major; + let Inst{21-20} = 0b00; + let Inst{19-16} = n{3-0}; + let Inst{15-11} = rs; + let Inst{10-6} = wd; + let Inst{5-0} = minor; +} + +class MSA_ELM_INSERT_H_FMT major, bits<6> minor>: MSAInst { + bits<6> n; + bits<5> rs; + bits<5> wd; + + let Inst{25-22} = major; + let Inst{21-19} = 0b100; + let Inst{18-16} = n{2-0}; + let Inst{15-11} = rs; + let Inst{10-6} = wd; + let Inst{5-0} = minor; +} + +class MSA_ELM_INSERT_W_FMT major, bits<6> minor>: MSAInst { + bits<6> n; + bits<5> rs; + bits<5> wd; + + let Inst{25-22} = major; + let Inst{21-18} = 0b1100; + let Inst{17-16} = n{1-0}; + let Inst{15-11} = rs; + let Inst{10-6} = wd; + let Inst{5-0} = minor; +} + class MSA_I5_FMT major, bits<2> df, bits<6> minor>: MSAInst { bits<5> imm; bits<5> ws; diff --git a/lib/Target/Mips/MipsMSAInstrInfo.td b/lib/Target/Mips/MipsMSAInstrInfo.td index a3c9bac5b2d..f16977dde53 100644 --- a/lib/Target/Mips/MipsMSAInstrInfo.td +++ b/lib/Target/Mips/MipsMSAInstrInfo.td @@ -738,9 +738,9 @@ class ILVR_H_ENC : MSA_3R_FMT<0b101, 0b01, 0b010100>; class ILVR_W_ENC : MSA_3R_FMT<0b101, 0b10, 0b010100>; class ILVR_D_ENC : MSA_3R_FMT<0b101, 0b11, 0b010100>; -class INSERT_B_ENC : MSA_ELM_B_FMT<0b0100, 0b011001>; -class INSERT_H_ENC : MSA_ELM_H_FMT<0b0100, 0b011001>; -class INSERT_W_ENC : MSA_ELM_W_FMT<0b0100, 0b011001>; +class INSERT_B_ENC : MSA_ELM_INSERT_B_FMT<0b0100, 0b011001>; +class INSERT_H_ENC : MSA_ELM_INSERT_H_FMT<0b0100, 0b011001>; +class INSERT_W_ENC : MSA_ELM_INSERT_W_FMT<0b0100, 0b011001>; class INSVE_B_ENC : MSA_ELM_B_FMT<0b0101, 0b011001>; class INSVE_H_ENC : MSA_ELM_H_FMT<0b0101, 0b011001>; @@ -1239,13 +1239,13 @@ class MSA_CBRANCH_DESC_BASE { } class MSA_INSERT_DESC_BASE { - dag OutOperandList = (outs RCWD:$wd); - dag InOperandList = (ins RCWD:$wd_in, RCS:$rs, uimm6:$n); + dag OutOperandList = (outs ROWD:$wd); + dag InOperandList = (ins ROWD:$wd_in, ROS:$rs, uimm6:$n); string AsmString = !strconcat(instr_asm, "\t$wd[$n], $rs"); - list Pattern = [(set RCWD:$wd, (OpNode RCWD:$wd_in, - RCS:$rs, + list Pattern = [(set ROWD:$wd, (OpNode ROWD:$wd_in, + ROS:$rs, immZExt6:$n))]; InstrItinClass Itinerary = itin; string Constraints = "$wd = $wd_in"; @@ -1964,12 +1964,12 @@ class ILVR_H_DESC : MSA_3R_DESC_BASE<"ilvr.h", MipsILVR, MSA128HOpnd>; class ILVR_W_DESC : MSA_3R_DESC_BASE<"ilvr.w", MipsILVR, MSA128WOpnd>; class ILVR_D_DESC : MSA_3R_DESC_BASE<"ilvr.d", MipsILVR, MSA128DOpnd>; -class INSERT_B_DESC : MSA_INSERT_DESC_BASE<"insert.b", vinsert_v16i8, MSA128B, - GPR32>; -class INSERT_H_DESC : MSA_INSERT_DESC_BASE<"insert.h", vinsert_v8i16, MSA128H, - GPR32>; -class INSERT_W_DESC : MSA_INSERT_DESC_BASE<"insert.w", vinsert_v4i32, MSA128W, - GPR32>; +class INSERT_B_DESC : MSA_INSERT_DESC_BASE<"insert.b", vinsert_v16i8, + MSA128BOpnd, GPR32Opnd>; +class INSERT_H_DESC : MSA_INSERT_DESC_BASE<"insert.h", vinsert_v8i16, + MSA128HOpnd, GPR32Opnd>; +class INSERT_W_DESC : MSA_INSERT_DESC_BASE<"insert.w", vinsert_v4i32, + MSA128WOpnd, GPR32Opnd>; class INSERT_FW_PSEUDO_DESC : MSA_INSERT_PSEUDO_BASE; diff --git a/test/MC/Mips/msa/test_elm_insert.s b/test/MC/Mips/msa/test_elm_insert.s new file mode 100644 index 00000000000..5fc55f3ef0c --- /dev/null +++ b/test/MC/Mips/msa/test_elm_insert.s @@ -0,0 +1,15 @@ +# RUN: llvm-mc %s -triple=mipsel-unknown-linux -show-encoding -mcpu=mips32r2 -mattr=+msa -arch=mips | FileCheck %s +# +# RUN: llvm-mc %s -triple=mipsel-unknown-linux -mcpu=mips32r2 -mattr=+msa -arch=mips -filetype=obj -o - | llvm-objdump -d -triple=mipsel-unknown-linux -mattr=+msa -arch=mips - | FileCheck %s -check-prefix=CHECKOBJDUMP +# +# CHECK: insert.b $w23[3], $sp # encoding: [0x79,0x03,0xed,0xd9] +# CHECK: insert.h $w20[2], $5 # encoding: [0x79,0x22,0x2d,0x19] +# CHECK: insert.w $w8[2], $15 # encoding: [0x79,0x32,0x7a,0x19] + +# CHECKOBJDUMP: insert.b $w23[3], $sp +# CHECKOBJDUMP: insert.h $w20[2], $5 +# CHECKOBJDUMP: insert.w $w8[2], $15 + + insert.b $w23[3], $sp + insert.h $w20[2], $5 + insert.w $w8[2], $15