Index: lib/Target/Mips/AsmParser/MipsAsmParser.cpp =================================================================== --- lib/Target/Mips/AsmParser/MipsAsmParser.cpp +++ lib/Target/Mips/AsmParser/MipsAsmParser.cpp @@ -2361,58 +2361,8 @@ 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; } Index: lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp =================================================================== --- lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp +++ lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp @@ -149,6 +149,24 @@ << 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 @@ 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); +} Index: lib/Target/Mips/MipsTargetStreamer.h =================================================================== --- lib/Target/Mips/MipsTargetStreamer.h +++ lib/Target/Mips/MipsTargetStreamer.h @@ -50,6 +50,8 @@ // 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 @@ // 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 @@ // 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; } Index: test/MC/Mips/cpsetup.s =================================================================== --- test/MC/Mips/cpsetup.s +++ test/MC/Mips/cpsetup.s @@ -1,36 +1,78 @@ +# 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 + # RUN: llvm-mc -triple mips64-unknown-unknown -mattr=-n64,+o32 %s | \ -# RUN: FileCheck -check-prefix=ANY -check-prefix=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=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: FileCheck -check-prefix=ASM %s -# TODO: !PIC -> no output +# 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