Index: llvm/trunk/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp =================================================================== --- llvm/trunk/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp +++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp @@ -271,6 +271,11 @@ MaxStoresPerMemsetOptSize = 1; } + // Override the __gnu_f2h_ieee/__gnu_h2f_ieee names so that the f32 name is + // consistent with the f64 and f128 names. + setLibcallName(RTLIB::FPEXT_F16_F32, "__extendhfsf2"); + setLibcallName(RTLIB::FPROUND_F32_F16, "__truncsfhf2"); + // Always convert switches to br_tables unless there is only one case, which // is equivalent to a simple branch. This reduces code size for wasm, and we // defer possible jump table optimizations to the VM. Index: llvm/trunk/lib/Target/WebAssembly/WebAssemblyRuntimeLibcallSignatures.cpp =================================================================== --- llvm/trunk/lib/Target/WebAssembly/WebAssemblyRuntimeLibcallSignatures.cpp +++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyRuntimeLibcallSignatures.cpp @@ -51,6 +51,8 @@ f64_func_f64_i32, f64_func_i64_i64, i16_func_f32, + i16_func_f64, + i16_func_i64_i64, i8_func_i8_i8, func_f32_iPTR_iPTR, func_f64_iPTR_iPTR, @@ -228,13 +230,15 @@ Table[RTLIB::FMAX_F128] = func_iPTR_i64_i64_i64_i64; // Conversion - // All F80 and PPCF128 routines are unspported. + // All F80 and PPCF128 routines are unsupported. Table[RTLIB::FPEXT_F64_F128] = func_iPTR_f64; Table[RTLIB::FPEXT_F32_F128] = func_iPTR_f32; Table[RTLIB::FPEXT_F32_F64] = f64_func_f32; Table[RTLIB::FPEXT_F16_F32] = f32_func_i16; Table[RTLIB::FPROUND_F32_F16] = i16_func_f32; + Table[RTLIB::FPROUND_F64_F16] = i16_func_f64; Table[RTLIB::FPROUND_F64_F32] = f32_func_f64; + Table[RTLIB::FPROUND_F128_F16] = i16_func_i64_i64; Table[RTLIB::FPROUND_F128_F32] = f32_func_i64_i64; Table[RTLIB::FPROUND_F128_F64] = f64_func_i64_i64; Table[RTLIB::FPTOSINT_F32_I32] = i32_func_f32; @@ -482,6 +486,10 @@ Map[NameLibcall.first] = NameLibcall.second; } } + // Override the __gnu_f2h_ieee/__gnu_h2f_ieee names so that the f32 name is + // consistent with the f64 and f128 names. + Map["__extendhfsf2"] = RTLIB::FPEXT_F16_F32; + Map["__truncsfhf2"] = RTLIB::FPROUND_F32_F16; } }; @@ -595,6 +603,15 @@ Rets.push_back(wasm::ValType::I32); Params.push_back(wasm::ValType::F32); break; + case i16_func_f64: + Rets.push_back(wasm::ValType::I32); + Params.push_back(wasm::ValType::F64); + break; + case i16_func_i64_i64: + Rets.push_back(wasm::ValType::I32); + Params.push_back(wasm::ValType::I64); + Params.push_back(wasm::ValType::I64); + break; case i8_func_i8_i8: Rets.push_back(wasm::ValType::I32); Params.push_back(wasm::ValType::I32); Index: llvm/trunk/test/CodeGen/WebAssembly/f16.ll =================================================================== --- llvm/trunk/test/CodeGen/WebAssembly/f16.ll +++ llvm/trunk/test/CodeGen/WebAssembly/f16.ll @@ -6,22 +6,65 @@ target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128" target triple = "wasm32-unknown-unknown" -; CHECK-LABEL: demote: -; CHECK-NEXT: .functype demote (f32) -> (f32){{$}} +; CHECK-LABEL: demote.f32: +; CHECK-NEXT: .functype demote.f32 (f32) -> (f32){{$}} ; CHECK-NEXT: local.get $push[[L0:[0-9]+]]=, 0{{$}} -; CHECK-NEXT: i32.call $push[[L1:[0-9]+]]=, __gnu_f2h_ieee, $pop[[L0]]{{$}} -; CHECK-NEXT: f32.call $push[[L2:[0-9]+]]=, __gnu_h2f_ieee, $pop[[L1]]{{$}} +; CHECK-NEXT: i32.call $push[[L1:[0-9]+]]=, __truncsfhf2, $pop[[L0]]{{$}} +; CHECK-NEXT: f32.call $push[[L2:[0-9]+]]=, __extendhfsf2, $pop[[L1]]{{$}} ; CHECK-NEXT: return $pop[[L2]]{{$}} -define half @demote(float %f) { +define half @demote.f32(float %f) { %t = fptrunc float %f to half ret half %t } -; CHECK-LABEL: promote: -; CHECK-NEXT: .functype promote (f32) -> (f32){{$}} +; CHECK-LABEL: promote.f32: +; CHECK-NEXT: .functype promote.f32 (f32) -> (f32){{$}} ; CHECK-NEXT: local.get $push0=, 0{{$}} ; CHECK-NEXT: return $pop0{{$}} -define float @promote(half %f) { +define float @promote.f32(half %f) { %t = fpext half %f to float ret float %t } + +; CHECK-LABEL: demote.f64: +; CHECK-NEXT: .functype demote.f64 (f64) -> (f32){{$}} +; CHECK-NEXT: local.get $push[[L0:[0-9]+]]=, 0{{$}} +; CHECK-NEXT: i32.call $push[[L1:[0-9]+]]=, __truncdfhf2, $pop[[L0]]{{$}} +; CHECK-NEXT: f32.call $push[[L2:[0-9]+]]=, __extendhfsf2, $pop[[L1]]{{$}} +; CHECK-NEXT: return $pop[[L2]]{{$}} +define half @demote.f64(double %f) { + %t = fptrunc double %f to half + ret half %t +} + +; CHECK-LABEL: promote.f64: +; CHECK-NEXT: .functype promote.f64 (f32) -> (f64){{$}} +; CHECK-NEXT: local.get $push[[L0:[0-9]+]]=, 0{{$}} +; CHECK-NEXT: f64.promote_f32 $push[[L1:[0-9]+]]=, $pop[[L0]]{{$}} +; CHECK-NEXT: return $pop[[L1]]{{$}} +define double @promote.f64(half %f) { + %t = fpext half %f to double + ret double %t +} + +; CHECK-LABEL: demote.f128: +; CHECK-NEXT: .functype demote.f128 (i64, i64) -> (f32){{$}} +; CHECK-NEXT: local.get $push[[L0:[0-9]+]]=, 0{{$}} +; CHECK-NEXT: local.get $push[[L1:[0-9]+]]=, 1{{$}} +; CHECK-NEXT: i32.call $push[[L2:[0-9]+]]=, __trunctfhf2, $pop[[L0]], $pop[[L1]]{{$}} +; CHECK-NEXT: f32.call $push[[L3:[0-9]+]]=, __extendhfsf2, $pop[[L2]]{{$}} +; CHECK-NEXT: return $pop[[L3]]{{$}} +define half @demote.f128(fp128 %f) { + %t = fptrunc fp128 %f to half + ret half %t +} + +; CHECK-LABEL: promote.f128: +; CHECK-NEXT: .functype promote.f128 (i32, f32) -> (){{$}} +; CHECK: call __extendsftf2 +; CHECK: i64.store +; CHECK: i64.store +define fp128 @promote.f128(half %f) { + %t = fpext half %f to fp128 + ret fp128 %t +}