OperandMatchResultTy parseOperandWithModifier(OperandVector &Operands);
OperandMatchResultTy parseBareSymbol(OperandVector &Operands);
OperandMatchResultTy parseCallSymbol(OperandVector &Operands);
+ OperandMatchResultTy parsePseudoJumpSymbol(OperandVector &Operands);
OperandMatchResultTy parseJALOffset(OperandVector &Operands);
bool parseOperand(OperandVector &Operands, StringRef Mnemonic);
VK == RISCVMCExpr::VK_RISCV_CALL_PLT);
}
+ bool isPseudoJumpSymbol() const {
+ int64_t Imm;
+ RISCVMCExpr::VariantKind VK = RISCVMCExpr::VK_RISCV_None;
+ // Must be of 'immediate' type but not a constant.
+ if (!isImm() || evaluateConstantImm(getImm(), Imm, VK))
+ return false;
+ return RISCVAsmParser::classifySymbolRef(getImm(), VK, Imm) &&
+ VK == RISCVMCExpr::VK_RISCV_CALL;
+ }
+
bool isTPRelAddSymbol() const {
int64_t Imm;
RISCVMCExpr::VariantKind VK = RISCVMCExpr::VK_RISCV_None;
SMLoc ErrorLoc = ((RISCVOperand &)*Operands[ErrorInfo]).getStartLoc();
return Error(ErrorLoc, "operand must be a bare symbol name");
}
+ case Match_InvalidPseudoJumpSymbol: {
+ SMLoc ErrorLoc = ((RISCVOperand &)*Operands[ErrorInfo]).getStartLoc();
+ return Error(ErrorLoc, "operand must be a valid jump target");
+ }
case Match_InvalidCallSymbol: {
SMLoc ErrorLoc = ((RISCVOperand &)*Operands[ErrorInfo]).getStartLoc();
return Error(ErrorLoc, "operand must be a bare symbol name");
return MatchOperand_Success;
}
+OperandMatchResultTy
+RISCVAsmParser::parsePseudoJumpSymbol(OperandVector &Operands) {
+ SMLoc S = getLoc();
+ SMLoc E = SMLoc::getFromPointer(S.getPointer() - 1);
+ const MCExpr *Res;
+
+ if (getParser().parseExpression(Res))
+ return MatchOperand_ParseFail;
+
+ if (Res->getKind() != MCExpr::ExprKind::SymbolRef ||
+ cast<MCSymbolRefExpr>(Res)->getKind() ==
+ MCSymbolRefExpr::VariantKind::VK_PLT) {
+ Error(S, "operand must be a valid jump target");
+ return MatchOperand_ParseFail;
+ }
+
+ Res = RISCVMCExpr::create(Res, RISCVMCExpr::VK_RISCV_CALL, getContext());
+ Operands.push_back(RISCVOperand::createImm(Res, S, E, isRV64()));
+ 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
return new RISCVMCCodeEmitter(Ctx, MCII);
}
-// Expand PseudoCALL(Reg) and PseudoTAIL to AUIPC and JALR with relocation
-// types. We expand PseudoCALL(Reg) and PseudoTAIL while encoding, meaning AUIPC
-// and JALR won't go through RISCV MC to MC compressed instruction
+// Expand PseudoCALL(Reg), PseudoTAIL and PseudoJump to AUIPC and JALR with
+// relocation types. We those pseudo-instructions while encoding them, meaning
+// AUIPC and JALR won't go through RISCV MC to MC compressed instruction
// transformation. This is acceptable because AUIPC has no 16-bit form and
// C_JALR have no immediate operand field. We let linker relaxation deal with
// it. When linker relaxation enabled, AUIPC and JALR have chance relax to JAL.
} else if (MI.getOpcode() == RISCV::PseudoCALLReg) {
Func = MI.getOperand(1);
Ra = MI.getOperand(0).getReg();
- } else {
+ } else if (MI.getOpcode() == RISCV::PseudoCALL) {
Func = MI.getOperand(0);
Ra = RISCV::X1;
+ } else if (MI.getOpcode() == RISCV::PseudoJump) {
+ Func = MI.getOperand(1);
+ Ra = MI.getOperand(0).getReg();
}
uint32_t Binary;
Binary = getBinaryCodeForInstr(TmpInst, Fixups, STI);
support::endian::write(OS, Binary, support::little);
- if (MI.getOpcode() == RISCV::PseudoTAIL)
- // Emit JALR X0, X6, 0
+ if (MI.getOpcode() == RISCV::PseudoTAIL ||
+ MI.getOpcode() == RISCV::PseudoJump)
+ // Emit JALR X0, Ra, 0
TmpInst = MCInstBuilder(RISCV::JALR).addReg(RISCV::X0).addReg(Ra).addImm(0);
else
// Emit JALR Ra, Ra, 0
if (MI.getOpcode() == RISCV::PseudoCALLReg ||
MI.getOpcode() == RISCV::PseudoCALL ||
- MI.getOpcode() == RISCV::PseudoTAIL) {
+ MI.getOpcode() == RISCV::PseudoTAIL ||
+ MI.getOpcode() == RISCV::PseudoJump) {
expandFunctionCall(MI, OS, Fixups, STI);
MCNumEmitted += 2;
return;
return 0;
case RISCV::PseudoCALLReg:
case RISCV::PseudoCALL:
+ case RISCV::PseudoJump:
case RISCV::PseudoTAIL:
case RISCV::PseudoLLA:
case RISCV::PseudoLA:
let ParserMatchClass = CallSymbol;
}
+def PseudoJumpSymbol : AsmOperandClass {
+ let Name = "PseudoJumpSymbol";
+ let RenderMethod = "addImmOperands";
+ let DiagnosticType = "InvalidPseudoJumpSymbol";
+ let ParserMethod = "parsePseudoJumpSymbol";
+}
+
+// A bare symbol used for pseudo jumps only.
+def pseudo_jump_symbol : Operand<XLenVT> {
+ let ParserMatchClass = PseudoJumpSymbol;
+}
+
def TPRelAddSymbol : AsmOperandClass {
let Name = "TPRelAddSymbol";
let RenderMethod = "addImmOperands";
def : Pat<(riscv_tail (iPTR texternalsym:$dst)),
(PseudoTAIL texternalsym:$dst)>;
+let isCall = 0, isBarrier = 0, isCodeGenOnly = 0, hasSideEffects = 0,
+ mayStore = 0, mayLoad = 0 in
+def PseudoJump : Pseudo<(outs GPR:$rd), (ins pseudo_jump_symbol:$target), []> {
+ let AsmString = "jump\t$target, $rd";
+}
+
let hasSideEffects = 0, mayLoad = 0, mayStore = 0, isCodeGenOnly = 0,
isAsmParserOnly = 1 in
def PseudoLLA : Pseudo<(outs GPR:$dst), (ins bare_symbol:$src), [],
--- /dev/null
+# RUN: not llvm-mc -triple riscv32 < %s 2>&1 | FileCheck %s
+
+jump 1234, x31 # CHECK: :[[@LINE]]:6: error: operand must be a valid jump target
+jump foo@plt, x31 # CHECK: :[[@LINE]]:6: error: operand must be a valid jump target
+jump %pcrel_lo(1234), x31 # CHECK: :[[@LINE]]:6: error: unknown token in expression
--- /dev/null
+# RUN: llvm-mc -filetype=obj -triple riscv32 < %s \
+# RUN: | llvm-objdump -d - | FileCheck -check-prefix=INSTR %s
+# RUN: llvm-mc -filetype=obj -triple riscv32 < %s \
+# RUN: | llvm-readobj -r | FileCheck -check-prefix=RELOC %s
+# RUN: llvm-mc -triple riscv32 < %s -show-encoding \
+# RUN: | FileCheck -check-prefix=FIXUP %s
+
+.long foo
+
+jump foo, x31
+# RELOC: R_RISCV_CALL foo 0x0
+# INSTR: auipc t6, 0
+# INSTR: jr t6
+# FIXUP: fixup A - offset: 0, value: foo, kind: fixup_riscv_call
+
+# Ensure that jumps to symbols whose names coincide with register names work.
+
+jump zero, x1
+# RELOC: R_RISCV_CALL zero 0x0
+# INSTR: auipc ra, 0
+# INSTR: ret
+# FIXUP: fixup A - offset: 0, value: zero, kind: fixup_riscv_call
+
+1:
+jump 1b, x31
+# INSTR: auipc t6, 0
+# INSTR: jr t6
+# FIXUP: fixup A - offset: 0, value: .Ltmp0, kind: fixup_riscv_call