diff options
| author | Alex Bradbury <asb@lowrisc.org> | 2018-09-20 08:10:35 +0000 |
|---|---|---|
| committer | Alex Bradbury <asb@lowrisc.org> | 2018-09-20 08:10:35 +0000 |
| commit | 226f3ef5a52db932e4acbcfdf9bb860a25ba6d59 (patch) | |
| tree | d85cc59991553bc5d7ab0e9ba40db5817d73c4ee /llvm/lib/Target/RISCV | |
| parent | 6616b4c9e9ecdf68864cc1bdea4d4fa9dfd6f692 (diff) | |
| download | bcm5719-llvm-226f3ef5a52db932e4acbcfdf9bb860a25ba6d59.tar.gz bcm5719-llvm-226f3ef5a52db932e4acbcfdf9bb860a25ba6d59.zip | |
[RISCV][MC] Improve parsing of jal/j operands
Examples such as `jal a3`, `j a3` and `jal a3, a3` are accepted by gas
but rejected by LLVM MC. This patch rectifies this. I introduce
RISCVAsmParser::parseJALOffset to ensure that symbol names that coincide with
register names can safely be parsed. This is made a somewhat fiddly due to the
single-operand alias form (see the comment in parseJALOffset for more info).
Differential Revision: https://reviews.llvm.org/D52029
llvm-svn: 342629
Diffstat (limited to 'llvm/lib/Target/RISCV')
| -rw-r--r-- | llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp | 22 | ||||
| -rw-r--r-- | llvm/lib/Target/RISCV/RISCVInstrInfo.td | 18 |
2 files changed, 31 insertions, 9 deletions
diff --git a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp index 79d0de9ec63..e98d99fe1d7 100644 --- a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp +++ b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp @@ -92,6 +92,7 @@ class RISCVAsmParser : public MCTargetAsmParser { OperandMatchResultTy parseMemOpBaseReg(OperandVector &Operands); OperandMatchResultTy parseOperandWithModifier(OperandVector &Operands); OperandMatchResultTy parseBareSymbol(OperandVector &Operands); + OperandMatchResultTy parseJALOffset(OperandVector &Operands); bool parseOperand(OperandVector &Operands, StringRef Mnemonic); @@ -476,7 +477,7 @@ public: } } - bool isSImm21Lsb0() const { return isBareSimmNLsb0<21>(); } + bool isSImm21Lsb0JAL() const { return isBareSimmNLsb0<21>(); } /// getStartLoc - Gets location of the first token of this operand SMLoc getStartLoc() const override { return StartLoc; } @@ -809,7 +810,7 @@ bool RISCVAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, Operands, ErrorInfo, 0, (1 << 20) - 1, "operand must be a symbol with %pcrel_hi() modifier or an integer in " "the range"); - case Match_InvalidSImm21Lsb0: + case Match_InvalidSImm21Lsb0JAL: return generateImmOutOfRangeError( Operands, ErrorInfo, -(1 << 20), (1 << 20) - 2, "immediate must be a multiple of 2 bytes in the range"); @@ -985,6 +986,23 @@ OperandMatchResultTy RISCVAsmParser::parseBareSymbol(OperandVector &Operands) { return MatchOperand_Success; } +OperandMatchResultTy RISCVAsmParser::parseJALOffset(OperandVector &Operands) { + // Parsing jal operands is fiddly due to the `jal foo` and `jal ra, foo` + // both being acceptable forms. When parsing `jal ra, foo` this function + // will be called for the `ra` register operand in an attempt to match the + // single-operand alias. parseJALOffset must fail for this case. It would + // seem logical to try parse the operand using parseImmediate and return + // NoMatch if the next token is a comma (meaning we must be parsing a jal in + // the second form rather than the first). We can't do this as there's no + // way of rewinding the lexer state. Instead, return NoMatch if this operand + // is an identifier and is followed by a comma. + if (getLexer().is(AsmToken::Identifier) && + getLexer().peekTok().is(AsmToken::Comma)) + return MatchOperand_NoMatch; + + return parseImmediate(Operands); +} + OperandMatchResultTy RISCVAsmParser::parseMemOpBaseReg(OperandVector &Operands) { if (getLexer().isNot(AsmToken::LParen)) { diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfo.td b/llvm/lib/Target/RISCV/RISCVInstrInfo.td index dd739f03f9b..efbcd771c8e 100644 --- a/llvm/lib/Target/RISCV/RISCVInstrInfo.td +++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.td @@ -161,9 +161,13 @@ def uimm20_auipc : UImm20Operand { let ParserMatchClass = UImmAsmOperand<20, "AUIPC">; } +def Simm21Lsb0JALAsmOperand : SImmAsmOperand<21, "Lsb0JAL"> { + let ParserMethod = "parseJALOffset"; +} + // A 21-bit signed immediate where the least significant bit is zero. -def simm21_lsb0 : Operand<OtherVT> { - let ParserMatchClass = SImmAsmOperand<21, "Lsb0">; +def simm21_lsb0_jal : Operand<OtherVT> { + let ParserMatchClass = Simm21Lsb0JALAsmOperand; let EncoderMethod = "getImmOpValueAsr1"; let DecoderMethod = "decodeSImmOperandAndLsl1<21>"; let MCOperandPredicate = [{ @@ -296,7 +300,7 @@ def AUIPC : RVInstU<OPC_AUIPC, (outs GPR:$rd), (ins uimm20_auipc:$imm20), "auipc", "$rd, $imm20">; let isCall = 1 in -def JAL : RVInstJ<OPC_JAL, (outs GPR:$rd), (ins simm21_lsb0:$imm20), +def JAL : RVInstJ<OPC_JAL, (outs GPR:$rd), (ins simm21_lsb0_jal:$imm20), "jal", "$rd, $imm20">; let isCall = 1 in @@ -520,8 +524,8 @@ def : InstAlias<"bleu $rs, $rt, $offset", (BGEU GPR:$rt, GPR:$rs, simm13_lsb0:$offset), 0>; // "ret" has more weight since "ret" and "jr" alias the same "jalr" instruction. -def : InstAlias<"j $offset", (JAL X0, simm21_lsb0:$offset)>; -def : InstAlias<"jal $offset", (JAL X1, simm21_lsb0:$offset)>; +def : InstAlias<"j $offset", (JAL X0, simm21_lsb0_jal:$offset)>; +def : InstAlias<"jal $offset", (JAL X1, simm21_lsb0_jal:$offset)>; def : InstAlias<"jr $rs", (JALR X0, GPR:$rs, 0)>; def : InstAlias<"jalr $rs", (JALR X1, GPR:$rs, 0)>; def : InstAlias<"ret", (JALR X0, X1, 0), 2>; @@ -707,8 +711,8 @@ def : BccSwapPat<setule, BGEU>; def : Pat<(brcond GPR:$cond, bb:$imm12), (BNE GPR:$cond, X0, bb:$imm12)>; let isBarrier = 1, isBranch = 1, isTerminator = 1 in -def PseudoBR : Pseudo<(outs), (ins simm21_lsb0:$imm20), [(br bb:$imm20)]>, - PseudoInstExpansion<(JAL X0, simm21_lsb0:$imm20)>; +def PseudoBR : Pseudo<(outs), (ins simm21_lsb0_jal:$imm20), [(br bb:$imm20)]>, + PseudoInstExpansion<(JAL X0, simm21_lsb0_jal:$imm20)>; let isCall = 1, Defs=[X1] in let isBarrier = 1, isBranch = 1, isIndirectBranch = 1, isTerminator = 1 in |

