Index: llvm/trunk/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp =================================================================== --- llvm/trunk/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp +++ llvm/trunk/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp @@ -92,6 +92,7 @@ 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 @@ } } - 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 @@ 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 @@ 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)) { Index: llvm/trunk/lib/Target/RISCV/RISCVInstrInfo.td =================================================================== --- llvm/trunk/lib/Target/RISCV/RISCVInstrInfo.td +++ llvm/trunk/lib/Target/RISCV/RISCVInstrInfo.td @@ -161,9 +161,13 @@ 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 { - let ParserMatchClass = SImmAsmOperand<21, "Lsb0">; +def simm21_lsb0_jal : Operand { + let ParserMatchClass = Simm21Lsb0JALAsmOperand; let EncoderMethod = "getImmOpValueAsr1"; let DecoderMethod = "decodeSImmOperandAndLsl1<21>"; let MCOperandPredicate = [{ @@ -296,7 +300,7 @@ "auipc", "$rd, $imm20">; let isCall = 1 in -def JAL : RVInstJ; let isCall = 1 in @@ -520,8 +524,8 @@ (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 : 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 Index: llvm/trunk/test/MC/RISCV/rv32i-invalid.s =================================================================== --- llvm/trunk/test/MC/RISCV/rv32i-invalid.s +++ llvm/trunk/test/MC/RISCV/rv32i-invalid.s @@ -152,8 +152,6 @@ # 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 Index: llvm/trunk/test/MC/RISCV/rv32i-valid.s =================================================================== --- llvm/trunk/test/MC/RISCV/rv32i-valid.s +++ llvm/trunk/test/MC/RISCV/rv32i-valid.s @@ -60,6 +60,16 @@ # 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] Index: llvm/trunk/test/MC/RISCV/rvi-aliases-valid.s =================================================================== --- llvm/trunk/test/MC/RISCV/rvi-aliases-valid.s +++ llvm/trunk/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 @@ # 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