1; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py 2; RUN: llc < %s -mtriple=arm-eabi-unknown-unknown | FileCheck %s 3 4; Select of constants: control flow / conditional moves can always be replaced by logic+math (but may not be worth it?). 5; Test the zeroext/signext variants of each pattern to see if that makes a difference. 6 7; select Cond, 0, 1 --> zext (!Cond) 8 9define i32 @select_0_or_1(i1 %cond) { 10; CHECK-LABEL: select_0_or_1: 11; CHECK: @ %bb.0: 12; CHECK-NEXT: mov r1, #1 13; CHECK-NEXT: bic r0, r1, r0 14; CHECK-NEXT: mov pc, lr 15 %sel = select i1 %cond, i32 0, i32 1 16 ret i32 %sel 17} 18 19define i32 @select_0_or_1_zeroext(i1 zeroext %cond) { 20; CHECK-LABEL: select_0_or_1_zeroext: 21; CHECK: @ %bb.0: 22; CHECK-NEXT: eor r0, r0, #1 23; CHECK-NEXT: mov pc, lr 24 %sel = select i1 %cond, i32 0, i32 1 25 ret i32 %sel 26} 27 28define i32 @select_0_or_1_signext(i1 signext %cond) { 29; CHECK-LABEL: select_0_or_1_signext: 30; CHECK: @ %bb.0: 31; CHECK-NEXT: mov r1, #1 32; CHECK-NEXT: bic r0, r1, r0 33; CHECK-NEXT: mov pc, lr 34 %sel = select i1 %cond, i32 0, i32 1 35 ret i32 %sel 36} 37 38; select Cond, 1, 0 --> zext (Cond) 39 40define i32 @select_1_or_0(i1 %cond) { 41; CHECK-LABEL: select_1_or_0: 42; CHECK: @ %bb.0: 43; CHECK-NEXT: and r0, r0, #1 44; CHECK-NEXT: mov pc, lr 45 %sel = select i1 %cond, i32 1, i32 0 46 ret i32 %sel 47} 48 49define i32 @select_1_or_0_zeroext(i1 zeroext %cond) { 50; CHECK-LABEL: select_1_or_0_zeroext: 51; CHECK: @ %bb.0: 52; CHECK-NEXT: mov pc, lr 53 %sel = select i1 %cond, i32 1, i32 0 54 ret i32 %sel 55} 56 57define i32 @select_1_or_0_signext(i1 signext %cond) { 58; CHECK-LABEL: select_1_or_0_signext: 59; CHECK: @ %bb.0: 60; CHECK-NEXT: and r0, r0, #1 61; CHECK-NEXT: mov pc, lr 62 %sel = select i1 %cond, i32 1, i32 0 63 ret i32 %sel 64} 65 66; select Cond, 0, -1 --> sext (!Cond) 67 68define i32 @select_0_or_neg1(i1 %cond) { 69; CHECK-LABEL: select_0_or_neg1: 70; CHECK: @ %bb.0: 71; CHECK-NEXT: mov r1, #1 72; CHECK-NEXT: bic r0, r1, r0 73; CHECK-NEXT: rsb r0, r0, #0 74; CHECK-NEXT: mov pc, lr 75 %sel = select i1 %cond, i32 0, i32 -1 76 ret i32 %sel 77} 78 79define i32 @select_0_or_neg1_zeroext(i1 zeroext %cond) { 80; CHECK-LABEL: select_0_or_neg1_zeroext: 81; CHECK: @ %bb.0: 82; CHECK-NEXT: eor r0, r0, #1 83; CHECK-NEXT: rsb r0, r0, #0 84; CHECK-NEXT: mov pc, lr 85 %sel = select i1 %cond, i32 0, i32 -1 86 ret i32 %sel 87} 88 89define i32 @select_0_or_neg1_signext(i1 signext %cond) { 90; CHECK-LABEL: select_0_or_neg1_signext: 91; CHECK: @ %bb.0: 92; CHECK-NEXT: mvn r0, r0 93; CHECK-NEXT: mov pc, lr 94 %sel = select i1 %cond, i32 0, i32 -1 95 ret i32 %sel 96} 97 98define i32 @select_0_or_neg1_alt(i1 %cond) { 99; CHECK-LABEL: select_0_or_neg1_alt: 100; CHECK: @ %bb.0: 101; CHECK-NEXT: and r0, r0, #1 102; CHECK-NEXT: sub r0, r0, #1 103; CHECK-NEXT: mov pc, lr 104 %z = zext i1 %cond to i32 105 %add = add i32 %z, -1 106 ret i32 %add 107} 108 109define i32 @select_0_or_neg1_alt_zeroext(i1 zeroext %cond) { 110; CHECK-LABEL: select_0_or_neg1_alt_zeroext: 111; CHECK: @ %bb.0: 112; CHECK-NEXT: sub r0, r0, #1 113; CHECK-NEXT: mov pc, lr 114 %z = zext i1 %cond to i32 115 %add = add i32 %z, -1 116 ret i32 %add 117} 118 119define i32 @select_0_or_neg1_alt_signext(i1 signext %cond) { 120; CHECK-LABEL: select_0_or_neg1_alt_signext: 121; CHECK: @ %bb.0: 122; CHECK-NEXT: mvn r0, r0 123; CHECK-NEXT: mov pc, lr 124 %z = zext i1 %cond to i32 125 %add = add i32 %z, -1 126 ret i32 %add 127} 128 129; select Cond, -1, 0 --> sext (Cond) 130 131define i32 @select_neg1_or_0(i1 %cond) { 132; CHECK-LABEL: select_neg1_or_0: 133; CHECK: @ %bb.0: 134; CHECK-NEXT: and r0, r0, #1 135; CHECK-NEXT: rsb r0, r0, #0 136; CHECK-NEXT: mov pc, lr 137 %sel = select i1 %cond, i32 -1, i32 0 138 ret i32 %sel 139} 140 141define i32 @select_neg1_or_0_zeroext(i1 zeroext %cond) { 142; CHECK-LABEL: select_neg1_or_0_zeroext: 143; CHECK: @ %bb.0: 144; CHECK-NEXT: rsb r0, r0, #0 145; CHECK-NEXT: mov pc, lr 146 %sel = select i1 %cond, i32 -1, i32 0 147 ret i32 %sel 148} 149 150define i32 @select_neg1_or_0_signext(i1 signext %cond) { 151; CHECK-LABEL: select_neg1_or_0_signext: 152; CHECK: @ %bb.0: 153; CHECK-NEXT: mov pc, lr 154 %sel = select i1 %cond, i32 -1, i32 0 155 ret i32 %sel 156} 157 158; select Cond, C+1, C --> add (zext Cond), C 159 160define i32 @select_Cplus1_C(i1 %cond) { 161; CHECK-LABEL: select_Cplus1_C: 162; CHECK: @ %bb.0: 163; CHECK-NEXT: mov r1, #41 164; CHECK-NEXT: tst r0, #1 165; CHECK-NEXT: movne r1, #42 166; CHECK-NEXT: mov r0, r1 167; CHECK-NEXT: mov pc, lr 168 %sel = select i1 %cond, i32 42, i32 41 169 ret i32 %sel 170} 171 172define i32 @select_Cplus1_C_zeroext(i1 zeroext %cond) { 173; CHECK-LABEL: select_Cplus1_C_zeroext: 174; CHECK: @ %bb.0: 175; CHECK-NEXT: mov r1, #41 176; CHECK-NEXT: cmp r0, #0 177; CHECK-NEXT: movne r1, #42 178; CHECK-NEXT: mov r0, r1 179; CHECK-NEXT: mov pc, lr 180 %sel = select i1 %cond, i32 42, i32 41 181 ret i32 %sel 182} 183 184define i32 @select_Cplus1_C_signext(i1 signext %cond) { 185; CHECK-LABEL: select_Cplus1_C_signext: 186; CHECK: @ %bb.0: 187; CHECK-NEXT: mov r1, #41 188; CHECK-NEXT: tst r0, #1 189; CHECK-NEXT: movne r1, #42 190; CHECK-NEXT: mov r0, r1 191; CHECK-NEXT: mov pc, lr 192 %sel = select i1 %cond, i32 42, i32 41 193 ret i32 %sel 194} 195 196; select Cond, C, C+1 --> add (sext Cond), C 197 198define i32 @select_C_Cplus1(i1 %cond) { 199; CHECK-LABEL: select_C_Cplus1: 200; CHECK: @ %bb.0: 201; CHECK-NEXT: mov r1, #42 202; CHECK-NEXT: tst r0, #1 203; CHECK-NEXT: movne r1, #41 204; CHECK-NEXT: mov r0, r1 205; CHECK-NEXT: mov pc, lr 206 %sel = select i1 %cond, i32 41, i32 42 207 ret i32 %sel 208} 209 210define i32 @select_C_Cplus1_zeroext(i1 zeroext %cond) { 211; CHECK-LABEL: select_C_Cplus1_zeroext: 212; CHECK: @ %bb.0: 213; CHECK-NEXT: mov r1, #42 214; CHECK-NEXT: cmp r0, #0 215; CHECK-NEXT: movne r1, #41 216; CHECK-NEXT: mov r0, r1 217; CHECK-NEXT: mov pc, lr 218 %sel = select i1 %cond, i32 41, i32 42 219 ret i32 %sel 220} 221 222define i32 @select_C_Cplus1_signext(i1 signext %cond) { 223; CHECK-LABEL: select_C_Cplus1_signext: 224; CHECK: @ %bb.0: 225; CHECK-NEXT: mov r1, #42 226; CHECK-NEXT: tst r0, #1 227; CHECK-NEXT: movne r1, #41 228; CHECK-NEXT: mov r0, r1 229; CHECK-NEXT: mov pc, lr 230 %sel = select i1 %cond, i32 41, i32 42 231 ret i32 %sel 232} 233 234; In general, select of 2 constants could be: 235; select Cond, C1, C2 --> add (mul (zext Cond), C1-C2), C2 --> add (and (sext Cond), C1-C2), C2 236 237define i32 @select_C1_C2(i1 %cond) { 238; CHECK-LABEL: select_C1_C2: 239; CHECK: @ %bb.0: 240; CHECK-NEXT: mov r1, #165 241; CHECK-NEXT: tst r0, #1 242; CHECK-NEXT: orr r1, r1, #256 243; CHECK-NEXT: moveq r1, #42 244; CHECK-NEXT: mov r0, r1 245; CHECK-NEXT: mov pc, lr 246 %sel = select i1 %cond, i32 421, i32 42 247 ret i32 %sel 248} 249 250define i32 @select_C1_C2_zeroext(i1 zeroext %cond) { 251; CHECK-LABEL: select_C1_C2_zeroext: 252; CHECK: @ %bb.0: 253; CHECK-NEXT: mov r1, #165 254; CHECK-NEXT: cmp r0, #0 255; CHECK-NEXT: orr r1, r1, #256 256; CHECK-NEXT: moveq r1, #42 257; CHECK-NEXT: mov r0, r1 258; CHECK-NEXT: mov pc, lr 259 %sel = select i1 %cond, i32 421, i32 42 260 ret i32 %sel 261} 262 263define i32 @select_C1_C2_signext(i1 signext %cond) { 264; CHECK-LABEL: select_C1_C2_signext: 265; CHECK: @ %bb.0: 266; CHECK-NEXT: mov r1, #165 267; CHECK-NEXT: tst r0, #1 268; CHECK-NEXT: orr r1, r1, #256 269; CHECK-NEXT: moveq r1, #42 270; CHECK-NEXT: mov r0, r1 271; CHECK-NEXT: mov pc, lr 272 %sel = select i1 %cond, i32 421, i32 42 273 ret i32 %sel 274} 275 276; 4295032833 = 0x100010001. 277; This becomes an opaque constant via ConstantHoisting, so we don't fold it into the select. 278 279define i64 @opaque_constant1(i1 %cond, i64 %x) { 280; CHECK-LABEL: opaque_constant1: 281; CHECK: @ %bb.0: 282; CHECK-NEXT: .save {r4, lr} 283; CHECK-NEXT: push {r4, lr} 284; CHECK-NEXT: mov lr, #1 285; CHECK-NEXT: ands r12, r0, #1 286; CHECK-NEXT: mov r0, #23 287; CHECK-NEXT: orr lr, lr, #65536 288; CHECK-NEXT: mvnne r0, #3 289; CHECK-NEXT: and r4, r0, lr 290; CHECK-NEXT: movne r12, #1 291; CHECK-NEXT: subs r0, r4, #1 292; CHECK-NEXT: eor r2, r2, lr 293; CHECK-NEXT: eor r3, r3, #1 294; CHECK-NEXT: sbc r1, r12, #0 295; CHECK-NEXT: orrs r2, r2, r3 296; CHECK-NEXT: movne r0, r4 297; CHECK-NEXT: movne r1, r12 298; CHECK-NEXT: pop {r4, lr} 299; CHECK-NEXT: mov pc, lr 300 %sel = select i1 %cond, i64 -4, i64 23 301 %bo = and i64 %sel, 4295032833 ; 0x100010001 302 %cmp = icmp eq i64 %x, 4295032833 303 %sext = sext i1 %cmp to i64 304 %add = add i64 %bo, %sext 305 ret i64 %add 306} 307 308; 65537 == 0x10001. 309; This becomes an opaque constant via ConstantHoisting, so we don't fold it into the select. 310 311define i64 @opaque_constant2(i1 %cond, i64 %x) { 312; CHECK-LABEL: opaque_constant2: 313; CHECK: @ %bb.0: 314; CHECK-NEXT: mov r1, #1 315; CHECK-NEXT: tst r0, #1 316; CHECK-NEXT: orr r1, r1, #65536 317; CHECK-NEXT: mov r0, r1 318; CHECK-NEXT: moveq r0, #23 319; CHECK-NEXT: and r0, r0, r1 320; CHECK-NEXT: mov r1, #0 321; CHECK-NEXT: mov pc, lr 322 %sel = select i1 %cond, i64 65537, i64 23 323 %bo = and i64 %sel, 65537 324 ret i64 %bo 325} 326 327