Skip to content

Commit

Permalink
[mips] Add support for .cpload.
Browse files Browse the repository at this point in the history
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

llvm-svn: 207637
  • Loading branch information
Matheus Almeida committed Apr 30, 2014
1 parent c0284d1 commit 525bc4f
Show file tree
Hide file tree
Showing 5 changed files with 148 additions and 0 deletions.
32 changes: 32 additions & 0 deletions llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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();
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
54 changes: 54 additions & 0 deletions llvm/lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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);
}
14 changes: 14 additions & 0 deletions llvm/lib/Target/Mips/MipsTargetStreamer.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ class MipsTargetStreamer : public MCTargetStreamer {
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
Expand Down Expand Up @@ -83,6 +86,9 @@ class MipsTargetAsmStreamer : public MipsTargetStreamer {
void emitDirectiveSetMips64() override;
void emitDirectiveSetMips64R2() override;
void emitDirectiveSetDsp() override;

// PIC support
virtual void emitDirectiveCpload(unsigned RegNo);
};

// This part is for ELF object output
Expand Down Expand Up @@ -128,6 +134,14 @@ class MipsTargetELFStreamer : public MipsTargetStreamer {
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 changes: 15 additions & 0 deletions llvm/test/MC/Mips/cpload-bad.s
Original file line number Diff line number Diff line change
@@ -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 changes: 33 additions & 0 deletions llvm/test/MC/Mips/cpload.s
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit 525bc4f

Please sign in to comment.