Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add rzil 'fexcept'|'FEXCEPT' #4771

Merged
merged 4 commits into from
Dec 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions librz/il/definitions/float.c
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,28 @@ RZ_API const char *rz_il_float_stringify_rmode(RzFloatRMode mode) {
}
}

/**
* convert RzFloatException into const string for exporting info
* \param e RzFloatException
* \return RzFloatException string
*/
RZ_API const char *rz_il_float_stringify_exception(RzFloatException e) {
switch (e) {
case RZ_FLOAT_E_DIV_ZERO:
return "e_div_zero";
case RZ_FLOAT_E_INEXACT:
return "e_inexact";
case RZ_FLOAT_E_OVERFLOW:
return "e_overflow";
case RZ_FLOAT_E_INVALID_OP:
return "e_invalid_op";
case RZ_FLOAT_E_UNDERFLOW:
return "e_underflow";
default:
return "e_unk";
}
}

/**
* convert format to human readable string
* \param format float format
Expand Down
25 changes: 25 additions & 0 deletions librz/il/il_export_string.c
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,22 @@ static void il_op_effect_string_resolve(RzILOpEffect *op, RzStrBuf *sb, int pad)
} \
} while (0)

#define il_op_param_1_with_fexcept(name, opx, v0, e) \
do { \
const char *str = rz_il_float_stringify_exception(opx.e); \
if (pad < 0) { \
rz_strbuf_append(sb, "(" name " "); \
rz_strbuf_append(sb, str); \
rz_strbuf_append(sb, " "); \
il_op_pure_string_resolve(opx.v0, sb, pad); \
rz_strbuf_append(sb, ")"); \
} else { \
rz_strbuf_appendf(sb, "%*.s(" name " %s\n", pad, "", str); \
il_op_pure_string_resolve(opx.v0, sb, pad + PRETTY_PAD); \
rz_strbuf_append(sb, ")"); \
} \
} while (0)

static void il_opdmp_var(RzILOpPure *op, RzStrBuf *sb, int pad) {
RzILOpArgsVar *opx = &op->op.var;
if (pad < 0) {
Expand Down Expand Up @@ -525,6 +541,10 @@ static void il_opdmp_frsqrt(RzILOpPure *op, RzStrBuf *sb, int pad) {
il_op_param_1_with_rmode("frsqrt", op->op.frsqrt, f, rmode);
}

static void il_opdmp_fexcept(RzILOpPure *op, RzStrBuf *sb, int pad) {
il_op_param_1_with_fexcept("fexcept", op->op.fexcept, x, e);
}

static void il_opdmp_fadd(RzILOpPure *op, RzStrBuf *sb, int pad) {
il_op_param_2_with_rmode("+.", op->op.fadd, pure, x, pure, y, rmode);
}
Expand Down Expand Up @@ -899,6 +919,9 @@ static void il_op_pure_string_resolve(RzILOpPure *op, RzStrBuf *sb, int pad) {
case RZ_IL_OP_FRSQRT:
il_opdmp_frsqrt(op, sb, pad);
return;
case RZ_IL_OP_FEXCEPT:
il_opdmp_fexcept(op, sb, pad);
return;
case RZ_IL_OP_FADD:
il_opdmp_fadd(op, sb, pad);
return;
Expand Down Expand Up @@ -1203,6 +1226,8 @@ RZ_API RZ_NONNULL const char *rz_il_op_pure_code_stringify(RzILOpPureCode code)
return "fsqrt";
case RZ_IL_OP_FRSQRT:
return "frsqrt";
case RZ_IL_OP_FEXCEPT:
return "fexcept";
case RZ_IL_OP_FADD:
return "fadd";
case RZ_IL_OP_FSUB:
Expand Down
14 changes: 14 additions & 0 deletions librz/il/il_opcodes.c
Original file line number Diff line number Diff line change
Expand Up @@ -945,6 +945,13 @@ RZ_API RZ_OWN RzILOpFloat *rz_il_op_new_frsqrt(RzFloatRMode rmode, RZ_NONNULL Rz
return ret;
}

RZ_API RZ_OWN RzILOpBool *rz_il_op_new_fexcept(RzFloatException e, RZ_NONNULL RzILOpFloat *x) {
rz_return_val_if_fail(x, NULL);
RzILOpBool *ret;
rz_il_op_new_2(Bool, RZ_IL_OP_FEXCEPT, RzILOpArgsFexcept, fexcept, e, x);
return ret;
}

RZ_API RZ_OWN RzILOpFloat *rz_il_op_new_fadd(RzFloatRMode rmode, RZ_NONNULL RzILOpFloat *x, RZ_NONNULL RzILOpFloat *y) {
rz_return_val_if_fail(x && y, NULL);
RzILOpFloat *ret;
Expand Down Expand Up @@ -1262,6 +1269,10 @@ RZ_API RzILOpPure *rz_il_op_pure_dup(RZ_NONNULL RzILOpPure *op) {
CONST_CP1(frsqrt, rmode);
DUP_OP1(frsqrt, f);
break;
case RZ_IL_OP_FEXCEPT:
CONST_CP1(fexcept, e);
DUP_OP1(fexcept, x);
break;
case RZ_IL_OP_FADD:
CONST_CP1(fadd, rmode);
DUP_OP2(fadd, x, y);
Expand Down Expand Up @@ -1465,6 +1476,9 @@ RZ_API void rz_il_op_pure_free(RZ_NULLABLE RzILOpPure *op) {
case RZ_IL_OP_FRSQRT:
rz_il_op_free_1(pure, fsqrt, f);
break;
case RZ_IL_OP_FEXCEPT:
rz_il_op_free_1(pure, fexcept, x);
break;
case RZ_IL_OP_FADD:
case RZ_IL_OP_FSUB:
case RZ_IL_OP_FMUL:
Expand Down
12 changes: 12 additions & 0 deletions librz/il/il_validate.c
Original file line number Diff line number Diff line change
Expand Up @@ -631,6 +631,17 @@ VALIDATOR_PURE(float_uop_with_round) {
return true;
}

VALIDATOR_PURE(float_uop_except) {
RzILOpArgsFexcept *args = &op->op.fexcept;
RzILSortPure sort;

VALIDATOR_DESCEND(args->x, &sort);
VALIDATOR_ASSERT(sort.type == RZ_IL_TYPE_PURE_FLOAT, "operand of %s op is not a float.\n", rz_il_op_pure_code_stringify(op->code));

*sort_out = rz_il_sort_pure_bool();
return true;
}

VALIDATOR_PURE(float_binop_with_round) {
RzILOpArgsFadd *args = &op->op.fadd;
RzILSortPure sx, sy;
Expand Down Expand Up @@ -739,6 +750,7 @@ static ValidatePureFn validate_pure_table[RZ_IL_OP_PURE_MAX] = {
[RZ_IL_OP_FROUND] = VALIDATOR_PURE_NAME(float_uop_with_round),
[RZ_IL_OP_FSQRT] = VALIDATOR_PURE_NAME(float_uop_with_round),
[RZ_IL_OP_FRSQRT] = VALIDATOR_PURE_NAME(float_uop_with_round),
[RZ_IL_OP_FEXCEPT] = VALIDATOR_PURE_NAME(float_uop_except),
[RZ_IL_OP_FADD] = VALIDATOR_PURE_NAME(float_binop_with_round),
[RZ_IL_OP_FSUB] = VALIDATOR_PURE_NAME(float_binop_with_round),
[RZ_IL_OP_FMUL] = VALIDATOR_PURE_NAME(float_binop_with_round),
Expand Down
2 changes: 2 additions & 0 deletions librz/il/il_vm_eval.c
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ void *rz_il_handler_forder(RzILVM *vm, RzILOpPure *op, RzILTypePure *type);
void *rz_il_handler_fround(RzILVM *vm, RzILOpPure *op, RzILTypePure *type);
void *rz_il_handler_fsqrt(RzILVM *vm, RzILOpPure *op, RzILTypePure *type);
void *rz_il_handler_frsqrt(RzILVM *vm, RzILOpPure *op, RzILTypePure *type);
void *rz_il_handler_fexcept(RzILVM *vm, RzILOpPure *op, RzILTypePure *type);
void *rz_il_handler_fadd(RzILVM *vm, RzILOpPure *op, RzILTypePure *type);
void *rz_il_handler_fsub(RzILVM *vm, RzILOpPure *op, RzILTypePure *type);
void *rz_il_handler_fdiv(RzILVM *vm, RzILOpPure *op, RzILTypePure *type);
Expand Down Expand Up @@ -152,6 +153,7 @@ RZ_IPI RzILOpPureHandler rz_il_op_handler_pure_table_default[RZ_IL_OP_PURE_MAX]
[RZ_IL_OP_FROUND] = rz_il_handler_fround,
[RZ_IL_OP_FSQRT] = rz_il_handler_fsqrt,
[RZ_IL_OP_FRSQRT] = rz_il_handler_pure_unimplemented,
[RZ_IL_OP_FEXCEPT] = rz_il_handler_fexcept,
[RZ_IL_OP_FADD] = rz_il_handler_fadd,
[RZ_IL_OP_FSUB] = rz_il_handler_fsub,
[RZ_IL_OP_FMUL] = rz_il_handler_fmul,
Expand Down
36 changes: 36 additions & 0 deletions librz/il/theory_fbasic.c
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,42 @@ void *rz_il_handler_fsqrt(RzILVM *vm, RzILOpPure *op, RzILTypePure *type) {
return ret;
}

void *rz_il_handler_fexcept(RzILVM *vm, RzILOpPure *op, RzILTypePure *type) {
rz_return_val_if_fail(vm && op && type, NULL);
RzILOpArgsFexcept args = op->op.fexcept;
RzFloat *n = rz_il_evaluate_float(vm, args.x);
if (!n) {
return NULL;
}

bool e = false;
switch (args.e) {
case RZ_FLOAT_E_DIV_ZERO:
e = n->exception & RZ_FLOAT_E_DIV_ZERO;
rz_il_vm_event_add(vm, rz_il_event_exception_new("float division by zero"));
break;
case RZ_FLOAT_E_OVERFLOW:
e = n->exception & RZ_FLOAT_E_OVERFLOW;
rz_il_vm_event_add(vm, rz_il_event_exception_new("float overflow"));
break;
case RZ_FLOAT_E_UNDERFLOW:
e = n->exception & RZ_FLOAT_E_UNDERFLOW;
rz_il_vm_event_add(vm, rz_il_event_exception_new("float underflow"));
break;
case RZ_FLOAT_E_INEXACT:
e = n->exception & RZ_FLOAT_E_INEXACT;
rz_il_vm_event_add(vm, rz_il_event_exception_new("float inexact"));
break;
default:;
}

RzILBool *ret = rz_il_bool_new(e);
rz_float_free(n);

*type = RZ_IL_TYPE_PURE_BOOL;
return ret;
}

void *rz_il_handler_frsqrt(RzILVM *vm, RzILOpPure *op, RzILTypePure *type) {
// TODO : float todo unimplemented
rz_return_val_if_fail(vm && op && type, NULL);
Expand Down
1 change: 1 addition & 0 deletions librz/include/rz_il/definitions/float.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ RZ_API RZ_OWN RzFloat *rz_il_float_new(RZ_NONNULL RzFloatFormat format, RZ_NONNU

// return const string for il_export
RZ_API const char *rz_il_float_stringify_rmode(RzFloatRMode mode);
RZ_API const char *rz_il_float_stringify_exception(RzFloatException e);
RZ_API const char *rz_il_float_stringify_format(RzFloatFormat format);

#ifdef __cplusplus
Expand Down
1 change: 1 addition & 0 deletions librz/include/rz_il/rz_il_opbuilder_begin.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@
#define FROUND(rmode, fl) rz_il_op_new_fround(rmode, fl)
#define FSQRT(rmode, fl) rz_il_op_new_fsqrt(rmode, fl)
#define FRSQRT(rmode, fl) rz_il_op_new_frsqrt(rmode, fl)
#define FEXCEPT(e, fl) rz_il_op_new_fexcept(e, fl)
#define FADD(rmode, flx, fly) rz_il_op_new_fadd(rmode, flx, fly)
#define FSUB(rmode, flx, fly) rz_il_op_new_fsub(rmode, flx, fly)
#define FMUL(rmode, flx, fly) rz_il_op_new_fmul(rmode, flx, fly)
Expand Down
8 changes: 8 additions & 0 deletions librz/include/rz_il/rz_il_opcodes.h
Original file line number Diff line number Diff line change
Expand Up @@ -467,6 +467,11 @@ typedef struct rz_il_op_args_float_alg_unop_t RzILOpArgsFround;
typedef struct rz_il_op_args_float_alg_unop_t RzILOpArgsFsqrt;
typedef struct rz_il_op_args_float_alg_unop_t RzILOpArgsFrsqrt;

typedef struct rz_il_op_args_float_expect_t {
RzFloatException e;
RzILOpFloat *x;
} RzILOpArgsFexcept;

/**
* \brief op structure for float basic arithmetic operations (binary op with rmode)
* rmode -> 'f float -> 'f float -> 'f float
Expand Down Expand Up @@ -588,6 +593,7 @@ typedef enum {
RZ_IL_OP_FROOTN,
RZ_IL_OP_FPOWN,
RZ_IL_OP_FCOMPOUND,
RZ_IL_OP_FEXCEPT,
// ...

// Memory
Expand Down Expand Up @@ -667,6 +673,7 @@ struct rz_il_op_pure_t {
RzILOpArgsFround fround;
RzILOpArgsFsqrt fsqrt;
RzILOpArgsFrsqrt frsqrt;
RzILOpArgsFexcept fexcept;
RzILOpArgsFadd fadd;
RzILOpArgsFsub fsub;
RzILOpArgsFmul fmul;
Expand Down Expand Up @@ -759,6 +766,7 @@ RZ_API RZ_OWN RzILOpBool *rz_il_op_new_forder(RZ_NONNULL RzILOpFloat *x, RZ_NONN
RZ_API RZ_OWN RzILOpFloat *rz_il_op_new_fround(RzFloatRMode rmode, RZ_NONNULL RzILOpFloat *f);
RZ_API RZ_OWN RzILOpFloat *rz_il_op_new_fsqrt(RzFloatRMode rmode, RZ_NONNULL RzILOpFloat *f);
RZ_API RZ_OWN RzILOpFloat *rz_il_op_new_frsqrt(RzFloatRMode rmode, RZ_NONNULL RzILOpFloat *f);
RZ_API RZ_OWN RzILOpBool *rz_il_op_new_fexcept(RzFloatException e, RZ_NONNULL RzILOpFloat *x);
RZ_API RZ_OWN RzILOpFloat *rz_il_op_new_fadd(RzFloatRMode rmode, RZ_NONNULL RzILOpFloat *x, RZ_NONNULL RzILOpFloat *y);
RZ_API RZ_OWN RzILOpFloat *rz_il_op_new_fsub(RzFloatRMode rmode, RZ_NONNULL RzILOpFloat *x, RZ_NONNULL RzILOpFloat *y);
RZ_API RZ_OWN RzILOpFloat *rz_il_op_new_fmul(RzFloatRMode rmode, RZ_NONNULL RzILOpFloat *x, RZ_NONNULL RzILOpFloat *y);
Expand Down
68 changes: 68 additions & 0 deletions test/unit/test_il_vm.c
Original file line number Diff line number Diff line change
Expand Up @@ -1019,6 +1019,73 @@ static bool test_rzil_vm_op_fcast() {
mu_end;
}

static bool test_rzil_vm_op_fexcept() {
/**
* test for execute fexcept op in rzil vm
* 1. div by zero
* 2. overflow
* 3. underflow
* 4. inexact result
*/

RzILVM *vm = rz_il_vm_new(0, 32, false);
RzFloat *result;
RzILBool *e;
RzILOpFloat *op;
RzILOpBool *eop;

// 1. Test division by zero
op = rz_il_op_new_fdiv(RZ_FLOAT_RMODE_RNE,
rz_il_op_new_float_from_f64(1.0),
rz_il_op_new_float_from_f64(0.0));
result = rz_il_evaluate_float(vm, op);

eop = rz_il_op_new_fexcept(RZ_FLOAT_E_DIV_ZERO, op);
e = rz_il_evaluate_bool(vm, eop);

mu_assert_true(rz_float_is_inf(result), "div by zero should result in infinity");
mu_assert_true(e->b, "div by zero exception should be set");
rz_float_free(result);
rz_il_op_pure_free(eop);

// 2. Test overflow
op = rz_il_op_new_fmul(RZ_FLOAT_RMODE_RNE,
rz_il_op_new_float_from_f64(1e308),
rz_il_op_new_float_from_f64(1e308));
result = rz_il_evaluate_float(vm, op);
eop = rz_il_op_new_fexcept(RZ_FLOAT_E_OVERFLOW, op);
e = rz_il_evaluate_bool(vm, eop);

mu_assert_true(rz_float_is_inf(result), "overflow should result in infinity");
mu_assert_true(e->b, "overflow exception should be set");
rz_float_free(result);
rz_il_op_pure_free(eop);
rz_il_bool_free(e);

// 3. Test underflow
op = rz_il_op_new_fmul(RZ_FLOAT_RMODE_RNE,
rz_il_op_new_float_from_f64(1e-308),
rz_il_op_new_float_from_f64(1e-308));
eop = rz_il_op_new_fexcept(RZ_FLOAT_E_UNDERFLOW, op);
e = rz_il_evaluate_bool(vm, eop);
mu_assert_true(e->b, "underflow exception should be set");
rz_il_op_pure_free(eop);
rz_il_bool_free(e);

// 4. Test inexact result
op = rz_il_op_new_fdiv(RZ_FLOAT_RMODE_RNE,
rz_il_op_new_float_from_f64(1.0),
rz_il_op_new_float_from_f64(3.0));
eop = rz_il_op_new_fexcept(RZ_FLOAT_E_INEXACT, op);
e = rz_il_evaluate_bool(vm, eop);
mu_assert_true(e->b, "inexact exception should be set");
rz_il_op_pure_free(eop);
rz_il_bool_free(e);

rz_il_vm_free(vm);
mu_end;
}

bool all_tests() {
mu_run_test(test_rzil_vm_init);
mu_run_test(test_rzil_vm_global_vars);
Expand Down Expand Up @@ -1047,6 +1114,7 @@ bool all_tests() {
mu_run_test(test_rzil_vm_op_compare);
mu_run_test(test_rzil_vm_op_float);
mu_run_test(test_rzil_vm_op_fcast);
mu_run_test(test_rzil_vm_op_fexcept);
return tests_passed != tests_run;
}

Expand Down
Loading