[mips] Move expansion of .cpsetup to target streamer.

Summary:
There are two functional changes:
1) The directive is not expanded for the ASM->ASM code path.
2) If PIC is not set, there's no expansion for the ASM->OBJ code path (same behaviour as GAS).

Reviewers: dsanders

Reviewed By: dsanders

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

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@207741 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Matheus Almeida 2014-05-01 10:24:46 +00:00
parent 873f87c2de
commit 4c715625d9
4 changed files with 135 additions and 64 deletions

View File

@ -2361,58 +2361,8 @@ bool MipsAsmParser::parseDirectiveCPSetup() {
if (Parser.parseIdentifier(Name))
reportParseError("expected identifier");
MCSymbol *Sym = getContext().GetOrCreateSymbol(Name);
unsigned GPReg = getGPR(matchCPURegisterName("gp"));
// FIXME: The code below this point should be in the TargetStreamers.
// Only N32 and N64 emit anything for .cpsetup
// FIXME: We should only emit something for PIC mode too.
if (!isN32() && !isN64())
return false;
MCStreamer &TS = getStreamer();
MCInst Inst;
// Either store the old $gp in a register or on the stack
if (SaveIsReg) {
// move $save, $gpreg
Inst.setOpcode(Mips::DADDu);
Inst.addOperand(MCOperand::CreateReg(Save));
Inst.addOperand(MCOperand::CreateReg(GPReg));
Inst.addOperand(MCOperand::CreateReg(getGPR(0)));
} else {
// sd $gpreg, offset($sp)
Inst.setOpcode(Mips::SD);
Inst.addOperand(MCOperand::CreateReg(GPReg));
Inst.addOperand(MCOperand::CreateReg(getGPR(matchCPURegisterName("sp"))));
Inst.addOperand(MCOperand::CreateImm(Save));
}
TS.EmitInstruction(Inst, STI);
Inst.clear();
const MCSymbolRefExpr *HiExpr = MCSymbolRefExpr::Create(
Sym->getName(), MCSymbolRefExpr::VK_Mips_GPOFF_HI, getContext());
const MCSymbolRefExpr *LoExpr = MCSymbolRefExpr::Create(
Sym->getName(), MCSymbolRefExpr::VK_Mips_GPOFF_LO, getContext());
// lui $gp, %hi(%neg(%gp_rel(funcSym)))
Inst.setOpcode(Mips::LUi);
Inst.addOperand(MCOperand::CreateReg(GPReg));
Inst.addOperand(MCOperand::CreateExpr(HiExpr));
TS.EmitInstruction(Inst, STI);
Inst.clear();
// addiu $gp, $gp, %lo(%neg(%gp_rel(funcSym)))
Inst.setOpcode(Mips::ADDiu);
Inst.addOperand(MCOperand::CreateReg(GPReg));
Inst.addOperand(MCOperand::CreateReg(GPReg));
Inst.addOperand(MCOperand::CreateExpr(LoExpr));
TS.EmitInstruction(Inst, STI);
Inst.clear();
// daddu $gp, $gp, $funcreg
Inst.setOpcode(Mips::DADDu);
Inst.addOperand(MCOperand::CreateReg(GPReg));
Inst.addOperand(MCOperand::CreateReg(GPReg));
Inst.addOperand(MCOperand::CreateReg(FuncReg));
TS.EmitInstruction(Inst, STI);
getTargetStreamer().emitDirectiveCpsetup(FuncReg, Save, *Sym, SaveIsReg);
return false;
}

View File

@ -149,6 +149,24 @@ void MipsTargetAsmStreamer::emitDirectiveCpload(unsigned RegNo) {
<< StringRef(MipsInstPrinter::getRegisterName(RegNo)).lower() << "\n";
}
void MipsTargetAsmStreamer::emitDirectiveCpsetup(unsigned RegNo,
int RegOrOffset,
const MCSymbol &Sym,
bool IsReg) {
OS << "\t.cpsetup\t$"
<< StringRef(MipsInstPrinter::getRegisterName(RegNo)).lower() << ", ";
if (IsReg)
OS << "$"
<< StringRef(MipsInstPrinter::getRegisterName(RegOrOffset)).lower();
else
OS << RegOrOffset;
OS << ", ";
OS << Sym.getName() << "\n";
}
// This part is for ELF object output.
MipsTargetELFStreamer::MipsTargetELFStreamer(MCStreamer &S,
const MCSubtargetInfo &STI)
@ -456,3 +474,58 @@ void MipsTargetELFStreamer::emitDirectiveCpload(unsigned RegNo) {
TmpInst.addOperand(MCOperand::CreateReg(RegNo));
getStreamer().EmitInstruction(TmpInst, STI);
}
void MipsTargetELFStreamer::emitDirectiveCpsetup(unsigned RegNo,
int RegOrOffset,
const MCSymbol &Sym,
bool IsReg) {
// Only N32 and N64 emit anything for .cpsetup iff PIC is set.
if (!Pic || !(isN32() || isN64()))
return;
MCAssembler &MCA = getStreamer().getAssembler();
MCInst Inst;
// Either store the old $gp in a register or on the stack
if (IsReg) {
// move $save, $gpreg
Inst.setOpcode(Mips::DADDu);
Inst.addOperand(MCOperand::CreateReg(RegOrOffset));
Inst.addOperand(MCOperand::CreateReg(Mips::GP));
Inst.addOperand(MCOperand::CreateReg(Mips::ZERO));
} else {
// sd $gpreg, offset($sp)
Inst.setOpcode(Mips::SD);
Inst.addOperand(MCOperand::CreateReg(Mips::GP));
Inst.addOperand(MCOperand::CreateReg(Mips::SP));
Inst.addOperand(MCOperand::CreateImm(RegOrOffset));
}
getStreamer().EmitInstruction(Inst, STI);
Inst.clear();
const MCSymbolRefExpr *HiExpr = MCSymbolRefExpr::Create(
Sym.getName(), MCSymbolRefExpr::VK_Mips_GPOFF_HI, MCA.getContext());
const MCSymbolRefExpr *LoExpr = MCSymbolRefExpr::Create(
Sym.getName(), MCSymbolRefExpr::VK_Mips_GPOFF_LO, MCA.getContext());
// lui $gp, %hi(%neg(%gp_rel(funcSym)))
Inst.setOpcode(Mips::LUi);
Inst.addOperand(MCOperand::CreateReg(Mips::GP));
Inst.addOperand(MCOperand::CreateExpr(HiExpr));
getStreamer().EmitInstruction(Inst, STI);
Inst.clear();
// addiu $gp, $gp, %lo(%neg(%gp_rel(funcSym)))
Inst.setOpcode(Mips::ADDiu);
Inst.addOperand(MCOperand::CreateReg(Mips::GP));
Inst.addOperand(MCOperand::CreateReg(Mips::GP));
Inst.addOperand(MCOperand::CreateExpr(LoExpr));
getStreamer().EmitInstruction(Inst, STI);
Inst.clear();
// daddu $gp, $gp, $funcreg
Inst.setOpcode(Mips::DADDu);
Inst.addOperand(MCOperand::CreateReg(Mips::GP));
Inst.addOperand(MCOperand::CreateReg(Mips::GP));
Inst.addOperand(MCOperand::CreateReg(RegNo));
getStreamer().EmitInstruction(Inst, STI);
}

View File

@ -50,6 +50,8 @@ public:
// PIC support
virtual void emitDirectiveCpload(unsigned RegNo) = 0;
virtual void emitDirectiveCpsetup(unsigned RegNo, int RegOrOffset,
const MCSymbol &Sym, bool IsReg) = 0;
};
// This part is for ascii assembly output
@ -89,6 +91,8 @@ public:
// PIC support
virtual void emitDirectiveCpload(unsigned RegNo);
void emitDirectiveCpsetup(unsigned RegNo, int RegOrOffset,
const MCSymbol &Sym, bool IsReg) override;
};
// This part is for ELF object output
@ -137,6 +141,8 @@ public:
// PIC support
virtual void emitDirectiveCpload(unsigned RegNo);
void emitDirectiveCpsetup(unsigned RegNo, int RegOrOffset,
const MCSymbol &Sym, bool IsReg) override;
protected:
bool isO32() const { return STI.getFeatureBits() & Mips::FeatureO32; }

View File

@ -1,36 +1,78 @@
# RUN: llvm-mc -triple mips64-unknown-unknown -mattr=-n64,+o32 %s | \
# RUN: FileCheck -check-prefix=ANY -check-prefix=O32 %s
# RUN: llvm-mc -triple mips64-unknown-unknown -mattr=-n64,+n32 %s | \
# RUN: FileCheck -check-prefix=ANY -check-prefix=NXX -check-prefix=N32 %s
# RUN: llvm-mc -triple mips64-unknown-unknown %s | \
# RUN: FileCheck -check-prefix=ANY -check-prefix=NXX -check-prefix=N64 %s
# RUN: llvm-mc -triple mips64-unknown-unknown -mattr=-n64,+o32 -filetype=obj -o - %s | \
# RUN: llvm-objdump -d -r -arch=mips64 - | \
# RUN: FileCheck -check-prefix=O32 %s
# TODO: !PIC -> no output
# RUN: llvm-mc -triple mips64-unknown-unknown -mattr=-n64,+o32 %s | \
# RUN: FileCheck -check-prefix=ASM %s
# RUN: llvm-mc -triple mips64-unknown-unknown -mattr=-n64,+n32 -filetype=obj -o - %s | \
# RUN: llvm-objdump -d -r -arch=mips64 - | \
# RUN: FileCheck -check-prefix=NXX -check-prefix=N32 %s
# RUN: llvm-mc -triple mips64-unknown-unknown -mattr=-n64,+n32 %s | \
# RUN: FileCheck -check-prefix=ASM %s
# RUN: llvm-mc -triple mips64-unknown-unknown %s -filetype=obj -o - | \
# RUN: llvm-objdump -d -r -arch=mips64 - | \
# RUN: FileCheck -check-prefix=NXX -check-prefix=N64 %s
# RUN: llvm-mc -triple mips64-unknown-unknown %s | \
# RUN: FileCheck -check-prefix=ASM %s
.text
.option pic2
t1:
.cpsetup $25, 8, __cerror
# ANY-LABEL: t1:
# O32-NOT: __cerror
# FIXME: Direct object emission for N32 is still under development.
# N32 doesn't allow 3 operations to be specified in the same relocation
# record like N64 does.
# NXX: sd $gp, 8($sp)
# NXX: lui $gp, %hi(%neg(%gp_rel(__cerror)))
# NXX: addiu $gp, $gp, %lo(%neg(%gp_rel(__cerror)))
# NXX: lui $gp, 0
# NXX: R_MIPS_GPREL16/R_MIPS_SUB/R_MIPS_HI16 __cerror
# NXX: addiu $gp, $gp, 0
# NXX: R_MIPS_GPREL16/R_MIPS_SUB/R_MIPS_LO16 __cerror
# N32: addu $gp, $gp, $25
# N64: daddu $gp, $gp, $25
# ASM: .cpsetup $25, 8, __cerror
t2:
# ANY-LABEL: t2:
.cpsetup $25, $2, __cerror
# O32-NOT: __cerror
# FIXME: Direct object emission for N32 is still under development.
# N32 doesn't allow 3 operations to be specified in the same relocation
# record like N64 does.
# NXX: move $2, $gp
# NXX: lui $gp, %hi(%neg(%gp_rel(__cerror)))
# NXX: addiu $gp, $gp, %lo(%neg(%gp_rel(__cerror)))
# NXX: lui $gp, 0
# NXX: R_MIPS_GPREL16/R_MIPS_SUB/R_MIPS_HI16 __cerror
# NXX: addiu $gp, $gp, 0
# NXX: R_MIPS_GPREL16/R_MIPS_SUB/R_MIPS_LO16 __cerror
# N32: addu $gp, $gp, $25
# N64: daddu $gp, $gp, $25
# ASM: .cpsetup $25, $2, __cerror
t3:
.option pic0
nop
.cpsetup $25, 8, __cerror
nop
# Testing that .cpsetup expands to nothing in this case
# by checking that the next instruction after the first
# nop is also a 'nop'.
# NXX: nop
# NXX-NEXT: nop
# ASM: nop
# ASM: .cpsetup $25, 8, __cerror
# ASM: nop