1; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py 2; RUN: llc < %s -disable-wasm-fallthrough-return-opt -wasm-keep-registers | FileCheck %s 3 4; Test that basic 32-bit floating-point operations assemble as expected. 5 6target triple = "wasm32-unknown-unknown" 7 8declare float @llvm.fabs.f32(float) 9declare float @llvm.copysign.f32(float, float) 10declare float @llvm.sqrt.f32(float) 11declare float @llvm.ceil.f32(float) 12declare float @llvm.floor.f32(float) 13declare float @llvm.trunc.f32(float) 14declare float @llvm.nearbyint.f32(float) 15declare float @llvm.rint.f32(float) 16declare float @llvm.roundeven.f32(float) 17declare float @llvm.fma.f32(float, float, float) 18 19define float @fadd32(float %x, float %y) { 20; CHECK-LABEL: fadd32: 21; CHECK: .functype fadd32 (f32, f32) -> (f32) 22; CHECK-NEXT: # %bb.0: 23; CHECK-NEXT: local.get $push2=, 0 24; CHECK-NEXT: local.get $push1=, 1 25; CHECK-NEXT: f32.add $push0=, $pop2, $pop1 26; CHECK-NEXT: return $pop0 27 %a = fadd float %x, %y 28 ret float %a 29} 30 31define float @fsub32(float %x, float %y) { 32; CHECK-LABEL: fsub32: 33; CHECK: .functype fsub32 (f32, f32) -> (f32) 34; CHECK-NEXT: # %bb.0: 35; CHECK-NEXT: local.get $push2=, 0 36; CHECK-NEXT: local.get $push1=, 1 37; CHECK-NEXT: f32.sub $push0=, $pop2, $pop1 38; CHECK-NEXT: return $pop0 39 %a = fsub float %x, %y 40 ret float %a 41} 42 43define float @fmul32(float %x, float %y) { 44; CHECK-LABEL: fmul32: 45; CHECK: .functype fmul32 (f32, f32) -> (f32) 46; CHECK-NEXT: # %bb.0: 47; CHECK-NEXT: local.get $push2=, 0 48; CHECK-NEXT: local.get $push1=, 1 49; CHECK-NEXT: f32.mul $push0=, $pop2, $pop1 50; CHECK-NEXT: return $pop0 51 %a = fmul float %x, %y 52 ret float %a 53} 54 55define float @fdiv32(float %x, float %y) { 56; CHECK-LABEL: fdiv32: 57; CHECK: .functype fdiv32 (f32, f32) -> (f32) 58; CHECK-NEXT: # %bb.0: 59; CHECK-NEXT: local.get $push2=, 0 60; CHECK-NEXT: local.get $push1=, 1 61; CHECK-NEXT: f32.div $push0=, $pop2, $pop1 62; CHECK-NEXT: return $pop0 63 %a = fdiv float %x, %y 64 ret float %a 65} 66 67define float @fabs32(float %x) { 68; CHECK-LABEL: fabs32: 69; CHECK: .functype fabs32 (f32) -> (f32) 70; CHECK-NEXT: # %bb.0: 71; CHECK-NEXT: local.get $push1=, 0 72; CHECK-NEXT: f32.abs $push0=, $pop1 73; CHECK-NEXT: return $pop0 74 %a = call float @llvm.fabs.f32(float %x) 75 ret float %a 76} 77 78define float @fneg32(float %x) { 79; CHECK-LABEL: fneg32: 80; CHECK: .functype fneg32 (f32) -> (f32) 81; CHECK-NEXT: # %bb.0: 82; CHECK-NEXT: local.get $push1=, 0 83; CHECK-NEXT: f32.neg $push0=, $pop1 84; CHECK-NEXT: return $pop0 85 %a = fsub float -0., %x 86 ret float %a 87} 88 89define float @copysign32(float %x, float %y) { 90; CHECK-LABEL: copysign32: 91; CHECK: .functype copysign32 (f32, f32) -> (f32) 92; CHECK-NEXT: # %bb.0: 93; CHECK-NEXT: local.get $push2=, 0 94; CHECK-NEXT: local.get $push1=, 1 95; CHECK-NEXT: f32.copysign $push0=, $pop2, $pop1 96; CHECK-NEXT: return $pop0 97 %a = call float @llvm.copysign.f32(float %x, float %y) 98 ret float %a 99} 100 101define float @sqrt32(float %x) { 102; CHECK-LABEL: sqrt32: 103; CHECK: .functype sqrt32 (f32) -> (f32) 104; CHECK-NEXT: # %bb.0: 105; CHECK-NEXT: local.get $push1=, 0 106; CHECK-NEXT: f32.sqrt $push0=, $pop1 107; CHECK-NEXT: return $pop0 108 %a = call float @llvm.sqrt.f32(float %x) 109 ret float %a 110} 111 112define float @ceil32(float %x) { 113; CHECK-LABEL: ceil32: 114; CHECK: .functype ceil32 (f32) -> (f32) 115; CHECK-NEXT: # %bb.0: 116; CHECK-NEXT: local.get $push1=, 0 117; CHECK-NEXT: f32.ceil $push0=, $pop1 118; CHECK-NEXT: return $pop0 119 %a = call float @llvm.ceil.f32(float %x) 120 ret float %a 121} 122 123define float @floor32(float %x) { 124; CHECK-LABEL: floor32: 125; CHECK: .functype floor32 (f32) -> (f32) 126; CHECK-NEXT: # %bb.0: 127; CHECK-NEXT: local.get $push1=, 0 128; CHECK-NEXT: f32.floor $push0=, $pop1 129; CHECK-NEXT: return $pop0 130 %a = call float @llvm.floor.f32(float %x) 131 ret float %a 132} 133 134define float @trunc32(float %x) { 135; CHECK-LABEL: trunc32: 136; CHECK: .functype trunc32 (f32) -> (f32) 137; CHECK-NEXT: # %bb.0: 138; CHECK-NEXT: local.get $push1=, 0 139; CHECK-NEXT: f32.trunc $push0=, $pop1 140; CHECK-NEXT: return $pop0 141 %a = call float @llvm.trunc.f32(float %x) 142 ret float %a 143} 144 145define float @nearest32(float %x) { 146; CHECK-LABEL: nearest32: 147; CHECK: .functype nearest32 (f32) -> (f32) 148; CHECK-NEXT: # %bb.0: 149; CHECK-NEXT: local.get $push1=, 0 150; CHECK-NEXT: f32.nearest $push0=, $pop1 151; CHECK-NEXT: return $pop0 152 %a = call float @llvm.nearbyint.f32(float %x) 153 ret float %a 154} 155 156define float @nearest32_via_rint(float %x) { 157; CHECK-LABEL: nearest32_via_rint: 158; CHECK: .functype nearest32_via_rint (f32) -> (f32) 159; CHECK-NEXT: # %bb.0: 160; CHECK-NEXT: local.get $push1=, 0 161; CHECK-NEXT: f32.nearest $push0=, $pop1 162; CHECK-NEXT: return $pop0 163 %a = call float @llvm.rint.f32(float %x) 164 ret float %a 165} 166 167define float @nearest32_via_roundeven(float %x) { 168; CHECK-LABEL: nearest32_via_roundeven: 169; CHECK: .functype nearest32_via_roundeven (f32) -> (f32) 170; CHECK-NEXT: # %bb.0: 171; CHECK-NEXT: local.get $push1=, 0 172; CHECK-NEXT: f32.nearest $push0=, $pop1 173; CHECK-NEXT: return $pop0 174 %a = call float @llvm.roundeven.f32(float %x) 175 ret float %a 176} 177 178; This is not "minimum" because a -0.0 input returns +0.0. 179 180define float @fmin32(float %x) { 181; CHECK-LABEL: fmin32: 182; CHECK: .functype fmin32 (f32) -> (f32) 183; CHECK-NEXT: # %bb.0: 184; CHECK-NEXT: f32.const $push0=, 0x0p0 185; CHECK-NEXT: local.get $push5=, 0 186; CHECK-NEXT: local.get $push4=, 0 187; CHECK-NEXT: f32.const $push3=, 0x0p0 188; CHECK-NEXT: f32.ge $push1=, $pop4, $pop3 189; CHECK-NEXT: f32.select $push2=, $pop0, $pop5, $pop1 190; CHECK-NEXT: return $pop2 191 %a = fcmp ult float %x, 0.0 192 %b = select i1 %a, float %x, float 0.0 193 ret float %b 194} 195 196; This is not "maximum" because a -0.0 input returns +0.0. 197 198define float @fmax32(float %x) { 199; CHECK-LABEL: fmax32: 200; CHECK: .functype fmax32 (f32) -> (f32) 201; CHECK-NEXT: # %bb.0: 202; CHECK-NEXT: f32.const $push0=, 0x0p0 203; CHECK-NEXT: local.get $push5=, 0 204; CHECK-NEXT: local.get $push4=, 0 205; CHECK-NEXT: f32.const $push3=, 0x0p0 206; CHECK-NEXT: f32.le $push1=, $pop4, $pop3 207; CHECK-NEXT: f32.select $push2=, $pop0, $pop5, $pop1 208; CHECK-NEXT: return $pop2 209 %a = fcmp ugt float %x, 0.0 210 %b = select i1 %a, float %x, float 0.0 211 ret float %b 212} 213 214declare float @llvm.minimum.f32(float, float) 215define float @fmin32_intrinsic(float %x, float %y) { 216; CHECK-LABEL: fmin32_intrinsic: 217; CHECK: .functype fmin32_intrinsic (f32, f32) -> (f32) 218; CHECK-NEXT: # %bb.0: 219; CHECK-NEXT: local.get $push2=, 0 220; CHECK-NEXT: local.get $push1=, 1 221; CHECK-NEXT: f32.min $push0=, $pop2, $pop1 222; CHECK-NEXT: return $pop0 223 %a = call float @llvm.minimum.f32(float %x, float %y) 224 ret float %a 225} 226 227declare float @llvm.minnum.f32(float, float) 228define float @fminnum32_intrinsic(float %x, float %y) { 229; CHECK-LABEL: fminnum32_intrinsic: 230; CHECK: .functype fminnum32_intrinsic (f32, f32) -> (f32) 231; CHECK-NEXT: # %bb.0: 232; CHECK-NEXT: local.get $push5=, 0 233; CHECK-NEXT: local.get $push4=, 1 234; CHECK-NEXT: local.get $push3=, 0 235; CHECK-NEXT: local.get $push2=, 1 236; CHECK-NEXT: f32.lt $push0=, $pop3, $pop2 237; CHECK-NEXT: f32.select $push1=, $pop5, $pop4, $pop0 238; CHECK-NEXT: return $pop1 239 %a = call nnan float @llvm.minnum.f32(float %x, float %y) 240 ret float %a 241} 242 243define float @fminnum32_non_zero_intrinsic(float %x) { 244; CHECK-LABEL: fminnum32_non_zero_intrinsic: 245; CHECK: .functype fminnum32_non_zero_intrinsic (f32) -> (f32) 246; CHECK-NEXT: # %bb.0: 247; CHECK-NEXT: local.get $push2=, 0 248; CHECK-NEXT: f32.const $push0=, -0x1p0 249; CHECK-NEXT: f32.min $push1=, $pop2, $pop0 250; CHECK-NEXT: return $pop1 251 %a = call nnan float @llvm.minnum.f32(float %x, float -1.0) 252 ret float %a 253} 254 255define float @fminnum32_nsz_intrinsic(float %x, float %y) { 256; CHECK-LABEL: fminnum32_nsz_intrinsic: 257; CHECK: .functype fminnum32_nsz_intrinsic (f32, f32) -> (f32) 258; CHECK-NEXT: # %bb.0: 259; CHECK-NEXT: local.get $push2=, 0 260; CHECK-NEXT: local.get $push1=, 1 261; CHECK-NEXT: f32.min $push0=, $pop2, $pop1 262; CHECK-NEXT: return $pop0 263 %a = call nnan nsz float @llvm.minnum.f32(float %x, float %y) 264 ret float %a 265} 266 267declare float @llvm.maximum.f32(float, float) 268define float @fmax32_intrinsic(float %x, float %y) { 269; CHECK-LABEL: fmax32_intrinsic: 270; CHECK: .functype fmax32_intrinsic (f32, f32) -> (f32) 271; CHECK-NEXT: # %bb.0: 272; CHECK-NEXT: local.get $push2=, 0 273; CHECK-NEXT: local.get $push1=, 1 274; CHECK-NEXT: f32.max $push0=, $pop2, $pop1 275; CHECK-NEXT: return $pop0 276 %a = call float @llvm.maximum.f32(float %x, float %y) 277 ret float %a 278} 279 280declare float @llvm.maxnum.f32(float, float) 281define float @fmaxnum32_intrinsic(float %x, float %y) { 282; CHECK-LABEL: fmaxnum32_intrinsic: 283; CHECK: .functype fmaxnum32_intrinsic (f32, f32) -> (f32) 284; CHECK-NEXT: # %bb.0: 285; CHECK-NEXT: local.get $push5=, 0 286; CHECK-NEXT: local.get $push4=, 1 287; CHECK-NEXT: local.get $push3=, 0 288; CHECK-NEXT: local.get $push2=, 1 289; CHECK-NEXT: f32.gt $push0=, $pop3, $pop2 290; CHECK-NEXT: f32.select $push1=, $pop5, $pop4, $pop0 291; CHECK-NEXT: return $pop1 292 %a = call nnan float @llvm.maxnum.f32(float %x, float %y) 293 ret float %a 294} 295 296define float @fmaxnum32_nsz_intrinsic(float %x, float %y) { 297; CHECK-LABEL: fmaxnum32_nsz_intrinsic: 298; CHECK: .functype fmaxnum32_nsz_intrinsic (f32, f32) -> (f32) 299; CHECK-NEXT: # %bb.0: 300; CHECK-NEXT: local.get $push2=, 0 301; CHECK-NEXT: local.get $push1=, 1 302; CHECK-NEXT: f32.max $push0=, $pop2, $pop1 303; CHECK-NEXT: return $pop0 304 %a = call nnan nsz float @llvm.maxnum.f32(float %x, float %y) 305 ret float %a 306} 307 308define float @fmaxnum32_zero_intrinsic(float %x) { 309; CHECK-LABEL: fmaxnum32_zero_intrinsic: 310; CHECK: .functype fmaxnum32_zero_intrinsic (f32) -> (f32) 311; CHECK-NEXT: # %bb.0: 312; CHECK-NEXT: local.get $push5=, 0 313; CHECK-NEXT: f32.const $push0=, 0x0p0 314; CHECK-NEXT: local.get $push4=, 0 315; CHECK-NEXT: f32.const $push3=, 0x0p0 316; CHECK-NEXT: f32.gt $push1=, $pop4, $pop3 317; CHECK-NEXT: f32.select $push2=, $pop5, $pop0, $pop1 318; CHECK-NEXT: return $pop2 319 %a = call nnan float @llvm.maxnum.f32(float %x, float 0.0) 320 ret float %a 321} 322 323define float @fmaxnum32_non_zero_intrinsic(float %x) { 324; CHECK-LABEL: fmaxnum32_non_zero_intrinsic: 325; CHECK: .functype fmaxnum32_non_zero_intrinsic (f32) -> (f32) 326; CHECK-NEXT: # %bb.0: 327; CHECK-NEXT: local.get $push2=, 0 328; CHECK-NEXT: f32.const $push0=, 0x1p0 329; CHECK-NEXT: f32.max $push1=, $pop2, $pop0 330; CHECK-NEXT: return $pop1 331 %a = call nnan float @llvm.maxnum.f32(float %x, float 1.0) 332 ret float %a 333} 334 335define float @fma32(float %a, float %b, float %c) { 336; CHECK-LABEL: fma32: 337; CHECK: .functype fma32 (f32, f32, f32) -> (f32) 338; CHECK-NEXT: # %bb.0: 339; CHECK-NEXT: local.get $push3=, 0 340; CHECK-NEXT: local.get $push2=, 1 341; CHECK-NEXT: local.get $push1=, 2 342; CHECK-NEXT: call $push0=, fmaf, $pop3, $pop2, $pop1 343; CHECK-NEXT: return $pop0 344 %d = call float @llvm.fma.f32(float %a, float %b, float %c) 345 ret float %d 346} 347