Index: lib/Target/Mips/Mips64InstrInfo.td =================================================================== --- lib/Target/Mips/Mips64InstrInfo.td +++ lib/Target/Mips/Mips64InstrInfo.td @@ -494,10 +494,15 @@ defm : SetgeImmPats; // truncate +// Truncation from i64 to i32 with no zero/sign extension. +def Mips64TruncNoExt : SDNode<"MipsISD::TruncNoExt", SDTIntTruncOp>; + def : MipsPat<(trunc (assertsext GPR64:$src)), (EXTRACT_SUBREG GPR64:$src, sub_32)>; -def : MipsPat<(trunc (assertzext GPR64:$src)), +def : MipsPat<(Mips64TruncNoExt GPR64:$src), (EXTRACT_SUBREG GPR64:$src, sub_32)>; +def : MipsPat<(trunc (assertzext GPR64:$src)), + (SLL (EXTRACT_SUBREG GPR64:$src, sub_32), 0)>; def : MipsPat<(i32 (trunc GPR64:$src)), (SLL (EXTRACT_SUBREG GPR64:$src, sub_32), 0)>; Index: lib/Target/Mips/MipsISelLowering.h =================================================================== --- lib/Target/Mips/MipsISelLowering.h +++ lib/Target/Mips/MipsISelLowering.h @@ -64,6 +64,10 @@ // FP-to-int truncation node. TruncIntFP, + // Node used to truncate from i64 to i32 with no zero/sign extension. + // This is only used for N32/N64 ABI. + TruncNoExt, + // Return Ret, Index: lib/Target/Mips/MipsISelLowering.cpp =================================================================== --- lib/Target/Mips/MipsISelLowering.cpp +++ lib/Target/Mips/MipsISelLowering.cpp @@ -110,6 +110,7 @@ const char *MipsTargetLowering::getTargetNodeName(unsigned Opcode) const { switch ((MipsISD::NodeType)Opcode) { case MipsISD::FIRST_NUMBER: break; + case MipsISD::TruncNoExt: return "MipsISD::TruncNoExt"; case MipsISD::JmpLink: return "MipsISD::JmpLink"; case MipsISD::TailCall: return "MipsISD::TailCall"; case MipsISD::Hi: return "MipsISD::Hi"; @@ -2879,7 +2880,8 @@ } static SDValue UnpackFromArgumentSlot(SDValue Val, const CCValAssign &VA, - EVT ArgVT, SDLoc DL, SelectionDAG &DAG) { + EVT ArgVT, SDLoc DL, SelectionDAG &DAG, + const MipsABIInfo &ABI) { MVT LocVT = VA.getLocVT(); EVT ValVT = VA.getValVT(); @@ -2904,7 +2906,8 @@ // If this is an value smaller than the argument slot size (32-bit for O32, // 64-bit for N32/N64), it has been promoted in some way to the argument slot // size. Extract the value and insert any appropriate assertions regarding - // sign/zero extension. + // sign/zero extension. In N32/N64 ABI unsigned 32-bit integers are + // represented in a 64-bit register as sign-extended value. switch (VA.getLocInfo()) { default: llvm_unreachable("Unknown loc info!"); @@ -2921,8 +2924,13 @@ break; case CCValAssign::ZExtUpper: case CCValAssign::ZExt: - Val = DAG.getNode(ISD::AssertZext, DL, LocVT, Val, DAG.getValueType(ValVT)); - Val = DAG.getNode(ISD::TRUNCATE, DL, ValVT, Val); + // We don't need to sign extend values smaller than 32bit. + if (ABI.AreGprs64bit() && ArgVT.getSimpleVT() < MVT::i32) + Val = DAG.getNode(MipsISD::TruncNoExt, DL, ValVT, Val); + else { + Val = DAG.getNode(ISD::AssertZext, DL, LocVT, Val, DAG.getValueType(ValVT)); + Val = DAG.getNode(ISD::TRUNCATE, DL, ValVT, Val); + } break; case CCValAssign::BCvt: Val = DAG.getNode(ISD::BITCAST, DL, ValVT, Val); @@ -3009,7 +3017,7 @@ unsigned Reg = addLiveIn(DAG.getMachineFunction(), ArgReg, RC); SDValue ArgValue = DAG.getCopyFromReg(Chain, DL, Reg, RegVT); - ArgValue = UnpackFromArgumentSlot(ArgValue, VA, Ins[i].ArgVT, DL, DAG); + ArgValue = UnpackFromArgumentSlot(ArgValue, VA, Ins[i].ArgVT, DL, DAG, ABI); // Handle floating point arguments passed in integer registers and // long double arguments passed in floating point registers. @@ -3056,7 +3064,7 @@ false, false, false, 0); OutChains.push_back(ArgValue.getValue(1)); - ArgValue = UnpackFromArgumentSlot(ArgValue, VA, Ins[i].ArgVT, DL, DAG); + ArgValue = UnpackFromArgumentSlot(ArgValue, VA, Ins[i].ArgVT, DL, DAG, ABI); InVals.push_back(ArgValue); } 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/mips64-sign-extend.ll =================================================================== --- /dev/null +++ test/CodeGen/Mips/mips64-sign-extend.ll @@ -0,0 +1,48 @@ +; RUN: llc < %s -march=mips64el -mcpu=mips64r2 -target-abi=n64 | FileCheck %s +; RUN: llc < %s -march=mips64el -mcpu=mips64r2 -target-abi=n32 | FileCheck %s + +define i64 @foo1(i64 zeroext %var) { +entry: +; CHECK: sll ${{[0-9]+}}, ${{[0-9]+}}, 0 + %shr = lshr i64 %var, 32 + %cmp = icmp eq i64 %shr, 0 + br i1 %cmp, label %if.end6, label %if.then + +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 +} + +define i32 @foo2(i32 zeroext %var) #0 { +entry: +; CHECK: sll ${{[0-9]+}}, ${{[0-9]+}}, 0 + %add = add i32 %var, 5 + ret i32 %add +} + +define i16 @foo3(i16 zeroext %var) #0 { +entry: +; CHECK-NOT: sll ${{[0-9]+}}, ${{[0-9]+}}, 0 + %add = add i16 %var, 5 + ret i16 %add +} + +define i8 @foo4(i8 zeroext %var) #0 { +entry: +; CHECK-NOT: sll ${{[0-9]+}}, ${{[0-9]+}}, 0 + %add = add i8 %var, 5 + ret i8 %add +} 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: