Index: lib/Target/Mips/MipsLegalizerInfo.cpp =================================================================== --- lib/Target/Mips/MipsLegalizerInfo.cpp +++ lib/Target/Mips/MipsLegalizerInfo.cpp @@ -24,7 +24,7 @@ const LLT s64 = LLT::scalar(64); const LLT p0 = LLT::pointer(0, 32); - getActionDefinitionsBuilder(G_ADD) + getActionDefinitionsBuilder({G_ADD, G_SUB}) .legalFor({s32}) .minScalar(0, s32) .customFor({s64}); @@ -66,7 +66,8 @@ MIRBuilder.setInstr(MI); switch (MI.getOpcode()) { - case G_ADD: { + case G_ADD: + case G_SUB: { unsigned Size = MRI.getType(MI.getOperand(0).getReg()).getSizeInBits(); const LLT sHalf = LLT::scalar(Size / 2); @@ -77,16 +78,34 @@ unsigned LHSHigh = MRI.createGenericVirtualRegister(sHalf); unsigned ResLow = MRI.createGenericVirtualRegister(sHalf); unsigned ResHigh = MRI.createGenericVirtualRegister(sHalf); - unsigned Carry = MRI.createGenericVirtualRegister(sHalf); - unsigned TmpResHigh = MRI.createGenericVirtualRegister(sHalf); MIRBuilder.buildUnmerge({RHSHigh, RHSLow}, MI.getOperand(2).getReg()); MIRBuilder.buildUnmerge({LHSHigh, LHSLow}, MI.getOperand(1).getReg()); - MIRBuilder.buildAdd(TmpResHigh, LHSHigh, RHSHigh); - MIRBuilder.buildAdd(ResLow, LHSLow, RHSLow); - MIRBuilder.buildICmp(CmpInst::ICMP_ULT, Carry, ResLow, LHSLow); - MIRBuilder.buildAdd(ResHigh, TmpResHigh, Carry); + switch (MI.getOpcode()) { + case G_ADD: { + unsigned Carry = MRI.createGenericVirtualRegister(sHalf); + unsigned TmpResHigh = MRI.createGenericVirtualRegister(sHalf); + + MIRBuilder.buildAdd(TmpResHigh, LHSHigh, RHSHigh); + MIRBuilder.buildAdd(ResLow, LHSLow, RHSLow); + MIRBuilder.buildICmp(CmpInst::ICMP_ULT, Carry, ResLow, LHSLow); + MIRBuilder.buildAdd(ResHigh, TmpResHigh, Carry); + break; + } + case G_SUB: { + unsigned Borrow = MRI.createGenericVirtualRegister(sHalf); + unsigned TmpResHigh = MRI.createGenericVirtualRegister(sHalf); + + MIRBuilder.buildSub(TmpResHigh, LHSHigh, RHSHigh); + MIRBuilder.buildSub(ResLow, LHSLow, RHSLow); + MIRBuilder.buildICmp(CmpInst::ICMP_ULT, Borrow, LHSLow, RHSLow); + MIRBuilder.buildSub(ResHigh, TmpResHigh, Borrow); + break; + } + default: + llvm_unreachable("Unexpected opcode!"); + } MIRBuilder.buildMerge(MI.getOperand(0).getReg(), {ResHigh, ResLow}); Index: lib/Target/Mips/MipsRegisterBankInfo.cpp =================================================================== --- lib/Target/Mips/MipsRegisterBankInfo.cpp +++ lib/Target/Mips/MipsRegisterBankInfo.cpp @@ -84,6 +84,7 @@ switch (Opc) { case G_ADD: + case G_SUB: case G_LOAD: case G_STORE: case G_GEP: Index: test/CodeGen/Mips/GlobalISel/instruction-select/sub.mir =================================================================== --- /dev/null +++ test/CodeGen/Mips/GlobalISel/instruction-select/sub.mir @@ -0,0 +1,31 @@ +# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py +# RUN: llc -O0 -mtriple=mipsel-linux-gnu -run-pass=instruction-select -verify-machineinstrs %s -o - | FileCheck %s -check-prefixes=MIPS32 +--- | + + define void @sub_i32(i32 %x, i32 %y) {entry: ret void} + +... +--- +name: sub_i32 +alignment: 2 +legalized: true +regBankSelected: true +tracksRegLiveness: true +body: | + bb.0.entry: + liveins: $a0, $a1 + + ; MIPS32-LABEL: name: sub_i32 + ; MIPS32: liveins: $a0, $a1 + ; MIPS32: [[COPY:%[0-9]+]]:gpr32 = COPY $a0 + ; MIPS32: [[COPY1:%[0-9]+]]:gpr32 = COPY $a1 + ; MIPS32: [[SUBu:%[0-9]+]]:gpr32 = SUBu [[COPY]], [[COPY1]] + ; MIPS32: $v0 = COPY [[SUBu]] + ; MIPS32: RetRA implicit $v0 + %0:gprb(s32) = COPY $a0 + %1:gprb(s32) = COPY $a1 + %2:gprb(s32) = G_SUB %0, %1 + $v0 = COPY %2(s32) + RetRA implicit $v0 + +... Index: test/CodeGen/Mips/GlobalISel/legalizer/sub.mir =================================================================== --- /dev/null +++ test/CodeGen/Mips/GlobalISel/legalizer/sub.mir @@ -0,0 +1,248 @@ +# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py +# RUN: llc -O0 -mtriple=mipsel-linux-gnu -run-pass=legalizer -verify-machineinstrs %s -o - | FileCheck %s -check-prefixes=MIPS32 +--- | + + define void @sub_i32() {entry: ret void} + define void @sub_i8_sext() {entry: ret void} + define void @sub_i8_zext() {entry: ret void} + define void @sub_i8_aext() {entry: ret void} + define void @sub_i16_sext() {entry: ret void} + define void @sub_i16_zext() {entry: ret void} + define void @sub_i16_aext() {entry: ret void} + define void @sub_i64() {entry: ret void} + +... +--- +name: sub_i32 +alignment: 2 +tracksRegLiveness: true +body: | + bb.1.entry: + liveins: $a0, $a1 + + ; MIPS32-LABEL: name: sub_i32 + ; MIPS32: liveins: $a0, $a1 + ; MIPS32: [[COPY:%[0-9]+]]:_(s32) = COPY $a0 + ; MIPS32: [[COPY1:%[0-9]+]]:_(s32) = COPY $a1 + ; MIPS32: [[SUB:%[0-9]+]]:_(s32) = G_SUB [[COPY]], [[COPY1]] + ; MIPS32: $v0 = COPY [[SUB]](s32) + ; MIPS32: RetRA implicit $v0 + %0:_(s32) = COPY $a0 + %1:_(s32) = COPY $a1 + %2:_(s32) = G_SUB %0, %1 + $v0 = COPY %2(s32) + RetRA implicit $v0 + +... +--- +name: sub_i8_sext +alignment: 2 +tracksRegLiveness: true +body: | + bb.1.entry: + liveins: $a0, $a1 + + ; MIPS32-LABEL: name: sub_i8_sext + ; MIPS32: liveins: $a0, $a1 + ; MIPS32: [[COPY:%[0-9]+]]:_(s32) = COPY $a0 + ; MIPS32: [[COPY1:%[0-9]+]]:_(s32) = COPY $a1 + ; MIPS32: [[COPY2:%[0-9]+]]:_(s32) = COPY [[COPY1]](s32) + ; MIPS32: [[COPY3:%[0-9]+]]:_(s32) = COPY [[COPY]](s32) + ; MIPS32: [[SUB:%[0-9]+]]:_(s32) = G_SUB [[COPY2]], [[COPY3]] + ; MIPS32: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 24 + ; MIPS32: [[COPY4:%[0-9]+]]:_(s32) = COPY [[SUB]](s32) + ; MIPS32: [[SHL:%[0-9]+]]:_(s32) = G_SHL [[COPY4]], [[C]] + ; MIPS32: [[ASHR:%[0-9]+]]:_(s32) = G_ASHR [[SHL]], [[C]] + ; MIPS32: $v0 = COPY [[ASHR]](s32) + ; MIPS32: RetRA implicit $v0 + %2:_(s32) = COPY $a0 + %0:_(s8) = G_TRUNC %2(s32) + %3:_(s32) = COPY $a1 + %1:_(s8) = G_TRUNC %3(s32) + %4:_(s8) = G_SUB %1, %0 + %5:_(s32) = G_SEXT %4(s8) + $v0 = COPY %5(s32) + RetRA implicit $v0 + +... +--- +name: sub_i8_zext +alignment: 2 +tracksRegLiveness: true +body: | + bb.1.entry: + liveins: $a0, $a1 + + ; MIPS32-LABEL: name: sub_i8_zext + ; MIPS32: liveins: $a0, $a1 + ; MIPS32: [[COPY:%[0-9]+]]:_(s32) = COPY $a0 + ; MIPS32: [[COPY1:%[0-9]+]]:_(s32) = COPY $a1 + ; MIPS32: [[COPY2:%[0-9]+]]:_(s32) = COPY [[COPY1]](s32) + ; MIPS32: [[COPY3:%[0-9]+]]:_(s32) = COPY [[COPY]](s32) + ; MIPS32: [[SUB:%[0-9]+]]:_(s32) = G_SUB [[COPY2]], [[COPY3]] + ; MIPS32: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 255 + ; MIPS32: [[COPY4:%[0-9]+]]:_(s32) = COPY [[SUB]](s32) + ; MIPS32: [[AND:%[0-9]+]]:_(s32) = G_AND [[COPY4]], [[C]] + ; MIPS32: $v0 = COPY [[AND]](s32) + ; MIPS32: RetRA implicit $v0 + %2:_(s32) = COPY $a0 + %0:_(s8) = G_TRUNC %2(s32) + %3:_(s32) = COPY $a1 + %1:_(s8) = G_TRUNC %3(s32) + %4:_(s8) = G_SUB %1, %0 + %5:_(s32) = G_ZEXT %4(s8) + $v0 = COPY %5(s32) + RetRA implicit $v0 + +... +--- +name: sub_i8_aext +alignment: 2 +tracksRegLiveness: true +body: | + bb.1.entry: + liveins: $a0, $a1 + + ; MIPS32-LABEL: name: sub_i8_aext + ; MIPS32: liveins: $a0, $a1 + ; MIPS32: [[COPY:%[0-9]+]]:_(s32) = COPY $a0 + ; MIPS32: [[COPY1:%[0-9]+]]:_(s32) = COPY $a1 + ; MIPS32: [[COPY2:%[0-9]+]]:_(s32) = COPY [[COPY1]](s32) + ; MIPS32: [[COPY3:%[0-9]+]]:_(s32) = COPY [[COPY]](s32) + ; MIPS32: [[SUB:%[0-9]+]]:_(s32) = G_SUB [[COPY2]], [[COPY3]] + ; MIPS32: [[COPY4:%[0-9]+]]:_(s32) = COPY [[SUB]](s32) + ; MIPS32: $v0 = COPY [[COPY4]](s32) + ; MIPS32: RetRA implicit $v0 + %2:_(s32) = COPY $a0 + %0:_(s8) = G_TRUNC %2(s32) + %3:_(s32) = COPY $a1 + %1:_(s8) = G_TRUNC %3(s32) + %4:_(s8) = G_SUB %1, %0 + %5:_(s32) = G_ANYEXT %4(s8) + $v0 = COPY %5(s32) + RetRA implicit $v0 + +... +--- +name: sub_i16_sext +alignment: 2 +tracksRegLiveness: true +body: | + bb.1.entry: + liveins: $a0, $a1 + + ; MIPS32-LABEL: name: sub_i16_sext + ; MIPS32: liveins: $a0, $a1 + ; MIPS32: [[COPY:%[0-9]+]]:_(s32) = COPY $a0 + ; MIPS32: [[COPY1:%[0-9]+]]:_(s32) = COPY $a1 + ; MIPS32: [[COPY2:%[0-9]+]]:_(s32) = COPY [[COPY1]](s32) + ; MIPS32: [[COPY3:%[0-9]+]]:_(s32) = COPY [[COPY]](s32) + ; MIPS32: [[SUB:%[0-9]+]]:_(s32) = G_SUB [[COPY2]], [[COPY3]] + ; MIPS32: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 16 + ; MIPS32: [[COPY4:%[0-9]+]]:_(s32) = COPY [[SUB]](s32) + ; MIPS32: [[SHL:%[0-9]+]]:_(s32) = G_SHL [[COPY4]], [[C]] + ; MIPS32: [[ASHR:%[0-9]+]]:_(s32) = G_ASHR [[SHL]], [[C]] + ; MIPS32: $v0 = COPY [[ASHR]](s32) + ; MIPS32: RetRA implicit $v0 + %2:_(s32) = COPY $a0 + %0:_(s16) = G_TRUNC %2(s32) + %3:_(s32) = COPY $a1 + %1:_(s16) = G_TRUNC %3(s32) + %4:_(s16) = G_SUB %1, %0 + %5:_(s32) = G_SEXT %4(s16) + $v0 = COPY %5(s32) + RetRA implicit $v0 + +... +--- +name: sub_i16_zext +alignment: 2 +tracksRegLiveness: true +body: | + bb.1.entry: + liveins: $a0, $a1 + + ; MIPS32-LABEL: name: sub_i16_zext + ; MIPS32: liveins: $a0, $a1 + ; MIPS32: [[COPY:%[0-9]+]]:_(s32) = COPY $a0 + ; MIPS32: [[COPY1:%[0-9]+]]:_(s32) = COPY $a1 + ; MIPS32: [[COPY2:%[0-9]+]]:_(s32) = COPY [[COPY1]](s32) + ; MIPS32: [[COPY3:%[0-9]+]]:_(s32) = COPY [[COPY]](s32) + ; MIPS32: [[SUB:%[0-9]+]]:_(s32) = G_SUB [[COPY2]], [[COPY3]] + ; MIPS32: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 65535 + ; MIPS32: [[COPY4:%[0-9]+]]:_(s32) = COPY [[SUB]](s32) + ; MIPS32: [[AND:%[0-9]+]]:_(s32) = G_AND [[COPY4]], [[C]] + ; MIPS32: $v0 = COPY [[AND]](s32) + ; MIPS32: RetRA implicit $v0 + %2:_(s32) = COPY $a0 + %0:_(s16) = G_TRUNC %2(s32) + %3:_(s32) = COPY $a1 + %1:_(s16) = G_TRUNC %3(s32) + %4:_(s16) = G_SUB %1, %0 + %5:_(s32) = G_ZEXT %4(s16) + $v0 = COPY %5(s32) + RetRA implicit $v0 + +... +--- +name: sub_i16_aext +alignment: 2 +tracksRegLiveness: true +body: | + bb.1.entry: + liveins: $a0, $a1 + + ; MIPS32-LABEL: name: sub_i16_aext + ; MIPS32: liveins: $a0, $a1 + ; MIPS32: [[COPY:%[0-9]+]]:_(s32) = COPY $a0 + ; MIPS32: [[COPY1:%[0-9]+]]:_(s32) = COPY $a1 + ; MIPS32: [[COPY2:%[0-9]+]]:_(s32) = COPY [[COPY1]](s32) + ; MIPS32: [[COPY3:%[0-9]+]]:_(s32) = COPY [[COPY]](s32) + ; MIPS32: [[SUB:%[0-9]+]]:_(s32) = G_SUB [[COPY2]], [[COPY3]] + ; MIPS32: [[COPY4:%[0-9]+]]:_(s32) = COPY [[SUB]](s32) + ; MIPS32: $v0 = COPY [[COPY4]](s32) + ; MIPS32: RetRA implicit $v0 + %2:_(s32) = COPY $a0 + %0:_(s16) = G_TRUNC %2(s32) + %3:_(s32) = COPY $a1 + %1:_(s16) = G_TRUNC %3(s32) + %4:_(s16) = G_SUB %1, %0 + %5:_(s32) = G_ANYEXT %4(s16) + $v0 = COPY %5(s32) + RetRA implicit $v0 + +... +--- +name: sub_i64 +alignment: 2 +tracksRegLiveness: true +body: | + bb.1.entry: + liveins: $a0, $a1, $a2, $a3 + + ; MIPS32-LABEL: name: sub_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: [[SUB:%[0-9]+]]:_(s32) = G_SUB [[COPY3]], [[COPY1]] + ; MIPS32: [[SUB1:%[0-9]+]]:_(s32) = G_SUB [[COPY2]], [[COPY]] + ; MIPS32: [[ICMP:%[0-9]+]]:_(s32) = G_ICMP intpred(ult), [[COPY2]](s32), [[COPY]] + ; MIPS32: [[SUB2:%[0-9]+]]:_(s32) = G_SUB [[SUB]], [[ICMP]] + ; MIPS32: $v0 = COPY [[SUB1]](s32) + ; MIPS32: $v1 = COPY [[SUB2]](s32) + ; MIPS32: RetRA implicit $v0, implicit $v1 + %2:_(s32) = COPY $a0 + %3:_(s32) = COPY $a1 + %0:_(s64) = G_MERGE_VALUES %3(s32), %2(s32) + %4:_(s32) = COPY $a2 + %5:_(s32) = COPY $a3 + %1:_(s64) = G_MERGE_VALUES %5(s32), %4(s32) + %6:_(s64) = G_SUB %1, %0 + %7:_(s32), %8:_(s32) = G_UNMERGE_VALUES %6(s64) + $v0 = COPY %8(s32) + $v1 = COPY %7(s32) + RetRA implicit $v0, implicit $v1 + +... Index: test/CodeGen/Mips/GlobalISel/llvm-ir/sub.ll =================================================================== --- /dev/null +++ test/CodeGen/Mips/GlobalISel/llvm-ir/sub.ll @@ -0,0 +1,103 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -O0 -mtriple=mipsel-linux-gnu -global-isel -verify-machineinstrs %s -o -| FileCheck %s -check-prefixes=MIPS32 + +define i32 @sub_i32(i32 %x, i32 %y) { +; MIPS32-LABEL: sub_i32: +; MIPS32: # %bb.0: # %entry +; MIPS32-NEXT: subu $2, $4, $5 +; MIPS32-NEXT: jr $ra +; MIPS32-NEXT: nop +entry: + %z = sub i32 %x, %y + ret i32 %z +} + +define signext i8 @sub_i8_sext(i8 signext %a, i8 signext %b) { +; MIPS32-LABEL: sub_i8_sext: +; MIPS32: # %bb.0: # %entry +; MIPS32-NEXT: subu $4, $5, $4 +; MIPS32-NEXT: sll $4, $4, 24 +; MIPS32-NEXT: sra $2, $4, 24 +; MIPS32-NEXT: jr $ra +; MIPS32-NEXT: nop +entry: + %sub = sub i8 %b, %a + ret i8 %sub +} + +define zeroext i8 @sub_i8_zext(i8 zeroext %a, i8 zeroext %b) { +; MIPS32-LABEL: sub_i8_zext: +; MIPS32: # %bb.0: # %entry +; MIPS32-NEXT: subu $4, $5, $4 +; MIPS32-NEXT: lui $5, 0 +; MIPS32-NEXT: ori $5, $5, 255 +; MIPS32-NEXT: and $2, $4, $5 +; MIPS32-NEXT: jr $ra +; MIPS32-NEXT: nop +entry: + %sub = sub i8 %b, %a + ret i8 %sub +} + +define i8 @sub_i8_aext(i8 %a, i8 %b) { +; MIPS32-LABEL: sub_i8_aext: +; MIPS32: # %bb.0: # %entry +; MIPS32-NEXT: subu $2, $5, $4 +; MIPS32-NEXT: jr $ra +; MIPS32-NEXT: nop +entry: + %sub = sub i8 %b, %a + ret i8 %sub +} + +define signext i16 @sub_i16_sext(i16 signext %a, i16 signext %b) { +; MIPS32-LABEL: sub_i16_sext: +; MIPS32: # %bb.0: # %entry +; MIPS32-NEXT: subu $4, $5, $4 +; MIPS32-NEXT: sll $4, $4, 16 +; MIPS32-NEXT: sra $2, $4, 16 +; MIPS32-NEXT: jr $ra +; MIPS32-NEXT: nop +entry: + %sub = sub i16 %b, %a + ret i16 %sub +} + +define zeroext i16 @sub_i16_zext(i16 zeroext %a, i16 zeroext %b) { +; MIPS32-LABEL: sub_i16_zext: +; MIPS32: # %bb.0: # %entry +; MIPS32-NEXT: subu $4, $5, $4 +; MIPS32-NEXT: lui $5, 0 +; MIPS32-NEXT: ori $5, $5, 65535 +; MIPS32-NEXT: and $2, $4, $5 +; MIPS32-NEXT: jr $ra +; MIPS32-NEXT: nop +entry: + %sub = sub i16 %b, %a + ret i16 %sub +} + +define i16 @sub_i16_aext(i16 %a, i16 %b) { +; MIPS32-LABEL: sub_i16_aext: +; MIPS32: # %bb.0: # %entry +; MIPS32-NEXT: subu $2, $5, $4 +; MIPS32-NEXT: jr $ra +; MIPS32-NEXT: nop +entry: + %sub = sub i16 %b, %a + ret i16 %sub +} + +define i64 @sub_i64(i64 %a, i64 %b) { +; MIPS32-LABEL: sub_i64: +; MIPS32: # %bb.0: # %entry +; MIPS32-NEXT: subu $5, $7, $5 +; MIPS32-NEXT: subu $2, $6, $4 +; MIPS32-NEXT: sltu $4, $6, $4 +; MIPS32-NEXT: subu $3, $5, $4 +; MIPS32-NEXT: jr $ra +; MIPS32-NEXT: nop +entry: + %sub = sub i64 %b, %a + ret i64 %sub +} Index: test/CodeGen/Mips/GlobalISel/regbankselect/sub.mir =================================================================== --- /dev/null +++ test/CodeGen/Mips/GlobalISel/regbankselect/sub.mir @@ -0,0 +1,30 @@ +# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py +# RUN: llc -O0 -mtriple=mipsel-linux-gnu -run-pass=regbankselect -verify-machineinstrs %s -o - | FileCheck %s -check-prefixes=MIPS32 +--- | + + define void @sub_i32(i32 %x, i32 %y) {entry: ret void} + +... +--- +name: sub_i32 +alignment: 2 +legalized: true +tracksRegLiveness: true +body: | + bb.0.entry: + liveins: $a0, $a1 + + ; MIPS32-LABEL: name: sub_i32 + ; MIPS32: liveins: $a0, $a1 + ; MIPS32: [[COPY:%[0-9]+]]:gprb(s32) = COPY $a0 + ; MIPS32: [[COPY1:%[0-9]+]]:gprb(s32) = COPY $a1 + ; MIPS32: [[SUB:%[0-9]+]]:gprb(s32) = G_SUB [[COPY]], [[COPY1]] + ; MIPS32: $v0 = COPY [[SUB]](s32) + ; MIPS32: RetRA implicit $v0 + %0:_(s32) = COPY $a0 + %1:_(s32) = COPY $a1 + %2:_(s32) = G_SUB %0, %1 + $v0 = COPY %2(s32) + RetRA implicit $v0 + +...