Index: lib/CodeGen/GlobalISel/LegalizerHelper.cpp =================================================================== --- lib/CodeGen/GlobalISel/LegalizerHelper.cpp +++ lib/CodeGen/GlobalISel/LegalizerHelper.cpp @@ -535,6 +535,7 @@ return Legalized; } case TargetOpcode::G_MUL: + case TargetOpcode::G_UMULH: return narrowScalarMul(MI, NarrowTy); case TargetOpcode::G_EXTRACT: return narrowScalarExtract(MI, TypeIdx, NarrowTy); @@ -2636,14 +2637,20 @@ unsigned NumDstParts = DstSize / NarrowSize; unsigned NumSrcParts = SrcSize / NarrowSize; + bool IsMulHigh = MI.getOpcode() == TargetOpcode::G_UMULH; + unsigned DstTmpParts = NumDstParts * (IsMulHigh ? 2 : 1); - SmallVector Src1Parts, Src2Parts, DstRegs; + SmallVector Src1Parts, Src2Parts, DstTmpRegs; extractParts(Src1, NarrowTy, NumSrcParts, Src1Parts); extractParts(Src2, NarrowTy, NumSrcParts, Src2Parts); - DstRegs.resize(NumDstParts); - MultiplyRegisters(DstRegs, Src1Parts, Src2Parts, NarrowTy); + DstTmpRegs.resize(DstTmpParts); + MultiplyRegisters(DstTmpRegs, Src1Parts, Src2Parts, NarrowTy); + // Take only high half of registers if this is high mul. + ArrayRef DstRegs( + IsMulHigh ? &DstTmpRegs[DstTmpParts / 2] : &DstTmpRegs[0], NumDstParts); MIRBuilder.buildMerge(DstReg, DstRegs); + MI.eraseFromParent(); return Legalized; } Index: lib/Target/Mips/MipsLegalizerInfo.cpp =================================================================== --- lib/Target/Mips/MipsLegalizerInfo.cpp +++ lib/Target/Mips/MipsLegalizerInfo.cpp @@ -32,7 +32,8 @@ .lowerFor({{s32, s1}}); getActionDefinitionsBuilder(G_UMULH) - .legalFor({s32}); + .legalFor({s32}) + .maxScalar(0, s32); getActionDefinitionsBuilder({G_LOAD, G_STORE}) .legalForTypesWithMemDesc({{s32, p0, 8, 8}, Index: test/CodeGen/Mips/GlobalISel/legalizer/mul.mir =================================================================== --- test/CodeGen/Mips/GlobalISel/legalizer/mul.mir +++ test/CodeGen/Mips/GlobalISel/legalizer/mul.mir @@ -11,6 +11,7 @@ define void @mul_i16_aext() {entry: ret void} define void @mul_i64() {entry: ret void} define void @mul_i128() {entry: ret void} + define void @umulh_i64() {entry: ret void} define void @umul_with_overflow(i32 %lhs, i32 %rhs, i32* %pmul, i1* %pcarry_flag) { ret void } ... @@ -367,6 +368,72 @@ $a1 = COPY %18(s32) RetRA implicit $v0, implicit $v1, implicit $a0, implicit $a1 +... +--- +name: umulh_i64 +alignment: 2 +tracksRegLiveness: true +body: | + bb.1.entry: + liveins: $a0, $a1, $a2, $a3 + + ; MIPS32-LABEL: name: umulh_i64 + ; MIPS32: liveins: $a0, $a1, $a2, $a3 + ; MIPS32: [[COPY:%[0-9]+]]:_(s32) = COPY $a0 + ; MIPS32: [[COPY1:%[0-9]+]]:_(s32) = COPY $a1 + ; MIPS32: [[COPY2:%[0-9]+]]:_(s32) = COPY $a2 + ; MIPS32: [[COPY3:%[0-9]+]]:_(s32) = COPY $a3 + ; MIPS32: [[MUL:%[0-9]+]]:_(s32) = G_MUL [[COPY3]], [[COPY]] + ; MIPS32: [[MUL1:%[0-9]+]]:_(s32) = G_MUL [[COPY2]], [[COPY1]] + ; MIPS32: [[UMULH:%[0-9]+]]:_(s32) = G_UMULH [[COPY2]], [[COPY]] + ; MIPS32: [[ADD:%[0-9]+]]:_(s32) = G_ADD [[MUL]], [[MUL1]] + ; MIPS32: [[ICMP:%[0-9]+]]:_(s32) = G_ICMP intpred(ult), [[ADD]](s32), [[MUL1]] + ; MIPS32: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 1 + ; MIPS32: [[COPY4:%[0-9]+]]:_(s32) = COPY [[ICMP]](s32) + ; MIPS32: [[AND:%[0-9]+]]:_(s32) = G_AND [[COPY4]], [[C]] + ; MIPS32: [[ADD1:%[0-9]+]]:_(s32) = G_ADD [[ADD]], [[UMULH]] + ; MIPS32: [[ICMP1:%[0-9]+]]:_(s32) = G_ICMP intpred(ult), [[ADD1]](s32), [[UMULH]] + ; MIPS32: [[C1:%[0-9]+]]:_(s32) = G_CONSTANT i32 1 + ; MIPS32: [[COPY5:%[0-9]+]]:_(s32) = COPY [[ICMP1]](s32) + ; MIPS32: [[AND1:%[0-9]+]]:_(s32) = G_AND [[COPY5]], [[C1]] + ; MIPS32: [[ADD2:%[0-9]+]]:_(s32) = G_ADD [[AND]], [[AND1]] + ; MIPS32: [[MUL2:%[0-9]+]]:_(s32) = G_MUL [[COPY3]], [[COPY1]] + ; MIPS32: [[UMULH1:%[0-9]+]]:_(s32) = G_UMULH [[COPY3]], [[COPY]] + ; MIPS32: [[UMULH2:%[0-9]+]]:_(s32) = G_UMULH [[COPY2]], [[COPY1]] + ; MIPS32: [[ADD3:%[0-9]+]]:_(s32) = G_ADD [[MUL2]], [[UMULH1]] + ; MIPS32: [[ICMP2:%[0-9]+]]:_(s32) = G_ICMP intpred(ult), [[ADD3]](s32), [[UMULH1]] + ; MIPS32: [[C2:%[0-9]+]]:_(s32) = G_CONSTANT i32 1 + ; MIPS32: [[COPY6:%[0-9]+]]:_(s32) = COPY [[ICMP2]](s32) + ; MIPS32: [[AND2:%[0-9]+]]:_(s32) = G_AND [[COPY6]], [[C2]] + ; MIPS32: [[ADD4:%[0-9]+]]:_(s32) = G_ADD [[ADD3]], [[UMULH2]] + ; MIPS32: [[ICMP3:%[0-9]+]]:_(s32) = G_ICMP intpred(ult), [[ADD4]](s32), [[UMULH2]] + ; MIPS32: [[C3:%[0-9]+]]:_(s32) = G_CONSTANT i32 1 + ; MIPS32: [[COPY7:%[0-9]+]]:_(s32) = COPY [[ICMP3]](s32) + ; MIPS32: [[AND3:%[0-9]+]]:_(s32) = G_AND [[COPY7]], [[C3]] + ; MIPS32: [[ADD5:%[0-9]+]]:_(s32) = G_ADD [[AND2]], [[AND3]] + ; MIPS32: [[ADD6:%[0-9]+]]:_(s32) = G_ADD [[ADD4]], [[ADD2]] + ; MIPS32: [[ICMP4:%[0-9]+]]:_(s32) = G_ICMP intpred(ult), [[ADD6]](s32), [[ADD2]] + ; MIPS32: [[C4:%[0-9]+]]:_(s32) = G_CONSTANT i32 1 + ; MIPS32: [[COPY8:%[0-9]+]]:_(s32) = COPY [[ICMP4]](s32) + ; MIPS32: [[AND4:%[0-9]+]]:_(s32) = G_AND [[COPY8]], [[C4]] + ; MIPS32: [[ADD7:%[0-9]+]]:_(s32) = G_ADD [[ADD5]], [[AND4]] + ; MIPS32: [[UMULH3:%[0-9]+]]:_(s32) = G_UMULH [[COPY3]], [[COPY1]] + ; MIPS32: [[ADD8:%[0-9]+]]:_(s32) = G_ADD [[UMULH3]], [[ADD7]] + ; MIPS32: $v0 = COPY [[ADD6]](s32) + ; MIPS32: $v1 = COPY [[ADD8]](s32) + ; MIPS32: RetRA implicit $v0, implicit $v1 + %2:_(s32) = COPY $a0 + %3:_(s32) = COPY $a1 + %0:_(s64) = G_MERGE_VALUES %2(s32), %3(s32) + %4:_(s32) = COPY $a2 + %5:_(s32) = COPY $a3 + %1:_(s64) = G_MERGE_VALUES %4(s32), %5(s32) + %6:_(s64) = G_UMULH %1, %0 + %7:_(s32), %8:_(s32) = G_UNMERGE_VALUES %6(s64) + $v0 = COPY %7(s32) + $v1 = COPY %8(s32) + RetRA implicit $v0, implicit $v1 + ... --- name: umul_with_overflow