From 00bdeb4c545051f04e0a85b5773813b277095de4 Mon Sep 17 00:00:00 2001 From: Matheus Almeida Date: Wed, 30 Apr 2014 11:28:42 +0000 Subject: [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 --- lib/Target/Mips/AsmParser/MipsAsmParser.cpp | 32 +++++++++++++ .../Mips/MCTargetDesc/MipsTargetStreamer.cpp | 54 ++++++++++++++++++++++ lib/Target/Mips/MipsTargetStreamer.h | 14 ++++++ 3 files changed, 100 insertions(+) (limited to 'lib') diff --git a/lib/Target/Mips/AsmParser/MipsAsmParser.cpp b/lib/Target/Mips/AsmParser/MipsAsmParser.cpp index 4bc681b7a2..4449cc20c9 100644 --- a/lib/Target/Mips/AsmParser/MipsAsmParser.cpp +++ b/lib/Target/Mips/AsmParser/MipsAsmParser.cpp @@ -137,6 +137,7 @@ class MipsAsmParser : public MCTargetAsmParser { SmallVectorImpl &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 Reg; + OperandMatchResultTy ResTy = ParseAnyRegister(Reg); + if (ResTy == MatchOperand_NoMatch || ResTy == MatchOperand_ParseFail) { + reportParseError("expected register containing function address"); + return false; + } + + MipsOperand *RegOpnd = static_cast(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; diff --git a/lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp b/lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp index 053e13e556..ab1b1f6043 100644 --- a/lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp +++ b/lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp @@ -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); +} diff --git a/lib/Target/Mips/MipsTargetStreamer.h b/lib/Target/Mips/MipsTargetStreamer.h index 7873ed9a60..e649a4d14f 100644 --- a/lib/Target/Mips/MipsTargetStreamer.h +++ b/lib/Target/Mips/MipsTargetStreamer.h @@ -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 -- cgit v1.2.3