diff --git a/ast.c b/ast.c index 4262e63..fd0d8e6 100644 --- a/ast.c +++ b/ast.c @@ -3842,16 +3842,25 @@ static VarType get_native_call_static_type(ASTNode *node) return stdrot_type_to_vartype(entry->return_type.type); } -/* An int-typed operand's value widened for a float/double operation -- - through unsigned int for a nonut rizz (#371), so 3000000000 + 0.5 is - 3000000000.5 rather than the signed reinterpretation. */ +/* Preserve the integer operand's width before widening (#372), and its + unsigned interpretation for a nonut rizz (#371). */ static double int_operand_as_double(ASTNode *expr) { + if (expression_is_long(expr)) + return (double)evaluate_expression_long(expr); int value = evaluate_expression_int(expr); return expression_is_unsigned(expr) ? (double)(unsigned int)value : (double)value; } +static float int_operand_as_float(ASTNode *expr) +{ + /* int64 -> double -> float can round twice at a float halfway point. */ + if (expression_is_long(expr)) + return (float)evaluate_expression_long(expr); + return (float)int_operand_as_double(expr); +} + void *handle_binary_operation(ASTNode *node) { if (!node || node->type != NODE_OPERATION) @@ -3908,11 +3917,11 @@ void *handle_binary_operation(ASTNode *node) right_value = SAFE_MALLOC(float); *(float *)left_value = (left_type == VAR_INT) - ? (float)int_operand_as_double(node->data.op.left) + ? int_operand_as_float(node->data.op.left) : evaluate_expression_float(node->data.op.left); *(float *)right_value = (right_type == VAR_INT) - ? (float)int_operand_as_double(node->data.op.right) + ? int_operand_as_float(node->data.op.right) : evaluate_expression_float(node->data.op.right); break; @@ -5309,6 +5318,12 @@ float evaluate_expression_float(ASTNode *node) if (!node) return 0.0f; + /* Integer expressions must be evaluated at their own width before + conversion. The type guard keeps mixed floating operations floating; + expression_is_long() excludes pointers and does not evaluate operands. */ + if (get_expression_type(node) == VAR_INT && expression_is_long(node)) + return (float)evaluate_expression_long(node); + switch (node->type) { case NODE_ARRAY_ACCESS: @@ -5462,6 +5477,10 @@ double evaluate_expression_double(ASTNode *node) if (!node) return 0.0L; + /* As above, do not read a giga/thicc through a 32-bit value slot. */ + if (get_expression_type(node) == VAR_INT && expression_is_long(node)) + return (double)evaluate_expression_long(node); + switch (node->type) { case NODE_ARRAY_ACCESS: diff --git a/test_cases/wide_integer_float.brainrot b/test_cases/wide_integer_float.brainrot new file mode 100644 index 0000000..501fcb6 --- /dev/null +++ b/test_cases/wide_integer_float.brainrot @@ -0,0 +1,49 @@ +skibidi main { + giga rizz a = 5000000000; + thicc rizz b = 0 - 5000000000; + gigachad d = a; + chad f = a; + yapping("%.0f %.0f", d, f); + d = b; + f = b; + yapping("%.0f %.0f", d, f); + + gigachad two_d = 2.0; + chad two_f = 2.0; + yapping("%.0f %.0f", a * two_d, two_d * a); + yapping("%.0f %.0f", b * two_f, two_f * b); + yapping("%.1f %.1f", a + 0.5, 0.5 + b); + yapping("%.1f %.1f", a / two_d, two_d - b); + yapping("%d %d %d %d", a > two_d, two_d < a, b < two_f, two_f > b); + + d = a + 3; + f = b * 2; + yapping("%.0f %.0f", d, f); + d = 5000000000; + f = 5000000000; + yapping("%.0f %.0f", d, f); + d = -a; + f = -b; + yapping("%.0f %.0f", d, f); + + thicc rizz zero = 0; + thicc rizz edge = 2147483648; + thicc rizz high = 4294967296; + yapping("%.0f %.0f %.0f", zero + two_d, edge + two_d, high + two_d); + thicc rizz minimum = 0 - 9223372036854775807 - 1; + d = minimum; + f = minimum; + yapping("%.0f %.0f", d, f); + + 🚽 Above a float halfway point: converting via double would round twice. + thicc rizz halfway = 4611686293305294849; + chad zero_f = 0.0; + f = halfway; + yapping("%.0f %.0f %.0f", f, halfway + zero_f, zero_f + halfway); + + 🚽 Retain the existing unsigned-32 conversion and mixed-fraction paths. + nonut rizz u = 3000000000; + yapping("%.1f %.1f", u + 0.5, 0.5 + u); + yapping("%.1f", (a + 0.5) + two_d); + bussin 0; +} diff --git a/test_cases/wide_integer_float_loads.brainrot b/test_cases/wide_integer_float_loads.brainrot new file mode 100644 index 0000000..51be03d --- /dev/null +++ b/test_cases/wide_integer_float_loads.brainrot @@ -0,0 +1,34 @@ +rizz next_factor(rizz *calls) { + *calls = *calls + 1; + bussin 2; +} + +skibidi main { + rizz calls = 0; + thicc rizz values[2] = {5000000000, 6000000000}; + thicc rizz *p = &values[0]; + gigachad d = values[0]; + chad f = values[1]; + yapping("%.0f %.0f", d, f); + d = *p; + f = *(p + 1); + yapping("%.0f %.0f", d, f); + + 🚽 Integer expressions must be evaluated once, including their effects. + d = values[0] * next_factor(&calls); + f = next_factor(&calls) * values[0]; + yapping("%.0f %.0f %d", d, f, calls); + d = (values[0] + next_factor(&calls)) + 0.5; + chad half = 0.5; + f = half * (values[0] * next_factor(&calls)); + yapping("%.1f %.0f %d", d, f, calls); + rizz index = 0; + d = values[index++]; + f = values[index++]; + yapping("%.0f %.0f %d", d, f, index); + thicc rizz value = 5000000000; + d = value++; + gigachad after = ++value; + yapping("%.0f %.0f %lld", d, after, value); + bussin 0; +} diff --git a/tests/expected_results.json b/tests/expected_results.json index 9f760c1..929a5ff 100644 --- a/tests/expected_results.json +++ b/tests/expected_results.json @@ -469,5 +469,7 @@ "array_decay_const_fail": "Error: Cannot modify const variable at line 37\nError: Cannot modify const variable at line 36\nError: Cannot modify const variable at line 35\nError: Cannot modify const variable at line 34\nError: Cannot modify const variable at line 33\nError: Cannot modify const variable at line 32\nError: Cannot modify const variable at line 31\nError: Cannot modify const variable at line 30\nError: Cannot modify const variable at line 29", "pointer_width_consistency": "giga index: 20 30\ngiga arith: 20 30\nthicc index: 7000000000 5000000000 6000000000\nthicc arith: 7000000000 5000000000 6000000000\nthicc element: 8000000000\nthicc scalar: 9000000000", "array_decay_local_return_fail": "Error: 'local_struct_field' returns an address inside local variable 'b', which is freed when the function returns -- make it `salty` (static), or have the caller pass the array in at line 31\nError: 'local_array_plus' returns an address inside local variable 'xs', which is freed when the function returns -- make it `salty` (static), or have the caller pass the array in at line 26\nError: 'local_array' returns an address inside local variable 'xs', which is freed when the function returns -- make it `salty` (static), or have the caller pass the array in at line 21", - "native_ptr_user_pointer_param": "inline: 41\nstored: 42" + "native_ptr_user_pointer_param": "inline: 41\nstored: 42", + "wide_integer_float": "5000000000 5000000000\n-5000000000 -5000000000\n10000000000 10000000000\n-10000000000 -10000000000\n5000000000.5 -4999999999.5\n2500000000.0 5000000002.0\n1 1 1 1\n5000000003 -10000000000\n5000000000 5000000000\n-5000000000 5000000000\n2 2147483650 4294967298\n-9223372036854775808 -9223372036854775808\n4611686568183201792 4611686568183201792 4611686568183201792\n3000000000.5 3000000000.5\n5000000002.5", + "wide_integer_float_loads": "5000000000 6000000000\n5000000000 6000000000\n10000000000 10000000000 2\n5000000002.5 5000000000 4\n5000000000 6000000000 2\n5000000000 5000000002 5000000002" }