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(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(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(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: