Skip to content

Commit

Permalink
[RISCV][MC] Improve parsing of jal/j operands
Browse files Browse the repository at this point in the history
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
  • Loading branch information
asb committed Sep 20, 2018
1 parent 6616b4c commit 226f3ef
Show file tree
Hide file tree
Showing 5 changed files with 69 additions and 15 deletions.
22 changes: 20 additions & 2 deletions llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
Expand Up @@ -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);

Expand Down Expand Up @@ -476,7 +477,7 @@ struct RISCVOperand : public MCParsedAsmOperand {
}
}

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; }
Expand Down Expand Up @@ -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");
Expand Down Expand Up @@ -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)) {
Expand Down
18 changes: 11 additions & 7 deletions llvm/lib/Target/RISCV/RISCVInstrInfo.td
Expand Up @@ -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 = [{
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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>;
Expand Down Expand Up @@ -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
Expand Down
2 changes: 0 additions & 2 deletions llvm/test/MC/RISCV/rv32i-invalid.s
Expand Up @@ -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
Expand Down
10 changes: 10 additions & 0 deletions llvm/test/MC/RISCV/rv32i-valid.s
Expand Up @@ -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]
Expand Down
32 changes: 28 additions & 4 deletions llvm/test/MC/RISCV/rvi-aliases-valid.s
Expand Up @@ -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:
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit 226f3ef

Please sign in to comment.