1; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py 2; RUN: llc -mtriple=riscv64 -mattr=+c -verify-machineinstrs < %s \ 3; RUN: | FileCheck -check-prefix=NOCMOV %s 4; RUN: llc -mtriple=riscv64 -mattr=+conditional-cmv-fusion,+c -verify-machineinstrs < %s \ 5; RUN: | FileCheck -check-prefixes=CMOV,CMOV-NOZICOND %s 6; RUN: llc -mtriple=riscv64 -mattr=+conditional-cmv-fusion,+c,+zicond -verify-machineinstrs < %s \ 7; RUN: | FileCheck -check-prefixes=CMOV,CMOV-ZICOND %s 8; RUN: llc -mtriple=riscv64 -mattr=+short-forward-branch-opt -verify-machineinstrs < %s \ 9; RUN: | FileCheck -check-prefixes=SHORT_FORWARD,SFB-NOZICOND %s 10; RUN: llc -mtriple=riscv64 -mattr=+short-forward-branch-opt,+c -verify-machineinstrs < %s \ 11; RUN: | FileCheck -check-prefixes=SHORT_FORWARD,SFB-NOZICOND %s 12; RUN: llc -mtriple=riscv64 -mattr=+short-forward-branch-opt,+zicond -verify-machineinstrs < %s \ 13; RUN: | FileCheck -check-prefixes=SHORT_FORWARD,SFB-ZICOND %s 14 15; The conditional move optimization in sifive-p450 requires that only a 16; single c.mv instruction appears in the branch shadow. 17 18; The sifive-7-series can predicate an xor. 19 20define signext i32 @test1(i32 signext %x, i32 signext %y, i32 signext %z) { 21; NOCMOV-LABEL: test1: 22; NOCMOV: # %bb.0: 23; NOCMOV-NEXT: snez a2, a2 24; NOCMOV-NEXT: addi a2, a2, -1 25; NOCMOV-NEXT: and a1, a1, a2 26; NOCMOV-NEXT: xor a0, a0, a1 27; NOCMOV-NEXT: ret 28; 29; CMOV-LABEL: test1: 30; CMOV: # %bb.0: 31; CMOV-NEXT: xor a1, a1, a0 32; CMOV-NEXT: bnez a2, .LBB0_2 33; CMOV-NEXT: # %bb.1: 34; CMOV-NEXT: mv a0, a1 35; CMOV-NEXT: .LBB0_2: 36; CMOV-NEXT: ret 37; 38; SHORT_FORWARD-LABEL: test1: 39; SHORT_FORWARD: # %bb.0: 40; SHORT_FORWARD-NEXT: bnez a2, .LBB0_2 41; SHORT_FORWARD-NEXT: # %bb.1: 42; SHORT_FORWARD-NEXT: xor a0, a0, a1 43; SHORT_FORWARD-NEXT: .LBB0_2: 44; SHORT_FORWARD-NEXT: ret 45 %c = icmp eq i32 %z, 0 46 %a = xor i32 %x, %y 47 %b = select i1 %c, i32 %a, i32 %x 48 ret i32 %b 49} 50 51define signext i32 @test2(i32 signext %x, i32 signext %y, i32 signext %z) { 52; NOCMOV-LABEL: test2: 53; NOCMOV: # %bb.0: 54; NOCMOV-NEXT: seqz a2, a2 55; NOCMOV-NEXT: addi a2, a2, -1 56; NOCMOV-NEXT: and a1, a1, a2 57; NOCMOV-NEXT: xor a0, a0, a1 58; NOCMOV-NEXT: ret 59; 60; CMOV-LABEL: test2: 61; CMOV: # %bb.0: 62; CMOV-NEXT: xor a1, a1, a0 63; CMOV-NEXT: beqz a2, .LBB1_2 64; CMOV-NEXT: # %bb.1: 65; CMOV-NEXT: mv a0, a1 66; CMOV-NEXT: .LBB1_2: 67; CMOV-NEXT: ret 68; 69; SHORT_FORWARD-LABEL: test2: 70; SHORT_FORWARD: # %bb.0: 71; SHORT_FORWARD-NEXT: beqz a2, .LBB1_2 72; SHORT_FORWARD-NEXT: # %bb.1: 73; SHORT_FORWARD-NEXT: xor a0, a0, a1 74; SHORT_FORWARD-NEXT: .LBB1_2: 75; SHORT_FORWARD-NEXT: ret 76 %c = icmp eq i32 %z, 0 77 %a = xor i32 %x, %y 78 %b = select i1 %c, i32 %x, i32 %a 79 ret i32 %b 80} 81 82; Make sure we don't share the same basic block for two selects with the same 83; condition. 84define signext i32 @test3(i32 signext %v, i32 signext %w, i32 signext %x, i32 signext %y, i32 signext %z) { 85; NOCMOV-LABEL: test3: 86; NOCMOV: # %bb.0: 87; NOCMOV-NEXT: seqz a4, a4 88; NOCMOV-NEXT: addi a4, a4, -1 89; NOCMOV-NEXT: and a1, a1, a4 90; NOCMOV-NEXT: and a3, a3, a4 91; NOCMOV-NEXT: xor a0, a0, a1 92; NOCMOV-NEXT: xor a2, a2, a3 93; NOCMOV-NEXT: addw a0, a0, a2 94; NOCMOV-NEXT: ret 95; 96; CMOV-LABEL: test3: 97; CMOV: # %bb.0: 98; CMOV-NEXT: xor a1, a1, a0 99; CMOV-NEXT: xor a3, a3, a2 100; CMOV-NEXT: bnez a4, .LBB2_2 101; CMOV-NEXT: # %bb.1: 102; CMOV-NEXT: mv a1, a0 103; CMOV-NEXT: .LBB2_2: 104; CMOV-NEXT: bnez a4, .LBB2_4 105; CMOV-NEXT: # %bb.3: 106; CMOV-NEXT: mv a3, a2 107; CMOV-NEXT: .LBB2_4: 108; CMOV-NEXT: addw a0, a1, a3 109; CMOV-NEXT: ret 110; 111; SHORT_FORWARD-LABEL: test3: 112; SHORT_FORWARD: # %bb.0: 113; SHORT_FORWARD-NEXT: beqz a4, .LBB2_2 114; SHORT_FORWARD-NEXT: # %bb.1: 115; SHORT_FORWARD-NEXT: xor a0, a0, a1 116; SHORT_FORWARD-NEXT: .LBB2_2: 117; SHORT_FORWARD-NEXT: beqz a4, .LBB2_4 118; SHORT_FORWARD-NEXT: # %bb.3: 119; SHORT_FORWARD-NEXT: xor a2, a2, a3 120; SHORT_FORWARD-NEXT: .LBB2_4: 121; SHORT_FORWARD-NEXT: addw a0, a0, a2 122; SHORT_FORWARD-NEXT: ret 123 %c = icmp eq i32 %z, 0 124 %a = xor i32 %v, %w 125 %b = select i1 %c, i32 %v, i32 %a 126 %d = xor i32 %x, %y 127 %e = select i1 %c, i32 %x, i32 %d 128 %f = add i32 %b, %e 129 ret i32 %f 130} 131 132define signext i32 @test4(i32 signext %x, i32 signext %y, i32 signext %z) { 133; NOCMOV-LABEL: test4: 134; NOCMOV: # %bb.0: 135; NOCMOV-NEXT: snez a0, a2 136; NOCMOV-NEXT: addi a0, a0, -1 137; NOCMOV-NEXT: andi a0, a0, 3 138; NOCMOV-NEXT: ret 139; 140; CMOV-NOZICOND-LABEL: test4: 141; CMOV-NOZICOND: # %bb.0: 142; CMOV-NOZICOND-NEXT: li a1, 0 143; CMOV-NOZICOND-NEXT: li a0, 3 144; CMOV-NOZICOND-NEXT: beqz a2, .LBB3_2 145; CMOV-NOZICOND-NEXT: # %bb.1: 146; CMOV-NOZICOND-NEXT: mv a0, a1 147; CMOV-NOZICOND-NEXT: .LBB3_2: 148; CMOV-NOZICOND-NEXT: ret 149; 150; CMOV-ZICOND-LABEL: test4: 151; CMOV-ZICOND: # %bb.0: 152; CMOV-ZICOND-NEXT: li a0, 3 153; CMOV-ZICOND-NEXT: czero.nez a0, a0, a2 154; CMOV-ZICOND-NEXT: ret 155; 156; SFB-NOZICOND-LABEL: test4: 157; SFB-NOZICOND: # %bb.0: 158; SFB-NOZICOND-NEXT: li a0, 3 159; SFB-NOZICOND-NEXT: beqz a2, .LBB3_2 160; SFB-NOZICOND-NEXT: # %bb.1: 161; SFB-NOZICOND-NEXT: li a0, 0 162; SFB-NOZICOND-NEXT: .LBB3_2: 163; SFB-NOZICOND-NEXT: ret 164; 165; SFB-ZICOND-LABEL: test4: 166; SFB-ZICOND: # %bb.0: 167; SFB-ZICOND-NEXT: li a0, 3 168; SFB-ZICOND-NEXT: czero.nez a0, a0, a2 169; SFB-ZICOND-NEXT: ret 170 %c = icmp eq i32 %z, 0 171 %a = select i1 %c, i32 3, i32 0 172 ret i32 %a 173} 174 175define i16 @select_xor_1(i16 %A, i8 %cond) { 176; NOCMOV-LABEL: select_xor_1: 177; NOCMOV: # %bb.0: # %entry 178; NOCMOV-NEXT: slli a1, a1, 63 179; NOCMOV-NEXT: srai a1, a1, 63 180; NOCMOV-NEXT: andi a1, a1, 43 181; NOCMOV-NEXT: xor a0, a0, a1 182; NOCMOV-NEXT: ret 183; 184; CMOV-LABEL: select_xor_1: 185; CMOV: # %bb.0: # %entry 186; CMOV-NEXT: andi a1, a1, 1 187; CMOV-NEXT: xori a2, a0, 43 188; CMOV-NEXT: beqz a1, .LBB4_2 189; CMOV-NEXT: # %bb.1: # %entry 190; CMOV-NEXT: mv a0, a2 191; CMOV-NEXT: .LBB4_2: # %entry 192; CMOV-NEXT: ret 193; 194; SHORT_FORWARD-LABEL: select_xor_1: 195; SHORT_FORWARD: # %bb.0: # %entry 196; SHORT_FORWARD-NEXT: andi a1, a1, 1 197; SHORT_FORWARD-NEXT: beqz a1, .LBB4_2 198; SHORT_FORWARD-NEXT: # %bb.1: # %entry 199; SHORT_FORWARD-NEXT: xori a0, a0, 43 200; SHORT_FORWARD-NEXT: .LBB4_2: # %entry 201; SHORT_FORWARD-NEXT: ret 202entry: 203 %and = and i8 %cond, 1 204 %cmp10 = icmp eq i8 %and, 0 205 %0 = xor i16 %A, 43 206 %1 = select i1 %cmp10, i16 %A, i16 %0 207 ret i16 %1 208} 209 210; Equivalent to above, but with icmp ne (and %cond, 1), 1 instead of 211; icmp eq (and %cond, 1), 0 212define i16 @select_xor_1b(i16 %A, i8 %cond) { 213; NOCMOV-LABEL: select_xor_1b: 214; NOCMOV: # %bb.0: # %entry 215; NOCMOV-NEXT: slli a1, a1, 63 216; NOCMOV-NEXT: srai a1, a1, 63 217; NOCMOV-NEXT: andi a1, a1, 43 218; NOCMOV-NEXT: xor a0, a0, a1 219; NOCMOV-NEXT: ret 220; 221; CMOV-LABEL: select_xor_1b: 222; CMOV: # %bb.0: # %entry 223; CMOV-NEXT: andi a1, a1, 1 224; CMOV-NEXT: xori a2, a0, 43 225; CMOV-NEXT: beqz a1, .LBB5_2 226; CMOV-NEXT: # %bb.1: # %entry 227; CMOV-NEXT: mv a0, a2 228; CMOV-NEXT: .LBB5_2: # %entry 229; CMOV-NEXT: ret 230; 231; SHORT_FORWARD-LABEL: select_xor_1b: 232; SHORT_FORWARD: # %bb.0: # %entry 233; SHORT_FORWARD-NEXT: andi a1, a1, 1 234; SHORT_FORWARD-NEXT: beqz a1, .LBB5_2 235; SHORT_FORWARD-NEXT: # %bb.1: # %entry 236; SHORT_FORWARD-NEXT: xori a0, a0, 43 237; SHORT_FORWARD-NEXT: .LBB5_2: # %entry 238; SHORT_FORWARD-NEXT: ret 239entry: 240 %and = and i8 %cond, 1 241 %cmp10 = icmp ne i8 %and, 1 242 %0 = xor i16 %A, 43 243 %1 = select i1 %cmp10, i16 %A, i16 %0 244 ret i16 %1 245} 246 247define i32 @select_xor_2(i32 %A, i32 %B, i8 %cond) { 248; NOCMOV-LABEL: select_xor_2: 249; NOCMOV: # %bb.0: # %entry 250; NOCMOV-NEXT: slli a2, a2, 63 251; NOCMOV-NEXT: srai a2, a2, 63 252; NOCMOV-NEXT: and a1, a1, a2 253; NOCMOV-NEXT: xor a0, a0, a1 254; NOCMOV-NEXT: ret 255; 256; CMOV-LABEL: select_xor_2: 257; CMOV: # %bb.0: # %entry 258; CMOV-NEXT: andi a2, a2, 1 259; CMOV-NEXT: xor a1, a1, a0 260; CMOV-NEXT: beqz a2, .LBB6_2 261; CMOV-NEXT: # %bb.1: # %entry 262; CMOV-NEXT: mv a0, a1 263; CMOV-NEXT: .LBB6_2: # %entry 264; CMOV-NEXT: ret 265; 266; SFB-ZICOND-LABEL: select_xor_2: 267; SFB-ZICOND: # %bb.0: # %entry 268; SFB-ZICOND-NEXT: andi a2, a2, 1 269; SFB-ZICOND-NEXT: beqz a2, .LBB6_2 270; SFB-ZICOND-NEXT: # %bb.1: # %entry 271; SFB-ZICOND-NEXT: xor a0, a1, a0 272; SFB-ZICOND-NEXT: .LBB6_2: # %entry 273; SFB-ZICOND-NEXT: ret 274entry: 275 %and = and i8 %cond, 1 276 %cmp10 = icmp eq i8 %and, 0 277 %0 = xor i32 %B, %A 278 %1 = select i1 %cmp10, i32 %A, i32 %0 279 ret i32 %1 280} 281 282; Equivalent to above, but with icmp ne (and %cond, 1), 1 instead of 283; icmp eq (and %cond, 1), 0 284define i32 @select_xor_2b(i32 %A, i32 %B, i8 %cond) { 285; NOCMOV-LABEL: select_xor_2b: 286; NOCMOV: # %bb.0: # %entry 287; NOCMOV-NEXT: slli a2, a2, 63 288; NOCMOV-NEXT: srai a2, a2, 63 289; NOCMOV-NEXT: and a1, a1, a2 290; NOCMOV-NEXT: xor a0, a0, a1 291; NOCMOV-NEXT: ret 292; 293; CMOV-LABEL: select_xor_2b: 294; CMOV: # %bb.0: # %entry 295; CMOV-NEXT: andi a2, a2, 1 296; CMOV-NEXT: xor a1, a1, a0 297; CMOV-NEXT: beqz a2, .LBB7_2 298; CMOV-NEXT: # %bb.1: # %entry 299; CMOV-NEXT: mv a0, a1 300; CMOV-NEXT: .LBB7_2: # %entry 301; CMOV-NEXT: ret 302; 303; SFB-ZICOND-LABEL: select_xor_2b: 304; SFB-ZICOND: # %bb.0: # %entry 305; SFB-ZICOND-NEXT: andi a2, a2, 1 306; SFB-ZICOND-NEXT: beqz a2, .LBB7_2 307; SFB-ZICOND-NEXT: # %bb.1: # %entry 308; SFB-ZICOND-NEXT: xor a0, a1, a0 309; SFB-ZICOND-NEXT: .LBB7_2: # %entry 310; SFB-ZICOND-NEXT: ret 311entry: 312 %and = and i8 %cond, 1 313 %cmp10 = icmp ne i8 %and, 1 314 %0 = xor i32 %B, %A 315 %1 = select i1 %cmp10, i32 %A, i32 %0 316 ret i32 %1 317} 318 319define i32 @select_or(i32 %A, i32 %B, i8 %cond) { 320; NOCMOV-LABEL: select_or: 321; NOCMOV: # %bb.0: # %entry 322; NOCMOV-NEXT: slli a2, a2, 63 323; NOCMOV-NEXT: srai a2, a2, 63 324; NOCMOV-NEXT: and a1, a1, a2 325; NOCMOV-NEXT: or a0, a0, a1 326; NOCMOV-NEXT: ret 327; 328; CMOV-LABEL: select_or: 329; CMOV: # %bb.0: # %entry 330; CMOV-NEXT: andi a2, a2, 1 331; CMOV-NEXT: or a1, a1, a0 332; CMOV-NEXT: beqz a2, .LBB8_2 333; CMOV-NEXT: # %bb.1: # %entry 334; CMOV-NEXT: mv a0, a1 335; CMOV-NEXT: .LBB8_2: # %entry 336; CMOV-NEXT: ret 337; 338; SFB-ZICOND-LABEL: select_or: 339; SFB-ZICOND: # %bb.0: # %entry 340; SFB-ZICOND-NEXT: andi a2, a2, 1 341; SFB-ZICOND-NEXT: beqz a2, .LBB8_2 342; SFB-ZICOND-NEXT: # %bb.1: # %entry 343; SFB-ZICOND-NEXT: or a0, a1, a0 344; SFB-ZICOND-NEXT: .LBB8_2: # %entry 345; SFB-ZICOND-NEXT: ret 346entry: 347 %and = and i8 %cond, 1 348 %cmp10 = icmp eq i8 %and, 0 349 %0 = or i32 %B, %A 350 %1 = select i1 %cmp10, i32 %A, i32 %0 351 ret i32 %1 352} 353 354; Equivalent to above, but with icmp ne (and %cond, 1), 1 instead of 355; icmp eq (and %cond, 1), 0 356define i32 @select_or_b(i32 %A, i32 %B, i8 %cond) { 357; NOCMOV-LABEL: select_or_b: 358; NOCMOV: # %bb.0: # %entry 359; NOCMOV-NEXT: slli a2, a2, 63 360; NOCMOV-NEXT: srai a2, a2, 63 361; NOCMOV-NEXT: and a1, a1, a2 362; NOCMOV-NEXT: or a0, a0, a1 363; NOCMOV-NEXT: ret 364; 365; CMOV-LABEL: select_or_b: 366; CMOV: # %bb.0: # %entry 367; CMOV-NEXT: andi a2, a2, 1 368; CMOV-NEXT: or a1, a1, a0 369; CMOV-NEXT: beqz a2, .LBB9_2 370; CMOV-NEXT: # %bb.1: # %entry 371; CMOV-NEXT: mv a0, a1 372; CMOV-NEXT: .LBB9_2: # %entry 373; CMOV-NEXT: ret 374; 375; SFB-ZICOND-LABEL: select_or_b: 376; SFB-ZICOND: # %bb.0: # %entry 377; SFB-ZICOND-NEXT: andi a2, a2, 1 378; SFB-ZICOND-NEXT: beqz a2, .LBB9_2 379; SFB-ZICOND-NEXT: # %bb.1: # %entry 380; SFB-ZICOND-NEXT: or a0, a1, a0 381; SFB-ZICOND-NEXT: .LBB9_2: # %entry 382; SFB-ZICOND-NEXT: ret 383entry: 384 %and = and i8 %cond, 1 385 %cmp10 = icmp ne i8 %and, 1 386 %0 = or i32 %B, %A 387 %1 = select i1 %cmp10, i32 %A, i32 %0 388 ret i32 %1 389} 390 391define i32 @select_or_1(i32 %A, i32 %B, i32 %cond) { 392; NOCMOV-LABEL: select_or_1: 393; NOCMOV: # %bb.0: # %entry 394; NOCMOV-NEXT: slli a2, a2, 63 395; NOCMOV-NEXT: srai a2, a2, 63 396; NOCMOV-NEXT: and a1, a1, a2 397; NOCMOV-NEXT: or a0, a0, a1 398; NOCMOV-NEXT: ret 399; 400; CMOV-LABEL: select_or_1: 401; CMOV: # %bb.0: # %entry 402; CMOV-NEXT: andi a2, a2, 1 403; CMOV-NEXT: or a1, a1, a0 404; CMOV-NEXT: beqz a2, .LBB10_2 405; CMOV-NEXT: # %bb.1: # %entry 406; CMOV-NEXT: mv a0, a1 407; CMOV-NEXT: .LBB10_2: # %entry 408; CMOV-NEXT: ret 409; 410; SFB-ZICOND-LABEL: select_or_1: 411; SFB-ZICOND: # %bb.0: # %entry 412; SFB-ZICOND-NEXT: andi a2, a2, 1 413; SFB-ZICOND-NEXT: beqz a2, .LBB10_2 414; SFB-ZICOND-NEXT: # %bb.1: # %entry 415; SFB-ZICOND-NEXT: or a0, a1, a0 416; SFB-ZICOND-NEXT: .LBB10_2: # %entry 417; SFB-ZICOND-NEXT: ret 418entry: 419 %and = and i32 %cond, 1 420 %cmp10 = icmp eq i32 %and, 0 421 %0 = or i32 %B, %A 422 %1 = select i1 %cmp10, i32 %A, i32 %0 423 ret i32 %1 424} 425 426; Equivalent to above, but with icmp ne (and %cond, 1), 1 instead of 427; icmp eq (and %cond, 1), 0 428define i32 @select_or_1b(i32 %A, i32 %B, i32 %cond) { 429; NOCMOV-LABEL: select_or_1b: 430; NOCMOV: # %bb.0: # %entry 431; NOCMOV-NEXT: slli a2, a2, 63 432; NOCMOV-NEXT: srai a2, a2, 63 433; NOCMOV-NEXT: and a1, a1, a2 434; NOCMOV-NEXT: or a0, a0, a1 435; NOCMOV-NEXT: ret 436; 437; CMOV-LABEL: select_or_1b: 438; CMOV: # %bb.0: # %entry 439; CMOV-NEXT: andi a2, a2, 1 440; CMOV-NEXT: or a1, a1, a0 441; CMOV-NEXT: beqz a2, .LBB11_2 442; CMOV-NEXT: # %bb.1: # %entry 443; CMOV-NEXT: mv a0, a1 444; CMOV-NEXT: .LBB11_2: # %entry 445; CMOV-NEXT: ret 446; 447; SFB-ZICOND-LABEL: select_or_1b: 448; SFB-ZICOND: # %bb.0: # %entry 449; SFB-ZICOND-NEXT: andi a2, a2, 1 450; SFB-ZICOND-NEXT: beqz a2, .LBB11_2 451; SFB-ZICOND-NEXT: # %bb.1: # %entry 452; SFB-ZICOND-NEXT: or a0, a1, a0 453; SFB-ZICOND-NEXT: .LBB11_2: # %entry 454; SFB-ZICOND-NEXT: ret 455entry: 456 %and = and i32 %cond, 1 457 %cmp10 = icmp ne i32 %and, 1 458 %0 = or i32 %B, %A 459 %1 = select i1 %cmp10, i32 %A, i32 %0 460 ret i32 %1 461} 462