diff --git a/test/wasmBenchmarker/benchmark.py b/test/wasmBenchmarker/benchmark.py index 29bdc823f..666984a76 100755 --- a/test/wasmBenchmarker/benchmark.py +++ b/test/wasmBenchmarker/benchmark.py @@ -36,17 +36,21 @@ "heapsort": 0, "huffman": 0, "k_nucleotide": 1, - "mandelbrot": 2091942736, - "nbody": -0.169083713, + "mandelbrot": 775007, + "nbody": -0.1691057, "nqueens": 0, "prime": 48611, "quick_sort": 0, "red-black": 4000000, - "salesman": 840 + "salesman": 840, + "simdMandelbrot": 775007, + "simdNbody": -0.1691057 } # https://benchmarksgame-team.pages.debian.net/benchmarksgame/description/simple.html#simple gameTests = ["mandelbrot", "nbody", "gregory", "fannkuch", "k_nucleotide"] +simdTests = ["simdMandelbrot", "simdNbody"] + def prepare_arg_pars(): parser = argparse.ArgumentParser() parser.add_argument('--test-dir', metavar='PATH', help='path to the test files written in c', nargs='?', @@ -58,6 +62,7 @@ def prepare_arg_pars(): parser.add_argument('--iterations', metavar='NUMBER', help='how many times run the tests', nargs='?', const='10', default=10, type=int) parser.add_argument('--compile-anyway', help='compile the tests even if they are compiled', action='store_true') + parser.add_argument('--enable-simd', help='run SIMD tests too', action='store_true') return parser.parse_args() @@ -98,7 +103,7 @@ def get_emcc(): return emcc_path -def compile_tests(emcc_path, path, only_game=False, compile_anyway=False, run=None): +def compile_tests(emcc_path, path, only_game=False, compile_anyway=False, simd=False, run=None): if not os.path.exists(emcc_path): print("invalid path for emcc: " + emcc_path) exit(1) @@ -118,7 +123,9 @@ def compile_tests(emcc_path, path, only_game=False, compile_anyway=False, run=No for file in test_list: name = file.split('.')[0] - if (name not in gameTests and only_game) or (run is not None and name != run): + if (name not in gameTests and only_game) or \ + (run is not None and name != run) or \ + (name in simdTests and not simd): continue test_names.append(name) @@ -127,8 +134,10 @@ def compile_tests(emcc_path, path, only_game=False, compile_anyway=False, run=No print("target files are found; compilation skipped") continue + extraFlags = "-msimd128" if file.startswith("simd") else "" + print("compiling " + name) - bob_the_stringbuilder = emcc_path + " " + path + "/" + file + " --no-entry -s WASM=1 -s EXPORTED_FUNCTIONS=_runtime -s EXPORTED_RUNTIME_METHODS=ccall,cwrap -o " + path + "/wasm/" + name + ".wasm" + bob_the_stringbuilder = emcc_path + " " + path + "/" + file + " " + extraFlags + " --no-entry -s WASM=1 -s EXPORTED_FUNCTIONS=_runtime -s EXPORTED_RUNTIME_METHODS=ccall,cwrap -o " + path + "/wasm/" + name + ".wasm" print(bob_the_stringbuilder) os.system(bob_the_stringbuilder) @@ -217,7 +226,7 @@ def main(): check_programs(args.engines) emcc_path = get_emcc() - test_names = compile_tests(emcc_path, args.test_dir, args.only_game, args.compile_anyway, args.run) + test_names = compile_tests(emcc_path, args.test_dir, args.only_game, args.compile_anyway, args.enable_simd, args.run) generate_report( run_tests(args.test_dir, test_names, args.engines, args.iterations), args.report) diff --git a/test/wasmBenchmarker/ctests/mandelbrot.c b/test/wasmBenchmarker/ctests/mandelbrot.c index 5ce52f081..7b0d91c29 100755 --- a/test/wasmBenchmarker/ctests/mandelbrot.c +++ b/test/wasmBenchmarker/ctests/mandelbrot.c @@ -14,57 +14,67 @@ * limitations under the License. */ -#include #include +#include +#include +#include -#define LOOP 600 -#define X_MIN -1.5 -#define X_MAX 0.5 -#define Y_MIN -1.0 -#define Y_MAX 1.0 -#define X_RES 512 +#define WIDTH 1600 +#define HIGHT 1400 +#define N 20 +#define REAL_AXIS_SHIFT -1.8 // ~ horizontal shift +#define IMAGINARY_AXIS_SHIFT -1.0 // ~ vertical shift +#define ZOOM 0.0015 -uint32_t runtime() { - const int yRes = (X_RES * (Y_MAX - Y_MIN)) / (X_MAX - X_MIN); +#define getNthBit(b, n) ((b & (1 << (7 - n))) > 0) - double dx = (X_MAX - X_MIN) / X_RES; - double dy = (Y_MAX - Y_MIN) / yRes; - double x, y; - int k; +#define clearNthBit(b, n) b = b & (0xFF - (1 << (7 - n))) - uint16_t retValLower = 0; - uint16_t retValHigher = 0; +#define setNthBit(b, n) b = b | (1 << (7 - n)) - for (int j = 0; j < yRes; j++) { - y = Y_MAX - j * dy; +#define ABS_COMPLEX(z_real, z_complex) (sqrtf(z_real * z_real + z_complex * z_complex)) - for (int i = 0; i < X_RES; i++) { - double u = 0; - double v = 0; - double u2 = 0; - double v2 = 0; +typedef uint8_t byte; - x = X_MIN + i * dx; +byte isInMandelbrotSet(float c_real, float c_imaginary) +{ + byte result = 0b10000000; + float z_real = 0; + float z_imaginary = 0; + for (size_t k = 0; k < N; k++) { + float complex_abs = ABS_COMPLEX(z_real, z_imaginary); + if (getNthBit(result, 0) == 1 && complex_abs > 2) { + clearNthBit(result, 0); + } else { + float next_z_real = (z_real * z_real - z_imaginary * z_imaginary) + c_real; + float next_z_imaginary = ((float)2.0 * z_real * z_imaginary) + c_imaginary; + z_real = next_z_real; + z_imaginary = next_z_imaginary; + } - for (k = 1; k < LOOP && (u2 + v2 < 4.0); k++) { - v = 2 * u * v + y; - u = u2 - v2 + x; - u2 = u * u; - v2 = v * v; - } + if (result == 0) { + break; + } + } + return result; +} - if (k >= LOOP) { - retValLower++; - } else { - retValHigher++; +uint32_t runtime() { + uint32_t setSize = 0; + for (int i = 0; i < HIGHT; i++) { + for (int j = 0; j < WIDTH; j++) { + float real = ((float)j * (float)ZOOM) + (float)REAL_AXIS_SHIFT; + float imaginary = ((float)i * (float)ZOOM) + (float)IMAGINARY_AXIS_SHIFT; + if (getNthBit(isInMandelbrotSet(real, imaginary),0)) { + setSize++; } } } - - return retValLower + (retValHigher << 16); + return setSize; } + int main() { - printf("%d\n", runtime()); + printf("%u\n", runtime()); return 0; -} \ No newline at end of file +} diff --git a/test/wasmBenchmarker/ctests/nbody.c b/test/wasmBenchmarker/ctests/nbody.c index f8c19452e..b789bcdd3 100755 --- a/test/wasmBenchmarker/ctests/nbody.c +++ b/test/wasmBenchmarker/ctests/nbody.c @@ -15,128 +15,75 @@ */ #include +#include -#define LOOP 200000 -#define SOLAR_MASS 39.47841760435743 -#define DAYS_PER_YEAR 365.24 +#define LOOP 450000 +#define SOLAR_MASS 39.47841760435743f +#define DAYS_PER_YEAR 365.24f #define BODIES_COUNT 5 #define INTERACTIONS_COUNT (BODIES_COUNT * (BODIES_COUNT - 1) / 2) +#define square(x) x * x + typedef struct { - double position[3], velocity[3], mass; + float position[3]; + float velocity[3]; + float mass; } body; -body solarBodies[] = { - {// Sun - .mass = SOLAR_MASS - }, - {// Jupiter - {4.84143144246472090e+00, -1.16032004402742839e+00, -1.03622044471123109e-01}, - {1.66007664274403694e-03 * DAYS_PER_YEAR, 7.69901118419740425e-03 * DAYS_PER_YEAR, - -6.90460016972063023e-05 * - DAYS_PER_YEAR}, - 9.54791938424326609e-04 * SOLAR_MASS - }, - {// Saturn - {8.34336671824457987e+00, 4.12479856412430479e+00, -4.03523417114321381e-01}, - {-2.76742510726862411e-03 * DAYS_PER_YEAR, 4.99852801234917238e-03 * - DAYS_PER_YEAR, 2.30417297573763929e-05 * - DAYS_PER_YEAR}, - 2.85885980666130812e-04 * SOLAR_MASS - }, - {// Uranus - {1.28943695621391310e+01, -1.51111514016986312e+01, -2.23307578892655734e-01}, - {2.96460137564761618e-03 * DAYS_PER_YEAR, 2.37847173959480950e-03 * - DAYS_PER_YEAR, -2.96589568540237556e-05 * - DAYS_PER_YEAR}, - 4.36624404335156298e-05 * SOLAR_MASS - }, - {// Neptune - {1.53796971148509165e+01, -2.59193146099879641e+01, 1.79258772950371181e-01}, - {2.68067772490389322e-03 * DAYS_PER_YEAR, 1.62824170038242295e-03 * - DAYS_PER_YEAR, -9.51592254519715870e-05 * - DAYS_PER_YEAR}, - 5.15138902046611451e-05 * SOLAR_MASS - } -}; - -double square_root(double x) { - int square; - int p = 0; - - do { - p++; - square = (p + 1) * (p + 1); - } while (x > square); - - double y = (double) p; - int c = 0; - - while (c < 10) { - y = (x / y + y) / 2; - - if (y * y == x) { - return y; - } - - c++; - } - - return y; -} - -void move() { - double dPosition[3][INTERACTIONS_COUNT], magnitudes[INTERACTIONS_COUNT]; +void move(body solarBodies[]) { + float dPosition[INTERACTIONS_COUNT][3]; + float magnitudes[INTERACTIONS_COUNT]; for (unsigned int i = 0, k = 0; i < BODIES_COUNT - 1; i++) { for (unsigned int j = i + 1; j < BODIES_COUNT; j++, k++) { for (unsigned int m = 0; m < 3; m++) { - dPosition[m][k] = solarBodies[i].position[m] - solarBodies[j].position[m]; + dPosition[k][m] = solarBodies[i].position[m] - solarBodies[j].position[m]; } } } for (unsigned int i = 0; i < INTERACTIONS_COUNT; i++) { - const double dx = dPosition[0][i]; - const double dy = dPosition[1][i]; - const double dz = dPosition[2][i]; - const double distanceSquared = dx * dx + dy * dy + dz * dz; - magnitudes[i] = 0.01 / (square_root(distanceSquared) * distanceSquared); + const float dx = dPosition[i][0]; + const float dy = dPosition[i][1]; + const float dz = dPosition[i][2]; + const float distanceSquared = square(dx) + square(dy) + square(dz); + magnitudes[i] = 0.01f / (sqrtf(distanceSquared) * distanceSquared); } for (unsigned int i = 0, k = 0; i < BODIES_COUNT - 1; i++) { for (unsigned int j = i + 1; j < BODIES_COUNT; j++, k++) { - const double massI = solarBodies[i].mass * magnitudes[k]; - const double massJ = solarBodies[j].mass * magnitudes[k]; + const float massI = solarBodies[i].mass * magnitudes[k]; + const float massJ = solarBodies[j].mass * magnitudes[k]; - for (unsigned int m = 0; m < 3; ++m) { - solarBodies[i].velocity[m] -= dPosition[m][k] * massJ; - solarBodies[j].velocity[m] += dPosition[m][k] * massI; + for (unsigned int m = 0; m < 3; m++) { + solarBodies[i].velocity[m] -= dPosition[k][m] * massJ; + solarBodies[j].velocity[m] += dPosition[k][m] * massI; } } } for (unsigned int i = 0; i < BODIES_COUNT; i++) { for (unsigned int m = 0; m < 3; m++) { - solarBodies[i].position[m] += 0.01 * solarBodies[i].velocity[m]; + solarBodies[i].position[m] += 0.01f * solarBodies[i].velocity[m]; } } } -double energy() { - double energy = 0.0; +float energy(body solarBodies[]) { + float energy = 0.0f; for (unsigned int i = 0; i < BODIES_COUNT; i++) { - energy += 0.5 * solarBodies[i].mass * + energy += 0.5f * solarBodies[i].mass * (solarBodies[i].velocity[0] * solarBodies[i].velocity[0] + solarBodies[i].velocity[1] * solarBodies[i].velocity[1] + solarBodies[i].velocity[2] * solarBodies[i].velocity[2]); for (unsigned int j = i + 1; j < BODIES_COUNT; j++) { - double dx = solarBodies[i].position[0] - solarBodies[j].position[0]; - double dy = solarBodies[i].position[1] - solarBodies[j].position[1]; - double dz = solarBodies[i].position[2] - solarBodies[j].position[2]; - double distance = square_root(dx * dx + dy * dy + dz * dz); + float dx = solarBodies[i].position[0] - solarBodies[j].position[0]; + float dy = solarBodies[i].position[1] - solarBodies[j].position[1]; + float dz = solarBodies[i].position[2] - solarBodies[j].position[2]; + float distance = sqrtf(square(dx) + square(dy) + square(dz)); energy -= (solarBodies[i].mass * solarBodies[j].mass) / distance; } } @@ -144,21 +91,89 @@ double energy() { return energy; } -double runtime() { - for (unsigned int i = 0; i < BODIES_COUNT; ++i) { - for (unsigned int m = 0; m < 3; ++m) { +float runtime() { + body solarBodies[] = { + { // Sun + .position = { + 0.0f, + 0.0f, + 0.0f + }, + .velocity = { + 0.0f, + 0.0f, + 0.0f + }, + .mass = SOLAR_MASS + }, + { // Jupiter + .position = { + +4.84143144246472090e+00f, + -1.16032004402742839e+00f, + -1.03622044471123109e-01f + }, + .velocity = { + +1.66007664274403694e-03f * DAYS_PER_YEAR, + +7.69901118419740425e-03f * DAYS_PER_YEAR, + -6.90460016972063023e-05f * DAYS_PER_YEAR, + }, + .mass = +9.54791938424326609e-04f * SOLAR_MASS + }, + { // Saturn + .position = { + +8.34336671824457987e+00f, + +4.12479856412430479e+00f, + -4.03523417114321381e-01f + }, + .velocity = { + -2.76742510726862411e-03f * DAYS_PER_YEAR, + +4.99852801234917238e-03f * DAYS_PER_YEAR, + +2.30417297573763929e-05f * DAYS_PER_YEAR + }, + .mass = +2.85885980666130812e-04f * SOLAR_MASS + }, + { // Uranus + .position = { + +1.28943695621391310e+01f, + -1.51111514016986312e+01f, + -2.23307578892655734e-01f + }, + .velocity = { + +2.96460137564761618e-03f * DAYS_PER_YEAR, + +2.37847173959480950e-03f * DAYS_PER_YEAR, + -2.96589568540237556e-05f * DAYS_PER_YEAR + }, + .mass = +4.36624404335156298e-05f * SOLAR_MASS + }, + { // Neptune + .position = { + +1.53796971148509165e+01f, + -2.59193146099879641e+01f, + +1.79258772950371181e-01f + }, + .velocity = { + +2.68067772490389322e-03f * DAYS_PER_YEAR, + +1.62824170038242295e-03f * DAYS_PER_YEAR, + -9.51592254519715870e-05f * DAYS_PER_YEAR + }, + .mass = +5.15138902046611451e-05f * SOLAR_MASS + } + }; + + for (unsigned int i = 0; i < BODIES_COUNT; i++) { + for (unsigned int m = 0; m < 3; m++) { solarBodies[0].velocity[m] -= solarBodies[i].velocity[m] * solarBodies[i].mass / SOLAR_MASS; } } for (unsigned int i = 0; i < LOOP; i++) { - move(); + move(solarBodies); } - return energy(); + return energy(solarBodies); } int main() { printf("%.9f\n", runtime()); return 0; -} \ No newline at end of file +} diff --git a/test/wasmBenchmarker/ctests/simdMandelbrot.c b/test/wasmBenchmarker/ctests/simdMandelbrot.c new file mode 100644 index 000000000..8399aab83 --- /dev/null +++ b/test/wasmBenchmarker/ctests/simdMandelbrot.c @@ -0,0 +1,70 @@ +#include +#include +#include + +#include + +#define WIDTH 1600 +#define HIGHT 1400 +#define N 20 +#define REAL_AXIS_SHIFT -1.8 // ~ horizontal shift +#define IMAGINARY_AXIS_SHIFT -1.0 // ~ vertical shift +#define ZOOM 0.0015 + +#define getNthBit(b, n) ((b & (1 << (7 - n))) > 0) + +#define clearNthBit(b, n) b = b & (0xFF - (1 << (7 - n))) + +#define setNthBit(b, n) b = b | (1 << (7 - n)) + +#define SQUARE(z) wasm_f32x4_mul(z, z) + +#define ABS_COMPLEX(z_real, z_complex) wasm_f32x4_sqrt(wasm_f32x4_add(SQUARE(z_real), SQUARE(z_imaginary))) + +typedef uint8_t byte; + +byte areInMandelbrotSet(v128_t c_real, v128_t c_imaginary) +{ + byte result = 0b11110000; + v128_t z_real = wasm_f32x4_const_splat(0); + v128_t z_imaginary = wasm_f32x4_const_splat(0); + for (size_t k = 0; k < N; k++) { + v128_t cmp_result = wasm_f32x4_gt(ABS_COMPLEX(z_real, z_imaginary), wasm_f32x4_const_splat(2)); + for (size_t i = 0; i < 4; i++) { + if (getNthBit(result, i) == 1 && ((float*)&cmp_result)[i] != 0) { + clearNthBit(result, i); + } + } + v128_t next_z_real = wasm_f32x4_add(wasm_f32x4_sub(SQUARE(z_real), SQUARE(z_imaginary)), c_real); + v128_t next_z_imaginary = wasm_f32x4_add(wasm_f32x4_mul(wasm_f32x4_mul(z_real, z_imaginary), wasm_f32x4_const_splat(2)), c_imaginary); + z_real = next_z_real; + z_imaginary = next_z_imaginary; + + if (result == 0) { + break; + } + } + return result; +} + +uint32_t runtime() { + uint32_t setSize = 0; + for (int i = 0; i < HIGHT; i++) { + for (int j = 0; j < WIDTH; j+=4) { + v128_t real = wasm_f32x4_add(wasm_f32x4_mul(wasm_f32x4_make(j, j+1, j+2, j+3), wasm_f32x4_const_splat(ZOOM)), wasm_f32x4_const_splat(REAL_AXIS_SHIFT)); + v128_t imaginary = wasm_f32x4_add(wasm_f32x4_mul(wasm_f32x4_make(i, i, i, i), wasm_f32x4_const_splat(ZOOM)), wasm_f32x4_const_splat(IMAGINARY_AXIS_SHIFT)); + byte pixels = areInMandelbrotSet(real, imaginary); + for (int i = 0; i < 4; i++) { + if (getNthBit(pixels, i)) { + setSize++; + } + } + } + } + return setSize; +} + +int main() { + printf("%u\n", runtime()); + return 0; +} diff --git a/test/wasmBenchmarker/ctests/simdNbody.c b/test/wasmBenchmarker/ctests/simdNbody.c new file mode 100755 index 000000000..997d81992 --- /dev/null +++ b/test/wasmBenchmarker/ctests/simdNbody.c @@ -0,0 +1,179 @@ +/* + * Copyright (c) 2023-present Samsung Electronics Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include + +#define LOOP 450000 +#define SOLAR_MASS 39.47841760435743f +#define DAYS_PER_YEAR 365.24f +#define BODIES_COUNT 5 +#define INTERACTIONS_COUNT (BODIES_COUNT * (BODIES_COUNT - 1) / 2) + +typedef struct { + v128_t position; // last element is not used + v128_t velocity; // last element is not used + float mass; +} body; + +void move(body solarBodies[]) { + v128_t dPosition[INTERACTIONS_COUNT]; // last element of each one is unused + float magnitudes[INTERACTIONS_COUNT]; + + for (unsigned int i = 0, k = 0; i < BODIES_COUNT - 1; i++) { + for (unsigned int j = i + 1; j < BODIES_COUNT; j++, k++) { + dPosition[k] = wasm_f32x4_sub(solarBodies[i].position, solarBodies[j].position); + } + } + + for (unsigned int i = 0; i < INTERACTIONS_COUNT; i++) { + v128_t dPosition_squared = wasm_f32x4_mul(dPosition[i], dPosition[i]); + const float distanceSquared = wasm_f32x4_extract_lane(dPosition_squared, 0) + + wasm_f32x4_extract_lane(dPosition_squared, 1) + + wasm_f32x4_extract_lane(dPosition_squared, 2); + magnitudes[i] = 0.01f / (sqrtf(distanceSquared) * distanceSquared); + } + + for (unsigned int i = 0, k = 0; i < BODIES_COUNT - 1; i++) { + for (unsigned int j = i + 1; j < BODIES_COUNT; j++, k++) { + const float massI = solarBodies[i].mass * magnitudes[k]; + const float massJ = solarBodies[j].mass * magnitudes[k]; + + solarBodies[i].velocity = wasm_f32x4_sub(solarBodies[i].velocity, wasm_f32x4_mul(dPosition[k], wasm_f32x4_splat(massJ))); + solarBodies[j].velocity = wasm_f32x4_add(solarBodies[j].velocity, wasm_f32x4_mul(dPosition[k], wasm_f32x4_splat(massI))); + } + } + + for (unsigned int i = 0; i < BODIES_COUNT; i++) { + solarBodies[i].position = wasm_f32x4_add(solarBodies[i].position, wasm_f32x4_mul(wasm_f32x4_splat(0.01f), solarBodies[i].velocity)); + } +} + +float energy(body solarBodies[]) { + float energy = 0.0f; + + for (unsigned int i = 0; i < BODIES_COUNT; i++) { + v128_t solarBodyVelocitySquare = wasm_f32x4_mul(solarBodies[i].velocity, solarBodies[i].velocity); + float sum = wasm_f32x4_extract_lane(solarBodyVelocitySquare, 0) + + wasm_f32x4_extract_lane(solarBodyVelocitySquare, 1) + + wasm_f32x4_extract_lane(solarBodyVelocitySquare, 2); + energy += 0.5f * solarBodies[i].mass * sum; + + for (unsigned int j = i + 1; j < BODIES_COUNT; j++) { + v128_t d = wasm_f32x4_sub(solarBodies[i].position, solarBodies[j].position); + v128_t dSquare = wasm_f32x4_mul(d, d); + float distance = sqrtf( wasm_f32x4_extract_lane(dSquare, 0) + + wasm_f32x4_extract_lane(dSquare, 1) + + wasm_f32x4_extract_lane(dSquare, 2) + ); + energy -= (solarBodies[i].mass * solarBodies[j].mass) / distance; + } + } + + return energy; +} + +float runtime() { + body solarBodies[] = { + { // Sun + .position = wasm_f32x4_make( + 0.0f, + 0.0f, + 0.0f, + 0.0f // unused + ), + .velocity = wasm_f32x4_make( + 0.0f, + 0.0f, + 0.0f, + 0.0f // unused + ), + .mass = SOLAR_MASS + }, + { // Jupiter + .position = wasm_f32x4_make( + +4.84143144246472090e+00f, + -1.16032004402742839e+00f, + -1.03622044471123109e-01f, + +0.0f // unused + ), + .velocity = wasm_f32x4_mul( wasm_f32x4_make( + +1.66007664274403694e-03f, + +7.69901118419740425e-03f, + -6.90460016972063023e-05f, + +0.0f // unused + ), wasm_f32x4_splat(DAYS_PER_YEAR)), + .mass = +9.54791938424326609e-04f * SOLAR_MASS + }, + { // Saturn + .position = wasm_f32x4_make( + +8.34336671824457987e+00f, + +4.12479856412430479e+00f, + -4.03523417114321381e-01f, + +0.0f // unused + ), + .velocity = wasm_f32x4_mul( wasm_f32x4_make( + -2.76742510726862411e-03f, + +4.99852801234917238e-03f, + +2.30417297573763929e-05f, + +0.0f // unused + ), wasm_f32x4_splat(DAYS_PER_YEAR)), + .mass = +2.85885980666130812e-04f * SOLAR_MASS + }, + { // Uranus + .position = wasm_f32x4_make( + +1.28943695621391310e+01f, + -1.51111514016986312e+01f, + -2.23307578892655734e-01f, + +0.0f // unused + ), + .velocity = wasm_f32x4_mul( wasm_f32x4_make( + +2.96460137564761618e-03f, + +2.37847173959480950e-03f, + -2.96589568540237556e-05f, + +0.0f // unused + ), wasm_f32x4_splat(DAYS_PER_YEAR)), + .mass = +4.36624404335156298e-05f * SOLAR_MASS + }, + { // Neptune + .position = wasm_f32x4_make( + +1.53796971148509165e+01f, + -2.59193146099879641e+01f, + +1.79258772950371181e-01f, + +0.0f // unused + ), + .velocity = wasm_f32x4_mul( wasm_f32x4_make( + +2.68067772490389322e-03f, + +1.62824170038242295e-03f, + -9.51592254519715870e-05f, + +0.0f // unused + ), wasm_f32x4_splat(DAYS_PER_YEAR)), + .mass = +5.15138902046611451e-05f * SOLAR_MASS + } + }; + + for (unsigned int i = 0; i < BODIES_COUNT; i++) { + solarBodies[0].velocity = wasm_f32x4_sub(solarBodies[0].velocity, wasm_f32x4_div(wasm_f32x4_mul(solarBodies[i].velocity, wasm_f32x4_splat(solarBodies[i].mass)),wasm_f32x4_splat(SOLAR_MASS))); + } + + for (unsigned int i = 0; i < LOOP; i++) { + move(solarBodies); + } + + return energy(solarBodies); +}