| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 4 | |
| ; RUN: opt -S -passes=bdce < %s | FileCheck %s | |
| define void @or(i64 %a) { | |
| ; CHECK-LABEL: define void @or( | |
| ; CHECK-SAME: i64 [[A:%.*]]) { | |
| ; CHECK-NEXT: entry: | |
| ; CHECK-NEXT: [[RET1:%.*]] = and i64 [[A]], 8 | |
| ; CHECK-NEXT: [[RET2:%.*]] = and i64 [[A]], 16 | |
| ; CHECK-NEXT: call void @use(i64 [[RET1]]) | |
| ; CHECK-NEXT: call void @use(i64 [[RET2]]) | |
| ; CHECK-NEXT: ret void | |
| ; | |
| entry: | |
| %or = or i64 %a, 3 ; Mask: 0000 0011 | |
| %ret1 = and i64 %or, 8 ; Demanded bits: 0000 1000 | |
| %ret2 = and i64 %or, 16 ; Demanded bits: 0001 0000 | |
| call void @use(i64 %ret1) | |
| call void @use(i64 %ret2) | |
| ret void | |
| } | |
| define void @xor(i64 %a) { | |
| ; CHECK-LABEL: define void @xor( | |
| ; CHECK-SAME: i64 [[A:%.*]]) { | |
| ; CHECK-NEXT: entry: | |
| ; CHECK-NEXT: [[RET1:%.*]] = and i64 [[A]], 8 | |
| ; CHECK-NEXT: [[RET2:%.*]] = and i64 [[A]], 16 | |
| ; CHECK-NEXT: call void @use(i64 [[RET1]]) | |
| ; CHECK-NEXT: call void @use(i64 [[RET2]]) | |
| ; CHECK-NEXT: ret void | |
| ; | |
| entry: | |
| %xor = xor i64 %a, 3 ; Mask: 0000 0011 | |
| %ret1 = and i64 %xor, 8 ; Demanded bits: 0000 1000 | |
| %ret2 = and i64 %xor, 16 ; Demanded bits: 0001 0000 | |
| call void @use(i64 %ret1) | |
| call void @use(i64 %ret2) | |
| ret void | |
| } | |
| define void @and(i64 %a) { | |
| ; CHECK-LABEL: define void @and( | |
| ; CHECK-SAME: i64 [[A:%.*]]) { | |
| ; CHECK-NEXT: entry: | |
| ; CHECK-NEXT: [[RET1:%.*]] = and i64 [[A]], 8 | |
| ; CHECK-NEXT: [[RET2:%.*]] = and i64 [[A]], 16 | |
| ; CHECK-NEXT: call void @use(i64 [[RET1]]) | |
| ; CHECK-NEXT: call void @use(i64 [[RET2]]) | |
| ; CHECK-NEXT: ret void | |
| ; | |
| entry: | |
| %and = and i64 %a, 24 ; Mask: 0001 1000 | |
| %ret1 = and i64 %and, 8 ; Demanded bits: 0000 1000 | |
| %ret2 = and i64 %and, 16 ; Demanded bits: 0001 0000 | |
| call void @use(i64 %ret1) | |
| call void @use(i64 %ret2) | |
| ret void | |
| } | |
| define void @or_of_and(i64 %a, i64 %b) { | |
| ; CHECK-LABEL: define void @or_of_and( | |
| ; CHECK-SAME: i64 [[A:%.*]], i64 [[B:%.*]]) { | |
| ; CHECK-NEXT: entry: | |
| ; CHECK-NEXT: [[OR:%.*]] = or i64 [[A]], [[B]] | |
| ; CHECK-NEXT: [[RET1:%.*]] = and i64 [[OR]], 8 | |
| ; CHECK-NEXT: [[RET2:%.*]] = and i64 [[OR]], 16 | |
| ; CHECK-NEXT: call void @use(i64 [[RET1]]) | |
| ; CHECK-NEXT: call void @use(i64 [[RET2]]) | |
| ; CHECK-NEXT: ret void | |
| ; | |
| entry: | |
| %and1 = and i64 %a, 24 ; Mask: 0001 1000 | |
| %and2 = and i64 %b, 25 ; Mask: 0001 1001 | |
| %or = or i64 %and1, %and2 | |
| %ret1 = and i64 %or, 8 ; Demanded bits: 0000 1000 | |
| %ret2 = and i64 %or, 16 ; Demanded bits: 0001 0000 | |
| call void @use(i64 %ret1) | |
| call void @use(i64 %ret2) | |
| ret void | |
| } | |
| define void @or_disjoint_of_and(i64 %a, i64 %b) { | |
| ; CHECK-LABEL: define void @or_disjoint_of_and( | |
| ; CHECK-SAME: i64 [[A:%.*]], i64 [[B:%.*]]) { | |
| ; CHECK-NEXT: entry: | |
| ; CHECK-NEXT: [[OR:%.*]] = or i64 [[A]], [[B]] | |
| ; CHECK-NEXT: [[RET1:%.*]] = and i64 [[OR]], 8 | |
| ; CHECK-NEXT: [[RET2:%.*]] = and i64 [[OR]], 16 | |
| ; CHECK-NEXT: call void @use(i64 [[RET1]]) | |
| ; CHECK-NEXT: call void @use(i64 [[RET2]]) | |
| ; CHECK-NEXT: ret void | |
| ; | |
| entry: | |
| %and1 = and i64 %a, 56 ; Mask: 0011 1000 | |
| %and2 = and i64 %b, 25 ; Mask: 0001 1001 | |
| %or = or disjoint i64 %and1, %and2 | |
| %ret1 = and i64 %or, 8 ; Demanded bits: 0000 1000 | |
| %ret2 = and i64 %or, 16 ; Demanded bits: 0001 0000 | |
| call void @use(i64 %ret1) | |
| call void @use(i64 %ret2) | |
| ret void | |
| } | |
| define void @select_of_and(i1 %c, i64 %a, i64 %b) { | |
| ; CHECK-LABEL: define void @select_of_and( | |
| ; CHECK-SAME: i1 [[C:%.*]], i64 [[A:%.*]], i64 [[B:%.*]]) { | |
| ; CHECK-NEXT: entry: | |
| ; CHECK-NEXT: [[S:%.*]] = select i1 [[C]], i64 [[A]], i64 [[B]] | |
| ; CHECK-NEXT: [[RET1:%.*]] = and i64 [[S]], 8 | |
| ; CHECK-NEXT: [[RET2:%.*]] = and i64 [[S]], 16 | |
| ; CHECK-NEXT: call void @use(i64 [[RET1]]) | |
| ; CHECK-NEXT: call void @use(i64 [[RET2]]) | |
| ; CHECK-NEXT: ret void | |
| ; | |
| entry: | |
| %and1 = and i64 %a, 24 ; Mask: 0001 1000 | |
| %and2 = and i64 %b, 25 ; Mask: 0001 1001 | |
| %s = select i1 %c, i64 %and1, i64 %and2 | |
| %ret1 = and i64 %s, 8 ; Demanded bits: 0000 1000 | |
| %ret2 = and i64 %s, 16 ; Demanded bits: 0001 0000 | |
| call void @use(i64 %ret1) | |
| call void @use(i64 %ret2) | |
| ret void | |
| } | |
| define void @select_of_and_2(i1 %c, i64 %a, i64 %b) { | |
| ; CHECK-LABEL: define void @select_of_and_2( | |
| ; CHECK-SAME: i1 [[C:%.*]], i64 [[A:%.*]], i64 [[B:%.*]]) { | |
| ; CHECK-NEXT: entry: | |
| ; CHECK-NEXT: [[AND2:%.*]] = and i64 [[B]], 23 | |
| ; CHECK-NEXT: [[S:%.*]] = select i1 [[C]], i64 [[A]], i64 [[AND2]] | |
| ; CHECK-NEXT: [[RET1:%.*]] = and i64 [[S]], 8 | |
| ; CHECK-NEXT: [[RET2:%.*]] = and i64 [[S]], 16 | |
| ; CHECK-NEXT: call void @use(i64 [[RET1]]) | |
| ; CHECK-NEXT: call void @use(i64 [[RET2]]) | |
| ; CHECK-NEXT: ret void | |
| ; | |
| entry: | |
| %and1 = and i64 %a, 25 ; Mask: 0001 1001 | |
| %and2 = and i64 %b, 23 ; Mask: 0001 0111 | |
| %s = select i1 %c, i64 %and1, i64 %and2 | |
| %ret1 = and i64 %s, 8 ; Demanded bits: 0000 1000 | |
| %ret2 = and i64 %s, 16 ; Demanded bits: 0001 0000 | |
| call void @use(i64 %ret1) | |
| call void @use(i64 %ret2) | |
| ret void | |
| } | |
| define void @select_of_and_multiuse(i1 %c, i64 %a, i64 %b) { | |
| ; CHECK-LABEL: define void @select_of_and_multiuse( | |
| ; CHECK-SAME: i1 [[C:%.*]], i64 [[A:%.*]], i64 [[B:%.*]]) { | |
| ; CHECK-NEXT: entry: | |
| ; CHECK-NEXT: [[AND2:%.*]] = and i64 [[B]], 25 | |
| ; CHECK-NEXT: [[S:%.*]] = select i1 [[C]], i64 [[A]], i64 [[AND2]] | |
| ; CHECK-NEXT: [[RET1:%.*]] = and i64 [[S]], 8 | |
| ; CHECK-NEXT: [[RET2:%.*]] = and i64 [[S]], 16 | |
| ; CHECK-NEXT: call void @use(i64 [[RET1]]) | |
| ; CHECK-NEXT: call void @use2(i64 [[RET2]], i64 [[AND2]]) | |
| ; CHECK-NEXT: ret void | |
| ; | |
| entry: | |
| %and1 = and i64 %a, 24 ; Mask: 0001 1000 | |
| %and2 = and i64 %b, 25 ; Mask: 0001 1001 | |
| %s = select i1 %c, i64 %and1, i64 %and2 | |
| %ret1 = and i64 %s, 8 ; Demanded bits: 0000 1000 | |
| %ret2 = and i64 %s, 16 ; Demanded bits: 0001 0000 | |
| call void @use(i64 %ret1) | |
| call void @use2(i64 %ret2, i64 %and2) | |
| ret void | |
| } | |
| define void @select_of_and_different_demanded(i1 %c, i64 %a, i64 %b) { | |
| ; CHECK-LABEL: define void @select_of_and_different_demanded( | |
| ; CHECK-SAME: i1 [[C:%.*]], i64 [[A:%.*]], i64 [[B:%.*]]) { | |
| ; CHECK-NEXT: entry: | |
| ; CHECK-NEXT: [[AND1:%.*]] = and i64 0, 24 | |
| ; CHECK-NEXT: [[AND2:%.*]] = and i64 [[B]], 25 | |
| ; CHECK-NEXT: [[S:%.*]] = select i1 [[C]], i64 [[AND1]], i64 [[AND2]] | |
| ; CHECK-NEXT: [[RET1:%.*]] = and i64 [[S]], 3 | |
| ; CHECK-NEXT: [[RET2:%.*]] = and i64 [[S]], 7 | |
| ; CHECK-NEXT: call void @use(i64 [[RET1]]) | |
| ; CHECK-NEXT: call void @use(i64 [[RET2]]) | |
| ; CHECK-NEXT: ret void | |
| ; | |
| entry: | |
| %and1 = and i64 %a, 24 ; Mask: 0001 1000 | |
| %and2 = and i64 %b, 25 ; Mask: 0001 1001 | |
| %s = select i1 %c, i64 %and1, i64 %and2 | |
| %ret1 = and i64 %s, 3 ; Demanded bits: 0000 0011 | |
| %ret2 = and i64 %s, 7 ; Demanded bits: 0000 0111 | |
| call void @use(i64 %ret1) | |
| call void @use(i64 %ret2) | |
| ret void | |
| } | |
| define void @select_of_or(i1 %c, i64 %a, i64 %b) { | |
| ; CHECK-LABEL: define void @select_of_or( | |
| ; CHECK-SAME: i1 [[C:%.*]], i64 [[A:%.*]], i64 [[B:%.*]]) { | |
| ; CHECK-NEXT: entry: | |
| ; CHECK-NEXT: [[S:%.*]] = select i1 [[C]], i64 [[A]], i64 [[B]] | |
| ; CHECK-NEXT: [[RET1:%.*]] = and i64 [[S]], 8 | |
| ; CHECK-NEXT: [[RET2:%.*]] = and i64 [[S]], 16 | |
| ; CHECK-NEXT: call void @use(i64 [[RET1]]) | |
| ; CHECK-NEXT: call void @use(i64 [[RET2]]) | |
| ; CHECK-NEXT: ret void | |
| ; | |
| entry: | |
| %or1 = or i64 %a, 3 ; Mask: 0000 0011 | |
| %or2 = or i64 %b, 192 ; Mask: 1100 0000 | |
| %s = select i1 %c, i64 %or1, i64 %or2 | |
| %ret1 = and i64 %s, 8 ; Demanded bits: 0000 1000 | |
| %ret2 = and i64 %s, 16 ; Demanded bits: 0001 0000 | |
| call void @use(i64 %ret1) | |
| call void @use(i64 %ret2) | |
| ret void | |
| } | |
| define void @select_of_xor(i1 %c, i64 %a, i64 %b) { | |
| ; CHECK-LABEL: define void @select_of_xor( | |
| ; CHECK-SAME: i1 [[C:%.*]], i64 [[A:%.*]], i64 [[B:%.*]]) { | |
| ; CHECK-NEXT: entry: | |
| ; CHECK-NEXT: [[S:%.*]] = select i1 [[C]], i64 [[A]], i64 [[B]] | |
| ; CHECK-NEXT: [[RET1:%.*]] = and i64 [[S]], 8 | |
| ; CHECK-NEXT: [[RET2:%.*]] = and i64 [[S]], 16 | |
| ; CHECK-NEXT: call void @use(i64 [[RET1]]) | |
| ; CHECK-NEXT: call void @use(i64 [[RET2]]) | |
| ; CHECK-NEXT: ret void | |
| ; | |
| entry: | |
| %xor1 = xor i64 %a, 128 ; Mask: 1000 0000 | |
| %xor2 = xor i64 %b, 36 ; Mask: 0010 0100 | |
| %s = select i1 %c, i64 %xor1, i64 %xor2 | |
| %ret1 = and i64 %s, 8 ; Demanded bits: 0000 1000 | |
| %ret2 = and i64 %s, 16 ; Demanded bits: 0001 0000 | |
| call void @use(i64 %ret1) | |
| call void @use(i64 %ret2) | |
| ret void | |
| } | |
| define void @select_vectorized(i1 %c, <2 x i8> %a, <2 x i8> %b) { | |
| ; CHECK-LABEL: define void @select_vectorized( | |
| ; CHECK-SAME: i1 [[C:%.*]], <2 x i8> [[A:%.*]], <2 x i8> [[B:%.*]]) { | |
| ; CHECK-NEXT: entry: | |
| ; CHECK-NEXT: [[S:%.*]] = select i1 [[C]], <2 x i8> [[A]], <2 x i8> [[B]] | |
| ; CHECK-NEXT: [[RET1:%.*]] = and <2 x i8> [[S]], splat (i8 4) | |
| ; CHECK-NEXT: [[RET2:%.*]] = and <2 x i8> [[S]], splat (i8 12) | |
| ; CHECK-NEXT: call void @use3(<2 x i8> [[RET1]]) | |
| ; CHECK-NEXT: call void @use3(<2 x i8> [[RET2]]) | |
| ; CHECK-NEXT: ret void | |
| ; | |
| entry: | |
| %and1 = and <2 x i8> %a, <i8 28, i8 28> | |
| %and2 = and <2 x i8> %b, <i8 29, i8 29> | |
| %s = select i1 %c, <2 x i8> %and1, <2 x i8> %and2 | |
| %ret1 = and <2 x i8> %s, <i8 4, i8 4> | |
| %ret2 = and <2 x i8> %s, <i8 12, i8 12> | |
| call void @use3(<2 x i8> %ret1) | |
| call void @use3(<2 x i8> %ret2) | |
| ret void | |
| } | |
| declare void @use(i64) | |
| declare void @use2(i64, i64) | |
| declare void @use3(<2 x i8>) |