mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-26 04:32:44 +01:00
[RISCV] Implement jump pseudo-instruction
Summary: Implements the jump pseudo-instruction, which is used in e.g. the Linux kernel. Reviewers: asb, lenary Reviewed By: lenary Tags: #llvm Differential Revision: https://reviews.llvm.org/D73178
This commit is contained in:
parent
38bd7088ce
commit
8d59a47e49
@ -138,6 +138,7 @@ class RISCVAsmParser : public MCTargetAsmParser {
|
||||
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);
|
||||
@ -337,6 +338,16 @@ public:
|
||||
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;
|
||||
@ -976,6 +987,10 @@ bool RISCVAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
|
||||
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");
|
||||
@ -1287,6 +1302,27 @@ OperandMatchResultTy RISCVAsmParser::parseCallSymbol(OperandVector &Operands) {
|
||||
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
|
||||
|
@ -89,9 +89,9 @@ MCCodeEmitter *llvm::createRISCVMCCodeEmitter(const MCInstrInfo &MCII,
|
||||
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.
|
||||
@ -108,9 +108,12 @@ void RISCVMCCodeEmitter::expandFunctionCall(const MCInst &MI, raw_ostream &OS,
|
||||
} 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;
|
||||
|
||||
@ -125,8 +128,9 @@ void RISCVMCCodeEmitter::expandFunctionCall(const MCInst &MI, raw_ostream &OS,
|
||||
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
|
||||
@ -182,7 +186,8 @@ void RISCVMCCodeEmitter::encodeInstruction(const MCInst &MI, raw_ostream &OS,
|
||||
|
||||
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;
|
||||
|
@ -473,6 +473,7 @@ unsigned RISCVInstrInfo::getInstSizeInBytes(const MachineInstr &MI) const {
|
||||
return 0;
|
||||
case RISCV::PseudoCALLReg:
|
||||
case RISCV::PseudoCALL:
|
||||
case RISCV::PseudoJump:
|
||||
case RISCV::PseudoTAIL:
|
||||
case RISCV::PseudoLLA:
|
||||
case RISCV::PseudoLA:
|
||||
|
@ -222,6 +222,18 @@ def call_symbol : Operand<XLenVT> {
|
||||
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";
|
||||
@ -968,6 +980,12 @@ def : Pat<(riscv_tail (iPTR tglobaladdr:$dst)),
|
||||
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), [],
|
||||
|
5
test/MC/RISCV/pseudo-jump-invalid.s
Normal file
5
test/MC/RISCV/pseudo-jump-invalid.s
Normal file
@ -0,0 +1,5 @@
|
||||
# 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
|
28
test/MC/RISCV/pseudo-jump.s
Normal file
28
test/MC/RISCV/pseudo-jump.s
Normal file
@ -0,0 +1,28 @@
|
||||
# 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
|
Loading…
Reference in New Issue
Block a user