xref: /qemu/tests/fp/fp-bench.c (revision afbcca0ea41f109c2a5eae308d636dfcf98eb82b)
125f539f3SEmilio G. Cota /*
225f539f3SEmilio G. Cota  * fp-bench.c - A collection of simple floating point microbenchmarks.
325f539f3SEmilio G. Cota  *
425f539f3SEmilio G. Cota  * Copyright (C) 2018, Emilio G. Cota <cota@braap.org>
525f539f3SEmilio G. Cota  *
625f539f3SEmilio G. Cota  * License: GNU GPL, version 2 or later.
725f539f3SEmilio G. Cota  *   See the COPYING file in the top-level directory.
825f539f3SEmilio G. Cota  */
925f539f3SEmilio G. Cota #ifndef HW_POISON_H
1025f539f3SEmilio G. Cota #error Must define HW_POISON_H to work around TARGET_* poisoning
1125f539f3SEmilio G. Cota #endif
1225f539f3SEmilio G. Cota 
1325f539f3SEmilio G. Cota #include "qemu/osdep.h"
1425f539f3SEmilio G. Cota #include <math.h>
1525f539f3SEmilio G. Cota #include <fenv.h>
1625f539f3SEmilio G. Cota #include "qemu/timer.h"
17f2b84b9eSAlex Bennée #include "qemu/int128.h"
1825f539f3SEmilio G. Cota #include "fpu/softfloat.h"
1925f539f3SEmilio G. Cota 
2025f539f3SEmilio G. Cota /* amortize the computation of random inputs */
2125f539f3SEmilio G. Cota #define OPS_PER_ITER     50000
2225f539f3SEmilio G. Cota 
2325f539f3SEmilio G. Cota #define MAX_OPERANDS 3
2425f539f3SEmilio G. Cota 
2525f539f3SEmilio G. Cota #define SEED_A 0xdeadfacedeadface
2625f539f3SEmilio G. Cota #define SEED_B 0xbadc0feebadc0fee
2725f539f3SEmilio G. Cota #define SEED_C 0xbeefdeadbeefdead
2825f539f3SEmilio G. Cota 
2925f539f3SEmilio G. Cota enum op {
3025f539f3SEmilio G. Cota     OP_ADD,
3125f539f3SEmilio G. Cota     OP_SUB,
3225f539f3SEmilio G. Cota     OP_MUL,
3325f539f3SEmilio G. Cota     OP_DIV,
3425f539f3SEmilio G. Cota     OP_FMA,
3525f539f3SEmilio G. Cota     OP_SQRT,
3625f539f3SEmilio G. Cota     OP_CMP,
3725f539f3SEmilio G. Cota     OP_MAX_NR,
3825f539f3SEmilio G. Cota };
3925f539f3SEmilio G. Cota 
4025f539f3SEmilio G. Cota static const char * const op_names[] = {
4125f539f3SEmilio G. Cota     [OP_ADD] = "add",
4225f539f3SEmilio G. Cota     [OP_SUB] = "sub",
4325f539f3SEmilio G. Cota     [OP_MUL] = "mul",
4425f539f3SEmilio G. Cota     [OP_DIV] = "div",
4525f539f3SEmilio G. Cota     [OP_FMA] = "mulAdd",
4625f539f3SEmilio G. Cota     [OP_SQRT] = "sqrt",
4725f539f3SEmilio G. Cota     [OP_CMP] = "cmp",
4825f539f3SEmilio G. Cota     [OP_MAX_NR] = NULL,
4925f539f3SEmilio G. Cota };
5025f539f3SEmilio G. Cota 
5125f539f3SEmilio G. Cota enum precision {
5225f539f3SEmilio G. Cota     PREC_SINGLE,
5325f539f3SEmilio G. Cota     PREC_DOUBLE,
54f2b84b9eSAlex Bennée     PREC_QUAD,
5525f539f3SEmilio G. Cota     PREC_FLOAT32,
5625f539f3SEmilio G. Cota     PREC_FLOAT64,
57f2b84b9eSAlex Bennée     PREC_FLOAT128,
5825f539f3SEmilio G. Cota     PREC_MAX_NR,
5925f539f3SEmilio G. Cota };
6025f539f3SEmilio G. Cota 
6125f539f3SEmilio G. Cota enum rounding {
6225f539f3SEmilio G. Cota     ROUND_EVEN,
6325f539f3SEmilio G. Cota     ROUND_ZERO,
6425f539f3SEmilio G. Cota     ROUND_DOWN,
6525f539f3SEmilio G. Cota     ROUND_UP,
6625f539f3SEmilio G. Cota     ROUND_TIEAWAY,
6725f539f3SEmilio G. Cota     N_ROUND_MODES,
6825f539f3SEmilio G. Cota };
6925f539f3SEmilio G. Cota 
7025f539f3SEmilio G. Cota static const char * const round_names[] = {
7125f539f3SEmilio G. Cota     [ROUND_EVEN] = "even",
7225f539f3SEmilio G. Cota     [ROUND_ZERO] = "zero",
7325f539f3SEmilio G. Cota     [ROUND_DOWN] = "down",
7425f539f3SEmilio G. Cota     [ROUND_UP] = "up",
7525f539f3SEmilio G. Cota     [ROUND_TIEAWAY] = "tieaway",
7625f539f3SEmilio G. Cota };
7725f539f3SEmilio G. Cota 
7825f539f3SEmilio G. Cota enum tester {
7925f539f3SEmilio G. Cota     TESTER_SOFT,
8025f539f3SEmilio G. Cota     TESTER_HOST,
8125f539f3SEmilio G. Cota     TESTER_MAX_NR,
8225f539f3SEmilio G. Cota };
8325f539f3SEmilio G. Cota 
8425f539f3SEmilio G. Cota static const char * const tester_names[] = {
8525f539f3SEmilio G. Cota     [TESTER_SOFT] = "soft",
8625f539f3SEmilio G. Cota     [TESTER_HOST] = "host",
8725f539f3SEmilio G. Cota     [TESTER_MAX_NR] = NULL,
8825f539f3SEmilio G. Cota };
8925f539f3SEmilio G. Cota 
9025f539f3SEmilio G. Cota union fp {
9125f539f3SEmilio G. Cota     float f;
9225f539f3SEmilio G. Cota     double d;
9325f539f3SEmilio G. Cota     float32 f32;
9425f539f3SEmilio G. Cota     float64 f64;
95f2b84b9eSAlex Bennée     float128 f128;
9625f539f3SEmilio G. Cota     uint64_t u64;
9725f539f3SEmilio G. Cota };
9825f539f3SEmilio G. Cota 
9925f539f3SEmilio G. Cota struct op_state;
10025f539f3SEmilio G. Cota 
10125f539f3SEmilio G. Cota typedef float (*float_func_t)(const struct op_state *s);
10225f539f3SEmilio G. Cota typedef double (*double_func_t)(const struct op_state *s);
10325f539f3SEmilio G. Cota 
10425f539f3SEmilio G. Cota union fp_func {
10525f539f3SEmilio G. Cota     float_func_t float_func;
10625f539f3SEmilio G. Cota     double_func_t double_func;
10725f539f3SEmilio G. Cota };
10825f539f3SEmilio G. Cota 
10925f539f3SEmilio G. Cota typedef void (*bench_func_t)(void);
11025f539f3SEmilio G. Cota 
11125f539f3SEmilio G. Cota struct op_desc {
11225f539f3SEmilio G. Cota     const char * const name;
11325f539f3SEmilio G. Cota };
11425f539f3SEmilio G. Cota 
11525f539f3SEmilio G. Cota #define DEFAULT_DURATION_SECS 1
11625f539f3SEmilio G. Cota 
11725f539f3SEmilio G. Cota static uint64_t random_ops[MAX_OPERANDS] = {
11825f539f3SEmilio G. Cota     SEED_A, SEED_B, SEED_C,
11925f539f3SEmilio G. Cota };
120f2b84b9eSAlex Bennée 
121f2b84b9eSAlex Bennée static float128 random_quad_ops[MAX_OPERANDS] = {
122f2b84b9eSAlex Bennée     {SEED_A, SEED_B}, {SEED_B, SEED_C}, {SEED_C, SEED_A},
123f2b84b9eSAlex Bennée };
12425f539f3SEmilio G. Cota static float_status soft_status;
12525f539f3SEmilio G. Cota static enum precision precision;
12625f539f3SEmilio G. Cota static enum op operation;
12725f539f3SEmilio G. Cota static enum tester tester;
12825f539f3SEmilio G. Cota static uint64_t n_completed_ops;
12925f539f3SEmilio G. Cota static unsigned int duration = DEFAULT_DURATION_SECS;
13025f539f3SEmilio G. Cota static int64_t ns_elapsed;
13125f539f3SEmilio G. Cota /* disable optimizations with volatile */
13225f539f3SEmilio G. Cota static volatile union fp res;
13325f539f3SEmilio G. Cota 
13425f539f3SEmilio G. Cota /*
13525f539f3SEmilio G. Cota  * From: https://en.wikipedia.org/wiki/Xorshift
13625f539f3SEmilio G. Cota  * This is faster than rand_r(), and gives us a wider range (RAND_MAX is only
13725f539f3SEmilio G. Cota  * guaranteed to be >= INT_MAX).
13825f539f3SEmilio G. Cota  */
xorshift64star(uint64_t x)13925f539f3SEmilio G. Cota static uint64_t xorshift64star(uint64_t x)
14025f539f3SEmilio G. Cota {
14125f539f3SEmilio G. Cota     x ^= x >> 12; /* a */
14225f539f3SEmilio G. Cota     x ^= x << 25; /* b */
14325f539f3SEmilio G. Cota     x ^= x >> 27; /* c */
14425f539f3SEmilio G. Cota     return x * UINT64_C(2685821657736338717);
14525f539f3SEmilio G. Cota }
14625f539f3SEmilio G. Cota 
update_random_ops(int n_ops,enum precision prec)14725f539f3SEmilio G. Cota static void update_random_ops(int n_ops, enum precision prec)
14825f539f3SEmilio G. Cota {
14925f539f3SEmilio G. Cota     int i;
15025f539f3SEmilio G. Cota 
15125f539f3SEmilio G. Cota     for (i = 0; i < n_ops; i++) {
15225f539f3SEmilio G. Cota 
153446cfb0dSEmilio G. Cota         switch (prec) {
154446cfb0dSEmilio G. Cota         case PREC_SINGLE:
155446cfb0dSEmilio G. Cota         case PREC_FLOAT32:
156f2b84b9eSAlex Bennée         {
157f2b84b9eSAlex Bennée             uint64_t r = random_ops[i];
15825f539f3SEmilio G. Cota             do {
15925f539f3SEmilio G. Cota                 r = xorshift64star(r);
16025f539f3SEmilio G. Cota             } while (!float32_is_normal(r));
161f2b84b9eSAlex Bennée             random_ops[i] = r;
162446cfb0dSEmilio G. Cota             break;
163f2b84b9eSAlex Bennée         }
164446cfb0dSEmilio G. Cota         case PREC_DOUBLE:
165446cfb0dSEmilio G. Cota         case PREC_FLOAT64:
166f2b84b9eSAlex Bennée         {
167f2b84b9eSAlex Bennée             uint64_t r = random_ops[i];
16825f539f3SEmilio G. Cota             do {
16925f539f3SEmilio G. Cota                 r = xorshift64star(r);
17025f539f3SEmilio G. Cota             } while (!float64_is_normal(r));
171f2b84b9eSAlex Bennée             random_ops[i] = r;
172446cfb0dSEmilio G. Cota             break;
173f2b84b9eSAlex Bennée         }
174f2b84b9eSAlex Bennée         case PREC_QUAD:
175f2b84b9eSAlex Bennée         case PREC_FLOAT128:
176f2b84b9eSAlex Bennée         {
177f2b84b9eSAlex Bennée             float128 r = random_quad_ops[i];
178f2b84b9eSAlex Bennée             uint64_t hi = r.high;
179f2b84b9eSAlex Bennée             uint64_t lo = r.low;
180f2b84b9eSAlex Bennée             do {
181f2b84b9eSAlex Bennée                 hi = xorshift64star(hi);
182f2b84b9eSAlex Bennée                 lo = xorshift64star(lo);
183f2b84b9eSAlex Bennée                 r = make_float128(hi, lo);
184f2b84b9eSAlex Bennée             } while (!float128_is_normal(r));
185f2b84b9eSAlex Bennée             random_quad_ops[i] = r;
186f2b84b9eSAlex Bennée             break;
187f2b84b9eSAlex Bennée         }
188446cfb0dSEmilio G. Cota         default:
18925f539f3SEmilio G. Cota             g_assert_not_reached();
19025f539f3SEmilio G. Cota         }
19125f539f3SEmilio G. Cota     }
19225f539f3SEmilio G. Cota }
19325f539f3SEmilio G. Cota 
fill_random(union fp * ops,int n_ops,enum precision prec,bool no_neg)19425f539f3SEmilio G. Cota static void fill_random(union fp *ops, int n_ops, enum precision prec,
19525f539f3SEmilio G. Cota                         bool no_neg)
19625f539f3SEmilio G. Cota {
19725f539f3SEmilio G. Cota     int i;
19825f539f3SEmilio G. Cota 
19925f539f3SEmilio G. Cota     for (i = 0; i < n_ops; i++) {
20025f539f3SEmilio G. Cota         switch (prec) {
20125f539f3SEmilio G. Cota         case PREC_SINGLE:
20225f539f3SEmilio G. Cota         case PREC_FLOAT32:
20325f539f3SEmilio G. Cota             ops[i].f32 = make_float32(random_ops[i]);
20425f539f3SEmilio G. Cota             if (no_neg && float32_is_neg(ops[i].f32)) {
20525f539f3SEmilio G. Cota                 ops[i].f32 = float32_chs(ops[i].f32);
20625f539f3SEmilio G. Cota             }
20725f539f3SEmilio G. Cota             break;
20825f539f3SEmilio G. Cota         case PREC_DOUBLE:
20925f539f3SEmilio G. Cota         case PREC_FLOAT64:
21025f539f3SEmilio G. Cota             ops[i].f64 = make_float64(random_ops[i]);
21125f539f3SEmilio G. Cota             if (no_neg && float64_is_neg(ops[i].f64)) {
21225f539f3SEmilio G. Cota                 ops[i].f64 = float64_chs(ops[i].f64);
21325f539f3SEmilio G. Cota             }
21425f539f3SEmilio G. Cota             break;
215f2b84b9eSAlex Bennée         case PREC_QUAD:
216f2b84b9eSAlex Bennée         case PREC_FLOAT128:
217f2b84b9eSAlex Bennée             ops[i].f128 = random_quad_ops[i];
218f2b84b9eSAlex Bennée             if (no_neg && float128_is_neg(ops[i].f128)) {
219f2b84b9eSAlex Bennée                 ops[i].f128 = float128_chs(ops[i].f128);
220f2b84b9eSAlex Bennée             }
221f2b84b9eSAlex Bennée             break;
22225f539f3SEmilio G. Cota         default:
22325f539f3SEmilio G. Cota             g_assert_not_reached();
22425f539f3SEmilio G. Cota         }
22525f539f3SEmilio G. Cota     }
22625f539f3SEmilio G. Cota }
22725f539f3SEmilio G. Cota 
22825f539f3SEmilio G. Cota /*
22925f539f3SEmilio G. Cota  * The main benchmark function. Instead of (ab)using macros, we rely
23025f539f3SEmilio G. Cota  * on the compiler to unfold this at compile-time.
23125f539f3SEmilio G. Cota  */
bench(enum precision prec,enum op op,int n_ops,bool no_neg)23225f539f3SEmilio G. Cota static void bench(enum precision prec, enum op op, int n_ops, bool no_neg)
23325f539f3SEmilio G. Cota {
23425f539f3SEmilio G. Cota     int64_t tf = get_clock() + duration * 1000000000LL;
23525f539f3SEmilio G. Cota 
23625f539f3SEmilio G. Cota     while (get_clock() < tf) {
23725f539f3SEmilio G. Cota         union fp ops[MAX_OPERANDS];
23825f539f3SEmilio G. Cota         int64_t t0;
23925f539f3SEmilio G. Cota         int i;
24025f539f3SEmilio G. Cota 
24125f539f3SEmilio G. Cota         update_random_ops(n_ops, prec);
24225f539f3SEmilio G. Cota         switch (prec) {
24325f539f3SEmilio G. Cota         case PREC_SINGLE:
24425f539f3SEmilio G. Cota             fill_random(ops, n_ops, prec, no_neg);
24525f539f3SEmilio G. Cota             t0 = get_clock();
24625f539f3SEmilio G. Cota             for (i = 0; i < OPS_PER_ITER; i++) {
24725f539f3SEmilio G. Cota                 float a = ops[0].f;
24825f539f3SEmilio G. Cota                 float b = ops[1].f;
24925f539f3SEmilio G. Cota                 float c = ops[2].f;
25025f539f3SEmilio G. Cota 
25125f539f3SEmilio G. Cota                 switch (op) {
25225f539f3SEmilio G. Cota                 case OP_ADD:
25325f539f3SEmilio G. Cota                     res.f = a + b;
25425f539f3SEmilio G. Cota                     break;
25525f539f3SEmilio G. Cota                 case OP_SUB:
25625f539f3SEmilio G. Cota                     res.f = a - b;
25725f539f3SEmilio G. Cota                     break;
25825f539f3SEmilio G. Cota                 case OP_MUL:
25925f539f3SEmilio G. Cota                     res.f = a * b;
26025f539f3SEmilio G. Cota                     break;
26125f539f3SEmilio G. Cota                 case OP_DIV:
26225f539f3SEmilio G. Cota                     res.f = a / b;
26325f539f3SEmilio G. Cota                     break;
26425f539f3SEmilio G. Cota                 case OP_FMA:
26525f539f3SEmilio G. Cota                     res.f = fmaf(a, b, c);
26625f539f3SEmilio G. Cota                     break;
26725f539f3SEmilio G. Cota                 case OP_SQRT:
26825f539f3SEmilio G. Cota                     res.f = sqrtf(a);
26925f539f3SEmilio G. Cota                     break;
27025f539f3SEmilio G. Cota                 case OP_CMP:
27125f539f3SEmilio G. Cota                     res.u64 = isgreater(a, b);
27225f539f3SEmilio G. Cota                     break;
27325f539f3SEmilio G. Cota                 default:
27425f539f3SEmilio G. Cota                     g_assert_not_reached();
27525f539f3SEmilio G. Cota                 }
27625f539f3SEmilio G. Cota             }
27725f539f3SEmilio G. Cota             break;
27825f539f3SEmilio G. Cota         case PREC_DOUBLE:
27925f539f3SEmilio G. Cota             fill_random(ops, n_ops, prec, no_neg);
28025f539f3SEmilio G. Cota             t0 = get_clock();
28125f539f3SEmilio G. Cota             for (i = 0; i < OPS_PER_ITER; i++) {
28225f539f3SEmilio G. Cota                 double a = ops[0].d;
28325f539f3SEmilio G. Cota                 double b = ops[1].d;
28425f539f3SEmilio G. Cota                 double c = ops[2].d;
28525f539f3SEmilio G. Cota 
28625f539f3SEmilio G. Cota                 switch (op) {
28725f539f3SEmilio G. Cota                 case OP_ADD:
28825f539f3SEmilio G. Cota                     res.d = a + b;
28925f539f3SEmilio G. Cota                     break;
29025f539f3SEmilio G. Cota                 case OP_SUB:
29125f539f3SEmilio G. Cota                     res.d = a - b;
29225f539f3SEmilio G. Cota                     break;
29325f539f3SEmilio G. Cota                 case OP_MUL:
29425f539f3SEmilio G. Cota                     res.d = a * b;
29525f539f3SEmilio G. Cota                     break;
29625f539f3SEmilio G. Cota                 case OP_DIV:
29725f539f3SEmilio G. Cota                     res.d = a / b;
29825f539f3SEmilio G. Cota                     break;
29925f539f3SEmilio G. Cota                 case OP_FMA:
30025f539f3SEmilio G. Cota                     res.d = fma(a, b, c);
30125f539f3SEmilio G. Cota                     break;
30225f539f3SEmilio G. Cota                 case OP_SQRT:
30325f539f3SEmilio G. Cota                     res.d = sqrt(a);
30425f539f3SEmilio G. Cota                     break;
30525f539f3SEmilio G. Cota                 case OP_CMP:
30625f539f3SEmilio G. Cota                     res.u64 = isgreater(a, b);
30725f539f3SEmilio G. Cota                     break;
30825f539f3SEmilio G. Cota                 default:
30925f539f3SEmilio G. Cota                     g_assert_not_reached();
31025f539f3SEmilio G. Cota                 }
31125f539f3SEmilio G. Cota             }
31225f539f3SEmilio G. Cota             break;
31325f539f3SEmilio G. Cota         case PREC_FLOAT32:
31425f539f3SEmilio G. Cota             fill_random(ops, n_ops, prec, no_neg);
31525f539f3SEmilio G. Cota             t0 = get_clock();
31625f539f3SEmilio G. Cota             for (i = 0; i < OPS_PER_ITER; i++) {
31725f539f3SEmilio G. Cota                 float32 a = ops[0].f32;
31825f539f3SEmilio G. Cota                 float32 b = ops[1].f32;
31925f539f3SEmilio G. Cota                 float32 c = ops[2].f32;
32025f539f3SEmilio G. Cota 
32125f539f3SEmilio G. Cota                 switch (op) {
32225f539f3SEmilio G. Cota                 case OP_ADD:
32325f539f3SEmilio G. Cota                     res.f32 = float32_add(a, b, &soft_status);
32425f539f3SEmilio G. Cota                     break;
32525f539f3SEmilio G. Cota                 case OP_SUB:
32625f539f3SEmilio G. Cota                     res.f32 = float32_sub(a, b, &soft_status);
32725f539f3SEmilio G. Cota                     break;
32825f539f3SEmilio G. Cota                 case OP_MUL:
32925f539f3SEmilio G. Cota                     res.f = float32_mul(a, b, &soft_status);
33025f539f3SEmilio G. Cota                     break;
33125f539f3SEmilio G. Cota                 case OP_DIV:
33225f539f3SEmilio G. Cota                     res.f32 = float32_div(a, b, &soft_status);
33325f539f3SEmilio G. Cota                     break;
33425f539f3SEmilio G. Cota                 case OP_FMA:
33525f539f3SEmilio G. Cota                     res.f32 = float32_muladd(a, b, c, 0, &soft_status);
33625f539f3SEmilio G. Cota                     break;
33725f539f3SEmilio G. Cota                 case OP_SQRT:
33825f539f3SEmilio G. Cota                     res.f32 = float32_sqrt(a, &soft_status);
33925f539f3SEmilio G. Cota                     break;
34025f539f3SEmilio G. Cota                 case OP_CMP:
34125f539f3SEmilio G. Cota                     res.u64 = float32_compare_quiet(a, b, &soft_status);
34225f539f3SEmilio G. Cota                     break;
34325f539f3SEmilio G. Cota                 default:
34425f539f3SEmilio G. Cota                     g_assert_not_reached();
34525f539f3SEmilio G. Cota                 }
34625f539f3SEmilio G. Cota             }
34725f539f3SEmilio G. Cota             break;
34825f539f3SEmilio G. Cota         case PREC_FLOAT64:
34925f539f3SEmilio G. Cota             fill_random(ops, n_ops, prec, no_neg);
35025f539f3SEmilio G. Cota             t0 = get_clock();
35125f539f3SEmilio G. Cota             for (i = 0; i < OPS_PER_ITER; i++) {
35225f539f3SEmilio G. Cota                 float64 a = ops[0].f64;
35325f539f3SEmilio G. Cota                 float64 b = ops[1].f64;
35425f539f3SEmilio G. Cota                 float64 c = ops[2].f64;
35525f539f3SEmilio G. Cota 
35625f539f3SEmilio G. Cota                 switch (op) {
35725f539f3SEmilio G. Cota                 case OP_ADD:
35825f539f3SEmilio G. Cota                     res.f64 = float64_add(a, b, &soft_status);
35925f539f3SEmilio G. Cota                     break;
36025f539f3SEmilio G. Cota                 case OP_SUB:
36125f539f3SEmilio G. Cota                     res.f64 = float64_sub(a, b, &soft_status);
36225f539f3SEmilio G. Cota                     break;
36325f539f3SEmilio G. Cota                 case OP_MUL:
36425f539f3SEmilio G. Cota                     res.f = float64_mul(a, b, &soft_status);
36525f539f3SEmilio G. Cota                     break;
36625f539f3SEmilio G. Cota                 case OP_DIV:
36725f539f3SEmilio G. Cota                     res.f64 = float64_div(a, b, &soft_status);
36825f539f3SEmilio G. Cota                     break;
36925f539f3SEmilio G. Cota                 case OP_FMA:
37025f539f3SEmilio G. Cota                     res.f64 = float64_muladd(a, b, c, 0, &soft_status);
37125f539f3SEmilio G. Cota                     break;
37225f539f3SEmilio G. Cota                 case OP_SQRT:
37325f539f3SEmilio G. Cota                     res.f64 = float64_sqrt(a, &soft_status);
37425f539f3SEmilio G. Cota                     break;
37525f539f3SEmilio G. Cota                 case OP_CMP:
37625f539f3SEmilio G. Cota                     res.u64 = float64_compare_quiet(a, b, &soft_status);
37725f539f3SEmilio G. Cota                     break;
37825f539f3SEmilio G. Cota                 default:
37925f539f3SEmilio G. Cota                     g_assert_not_reached();
38025f539f3SEmilio G. Cota                 }
38125f539f3SEmilio G. Cota             }
38225f539f3SEmilio G. Cota             break;
383f2b84b9eSAlex Bennée         case PREC_FLOAT128:
384f2b84b9eSAlex Bennée             fill_random(ops, n_ops, prec, no_neg);
385f2b84b9eSAlex Bennée             t0 = get_clock();
386f2b84b9eSAlex Bennée             for (i = 0; i < OPS_PER_ITER; i++) {
387f2b84b9eSAlex Bennée                 float128 a = ops[0].f128;
388f2b84b9eSAlex Bennée                 float128 b = ops[1].f128;
389dedd123cSRichard Henderson                 float128 c = ops[2].f128;
390f2b84b9eSAlex Bennée 
391f2b84b9eSAlex Bennée                 switch (op) {
392f2b84b9eSAlex Bennée                 case OP_ADD:
393f2b84b9eSAlex Bennée                     res.f128 = float128_add(a, b, &soft_status);
394f2b84b9eSAlex Bennée                     break;
395f2b84b9eSAlex Bennée                 case OP_SUB:
396f2b84b9eSAlex Bennée                     res.f128 = float128_sub(a, b, &soft_status);
397f2b84b9eSAlex Bennée                     break;
398f2b84b9eSAlex Bennée                 case OP_MUL:
399f2b84b9eSAlex Bennée                     res.f128 = float128_mul(a, b, &soft_status);
400f2b84b9eSAlex Bennée                     break;
401f2b84b9eSAlex Bennée                 case OP_DIV:
402f2b84b9eSAlex Bennée                     res.f128 = float128_div(a, b, &soft_status);
403f2b84b9eSAlex Bennée                     break;
404dedd123cSRichard Henderson                 case OP_FMA:
405dedd123cSRichard Henderson                     res.f128 = float128_muladd(a, b, c, 0, &soft_status);
406dedd123cSRichard Henderson                     break;
407f2b84b9eSAlex Bennée                 case OP_SQRT:
408f2b84b9eSAlex Bennée                     res.f128 = float128_sqrt(a, &soft_status);
409f2b84b9eSAlex Bennée                     break;
410f2b84b9eSAlex Bennée                 case OP_CMP:
411f2b84b9eSAlex Bennée                     res.u64 = float128_compare_quiet(a, b, &soft_status);
412f2b84b9eSAlex Bennée                     break;
413f2b84b9eSAlex Bennée                 default:
414f2b84b9eSAlex Bennée                     g_assert_not_reached();
415f2b84b9eSAlex Bennée                 }
416f2b84b9eSAlex Bennée             }
417f2b84b9eSAlex Bennée             break;
41825f539f3SEmilio G. Cota         default:
41925f539f3SEmilio G. Cota             g_assert_not_reached();
42025f539f3SEmilio G. Cota         }
42125f539f3SEmilio G. Cota         ns_elapsed += get_clock() - t0;
42225f539f3SEmilio G. Cota         n_completed_ops += OPS_PER_ITER;
42325f539f3SEmilio G. Cota     }
42425f539f3SEmilio G. Cota }
42525f539f3SEmilio G. Cota 
42625f539f3SEmilio G. Cota #define GEN_BENCH(name, type, prec, op, n_ops)          \
42725f539f3SEmilio G. Cota     static void __attribute__((flatten)) name(void)     \
42825f539f3SEmilio G. Cota     {                                                   \
42925f539f3SEmilio G. Cota         bench(prec, op, n_ops, false);                  \
43025f539f3SEmilio G. Cota     }
43125f539f3SEmilio G. Cota 
43225f539f3SEmilio G. Cota #define GEN_BENCH_NO_NEG(name, type, prec, op, n_ops)   \
43325f539f3SEmilio G. Cota     static void __attribute__((flatten)) name(void)     \
43425f539f3SEmilio G. Cota     {                                                   \
43525f539f3SEmilio G. Cota         bench(prec, op, n_ops, true);                   \
43625f539f3SEmilio G. Cota     }
43725f539f3SEmilio G. Cota 
43825f539f3SEmilio G. Cota #define GEN_BENCH_ALL_TYPES(opname, op, n_ops)                          \
43925f539f3SEmilio G. Cota     GEN_BENCH(bench_ ## opname ## _float, float, PREC_SINGLE, op, n_ops) \
44025f539f3SEmilio G. Cota     GEN_BENCH(bench_ ## opname ## _double, double, PREC_DOUBLE, op, n_ops) \
44125f539f3SEmilio G. Cota     GEN_BENCH(bench_ ## opname ## _float32, float32, PREC_FLOAT32, op, n_ops) \
442f2b84b9eSAlex Bennée     GEN_BENCH(bench_ ## opname ## _float64, float64, PREC_FLOAT64, op, n_ops) \
443f2b84b9eSAlex Bennée     GEN_BENCH(bench_ ## opname ## _float128, float128, PREC_FLOAT128, op, n_ops)
44425f539f3SEmilio G. Cota 
44525f539f3SEmilio G. Cota GEN_BENCH_ALL_TYPES(add, OP_ADD, 2)
44625f539f3SEmilio G. Cota GEN_BENCH_ALL_TYPES(sub, OP_SUB, 2)
44725f539f3SEmilio G. Cota GEN_BENCH_ALL_TYPES(mul, OP_MUL, 2)
44825f539f3SEmilio G. Cota GEN_BENCH_ALL_TYPES(div, OP_DIV, 2)
44925f539f3SEmilio G. Cota GEN_BENCH_ALL_TYPES(fma, OP_FMA, 3)
45025f539f3SEmilio G. Cota GEN_BENCH_ALL_TYPES(cmp, OP_CMP, 2)
45125f539f3SEmilio G. Cota #undef GEN_BENCH_ALL_TYPES
45225f539f3SEmilio G. Cota 
45325f539f3SEmilio G. Cota #define GEN_BENCH_ALL_TYPES_NO_NEG(name, op, n)                         \
45425f539f3SEmilio G. Cota     GEN_BENCH_NO_NEG(bench_ ## name ## _float, float, PREC_SINGLE, op, n) \
45525f539f3SEmilio G. Cota     GEN_BENCH_NO_NEG(bench_ ## name ## _double, double, PREC_DOUBLE, op, n) \
45625f539f3SEmilio G. Cota     GEN_BENCH_NO_NEG(bench_ ## name ## _float32, float32, PREC_FLOAT32, op, n) \
457f2b84b9eSAlex Bennée     GEN_BENCH_NO_NEG(bench_ ## name ## _float64, float64, PREC_FLOAT64, op, n) \
458f2b84b9eSAlex Bennée     GEN_BENCH_NO_NEG(bench_ ## name ## _float128, float128, PREC_FLOAT128, op, n)
45925f539f3SEmilio G. Cota 
46025f539f3SEmilio G. Cota GEN_BENCH_ALL_TYPES_NO_NEG(sqrt, OP_SQRT, 1)
46125f539f3SEmilio G. Cota #undef GEN_BENCH_ALL_TYPES_NO_NEG
46225f539f3SEmilio G. Cota 
46325f539f3SEmilio G. Cota #undef GEN_BENCH_NO_NEG
46425f539f3SEmilio G. Cota #undef GEN_BENCH
46525f539f3SEmilio G. Cota 
46625f539f3SEmilio G. Cota #define GEN_BENCH_FUNCS(opname, op)                             \
46725f539f3SEmilio G. Cota     [op] = {                                                    \
46825f539f3SEmilio G. Cota         [PREC_SINGLE]    = bench_ ## opname ## _float,          \
46925f539f3SEmilio G. Cota         [PREC_DOUBLE]    = bench_ ## opname ## _double,         \
47025f539f3SEmilio G. Cota         [PREC_FLOAT32]   = bench_ ## opname ## _float32,        \
47125f539f3SEmilio G. Cota         [PREC_FLOAT64]   = bench_ ## opname ## _float64,        \
472f2b84b9eSAlex Bennée         [PREC_FLOAT128]   = bench_ ## opname ## _float128,      \
47325f539f3SEmilio G. Cota     }
47425f539f3SEmilio G. Cota 
47525f539f3SEmilio G. Cota static const bench_func_t bench_funcs[OP_MAX_NR][PREC_MAX_NR] = {
47625f539f3SEmilio G. Cota     GEN_BENCH_FUNCS(add, OP_ADD),
47725f539f3SEmilio G. Cota     GEN_BENCH_FUNCS(sub, OP_SUB),
47825f539f3SEmilio G. Cota     GEN_BENCH_FUNCS(mul, OP_MUL),
47925f539f3SEmilio G. Cota     GEN_BENCH_FUNCS(div, OP_DIV),
48025f539f3SEmilio G. Cota     GEN_BENCH_FUNCS(fma, OP_FMA),
48125f539f3SEmilio G. Cota     GEN_BENCH_FUNCS(sqrt, OP_SQRT),
48225f539f3SEmilio G. Cota     GEN_BENCH_FUNCS(cmp, OP_CMP),
48325f539f3SEmilio G. Cota };
48425f539f3SEmilio G. Cota 
48525f539f3SEmilio G. Cota #undef GEN_BENCH_FUNCS
48625f539f3SEmilio G. Cota 
run_bench(void)48725f539f3SEmilio G. Cota static void run_bench(void)
48825f539f3SEmilio G. Cota {
48925f539f3SEmilio G. Cota     bench_func_t f;
49025f539f3SEmilio G. Cota 
49127aedf7dSPeter Maydell     /*
49227aedf7dSPeter Maydell      * These implementation-defined choices for various things IEEE
49327aedf7dSPeter Maydell      * doesn't specify match those used by the Arm architecture.
49427aedf7dSPeter Maydell      */
495d22c9949SPeter Maydell     set_float_2nan_prop_rule(float_2nan_prop_s_ab, &soft_status);
49643e51128SPeter Maydell     set_float_3nan_prop_rule(float_3nan_prop_s_cab, &soft_status);
49727aedf7dSPeter Maydell     set_float_infzeronan_rule(float_infzeronan_dnan_if_qnan, &soft_status);
498a264fd5aSPeter Maydell     set_float_default_nan_pattern(0b01000000, &soft_status);
499*28f13bccSPeter Maydell     set_float_ftz_detection(float_ftz_before_rounding, &soft_status);
500d22c9949SPeter Maydell 
50125f539f3SEmilio G. Cota     f = bench_funcs[operation][precision];
50225f539f3SEmilio G. Cota     g_assert(f);
50325f539f3SEmilio G. Cota     f();
50425f539f3SEmilio G. Cota }
50525f539f3SEmilio G. Cota 
50625f539f3SEmilio G. Cota /* @arr must be NULL-terminated */
find_name(const char * const * arr,const char * name)50725f539f3SEmilio G. Cota static int find_name(const char * const *arr, const char *name)
50825f539f3SEmilio G. Cota {
50925f539f3SEmilio G. Cota     int i;
51025f539f3SEmilio G. Cota 
51125f539f3SEmilio G. Cota     for (i = 0; arr[i] != NULL; i++) {
51225f539f3SEmilio G. Cota         if (strcmp(name, arr[i]) == 0) {
51325f539f3SEmilio G. Cota             return i;
51425f539f3SEmilio G. Cota         }
51525f539f3SEmilio G. Cota     }
51625f539f3SEmilio G. Cota     return -1;
51725f539f3SEmilio G. Cota }
51825f539f3SEmilio G. Cota 
usage_complete(int argc,char * argv[])51925f539f3SEmilio G. Cota static void usage_complete(int argc, char *argv[])
52025f539f3SEmilio G. Cota {
52125f539f3SEmilio G. Cota     gchar *op_list = g_strjoinv(", ", (gchar **)op_names);
52225f539f3SEmilio G. Cota     gchar *tester_list = g_strjoinv(", ", (gchar **)tester_names);
52325f539f3SEmilio G. Cota 
52425f539f3SEmilio G. Cota     fprintf(stderr, "Usage: %s [options]\n", argv[0]);
52525f539f3SEmilio G. Cota     fprintf(stderr, "options:\n");
52625f539f3SEmilio G. Cota     fprintf(stderr, " -d = duration, in seconds. Default: %d\n",
52725f539f3SEmilio G. Cota             DEFAULT_DURATION_SECS);
52825f539f3SEmilio G. Cota     fprintf(stderr, " -h = show this help message.\n");
52925f539f3SEmilio G. Cota     fprintf(stderr, " -o = floating point operation (%s). Default: %s\n",
53025f539f3SEmilio G. Cota             op_list, op_names[0]);
531f2b84b9eSAlex Bennée     fprintf(stderr, " -p = floating point precision (single, double, quad[soft only]). "
53225f539f3SEmilio G. Cota             "Default: single\n");
53325f539f3SEmilio G. Cota     fprintf(stderr, " -r = rounding mode (even, zero, down, up, tieaway). "
53425f539f3SEmilio G. Cota             "Default: even\n");
53525f539f3SEmilio G. Cota     fprintf(stderr, " -t = tester (%s). Default: %s\n",
53625f539f3SEmilio G. Cota             tester_list, tester_names[0]);
53725f539f3SEmilio G. Cota     fprintf(stderr, " -z = flush inputs to zero (soft tester only). "
53825f539f3SEmilio G. Cota             "Default: disabled\n");
53925f539f3SEmilio G. Cota     fprintf(stderr, " -Z = flush output to zero (soft tester only). "
54025f539f3SEmilio G. Cota             "Default: disabled\n");
54125f539f3SEmilio G. Cota 
54225f539f3SEmilio G. Cota     g_free(tester_list);
54325f539f3SEmilio G. Cota     g_free(op_list);
54425f539f3SEmilio G. Cota }
54525f539f3SEmilio G. Cota 
round_name_to_mode(const char * name)54625f539f3SEmilio G. Cota static int round_name_to_mode(const char *name)
54725f539f3SEmilio G. Cota {
54825f539f3SEmilio G. Cota     int i;
54925f539f3SEmilio G. Cota 
55025f539f3SEmilio G. Cota     for (i = 0; i < N_ROUND_MODES; i++) {
55125f539f3SEmilio G. Cota         if (!strcmp(round_names[i], name)) {
55225f539f3SEmilio G. Cota             return i;
55325f539f3SEmilio G. Cota         }
55425f539f3SEmilio G. Cota     }
55525f539f3SEmilio G. Cota     return -1;
55625f539f3SEmilio G. Cota }
55725f539f3SEmilio G. Cota 
5588905770bSMarc-André Lureau static G_NORETURN
die_host_rounding(enum rounding rounding)5598905770bSMarc-André Lureau void die_host_rounding(enum rounding rounding)
56025f539f3SEmilio G. Cota {
56125f539f3SEmilio G. Cota     fprintf(stderr, "fatal: '%s' rounding not supported on this host\n",
56225f539f3SEmilio G. Cota             round_names[rounding]);
56325f539f3SEmilio G. Cota     exit(EXIT_FAILURE);
56425f539f3SEmilio G. Cota }
56525f539f3SEmilio G. Cota 
set_host_precision(enum rounding rounding)56625f539f3SEmilio G. Cota static void set_host_precision(enum rounding rounding)
56725f539f3SEmilio G. Cota {
56825f539f3SEmilio G. Cota     int rhost;
56925f539f3SEmilio G. Cota 
57025f539f3SEmilio G. Cota     switch (rounding) {
57125f539f3SEmilio G. Cota     case ROUND_EVEN:
57225f539f3SEmilio G. Cota         rhost = FE_TONEAREST;
57325f539f3SEmilio G. Cota         break;
57425f539f3SEmilio G. Cota     case ROUND_ZERO:
57525f539f3SEmilio G. Cota         rhost = FE_TOWARDZERO;
57625f539f3SEmilio G. Cota         break;
57725f539f3SEmilio G. Cota     case ROUND_DOWN:
57825f539f3SEmilio G. Cota         rhost = FE_DOWNWARD;
57925f539f3SEmilio G. Cota         break;
58025f539f3SEmilio G. Cota     case ROUND_UP:
58125f539f3SEmilio G. Cota         rhost = FE_UPWARD;
58225f539f3SEmilio G. Cota         break;
58325f539f3SEmilio G. Cota     case ROUND_TIEAWAY:
58425f539f3SEmilio G. Cota         die_host_rounding(rounding);
58525f539f3SEmilio G. Cota         return;
58625f539f3SEmilio G. Cota     default:
58725f539f3SEmilio G. Cota         g_assert_not_reached();
58825f539f3SEmilio G. Cota     }
58925f539f3SEmilio G. Cota 
59025f539f3SEmilio G. Cota     if (fesetround(rhost)) {
59125f539f3SEmilio G. Cota         die_host_rounding(rounding);
59225f539f3SEmilio G. Cota     }
59325f539f3SEmilio G. Cota }
59425f539f3SEmilio G. Cota 
set_soft_precision(enum rounding rounding)59525f539f3SEmilio G. Cota static void set_soft_precision(enum rounding rounding)
59625f539f3SEmilio G. Cota {
59725f539f3SEmilio G. Cota     signed char mode;
59825f539f3SEmilio G. Cota 
59925f539f3SEmilio G. Cota     switch (rounding) {
60025f539f3SEmilio G. Cota     case ROUND_EVEN:
60125f539f3SEmilio G. Cota         mode = float_round_nearest_even;
60225f539f3SEmilio G. Cota         break;
60325f539f3SEmilio G. Cota     case ROUND_ZERO:
60425f539f3SEmilio G. Cota         mode = float_round_to_zero;
60525f539f3SEmilio G. Cota         break;
60625f539f3SEmilio G. Cota     case ROUND_DOWN:
60725f539f3SEmilio G. Cota         mode = float_round_down;
60825f539f3SEmilio G. Cota         break;
60925f539f3SEmilio G. Cota     case ROUND_UP:
61025f539f3SEmilio G. Cota         mode = float_round_up;
61125f539f3SEmilio G. Cota         break;
61225f539f3SEmilio G. Cota     case ROUND_TIEAWAY:
61325f539f3SEmilio G. Cota         mode = float_round_ties_away;
61425f539f3SEmilio G. Cota         break;
61525f539f3SEmilio G. Cota     default:
61625f539f3SEmilio G. Cota         g_assert_not_reached();
61725f539f3SEmilio G. Cota     }
61825f539f3SEmilio G. Cota     soft_status.float_rounding_mode = mode;
61925f539f3SEmilio G. Cota }
62025f539f3SEmilio G. Cota 
parse_args(int argc,char * argv[])62125f539f3SEmilio G. Cota static void parse_args(int argc, char *argv[])
62225f539f3SEmilio G. Cota {
62325f539f3SEmilio G. Cota     int c;
62425f539f3SEmilio G. Cota     int val;
62525f539f3SEmilio G. Cota     int rounding = ROUND_EVEN;
62625f539f3SEmilio G. Cota 
62725f539f3SEmilio G. Cota     for (;;) {
62825f539f3SEmilio G. Cota         c = getopt(argc, argv, "d:ho:p:r:t:zZ");
62925f539f3SEmilio G. Cota         if (c < 0) {
63025f539f3SEmilio G. Cota             break;
63125f539f3SEmilio G. Cota         }
63225f539f3SEmilio G. Cota         switch (c) {
63325f539f3SEmilio G. Cota         case 'd':
63425f539f3SEmilio G. Cota             duration = atoi(optarg);
63525f539f3SEmilio G. Cota             break;
63625f539f3SEmilio G. Cota         case 'h':
63725f539f3SEmilio G. Cota             usage_complete(argc, argv);
63825f539f3SEmilio G. Cota             exit(EXIT_SUCCESS);
63925f539f3SEmilio G. Cota         case 'o':
64025f539f3SEmilio G. Cota             val = find_name(op_names, optarg);
64125f539f3SEmilio G. Cota             if (val < 0) {
64225f539f3SEmilio G. Cota                 fprintf(stderr, "Unsupported op '%s'\n", optarg);
64325f539f3SEmilio G. Cota                 exit(EXIT_FAILURE);
64425f539f3SEmilio G. Cota             }
64525f539f3SEmilio G. Cota             operation = val;
64625f539f3SEmilio G. Cota             break;
64725f539f3SEmilio G. Cota         case 'p':
64825f539f3SEmilio G. Cota             if (!strcmp(optarg, "single")) {
64925f539f3SEmilio G. Cota                 precision = PREC_SINGLE;
65025f539f3SEmilio G. Cota             } else if (!strcmp(optarg, "double")) {
65125f539f3SEmilio G. Cota                 precision = PREC_DOUBLE;
652f2b84b9eSAlex Bennée             } else if (!strcmp(optarg, "quad")) {
653f2b84b9eSAlex Bennée                 precision = PREC_QUAD;
65425f539f3SEmilio G. Cota             } else {
65525f539f3SEmilio G. Cota                 fprintf(stderr, "Unsupported precision '%s'\n", optarg);
65625f539f3SEmilio G. Cota                 exit(EXIT_FAILURE);
65725f539f3SEmilio G. Cota             }
65825f539f3SEmilio G. Cota             break;
65925f539f3SEmilio G. Cota         case 'r':
66025f539f3SEmilio G. Cota             rounding = round_name_to_mode(optarg);
66125f539f3SEmilio G. Cota             if (rounding < 0) {
66225f539f3SEmilio G. Cota                 fprintf(stderr, "fatal: invalid rounding mode '%s'\n", optarg);
66325f539f3SEmilio G. Cota                 exit(EXIT_FAILURE);
66425f539f3SEmilio G. Cota             }
66525f539f3SEmilio G. Cota             break;
66625f539f3SEmilio G. Cota         case 't':
66725f539f3SEmilio G. Cota             val = find_name(tester_names, optarg);
66825f539f3SEmilio G. Cota             if (val < 0) {
66925f539f3SEmilio G. Cota                 fprintf(stderr, "Unsupported tester '%s'\n", optarg);
67025f539f3SEmilio G. Cota                 exit(EXIT_FAILURE);
67125f539f3SEmilio G. Cota             }
67225f539f3SEmilio G. Cota             tester = val;
67325f539f3SEmilio G. Cota             break;
67425f539f3SEmilio G. Cota         case 'z':
67525f539f3SEmilio G. Cota             soft_status.flush_inputs_to_zero = 1;
67625f539f3SEmilio G. Cota             break;
67725f539f3SEmilio G. Cota         case 'Z':
67825f539f3SEmilio G. Cota             soft_status.flush_to_zero = 1;
67925f539f3SEmilio G. Cota             break;
68025f539f3SEmilio G. Cota         }
68125f539f3SEmilio G. Cota     }
68225f539f3SEmilio G. Cota 
68325f539f3SEmilio G. Cota     /* set precision and rounding mode based on the tester */
68425f539f3SEmilio G. Cota     switch (tester) {
68525f539f3SEmilio G. Cota     case TESTER_HOST:
68625f539f3SEmilio G. Cota         set_host_precision(rounding);
68725f539f3SEmilio G. Cota         break;
68825f539f3SEmilio G. Cota     case TESTER_SOFT:
68925f539f3SEmilio G. Cota         set_soft_precision(rounding);
69025f539f3SEmilio G. Cota         switch (precision) {
69125f539f3SEmilio G. Cota         case PREC_SINGLE:
69225f539f3SEmilio G. Cota             precision = PREC_FLOAT32;
69325f539f3SEmilio G. Cota             break;
69425f539f3SEmilio G. Cota         case PREC_DOUBLE:
69525f539f3SEmilio G. Cota             precision = PREC_FLOAT64;
69625f539f3SEmilio G. Cota             break;
697f2b84b9eSAlex Bennée         case PREC_QUAD:
698f2b84b9eSAlex Bennée             precision = PREC_FLOAT128;
699f2b84b9eSAlex Bennée             break;
70025f539f3SEmilio G. Cota         default:
70125f539f3SEmilio G. Cota             g_assert_not_reached();
70225f539f3SEmilio G. Cota         }
70325f539f3SEmilio G. Cota         break;
70425f539f3SEmilio G. Cota     default:
70525f539f3SEmilio G. Cota         g_assert_not_reached();
70625f539f3SEmilio G. Cota     }
70725f539f3SEmilio G. Cota }
70825f539f3SEmilio G. Cota 
pr_stats(void)70925f539f3SEmilio G. Cota static void pr_stats(void)
71025f539f3SEmilio G. Cota {
71125f539f3SEmilio G. Cota     printf("%.2f MFlops\n", (double)n_completed_ops / ns_elapsed * 1e3);
71225f539f3SEmilio G. Cota }
71325f539f3SEmilio G. Cota 
main(int argc,char * argv[])71425f539f3SEmilio G. Cota int main(int argc, char *argv[])
71525f539f3SEmilio G. Cota {
71625f539f3SEmilio G. Cota     parse_args(argc, argv);
71725f539f3SEmilio G. Cota     run_bench();
71825f539f3SEmilio G. Cota     pr_stats();
71925f539f3SEmilio G. Cota     return 0;
72025f539f3SEmilio G. Cota }
721