[mips] Add assembler support for the .cprestore directive.

Summary:
This assembler directive is used in O32 PIC to restore the current function's $gp after executing JAL's. The $gp is first stored on the stack at a user-specified offset.
It has the following format: ".cprestore 8" (where 8 is the offset).

This fixes llvm.org/PR20967.

Patch by Toma Tabacu.

Reviewers: seanbruno, tomatabacu

Subscribers: brooks, seanbruno, emaste, llvm-commits

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

llvm-svn: 247897
This commit is contained in:
Daniel Sanders 2015-09-17 16:08:39 +00:00
parent 30618f978e
commit e2982adc0b
7 changed files with 387 additions and 13 deletions

View File

@ -116,6 +116,8 @@ class MipsAsmParser : public MCTargetAsmParser {
// directive.
bool IsLittleEndian;
bool IsPicEnabled;
bool IsCpRestoreSet;
int CpRestoreOffset;
// Print a warning along with its fix-it message at the given range.
void printWarningWithFixIt(const Twine &Msg, const Twine &FixMsg,
@ -219,6 +221,9 @@ class MipsAsmParser : public MCTargetAsmParser {
void createAddu(unsigned DstReg, unsigned SrcReg, unsigned TrgReg,
bool Is64Bit, SmallVectorImpl<MCInst> &Instructions);
void createCpRestoreMemOp(bool IsLoad, int StackOffset, SMLoc IDLoc,
SmallVectorImpl<MCInst> &Instructions);
bool reportParseError(Twine ErrorMsg);
bool reportParseError(SMLoc Loc, Twine ErrorMsg);
@ -231,7 +236,9 @@ class MipsAsmParser : public MCTargetAsmParser {
bool parseSetMips0Directive();
bool parseSetArchDirective();
bool parseSetFeature(uint64_t Feature);
bool isPicAndNotNxxAbi(); // Used by .cpload, .cprestore, and .cpsetup.
bool parseDirectiveCpLoad(SMLoc Loc);
bool parseDirectiveCpRestore(SMLoc Loc);
bool parseDirectiveCPSetup();
bool parseDirectiveNaN();
bool parseDirectiveSet();
@ -402,6 +409,9 @@ public:
IsPicEnabled =
(getContext().getObjectFileInfo()->getRelocM() == Reloc::PIC_);
IsCpRestoreSet = false;
CpRestoreOffset = -1;
Triple TheTriple(sti.getTargetTriple());
if ((TheTriple.getArch() == Triple::mips) ||
(TheTriple.getArch() == Triple::mips64))
@ -1355,6 +1365,7 @@ static unsigned countMCSymbolRefExpr(const MCExpr *Expr) {
bool MipsAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc,
SmallVectorImpl<MCInst> &Instructions) {
const MCInstrDesc &MCID = getInstDesc(Inst.getOpcode());
bool ExpandedJalSym = false;
Inst.setLoc(IDLoc);
@ -1581,7 +1592,10 @@ bool MipsAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc,
}
MCInst JalrInst;
JalrInst.setOpcode(inMicroMipsMode() ? Mips::JALR_MM : Mips::JALR);
if (IsCpRestoreSet && inMicroMipsMode())
JalrInst.setOpcode(Mips::JALRS_MM);
else
JalrInst.setOpcode(inMicroMipsMode() ? Mips::JALR_MM : Mips::JALR);
JalrInst.addOperand(MCOperand::createReg(Mips::RA));
JalrInst.addOperand(MCOperand::createReg(Mips::T9));
@ -1590,6 +1604,7 @@ bool MipsAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc,
// and is not necessary for correctness.
Inst = JalrInst;
ExpandedJalSym = true;
}
if (MCID.mayLoad() || MCID.mayStore()) {
@ -1800,6 +1815,28 @@ bool MipsAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc,
if (MCID.hasDelaySlot() && AssemblerOptions.back()->isReorder())
createNop(hasShortDelaySlot(Inst.getOpcode()), IDLoc, Instructions);
if ((Inst.getOpcode() == Mips::JalOneReg ||
Inst.getOpcode() == Mips::JalTwoReg || ExpandedJalSym) &&
isPicAndNotNxxAbi()) {
if (IsCpRestoreSet) {
// We need a NOP between the JALR and the LW:
// If .set reorder has been used, we've already emitted a NOP.
// If .set noreorder has been used, we need to emit a NOP at this point.
if (!AssemblerOptions.back()->isReorder())
createNop(hasShortDelaySlot(Inst.getOpcode()), IDLoc, Instructions);
// Load the $gp from the stack.
SmallVector<MCInst, 3> LoadInsts;
createCpRestoreMemOp(true /*IsLoad*/, CpRestoreOffset /*StackOffset*/,
IDLoc, LoadInsts);
for (const MCInst &Inst : LoadInsts)
Instructions.push_back(Inst);
} else
Warning(IDLoc, "no .cprestore used in PIC mode");
}
return false;
}
@ -2004,7 +2041,10 @@ bool MipsAsmParser::expandJalWithRegs(MCInst &Inst, SMLoc IDLoc,
if (Opcode == Mips::JalOneReg) {
// jal $rs => jalr $rs
if (inMicroMipsMode()) {
if (IsCpRestoreSet && inMicroMipsMode()) {
JalrInst.setOpcode(Mips::JALRS16_MM);
JalrInst.addOperand(FirstRegOp);
} else if (inMicroMipsMode()) {
JalrInst.setOpcode(Mips::JALR16_MM);
JalrInst.addOperand(FirstRegOp);
} else {
@ -2014,7 +2054,10 @@ bool MipsAsmParser::expandJalWithRegs(MCInst &Inst, SMLoc IDLoc,
}
} else if (Opcode == Mips::JalTwoReg) {
// jal $rd, $rs => jalr $rd, $rs
JalrInst.setOpcode(inMicroMipsMode() ? Mips::JALR_MM : Mips::JALR);
if (IsCpRestoreSet && inMicroMipsMode())
JalrInst.setOpcode(Mips::JALRS_MM);
else
JalrInst.setOpcode(inMicroMipsMode() ? Mips::JALR_MM : Mips::JALR);
JalrInst.addOperand(FirstRegOp);
const MCOperand SecondRegOp = Inst.getOperand(1);
JalrInst.addOperand(SecondRegOp);
@ -2022,16 +2065,8 @@ bool MipsAsmParser::expandJalWithRegs(MCInst &Inst, SMLoc IDLoc,
Instructions.push_back(JalrInst);
// If .set reorder is active, emit a NOP after it.
if (AssemblerOptions.back()->isReorder()) {
// This is a 32-bit NOP because these 2 pseudo-instructions
// do not have a short delay slot.
MCInst NopInst;
NopInst.setOpcode(Mips::SLL);
NopInst.addOperand(MCOperand::createReg(Mips::ZERO));
NopInst.addOperand(MCOperand::createReg(Mips::ZERO));
NopInst.addOperand(MCOperand::createImm(0));
Instructions.push_back(NopInst);
}
if (AssemblerOptions.back()->isReorder())
createNop(hasShortDelaySlot(JalrInst.getOpcode()), IDLoc, Instructions);
return false;
}
@ -3109,6 +3144,22 @@ void MipsAsmParser::createAddu(unsigned DstReg, unsigned SrcReg,
Instructions);
}
void MipsAsmParser::createCpRestoreMemOp(
bool IsLoad, int StackOffset, SMLoc IDLoc,
SmallVectorImpl<MCInst> &Instructions) {
MCInst MemInst;
MemInst.setOpcode(IsLoad ? Mips::LW : Mips::SW);
MemInst.addOperand(MCOperand::createReg(Mips::GP));
MemInst.addOperand(MCOperand::createReg(Mips::SP));
MemInst.addOperand(MCOperand::createImm(StackOffset));
// If the offset can not fit into 16 bits, we need to expand.
if (!isInt<16>(StackOffset))
expandMemInst(MemInst, IDLoc, Instructions, IsLoad, true /*HasImmOpnd*/);
else
Instructions.push_back(MemInst);
}
unsigned MipsAsmParser::checkTargetMatchPredicate(MCInst &Inst) {
// As described by the Mips32r2 spec, the registers Rd and Rs for
// jalr.hb must be different.
@ -4758,6 +4809,14 @@ bool MipsAsmParser::eatComma(StringRef ErrorStr) {
return true;
}
// Used to determine if .cpload, .cprestore, and .cpsetup have any effect.
// In this class, it is only used for .cprestore.
// FIXME: Only keep track of IsPicEnabled in one place, instead of in both
// MipsTargetELFStreamer and MipsAsmParser.
bool MipsAsmParser::isPicAndNotNxxAbi() {
return inPicMode() && !(isABI_N32() || isABI_N64());
}
bool MipsAsmParser::parseDirectiveCpLoad(SMLoc Loc) {
if (AssemblerOptions.back()->isReorder())
Warning(Loc, ".cpload should be inside a noreorder section");
@ -4790,6 +4849,54 @@ bool MipsAsmParser::parseDirectiveCpLoad(SMLoc Loc) {
return false;
}
bool MipsAsmParser::parseDirectiveCpRestore(SMLoc Loc) {
MCAsmParser &Parser = getParser();
// Note that .cprestore is ignored if used with the N32 and N64 ABIs or if it
// is used in non-PIC mode.
if (inMips16Mode()) {
reportParseError(".cprestore is not supported in Mips16 mode");
return false;
}
// Get the stack offset value.
const MCExpr *StackOffset;
int64_t StackOffsetVal;
if (Parser.parseExpression(StackOffset)) {
reportParseError("expected stack offset value");
return false;
}
if (!StackOffset->evaluateAsAbsolute(StackOffsetVal)) {
reportParseError("stack offset is not an absolute expression");
return false;
}
if (StackOffsetVal < 0) {
Warning(Loc, ".cprestore with negative stack offset has no effect");
IsCpRestoreSet = false;
} else {
IsCpRestoreSet = true;
CpRestoreOffset = StackOffsetVal;
}
// 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;
}
// Store the $gp on the stack.
SmallVector<MCInst, 3> StoreInsts;
createCpRestoreMemOp(false /*IsLoad*/, CpRestoreOffset /*StackOffset*/, Loc,
StoreInsts);
getTargetStreamer().emitDirectiveCpRestore(StoreInsts, CpRestoreOffset);
Parser.Lex(); // Consume the EndOfStatement.
return false;
}
bool MipsAsmParser::parseDirectiveCPSetup() {
MCAsmParser &Parser = getParser();
unsigned FuncReg;
@ -5322,6 +5429,8 @@ bool MipsAsmParser::ParseDirective(AsmToken DirectiveID) {
if (IDVal == ".cpload")
return parseDirectiveCpLoad(DirectiveID.getLoc());
if (IDVal == ".cprestore")
return parseDirectiveCpRestore(DirectiveID.getLoc());
if (IDVal == ".dword") {
parseDataDirective(8, DirectiveID.getLoc());
return false;
@ -5372,6 +5481,7 @@ bool MipsAsmParser::ParseDirective(AsmToken DirectiveID) {
getTargetStreamer().emitDirectiveEnt(*Sym);
CurrentFn = Sym;
IsCpRestoreSet = false;
return false;
}
@ -5400,6 +5510,7 @@ bool MipsAsmParser::ParseDirective(AsmToken DirectiveID) {
getTargetStreamer().emitDirectiveEnd(SymbolName);
CurrentFn = nullptr;
IsCpRestoreSet = false;
return false;
}
@ -5471,6 +5582,7 @@ bool MipsAsmParser::ParseDirective(AsmToken DirectiveID) {
getTargetStreamer().emitFrame(StackReg, FrameSizeVal,
ReturnRegOpnd.getGPR32Reg());
IsCpRestoreSet = false;
return false;
}

View File

@ -89,6 +89,10 @@ void MipsTargetStreamer::emitDirectiveSetHardFloat() {
void MipsTargetStreamer::emitDirectiveSetDsp() { forbidModuleDirective(); }
void MipsTargetStreamer::emitDirectiveSetNoDsp() { forbidModuleDirective(); }
void MipsTargetStreamer::emitDirectiveCpLoad(unsigned RegNo) {}
void MipsTargetStreamer::emitDirectiveCpRestore(
SmallVector<MCInst, 3> &StoreInsts, int Offset) {
forbidModuleDirective();
}
void MipsTargetStreamer::emitDirectiveCpsetup(unsigned RegNo, int RegOrOffset,
const MCSymbol &Sym, bool IsReg) {
}
@ -358,6 +362,12 @@ void MipsTargetAsmStreamer::emitDirectiveCpLoad(unsigned RegNo) {
forbidModuleDirective();
}
void MipsTargetAsmStreamer::emitDirectiveCpRestore(
SmallVector<MCInst, 3> &StoreInsts, int Offset) {
MipsTargetStreamer::emitDirectiveCpRestore(StoreInsts, Offset);
OS << "\t.cprestore\t" << Offset << "\n";
}
void MipsTargetAsmStreamer::emitDirectiveCpsetup(unsigned RegNo,
int RegOrOffset,
const MCSymbol &Sym,
@ -752,6 +762,24 @@ void MipsTargetELFStreamer::emitDirectiveCpLoad(unsigned RegNo) {
forbidModuleDirective();
}
void MipsTargetELFStreamer::emitDirectiveCpRestore(
SmallVector<MCInst, 3> &StoreInsts, int Offset) {
MipsTargetStreamer::emitDirectiveCpRestore(StoreInsts, Offset);
// .cprestore offset
// When PIC mode is enabled and the O32 ABI is used, this directive expands
// to:
// sw $gp, offset($sp)
// and adds a corresponding LW after every JAL.
// Note that .cprestore is ignored if used with the N32 and N64 ABIs or if it
// is used in non-PIC mode.
if (!Pic || (getABI().IsN32() || getABI().IsN64()))
return;
for (const MCInst &Inst : StoreInsts)
getStreamer().EmitInstruction(Inst, STI);
}
void MipsTargetELFStreamer::emitDirectiveCpsetup(unsigned RegNo,
int RegOrOffset,
const MCSymbol &Sym,

View File

@ -78,6 +78,8 @@ public:
// PIC support
virtual void emitDirectiveCpLoad(unsigned RegNo);
virtual void emitDirectiveCpRestore(SmallVector<MCInst, 3> &StoreInsts,
int Offset);
virtual void emitDirectiveCpsetup(unsigned RegNo, int RegOrOffset,
const MCSymbol &Sym, bool IsReg);
@ -189,6 +191,8 @@ public:
// PIC support
void emitDirectiveCpLoad(unsigned RegNo) override;
void emitDirectiveCpRestore(SmallVector<MCInst, 3> &StoreInsts,
int Offset) override;
void emitDirectiveCpsetup(unsigned RegNo, int RegOrOffset,
const MCSymbol &Sym, bool IsReg) override;
@ -238,6 +242,8 @@ public:
// PIC support
void emitDirectiveCpLoad(unsigned RegNo) override;
void emitDirectiveCpRestore(SmallVector<MCInst, 3> &StoreInsts,
int Offset) override;
void emitDirectiveCpsetup(unsigned RegNo, int RegOrOffset,
const MCSymbol &Sym, bool IsReg) override;

View File

@ -0,0 +1,23 @@
# RUN: not llvm-mc %s -arch=mips -mcpu=mips32 -relocation-model=pic 2>%t1
# RUN: FileCheck %s < %t1
.text
.set noreorder
.cpload $25
.set mips16
.cprestore 8
# CHECK: :[[@LINE-1]]:14: error: .cprestore is not supported in Mips16 mode
.set nomips16
.cprestore
# CHECK: :[[@LINE-1]]:13: error: expected stack offset value
.cprestore foo
# CHECK: :[[@LINE-1]]:17: error: stack offset is not an absolute expression
.cprestore -8
# CHECK: :[[@LINE-1]]:3: warning: .cprestore with negative stack offset has no effect
.cprestore 8, 35, bar
# CHECK: :[[@LINE-1]]:15: error: unexpected token, expected end of statement

View File

@ -0,0 +1,97 @@
# RUN: llvm-mc %s -arch=mips -mcpu=mips32 -relocation-model=pic -show-encoding | \
# RUN: FileCheck %s
# RUN: llvm-mc %s -arch=mips -mcpu=mips32 -relocation-model=pic -filetype=obj -o -| \
# RUN: llvm-objdump -d -r -arch=mips - | \
# RUN: FileCheck %s -check-prefix=CHECK-FOR-STORE
# RUN: llvm-mc %s -arch=mips -mcpu=mips32 -mattr=+micromips -relocation-model=pic -show-encoding | \
# RUN: FileCheck %s -check-prefix=MICROMIPS
# RUN: llvm-mc %s -arch=mips -mcpu=mips32 -relocation-model=static -show-encoding | \
# RUN: FileCheck %s -check-prefix=NO-PIC
# RUN: llvm-mc %s -arch=mips -mcpu=mips64 -target-abi n32 -relocation-model=pic -show-encoding | \
# RUN: FileCheck %s -check-prefix=BAD-ABI -check-prefix=BAD-ABI-N32
# RUN: llvm-mc %s -arch=mips64 -mcpu=mips64 -target-abi n64 -relocation-model=pic -show-encoding | \
# RUN: FileCheck %s -check-prefix=BAD-ABI -check-prefix=BAD-ABI-N64
.text
.ent foo
foo:
.frame $sp, 0, $ra
.set noreorder
.cpload $25
.cprestore 8
jal $25
jal $4, $25
jal foo
.end foo
# CHECK-FOR-STORE: sw $gp, 8($sp)
# CHECK: .cprestore 8
# CHECK: jalr $25 # encoding: [0x03,0x20,0xf8,0x09]
# CHECK: nop # encoding: [0x00,0x00,0x00,0x00]
# CHECK: lw $gp, 8($sp) # encoding: [0x8f,0xbc,0x00,0x08]
# CHECK: jalr $4, $25 # encoding: [0x03,0x20,0x20,0x09]
# CHECK: nop # encoding: [0x00,0x00,0x00,0x00]
# CHECK: lw $gp, 8($sp) # encoding: [0x8f,0xbc,0x00,0x08]
# CHECK: lw $25, %got(foo)($gp) # encoding: [0x8f,0x99,A,A]
# CHECK: # fixup A - offset: 0, value: foo@GOT, kind: fixup_Mips_GOT_Local
# CHECK: addiu $25, $25, %lo(foo) # encoding: [0x27,0x39,A,A]
# CHECK: # fixup A - offset: 0, value: foo@ABS_LO, kind: fixup_Mips_LO16
# CHECK: jalr $25 # encoding: [0x03,0x20,0xf8,0x09]
# CHECK: nop # encoding: [0x00,0x00,0x00,0x00]
# CHECK: lw $gp, 8($sp) # encoding: [0x8f,0xbc,0x00,0x08]
# CHECK: .end foo
# MICROMIPS: .cprestore 8
# MICROMIPS: jalrs16 $25 # encoding: [0x45,0xf9]
# MICROMIPS: nop # encoding: [0x00,0x00,0x00,0x00]
# MICROMIPS: lw $gp, 8($sp) # encoding: [0xff,0x9d,0x00,0x08]
# MICROMIPS: jalrs $4, $25 # encoding: [0x00,0x99,0x4f,0x3c]
# MICROMIPS: nop # encoding: [0x00,0x00,0x00,0x00]
# MICROMIPS: lw $gp, 8($sp) # encoding: [0xff,0x9d,0x00,0x08]
# MICROMIPS: lw $25, %got(foo)($gp) # encoding: [0xff,0x3c,A,A]
# MICROMIPS: # fixup A - offset: 0, value: foo@GOT, kind: fixup_MICROMIPS_GOT16
# MICROMIPS: addiu $25, $25, %lo(foo) # encoding: [0x33,0x39,A,A]
# MICROMIPS: # fixup A - offset: 0, value: foo@ABS_LO, kind: fixup_MICROMIPS_LO16
# MICROMIPS: jalrs $ra, $25 # encoding: [0x03,0xf9,0x4f,0x3c]
# MICROMIPS: nop # encoding: [0x0c,0x00]
# MICROMIPS: lw $gp, 8($sp) # encoding: [0xff,0x9d,0x00,0x08]
# MICROMIPS: .end foo
# NO-PIC: .cprestore 8
# NO-PIC: jalr $25 # encoding: [0x03,0x20,0xf8,0x09]
# NO-PIC-NOT: lw $gp, 8($sp) # encoding: [0x8f,0xbc,0x00,0x08]
# NO-PIC: jalr $4, $25 # encoding: [0x03,0x20,0x20,0x09]
# NO-PIC-NOT: lw $gp, 8($sp) # encoding: [0x8f,0xbc,0x00,0x08]
# NO-PIC: jal foo # encoding: [0b000011AA,A,A,A]
# NO-PIC: # fixup A - offset: 0, value: foo, kind: fixup_Mips_26
# NO-PIC-NOT: lw $gp, 8($sp) # encoding: [0x8f,0xbc,0x00,0x08]
# NO-PIC: .end foo
# BAD-ABI: .cprestore 8
# BAD-ABI: jalr $25 # encoding: [0x03,0x20,0xf8,0x09]
# BAD-ABI-NOT: lw $gp, 8($sp) # encoding: [0x8f,0xbc,0x00,0x08]
# BAD-ABI: jalr $4, $25 # encoding: [0x03,0x20,0x20,0x09]
# BAD-ABI-NOT: lw $gp, 8($sp) # encoding: [0x8f,0xbc,0x00,0x08]
# BAD-ABI-N32: lw $25, %got_disp(foo)($gp) # encoding: [0x8f,0x99,A,A]
# BAD-ABI-N64: ld $25, %got_disp(foo)($gp) # encoding: [0xdf,0x99,A,A]
# BAD-ABI: # fixup A - offset: 0, value: foo@GOT_DISP, kind: fixup_Mips_GOT_DISP
# BAD-ABI: jalr $25 # encoding: [0x03,0x20,0xf8,0x09]
# BAD-ABI-NOT: lw $gp, 8($sp) # encoding: [0x8f,0xbc,0x00,0x08]
# BAD-ABI: .end foo

View File

@ -0,0 +1,98 @@
# RUN: llvm-mc %s -arch=mips -mcpu=mips32 -relocation-model=pic -show-encoding | \
# RUN: FileCheck %s
# RUN: llvm-mc %s -arch=mips -mcpu=mips32 -relocation-model=pic -filetype=obj -o -| \
# RUN: llvm-objdump -d -r -arch=mips - | \
# RUN: FileCheck %s -check-prefix=CHECK-FOR-STORE
# RUN: llvm-mc %s -arch=mips -mcpu=mips32 -mattr=+micromips -relocation-model=pic -show-encoding | \
# RUN: FileCheck %s -check-prefix=MICROMIPS
# RUN: llvm-mc %s -arch=mips -mcpu=mips32 -relocation-model=static -show-encoding | \
# RUN: FileCheck %s -check-prefix=NO-PIC
# RUN: llvm-mc %s -arch=mips -mcpu=mips64 -target-abi n32 -relocation-model=pic -show-encoding | \
# RUN: FileCheck %s -check-prefix=BAD-ABI -check-prefix=BAD-ABI-N32
# RUN: llvm-mc %s -arch=mips64 -mcpu=mips64 -target-abi n64 -relocation-model=pic -show-encoding | \
# RUN: FileCheck %s -check-prefix=BAD-ABI -check-prefix=BAD-ABI-N64
.text
.ent foo
foo:
.frame $sp, 0, $ra
.set noreorder
.cpload $25
.set reorder
.cprestore 8
jal $25
jal $4, $25
jal foo
.end foo
# CHECK-FOR-STORE: sw $gp, 8($sp)
# CHECK: .cprestore 8
# CHECK: jalr $25 # encoding: [0x03,0x20,0xf8,0x09]
# CHECK: nop # encoding: [0x00,0x00,0x00,0x00]
# CHECK: lw $gp, 8($sp) # encoding: [0x8f,0xbc,0x00,0x08]
# CHECK: jalr $4, $25 # encoding: [0x03,0x20,0x20,0x09]
# CHECK: nop # encoding: [0x00,0x00,0x00,0x00]
# CHECK: lw $gp, 8($sp) # encoding: [0x8f,0xbc,0x00,0x08]
# CHECK: lw $25, %got(foo)($gp) # encoding: [0x8f,0x99,A,A]
# CHECK: # fixup A - offset: 0, value: foo@GOT, kind: fixup_Mips_GOT_Local
# CHECK: addiu $25, $25, %lo(foo) # encoding: [0x27,0x39,A,A]
# CHECK: # fixup A - offset: 0, value: foo@ABS_LO, kind: fixup_Mips_LO16
# CHECK: jalr $25 # encoding: [0x03,0x20,0xf8,0x09]
# CHECK: nop # encoding: [0x00,0x00,0x00,0x00]
# CHECK: lw $gp, 8($sp) # encoding: [0x8f,0xbc,0x00,0x08]
# CHECK: .end foo
# MICROMIPS: .cprestore 8
# MICROMIPS: jalrs16 $25 # encoding: [0x45,0xf9]
# MICROMIPS: nop # encoding: [0x0c,0x00]
# MICROMIPS: lw $gp, 8($sp) # encoding: [0xff,0x9d,0x00,0x08]
# MICROMIPS: jalrs $4, $25 # encoding: [0x00,0x99,0x4f,0x3c]
# MICROMIPS: nop # encoding: [0x0c,0x00]
# MICROMIPS: lw $gp, 8($sp) # encoding: [0xff,0x9d,0x00,0x08]
# MICROMIPS: lw $25, %got(foo)($gp) # encoding: [0xff,0x3c,A,A]
# MICROMIPS: # fixup A - offset: 0, value: foo@GOT, kind: fixup_MICROMIPS_GOT16
# MICROMIPS: addiu $25, $25, %lo(foo) # encoding: [0x33,0x39,A,A]
# MICROMIPS: # fixup A - offset: 0, value: foo@ABS_LO, kind: fixup_MICROMIPS_LO16
# MICROMIPS: jalrs $ra, $25 # encoding: [0x03,0xf9,0x4f,0x3c]
# MICROMIPS: nop # encoding: [0x0c,0x00]
# MICROMIPS: lw $gp, 8($sp) # encoding: [0xff,0x9d,0x00,0x08]
# MICROMIPS: .end foo
# NO-PIC: .cprestore 8
# NO-PIC: jalr $25 # encoding: [0x03,0x20,0xf8,0x09]
# NO-PIC-NOT: lw $gp, 8($sp) # encoding: [0x8f,0xbc,0x00,0x08]
# NO-PIC: jalr $4, $25 # encoding: [0x03,0x20,0x20,0x09]
# NO-PIC-NOT: lw $gp, 8($sp) # encoding: [0x8f,0xbc,0x00,0x08]
# NO-PIC: jal foo # encoding: [0b000011AA,A,A,A]
# NO-PIC: # fixup A - offset: 0, value: foo, kind: fixup_Mips_26
# NO-PIC-NOT: lw $gp, 8($sp) # encoding: [0x8f,0xbc,0x00,0x08]
# NO-PIC: .end foo
# BAD-ABI: .cprestore 8
# BAD-ABI: jalr $25 # encoding: [0x03,0x20,0xf8,0x09]
# BAD-ABI-NOT: lw $gp, 8($sp) # encoding: [0x8f,0xbc,0x00,0x08]
# BAD-ABI: jalr $4, $25 # encoding: [0x03,0x20,0x20,0x09]
# BAD-ABI-NOT: lw $gp, 8($sp) # encoding: [0x8f,0xbc,0x00,0x08]
# BAD-ABI-N32: lw $25, %got_disp(foo)($gp) # encoding: [0x8f,0x99,A,A]
# BAD-ABI-N64: ld $25, %got_disp(foo)($gp) # encoding: [0xdf,0x99,A,A]
# BAD-ABI: # fixup A - offset: 0, value: foo@GOT_DISP, kind: fixup_Mips_GOT_DISP
# BAD-ABI: jalr $25 # encoding: [0x03,0x20,0xf8,0x09]
# BAD-ABI-NOT: lw $gp, 8($sp) # encoding: [0x8f,0xbc,0x00,0x08]
# BAD-ABI: .end foo

View File

@ -0,0 +1,10 @@
# RUN: llvm-mc %s -arch=mips -mcpu=mips32 -relocation-model=pic 2>%t1
# RUN: FileCheck %s < %t1
.text
.set noreorder
.cpload $25
.set reorder
jal $25
# CHECK: :[[@LINE-1]]:3: warning: no .cprestore used in PIC mode