Index: lib/Target/Mips/AsmParser/MipsAsmParser.cpp =================================================================== --- lib/Target/Mips/AsmParser/MipsAsmParser.cpp +++ lib/Target/Mips/AsmParser/MipsAsmParser.cpp @@ -1895,8 +1895,7 @@ STI); // Load the $gp from the stack. - createCpRestoreMemOp(true /*IsLoad*/, CpRestoreOffset /*StackOffset*/, - IDLoc, Out, STI); + TOut.emitGPRestore(CpRestoreOffset, IDLoc, STI); } else Warning(IDLoc, "no .cprestore used in PIC mode"); } @@ -3597,19 +3596,18 @@ const MCSubtargetInfo *STI) { MipsTargetStreamer &TOut = getTargetStreamer(); - // If the offset can not fit into 16 bits, we need to expand. - if (!isInt<16>(StackOffset)) { - 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)); - expandMemInst(MemInst, IDLoc, Out, STI, IsLoad, true /*HasImmOpnd*/); + if (IsLoad) { + TOut.emitLoadWithImmOffset(Mips::LW, Mips::GP, Mips::SP, StackOffset, + Mips::GP, IDLoc, STI); return; } - TOut.emitRRI(IsLoad ? Mips::LW : Mips::SW, Mips::GP, Mips::SP, StackOffset, - IDLoc, STI); + unsigned ATReg = getATReg(IDLoc); + if (!ATReg) + return; + + TOut.emitStoreWithImmOffset(Mips::SW, Mips::GP, Mips::SP, StackOffset, ATReg, + IDLoc, STI); } unsigned MipsAsmParser::checkTargetMatchPredicate(MCInst &Inst) { @@ -5479,14 +5477,11 @@ return false; } - // Store the $gp on the stack. - if (getStreamer().isIntegratedAssemblerRequired()) { - const MCSubtargetInfo &STI = getSTI(); - createCpRestoreMemOp(false /*IsLoad*/, CpRestoreOffset /*StackOffset*/, Loc, - getStreamer(), &STI); - } + unsigned ATReg = getATReg(Loc); + if (!ATReg) + return true; - getTargetStreamer().emitDirectiveCpRestore(CpRestoreOffset); + getTargetStreamer().emitDirectiveCpRestore(CpRestoreOffset, ATReg, Loc, STI); Parser.Lex(); // Consume the EndOfStatement. return false; } Index: lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp =================================================================== --- lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp +++ lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp @@ -88,7 +88,9 @@ void MipsTargetStreamer::emitDirectiveSetDsp() { forbidModuleDirective(); } void MipsTargetStreamer::emitDirectiveSetNoDsp() { forbidModuleDirective(); } void MipsTargetStreamer::emitDirectiveCpLoad(unsigned RegNo) {} -void MipsTargetStreamer::emitDirectiveCpRestore(int Offset) { +void MipsTargetStreamer::emitDirectiveCpRestore(int Offset, unsigned ATReg, + SMLoc IDLoc, + const MCSubtargetInfo *STI) { forbidModuleDirective(); } void MipsTargetStreamer::emitDirectiveCpsetup(unsigned RegNo, int RegOrOffset, @@ -207,12 +209,22 @@ emitRRI(Mips::SLL, Mips::ZERO, Mips::ZERO, 0, IDLoc, STI); } -/// Emit a store instruction with an immediate offset. The immediate is -/// expected to be out-of-range for a simm16 and will be expanded to -/// appropriate instructions. +/// Emit the $gp restore operation for .cprestore. +void MipsTargetStreamer::emitGPRestore(int Offset, SMLoc IDLoc, + const MCSubtargetInfo *STI) { + emitLoadWithImmOffset(Mips::LW, Mips::GP, Mips::SP, Offset, Mips::GP, IDLoc, + STI); +} + +/// Emit a store instruction with an immediate offset. void MipsTargetStreamer::emitStoreWithImmOffset( unsigned Opcode, unsigned SrcReg, unsigned BaseReg, int64_t Offset, unsigned ATReg, SMLoc IDLoc, const MCSubtargetInfo *STI) { + if (isInt<16>(Offset)) { + emitRRI(Opcode, SrcReg, BaseReg, Offset, IDLoc, STI); + return; + } + // sw $8, offset($8) => lui $at, %hi(offset) // add $at, $at, $8 // sw $8, %lo(offset)($at) @@ -250,16 +262,19 @@ emitRRX(Opcode, SrcReg, ATReg, LoOperand, IDLoc, STI); } -/// Emit a load instruction with an immediate offset. The immediate is expected -/// to be out-of-range for a simm16 and will be expanded to appropriate -/// instructions. DstReg and TmpReg are permitted to be the same register iff -/// DstReg is distinct from BaseReg and DstReg is a GPR. It is the callers -/// responsibility to identify such cases and pass the appropriate register in -/// TmpReg. +/// Emit a load instruction with an immediate offset. DstReg and TmpReg are +/// permitted to be the same register iff DstReg is distinct from BaseReg and +/// DstReg is a GPR. It is the callers responsibility to identify such cases +/// and pass the appropriate register in TmpReg. void MipsTargetStreamer::emitLoadWithImmOffset(unsigned Opcode, unsigned DstReg, unsigned BaseReg, int64_t Offset, unsigned TmpReg, SMLoc IDLoc, const MCSubtargetInfo *STI) { + if (isInt<16>(Offset)) { + emitRRI(Opcode, DstReg, BaseReg, Offset, IDLoc, STI); + return; + } + // 1) lw $8, offset($9) => lui $8, %hi(offset) // add $8, $8, $9 // lw $8, %lo(offset)($9) @@ -555,8 +570,10 @@ forbidModuleDirective(); } -void MipsTargetAsmStreamer::emitDirectiveCpRestore(int Offset) { - MipsTargetStreamer::emitDirectiveCpRestore(Offset); +void MipsTargetAsmStreamer::emitDirectiveCpRestore(int Offset, unsigned ATReg, + SMLoc IDLoc, + const MCSubtargetInfo *STI) { + MipsTargetStreamer::emitDirectiveCpRestore(Offset, ATReg, IDLoc, STI); OS << "\t.cprestore\t" << Offset << "\n"; } @@ -975,8 +992,10 @@ forbidModuleDirective(); } -void MipsTargetELFStreamer::emitDirectiveCpRestore(int Offset) { - MipsTargetStreamer::emitDirectiveCpRestore(Offset); +void MipsTargetELFStreamer::emitDirectiveCpRestore(int Offset, unsigned ATReg, + SMLoc IDLoc, + const MCSubtargetInfo *STI) { + MipsTargetStreamer::emitDirectiveCpRestore(Offset, ATReg, IDLoc, STI); // .cprestore offset // When PIC mode is enabled and the O32 ABI is used, this directive expands // to: @@ -988,8 +1007,9 @@ if (!Pic || (getABI().IsN32() || getABI().IsN64())) return; - // FIXME: MipsAsmParser currently emits the instructions that should be - // emitted here. + // Store the $gp on the stack. + emitStoreWithImmOffset(Mips::SW, Mips::GP, Mips::SP, Offset, ATReg, IDLoc, + STI); } void MipsTargetELFStreamer::emitDirectiveCpsetup(unsigned RegNo, Index: lib/Target/Mips/MipsTargetStreamer.h =================================================================== --- lib/Target/Mips/MipsTargetStreamer.h +++ lib/Target/Mips/MipsTargetStreamer.h @@ -78,7 +78,8 @@ // PIC support virtual void emitDirectiveCpLoad(unsigned RegNo); - virtual void emitDirectiveCpRestore(int Offset); + virtual void emitDirectiveCpRestore(int Offset, unsigned ATReg, SMLoc IDLoc, + const MCSubtargetInfo *STI); virtual void emitDirectiveCpsetup(unsigned RegNo, int RegOrOffset, const MCSymbol &Sym, bool IsReg); virtual void emitDirectiveCpreturn(unsigned SaveLocation, @@ -130,6 +131,7 @@ MCOperand &HiOperand, MCOperand &LoOperand, unsigned ATReg, SMLoc IDLoc, const MCSubtargetInfo *STI); + void emitGPRestore(int Offset, SMLoc IDLoc, const MCSubtargetInfo *STI); void forbidModuleDirective() { ModuleDirectiveAllowed = false; } void reallowModuleDirective() { ModuleDirectiveAllowed = true; } @@ -230,7 +232,8 @@ // PIC support void emitDirectiveCpLoad(unsigned RegNo) override; - void emitDirectiveCpRestore(int Offset) override; + void emitDirectiveCpRestore(int Offset, unsigned ATReg, SMLoc IDLoc, + const MCSubtargetInfo *STI) override; void emitDirectiveCpsetup(unsigned RegNo, int RegOrOffset, const MCSymbol &Sym, bool IsReg) override; void emitDirectiveCpreturn(unsigned SaveLocation, @@ -282,7 +285,8 @@ // PIC support void emitDirectiveCpLoad(unsigned RegNo) override; - void emitDirectiveCpRestore(int Offset) override; + void emitDirectiveCpRestore(int Offset, unsigned ATReg, SMLoc IDLoc, + const MCSubtargetInfo *STI) override; void emitDirectiveCpsetup(unsigned RegNo, int RegOrOffset, const MCSymbol &Sym, bool IsReg) override; void emitDirectiveCpreturn(unsigned SaveLocation, Index: test/MC/Mips/double-expand.s =================================================================== --- test/MC/Mips/double-expand.s +++ test/MC/Mips/double-expand.s @@ -2,9 +2,25 @@ # RUN: llvm-mc -triple=mipsel-unknown-linux < %s | \ # RUN: llvm-mc -triple=mipsel-unknown-linux | FileCheck %s -# CHECK: bnez $2, foo -# CHECK: nop -# CHECK-NOT: nop - .text +branch: bnez $2, foo + +# CHECK-LABEL: branch: +# CHECK: bnez $2, foo +# CHECK: nop +# CHECK-NOT: nop + +cprestore: + .option pic2 + .cprestore 16 + jal foo + +# CHECK-LABEL: cprestore: +# CHECK: .cprestore 16 +# CHECK: lw $25, %call16(foo)($gp) +# CHECK: jalr $25 +# CHECK: nop +# CHECK: lw $gp, 16($sp) +# CHECK-NOT: nop +# CHECK-NOT: lw