Index: lib/Target/Mips/Mips64InstrInfo.td
===================================================================
--- lib/Target/Mips/Mips64InstrInfo.td
+++ lib/Target/Mips/Mips64InstrInfo.td
@@ -509,6 +509,9 @@
 // truncate
 def : MipsPat<(trunc (assertsext GPR64:$src)),
               (EXTRACT_SUBREG GPR64:$src, sub_32)>;
+// NOTE: This pattern is mostly fine, except for the case where we truncate to
+// i32 from a value that has been assertzext'd from i32. This edge case is
+// handled before we reach the auto-generated tablegen selection.
 def : MipsPat<(trunc (assertzext GPR64:$src)),
               (EXTRACT_SUBREG GPR64:$src, sub_32)>;
 def : MipsPat<(i32 (trunc GPR64:$src)),
Index: lib/Target/Mips/MipsISelLowering.cpp
===================================================================
--- lib/Target/Mips/MipsISelLowering.cpp
+++ lib/Target/Mips/MipsISelLowering.cpp
@@ -428,6 +428,7 @@
   setTargetDAGCombine(ISD::AND);
   setTargetDAGCombine(ISD::OR);
   setTargetDAGCombine(ISD::ADD);
+  setTargetDAGCombine(ISD::AssertZext);
 
   setMinFunctionAlignment(Subtarget.isGP64bit() ? 3 : 2);
 
@@ -807,6 +808,37 @@
   return DAG.getNode(ISD::ADD, DL, ValTy, Add1, Lo);
 }
 
+static SDValue performAssertZextCombine(SDNode *N, SelectionDAG &DAG,
+                                        TargetLowering::DAGCombinerInfo &DCI,
+                                        const MipsSubtarget &Subtarget) {
+  SDValue N0 = N->getOperand(0);
+  EVT NewVT = cast<VTSDNode>(N->getOperand(1))->getVT();
+
+  if (N0.getOpcode() != ISD::TRUNCATE)
+    return SDValue();
+
+  if (N0.getOperand(0).getOpcode() != ISD::AssertZext)
+    return SDValue();
+
+  // fold (AssertZext (trunc (AssertZext x) -> (trunc (AssertZext x))
+  // if the type of the extension of the innermost AssertZext node is
+  // smaller from that of the outermost node, eg:
+  // (AssertZext (trunc:i32 (AssertZext:i64 x, i8)), i32) ->
+  //                                                (trunc (AssertZext x, i8))
+  SDValue OuterAssertZext = N0.getOperand(0);
+  EVT OuterVT = cast<VTSDNode>(OuterAssertZext->getOperand(1))->getVT();
+
+  if (NewVT.bitsLT(OuterVT)) {
+    SDValue NewAssertZext =
+        DAG.getNode(ISD::AssertZext, SDLoc(N), OuterAssertZext.getValueType(),
+                    OuterAssertZext.getOperand(0), DAG.getValueType(NewVT));
+    return DAG.getNode(ISD::TRUNCATE, SDLoc(N), N->getValueType(0),
+                       NewAssertZext);
+  }
+
+  return SDValue();
+}
+
 SDValue  MipsTargetLowering::PerformDAGCombine(SDNode *N, DAGCombinerInfo &DCI)
   const {
   SelectionDAG &DAG = DCI.DAG;
@@ -828,6 +860,8 @@
     return performORCombine(N, DAG, DCI, Subtarget);
   case ISD::ADD:
     return performADDCombine(N, DAG, DCI, Subtarget);
+  case ISD::AssertZext:
+    return performAssertZextCombine(N, DAG, DCI, Subtarget);
   }
 
   return SDValue();
Index: lib/Target/Mips/MipsSEISelDAGToDAG.cpp
===================================================================
--- lib/Target/Mips/MipsSEISelDAGToDAG.cpp
+++ lib/Target/Mips/MipsSEISelDAGToDAG.cpp
@@ -715,6 +715,24 @@
   switch(Opcode) {
   default: break;
 
+  case ISD::TRUNCATE: {
+    SDValue N0 = Node->getOperand(0);
+
+    // Handle only (i32 (trunc (i64 (assertzext (i64 ..), i32)))) nodes.
+    if ((N0.getOpcode() != ISD::AssertZext) ||
+        (N0.getValueType() != MVT::i64) ||
+        (cast<VTSDNode>(N0->getOperand(1))->getVT() != MVT::i32))
+      break;
+
+    // Sign-extend the subreg, with the lower 32-bits, from the input value.
+    SDValue sub_32 = CurDAG->getTargetConstant(Mips::sub_32, DL, MVT::i32);
+    SDNode *SubReg = CurDAG->getMachineNode(TargetOpcode::EXTRACT_SUBREG, DL,
+                                            MVT::i32, N0.getOperand(0), sub_32);
+    Result = CurDAG->getMachineNode(Mips::SLL, DL, MVT::i32, SDValue(SubReg, 0),
+                                    CurDAG->getTargetConstant(0, DL, MVT::i32));
+    return std::make_pair(true, Result);
+  }
+
   case ISD::SUBE: {
     SDValue InFlag = Node->getOperand(2);
     unsigned Opc = Subtarget->isGP64bit() ? Mips::DSUBu : Mips::SUBu;
Index: test/CodeGen/Mips/assertzext-trunc.ll
===================================================================
--- /dev/null
+++ test/CodeGen/Mips/assertzext-trunc.ll
@@ -0,0 +1,28 @@
+; RUN: llc -march=mips64 -mcpu=mips64r2 < %s | FileCheck %s
+; RUN: llc -march=mips64 -mcpu=mips64r6 < %s | FileCheck %s
+
+define i64 @foo1(i64 zeroext %var) {
+entry:
+  %shr = lshr i64 %var, 32
+  %cmp = icmp eq i64 %shr, 0
+  br i1 %cmp, label %if.end6, label %if.then
+
+  ; CHECK:    dsrl   $[[T0:[0-9]+]], $4, 32
+  ; CHECK:    sll    $[[T1:[0-9]+]], $[[T0]], 0
+  if.then:                                          ; preds = %entry
+  %conv = trunc i64 %shr to i32
+  %cmp2 = icmp slt i32 %conv, 0
+  br i1 %cmp2, label %if.then4, label %if.else
+
+  if.then4:                                         ; preds = %if.then
+  %add = add i64 %var, 16
+  br label %if.end6
+
+  if.else:                                          ; preds = %if.then
+  %add5 = add i64 %var, 32
+  br label %if.end6
+
+  if.end6:                                          ; preds = %entry, %if.then4, %if.else
+  %var.addr.0 = phi i64 [ %add, %if.then4 ], [ %add5, %if.else ], [ %var, %entry ]
+  ret i64 %var.addr.0
+}
Index: test/CodeGen/Mips/divrem.ll
===================================================================
--- test/CodeGen/Mips/divrem.ll
+++ test/CodeGen/Mips/divrem.ll
@@ -81,7 +81,7 @@
   ret i32 %rem
 }
 
-define i32 @udiv1(i32 zeroext %a0, i32 zeroext %a1) nounwind readnone {
+define i32 @udiv1(i32 signext %a0, i32 signext %a1) nounwind readnone {
 entry:
 ; ALL-LABEL: udiv1:
 
@@ -107,7 +107,7 @@
   ret i32 %div
 }
 
-define i32 @urem1(i32 zeroext %a0, i32 zeroext %a1) nounwind readnone {
+define i32 @urem1(i32 signext %a0, i32 signext %a1) nounwind readnone {
 entry:
 ; ALL-LABEL: urem1:
 
@@ -175,7 +175,7 @@
   ret i32 %div
 }
 
-define i32 @udivrem1(i32 zeroext %a0, i32 zeroext %a1, i32* nocapture %r) nounwind {
+define i32 @udivrem1(i32 signext %a0, i32 signext %a1, i32* nocapture %r) nounwind {
 entry:
 ; ALL-LABEL: udivrem1:
 
Index: test/CodeGen/Mips/octeon_popcnt.ll
===================================================================
--- test/CodeGen/Mips/octeon_popcnt.ll
+++ test/CodeGen/Mips/octeon_popcnt.ll
@@ -21,7 +21,7 @@
 ; MIPS64-NOT: pop
 }
 
-define i32 @cnt32(i32 zeroext %x) nounwind readnone {
+define i32 @cnt32(i32 signext %x) nounwind readnone {
   %cnt = tail call i32 @llvm.ctpop.i32(i32 %x)
   ret i32 %cnt
 ; OCTEON-LABEL: cnt32: