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: fmv.w.x ft0, a1 343; RV32IF-NEXT: fmv.w.x ft1, a0 344; RV32IF-NEXT: fmv.w.x ft2, a2 345; RV32IF-NEXT: fmv.w.x ft3, zero 346; RV32IF-NEXT: fadd.s ft2, ft2, ft3 347; RV32IF-NEXT: fmsub.s ft0, ft1, ft0, ft2 348; RV32IF-NEXT: fmv.x.w a0, ft0 349; RV32IF-NEXT: ret 350; 351; RV64IF-LABEL: fmsub_s: 352; RV64IF: # %bb.0: 353; RV64IF-NEXT: fmv.w.x ft0, a1 354; RV64IF-NEXT: fmv.w.x ft1, a0 355; RV64IF-NEXT: fmv.w.x ft2, a2 356; RV64IF-NEXT: fmv.w.x ft3, zero 357; RV64IF-NEXT: fadd.s ft2, ft2, ft3 358; RV64IF-NEXT: fmsub.s ft0, ft1, ft0, ft2 359; RV64IF-NEXT: fmv.x.w a0, ft0 360; RV64IF-NEXT: ret 361 %c_ = fadd float 0.0, %c ; avoid negation using xor 362 %negc = fsub float -0.0, %c_ 363 %1 = call float @llvm.fma.f32(float %a, float %b, float %negc) 364 ret float %1 365} 366 367define float @fnmadd_s(float %a, float %b, float %c) nounwind { 368; RV32IF-LABEL: fnmadd_s: 369; RV32IF: # %bb.0: 370; RV32IF-NEXT: fmv.w.x ft0, a1 371; RV32IF-NEXT: fmv.w.x ft1, a2 372; RV32IF-NEXT: fmv.w.x ft2, a0 373; RV32IF-NEXT: fmv.w.x ft3, zero 374; RV32IF-NEXT: fadd.s ft2, ft2, ft3 375; RV32IF-NEXT: fadd.s ft1, ft1, ft3 376; RV32IF-NEXT: fnmadd.s ft0, ft2, ft0, ft1 377; RV32IF-NEXT: fmv.x.w a0, ft0 378; RV32IF-NEXT: ret 379; 380; RV64IF-LABEL: fnmadd_s: 381; RV64IF: # %bb.0: 382; RV64IF-NEXT: fmv.w.x ft0, a1 383; RV64IF-NEXT: fmv.w.x ft1, a2 384; RV64IF-NEXT: fmv.w.x ft2, a0 385; RV64IF-NEXT: fmv.w.x ft3, zero 386; RV64IF-NEXT: fadd.s ft2, ft2, ft3 387; RV64IF-NEXT: fadd.s ft1, ft1, ft3 388; RV64IF-NEXT: fnmadd.s ft0, ft2, ft0, ft1 389; RV64IF-NEXT: fmv.x.w a0, ft0 390; RV64IF-NEXT: ret 391 %a_ = fadd float 0.0, %a 392 %c_ = fadd float 0.0, %c 393 %nega = fsub float -0.0, %a_ 394 %negc = fsub float -0.0, %c_ 395 %1 = call float @llvm.fma.f32(float %nega, float %b, float %negc) 396 ret float %1 397} 398 399define float @fnmadd_s_2(float %a, float %b, float %c) nounwind { 400; RV32IF-LABEL: fnmadd_s_2: 401; RV32IF: # %bb.0: 402; RV32IF-NEXT: fmv.w.x ft0, a0 403; RV32IF-NEXT: fmv.w.x ft1, a2 404; RV32IF-NEXT: fmv.w.x ft2, a1 405; RV32IF-NEXT: fmv.w.x ft3, zero 406; RV32IF-NEXT: fadd.s ft2, ft2, ft3 407; RV32IF-NEXT: fadd.s ft1, ft1, ft3 408; RV32IF-NEXT: fnmadd.s ft0, ft2, ft0, ft1 409; RV32IF-NEXT: fmv.x.w a0, ft0 410; RV32IF-NEXT: ret 411; 412; RV64IF-LABEL: fnmadd_s_2: 413; RV64IF: # %bb.0: 414; RV64IF-NEXT: fmv.w.x ft0, a0 415; RV64IF-NEXT: fmv.w.x ft1, a2 416; RV64IF-NEXT: fmv.w.x ft2, a1 417; RV64IF-NEXT: fmv.w.x ft3, zero 418; RV64IF-NEXT: fadd.s ft2, ft2, ft3 419; RV64IF-NEXT: fadd.s ft1, ft1, ft3 420; RV64IF-NEXT: fnmadd.s ft0, ft2, ft0, ft1 421; RV64IF-NEXT: fmv.x.w a0, ft0 422; RV64IF-NEXT: ret 423 %b_ = fadd float 0.0, %b 424 %c_ = fadd float 0.0, %c 425 %negb = fsub float -0.0, %b_ 426 %negc = fsub float -0.0, %c_ 427 %1 = call float @llvm.fma.f32(float %a, float %negb, float %negc) 428 ret float %1 429} 430 431define float @fnmsub_s(float %a, float %b, float %c) nounwind { 432; RV32IF-LABEL: fnmsub_s: 433; RV32IF: # %bb.0: 434; RV32IF-NEXT: fmv.w.x ft0, a2 435; RV32IF-NEXT: fmv.w.x ft1, a1 436; RV32IF-NEXT: fmv.w.x ft2, a0 437; RV32IF-NEXT: fmv.w.x ft3, zero 438; RV32IF-NEXT: fadd.s ft2, ft2, ft3 439; RV32IF-NEXT: fnmsub.s ft0, ft2, ft1, ft0 440; RV32IF-NEXT: fmv.x.w a0, ft0 441; RV32IF-NEXT: ret 442; 443; RV64IF-LABEL: fnmsub_s: 444; RV64IF: # %bb.0: 445; RV64IF-NEXT: fmv.w.x ft0, a2 446; RV64IF-NEXT: fmv.w.x ft1, a1 447; RV64IF-NEXT: fmv.w.x ft2, a0 448; RV64IF-NEXT: fmv.w.x ft3, zero 449; RV64IF-NEXT: fadd.s ft2, ft2, ft3 450; RV64IF-NEXT: fnmsub.s ft0, ft2, ft1, ft0 451; RV64IF-NEXT: fmv.x.w a0, ft0 452; RV64IF-NEXT: ret 453 %a_ = fadd float 0.0, %a 454 %nega = fsub float -0.0, %a_ 455 %1 = call float @llvm.fma.f32(float %nega, float %b, float %c) 456 ret float %1 457} 458 459define float @fnmsub_s_2(float %a, float %b, float %c) nounwind { 460; RV32IF-LABEL: fnmsub_s_2: 461; RV32IF: # %bb.0: 462; RV32IF-NEXT: fmv.w.x ft0, a2 463; RV32IF-NEXT: fmv.w.x ft1, a0 464; RV32IF-NEXT: fmv.w.x ft2, a1 465; RV32IF-NEXT: fmv.w.x ft3, zero 466; RV32IF-NEXT: fadd.s ft2, ft2, ft3 467; RV32IF-NEXT: fnmsub.s ft0, ft2, ft1, ft0 468; RV32IF-NEXT: fmv.x.w a0, ft0 469; RV32IF-NEXT: ret 470; 471; RV64IF-LABEL: fnmsub_s_2: 472; RV64IF: # %bb.0: 473; RV64IF-NEXT: fmv.w.x ft0, a2 474; RV64IF-NEXT: fmv.w.x ft1, a0 475; RV64IF-NEXT: fmv.w.x ft2, a1 476; RV64IF-NEXT: fmv.w.x ft3, zero 477; RV64IF-NEXT: fadd.s ft2, ft2, ft3 478; RV64IF-NEXT: fnmsub.s ft0, ft2, ft1, ft0 479; RV64IF-NEXT: fmv.x.w a0, ft0 480; RV64IF-NEXT: ret 481 %b_ = fadd float 0.0, %b 482 %negb = fsub float -0.0, %b_ 483 %1 = call float @llvm.fma.f32(float %a, float %negb, float %c) 484 ret float %1 485} 486 487define float @fmadd_s_contract(float %a, float %b, float %c) nounwind { 488; RV32IF-LABEL: fmadd_s_contract: 489; RV32IF: # %bb.0: 490; RV32IF-NEXT: fmv.w.x ft0, a2 491; RV32IF-NEXT: fmv.w.x ft1, a1 492; RV32IF-NEXT: fmv.w.x ft2, a0 493; RV32IF-NEXT: fmadd.s ft0, ft2, ft1, ft0 494; RV32IF-NEXT: fmv.x.w a0, ft0 495; RV32IF-NEXT: ret 496; 497; RV64IF-LABEL: fmadd_s_contract: 498; RV64IF: # %bb.0: 499; RV64IF-NEXT: fmv.w.x ft0, a2 500; RV64IF-NEXT: fmv.w.x ft1, a1 501; RV64IF-NEXT: fmv.w.x ft2, a0 502; RV64IF-NEXT: fmadd.s ft0, ft2, ft1, ft0 503; RV64IF-NEXT: fmv.x.w a0, ft0 504; RV64IF-NEXT: ret 505 %1 = fmul contract float %a, %b 506 %2 = fadd contract float %1, %c 507 ret float %2 508} 509 510define float @fmsub_s_contract(float %a, float %b, float %c) nounwind { 511; RV32IF-LABEL: fmsub_s_contract: 512; RV32IF: # %bb.0: 513; RV32IF-NEXT: fmv.w.x ft0, a1 514; RV32IF-NEXT: fmv.w.x ft1, a0 515; RV32IF-NEXT: fmv.w.x ft2, a2 516; RV32IF-NEXT: fmv.w.x ft3, zero 517; RV32IF-NEXT: fadd.s ft2, ft2, ft3 518; RV32IF-NEXT: fmsub.s ft0, ft1, ft0, ft2 519; RV32IF-NEXT: fmv.x.w a0, ft0 520; RV32IF-NEXT: ret 521; 522; RV64IF-LABEL: fmsub_s_contract: 523; RV64IF: # %bb.0: 524; RV64IF-NEXT: fmv.w.x ft0, a1 525; RV64IF-NEXT: fmv.w.x ft1, a0 526; RV64IF-NEXT: fmv.w.x ft2, a2 527; RV64IF-NEXT: fmv.w.x ft3, zero 528; RV64IF-NEXT: fadd.s ft2, ft2, ft3 529; RV64IF-NEXT: fmsub.s ft0, ft1, ft0, ft2 530; RV64IF-NEXT: fmv.x.w a0, ft0 531; RV64IF-NEXT: ret 532 %c_ = fadd float 0.0, %c ; avoid negation using xor 533 %1 = fmul contract float %a, %b 534 %2 = fsub contract float %1, %c_ 535 ret float %2 536} 537 538define float @fnmadd_s_contract(float %a, float %b, float %c) nounwind { 539; RV32IF-LABEL: fnmadd_s_contract: 540; RV32IF: # %bb.0: 541; RV32IF-NEXT: fmv.w.x ft0, a2 542; RV32IF-NEXT: fmv.w.x ft1, a1 543; RV32IF-NEXT: fmv.w.x ft2, a0 544; RV32IF-NEXT: fmv.w.x ft3, zero 545; RV32IF-NEXT: fadd.s ft2, ft2, ft3 546; RV32IF-NEXT: fadd.s ft1, ft1, ft3 547; RV32IF-NEXT: fadd.s ft0, ft0, ft3 548; RV32IF-NEXT: fnmadd.s ft0, ft2, ft1, ft0 549; RV32IF-NEXT: fmv.x.w a0, ft0 550; RV32IF-NEXT: ret 551; 552; RV64IF-LABEL: fnmadd_s_contract: 553; RV64IF: # %bb.0: 554; RV64IF-NEXT: fmv.w.x ft0, a2 555; RV64IF-NEXT: fmv.w.x ft1, a1 556; RV64IF-NEXT: fmv.w.x ft2, a0 557; RV64IF-NEXT: fmv.w.x ft3, zero 558; RV64IF-NEXT: fadd.s ft2, ft2, ft3 559; RV64IF-NEXT: fadd.s ft1, ft1, ft3 560; RV64IF-NEXT: fadd.s ft0, ft0, ft3 561; RV64IF-NEXT: fnmadd.s ft0, ft2, ft1, ft0 562; RV64IF-NEXT: fmv.x.w a0, ft0 563; RV64IF-NEXT: ret 564 %a_ = fadd float 0.0, %a ; avoid negation using xor 565 %b_ = fadd float 0.0, %b ; avoid negation using xor 566 %c_ = fadd float 0.0, %c ; avoid negation using xor 567 %1 = fmul contract float %a_, %b_ 568 %2 = fneg float %1 569 %3 = fsub contract float %2, %c_ 570 ret float %3 571} 572 573define float @fnmsub_s_contract(float %a, float %b, float %c) nounwind { 574; RV32IF-LABEL: fnmsub_s_contract: 575; RV32IF: # %bb.0: 576; RV32IF-NEXT: fmv.w.x ft0, a2 577; RV32IF-NEXT: fmv.w.x ft1, a1 578; RV32IF-NEXT: fmv.w.x ft2, a0 579; RV32IF-NEXT: fmv.w.x ft3, zero 580; RV32IF-NEXT: fadd.s ft2, ft2, ft3 581; RV32IF-NEXT: fadd.s ft1, ft1, ft3 582; RV32IF-NEXT: fnmsub.s ft0, ft2, ft1, ft0 583; RV32IF-NEXT: fmv.x.w a0, ft0 584; RV32IF-NEXT: ret 585; 586; RV64IF-LABEL: fnmsub_s_contract: 587; RV64IF: # %bb.0: 588; RV64IF-NEXT: fmv.w.x ft0, a2 589; RV64IF-NEXT: fmv.w.x ft1, a1 590; RV64IF-NEXT: fmv.w.x ft2, a0 591; RV64IF-NEXT: fmv.w.x ft3, zero 592; RV64IF-NEXT: fadd.s ft2, ft2, ft3 593; RV64IF-NEXT: fadd.s ft1, ft1, ft3 594; RV64IF-NEXT: fnmsub.s ft0, ft2, ft1, ft0 595; RV64IF-NEXT: fmv.x.w a0, ft0 596; RV64IF-NEXT: ret 597 %a_ = fadd float 0.0, %a ; avoid negation using xor 598 %b_ = fadd float 0.0, %b ; avoid negation using xor 599 %1 = fmul contract float %a_, %b_ 600 %2 = fsub contract float %c, %1 601 ret float %2 602} 603