1; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py 2; RUN: llc -mtriple=riscv32 -mattr=+d -verify-machineinstrs < %s \ 3; RUN: | FileCheck %s -check-prefix=RV32I 4; RUN: llc -mtriple=riscv64 -mattr=+d -verify-machineinstrs < %s \ 5; RUN: | FileCheck %s -check-prefix=RV64I 6 7; Selects of wide values are split into two selects, which can easily cause 8; unnecessary control flow. Here we check some cases where we can currently 9; emit a sequence of selects with shared control flow. 10 11define i64 @cmovcc64(i32 signext %a, i64 %b, i64 %c) nounwind { 12; RV32I-LABEL: cmovcc64: 13; RV32I: # %bb.0: # %entry 14; RV32I-NEXT: addi a5, zero, 123 15; RV32I-NEXT: beq a0, a5, .LBB0_2 16; RV32I-NEXT: # %bb.1: # %entry 17; RV32I-NEXT: mv a1, a3 18; RV32I-NEXT: mv a2, a4 19; RV32I-NEXT: .LBB0_2: # %entry 20; RV32I-NEXT: mv a0, a1 21; RV32I-NEXT: mv a1, a2 22; RV32I-NEXT: ret 23; 24; RV64I-LABEL: cmovcc64: 25; RV64I: # %bb.0: # %entry 26; RV64I-NEXT: addi a3, zero, 123 27; RV64I-NEXT: beq a0, a3, .LBB0_2 28; RV64I-NEXT: # %bb.1: # %entry 29; RV64I-NEXT: mv a1, a2 30; RV64I-NEXT: .LBB0_2: # %entry 31; RV64I-NEXT: mv a0, a1 32; RV64I-NEXT: ret 33entry: 34 %cmp = icmp eq i32 %a, 123 35 %cond = select i1 %cmp, i64 %b, i64 %c 36 ret i64 %cond 37} 38 39define i128 @cmovcc128(i64 signext %a, i128 %b, i128 %c) nounwind { 40; RV32I-LABEL: cmovcc128: 41; RV32I: # %bb.0: # %entry 42; RV32I-NEXT: xori a1, a1, 123 43; RV32I-NEXT: or a1, a1, a2 44; RV32I-NEXT: beqz a1, .LBB1_2 45; RV32I-NEXT: # %bb.1: # %entry 46; RV32I-NEXT: addi a1, a4, 4 47; RV32I-NEXT: addi a2, a4, 8 48; RV32I-NEXT: addi a5, a4, 12 49; RV32I-NEXT: mv a3, a4 50; RV32I-NEXT: j .LBB1_3 51; RV32I-NEXT: .LBB1_2: 52; RV32I-NEXT: addi a1, a3, 4 53; RV32I-NEXT: addi a2, a3, 8 54; RV32I-NEXT: addi a5, a3, 12 55; RV32I-NEXT: .LBB1_3: # %entry 56; RV32I-NEXT: lw a4, 0(a5) 57; RV32I-NEXT: sw a4, 12(a0) 58; RV32I-NEXT: lw a2, 0(a2) 59; RV32I-NEXT: sw a2, 8(a0) 60; RV32I-NEXT: lw a1, 0(a1) 61; RV32I-NEXT: sw a1, 4(a0) 62; RV32I-NEXT: lw a1, 0(a3) 63; RV32I-NEXT: sw a1, 0(a0) 64; RV32I-NEXT: ret 65; 66; RV64I-LABEL: cmovcc128: 67; RV64I: # %bb.0: # %entry 68; RV64I-NEXT: addi a5, zero, 123 69; RV64I-NEXT: beq a0, a5, .LBB1_2 70; RV64I-NEXT: # %bb.1: # %entry 71; RV64I-NEXT: mv a1, a3 72; RV64I-NEXT: mv a2, a4 73; RV64I-NEXT: .LBB1_2: # %entry 74; RV64I-NEXT: mv a0, a1 75; RV64I-NEXT: mv a1, a2 76; RV64I-NEXT: ret 77entry: 78 %cmp = icmp eq i64 %a, 123 79 %cond = select i1 %cmp, i128 %b, i128 %c 80 ret i128 %cond 81} 82 83define i64 @cmov64(i1 %a, i64 %b, i64 %c) nounwind { 84; RV32I-LABEL: cmov64: 85; RV32I: # %bb.0: # %entry 86; RV32I-NEXT: andi a0, a0, 1 87; RV32I-NEXT: bnez a0, .LBB2_2 88; RV32I-NEXT: # %bb.1: # %entry 89; RV32I-NEXT: mv a1, a3 90; RV32I-NEXT: mv a2, a4 91; RV32I-NEXT: .LBB2_2: # %entry 92; RV32I-NEXT: mv a0, a1 93; RV32I-NEXT: mv a1, a2 94; RV32I-NEXT: ret 95; 96; RV64I-LABEL: cmov64: 97; RV64I: # %bb.0: # %entry 98; RV64I-NEXT: andi a0, a0, 1 99; RV64I-NEXT: bnez a0, .LBB2_2 100; RV64I-NEXT: # %bb.1: # %entry 101; RV64I-NEXT: mv a1, a2 102; RV64I-NEXT: .LBB2_2: # %entry 103; RV64I-NEXT: mv a0, a1 104; RV64I-NEXT: ret 105entry: 106 %cond = select i1 %a, i64 %b, i64 %c 107 ret i64 %cond 108} 109 110define i128 @cmov128(i1 %a, i128 %b, i128 %c) nounwind { 111; RV32I-LABEL: cmov128: 112; RV32I: # %bb.0: # %entry 113; RV32I-NEXT: andi a1, a1, 1 114; RV32I-NEXT: bnez a1, .LBB3_2 115; RV32I-NEXT: # %bb.1: # %entry 116; RV32I-NEXT: addi a1, a3, 4 117; RV32I-NEXT: addi a4, a3, 8 118; RV32I-NEXT: addi a5, a3, 12 119; RV32I-NEXT: mv a2, a3 120; RV32I-NEXT: j .LBB3_3 121; RV32I-NEXT: .LBB3_2: 122; RV32I-NEXT: addi a1, a2, 4 123; RV32I-NEXT: addi a4, a2, 8 124; RV32I-NEXT: addi a5, a2, 12 125; RV32I-NEXT: .LBB3_3: # %entry 126; RV32I-NEXT: lw a3, 0(a5) 127; RV32I-NEXT: sw a3, 12(a0) 128; RV32I-NEXT: lw a3, 0(a4) 129; RV32I-NEXT: sw a3, 8(a0) 130; RV32I-NEXT: lw a1, 0(a1) 131; RV32I-NEXT: sw a1, 4(a0) 132; RV32I-NEXT: lw a1, 0(a2) 133; RV32I-NEXT: sw a1, 0(a0) 134; RV32I-NEXT: ret 135; 136; RV64I-LABEL: cmov128: 137; RV64I: # %bb.0: # %entry 138; RV64I-NEXT: andi a0, a0, 1 139; RV64I-NEXT: bnez a0, .LBB3_2 140; RV64I-NEXT: # %bb.1: # %entry 141; RV64I-NEXT: mv a1, a3 142; RV64I-NEXT: mv a2, a4 143; RV64I-NEXT: .LBB3_2: # %entry 144; RV64I-NEXT: mv a0, a1 145; RV64I-NEXT: mv a1, a2 146; RV64I-NEXT: ret 147entry: 148 %cond = select i1 %a, i128 %b, i128 %c 149 ret i128 %cond 150} 151 152define float @cmovfloat(i1 %a, float %b, float %c, float %d, float %e) nounwind { 153; RV32I-LABEL: cmovfloat: 154; RV32I: # %bb.0: # %entry 155; RV32I-NEXT: andi a0, a0, 1 156; RV32I-NEXT: bnez a0, .LBB4_2 157; RV32I-NEXT: # %bb.1: # %entry 158; RV32I-NEXT: fmv.w.x ft0, a4 159; RV32I-NEXT: fmv.w.x ft1, a2 160; RV32I-NEXT: j .LBB4_3 161; RV32I-NEXT: .LBB4_2: 162; RV32I-NEXT: fmv.w.x ft0, a3 163; RV32I-NEXT: fmv.w.x ft1, a1 164; RV32I-NEXT: .LBB4_3: # %entry 165; RV32I-NEXT: fadd.s ft0, ft1, ft0 166; RV32I-NEXT: fmv.x.w a0, ft0 167; RV32I-NEXT: ret 168; 169; RV64I-LABEL: cmovfloat: 170; RV64I: # %bb.0: # %entry 171; RV64I-NEXT: andi a0, a0, 1 172; RV64I-NEXT: bnez a0, .LBB4_2 173; RV64I-NEXT: # %bb.1: # %entry 174; RV64I-NEXT: fmv.w.x ft0, a4 175; RV64I-NEXT: fmv.w.x ft1, a2 176; RV64I-NEXT: j .LBB4_3 177; RV64I-NEXT: .LBB4_2: 178; RV64I-NEXT: fmv.w.x ft0, a3 179; RV64I-NEXT: fmv.w.x ft1, a1 180; RV64I-NEXT: .LBB4_3: # %entry 181; RV64I-NEXT: fadd.s ft0, ft1, ft0 182; RV64I-NEXT: fmv.x.w a0, ft0 183; RV64I-NEXT: ret 184entry: 185 %cond1 = select i1 %a, float %b, float %c 186 %cond2 = select i1 %a, float %d, float %e 187 %ret = fadd float %cond1, %cond2 188 ret float %ret 189} 190 191define double @cmovdouble(i1 %a, double %b, double %c) nounwind { 192; RV32I-LABEL: cmovdouble: 193; RV32I: # %bb.0: # %entry 194; RV32I-NEXT: addi sp, sp, -16 195; RV32I-NEXT: sw a3, 8(sp) 196; RV32I-NEXT: sw a4, 12(sp) 197; RV32I-NEXT: fld ft0, 8(sp) 198; RV32I-NEXT: sw a1, 8(sp) 199; RV32I-NEXT: sw a2, 12(sp) 200; RV32I-NEXT: fld ft1, 8(sp) 201; RV32I-NEXT: andi a0, a0, 1 202; RV32I-NEXT: bnez a0, .LBB5_2 203; RV32I-NEXT: # %bb.1: # %entry 204; RV32I-NEXT: fmv.d ft1, ft0 205; RV32I-NEXT: .LBB5_2: # %entry 206; RV32I-NEXT: fsd ft1, 8(sp) 207; RV32I-NEXT: lw a0, 8(sp) 208; RV32I-NEXT: lw a1, 12(sp) 209; RV32I-NEXT: addi sp, sp, 16 210; RV32I-NEXT: ret 211; 212; RV64I-LABEL: cmovdouble: 213; RV64I: # %bb.0: # %entry 214; RV64I-NEXT: andi a0, a0, 1 215; RV64I-NEXT: bnez a0, .LBB5_2 216; RV64I-NEXT: # %bb.1: # %entry 217; RV64I-NEXT: fmv.d.x ft0, a2 218; RV64I-NEXT: fmv.x.d a0, ft0 219; RV64I-NEXT: ret 220; RV64I-NEXT: .LBB5_2: 221; RV64I-NEXT: fmv.d.x ft0, a1 222; RV64I-NEXT: fmv.x.d a0, ft0 223; RV64I-NEXT: ret 224entry: 225 %cond = select i1 %a, double %b, double %c 226 ret double %cond 227} 228 229; Check that selects with dependencies on previous ones aren't incorrectly 230; optimized. 231 232define i32 @cmovccdep(i32 signext %a, i32 %b, i32 %c, i32 %d) nounwind { 233; RV32I-LABEL: cmovccdep: 234; RV32I: # %bb.0: # %entry 235; RV32I-NEXT: addi a4, zero, 123 236; RV32I-NEXT: bne a0, a4, .LBB6_3 237; RV32I-NEXT: # %bb.1: # %entry 238; RV32I-NEXT: mv a2, a1 239; RV32I-NEXT: bne a0, a4, .LBB6_4 240; RV32I-NEXT: .LBB6_2: # %entry 241; RV32I-NEXT: add a0, a1, a2 242; RV32I-NEXT: ret 243; RV32I-NEXT: .LBB6_3: # %entry 244; RV32I-NEXT: mv a1, a2 245; RV32I-NEXT: mv a2, a1 246; RV32I-NEXT: beq a0, a4, .LBB6_2 247; RV32I-NEXT: .LBB6_4: # %entry 248; RV32I-NEXT: mv a2, a3 249; RV32I-NEXT: add a0, a1, a2 250; RV32I-NEXT: ret 251; 252; RV64I-LABEL: cmovccdep: 253; RV64I: # %bb.0: # %entry 254; RV64I-NEXT: addi a4, zero, 123 255; RV64I-NEXT: bne a0, a4, .LBB6_3 256; RV64I-NEXT: # %bb.1: # %entry 257; RV64I-NEXT: mv a2, a1 258; RV64I-NEXT: bne a0, a4, .LBB6_4 259; RV64I-NEXT: .LBB6_2: # %entry 260; RV64I-NEXT: addw a0, a1, a2 261; RV64I-NEXT: ret 262; RV64I-NEXT: .LBB6_3: # %entry 263; RV64I-NEXT: mv a1, a2 264; RV64I-NEXT: mv a2, a1 265; RV64I-NEXT: beq a0, a4, .LBB6_2 266; RV64I-NEXT: .LBB6_4: # %entry 267; RV64I-NEXT: mv a2, a3 268; RV64I-NEXT: addw a0, a1, a2 269; RV64I-NEXT: ret 270entry: 271 %cmp = icmp eq i32 %a, 123 272 %cond1 = select i1 %cmp, i32 %b, i32 %c 273 %cond2 = select i1 %cmp, i32 %cond1, i32 %d 274 %ret = add i32 %cond1, %cond2 275 ret i32 %ret 276} 277 278; Check that selects with different conditions aren't incorrectly optimized. 279 280define i32 @cmovdiffcc(i1 %a, i1 %b, i32 %c, i32 %d, i32 %e, i32 %f) nounwind { 281; RV32I-LABEL: cmovdiffcc: 282; RV32I: # %bb.0: # %entry 283; RV32I-NEXT: andi a1, a1, 1 284; RV32I-NEXT: beqz a1, .LBB7_3 285; RV32I-NEXT: # %bb.1: # %entry 286; RV32I-NEXT: andi a0, a0, 1 287; RV32I-NEXT: beqz a0, .LBB7_4 288; RV32I-NEXT: .LBB7_2: # %entry 289; RV32I-NEXT: add a0, a2, a4 290; RV32I-NEXT: ret 291; RV32I-NEXT: .LBB7_3: # %entry 292; RV32I-NEXT: mv a4, a5 293; RV32I-NEXT: andi a0, a0, 1 294; RV32I-NEXT: bnez a0, .LBB7_2 295; RV32I-NEXT: .LBB7_4: # %entry 296; RV32I-NEXT: mv a2, a3 297; RV32I-NEXT: add a0, a2, a4 298; RV32I-NEXT: ret 299; 300; RV64I-LABEL: cmovdiffcc: 301; RV64I: # %bb.0: # %entry 302; RV64I-NEXT: andi a1, a1, 1 303; RV64I-NEXT: beqz a1, .LBB7_3 304; RV64I-NEXT: # %bb.1: # %entry 305; RV64I-NEXT: andi a0, a0, 1 306; RV64I-NEXT: beqz a0, .LBB7_4 307; RV64I-NEXT: .LBB7_2: # %entry 308; RV64I-NEXT: addw a0, a2, a4 309; RV64I-NEXT: ret 310; RV64I-NEXT: .LBB7_3: # %entry 311; RV64I-NEXT: mv a4, a5 312; RV64I-NEXT: andi a0, a0, 1 313; RV64I-NEXT: bnez a0, .LBB7_2 314; RV64I-NEXT: .LBB7_4: # %entry 315; RV64I-NEXT: mv a2, a3 316; RV64I-NEXT: addw a0, a2, a4 317; RV64I-NEXT: ret 318entry: 319 %cond1 = select i1 %a, i32 %c, i32 %d 320 %cond2 = select i1 %b, i32 %e, i32 %f 321 %ret = add i32 %cond1, %cond2 322 ret i32 %ret 323} 324