Index: test/CodeGen/AArch64/demorgan-extra.ll =================================================================== --- /dev/null +++ test/CodeGen/AArch64/demorgan-extra.ll @@ -0,0 +1,494 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=aarch64-unknown-linux-gnu -o - %s | FileCheck %s + +; There is a identical twin test in test/Transforms/InstCombine/demorgan-extra.ll +; Please keep them in sync! :) + +declare void @use32(i32) +declare i32 @gen32() + +; ============================================================================ ; + +; ~(~A & B) --> (A | ~B) + +define i32 @demorgan_nand(i32 %A, i32 %B) nounwind { +; CHECK-LABEL: demorgan_nand: +; CHECK: // %bb.0: +; CHECK-NEXT: and w8, w0, w1 +; CHECK-NEXT: orn w0, w8, w1 +; CHECK-NEXT: ret + %notx = xor i32 %A, -1 + %c = and i32 %notx, %B + %notc = xor i32 %c, -1 + ret i32 %notc +} + +define i32 @demorgan_nand_const(i32 %A) nounwind { +; CHECK-LABEL: demorgan_nand_const: +; CHECK: // %bb.0: +; CHECK-NEXT: mov w8, #-43 +; CHECK-NEXT: orr w0, w0, w8 +; CHECK-NEXT: ret + %notx = xor i32 %A, -1 + %c = and i32 %notx, 42 + %notc = xor i32 %c, -1 + ret i32 %notc +} + +define <2 x i32> @demorgan_nand_vec(<2 x i32> %A, <2 x i32> %B) nounwind { +; CHECK-LABEL: demorgan_nand_vec: +; CHECK: // %bb.0: +; CHECK-NEXT: bic v0.8b, v1.8b, v0.8b +; CHECK-NEXT: mvn v0.8b, v0.8b +; CHECK-NEXT: ret + %notx = xor <2 x i32> %A, + %c = and <2 x i32> %notx, %B + %notc = xor <2 x i32> %c, + ret <2 x i32> %notc +} + +define <3 x i32> @demorgan_nand_vec_undef(<3 x i32> %A, <3 x i32> %B) nounwind { +; CHECK-LABEL: demorgan_nand_vec_undef: +; CHECK: // %bb.0: +; CHECK-NEXT: bic v0.16b, v1.16b, v0.16b +; CHECK-NEXT: mvn v0.16b, v0.16b +; CHECK-NEXT: ret + %notx = xor <3 x i32> %A, + %c = and <3 x i32> %notx, %B + %notc = xor <3 x i32> %c, + ret <3 x i32> %notc +} + +define <2 x i32> @demorgan_nand_vec_splatconst(<2 x i32> %A) nounwind { +; CHECK-LABEL: demorgan_nand_vec_splatconst: +; CHECK: // %bb.0: +; CHECK-NEXT: movi v1.2s, #42 +; CHECK-NEXT: bic v0.8b, v1.8b, v0.8b +; CHECK-NEXT: mvn v0.8b, v0.8b +; CHECK-NEXT: ret + %notx = xor <2 x i32> %A, + %c = and <2 x i32> %notx, + %notc = xor <2 x i32> %c, + ret <2 x i32> %notc +} + +define <3 x i32> @demorgan_nand_vec_const_undef(<3 x i32> %A) nounwind { +; CHECK-LABEL: demorgan_nand_vec_const_undef: +; CHECK: // %bb.0: +; CHECK-NEXT: movi v1.4s, #42 +; CHECK-NEXT: bic v0.16b, v1.16b, v0.16b +; CHECK-NEXT: mvn v0.16b, v0.16b +; CHECK-NEXT: ret + %notx = xor <3 x i32> %A, + %c = and <3 x i32> %notx, + %notc = xor <3 x i32> %c, + ret <3 x i32> %notc +} + +define <2 x i32> @demorgan_nand_vec_const(<2 x i32> %A) nounwind { +; CHECK-LABEL: demorgan_nand_vec_const: +; CHECK: // %bb.0: +; CHECK-NEXT: adrp x8, .LCPI6_0 +; CHECK-NEXT: ldr d1, [x8, :lo12:.LCPI6_0] +; CHECK-NEXT: bic v0.8b, v1.8b, v0.8b +; CHECK-NEXT: mvn v0.8b, v0.8b +; CHECK-NEXT: ret + %notx = xor <2 x i32> %A, + %c = and <2 x i32> %notx, + %notc = xor <2 x i32> %c, + ret <2 x i32> %notc +} + +define <4 x i32> @demorgan_nand_vec_128bit(<4 x i32> %A, <4 x i32> %B) nounwind { +; CHECK-LABEL: demorgan_nand_vec_128bit: +; CHECK: // %bb.0: +; CHECK-NEXT: bic v0.16b, v1.16b, v0.16b +; CHECK-NEXT: mvn v0.16b, v0.16b +; CHECK-NEXT: ret + %notx = xor <4 x i32> %A, + %c = and <4 x i32> %notx, %B + %notc = xor <4 x i32> %c, + ret <4 x i32> %notc +} + +define <4 x i32> @demorgan_nand_vec_128bit_undef(<4 x i32> %A, <4 x i32> %B) nounwind { +; CHECK-LABEL: demorgan_nand_vec_128bit_undef: +; CHECK: // %bb.0: +; CHECK-NEXT: bic v0.16b, v1.16b, v0.16b +; CHECK-NEXT: mvn v0.16b, v0.16b +; CHECK-NEXT: ret + %notx = xor <4 x i32> %A, + %c = and <4 x i32> %notx, %B + %notc = xor <4 x i32> %c, + ret <4 x i32> %notc +} + +define i32 @demorgan_nand_commutative(i32 %A) nounwind { +; CHECK-LABEL: demorgan_nand_commutative: +; CHECK: // %bb.0: +; CHECK-NEXT: stp x19, x30, [sp, #-16]! // 8-byte Folded Spill +; CHECK-NEXT: mov w19, w0 +; CHECK-NEXT: bl gen32 +; CHECK-NEXT: and w8, w19, w0 +; CHECK-NEXT: orn w0, w8, w0 +; CHECK-NEXT: ldp x19, x30, [sp], #16 // 8-byte Folded Reload +; CHECK-NEXT: ret + %B = call i32 @gen32() + %notx = xor i32 %A, -1 + %c = and i32 %B, %notx ; swapped + %notc = xor i32 %c, -1 + ret i32 %notc +} + +define i32 @demorgan_nand_extraxor(i32 %A) nounwind { +; CHECK-LABEL: demorgan_nand_extraxor: +; CHECK: // %bb.0: +; CHECK-NEXT: str x20, [sp, #-32]! // 8-byte Folded Spill +; CHECK-NEXT: stp x19, x30, [sp, #16] // 8-byte Folded Spill +; CHECK-NEXT: mov w19, w0 +; CHECK-NEXT: bl gen32 +; CHECK-NEXT: mov w20, w0 +; CHECK-NEXT: bl gen32 +; CHECK-NEXT: eor w8, w20, w0 +; CHECK-NEXT: and w9, w19, w8 +; CHECK-NEXT: ldp x19, x30, [sp, #16] // 8-byte Folded Reload +; CHECK-NEXT: orn w0, w9, w8 +; CHECK-NEXT: ldr x20, [sp], #32 // 8-byte Folded Reload +; CHECK-NEXT: ret + %V = call i32 @gen32() + %Z = call i32 @gen32() + %B = xor i32 %V, %Z ; not with -1 + %notx = xor i32 %A, -1 + %c = and i32 %notx, %B + %notc = xor i32 %c, -1 + ret i32 %notc +} + +define i32 @demorgan_nand_extraxor_commutative(i32 %A) nounwind { +; CHECK-LABEL: demorgan_nand_extraxor_commutative: +; CHECK: // %bb.0: +; CHECK-NEXT: str x20, [sp, #-32]! // 8-byte Folded Spill +; CHECK-NEXT: stp x19, x30, [sp, #16] // 8-byte Folded Spill +; CHECK-NEXT: mov w19, w0 +; CHECK-NEXT: bl gen32 +; CHECK-NEXT: mov w20, w0 +; CHECK-NEXT: bl gen32 +; CHECK-NEXT: eor w8, w20, w0 +; CHECK-NEXT: and w9, w19, w8 +; CHECK-NEXT: ldp x19, x30, [sp, #16] // 8-byte Folded Reload +; CHECK-NEXT: orn w0, w9, w8 +; CHECK-NEXT: ldr x20, [sp], #32 // 8-byte Folded Reload +; CHECK-NEXT: ret + %V = call i32 @gen32() + %Z = call i32 @gen32() + %B = xor i32 %V, %Z ; not with -1 + %notx = xor i32 %A, -1 + %c = and i32 %B, %notx ; swapped + %notc = xor i32 %c, -1 + ret i32 %notc +} + +define i32 @demorgan_nand_badxor0(i32 %A, i32 %B) nounwind { +; CHECK-LABEL: demorgan_nand_badxor0: +; CHECK: // %bb.0: +; CHECK-NEXT: eor w8, w0, #0x1 +; CHECK-NEXT: and w8, w8, w1 +; CHECK-NEXT: mvn w0, w8 +; CHECK-NEXT: ret + %notx = xor i32 %A, 1 ; not -1 + %c = and i32 %notx, %B + %notc = xor i32 %c, -1 + ret i32 %notc +} + +define i32 @demorgan_nand_badxor1(i32 %A, i32 %B) nounwind { +; CHECK-LABEL: demorgan_nand_badxor1: +; CHECK: // %bb.0: +; CHECK-NEXT: bic w8, w1, w0 +; CHECK-NEXT: eor w0, w8, #0x1 +; CHECK-NEXT: ret + %notx = xor i32 %A, -1 + %c = and i32 %notx, %B + %notc = xor i32 %c, 1 ; not -1 + ret i32 %notc +} + +define i32 @demorgan_nand_oneuse0(i32 %A, i32 %B) nounwind { +; CHECK-LABEL: demorgan_nand_oneuse0: +; CHECK: // %bb.0: +; CHECK-NEXT: stp x19, x30, [sp, #-16]! // 8-byte Folded Spill +; CHECK-NEXT: mvn w8, w0 +; CHECK-NEXT: bic w9, w1, w0 +; CHECK-NEXT: mov w0, w8 +; CHECK-NEXT: mvn w19, w9 +; CHECK-NEXT: bl use32 +; CHECK-NEXT: mov w0, w19 +; CHECK-NEXT: ldp x19, x30, [sp], #16 // 8-byte Folded Reload +; CHECK-NEXT: ret + %notx = xor i32 %A, -1 + %c = and i32 %notx, %B + %notc = xor i32 %c, -1 + call void @use32(i32 %notx) + ret i32 %notc +} + +define i32 @demorgan_nand_oneuse1(i32 %A, i32 %B) nounwind { +; CHECK-LABEL: demorgan_nand_oneuse1: +; CHECK: // %bb.0: +; CHECK-NEXT: stp x19, x30, [sp, #-16]! // 8-byte Folded Spill +; CHECK-NEXT: bic w0, w1, w0 +; CHECK-NEXT: mvn w19, w0 +; CHECK-NEXT: bl use32 +; CHECK-NEXT: mov w0, w19 +; CHECK-NEXT: ldp x19, x30, [sp], #16 // 8-byte Folded Reload +; CHECK-NEXT: ret + %notx = xor i32 %A, -1 + %c = and i32 %notx, %B + %notc = xor i32 %c, -1 + call void @use32(i32 %c) + ret i32 %notc +} + +; ============================================================================ ; + +; ~(~A | B) --> (A & ~B) + +define i32 @demorgan_nor(i32 %A, i32 %B) nounwind { +; CHECK-LABEL: demorgan_nor: +; CHECK: // %bb.0: +; CHECK-NEXT: orn w8, w1, w0 +; CHECK-NEXT: mvn w0, w8 +; CHECK-NEXT: ret + %notx = xor i32 %A, -1 + %c = or i32 %notx, %B + %notc = xor i32 %c, -1 + ret i32 %notc +} + +define i32 @demorgan_nor_const(i32 %A) nounwind { +; CHECK-LABEL: demorgan_nor_const: +; CHECK: // %bb.0: +; CHECK-NEXT: mov w8, #-43 +; CHECK-NEXT: and w0, w0, w8 +; CHECK-NEXT: ret + %notx = xor i32 %A, -1 + %c = or i32 %notx, 42 + %notc = xor i32 %c, -1 + ret i32 %notc +} + +define <2 x i32> @demorgan_nor_vec(<2 x i32> %A, <2 x i32> %B) nounwind { +; CHECK-LABEL: demorgan_nor_vec: +; CHECK: // %bb.0: +; CHECK-NEXT: orn v0.8b, v1.8b, v0.8b +; CHECK-NEXT: mvn v0.8b, v0.8b +; CHECK-NEXT: ret + %notx = xor <2 x i32> %A, + %c = or <2 x i32> %notx, %B + %notc = xor <2 x i32> %c, + ret <2 x i32> %notc +} + +define <3 x i32> @demorgan_nor_vec_undef(<3 x i32> %A, <3 x i32> %B) nounwind { +; CHECK-LABEL: demorgan_nor_vec_undef: +; CHECK: // %bb.0: +; CHECK-NEXT: orn v0.16b, v1.16b, v0.16b +; CHECK-NEXT: mvn v0.16b, v0.16b +; CHECK-NEXT: ret + %notx = xor <3 x i32> %A, + %c = or <3 x i32> %notx, %B + %notc = xor <3 x i32> %c, + ret <3 x i32> %notc +} + +define <2 x i32> @demorgan_nor_vec_splatconst(<2 x i32> %A) nounwind { +; CHECK-LABEL: demorgan_nor_vec_splatconst: +; CHECK: // %bb.0: +; CHECK-NEXT: mvn v0.8b, v0.8b +; CHECK-NEXT: orr v0.2s, #42 +; CHECK-NEXT: mvn v0.8b, v0.8b +; CHECK-NEXT: ret + %notx = xor <2 x i32> %A, + %c = or <2 x i32> %notx, + %notc = xor <2 x i32> %c, + ret <2 x i32> %notc +} + +define <3 x i32> @demorgan_nor_vec_const_undef(<3 x i32> %A) nounwind { +; CHECK-LABEL: demorgan_nor_vec_const_undef: +; CHECK: // %bb.0: +; CHECK-NEXT: mvn v0.16b, v0.16b +; CHECK-NEXT: orr v0.4s, #42 +; CHECK-NEXT: mvn v0.16b, v0.16b +; CHECK-NEXT: ret + %notx = xor <3 x i32> %A, + %c = or <3 x i32> %notx, + %notc = xor <3 x i32> %c, + ret <3 x i32> %notc +} + +define <2 x i32> @demorgan_nor_vec_const(<2 x i32> %A) nounwind { +; CHECK-LABEL: demorgan_nor_vec_const: +; CHECK: // %bb.0: +; CHECK-NEXT: adrp x8, .LCPI22_0 +; CHECK-NEXT: ldr d1, [x8, :lo12:.LCPI22_0] +; CHECK-NEXT: orn v0.8b, v1.8b, v0.8b +; CHECK-NEXT: mvn v0.8b, v0.8b +; CHECK-NEXT: ret + %notx = xor <2 x i32> %A, + %c = or <2 x i32> %notx, + %notc = xor <2 x i32> %c, + ret <2 x i32> %notc +} + +define <4 x i32> @demorgan_nor_vec_128bit(<4 x i32> %A, <4 x i32> %B) nounwind { +; CHECK-LABEL: demorgan_nor_vec_128bit: +; CHECK: // %bb.0: +; CHECK-NEXT: orn v0.16b, v1.16b, v0.16b +; CHECK-NEXT: mvn v0.16b, v0.16b +; CHECK-NEXT: ret + %notx = xor <4 x i32> %A, + %c = or <4 x i32> %notx, %B + %notc = xor <4 x i32> %c, + ret <4 x i32> %notc +} + +define <4 x i32> @demorgan_nor_vec_128bit_undef(<4 x i32> %A, <4 x i32> %B) nounwind { +; CHECK-LABEL: demorgan_nor_vec_128bit_undef: +; CHECK: // %bb.0: +; CHECK-NEXT: orn v0.16b, v1.16b, v0.16b +; CHECK-NEXT: mvn v0.16b, v0.16b +; CHECK-NEXT: ret + %notx = xor <4 x i32> %A, + %c = or <4 x i32> %notx, %B + %notc = xor <4 x i32> %c, + ret <4 x i32> %notc +} + +define i32 @demorgan_nor_commutative(i32 %A) nounwind { +; CHECK-LABEL: demorgan_nor_commutative: +; CHECK: // %bb.0: +; CHECK-NEXT: stp x19, x30, [sp, #-16]! // 8-byte Folded Spill +; CHECK-NEXT: mov w19, w0 +; CHECK-NEXT: bl gen32 +; CHECK-NEXT: orn w8, w0, w19 +; CHECK-NEXT: mvn w0, w8 +; CHECK-NEXT: ldp x19, x30, [sp], #16 // 8-byte Folded Reload +; CHECK-NEXT: ret + %B = call i32 @gen32() + %notx = xor i32 %A, -1 + %c = or i32 %B, %notx ; swapped + %notc = xor i32 %c, -1 + ret i32 %notc +} + +define i32 @demorgan_nor_extraxor(i32 %A) nounwind { +; CHECK-LABEL: demorgan_nor_extraxor: +; CHECK: // %bb.0: +; CHECK-NEXT: str x20, [sp, #-32]! // 8-byte Folded Spill +; CHECK-NEXT: stp x19, x30, [sp, #16] // 8-byte Folded Spill +; CHECK-NEXT: mov w19, w0 +; CHECK-NEXT: bl gen32 +; CHECK-NEXT: mov w20, w0 +; CHECK-NEXT: bl gen32 +; CHECK-NEXT: eor w8, w20, w0 +; CHECK-NEXT: orn w8, w8, w19 +; CHECK-NEXT: ldp x19, x30, [sp, #16] // 8-byte Folded Reload +; CHECK-NEXT: mvn w0, w8 +; CHECK-NEXT: ldr x20, [sp], #32 // 8-byte Folded Reload +; CHECK-NEXT: ret + %V = call i32 @gen32() + %Z = call i32 @gen32() + %B = xor i32 %V, %Z ; not with -1 + %notx = xor i32 %A, -1 + %c = or i32 %notx, %B + %notc = xor i32 %c, -1 + ret i32 %notc +} + +define i32 @demorgan_nor_extraxor_commutative(i32 %A) nounwind { +; CHECK-LABEL: demorgan_nor_extraxor_commutative: +; CHECK: // %bb.0: +; CHECK-NEXT: str x20, [sp, #-32]! // 8-byte Folded Spill +; CHECK-NEXT: stp x19, x30, [sp, #16] // 8-byte Folded Spill +; CHECK-NEXT: mov w19, w0 +; CHECK-NEXT: bl gen32 +; CHECK-NEXT: mov w20, w0 +; CHECK-NEXT: bl gen32 +; CHECK-NEXT: eor w8, w20, w0 +; CHECK-NEXT: orn w8, w8, w19 +; CHECK-NEXT: ldp x19, x30, [sp, #16] // 8-byte Folded Reload +; CHECK-NEXT: mvn w0, w8 +; CHECK-NEXT: ldr x20, [sp], #32 // 8-byte Folded Reload +; CHECK-NEXT: ret + %V = call i32 @gen32() + %Z = call i32 @gen32() + %B = xor i32 %V, %Z ; not with -1 + %notx = xor i32 %A, -1 + %c = or i32 %B, %notx ; swapped + %notc = xor i32 %c, -1 + ret i32 %notc +} + +define i32 @demorgan_nor_badxor0(i32 %A, i32 %B) nounwind { +; CHECK-LABEL: demorgan_nor_badxor0: +; CHECK: // %bb.0: +; CHECK-NEXT: eor w8, w0, #0x1 +; CHECK-NEXT: orr w8, w8, w1 +; CHECK-NEXT: mvn w0, w8 +; CHECK-NEXT: ret + %notx = xor i32 %A, 1 ; not -1 + %c = or i32 %notx, %B + %notc = xor i32 %c, -1 + ret i32 %notc +} + +define i32 @demorgan_nor_badxor1(i32 %A, i32 %B) nounwind { +; CHECK-LABEL: demorgan_nor_badxor1: +; CHECK: // %bb.0: +; CHECK-NEXT: orn w8, w1, w0 +; CHECK-NEXT: eor w0, w8, #0x1 +; CHECK-NEXT: ret + %notx = xor i32 %A, -1 + %c = or i32 %notx, %B + %notc = xor i32 %c, 1 ; not -1 + ret i32 %notc +} + +define i32 @demorgan_nor_oneuse0(i32 %A, i32 %B) nounwind { +; CHECK-LABEL: demorgan_nor_oneuse0: +; CHECK: // %bb.0: +; CHECK-NEXT: stp x19, x30, [sp, #-16]! // 8-byte Folded Spill +; CHECK-NEXT: mvn w8, w0 +; CHECK-NEXT: orn w9, w1, w0 +; CHECK-NEXT: mov w0, w8 +; CHECK-NEXT: mvn w19, w9 +; CHECK-NEXT: bl use32 +; CHECK-NEXT: mov w0, w19 +; CHECK-NEXT: ldp x19, x30, [sp], #16 // 8-byte Folded Reload +; CHECK-NEXT: ret + %notx = xor i32 %A, -1 + %c = or i32 %notx, %B + %notc = xor i32 %c, -1 + call void @use32(i32 %notx) + ret i32 %notc +} + +define i32 @demorgan_nor_oneuse1(i32 %A, i32 %B) nounwind { +; CHECK-LABEL: demorgan_nor_oneuse1: +; CHECK: // %bb.0: +; CHECK-NEXT: stp x19, x30, [sp, #-16]! // 8-byte Folded Spill +; CHECK-NEXT: orn w0, w1, w0 +; CHECK-NEXT: mvn w19, w0 +; CHECK-NEXT: bl use32 +; CHECK-NEXT: mov w0, w19 +; CHECK-NEXT: ldp x19, x30, [sp], #16 // 8-byte Folded Reload +; CHECK-NEXT: ret + %notx = xor i32 %A, -1 + %c = or i32 %notx, %B + %notc = xor i32 %c, -1 + call void @use32(i32 %c) + ret i32 %notc +} + +; ============================================================================ ; Index: test/CodeGen/X86/demorgan-extra.ll =================================================================== --- /dev/null +++ test/CodeGen/X86/demorgan-extra.ll @@ -0,0 +1,534 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=x86_64-unknown-linux-gnu -o - %s | FileCheck %s + +; There is a identical twin test in test/Transforms/InstCombine/demorgan-extra.ll +; Please keep them in sync! :) + +declare void @use32(i32) +declare i32 @gen32() + +; ============================================================================ ; + +; ~(~A & B) --> (A | ~B) + +define i32 @demorgan_nand(i32 %A, i32 %B) nounwind { +; CHECK-LABEL: demorgan_nand: +; CHECK: # %bb.0: +; CHECK-NEXT: notl %edi +; CHECK-NEXT: andl %esi, %edi +; CHECK-NEXT: notl %edi +; CHECK-NEXT: movl %edi, %eax +; CHECK-NEXT: retq + %notx = xor i32 %A, -1 + %c = and i32 %notx, %B + %notc = xor i32 %c, -1 + ret i32 %notc +} + +define i32 @demorgan_nand_const(i32 %A) nounwind { +; CHECK-LABEL: demorgan_nand_const: +; CHECK: # %bb.0: +; CHECK-NEXT: orl $-43, %edi +; CHECK-NEXT: movl %edi, %eax +; CHECK-NEXT: retq + %notx = xor i32 %A, -1 + %c = and i32 %notx, 42 + %notc = xor i32 %c, -1 + ret i32 %notc +} + +define <2 x i32> @demorgan_nand_vec(<2 x i32> %A, <2 x i32> %B) nounwind { +; CHECK-LABEL: demorgan_nand_vec: +; CHECK: # %bb.0: +; CHECK-NEXT: movaps {{.*#+}} xmm2 = [4294967295,4294967295] +; CHECK-NEXT: xorps %xmm2, %xmm0 +; CHECK-NEXT: andps %xmm1, %xmm0 +; CHECK-NEXT: xorps %xmm2, %xmm0 +; CHECK-NEXT: retq + %notx = xor <2 x i32> %A, + %c = and <2 x i32> %notx, %B + %notc = xor <2 x i32> %c, + ret <2 x i32> %notc +} + +define <3 x i32> @demorgan_nand_vec_undef(<3 x i32> %A, <3 x i32> %B) nounwind { +; CHECK-LABEL: demorgan_nand_vec_undef: +; CHECK: # %bb.0: +; CHECK-NEXT: pcmpeqd %xmm2, %xmm2 +; CHECK-NEXT: pandn %xmm1, %xmm0 +; CHECK-NEXT: pxor %xmm2, %xmm0 +; CHECK-NEXT: retq + %notx = xor <3 x i32> %A, + %c = and <3 x i32> %notx, %B + %notc = xor <3 x i32> %c, + ret <3 x i32> %notc +} + +define <2 x i32> @demorgan_nand_vec_splatconst(<2 x i32> %A) nounwind { +; CHECK-LABEL: demorgan_nand_vec_splatconst: +; CHECK: # %bb.0: +; CHECK-NEXT: andnps {{.*}}(%rip), %xmm0 +; CHECK-NEXT: xorps {{.*}}(%rip), %xmm0 +; CHECK-NEXT: retq + %notx = xor <2 x i32> %A, + %c = and <2 x i32> %notx, + %notc = xor <2 x i32> %c, + ret <2 x i32> %notc +} + +define <3 x i32> @demorgan_nand_vec_const_undef(<3 x i32> %A) nounwind { +; CHECK-LABEL: demorgan_nand_vec_const_undef: +; CHECK: # %bb.0: +; CHECK-NEXT: pcmpeqd %xmm1, %xmm1 +; CHECK-NEXT: pandn {{.*}}(%rip), %xmm0 +; CHECK-NEXT: pxor %xmm1, %xmm0 +; CHECK-NEXT: retq + %notx = xor <3 x i32> %A, + %c = and <3 x i32> %notx, + %notc = xor <3 x i32> %c, + ret <3 x i32> %notc +} + +define <2 x i32> @demorgan_nand_vec_const(<2 x i32> %A) nounwind { +; CHECK-LABEL: demorgan_nand_vec_const: +; CHECK: # %bb.0: +; CHECK-NEXT: andnps {{.*}}(%rip), %xmm0 +; CHECK-NEXT: xorps {{.*}}(%rip), %xmm0 +; CHECK-NEXT: retq + %notx = xor <2 x i32> %A, + %c = and <2 x i32> %notx, + %notc = xor <2 x i32> %c, + ret <2 x i32> %notc +} + +define <4 x i32> @demorgan_nand_vec_128bit(<4 x i32> %A, <4 x i32> %B) nounwind { +; CHECK-LABEL: demorgan_nand_vec_128bit: +; CHECK: # %bb.0: +; CHECK-NEXT: pcmpeqd %xmm2, %xmm2 +; CHECK-NEXT: pandn %xmm1, %xmm0 +; CHECK-NEXT: pxor %xmm2, %xmm0 +; CHECK-NEXT: retq + %notx = xor <4 x i32> %A, + %c = and <4 x i32> %notx, %B + %notc = xor <4 x i32> %c, + ret <4 x i32> %notc +} + +define <4 x i32> @demorgan_nand_vec_128bit_undef(<4 x i32> %A, <4 x i32> %B) nounwind { +; CHECK-LABEL: demorgan_nand_vec_128bit_undef: +; CHECK: # %bb.0: +; CHECK-NEXT: pcmpeqd %xmm2, %xmm2 +; CHECK-NEXT: pandn %xmm1, %xmm0 +; CHECK-NEXT: pxor %xmm2, %xmm0 +; CHECK-NEXT: retq + %notx = xor <4 x i32> %A, + %c = and <4 x i32> %notx, %B + %notc = xor <4 x i32> %c, + ret <4 x i32> %notc +} + +define i32 @demorgan_nand_commutative(i32 %A) nounwind { +; CHECK-LABEL: demorgan_nand_commutative: +; CHECK: # %bb.0: +; CHECK-NEXT: pushq %rbx +; CHECK-NEXT: movl %edi, %ebx +; CHECK-NEXT: callq gen32 +; CHECK-NEXT: notl %ebx +; CHECK-NEXT: andl %ebx, %eax +; CHECK-NEXT: notl %eax +; CHECK-NEXT: popq %rbx +; CHECK-NEXT: retq + %B = call i32 @gen32() + %notx = xor i32 %A, -1 + %c = and i32 %B, %notx ; swapped + %notc = xor i32 %c, -1 + ret i32 %notc +} + +define i32 @demorgan_nand_extraxor(i32 %A) nounwind { +; CHECK-LABEL: demorgan_nand_extraxor: +; CHECK: # %bb.0: +; CHECK-NEXT: pushq %rbp +; CHECK-NEXT: pushq %rbx +; CHECK-NEXT: pushq %rax +; CHECK-NEXT: movl %edi, %ebx +; CHECK-NEXT: callq gen32 +; CHECK-NEXT: movl %eax, %ebp +; CHECK-NEXT: callq gen32 +; CHECK-NEXT: xorl %ebp, %eax +; CHECK-NEXT: notl %ebx +; CHECK-NEXT: andl %ebx, %eax +; CHECK-NEXT: notl %eax +; CHECK-NEXT: addq $8, %rsp +; CHECK-NEXT: popq %rbx +; CHECK-NEXT: popq %rbp +; CHECK-NEXT: retq + %V = call i32 @gen32() + %Z = call i32 @gen32() + %B = xor i32 %V, %Z ; not with -1 + %notx = xor i32 %A, -1 + %c = and i32 %notx, %B + %notc = xor i32 %c, -1 + ret i32 %notc +} + +define i32 @demorgan_nand_extraxor_commutative(i32 %A) nounwind { +; CHECK-LABEL: demorgan_nand_extraxor_commutative: +; CHECK: # %bb.0: +; CHECK-NEXT: pushq %rbp +; CHECK-NEXT: pushq %rbx +; CHECK-NEXT: pushq %rax +; CHECK-NEXT: movl %edi, %ebx +; CHECK-NEXT: callq gen32 +; CHECK-NEXT: movl %eax, %ebp +; CHECK-NEXT: callq gen32 +; CHECK-NEXT: xorl %ebp, %eax +; CHECK-NEXT: notl %ebx +; CHECK-NEXT: andl %ebx, %eax +; CHECK-NEXT: notl %eax +; CHECK-NEXT: addq $8, %rsp +; CHECK-NEXT: popq %rbx +; CHECK-NEXT: popq %rbp +; CHECK-NEXT: retq + %V = call i32 @gen32() + %Z = call i32 @gen32() + %B = xor i32 %V, %Z ; not with -1 + %notx = xor i32 %A, -1 + %c = and i32 %B, %notx ; swapped + %notc = xor i32 %c, -1 + ret i32 %notc +} + +define i32 @demorgan_nand_badxor0(i32 %A, i32 %B) nounwind { +; CHECK-LABEL: demorgan_nand_badxor0: +; CHECK: # %bb.0: +; CHECK-NEXT: xorl $1, %edi +; CHECK-NEXT: andl %esi, %edi +; CHECK-NEXT: notl %edi +; CHECK-NEXT: movl %edi, %eax +; CHECK-NEXT: retq + %notx = xor i32 %A, 1 ; not -1 + %c = and i32 %notx, %B + %notc = xor i32 %c, -1 + ret i32 %notc +} + +define i32 @demorgan_nand_badxor1(i32 %A, i32 %B) nounwind { +; CHECK-LABEL: demorgan_nand_badxor1: +; CHECK: # %bb.0: +; CHECK-NEXT: notl %edi +; CHECK-NEXT: andl %esi, %edi +; CHECK-NEXT: xorl $1, %edi +; CHECK-NEXT: movl %edi, %eax +; CHECK-NEXT: retq + %notx = xor i32 %A, -1 + %c = and i32 %notx, %B + %notc = xor i32 %c, 1 ; not -1 + ret i32 %notc +} + +define i32 @demorgan_nand_oneuse0(i32 %A, i32 %B) nounwind { +; CHECK-LABEL: demorgan_nand_oneuse0: +; CHECK: # %bb.0: +; CHECK-NEXT: pushq %rbx +; CHECK-NEXT: movl %esi, %ebx +; CHECK-NEXT: notl %edi +; CHECK-NEXT: andl %edi, %ebx +; CHECK-NEXT: notl %ebx +; CHECK-NEXT: callq use32 +; CHECK-NEXT: movl %ebx, %eax +; CHECK-NEXT: popq %rbx +; CHECK-NEXT: retq + %notx = xor i32 %A, -1 + %c = and i32 %notx, %B + %notc = xor i32 %c, -1 + call void @use32(i32 %notx) + ret i32 %notc +} + +define i32 @demorgan_nand_oneuse1(i32 %A, i32 %B) nounwind { +; CHECK-LABEL: demorgan_nand_oneuse1: +; CHECK: # %bb.0: +; CHECK-NEXT: pushq %rbx +; CHECK-NEXT: notl %edi +; CHECK-NEXT: andl %esi, %edi +; CHECK-NEXT: movl %edi, %ebx +; CHECK-NEXT: notl %ebx +; CHECK-NEXT: callq use32 +; CHECK-NEXT: movl %ebx, %eax +; CHECK-NEXT: popq %rbx +; CHECK-NEXT: retq + %notx = xor i32 %A, -1 + %c = and i32 %notx, %B + %notc = xor i32 %c, -1 + call void @use32(i32 %c) + ret i32 %notc +} + +; ============================================================================ ; + +; ~(~A | B) --> (A & ~B) + +define i32 @demorgan_nor(i32 %A, i32 %B) nounwind { +; CHECK-LABEL: demorgan_nor: +; CHECK: # %bb.0: +; CHECK-NEXT: notl %edi +; CHECK-NEXT: orl %esi, %edi +; CHECK-NEXT: notl %edi +; CHECK-NEXT: movl %edi, %eax +; CHECK-NEXT: retq + %notx = xor i32 %A, -1 + %c = or i32 %notx, %B + %notc = xor i32 %c, -1 + ret i32 %notc +} + +define i32 @demorgan_nor_const(i32 %A) nounwind { +; CHECK-LABEL: demorgan_nor_const: +; CHECK: # %bb.0: +; CHECK-NEXT: andl $-43, %edi +; CHECK-NEXT: movl %edi, %eax +; CHECK-NEXT: retq + %notx = xor i32 %A, -1 + %c = or i32 %notx, 42 + %notc = xor i32 %c, -1 + ret i32 %notc +} + +define <2 x i32> @demorgan_nor_vec(<2 x i32> %A, <2 x i32> %B) nounwind { +; CHECK-LABEL: demorgan_nor_vec: +; CHECK: # %bb.0: +; CHECK-NEXT: movaps {{.*#+}} xmm2 = [4294967295,4294967295] +; CHECK-NEXT: xorps %xmm2, %xmm0 +; CHECK-NEXT: orps %xmm1, %xmm0 +; CHECK-NEXT: xorps %xmm2, %xmm0 +; CHECK-NEXT: retq + %notx = xor <2 x i32> %A, + %c = or <2 x i32> %notx, %B + %notc = xor <2 x i32> %c, + ret <2 x i32> %notc +} + +define <3 x i32> @demorgan_nor_vec_undef(<3 x i32> %A, <3 x i32> %B) nounwind { +; CHECK-LABEL: demorgan_nor_vec_undef: +; CHECK: # %bb.0: +; CHECK-NEXT: pcmpeqd %xmm2, %xmm2 +; CHECK-NEXT: pxor %xmm2, %xmm0 +; CHECK-NEXT: por %xmm1, %xmm0 +; CHECK-NEXT: pxor %xmm2, %xmm0 +; CHECK-NEXT: retq + %notx = xor <3 x i32> %A, + %c = or <3 x i32> %notx, %B + %notc = xor <3 x i32> %c, + ret <3 x i32> %notc +} + +define <2 x i32> @demorgan_nor_vec_splatconst(<2 x i32> %A) nounwind { +; CHECK-LABEL: demorgan_nor_vec_splatconst: +; CHECK: # %bb.0: +; CHECK-NEXT: movaps {{.*#+}} xmm1 = [4294967295,4294967295] +; CHECK-NEXT: xorps %xmm1, %xmm0 +; CHECK-NEXT: orps {{.*}}(%rip), %xmm0 +; CHECK-NEXT: xorps %xmm1, %xmm0 +; CHECK-NEXT: retq + %notx = xor <2 x i32> %A, + %c = or <2 x i32> %notx, + %notc = xor <2 x i32> %c, + ret <2 x i32> %notc +} + +define <3 x i32> @demorgan_nor_vec_const_undef(<3 x i32> %A) nounwind { +; CHECK-LABEL: demorgan_nor_vec_const_undef: +; CHECK: # %bb.0: +; CHECK-NEXT: pcmpeqd %xmm1, %xmm1 +; CHECK-NEXT: pxor %xmm1, %xmm0 +; CHECK-NEXT: por {{.*}}(%rip), %xmm0 +; CHECK-NEXT: pxor %xmm1, %xmm0 +; CHECK-NEXT: retq + %notx = xor <3 x i32> %A, + %c = or <3 x i32> %notx, + %notc = xor <3 x i32> %c, + ret <3 x i32> %notc +} + +define <2 x i32> @demorgan_nor_vec_const(<2 x i32> %A) nounwind { +; CHECK-LABEL: demorgan_nor_vec_const: +; CHECK: # %bb.0: +; CHECK-NEXT: movaps {{.*#+}} xmm1 = [4294967295,4294967295] +; CHECK-NEXT: xorps %xmm1, %xmm0 +; CHECK-NEXT: orps {{.*}}(%rip), %xmm0 +; CHECK-NEXT: xorps %xmm1, %xmm0 +; CHECK-NEXT: retq + %notx = xor <2 x i32> %A, + %c = or <2 x i32> %notx, + %notc = xor <2 x i32> %c, + ret <2 x i32> %notc +} + +define <4 x i32> @demorgan_nor_vec_128bit(<4 x i32> %A, <4 x i32> %B) nounwind { +; CHECK-LABEL: demorgan_nor_vec_128bit: +; CHECK: # %bb.0: +; CHECK-NEXT: pcmpeqd %xmm2, %xmm2 +; CHECK-NEXT: pxor %xmm2, %xmm0 +; CHECK-NEXT: por %xmm1, %xmm0 +; CHECK-NEXT: pxor %xmm2, %xmm0 +; CHECK-NEXT: retq + %notx = xor <4 x i32> %A, + %c = or <4 x i32> %notx, %B + %notc = xor <4 x i32> %c, + ret <4 x i32> %notc +} + +define <4 x i32> @demorgan_nor_vec_128bit_undef(<4 x i32> %A, <4 x i32> %B) nounwind { +; CHECK-LABEL: demorgan_nor_vec_128bit_undef: +; CHECK: # %bb.0: +; CHECK-NEXT: pcmpeqd %xmm2, %xmm2 +; CHECK-NEXT: pxor %xmm2, %xmm0 +; CHECK-NEXT: por %xmm1, %xmm0 +; CHECK-NEXT: pxor %xmm2, %xmm0 +; CHECK-NEXT: retq + %notx = xor <4 x i32> %A, + %c = or <4 x i32> %notx, %B + %notc = xor <4 x i32> %c, + ret <4 x i32> %notc +} + +define i32 @demorgan_nor_commutative(i32 %A) nounwind { +; CHECK-LABEL: demorgan_nor_commutative: +; CHECK: # %bb.0: +; CHECK-NEXT: pushq %rbx +; CHECK-NEXT: movl %edi, %ebx +; CHECK-NEXT: callq gen32 +; CHECK-NEXT: notl %ebx +; CHECK-NEXT: orl %ebx, %eax +; CHECK-NEXT: notl %eax +; CHECK-NEXT: popq %rbx +; CHECK-NEXT: retq + %B = call i32 @gen32() + %notx = xor i32 %A, -1 + %c = or i32 %B, %notx ; swapped + %notc = xor i32 %c, -1 + ret i32 %notc +} + +define i32 @demorgan_nor_extraxor(i32 %A) nounwind { +; CHECK-LABEL: demorgan_nor_extraxor: +; CHECK: # %bb.0: +; CHECK-NEXT: pushq %rbp +; CHECK-NEXT: pushq %rbx +; CHECK-NEXT: pushq %rax +; CHECK-NEXT: movl %edi, %ebx +; CHECK-NEXT: callq gen32 +; CHECK-NEXT: movl %eax, %ebp +; CHECK-NEXT: callq gen32 +; CHECK-NEXT: xorl %ebp, %eax +; CHECK-NEXT: notl %ebx +; CHECK-NEXT: orl %ebx, %eax +; CHECK-NEXT: notl %eax +; CHECK-NEXT: addq $8, %rsp +; CHECK-NEXT: popq %rbx +; CHECK-NEXT: popq %rbp +; CHECK-NEXT: retq + %V = call i32 @gen32() + %Z = call i32 @gen32() + %B = xor i32 %V, %Z ; not with -1 + %notx = xor i32 %A, -1 + %c = or i32 %notx, %B + %notc = xor i32 %c, -1 + ret i32 %notc +} + +define i32 @demorgan_nor_extraxor_commutative(i32 %A) nounwind { +; CHECK-LABEL: demorgan_nor_extraxor_commutative: +; CHECK: # %bb.0: +; CHECK-NEXT: pushq %rbp +; CHECK-NEXT: pushq %rbx +; CHECK-NEXT: pushq %rax +; CHECK-NEXT: movl %edi, %ebx +; CHECK-NEXT: callq gen32 +; CHECK-NEXT: movl %eax, %ebp +; CHECK-NEXT: callq gen32 +; CHECK-NEXT: xorl %ebp, %eax +; CHECK-NEXT: notl %ebx +; CHECK-NEXT: orl %ebx, %eax +; CHECK-NEXT: notl %eax +; CHECK-NEXT: addq $8, %rsp +; CHECK-NEXT: popq %rbx +; CHECK-NEXT: popq %rbp +; CHECK-NEXT: retq + %V = call i32 @gen32() + %Z = call i32 @gen32() + %B = xor i32 %V, %Z ; not with -1 + %notx = xor i32 %A, -1 + %c = or i32 %B, %notx ; swapped + %notc = xor i32 %c, -1 + ret i32 %notc +} + +define i32 @demorgan_nor_badxor0(i32 %A, i32 %B) nounwind { +; CHECK-LABEL: demorgan_nor_badxor0: +; CHECK: # %bb.0: +; CHECK-NEXT: xorl $1, %edi +; CHECK-NEXT: orl %esi, %edi +; CHECK-NEXT: notl %edi +; CHECK-NEXT: movl %edi, %eax +; CHECK-NEXT: retq + %notx = xor i32 %A, 1 ; not -1 + %c = or i32 %notx, %B + %notc = xor i32 %c, -1 + ret i32 %notc +} + +define i32 @demorgan_nor_badxor1(i32 %A, i32 %B) nounwind { +; CHECK-LABEL: demorgan_nor_badxor1: +; CHECK: # %bb.0: +; CHECK-NEXT: notl %edi +; CHECK-NEXT: orl %esi, %edi +; CHECK-NEXT: xorl $1, %edi +; CHECK-NEXT: movl %edi, %eax +; CHECK-NEXT: retq + %notx = xor i32 %A, -1 + %c = or i32 %notx, %B + %notc = xor i32 %c, 1 ; not -1 + ret i32 %notc +} + +define i32 @demorgan_nor_oneuse0(i32 %A, i32 %B) nounwind { +; CHECK-LABEL: demorgan_nor_oneuse0: +; CHECK: # %bb.0: +; CHECK-NEXT: pushq %rbx +; CHECK-NEXT: movl %esi, %ebx +; CHECK-NEXT: notl %edi +; CHECK-NEXT: orl %edi, %ebx +; CHECK-NEXT: notl %ebx +; CHECK-NEXT: callq use32 +; CHECK-NEXT: movl %ebx, %eax +; CHECK-NEXT: popq %rbx +; CHECK-NEXT: retq + %notx = xor i32 %A, -1 + %c = or i32 %notx, %B + %notc = xor i32 %c, -1 + call void @use32(i32 %notx) + ret i32 %notc +} + +define i32 @demorgan_nor_oneuse1(i32 %A, i32 %B) nounwind { +; CHECK-LABEL: demorgan_nor_oneuse1: +; CHECK: # %bb.0: +; CHECK-NEXT: pushq %rbx +; CHECK-NEXT: notl %edi +; CHECK-NEXT: orl %esi, %edi +; CHECK-NEXT: movl %edi, %ebx +; CHECK-NEXT: notl %ebx +; CHECK-NEXT: callq use32 +; CHECK-NEXT: movl %ebx, %eax +; CHECK-NEXT: popq %rbx +; CHECK-NEXT: retq + %notx = xor i32 %A, -1 + %c = or i32 %notx, %B + %notc = xor i32 %c, -1 + call void @use32(i32 %c) + ret i32 %notc +} + +; ============================================================================ ; Index: test/Transforms/InstCombine/demorgan-extra.ll =================================================================== --- /dev/null +++ test/Transforms/InstCombine/demorgan-extra.ll @@ -0,0 +1,442 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt < %s -instcombine -S | FileCheck %s + +; There is a identical twin test in test/CodeGen/{X86,AArch64}/demorgan-extra.ll +; Please keep them in sync! :) + +declare void @use32(i32) +declare i32 @gen32() + +; ============================================================================ ; + +; ~(~A & B) --> (A | ~B) + +define i32 @demorgan_nand(i32 %A, i32 %B) nounwind { +; CHECK-LABEL: @demorgan_nand( +; CHECK-NEXT: [[B_NOT:%.*]] = xor i32 [[B:%.*]], -1 +; CHECK-NEXT: [[NOTC:%.*]] = or i32 [[B_NOT]], [[A:%.*]] +; CHECK-NEXT: ret i32 [[NOTC]] +; + %notx = xor i32 %A, -1 + %c = and i32 %notx, %B + %notc = xor i32 %c, -1 + ret i32 %notc +} + +define i32 @demorgan_nand_const(i32 %A) nounwind { +; CHECK-LABEL: @demorgan_nand_const( +; CHECK-NEXT: [[NOTC1:%.*]] = or i32 [[A:%.*]], -43 +; CHECK-NEXT: ret i32 [[NOTC1]] +; + %notx = xor i32 %A, -1 + %c = and i32 %notx, 42 + %notc = xor i32 %c, -1 + ret i32 %notc +} + +define <2 x i32> @demorgan_nand_vec(<2 x i32> %A, <2 x i32> %B) nounwind { +; CHECK-LABEL: @demorgan_nand_vec( +; CHECK-NEXT: [[B_NOT:%.*]] = xor <2 x i32> [[B:%.*]], +; CHECK-NEXT: [[NOTC:%.*]] = or <2 x i32> [[B_NOT]], [[A:%.*]] +; CHECK-NEXT: ret <2 x i32> [[NOTC]] +; + %notx = xor <2 x i32> %A, + %c = and <2 x i32> %notx, %B + %notc = xor <2 x i32> %c, + ret <2 x i32> %notc +} + +define <3 x i32> @demorgan_nand_vec_undef(<3 x i32> %A, <3 x i32> %B) nounwind { +; CHECK-LABEL: @demorgan_nand_vec_undef( +; CHECK-NEXT: [[B_NOT:%.*]] = xor <3 x i32> [[B:%.*]], +; CHECK-NEXT: [[NOTC:%.*]] = or <3 x i32> [[B_NOT]], [[A:%.*]] +; CHECK-NEXT: ret <3 x i32> [[NOTC]] +; + %notx = xor <3 x i32> %A, + %c = and <3 x i32> %notx, %B + %notc = xor <3 x i32> %c, + ret <3 x i32> %notc +} + +define <2 x i32> @demorgan_nand_vec_splatconst(<2 x i32> %A) nounwind { +; CHECK-LABEL: @demorgan_nand_vec_splatconst( +; CHECK-NEXT: [[NOTC1:%.*]] = or <2 x i32> [[A:%.*]], +; CHECK-NEXT: ret <2 x i32> [[NOTC1]] +; + %notx = xor <2 x i32> %A, + %c = and <2 x i32> %notx, + %notc = xor <2 x i32> %c, + ret <2 x i32> %notc +} + +define <3 x i32> @demorgan_nand_vec_const_undef(<3 x i32> %A) nounwind { +; CHECK-LABEL: @demorgan_nand_vec_const_undef( +; CHECK-NEXT: [[NOTC:%.*]] = or <3 x i32> [[A:%.*]], +; CHECK-NEXT: ret <3 x i32> [[NOTC]] +; + %notx = xor <3 x i32> %A, + %c = and <3 x i32> %notx, + %notc = xor <3 x i32> %c, + ret <3 x i32> %notc +} + +define <2 x i32> @demorgan_nand_vec_const(<2 x i32> %A) nounwind { +; CHECK-LABEL: @demorgan_nand_vec_const( +; CHECK-NEXT: [[NOTX:%.*]] = xor <2 x i32> [[A:%.*]], +; CHECK-NEXT: [[C:%.*]] = and <2 x i32> [[NOTX]], +; CHECK-NEXT: [[NOTC:%.*]] = xor <2 x i32> [[C]], +; CHECK-NEXT: ret <2 x i32> [[NOTC]] +; + %notx = xor <2 x i32> %A, + %c = and <2 x i32> %notx, + %notc = xor <2 x i32> %c, + ret <2 x i32> %notc +} + +define <4 x i32> @demorgan_nand_vec_128bit(<4 x i32> %A, <4 x i32> %B) nounwind { +; CHECK-LABEL: @demorgan_nand_vec_128bit( +; CHECK-NEXT: [[B_NOT:%.*]] = xor <4 x i32> [[B:%.*]], +; CHECK-NEXT: [[NOTC:%.*]] = or <4 x i32> [[B_NOT]], [[A:%.*]] +; CHECK-NEXT: ret <4 x i32> [[NOTC]] +; + %notx = xor <4 x i32> %A, + %c = and <4 x i32> %notx, %B + %notc = xor <4 x i32> %c, + ret <4 x i32> %notc +} + +define <4 x i32> @demorgan_nand_vec_128bit_undef(<4 x i32> %A, <4 x i32> %B) nounwind { +; CHECK-LABEL: @demorgan_nand_vec_128bit_undef( +; CHECK-NEXT: [[B_NOT:%.*]] = xor <4 x i32> [[B:%.*]], +; CHECK-NEXT: [[NOTC:%.*]] = or <4 x i32> [[B_NOT]], [[A:%.*]] +; CHECK-NEXT: ret <4 x i32> [[NOTC]] +; + %notx = xor <4 x i32> %A, + %c = and <4 x i32> %notx, %B + %notc = xor <4 x i32> %c, + ret <4 x i32> %notc +} + +define i32 @demorgan_nand_commutative(i32 %A) nounwind { +; CHECK-LABEL: @demorgan_nand_commutative( +; CHECK-NEXT: [[B:%.*]] = call i32 @gen32() #0 +; CHECK-NEXT: [[B_NOT:%.*]] = xor i32 [[B]], -1 +; CHECK-NEXT: [[NOTC:%.*]] = or i32 [[B_NOT]], [[A:%.*]] +; CHECK-NEXT: ret i32 [[NOTC]] +; + %B = call i32 @gen32() + %notx = xor i32 %A, -1 + %c = and i32 %B, %notx ; swapped + %notc = xor i32 %c, -1 + ret i32 %notc +} + +define i32 @demorgan_nand_extraxor(i32 %A) nounwind { +; CHECK-LABEL: @demorgan_nand_extraxor( +; CHECK-NEXT: [[V:%.*]] = call i32 @gen32() #0 +; CHECK-NEXT: [[Z:%.*]] = call i32 @gen32() #0 +; CHECK-NEXT: [[B:%.*]] = xor i32 [[V]], [[Z]] +; CHECK-NEXT: [[B_NOT:%.*]] = xor i32 [[B]], -1 +; CHECK-NEXT: [[NOTC:%.*]] = or i32 [[B_NOT]], [[A:%.*]] +; CHECK-NEXT: ret i32 [[NOTC]] +; + %V = call i32 @gen32() + %Z = call i32 @gen32() + %B = xor i32 %V, %Z ; not with -1 + %notx = xor i32 %A, -1 + %c = and i32 %notx, %B + %notc = xor i32 %c, -1 + ret i32 %notc +} + +define i32 @demorgan_nand_extraxor_commutative(i32 %A) nounwind { +; CHECK-LABEL: @demorgan_nand_extraxor_commutative( +; CHECK-NEXT: [[V:%.*]] = call i32 @gen32() #0 +; CHECK-NEXT: [[Z:%.*]] = call i32 @gen32() #0 +; CHECK-NEXT: [[B:%.*]] = xor i32 [[V]], [[Z]] +; CHECK-NEXT: [[B_NOT:%.*]] = xor i32 [[B]], -1 +; CHECK-NEXT: [[NOTC:%.*]] = or i32 [[B_NOT]], [[A:%.*]] +; CHECK-NEXT: ret i32 [[NOTC]] +; + %V = call i32 @gen32() + %Z = call i32 @gen32() + %B = xor i32 %V, %Z ; not with -1 + %notx = xor i32 %A, -1 + %c = and i32 %B, %notx ; swapped + %notc = xor i32 %c, -1 + ret i32 %notc +} + +define i32 @demorgan_nand_badxor0(i32 %A, i32 %B) nounwind { +; CHECK-LABEL: @demorgan_nand_badxor0( +; CHECK-NEXT: [[NOTX:%.*]] = xor i32 [[A:%.*]], 1 +; CHECK-NEXT: [[C:%.*]] = and i32 [[NOTX]], [[B:%.*]] +; CHECK-NEXT: [[NOTC:%.*]] = xor i32 [[C]], -1 +; CHECK-NEXT: ret i32 [[NOTC]] +; + %notx = xor i32 %A, 1 ; not -1 + %c = and i32 %notx, %B + %notc = xor i32 %c, -1 + ret i32 %notc +} + +define i32 @demorgan_nand_badxor1(i32 %A, i32 %B) nounwind { +; CHECK-LABEL: @demorgan_nand_badxor1( +; CHECK-NEXT: [[NOTX:%.*]] = xor i32 [[A:%.*]], -1 +; CHECK-NEXT: [[C:%.*]] = and i32 [[NOTX]], [[B:%.*]] +; CHECK-NEXT: [[NOTC:%.*]] = xor i32 [[C]], 1 +; CHECK-NEXT: ret i32 [[NOTC]] +; + %notx = xor i32 %A, -1 + %c = and i32 %notx, %B + %notc = xor i32 %c, 1 ; not -1 + ret i32 %notc +} + +define i32 @demorgan_nand_oneuse0(i32 %A, i32 %B) nounwind { +; CHECK-LABEL: @demorgan_nand_oneuse0( +; CHECK-NEXT: [[NOTX:%.*]] = xor i32 [[A:%.*]], -1 +; CHECK-NEXT: [[B_NOT:%.*]] = xor i32 [[B:%.*]], -1 +; CHECK-NEXT: [[NOTC:%.*]] = or i32 [[B_NOT]], [[A]] +; CHECK-NEXT: call void @use32(i32 [[NOTX]]) #0 +; CHECK-NEXT: ret i32 [[NOTC]] +; + %notx = xor i32 %A, -1 + %c = and i32 %notx, %B + %notc = xor i32 %c, -1 + call void @use32(i32 %notx) + ret i32 %notc +} + +define i32 @demorgan_nand_oneuse1(i32 %A, i32 %B) nounwind { +; CHECK-LABEL: @demorgan_nand_oneuse1( +; CHECK-NEXT: [[NOTX:%.*]] = xor i32 [[A:%.*]], -1 +; CHECK-NEXT: [[C:%.*]] = and i32 [[NOTX]], [[B:%.*]] +; CHECK-NEXT: [[NOTC:%.*]] = xor i32 [[C]], -1 +; CHECK-NEXT: call void @use32(i32 [[C]]) #0 +; CHECK-NEXT: ret i32 [[NOTC]] +; + %notx = xor i32 %A, -1 + %c = and i32 %notx, %B + %notc = xor i32 %c, -1 + call void @use32(i32 %c) + ret i32 %notc +} + +; ============================================================================ ; + +; ~(~A | B) --> (A & ~B) + +define i32 @demorgan_nor(i32 %A, i32 %B) nounwind { +; CHECK-LABEL: @demorgan_nor( +; CHECK-NEXT: [[B_NOT:%.*]] = xor i32 [[B:%.*]], -1 +; CHECK-NEXT: [[NOTC:%.*]] = and i32 [[B_NOT]], [[A:%.*]] +; CHECK-NEXT: ret i32 [[NOTC]] +; + %notx = xor i32 %A, -1 + %c = or i32 %notx, %B + %notc = xor i32 %c, -1 + ret i32 %notc +} + +define i32 @demorgan_nor_const(i32 %A) nounwind { +; CHECK-LABEL: @demorgan_nor_const( +; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[A:%.*]], -43 +; CHECK-NEXT: ret i32 [[TMP1]] +; + %notx = xor i32 %A, -1 + %c = or i32 %notx, 42 + %notc = xor i32 %c, -1 + ret i32 %notc +} + +define <2 x i32> @demorgan_nor_vec(<2 x i32> %A, <2 x i32> %B) nounwind { +; CHECK-LABEL: @demorgan_nor_vec( +; CHECK-NEXT: [[B_NOT:%.*]] = xor <2 x i32> [[B:%.*]], +; CHECK-NEXT: [[NOTC:%.*]] = and <2 x i32> [[B_NOT]], [[A:%.*]] +; CHECK-NEXT: ret <2 x i32> [[NOTC]] +; + %notx = xor <2 x i32> %A, + %c = or <2 x i32> %notx, %B + %notc = xor <2 x i32> %c, + ret <2 x i32> %notc +} + +define <3 x i32> @demorgan_nor_vec_undef(<3 x i32> %A, <3 x i32> %B) nounwind { +; CHECK-LABEL: @demorgan_nor_vec_undef( +; CHECK-NEXT: [[B_NOT:%.*]] = xor <3 x i32> [[B:%.*]], +; CHECK-NEXT: [[NOTC:%.*]] = and <3 x i32> [[B_NOT]], [[A:%.*]] +; CHECK-NEXT: ret <3 x i32> [[NOTC]] +; + %notx = xor <3 x i32> %A, + %c = or <3 x i32> %notx, %B + %notc = xor <3 x i32> %c, + ret <3 x i32> %notc +} + +define <2 x i32> @demorgan_nor_vec_splatconst(<2 x i32> %A) nounwind { +; CHECK-LABEL: @demorgan_nor_vec_splatconst( +; CHECK-NEXT: [[TMP1:%.*]] = and <2 x i32> [[A:%.*]], +; CHECK-NEXT: ret <2 x i32> [[TMP1]] +; + %notx = xor <2 x i32> %A, + %c = or <2 x i32> %notx, + %notc = xor <2 x i32> %c, + ret <2 x i32> %notc +} + +define <3 x i32> @demorgan_nor_vec_const_undef(<3 x i32> %A) nounwind { +; CHECK-LABEL: @demorgan_nor_vec_const_undef( +; CHECK-NEXT: [[NOTC:%.*]] = and <3 x i32> [[A:%.*]], +; CHECK-NEXT: ret <3 x i32> [[NOTC]] +; + %notx = xor <3 x i32> %A, + %c = or <3 x i32> %notx, + %notc = xor <3 x i32> %c, + ret <3 x i32> %notc +} + +define <2 x i32> @demorgan_nor_vec_const(<2 x i32> %A) nounwind { +; CHECK-LABEL: @demorgan_nor_vec_const( +; CHECK-NEXT: [[NOTX:%.*]] = xor <2 x i32> [[A:%.*]], +; CHECK-NEXT: [[C:%.*]] = or <2 x i32> [[NOTX]], +; CHECK-NEXT: [[NOTC:%.*]] = xor <2 x i32> [[C]], +; CHECK-NEXT: ret <2 x i32> [[NOTC]] +; + %notx = xor <2 x i32> %A, + %c = or <2 x i32> %notx, + %notc = xor <2 x i32> %c, + ret <2 x i32> %notc +} + +define <4 x i32> @demorgan_nor_vec_128bit(<4 x i32> %A, <4 x i32> %B) nounwind { +; CHECK-LABEL: @demorgan_nor_vec_128bit( +; CHECK-NEXT: [[B_NOT:%.*]] = xor <4 x i32> [[B:%.*]], +; CHECK-NEXT: [[NOTC:%.*]] = and <4 x i32> [[B_NOT]], [[A:%.*]] +; CHECK-NEXT: ret <4 x i32> [[NOTC]] +; + %notx = xor <4 x i32> %A, + %c = or <4 x i32> %notx, %B + %notc = xor <4 x i32> %c, + ret <4 x i32> %notc +} + +define <4 x i32> @demorgan_nor_vec_128bit_undef(<4 x i32> %A, <4 x i32> %B) nounwind { +; CHECK-LABEL: @demorgan_nor_vec_128bit_undef( +; CHECK-NEXT: [[B_NOT:%.*]] = xor <4 x i32> [[B:%.*]], +; CHECK-NEXT: [[NOTC:%.*]] = and <4 x i32> [[B_NOT]], [[A:%.*]] +; CHECK-NEXT: ret <4 x i32> [[NOTC]] +; + %notx = xor <4 x i32> %A, + %c = or <4 x i32> %notx, %B + %notc = xor <4 x i32> %c, + ret <4 x i32> %notc +} + +define i32 @demorgan_nor_commutative(i32 %A) nounwind { +; CHECK-LABEL: @demorgan_nor_commutative( +; CHECK-NEXT: [[B:%.*]] = call i32 @gen32() #0 +; CHECK-NEXT: [[B_NOT:%.*]] = xor i32 [[B]], -1 +; CHECK-NEXT: [[NOTC:%.*]] = and i32 [[B_NOT]], [[A:%.*]] +; CHECK-NEXT: ret i32 [[NOTC]] +; + %B = call i32 @gen32() + %notx = xor i32 %A, -1 + %c = or i32 %B, %notx ; swapped + %notc = xor i32 %c, -1 + ret i32 %notc +} + +define i32 @demorgan_nor_extraxor(i32 %A) nounwind { +; CHECK-LABEL: @demorgan_nor_extraxor( +; CHECK-NEXT: [[V:%.*]] = call i32 @gen32() #0 +; CHECK-NEXT: [[Z:%.*]] = call i32 @gen32() #0 +; CHECK-NEXT: [[B:%.*]] = xor i32 [[V]], [[Z]] +; CHECK-NEXT: [[B_NOT:%.*]] = xor i32 [[B]], -1 +; CHECK-NEXT: [[NOTC:%.*]] = and i32 [[B_NOT]], [[A:%.*]] +; CHECK-NEXT: ret i32 [[NOTC]] +; + %V = call i32 @gen32() + %Z = call i32 @gen32() + %B = xor i32 %V, %Z ; not with -1 + %notx = xor i32 %A, -1 + %c = or i32 %notx, %B + %notc = xor i32 %c, -1 + ret i32 %notc +} + +define i32 @demorgan_nor_extraxor_commutative(i32 %A) nounwind { +; CHECK-LABEL: @demorgan_nor_extraxor_commutative( +; CHECK-NEXT: [[V:%.*]] = call i32 @gen32() #0 +; CHECK-NEXT: [[Z:%.*]] = call i32 @gen32() #0 +; CHECK-NEXT: [[B:%.*]] = xor i32 [[V]], [[Z]] +; CHECK-NEXT: [[B_NOT:%.*]] = xor i32 [[B]], -1 +; CHECK-NEXT: [[NOTC:%.*]] = and i32 [[B_NOT]], [[A:%.*]] +; CHECK-NEXT: ret i32 [[NOTC]] +; + %V = call i32 @gen32() + %Z = call i32 @gen32() + %B = xor i32 %V, %Z ; not with -1 + %notx = xor i32 %A, -1 + %c = or i32 %B, %notx ; swapped + %notc = xor i32 %c, -1 + ret i32 %notc +} + +define i32 @demorgan_nor_badxor0(i32 %A, i32 %B) nounwind { +; CHECK-LABEL: @demorgan_nor_badxor0( +; CHECK-NEXT: [[NOTX:%.*]] = xor i32 [[A:%.*]], 1 +; CHECK-NEXT: [[C:%.*]] = or i32 [[NOTX]], [[B:%.*]] +; CHECK-NEXT: [[NOTC:%.*]] = xor i32 [[C]], -1 +; CHECK-NEXT: ret i32 [[NOTC]] +; + %notx = xor i32 %A, 1 ; not -1 + %c = or i32 %notx, %B + %notc = xor i32 %c, -1 + ret i32 %notc +} + +define i32 @demorgan_nor_badxor1(i32 %A, i32 %B) nounwind { +; CHECK-LABEL: @demorgan_nor_badxor1( +; CHECK-NEXT: [[NOTX:%.*]] = xor i32 [[A:%.*]], -1 +; CHECK-NEXT: [[C:%.*]] = or i32 [[NOTX]], [[B:%.*]] +; CHECK-NEXT: [[NOTC:%.*]] = xor i32 [[C]], 1 +; CHECK-NEXT: ret i32 [[NOTC]] +; + %notx = xor i32 %A, -1 + %c = or i32 %notx, %B + %notc = xor i32 %c, 1 ; not -1 + ret i32 %notc +} + +define i32 @demorgan_nor_oneuse0(i32 %A, i32 %B) nounwind { +; CHECK-LABEL: @demorgan_nor_oneuse0( +; CHECK-NEXT: [[NOTX:%.*]] = xor i32 [[A:%.*]], -1 +; CHECK-NEXT: [[B_NOT:%.*]] = xor i32 [[B:%.*]], -1 +; CHECK-NEXT: [[NOTC:%.*]] = and i32 [[B_NOT]], [[A]] +; CHECK-NEXT: call void @use32(i32 [[NOTX]]) #0 +; CHECK-NEXT: ret i32 [[NOTC]] +; + %notx = xor i32 %A, -1 + %c = or i32 %notx, %B + %notc = xor i32 %c, -1 + call void @use32(i32 %notx) + ret i32 %notc +} + +define i32 @demorgan_nor_oneuse1(i32 %A, i32 %B) nounwind { +; CHECK-LABEL: @demorgan_nor_oneuse1( +; CHECK-NEXT: [[NOTX:%.*]] = xor i32 [[A:%.*]], -1 +; CHECK-NEXT: [[C:%.*]] = or i32 [[NOTX]], [[B:%.*]] +; CHECK-NEXT: [[NOTC:%.*]] = xor i32 [[C]], -1 +; CHECK-NEXT: call void @use32(i32 [[C]]) #0 +; CHECK-NEXT: ret i32 [[NOTC]] +; + %notx = xor i32 %A, -1 + %c = or i32 %notx, %B + %notc = xor i32 %c, -1 + call void @use32(i32 %c) + ret i32 %notc +} + +; ============================================================================ ;