| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py |
| ; RUN: opt < %s -instcombine -S | FileCheck %s |
| |
| ; https://bugs.llvm.org/show_bug.cgi?id=38446 |
| |
| ; Pattern: |
| ; ~(x ^ y) |
| ; Should be transformed into: |
| ; (~x) ^ y |
| ; or into |
| ; x ^ (~y) |
| |
| ; While -reassociate does handle this simple pattern, it does not handle |
| ; the more complicated motivating pattern. |
| |
| ; ============================================================================ ; |
| ; Basic positive tests |
| ; ============================================================================ ; |
| |
| ; If the operand is easily-invertible, fold into it. |
| declare i1 @gen1() |
| |
| define i1 @positive_easyinvert(i16 %x, i8 %y) { |
| ; CHECK-LABEL: @positive_easyinvert( |
| ; CHECK-NEXT: [[TMP1:%.*]] = icmp slt i16 [[X:%.*]], 0 |
| ; CHECK-NEXT: [[TMP2:%.*]] = icmp sgt i8 [[Y:%.*]], -1 |
| ; CHECK-NEXT: [[TMP4:%.*]] = xor i1 [[TMP2]], [[TMP1]] |
| ; CHECK-NEXT: ret i1 [[TMP4]] |
| ; |
| %tmp1 = icmp slt i16 %x, 0 |
| %tmp2 = icmp slt i8 %y, 0 |
| %tmp3 = xor i1 %tmp2, %tmp1 |
| %tmp4 = xor i1 %tmp3, true |
| ret i1 %tmp4 |
| } |
| |
| define i1 @positive_easyinvert0(i8 %y) { |
| ; CHECK-LABEL: @positive_easyinvert0( |
| ; CHECK-NEXT: [[TMP1:%.*]] = call i1 @gen1() |
| ; CHECK-NEXT: [[TMP2:%.*]] = icmp sgt i8 [[Y:%.*]], -1 |
| ; CHECK-NEXT: [[TMP4:%.*]] = xor i1 [[TMP2]], [[TMP1]] |
| ; CHECK-NEXT: ret i1 [[TMP4]] |
| ; |
| %tmp1 = call i1 @gen1() |
| %tmp2 = icmp slt i8 %y, 0 |
| %tmp3 = xor i1 %tmp2, %tmp1 |
| %tmp4 = xor i1 %tmp3, true |
| ret i1 %tmp4 |
| } |
| |
| define i1 @positive_easyinvert1(i8 %y) { |
| ; CHECK-LABEL: @positive_easyinvert1( |
| ; CHECK-NEXT: [[TMP1:%.*]] = call i1 @gen1() |
| ; CHECK-NEXT: [[TMP2:%.*]] = icmp sgt i8 [[Y:%.*]], -1 |
| ; CHECK-NEXT: [[TMP4:%.*]] = xor i1 [[TMP2]], [[TMP1]] |
| ; CHECK-NEXT: ret i1 [[TMP4]] |
| ; |
| %tmp1 = call i1 @gen1() |
| %tmp2 = icmp slt i8 %y, 0 |
| %tmp3 = xor i1 %tmp1, %tmp2 |
| %tmp4 = xor i1 %tmp3, true |
| ret i1 %tmp4 |
| } |
| |
| ; ============================================================================ ; |
| ; One-use tests with easily-invertible operand. |
| ; ============================================================================ ; |
| |
| declare void @use1(i1) |
| |
| define i1 @oneuse_easyinvert_0(i8 %y) { |
| ; CHECK-LABEL: @oneuse_easyinvert_0( |
| ; CHECK-NEXT: [[TMP1:%.*]] = call i1 @gen1() |
| ; CHECK-NEXT: [[TMP2:%.*]] = icmp slt i8 [[Y:%.*]], 0 |
| ; CHECK-NEXT: call void @use1(i1 [[TMP2]]) |
| ; CHECK-NEXT: [[TMP3:%.*]] = xor i1 [[TMP1]], [[TMP2]] |
| ; CHECK-NEXT: [[TMP4:%.*]] = xor i1 [[TMP3]], true |
| ; CHECK-NEXT: ret i1 [[TMP4]] |
| ; |
| %tmp1 = call i1 @gen1() |
| %tmp2 = icmp slt i8 %y, 0 |
| call void @use1(i1 %tmp2) |
| %tmp3 = xor i1 %tmp1, %tmp2 |
| %tmp4 = xor i1 %tmp3, true |
| ret i1 %tmp4 |
| } |
| |
| define i1 @oneuse_easyinvert_1(i8 %y) { |
| ; CHECK-LABEL: @oneuse_easyinvert_1( |
| ; CHECK-NEXT: [[TMP1:%.*]] = call i1 @gen1() |
| ; CHECK-NEXT: [[TMP2:%.*]] = icmp slt i8 [[Y:%.*]], 0 |
| ; CHECK-NEXT: [[TMP3:%.*]] = xor i1 [[TMP1]], [[TMP2]] |
| ; CHECK-NEXT: call void @use1(i1 [[TMP3]]) |
| ; CHECK-NEXT: [[TMP4:%.*]] = xor i1 [[TMP3]], true |
| ; CHECK-NEXT: ret i1 [[TMP4]] |
| ; |
| %tmp1 = call i1 @gen1() |
| %tmp2 = icmp slt i8 %y, 0 |
| %tmp3 = xor i1 %tmp1, %tmp2 |
| call void @use1(i1 %tmp3) |
| %tmp4 = xor i1 %tmp3, true |
| ret i1 %tmp4 |
| } |
| |
| define i1 @oneuse_easyinvert_2(i8 %y) { |
| ; CHECK-LABEL: @oneuse_easyinvert_2( |
| ; CHECK-NEXT: [[TMP1:%.*]] = call i1 @gen1() |
| ; CHECK-NEXT: [[TMP2:%.*]] = icmp slt i8 [[Y:%.*]], 0 |
| ; CHECK-NEXT: call void @use1(i1 [[TMP2]]) |
| ; CHECK-NEXT: [[TMP3:%.*]] = xor i1 [[TMP1]], [[TMP2]] |
| ; CHECK-NEXT: call void @use1(i1 [[TMP3]]) |
| ; CHECK-NEXT: [[TMP4:%.*]] = xor i1 [[TMP3]], true |
| ; CHECK-NEXT: ret i1 [[TMP4]] |
| ; |
| %tmp1 = call i1 @gen1() |
| %tmp2 = icmp slt i8 %y, 0 |
| call void @use1(i1 %tmp2) |
| %tmp3 = xor i1 %tmp1, %tmp2 |
| call void @use1(i1 %tmp3) |
| %tmp4 = xor i1 %tmp3, true |
| ret i1 %tmp4 |
| } |
| |
| ; ============================================================================ ; |
| ; Negative tests |
| ; ============================================================================ ; |
| |
| ; Not easily invertible. |
| define i32 @negative(i32 %x, i32 %y) { |
| ; CHECK-LABEL: @negative( |
| ; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[X:%.*]], [[Y:%.*]] |
| ; CHECK-NEXT: [[TMP2:%.*]] = xor i32 [[TMP1]], -1 |
| ; CHECK-NEXT: ret i32 [[TMP2]] |
| ; |
| %tmp1 = xor i32 %x, %y |
| %tmp2 = xor i32 %tmp1, -1 |
| ret i32 %tmp2 |
| } |