mirror of
https://github.com/fluencelabs/wasmer
synced 2024-12-12 13:55:33 +00:00
Implement saturation part of the saturating truncation operators.
These are described here: https://github.com/WebAssembly/nontrapping-float-to-int-conversions/blob/master/proposals/nontrapping-float-to-int-conversion/Overview.md with the relevant text being: "Instead of trapping on positive or negative overflow, they return the maximum or minimum integer value, respectively, and do not trap. (This behavior is also referred to as 'saturating'.)" "Instead of trapping on NaN, they return 0 and do not trap."
This commit is contained in:
parent
7fb88251d4
commit
481bdb7d48
@ -101,6 +101,40 @@ fn trap_if_not_representable_as_int(
|
||||
builder.position_at_end(&continue_block);
|
||||
}
|
||||
|
||||
fn saturate_if_not_representable_as_int(
|
||||
builder: &Builder,
|
||||
lower_bound: f64,
|
||||
upper_bound: f64,
|
||||
value: FloatValue,
|
||||
) -> FloatValue {
|
||||
let float_ty = value.get_type();
|
||||
|
||||
let zero = float_ty.const_zero();
|
||||
let lower_bound = float_ty.const_float(lower_bound);
|
||||
let upper_bound = float_ty.const_float(upper_bound);
|
||||
|
||||
let is_nan_cmp = builder.build_float_compare(FloatPredicate::UNE, value, value, "is_nan");
|
||||
let above_upper_bound_cmp =
|
||||
builder.build_float_compare(FloatPredicate::OGT, value, upper_bound, "above_upper_bound");
|
||||
let below_lower_bound_cmp =
|
||||
builder.build_float_compare(FloatPredicate::OLT, value, lower_bound, "below_lower_bound");
|
||||
let value = builder.build_select(is_nan_cmp, zero, value, "nan_to_zero");
|
||||
let value = builder.build_select(
|
||||
above_upper_bound_cmp,
|
||||
upper_bound,
|
||||
*value.as_float_value(),
|
||||
"saturate_upper_bound",
|
||||
);
|
||||
let value = builder.build_select(
|
||||
below_lower_bound_cmp,
|
||||
lower_bound,
|
||||
*value.as_float_value(),
|
||||
"saturate_lower_bound",
|
||||
);
|
||||
|
||||
value.into_float_value()
|
||||
}
|
||||
|
||||
fn trap_if_zero_or_overflow(
|
||||
builder: &Builder,
|
||||
intrinsics: &Intrinsics,
|
||||
@ -1685,8 +1719,18 @@ impl FunctionCodeGenerator<CodegenError> for LLVMFunctionCodeGenerator {
|
||||
builder.build_float_to_signed_int(v1, intrinsics.i32_ty, &state.var_name());
|
||||
state.push1(res);
|
||||
}
|
||||
Operator::I32TruncSSatF32 | Operator::I32TruncSSatF64 => {
|
||||
Operator::I32TruncSSatF32 => {
|
||||
let v1 = state.pop1()?.into_float_value();
|
||||
let v1 =
|
||||
saturate_if_not_representable_as_int(builder, -2147483904.0, 2147483648.0, v1);
|
||||
let res =
|
||||
builder.build_float_to_signed_int(v1, intrinsics.i32_ty, &state.var_name());
|
||||
state.push1(res);
|
||||
}
|
||||
Operator::I32TruncSSatF64 => {
|
||||
let v1 = state.pop1()?.into_float_value();
|
||||
let v1 =
|
||||
saturate_if_not_representable_as_int(builder, -2147483649.0, 2147483648.0, v1);
|
||||
let res =
|
||||
builder.build_float_to_signed_int(v1, intrinsics.i32_ty, &state.var_name());
|
||||
state.push1(res);
|
||||
@ -1721,28 +1765,31 @@ impl FunctionCodeGenerator<CodegenError> for LLVMFunctionCodeGenerator {
|
||||
builder.build_float_to_signed_int(v1, intrinsics.i64_ty, &state.var_name());
|
||||
state.push1(res);
|
||||
}
|
||||
Operator::I64TruncSSatF32 | Operator::I64TruncSSatF64 => {
|
||||
Operator::I64TruncSSatF32 => {
|
||||
let v1 = state.pop1()?.into_float_value();
|
||||
let v1 = saturate_if_not_representable_as_int(
|
||||
builder,
|
||||
-9223373136366403584.0,
|
||||
9223372036854775808.0,
|
||||
v1,
|
||||
);
|
||||
let res =
|
||||
builder.build_float_to_signed_int(v1, intrinsics.i64_ty, &state.var_name());
|
||||
state.push1(res);
|
||||
}
|
||||
Operator::I32TruncUF32 => {
|
||||
Operator::I64TruncSSatF64 => {
|
||||
let v1 = state.pop1()?.into_float_value();
|
||||
trap_if_not_representable_as_int(
|
||||
let v1 = saturate_if_not_representable_as_int(
|
||||
builder,
|
||||
intrinsics,
|
||||
context,
|
||||
&function,
|
||||
-1.0,
|
||||
4294967296.0,
|
||||
-9223372036854777856.0,
|
||||
9223372036854775808.0,
|
||||
v1,
|
||||
);
|
||||
let res =
|
||||
builder.build_float_to_unsigned_int(v1, intrinsics.i32_ty, &state.var_name());
|
||||
builder.build_float_to_signed_int(v1, intrinsics.i64_ty, &state.var_name());
|
||||
state.push1(res);
|
||||
}
|
||||
Operator::I32TruncUF64 => {
|
||||
Operator::I32TruncUF32 | Operator::I32TruncUF64 => {
|
||||
let v1 = state.pop1()?.into_float_value();
|
||||
trap_if_not_representable_as_int(
|
||||
builder,
|
||||
@ -1759,6 +1806,7 @@ impl FunctionCodeGenerator<CodegenError> for LLVMFunctionCodeGenerator {
|
||||
}
|
||||
Operator::I32TruncUSatF32 | Operator::I32TruncUSatF64 => {
|
||||
let v1 = state.pop1()?.into_float_value();
|
||||
let v1 = saturate_if_not_representable_as_int(builder, -1.0, 4294967296.0, v1);
|
||||
let res =
|
||||
builder.build_float_to_unsigned_int(v1, intrinsics.i32_ty, &state.var_name());
|
||||
state.push1(res);
|
||||
@ -1795,6 +1843,8 @@ impl FunctionCodeGenerator<CodegenError> for LLVMFunctionCodeGenerator {
|
||||
}
|
||||
Operator::I64TruncUSatF32 | Operator::I64TruncUSatF64 => {
|
||||
let v1 = state.pop1()?.into_float_value();
|
||||
let v1 =
|
||||
saturate_if_not_representable_as_int(builder, -1.0, 18446744073709551616.0, v1);
|
||||
let res =
|
||||
builder.build_float_to_unsigned_int(v1, intrinsics.i64_ty, &state.var_name());
|
||||
state.push1(res);
|
||||
|
Loading…
Reference in New Issue
Block a user