#include #include #include typedef int32_t i32; typedef int64_t i64; #define COMM_OP(name, op, typ) \ void oxarop_ ## name ## _ ## typ ## _sv(i64 n, typ *out, typ x, typ *y) { \ for (i64 i = 0; i < n; i++) out[i] = x op y[i]; \ } \ void oxarop_ ## name ## _ ## typ ## _vv(i64 n, typ *out, const typ *x, const typ *y) { \ for (i64 i = 0; i < n; i++) out[i] = x[i] op y[i]; \ } #define NONCOMM_OP(name, op, typ) \ COMM_OP(name, op, typ) \ void oxarop_ ## name ## _ ## typ ## _vs(i64 n, typ *out, typ *x, typ y) { \ for (i64 i = 0; i < n; i++) out[i] = x[i] op y; \ } #define UNARY_OP(name, op, typ) \ void oxarop_ ## name ## _ ## typ(i64 n, typ *out, typ *x) { \ for (i64 i = 0; i < n; i++) out[i] = op(x[i]); \ } #define GEN_ABS(x) \ _Generic((x), \ int: abs, \ long: labs, \ long long: llabs, \ float: fabsf, \ double: fabs)(x) // This does not result in multiple loads with GCC 13. #define GEN_SIGNUM(x) ((x) < 0 ? -1 : (x) > 0 ? 1 : 0) #define NUM_TYPES_LOOP_XLIST \ X(i32) X(i64) X(double) X(float) #define X(typ) \ COMM_OP(add, +, typ) \ NONCOMM_OP(sub, -, typ) \ COMM_OP(mul, *, typ) \ UNARY_OP(neg, -, typ) \ UNARY_OP(abs, GEN_ABS, typ) \ UNARY_OP(signum, GEN_SIGNUM, typ) NUM_TYPES_LOOP_XLIST #undef X