Skip to content

Commit

Permalink
[WebAssembly] Support f16 libcalls
Browse files Browse the repository at this point in the history
Add support for f16 libcalls in WebAssembly. This entails adding signatures
for the remaining F16 libcalls, and renaming gnu_f2h_ieee/gnu_h2f_ieee to
truncsfhf2/extendhfsf2 for consistency between f32 and f64/f128 (compiler-rt
already supports this).

Differential Revision: https://reviews.llvm.org/D61287

Reviewer: dschuff
llvm-svn: 359600
  • Loading branch information
Dan Gohman committed Apr 30, 2019
1 parent 1ca7461 commit 3a7532e
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 9 deletions.
5 changes: 5 additions & 0 deletions llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
Expand Up @@ -271,6 +271,11 @@ WebAssemblyTargetLowering::WebAssemblyTargetLowering(
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.
Expand Down
Expand Up @@ -51,6 +51,8 @@ enum RuntimeLibcallSignature {
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,
Expand Down Expand Up @@ -228,13 +230,15 @@ struct RuntimeLibcallSignatureTable {
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;
Expand Down Expand Up @@ -482,6 +486,10 @@ struct StaticLibcallNameMap {
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;
}
};

Expand Down Expand Up @@ -595,6 +603,15 @@ void llvm::getLibcallSignature(const WebAssemblySubtarget &Subtarget,
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);
Expand Down
59 changes: 51 additions & 8 deletions llvm/test/CodeGen/WebAssembly/f16.ll
Expand Up @@ -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
}

0 comments on commit 3a7532e

Please sign in to comment.