Index: lib/Target/Mips/AsmParser/MipsAsmParser.cpp
===================================================================
--- lib/Target/Mips/AsmParser/MipsAsmParser.cpp
+++ lib/Target/Mips/AsmParser/MipsAsmParser.cpp
@@ -102,6 +102,8 @@
                        // selected. This usually happens after an '.end func'
                        // directive.
   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,
@@ -177,6 +179,10 @@
   void expandMemInst(MCInst &Inst, SMLoc IDLoc,
                      SmallVectorImpl<MCInst> &Instructions, bool isLoad,
                      bool isImmOpnd);
+
+  void createCpRestoreMemOp(bool IsLoad, int StackOffset, SMLoc IDLoc,
+                            SmallVectorImpl<MCInst> &Instructions);
+
   bool reportParseError(Twine ErrorMsg);
   bool reportParseError(SMLoc Loc, Twine ErrorMsg);
 
@@ -190,6 +196,7 @@
   bool parseSetArchDirective();
   bool parseSetFeature(uint64_t Feature);
   bool parseDirectiveCpLoad(SMLoc Loc);
+  bool parseDirectiveCpRestore(SMLoc Loc);
   bool parseDirectiveCPSetup();
   bool parseDirectiveNaN();
   bool parseDirectiveSet();
@@ -341,6 +348,8 @@
 
     IsPicEnabled =
         (getContext().getObjectFileInfo()->getRelocM() == Reloc::PIC_);
+
+    IsCpRestoreSet = false;
   }
 
   /// True if all of $fcc0 - $fcc7 exist for the current ISA.
@@ -1043,7 +1052,7 @@
 bool MipsAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc,
                                        SmallVectorImpl<MCInst> &Instructions) {
   const MCInstrDesc &MCID = getInstDesc(Inst.getOpcode());
-
+  bool ExpandedJalSym = false;
   Inst.setLoc(IDLoc);
 
   if (MCID.isBranch() || MCID.isCall()) {
@@ -1186,7 +1195,9 @@
     }
 
     MCInst JalrInst;
-    if (inMicroMipsMode())
+    if (IsCpRestoreSet && inMicroMipsMode())
+      JalrInst.setOpcode(Mips::JALRS_MM);
+    else if (inMicroMipsMode())
       JalrInst.setOpcode(Mips::JALR_MM);
     else
       JalrInst.setOpcode(Mips::JALR);
@@ -1201,6 +1212,7 @@
     // we're jumping to.
 
     Inst = JalrInst;
+    ExpandedJalSym = true;
   }
 
   if (MCID.hasDelaySlot() && AssemblerOptions.back()->isReorder()) {
@@ -1219,7 +1231,9 @@
       NopInst.addOperand(MCOperand::CreateImm(0));
     }
     Instructions.push_back(NopInst);
-    return false;
+
+    if (ExpandedJalSym == false)
+      return false;
   }
 
   if (MCID.mayLoad() || MCID.mayStore()) {
@@ -1330,11 +1344,48 @@
     }
   }
 
-  if (needsExpansion(Inst))
-    return expandInstruction(Inst, IDLoc, Instructions);
-  else
+  if (needsExpansion(Inst)) {
+    if (expandInstruction(Inst, IDLoc, Instructions))
+      return true;
+  } else {
     Instructions.push_back(Inst);
+  }
+
+  if ((Inst.getOpcode() == Mips::JalOneReg ||
+       Inst.getOpcode() == Mips::JalTwoReg || ExpandedJalSym) &&
+      inPicMode() && !(isABI_N32() || isABI_N64())) {
+    if (IsCpRestoreSet) {
+      // Emit a NOP after the JALR, even if .set reorder has not been used.
+      if (!AssemblerOptions.back()->isReorder()) {
+        MCInst NopInst;
+        if (hasShortDelaySlot(Inst.getOpcode()) ||
+            ((Inst.getOpcode() == Mips::JalOneReg ||
+              Inst.getOpcode() == Mips::JalTwoReg) &&
+             inMicroMipsMode())) {
+          NopInst.setOpcode(Mips::MOVE16_MM);
+          NopInst.addOperand(MCOperand::CreateReg(Mips::ZERO));
+          NopInst.addOperand(MCOperand::CreateReg(Mips::ZERO));
+        } else {
+          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);
+      }
+
+      // 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;
 }
 
@@ -1418,7 +1469,10 @@
 
   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 {
@@ -1428,7 +1482,9 @@
     }
   } else if (Opcode == Mips::JalTwoReg) {
     // jal $rd, $rs => jalr $rd, $rs
-    if (inMicroMipsMode())
+    if (IsCpRestoreSet && inMicroMipsMode())
+      JalrInst.setOpcode(Mips::JALRS_MM);
+    else if (inMicroMipsMode())
       JalrInst.setOpcode(Mips::JALR_MM);
     else
       JalrInst.setOpcode(Mips::JALR);
@@ -1441,13 +1497,17 @@
 
   // 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));
+    if (hasShortDelaySlot(JalrInst.getOpcode())) {
+      NopInst.setOpcode(Mips::MOVE16_MM);
+      NopInst.addOperand(MCOperand::CreateReg(Mips::ZERO));
+      NopInst.addOperand(MCOperand::CreateReg(Mips::ZERO));
+    } else {
+      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);
   }
 
@@ -1821,6 +1881,26 @@
   TempInst.clear();
 }
 
+void MipsAsmParser::createCpRestoreMemOp(
+    bool IsLoad, int StackOffset, SMLoc IDLoc,
+    SmallVectorImpl<MCInst> &Instructions) {
+  MCInst MemInst;
+  if (IsLoad)
+    MemInst.setOpcode(Mips::LW);
+  else
+    MemInst.setOpcode(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 (StackOffset < -32768 || StackOffset > 32767)
+    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.
@@ -3284,6 +3364,57 @@
   return false;
 }
 
+bool MipsAsmParser::parseDirectiveCpRestore(SMLoc Loc) {
+  MCAsmParser &Parser = getParser();
+
+  if (isABI_N32() || isABI_N64())
+    Warning(Loc, ".cprestore is not supported on the N32 and N64 ABIs");
+
+  if (!inPicMode())
+    Warning(Loc, ".cprestore requires 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;
@@ -3688,6 +3819,8 @@
 
   if (IDVal == ".cpload")
     return parseDirectiveCpLoad(DirectiveID.getLoc());
+  if (IDVal == ".cprestore")
+    return parseDirectiveCpRestore(DirectiveID.getLoc());
   if (IDVal == ".dword") {
     parseDataDirective(8, DirectiveID.getLoc());
     return false;
@@ -3738,6 +3871,7 @@
 
     getTargetStreamer().emitDirectiveEnt(*Sym);
     CurrentFn = Sym;
+    IsCpRestoreSet = false;
     return false;
   }
 
@@ -3766,6 +3900,7 @@
 
     getTargetStreamer().emitDirectiveEnd(SymbolName);
     CurrentFn = nullptr;
+    IsCpRestoreSet = false;
     return false;
   }
 
@@ -3837,6 +3972,7 @@
 
     getTargetStreamer().emitFrame(StackReg, FrameSizeVal,
                                   ReturnRegOpnd.getGPR32Reg());
+    IsCpRestoreSet = false;
     return false;
   }
 
Index: lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp
===================================================================
--- lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp
+++ lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp
@@ -76,6 +76,8 @@
 void MipsTargetStreamer::emitDirectiveSetDsp() { forbidModuleDirective(); }
 void MipsTargetStreamer::emitDirectiveSetNoDsp() { forbidModuleDirective(); }
 void MipsTargetStreamer::emitDirectiveCpLoad(unsigned RegNo) {}
+void MipsTargetStreamer::emitDirectiveCpRestore(
+    SmallVector<MCInst, 3> &StoreInsts, int Offset) {}
 void MipsTargetStreamer::emitDirectiveCpsetup(unsigned RegNo, int RegOrOffset,
                                               const MCSymbol &Sym, bool IsReg) {
 }
@@ -284,6 +286,12 @@
   forbidModuleDirective();
 }
 
+void MipsTargetAsmStreamer::emitDirectiveCpRestore(
+    SmallVector<MCInst, 3> &StoreInsts, int Offset) {
+  OS << "\t.cprestore\t" << Offset << "\n";
+  forbidModuleDirective();
+}
+
 void MipsTargetAsmStreamer::emitDirectiveCpsetup(unsigned RegNo,
                                                  int RegOrOffset,
                                                  const MCSymbol &Sym,
@@ -648,6 +656,23 @@
   forbidModuleDirective();
 }
 
+void MipsTargetELFStreamer::emitDirectiveCpRestore(
+    SmallVector<MCInst, 3> &StoreInsts, int 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.
+
+  if (!Pic || (isN32() || isN64()))
+    return;
+
+  for (const MCInst &Inst : StoreInsts)
+    getStreamer().EmitInstruction(Inst, STI);
+
+  forbidModuleDirective();
+}
+
 void MipsTargetELFStreamer::emitDirectiveCpsetup(unsigned RegNo,
                                                  int RegOrOffset,
                                                  const MCSymbol &Sym,
Index: lib/Target/Mips/MipsTargetStreamer.h
===================================================================
--- lib/Target/Mips/MipsTargetStreamer.h
+++ lib/Target/Mips/MipsTargetStreamer.h
@@ -68,6 +68,8 @@
 
   // 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);
 
@@ -172,6 +174,8 @@
 
   // 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;
 
@@ -218,6 +222,8 @@
 
   // 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;
 
Index: test/MC/Mips/cprestore-bad.s
===================================================================
--- /dev/null
+++ test/MC/Mips/cprestore-bad.s
@@ -0,0 +1,35 @@
+# RUN: not llvm-mc %s -arch=mips -mcpu=mips32 -relocation-model=pic 2>%t1
+# RUN: FileCheck %s < %t1
+
+# RUN: not llvm-mc %s -arch=mips -mcpu=mips32 -relocation-model=static 2>%t1
+# RUN: FileCheck %s < %t1 -check-prefix=NO-PIC
+
+# RUN: not llvm-mc %s -arch=mips -mcpu=mips64 -mattr=-n64,+n32 -relocation-model=pic 2>%t1
+# RUN: FileCheck %s < %t1 -check-prefix=BAD-ABI
+
+# RUN: not llvm-mc %s -arch=mips -mcpu=mips64 -mattr=+n64 -relocation-model=pic 2>%t1
+# RUN: FileCheck %s < %t1 -check-prefix=BAD-ABI
+
+  .text
+  .set noreorder
+  .cpload $25
+  .cprestore 8
+# BAD-ABI: :[[@LINE-1]]:3: warning: .cprestore is not supported on the N32 and N64 ABIs
+# NO-PIC: :[[@LINE-2]]:3: warning: .cprestore requires PIC mode
+
+  .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
Index: test/MC/Mips/cprestore-noreorder.s
===================================================================
--- /dev/null
+++ test/MC/Mips/cprestore-noreorder.s
@@ -0,0 +1,131 @@
+# 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 -mattr=-n64,+n32 -relocation-model=pic -show-encoding | \
+# RUN:  FileCheck %s -check-prefix=BAD-ABI
+
+# RUN: llvm-mc %s -arch=mips64 -mcpu=mips64 -mattr=+n64 -relocation-model=pic -show-encoding | \
+# RUN:  FileCheck %s -check-prefix=BAD-ABI
+
+  .text
+  .weak weak_label
+
+  .ent local_label
+local_label:
+  .frame  $sp, 0, $ra
+  .set noreorder
+
+  .cpload $25
+  .cprestore 8
+
+  jal $25
+  jal $4, $25
+
+  jal local_label
+  jal weak_label
+  jal external_label
+
+  .end local_label
+
+# 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(.text)($gp)             # encoding: [0x8f,0x99,A,A]
+# CHECK:       #   fixup A - offset: 0, value: .text@GOT, kind: fixup_Mips_GOT_Local
+# CHECK: addiu $25, $25, %lo(.text)              # encoding: [0x27,0x39,A,A]
+# CHECK:       #   fixup A - offset: 0, value: .text@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: lw    $25, %call16(weak_label)($gp)     # encoding: [0x8f,0x99,A,A]
+# CHECK:       #   fixup A - offset: 0, value: weak_label@GOT_CALL, kind: fixup_Mips_CALL16
+# 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: lw    $25, %call16(external_label)($gp) # encoding: [0x8f,0x99,A,A]
+# CHECK:       #   fixup A - offset: 0, value: external_label@GOT_CALL, kind: fixup_Mips_CALL16
+# 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  local_label
+
+# MICROMIPS: .cprestore  8
+# MICROMIPS: jalrs16 $25                                 # encoding: [0x45,0xf9]
+# MICROMIPS: move    $zero, $zero                        # encoding: [0x0c,0x00]
+# MICROMIPS: lw      $gp,   8($sp)                       # encoding: [0xff,0x9d,0x00,0x08]
+
+# MICROMIPS: jalrs   $4,    $25                          # encoding: [0x00,0x99,0x4f,0x3c]
+# MICROMIPS: move    $zero, $zero                        # encoding: [0x0c,0x00]
+# MICROMIPS: lw      $gp,   8($sp)                       # encoding: [0xff,0x9d,0x00,0x08]
+
+# MICROMIPS: lw      $25,   %got(local_label)($gp)       # encoding: [0xff,0x3c,A,A]
+# MICROMIPS:         #   fixup A - offset: 0, value: local_label@GOT, kind: fixup_MICROMIPS_GOT16
+# MICROMIPS: addiu   $25,   $25,   %lo(local_label)      # encoding: [0x33,0x39,A,A]
+# MICROMIPS:         #   fixup A - offset: 0, value: local_label@ABS_LO, kind: fixup_MICROMIPS_LO16
+# MICROMIPS: jalrs   $ra,   $25                          # encoding: [0x03,0xf9,0x4f,0x3c]
+# MICROMIPS: move    $zero, $zero                        # encoding: [0x0c,0x00]
+# MICROMIPS: lw      $gp,   8($sp)                       # encoding: [0xff,0x9d,0x00,0x08]
+
+# MICROMIPS: lw      $25,   %call16(weak_label)($gp)     # encoding: [0xff,0x3c,A,A]
+# MICROMIPS:         #   fixup A - offset: 0, value: weak_label@GOT_CALL, kind: fixup_MICROMIPS_CALL16
+# MICROMIPS: jalrs   $ra,   $25                          # encoding: [0x03,0xf9,0x4f,0x3c]
+# MICROMIPS: move    $zero, $zero                        # encoding: [0x0c,0x00]
+# MICROMIPS: lw      $gp,   8($sp)                       # encoding: [0xff,0x9d,0x00,0x08]
+
+# MICROMIPS: lw      $25,   %call16(external_label)($gp) # encoding: [0xff,0x3c,A,A]
+# MICROMIPS:         #   fixup A - offset: 0, value: external_label@GOT_CALL, kind: fixup_MICROMIPS_CALL16
+# MICROMIPS: jalrs   $ra,   $25                          # encoding: [0x03,0xf9,0x4f,0x3c]
+# MICROMIPS: move    $zero, $zero                        # encoding: [0x0c,0x00]
+# MICROMIPS: lw      $gp,   8($sp)                       # encoding: [0xff,0x9d,0x00,0x08]
+# MICROMIPS: .end  local_label
+
+# NO-PIC: .cprestore  8
+# NO-PIC: jalr  $25             # encoding: [0x03,0x20,0xf8,0x09]
+# NO-PIC: jalr  $4, $25         # encoding: [0x03,0x20,0x20,0x09]
+
+# NO-PIC: jal   local_label     # encoding: [0b000011AA,A,A,A]
+# NO-PIC:       #   fixup A - offset: 0, value: local_label, kind: fixup_Mips_26
+
+# NO-PIC: jal   weak_label      # encoding: [0b000011AA,A,A,A]
+# NO-PIC:       #   fixup A - offset: 0, value: weak_label, kind: fixup_Mips_26
+
+# NO-PIC: jal   external_label  # encoding: [0b000011AA,A,A,A]
+# NO-PIC:       #   fixup A - offset: 0, value: external_label, kind: fixup_Mips_26
+# NO-PIC: .end  local_label
+
+# BAD-ABI: .cprestore  8
+# BAD-ABI: jalr   $25                               # encoding: [0x03,0x20,0xf8,0x09]
+# BAD-ABI: jalr   $4, $25                           # encoding: [0x03,0x20,0x20,0x09]
+
+# BAD-ABI:  lw    $25, %got_disp(.text)($gp)        # encoding: [0x8f,0x99,A,A]
+# BAD-ABI:        #   fixup A - offset: 0, value: .text@GOT_DISP, kind: fixup_Mips_GOT_DISP
+# BAD-ABI:  jalr  $25                               # encoding: [0x03,0x20,0xf8,0x09]
+
+# BAD-ABI:  lw    $25, %call16(weak_label)($gp)     # encoding: [0x8f,0x99,A,A]
+# BAD-ABI:        #   fixup A - offset: 0, value: weak_label@GOT_CALL, kind: fixup_Mips_CALL16
+# BAD-ABI:  jalr  $25                               # encoding: [0x03,0x20,0xf8,0x09]
+
+# BAD-ABI:  lw    $25, %call16(external_label)($gp) # encoding: [0x8f,0x99,A,A]
+# BAD-ABI:        #   fixup A - offset: 0, value: external_label@GOT_CALL, kind: fixup_Mips_CALL16
+# BAD-ABI:  jalr  $25                               # encoding: [0x03,0x20,0xf8,0x09]
+# BAD-ABI:  .end  local_label
Index: test/MC/Mips/cprestore-reorder.s
===================================================================
--- /dev/null
+++ test/MC/Mips/cprestore-reorder.s
@@ -0,0 +1,132 @@
+# 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 -mattr=-n64,+n32 -relocation-model=pic -show-encoding | \
+# RUN:  FileCheck %s -check-prefix=BAD-ABI
+
+# RUN: llvm-mc %s -arch=mips64 -mcpu=mips64 -mattr=+n64 -relocation-model=pic -show-encoding | \
+# RUN:  FileCheck %s -check-prefix=BAD-ABI
+
+  .text
+  .weak weak_label
+
+  .ent local_label
+local_label:
+  .frame  $sp, 0, $ra
+  .set noreorder
+  .cpload $25
+  .set reorder
+
+  .cprestore 8
+
+  jal $25
+  jal $4, $25
+
+  jal local_label
+  jal weak_label
+  jal external_label
+
+  .end local_label
+
+# 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(.text)($gp)             # encoding: [0x8f,0x99,A,A]
+# CHECK:       #   fixup A - offset: 0, value: .text@GOT, kind: fixup_Mips_GOT_Local
+# CHECK: addiu $25, $25, %lo(.text)              # encoding: [0x27,0x39,A,A]
+# CHECK:       #   fixup A - offset: 0, value: .text@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: lw    $25, %call16(weak_label)($gp)     # encoding: [0x8f,0x99,A,A]
+# CHECK:       #   fixup A - offset: 0, value: weak_label@GOT_CALL, kind: fixup_Mips_CALL16
+# 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: lw    $25, %call16(external_label)($gp) # encoding: [0x8f,0x99,A,A]
+# CHECK:       #   fixup A - offset: 0, value: external_label@GOT_CALL, kind: fixup_Mips_CALL16
+# 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  local_label
+
+# MICROMIPS: .cprestore  8
+# MICROMIPS: jalrs16 $25                                 # encoding: [0x45,0xf9]
+# MICROMIPS: move    $zero, $zero                        # encoding: [0x0c,0x00]
+# MICROMIPS: lw      $gp,   8($sp)                       # encoding: [0xff,0x9d,0x00,0x08]
+
+# MICROMIPS: jalrs   $4,    $25                          # encoding: [0x00,0x99,0x4f,0x3c]
+# MICROMIPS: move    $zero, $zero                        # encoding: [0x0c,0x00]
+# MICROMIPS: lw      $gp,   8($sp)                       # encoding: [0xff,0x9d,0x00,0x08]
+
+# MICROMIPS: lw      $25,   %got(local_label)($gp)       # encoding: [0xff,0x3c,A,A]
+# MICROMIPS:         #   fixup A - offset: 0, value: local_label@GOT, kind: fixup_MICROMIPS_GOT16
+# MICROMIPS: addiu   $25,   $25,   %lo(local_label)      # encoding: [0x33,0x39,A,A]
+# MICROMIPS:         #   fixup A - offset: 0, value: local_label@ABS_LO, kind: fixup_MICROMIPS_LO16
+# MICROMIPS: jalrs   $ra,   $25                          # encoding: [0x03,0xf9,0x4f,0x3c]
+# MICROMIPS: move    $zero, $zero                        # encoding: [0x0c,0x00]
+# MICROMIPS: lw      $gp,   8($sp)                       # encoding: [0xff,0x9d,0x00,0x08]
+
+# MICROMIPS: lw      $25,   %call16(weak_label)($gp)     # encoding: [0xff,0x3c,A,A]
+# MICROMIPS:         #   fixup A - offset: 0, value: weak_label@GOT_CALL, kind: fixup_MICROMIPS_CALL16
+# MICROMIPS: jalrs   $ra,   $25                          # encoding: [0x03,0xf9,0x4f,0x3c]
+# MICROMIPS: move    $zero, $zero                        # encoding: [0x0c,0x00]
+# MICROMIPS: lw      $gp,   8($sp)                       # encoding: [0xff,0x9d,0x00,0x08]
+
+# MICROMIPS: lw      $25,   %call16(external_label)($gp) # encoding: [0xff,0x3c,A,A]
+# MICROMIPS:         #   fixup A - offset: 0, value: external_label@GOT_CALL, kind: fixup_MICROMIPS_CALL16
+# MICROMIPS: jalrs   $ra,   $25                          # encoding: [0x03,0xf9,0x4f,0x3c]
+# MICROMIPS: move    $zero, $zero                        # encoding: [0x0c,0x00]
+# MICROMIPS: lw      $gp,   8($sp)                       # encoding: [0xff,0x9d,0x00,0x08]
+# MICROMIPS: .end  local_label
+
+# NO-PIC: .cprestore  8
+# NO-PIC: jalr  $25             # encoding: [0x03,0x20,0xf8,0x09]
+# NO-PIC: jalr  $4, $25         # encoding: [0x03,0x20,0x20,0x09]
+
+# NO-PIC: jal   local_label     # encoding: [0b000011AA,A,A,A]
+# NO-PIC:       #   fixup A - offset: 0, value: local_label, kind: fixup_Mips_26
+
+# NO-PIC: jal   weak_label      # encoding: [0b000011AA,A,A,A]
+# NO-PIC:       #   fixup A - offset: 0, value: weak_label, kind: fixup_Mips_26
+
+# NO-PIC: jal   external_label  # encoding: [0b000011AA,A,A,A]
+# NO-PIC:       #   fixup A - offset: 0, value: external_label, kind: fixup_Mips_26
+# NO-PIC: .end  local_label
+
+# BAD-ABI: .cprestore  8
+# BAD-ABI: jalr   $25                               # encoding: [0x03,0x20,0xf8,0x09]
+# BAD-ABI: jalr   $4, $25                           # encoding: [0x03,0x20,0x20,0x09]
+
+# BAD-ABI:  lw    $25, %got_disp(.text)($gp)        # encoding: [0x8f,0x99,A,A]
+# BAD-ABI:        #   fixup A - offset: 0, value: .text@GOT_DISP, kind: fixup_Mips_GOT_DISP
+# BAD-ABI:  jalr  $25                               # encoding: [0x03,0x20,0xf8,0x09]
+
+# BAD-ABI:  lw    $25, %call16(weak_label)($gp)     # encoding: [0x8f,0x99,A,A]
+# BAD-ABI:        #   fixup A - offset: 0, value: weak_label@GOT_CALL, kind: fixup_Mips_CALL16
+# BAD-ABI:  jalr  $25                               # encoding: [0x03,0x20,0xf8,0x09]
+
+# BAD-ABI:  lw    $25, %call16(external_label)($gp) # encoding: [0x8f,0x99,A,A]
+# BAD-ABI:        #   fixup A - offset: 0, value: external_label@GOT_CALL, kind: fixup_Mips_CALL16
+# BAD-ABI:  jalr  $25                               # encoding: [0x03,0x20,0xf8,0x09]
+# BAD-ABI:  .end  local_label
Index: test/MC/Mips/cprestore-warning-unused.s
===================================================================
--- /dev/null
+++ test/MC/Mips/cprestore-warning-unused.s
@@ -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