1; RUN: llc < %s --mtriple=wasm32-unknown-unknown -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -wasm-keep-registers -mattr=+fp16,+simd128 | FileCheck %s 2 3declare float @llvm.wasm.loadf32.f16(ptr) 4declare void @llvm.wasm.storef16.f32(float, ptr) 5 6; CHECK-LABEL: ldf16_32: 7; CHECK: f32.load_f16 $push[[NUM0:[0-9]+]]=, 0($0){{$}} 8; CHECK-NEXT: return $pop[[NUM0]]{{$}} 9define float @ldf16_32(ptr %p) { 10 %v = call float @llvm.wasm.loadf16.f32(ptr %p) 11 ret float %v 12} 13 14; CHECK-LABEL: stf16_32: 15; CHECK: f32.store_f16 0($1), $0 16; CHECK-NEXT: return 17define void @stf16_32(float %v, ptr %p) { 18 tail call void @llvm.wasm.storef16.f32(float %v, ptr %p) 19 ret void 20} 21 22; CHECK-LABEL: splat_v8f16: 23; CHECK: f16x8.splat $push0=, $0 24; CHECK-NEXT: return $pop0 25define <8 x half> @splat_v8f16(float %x) { 26 %v = call <8 x half> @llvm.wasm.splat.f16x8(float %x) 27 ret <8 x half> %v 28} 29 30; CHECK-LABEL: const_splat_v8f16: 31; CHECK: v128.const $push0=, 20800, 0, 0, 0, 0, 0, 0, 20800 32; CHECK-NEXT: return $pop0 33define <8 x half> @const_splat_v8f16() { 34 ret <8 x half> <half 42., half 0., half 0., half 0., half 0., half 0., half 0., half 42.> 35} 36 37; CHECK-LABEL: extract_lane_v8f16: 38; CHECK: f16x8.extract_lane $push0=, $0, 1 39; CHECK-NEXT: return $pop0 40define float @extract_lane_v8f16(<8 x half> %v) { 41 %r = call float @llvm.wasm.extract.lane.f16x8(<8 x half> %v, i32 1) 42 ret float %r 43} 44 45; CHECK-LABEL: replace_lane_v8f16: 46; CHECK: f16x8.replace_lane $push0=, $0, 1, $1 47; CHECK-NEXT: return $pop0 48define <8 x half> @replace_lane_v8f16(<8 x half> %v, float %f) { 49 %r = call <8 x half> @llvm.wasm.replace.lane.f16x8(<8 x half> %v, i32 1, float %f) 50 ret <8 x half> %r 51} 52 53; CHECK-LABEL: add_v8f16: 54; CHECK: f16x8.add $push0=, $0, $1 55; CHECK-NEXT: return $pop0 56define <8 x half> @add_v8f16(<8 x half> %a, <8 x half> %b) { 57 %r = fadd <8 x half> %a, %b 58 ret <8 x half> %r 59} 60 61; CHECK-LABEL: sub_v8f16: 62; CHECK: f16x8.sub $push0=, $0, $1 63; CHECK-NEXT: return $pop0 64define <8 x half> @sub_v8f16(<8 x half> %a, <8 x half> %b) { 65 %r = fsub <8 x half> %a, %b 66 ret <8 x half> %r 67} 68 69; CHECK-LABEL: mul_v8f16: 70; CHECK: f16x8.mul $push0=, $0, $1 71; CHECK-NEXT: return $pop0 72define <8 x half> @mul_v8f16(<8 x half> %a, <8 x half> %b) { 73 %r = fmul <8 x half> %a, %b 74 ret <8 x half> %r 75} 76 77; CHECK-LABEL: div_v8f16: 78; CHECK: f16x8.div $push0=, $0, $1 79; CHECK-NEXT: return $pop0 80define <8 x half> @div_v8f16(<8 x half> %a, <8 x half> %b) { 81 %r = fdiv <8 x half> %a, %b 82 ret <8 x half> %r 83} 84 85; CHECK-LABEL: min_intrinsic_v8f16: 86; CHECK: f16x8.min $push0=, $0, $1 87; CHECK-NEXT: return $pop0 88declare <8 x half> @llvm.minimum.v8f16(<8 x half>, <8 x half>) 89define <8 x half> @min_intrinsic_v8f16(<8 x half> %x, <8 x half> %y) { 90 %a = call <8 x half> @llvm.minimum.v8f16(<8 x half> %x, <8 x half> %y) 91 ret <8 x half> %a 92} 93 94; CHECK-LABEL: max_intrinsic_v8f16: 95; CHECK: f16x8.max $push0=, $0, $1 96; CHECK-NEXT: return $pop0 97declare <8 x half> @llvm.maximum.v8f16(<8 x half>, <8 x half>) 98define <8 x half> @max_intrinsic_v8f16(<8 x half> %x, <8 x half> %y) { 99 %a = call <8 x half> @llvm.maximum.v8f16(<8 x half> %x, <8 x half> %y) 100 ret <8 x half> %a 101} 102 103; CHECK-LABEL: pmin_intrinsic_v8f16: 104; CHECK: f16x8.pmin $push0=, $0, $1 105; CHECK-NEXT: return $pop0 106declare <8 x half> @llvm.wasm.pmin.v8f16(<8 x half>, <8 x half>) 107define <8 x half> @pmin_intrinsic_v8f16(<8 x half> %a, <8 x half> %b) { 108 %v = call <8 x half> @llvm.wasm.pmin.v8f16(<8 x half> %a, <8 x half> %b) 109 ret <8 x half> %v 110} 111 112; CHECK-LABEL: pmax_intrinsic_v8f16: 113; CHECK: f16x8.pmax $push0=, $0, $1 114; CHECK-NEXT: return $pop0 115declare <8 x half> @llvm.wasm.pmax.v8f16(<8 x half>, <8 x half>) 116define <8 x half> @pmax_intrinsic_v8f16(<8 x half> %a, <8 x half> %b) { 117 %v = call <8 x half> @llvm.wasm.pmax.v8f16(<8 x half> %a, <8 x half> %b) 118 ret <8 x half> %v 119} 120 121; CHECK-LABEL: compare_oeq_v8f16: 122; CHECK-NEXT: .functype compare_oeq_v8f16 (v128, v128) -> (v128){{$}} 123; CHECK-NEXT: f16x8.eq $push[[R:[0-9]+]]=, $0, $1{{$}} 124; CHECK-NEXT: return $pop[[R]]{{$}} 125define <8 x i1> @compare_oeq_v8f16 (<8 x half> %x, <8 x half> %y) { 126 %res = fcmp oeq <8 x half> %x, %y 127 ret <8 x i1> %res 128} 129 130; CHECK-LABEL: compare_une_v8f16: 131; CHECK-NEXT: .functype compare_une_v8f16 (v128, v128) -> (v128){{$}} 132; CHECK-NEXT: f16x8.ne $push[[R:[0-9]+]]=, $0, $1{{$}} 133; CHECK-NEXT: return $pop[[R]]{{$}} 134define <8 x i1> @compare_une_v8f16 (<8 x half> %x, <8 x half> %y) { 135 %res = fcmp une <8 x half> %x, %y 136 ret <8 x i1> %res 137} 138 139; CHECK-LABEL: compare_olt_v8f16: 140; CHECK-NEXT: .functype compare_olt_v8f16 (v128, v128) -> (v128){{$}} 141; CHECK-NEXT: f16x8.lt $push[[R:[0-9]+]]=, $0, $1{{$}} 142; CHECK-NEXT: return $pop[[R]]{{$}} 143define <8 x i1> @compare_olt_v8f16 (<8 x half> %x, <8 x half> %y) { 144 %res = fcmp olt <8 x half> %x, %y 145 ret <8 x i1> %res 146} 147 148; CHECK-LABEL: compare_ogt_v8f16: 149; CHECK-NEXT: .functype compare_ogt_v8f16 (v128, v128) -> (v128){{$}} 150; CHECK-NEXT: f16x8.gt $push[[R:[0-9]+]]=, $0, $1{{$}} 151; CHECK-NEXT: return $pop[[R]]{{$}} 152define <8 x i1> @compare_ogt_v8f16 (<8 x half> %x, <8 x half> %y) { 153 %res = fcmp ogt <8 x half> %x, %y 154 ret <8 x i1> %res 155} 156 157; CHECK-LABEL: compare_ole_v8f16: 158; CHECK-NEXT: .functype compare_ole_v8f16 (v128, v128) -> (v128){{$}} 159; CHECK-NEXT: f16x8.le $push[[R:[0-9]+]]=, $0, $1{{$}} 160; CHECK-NEXT: return $pop[[R]]{{$}} 161define <8 x i1> @compare_ole_v8f16 (<8 x half> %x, <8 x half> %y) { 162 %res = fcmp ole <8 x half> %x, %y 163 ret <8 x i1> %res 164} 165 166; CHECK-LABEL: compare_oge_v8f16: 167; CHECK-NEXT: .functype compare_oge_v8f16 (v128, v128) -> (v128){{$}} 168; CHECK-NEXT: f16x8.ge $push[[R:[0-9]+]]=, $0, $1{{$}} 169; CHECK-NEXT: return $pop[[R]]{{$}} 170define <8 x i1> @compare_oge_v8f16 (<8 x half> %x, <8 x half> %y) { 171 %res = fcmp oge <8 x half> %x, %y 172 ret <8 x i1> %res 173} 174 175; CHECK-LABEL: abs_v8f16: 176; CHECK-NEXT: .functype abs_v8f16 (v128) -> (v128) 177; CHECK-NEXT: f16x8.abs $push0=, $0 178; CHECK-NEXT: return $pop0 179declare <8 x half> @llvm.fabs.v8f16(<8 x half>) nounwind readnone 180define <8 x half> @abs_v8f16(<8 x half> %x) { 181 %a = call <8 x half> @llvm.fabs.v8f16(<8 x half> %x) 182 ret <8 x half> %a 183} 184 185; CHECK-LABEL: neg_v8f16: 186; CHECK-NEXT: .functype neg_v8f16 (v128) -> (v128) 187; CHECK-NEXT: f16x8.neg $push0=, $0 188; CHECK-NEXT: return $pop0 189define <8 x half> @neg_v8f16(<8 x half> %x) { 190 %a = fsub nsz <8 x half> <half 0., half 0., half 0., half 0., half 0., half 0., half 0., half 0.>, %x 191 ret <8 x half> %a 192} 193 194; CHECK-LABEL: sqrt_v8f16: 195; CHECK-NEXT: .functype sqrt_v8f16 (v128) -> (v128) 196; CHECK-NEXT: f16x8.sqrt $push0=, $0 197; CHECK-NEXT: return $pop0 198declare <8 x half> @llvm.sqrt.v8f16(<8 x half> %x) 199define <8 x half> @sqrt_v8f16(<8 x half> %x) { 200 %a = call <8 x half> @llvm.sqrt.v8f16(<8 x half> %x) 201 ret <8 x half> %a 202} 203 204; CHECK-LABEL: ceil_v8f16: 205; CHECK-NEXT: .functype ceil_v8f16 (v128) -> (v128){{$}} 206; CHECK-NEXT: f16x8.ceil $push[[R:[0-9]+]]=, $0{{$}} 207; CHECK-NEXT: return $pop[[R]]{{$}} 208declare <8 x half> @llvm.ceil.v8f16(<8 x half>) 209define <8 x half> @ceil_v8f16(<8 x half> %a) { 210 %v = call <8 x half> @llvm.ceil.v8f16(<8 x half> %a) 211 ret <8 x half> %v 212} 213 214; CHECK-LABEL: floor_v8f16: 215; CHECK-NEXT: .functype floor_v8f16 (v128) -> (v128){{$}} 216; CHECK-NEXT: f16x8.floor $push[[R:[0-9]+]]=, $0{{$}} 217; CHECK-NEXT: return $pop[[R]]{{$}} 218declare <8 x half> @llvm.floor.v8f16(<8 x half>) 219define <8 x half> @floor_v8f16(<8 x half> %a) { 220 %v = call <8 x half> @llvm.floor.v8f16(<8 x half> %a) 221 ret <8 x half> %v 222} 223 224; CHECK-LABEL: trunc_v8f16: 225; CHECK-NEXT: .functype trunc_v8f16 (v128) -> (v128){{$}} 226; CHECK-NEXT: f16x8.trunc $push[[R:[0-9]+]]=, $0{{$}} 227; CHECK-NEXT: return $pop[[R]]{{$}} 228declare <8 x half> @llvm.trunc.v8f16(<8 x half>) 229define <8 x half> @trunc_v8f16(<8 x half> %a) { 230 %v = call <8 x half> @llvm.trunc.v8f16(<8 x half> %a) 231 ret <8 x half> %v 232} 233 234; CHECK-LABEL: nearest_v8f16: 235; CHECK-NEXT: .functype nearest_v8f16 (v128) -> (v128){{$}} 236; CHECK-NEXT: f16x8.nearest $push[[R:[0-9]+]]=, $0{{$}} 237; CHECK-NEXT: return $pop[[R]]{{$}} 238declare <8 x half> @llvm.nearbyint.v8f16(<8 x half>) 239define <8 x half> @nearest_v8f16(<8 x half> %a) { 240 %v = call <8 x half> @llvm.nearbyint.v8f16(<8 x half> %a) 241 ret <8 x half> %v 242} 243 244; CHECK-LABEL: nearest_v8f16_via_rint: 245; CHECK-NEXT: .functype nearest_v8f16_via_rint (v128) -> (v128){{$}} 246; CHECK-NEXT: f16x8.nearest $push[[R:[0-9]+]]=, $0{{$}} 247; CHECK-NEXT: return $pop[[R]]{{$}} 248declare <8 x half> @llvm.rint.v8f16(<8 x half>) 249define <8 x half> @nearest_v8f16_via_rint(<8 x half> %a) { 250 %v = call <8 x half> @llvm.rint.v8f16(<8 x half> %a) 251 ret <8 x half> %v 252} 253 254; CHECK-LABEL: nearest_v8f16_via_roundeven: 255; CHECK-NEXT: .functype nearest_v8f16_via_roundeven (v128) -> (v128){{$}} 256; CHECK-NEXT: f16x8.nearest $push[[R:[0-9]+]]=, $0{{$}} 257; CHECK-NEXT: return $pop[[R]]{{$}} 258declare <8 x half> @llvm.roundeven.v8f16(<8 x half>) 259define <8 x half> @nearest_v8f16_via_roundeven(<8 x half> %a) { 260 %v = call <8 x half> @llvm.roundeven.v8f16(<8 x half> %a) 261 ret <8 x half> %v 262} 263 264define <8 x half> @convert_s_v8f16(<8 x i16> %x) { 265; CHECK-LABEL: convert_s_v8f16: 266; CHECK: .functype convert_s_v8f16 (v128) -> (v128) 267; CHECK-NEXT: f16x8.convert_i16x8_s $push0=, $0 268; CHECK-NEXT: return $pop[[R]]{{$}} 269 %a = sitofp <8 x i16> %x to <8 x half> 270 ret <8 x half> %a 271} 272 273define <8 x half> @convert_u_v8f16(<8 x i16> %x) { 274; CHECK-LABEL: convert_u_v8f16: 275; CHECK: .functype convert_u_v8f16 (v128) -> (v128) 276; CHECK-NEXT: f16x8.convert_i16x8_u $push0=, $0 277; CHECK-NEXT: return $pop[[R]]{{$}} 278 %a = uitofp <8 x i16> %x to <8 x half> 279 ret <8 x half> %a 280} 281 282define <8 x i16> @trunc_sat_s_v8i16(<8 x half> %x) { 283; CHECK-LABEL: trunc_sat_s_v8i16: 284; CHECK: .functype trunc_sat_s_v8i16 (v128) -> (v128) 285; CHECK-NEXT: i16x8.trunc_sat_f16x8_s $push0=, $0 286; CHECK-NEXT: return $pop[[R]]{{$}} 287 %a = fptosi <8 x half> %x to <8 x i16> 288 ret <8 x i16> %a 289} 290 291define <8 x i16> @trunc_sat_u_v8i16(<8 x half> %x) { 292; CHECK-LABEL: trunc_sat_u_v8i16: 293; CHECK: .functype trunc_sat_u_v8i16 (v128) -> (v128) 294; CHECK-NEXT: i16x8.trunc_sat_f16x8_u $push0=, $0 295; CHECK-NEXT: return $pop[[R]]{{$}} 296 %a = fptoui <8 x half> %x to <8 x i16> 297 ret <8 x i16> %a 298} 299 300define <8 x i16> @trunc_sat_s_v8i16_sat(<8 x half> %x) { 301; CHECK-LABEL: trunc_sat_s_v8i16_sat: 302; CHECK: .functype trunc_sat_s_v8i16_sat (v128) -> (v128) 303; CHECK-NEXT: i16x8.trunc_sat_f16x8_s $push0=, $0 304; CHECK-NEXT: return $pop[[R]]{{$}} 305 %a = call <8 x i16> @llvm.fptosi.sat.v8i16.v8f16(<8 x half> %x) 306 ret <8 x i16> %a 307} 308 309define <8 x i16> @trunc_sat_u_v8i16_sat(<8 x half> %x) { 310; CHECK-LABEL: trunc_sat_u_v8i16_sat: 311; CHECK: .functype trunc_sat_u_v8i16_sat (v128) -> (v128) 312; CHECK-NEXT: i16x8.trunc_sat_f16x8_u $push0=, $0 313; CHECK-NEXT: return $pop[[R]]{{$}} 314 %a = call <8 x i16> @llvm.fptoui.sat.v8i16.v8f16(<8 x half> %x) 315 ret <8 x i16> %a 316} 317 318; ============================================================================== 319; Load and Store 320; ============================================================================== 321define <8 x half> @load_v8f16(ptr %p) { 322; CHECK-LABEL: load_v8f16: 323; CHECK: .functype load_v8f16 (i32) -> (v128) 324; CHECK-NEXT: v128.load $push0=, 0($0) 325; CHECK-NEXT: return $pop0 326 %v = load <8 x half>, ptr %p 327 ret <8 x half> %v 328} 329 330define void @store_v8f16(<8 x half> %v, ptr %p) { 331; CHECK-LABEL: store_v8f16: 332; CHECK: .functype store_v8f16 (v128, i32) -> () 333; CHECK-NEXT: v128.store 0($1), $0 334; CHECK-NEXT: return 335 store <8 x half> %v , ptr %p 336 ret void 337} 338