diff --git a/A4/test b/A4/test new file mode 100755 index 0000000..749ea35 --- /dev/null +++ b/A4/test @@ -0,0 +1,114 @@ +testdir="tests" + + +if [ ! -d "$testdir" ]; +then + echo "No directory named $testdir" + exit +fi + +make + +nodiff=true +stopondiff=false +#ignore these for now + +for filename in "$testdir"/*.c; do + + ./mysclp -icode "$filename" 2>"$filename.myerr" + mv "$filename.spim" "$filename.myspim" + mv "$filename.ic" "$filename.myic" + + ./sclp -icode "$filename" 2>"$filename.err" + DIFF1=$(diff "$filename.spim" "$filename.myspim") + DIFF2=$(diff "$filename.err" "$filename.myerr") + + DIFF3=$(diff "$filename.ic" "$filename.myic") + + + + + ./mysclp -tokens -ast -symtab -eval "$filename" 2> /dev/null + mv "$filename.eval" "$filename.myeval" + mv "$filename.ast" "$filename.myast" + mv "$filename.sym" "$filename.mysym" + mv "$filename.toks" "$filename.mytoks" + ./sclp -tokens -ast -symtab -eval "$filename" 2> /dev/null + DIFF4=$(diff "$filename.ast" "$filename.myast") + DIFF5=$(diff "$filename.eval" "$filename.myeval") + + DIFF6=$(diff "$filename.toks" "$filename.mytoks") + DIFF7=$(diff "$filename.sym" "$filename.mysym") + + if [ "$DIFF5" != "" ] + then + echo "eval comparison failed on $filename. Did not run further tests (lexicographic ordering)." + echo "Showing diff:" + echo "$DIFF5" + exit + fi + + if [ "$DIFF1" != "" ] + then + echo "spim code comparison failed on $filename. Continuing further tests." + echo "continuing with further tests" + echo "Showing diff:" + echo "$DIFF1" + # exit + fi + + if [ "$DIFF2" != "" ] + then + echo "error message comparison failed on $filename. " + echo "Showing diff:" + echo "$DIFF2" + echo "Continuing with further tests." + echo "" + echo "" + # exit + fi + + # if [ "$DIFF3" != "" ] + # then + # echo "icode comparison failed on $filename. Continuing further tests." + # echo "Showing diff:" + # echo "$DIFF3" + # # exit + # fi + + + if [ "$DIFF4" != "" ] + then + echo "ast comparison failed on $filename. Continuing further tests." + echo "Showing diff:" + echo "$DIFF4" + # exit + fi + + + + if [ "$DIFF6" != "" ] + then + if ! [ -s "$filename.myerr" ] #myerr is empty + then + echo "tokens comparison failed on $filename even though myerr is empty. Did not run further tests (lexicographic ordering)." + exit + fi + echo "tokens comparison failed on $filename, but myerr is non-empty. Continuing tests" + echo "" + # echo "Showing diff:" + # echo "$DIFF6" + # exit + fi + + if [ "$DIFF7" != "" ] + then + echo "symtab comparison failed on $filename. Did not run further tests (lexicographic ordering)." + echo "Showing diff:" + echo "$DIFF7" + exit + fi + + +done +echo "All tests passed!" diff --git a/A5/Makefile b/A5/Makefile new file mode 100644 index 0000000..3951f28 --- /dev/null +++ b/A5/Makefile @@ -0,0 +1,24 @@ +#------------------------------------------------------------------------------ +CPP=g++ +SOURCE=lex.yy.c parser.tab.c ast.cc ast-eval.cc local-environment.cc procedure-eval.cc program-eval.cc ast-compile.cc icode.cc +MYPROGRAM=sclp +MYLIBRARY=$(CURDIR) +LDFLAGS=-Wl,-rpath=$(CURDIR) +CFLAGS=-std=c++0x +FLEX=flex +ALLHEADERS=allheaders.h +BISON=bison +#----------------------------------------------------------------------------- + +all: $(MYPROGRAM) + +$(MYPROGRAM): $(SOURCE) + $(CPP) -include $(ALLHEADERS) -L$(MYLIBRARY) $(CFLAGS) $(LDFLAGS) $(SOURCE) -o $(MYPROGRAM) -lsclpshared -lfl -ly + +lex.yy.c: scanner.l parser.tab.h + $(FLEX) -l --yylineno scanner.l +parser.tab.c parser.tab.h : parser.y + $(BISON) -d parser.y + +clean: + rm -f $(MYPROGRAM) diff --git a/A5/README b/A5/README new file mode 100644 index 0000000..b071b24 --- /dev/null +++ b/A5/README @@ -0,0 +1,60 @@ +This directory contains the following files: + +- allheaders.h.gch which is a pre-compiled header file. +- libsclpshared.so which is a shared object file. +- sclp which is the reference implementation. +- program-eval.cc, procedure-eval.cc to get the flow of interpreter eval option, use of Symbol Table create + function with local environment. +- reg-alloc.cc for register allocation scheme +- Makefile which contains the commands to build your implementation. +- Besides, the following header files are provided ONLY for telling you the + class structure and the member functions whose implementation is provided + in the library. YOU DO NOT NEED TO INCLUDE ANY OF THESE FILES IN YOUR IMPLEMENTATION. + . storetokens.hh contains the declaration of the function which you can call to + store tokens and print them. + . ast.hh + . procedure.hh + . program.hh + . symbol-table.hh + . local-environment.hh + . reg-alloc.hh + . icode.hh +You need to write + - a scanner, + - a parser, + - actions within the scanner and parser to construct Abstract Syntax Trees, + - ast functions, and + - an interperter + - a compiler which generates spim code + for the input program. + + You need to understand the local environment used for evaluation. + + A high level description of the classes can be found on the sclp web page + https://www.cse.iitb.ac.in/~uday/web-source/. + You need to create the top level object for program. + +You should work in the following steps: + + 1. Enhance your implementation of A4 by adding new rules in the scanner and parser for print operator (syntax: print var) + 2. Add code to construct the ASTs for the new constructs. + 3. Add code to generate spim code from ASTs. + +For ease of working on small programs, you can use the -d option to produce the dump on the screen +instead of having to open the dump files. + +For the AST you need to create objects of the following classes: + + - Assignment_Ast, + - Name_Ast, + - Number_Ast, + - Arithmetic_Expr_Ast (and its derived classes) + - Selection_Statement_Ast + - Relational_Expr_Ast + - Logical_Expr_Ast + - COnditional_Op_Ast + - Iterative_Statement_Ast + - Sequence_Statement_Ast + - Print_Ast + +You will need to submit ONLY the scanner.l, parser.y, ast.cc, local-environment.cc, ast-eval.cc, ast-compile.cc, and icode.cc files. diff --git a/A5/allheaders.h.gch b/A5/allheaders.h.gch new file mode 100644 index 0000000..ab2db12 Binary files /dev/null and b/A5/allheaders.h.gch differ diff --git a/A5/ast.hh b/A5/ast.hh new file mode 100644 index 0000000..90a805e --- /dev/null +++ b/A5/ast.hh @@ -0,0 +1,365 @@ + +#ifndef AST_HH +#define AST_HH + +#include +#include +#include +#include +#include + +#define AST_SPACE " " +#define AST_NODE_SPACE " " +#define AST_SUB_NODE_SPACE " " + +#define END_OF_PROG -3 +// Used by goto_ast and basic_block + +using namespace std; + +class Ast; + +class Ast +{ +protected: + typedef enum + { + zero_arity = 0, + unary_arity = 1, + binary_arity = 2, + ternary_arity = 3 + }Ast_Arity; + + Data_Type node_data_type; + Ast_Arity ast_num_child; + + static int labelCounter; + int lineno; + string get_new_label(){ + + return "label"+to_string(labelCounter++); + } + +public: + Ast(); + ~Ast(); + + virtual Data_Type get_data_type(); + virtual void set_data_type(Data_Type dt); + + virtual bool is_value_zero(); + + virtual bool check_ast(); + virtual Symbol_Table_Entry & get_symbol_entry(); + + virtual void print(ostream & file_buffer) = 0; + virtual void print_value(Local_Environment & eval_env, ostream & file_buffer); + + virtual Eval_Result & get_value_of_evaluation(Local_Environment & eval_env); + virtual void set_value_of_evaluation(Local_Environment & eval_env, Eval_Result & result); + virtual Eval_Result & evaluate(Local_Environment & eval_env, ostream & file_buffer) = 0; + + virtual Code_For_Ast & compile() = 0; + virtual Code_For_Ast & compile_and_optimize_ast(Lra_Outcome & lra) = 0; + virtual Code_For_Ast & create_store_stmt(Register_Descriptor * store_register); +}; + +class Assignment_Ast:public Ast +{ + Ast * lhs; + Ast * rhs; + +public: + Assignment_Ast(Ast * temp_lhs, Ast * temp_rhs, int line); + ~Assignment_Ast(); + + bool check_ast(); + + void print(ostream & file_buffer); + + Eval_Result & evaluate(Local_Environment & eval_env, ostream & file_buffer); + + Code_For_Ast & compile(); + Code_For_Ast & compile_and_optimize_ast(Lra_Outcome & lra); +}; + +class Name_Ast:public Ast +{ + Symbol_Table_Entry * variable_symbol_entry; + +public: + Name_Ast(string & name, Symbol_Table_Entry & var_entry, int line); + ~Name_Ast(); + + Data_Type get_data_type(); + Symbol_Table_Entry & get_symbol_entry(); + void set_data_type(Data_Type dt); + + void print(ostream & file_buffer); + + void print_value(Local_Environment & eval_env, ostream & file_buffer); + Eval_Result & get_value_of_evaluation(Local_Environment & eval_env); + void set_value_of_evaluation(Local_Environment & eval_env, Eval_Result & result); + Eval_Result & evaluate(Local_Environment & eval_env, ostream & file_buffer); + + Code_For_Ast & compile(); + Code_For_Ast & compile_and_optimize_ast(Lra_Outcome & lra); + Code_For_Ast & create_store_stmt(Register_Descriptor * store_register); +}; + +template +class Number_Ast:public Ast +{ + T constant; + +public: + Number_Ast(T number, Data_Type constant_data_type, int line); + ~Number_Ast(); + + Data_Type get_data_type(); + void set_data_type(Data_Type dt); + bool is_value_zero(); + + void print(ostream & file_buffer); + + Eval_Result & evaluate(Local_Environment & eval_env, ostream & file_buffer); + + Code_For_Ast & compile(); + Code_For_Ast & compile_and_optimize_ast(Lra_Outcome & lra); +}; + +class Arithmetic_Expr_Ast:public Ast +{ +protected: + Ast * lhs; + Ast * rhs; + +public: + Arithmetic_Expr_Ast() {} + ~Arithmetic_Expr_Ast() {} + + Data_Type get_data_type(); + void set_data_type(Data_Type dt); + bool check_ast(); + + virtual void print(ostream & file_buffer) = 0; + + virtual Eval_Result & evaluate(Local_Environment & eval_env, ostream & file_buffer) = 0; + + // compile + virtual Code_For_Ast & compile() = 0; + virtual Code_For_Ast & compile_and_optimize_ast(Lra_Outcome & lra) = 0; +}; + +class Plus_Ast:public Arithmetic_Expr_Ast +{ +public: + Plus_Ast(Ast * l, Ast * r, int line); + ~Plus_Ast() {} + + void print(ostream & file_buffer); + + Eval_Result & evaluate(Local_Environment & eval_env, ostream & file_buffer); + + // compile + Code_For_Ast & compile(); + Code_For_Ast & compile_and_optimize_ast(Lra_Outcome & lra); +}; + +class Minus_Ast:public Arithmetic_Expr_Ast +{ +public: + Minus_Ast(Ast * l, Ast * r, int line); + ~Minus_Ast() {} + + void print(ostream & file_buffer); + + Eval_Result & evaluate(Local_Environment & eval_env, ostream & file_buffer); + + // compile + Code_For_Ast & compile(); + Code_For_Ast & compile_and_optimize_ast(Lra_Outcome & lra); +}; + +class Divide_Ast:public Arithmetic_Expr_Ast +{ +public: + Divide_Ast(Ast * l, Ast * r, int line); + ~Divide_Ast() {} + + void print(ostream & file_buffer); + + Eval_Result & evaluate(Local_Environment & eval_env, ostream & file_buffer); + + // compile + Code_For_Ast & compile(); + Code_For_Ast & compile_and_optimize_ast(Lra_Outcome & lra); +}; + +class Mult_Ast:public Arithmetic_Expr_Ast +{ +public: + Mult_Ast(Ast * l, Ast * r, int line); + ~Mult_Ast() {} + + void print(ostream & file_buffer); + + Eval_Result & evaluate(Local_Environment & eval_env, ostream & file_buffer); + + // compile + Code_For_Ast & compile(); + Code_For_Ast & compile_and_optimize_ast(Lra_Outcome & lra); +}; + +class UMinus_Ast:public Arithmetic_Expr_Ast +{ +public: + UMinus_Ast(Ast * l, Ast * r, int line); + ~UMinus_Ast() {} + + void print(ostream & file_buffer); + + Eval_Result & evaluate(Local_Environment & eval_env, ostream & file_buffer); + + // compile + Code_For_Ast & compile(); + Code_For_Ast & compile_and_optimize_ast(Lra_Outcome & lra); +}; + +class Conditional_Expression_Ast: public Arithmetic_Expr_Ast + +{ +protected: + Ast* cond; +public: + Conditional_Expression_Ast(Ast* cond, Ast* l, Ast* r, int line); + ~Conditional_Expression_Ast(); + + void print(ostream & file_buffer); + + Code_For_Ast & compile(); + Eval_Result & evaluate(Local_Environment & eval_env, ostream & file_buffer); + Code_For_Ast & compile_and_optimize_ast(Lra_Outcome & lra){} +}; + +class Return_Ast:public Ast +{ + +public: + Return_Ast(int line); + ~Return_Ast(); + + void print(ostream & file_buffer); + + Eval_Result & evaluate(Local_Environment & eval_env, ostream & file_buffer); + + Code_For_Ast & compile(); + Code_For_Ast & compile_and_optimize_ast(Lra_Outcome & lra); +}; + +class Relational_Expr_Ast:public Ast +{ + Ast * lhs_condition; + Ast * rhs_condition; + Relational_Op rel_op; + +public: + Relational_Expr_Ast(Ast * lhs, Relational_Op rop, Ast * rhs, int line); + ~Relational_Expr_Ast(); + + Data_Type get_data_type(); + void set_data_type(Data_Type dt); + + bool check_ast(); + + void print(ostream & file_buffer); + Code_For_Ast & compile(); + + Eval_Result & evaluate(Local_Environment & eval_env, ostream & file_buffer); + Code_For_Ast & compile_and_optimize_ast(Lra_Outcome & lra){} +}; + +class Logical_Expr_Ast:public Ast +{ + Ast * lhs_op; + Ast * rhs_op; + Logical_Op bool_op; + +public: + Logical_Expr_Ast(Ast * lhs, Logical_Op bop, Ast * rhs, int line); + ~Logical_Expr_Ast(); + + Data_Type get_data_type(); + void set_data_type(Data_Type dt); + + bool check_ast(); + + void print(ostream & file_buffer); + + Code_For_Ast & compile(); + Eval_Result & evaluate(Local_Environment & eval_env, ostream & file_buffer); + Code_For_Ast & compile_and_optimize_ast(Lra_Outcome & lra){} +}; + +class Selection_Statement_Ast: public Ast { +protected: + Ast* cond; + Ast* then_part; + Ast* else_part; +public: + Selection_Statement_Ast(Ast * cond,Ast* then_part, Ast* else_part, int line); + ~Selection_Statement_Ast(); + + Data_Type get_data_type(); + void set_data_type(Data_Type dt); + + bool check_ast(); + + void print(ostream & file_buffer); + + Code_For_Ast & compile(); + Eval_Result & evaluate(Local_Environment & eval_env, ostream & file_buffer); + Code_For_Ast & compile_and_optimize_ast(Lra_Outcome & lra){} +}; + +class Iteration_Statement_Ast: public Ast { +protected: + Ast* cond; + Ast* body; + bool is_do_form; +public: + Iteration_Statement_Ast(Ast * cond, Ast* body, int line, bool do_form); + ~Iteration_Statement_Ast(); + + Data_Type get_data_type(); + void set_data_type(Data_Type dt); + + bool check_ast(); + + void print(ostream & file_buffer); + + Code_For_Ast & compile(); + Eval_Result & evaluate(Local_Environment & eval_env, ostream & file_buffer); + Code_For_Ast & compile_and_optimize_ast(Lra_Outcome & lra){} +}; + + + +class Sequence_Ast: public Ast{ + list statement_list; + list sa_icode_list; +public: + Sequence_Ast(int line); + ~Sequence_Ast(); + void ast_push_back(Ast * ast); + void print(ostream & file_buffer); + Code_For_Ast & compile(); + void print_assembly(ostream & file_buffer); + void print_icode(ostream & file_buffer); + + Eval_Result & evaluate(Local_Environment & eval_env, ostream & file_buffer); + Code_For_Ast & compile_and_optimize_ast(Lra_Outcome & lra){} +}; + + +#endif diff --git a/A5/ex.c b/A5/ex.c new file mode 100644 index 0000000..113e6f9 --- /dev/null +++ b/A5/ex.c @@ -0,0 +1,11 @@ +void main() +{ + int a,b,c; + + c=20; + a=30; + if(c>20) + a=20; + else + b=a+30; +} diff --git a/A5/ex.c.eval b/A5/ex.c.eval new file mode 100644 index 0000000..01206a7 --- /dev/null +++ b/A5/ex.c.eval @@ -0,0 +1,36 @@ +Evaluating Program + Global Variables (before evaluating): + Evaluating Procedure main_ + Local Variables (before evaluating): + a_ : undefined + b_ : undefined + c_ : undefined + + + Asgn: + LHS (Name : c_) + RHS (Num : 20) + c_ : 20 + + + Asgn: + LHS (Name : a_) + RHS (Num : 30) + a_ : 30 + + + Asgn: + LHS (Name : b_) + RHS ( + Arith: PLUS + LHS (Name : a_) + RHS (Num : 30)) + b_ : 60 + + + + Local Variables (after evaluating): + a_ : 30 + b_ : 60 + c_ : 20 + Global Variables (after evaluating): diff --git a/A5/ex.c.spim b/A5/ex.c.spim new file mode 100644 index 0000000..a609a2f --- /dev/null +++ b/A5/ex.c.spim @@ -0,0 +1,38 @@ + + .text # The .text assembler directive indicates + .globl main_ # The following is the code (as oppose to data) +main_: # .globl makes main know to the + # outside of the program. +# Prologue begins + sw $fp, 0($sp) # Save the frame pointer + sub $fp, $sp, 4 # Update the frame pointer + + sub $sp, $sp, 16 # Make space for the locals +# Prologue ends + + li $v0, 20 + sw $v0, -8($fp) + li $v0, 30 + sw $v0, 0($fp) + lw $v0, -8($fp) + li $t0, 20 + sgt $t1, $v0, $t0 + beq $t1, $zero, label0 + li $v0, 20 + sw $v0, 0($fp) + j label1 + +label0: + lw $v0, 0($fp) + li $t0, 30 + add $t2, $v0, $t0 + sw $t2, -4($fp) + +label1: + +# Epilogue Begins + add $sp, $sp, 16 + lw $fp, 0($sp) + jr $31 # Jump back to the operating system. +# Epilogue Ends + diff --git a/A5/icode.hh b/A5/icode.hh new file mode 100644 index 0000000..0cc4620 --- /dev/null +++ b/A5/icode.hh @@ -0,0 +1,338 @@ +#ifndef ICODE_HH +#define ICODE_HH + +#include +#include +#include +#include +#include +#include + +#include"symbol-table.hh" + +/* + This file defines classes for intermediate form of the code generated + by our compiler. It also defined classes for machine instructions. + + An intermediate code (IC) statement consists of an instruction, + possibly two operands and a result. +*/ + +typedef enum +{ /* a: assembly format; r: result; o1: opd1; o2: opd2; op: operator */ + a_op, /* Only the operator, no operand */ + a_op_o1, /* Only one operand, no result, eg. goto L */ + a_op_r, /* Only the result. Operand implicit? */ + a_op_r_o1, /* r <- o1 */ + a_op_o1_r, /* r <- o1 */ + a_op_r_r_o1, /* r <- r op o1 */ + a_op_r_o1_o2, /* r <- o1 op o2 */ + a_op_o1_o2_r, /* r <- o1 op o2 */ + a_op_o1_o2_st, /*for conditional branch*/ + a_op_st, /* label instr */ + a_nsy /* not specified yet */ +} Assembly_Format; + +typedef enum +{ /* i: intermediate format; r: result; o1: opd1; o2: opd2; op: operator */ + i_op, /* Only the operator, no operand */ + i_op_o1, /* Only one operand, no result, eg. goto L */ + i_r_op, /* Only the result. Operand implicit? */ + i_op_o1_r, + i_op_r_o1, + i_r_op_o1, /* r <- o1 */ + i_r_r_op_o1, /* r <- r op o1 */ + i_r_o1_op_o2, /* r <- o1 op o2 */ + i_op_o1_o2_st, /* for conditional branch */ + i_op_st, /* label instr */ + i_nsy /* not specified yet */ +} Icode_Format; + +typedef enum +{ + load, + imm_load, + and_t, + or_t, + not_t, + store, + mfc1, + mtc1, + mov, + add, + sub, + mult, + divd, + uminus, + load_d, + imm_load_d, + store_d, + move_d, + add_d, + sub_d, + mult_d, + div_d, + uminus_d, + slt, + sle, + sgt, + sge, + sne, + seq, + beq, + bne, + bgtz, + bgez, + bltz, + blez, + j, + label, + ret_inst, + nop, + jal +} Tgt_Op; + +///////////////////////// Instruction Descriptor /////////////////////////////////// + +class Instruction_Descriptor +{ + /* + This class stores objects representing machine instructions + which in our case are assembly instructions supported by spim. + */ + + Tgt_Op inst_op; + string mnemonic; + string ic_symbol; /* symbol for printing in intermediate code */ + string name; + Icode_Format ic_format; /* format for printing in intemediate code */ + Assembly_Format assem_format; + +public: + Instruction_Descriptor (Tgt_Op op, string name, string mnn, string ics, Icode_Format icf, Assembly_Format af); + Instruction_Descriptor(); + ~Instruction_Descriptor() {} + + Tgt_Op get_op(); + string get_name(); + string get_mnemonic(); + string get_ic_symbol(); + Icode_Format get_ic_format(); + Assembly_Format get_assembly_format(); + + void print_instruction_descriptor(ostream & file_buffer); +}; + +///////////////////////////// Icode statement operand /////////////////////////////////// + +class Ics_Opd +{ + /* + Abstract base class for ic operands. From this class we + derive classes for three kinds of operands: memory addresses, + constants, and registers + */ + +public: + virtual Register_Descriptor * get_reg(); + + /* Operands are printed differently in icode and assembly code */ + + virtual void print_ics_opd(ostream & file_buffer) = 0; + virtual void print_asm_opd(ostream & file_buffer) = 0; +}; + +class Mem_Addr_Opd:public Ics_Opd +{ + Symbol_Table_Entry * symbol_entry; + +public: + Mem_Addr_Opd(Symbol_Table_Entry & se); + ~Mem_Addr_Opd() {} + + void print_ics_opd(ostream & file_buffer); + void print_asm_opd(ostream & file_buffer); + + Mem_Addr_Opd & operator= (const Mem_Addr_Opd & rhs); +}; + +class Register_Addr_Opd: public Ics_Opd +{ + Register_Descriptor * register_description; + +public: + Register_Addr_Opd(Register_Descriptor * rd); + ~Register_Addr_Opd() {} + + Register_Descriptor * get_reg(); + void print_ics_opd(ostream & file_buffer); + void print_asm_opd(ostream & file_buffer); + + Register_Addr_Opd & operator=(const Register_Addr_Opd & rhs); +}; + +template +class Const_Opd: public Ics_Opd +{ + T num; + +public: + Const_Opd (T num); + ~Const_Opd() {} + + void print_ics_opd(ostream & file_buffer); + void print_asm_opd(ostream & file_buffer); + + Const_Opd & operator=(const Const_Opd & rhs); +}; + +///////////////////////////////// Intermediate code statements ////////////////////////// + +class Icode_Stmt +{ + /* + Abstract base class for generated ic statements. From this + class, we derive three classes: move, compute, control_Flow. + In this version, we need move sub class only + */ + +protected: + Instruction_Descriptor op_desc; + +public: + Icode_Stmt() {} + ~Icode_Stmt() {} + + Instruction_Descriptor & get_op(); + virtual Ics_Opd * get_opd1(); + virtual Ics_Opd * get_opd2(); + virtual Ics_Opd * get_result(); + + virtual void set_opd1(Ics_Opd * io); + virtual void set_opd2(Ics_Opd * io); + virtual void set_result(Ics_Opd * io); + + virtual void print_icode(ostream & file_buffer) = 0; + virtual void print_assembly(ostream & file_buffer) = 0; +}; + +class Move_IC_Stmt: public Icode_Stmt +{ + Ics_Opd * opd1; + Ics_Opd * result; + +public: + Move_IC_Stmt(Tgt_Op inst_op, Ics_Opd * opd1, Ics_Opd * result); + ~Move_IC_Stmt() {} + Move_IC_Stmt & operator=(const Move_IC_Stmt & rhs); + + Instruction_Descriptor & get_inst_op_of_ics(); + + Ics_Opd * get_opd1(); + void set_opd1(Ics_Opd * io); + + Ics_Opd * get_result(); + void set_result(Ics_Opd * io); + + void print_icode(ostream & file_buffer); + void print_assembly(ostream & file_buffer); +}; + + +// TODO -> write code for other Icode_Stmt derived classes +class Compute_IC_Stmt: public Icode_Stmt +{ + Ics_Opd * opd1; + Ics_Opd * opd2; + Ics_Opd * result; + +public: + Compute_IC_Stmt(Tgt_Op inst_op, Ics_Opd * opd1, Ics_Opd * opd2, Ics_Opd * result); + ~Compute_IC_Stmt() {} + Compute_IC_Stmt & operator=(const Compute_IC_Stmt & rhs); + + Instruction_Descriptor & get_inst_op_of_ics(); + + Ics_Opd * get_opd1(); + void set_opd1(Ics_Opd * io); + + Ics_Opd * get_opd2(); + void set_opd2(Ics_Opd * io); + + Ics_Opd * get_result(); + void set_result(Ics_Opd * io); + + void print_icode(ostream & file_buffer); + void print_assembly(ostream & file_buffer); +}; + +class Control_Flow_IC_Stmt: public Icode_Stmt +{ + Ics_Opd * opd1; + string label; + +public: + Control_Flow_IC_Stmt(Tgt_Op inst_op, Ics_Opd * opd1, string label); + ~Control_Flow_IC_Stmt() {} + Control_Flow_IC_Stmt & operator=(const Control_Flow_IC_Stmt & rhs); + + Instruction_Descriptor & get_inst_op_of_ics(); + + Ics_Opd * get_opd1(); + void set_opd1(Ics_Opd * io); + + string get_label(); + void set_label(string label); + + void print_icode(ostream & file_buffer); + void print_assembly(ostream & file_buffer); +}; + +class Label_IC_Stmt: public Icode_Stmt +{ + string label; + +public: + Label_IC_Stmt(Tgt_Op inst_op, string label); + ~Label_IC_Stmt() {} + Label_IC_Stmt & operator=(const Label_IC_Stmt & rhs); + + Instruction_Descriptor & get_inst_op_of_ics(); + + string get_label(); + void set_label(string label); + + void print_icode(ostream & file_buffer); + void print_assembly(ostream & file_buffer); +}; + +//////////////////////// Intermediate code for Ast statements //////////////////////// + +class Code_For_Ast +{ + /* + This class describes the code generated for a given + AST in a sequence ast. Note that a single AST would + in general need multiple statements to implement it. + We also need to remember the intermediate results of + an AST because it could be a subtree of a larger AST. + */ + + list ics_list; + Register_Descriptor * result_register; + +public: + Code_For_Ast(); + Code_For_Ast(list & ic_l, Register_Descriptor * reg); + ~Code_For_Ast() {} + + void append_ics(Icode_Stmt & ics); + list & get_icode_list(); + + Register_Descriptor * get_reg(); + void set_reg(Register_Descriptor * reg); + + Code_For_Ast & operator=(const Code_For_Ast & rhs); +}; + +#endif diff --git a/A5/libsclpshared.so b/A5/libsclpshared.so new file mode 100755 index 0000000..ad66dee Binary files /dev/null and b/A5/libsclpshared.so differ diff --git a/A5/local-environment.hh b/A5/local-environment.hh new file mode 100644 index 0000000..052de08 --- /dev/null +++ b/A5/local-environment.hh @@ -0,0 +1,111 @@ + + +#ifndef LOCAL_ENVIRONMENT_HH +#define LOCAL_ENVIRONMENT_HH + +#include +#include + +#define VAR_SPACE " " + +using namespace std; + +typedef enum +{ + int_result, + void_result, + double_result +} Result_Enum; + +class Eval_Result; +class Local_Environment; + +class Eval_Result +{ +protected: + Result_Enum result_type; + +public: + virtual int get_int_value(); + virtual void set_value(int value); + virtual double get_double_value(); + virtual void set_value(double value); + + virtual bool is_variable_defined(); + virtual void set_variable_status(bool def); + + virtual void set_result_enum(Result_Enum) = 0; + virtual Result_Enum get_result_enum() = 0; +}; + +class Eval_Result_Value:public Eval_Result +{ +public: + virtual void set_value(int number); + virtual void set_value(double number); + virtual int get_int_value(); + virtual double get_double_value(); + + virtual bool is_variable_defined() = 0; + virtual void set_variable_status(bool def) = 0; + + virtual void set_result_enum(Result_Enum res) = 0; + virtual Result_Enum get_result_enum() = 0; +}; + +class Eval_Result_Value_Int:public Eval_Result_Value +{ + int value; + bool defined; +public: + Eval_Result_Value_Int(); + ~Eval_Result_Value_Int(); + + void set_value(int number); + void set_value(double number); + int get_int_value(); + + void set_variable_status(bool def); + bool is_variable_defined(); + + void set_result_enum(Result_Enum res); + Result_Enum get_result_enum(); +}; + +class Eval_Result_Value_Double:public Eval_Result_Value +{ + double value; + bool defined; +public: + Eval_Result_Value_Double(); + ~Eval_Result_Value_Double(); + + void set_value(double number); + void set_value(int number); + double get_double_value(); + + void set_variable_status(bool def); + bool is_variable_defined(); + + void set_result_enum(Result_Enum res); + Result_Enum get_result_enum(); +}; + +class Local_Environment +{ + map variable_table; + +public: + Local_Environment(); + ~Local_Environment(); + + void print(ostream & file_buffer); + bool is_variable_defined(string name); + Eval_Result * get_variable_value(string name); + void put_variable_value(Eval_Result & value, string name); + bool does_variable_exist(string name); +}; + +extern Local_Environment interpreter_global_table; + +#endif diff --git a/A5/procedure-eval.cc b/A5/procedure-eval.cc new file mode 100644 index 0000000..cd4c15d --- /dev/null +++ b/A5/procedure-eval.cc @@ -0,0 +1,39 @@ + +#include +#include +#include + +using namespace std; + + +Eval_Result & Procedure::evaluate(ostream & file_buffer) +{ + Local_Environment & eval_env = *new Local_Environment(); + local_symbol_table.create(eval_env); + + Eval_Result * result = NULL; + + file_buffer << PROC_SPACE << "Evaluating Procedure " << name << "\n"; + file_buffer << LOC_VAR_SPACE << "Local Variables (before evaluating):\n"; + eval_env.print(file_buffer); + file_buffer << "\n"; + + + //file_buffer << "\n" << BB_SPACE << "Basic Block: " << id_number << "\n"; + + list ::iterator i; + for (i = statement_list.begin(); i != statement_list.end(); i++) + { + CHECK_INVARIANT(((*i) != NULL), "Ast pointer seems to be NULL into the basic block"); + result = &((*i)->evaluate(eval_env, file_buffer)); + } + + + //result = &(basic_block->evaluate(eval_env, file_buffer)); + + file_buffer << "\n\n"; + file_buffer << LOC_VAR_SPACE << "Local Variables (after evaluating):\n"; + eval_env.print(file_buffer); + + return *result; +} diff --git a/A5/procedure.hh b/A5/procedure.hh new file mode 100644 index 0000000..b024f5c --- /dev/null +++ b/A5/procedure.hh @@ -0,0 +1,71 @@ + +#ifndef PROCEDURE_HH +#define PROCEDURE_HH + +#include +#include +#include + +#define PROC_SPACE " " +#define LOC_VAR_SPACE " " + +using namespace std; + +class Procedure; + +class Procedure +{ + Data_Type return_type; + + string name; + + Symbol_Table local_symbol_table; + + Basic_Block * basic_block; + + list statement_list; + + list bb_icode_list; + + int lineno; + +public: + Procedure(Data_Type proc_return_type, string proc_name, int line); + + ~Procedure(); + + string get_proc_name(); + + void set_basic_block(Basic_Block & bb_list); + + void set_ast_list(list & ast_list); + + void set_local_list(Symbol_Table & new_list); + + Symbol_Table get_local_list(); + + Data_Type get_return_type(); + + Symbol_Table_Entry & get_symbol_table_entry(string variable_name); + + void print(ostream & file_buffer); + + void print_sym(ostream & file_buffer); + + void evaluate_print(ostream & fil_buffer); + + Eval_Result & evaluate(ostream & file_buffer); + + bool variable_in_symbol_list_check(string variable); + + // compile + void compile(); + void print_icode(ostream & file_buffer); + void print_assembly(ostream & file_buffer); + +private: + void print_prologue(ostream & file_buffer); + void print_epilogue(ostream & file_buffer); +}; + +#endif diff --git a/A5/program-eval.cc b/A5/program-eval.cc new file mode 100644 index 0000000..f1c882a --- /dev/null +++ b/A5/program-eval.cc @@ -0,0 +1,32 @@ + +#include +#include + +using namespace std; + + + +Local_Environment interpreter_global_table; + +Eval_Result & Program::evaluate() +{ + Procedure * main_proc = procedure; + CHECK_INPUT_AND_ABORT(((main_proc != NULL) && (main_proc->get_proc_name() == "main")), + "No main function found in the program", NO_FILE_LINE); + + global_symbol_table.create(interpreter_global_table); + + command_options.create_output_buffer(); + ostream & file_buffer = command_options.get_output_buffer(); + file_buffer << "Evaluating Program\n"; + file_buffer << GLOB_SPACE << "Global Variables (before evaluating):\n"; + + interpreter_global_table.print(file_buffer); + + Eval_Result & result = main_proc->evaluate(file_buffer); + + file_buffer << GLOB_SPACE << "Global Variables (after evaluating):\n"; + interpreter_global_table.print(file_buffer); + + return result; +} diff --git a/A5/program.hh b/A5/program.hh new file mode 100644 index 0000000..005647b --- /dev/null +++ b/A5/program.hh @@ -0,0 +1,46 @@ + + +#ifndef PROGRAM_HH +#define PROGRAM_HH + +#include + +#define GLOB_SPACE " " + +using namespace std; + +class Program; + +extern Program program_object; + +class Program +{ + Symbol_Table global_symbol_table; + Procedure * procedure; + +public: + Program(); + ~Program(); + void delete_all(); + + void set_procedure(Procedure * proc, int line); + void set_global_table(Symbol_Table & new_global_table); + + Symbol_Table_Entry & get_symbol_table_entry(string variable); + + void print_sym(); + void print(); + + void evaluate_print(); + Eval_Result & evaluate(); + + bool variable_proc_name_check(string symbol); + bool variable_in_symbol_list_check(string variable); + void global_list_in_proc_check(); + + // compile + void compile(); + void print_assembly(); +}; + +#endif diff --git a/A5/reg-alloc.cc b/A5/reg-alloc.cc new file mode 100644 index 0000000..6ac4ab9 --- /dev/null +++ b/A5/reg-alloc.cc @@ -0,0 +1,522 @@ + + +#include +#include +#include +#include +#include +#include + +using namespace std; + +#include "common-classes.hh" +#include "error-display.hh" +#include "local-environment.hh" +#include "icode.hh" +#include "reg-alloc.hh" +#include "symbol-table.hh" +#include "ast.hh" +#include "program.hh" + +Machine_Description machine_desc_object; + +//////////////////////////// Register Descriptor /////////////////////////////// + +Register_Descriptor::Register_Descriptor(Spim_Register reg, string s, Register_Val_Type vt, Register_Use_Category uc) +{ + reg_id = reg; + reg_name = s; + value_type = vt; + reg_use = uc; + used_for_expr_result = false; + reg_occupied = false; + used_for_fn_return = false; +} + +Register_Use_Category Register_Descriptor::get_use_category() { return reg_use; } +Spim_Register Register_Descriptor::get_register() { return reg_id; } +string Register_Descriptor::get_name() { return reg_name; } +bool Register_Descriptor::is_symbol_list_empty() { return lra_symbol_list.empty(); } + +bool Register_Descriptor::is_register_occupied() { return reg_occupied; } +void Register_Descriptor::set_register_occupied() { reg_occupied = true; } +void Register_Descriptor::reset_register_occupied() { reg_occupied = false; } + +bool Register_Descriptor::is_used_for_expr_result() { return used_for_expr_result; } +void Register_Descriptor::reset_use_for_expr_result() { used_for_expr_result = false; + reg_occupied = false; + used_for_fn_return = false; } +void Register_Descriptor::set_use_for_expr_result() { used_for_expr_result = true; } + +void Register_Descriptor::set_used_for_fn_return() { used_for_fn_return = true; } +void Register_Descriptor::reset_used_for_fn_return() { used_for_fn_return = false; } +bool Register_Descriptor::is_used_for_fn_return() { return used_for_fn_return; } + +int Register_Descriptor::count_symbol_entry_in_list() +{ + int count = 0; + + list::iterator i; + for(i = lra_symbol_list.begin(); i != lra_symbol_list.end(); i++) + count++; + + return count; +} + +template +bool Register_Descriptor::is_free() +{ + if ((reg_use == dt) && + (lra_symbol_list.empty()) && + (is_used_for_expr_result() == false) && + (is_register_occupied() == false)) + return true; + else + return false; +} + +void Register_Descriptor::remove_symbol_entry_from_list(Symbol_Table_Entry & sym_entry) +{ + lra_symbol_list.remove(&sym_entry); +} + +bool Register_Descriptor::find_symbol_entry_in_list(Symbol_Table_Entry & sym_entry) +{ + list::iterator i; + for (i = lra_symbol_list.begin(); i != lra_symbol_list.end(); i++) + if (**i == sym_entry) + return true; + + return false; +} + +void Register_Descriptor::clear_lra_symbol_list() +{ + list::iterator i; + for (i = lra_symbol_list.begin(); i != lra_symbol_list.end(); i++) + { + Symbol_Table_Entry & sym_entry = **i; + sym_entry.set_register(NULL); + } + + lra_symbol_list.clear(); +} + +void Register_Descriptor::update_symbol_information(Symbol_Table_Entry & sym_entry) +{ + if (find_symbol_entry_in_list(sym_entry) == false) + lra_symbol_list.push_back(&sym_entry); +} + +//////////////////////////////// Lra_Outcome ////////////////////////////////////////// + +Lra_Outcome::Lra_Outcome(Register_Descriptor * rdp, bool nr, bool sr, bool dr, bool mv, bool ld) +{ + register_description = rdp; + is_a_new_register = nr; + is_same_as_source = sr; + is_same_as_destination = dr; + register_move_needed = mv; + load_needed = ld; +} + +Lra_Outcome::Lra_Outcome() +{ + register_description = NULL; + is_a_new_register = false; + is_same_as_source = false; + is_same_as_destination = false; + register_move_needed = false; + load_needed = false; +} + + +Register_Descriptor * Lra_Outcome::get_register() { return register_description; } +bool Lra_Outcome::is_new_register() { return is_a_new_register; } +bool Lra_Outcome::is_source_register() { return is_same_as_source; } +bool Lra_Outcome::is_destination_register() { return is_same_as_destination; } +bool Lra_Outcome::is_move_needed() { return register_move_needed; } +bool Lra_Outcome::is_load_needed() { return load_needed; } + +template +void Lra_Outcome::optimize_lra(Lra_Scenario lcase, Ast * destination_memory, Ast * source_memory) +{ + // Register allocation is done only when the source is in either memory or is a constant + + Register_Descriptor * destination_register, * source_register, * result_register; + Symbol_Table_Entry * source_symbol_entry, * destination_symbol_entry; + + destination_register = NULL; + source_register = NULL; + result_register = NULL; + + is_a_new_register = false; + is_same_as_source = false; + is_same_as_destination = false; + register_move_needed = false; + load_needed = false; + + switch (lcase) + { + case mc_2m: + if (destination_memory != NULL) + { + CHECK_INVARIANT((typeid(*destination_memory) != typeid(Number_Ast) || (typeid(*destination_memory) != typeid(Number_Ast))), + "Destination memory cannot be a constant"); + + destination_symbol_entry = &(destination_memory->get_symbol_entry()); + destination_register = destination_symbol_entry->get_register(); + } + else + destination_register = NULL; + + CHECK_INVARIANT(source_memory, + "Sourse ast pointer cannot be NULL for m2m scenario in lra"); + if (typeid(*source_memory) == typeid(Number_Ast) || (typeid(*source_memory) == typeid(Number_Ast))) + source_register = NULL; + else + { + source_symbol_entry = &(source_memory->get_symbol_entry()); + source_register = source_symbol_entry->get_register(); + } + + if (source_register != NULL) + { + result_register = source_register; + is_same_as_source = true; + load_needed = false; + } + else if (destination_register != NULL) + { + int count_var = destination_register->count_symbol_entry_in_list(); + if (count_var > 1) + { + result_register = machine_desc_object.get_new_register
(); + is_a_new_register = true; + } + + else + { + result_register = destination_register; + is_same_as_destination = true; + } + + load_needed = true; + } + else + { + result_register = machine_desc_object.get_new_register
(); + is_a_new_register = true; + load_needed = true; + } + + break; + + case mc_2r: + CHECK_INVARIANT(source_memory, "Sourse ast pointer cannot be NULL for m2r scenario in lra"); + + if (typeid(*source_memory) == typeid(Number_Ast) || (typeid(*source_memory) == typeid(Number_Ast))) + source_register = NULL; + else + { + source_symbol_entry = &(source_memory->get_symbol_entry()); + source_register = source_symbol_entry->get_register(); + } + + if (source_register != NULL) + { + result_register = source_register; + is_same_as_source = true; + load_needed = false; + } + else + { + result_register = machine_desc_object.get_new_register
(); + is_a_new_register = true; + load_needed = true; + } + + break; + + case r2r: + CHECK_INVARIANT(CONTROL_SHOULD_NOT_REACH, + "r2r scenario does not call for local register allocation"); + + break; + + case r2m: + CHECK_INVARIANT(CONTROL_SHOULD_NOT_REACH, + "r2m scenario does not call for local register allocation. Register allocation only allowed in mc_2m or mc_2r. So register allocation is not required in r2m"); + + break; + + default: + CHECK_INVARIANT(CONTROL_SHOULD_NOT_REACH, + "Illegal local register allocation scenario"); + + break; + } + + CHECK_INVARIANT ((result_register != NULL), "Inconsistent information in lra"); + register_description = result_register; + + // Assign register to source memory + if ((source_register) && + (typeid(*source_memory) != typeid(Number_Ast) && + (typeid(*source_memory) != typeid(Number_Ast))) && + (source_memory != NULL)) + { + source_symbol_entry->free_register(source_register); + } + + if ((source_memory != NULL) && + (typeid(*source_memory) != typeid(Number_Ast) && + (typeid(*source_memory) != typeid(Number_Ast)))) + { + source_symbol_entry->update_register(result_register); + } + + if ((destination_register) && (destination_memory != NULL)) + destination_symbol_entry->free_register(destination_register); + + if ((result_register != NULL) && (destination_memory != NULL)) + destination_symbol_entry->update_register(result_register); +} + +/******************************* Machine Description *****************************************/ + +void Machine_Description::initialize_register_table() +{ + spim_register_table[zero] = new Register_Descriptor(zero, "zero", int_num, fixed_reg); + spim_register_table[v0] = new Register_Descriptor(v0, "v0", int_num, gp_data); + spim_register_table[v1] = new Register_Descriptor(v1, "v1", int_num, fn_result); + spim_register_table[a0] = new Register_Descriptor(a0, "a0", int_num, argument); + spim_register_table[a1] = new Register_Descriptor(a1, "a1", int_num, argument); + spim_register_table[a2] = new Register_Descriptor(a2, "a2", int_num, argument); + spim_register_table[a3] = new Register_Descriptor(a3, "a3", int_num, argument); + spim_register_table[t0] = new Register_Descriptor(t0, "t0", int_num, gp_data); + spim_register_table[t1] = new Register_Descriptor(t1, "t1", int_num, gp_data); + spim_register_table[t2] = new Register_Descriptor(t2, "t2", int_num, gp_data); + spim_register_table[t3] = new Register_Descriptor(t3, "t3", int_num, gp_data); + spim_register_table[t4] = new Register_Descriptor(t4, "t4", int_num, gp_data); + spim_register_table[t5] = new Register_Descriptor(t5, "t5", int_num, gp_data); + spim_register_table[t6] = new Register_Descriptor(t6, "t6", int_num, gp_data); + spim_register_table[t7] = new Register_Descriptor(t7, "t7", int_num, gp_data); + spim_register_table[t8] = new Register_Descriptor(t8, "t8", int_num, gp_data); + spim_register_table[t9] = new Register_Descriptor(t9, "t9", int_num, gp_data); + spim_register_table[s0] = new Register_Descriptor(s0, "s0", int_num, gp_data); + spim_register_table[s1] = new Register_Descriptor(s1, "s1", int_num, gp_data); + spim_register_table[s2] = new Register_Descriptor(s2, "s2", int_num, gp_data); + spim_register_table[s3] = new Register_Descriptor(s3, "s3", int_num, gp_data); + spim_register_table[s4] = new Register_Descriptor(s4, "s4", int_num, gp_data); + spim_register_table[s5] = new Register_Descriptor(s5, "s5", int_num, gp_data); + spim_register_table[s6] = new Register_Descriptor(s6, "s6", int_num, gp_data); + spim_register_table[s7] = new Register_Descriptor(s7, "s7", int_num, gp_data); + spim_register_table[f0] = new Register_Descriptor(f0, "f0", float_num, fn_result); + spim_register_table[f2] = new Register_Descriptor(f2, "f2", float_num, float_reg); + spim_register_table[f4] = new Register_Descriptor(f4, "f4", float_num, float_reg); + spim_register_table[f6] = new Register_Descriptor(f6, "f6", float_num, float_reg); + spim_register_table[f8] = new Register_Descriptor(f8, "f8", float_num, float_reg); + spim_register_table[f10] = new Register_Descriptor(f10, "f10", float_num, float_reg); + spim_register_table[f12] = new Register_Descriptor(f12, "f12", float_num, float_reg); + spim_register_table[f14] = new Register_Descriptor(f14, "f14", float_num, float_reg); + spim_register_table[f16] = new Register_Descriptor(f16, "f16", float_num, float_reg); + spim_register_table[f18] = new Register_Descriptor(f18, "f18", float_num, float_reg); + spim_register_table[f20] = new Register_Descriptor(f20, "f20", float_num, float_reg); + spim_register_table[f22] = new Register_Descriptor(f22, "f22", float_num, float_reg); + spim_register_table[f24] = new Register_Descriptor(f24, "f24", float_num, float_reg); + spim_register_table[f26] = new Register_Descriptor(f26, "f26", float_num, float_reg); + spim_register_table[f28] = new Register_Descriptor(f28, "f28", float_num, float_reg); + spim_register_table[f30] = new Register_Descriptor(f30, "f30", float_num, float_reg); + spim_register_table[gp] = new Register_Descriptor(gp, "gp", int_num, pointer); + spim_register_table[sp] = new Register_Descriptor(sp, "sp", int_num, pointer); + spim_register_table[fp] = new Register_Descriptor(fp, "fp", int_num, pointer); + spim_register_table[ra] = new Register_Descriptor(ra, "ra", int_num, ret_address); +} + +void Machine_Description::initialize_instruction_table() +{ + spim_instruction_table[store] = new Instruction_Descriptor(store, "store", "sw", "", i_r_op_o1, a_op_o1_r); + spim_instruction_table[load] = new Instruction_Descriptor(load, "load", "lw", "", i_r_op_o1, a_op_r_o1); + spim_instruction_table[la] = new Instruction_Descriptor(la, "loadAdd", "la", "", i_r_op_o1, a_op_r_o1); + spim_instruction_table[imm_load] = new Instruction_Descriptor(imm_load, "iLoad", "li", "", i_r_op_o1, a_op_r_o1); + spim_instruction_table[and_t] = new Instruction_Descriptor(and_t, "and", "and", "", i_r_o1_op_o2, a_op_r_o1_o2); + spim_instruction_table[or_t] = new Instruction_Descriptor(or_t, "or", "or", "", i_r_o1_op_o2, a_op_r_o1_o2); + spim_instruction_table[not_t] = new Instruction_Descriptor(not_t, "not", "sltu", "", i_r_o1_op_o2, a_op_r_o1_o2); + spim_instruction_table[mov] = new Instruction_Descriptor(mov, "move", "move", "", i_r_op_o1, a_op_r_o1); + spim_instruction_table[add] = new Instruction_Descriptor(add, "add", "add", "", i_r_o1_op_o2, a_op_r_o1_o2); + spim_instruction_table[sub] = new Instruction_Descriptor(sub, "sub", "sub", "", i_r_o1_op_o2, a_op_r_o1_o2); + spim_instruction_table[mult] = new Instruction_Descriptor(mult, "mul", "mul", "", i_r_o1_op_o2, a_op_r_o1_o2); + spim_instruction_table[divd] = new Instruction_Descriptor(divd, "div", "div", "", i_r_o1_op_o2, a_op_r_o1_o2); + spim_instruction_table[imm_add] = new Instruction_Descriptor(imm_add, "addi", "addi", "", i_r_o1_op_o2, a_op_r_o1_o2); + spim_instruction_table[uminus] = new Instruction_Descriptor(uminus, "uminus", "neg", "", i_r_op_o1, a_op_r_o1); + spim_instruction_table[store_d] = new Instruction_Descriptor(store_d, "store.d", "s.d", "", i_r_op_o1, a_op_o1_r); + spim_instruction_table[load_d] = new Instruction_Descriptor(load_d, "load.d", "l.d", "", i_r_op_o1, a_op_r_o1); + spim_instruction_table[imm_load_d] = new Instruction_Descriptor(imm_load_d, "iLoad.d", "li.d", "", i_r_op_o1, a_op_r_o1); + spim_instruction_table[move_d] = new Instruction_Descriptor(move_d, "move.d", "mov.d", "", i_r_op_o1, a_op_r_o1); + spim_instruction_table[add_d] = new Instruction_Descriptor(add_d, "add.d", "add.d", "", i_r_o1_op_o2, a_op_r_o1_o2); + spim_instruction_table[sub_d] = new Instruction_Descriptor(sub_d, "sub.d", "sub.d", "", i_r_o1_op_o2, a_op_r_o1_o2); + spim_instruction_table[mult_d] = new Instruction_Descriptor(mult_d, "mul.d", "mul.d", "", i_r_o1_op_o2, a_op_r_o1_o2); + spim_instruction_table[div_d] = new Instruction_Descriptor(div_d, "div.d", "div.d", "", i_r_o1_op_o2, a_op_r_o1_o2); + spim_instruction_table[uminus_d] = new Instruction_Descriptor(uminus_d, "uminus.d", "neg.d", "", i_r_op_o1, a_op_r_o1); + spim_instruction_table[slt] = new Instruction_Descriptor(slt, "slt", "slt", "", i_r_o1_op_o2, a_op_r_o1_o2); + spim_instruction_table[sle] = new Instruction_Descriptor(sle, "sle", "sle", "", i_r_o1_op_o2, a_op_r_o1_o2); + spim_instruction_table[sgt] = new Instruction_Descriptor(sgt, "sgt", "sgt", "", i_r_o1_op_o2, a_op_r_o1_o2); + spim_instruction_table[sge] = new Instruction_Descriptor(sge, "sge", "sge", "", i_r_o1_op_o2, a_op_r_o1_o2); + spim_instruction_table[seq] = new Instruction_Descriptor(seq, "seq", "seq", "", i_r_o1_op_o2, a_op_r_o1_o2); + spim_instruction_table[sne] = new Instruction_Descriptor(sne, "sne", "sne", "", i_r_o1_op_o2, a_op_r_o1_o2); + spim_instruction_table[beq] = new Instruction_Descriptor(beq, "beq", "beq", "", i_op_o1_o2_st, a_op_o1_o2_st); + spim_instruction_table[bne] = new Instruction_Descriptor(bne, "bne", "bne", "", i_op_o1_o2_st, a_op_o1_o2_st); + spim_instruction_table[bgtz] = new Instruction_Descriptor(bgtz, "bgtz", "bgtz", "", i_op_o1_o2_st, a_op_o1_o2_st); + spim_instruction_table[bgez] = new Instruction_Descriptor(bgez, "bgez", "bgez", "", i_op_o1_o2_st, a_op_o1_o2_st); + spim_instruction_table[bltz] = new Instruction_Descriptor(bltz, "bltz", "bltz", "", i_op_o1_o2_st, a_op_o1_o2_st); + spim_instruction_table[blez] = new Instruction_Descriptor(blez, "blez", "blez", "", i_op_o1_o2_st, a_op_o1_o2_st); + spim_instruction_table[j] = new Instruction_Descriptor(j, "jump", "j", "", i_op_st, a_op_st); + spim_instruction_table[jal] = new Instruction_Descriptor(jal, "jal", "jal", "", i_op_st, a_op_st); + spim_instruction_table[syscal1] = new Instruction_Descriptor(syscal1, "syscall", "syscall", "", i_op_st, a_op_st); + spim_instruction_table[label] = new Instruction_Descriptor(label, "", "", "", i_op_st, a_op_st); + spim_instruction_table[ret_inst] = new Instruction_Descriptor(ret_inst, "return", "", "", i_op, a_op); + spim_instruction_table[seq_d] = new Instruction_Descriptor(seq_d, "seq.d", "c.eq.d", "", i_r_o1_op_o2, a_op_r_o1_o2); + spim_instruction_table[slt_d] = new Instruction_Descriptor(slt_d, "slt.d", "c.lt.d", "", i_r_o1_op_o2, a_op_r_o1_o2); + spim_instruction_table[sle_d] = new Instruction_Descriptor(sle_d, "sle.d", "c.le.d", "", i_r_o1_op_o2, a_op_r_o1_o2); + spim_instruction_table[bc1t] = new Instruction_Descriptor(bc1t, "bc1t", "bc1t", "", i_op_st, a_op_st); + spim_instruction_table[bc1f] = new Instruction_Descriptor(bc1f, "bc1f", "bc1f", "", i_op_st, a_op_st); +} + +void Machine_Description::validate_init_local_register_mapping_before_fn_call() +{ + map::iterator i; + for (i = spim_register_table.begin(); i != spim_register_table.end(); i++) + { + Register_Descriptor * reg_desc = i->second; + + if (reg_desc->is_used_for_fn_return() == false) + { + if (reg_desc->get_use_category() == gp_data) + { + CHECK_INVARIANT((reg_desc->is_free()), "GP data registers should be free at the start of a basic block or after a function call"); + } + + else if (reg_desc->get_use_category() == float_reg) + { + CHECK_INVARIANT((reg_desc->is_free()), "Float data registers should be free at the start of a basic block or after a function call"); + } + } + } +} + +void Machine_Description::validate_init_local_register_mapping() +{ + map::iterator i; + for (i = spim_register_table.begin(); i != spim_register_table.end(); i++) + { + Register_Descriptor * reg_desc = i->second; + + if (reg_desc->get_use_category() == gp_data) + { + CHECK_INVARIANT((reg_desc->is_free()), "GP data registers should be free at the start of a basic block or after a function call"); + } + + else if (reg_desc->get_use_category() == float_reg) + { + CHECK_INVARIANT((reg_desc->is_free()), "Float data registers should be free at the start of a basic block or after a function call"); + } + } +} + +void Machine_Description::clear_local_register_mappings() +{ + map::iterator i; + for (i = spim_register_table.begin(); i != spim_register_table.end(); i++) + { + Register_Descriptor * reg_desc = i->second; + reg_desc->clear_lra_symbol_list(); + } + + /* + Note that we do not need to save values at the end + of a basic block because the values have already been + saved for each assignment statement. Any optimization + that tries to postpone the store statements may have to + consider storing all unstored values at the end of + a basic block. + */ +} + +template +Register_Descriptor * Machine_Description::get_new_register() +{ + Register_Descriptor * reg_desc; + int count = 0; + + map::iterator i; + for (i = spim_register_table.begin(); i != spim_register_table.end(); i++) + { + reg_desc = i->second; + + CHECK_INVARIANT((reg_desc != NULL), "Null register descriptor in the register table"); + + if (reg_desc->is_free
()) + { + reg_desc->set_register_occupied(); + return reg_desc; + } + } + + machine_desc_object.clear_reg_not_used_for_expr_result(); + + count = machine_desc_object.count_free_register
(); + if (count > 0) + return get_new_register
(); + else + { + CHECK_INVARIANT(CONTROL_SHOULD_NOT_REACH, + "Error in get_new_reg or register requirements of input program cannot be met"); + } +} + +template +int Machine_Description::count_free_register() +{ + Register_Descriptor * rdp = NULL; + int count = 0; + + map::iterator i; + for (i = spim_register_table.begin(); i != spim_register_table.end(); i++) + { + rdp = i->second; + if (rdp->is_free
()) + count++; + } + + return count; +} + +void Machine_Description::clear_reg_not_used_for_expr_result() +{ + map::iterator i; + + for (i = spim_register_table.begin(); i != spim_register_table.end(); i++) + { + Register_Descriptor * rdp = i->second; + + if(!rdp->is_used_for_expr_result()) + { + rdp->reset_register_occupied(); /* reset reg occupied i.e register is not anymore occupied */ + rdp->clear_lra_symbol_list(); + break; + } + } +} + +template bool Register_Descriptor::is_free(); +template bool Register_Descriptor::is_free(); + +template void Lra_Outcome::optimize_lra(Lra_Scenario lcase, Ast * destination_memory, Ast * source_memory); +template void Lra_Outcome::optimize_lra(Lra_Scenario lcase, Ast * destination_memory, Ast * source_memory); + +template Register_Descriptor * Machine_Description::get_new_register(); +template Register_Descriptor * Machine_Description::get_new_register(); + +template int Machine_Description::count_free_register(); +template int Machine_Description::count_free_register(); diff --git a/A5/reg-alloc.hh b/A5/reg-alloc.hh new file mode 100644 index 0000000..f38bd84 --- /dev/null +++ b/A5/reg-alloc.hh @@ -0,0 +1,260 @@ + +#ifndef REG_ALLOC_HH +#define REG_ALLOC_HH + +#include +#include +#include +#include +#include +#include + +/////////////////////////////// Register_Descriptor //////////////////// + +typedef enum +{ + none, /* dummy to indicate no register */ + zero, /* constant register */ + v0, /* expression result register */ + v1, /* function result register */ + a0, /* argument register */ + a1, a2, a3, + t0, /* temporary caller-save registers */ + t1, t2, t3, t4, t5, t6, t7, t8, t9, + s0, /* temporary callee-save registers */ + s1, s2, s3, s4, s5, s6, s7, + mfc, /* float register to int register */ + mtc, /* int register to float register */ + f0, /* floating point registers */ + f2, f4, f6, f8, + f10, f12, f14, f16, f18, + f20, f22, f24, f26, f28, f30, + gp, /* global data pointer register */ + sp, /* stack pointer register */ + fp, /* frame pointer register */ + ra /* return address register */ +} Spim_Register; + +typedef enum +{ + int_num, + float_num +} Register_Val_Type; + +typedef enum +{ + fixed_reg, + gp_data, + fn_result, + argument, + pointer, + ret_address, + float_reg +} Register_Use_Category; + +class Register_Descriptor +{ + Spim_Register reg_id; + string reg_name; + Register_Val_Type value_type; + Register_Use_Category reg_use; + + list lra_symbol_list; + bool used_for_expr_result; + bool reg_occupied; + bool used_for_fn_return; + + public: + Register_Descriptor (Spim_Register reg, string nam, Register_Val_Type vt, Register_Use_Category uc); + Register_Descriptor() {} + ~Register_Descriptor() {} + + bool is_symbol_list_empty(); + void update_symbol_information(Symbol_Table_Entry & symbol_entry); + + int count_symbol_entry_in_list(); + + bool find_symbol_entry_in_list(Symbol_Table_Entry & symbol_entry); + void remove_symbol_entry_from_list(Symbol_Table_Entry & symbol_entry); + + Register_Use_Category get_use_category(); + Spim_Register get_register(); + + string get_name(); + void clear_lra_symbol_list(); + + bool is_register_occupied(); + void set_register_occupied(); + void reset_register_occupied(); + + bool is_used_for_fn_return(); + void set_used_for_fn_return(); + void reset_used_for_fn_return(); + + bool is_used_for_expr_result(); + void set_use_for_expr_result(); + void reset_use_for_expr_result(); + + template + bool is_free(); +}; + +////////////////////////////// Lra_Outcome /////////////////////////////////////// + +/* + The local register allocation (lra) restricts its attention to a basic block + and maintains the following two pieces of information + + - for each name encountered, the register in which current value of name + can be found + - for each register, the set of names whose values are held in the + register (they all have the same value). + + At the start of a block each name has register "none" and the name list of + each register is empty. + Local register allocation should consider the following cases described + in terms of "source to destination" moves where source and destination + could be memory (m), register (r), or constant (c). + + For each case we outline a step-wise decision process for identifying + (a) The register, (b) Load, if any + + 1. m2m is a typical assginment statemenmt involving memory on lhs + as well as RHS. Decision steps + if (rhs is in a register) + { + use the register. + no load required. + } + else if (lhs is in a register) + { + use the register. + load rhs into the register. + } + else + { + use a new register. + load rhs into the register. + } + 2. m2r is a typical load for a compute statemenmt. As a policy + we use a new register because the value may be updated by the + computation. This can be minimized by traversing the tree using + Sethi-Ullman lablelling, but we do not do it in this version. + if (rhs is in a register) + { + use a new register. + move from source register into the new register. + } + else + { + use a new register. + load rhs into the register. + } + 3. r2m. This is a typical store for a compute statemenmt. It does not need a + new register + 4. c2m. This is a store that needs an intermediate register. + if (lhs is in a register) + { + use the register. + load the rhs constant into the register. + } + else + { + use a new register. + load rhs constant into the new register. + } + 5. c2r. This is typical load immediate for computation. + unconditionally + { + use a new register. + load rhs constant into the new register. + } + 6. r2r does not need to bring in register allocation. + + Given the 3 candidates (m,r,c) and 2 positions (source and destination) + we have 3^2 = 9 possibility. Apart from the 6 possibilities + outlined above, the remaining three possibilities (m2c, r2c, c2c) + do not arise on common architectures. + + + In each of the above case, the following side-effects are noted: + - the register of the destination mem location is updated to + the new register by removing the earlier register. + - the destination is added to the name list of the new register. + + An invariant of our policy is that for a given location there + is only one register, although for a given register, there may be + multiple locations. This happens because of a call to register + allocation + - NEVER adds a source location to any register, and + - overwrites the previous register of the destination of the + new register. + + + At the end of a block both these information are nullified by setting + register to "none" for each name and by setting the name list of each + register to empty. +*/ + +typedef enum +{ + mc_2m = 1, + mc_2r, + r2m, + c2m, + r2r +} Lra_Scenario; + +class Lra_Outcome +{ + Register_Descriptor * register_description; + + bool is_a_new_register; + bool is_same_as_source; + bool is_same_as_destination; + bool register_move_needed; + bool load_needed; + + public: + Lra_Outcome(Register_Descriptor * rd, bool nr, bool sr, bool dr, bool mv, bool ld); + Lra_Outcome(); + ~Lra_Outcome() {} + + Register_Descriptor * get_register(); + bool is_new_register(); + bool is_source_register(); + bool is_destination_register(); + bool is_move_needed(); + bool is_load_needed(); + + template + void optimize_lra(Lra_Scenario lcase, Ast * destination_memory, Ast * source_memory); +}; + +///////////////////////////// Machine Description //////////////////////////////// + +class Machine_Description +{ +public: + map spim_instruction_table; + map spim_register_table; + + void initialize_instruction_table(); + void initialize_register_table(); + + void validate_init_local_register_mapping_before_fn_call(); + void validate_init_local_register_mapping(); + void clear_local_register_mappings(); + + void clear_reg_not_used_for_expr_result(); + + template + int count_free_register(); + + template + Register_Descriptor * get_new_register(); +}; + +extern Machine_Description machine_desc_object; + +#endif diff --git a/A5/sclp b/A5/sclp new file mode 100755 index 0000000..d618fea Binary files /dev/null and b/A5/sclp differ diff --git a/A5/symbol-table.hh b/A5/symbol-table.hh new file mode 100644 index 0000000..795cc6a --- /dev/null +++ b/A5/symbol-table.hh @@ -0,0 +1,132 @@ + +#ifndef SYMBOL_TABLE_HH +#define SYMBOL_TABLE_HH + +#include +#include + +using namespace std; + +class Symbol_Table; +class Symbol_Table_Entry; + +typedef enum +{ + void_data_type, + int_data_type, + double_data_type, +} Data_Type; + +typedef enum +{ + global, + local, + formal +} Table_Scope; + +typedef enum +{ + less_equalto, + less_than, + greater_than, + greater_equalto, + equalto, + not_equalto +} Relational_Op; + + +typedef enum +{ + _logical_not, + _logical_or, + _logical_and +} Logical_Op; + + + +class Symbol_Table +{ + list variable_table; + Table_Scope scope; + + // compile + int size_in_bytes; // size of list + int start_offset_of_first_symbol; + +public: + Symbol_Table(); + ~Symbol_Table(); + + bool is_empty(); + + Table_Scope get_table_scope(); + void set_table_scope(Table_Scope list_scope); + + void print(ostream & file_buffer); + + void push_symbol(Symbol_Table_Entry * variable); + + bool variable_in_symbol_list_check(string variable); + Symbol_Table_Entry & get_symbol_table_entry(string variable_name); + void global_list_in_proc_check(); + + void append_list(Symbol_Table sym_t,int lineno); + + void create(Local_Environment & local_global_variables_table); + + // compile +private: + int get_size_of_value_type(Data_Type dt); + +public: + void set_start_offset_of_first_symbol(int n); + int get_start_offset_of_first_symbol(); + + void assign_offsets(); + int get_size(); + + void print_assembly(ostream & file_buffer); +}; + +class Symbol_Table_Entry +{ + string variable_name; + Data_Type variable_data_type; + Table_Scope scope; + + int lineno; + + // compile + int start_offset; + int end_offset; + Register_Descriptor * register_description; + +public: + Symbol_Table_Entry(); + Symbol_Table_Entry(string & name, Data_Type new_data_type, int line); + ~Symbol_Table_Entry(); + + int get_lineno(); + + bool operator==(Symbol_Table_Entry & entry); + + void set_symbol_scope(Table_Scope sp); + Table_Scope get_symbol_scope(); + + Data_Type get_data_type(); + void set_data_type(Data_Type dt); + string get_variable_name(); + + //compile + void set_start_offset(int num); + int get_start_offset(); + void set_end_offset(int num); + int get_end_offset(); + + Register_Descriptor * get_register(); + void set_register(Register_Descriptor * reg); + void free_register(Register_Descriptor * destination_reg_descr); + void update_register(Register_Descriptor * result_reg_descr); +}; + +#endif