Compile time fmod evaluates to 0 #1195

This commit is contained in:
Christoffer Lerno
2024-05-16 14:33:11 +02:00
parent 094c105464
commit c40c93340d
5 changed files with 52 additions and 10 deletions

View File

@@ -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`.

View File

@@ -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);

View File

@@ -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;

View File

@@ -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));

View File

@@ -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