From bc7232449b404727fc2fbf752ec753dee9ecc800 Mon Sep 17 00:00:00 2001 From: SantriptaSharma Date: Thu, 7 Dec 2023 17:03:51 +0530 Subject: [PATCH] arithmetic operations (a5) --- .gitignore | 2 + 15_A5_translator.c | 11 +- A4_tests/testthing.nc | 4 +- Makefile | 8 +- compiler.c | 261 +++++++++++++++++++++++++++++++++++++++++- compiler.h | 1 + compilertest.nc | 6 + test.asm | 155 ------------------------- 8 files changed, 279 insertions(+), 169 deletions(-) create mode 100644 compilertest.nc delete mode 100644 test.asm diff --git a/.gitignore b/.gitignore index 1ac2fee..2fe8d4e 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,8 @@ lexer.c parser.c *.tab.* *.o +*.asm +*.s #debugger files counterexamples diff --git a/15_A5_translator.c b/15_A5_translator.c index 24b7654..5777b8c 100644 --- a/15_A5_translator.c +++ b/15_A5_translator.c @@ -757,7 +757,7 @@ int main(int argc, const char *argv[]) { char *out_filename = malloc(filename_len + 5); char *asm_filename = malloc(filename_len + 5); sprintf(out_filename, "%s.out", argv[1]); - sprintf(asm_filename, "%s.asm", argv[1]); + sprintf(asm_filename, "%s.s", argv[1]); FILE *quads_file = fopen(out_filename, "w"); free(out_filename); @@ -809,14 +809,11 @@ int main(int argc, const char *argv[]) { WriteDataSeg(file); // generate entry point, emit all global instructions - fprintf(file, ".text\n"); - fprintf(file, ".global main\n"); - WriteEntryPoint(file); + WriteFunctions(file); - // TODO: generate asm from quads - - // TODO: write asm to file + // GAS syntax requires ending the file with a newline, not EOF + fprintf(file, "\n"); fclose(file); FreeTables(); diff --git a/A4_tests/testthing.nc b/A4_tests/testthing.nc index 74ebaf3..2eaadca 100644 --- a/A4_tests/testthing.nc +++ b/A4_tests/testthing.nc @@ -1,7 +1,7 @@ -int a = 5 + 3 + "garbo king"; +int a = 5 + 3; int *d = a + 5; int *make_fib_list(int a, int b, int n); -int b = 110 + 'c' + "garbo king" + a; +int b = 110 + 'c' + a; void garbo(); char c = (d[10] + 12) * 32 - 3 * 4 * "okiii"; void garbo(); \ No newline at end of file diff --git a/Makefile b/Makefile index f2e4180..b141c7f 100644 --- a/Makefile +++ b/Makefile @@ -2,6 +2,7 @@ CC=gcc l=flex yy=bison CFLAGS=-Werror -lfl -g +SFLAGS=-no-pie -g o=compiler lx=lexer @@ -34,6 +35,11 @@ $(lx).c: $(fname).l $(fname).tab.c %.o: %.c $(CC) -c $^ $(CFLAGS) +test: build + ./$(o) test < compilertest.nc + gcc -c test.s $(SFLAGS) + gcc -o testexec test.o $(SFLAGS) + clean: rm -rf $(o) rm -rf $(o).exe @@ -41,4 +47,4 @@ clean: rm -rf *.o rm -rf $(fname).tab.* -.PHONY: default clean build lex \ No newline at end of file +.PHONY: default clean build lex test \ No newline at end of file diff --git a/compiler.c b/compiler.c index 7cd38a7..1ed32f7 100644 --- a/compiler.c +++ b/compiler.c @@ -4,6 +4,8 @@ #include "compiler.h" +#define MAX(a, b) ((a) > (b) ? (a) : (b)) + const char *CONST_DIRECTIVES[] = { [1] = ".byte", [2] = ".short", @@ -11,7 +13,7 @@ const char *CONST_DIRECTIVES[] = { [8] = ".quad" }; -static void WriteConstSym(Symbol *sym, FILE *file) { +static void WriteGlobalSym(Symbol *sym, FILE *file) { static int strings_count = 0; if (!sym->is_temp && sym->type.kind != ARRAY_T) { @@ -21,6 +23,7 @@ static void WriteConstSym(Symbol *sym, FILE *file) { switch (sym->type.kind) { case PRIMITIVE_T: case PRIMITIVE_PTR: + if (sym->initial_value != 0) { break; } // will be a literal in the assembly code fprintf(file, "%s:\n\t%s %d\n", sym->name, CONST_DIRECTIVES[sym->size], sym->initial_value); break; @@ -59,7 +62,7 @@ void WriteDataSeg(FILE *file) { while (sym != NULL) { if (sym->type.kind != FUNC_T) { - WriteConstSym(sym, file); + WriteGlobalSym(sym, file); } else { if (strcmp(sym->name, "main") == 0) { char *main_label = malloc(strlen(sym->name) + 2); @@ -134,8 +137,241 @@ static void FindQuadExtents() { ext_count = next; } +static const char postfixes[] = { + [1] = 'b', [2] = 'w', [4] = 'l', [8] = 'q' +}; + +static const char movpostfix[] = { + [1] = 'l', [2] = 'l', [4] = 'l', [8] = 'q' +}; + +static const char regprefixes[] = { + [1] = 'e', [4] = 'e', [8] = 'r' +}; + +static const char *arithmetic_ops[] ={ + [ADD] = "add", + [SUB] = "sub", + [MUL] = "imul", + [DIV] = "idiv", + [MOD] = "idiv" +}; + +// holds context for the current function being translated +struct { + int argc; + // + int argstartoff; + int localsoff; +} func_context; + +static void TranslateOperand(Addr a, FILE *file) { + switch (a.kind) { + case SYMBOL_A: + if (a.sym->initial_value != 0) { + fprintf(file, "$%d", a.sym->initial_value); + return; + } + + // check for string + if (a.sym->type.kind == ARRAY_T && a.sym->type.array.base == CHAR_T) { + size_t it = 0; + const char *pref = "__str_"; + + while (a.sym->name[it] == pref[it]) { + it++; + } + + if (pref[it] == '\0') { + fprintf(file, "$_user_string_%d", a.sym->initial_value); + return; + } + } + + if(current_table == &glb_table) { + fprintf(file, "%s", a.sym->name); + return; + } + + // check if symbol in glb table, if so, use variable + + // otherwise, check if symbol is a parameter, if so, use +offset(%rbp) + + // otherwise, use -offset(%rbp) + break; + + case IMMEDIATE: + fprintf(file, "$%d", a.imm); + break; + } +} + +static void LoadBinOps(Quad q, FILE *file) { + size_t sd = q.rd.sym->size; + size_t ss = q.rs.sym->size; + size_t st = q.rt.sym->size; + + // for sign extension char -> 32/64 requires movsx, int -> 64 requires movsxd + const char *extension_instr = q.rs.sym->initial_value == 0 ? + (ss == 1 ? "movsx" : "movsxd") + : "mov"; + // sorry + + if (q.opcode == DIV || q.opcode == MOD) { + fprintf(file, "xor %%rdx, %%rdx\n\t"); + fprintf(file, "%s ", extension_instr); + TranslateOperand(q.rs, file); + fprintf(file, ", %%rax\n\t"); + + extension_instr = q.rt.sym->initial_value == 0 ? + (st == 1 ? "movsx" : "movsxd") + : "mov"; + + fprintf(file, "%s ", extension_instr); + TranslateOperand(q.rt, file); + fprintf(file, ", %%%cbx\n\t", regprefixes[st]); + return; + } + + fprintf(file, "mov%c ", movpostfix[ss]); + TranslateOperand(q.rs, file); + fprintf(file, ", %%%cax\n\t", regprefixes[ss]); + + // sign extension + + if (ss < sd && q.rs.sym->initial_value == 0) { + fprintf(file, "%s %%%cax, %%%cax\n\t", extension_instr, regprefixes[ss], regprefixes[sd]); + } + + fprintf(file, "mov%c ", movpostfix[st]); + TranslateOperand(q.rt, file); + fprintf(file, ", %%%cbx\n\t", regprefixes[st]); + + if (st < sd && q.rt.sym->initial_value == 0) { + extension_instr = st == 1 ? "movsx" : "movsxd"; + + fprintf(file, "%s %%%cbx, %%%cbx\n\t", extension_instr, regprefixes[st], regprefixes[sd]); + } +} + static void TranslateQuad(Quad q, FILE *file, SymbolTable *tab) { + SymbolTable *saved = current_table; + current_table = tab; + + switch (q.opcode) { + size_t sd, ss, st; + + case ADD: + case SUB: + case MUL: + case DIV: + case MOD: + sd = q.rd.sym->size; + ss = q.rs.sym->size; + st = q.rt.sym->size; + + // first we get the operands in rbx/ebx and rax/eax respectively (except for division, where it's flipped) + LoadBinOps(q, file); + // size for the operation + int size = MAX(q.rs.sym->size, q.rt.sym->size); + + // now we perform the operation + + if (q.opcode == DIV || q.opcode == MOD) { + fprintf(file, "idiv %%%cbx\n\t", regprefixes[st]); + + if (q.opcode == DIV) { + fprintf(file, "mov%c %%rax, ", movpostfix[sd]); + TranslateOperand(q.rd, file); + fprintf(file, "\n\t"); + } else { + fprintf(file, "mov%c %%rdx, ", movpostfix[sd]); + TranslateOperand(q.rd, file); + fprintf(file, "\n\t"); + } + break; + } + fprintf(file, "%s%c %%%cbx, %%%cax\n\t", arithmetic_ops[q.opcode], postfixes[size], regprefixes[sd], regprefixes[sd]); + + // now we store the result + fprintf(file, "mov%c %%%cax, ", movpostfix[sd], regprefixes[sd]); + TranslateOperand(q.rd, file); + break; + + case ADDR: + case DEREF: + break; + + case NEG: + case POS: + fprintf(file, "%s%c\t", q.opcode == NEG ? "neg" : "not", postfixes[q.rd.sym->size]); + TranslateOperand(q.rs, file); + break; + + case JMP: + + break; + + case JIF: + case JNT: + break; + + case JLT: + case JLE: + break; + + case JGT: + case JGE: + break; + + case JEQ: + case JNE: + break; + + case MOV: + sd = q.rd.sym->size; + ss = q.rs.sym->size; + + if (strcmp(q.rd.sym->name, "__retval") == 0) { + fprintf(file, "mov%c ", movpostfix[sd]); + TranslateOperand(q.rs, file); + fprintf(file, ", %%%cax", regprefixes[sd]); + break; + } + + fprintf(file, "mov%c ", movpostfix[sd]); + TranslateOperand(q.rs, file); + fprintf(file, ", %%%cbx\n\t", regprefixes[sd]); + fprintf(file, "mov%c %%%cbx, ", movpostfix[sd], regprefixes[sd]); + TranslateOperand(q.rd, file); + break; + + case INDR: + case INDW: + break; + + case PTRW: + break; + + case FN_LABEL: + fprintf(file, "%s:\n", q.rd.sym->name); + break; + + case RET: + fprintf(file, "ret\n"); + break; + + case PAR: + + break; + + case CAL: + fprintf(file, "call %s\n", q.rd.sym->name); + break; + } + + current_table = saved; } void WriteEntryPoint(FILE *file) { @@ -156,9 +392,11 @@ void WriteEntryPoint(FILE *file) { // first, write the external quad blocks for (int i = 0; i < ext_count; i++) { for (int j = ext_quad_blocks[i].start; j <= ext_quad_blocks[i].end; j++) { - fprintf(file, "\t"); + fprintf(file, "#\t"); + DisplayQuad(quads[j], file); + fprintf(file, "\n\t"); TranslateQuad(quads[j], file, &glb_table); - fprintf(file, "\n"); + fprintf(file, "\n\n"); } } @@ -166,4 +404,19 @@ void WriteEntryPoint(FILE *file) { // jump to nanoC file's entry point, main, now called _main fprintf(file, "\tcall _main\n"); + + // when _main returns, exit w exit code returned by main (in eax) + fprintf(file, "\texit_loop:\n"); + fprintf(file, "\tmovl %%eax, %%ebx\n"); + fprintf(file, "\tmovl $0x1, %%eax\n"); + fprintf(file, "\tint $0x80\n"); + fprintf(file, "\tjmp exit_loop\n"); +} + +void WriteFunction(FILE *file) { + +} + +void WriteFunctions(FILE *file) { + } \ No newline at end of file diff --git a/compiler.h b/compiler.h index 49e7e73..b14511d 100644 --- a/compiler.h +++ b/compiler.h @@ -4,5 +4,6 @@ void WriteDataSeg(FILE *file); void WriteEntryPoint(FILE *file); +void WriteFunctions(FILE *file); #endif \ No newline at end of file diff --git a/compilertest.nc b/compilertest.nc new file mode 100644 index 0000000..e5a38d2 --- /dev/null +++ b/compilertest.nc @@ -0,0 +1,6 @@ +int d = 38; +int c = d - 14; + +int main() { + return c; +} \ No newline at end of file diff --git a/test.asm b/test.asm deleted file mode 100644 index a47354f..0000000 --- a/test.asm +++ /dev/null @@ -1,155 +0,0 @@ -.data -__t_0_: - .quad 1 -.global GLOB -GLOB: - .long 0 -__t_1_: - .quad 99 -.global POPPING_thing -POPPING_thing: - .byte 0 -__t_2_: - .quad 100 -__t_3_: - .quad 0 -__t_4_: - .quad 99 -__t_5_: - .quad 0 -.global charithmetic -charithmetic: - .byte 0 -__t_6_: - .quad 100 -__t_7_: - .quad 0 -.global ithmetic2 -ithmetic2: - .byte 0 -__t_8_: - .quad 5 -__t_9_: - .quad 0 -.global arithmetic -arithmetic: - .long 0 -__t_10_: - .quad 99 -__t_11_: - .quad 99 -.global d -d: - .byte 0 -__t_12_: - .quad 102 -__t_13_: - .quad -102 -.global f -f: - .byte 0 -__t_14_: - .quad 0 -.global thing -thing: - .quad 0 -.global printf -__t_15_: - .quad 5 -__t_16_: - .quad 3 -__t_17_: - .quad 8 -_user_string_0: - .string "garbo king" -__t_18_: - .quad 0 -.global a -a: - .long 0 -__t_19_: - .quad 5 -__t_20_: - .quad 0 -.global e -e: - .quad 0 -.global make_fib_list -__t_21_: - .quad 110 -__t_22_: - .quad 99 -__t_23_: - .quad 209 -__t_24_: - .quad 0 -__t_25_: - .quad 0 -.global b -b: - .long 0 -.global garbo -__t_26_: - .quad 10 -.global e__ind_27_ -e__ind_27_: - .long 0 -__t_28_: - .quad 12 -__t_29_: - .quad 0 -__t_30_: - .quad 32 -__t_31_: - .quad 0 -__t_32_: - .quad 3 -__t_33_: - .quad 4 -__t_34_: - .quad 12 -_user_string_1: - .string "okiii" -__t_35_: - .quad 0 -__t_36_: - .quad 0 -.global c -c: - .byte 0 -.global _main -_user_string_2: - .string "%d, " -.text -.global main -.text -.global main -main: - - - - - - - - - - - - - - - - - - - - - - - - - - - - call _main