1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-23 11:13:28 +01:00

[mips] Implement .cplocal directive

This directive forces to use the alternate register for context pointer.
For example, this code:
  .cplocal $4
  jal foo
expands to:
  ld    $25, %call16(foo)($4)
  jalr  $25

Differential Revision: https://reviews.llvm.org/D64743

llvm-svn: 366300
This commit is contained in:
Simon Atanasyan 2019-07-17 08:11:31 +00:00
parent 94c2670118
commit f709c58051
5 changed files with 170 additions and 33 deletions

View File

@ -146,6 +146,7 @@ class MipsAsmParser : public MCTargetAsmParser {
bool IsPicEnabled;
bool IsCpRestoreSet;
int CpRestoreOffset;
unsigned GPReg;
unsigned CpSaveLocation;
/// If true, then CpSaveLocation is a register, otherwise it's an offset.
bool CpSaveLocationIsRegister;
@ -334,6 +335,7 @@ class MipsAsmParser : public MCTargetAsmParser {
bool parseSetFeature(uint64_t Feature);
bool isPicAndNotNxxAbi(); // Used by .cpload, .cprestore, and .cpsetup.
bool parseDirectiveCpLoad(SMLoc Loc);
bool parseDirectiveCpLocal(SMLoc Loc);
bool parseDirectiveCpRestore(SMLoc Loc);
bool parseDirectiveCPSetup();
bool parseDirectiveCPReturn();
@ -527,6 +529,7 @@ public:
IsCpRestoreSet = false;
CpRestoreOffset = -1;
GPReg = ABI.GetGlobalPtr();
const Triple &TheTriple = sti.getTargetTriple();
IsLittleEndian = TheTriple.isLittleEndian();
@ -2040,7 +2043,7 @@ bool MipsAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc,
const MCExpr *Lo16RelocExpr =
MipsMCExpr::create(MipsMCExpr::MEK_LO, JalExpr, getContext());
TOut.emitRRX(Mips::LW, Mips::T9, Mips::GP,
TOut.emitRRX(Mips::LW, Mips::T9, GPReg,
MCOperand::createExpr(Got16RelocExpr), IDLoc, STI);
TOut.emitRRX(Mips::ADDiu, Mips::T9, Mips::T9,
MCOperand::createExpr(Lo16RelocExpr), IDLoc, STI);
@ -2054,7 +2057,7 @@ bool MipsAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc,
MipsMCExpr::create(MipsMCExpr::MEK_GOT_DISP, JalExpr, getContext());
TOut.emitRRX(ABI.ArePtrs64bit() ? Mips::LD : Mips::LW, Mips::T9,
Mips::GP, MCOperand::createExpr(GotDispRelocExpr), IDLoc,
GPReg, MCOperand::createExpr(GotDispRelocExpr), IDLoc,
STI);
}
} else {
@ -2065,7 +2068,7 @@ bool MipsAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc,
const MCExpr *Call16RelocExpr =
MipsMCExpr::create(MipsMCExpr::MEK_GOT_CALL, JalExpr, getContext());
TOut.emitRRX(ABI.ArePtrs64bit() ? Mips::LD : Mips::LW, Mips::T9, Mips::GP,
TOut.emitRRX(ABI.ArePtrs64bit() ? Mips::LD : Mips::LW, Mips::T9, GPReg,
MCOperand::createExpr(Call16RelocExpr), IDLoc, STI);
}
@ -2893,8 +2896,8 @@ bool MipsAsmParser::loadAndAddSymbolAddress(const MCExpr *SymExpr,
ELF::STB_LOCAL))) {
const MCExpr *CallExpr =
MipsMCExpr::create(MipsMCExpr::MEK_GOT_CALL, SymExpr, getContext());
TOut.emitRRX(Mips::LW, DstReg, ABI.GetGlobalPtr(),
MCOperand::createExpr(CallExpr), IDLoc, STI);
TOut.emitRRX(Mips::LW, DstReg, GPReg, MCOperand::createExpr(CallExpr),
IDLoc, STI);
return false;
}
@ -2933,8 +2936,8 @@ bool MipsAsmParser::loadAndAddSymbolAddress(const MCExpr *SymExpr,
TmpReg = ATReg;
}
TOut.emitRRX(Mips::LW, TmpReg, ABI.GetGlobalPtr(),
MCOperand::createExpr(GotExpr), IDLoc, STI);
TOut.emitRRX(Mips::LW, TmpReg, GPReg, MCOperand::createExpr(GotExpr), IDLoc,
STI);
if (LoExpr)
TOut.emitRRX(Mips::ADDiu, TmpReg, TmpReg, MCOperand::createExpr(LoExpr),
@ -2969,8 +2972,8 @@ bool MipsAsmParser::loadAndAddSymbolAddress(const MCExpr *SymExpr,
ELF::STB_LOCAL))) {
const MCExpr *CallExpr =
MipsMCExpr::create(MipsMCExpr::MEK_GOT_CALL, SymExpr, getContext());
TOut.emitRRX(Mips::LD, DstReg, ABI.GetGlobalPtr(),
MCOperand::createExpr(CallExpr), IDLoc, STI);
TOut.emitRRX(Mips::LD, DstReg, GPReg, MCOperand::createExpr(CallExpr),
IDLoc, STI);
return false;
}
@ -3012,8 +3015,8 @@ bool MipsAsmParser::loadAndAddSymbolAddress(const MCExpr *SymExpr,
TmpReg = ATReg;
}
TOut.emitRRX(Mips::LD, TmpReg, ABI.GetGlobalPtr(),
MCOperand::createExpr(GotExpr), IDLoc, STI);
TOut.emitRRX(Mips::LD, TmpReg, GPReg, MCOperand::createExpr(GotExpr), IDLoc,
STI);
if (LoExpr)
TOut.emitRRX(Mips::DADDiu, TmpReg, TmpReg, MCOperand::createExpr(LoExpr),
@ -3243,10 +3246,10 @@ bool MipsAsmParser::emitPartialAddress(MipsTargetStreamer &TOut, SMLoc IDLoc,
MipsMCExpr::create(MipsMCExpr::MEK_GOT, GotSym, getContext());
if(isABI_O32() || isABI_N32()) {
TOut.emitRRX(Mips::LW, ATReg, Mips::GP, MCOperand::createExpr(GotExpr),
TOut.emitRRX(Mips::LW, ATReg, GPReg, MCOperand::createExpr(GotExpr),
IDLoc, STI);
} else { //isABI_N64()
TOut.emitRRX(Mips::LD, ATReg, Mips::GP, MCOperand::createExpr(GotExpr),
TOut.emitRRX(Mips::LD, ATReg, GPReg, MCOperand::createExpr(GotExpr),
IDLoc, STI);
}
} else { //!IsPicEnabled
@ -7241,6 +7244,40 @@ bool MipsAsmParser::parseDirectiveCpLoad(SMLoc Loc) {
return false;
}
bool MipsAsmParser::parseDirectiveCpLocal(SMLoc Loc) {
if (!isABI_N32() && !isABI_N64()) {
reportParseError(".cplocal is allowed only in N32 or N64 mode");
return false;
}
SmallVector<std::unique_ptr<MCParsedAsmOperand>, 1> Reg;
OperandMatchResultTy ResTy = parseAnyRegister(Reg);
if (ResTy == MatchOperand_NoMatch || ResTy == MatchOperand_ParseFail) {
reportParseError("expected register containing global pointer");
return false;
}
MipsOperand &RegOpnd = static_cast<MipsOperand &>(*Reg[0]);
if (!RegOpnd.isGPRAsmReg()) {
reportParseError(RegOpnd.getStartLoc(), "invalid register");
return false;
}
// If this is not the end of the statement, report an error.
if (getLexer().isNot(AsmToken::EndOfStatement)) {
reportParseError("unexpected token, expected end of statement");
return false;
}
getParser().Lex(); // Consume the EndOfStatement.
unsigned NewReg = RegOpnd.getGPR32Reg();
if (IsPicEnabled)
GPReg = NewReg;
getTargetStreamer().emitDirectiveCpLocal(NewReg);
return false;
}
bool MipsAsmParser::parseDirectiveCpRestore(SMLoc Loc) {
MCAsmParser &Parser = getParser();
@ -8091,6 +8128,10 @@ bool MipsAsmParser::ParseDirective(AsmToken DirectiveID) {
parseDirectiveCpRestore(DirectiveID.getLoc());
return false;
}
if (IDVal == ".cplocal") {
parseDirectiveCpLocal(DirectiveID.getLoc());
return false;
}
if (IDVal == ".ent") {
StringRef SymbolName;

View File

@ -35,7 +35,7 @@ static cl::opt<bool> RoundSectionSizes(
} // end anonymous namespace
MipsTargetStreamer::MipsTargetStreamer(MCStreamer &S)
: MCTargetStreamer(S), ModuleDirectiveAllowed(true) {
: MCTargetStreamer(S), GPReg(Mips::GP), ModuleDirectiveAllowed(true) {
GPRInfoSet = FPRInfoSet = FrameInfoSet = false;
}
void MipsTargetStreamer::emitDirectiveSetMicroMips() {}
@ -106,6 +106,23 @@ void MipsTargetStreamer::emitDirectiveSetDsp() { forbidModuleDirective(); }
void MipsTargetStreamer::emitDirectiveSetDspr2() { forbidModuleDirective(); }
void MipsTargetStreamer::emitDirectiveSetNoDsp() { forbidModuleDirective(); }
void MipsTargetStreamer::emitDirectiveCpLoad(unsigned RegNo) {}
void MipsTargetStreamer::emitDirectiveCpLocal(unsigned RegNo) {
// .cplocal $reg
// This directive forces to use the alternate register for context pointer.
// For example
// .cplocal $4
// jal foo
// expands to
// ld $25, %call16(foo)($4)
// jalr $25
if (!getABI().IsN32() && !getABI().IsN64())
return;
GPReg = RegNo;
forbidModuleDirective();
}
bool MipsTargetStreamer::emitDirectiveCpRestore(
int Offset, function_ref<unsigned()> GetATReg, SMLoc IDLoc,
const MCSubtargetInfo *STI) {
@ -257,8 +274,7 @@ void MipsTargetStreamer::emitNop(SMLoc IDLoc, const MCSubtargetInfo *STI) {
/// Emit the $gp restore operation for .cprestore.
void MipsTargetStreamer::emitGPRestore(int Offset, SMLoc IDLoc,
const MCSubtargetInfo *STI) {
emitLoadWithImmOffset(Mips::LW, Mips::GP, Mips::SP, Offset, Mips::GP, IDLoc,
STI);
emitLoadWithImmOffset(Mips::LW, GPReg, Mips::SP, Offset, GPReg, IDLoc, STI);
}
/// Emit a store instruction with an immediate offset.
@ -665,6 +681,12 @@ void MipsTargetAsmStreamer::emitDirectiveCpLoad(unsigned RegNo) {
forbidModuleDirective();
}
void MipsTargetAsmStreamer::emitDirectiveCpLocal(unsigned RegNo) {
OS << "\t.cplocal\t$"
<< StringRef(MipsInstPrinter::getRegisterName(RegNo)).lower() << "\n";
MipsTargetStreamer::emitDirectiveCpLocal(RegNo);
}
bool MipsTargetAsmStreamer::emitDirectiveCpRestore(
int Offset, function_ref<unsigned()> GetATReg, SMLoc IDLoc,
const MCSubtargetInfo *STI) {
@ -1135,7 +1157,7 @@ void MipsTargetELFStreamer::emitDirectiveCpLoad(unsigned RegNo) {
MCInst TmpInst;
TmpInst.setOpcode(Mips::LUi);
TmpInst.addOperand(MCOperand::createReg(Mips::GP));
TmpInst.addOperand(MCOperand::createReg(GPReg));
const MCExpr *HiSym = MipsMCExpr::create(
MipsMCExpr::MEK_HI,
MCSymbolRefExpr::create("_gp_disp", MCSymbolRefExpr::VK_None,
@ -1147,8 +1169,8 @@ void MipsTargetELFStreamer::emitDirectiveCpLoad(unsigned RegNo) {
TmpInst.clear();
TmpInst.setOpcode(Mips::ADDiu);
TmpInst.addOperand(MCOperand::createReg(Mips::GP));
TmpInst.addOperand(MCOperand::createReg(Mips::GP));
TmpInst.addOperand(MCOperand::createReg(GPReg));
TmpInst.addOperand(MCOperand::createReg(GPReg));
const MCExpr *LoSym = MipsMCExpr::create(
MipsMCExpr::MEK_LO,
MCSymbolRefExpr::create("_gp_disp", MCSymbolRefExpr::VK_None,
@ -1160,14 +1182,19 @@ void MipsTargetELFStreamer::emitDirectiveCpLoad(unsigned RegNo) {
TmpInst.clear();
TmpInst.setOpcode(Mips::ADDu);
TmpInst.addOperand(MCOperand::createReg(Mips::GP));
TmpInst.addOperand(MCOperand::createReg(Mips::GP));
TmpInst.addOperand(MCOperand::createReg(GPReg));
TmpInst.addOperand(MCOperand::createReg(GPReg));
TmpInst.addOperand(MCOperand::createReg(RegNo));
getStreamer().EmitInstruction(TmpInst, STI);
forbidModuleDirective();
}
void MipsTargetELFStreamer::emitDirectiveCpLocal(unsigned RegNo) {
if (Pic)
MipsTargetStreamer::emitDirectiveCpLocal(RegNo);
}
bool MipsTargetELFStreamer::emitDirectiveCpRestore(
int Offset, function_ref<unsigned()> GetATReg, SMLoc IDLoc,
const MCSubtargetInfo *STI) {
@ -1184,7 +1211,7 @@ bool MipsTargetELFStreamer::emitDirectiveCpRestore(
return true;
// Store the $gp on the stack.
emitStoreWithImmOffset(Mips::SW, Mips::GP, Mips::SP, Offset, GetATReg, IDLoc,
emitStoreWithImmOffset(Mips::SW, GPReg, Mips::SP, Offset, GetATReg, IDLoc,
STI);
return true;
}
@ -1205,10 +1232,10 @@ void MipsTargetELFStreamer::emitDirectiveCpsetup(unsigned RegNo,
// Either store the old $gp in a register or on the stack
if (IsReg) {
// move $save, $gpreg
emitRRR(Mips::OR64, RegOrOffset, Mips::GP, Mips::ZERO, SMLoc(), &STI);
emitRRR(Mips::OR64, RegOrOffset, GPReg, Mips::ZERO, SMLoc(), &STI);
} else {
// sd $gpreg, offset($sp)
emitRRI(Mips::SD, Mips::GP, Mips::SP, RegOrOffset, SMLoc(), &STI);
emitRRI(Mips::SD, GPReg, Mips::SP, RegOrOffset, SMLoc(), &STI);
}
if (getABI().IsN32()) {
@ -1221,11 +1248,11 @@ void MipsTargetELFStreamer::emitDirectiveCpsetup(unsigned RegNo,
MCA.getContext());
// lui $gp, %hi(__gnu_local_gp)
emitRX(Mips::LUi, Mips::GP, MCOperand::createExpr(HiExpr), SMLoc(), &STI);
emitRX(Mips::LUi, GPReg, MCOperand::createExpr(HiExpr), SMLoc(), &STI);
// addiu $gp, $gp, %lo(__gnu_local_gp)
emitRRX(Mips::ADDiu, Mips::GP, Mips::GP, MCOperand::createExpr(LoExpr),
SMLoc(), &STI);
emitRRX(Mips::ADDiu, GPReg, GPReg, MCOperand::createExpr(LoExpr), SMLoc(),
&STI);
return;
}
@ -1238,14 +1265,14 @@ void MipsTargetELFStreamer::emitDirectiveCpsetup(unsigned RegNo,
MCA.getContext());
// lui $gp, %hi(%neg(%gp_rel(funcSym)))
emitRX(Mips::LUi, Mips::GP, MCOperand::createExpr(HiExpr), SMLoc(), &STI);
emitRX(Mips::LUi, GPReg, MCOperand::createExpr(HiExpr), SMLoc(), &STI);
// addiu $gp, $gp, %lo(%neg(%gp_rel(funcSym)))
emitRRX(Mips::ADDiu, Mips::GP, Mips::GP, MCOperand::createExpr(LoExpr),
SMLoc(), &STI);
emitRRX(Mips::ADDiu, GPReg, GPReg, MCOperand::createExpr(LoExpr), SMLoc(),
&STI);
// daddu $gp, $gp, $funcreg
emitRRR(Mips::DADDu, Mips::GP, Mips::GP, RegNo, SMLoc(), &STI);
emitRRR(Mips::DADDu, GPReg, GPReg, RegNo, SMLoc(), &STI);
}
void MipsTargetELFStreamer::emitDirectiveCpreturn(unsigned SaveLocation,
@ -1258,12 +1285,12 @@ void MipsTargetELFStreamer::emitDirectiveCpreturn(unsigned SaveLocation,
// Either restore the old $gp from a register or on the stack
if (SaveLocationIsRegister) {
Inst.setOpcode(Mips::OR);
Inst.addOperand(MCOperand::createReg(Mips::GP));
Inst.addOperand(MCOperand::createReg(GPReg));
Inst.addOperand(MCOperand::createReg(SaveLocation));
Inst.addOperand(MCOperand::createReg(Mips::ZERO));
} else {
Inst.setOpcode(Mips::LD);
Inst.addOperand(MCOperand::createReg(Mips::GP));
Inst.addOperand(MCOperand::createReg(GPReg));
Inst.addOperand(MCOperand::createReg(Mips::SP));
Inst.addOperand(MCOperand::createImm(SaveLocation));
}

View File

@ -91,6 +91,7 @@ public:
// PIC support
virtual void emitDirectiveCpLoad(unsigned RegNo);
virtual void emitDirectiveCpLocal(unsigned RegNo);
virtual bool emitDirectiveCpRestore(int Offset,
function_ref<unsigned()> GetATReg,
SMLoc IDLoc, const MCSubtargetInfo *STI);
@ -199,6 +200,7 @@ protected:
bool FrameInfoSet;
int FrameOffset;
unsigned FrameReg;
unsigned GPReg;
unsigned ReturnReg;
private:
@ -274,6 +276,7 @@ public:
// PIC support
void emitDirectiveCpLoad(unsigned RegNo) override;
void emitDirectiveCpLocal(unsigned RegNo) override;
/// Emit a .cprestore directive. If the offset is out of range then it will
/// be synthesized using the assembler temporary.
@ -345,6 +348,7 @@ public:
// PIC support
void emitDirectiveCpLoad(unsigned RegNo) override;
void emitDirectiveCpLocal(unsigned RegNo) override;
bool emitDirectiveCpRestore(int Offset, function_ref<unsigned()> GetATReg,
SMLoc IDLoc, const MCSubtargetInfo *STI) override;
void emitDirectiveCpsetup(unsigned RegNo, int RegOrOffset,

View File

@ -0,0 +1,20 @@
# RUN: not llvm-mc -triple=mips-unknown-linux-gnu %s 2>&1 \
# RUN: | FileCheck -check-prefix=O32 %s
# RUN: not llvm-mc -triple=mips64-unknown-linux-gnuabin32 %s 2>&1 \
# RUN: | FileCheck -check-prefix=NABI %s
# RUN: not llvm-mc -triple=mips64-unknown-linux-gnu %s 2>&1 \
# RUN: | FileCheck -check-prefix=NABI %s
.text
.cplocal $32
# O32: :[[@LINE-1]]:{{[0-9]+}}: error: .cplocal is allowed only in N32 or N64 mode
# NABI: :[[@LINE-2]]:{{[0-9]+}}: error: invalid register
.cplocal $foo
# O32: :[[@LINE-1]]:{{[0-9]+}}: error: .cplocal is allowed only in N32 or N64 mode
# NABI: :[[@LINE-2]]:{{[0-9]+}}: error: expected register containing global pointer
.cplocal bar
# O32: :[[@LINE-1]]:{{[0-9]+}}: error: .cplocal is allowed only in N32 or N64 mode
# NABI: :[[@LINE-2]]:{{[0-9]+}}: error: expected register containing global pointer
.cplocal $25 foobar
# O32: :[[@LINE-1]]:{{[0-9]+}}: error: .cplocal is allowed only in N32 or N64 mode
# NABI: :[[@LINE-2]]:{{[0-9]+}}: error: unexpected token, expected end of statement

45
test/MC/Mips/cplocal.s Normal file
View File

@ -0,0 +1,45 @@
# RUN: llvm-mc -triple=mips64-unknown-linux-gnuabin32 -position-independent %s \
# RUN: | FileCheck -check-prefix=ASM-PIC32 %s
# RUN: llvm-mc -triple=mips64-unknown-linux-gnu -position-independent %s \
# RUN: | FileCheck -check-prefix=ASM-PIC64 %s
# RUN: llvm-mc -triple=mips64-unknown-linux-gnuabin32 %s \
# RUN: | FileCheck -check-prefix=ASM-NPIC %s
# RUN: llvm-mc -triple=mips64-unknown-linux-gnu %s \
# RUN: | FileCheck -check-prefix=ASM-NPIC %s
# RUN: llvm-mc -triple=mips64-unknown-linux-gnuabin32 \
# RUN: -position-independent -filetype=obj -o - %s \
# RUN: | llvm-objdump -d -r - | FileCheck -check-prefix=OBJ32 %s
# RUN: llvm-mc -triple=mips64-unknown-linux-gnu \
# RUN: -position-independent -filetype=obj -o - %s \
# RUN: | llvm-objdump -d -r - | FileCheck -check-prefix=OBJ64 %s
# ASM-PIC32: .text
# ASM-PIC32: .cplocal $4
# ASM-PIC32: lw $25, %call16(foo)($4)
# ASM-PIC32: jalr $25
# ASM-PIC64: .text
# ASM-PIC64: .cplocal $4
# ASM-PIC64: ld $25, %call16(foo)($4)
# ASM-PIC64: jalr $25
# ASM-NPIC: .text
# ASM-NPIC: .cplocal $4
# ASM-NPIC: jal foo
# OBJ32: lw $25, 0($4)
# OBJ32: R_MIPS_CALL16 foo
# OBJ32: jalr $25
# OBJ32: R_MIPS_JALR foo
# OBJ64: ld $25, 0($4)
# OBJ64: R_MIPS_CALL16/R_MIPS_NONE/R_MIPS_NONE foo
# OBJ64: jalr $25
# OBJ64: R_MIPS_JALR/R_MIPS_NONE/R_MIPS_NONE foo
.text
.cplocal $4
jal foo
foo:
nop