Index: lib/Target/Mips/AsmParser/MipsAsmParser.cpp =================================================================== --- lib/Target/Mips/AsmParser/MipsAsmParser.cpp +++ lib/Target/Mips/AsmParser/MipsAsmParser.cpp @@ -137,6 +137,7 @@ 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 @@ bool isEvaluated(const MCExpr *Expr); bool parseSetFeature(uint64_t Feature); + bool parseDirectiveCPLoad(SMLoc Loc); bool parseDirectiveCPSetup(); bool parseDirectiveNaN(); bool parseDirectiveSet(); @@ -185,6 +187,8 @@ bool eatComma(StringRef ErrorStr); + bool isGPR(unsigned RegNo); + int matchCPURegisterName(StringRef Symbol); int matchRegisterByNumber(unsigned RegNum, unsigned RegClass); @@ -2083,6 +2087,10 @@ 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 +2309,32 @@ return true; } +bool MipsAsmParser::isGPR(unsigned RegNo) { + return RegNo <= 31; +} + +bool MipsAsmParser::parseDirectiveCPLoad(SMLoc Loc) { + unsigned RegNo; + + if (Options.isReorder()) + Warning(Loc, ".cpload in reorder section"); + + SMLoc BeforeParsingReg = getLexer().getLoc(); + if (!parseRegister(RegNo)) { + reportParseError("expected register containing function address"); + return false; + } + + if (!isGPR(RegNo)) { + reportParseError(BeforeParsingReg, "invalid register"); + return false; + } + + RegNo = getGPR(RegNo); + getTargetStreamer().emitDirectiveCpload(RegNo); + return false; +} + bool MipsAsmParser::parseDirectiveCPSetup() { unsigned FuncReg; unsigned Save; @@ -2550,11 +2584,12 @@ 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; } - if (IDVal == ".ent") { // Ignore this directive for now. Parser.Lex(); Index: lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp =================================================================== --- lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp +++ lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp @@ -144,6 +144,11 @@ 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,60 @@ 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 independant code is enabled. + if (!Pic || !(STI.getFeatureBits() & Mips::FeatureO32)) + 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) + + bool Shared = true; // Assumes -mshared was specified. + StringRef SymName = Shared ? "_gp_disp" : "__gnu_local_gp"; + MCAssembler &MCA = getStreamer().getAssembler(); + MCSymbol *GP_Disp = MCA.getContext().GetOrCreateSymbol(SymName); + MCSymbolData &GP_DispData = MCA.getOrCreateSymbolData(*GP_Disp); + + (void)GP_DispData; // Silence unused variable. + + MCInst TmpInst; + TmpInst.setOpcode(Mips::LUi); + TmpInst.addOperand(MCOperand::CreateReg(Mips::GP)); + const MCSymbolRefExpr *HiSym = + MCSymbolRefExpr::Create("_gp_disp", MCSymbolRefExpr::VK_Mips_ABS_HI, + getStreamer().getAssembler().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, + getStreamer().getAssembler().getContext()); + TmpInst.addOperand(MCOperand::CreateExpr(LoSym)); + getStreamer().EmitInstruction(TmpInst, STI); + + TmpInst.clear(); + + if (!Shared) + return; + + 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); +} Index: lib/Target/Mips/MipsTargetStreamer.h =================================================================== --- lib/Target/Mips/MipsTargetStreamer.h +++ lib/Target/Mips/MipsTargetStreamer.h @@ -47,6 +47,9 @@ 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 @@ virtual void emitDirectiveSetMips64(); virtual void emitDirectiveSetMips64R2(); virtual void emitDirectiveSetDsp(); + + // PIC support + virtual void emitDirectiveCpload(unsigned RegNo); }; // This part is for ELF object output @@ -128,6 +134,9 @@ virtual void emitDirectiveSetMips64(); virtual void emitDirectiveSetMips64R2(); virtual void emitDirectiveSetDsp(); + + // PIC support + virtual void emitDirectiveCpload(unsigned RegNo); }; } #endif Index: test/MC/Mips/cpload-bad.s =================================================================== --- /dev/null +++ test/MC/Mips/cpload-bad.s @@ -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: invalid register + .cpload bar +# ASM: :[[@LINE-1]]:17: error: expected register containing function address Index: test/MC/Mips/cpload.s =================================================================== --- /dev/null +++ test/MC/Mips/cpload.s @@ -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