Skip to content

Commit

Permalink
Compile time fmod evaluates to 0 #1195
Browse files Browse the repository at this point in the history
  • Loading branch information
lerno committed May 16, 2024
1 parent 094c105 commit c40c933
Show file tree
Hide file tree
Showing 5 changed files with 52 additions and 10 deletions.
1 change: 1 addition & 0 deletions releasenotes.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
- Duplicate emit of expressions on negation would incorrectly compile negated macros.
- Casting a slice address to its pointer type should not compile #1193.
- Union is not properly zero-initialized with designated initializer #1194.
- Compile time fmod evaluates to 0 #1195.

### Stdlib changes
- Add 'zstr' variants for `string::new_format` / `string::tformat`.
Expand Down
1 change: 1 addition & 0 deletions src/compiler/compiler_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -2015,6 +2015,7 @@ Float float_sub(Float op1, Float op2);
Float float_mul(Float op1, Float op2);
Float float_div(Float op1, Float op2);
Float float_neg(Float op);
Float float_rem(Float op1, Float op2);
Float float_from_string(const char *string, char **error);
Float float_from_hex(const char *string, char **error);
Int128 i128_from_double(double x);
Expand Down
6 changes: 6 additions & 0 deletions src/compiler/float.c
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,12 @@ Float float_div(Float op1, Float op2)
return (Float){ op1.f / op2.f, op1.type };
}

Float float_rem(Float op1, Float op2)
{
assert(op1.type == op2.type);
return (Float){fmod(op1.f, op2.f), op1.type };
}

Float float_neg(Float op)
{
op.f = -op.f;
Expand Down
37 changes: 27 additions & 10 deletions src/compiler/sema_expr.c
Original file line number Diff line number Diff line change
Expand Up @@ -5561,19 +5561,36 @@ static bool sema_expr_analyse_mod(SemaContext *context, Expr *expr, Expr *left,
// 1. Analyse both sides and promote to a common type
if (!sema_binary_analyse_arithmetic_subexpr(context, expr, NULL, false)) return false;

// 3. a % 0 is not valid, so detect it.
if (expr_is_const(right) && int_is_zero(right->const_expr.ixx))
Type *flat = type_flatten(left->type);
if (type_is_float(flat))
{
SEMA_ERROR(right, "Cannot perform %% with a constant zero.");
return false;
}
// 3. a % 0 is not valid, so detect it.
if (expr_is_const(right) && right->const_expr.fxx.f == 0.0)
{
RETURN_SEMA_ERROR(right, "Cannot perform %% with a constant zero.");
}

// 4. Constant fold
if (expr_both_const(left, right) && sema_constant_fold_ops(left))
// 4. Constant fold
if (expr_both_const(left, right) && sema_constant_fold_ops(left))
{
expr_replace(expr, left);
// 4a. Remember this is remainder.
expr->const_expr.fxx = float_rem(left->const_expr.fxx, right->const_expr.fxx);
}
}
else
{
expr_replace(expr, left);
// 4a. Remember this is remainder.
expr->const_expr.ixx = int_rem(left->const_expr.ixx, right->const_expr.ixx);
assert(type_is_integer(flat));
// 3. a % 0 is not valid, so detect it.
if (expr_is_const(right) && int_is_zero(right->const_expr.ixx)) RETURN_SEMA_ERROR(right, "Cannot perform %% with a constant zero.");

// 4. Constant fold
if (expr_both_const(left, right) && sema_constant_fold_ops(left))
{
expr_replace(expr, left);
// 4a. Remember this is remainder.
expr->const_expr.ixx = int_rem(left->const_expr.ixx, right->const_expr.ixx);
}
}

expr->type = type_add_optional(left->type, IS_OPTIONAL(right));
Expand Down
17 changes: 17 additions & 0 deletions test/test_suite/compile_time/mod_ct.c3t
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// #target: macos-x64
module test;
fn int main()
{
double a = 4.5 % 5;
double b = -4.5 % 5;
int ai = 4 % 5;
int bi = -4 % 5;
return 0;
}

/* #expect: test.ll

store double 4.500000e+00, ptr %a, align 8
store double -4.500000e+00, ptr %b, align 8
store i32 4, ptr %ai, align 4
store i32 -4, ptr %bi, align 4

0 comments on commit c40c933

Please sign in to comment.