1; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py 2; RUN: llc -o - %s -mtriple=x86_64-- | FileCheck %s --check-prefixes=CHECK,NOBMI 3; RUN: llc -o - %s -mtriple=x86_64-- -mattr=+bmi | FileCheck %s --check-prefixes=CHECK,BMI 4; 5; test that masked-merge code is generated as "xor;and;xor" sequence or 6; "andn ; and; or" if and-not is available. 7 8define i32 @masked_merge0(i32 %a0, i32 %a1, i32 %a2) { 9; NOBMI-LABEL: masked_merge0: 10; NOBMI: # %bb.0: 11; NOBMI-NEXT: movl %esi, %eax 12; NOBMI-NEXT: xorl %edx, %eax 13; NOBMI-NEXT: andl %edi, %eax 14; NOBMI-NEXT: xorl %edx, %eax 15; NOBMI-NEXT: retq 16; 17; BMI-LABEL: masked_merge0: 18; BMI: # %bb.0: 19; BMI-NEXT: andl %edi, %esi 20; BMI-NEXT: andnl %edx, %edi, %eax 21; BMI-NEXT: orl %esi, %eax 22; BMI-NEXT: retq 23 %and0 = and i32 %a0, %a1 24 %not = xor i32 %a0, -1 25 %and1 = and i32 %not, %a2 26 %or = or i32 %and0, %and1 27 ret i32 %or 28} 29 30define i16 @masked_merge1(i16 %a0, i16 %a1, i16 %a2) { 31; NOBMI-LABEL: masked_merge1: 32; NOBMI: # %bb.0: 33; NOBMI-NEXT: movl %edi, %eax 34; NOBMI-NEXT: andl %edi, %esi 35; NOBMI-NEXT: notl %eax 36; NOBMI-NEXT: andl %edx, %eax 37; NOBMI-NEXT: orl %esi, %eax 38; NOBMI-NEXT: # kill: def $ax killed $ax killed $eax 39; NOBMI-NEXT: retq 40; 41; BMI-LABEL: masked_merge1: 42; BMI: # %bb.0: 43; BMI-NEXT: andl %edi, %esi 44; BMI-NEXT: andnl %edx, %edi, %eax 45; BMI-NEXT: orl %esi, %eax 46; BMI-NEXT: # kill: def $ax killed $ax killed $eax 47; BMI-NEXT: retq 48 %and0 = and i16 %a0, %a1 49 %not = xor i16 %a0, -1 50 %and1 = and i16 %a2, %not 51 %or = or i16 %and0, %and1 52 ret i16 %or 53} 54 55define i8 @masked_merge2(i8 %a0, i8 %a1, i8 %a2) { 56; NOBMI-LABEL: masked_merge2: 57; NOBMI: # %bb.0: 58; NOBMI-NEXT: movl %esi, %eax 59; NOBMI-NEXT: # kill: def $al killed $al killed $eax 60; NOBMI-NEXT: retq 61; 62; BMI-LABEL: masked_merge2: 63; BMI: # %bb.0: 64; BMI-NEXT: movl %edi, %eax 65; BMI-NEXT: notb %al 66; BMI-NEXT: andb %sil, %al 67; BMI-NEXT: andb %dil, %sil 68; BMI-NEXT: orb %sil, %al 69; BMI-NEXT: retq 70 %not = xor i8 %a0, -1 71 %and0 = and i8 %not, %a1 72 %and1 = and i8 %a1, %a0 73 %or = or i8 %and0, %and1 74 ret i8 %or 75} 76 77define i64 @masked_merge3(i64 %a0, i64 %a1, i64 %a2) { 78; NOBMI-LABEL: masked_merge3: 79; NOBMI: # %bb.0: 80; NOBMI-NEXT: movq %rsi, %rax 81; NOBMI-NEXT: notq %rdx 82; NOBMI-NEXT: xorq %rdx, %rax 83; NOBMI-NEXT: notq %rax 84; NOBMI-NEXT: andq %rdi, %rax 85; NOBMI-NEXT: xorq %rdx, %rax 86; NOBMI-NEXT: retq 87; 88; BMI-LABEL: masked_merge3: 89; BMI: # %bb.0: 90; BMI-NEXT: notq %rdx 91; BMI-NEXT: andnq %rdx, %rdi, %rcx 92; BMI-NEXT: andnq %rdi, %rsi, %rax 93; BMI-NEXT: orq %rcx, %rax 94; BMI-NEXT: retq 95 %v0 = xor i64 %a1, -1 96 %v1 = xor i64 %a2, -1 97 %not = xor i64 %a0, -1 98 %and0 = and i64 %not, %v1 99 %and1 = and i64 %v0, %a0 100 %or = or i64 %and0, %and1 101 ret i64 %or 102} 103 104; not a masked merge: there is no `not` operation. 105define i32 @not_a_masked_merge0(i32 %a0, i32 %a1, i32 %a2) { 106; CHECK-LABEL: not_a_masked_merge0: 107; CHECK: # %bb.0: 108; CHECK-NEXT: movl %edi, %eax 109; CHECK-NEXT: andl %edi, %esi 110; CHECK-NEXT: negl %eax 111; CHECK-NEXT: andl %edx, %eax 112; CHECK-NEXT: orl %esi, %eax 113; CHECK-NEXT: retq 114 %and0 = and i32 %a0, %a1 115 %not_a_not = sub i32 0, %a0 116 %and1 = and i32 %not_a_not, %a2 117 %or = or i32 %and0, %and1 118 ret i32 %or 119} 120 121; not a masked merge: `not` operand does not match another `and`-operand. 122define i32 @not_a_masked_merge1(i32 %a0, i32 %a1, i32 %a2, i32 %a3) { 123; NOBMI-LABEL: not_a_masked_merge1: 124; NOBMI: # %bb.0: 125; NOBMI-NEXT: movl %ecx, %eax 126; NOBMI-NEXT: andl %esi, %edi 127; NOBMI-NEXT: notl %eax 128; NOBMI-NEXT: andl %edx, %eax 129; NOBMI-NEXT: orl %edi, %eax 130; NOBMI-NEXT: retq 131; 132; BMI-LABEL: not_a_masked_merge1: 133; BMI: # %bb.0: 134; BMI-NEXT: andl %esi, %edi 135; BMI-NEXT: andnl %edx, %ecx, %eax 136; BMI-NEXT: orl %edi, %eax 137; BMI-NEXT: retq 138 %and0 = and i32 %a0, %a1 139 %not = xor i32 %a3, -1 140 %and1 = and i32 %not, %a2 141 %or = or i32 %and0, %and1 142 ret i32 %or 143} 144 145; not a masked merge: one of the operands of `or` is not an `and`. 146define i32 @not_a_masked_merge2(i32 %a0, i32 %a1, i32 %a2) { 147; NOBMI-LABEL: not_a_masked_merge2: 148; NOBMI: # %bb.0: 149; NOBMI-NEXT: movl %edi, %eax 150; NOBMI-NEXT: orl %edi, %esi 151; NOBMI-NEXT: notl %eax 152; NOBMI-NEXT: andl %edx, %eax 153; NOBMI-NEXT: orl %esi, %eax 154; NOBMI-NEXT: retq 155; 156; BMI-LABEL: not_a_masked_merge2: 157; BMI: # %bb.0: 158; BMI-NEXT: orl %edi, %esi 159; BMI-NEXT: andnl %edx, %edi, %eax 160; BMI-NEXT: orl %esi, %eax 161; BMI-NEXT: retq 162 %not_an_and0 = or i32 %a0, %a1 163 %not = xor i32 %a0, -1 164 %and1 = and i32 %not, %a2 165 %or = or i32 %not_an_and0, %and1 166 ret i32 %or 167} 168 169; not a masked merge: one of the operands of `or` is not an `and`. 170define i32 @not_a_masked_merge3(i32 %a0, i32 %a1, i32 %a2) { 171; CHECK-LABEL: not_a_masked_merge3: 172; CHECK: # %bb.0: 173; CHECK-NEXT: movl %edx, %eax 174; CHECK-NEXT: andl %edi, %esi 175; CHECK-NEXT: xorl %edi, %eax 176; CHECK-NEXT: notl %eax 177; CHECK-NEXT: orl %esi, %eax 178; CHECK-NEXT: retq 179 %and0 = and i32 %a0, %a1 180 %not = xor i32 %a0, -1 181 %not_an_and1 = xor i32 %not, %a2 182 %or = or i32 %and0, %not_an_and1 183 ret i32 %or 184} 185 186; not a masked merge: `not` operand must not be on same `and`. 187define i32 @not_a_masked_merge4(i32 %a0, i32 %a1, i32 %a2) { 188; CHECK-LABEL: not_a_masked_merge4: 189; CHECK: # %bb.0: 190; CHECK-NEXT: movl %edi, %eax 191; CHECK-NEXT: andl %esi, %eax 192; CHECK-NEXT: retq 193 %and0 = and i32 %a0, %a1 194 %not = xor i32 %a2, -1 195 %and1 = and i32 %not, %a2 196 %or = or i32 %and0, %and1 197 ret i32 %or 198} 199 200; should not transform when operands have multiple users. 201define i32 @masked_merge_no_transform0(i32 %a0, i32 %a1, i32 %a2, ptr %p1) { 202; NOBMI-LABEL: masked_merge_no_transform0: 203; NOBMI: # %bb.0: 204; NOBMI-NEXT: movl %edi, %eax 205; NOBMI-NEXT: andl %edi, %esi 206; NOBMI-NEXT: notl %eax 207; NOBMI-NEXT: andl %edx, %eax 208; NOBMI-NEXT: orl %esi, %eax 209; NOBMI-NEXT: movl %esi, (%rcx) 210; NOBMI-NEXT: retq 211; 212; BMI-LABEL: masked_merge_no_transform0: 213; BMI: # %bb.0: 214; BMI-NEXT: andl %edi, %esi 215; BMI-NEXT: andnl %edx, %edi, %eax 216; BMI-NEXT: orl %esi, %eax 217; BMI-NEXT: movl %esi, (%rcx) 218; BMI-NEXT: retq 219 %and0 = and i32 %a0, %a1 220 %not = xor i32 %a0, -1 221 %and1 = and i32 %not, %a2 222 %or = or i32 %and0, %and1 223 store i32 %and0, ptr %p1 224 ret i32 %or 225} 226 227; should not transform when operands have multiple users. 228define i32 @masked_merge_no_transform1(i32 %a0, i32 %a1, i32 %a2, ptr %p1) { 229; NOBMI-LABEL: masked_merge_no_transform1: 230; NOBMI: # %bb.0: 231; NOBMI-NEXT: movl %edx, %eax 232; NOBMI-NEXT: andl %edi, %esi 233; NOBMI-NEXT: notl %edi 234; NOBMI-NEXT: andl %edi, %eax 235; NOBMI-NEXT: orl %esi, %eax 236; NOBMI-NEXT: movl %edi, (%rcx) 237; NOBMI-NEXT: retq 238; 239; BMI-LABEL: masked_merge_no_transform1: 240; BMI: # %bb.0: 241; BMI-NEXT: andl %edi, %esi 242; BMI-NEXT: andnl %edx, %edi, %eax 243; BMI-NEXT: notl %edi 244; BMI-NEXT: orl %esi, %eax 245; BMI-NEXT: movl %edi, (%rcx) 246; BMI-NEXT: retq 247 %and0 = and i32 %a0, %a1 248 %not = xor i32 %a0, -1 249 %and1 = and i32 %not, %a2 250 %or = or i32 %and0, %and1 251 store i32 %not, ptr %p1 252 ret i32 %or 253} 254 255; should not transform when operands have multiple users. 256define i32 @masked_merge_no_transform2(i32 %a0, i32 %a1, i32 %a2, ptr %p1) { 257; NOBMI-LABEL: masked_merge_no_transform2: 258; NOBMI: # %bb.0: 259; NOBMI-NEXT: movl %esi, %eax 260; NOBMI-NEXT: andl %edi, %eax 261; NOBMI-NEXT: notl %edi 262; NOBMI-NEXT: andl %edx, %edi 263; NOBMI-NEXT: orl %edi, %eax 264; NOBMI-NEXT: movl %edi, (%rcx) 265; NOBMI-NEXT: retq 266; 267; BMI-LABEL: masked_merge_no_transform2: 268; BMI: # %bb.0: 269; BMI-NEXT: movl %esi, %eax 270; BMI-NEXT: andl %edi, %eax 271; BMI-NEXT: andnl %edx, %edi, %edx 272; BMI-NEXT: orl %edx, %eax 273; BMI-NEXT: movl %edx, (%rcx) 274; BMI-NEXT: retq 275 %and0 = and i32 %a0, %a1 276 %not = xor i32 %a0, -1 277 %and1 = and i32 %not, %a2 278 %or = or i32 %and0, %and1 279 store i32 %and1, ptr %p1 280 ret i32 %or 281} 282