1; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -wasm-keep-registers -mattr=+nontrapping-fptoint | FileCheck %s 2 3; Test that basic conversion operations assemble as expected. 4 5target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128" 6target triple = "wasm32-unknown-unknown" 7 8; CHECK-LABEL: i32_wrap_i64: 9; CHECK-NEXT: .param i64{{$}} 10; CHECK-NEXT: .result i32{{$}} 11; CHECK-NEXT: i32.wrap/i64 $push[[NUM:[0-9]+]]=, $0{{$}} 12; CHECK-NEXT: return $pop[[NUM]]{{$}} 13define i32 @i32_wrap_i64(i64 %x) { 14 %a = trunc i64 %x to i32 15 ret i32 %a 16} 17 18; CHECK-LABEL: i64_extend_s_i32: 19; CHECK-NEXT: .param i32{{$}} 20; CHECK-NEXT: .result i64{{$}} 21; CHECK-NEXT: i64.extend_s/i32 $push[[NUM:[0-9]+]]=, $0{{$}} 22; CHECK-NEXT: return $pop[[NUM]]{{$}} 23define i64 @i64_extend_s_i32(i32 %x) { 24 %a = sext i32 %x to i64 25 ret i64 %a 26} 27 28; CHECK-LABEL: i64_extend_u_i32: 29; CHECK-NEXT: .param i32{{$}} 30; CHECK-NEXT: .result i64{{$}} 31; CHECK-NEXT: i64.extend_u/i32 $push[[NUM:[0-9]+]]=, $0{{$}} 32; CHECK-NEXT: return $pop[[NUM]]{{$}} 33define i64 @i64_extend_u_i32(i32 %x) { 34 %a = zext i32 %x to i64 35 ret i64 %a 36} 37 38; CHECK-LABEL: i32_trunc_s_f32: 39; CHECK-NEXT: .param f32{{$}} 40; CHECK-NEXT: .result i32{{$}} 41; CHECK-NEXT: i32.trunc_s:sat/f32 $push[[NUM:[0-9]+]]=, $0{{$}} 42; CHECK-NEXT: return $pop[[NUM]]{{$}} 43define i32 @i32_trunc_s_f32(float %x) { 44 %a = fptosi float %x to i32 45 ret i32 %a 46} 47 48; CHECK-LABEL: i32_trunc_sat_s_f32: 49; CHECK-NEXT: .param f32{{$}} 50; CHECK-NEXT: .result i32{{$}} 51; CHECK-NEXT: i32.trunc_s:sat/f32 $push[[NUM:[0-9]+]]=, $0{{$}} 52; CHECK-NEXT: return $pop[[NUM]]{{$}} 53declare i32 @llvm.wasm.trunc.saturate.signed.i32.f32(float) 54define i32 @i32_trunc_sat_s_f32(float %x) { 55 %a = call i32 @llvm.wasm.trunc.saturate.signed.i32.f32(float %x) 56 ret i32 %a 57} 58 59; CHECK-LABEL: i32_trunc_u_f32: 60; CHECK-NEXT: .param f32{{$}} 61; CHECK-NEXT: .result i32{{$}} 62; CHECK-NEXT: i32.trunc_u:sat/f32 $push[[NUM:[0-9]+]]=, $0{{$}} 63; CHECK-NEXT: return $pop[[NUM]]{{$}} 64define i32 @i32_trunc_u_f32(float %x) { 65 %a = fptoui float %x to i32 66 ret i32 %a 67} 68 69; CHECK-LABEL: i32_trunc_sat_u_f32: 70; CHECK-NEXT: .param f32{{$}} 71; CHECK-NEXT: .result i32{{$}} 72; CHECK-NEXT: i32.trunc_u:sat/f32 $push[[NUM:[0-9]+]]=, $0{{$}} 73; CHECK-NEXT: return $pop[[NUM]]{{$}} 74declare i32 @llvm.wasm.trunc.saturate.unsigned.i32.f32(float) 75define i32 @i32_trunc_sat_u_f32(float %x) { 76 %a = call i32 @llvm.wasm.trunc.saturate.unsigned.i32.f32(float %x) 77 ret i32 %a 78} 79 80; CHECK-LABEL: i32_trunc_s_f64: 81; CHECK-NEXT: .param f64{{$}} 82; CHECK-NEXT: .result i32{{$}} 83; CHECK-NEXT: i32.trunc_s:sat/f64 $push[[NUM:[0-9]+]]=, $0{{$}} 84; CHECK-NEXT: return $pop[[NUM]]{{$}} 85define i32 @i32_trunc_s_f64(double %x) { 86 %a = fptosi double %x to i32 87 ret i32 %a 88} 89 90; CHECK-LABEL: i32_trunc_sat_s_f64: 91; CHECK-NEXT: .param f64{{$}} 92; CHECK-NEXT: .result i32{{$}} 93; CHECK-NEXT: i32.trunc_s:sat/f64 $push[[NUM:[0-9]+]]=, $0{{$}} 94; CHECK-NEXT: return $pop[[NUM]]{{$}} 95declare i32 @llvm.wasm.trunc.saturate.signed.i32.f64(double) 96define i32 @i32_trunc_sat_s_f64(double %x) { 97 %a = call i32 @llvm.wasm.trunc.saturate.signed.i32.f64(double %x) 98 ret i32 %a 99} 100 101; CHECK-LABEL: i32_trunc_u_f64: 102; CHECK-NEXT: .param f64{{$}} 103; CHECK-NEXT: .result i32{{$}} 104; CHECK-NEXT: i32.trunc_u:sat/f64 $push[[NUM:[0-9]+]]=, $0{{$}} 105; CHECK-NEXT: return $pop[[NUM]]{{$}} 106define i32 @i32_trunc_u_f64(double %x) { 107 %a = fptoui double %x to i32 108 ret i32 %a 109} 110 111; CHECK-LABEL: i32_trunc_sat_u_f64: 112; CHECK-NEXT: .param f64{{$}} 113; CHECK-NEXT: .result i32{{$}} 114; CHECK-NEXT: i32.trunc_u:sat/f64 $push[[NUM:[0-9]+]]=, $0{{$}} 115; CHECK-NEXT: return $pop[[NUM]]{{$}} 116declare i32 @llvm.wasm.trunc.saturate.unsigned.i32.f64(double) 117define i32 @i32_trunc_sat_u_f64(double %x) { 118 %a = call i32 @llvm.wasm.trunc.saturate.unsigned.i32.f64(double %x) 119 ret i32 %a 120} 121 122; CHECK-LABEL: i64_trunc_s_f32: 123; CHECK-NEXT: .param f32{{$}} 124; CHECK-NEXT: .result i64{{$}} 125; CHECK-NEXT: i64.trunc_s:sat/f32 $push[[NUM:[0-9]+]]=, $0{{$}} 126; CHECK-NEXT: return $pop[[NUM]]{{$}} 127define i64 @i64_trunc_s_f32(float %x) { 128 %a = fptosi float %x to i64 129 ret i64 %a 130} 131 132; CHECK-LABEL: i64_trunc_sat_s_f32: 133; CHECK-NEXT: .param f32{{$}} 134; CHECK-NEXT: .result i64{{$}} 135; CHECK-NEXT: i64.trunc_s:sat/f32 $push[[NUM:[0-9]+]]=, $0{{$}} 136; CHECK-NEXT: return $pop[[NUM]]{{$}} 137declare i64 @llvm.wasm.trunc.saturate.signed.i64.f32(float) 138define i64 @i64_trunc_sat_s_f32(float %x) { 139 %a = call i64 @llvm.wasm.trunc.saturate.signed.i64.f32(float %x) 140 ret i64 %a 141} 142 143; CHECK-LABEL: i64_trunc_u_f32: 144; CHECK-NEXT: .param f32{{$}} 145; CHECK-NEXT: .result i64{{$}} 146; CHECK-NEXT: i64.trunc_u:sat/f32 $push[[NUM:[0-9]+]]=, $0{{$}} 147; CHECK-NEXT: return $pop[[NUM]]{{$}} 148define i64 @i64_trunc_u_f32(float %x) { 149 %a = fptoui float %x to i64 150 ret i64 %a 151} 152 153; CHECK-LABEL: i64_trunc_sat_u_f32: 154; CHECK-NEXT: .param f32{{$}} 155; CHECK-NEXT: .result i64{{$}} 156; CHECK-NEXT: i64.trunc_u:sat/f32 $push[[NUM:[0-9]+]]=, $0{{$}} 157; CHECK-NEXT: return $pop[[NUM]]{{$}} 158declare i64 @llvm.wasm.trunc.saturate.unsigned.i64.f32(float) 159define i64 @i64_trunc_sat_u_f32(float %x) { 160 %a = call i64 @llvm.wasm.trunc.saturate.unsigned.i64.f32(float %x) 161 ret i64 %a 162} 163 164; CHECK-LABEL: i64_trunc_s_f64: 165; CHECK-NEXT: .param f64{{$}} 166; CHECK-NEXT: .result i64{{$}} 167; CHECK-NEXT: i64.trunc_s:sat/f64 $push[[NUM:[0-9]+]]=, $0{{$}} 168; CHECK-NEXT: return $pop[[NUM]]{{$}} 169define i64 @i64_trunc_s_f64(double %x) { 170 %a = fptosi double %x to i64 171 ret i64 %a 172} 173 174; CHECK-LABEL: i64_trunc_sat_s_f64: 175; CHECK-NEXT: .param f64{{$}} 176; CHECK-NEXT: .result i64{{$}} 177; CHECK-NEXT: i64.trunc_s:sat/f64 $push[[NUM:[0-9]+]]=, $0{{$}} 178; CHECK-NEXT: return $pop[[NUM]]{{$}} 179declare i64 @llvm.wasm.trunc.saturate.signed.i64.f64(double) 180define i64 @i64_trunc_sat_s_f64(double %x) { 181 %a = call i64 @llvm.wasm.trunc.saturate.signed.i64.f64(double %x) 182 ret i64 %a 183} 184 185; CHECK-LABEL: i64_trunc_u_f64: 186; CHECK-NEXT: .param f64{{$}} 187; CHECK-NEXT: .result i64{{$}} 188; CHECK-NEXT: i64.trunc_u:sat/f64 $push[[NUM:[0-9]+]]=, $0{{$}} 189; CHECK-NEXT: return $pop[[NUM]]{{$}} 190define i64 @i64_trunc_u_f64(double %x) { 191 %a = fptoui double %x to i64 192 ret i64 %a 193} 194 195; CHECK-LABEL: i64_trunc_sat_u_f64: 196; CHECK-NEXT: .param f64{{$}} 197; CHECK-NEXT: .result i64{{$}} 198; CHECK-NEXT: i64.trunc_u:sat/f64 $push[[NUM:[0-9]+]]=, $0{{$}} 199; CHECK-NEXT: return $pop[[NUM]]{{$}} 200declare i64 @llvm.wasm.trunc.saturate.unsigned.i64.f64(double) 201define i64 @i64_trunc_sat_u_f64(double %x) { 202 %a = call i64 @llvm.wasm.trunc.saturate.unsigned.i64.f64(double %x) 203 ret i64 %a 204} 205 206; CHECK-LABEL: f32_convert_s_i32: 207; CHECK-NEXT: .param i32{{$}} 208; CHECK-NEXT: .result f32{{$}} 209; CHECK-NEXT: f32.convert_s/i32 $push[[NUM:[0-9]+]]=, $0{{$}} 210; CHECK-NEXT: return $pop[[NUM]]{{$}} 211define float @f32_convert_s_i32(i32 %x) { 212 %a = sitofp i32 %x to float 213 ret float %a 214} 215 216; CHECK-LABEL: f32_convert_u_i32: 217; CHECK-NEXT: .param i32{{$}} 218; CHECK-NEXT: .result f32{{$}} 219; CHECK-NEXT: f32.convert_u/i32 $push[[NUM:[0-9]+]]=, $0{{$}} 220; CHECK-NEXT: return $pop[[NUM]]{{$}} 221define float @f32_convert_u_i32(i32 %x) { 222 %a = uitofp i32 %x to float 223 ret float %a 224} 225 226; CHECK-LABEL: f64_convert_s_i32: 227; CHECK-NEXT: .param i32{{$}} 228; CHECK-NEXT: .result f64{{$}} 229; CHECK-NEXT: f64.convert_s/i32 $push[[NUM:[0-9]+]]=, $0{{$}} 230; CHECK-NEXT: return $pop[[NUM]]{{$}} 231define double @f64_convert_s_i32(i32 %x) { 232 %a = sitofp i32 %x to double 233 ret double %a 234} 235 236; CHECK-LABEL: f64_convert_u_i32: 237; CHECK-NEXT: .param i32{{$}} 238; CHECK-NEXT: .result f64{{$}} 239; CHECK-NEXT: f64.convert_u/i32 $push[[NUM:[0-9]+]]=, $0{{$}} 240; CHECK-NEXT: return $pop[[NUM]]{{$}} 241define double @f64_convert_u_i32(i32 %x) { 242 %a = uitofp i32 %x to double 243 ret double %a 244} 245 246; CHECK-LABEL: f32_convert_s_i64: 247; CHECK-NEXT: .param i64{{$}} 248; CHECK-NEXT: .result f32{{$}} 249; CHECK-NEXT: f32.convert_s/i64 $push[[NUM:[0-9]+]]=, $0{{$}} 250; CHECK-NEXT: return $pop[[NUM]]{{$}} 251define float @f32_convert_s_i64(i64 %x) { 252 %a = sitofp i64 %x to float 253 ret float %a 254} 255 256; CHECK-LABEL: f32_convert_u_i64: 257; CHECK-NEXT: .param i64{{$}} 258; CHECK-NEXT: .result f32{{$}} 259; CHECK-NEXT: f32.convert_u/i64 $push[[NUM:[0-9]+]]=, $0{{$}} 260; CHECK-NEXT: return $pop[[NUM]]{{$}} 261define float @f32_convert_u_i64(i64 %x) { 262 %a = uitofp i64 %x to float 263 ret float %a 264} 265 266; CHECK-LABEL: f64_convert_s_i64: 267; CHECK-NEXT: .param i64{{$}} 268; CHECK-NEXT: .result f64{{$}} 269; CHECK-NEXT: f64.convert_s/i64 $push[[NUM:[0-9]+]]=, $0{{$}} 270; CHECK-NEXT: return $pop[[NUM]]{{$}} 271define double @f64_convert_s_i64(i64 %x) { 272 %a = sitofp i64 %x to double 273 ret double %a 274} 275 276; CHECK-LABEL: f64_convert_u_i64: 277; CHECK-NEXT: .param i64{{$}} 278; CHECK-NEXT: .result f64{{$}} 279; CHECK-NEXT: f64.convert_u/i64 $push[[NUM:[0-9]+]]=, $0{{$}} 280; CHECK-NEXT: return $pop[[NUM]]{{$}} 281define double @f64_convert_u_i64(i64 %x) { 282 %a = uitofp i64 %x to double 283 ret double %a 284} 285 286; CHECK-LABEL: f64_promote_f32: 287; CHECK-NEXT: .param f32{{$}} 288; CHECK-NEXT: .result f64{{$}} 289; CHECK-NEXT: f64.promote/f32 $push[[NUM:[0-9]+]]=, $0{{$}} 290; CHECK-NEXT: return $pop[[NUM]]{{$}} 291define double @f64_promote_f32(float %x) { 292 %a = fpext float %x to double 293 ret double %a 294} 295 296; CHECK-LABEL: f32_demote_f64: 297; CHECK-NEXT: .param f64{{$}} 298; CHECK-NEXT: .result f32{{$}} 299; CHECK-NEXT: f32.demote/f64 $push[[NUM:[0-9]+]]=, $0{{$}} 300; CHECK-NEXT: return $pop[[NUM]]{{$}} 301define float @f32_demote_f64(double %x) { 302 %a = fptrunc double %x to float 303 ret float %a 304} 305 306; If the high its are unused, LLVM will optimize sext/zext into anyext, which 307; we need to patterm-match back to a specific instruction. 308 309; CHECK-LABEL: anyext: 310; CHECK: i64.extend_u/i32 $push0=, $0{{$}} 311define i64 @anyext(i32 %x) { 312 %y = sext i32 %x to i64 313 %w = shl i64 %y, 32 314 ret i64 %w 315} 316 317; CHECK-LABEL: bitcast_i32_to_float: 318; CHECK: f32.reinterpret/i32 $push0=, $0{{$}} 319define float @bitcast_i32_to_float(i32 %a) { 320 %t = bitcast i32 %a to float 321 ret float %t 322} 323 324; CHECK-LABEL: bitcast_float_to_i32: 325; CHECK: i32.reinterpret/f32 $push0=, $0{{$}} 326define i32 @bitcast_float_to_i32(float %a) { 327 %t = bitcast float %a to i32 328 ret i32 %t 329} 330 331; CHECK-LABEL: bitcast_i64_to_double: 332; CHECK: f64.reinterpret/i64 $push0=, $0{{$}} 333define double @bitcast_i64_to_double(i64 %a) { 334 %t = bitcast i64 %a to double 335 ret double %t 336} 337 338; CHECK-LABEL: bitcast_double_to_i64: 339; CHECK: i64.reinterpret/f64 $push0=, $0{{$}} 340define i64 @bitcast_double_to_i64(double %a) { 341 %t = bitcast double %a to i64 342 ret i64 %t 343} 344