diff options
-rw-r--r-- | 04/in03 | 29 | ||||
-rw-r--r-- | 05/constants.b | 2 | ||||
-rw-r--r-- | 05/main.c | 2 | ||||
-rw-r--r-- | 05/parse.b | 44 | ||||
-rw-r--r-- | 05/util.b | 75 | ||||
-rw-r--r-- | README.md | 1 |
6 files changed, 127 insertions, 26 deletions
@@ -1005,7 +1005,7 @@ align I=:line call :set_rax_to_rvalue call :set_rbx_to_rdi - call :emit_zero_rdx_idiv_rbx + call :emit_cqo_idiv_rbx I=:line call :set_lvalue_to_rax !:read_line @@ -1014,7 +1014,7 @@ align I=:line call :set_rax_to_rvalue call :set_rbx_to_rdi - call :emit_zero_rdx_idiv_rbx + call :emit_cqo_idiv_rbx call :set_rax_to_rdx I=:line call :set_lvalue_to_rax @@ -1475,11 +1475,11 @@ align :rvalue_div call :set_rbx_to_rsi - !:emit_zero_rdx_idiv_rbx + !:emit_cqo_idiv_rbx :rvalue_rem call :set_rbx_to_rsi - call :emit_zero_rdx_idiv_rbx + call :emit_cqo_idiv_rbx call :set_rax_to_rdx return @@ -1745,16 +1745,6 @@ align x31 xc0 -:zero_rdx - J=d4 - I=:xor_edx_edx - D=d2 - syscall x1 - return -:xor_edx_edx - x31 - xd2 - :set_rbx_to_rax J=d4 I=:mov_rbx_rax @@ -2014,14 +2004,15 @@ align xf7 xeb -:emit_zero_rdx_idiv_rbx - call :zero_rdx +:emit_cqo_idiv_rbx J=d4 - I=:idiv_rbx - D=d3 + I=:cqo_idiv_rbx + D=d5 syscall x1 return -:idiv_rbx +:cqo_idiv_rbx + x48 + x99 x48 xf7 xfb diff --git a/05/constants.b b/05/constants.b index 85aff7a..fa2d0f4 100644 --- a/05/constants.b +++ b/05/constants.b @@ -126,7 +126,7 @@ ; uchar kind (one of the constants below) ; uchar info ; ushort (padding) -; uint type (0 if expression hasn't been typed yet) +; uint type ; immediately following the header in memory are the arguments of the expression ; - for constant ints, the 64-bit integral value ; - for constant floats, the 64-bit double value (even if expression has type float) @@ -3,4 +3,4 @@ long double d; } (*x)(void); */ -typedef long int unsigned Foo[3 * 3]; +typedef long int unsigned Foo[19 + (-3) % 187 - 28 + 5 * 6]; @@ -943,6 +943,7 @@ function evaluate_constant_expression argument p_value local a local b + local p if *1expr == EXPRESSION_CONSTANT_INT goto eval_constant_int if *1expr == EXPRESSION_IDENTIFIER goto eval_constant_identifier @@ -951,8 +952,11 @@ function evaluate_constant_expression if *1expr == EXPRESSION_BITWISE_NOT goto eval_bitwise_not if *1expr == EXPRESSION_LOGICAL_NOT goto eval_logical_not if *1expr == EXPRESSION_CAST goto eval_todo ; @TODO - if *1expr == EXPRESSION_LOGICAL_NOT goto eval_logical_not + if *1expr == EXPRESSION_ADD goto eval_add + if *1expr == EXPRESSION_SUB goto eval_sub if *1expr == EXPRESSION_MUL goto eval_mul + if *1expr == EXPRESSION_DIV goto eval_div + if *1expr == EXPRESSION_REMAINDER goto eval_remainder byte 0xcc :eval_todo @@ -998,13 +1002,49 @@ function evaluate_constant_expression :eval_logical_not0 *8p_value = 1 return expr + :eval_add + expr += 8 + expr = evaluate_constant_expression(expr, &a) + expr = evaluate_constant_expression(expr, &b) + *8p_value = a + b + return expr + :eval_sub + expr += 8 + expr = evaluate_constant_expression(expr, &a) + expr = evaluate_constant_expression(expr, &b) + *8p_value = a - b + return expr :eval_mul expr += 8 expr = evaluate_constant_expression(expr, &a) expr = evaluate_constant_expression(expr, &b) *8p_value = a * b return expr - + :eval_div + p = expr + 4 ; pointer to type + expr += 8 + expr = evaluate_constant_expression(expr, &a) + expr = evaluate_constant_expression(expr, &b) + if *1p == TYPE_UNSIGNED_LONG goto eval_div_unsigned + ; division is signed or uses a small type, so we can use 64-bit signed division + *8p_value = a / b + return expr + :eval_div_unsigned + ; must use unsigned division + divmod_unsigned(a, b, p_value, &a) + return expr + :eval_remainder + p = expr + 4 ; pointer to type + expr += 8 + expr = evaluate_constant_expression(expr, &a) + expr = evaluate_constant_expression(expr, &b) + if *1p == TYPE_UNSIGNED_LONG goto eval_rem_unsigned + *8p_value = a % b + return expr + :eval_rem_unsigned + divmod_unsigned(a, b, &a, p_value) + return expr + ; the "usual conversions" for binary operators, as the C standard calls it function expr_binary_type_usual_conversions argument token ; for errors @@ -25,6 +25,75 @@ function full_multiply_signed *8p_upper = upper return + +function divmod_unsigned + argument a + argument b + argument p_quotient + argument p_remainder + local q + local r + + ; mov rax, [rbp-16] + byte 0x48 + byte 0x8b + byte 0x85 + byte 0xf0 + byte 0xff + byte 0xff + byte 0xff + + ; mov rbx, rax + byte 0x48 + byte 0x89 + byte 0xc3 + + ; mov rax, [rbp-8] + byte 0x48 + byte 0x8b + byte 0x85 + byte 0xf8 + byte 0xff + byte 0xff + byte 0xff + + ; xor edx, edx + byte 0x31 + byte 0xd2 + + ; div rbx + byte 0x48 + byte 0xf7 + byte 0xf3 + + ; mov [rbp-40], rax + byte 0x48 + byte 0x89 + byte 0x85 + byte 0xd8 + byte 0xff + byte 0xff + byte 0xff + + ; mov rax, rdx + byte 0x48 + byte 0x89 + byte 0xd0 + + ; mov [rbp-48], rax + byte 0x48 + byte 0x89 + byte 0x85 + byte 0xd0 + byte 0xff + byte 0xff + byte 0xff + + *8p_quotient = q + *8p_remainder = r + + return + ; allows for negative shifts function right_shift argument x @@ -93,7 +162,8 @@ function free syscall(11, psize, size) return -; returns a pointer to a null-terminated string containing the number given +; returns a pointer to a null-terminated string containing the +; (unsigned) number given function itos global 32 itos_string argument x @@ -102,10 +172,9 @@ function itos p = &itos_string p += 30 :itos_loop - c = x % 10 + divmod_unsigned(x, 10, &x, &c) c += '0 *1p = c - x /= 10 if x == 0 goto itos_loop_end p -= 1 goto itos_loop @@ -137,6 +137,7 @@ In the table below, `IMM64` means a 64-bit *immediate* (a constant number). │ add rax, rbx │ 48 01 d8 │ add rbx to rax │ │ sub rax, rbx │ 48 29 d8 │ subtract rbx from rax │ │ imul rbx │ 48 f7 eb │ set rdx:rax to rax * rbx (signed) │ +│ cqo │ 48 99 │ sign-extend rax to rdx:rax | │ idiv rbx │ 48 f7 fb │ divide rdx:rax by rbx (signed); put │ │ │ │ quotient in rax, remainder in rbx │ │ mul rbx │ 48 f7 e3 │ like imul, but unsigned │ |