[mips] Add support for .cpload.

Summary:
This directive is used for setting up $gp in the beginning of a function.
It expands to three instructions if PIC is enabled:
lui   $gp, %hi(_gp_disp)
addui $gp, $gp, %lo(_gp_disp)
addu  $gp, $gp, $reg

_gp_disp is a special symbol that the linker sets to the distance between
the lui instruction and the context pointer (_gp).

Reviewers: dsanders

Reviewed By: dsanders

Differential Revision: http://reviews.llvm.org/D3480

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@207637 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Matheus Almeida 2014-04-30 11:28:42 +00:00
parent 737de9db8e
commit 00bdeb4c54
5 changed files with 148 additions and 0 deletions

View File

@ -137,6 +137,7 @@ class MipsAsmParser : public MCTargetAsmParser {
SmallVectorImpl<MCInst> &Instructions, bool isLoad,
bool isImmOpnd);
bool reportParseError(StringRef ErrorMsg);
bool reportParseError(SMLoc Loc, StringRef ErrorMsg);
bool parseMemOffset(const MCExpr *&Res, bool isParenExpr);
bool parseRelocOperand(const MCExpr *&Res);
@ -145,6 +146,7 @@ class MipsAsmParser : public MCTargetAsmParser {
bool isEvaluated(const MCExpr *Expr);
bool parseSetFeature(uint64_t Feature);
bool parseDirectiveCPLoad(SMLoc Loc);
bool parseDirectiveCPSetup();
bool parseDirectiveNaN();
bool parseDirectiveSet();
@ -2083,6 +2085,10 @@ bool MipsAsmParser::reportParseError(StringRef ErrorMsg) {
return Error(Loc, ErrorMsg);
}
bool MipsAsmParser::reportParseError(SMLoc Loc, StringRef ErrorMsg) {
return Error(Loc, ErrorMsg);
}
bool MipsAsmParser::parseSetNoAtDirective() {
// Line should look like: ".set noat".
// set at reg to 0.
@ -2301,6 +2307,30 @@ bool MipsAsmParser::eatComma(StringRef ErrorStr) {
return true;
}
bool MipsAsmParser::parseDirectiveCPLoad(SMLoc Loc) {
if (Options.isReorder())
Warning(Loc, ".cpload in reorder section");
// FIXME: Warn if cpload is used in Mips16 mode.
SmallVector<MCParsedAsmOperand *, 1> Reg;
OperandMatchResultTy ResTy = ParseAnyRegister(Reg);
if (ResTy == MatchOperand_NoMatch || ResTy == MatchOperand_ParseFail) {
reportParseError("expected register containing function address");
return false;
}
MipsOperand *RegOpnd = static_cast<MipsOperand *>(Reg[0]);
if (!RegOpnd->isGPRAsmReg()) {
reportParseError(RegOpnd->getStartLoc(), "invalid register");
return false;
}
getTargetStreamer().emitDirectiveCpload(RegOpnd->getGPR32Reg());
delete RegOpnd;
return false;
}
bool MipsAsmParser::parseDirectiveCPSetup() {
unsigned FuncReg;
unsigned Save;
@ -2550,6 +2580,8 @@ bool MipsAsmParser::parseDirectiveOption() {
bool MipsAsmParser::ParseDirective(AsmToken DirectiveID) {
StringRef IDVal = DirectiveID.getString();
if (IDVal == ".cpload")
return parseDirectiveCPLoad(DirectiveID.getLoc());
if (IDVal == ".dword") {
parseDataDirective(8, DirectiveID.getLoc());
return false;

View File

@ -144,6 +144,11 @@ void MipsTargetAsmStreamer::emitFMask(unsigned FPUBitmask,
OS << "," << FPUTopSavedRegOff << '\n';
}
void MipsTargetAsmStreamer::emitDirectiveCpload(unsigned RegNo) {
OS << "\t.cpload\t$"
<< StringRef(MipsInstPrinter::getRegisterName(RegNo)).lower() << "\n";
}
// This part is for ELF object output.
MipsTargetELFStreamer::MipsTargetELFStreamer(MCStreamer &S,
const MCSubtargetInfo &STI)
@ -402,3 +407,52 @@ void MipsTargetELFStreamer::emitDirectiveSetMips64R2() {
void MipsTargetELFStreamer::emitDirectiveSetDsp() {
// No action required for ELF output.
}
void MipsTargetELFStreamer::emitDirectiveCpload(unsigned RegNo) {
// .cpload $reg
// This directive expands to:
// lui $gp, %hi(_gp_disp)
// addui $gp, $gp, %lo(_gp_disp)
// addu $gp, $gp, $reg
// when support for position independent code is enabled.
if (!Pic || (isN32() || isN64()))
return;
// There's a GNU extension controlled by -mno-shared that allows
// locally-binding symbols to be accessed using absolute addresses.
// This is currently not supported. When supported -mno-shared makes
// .cpload expand to:
// lui $gp, %hi(__gnu_local_gp)
// addiu $gp, $gp, %lo(__gnu_local_gp)
StringRef SymName("_gp_disp");
MCAssembler &MCA = getStreamer().getAssembler();
MCSymbol *GP_Disp = MCA.getContext().GetOrCreateSymbol(SymName);
MCA.getOrCreateSymbolData(*GP_Disp);
MCInst TmpInst;
TmpInst.setOpcode(Mips::LUi);
TmpInst.addOperand(MCOperand::CreateReg(Mips::GP));
const MCSymbolRefExpr *HiSym = MCSymbolRefExpr::Create(
"_gp_disp", MCSymbolRefExpr::VK_Mips_ABS_HI, MCA.getContext());
TmpInst.addOperand(MCOperand::CreateExpr(HiSym));
getStreamer().EmitInstruction(TmpInst, STI);
TmpInst.clear();
TmpInst.setOpcode(Mips::ADDiu);
TmpInst.addOperand(MCOperand::CreateReg(Mips::GP));
TmpInst.addOperand(MCOperand::CreateReg(Mips::GP));
const MCSymbolRefExpr *LoSym = MCSymbolRefExpr::Create(
"_gp_disp", MCSymbolRefExpr::VK_Mips_ABS_LO, MCA.getContext());
TmpInst.addOperand(MCOperand::CreateExpr(LoSym));
getStreamer().EmitInstruction(TmpInst, STI);
TmpInst.clear();
TmpInst.setOpcode(Mips::ADDu);
TmpInst.addOperand(MCOperand::CreateReg(Mips::GP));
TmpInst.addOperand(MCOperand::CreateReg(Mips::GP));
TmpInst.addOperand(MCOperand::CreateReg(RegNo));
getStreamer().EmitInstruction(TmpInst, STI);
}

View File

@ -47,6 +47,9 @@ public:
virtual void emitDirectiveSetMips64() = 0;
virtual void emitDirectiveSetMips64R2() = 0;
virtual void emitDirectiveSetDsp() = 0;
// PIC support
virtual void emitDirectiveCpload(unsigned RegNo) = 0;
};
// This part is for ascii assembly output
@ -83,6 +86,9 @@ public:
void emitDirectiveSetMips64() override;
void emitDirectiveSetMips64R2() override;
void emitDirectiveSetDsp() override;
// PIC support
virtual void emitDirectiveCpload(unsigned RegNo);
};
// This part is for ELF object output
@ -128,6 +134,14 @@ public:
void emitDirectiveSetMips64() override;
void emitDirectiveSetMips64R2() override;
void emitDirectiveSetDsp() override;
// PIC support
virtual void emitDirectiveCpload(unsigned RegNo);
protected:
bool isO32() const { return STI.getFeatureBits() & Mips::FeatureO32; }
bool isN32() const { return STI.getFeatureBits() & Mips::FeatureN32; }
bool isN64() const { return STI.getFeatureBits() & Mips::FeatureN64; }
};
}
#endif

15
test/MC/Mips/cpload-bad.s Normal file
View File

@ -0,0 +1,15 @@
# RUN: not llvm-mc %s -arch=mips -mcpu=mips32r2 2>%t1
# RUN: FileCheck %s < %t1 -check-prefix=ASM
.text
.option pic2
.set reorder
.cpload $25
# ASM: :[[@LINE-1]]:9: warning: .cpload in reorder section
.set noreorder
.cpload $32
# ASM: :[[@LINE-1]]:17: error: invalid register
.cpload $foo
# ASM: :[[@LINE-1]]:17: error: expected register containing function address
.cpload bar
# ASM: :[[@LINE-1]]:17: error: expected register containing function address

33
test/MC/Mips/cpload.s Normal file
View File

@ -0,0 +1,33 @@
# RUN: llvm-mc %s -arch=mips -mcpu=mips32r2 | FileCheck %s -check-prefix=ASM
#
# RUN: llvm-mc %s -arch=mips -mcpu=mips32r2 -filetype=obj -o -| \
# RUN: llvm-objdump -d -r -arch=mips - | \
# RUN: FileCheck %s -check-prefix=OBJ
# RUN: llvm-mc %s -arch=mips64 -mcpu=mips64r2 -filetype=obj -o -| \
# RUN: llvm-objdump -d -r -arch=mips - | \
# RUN: FileCheck %s -check-prefix=OBJ64
# ASM: .text
# ASM: .option pic2
# ASM: .set noreorder
# ASM: .cpload $25
# ASM: .set reorder
# OBJ: .text
# OBJ: lui $gp, 0
# OBJ: R_MIPS_HI16 _gp_disp
# OBJ: addiu $gp, $gp, 0
# OBJ: R_MIPS_LO16 _gp_disp
# OBJ: addu $gp, $gp, $25
# OBJ64: .text
# OBJ64-NOT: lui $gp, 0
# OBJ64-NOT: addiu $gp, $gp, 0
# OBJ64-NOT: addu $gp, $gp, $25
.text
.option pic2
.set noreorder
.cpload $25
.set reorder