+ FPRInfoSet = true;
+ FPRBitMask = FPUBitmask;
+ FPROffset = FPUTopSavedRegOff;
+}
+
+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 || (getABI().IsN32() || getABI().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.registerSymbol(*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);
+
+ 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,
+ bool IsReg) {
+ // Only N32 and N64 emit anything for .cpsetup iff PIC is set.
+ if (!Pic || !(getABI().IsN32() || getABI().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::OR64);
+ 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, MCSymbolRefExpr::VK_Mips_GPOFF_HI, MCA.getContext());
+ const MCSymbolRefExpr *LoExpr = MCSymbolRefExpr::create(
+ &Sym, 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);
+
+ forbidModuleDirective();
+}
+
+void MipsTargetELFStreamer::emitDirectiveCpreturn(unsigned SaveLocation,
+ bool SaveLocationIsRegister) {
+ // Only N32 and N64 emit anything for .cpreturn iff PIC is set.
+ if (!Pic || !(getABI().IsN32() || getABI().IsN64()))
+ return;
+
+ MCInst Inst;
+ // Either restore the old $gp from a register or on the stack
+ if (SaveLocationIsRegister) {
+ Inst.setOpcode(Mips::OR);
+ Inst.addOperand(MCOperand::createReg(Mips::GP));
+ Inst.addOperand(MCOperand::createReg(SaveLocation));
+ Inst.addOperand(MCOperand::createReg(Mips::ZERO));
+ } else {
+ Inst.setOpcode(Mips::LD);
+ Inst.addOperand(MCOperand::createReg(Mips::GP));
+ Inst.addOperand(MCOperand::createReg(Mips::SP));
+ Inst.addOperand(MCOperand::createImm(SaveLocation));
+ }
+ getStreamer().EmitInstruction(Inst, STI);
+
+ forbidModuleDirective();
+}
+
+void MipsTargetELFStreamer::emitMipsAbiFlags() {
+ MCAssembler &MCA = getStreamer().getAssembler();
+ MCContext &Context = MCA.getContext();
+ MCStreamer &OS = getStreamer();
+ MCSectionELF *Sec = Context.getELFSection(
+ ".MIPS.abiflags", ELF::SHT_MIPS_ABIFLAGS, ELF::SHF_ALLOC, 24, "");
+ MCA.registerSection(*Sec);
+ Sec->setAlignment(8);
+ OS.SwitchSection(Sec);
+
+ OS << ABIFlagsSection;