diff --git a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp --- a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp +++ b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp @@ -3439,15 +3439,22 @@ const LLT CondTy = MRI.getType(CarryOut); const LLT Ty = MRI.getType(Res); + // Initial add of the two operands. auto TmpRes = MIRBuilder.buildAdd(Ty, LHS, RHS); + + // Initial check for carry. + auto Carry = MIRBuilder.buildICmp(CmpInst::ICMP_ULT, CondTy, TmpRes, LHS); + + // Add the sum and the carry. auto ZExtCarryIn = MIRBuilder.buildZExt(Ty, CarryIn); MIRBuilder.buildAdd(Res, TmpRes, ZExtCarryIn); - auto Res_EQ_LHS = MIRBuilder.buildICmp(CmpInst::ICMP_EQ, CondTy, Res, LHS); - auto Res_ULT_LHS = - MIRBuilder.buildICmp(CmpInst::ICMP_ULT, CondTy, Res, LHS); - auto And = MIRBuilder.buildAnd(CondTy, Res_EQ_LHS, CarryIn); - MIRBuilder.buildOr(CarryOut, And, Res_ULT_LHS); + // Second check for carry. We can only carry if the initial sum is all 1s + // and the carry is set, resulting in a new sum of 0. + auto Zero = MIRBuilder.buildConstant(Ty, 0); + auto ResEqZero = MIRBuilder.buildICmp(CmpInst::ICMP_EQ, CondTy, Res, Zero); + auto Carry2 = MIRBuilder.buildAnd(CondTy, ResEqZero, CarryIn); + MIRBuilder.buildOr(CarryOut, Carry, Carry2); MI.eraseFromParent(); return Legalized; @@ -3466,13 +3473,23 @@ const LLT CondTy = MRI.getType(BorrowOut); const LLT Ty = MRI.getType(Res); + // Initial subtract of the two operands. auto TmpRes = MIRBuilder.buildSub(Ty, LHS, RHS); + + // Initial check for borrow. + auto Borrow = MIRBuilder.buildICmp(CmpInst::ICMP_UGT, CondTy, TmpRes, LHS); + + // Subtract the borrow from the first subtract. auto ZExtBorrowIn = MIRBuilder.buildZExt(Ty, BorrowIn); MIRBuilder.buildSub(Res, TmpRes, ZExtBorrowIn); - auto LHS_EQ_RHS = MIRBuilder.buildICmp(CmpInst::ICMP_EQ, CondTy, LHS, RHS); - auto LHS_ULT_RHS = MIRBuilder.buildICmp(CmpInst::ICMP_ULT, CondTy, LHS, RHS); - MIRBuilder.buildSelect(BorrowOut, LHS_EQ_RHS, BorrowIn, LHS_ULT_RHS); + // Second check for borrow. We can only borrow if the initial difference is + // 0 and the borrow is set, resulting in a new difference of all 1s. + auto Zero = MIRBuilder.buildConstant(Ty, 0); + auto TmpResEqZero = + MIRBuilder.buildICmp(CmpInst::ICMP_EQ, CondTy, TmpRes, Zero); + auto Borrow2 = MIRBuilder.buildAnd(CondTy, TmpResEqZero, BorrowIn); + MIRBuilder.buildOr(BorrowOut, Borrow, Borrow2); MI.eraseFromParent(); return Legalized; diff --git a/llvm/test/CodeGen/Mips/GlobalISel/legalizer/add.mir b/llvm/test/CodeGen/Mips/GlobalISel/legalizer/add.mir --- a/llvm/test/CodeGen/Mips/GlobalISel/legalizer/add.mir +++ b/llvm/test/CodeGen/Mips/GlobalISel/legalizer/add.mir @@ -262,20 +262,21 @@ ; MIPS32: [[ADD:%[0-9]+]]:_(s32) = G_ADD [[LOAD]], [[COPY]] ; MIPS32: [[ICMP:%[0-9]+]]:_(s32) = G_ICMP intpred(ult), [[ADD]](s32), [[COPY]] ; MIPS32: [[ADD1:%[0-9]+]]:_(s32) = G_ADD [[LOAD1]], [[COPY1]] + ; MIPS32: [[ICMP1:%[0-9]+]]:_(s32) = G_ICMP intpred(ult), [[ADD1]](s32), [[LOAD1]] ; MIPS32: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 1 ; MIPS32: [[AND:%[0-9]+]]:_(s32) = G_AND [[ICMP]], [[C]] ; MIPS32: [[ADD2:%[0-9]+]]:_(s32) = G_ADD [[ADD1]], [[AND]] - ; MIPS32: [[ICMP1:%[0-9]+]]:_(s32) = G_ICMP intpred(eq), [[ADD2]](s32), [[LOAD1]] - ; MIPS32: [[ICMP2:%[0-9]+]]:_(s32) = G_ICMP intpred(ult), [[ADD2]](s32), [[LOAD1]] - ; MIPS32: [[AND1:%[0-9]+]]:_(s32) = G_AND [[ICMP1]], [[ICMP]] - ; MIPS32: [[OR:%[0-9]+]]:_(s32) = G_OR [[AND1]], [[ICMP2]] + ; MIPS32: [[C1:%[0-9]+]]:_(s32) = G_CONSTANT i32 0 + ; MIPS32: [[ICMP2:%[0-9]+]]:_(s32) = G_ICMP intpred(eq), [[ADD2]](s32), [[C1]] + ; MIPS32: [[AND1:%[0-9]+]]:_(s32) = G_AND [[ICMP2]], [[ICMP]] + ; MIPS32: [[OR:%[0-9]+]]:_(s32) = G_OR [[ICMP1]], [[AND1]] ; MIPS32: [[ADD3:%[0-9]+]]:_(s32) = G_ADD [[LOAD2]], [[COPY2]] + ; MIPS32: [[ICMP3:%[0-9]+]]:_(s32) = G_ICMP intpred(ult), [[ADD3]](s32), [[LOAD2]] ; MIPS32: [[AND2:%[0-9]+]]:_(s32) = G_AND [[OR]], [[C]] ; MIPS32: [[ADD4:%[0-9]+]]:_(s32) = G_ADD [[ADD3]], [[AND2]] - ; MIPS32: [[ICMP3:%[0-9]+]]:_(s32) = G_ICMP intpred(eq), [[ADD4]](s32), [[LOAD2]] - ; MIPS32: [[ICMP4:%[0-9]+]]:_(s32) = G_ICMP intpred(ult), [[ADD4]](s32), [[LOAD2]] - ; MIPS32: [[AND3:%[0-9]+]]:_(s32) = G_AND [[ICMP3]], [[OR]] - ; MIPS32: [[OR1:%[0-9]+]]:_(s32) = G_OR [[AND3]], [[ICMP4]] + ; MIPS32: [[ICMP4:%[0-9]+]]:_(s32) = G_ICMP intpred(eq), [[ADD4]](s32), [[C1]] + ; MIPS32: [[AND3:%[0-9]+]]:_(s32) = G_AND [[ICMP4]], [[OR]] + ; MIPS32: [[OR1:%[0-9]+]]:_(s32) = G_OR [[ICMP3]], [[AND3]] ; MIPS32: [[ADD5:%[0-9]+]]:_(s32) = G_ADD [[LOAD3]], [[COPY3]] ; MIPS32: [[AND4:%[0-9]+]]:_(s32) = G_AND [[OR1]], [[C]] ; MIPS32: [[ADD6:%[0-9]+]]:_(s32) = G_ADD [[ADD5]], [[AND4]] diff --git a/llvm/test/CodeGen/Mips/GlobalISel/legalizer/sub.mir b/llvm/test/CodeGen/Mips/GlobalISel/legalizer/sub.mir --- a/llvm/test/CodeGen/Mips/GlobalISel/legalizer/sub.mir +++ b/llvm/test/CodeGen/Mips/GlobalISel/legalizer/sub.mir @@ -261,22 +261,23 @@ ; MIPS32: [[SUB:%[0-9]+]]:_(s32) = G_SUB [[LOAD]], [[COPY]] ; MIPS32: [[ICMP:%[0-9]+]]:_(s32) = G_ICMP intpred(ult), [[LOAD]](s32), [[COPY]] ; MIPS32: [[SUB1:%[0-9]+]]:_(s32) = G_SUB [[LOAD1]], [[COPY1]] + ; MIPS32: [[ICMP1:%[0-9]+]]:_(s32) = G_ICMP intpred(ugt), [[SUB1]](s32), [[LOAD1]] ; MIPS32: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 1 ; MIPS32: [[AND:%[0-9]+]]:_(s32) = G_AND [[ICMP]], [[C]] ; MIPS32: [[SUB2:%[0-9]+]]:_(s32) = G_SUB [[SUB1]], [[AND]] - ; MIPS32: [[ICMP1:%[0-9]+]]:_(s32) = G_ICMP intpred(eq), [[LOAD1]](s32), [[COPY1]] - ; MIPS32: [[ICMP2:%[0-9]+]]:_(s32) = G_ICMP intpred(ult), [[LOAD1]](s32), [[COPY1]] - ; MIPS32: [[AND1:%[0-9]+]]:_(s32) = G_AND [[ICMP1]], [[C]] - ; MIPS32: [[SELECT:%[0-9]+]]:_(s32) = G_SELECT [[AND1]](s32), [[ICMP]], [[ICMP2]] + ; MIPS32: [[C1:%[0-9]+]]:_(s32) = G_CONSTANT i32 0 + ; MIPS32: [[ICMP2:%[0-9]+]]:_(s32) = G_ICMP intpred(eq), [[SUB1]](s32), [[C1]] + ; MIPS32: [[AND1:%[0-9]+]]:_(s32) = G_AND [[ICMP2]], [[ICMP]] + ; MIPS32: [[OR:%[0-9]+]]:_(s32) = G_OR [[ICMP1]], [[AND1]] ; MIPS32: [[SUB3:%[0-9]+]]:_(s32) = G_SUB [[LOAD2]], [[COPY2]] - ; MIPS32: [[AND2:%[0-9]+]]:_(s32) = G_AND [[SELECT]], [[C]] + ; MIPS32: [[ICMP3:%[0-9]+]]:_(s32) = G_ICMP intpred(ugt), [[SUB3]](s32), [[LOAD2]] + ; MIPS32: [[AND2:%[0-9]+]]:_(s32) = G_AND [[OR]], [[C]] ; MIPS32: [[SUB4:%[0-9]+]]:_(s32) = G_SUB [[SUB3]], [[AND2]] - ; MIPS32: [[ICMP3:%[0-9]+]]:_(s32) = G_ICMP intpred(eq), [[LOAD2]](s32), [[COPY2]] - ; MIPS32: [[ICMP4:%[0-9]+]]:_(s32) = G_ICMP intpred(ult), [[LOAD2]](s32), [[COPY2]] - ; MIPS32: [[AND3:%[0-9]+]]:_(s32) = G_AND [[ICMP3]], [[C]] - ; MIPS32: [[SELECT1:%[0-9]+]]:_(s32) = G_SELECT [[AND3]](s32), [[SELECT]], [[ICMP4]] + ; MIPS32: [[ICMP4:%[0-9]+]]:_(s32) = G_ICMP intpred(eq), [[SUB3]](s32), [[C1]] + ; MIPS32: [[AND3:%[0-9]+]]:_(s32) = G_AND [[ICMP4]], [[OR]] + ; MIPS32: [[OR1:%[0-9]+]]:_(s32) = G_OR [[ICMP3]], [[AND3]] ; MIPS32: [[SUB5:%[0-9]+]]:_(s32) = G_SUB [[LOAD3]], [[COPY3]] - ; MIPS32: [[AND4:%[0-9]+]]:_(s32) = G_AND [[SELECT1]], [[C]] + ; MIPS32: [[AND4:%[0-9]+]]:_(s32) = G_AND [[OR1]], [[C]] ; MIPS32: [[SUB6:%[0-9]+]]:_(s32) = G_SUB [[SUB5]], [[AND4]] ; MIPS32: $v0 = COPY [[SUB]](s32) ; MIPS32: $v1 = COPY [[SUB2]](s32) diff --git a/llvm/test/CodeGen/Mips/GlobalISel/llvm-ir/add.ll b/llvm/test/CodeGen/Mips/GlobalISel/llvm-ir/add.ll --- a/llvm/test/CodeGen/Mips/GlobalISel/llvm-ir/add.ll +++ b/llvm/test/CodeGen/Mips/GlobalISel/llvm-ir/add.ll @@ -101,33 +101,31 @@ define i128 @add_i128(i128 %a, i128 %b) { ; MIPS32-LABEL: add_i128: ; MIPS32: # %bb.0: # %entry -; MIPS32-NEXT: move $3, $4 -; MIPS32-NEXT: move $4, $6 +; MIPS32-NEXT: move $8, $4 +; MIPS32-NEXT: move $3, $5 ; MIPS32-NEXT: addiu $1, $sp, 16 ; MIPS32-NEXT: lw $2, 0($1) ; MIPS32-NEXT: addiu $1, $sp, 20 -; MIPS32-NEXT: lw $8, 0($1) +; MIPS32-NEXT: lw $4, 0($1) ; MIPS32-NEXT: addiu $1, $sp, 24 -; MIPS32-NEXT: lw $6, 0($1) +; MIPS32-NEXT: lw $5, 0($1) ; MIPS32-NEXT: addiu $1, $sp, 28 ; MIPS32-NEXT: lw $1, 0($1) -; MIPS32-NEXT: addu $2, $2, $3 -; MIPS32-NEXT: sltu $9, $2, $3 -; MIPS32-NEXT: addu $3, $8, $5 -; MIPS32-NEXT: andi $5, $9, 1 -; MIPS32-NEXT: addu $3, $3, $5 -; MIPS32-NEXT: xor $5, $3, $8 -; MIPS32-NEXT: sltiu $5, $5, 1 -; MIPS32-NEXT: sltu $8, $3, $8 -; MIPS32-NEXT: and $5, $5, $9 -; MIPS32-NEXT: or $8, $5, $8 -; MIPS32-NEXT: addu $4, $6, $4 -; MIPS32-NEXT: andi $5, $8, 1 -; MIPS32-NEXT: addu $4, $4, $5 -; MIPS32-NEXT: xor $5, $4, $6 -; MIPS32-NEXT: sltiu $5, $5, 1 -; MIPS32-NEXT: sltu $6, $4, $6 -; MIPS32-NEXT: and $5, $5, $8 +; MIPS32-NEXT: addu $2, $2, $8 +; MIPS32-NEXT: sltu $9, $2, $8 +; MIPS32-NEXT: addu $3, $4, $3 +; MIPS32-NEXT: sltu $4, $3, $4 +; MIPS32-NEXT: andi $8, $9, 1 +; MIPS32-NEXT: addu $3, $3, $8 +; MIPS32-NEXT: sltiu $8, $3, 1 +; MIPS32-NEXT: and $8, $8, $9 +; MIPS32-NEXT: or $8, $4, $8 +; MIPS32-NEXT: addu $4, $5, $6 +; MIPS32-NEXT: sltu $5, $4, $5 +; MIPS32-NEXT: andi $6, $8, 1 +; MIPS32-NEXT: addu $4, $4, $6 +; MIPS32-NEXT: sltiu $6, $4, 1 +; MIPS32-NEXT: and $6, $6, $8 ; MIPS32-NEXT: or $5, $5, $6 ; MIPS32-NEXT: addu $1, $1, $7 ; MIPS32-NEXT: andi $5, $5, 1 diff --git a/llvm/test/CodeGen/Mips/GlobalISel/llvm-ir/sub.ll b/llvm/test/CodeGen/Mips/GlobalISel/llvm-ir/sub.ll --- a/llvm/test/CodeGen/Mips/GlobalISel/llvm-ir/sub.ll +++ b/llvm/test/CodeGen/Mips/GlobalISel/llvm-ir/sub.ll @@ -102,34 +102,31 @@ define i128 @sub_i128(i128 %a, i128 %b) { ; MIPS32-LABEL: sub_i128: ; MIPS32: # %bb.0: # %entry -; MIPS32-NEXT: move $10, $5 -; MIPS32-NEXT: move $9, $6 +; MIPS32-NEXT: move $9, $4 ; MIPS32-NEXT: addiu $1, $sp, 16 -; MIPS32-NEXT: lw $3, 0($1) +; MIPS32-NEXT: lw $8, 0($1) ; MIPS32-NEXT: addiu $1, $sp, 20 -; MIPS32-NEXT: lw $6, 0($1) +; MIPS32-NEXT: lw $3, 0($1) ; MIPS32-NEXT: addiu $1, $sp, 24 -; MIPS32-NEXT: lw $5, 0($1) +; MIPS32-NEXT: lw $4, 0($1) ; MIPS32-NEXT: addiu $1, $sp, 28 ; MIPS32-NEXT: lw $1, 0($1) -; MIPS32-NEXT: subu $2, $3, $4 -; MIPS32-NEXT: sltu $4, $3, $4 -; MIPS32-NEXT: subu $3, $6, $10 -; MIPS32-NEXT: andi $8, $4, 1 -; MIPS32-NEXT: subu $3, $3, $8 -; MIPS32-NEXT: xor $8, $6, $10 -; MIPS32-NEXT: sltiu $8, $8, 1 -; MIPS32-NEXT: sltu $6, $6, $10 -; MIPS32-NEXT: andi $8, $8, 1 -; MIPS32-NEXT: movn $6, $4, $8 -; MIPS32-NEXT: subu $4, $5, $9 -; MIPS32-NEXT: andi $8, $6, 1 -; MIPS32-NEXT: subu $4, $4, $8 -; MIPS32-NEXT: xor $8, $5, $9 +; MIPS32-NEXT: subu $2, $8, $9 +; MIPS32-NEXT: sltu $9, $8, $9 +; MIPS32-NEXT: subu $8, $3, $5 +; MIPS32-NEXT: sltu $5, $3, $8 +; MIPS32-NEXT: andi $3, $9, 1 +; MIPS32-NEXT: subu $3, $8, $3 ; MIPS32-NEXT: sltiu $8, $8, 1 -; MIPS32-NEXT: sltu $5, $5, $9 -; MIPS32-NEXT: andi $8, $8, 1 -; MIPS32-NEXT: movn $5, $6, $8 +; MIPS32-NEXT: and $8, $8, $9 +; MIPS32-NEXT: or $8, $5, $8 +; MIPS32-NEXT: subu $6, $4, $6 +; MIPS32-NEXT: sltu $5, $4, $6 +; MIPS32-NEXT: andi $4, $8, 1 +; MIPS32-NEXT: subu $4, $6, $4 +; MIPS32-NEXT: sltiu $6, $6, 1 +; MIPS32-NEXT: and $6, $6, $8 +; MIPS32-NEXT: or $5, $5, $6 ; MIPS32-NEXT: subu $1, $1, $7 ; MIPS32-NEXT: andi $5, $5, 1 ; MIPS32-NEXT: subu $5, $1, $5