1
0
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:
Luís Marques 2020-01-31 18:52:37 +00:00
parent 38bd7088ce
commit 8d59a47e49
6 changed files with 100 additions and 7 deletions

View File

@ -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

View File

@ -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;

View File

@ -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:

View File

@ -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), [],

View 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

View 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