Commit ef98172d authored by Karl Schimpf's avatar Karl Schimpf Committed by Commit Bot

[wasm] Implement i64.trunc_s:sat/f32

Implements the saturating opcode i64.trunc_s:sat/f32.

Also does some refactoring of the i32 saturating opcodes use a simplier
solution (calling a single method to handle all i32 values).

Also refactors code so that the remaining i64 saturating conversions
should be easy to add to the wasm compiler.

Bug: v8:7226
Change-Id: I031aca1e059b4baa989a56ecbc16941f591ff9b3
Reviewed-on: https://chromium-review.googlesource.com/887333
Commit-Queue: Karl Schimpf <kschimpf@chromium.org>
Reviewed-by: 's avatarClemens Hammacher <clemensh@chromium.org>
Cr-Commit-Position: refs/heads/master@{#51001}
parent fcb5b4a5
This diff is collapsed.
......@@ -255,8 +255,16 @@ typedef ZoneVector<Node*> NodeVector;
class WasmGraphBuilder {
public:
enum EnforceBoundsCheck : bool { kNeedsBoundsCheck, kCanOmitBoundsCheck };
struct IntConvertOps;
struct FloatConvertOps;
enum class Type {
kInt8s,
kInt8u,
kInt32s,
kInt32u,
kInt64s,
kInt64u,
kFloat32,
kFloat64
};
WasmGraphBuilder(ModuleEnv* env, Zone* zone, JSGraph* graph,
Handle<Code> centry_stub, wasm::FunctionSig* sig,
......@@ -453,6 +461,7 @@ class WasmGraphBuilder {
private:
enum class NumericImplementation : uint8_t { kTrap, kSaturate };
static const int kDefaultBufferSize = 16;
Zone* const zone_;
......@@ -515,16 +524,10 @@ class WasmGraphBuilder {
Node* BuildF32CopySign(Node* left, Node* right);
Node* BuildF64CopySign(Node* left, Node* right);
Node* BuildI32ConvertOp(Node* input, wasm::WasmCodePosition position,
NumericImplementation impl, const Operator* op,
wasm::WasmOpcode check_op,
const IntConvertOps* int_ops,
const FloatConvertOps* float_ops);
Node* BuildConvertCheck(Node* test, Node* result, Node* input,
wasm::WasmCodePosition position,
NumericImplementation impl,
const IntConvertOps* int_ops,
const FloatConvertOps* float_ops);
Node* BuildI32ConvertFloat(Node* input, wasm::WasmCodePosition position,
NumericImplementation impl, Type int_type,
Type float_type, const Operator* conv_op,
const wasm::WasmOpcode check_op);
Node* BuildI32SConvertF32(Node* input, wasm::WasmCodePosition position,
NumericImplementation impl);
Node* BuildI32SConvertF64(Node* input, wasm::WasmCodePosition position,
......@@ -571,7 +574,15 @@ class WasmGraphBuilder {
Node* input, ExternalReference ref,
MachineRepresentation parameter_representation,
const MachineType result_type, wasm::WasmCodePosition position);
Node* BuildI64SConvertF32(Node* input, wasm::WasmCodePosition position);
Node* BuildI64CcallConvertFloat(Node* input, wasm::WasmCodePosition position,
NumericImplementation impl, Type int_type,
Type float_type, ExternalReference call_ref);
Node* BuildI64TruncConvertFloat(Node* input, wasm::WasmCodePosition position,
NumericImplementation impl, Type int_type,
Type float_type, const Operator* trunc_op);
Node* BuildI64SConvertF32(Node* input, wasm::WasmCodePosition position,
NumericImplementation impl);
Node* BuildI64UConvertF32(Node* input, wasm::WasmCodePosition position);
Node* BuildI64SConvertF64(Node* input, wasm::WasmCodePosition position);
Node* BuildI64UConvertF64(Node* input, wasm::WasmCodePosition position);
......
......@@ -477,6 +477,17 @@ int64_t ExecuteI64SConvertF32(float a, TrapReason* trap) {
return output;
}
int64_t ExecuteI64SConvertSatF32(float a) {
TrapReason base_trap = kTrapCount;
int64_t val = ExecuteI64SConvertF32(a, &base_trap);
if (base_trap == kTrapCount) {
return val;
}
return std::isnan(a) ? 0
: (a < 0.0 ? std::numeric_limits<int64_t>::min()
: std::numeric_limits<int64_t>::max());
}
int64_t ExecuteI64SConvertF64(double a, TrapReason* trap) {
int64_t output;
if (!float64_to_int64_wrapper(&a, &output)) {
......@@ -1565,6 +1576,10 @@ class ThreadImpl {
case kExprI32UConvertSatF64:
Push(WasmValue(ExecuteConvertSaturate<uint32_t>(Pop().to<double>())));
return true;
case kExprI64SConvertSatF32: {
Push(WasmValue(ExecuteI64SConvertSatF32(Pop().to<float>())));
return true;
}
default:
V8_Fatal(__FILE__, __LINE__, "Unknown or unimplemented opcode #%d:%s",
code->start[pc], OpcodeName(code->start[pc]));
......
......@@ -101,9 +101,10 @@ const char* WasmOpcodes::OpcodeName(WasmOpcode opcode) {
CASE_I32_OP(ConvertI64, "wrap/i64")
CASE_CONVERT_OP(Convert, INT, F32, "f32", "trunc")
CASE_CONVERT_OP(Convert, INT, F64, "f64", "trunc")
// TODO(kschimpf): Add I64 versions of saturating conversions.
// TODO(kschimpf): Simplify after filling in other saturating operations.
CASE_CONVERT_SAT_OP(Convert, I32, F32, "f32", "trunc")
CASE_CONVERT_SAT_OP(Convert, I32, F64, "f64", "trunc")
CASE_I64_OP(SConvertSatF32, "trunc_s::sat/f32")
CASE_CONVERT_OP(Convert, I64, I32, "i32", "extend")
CASE_CONVERT_OP(Convert, F32, I32, "i32", "convert")
......
......@@ -408,8 +408,9 @@ using WasmName = Vector<const char>;
V(I32SConvertSatF32, 0xfc00, i_f) \
V(I32UConvertSatF32, 0xfc01, i_f) \
V(I32SConvertSatF64, 0xfc02, i_d) \
V(I32UConvertSatF64, 0xfc03, i_d)
// TODO(kschimpf): Add remaining i64 numeric opcodes.
V(I32UConvertSatF64, 0xfc03, i_d) \
V(I64SConvertSatF32, 0xfc04, l_f)
// TODO(kschimpf): Add remaining numeric opcodes.
#define FOREACH_ATOMIC_OPCODE(V) \
V(I32AtomicLoad, 0xfe10, i_i) \
......
......@@ -73,6 +73,7 @@ namespace test_run_wasm_64 {
V(I64SConvertF64, true) \
V(I64UConvertF32, true) \
V(I64UConvertF64, true) \
V(I64SConvertSatF32, true) \
V(I64SConvertI32, true) \
V(I64UConvertI32, true) \
V(F32SConvertI64, true) \
......@@ -848,6 +849,27 @@ WASM_EXEC_TEST(I64SConvertF32a) {
}
}
WASM_EXEC_TEST(I64SConvertSatF32a) {
EXPERIMENTAL_FLAG_SCOPE(sat_f2i_conversions);
WasmRunner<int64_t, float> r(execution_mode);
BUILD(r, WASM_I64_SCONVERT_SAT_F32(WASM_GET_LOCAL(0)));
FOR_FLOAT32_INPUTS(i) {
int64_t expected;
if (*i < static_cast<float>(std::numeric_limits<int64_t>::max()) &&
*i >= static_cast<float>(std::numeric_limits<int64_t>::min())) {
expected = static_cast<int64_t>(*i);
} else if (std::isnan(*i)) {
expected = static_cast<int64_t>(0);
} else if (*i < 0.0) {
expected = std::numeric_limits<int64_t>::min();
} else {
expected = std::numeric_limits<int64_t>::max();
}
int64_t found = r.Call(*i);
CHECK_EQ(expected, found);
}
}
WASM_EXEC_TEST(I64SConvertF64a) {
WasmRunner<int64_t, double> r(execution_mode);
BUILD(r, WASM_I64_SCONVERT_F64(WASM_GET_LOCAL(0)));
......@@ -1280,6 +1302,29 @@ WASM_EXEC_TEST(I64SConvertF32b) {
}
}
WASM_EXEC_TEST(I64SConvertSatF32b) {
EXPERIMENTAL_FLAG_SCOPE(sat_f2i_conversions);
REQUIRE(I64SConvertSatF32);
WasmRunner<int64_t, float> r(execution_mode);
BUILD(r, WASM_I64_SCONVERT_SAT_F32(WASM_GET_LOCAL(0)));
FOR_FLOAT32_INPUTS(i) {
int64_t expected;
if (*i < static_cast<float>(INT64_MAX) &&
*i >= static_cast<float>(INT64_MIN)) {
expected = static_cast<int64_t>(*i);
} else if (std::isnan(*i)) {
expected = static_cast<int64_t>(0);
} else if (*i < 0.0) {
expected = INT64_MIN;
} else {
expected = INT64_MAX;
}
int64_t found = r.Call(*i);
CHECK_EQ(expected, found);
}
}
WASM_EXEC_TEST(I64SConvertF64b) {
REQUIRE(I64SConvertF64);
WasmRunner<int64_t, double> r(execution_mode);
......
......@@ -564,6 +564,7 @@ inline WasmOpcode LoadStoreOpcodeOf(MachineType type, bool store) {
#define WASM_I32_UCONVERT_SAT_F32(x) x, WASM_NUMERIC_OP(kExprI32UConvertSatF32)
#define WASM_I32_SCONVERT_SAT_F64(x) x, WASM_NUMERIC_OP(kExprI32SConvertSatF64)
#define WASM_I32_UCONVERT_SAT_F64(x) x, WASM_NUMERIC_OP(kExprI32UConvertSatF64)
#define WASM_I64_SCONVERT_SAT_F32(x) x, WASM_NUMERIC_OP(kExprI64SConvertSatF32)
//------------------------------------------------------------------------------
// Memory Operations.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment