KCC - Kayte C Compiler 1.10.0
A C compiler implementation with preprocessor, lexer, parser, and code generator
Loading...
Searching...
No Matches
multiarch_codegen.c
1#include "kcc.h"
2#include "multiarch_codegen.h"
3
4// ===== ARCHITECTURE DEFINITIONS =====
5
6// x86_64 registers
7static const RegisterInfo x86_64_general_regs[] = {
8 {"rax", REG_GENERAL, 8, false}, {"rbx", REG_GENERAL, 8, true},
9 {"rcx", REG_GENERAL, 8, false}, {"rdx", REG_GENERAL, 8, false},
10 {"rsi", REG_GENERAL, 8, false}, {"rdi", REG_GENERAL, 8, false},
11 {"r8", REG_GENERAL, 8, false}, {"r9", REG_GENERAL, 8, false},
12 {"r10", REG_GENERAL, 8, false}, {"r11", REG_GENERAL, 8, false},
13 {"r12", REG_GENERAL, 8, true}, {"r13", REG_GENERAL, 8, true},
14 {"r14", REG_GENERAL, 8, true}, {"r15", REG_GENERAL, 8, true},
15 {"rsp", REG_SPECIAL, 8, true}, {"rbp", REG_SPECIAL, 8, true}
16};
17
18static const RegisterInfo x86_64_float_regs[] = {
19 {"xmm0", REG_FLOAT, 16, false}, {"xmm1", REG_FLOAT, 16, false},
20 {"xmm2", REG_FLOAT, 16, false}, {"xmm3", REG_FLOAT, 16, false},
21 {"xmm4", REG_FLOAT, 16, false}, {"xmm5", REG_FLOAT, 16, false},
22 {"xmm6", REG_FLOAT, 16, false}, {"xmm7", REG_FLOAT, 16, false}
23};
24
25// ARM64 registers
26static const RegisterInfo arm64_general_regs[] = {
27 {"x0", REG_GENERAL, 8, false}, {"x1", REG_GENERAL, 8, false},
28 {"x2", REG_GENERAL, 8, false}, {"x3", REG_GENERAL, 8, false},
29 {"x4", REG_GENERAL, 8, false}, {"x5", REG_GENERAL, 8, false},
30 {"x6", REG_GENERAL, 8, false}, {"x7", REG_GENERAL, 8, false},
31 {"x8", REG_GENERAL, 8, false}, {"x9", REG_GENERAL, 8, false},
32 {"x10", REG_GENERAL, 8, false}, {"x11", REG_GENERAL, 8, false},
33 {"x12", REG_GENERAL, 8, false}, {"x13", REG_GENERAL, 8, false},
34 {"x14", REG_GENERAL, 8, false}, {"x15", REG_GENERAL, 8, false},
35 {"x19", REG_GENERAL, 8, true}, {"x20", REG_GENERAL, 8, true},
36 {"x21", REG_GENERAL, 8, true}, {"x22", REG_GENERAL, 8, true},
37 {"x29", REG_SPECIAL, 8, true}, {"x30", REG_SPECIAL, 8, true},
38 {"sp", REG_SPECIAL, 8, true}
39};
40
41static const RegisterInfo arm64_float_regs[] = {
42 {"v0", REG_FLOAT, 16, false}, {"v1", REG_FLOAT, 16, false},
43 {"v2", REG_FLOAT, 16, false}, {"v3", REG_FLOAT, 16, false},
44 {"v4", REG_FLOAT, 16, false}, {"v5", REG_FLOAT, 16, false},
45 {"v6", REG_FLOAT, 16, false}, {"v7", REG_FLOAT, 16, false}
46};
47
48// Parameter passing registers
49static const char *x86_64_sysv_param_regs[] = {"rdi", "rsi", "rdx", "rcx", "r8", "r9"};
50static const char *x86_64_sysv_return_regs[] = {"rax", "rdx"};
51
52static const char *arm64_param_regs[] = {"x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7"};
53static const char *arm64_return_regs[] = {"x0", "x1"};
54
55// ===== TARGET CONFIGURATION =====
56
57TargetArch detect_host_architecture(void) {
58#if defined(__x86_64__) || defined(_M_X64)
59 return ARCH_X86_64;
60#elif defined(__aarch64__) || defined(_M_ARM64)
61 return ARCH_ARM64;
62#else
63 return ARCH_UNKNOWN;
64#endif
65}
66
67TargetPlatform detect_host_platform(void) {
68#if defined(__linux__)
69 return PLATFORM_LINUX;
70#elif defined(__APPLE__)
71 return PLATFORM_MACOS;
72#else
73 return PLATFORM_UNKNOWN;
74#endif
75}
76
77TargetConfig *target_config_create(TargetArch arch, TargetPlatform platform) {
78 TargetConfig *config = malloc(sizeof(TargetConfig));
79 if (!config) return NULL;
80
81 config->arch = arch;
82 config->platform = platform;
83
84 // Configure based on architecture and platform
85 switch (arch) {
86 case ARCH_X86_64:
87 config->arch_name = "x86_64";
88 config->pointer_size = 8;
89 config->stack_alignment = 16;
90 config->general_regs = x86_64_general_regs;
91 config->float_regs = x86_64_float_regs;
92 config->num_general_regs = sizeof(x86_64_general_regs) / sizeof(RegisterInfo);
93 config->num_float_regs = sizeof(x86_64_float_regs) / sizeof(RegisterInfo);
94 config->calling_conv = CALL_CONV_SYSV;
95 config->param_regs = x86_64_sysv_param_regs;
96 config->return_regs = x86_64_sysv_return_regs;
97 config->num_param_regs = 6;
98 config->num_return_regs = 2;
99 config->syscall_reg = "rax";
100 config->syscall_instruction = "syscall";
101 config->comment_prefix = "#";
102 config->att_syntax = true;
103 break;
104
105 case ARCH_ARM64:
106 config->arch_name = "arm64";
107 config->pointer_size = 8;
108 config->stack_alignment = 16;
109 config->general_regs = arm64_general_regs;
110 config->float_regs = arm64_float_regs;
111 config->num_general_regs = sizeof(arm64_general_regs) / sizeof(RegisterInfo);
112 config->num_float_regs = sizeof(arm64_float_regs) / sizeof(RegisterInfo);
113 config->calling_conv = CALL_CONV_AARCH64;
114 config->param_regs = arm64_param_regs;
115 config->return_regs = arm64_return_regs;
116 config->num_param_regs = 8;
117 config->num_return_regs = 2;
118 config->syscall_reg = "x8";
119 config->syscall_instruction = "svc #0";
120 config->comment_prefix = "//";
121 config->att_syntax = false;
122 break;
123
124 default:
125 free(config);
126 return NULL;
127 }
128
129 // Configure platform-specific settings
130 switch (platform) {
131 case PLATFORM_LINUX:
132 config->platform_name = "linux";
133 config->global_directive = ".globl";
134 config->section_text = ".text";
135 config->section_data = ".data";
136 break;
137
138 case PLATFORM_MACOS:
139 config->platform_name = "macos";
140 config->global_directive = ".globl";
141 config->section_text = ".text";
142 config->section_data = ".data";
143 // macOS uses underscore prefix for symbols
144 break;
145
146 default:
147 free(config);
148 return NULL;
149 }
150
151 return config;
152}
153
154void target_config_destroy(TargetConfig *config) {
155 if (config) {
156 free(config);
157 }
158}
159
160// ===== MULTI-ARCH CODEGEN =====
161
162MultiArchCodegen *multiarch_codegen_create(const char *output_file, TargetArch arch, TargetPlatform platform) {
163 MultiArchCodegen *codegen = malloc(sizeof(MultiArchCodegen));
164 if (!codegen) return NULL;
165
166 codegen->output_file = fopen(output_file, "w");
167 if (!codegen->output_file) {
168 free(codegen);
169 return NULL;
170 }
171
172 codegen->target = target_config_create(arch, platform);
173 if (!codegen->target) {
174 fclose(codegen->output_file);
175 free(codegen);
176 return NULL;
177 }
178
179 codegen->label_counter = 0;
180 codegen->temp_counter = 0;
181 codegen->current_function_locals = 0;
182 codegen->stack_offset = 0;
183 codegen->local_var_count = 0;
184 codegen->in_function = false;
185 codegen->stack_size = 0;
186
187 return codegen;
188}
189
190void multiarch_codegen_destroy(MultiArchCodegen *codegen) {
191 if (codegen) {
192 if (codegen->output_file) {
193 fclose(codegen->output_file);
194 }
195 target_config_destroy(codegen->target);
196 free(codegen);
197 }
198}
199
200void multiarch_emit(MultiArchCodegen *codegen, const char *format, ...) {
201 va_list args;
202 va_start(args, format);
203 vfprintf(codegen->output_file, format, args);
204 va_end(args);
205 fprintf(codegen->output_file, "\n");
206}
207
208void multiarch_emit_comment(MultiArchCodegen *codegen, const char *comment) {
209 multiarch_emit(codegen, "%s %s", codegen->target->comment_prefix, comment);
210}
211
212void multiarch_emit_label(MultiArchCodegen *codegen, const char *label) {
213 multiarch_emit(codegen, "%s:", label);
214}
215
216void multiarch_emit_directive(MultiArchCodegen *codegen, const char *directive, const char *args) {
217 if (args) {
218 multiarch_emit(codegen, "%s %s", directive, args);
219 } else {
220 multiarch_emit(codegen, "%s", directive);
221 }
222}
223
224// ===== ARCHITECTURE-SPECIFIC IMPLEMENTATIONS =====
225
226void multiarch_load_immediate(MultiArchCodegen *codegen, const char *dest_reg, long value) {
227 switch (codegen->target->arch) {
228 case ARCH_X86_64:
229 multiarch_emit(codegen, " movq $%ld, %%%s", value, dest_reg);
230 break;
231 case ARCH_ARM64:
232 if (value >= 0 && value < 65536) {
233 multiarch_emit(codegen, " mov %s, #%ld", dest_reg, value);
234 } else {
235 multiarch_emit(codegen, " mov %s, #%ld", dest_reg, value & 0xFFFF);
236 if (value > 65535) {
237 multiarch_emit(codegen, " movk %s, #%ld, lsl #16", dest_reg, (value >> 16) & 0xFFFF);
238 }
239 if (value > 0xFFFFFFFF) {
240 multiarch_emit(codegen, " movk %s, #%ld, lsl #32", dest_reg, (value >> 32) & 0xFFFF);
241 multiarch_emit(codegen, " movk %s, #%ld, lsl #48", dest_reg, (value >> 48) & 0xFFFF);
242 }
243 }
244 break;
245 default:
246 break;
247 }
248}
249
250void multiarch_add(MultiArchCodegen *codegen, const char *dest, const char *src1, const char *src2) {
251 switch (codegen->target->arch) {
252 case ARCH_X86_64:
253 if (strcmp(dest, src1) == 0) {
254 multiarch_emit(codegen, " addq %%%s, %%%s", src2, dest);
255 } else {
256 multiarch_emit(codegen, " movq %%%s, %%%s", src1, dest);
257 multiarch_emit(codegen, " addq %%%s, %%%s", src2, dest);
258 }
259 break;
260 case ARCH_ARM64:
261 multiarch_emit(codegen, " add %s, %s, %s", dest, src1, src2);
262 break;
263 default:
264 break;
265 }
266}
267
268void multiarch_sub(MultiArchCodegen *codegen, const char *dest, const char *src1, const char *src2) {
269 switch (codegen->target->arch) {
270 case ARCH_X86_64:
271 if (strcmp(dest, src1) == 0) {
272 multiarch_emit(codegen, " subq %%%s, %%%s", src2, dest);
273 } else {
274 multiarch_emit(codegen, " movq %%%s, %%%s", src1, dest);
275 multiarch_emit(codegen, " subq %%%s, %%%s", src2, dest);
276 }
277 break;
278 case ARCH_ARM64:
279 multiarch_emit(codegen, " sub %s, %s, %s", dest, src1, src2);
280 break;
281 default:
282 break;
283 }
284}
285
286void multiarch_mul(MultiArchCodegen *codegen, const char *dest, const char *src1, const char *src2) {
287 switch (codegen->target->arch) {
288 case ARCH_X86_64:
289 if (strcmp(dest, src1) == 0) {
290 multiarch_emit(codegen, " imulq %%%s, %%%s", src2, dest);
291 } else {
292 multiarch_emit(codegen, " movq %%%s, %%%s", src1, dest);
293 multiarch_emit(codegen, " imulq %%%s, %%%s", src2, dest);
294 }
295 break;
296 case ARCH_ARM64:
297 multiarch_emit(codegen, " mul %s, %s, %s", dest, src1, src2);
298 break;
299 default:
300 break;
301 }
302}
303
304void multiarch_div(MultiArchCodegen *codegen, const char *dest, const char *src1, const char *src2) {
305 switch (codegen->target->arch) {
306 case ARCH_X86_64:
307 // x86_64 division is more complex - needs rax/rdx setup
308 multiarch_emit(codegen, " movq %%%s, %%rax", src1);
309 multiarch_emit(codegen, " cqo"); // Sign extend rax to rdx:rax
310 multiarch_emit(codegen, " idivq %%%s", src2);
311 if (strcmp(dest, "rax") != 0) {
312 multiarch_emit(codegen, " movq %%rax, %%%s", dest);
313 }
314 break;
315 case ARCH_ARM64:
316 multiarch_emit(codegen, " sdiv %s, %s, %s", dest, src1, src2);
317 break;
318 default:
319 break;
320 }
321}
322
323void multiarch_compare(MultiArchCodegen *codegen, const char *reg1, const char *reg2) {
324 switch (codegen->target->arch) {
325 case ARCH_X86_64:
326 multiarch_emit(codegen, " cmpq %%%s, %%%s", reg2, reg1);
327 break;
328 case ARCH_ARM64:
329 multiarch_emit(codegen, " cmp %s, %s", reg1, reg2);
330 break;
331 default:
332 break;
333 }
334}
335
336void multiarch_jump(MultiArchCodegen *codegen, const char *label) {
337 switch (codegen->target->arch) {
338 case ARCH_X86_64:
339 multiarch_emit(codegen, " jmp %s", label);
340 break;
341 case ARCH_ARM64:
342 multiarch_emit(codegen, " b %s", label);
343 break;
344 default:
345 break;
346 }
347}
348
349void multiarch_jump_if_zero(MultiArchCodegen *codegen, const char *label) {
350 switch (codegen->target->arch) {
351 case ARCH_X86_64:
352 multiarch_emit(codegen, " jz %s", label);
353 break;
354 case ARCH_ARM64:
355 multiarch_emit(codegen, " b.eq %s", label);
356 break;
357 default:
358 break;
359 }
360}
361
362void multiarch_jump_if_equal(MultiArchCodegen *codegen, const char *label) {
363 multiarch_jump_if_zero(codegen, label); // Same as jump if zero after compare
364}
365
366void multiarch_jump_if_not_equal(MultiArchCodegen *codegen, const char *label) {
367 switch (codegen->target->arch) {
368 case ARCH_X86_64:
369 multiarch_emit(codegen, " jnz %s", label);
370 break;
371 case ARCH_ARM64:
372 multiarch_emit(codegen, " b.ne %s", label);
373 break;
374 default:
375 break;
376 }
377}
378
379void multiarch_jump_if_less(MultiArchCodegen *codegen, const char *label) {
380 switch (codegen->target->arch) {
381 case ARCH_X86_64:
382 multiarch_emit(codegen, " jl %s", label);
383 break;
384 case ARCH_ARM64:
385 multiarch_emit(codegen, " b.lt %s", label);
386 break;
387 default:
388 break;
389 }
390}
391
392void multiarch_jump_if_greater(MultiArchCodegen *codegen, const char *label) {
393 switch (codegen->target->arch) {
394 case ARCH_X86_64:
395 multiarch_emit(codegen, " jg %s", label);
396 break;
397 case ARCH_ARM64:
398 multiarch_emit(codegen, " b.gt %s", label);
399 break;
400 default:
401 break;
402 }
403}
404
405void multiarch_function_prologue(MultiArchCodegen *codegen, const char *func_name, int param_count) {
406 codegen->in_function = true;
407 strncpy(codegen->current_function, func_name, sizeof(codegen->current_function) - 1);
408 codegen->local_var_count = 0;
409 codegen->stack_offset = 0;
410
411 // Emit function label
412 if (codegen->target->platform == PLATFORM_MACOS) {
413 multiarch_emit_label(codegen, func_name); // macOS may need underscore prefix
414 } else {
415 multiarch_emit_label(codegen, func_name);
416 }
417
418 switch (codegen->target->arch) {
419 case ARCH_X86_64:
420 multiarch_emit(codegen, " pushq %%rbp");
421 multiarch_emit(codegen, " movq %%rsp, %%rbp");
422 break;
423 case ARCH_ARM64:
424 case ARCH_ARM64:
425 multiarch_emit(codegen, " stp x29, x30, [sp, #-16]!");
426 multiarch_emit(codegen, " mov x29, sp");
427 break;
428 default:
429 break;
430 }
431}
432
433void multiarch_function_epilogue(MultiArchCodegen *codegen) {
434 switch (codegen->target->arch) {
435 case ARCH_X86_64:
436 multiarch_emit(codegen, " movq %%rbp, %%rsp");
437 multiarch_emit(codegen, " popq %%rbp");
438 multiarch_emit(codegen, " ret");
439 break;
440 case ARCH_ARM64:
441 multiarch_emit(codegen, " ldp x29, x30, [sp], #16");
442 multiarch_emit(codegen, " ret");
443 break;
444 default:
445 break;
446 }
447
448 codegen->in_function = false;
449}
450
451void multiarch_function_return(MultiArchCodegen *codegen, bool has_value) {
452 if (!has_value) {
453 // Set return value to 0 for void functions
454 multiarch_load_immediate(codegen, multiarch_get_return_reg(codegen), 0);
455 }
456 multiarch_function_epilogue(codegen);
457}
458
459void multiarch_function_call(MultiArchCodegen *codegen, const char *func_name, int arg_count) {
460 switch (codegen->target->arch) {
461 case ARCH_X86_64:
462 // Arguments should already be in the right registers
463 multiarch_emit(codegen, " call %s", func_name);
464 // Clean up stack if needed (for arguments passed on stack)
465 if (arg_count > 6) {
466 int stack_cleanup = (arg_count - 6) * 8;
467 multiarch_emit(codegen, " addq $%d, %%rsp", stack_cleanup);
468 }
469 break;
470 case ARCH_ARM64:
471 multiarch_emit(codegen, " bl %s", func_name);
472 break;
473 default:
474 break;
475 }
476}
477
478void multiarch_push(MultiArchCodegen *codegen, const char *reg) {
479 switch (codegen->target->arch) {
480 case ARCH_X86_64:
481 multiarch_emit(codegen, " pushq %%%s", reg);
482 break;
483 case ARCH_ARM64:
484 multiarch_emit(codegen, " str %s, [sp, #-16]!", reg);
485 break;
486 default:
487 break;
488 }
489}
490
491void multiarch_pop(MultiArchCodegen *codegen, const char *reg) {
492 switch (codegen->target->arch) {
493 case ARCH_X86_64:
494 multiarch_emit(codegen, " popq %%%s", reg);
495 break;
496 case ARCH_ARM64:
497 multiarch_emit(codegen, " ldr %s, [sp], #16", reg);
498 break;
499 default:
500 break;
501 }
502}
503
504const char *multiarch_get_param_reg(MultiArchCodegen *codegen, int param_index) {
505 if (param_index < codegen->target->num_param_regs) {
506 return codegen->target->param_regs[param_index];
507 }
508 return NULL; // Parameter passed on stack
509}
510
511const char *multiarch_get_return_reg(MultiArchCodegen *codegen) {
512 return codegen->target->return_regs[0];
513}
514
515const char *multiarch_get_temp_reg(MultiArchCodegen *codegen, int index) {
516 switch (codegen->target->arch) {
517 case ARCH_X86_64:
518 switch (index) {
519 case 0: return "r10";
520 case 1: return "r11";
521 default: return "rax";
522 }
523 case ARCH_ARM64:
524 switch (index) {
525 case 0: return "x9";
526 case 1: return "x10";
527 case 2: return "x11";
528 default: return "x0";
529 }
530 default:
531 return "unknown";
532 }
533}
534
535const char *multiarch_get_stack_pointer(MultiArchCodegen *codegen) {
536 switch (codegen->target->arch) {
537 case ARCH_X86_64:
538 return "rsp";
539 case ARCH_ARM64:
540 return "sp";
541 default:
542 return "unknown";
543 }
544}
545
546const char *multiarch_get_frame_pointer(MultiArchCodegen *codegen) {
547 switch (codegen->target->arch) {
548 case ARCH_X86_64:
549 return "rbp";
550 case ARCH_ARM64:
551 return "x29";
552 default:
553 return "unknown";
554 }
555}
556
557void multiarch_load_memory(MultiArchCodegen *codegen, const char *dest_reg, const char *src_addr, int size) {
558 switch (codegen->target->arch) {
559 case ARCH_X86_64:
560 if (size == 8) {
561 multiarch_emit(codegen, " movq %s, %%%s", src_addr, dest_reg);
562 } else if (size == 4) {
563 multiarch_emit(codegen, " movl %s, %%%s", src_addr, dest_reg);
564 } else if (size == 1) {
565 multiarch_emit(codegen, " movb %s, %%%s", src_addr, dest_reg);
566 }
567 break;
568 case ARCH_ARM64:
569 if (size == 8) {
570 multiarch_emit(codegen, " ldr %s, %s", dest_reg, src_addr);
571 } else if (size == 4) {
572 multiarch_emit(codegen, " ldr w%s, %s", dest_reg + 1, src_addr); // w register for 32-bit
573 } else if (size == 1) {
574 multiarch_emit(codegen, " ldrb w%s, %s", dest_reg + 1, src_addr);
575 }
576 break;
577 default:
578 break;
579 }
580}
581
582void multiarch_store_memory(MultiArchCodegen *codegen, const char *src_reg, const char *dest_addr, int size) {
583 switch (codegen->target->arch) {
584 case ARCH_X86_64:
585 if (size == 8) {
586 multiarch_emit(codegen, " movq %%%s, %s", src_reg, dest_addr);
587 } else if (size == 4) {
588 multiarch_emit(codegen, " movl %%%s, %s", src_reg, dest_addr);
589 } else if (size == 1) {
590 multiarch_emit(codegen, " movb %%%s, %s", src_reg, dest_addr);
591 }
592 break;
593 case ARCH_ARM64:
594 if (size == 8) {
595 multiarch_emit(codegen, " str %s, %s", src_reg, dest_addr);
596 } else if (size == 4) {
597 multiarch_emit(codegen, " str w%s, %s", src_reg + 1, dest_addr);
598 } else if (size == 1) {
599 multiarch_emit(codegen, " strb w%s, %s", src_reg + 1, dest_addr);
600 }
601 break;
602 default:
603 break;
604 }
605}
606
607void multiarch_syscall(MultiArchCodegen *codegen, int syscall_num, int arg_count) {
608 multiarch_load_immediate(codegen, codegen->target->syscall_reg, syscall_num);
609 multiarch_emit(codegen, " %s", codegen->target->syscall_instruction);
610}
611
612void multiarch_exit_program(MultiArchCodegen *codegen, int exit_code) {
613 const char *return_reg = multiarch_get_return_reg(codegen);
614 multiarch_load_immediate(codegen, return_reg, exit_code);
615
616 switch (codegen->target->platform) {
617 case PLATFORM_LINUX:
618 if (codegen->target->arch == ARCH_X86_64) {
619 multiarch_syscall(codegen, 60, 1); // sys_exit on Linux x86_64
620 } else if (codegen->target->arch == ARCH_ARM64) {
621 multiarch_syscall(codegen, 93, 1); // sys_exit on Linux ARM64
622 }
623 break;
624 case PLATFORM_MACOS:
625 if (codegen->target->arch == ARCH_X86_64) {
626 multiarch_syscall(codegen, 0x2000001, 1); // sys_exit on macOS x86_64
627 } else if (codegen->target->arch == ARCH_ARM64) {
628 multiarch_syscall(codegen, 1, 1); // sys_exit on macOS ARM64
629 }
630 break;
631 default:
632 break;
633 }
634}
635
636char *multiarch_new_label(MultiArchCodegen *codegen) {
637 char *label = malloc(32);
638 snprintf(label, 32, "L%d", codegen->label_counter++);
639 return label;
640}
641
642char *multiarch_new_temp(MultiArchCodegen *codegen) {
643 char *temp = malloc(32);
644 snprintf(temp, 32, "t%d", codegen->temp_counter++);
645 return temp;
646}
647
648void multiarch_declare_local_var(MultiArchCodegen *codegen, const char *name, int size) {
649 if (codegen->local_var_count >= 256) return;
650
651 // Align to proper boundary
652 int alignment = (size >= 8) ? 8 : size;
653 codegen->stack_offset = (codegen->stack_offset + alignment - 1) & ~(alignment - 1);
654 codegen->stack_offset += size;
655
656 // Store variable info
657 strncpy(codegen->local_vars[codegen->local_var_count].name, name, 63);
658 codegen->local_vars[codegen->local_var_count].name[63] = '\0';
659 codegen->local_vars[codegen->local_var_count].offset = -codegen->stack_offset;
660 codegen->local_vars[codegen->local_var_count].size = size;
661 codegen->local_var_count++;
662}
663
664int multiarch_get_local_var_offset(MultiArchCodegen *codegen, const char *name) {
665 for (int i = 0; i < codegen->local_var_count; i++) {
666 if (strcmp(codegen->local_vars[i].name, name) == 0) {
667 return codegen->local_vars[i].offset;
668 }
669 }
670 return 0; // Not found
671}
672
673void multiarch_load_local_var(MultiArchCodegen *codegen, const char *dest_reg, const char *var_name) {
674 int offset = multiarch_get_local_var_offset(codegen, var_name);
675 const char *fp = multiarch_get_frame_pointer(codegen);
676
677 switch (codegen->target->arch) {
678 case ARCH_X86_64:
679 multiarch_emit(codegen, " movq %d(%%%s), %%%s", offset, fp, dest_reg);
680 break;
681 case ARCH_ARM64:
682 multiarch_emit(codegen, " ldr %s, [%s, #%d]", dest_reg, fp, offset);
683 break;
684 default:
685 break;
686 }
687}
688
689void multiarch_store_local_var(MultiArchCodegen *codegen, const char *src_reg, const char *var_name) {
690 int offset = multiarch_get_local_var_offset(codegen, var_name);
691 const char *fp = multiarch_get_frame_pointer(codegen);
692
693 switch (codegen->target->arch) {
694 case ARCH_X86_64:
695 multiarch_emit(codegen, " movq %%%s, %d(%%%s)", src_reg, offset, fp);
696 break;
697 case ARCH_ARM64:
698 multiarch_emit(codegen, " str %s, [%s, #%d]", src_reg, fp, offset);
699 break;
700 default:
701 break;
702 }
703}
704
705// ===== AST CODE GENERATION =====
706
707bool multiarch_codegen_generate(MultiArchCodegen *codegen, struct ASTNode *ast) {
708 if (!codegen || !ast) return false;
709
710 // Emit header
711 multiarch_emit_comment(codegen, "Generated by KCC Multi-Architecture Compiler");
712 multiarch_emit_comment(codegen, "Target: %s-%s", codegen->target->arch_name, codegen->target->platform_name);
713 multiarch_emit(codegen, "");
714
715 // Emit sections
716 multiarch_emit_directive(codegen, codegen->target->section_text, NULL);
717 multiarch_emit(codegen, "");
718
719 // Generate code for the AST
720 multiarch_codegen_program(codegen, ast);
721
722 // Add program entry point
723 if (codegen->target->platform == PLATFORM_LINUX) {
724 multiarch_emit(codegen, "");
725 multiarch_emit_directive(codegen, codegen->target->global_directive, "_start");
726 multiarch_emit_label(codegen, "_start");
727 multiarch_function_call(codegen, "main", 0);
728 multiarch_exit_program(codegen, 0);
729 } else if (codegen->target->platform == PLATFORM_MACOS) {
730 multiarch_emit(codegen, "");
731 multiarch_emit_directive(codegen, codegen->target->global_directive, "_main");
732 // macOS handles entry differently
733 }
734
735 return true;
736}
737
738void multiarch_codegen_program(MultiArchCodegen *codegen, struct ASTNode *node) {
739 if (node->type != AST_PROGRAM) return;
740
741 for (int i = 0; i < node->data.program.declaration_count; i++) {
742 struct ASTNode *decl = node->data.program.declarations[i];
743
744 if (decl->type == AST_FUNCTION_DECL) {
745 multiarch_codegen_function_declaration(codegen, decl);
746 } else if (decl->type == AST_VAR_DECL) {
747 multiarch_codegen_variable_declaration(codegen, decl);
748 }
749 }
750}
751
752void multiarch_codegen_function_declaration(MultiArchCodegen *codegen, struct ASTNode *node) {
753 if (node->type != AST_FUNCTION_DECL) return;
754
755 multiarch_emit(codegen, "");
756 multiarch_emit_comment(codegen, "Function: %s", node->data.function_decl.name);
757
758 // Make function global if it's main or explicitly requested
759 if (strcmp(node->data.function_decl.name, "main") == 0) {
760 if (codegen->target->platform == PLATFORM_MACOS) {
761 multiarch_emit_directive(codegen, codegen->target->global_directive, "_main");
762 } else {
763 multiarch_emit_directive(codegen, codegen->target->global_directive, "main");
764 }
765 }
766
767 multiarch_function_prologue(codegen, node->data.function_decl.name, node->data.function_decl.parameter_count);
768
769 // Allocate space for local variables if needed
770 if (codegen->stack_offset > 0) {
771 multiarch_stack_alloc(codegen, codegen->stack_offset);
772 }
773
774 // Generate function body
775 if (node->data.function_decl.body) {
776 multiarch_codegen_statement(codegen, node->data.function_decl.body);
777 }
778
779 // Add default return if needed
780 multiarch_function_return(codegen, false);
781}
782
783void multiarch_codegen_variable_declaration(MultiArchCodegen *codegen, struct ASTNode *node) {
784 if (node->type != AST_VAR_DECL) return;
785
786 multiarch_emit_comment(codegen, "Variable: %s", node->data.var_decl.name);
787
788 // For local variables, declare space on stack
789 if (codegen->in_function) {
790 int size = 8; // Default size for int
791 multiarch_declare_local_var(codegen, node->data.var_decl.name, size);
792
793 if (node->data.var_decl.initializer) {
794 // Generate code for initializer
795 multiarch_codegen_expression(codegen, node->data.var_decl.initializer);
796 // Store result in variable
797 multiarch_store_local_var(codegen, multiarch_get_return_reg(codegen), node->data.var_decl.name);
798 }
799 }
800}
801
802void multiarch_codegen_statement(MultiArchCodegen *codegen, struct ASTNode *node) {
803 switch (node->type) {
804 case AST_COMPOUND_STMT:
805 for (int i = 0; i < node->data.compound_stmt.statement_count; i++) {
806 multiarch_codegen_statement(codegen, node->data.compound_stmt.statements[i]);
807 }
808 break;
809
810 case AST_EXPRESSION_STMT:
811 if (node->data.expression_stmt.expression) {
812 multiarch_codegen_expression(codegen, node->data.expression_stmt.expression);
813 }
814 break;
815
816 case AST_RETURN_STMT:
817 multiarch_codegen_return_stmt(codegen, node);
818 break;
819
820 case AST_IF_STMT:
821 multiarch_codegen_if_stmt(codegen, node);
822 break;
823
824 case AST_WHILE_STMT:
825 multiarch_codegen_while_stmt(codegen, node);
826 break;
827
828 case AST_VAR_DECL:
829 multiarch_codegen_variable_declaration(codegen, node);
830 break;
831
832 default:
833 multiarch_emit_comment(codegen, "Unsupported statement type");
834 break;
835 }
836}
837
838void multiarch_codegen_expression(MultiArchCodegen *codegen, struct ASTNode *node) {
839 switch (node->type) {
840 case AST_NUMBER:
841 multiarch_load_immediate(codegen, multiarch_get_return_reg(codegen), node->data.number.value);
842 break;
843
844 case AST_IDENTIFIER:
845 multiarch_load_local_var(codegen, multiarch_get_return_reg(codegen), node->data.identifier.name);
846 break;
847
848 case AST_BINARY_EXPR:
849 multiarch_codegen_binary_expr(codegen, node);
850 break;
851
852 case AST_CALL_EXPR:
853 multiarch_codegen_call_expr(codegen, node);
854 break;
855
856 default:
857 multiarch_emit_comment(codegen, "Unsupported expression type");
858 break;
859 }
860}
861
862void multiarch_codegen_binary_expr(MultiArchCodegen *codegen, struct ASTNode *node) {
863 if (node->type != AST_BINARY_EXPR) return;
864
865 // Generate left operand
866 multiarch_codegen_expression(codegen, node->data.binary_expr.left);
867 multiarch_push(codegen, multiarch_get_return_reg(codegen));
868
869 // Generate right operand
870 multiarch_codegen_expression(codegen, node->data.binary_expr.right);
871 const char *right_reg = multiarch_get_return_reg(codegen);
872 const char *temp_reg = multiarch_get_temp_reg(codegen, 0);
873 multiarch_pop(codegen, temp_reg);
874
875 // Perform operation
876 switch (node->data.binary_expr.operator) {
877 case TOKEN_PLUS:
878 multiarch_add(codegen, right_reg, temp_reg, right_reg);
879 break;
880 case TOKEN_MINUS:
881 multiarch_sub(codegen, right_reg, temp_reg, right_reg);
882 break;
883 case TOKEN_MULTIPLY:
884 multiarch_mul(codegen, right_reg, temp_reg, right_reg);
885 break;
886 case TOKEN_DIVIDE:
887 multiarch_div(codegen, right_reg, temp_reg, right_reg);
888 break;
889 default:
890 multiarch_emit_comment(codegen, "Unsupported binary operator");
891 break;
892 }
893}
894
895void multiarch_codegen_return_stmt(MultiArchCodegen *codegen, struct ASTNode *node) {
896 if (node->data.return_stmt.expression) {
897 multiarch_codegen_expression(codegen, node->data.return_stmt.expression);
898 }
899 multiarch_function_return(codegen, node->data.return_stmt.expression != NULL);
900}
901
902void multiarch_codegen_call_expr(MultiArchCodegen *codegen, struct ASTNode *node) {
903 if (node->type != AST_CALL_EXPR) return;
904
905 // Generate arguments and place in parameter registers
906 for (int i = 0; i < node->data.call_expr.argument_count && i < codegen->target->num_param_regs; i++) {
907 multiarch_codegen_expression(codegen, node->data.call_expr.arguments[i]);
908 const char *param_reg = multiarch_get_param_reg(codegen, i);
909 const char *return_reg = multiarch_get_return_reg(codegen);
910
911 if (strcmp(param_reg, return_reg) != 0) {
912 // Move result to parameter register
913 switch (codegen->target->arch) {
914 case ARCH_X86_64:
915 multiarch_emit(codegen, " movq %%%s, %%%s", return_reg, param_reg);
916 break;
917 case ARCH_ARM64:
918 multiarch_emit(codegen, " mov %s, %s", param_reg, return_reg);
919 break;
920 default:
921 break;
922 }
923 }
924 }
925
926 multiarch_function_call(codegen, node->data.call_expr.function_name, node->data.call_expr.argument_count);
927}
928
929void multiarch_codegen_if_stmt(MultiArchCodegen *codegen, struct ASTNode *node) {
930 if (node->type != AST_IF_STMT) return;
931
932 char *else_label = multiarch_new_label(codegen);
933 char *end_label = multiarch_new_label(codegen);
934
935 // Generate condition
936 multiarch_codegen_expression(codegen, node->data.if_stmt.condition);
937
938 // Test result and jump to else if false
939 const char *return_reg = multiarch_get_return_reg(codegen);
940 switch (codegen->target->arch) {
941 case ARCH_X86_64:
942 multiarch_emit(codegen, " testq %%%s, %%%s", return_reg, return_reg);
943 break;
944 case ARCH_ARM64:
945 multiarch_emit(codegen, " cmp %s, #0", return_reg);
946 break;
947 default:
948 break;
949 }
950
951 multiarch_jump_if_zero(codegen, else_label);
952
953 // Generate then statement
954 multiarch_codegen_statement(codegen, node->data.if_stmt.then_stmt);
955 multiarch_jump(codegen, end_label);
956
957 // Generate else statement
958 multiarch_emit_label(codegen, else_label);
959 if (node->data.if_stmt.else_stmt) {
960 multiarch_codegen_statement(codegen, node->data.if_stmt.else_stmt);
961 }
962
963 multiarch_emit_label(codegen, end_label);
964
965 free(else_label);
966 free(end_label);
967}
968
969void multiarch_codegen_while_stmt(MultiArchCodegen *codegen, struct ASTNode *node) {
970 if (node->type != AST_WHILE_STMT) return;
971
972 char *loop_label = multiarch_new_label(codegen);
973 char *end_label = multiarch_new_label(codegen);
974
975 multiarch_emit_label(codegen, loop_label);
976
977 // Generate condition
978 multiarch_codegen_expression(codegen, node->data.while_stmt.condition);
979
980 // Test and jump if false
981 const char *return_reg = multiarch_get_return_reg(codegen);
982 switch (codegen->target->arch) {
983 case ARCH_X86_64:
984 multiarch_emit(codegen, " testq %%%s, %%%s", return_reg, return_reg);
985 break;
986 case ARCH_ARM64:
987 multiarch_emit(codegen, " cmp %s, #0", return_reg);
988 break;
989 default:
990 break;
991 }
992
993 multiarch_jump_if_zero(codegen, end_label);
994
995 // Generate body
996 multiarch_codegen_statement(codegen, node->data.while_stmt.body);
997 multiarch_jump(codegen, loop_label);
998
999 multiarch_emit_label(codegen, end_label);
1000
1001 free(loop_label);
1002 free(end_label);
1003}
1004
1005void multiarch_stack_alloc(MultiArchCodegen *codegen, int bytes) {
1006 // Align to stack alignment
1007 bytes = (bytes + codegen->target->stack_alignment - 1) & ~(codegen->target->stack_alignment - 1);
1008
1009 switch (codegen->target->arch) {
1010 case ARCH_X86_64:
1011 multiarch_emit(codegen, " subq $%d, %%rsp", bytes);
1012 break;
1013 case ARCH_ARM64:
1014 multiarch_emit(codegen, " sub sp, sp, #%d", bytes);
1015 break;
1016 default:
1017 break;
1018 }
1019}
1020
1021void multiarch_stack_dealloc(MultiArchCodegen *codegen, int bytes) {
1022 // Align to stack alignment
1023 bytes = (bytes + codegen->target->stack_alignment - 1) & ~(codegen->target->stack_alignment - 1);
1024
1025 switch (codegen->target->arch) {
1026 case ARCH_X86_64:
1027 multiarch_emit(codegen, " addq $%d, %%rsp", bytes);
1028 break;
1029 case ARCH_ARM64:
1030 multiarch_emit(codegen, " add sp, sp, #%d", bytes);
1031 break;
1032 default:
1033 break;
1034 }
1035}
AST Node structure.
Definition types.h:333