[llvm-dev] error: expected memory with 32-bit signed offset
Leslie Zhai via llvm-dev
llvm-dev at lists.llvm.org
Fri Sep 28 20:19:59 PDT 2018
Hi Daniel,
Thanks for your teaching!
在 2018年09月28日 23:56, Daniel Sanders 写道:
>
>> On 28 Sep 2018, at 00:09, Leslie Zhai <zhaixiang at loongson.cn> wrote:
>>
>> Hi,
>>
>> I want to encode Loongson ISA initially https://gist.github.com/xiangzhai/8ae6966e2f02a94e180dd16ff1cd60ac
>>
>> gslbx $2,0($3,$4)
>>
>> It is equivalent to:
>>
>> dadd $1, $3, $4
>>
>> lb $2,0($1)
>>
>> I just use mem_simmptr as the default value of DAGOperand MO , because MipsMemAsmOperand use parseMemOperand to parse general MemOffset and only *one* AnyRegister , for example:
>>
>> 0($1)
>>
>> But Comma isNot AsmToken::RParen , for example:
>>
>> 0($3,$4)
>>
>> Then llvm-mc thrown such error:
>>
>> test/MC/Mips/loongson3a/valid.s:32:32: error: ')' expected
>> gslbx $2,0($3,$4)
>> ^
>> test/MC/Mips/loongson3a/valid.s:32:32: error: unexpected token in argument list
>> gslbx $2,0($3,$4)
>> ^
>>
>> So I just changed MipsAsmParser::parseMemOffset :
> I assume you mean parseMemOperand. parseMemOffset doesn't have the code you're referring to.
Sorry for typo...
>
>> if (Parser.getTok().isNot(AsmToken::RParen)) {
>> - Error(Parser.getTok().getLoc(), "')' expected");
>> - return MatchOperand_ParseFail;
>> + if (hasLoongson3A()) {
>> + if (Parser.getTok().isNot(AsmToken::Comma)) {
>> + Error(Parser.getTok().getLoc(), "',' expected");
>> + return MatchOperand_ParseFail;
>> + }
> This is going to break instructions like lw when Loongson3A is enabled because it makes the comma mandatory. You need to accept both 0($3) and 0($3, $4) and handle the difference in what you pass to Operands.push_back(). I expect you'll need to add another operand kind to MipsOperand to handle the 0($3,$4) case.
Thank you for pointing out my fault! I added OpStr startswith_lower
check:
if (Parser.getTok().isNot(AsmToken::RParen)) {
- Error(Parser.getTok().getLoc(), "')' expected");
- return MatchOperand_ParseFail;
+ StringRef OpStr = static_cast<MipsOperand &>(*Operands[0]).getToken();
+ if (hasLoongson3A() && OpStr.startswith_lower(LoongISAPrefix)) {
+ if (Parser.getTok().isNot(AsmToken::Comma)) {
+ Error(Parser.getTok().getLoc(), "',' expected");
+ return MatchOperand_ParseFail;
+ }
+
+ Parser.Lex(); // Eat the ',' token.
+
+ Res = parseAnyRegister(Operands);
+ if (Res != MatchOperand_Success)
+ return Res;
+
+ if (Parser.getTok().isNot(AsmToken::RParen)) {
+ Error(Parser.getTok().getLoc(), "')' expected");
+ return MatchOperand_ParseFail;
+ }
+ } else {
+ Error(Parser.getTok().getLoc(), "')' expected");
+ return MatchOperand_ParseFail;
+ }
}
Then llvm-mc is able to distinguish invalid instructions:
test/MC/Mips/loongson3a/invalid.s:5:19: error: ')' expected
lb $2,0($3,$4)
^
test/MC/Mips/loongson3a/invalid.s:5:19: error: unexpected token in
argument list
lb $2,0($3,$4)
^
>
>> +
>> + Parser.Lex(); // Eat the ',' token.
>> +
>> + Res = parseAnyRegister(Operands);
>> + if (Res != MatchOperand_Success)
>> + return Res;
>> +
>> + if (Parser.getTok().isNot(AsmToken::RParen)) {
>> + Error(Parser.getTok().getLoc(), "')' expected");
>> + return MatchOperand_ParseFail;
>> + }
>> + } else {
>> + Error(Parser.getTok().getLoc(), "')' expected");
>> + return MatchOperand_ParseFail;
>> + }
>> }
>>
>> ----- 8< -------- 8< -------- 8< -------- 8< -------- 8< -------- 8< ---
>>
>> But I have no idea how to handle custom getMemEncoding:
>>
>> test/MC/Mips/loongson3a/valid.s:32:30: error: expected memory with 32-bit signed offset
>> gslbx $2,0($3,$4)
>> ^
>>
>> I just copy-n-paste mem_generic and getMemEncoding:
>>
>> def gs_mem : Operand<iPTR> {
>> let PrintMethod = "printMemOperand";
>> let MIOperandInfo = (ops ptr_rc, ptr_rc, simm16);
>>
>> ^-- for two registers
>> let EncoderMethod = "getGSMemEncoding";
>>
>> ^-- just encoding two registers and one offset
> The EncoderMethod isn't used by the assembly parser, it's used later when it's encoding the instruction into the binary. You need to look into the ParserMatchClass instead.
>
> There's two bits of the ParserMatchClass that are important. ParserMethod is the function the parser will call to parse the assembly. You can either keep using parseMemOperand and modify it to accept the 0($3,$4) case or change it and implement a new parser there. You have a distinct mnemonic so both options are available but I should mention that if you have more than one instruction with the same mnemonic then it's best to make sure all of them use the same ParserMethod. This is because the parser might only call one of them and you can't be sure which one (it depends on the order in the generated matcher table and whether there's any ambiguity).
>
> The other bit is Name. This is used to choose which methods on MipsOperand are called to decide if the parsed instruction matches an instruction defined by the compiler. If it's set to 'Mem' then MipsOperand::isMem() determines whether the operand matches, and MipsOperand::addMemOperands() adds the MCInst operands to the MCInst.
I need to handle carefully about replacing *two* registers operands with
the memory operand:
// Replace the register operand with the memory operand.
std::unique_ptr<MipsOperand> op(
static_cast<MipsOperand *>(Operands.back().release()));
// Remove the register from the operands.
// "op" will be managed by k_Memory.
Operands.pop_back();
// Add the memory operand.
if (const MCBinaryExpr *BE = dyn_cast<MCBinaryExpr>(IdVal)) {
int64_t Imm;
if (IdVal->evaluateAsAbsolute(Imm))
IdVal = MCConstantExpr::create(Imm, getContext());
else if (BE->getLHS()->getKind() != MCExpr::SymbolRef)
IdVal = MCBinaryExpr::create(BE->getOpcode(), BE->getRHS(),
BE->getLHS(),
getContext());
}
Operands.push_back(MipsOperand::CreateMem(std::move(op), IdVal, S, E,
*this));
----- 8< -------- 8< -------- 8< -------- 8< -------- 8< -------- 8< ---
As you mentioned, I need to add MipsGSOperand to handle ($3, $4) case.
Thanks,
Leslie Zhai
>
>> let ParserMatchClass = MipsMemAsmOperand;
>> let OperandType = "OPERAND_MEMORY";
>> }
>>
>> ----- 8< -------- 8< -------- 8< -------- 8< -------- 8< -------- 8< ---
>>
>> I couldn't fool llvm-mc :)
>>
>> test/MC/Mips/loongson3a/valid.s:32:30: error: invalid operand for instruction
>> gslbx $2,0($3,$4)
>> ^
>>
>> Compare with Loongson GCC toolchain:
>>
>> .text
>> gs:
>> .set noat
>> gslble $2, $3, $4 # encoding: [0x10,0x20,0x62,0xc8]
>> # <MCInst #1546 GSLBLE
>> # <MCOperand Reg:321>
>> # <MCOperand Reg:322>
>> # <MCOperand Reg:22>>
>> gslbgt $5, $6, $7 # encoding: [0x11,0x38,0xc5,0xc8]
>> # <MCInst #1545 GSLBGT
>> # <MCOperand Reg:23>
>> # <MCOperand Reg:24>
>> # <MCOperand Reg:25>>
>> gslhle $8, $9, $10 # encoding: [0x12,0x50,0x28,0xc9]
>> # <MCInst #1553 GSLHLE
>> # <MCOperand Reg:311>
>> # <MCOperand Reg:312>
>> # <MCOperand Reg:313>>
>> gslhgt $11, $12, $13 # encoding: [0x13,0x68,0x8b,0xc9]
>> # <MCInst #1552 GSLHGT
>> # <MCOperand Reg:314>
>> # <MCOperand Reg:315>
>> # <MCOperand Reg:316>>
>> gslwle $14, $15, $16 # encoding: [0x14,0x80,0xee,0xc9]
>> # <MCInst #1557 GSLWLE
>> # <MCOperand Reg:317>
>> # <MCOperand Reg:318>
>> # <MCOperand Reg:302>>
>> gslwgt $17, $18, $19 # encoding: [0x15,0x98,0x51,0xca]
>> # <MCInst #1555 GSLWGT
>> # <MCOperand Reg:303>
>> # <MCOperand Reg:304>
>> # <MCOperand Reg:305>>
>> gsldle $20, $21, $22 # encoding: [0x16,0xb0,0xb4,0xca]
>> # <MCInst #1550 GSLDLE
>> # <MCOperand Reg:402>
>> # <MCOperand Reg:403>
>> # <MCOperand Reg:404>>
>> gsldgt $23, $24, $25 # encoding: [0x17,0xc8,0x17,0xcb]
>> # <MCInst #1548 GSLDGT
>> # <MCOperand Reg:405>
>> # <MCOperand Reg:414>
>> # <MCOperand Reg:415>>
>> gslwlec1 $f0, $2, $3 # encoding: [0x1c,0x18,0x40,0xc8]
>> # <MCInst #1558 GSLWLEC1
>> # <MCOperand Reg:147>
>> # <MCOperand Reg:321>
>> # <MCOperand Reg:322>>
>> gslwgtc1 $f1, $4, $5 # encoding: [0x1d,0x28,0x81,0xc8]
>> # <MCInst #1556 GSLWGTC1
>> # <MCOperand Reg:148>
>> # <MCOperand Reg:22>
>> # <MCOperand Reg:23>>
>> gsldlec1 $f2, $6, $7 # encoding: [0x1e,0x38,0xc2,0xc8]
>> # <MCInst #1551 GSLDLEC1
>> # <MCOperand Reg:363>
>> # <MCOperand Reg:358>
>> # <MCOperand Reg:359>>
>> gsldgtc1 $f3, $8, $9 # encoding: [0x1f,0x48,0x03,0xc9]
>> # <MCInst #1549 GSLDGTC1
>> # <MCOperand Reg:364>
>> # <MCOperand Reg:406>
>> # <MCOperand Reg:407>>
>> gslq $10, $11, 4080($12) # encoding: [0xea,0x3f,0x8b,0xc9]
>> # <MCInst #1554 GSLQ
>> # <MCOperand Reg:408>
>> # <MCOperand Reg:409>
>> # <MCOperand Reg:410>
>> # <MCOperand Imm:4080>>
>> gssble $2, $3, $4 # encoding: [0x10,0x20,0x62,0xe8]
>> # <MCInst #1560 GSSBLE
>> # <MCOperand Reg:321>
>> # <MCOperand Reg:322>
>> # <MCOperand Reg:22>>
>> gssbgt $5, $6, $7 # encoding: [0x11,0x38,0xc5,0xe8]
>> # <MCInst #1559 GSSBGT
>> # <MCOperand Reg:23>
>> # <MCOperand Reg:24>
>> # <MCOperand Reg:25>>
>> gsshle $8, $9, $10 # encoding: [0x12,0x50,0x28,0xe9]
>> # <MCInst #1566 GSSHLE
>> # <MCOperand Reg:311>
>> # <MCOperand Reg:312>
>> # <MCOperand Reg:313>>
>> gsshgt $11, $12, $13 # encoding: [0x13,0x68,0x8b,0xe9]
>> # <MCInst #1565 GSSHGT
>> # <MCOperand Reg:314>
>> # <MCOperand Reg:315>
>> # <MCOperand Reg:316>>
>> gsswle $14, $15, $16 # encoding: [0x14,0x80,0xee,0xe9]
>> # <MCInst #1570 GSSWLE
>> # <MCOperand Reg:317>
>> # <MCOperand Reg:318>
>> # <MCOperand Reg:302>>
>> gsswgt $17, $18, $19 # encoding: [0x15,0x98,0x51,0xea]
>> # <MCInst #1568 GSSWGT
>> # <MCOperand Reg:303>
>> # <MCOperand Reg:304>
>> # <MCOperand Reg:305>>
>> gssdle $20, $21, $22 # encoding: [0x16,0xb0,0xb4,0xea]
>> # <MCInst #1563 GSSDLE
>> # <MCOperand Reg:402>
>> # <MCOperand Reg:403>
>> # <MCOperand Reg:404>>
>> gssdgt $23, $24, $25 # encoding: [0x17,0xc8,0x17,0xeb]
>> # <MCInst #1561 GSSDGT
>> # <MCOperand Reg:405>
>> # <MCOperand Reg:414>
>> # <MCOperand Reg:415>>
>> gsswlec1 $f4, $10, $11 # encoding: [0x1c,0x58,0x44,0xe9]
>> # <MCInst #1571 GSSWLEC1
>> # <MCOperand Reg:151>
>> # <MCOperand Reg:313>
>> # <MCOperand Reg:314>>
>> gsswgtc1 $f5, $12, $13 # encoding: [0x1d,0x68,0x85,0xe9]
>> # <MCInst #1569 GSSWGTC1
>> # <MCOperand Reg:152>
>> # <MCOperand Reg:315>
>> # <MCOperand Reg:316>>
>> gssdlec1 $f6, $14, $15 # encoding: [0x1e,0x78,0xc6,0xe9]
>> # <MCInst #1564 GSSDLEC1
>> # <MCOperand Reg:367>
>> # <MCOperand Reg:412>
>> # <MCOperand Reg:413>>
>> gssdgtc1 $f7, $16, $17 # encoding: [0x1f,0x88,0x07,0xea]
>> # <MCInst #1562 GSSDGTC1
>> # <MCOperand Reg:368>
>> # <MCOperand Reg:398>
>> # <MCOperand Reg:399>>
>> gssq $13, $14, -4096($15) # encoding: [0x2d,0x40,0xee,0xe9]
>> # <MCInst #1567 GSSQ
>> # <MCOperand Reg:411>
>> # <MCOperand Reg:412>
>> # <MCOperand Reg:413>
>> # <MCOperand Imm:-4096>>
>> test/MC/Mips/loongson3a/valid.s:32:30: error: invalid operand for instruction
>> gslbx $2,0($3,$4)
>> ^
>>
>> valid-gnu.o: file format elf64-tradlittlemips
>>
>>
>> Disassembly of section .text:
>>
>> 0000000000000000 <gs>:
>> 0: c8622010 gslble v0,v1,a0
>> 4: c8c53811 gslbgt a1,a2,a3
>> 8: c9285012 gslhle a4,a5,a6
>> c: 00000000 nop
>> 10: c98b6813 gslhgt a7,t0,t1
>> 14: c9ee8014 gslwle t2,t3,s0
>> 18: ca519815 gslwgt s1,s2,s3
>> 1c: 00000000 nop
>> 20: cab4b016 gsldle s4,s5,s6
>> 24: cb17c817 gsldgt s7,t8,t9
>> 28: c840181c gslwlec1 $f0,v0,v1
>> 2c: 00000000 nop
>> 30: c881281d gslwgtc1 $f1,a0,a1
>> 34: c8c2381e gsldlec1 $f2,a2,a3
>> 38: c903481f gsldgtc1 $f3,a4,a5
>> 3c: c98b3fea gslq a6,a7,4080(t0)
>> 40: e8622010 gssble v0,v1,a0
>> 44: e8c53811 gssbgt a1,a2,a3
>> 48: e9285012 gsshle a4,a5,a6
>> 4c: e98b6813 gsshgt a7,t0,t1
>> 50: e9ee8014 gsswle t2,t3,s0
>> 54: ea519815 gsswgt s1,s2,s3
>> 58: eab4b016 gssdle s4,s5,s6
>> 5c: eb17c817 gssdgt s7,t8,t9
>> 60: e944581c gsswlec1 $f4,a6,a7
>> 64: e985681d gsswgtc1 $f5,t0,t1
>> 68: e9c6781e gssdlec1 $f6,t2,t3
>> 6c: ea07881f gssdgtc1 $f7,s0,s1
>> 70: e9ee402d gssq t1,t2,-4096(t3)
>> 74: d8622000 gslbx v0,0(v1,a0)
>> ...
>> -- Testing: 1 tests, 1 threads --
>> FAIL: LLVM :: MC/Mips/loongson3a/valid.s (1 of 1)
>> Testing Time: 0.45s
>> ********************
>> Failing Tests (1):
>> LLVM :: MC/Mips/loongson3a/valid.s
>>
>> Unexpected Failures: 1
>>
>> ----- 8< -------- 8< -------- 8< -------- 8< -------- 8< -------- 8< ---
>>
>> Please teach me how to implement custom MemEncoding.
>>
>> Thanks,
>>
>> Leslie Zhai
>>
>>
More information about the llvm-dev
mailing list