SDValue Sub = DAG.getNode(ISD::SUB, DL, VT, N0.getOperand(0), N1);
return DAG.getNode(ISD::SUB, DL, VT, Sub, N0.getOperand(1));
}
+ // (C - x) - y -> C - (x + y)
+ if (N0.hasOneUse() && N0.getOpcode() == ISD::SUB &&
+ isConstantOrConstantVector(N0.getOperand(0), /*NoOpaques=*/true)) {
+ SDValue Add = DAG.getNode(ISD::ADD, DL, VT, N0.getOperand(1), N1);
+ return DAG.getNode(ISD::SUB, DL, VT, N0.getOperand(0), Add);
+ }
// If the target's bool is represented as 0/-1, prefer to make this 'add 0/-1'
// rather than 'sub 0/1' (the sext should get folded).
define i32 @reg32_lshr_by_sub_from_negated(i32 %val, i32 %a, i32 %b) nounwind {
; CHECK-LABEL: reg32_lshr_by_sub_from_negated:
; CHECK: // %bb.0:
-; CHECK-NEXT: mov w8, #32
-; CHECK-NEXT: sub w8, w8, w1
-; CHECK-NEXT: sub w8, w8, w2
+; CHECK-NEXT: add w8, w1, w2
+; CHECK-NEXT: neg w8, w8
; CHECK-NEXT: lsr w0, w0, w8
; CHECK-NEXT: ret
%nega = sub i32 32, %a
define i64 @reg64_lshr_by_sub_from_negated(i64 %val, i64 %a, i64 %b) nounwind {
; CHECK-LABEL: reg64_lshr_by_sub_from_negated:
; CHECK: // %bb.0:
-; CHECK-NEXT: mov w8, #64
-; CHECK-NEXT: sub x8, x8, x1
-; CHECK-NEXT: sub x8, x8, x2
+; CHECK-NEXT: add x8, x1, x2
+; CHECK-NEXT: neg x8, x8
; CHECK-NEXT: lsr x0, x0, x8
; CHECK-NEXT: ret
%nega = sub i64 64, %a
define i32 @reg32_lshr_by_negated_unfolded_sub_b(i32 %val, i32 %a, i32 %b) nounwind {
; CHECK-LABEL: reg32_lshr_by_negated_unfolded_sub_b:
; CHECK: // %bb.0:
-; CHECK-NEXT: neg w8, w1
-; CHECK-NEXT: sub w8, w8, w2
+; CHECK-NEXT: add w8, w1, w2
+; CHECK-NEXT: neg w8, w8
; CHECK-NEXT: lsr w0, w0, w8
; CHECK-NEXT: ret
%nega = sub i32 0, %a
define i64 @reg64_lshr_by_negated_unfolded_sub_b(i64 %val, i64 %a, i64 %b) nounwind {
; CHECK-LABEL: reg64_lshr_by_negated_unfolded_sub_b:
; CHECK: // %bb.0:
-; CHECK-NEXT: neg x8, x1
-; CHECK-NEXT: sub x8, x8, x2
+; CHECK-NEXT: add x8, x1, x2
+; CHECK-NEXT: neg x8, x8
; CHECK-NEXT: lsr x0, x0, x8
; CHECK-NEXT: ret
%nega = sub i64 0, %a
define i32 @sink_sub_from_const_to_sub(i32 %a, i32 %b) {
; CHECK-LABEL: sink_sub_from_const_to_sub:
; CHECK: // %bb.0:
-; CHECK-NEXT: mov w8, #32
-; CHECK-NEXT: sub w8, w8, w0
-; CHECK-NEXT: sub w0, w8, w1
+; CHECK-NEXT: add w8, w0, w1
+; CHECK-NEXT: mov w9, #32
+; CHECK-NEXT: sub w0, w9, w8
; CHECK-NEXT: ret
%t0 = sub i32 32, %a
%r = sub i32 %t0, %b
; CHECK: // %bb.0:
; CHECK-NEXT: adrp x8, .LCPI22_0
; CHECK-NEXT: ldr q2, [x8, :lo12:.LCPI22_0]
+; CHECK-NEXT: add v0.4s, v0.4s, v1.4s
; CHECK-NEXT: sub v0.4s, v2.4s, v0.4s
-; CHECK-NEXT: sub v0.4s, v0.4s, v1.4s
; CHECK-NEXT: ret
%t0 = sub <4 x i32> <i32 42, i32 24, i32 undef, i32 46>, %a
%r = sub <4 x i32> %t0, %b
; CHECK-NEXT: st %fp, [--%sp]
; CHECK-NEXT: add %sp, 0x8, %fp
; CHECK-NEXT: sub %sp, 0x8, %sp
-; CHECK-NEXT: sub %r0, %r6, %r3
-; CHECK-NEXT: sh %r6, 0x3, %r9
-; CHECK-NEXT: sub %r3, %r9, %rv
+; CHECK-NEXT: sh %r6, 0x3, %r3
+; CHECK-NEXT: add %r6, %r3, %r3
+; CHECK-NEXT: sub %r0, %r3, %rv
; CHECK-NEXT: ld -4[%fp], %pc ! return
; CHECK-NEXT: add %fp, 0x0, %sp
; CHECK-NEXT: ld -8[%fp], %fp
; CHECK-NEXT: st %fp, [--%sp]
; CHECK-NEXT: add %sp, 0x8, %fp
; CHECK-NEXT: sub %sp, 0x8, %sp
-; CHECK-NEXT: sh %r6, 0x1, %r3
-; CHECK-NEXT: sub %r0, %r3, %r3
-; CHECK-NEXT: sh %r6, 0x3, %r9
-; CHECK-NEXT: sub %r3, %r9, %rv
+; CHECK-NEXT: sh %r6, 0x3, %r3
+; CHECK-NEXT: sh %r6, 0x1, %r9
+; CHECK-NEXT: add %r9, %r3, %r3
+; CHECK-NEXT: sub %r0, %r3, %rv
; CHECK-NEXT: ld -4[%fp], %pc ! return
; CHECK-NEXT: add %fp, 0x0, %sp
; CHECK-NEXT: ld -8[%fp], %fp
; MIPS32-NEXT: subu $1, $1, $3
; MIPS32-NEXT: subu $5, $1, $12
; MIPS32-NEXT: subu $4, $9, $10
-; MIPS32-NEXT: negu $1, $8
-; MIPS32-NEXT: subu $3, $1, $11
+; MIPS32-NEXT: addu $1, $8, $11
+; MIPS32-NEXT: negu $3, $1
; MIPS32-NEXT: jr $ra
; MIPS32-NEXT: negu $2, $2
;
;
; 32R6-LABEL: msub2:
; 32R6: # %bb.0: # %entry
-; 32R6-NEXT: mul $1, $5, $4
-; 32R6-NEXT: sltu $2, $6, $1
-; 32R6-NEXT: muhu $3, $5, $4
-; 32R6-NEXT: negu $3, $3
-; 32R6-NEXT: subu $2, $3, $2
+; 32R6-NEXT: muhu $1, $5, $4
+; 32R6-NEXT: mul $3, $5, $4
+; 32R6-NEXT: sltu $2, $6, $3
+; 32R6-NEXT: addu $1, $1, $2
+; 32R6-NEXT: negu $2, $1
; 32R6-NEXT: jr $ra
-; 32R6-NEXT: subu $3, $6, $1
+; 32R6-NEXT: subu $3, $6, $3
;
; DSP-LABEL: msub2:
; DSP: # %bb.0: # %entry
; 16: # %bb.0: # %entry
; 16-NEXT: multu $5, $4
; 16-NEXT: mflo $2
-; 16-NEXT: mfhi $4
-; 16-NEXT: subu $3, $6, $2
+; 16-NEXT: mfhi $3
; 16-NEXT: sltu $6, $2
-; 16-NEXT: move $2, $24
-; 16-NEXT: neg $4, $4
-; 16-NEXT: subu $2, $4, $2
+; 16-NEXT: move $4, $24
+; 16-NEXT: addu $4, $3, $4
+; 16-NEXT: subu $3, $6, $2
+; 16-NEXT: neg $2, $4
; 16-NEXT: jrc $ra
entry:
%conv = zext i32 %c to i64
; X32-LABEL: reg32_lshr_by_sub_from_negated:
; X32: # %bb.0:
; X32-NEXT: movl {{[0-9]+}}(%esp), %eax
-; X32-NEXT: movl $32, %ecx
-; X32-NEXT: subl {{[0-9]+}}(%esp), %ecx
-; X32-NEXT: subl {{[0-9]+}}(%esp), %ecx
+; X32-NEXT: movl {{[0-9]+}}(%esp), %ecx
+; X32-NEXT: addl {{[0-9]+}}(%esp), %ecx
+; X32-NEXT: negb %cl
; X32-NEXT: # kill: def $cl killed $cl killed $ecx
; X32-NEXT: shrl %cl, %eax
; X32-NEXT: retl
;
; X64-LABEL: reg32_lshr_by_sub_from_negated:
; X64: # %bb.0:
+; X64-NEXT: # kill: def $edx killed $edx def $rdx
+; X64-NEXT: # kill: def $esi killed $esi def $rsi
; X64-NEXT: movl %edi, %eax
-; X64-NEXT: movl $32, %ecx
-; X64-NEXT: subl %esi, %ecx
-; X64-NEXT: subl %edx, %ecx
+; X64-NEXT: leal (%rsi,%rdx), %ecx
+; X64-NEXT: negb %cl
; X64-NEXT: # kill: def $cl killed $cl killed $ecx
; X64-NEXT: shrl %cl, %eax
; X64-NEXT: retq
; X32-NEXT: pushl %esi
; X32-NEXT: movl {{[0-9]+}}(%esp), %eax
; X32-NEXT: movl {{[0-9]+}}(%esp), %esi
-; X32-NEXT: movl $64, %ecx
-; X32-NEXT: subl {{[0-9]+}}(%esp), %ecx
-; X32-NEXT: subl {{[0-9]+}}(%esp), %ecx
+; X32-NEXT: movl {{[0-9]+}}(%esp), %edx
+; X32-NEXT: addl {{[0-9]+}}(%esp), %edx
+; X32-NEXT: movb $64, %cl
+; X32-NEXT: subb %dl, %cl
; X32-NEXT: movl %esi, %edx
; X32-NEXT: shrl %cl, %edx
; X32-NEXT: shrdl %cl, %esi, %eax
; X64-LABEL: reg64_lshr_by_sub_from_negated:
; X64: # %bb.0:
; X64-NEXT: movq %rdi, %rax
-; X64-NEXT: movl $64, %ecx
-; X64-NEXT: subl %esi, %ecx
-; X64-NEXT: subl %edx, %ecx
+; X64-NEXT: leal (%rdx,%rsi), %ecx
+; X64-NEXT: negb %cl
; X64-NEXT: # kill: def $cl killed $cl killed $ecx
; X64-NEXT: shrq %cl, %rax
; X64-NEXT: retq
; X32-LABEL: reg32_lshr_by_negated_unfolded_sub_b:
; X32: # %bb.0:
; X32-NEXT: movl {{[0-9]+}}(%esp), %eax
-; X32-NEXT: xorl %ecx, %ecx
-; X32-NEXT: subl {{[0-9]+}}(%esp), %ecx
-; X32-NEXT: subl {{[0-9]+}}(%esp), %ecx
+; X32-NEXT: movl {{[0-9]+}}(%esp), %ecx
+; X32-NEXT: addl {{[0-9]+}}(%esp), %ecx
+; X32-NEXT: negb %cl
; X32-NEXT: # kill: def $cl killed $cl killed $ecx
; X32-NEXT: shrl %cl, %eax
; X32-NEXT: retl
;
; X64-LABEL: reg32_lshr_by_negated_unfolded_sub_b:
; X64: # %bb.0:
-; X64-NEXT: movl %esi, %ecx
+; X64-NEXT: # kill: def $edx killed $edx def $rdx
+; X64-NEXT: # kill: def $esi killed $esi def $rsi
; X64-NEXT: movl %edi, %eax
-; X64-NEXT: negl %ecx
-; X64-NEXT: subl %edx, %ecx
+; X64-NEXT: leal (%rsi,%rdx), %ecx
+; X64-NEXT: negb %cl
; X64-NEXT: # kill: def $cl killed $cl killed $ecx
; X64-NEXT: shrl %cl, %eax
; X64-NEXT: retq
; X32-NEXT: pushl %esi
; X32-NEXT: movl {{[0-9]+}}(%esp), %eax
; X32-NEXT: movl {{[0-9]+}}(%esp), %esi
-; X32-NEXT: xorl %ecx, %ecx
-; X32-NEXT: subl {{[0-9]+}}(%esp), %ecx
-; X32-NEXT: subl {{[0-9]+}}(%esp), %ecx
-; X32-NEXT: addb $64, %cl
+; X32-NEXT: movl {{[0-9]+}}(%esp), %edx
+; X32-NEXT: addl {{[0-9]+}}(%esp), %edx
+; X32-NEXT: movb $64, %cl
+; X32-NEXT: subb %dl, %cl
; X32-NEXT: movl %esi, %edx
; X32-NEXT: shrl %cl, %edx
; X32-NEXT: shrdl %cl, %esi, %eax
; X64-LABEL: reg64_lshr_by_negated_unfolded_sub_b:
; X64: # %bb.0:
; X64-NEXT: movq %rdi, %rax
-; X64-NEXT: movl $64, %ecx
-; X64-NEXT: subl %esi, %ecx
-; X64-NEXT: subl %edx, %ecx
+; X64-NEXT: leal (%rdx,%rsi), %ecx
+; X64-NEXT: negb %cl
; X64-NEXT: # kill: def $cl killed $cl killed $ecx
; X64-NEXT: shrq %cl, %rax
; X64-NEXT: retq
define i32 @sink_sub_from_const_to_sub(i32 %a, i32 %b) {
; X32-LABEL: sink_sub_from_const_to_sub:
; X32: # %bb.0:
+; X32-NEXT: movl {{[0-9]+}}(%esp), %ecx
+; X32-NEXT: addl {{[0-9]+}}(%esp), %ecx
; X32-NEXT: movl $32, %eax
-; X32-NEXT: subl {{[0-9]+}}(%esp), %eax
-; X32-NEXT: subl {{[0-9]+}}(%esp), %eax
+; X32-NEXT: subl %ecx, %eax
; X32-NEXT: retl
;
; X64-LABEL: sink_sub_from_const_to_sub:
; X64: # %bb.0:
+; X64-NEXT: addl %esi, %edi
; X64-NEXT: movl $32, %eax
; X64-NEXT: subl %edi, %eax
-; X64-NEXT: subl %esi, %eax
; X64-NEXT: retq
%t0 = sub i32 32, %a
%r = sub i32 %t0, %b
; ALL-LABEL: vec_sink_sub_from_const_to_sub:
; ALL: # %bb.0:
; ALL-NEXT: movdqa {{.*#+}} xmm2 = <42,24,u,46>
+; ALL-NEXT: paddd %xmm1, %xmm0
; ALL-NEXT: psubd %xmm0, %xmm2
-; ALL-NEXT: psubd %xmm1, %xmm2
; ALL-NEXT: movdqa %xmm2, %xmm0
; ALL-NEXT: ret{{[l|q]}}
%t0 = sub <4 x i32> <i32 42, i32 24, i32 undef, i32 46>, %a