Match operands

I’m trying to implement the standalone assembler for mips and I have encountered a problem in instruction operands matcher.
In mips instruction set there are math instructions with two format flags in the mnemonic, one for source and one for destination register.
For example ceil.w.s means both source and destination are F32 registers while ceil.l.d means both source and destination are F64 registers. Also, depending on the floating point unit configuration F64 may be either single 64 bit register or a pair of 32 bit registers. In the current implementation this instruction is defined as follows:

// Instructions that convert an FP value to 64-bit fixed point.
let Predicates = [IsFP64bit], DecoderNamespace = “Mips64” in
multiclass FFR1_L_M<bits<6> funct, string opstr> {
def _S : FFR1<funct, 16, opstr, “l.s”, FGR64, FGR32>;
def _D64 : FFR1<funct, 17, opstr, “l.d”, FGR64, FGR64>;
}

// Instructions that convert an FP value to 32-bit fixed point.
multiclass FFR1_W_M<bits<6> funct, string opstr> {
def _S : FFR1<funct, 16, opstr, “w.s”, FGR32, FGR32>;
def _D32 : FFR1<funct, 17, opstr, “w.d”, FGR32, AFGR64>,
Requires<[NotFP64bit]>;
def _D64 : FFR1<funct, 17, opstr, “w.d”, FGR32, FGR64>,
Requires<[IsFP64bit]> {
let DecoderNamespace = “Mips64”;
}
}

defm CEIL_W : FFR1_W_M<0xe, “ceil”>;
defm CEIL_L : FFR1_L_M<0xa, “ceil”>;

When assembly matcher is generated these are created as five instructions, each having ‘ceil’ as mnemonic:

static const MatchEntry MatchTable[277] = {
.
.
.

{ Mips::CEIL_L_D64, 93 /* ceil /, Convert__Reg1_2__Reg1_3, { MCK__DOT_l, MCK__DOT_d, MCK_FGR64, MCK_FGR64 }, Feature_IsFP64bit, 0},
{ Mips::CEIL_L_S, 93 /
ceil /, Convert__Reg1_2__Reg1_3, { MCK__DOT_l, MCK__DOT_s, MCK_FGR64, MCK_FGR32 }, Feature_IsFP64bit, 0},
{ Mips::CEIL_W_D64, 93 /
ceil /, Convert__Reg1_2__Reg1_3, { MCK__DOT_w, MCK__DOT_d, MCK_FGR32, MCK_FGR64 }, Feature_IsFP64bit, 0},
{ Mips::CEIL_W_D32, 93 /
ceil /, Convert__Reg1_2__Reg1_3, { MCK__DOT_w, MCK__DOT_d, MCK_FGR32, MCK_AFGR64 }, Feature_NotFP64bit, 0},
{ Mips::CEIL_W_S, 93 /
ceil */, Convert__Reg1_2__Reg1_3, { MCK__DOT_w, MCK__DOT_s, MCK_FGR32, MCK_FGR32 }, 0, 0},
.
.
.
}

So, when the MatchInstructionImpl is called it seems to look for a pair of instructions that match the mnemonic:

// Search the table.
std::pair<const MatchEntry*, const MatchEntry*> MnemonicRange =
std::equal_range(MatchTable, MatchTable+277, Mnemonic, LessOpcode());

The search will always end in first two entries ( Mips::CEIL_L_D64 and Mips::CEIL_L_S) thus reporting the ‘invalid operand’ error when ceil.w.x instruction is parsed.
Is there a way to direct this search somehow, maybe to use available features or we should change the definition of the instructions to have at least one format included in mnemonic?

Kind regards,
Vladimir

I’m trying to implement the standalone assembler for mips and I have encountered a problem in instruction operands matcher.
In mips instruction set there are math instructions with two format flags in the mnemonic, one for source and one for destination register.
For example ceil.w.s means both source and destination are F32 registers while ceil.l.d means both source and destination are F64 registers. Also, depending on the floating point unit configuration F64 may be either single 64 bit register or a pair of 32 bit registers. In the current implementation this instruction is defined as follows:

// Instructions that convert an FP value to 64-bit fixed point.
let Predicates = [IsFP64bit], DecoderNamespace = “Mips64” in
multiclass FFR1_L_M<bits<6> funct, string opstr> {
def _S : FFR1<funct, 16, opstr, “l.s”, FGR64, FGR32>;
def _D64 : FFR1<funct, 17, opstr, “l.d”, FGR64, FGR64>;
}

// Instructions that convert an FP value to 32-bit fixed point.
multiclass FFR1_W_M<bits<6> funct, string opstr> {
def _S : FFR1<funct, 16, opstr, “w.s”, FGR32, FGR32>;
def _D32 : FFR1<funct, 17, opstr, “w.d”, FGR32, AFGR64>,
Requires<[NotFP64bit]>;
def _D64 : FFR1<funct, 17, opstr, “w.d”, FGR32, FGR64>,
Requires<[IsFP64bit]> {
let DecoderNamespace = “Mips64”;
}
}

defm CEIL_W : FFR1_W_M<0xe, “ceil”>;
defm CEIL_L : FFR1_L_M<0xa, “ceil”>;

When assembly matcher is generated these are created as five instructions, each having ‘ceil’ as mnemonic:

static const MatchEntry MatchTable[277] = {
.
.
.

{ Mips::CEIL_L_D64, 93 /* ceil /, Convert__Reg1_2__Reg1_3, { MCK__DOT_l, MCK__DOT_d, MCK_FGR64, MCK_FGR64 }, Feature_IsFP64bit, 0},
{ Mips::CEIL_L_S, 93 /
ceil /, Convert__Reg1_2__Reg1_3, { MCK__DOT_l, MCK__DOT_s, MCK_FGR64, MCK_FGR32 }, Feature_IsFP64bit, 0},
{ Mips::CEIL_W_D64, 93 /
ceil /, Convert__Reg1_2__Reg1_3, { MCK__DOT_w, MCK__DOT_d, MCK_FGR32, MCK_FGR64 }, Feature_IsFP64bit, 0},
{ Mips::CEIL_W_D32, 93 /
ceil /, Convert__Reg1_2__Reg1_3, { MCK__DOT_w, MCK__DOT_d, MCK_FGR32, MCK_AFGR64 }, Feature_NotFP64bit, 0},
{ Mips::CEIL_W_S, 93 /
ceil */, Convert__Reg1_2__Reg1_3, { MCK__DOT_w, MCK__DOT_s, MCK_FGR32, MCK_FGR32 }, 0, 0},
.

Note the “MCK_DOT_l” and “MCK_DOT_d” entries there. The matcher is expect those to be in the operand list as explicit token operands. Your parser will initially get the mnemonic, including those suffices as a single string, most likely. That will need to be manually split into its components so that the base mnemonic and the suffices are distinct for the matcher. ARM does similar things. I suggest looking there an example of how this might be done. Avert your eyes from some of the other horrible hackery in that function, though. :wink:

-Jim

Hello Jim,

I have already done that, splitting for example ceil.w.s into 3 operands, this way:
Operands[0] = ‘ceil’ - mnemonic
Operands[1] = MCK__DOT_w
Operands[2] = MCK__DOT_s

The problem is that after call to:
// Search the table.
std::pair<const MatchEntry*, const MatchEntry*> MnemonicRange =
std::equal_range(MatchTable, MatchTable+277, Mnemonic, LessOpcode());

I have this:
MnemonicRange.first = { Mips::CEIL_L_D64, 93 /* ceil /, Convert__Reg1_2__Reg1_3, { MCK__DOT_l, MCK__DOT_d, MCK_FGR64, MCK_FGR64 }, Feature_IsFP64bit, 0}
MnemonicRange.second = { Mips::CEIL_L_S, 93 /
ceil */, Convert__Reg1_2__Reg1_3, { MCK__DOT_l, MCK__DOT_s, MCK_FGR64, MCK_FGR32 }, Feature_IsFP64bit, 0}

Thus, when the comparison is made the error is reported since actual operand is MCK__DOT_w and matcher expects MCK__DOT_l. So my question was how do I make the matcher take the entries with MCK__DOT_w, or if that is not possible, do I need to redefine the instruction so the ‘.w’ or ‘.l’ are not explicit operand types but rather a values for the same type?

Thanks

Vladimir