1; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py 2; RUN: llc -mtriple=riscv32 -mattr=+f -verify-machineinstrs < %s \ 3; RUN: | FileCheck -check-prefix=RV32IF %s 4; RUN: llc -mtriple=riscv64 -mattr=+f -verify-machineinstrs < %s \ 5; RUN: | FileCheck -check-prefix=RV64IF %s 6 7; These tests are each targeted at a particular RISC-V FPU instruction. Most 8; other files in this folder exercise LLVM IR instructions that don't directly 9; match a RISC-V instruction. 10 11define float @fadd_s(float %a, float %b) nounwind { 12; RV32IF-LABEL: fadd_s: 13; RV32IF: # %bb.0: 14; RV32IF-NEXT: fmv.w.x ft0, a1 15; RV32IF-NEXT: fmv.w.x ft1, a0 16; RV32IF-NEXT: fadd.s ft0, ft1, ft0 17; RV32IF-NEXT: fmv.x.w a0, ft0 18; RV32IF-NEXT: ret 19; 20; RV64IF-LABEL: fadd_s: 21; RV64IF: # %bb.0: 22; RV64IF-NEXT: fmv.w.x ft0, a1 23; RV64IF-NEXT: fmv.w.x ft1, a0 24; RV64IF-NEXT: fadd.s ft0, ft1, ft0 25; RV64IF-NEXT: fmv.x.w a0, ft0 26; RV64IF-NEXT: ret 27 %1 = fadd float %a, %b 28 ret float %1 29} 30 31define float @fsub_s(float %a, float %b) nounwind { 32; RV32IF-LABEL: fsub_s: 33; RV32IF: # %bb.0: 34; RV32IF-NEXT: fmv.w.x ft0, a1 35; RV32IF-NEXT: fmv.w.x ft1, a0 36; RV32IF-NEXT: fsub.s ft0, ft1, ft0 37; RV32IF-NEXT: fmv.x.w a0, ft0 38; RV32IF-NEXT: ret 39; 40; RV64IF-LABEL: fsub_s: 41; RV64IF: # %bb.0: 42; RV64IF-NEXT: fmv.w.x ft0, a1 43; RV64IF-NEXT: fmv.w.x ft1, a0 44; RV64IF-NEXT: fsub.s ft0, ft1, ft0 45; RV64IF-NEXT: fmv.x.w a0, ft0 46; RV64IF-NEXT: ret 47 %1 = fsub float %a, %b 48 ret float %1 49} 50 51define float @fmul_s(float %a, float %b) nounwind { 52; RV32IF-LABEL: fmul_s: 53; RV32IF: # %bb.0: 54; RV32IF-NEXT: fmv.w.x ft0, a1 55; RV32IF-NEXT: fmv.w.x ft1, a0 56; RV32IF-NEXT: fmul.s ft0, ft1, ft0 57; RV32IF-NEXT: fmv.x.w a0, ft0 58; RV32IF-NEXT: ret 59; 60; RV64IF-LABEL: fmul_s: 61; RV64IF: # %bb.0: 62; RV64IF-NEXT: fmv.w.x ft0, a1 63; RV64IF-NEXT: fmv.w.x ft1, a0 64; RV64IF-NEXT: fmul.s ft0, ft1, ft0 65; RV64IF-NEXT: fmv.x.w a0, ft0 66; RV64IF-NEXT: ret 67 %1 = fmul float %a, %b 68 ret float %1 69} 70 71define float @fdiv_s(float %a, float %b) nounwind { 72; RV32IF-LABEL: fdiv_s: 73; RV32IF: # %bb.0: 74; RV32IF-NEXT: fmv.w.x ft0, a1 75; RV32IF-NEXT: fmv.w.x ft1, a0 76; RV32IF-NEXT: fdiv.s ft0, ft1, ft0 77; RV32IF-NEXT: fmv.x.w a0, ft0 78; RV32IF-NEXT: ret 79; 80; RV64IF-LABEL: fdiv_s: 81; RV64IF: # %bb.0: 82; RV64IF-NEXT: fmv.w.x ft0, a1 83; RV64IF-NEXT: fmv.w.x ft1, a0 84; RV64IF-NEXT: fdiv.s ft0, ft1, ft0 85; RV64IF-NEXT: fmv.x.w a0, ft0 86; RV64IF-NEXT: ret 87 %1 = fdiv float %a, %b 88 ret float %1 89} 90 91declare float @llvm.sqrt.f32(float) 92 93define float @fsqrt_s(float %a) nounwind { 94; RV32IF-LABEL: fsqrt_s: 95; RV32IF: # %bb.0: 96; RV32IF-NEXT: fmv.w.x ft0, a0 97; RV32IF-NEXT: fsqrt.s ft0, ft0 98; RV32IF-NEXT: fmv.x.w a0, ft0 99; RV32IF-NEXT: ret 100; 101; RV64IF-LABEL: fsqrt_s: 102; RV64IF: # %bb.0: 103; RV64IF-NEXT: fmv.w.x ft0, a0 104; RV64IF-NEXT: fsqrt.s ft0, ft0 105; RV64IF-NEXT: fmv.x.w a0, ft0 106; RV64IF-NEXT: ret 107 %1 = call float @llvm.sqrt.f32(float %a) 108 ret float %1 109} 110 111declare float @llvm.copysign.f32(float, float) 112 113define float @fsgnj_s(float %a, float %b) nounwind { 114; RV32IF-LABEL: fsgnj_s: 115; RV32IF: # %bb.0: 116; RV32IF-NEXT: fmv.w.x ft0, a1 117; RV32IF-NEXT: fmv.w.x ft1, a0 118; RV32IF-NEXT: fsgnj.s ft0, ft1, ft0 119; RV32IF-NEXT: fmv.x.w a0, ft0 120; RV32IF-NEXT: ret 121; 122; RV64IF-LABEL: fsgnj_s: 123; RV64IF: # %bb.0: 124; RV64IF-NEXT: fmv.w.x ft0, a1 125; RV64IF-NEXT: fmv.w.x ft1, a0 126; RV64IF-NEXT: fsgnj.s ft0, ft1, ft0 127; RV64IF-NEXT: fmv.x.w a0, ft0 128; RV64IF-NEXT: ret 129 %1 = call float @llvm.copysign.f32(float %a, float %b) 130 ret float %1 131} 132 133; This function performs extra work to ensure that 134; DAGCombiner::visitBITCAST doesn't replace the fneg with an xor. 135define i32 @fneg_s(float %a, float %b) nounwind { 136; RV32IF-LABEL: fneg_s: 137; RV32IF: # %bb.0: 138; RV32IF-NEXT: fmv.w.x ft0, a0 139; RV32IF-NEXT: fadd.s ft0, ft0, ft0 140; RV32IF-NEXT: fneg.s ft1, ft0 141; RV32IF-NEXT: feq.s a0, ft0, ft1 142; RV32IF-NEXT: ret 143; 144; RV64IF-LABEL: fneg_s: 145; RV64IF: # %bb.0: 146; RV64IF-NEXT: fmv.w.x ft0, a0 147; RV64IF-NEXT: fadd.s ft0, ft0, ft0 148; RV64IF-NEXT: fneg.s ft1, ft0 149; RV64IF-NEXT: feq.s a0, ft0, ft1 150; RV64IF-NEXT: ret 151 %1 = fadd float %a, %a 152 %2 = fneg float %1 153 %3 = fcmp oeq float %1, %2 154 %4 = zext i1 %3 to i32 155 ret i32 %4 156} 157 158; This function performs extra work to ensure that 159; DAGCombiner::visitBITCAST doesn't replace the fneg with an xor. 160define float @fsgnjn_s(float %a, float %b) nounwind { 161; RV32IF-LABEL: fsgnjn_s: 162; RV32IF: # %bb.0: 163; RV32IF-NEXT: fmv.w.x ft0, a1 164; RV32IF-NEXT: fmv.w.x ft1, a0 165; RV32IF-NEXT: fadd.s ft0, ft1, ft0 166; RV32IF-NEXT: fsgnjn.s ft0, ft1, ft0 167; RV32IF-NEXT: fmv.x.w a0, ft0 168; RV32IF-NEXT: ret 169; 170; RV64IF-LABEL: fsgnjn_s: 171; RV64IF: # %bb.0: 172; RV64IF-NEXT: fmv.w.x ft0, a1 173; RV64IF-NEXT: fmv.w.x ft1, a0 174; RV64IF-NEXT: fadd.s ft0, ft1, ft0 175; RV64IF-NEXT: fsgnjn.s ft0, ft1, ft0 176; RV64IF-NEXT: fmv.x.w a0, ft0 177; RV64IF-NEXT: ret 178 %1 = fadd float %a, %b 179 %2 = fneg float %1 180 %3 = call float @llvm.copysign.f32(float %a, float %2) 181 ret float %3 182} 183 184declare float @llvm.fabs.f32(float) 185 186; This function performs extra work to ensure that 187; DAGCombiner::visitBITCAST doesn't replace the fabs with an and. 188define float @fabs_s(float %a, float %b) nounwind { 189; RV32IF-LABEL: fabs_s: 190; RV32IF: # %bb.0: 191; RV32IF-NEXT: fmv.w.x ft0, a1 192; RV32IF-NEXT: fmv.w.x ft1, a0 193; RV32IF-NEXT: fadd.s ft0, ft1, ft0 194; RV32IF-NEXT: fabs.s ft1, ft0 195; RV32IF-NEXT: fadd.s ft0, ft1, ft0 196; RV32IF-NEXT: fmv.x.w a0, ft0 197; RV32IF-NEXT: ret 198; 199; RV64IF-LABEL: fabs_s: 200; RV64IF: # %bb.0: 201; RV64IF-NEXT: fmv.w.x ft0, a1 202; RV64IF-NEXT: fmv.w.x ft1, a0 203; RV64IF-NEXT: fadd.s ft0, ft1, ft0 204; RV64IF-NEXT: fabs.s ft1, ft0 205; RV64IF-NEXT: fadd.s ft0, ft1, ft0 206; RV64IF-NEXT: fmv.x.w a0, ft0 207; RV64IF-NEXT: ret 208 %1 = fadd float %a, %b 209 %2 = call float @llvm.fabs.f32(float %1) 210 %3 = fadd float %2, %1 211 ret float %3 212} 213 214declare float @llvm.minnum.f32(float, float) 215 216define float @fmin_s(float %a, float %b) nounwind { 217; RV32IF-LABEL: fmin_s: 218; RV32IF: # %bb.0: 219; RV32IF-NEXT: fmv.w.x ft0, a1 220; RV32IF-NEXT: fmv.w.x ft1, a0 221; RV32IF-NEXT: fmin.s ft0, ft1, ft0 222; RV32IF-NEXT: fmv.x.w a0, ft0 223; RV32IF-NEXT: ret 224; 225; RV64IF-LABEL: fmin_s: 226; RV64IF: # %bb.0: 227; RV64IF-NEXT: fmv.w.x ft0, a1 228; RV64IF-NEXT: fmv.w.x ft1, a0 229; RV64IF-NEXT: fmin.s ft0, ft1, ft0 230; RV64IF-NEXT: fmv.x.w a0, ft0 231; RV64IF-NEXT: ret 232 %1 = call float @llvm.minnum.f32(float %a, float %b) 233 ret float %1 234} 235 236declare float @llvm.maxnum.f32(float, float) 237 238define float @fmax_s(float %a, float %b) nounwind { 239; RV32IF-LABEL: fmax_s: 240; RV32IF: # %bb.0: 241; RV32IF-NEXT: fmv.w.x ft0, a1 242; RV32IF-NEXT: fmv.w.x ft1, a0 243; RV32IF-NEXT: fmax.s ft0, ft1, ft0 244; RV32IF-NEXT: fmv.x.w a0, ft0 245; RV32IF-NEXT: ret 246; 247; RV64IF-LABEL: fmax_s: 248; RV64IF: # %bb.0: 249; RV64IF-NEXT: fmv.w.x ft0, a1 250; RV64IF-NEXT: fmv.w.x ft1, a0 251; RV64IF-NEXT: fmax.s ft0, ft1, ft0 252; RV64IF-NEXT: fmv.x.w a0, ft0 253; RV64IF-NEXT: ret 254 %1 = call float @llvm.maxnum.f32(float %a, float %b) 255 ret float %1 256} 257 258define i32 @feq_s(float %a, float %b) nounwind { 259; RV32IF-LABEL: feq_s: 260; RV32IF: # %bb.0: 261; RV32IF-NEXT: fmv.w.x ft0, a1 262; RV32IF-NEXT: fmv.w.x ft1, a0 263; RV32IF-NEXT: feq.s a0, ft1, ft0 264; RV32IF-NEXT: ret 265; 266; RV64IF-LABEL: feq_s: 267; RV64IF: # %bb.0: 268; RV64IF-NEXT: fmv.w.x ft0, a1 269; RV64IF-NEXT: fmv.w.x ft1, a0 270; RV64IF-NEXT: feq.s a0, ft1, ft0 271; RV64IF-NEXT: ret 272 %1 = fcmp oeq float %a, %b 273 %2 = zext i1 %1 to i32 274 ret i32 %2 275} 276 277define i32 @flt_s(float %a, float %b) nounwind { 278; RV32IF-LABEL: flt_s: 279; RV32IF: # %bb.0: 280; RV32IF-NEXT: fmv.w.x ft0, a1 281; RV32IF-NEXT: fmv.w.x ft1, a0 282; RV32IF-NEXT: flt.s a0, ft1, ft0 283; RV32IF-NEXT: ret 284; 285; RV64IF-LABEL: flt_s: 286; RV64IF: # %bb.0: 287; RV64IF-NEXT: fmv.w.x ft0, a1 288; RV64IF-NEXT: fmv.w.x ft1, a0 289; RV64IF-NEXT: flt.s a0, ft1, ft0 290; RV64IF-NEXT: ret 291 %1 = fcmp olt float %a, %b 292 %2 = zext i1 %1 to i32 293 ret i32 %2 294} 295 296define i32 @fle_s(float %a, float %b) nounwind { 297; RV32IF-LABEL: fle_s: 298; RV32IF: # %bb.0: 299; RV32IF-NEXT: fmv.w.x ft0, a1 300; RV32IF-NEXT: fmv.w.x ft1, a0 301; RV32IF-NEXT: fle.s a0, ft1, ft0 302; RV32IF-NEXT: ret 303; 304; RV64IF-LABEL: fle_s: 305; RV64IF: # %bb.0: 306; RV64IF-NEXT: fmv.w.x ft0, a1 307; RV64IF-NEXT: fmv.w.x ft1, a0 308; RV64IF-NEXT: fle.s a0, ft1, ft0 309; RV64IF-NEXT: ret 310 %1 = fcmp ole float %a, %b 311 %2 = zext i1 %1 to i32 312 ret i32 %2 313} 314 315declare float @llvm.fma.f32(float, float, float) 316 317define float @fmadd_s(float %a, float %b, float %c) nounwind { 318; RV32IF-LABEL: fmadd_s: 319; RV32IF: # %bb.0: 320; RV32IF-NEXT: fmv.w.x ft0, a2 321; RV32IF-NEXT: fmv.w.x ft1, a1 322; RV32IF-NEXT: fmv.w.x ft2, a0 323; RV32IF-NEXT: fmadd.s ft0, ft2, ft1, ft0 324; RV32IF-NEXT: fmv.x.w a0, ft0 325; RV32IF-NEXT: ret 326; 327; RV64IF-LABEL: fmadd_s: 328; RV64IF: # %bb.0: 329; RV64IF-NEXT: fmv.w.x ft0, a2 330; RV64IF-NEXT: fmv.w.x ft1, a1 331; RV64IF-NEXT: fmv.w.x ft2, a0 332; RV64IF-NEXT: fmadd.s ft0, ft2, ft1, ft0 333; RV64IF-NEXT: fmv.x.w a0, ft0 334; RV64IF-NEXT: ret 335 %1 = call float @llvm.fma.f32(float %a, float %b, float %c) 336 ret float %1 337} 338 339define float @fmsub_s(float %a, float %b, float %c) nounwind { 340; RV32IF-LABEL: fmsub_s: 341; RV32IF: # %bb.0: 342; RV32IF-NEXT: lui a3, %hi(.LCPI15_0) 343; RV32IF-NEXT: addi a3, a3, %lo(.LCPI15_0) 344; RV32IF-NEXT: flw ft0, 0(a3) 345; RV32IF-NEXT: fmv.w.x ft1, a1 346; RV32IF-NEXT: fmv.w.x ft2, a0 347; RV32IF-NEXT: fmv.w.x ft3, a2 348; RV32IF-NEXT: fadd.s ft0, ft3, ft0 349; RV32IF-NEXT: fmsub.s ft0, ft2, ft1, ft0 350; RV32IF-NEXT: fmv.x.w a0, ft0 351; RV32IF-NEXT: ret 352; 353; RV64IF-LABEL: fmsub_s: 354; RV64IF: # %bb.0: 355; RV64IF-NEXT: lui a3, %hi(.LCPI15_0) 356; RV64IF-NEXT: addi a3, a3, %lo(.LCPI15_0) 357; RV64IF-NEXT: flw ft0, 0(a3) 358; RV64IF-NEXT: fmv.w.x ft1, a1 359; RV64IF-NEXT: fmv.w.x ft2, a0 360; RV64IF-NEXT: fmv.w.x ft3, a2 361; RV64IF-NEXT: fadd.s ft0, ft3, ft0 362; RV64IF-NEXT: fmsub.s ft0, ft2, ft1, ft0 363; RV64IF-NEXT: fmv.x.w a0, ft0 364; RV64IF-NEXT: ret 365 %c_ = fadd float 0.0, %c ; avoid negation using xor 366 %negc = fsub float -0.0, %c_ 367 %1 = call float @llvm.fma.f32(float %a, float %b, float %negc) 368 ret float %1 369} 370 371define float @fnmadd_s(float %a, float %b, float %c) nounwind { 372; RV32IF-LABEL: fnmadd_s: 373; RV32IF: # %bb.0: 374; RV32IF-NEXT: lui a3, %hi(.LCPI16_0) 375; RV32IF-NEXT: addi a3, a3, %lo(.LCPI16_0) 376; RV32IF-NEXT: flw ft0, 0(a3) 377; RV32IF-NEXT: fmv.w.x ft1, a1 378; RV32IF-NEXT: fmv.w.x ft2, a2 379; RV32IF-NEXT: fmv.w.x ft3, a0 380; RV32IF-NEXT: fadd.s ft3, ft3, ft0 381; RV32IF-NEXT: fadd.s ft0, ft2, ft0 382; RV32IF-NEXT: fnmadd.s ft0, ft3, ft1, ft0 383; RV32IF-NEXT: fmv.x.w a0, ft0 384; RV32IF-NEXT: ret 385; 386; RV64IF-LABEL: fnmadd_s: 387; RV64IF: # %bb.0: 388; RV64IF-NEXT: lui a3, %hi(.LCPI16_0) 389; RV64IF-NEXT: addi a3, a3, %lo(.LCPI16_0) 390; RV64IF-NEXT: flw ft0, 0(a3) 391; RV64IF-NEXT: fmv.w.x ft1, a1 392; RV64IF-NEXT: fmv.w.x ft2, a2 393; RV64IF-NEXT: fmv.w.x ft3, a0 394; RV64IF-NEXT: fadd.s ft3, ft3, ft0 395; RV64IF-NEXT: fadd.s ft0, ft2, ft0 396; RV64IF-NEXT: fnmadd.s ft0, ft3, ft1, ft0 397; RV64IF-NEXT: fmv.x.w a0, ft0 398; RV64IF-NEXT: ret 399 %a_ = fadd float 0.0, %a 400 %c_ = fadd float 0.0, %c 401 %nega = fsub float -0.0, %a_ 402 %negc = fsub float -0.0, %c_ 403 %1 = call float @llvm.fma.f32(float %nega, float %b, float %negc) 404 ret float %1 405} 406 407define float @fnmsub_s(float %a, float %b, float %c) nounwind { 408; RV32IF-LABEL: fnmsub_s: 409; RV32IF: # %bb.0: 410; RV32IF-NEXT: lui a3, %hi(.LCPI17_0) 411; RV32IF-NEXT: addi a3, a3, %lo(.LCPI17_0) 412; RV32IF-NEXT: flw ft0, 0(a3) 413; RV32IF-NEXT: fmv.w.x ft1, a2 414; RV32IF-NEXT: fmv.w.x ft2, a1 415; RV32IF-NEXT: fmv.w.x ft3, a0 416; RV32IF-NEXT: fadd.s ft0, ft3, ft0 417; RV32IF-NEXT: fnmsub.s ft0, ft0, ft2, ft1 418; RV32IF-NEXT: fmv.x.w a0, ft0 419; RV32IF-NEXT: ret 420; 421; RV64IF-LABEL: fnmsub_s: 422; RV64IF: # %bb.0: 423; RV64IF-NEXT: lui a3, %hi(.LCPI17_0) 424; RV64IF-NEXT: addi a3, a3, %lo(.LCPI17_0) 425; RV64IF-NEXT: flw ft0, 0(a3) 426; RV64IF-NEXT: fmv.w.x ft1, a2 427; RV64IF-NEXT: fmv.w.x ft2, a1 428; RV64IF-NEXT: fmv.w.x ft3, a0 429; RV64IF-NEXT: fadd.s ft0, ft3, ft0 430; RV64IF-NEXT: fnmsub.s ft0, ft0, ft2, ft1 431; RV64IF-NEXT: fmv.x.w a0, ft0 432; RV64IF-NEXT: ret 433 %a_ = fadd float 0.0, %a 434 %nega = fsub float -0.0, %a_ 435 %1 = call float @llvm.fma.f32(float %nega, float %b, float %c) 436 ret float %1 437} 438