51#define TARGET_X86_64 0
52#elif defined(__x86_64__)
54#define TARGET_X86_64 1
56#error "Unsupported architecture"
62 error_fatal(
"Memory allocation failed for code generator");
66 codegen->output_file = fopen(output_filename,
"w");
67 if (!codegen->output_file) {
69 error_fatal(
"Could not open output file '%s'", output_filename);
73 codegen->label_counter = 0;
74 codegen->temp_counter = 0;
81 if (codegen->output_file) {
82 fclose(codegen->output_file);
88void codegen_emit(
CodeGenerator *codegen,
const char *format, ...) {
90 va_start(args, format);
91 vfprintf(codegen->output_file, format, args);
93 fprintf(codegen->output_file,
"\n");
97 char *label = malloc(32);
99 error_fatal(
"Memory allocation failed for label");
102 snprintf(label, 32,
"L%d", codegen->label_counter++);
107 char *temp = malloc(32);
109 error_fatal(
"Memory allocation failed for temp");
112 snprintf(temp, 32,
"t%d", codegen->temp_counter++);
117 if (!codegen || !ast) {
123 codegen_emit(codegen,
"// Generated by KCC (ARM64/Apple Silicon) v%s", KCC_VERSION);
124 codegen_emit(codegen,
".section __TEXT,__text,regular,pure_instructions");
125 codegen_emit(codegen,
".build_version macos, 11, 0");
126 codegen_emit(codegen,
".globl _main");
127 codegen_emit(codegen,
".p2align 2");
129 codegen_emit(codegen,
"# Generated by KCC (x86-64) v%s", KCC_VERSION);
130 codegen_emit(codegen,
".section __TEXT,__text,regular,pure_instructions");
131 codegen_emit(codegen,
".globl _main");
133 codegen_emit(codegen,
"");
136 codegen_program(codegen, ast);
139 codegen_emit(codegen,
"");
140 codegen_emit(codegen,
"_main:");
143 codegen_emit(codegen,
" stp fp, lr, [sp, #-16]!");
144 codegen_emit(codegen,
" mov fp, sp");
145 codegen_emit(codegen,
" bl _main_func");
146 codegen_emit(codegen,
" mov w0, #0");
147 codegen_emit(codegen,
" ldp fp, lr, [sp], #16");
148 codegen_emit(codegen,
" ret");
150 codegen_emit(codegen,
" pushq %%rbp");
151 codegen_emit(codegen,
" movq %%rsp, %%rbp");
152 codegen_emit(codegen,
" callq _main_func");
153 codegen_emit(codegen,
" movq $0x2000001, %%rax");
154 codegen_emit(codegen,
" movq $0, %%rdi");
155 codegen_emit(codegen,
" syscall");
156 codegen_emit(codegen,
" popq %%rbp");
157 codegen_emit(codegen,
" retq");
164 if (node->type != AST_PROGRAM)
return;
166 for (
int i = 0; i < node->data.program.declaration_count; i++) {
167 ASTNode *decl = node->data.program.declarations[i];
169 if (decl->type == AST_FUNCTION_DECLARATION) {
170 codegen_function_declaration(codegen, decl);
171 }
else if (decl->type == AST_VARIABLE_DECLARATION) {
172 codegen_variable_declaration(codegen, decl);
178 if (node->type != AST_FUNCTION_DECLARATION)
return;
180 codegen_emit(codegen,
"");
182 codegen_emit(codegen,
"// Function: %s", node->data.function_decl.name);
184 codegen_emit(codegen,
"# Function: %s", node->data.function_decl.name);
187 if (strcmp(node->data.function_decl.name,
"main") == 0) {
188 codegen_emit(codegen,
"_main_func:");
190 codegen_emit(codegen,
"_%s:", node->data.function_decl.name);
195 codegen_emit(codegen,
" stp fp, lr, [sp, #-16]!");
196 codegen_emit(codegen,
" mov fp, sp");
198 codegen_emit(codegen,
" pushq %%rbp");
199 codegen_emit(codegen,
" movq %%rsp, %%rbp");
202 if (node->data.function_decl.body) {
203 codegen_compound_statement(codegen, node->data.function_decl.body);
208 codegen_emit(codegen,
" mov w0, #0");
209 codegen_emit(codegen,
" ldp fp, lr, [sp], #16");
210 codegen_emit(codegen,
" ret");
212 codegen_emit(codegen,
" movq $0, %%rax");
213 codegen_emit(codegen,
" movq %%rbp, %%rsp");
214 codegen_emit(codegen,
" popq %%rbp");
215 codegen_emit(codegen,
" retq");
220 if (node->type != AST_VARIABLE_DECLARATION)
return;
223 codegen_emit(codegen,
"// Variable: %s", node->data.var_decl.name);
225 codegen_emit(codegen,
"# Variable: %s", node->data.var_decl.name);
228 if (node->data.var_decl.initializer) {
229 codegen_expression(codegen, node->data.var_decl.initializer);
231 codegen_emit(codegen,
" // Store result in %s", node->data.var_decl.name);
233 codegen_emit(codegen,
" # Store result in %s", node->data.var_decl.name);
239 switch (node->type) {
240 case AST_COMPOUND_STATEMENT:
241 codegen_compound_statement(codegen, node);
243 case AST_EXPRESSION_STATEMENT:
244 codegen_expression_statement(codegen, node);
246 case AST_RETURN_STATEMENT:
247 codegen_return_statement(codegen, node);
249 case AST_IF_STATEMENT:
250 codegen_if_statement(codegen, node);
252 case AST_WHILE_STATEMENT:
253 codegen_while_statement(codegen, node);
255 case AST_FOR_STATEMENT:
256 codegen_for_statement(codegen, node);
258 case AST_VARIABLE_DECLARATION:
259 codegen_variable_declaration(codegen, node);
263 codegen_emit(codegen,
" // Unsupported statement type: %s",
264 ast_node_type_to_string(node->type));
266 codegen_emit(codegen,
" # Unsupported statement type: %s",
267 ast_node_type_to_string(node->type));
274 if (node->type != AST_COMPOUND_STATEMENT)
return;
276 for (
int i = 0; i < node->data.compound_stmt.statement_count; i++) {
277 codegen_statement(codegen, node->data.compound_stmt.statements[i]);
282 if (node->type != AST_EXPRESSION_STATEMENT)
return;
284 if (node->data.expression_stmt.expression) {
285 codegen_expression(codegen, node->data.expression_stmt.expression);
290 if (node->type != AST_RETURN_STATEMENT)
return;
292 if (node->data.return_stmt.expression) {
293 codegen_expression(codegen, node->data.return_stmt.expression);
295 codegen_emit(codegen,
" // Result already in w0/x0");
297 codegen_emit(codegen,
" # Result already in %%rax");
301 codegen_emit(codegen,
" mov w0, #0");
303 codegen_emit(codegen,
" movq $0, %%rax");
308 codegen_emit(codegen,
" ldp fp, lr, [sp], #16");
309 codegen_emit(codegen,
" ret");
311 codegen_emit(codegen,
" movq %%rbp, %%rsp");
312 codegen_emit(codegen,
" popq %%rbp");
313 codegen_emit(codegen,
" retq");
318 if (node->type != AST_IF_STATEMENT)
return;
320 char *else_label = codegen_new_label(codegen);
321 char *end_label = codegen_new_label(codegen);
323 codegen_expression(codegen, node->data.if_stmt.condition);
325 codegen_emit(codegen,
" cmp w0, #0");
326 codegen_emit(codegen,
" b.eq %s", else_label);
328 codegen_emit(codegen,
" testq %%rax, %%rax");
329 codegen_emit(codegen,
" jz %s", else_label);
332 codegen_statement(codegen, node->data.if_stmt.then_stmt);
334 codegen_emit(codegen,
" b %s", end_label);
336 codegen_emit(codegen,
" jmp %s", end_label);
339 codegen_emit(codegen,
"%s:", else_label);
340 if (node->data.if_stmt.else_stmt) {
341 codegen_statement(codegen, node->data.if_stmt.else_stmt);
344 codegen_emit(codegen,
"%s:", end_label);
351 if (node->type != AST_WHILE_STATEMENT)
return;
353 char *loop_label = codegen_new_label(codegen);
354 char *end_label = codegen_new_label(codegen);
356 codegen_emit(codegen,
"%s:", loop_label);
358 codegen_expression(codegen, node->data.while_stmt.condition);
360 codegen_emit(codegen,
" cmp w0, #0");
361 codegen_emit(codegen,
" b.eq %s", end_label);
363 codegen_emit(codegen,
" testq %%rax, %%rax");
364 codegen_emit(codegen,
" jz %s", end_label);
367 codegen_statement(codegen, node->data.while_stmt.body);
369 codegen_emit(codegen,
" b %s", loop_label);
371 codegen_emit(codegen,
" jmp %s", loop_label);
374 codegen_emit(codegen,
"%s:", end_label);
381 if (node->type != AST_FOR_STATEMENT)
return;
383 char *loop_label = codegen_new_label(codegen);
384 char *update_label = codegen_new_label(codegen);
385 char *end_label = codegen_new_label(codegen);
387 if (node->data.for_stmt.init) {
388 codegen_expression(codegen, node->data.for_stmt.init);
391 codegen_emit(codegen,
"%s:", loop_label);
393 if (node->data.for_stmt.condition) {
394 codegen_expression(codegen, node->data.for_stmt.condition);
396 codegen_emit(codegen,
" cmp w0, #0");
397 codegen_emit(codegen,
" b.eq %s", end_label);
399 codegen_emit(codegen,
" testq %%rax, %%rax");
400 codegen_emit(codegen,
" jz %s", end_label);
404 codegen_statement(codegen, node->data.for_stmt.body);
406 codegen_emit(codegen,
"%s:", update_label);
407 if (node->data.for_stmt.update) {
408 codegen_expression(codegen, node->data.for_stmt.update);
411 codegen_emit(codegen,
" b %s", loop_label);
413 codegen_emit(codegen,
" jmp %s", loop_label);
416 codegen_emit(codegen,
"%s:", end_label);
424 switch (node->type) {
426 codegen_binary_expression(codegen, node);
429 codegen_unary_expression(codegen, node);
431 case AST_FUNCTION_CALL:
432 codegen_call_expression(codegen, node);
435 codegen_identifier(codegen, node);
437 case AST_NUMBER_LITERAL:
438 codegen_number(codegen, node);
440 case AST_STRING_LITERAL:
441 codegen_string(codegen, node);
444 codegen_assignment(codegen, node);
448 codegen_emit(codegen,
" // Unsupported expression type: %s",
449 ast_node_type_to_string(node->type));
451 codegen_emit(codegen,
" # Unsupported expression type: %s",
452 ast_node_type_to_string(node->type));
459 if (node->type != AST_BINARY_OP)
return;
461 codegen_expression(codegen, node->data.binary_expr.left);
463 codegen_emit(codegen,
" str w0, [sp, #-16]!");
465 codegen_emit(codegen,
" pushq %%rax");
468 codegen_expression(codegen, node->data.binary_expr.right);
470 codegen_emit(codegen,
" mov w1, w0");
471 codegen_emit(codegen,
" ldr w0, [sp], #16");
473 codegen_emit(codegen,
" movq %%rax, %%rbx");
474 codegen_emit(codegen,
" popq %%rax");
477 switch (node->data.binary_expr.operator) {
480 codegen_emit(codegen,
" add w0, w0, w1");
482 codegen_emit(codegen,
" addq %%rbx, %%rax");
487 codegen_emit(codegen,
" sub w0, w0, w1");
489 codegen_emit(codegen,
" subq %%rbx, %%rax");
494 codegen_emit(codegen,
" mul w0, w0, w1");
496 codegen_emit(codegen,
" imulq %%rbx, %%rax");
501 codegen_emit(codegen,
" cmp w0, w1");
502 codegen_emit(codegen,
" cset w0, gt");
504 codegen_emit(codegen,
" cmpq %%rbx, %%rax");
505 codegen_emit(codegen,
" setg %%al");
506 codegen_emit(codegen,
" movzbq %%al, %%rax");
511 codegen_emit(codegen,
" // Unsupported binary operator: %s",
512 token_type_to_string(node->data.binary_expr.operator));
514 codegen_emit(codegen,
" # Unsupported binary operator: %s",
515 token_type_to_string(node->data.binary_expr.operator));
522 if (node->type != AST_UNARY_OP)
return;
524 codegen_expression(codegen, node->data.unary_expr.operand);
526 switch (node->data.unary_expr.operator) {
529 codegen_emit(codegen,
" neg w0, w0");
531 codegen_emit(codegen,
" negq %%rax");
536 codegen_emit(codegen,
" cmp w0, #0");
537 codegen_emit(codegen,
" cset w0, eq");
539 codegen_emit(codegen,
" testq %%rax, %%rax");
540 codegen_emit(codegen,
" setz %%al");
541 codegen_emit(codegen,
" movzbq %%al, %%rax");
546 codegen_emit(codegen,
" // Unsupported unary operator: %s",
547 token_type_to_string(node->data.unary_expr.operator));
549 codegen_emit(codegen,
" # Unsupported unary operator: %s",
550 token_type_to_string(node->data.unary_expr.operator));
557 if (node->type != AST_FUNCTION_CALL)
return;
561 for (
int i = 0; i < node->data.call_expr.argument_count && i < 8; i++) {
562 codegen_expression(codegen, node->data.call_expr.arguments[i]);
564 codegen_emit(codegen,
" mov x%d, x0", i);
567 codegen_emit(codegen,
" bl _%s", node->data.call_expr.function_name);
570 for (
int i = node->data.call_expr.argument_count - 1; i >= 0; i--) {
571 codegen_expression(codegen, node->data.call_expr.arguments[i]);
572 codegen_emit(codegen,
" pushq %%rax");
574 codegen_emit(codegen,
" callq _%s", node->data.call_expr.function_name);
575 if (node->data.call_expr.argument_count > 0) {
576 codegen_emit(codegen,
" addq $%d, %%rsp",
577 node->data.call_expr.argument_count * 8);
583 if (node->type != AST_IDENTIFIER)
return;
586 codegen_emit(codegen,
" // Load variable %s", node->data.identifier.name);
587 codegen_emit(codegen,
" ldr w0, [fp, #-8]");
589 codegen_emit(codegen,
" # Load variable %s", node->data.identifier.name);
590 codegen_emit(codegen,
" movq -8(%%rbp), %%rax");
595 if (node->type != AST_NUMBER_LITERAL)
return;
598 codegen_emit(codegen,
" mov w0, #%d", node->data.number.value);
600 codegen_emit(codegen,
" movq $%d, %%rax", node->data.number.value);
605 if (node->type != AST_STRING_LITERAL)
return;
608 codegen_emit(codegen,
" // String literal: \"%s\"", node->data.string.value);
609 codegen_emit(codegen,
" adrp x0, string_literal_%d@PAGE", codegen->label_counter);
610 codegen_emit(codegen,
" add x0, x0, string_literal_%d@PAGEOFF", codegen->label_counter++);
612 codegen_emit(codegen,
" # String literal: \"%s\"", node->data.string.value);
613 codegen_emit(codegen,
" movq $string_literal_%d, %%rax", codegen->label_counter++);
618 if (node->type != AST_ASSIGNMENT)
return;
620 codegen_expression(codegen, node->data.assignment.value);
623 codegen_emit(codegen,
" // Assign to %s", node->data.assignment.variable);
624 codegen_emit(codegen,
" str w0, [fp, #-8]");
626 codegen_emit(codegen,
" # Assign to %s", node->data.assignment.variable);
627 codegen_emit(codegen,
" movq %%rax, -8(%%rbp)");