[mips][msa] Direct Object Emission of INSERT.{B,H,W} instruction.

INSERT is the first type of MSA instruction that requires a change to the way MSA registers are parsed. 
This happens because MSA registers may be suffixed by an index in the form of an immediate or a
 general purpose register. The changes to parseMSARegs reflect that requirement.



git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@192447 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Matheus Almeida 2013-10-11 13:29:36 +00:00
parent 71e7893757
commit 6f36ea5c47
4 changed files with 189 additions and 14 deletions

View File

@ -236,6 +236,12 @@ class MipsAsmParser : public MCTargetAsmParser {
bool processInstruction(MCInst &Inst, SMLoc IDLoc,
SmallVectorImpl<MCInst> &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<MCParsedAsmOperand*> &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<MCParsedAsmOperand*> &Operands,
int RegKind) {
@ -1589,6 +1615,101 @@ MipsAsmParser::parseMSARegs(SmallVectorImpl<MCParsedAsmOperand*> &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<MipsOperand *>(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());
}
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<MCConstantExpr>(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;
}

View File

@ -133,6 +133,45 @@ class MSA_ELM_D_FMT<bits<4> major, bits<6> minor>: MSAInst {
let Inst{5-0} = minor;
}
class MSA_ELM_INSERT_B_FMT<bits<4> 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<bits<4> 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<bits<4> 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<bits<3> major, bits<2> df, bits<6> minor>: MSAInst {
bits<5> imm;
bits<5> ws;

View File

@ -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<string instr_asm, RegisterClass RCWD> {
}
class MSA_INSERT_DESC_BASE<string instr_asm, SDPatternOperator OpNode,
RegisterClass RCWD, RegisterClass RCS,
RegisterOperand ROWD, RegisterOperand ROS,
InstrItinClass itin = NoItinerary> {
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<dag> Pattern = [(set RCWD:$wd, (OpNode RCWD:$wd_in,
RCS:$rs,
list<dag> 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<vector_insert, v4f32,
MSA128W, FGR32>;

View File

@ -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