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 5; These tests are each targeted at a particular RISC-V FPU instruction. Most 6; other files in this folder exercise LLVM IR instructions that don't directly 7; match a RISC-V instruction. 8 9define float @fadd_s(float %a, float %b) nounwind { 10; RV32IF-LABEL: fadd_s: 11; RV32IF: # %bb.0: 12; RV32IF-NEXT: fmv.w.x ft0, a1 13; RV32IF-NEXT: fmv.w.x ft1, a0 14; RV32IF-NEXT: fadd.s ft0, ft1, ft0 15; RV32IF-NEXT: fmv.x.w a0, ft0 16; RV32IF-NEXT: ret 17 %1 = fadd float %a, %b 18 ret float %1 19} 20 21define float @fsub_s(float %a, float %b) nounwind { 22; RV32IF-LABEL: fsub_s: 23; RV32IF: # %bb.0: 24; RV32IF-NEXT: fmv.w.x ft0, a1 25; RV32IF-NEXT: fmv.w.x ft1, a0 26; RV32IF-NEXT: fsub.s ft0, ft1, ft0 27; RV32IF-NEXT: fmv.x.w a0, ft0 28; RV32IF-NEXT: ret 29 %1 = fsub float %a, %b 30 ret float %1 31} 32 33define float @fmul_s(float %a, float %b) nounwind { 34; RV32IF-LABEL: fmul_s: 35; RV32IF: # %bb.0: 36; RV32IF-NEXT: fmv.w.x ft0, a1 37; RV32IF-NEXT: fmv.w.x ft1, a0 38; RV32IF-NEXT: fmul.s ft0, ft1, ft0 39; RV32IF-NEXT: fmv.x.w a0, ft0 40; RV32IF-NEXT: ret 41 %1 = fmul float %a, %b 42 ret float %1 43} 44 45define float @fdiv_s(float %a, float %b) nounwind { 46; RV32IF-LABEL: fdiv_s: 47; RV32IF: # %bb.0: 48; RV32IF-NEXT: fmv.w.x ft0, a1 49; RV32IF-NEXT: fmv.w.x ft1, a0 50; RV32IF-NEXT: fdiv.s ft0, ft1, ft0 51; RV32IF-NEXT: fmv.x.w a0, ft0 52; RV32IF-NEXT: ret 53 %1 = fdiv float %a, %b 54 ret float %1 55} 56 57declare float @llvm.sqrt.f32(float) 58 59define float @fsqrt_s(float %a) nounwind { 60; RV32IF-LABEL: fsqrt_s: 61; RV32IF: # %bb.0: 62; RV32IF-NEXT: fmv.w.x ft0, a0 63; RV32IF-NEXT: fsqrt.s ft0, ft0 64; RV32IF-NEXT: fmv.x.w a0, ft0 65; RV32IF-NEXT: ret 66 %1 = call float @llvm.sqrt.f32(float %a) 67 ret float %1 68} 69 70declare float @llvm.copysign.f32(float, float) 71 72define float @fsgnj_s(float %a, float %b) nounwind { 73; RV32IF-LABEL: fsgnj_s: 74; RV32IF: # %bb.0: 75; RV32IF-NEXT: fmv.w.x ft0, a1 76; RV32IF-NEXT: fmv.w.x ft1, a0 77; RV32IF-NEXT: fsgnj.s ft0, ft1, ft0 78; RV32IF-NEXT: fmv.x.w a0, ft0 79; RV32IF-NEXT: ret 80 %1 = call float @llvm.copysign.f32(float %a, float %b) 81 ret float %1 82} 83 84define float @fneg_s(float %a) nounwind { 85; TODO: doesn't test the fneg selection pattern because 86; DAGCombiner::visitBITCAST will generate a xor on the incoming integer 87; argument 88; RV32IF-LABEL: fneg_s: 89; RV32IF: # %bb.0: 90; RV32IF-NEXT: lui a1, 524288 91; RV32IF-NEXT: xor a0, a0, a1 92; RV32IF-NEXT: ret 93 %1 = fsub float -0.0, %a 94 ret float %1 95} 96 97define float @fsgnjn_s(float %a, float %b) nounwind { 98; TODO: fsgnjn.s isn't selected because DAGCombiner::visitBITCAST will convert 99; (bitconvert (fneg x)) to a xor 100; RV32IF-LABEL: fsgnjn_s: 101; RV32IF: # %bb.0: 102; RV32IF-NEXT: lui a2, 524288 103; RV32IF-NEXT: xor a1, a1, a2 104; RV32IF-NEXT: fmv.w.x ft0, a1 105; RV32IF-NEXT: fmv.w.x ft1, a0 106; RV32IF-NEXT: fsgnj.s ft0, ft1, ft0 107; RV32IF-NEXT: fmv.x.w a0, ft0 108; RV32IF-NEXT: ret 109 %1 = fsub float -0.0, %b 110 %2 = call float @llvm.copysign.f32(float %a, float %1) 111 ret float %2 112} 113 114declare float @llvm.fabs.f32(float) 115 116define float @fabs_s(float %a) nounwind { 117; TODO: doesn't test the fabs selection pattern because 118; DAGCombiner::visitBITCAST will generate an and on the incoming integer 119; argument 120; RV32IF-LABEL: fabs_s: 121; RV32IF: # %bb.0: 122; RV32IF-NEXT: lui a1, 524288 123; RV32IF-NEXT: addi a1, a1, -1 124; RV32IF-NEXT: and a0, a0, a1 125; RV32IF-NEXT: ret 126 %1 = call float @llvm.fabs.f32(float %a) 127 ret float %1 128} 129 130declare float @llvm.minnum.f32(float, float) 131 132define float @fmin_s(float %a, float %b) nounwind { 133; RV32IF-LABEL: fmin_s: 134; RV32IF: # %bb.0: 135; RV32IF-NEXT: fmv.w.x ft0, a1 136; RV32IF-NEXT: fmv.w.x ft1, a0 137; RV32IF-NEXT: fmin.s ft0, ft1, ft0 138; RV32IF-NEXT: fmv.x.w a0, ft0 139; RV32IF-NEXT: ret 140 %1 = call float @llvm.minnum.f32(float %a, float %b) 141 ret float %1 142} 143 144declare float @llvm.maxnum.f32(float, float) 145 146define float @fmax_s(float %a, float %b) nounwind { 147; RV32IF-LABEL: fmax_s: 148; RV32IF: # %bb.0: 149; RV32IF-NEXT: fmv.w.x ft0, a1 150; RV32IF-NEXT: fmv.w.x ft1, a0 151; RV32IF-NEXT: fmax.s ft0, ft1, ft0 152; RV32IF-NEXT: fmv.x.w a0, ft0 153; RV32IF-NEXT: ret 154 %1 = call float @llvm.maxnum.f32(float %a, float %b) 155 ret float %1 156} 157 158define i32 @feq_s(float %a, float %b) nounwind { 159; RV32IF-LABEL: feq_s: 160; RV32IF: # %bb.0: 161; RV32IF-NEXT: fmv.w.x ft0, a1 162; RV32IF-NEXT: fmv.w.x ft1, a0 163; RV32IF-NEXT: feq.s a0, ft1, ft0 164; RV32IF-NEXT: ret 165 %1 = fcmp oeq float %a, %b 166 %2 = zext i1 %1 to i32 167 ret i32 %2 168} 169 170define i32 @flt_s(float %a, float %b) nounwind { 171; RV32IF-LABEL: flt_s: 172; RV32IF: # %bb.0: 173; RV32IF-NEXT: fmv.w.x ft0, a1 174; RV32IF-NEXT: fmv.w.x ft1, a0 175; RV32IF-NEXT: flt.s a0, ft1, ft0 176; RV32IF-NEXT: ret 177 %1 = fcmp olt float %a, %b 178 %2 = zext i1 %1 to i32 179 ret i32 %2 180} 181 182define i32 @fle_s(float %a, float %b) nounwind { 183; RV32IF-LABEL: fle_s: 184; RV32IF: # %bb.0: 185; RV32IF-NEXT: fmv.w.x ft0, a1 186; RV32IF-NEXT: fmv.w.x ft1, a0 187; RV32IF-NEXT: fle.s a0, ft1, ft0 188; RV32IF-NEXT: ret 189 %1 = fcmp ole float %a, %b 190 %2 = zext i1 %1 to i32 191 ret i32 %2 192} 193 194declare float @llvm.fma.f32(float, float, float) 195 196define float @fmadd_s(float %a, float %b, float %c) nounwind { 197; RV32IF-LABEL: fmadd_s: 198; RV32IF: # %bb.0: 199; RV32IF-NEXT: fmv.w.x ft0, a2 200; RV32IF-NEXT: fmv.w.x ft1, a1 201; RV32IF-NEXT: fmv.w.x ft2, a0 202; RV32IF-NEXT: fmadd.s ft0, ft2, ft1, ft0 203; RV32IF-NEXT: fmv.x.w a0, ft0 204; RV32IF-NEXT: ret 205 %1 = call float @llvm.fma.f32(float %a, float %b, float %c) 206 ret float %1 207} 208 209define float @fmsub_s(float %a, float %b, float %c) nounwind { 210; RV32IF-LABEL: fmsub_s: 211; RV32IF: # %bb.0: 212; RV32IF-NEXT: fmv.w.x ft0, a2 213; RV32IF-NEXT: lui a2, %hi(.LCPI15_0) 214; RV32IF-NEXT: addi a2, a2, %lo(.LCPI15_0) 215; RV32IF-NEXT: flw ft1, 0(a2) 216; RV32IF-NEXT: fadd.s ft0, ft0, ft1 217; RV32IF-NEXT: fmv.w.x ft1, a1 218; RV32IF-NEXT: fmv.w.x ft2, a0 219; RV32IF-NEXT: fmsub.s ft0, ft2, ft1, ft0 220; RV32IF-NEXT: fmv.x.w a0, ft0 221; RV32IF-NEXT: ret 222 %c_ = fadd float 0.0, %c ; avoid negation using xor 223 %negc = fsub float -0.0, %c_ 224 %1 = call float @llvm.fma.f32(float %a, float %b, float %negc) 225 ret float %1 226} 227 228define float @fnmadd_s(float %a, float %b, float %c) nounwind { 229; RV32IF-LABEL: fnmadd_s: 230; RV32IF: # %bb.0: 231; RV32IF-NEXT: fmv.w.x ft0, a2 232; RV32IF-NEXT: lui a2, %hi(.LCPI16_0) 233; RV32IF-NEXT: addi a2, a2, %lo(.LCPI16_0) 234; RV32IF-NEXT: flw ft1, 0(a2) 235; RV32IF-NEXT: fadd.s ft0, ft0, ft1 236; RV32IF-NEXT: fmv.w.x ft2, a0 237; RV32IF-NEXT: fadd.s ft1, ft2, ft1 238; RV32IF-NEXT: fmv.w.x ft2, a1 239; RV32IF-NEXT: fnmadd.s ft0, ft1, ft2, ft0 240; RV32IF-NEXT: fmv.x.w a0, ft0 241; RV32IF-NEXT: ret 242 %a_ = fadd float 0.0, %a 243 %c_ = fadd float 0.0, %c 244 %nega = fsub float -0.0, %a_ 245 %negc = fsub float -0.0, %c_ 246 %1 = call float @llvm.fma.f32(float %nega, float %b, float %negc) 247 ret float %1 248} 249 250define float @fnmsub_s(float %a, float %b, float %c) nounwind { 251; RV32IF-LABEL: fnmsub_s: 252; RV32IF: # %bb.0: 253; RV32IF-NEXT: fmv.w.x ft0, a0 254; RV32IF-NEXT: lui a0, %hi(.LCPI17_0) 255; RV32IF-NEXT: addi a0, a0, %lo(.LCPI17_0) 256; RV32IF-NEXT: flw ft1, 0(a0) 257; RV32IF-NEXT: fadd.s ft0, ft0, ft1 258; RV32IF-NEXT: fmv.w.x ft1, a2 259; RV32IF-NEXT: fmv.w.x ft2, a1 260; RV32IF-NEXT: fnmsub.s ft0, ft0, ft2, ft1 261; RV32IF-NEXT: fmv.x.w a0, ft0 262; RV32IF-NEXT: ret 263 %a_ = fadd float 0.0, %a 264 %nega = fsub float -0.0, %a_ 265 %1 = call float @llvm.fma.f32(float %nega, float %b, float %c) 266 ret float %1 267} 268