summaryrefslogtreecommitdiffstats
path: root/llvm/lib/Target/RISCV
diff options
context:
space:
mode:
authorAlex Bradbury <asb@lowrisc.org>2018-09-20 08:10:35 +0000
committerAlex Bradbury <asb@lowrisc.org>2018-09-20 08:10:35 +0000
commit226f3ef5a52db932e4acbcfdf9bb860a25ba6d59 (patch)
treed85cc59991553bc5d7ab0e9ba40db5817d73c4ee /llvm/lib/Target/RISCV
parent6616b4c9e9ecdf68864cc1bdea4d4fa9dfd6f692 (diff)
downloadbcm5719-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.cpp22
-rw-r--r--llvm/lib/Target/RISCV/RISCVInstrInfo.td18
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
OpenPOWER on IntegriCloud