summaryrefslogtreecommitdiffstats
path: root/llvm
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
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')
-rw-r--r--llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp22
-rw-r--r--llvm/lib/Target/RISCV/RISCVInstrInfo.td18
-rw-r--r--llvm/test/MC/RISCV/rv32i-invalid.s2
-rw-r--r--llvm/test/MC/RISCV/rv32i-valid.s10
-rw-r--r--llvm/test/MC/RISCV/rvi-aliases-valid.s32
5 files changed, 69 insertions, 15 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
diff --git a/llvm/test/MC/RISCV/rv32i-invalid.s b/llvm/test/MC/RISCV/rv32i-invalid.s
index 18c1ca6ea72..0c6c0c0c4ac 100644
--- a/llvm/test/MC/RISCV/rv32i-invalid.s
+++ b/llvm/test/MC/RISCV/rv32i-invalid.s
@@ -152,8 +152,6 @@ lw a4, a5, 111 # CHECK: :[[@LINE]]:8: error: operand must be a symbol with %lo/%
# Too few operands
ori a0, a1 # CHECK: :[[@LINE]]:1: error: too few operands for instruction
xor s2, s2 # CHECK: :[[@LINE]]:1: error: too few operands for instruction
-# FIXME: Fix jal behavior to interpret a3 as a symbol rather than a register.
-jal a3 # CHECK: :[[@LINE]]:1: error: too few operands for instruction
# Instruction not in the base ISA
mul a4, ra, s0 # CHECK: :[[@LINE]]:1: error: instruction use requires an option to be enabled
diff --git a/llvm/test/MC/RISCV/rv32i-valid.s b/llvm/test/MC/RISCV/rv32i-valid.s
index f8141110ce8..54b7c05de24 100644
--- a/llvm/test/MC/RISCV/rv32i-valid.s
+++ b/llvm/test/MC/RISCV/rv32i-valid.s
@@ -60,6 +60,16 @@ jal a2, 1048574
# CHECK-ASM-AND-OBJ: jal a3, 256
# CHECK-ASM: encoding: [0xef,0x06,0x00,0x10]
jal a3, 256
+# CHECK-ASM: jal a0, foo
+# CHECK-ASM: encoding: [0x6f,0bAAAA0101,A,A]
+# CHECK-OBJ: jal a0, 0
+# CHECK-OBJ: R_RISCV_JAL foo
+jal a0, foo
+# CHECK-ASM: jal a0, a0
+# CHECK-ASM: encoding: [0x6f,0bAAAA0101,A,A]
+# CHECK-OBJ: jal a0, 0
+# CHECK-OBJ: R_RISCV_JAL a0
+jal a0, a0
# CHECK-ASM-AND-OBJ: jalr a0, a1, -2048
# CHECK-ASM: encoding: [0x67,0x85,0x05,0x80]
diff --git a/llvm/test/MC/RISCV/rvi-aliases-valid.s b/llvm/test/MC/RISCV/rvi-aliases-valid.s
index 12436c31c2d..bfed278a097 100644
--- a/llvm/test/MC/RISCV/rvi-aliases-valid.s
+++ b/llvm/test/MC/RISCV/rvi-aliases-valid.s
@@ -7,16 +7,16 @@
# RUN: llvm-mc %s -triple=riscv64 \
# RUN: | FileCheck -check-prefixes=CHECK-S,CHECK-S-OBJ %s
# RUN: llvm-mc -filetype=obj -triple riscv32 < %s \
-# RUN: | llvm-objdump -d -riscv-no-aliases - \
+# RUN: | llvm-objdump -d -r -riscv-no-aliases - \
# RUN: | FileCheck -check-prefixes=CHECK-OBJ-NOALIAS,CHECK-S-OBJ-NOALIAS %s
# RUN: llvm-mc -filetype=obj -triple riscv32 < %s \
-# RUN: | llvm-objdump -d - \
+# RUN: | llvm-objdump -d -r - \
# RUN: | FileCheck -check-prefixes=CHECK-OBJ,CHECK-S-OBJ %s
# RUN: llvm-mc -filetype=obj -triple riscv64 < %s \
-# RUN: | llvm-objdump -d -riscv-no-aliases - \
+# RUN: | llvm-objdump -d -r -riscv-no-aliases - \
# RUN: | FileCheck -check-prefixes=CHECK-OBJ-NOALIAS,CHECK-S-OBJ-NOALIAS %s
# RUN: llvm-mc -filetype=obj -triple riscv64 < %s \
-# RUN: | llvm-objdump -d - \
+# RUN: | llvm-objdump -d -r - \
# RUN: | FileCheck -check-prefixes=CHECK-OBJ,CHECK-S-OBJ %s
# The following check prefixes are used in this test:
@@ -105,9 +105,33 @@ bleu x18, x19, 32
# CHECK-S-OBJ-NOALIAS: jal zero, 2044
# CHECK-S-OBJ: j 2044
j 2044
+# CHECK-S-NOALIAS: jal zero, foo
+# CHECK-S: j foo
+# CHECK-OBJ-NOALIAS: jal zero, 0
+# CHECK-OBJ: j 0
+# CHECK-OBJ: R_RISCV_JAL foo
+j foo
+# CHECK-S-NOALIAS: jal zero, a0
+# CHECK-S: j a0
+# CHECK-OBJ-NOALIAS: jal zero, 0
+# CHECK-OBJ: j 0
+# CHECK-OBJ: R_RISCV_JAL a0
+j a0
# CHECK-S-OBJ-NOALIAS: jal ra, 2040
# CHECK-S-OBJ: jal 2040
jal 2040
+# CHECK-S-NOALIAS: jal ra, foo
+# CHECK-S: jal foo
+# CHECK-OBJ-NOALIAS: jal ra, 0
+# CHECK-OBJ: jal 0
+# CHECK-OBJ: R_RISCV_JAL foo
+jal foo
+# CHECK-S-NOALIAS: jal ra, a0
+# CHECK-S: jal a0
+# CHECK-OBJ-NOALIAS: jal ra, 0
+# CHECK-OBJ: jal 0
+# CHECK-OBJ: R_RISCV_JAL a0
+jal a0
# CHECK-S-OBJ-NOALIAS: jalr zero, s4, 0
# CHECK-S-OBJ: jr s4
jr x20
OpenPOWER on IntegriCloud