DEADSOFTWARE

JVM: Добавлены логические OR и AND
[dsw-obn.git] / src / backends / jvm / generator-jvm.c
index 9812f0ab7f5e2b56c243c94c97e6a0fc8ca86037..eb0f3dc16b014bc803edf7307ce29049917efb51 100644 (file)
@@ -369,6 +369,10 @@ oberon_generator_init_proc(oberon_context_t * ctx, oberon_object_t * proc)
        memset(p, 0, sizeof *p);
        proc -> gen_proc = p;
 
+       struct gen_register_file * rf = GC_MALLOC(sizeof *rf);
+       memset(rf, 0, sizeof *rf);
+       p -> rf = rf;
+
        if(proc -> local)
        {
                oberon_error(ctx, "generator: local procedures not implemented");
@@ -424,16 +428,157 @@ oberon_generate_end_module(oberon_context_t * ctx)
        fprintf(m -> fp, ".end method\n");
 }
 
+static int
+jvm_cell_size_for_type(oberon_type_t * type)
+{
+       if(type -> class == OBERON_TYPE_INTEGER
+               || type -> class == OBERON_TYPE_REAL)
+       {
+               if(type -> size > 4)
+               {
+                       return 2;
+               }
+       }
+
+       return 1;
+}
+
+static bool
+jvm_is_wide_type(oberon_type_t * type)
+{
+       int cell;
+       cell = jvm_cell_size_for_type(type);
+       assert(cell <= 2);
+       return (cell == 2);
+}
+
+static bool
+jvm_is_free_register(struct gen_register_file * rf, int i, bool wide)
+{
+       if(wide)
+       {
+               assert(i + 1 < MAX_REGISTERS);
+               return !(rf -> reg[i].used || rf -> reg[i + 1].used);
+       }
+       else
+       {
+               assert(i < MAX_REGISTERS);
+               return !(rf -> reg[i].used);
+       }
+}
+
+static int
+jvm_alloc_register(struct gen_register_file * rf, oberon_type_t * type)
+{
+       bool wide;
+       wide = jvm_is_wide_type(type);
+
+       int i = 0;
+       while(i < MAX_REGISTERS && !jvm_is_free_register(rf, i, wide))
+       {
+               i += 1;
+       }
+
+       if(wide)
+       {
+               assert(i + 1 <= MAX_REGISTERS);
+               rf -> num_used += 2;
+               rf -> reg[i].used = true;
+               rf -> reg[i + 1].used = true;
+               rf -> reg[i].used = true;
+               rf -> reg[i + 1].wide = false;
+       }
+       else
+       {
+               assert(i <= MAX_REGISTERS);
+               rf -> num_used += 1;
+               rf -> reg[i].used = true;
+               rf -> reg[i].wide = false;
+       }
+
+       if(rf -> num_used > rf -> max_used)
+       {
+               rf -> max_used = rf -> num_used;
+       }
+
+       return i;
+}
+
+static void
+jvm_init_local_object(oberon_context_t * ctx, FILE * fp, oberon_object_t * x)
+{
+       int reg;
+       gen_context_t * c;
+       gen_var_t * v;
+       char * desc;
+
+       c = ctx -> gen_context;
+       v = x -> gen_var;
+       desc = get_descriptor(ctx, x -> type);
+
+       reg = -1;
+       switch(x -> class)
+       {
+               case OBERON_CLASS_VAR:
+               case OBERON_CLASS_PARAM:
+                       if(x -> local)
+                       {
+                               reg = jvm_alloc_register(c -> rf, x -> type);
+                       }
+                       v -> reg = reg;
+                       fprintf(fp, ".var %i is %s %s from start to end\n", reg, x -> name, desc);
+                       break;
+               default:
+                       oberon_error(ctx, "jvm_init_local_object: wat");
+                       break;
+       }
+}
+
 void
 oberon_generate_begin_proc(oberon_context_t * ctx, oberon_object_t * proc)
 {
+       gen_context_t * c;
        gen_module_t * m;
+       gen_proc_t * p;
        char * signature;
 
+       c = ctx -> gen_context;
        m = ctx -> mod -> gen_mod;
-       signature = get_procedure_signature(ctx, proc -> type);
+       p = proc -> gen_proc;
 
+       signature = get_procedure_signature(ctx, proc -> type);
        fprintf(m -> fp, ".method public static %s%s\n", proc -> name, signature);
+
+       /* Сохраняем регистровый файл в стеке */
+       p -> rf -> up = c -> rf;
+       c -> rf = p -> rf;
+
+       oberon_object_t * var = proc -> type -> decl;
+       while(var)
+       {
+               jvm_init_local_object(ctx, m -> fp, var);
+               var = var -> next;
+       }
+
+       fprintf(m -> fp, "start:\n");
+}
+
+void
+oberon_generate_end_proc(oberon_context_t * ctx)
+{
+       gen_context_t * c;
+       gen_module_t * m;
+
+       c = ctx -> gen_context;
+       m = ctx -> mod -> gen_mod;
+
+       fprintf(m -> fp, "end:\n");
+       fprintf(m -> fp, "  .limit stack 32\n");
+       fprintf(m -> fp, "  .limit locals %i\n", c -> rf -> max_used);
+       fprintf(m -> fp, ".end method\n\n");
+
+       /* Возвращаем исходный регистровый файл */
+       c -> rf = c -> rf -> up;
 }
 
 void
@@ -463,27 +608,19 @@ oberon_generate_call_proc(oberon_context_t * ctx, oberon_expr_t * desig)
        fprintf(m -> fp, "invokestatic %s%s\n", fullname, signature);
 }
 
-void
-oberon_generate_end_proc(oberon_context_t * ctx)
-{
-       gen_module_t * m;
-       m = ctx -> mod -> gen_mod;
-
-       fprintf(m -> fp, "  .limit stack 32\n");
-       fprintf(m -> fp, "  .limit locals 32\n");
-       fprintf(m -> fp, ".end method\n\n");
-}
-
 void
 oberon_generate_return(oberon_context_t * ctx, oberon_expr_t * expr)
 {
        gen_module_t * m;
+       char prefix;
 
        m = ctx -> mod -> gen_mod;
 
        if(expr)
        {
-               oberon_error(ctx, "oberon_generate_return: TODO return expr");
+               push_expr(ctx, m -> fp, expr);
+               prefix = get_prefix(ctx, expr -> result);
+               fprintf(m -> fp, "  %creturn\n", prefix);
        }
        else
        {
@@ -559,8 +696,6 @@ push_float(FILE * fp, double f, int size)
        }
 }
 
-static void push_expr(oberon_context_t * ctx, FILE * fp, oberon_expr_t * expr);
-
 static void
 push_var(oberon_context_t * ctx, FILE * fp, oberon_object_t * var)
 {
@@ -593,7 +728,7 @@ push_item(oberon_context_t * ctx, FILE * fp, oberon_item_t * item)
                        push_int(fp, item -> boolean);
                        break;
                case MODE_CALL:
-                       oberon_error(ctx, "push_item: TODO call");
+                       oberon_generate_call_proc(ctx, (oberon_expr_t *) item);
                        break;
                case MODE_INDEX:
                        oberon_error(ctx, "push_item: TODO index");
@@ -619,60 +754,155 @@ push_item(oberon_context_t * ctx, FILE * fp, oberon_item_t * item)
        }
 }
 
+static int
+jvm_new_label_id(oberon_context_t * ctx)
+{
+       gen_context_t * c = ctx -> gen_context;
+       int label_id = c -> label_id;
+       c -> label_id += 1;
+       return label_id;
+}
+
+static char *
+jvm_get_label_name(int label_id)
+{
+       return new_string("L%i", label_id);
+}
+
 static void
-push_operator(oberon_context_t * ctx, FILE * fp, oberon_oper_t * oper)
+jvm_generate_label(FILE * fp, int label_id)
 {
-       char prefix = get_prefix(ctx, oper -> result);
-       switch(oper -> op)
+       fprintf(fp, "L%i:\n", label_id);
+}
+
+static void
+jvm_generate_logical_not(oberon_context_t * ctx, FILE * fp)
+{
+       int label_true = jvm_new_label_id(ctx);
+       int label_false = jvm_new_label_id(ctx);
+       char * label_name_true = jvm_get_label_name(label_true);
+       char * label_name_false = jvm_get_label_name(label_false);
+
+       fprintf(fp, "ifne %s\n", label_name_false);
+       fprintf(fp, "iconst_1\n");
+       fprintf(fp, "goto %s\n", label_name_true);
+       jvm_generate_label(fp, label_false);
+       fprintf(fp, "iconst_0\n");
+       jvm_generate_label(fp, label_true);
+}
+
+static char
+jvm_get_type_of_prefix(char prefix)
+{
+       switch(prefix)
+       {
+               case 'b':
+                       return 'B';
+               case 'c':
+                       return 'C';
+               case 'd':
+                       return 'D';
+               case 'f':
+                       return 'F';
+               case 'i':
+                       return 'I';
+               case 'l':
+                       return 'J';
+       }
+
+       assert(0);
+}
+
+static void
+jvm_generate_abs(FILE * fp, char prefix)
+{
+       char t = jvm_get_type_of_prefix(prefix);
+       fprintf(fp, "invokestatic java/lang/Math/abs(%c)%c\n", t, t);
+}
+
+static void
+jvm_generate_compare_op(oberon_context_t * ctx, FILE *fp, char prefix, int op)
+{
+       int label_true = jvm_new_label_id(ctx);
+       int label_false = jvm_new_label_id(ctx);
+       char * label_name_true = jvm_get_label_name(label_true);
+       char * label_name_false = jvm_get_label_name(label_false);
+
+       assert(prefix == 'i' || prefix == 'a');
+
+       switch(op)
+       {
+               case OP_EQ:
+                       fprintf(fp, "if_%ccmpeq %s\n", prefix, label_name_true);
+                       break;
+               case OP_NEQ:
+                       fprintf(fp, "if_%ccmpne %s\n", prefix, label_name_true);
+                       break;
+               case OP_LSS:
+                       fprintf(fp, "if_icmplt %s\n", label_name_true);
+                       break;
+               case OP_LEQ:
+                       fprintf(fp, "if_icmple %s\n", label_name_true);
+                       break;
+               case OP_GRT:
+                       fprintf(fp, "if_icmpgt %s\n", label_name_true);
+                       break;
+               case OP_GEQ:
+                       fprintf(fp, "if_icmpge %s\n", label_name_true);
+                       break;
+               default:
+                       oberon_error(ctx, "jvm_generate_compare_op: wat");
+                       break;
+       }
+
+       fprintf(fp, "iconst_0\n");
+       fprintf(fp, "goto %s\n", label_name_false);
+       jvm_generate_label(fp, label_true);
+       fprintf(fp, "iconst_1\n");
+       jvm_generate_label(fp, label_false);
+}
+
+static void
+jvm_generate_operator(oberon_context_t * ctx, FILE *fp, char prefix, int op)
+{
+       switch(op)
        {
                case OP_UNARY_MINUS:
-                       push_expr(ctx, fp, oper -> left);
                        fprintf(fp, "%cneg\n", prefix);
                        break;
                case OP_BITWISE_NOT:
-                       push_expr(ctx, fp, oper -> left);
                        push_int(fp, -1);
                        fprintf(fp, "%cxor\n", prefix);
                        break;
+               case OP_LOGIC_NOT:
+                       jvm_generate_logical_not(ctx, fp);
+                       break;
+               case OP_ABS:
+                       jvm_generate_abs(fp, prefix);
+                       break;
 
                case OP_ADD:
-                       push_expr(ctx, fp, oper -> left);
-                       push_expr(ctx, fp, oper -> right);
                        fprintf(fp, "%cadd\n", prefix);
                        break;
                case OP_SUB:
-                       push_expr(ctx, fp, oper -> left);
-                       push_expr(ctx, fp, oper -> right);
                        fprintf(fp, "%csub\n", prefix);
                        break;
                case OP_MUL:
-                       push_expr(ctx, fp, oper -> left);
-                       push_expr(ctx, fp, oper -> right);
                        fprintf(fp, "%cmul\n", prefix);
                        break;
                case OP_DIV:
-                       push_expr(ctx, fp, oper -> left);
-                       push_expr(ctx, fp, oper -> right);
                        fprintf(fp, "%cdiv\n", prefix);
                        break;
                case OP_MOD:
-                       push_expr(ctx, fp, oper -> left);
-                       push_expr(ctx, fp, oper -> right);
                        fprintf(fp, "%crem\n", prefix);
                        break;
                case OP_BITWISE_AND:
-                       push_expr(ctx, fp, oper -> left);
-                       push_expr(ctx, fp, oper -> right);
                        fprintf(fp, "%cand\n", prefix);
                        break;
                case OP_BITWISE_XOR:
-                       push_expr(ctx, fp, oper -> left);
-                       push_expr(ctx, fp, oper -> right);
                        fprintf(fp, "%cxor\n", prefix);
                        break;
                case OP_BITWISE_OR:
-                       push_expr(ctx, fp, oper -> left);
-                       push_expr(ctx, fp, oper -> right);
                        fprintf(fp, "%cor\n", prefix);
                        break;
 
@@ -682,12 +912,95 @@ push_operator(oberon_context_t * ctx, FILE * fp, oberon_oper_t * oper)
                case OP_LEQ:
                case OP_GRT:
                case OP_GEQ:
+                       jvm_generate_compare_op(ctx, fp, prefix, op);
+                       break;
+               default:
+                       oberon_error(ctx, "jvm_generate_operator: unk op %i", op);
+                       break;
+       }       
+}
+
+static void
+jvm_generate_logical_or(oberon_context_t * ctx, FILE * fp, oberon_expr_t * p, oberon_expr_t * q)
+{
+       int label_calc_q = jvm_new_label_id(ctx);
+       int label_done = jvm_new_label_id(ctx);
+       char * label_name_calc_q = jvm_get_label_name(label_calc_q);
+       char * label_name_done = jvm_get_label_name(label_done);
+
+       /* p OR q -- если p, то TRUE, иначе q */
+
+       push_expr(ctx, fp, p);
+       fprintf(fp, "ifne %s\n", label_name_calc_q);
+       fprintf(fp, "iconst_1\n");
+       fprintf(fp, "goto %s\n", label_name_done);
+       jvm_generate_label(fp, label_calc_q);
+       push_expr(ctx, fp, q);
+       jvm_generate_label(fp, label_done);
+}
+
+static void
+jvm_generate_logical_and(oberon_context_t * ctx, FILE * fp, oberon_expr_t * p, oberon_expr_t * q)
+{
+       int label_false = jvm_new_label_id(ctx);
+       int label_done = jvm_new_label_id(ctx);
+       char * label_name_false = jvm_get_label_name(label_false);
+       char * label_name_done = jvm_get_label_name(label_done);
+
+       /* p AND q -- если p, то q, иначе FALSE */
+
+       push_expr(ctx, fp, p);
+       fprintf(fp, "ifne %s\n", label_name_false);
+       push_expr(ctx, fp, q);
+       fprintf(fp, "goto %s\n", label_name_done);
+       jvm_generate_label(fp, label_false);
+       fprintf(fp, "iconst_0\n");
+       jvm_generate_label(fp, label_done);
+}
+
+static void
+push_operator(oberon_context_t * ctx, FILE * fp, oberon_oper_t * oper)
+{
+       char prefix = get_prefix(ctx, oper -> result);
+       int op = oper -> op;
+       switch(op)
+       {
+               case OP_UNARY_MINUS:
+               case OP_BITWISE_NOT:
                case OP_LOGIC_NOT:
                case OP_ABS:
-                       oberon_error(ctx, "push_oper: TODO op %i", oper -> op);
+                       push_expr(ctx, fp, oper -> left);
+                       jvm_generate_operator(ctx, fp, prefix, op);
+                       break;
+
+               case OP_ADD:
+               case OP_SUB:
+               case OP_MUL:
+               case OP_DIV:
+               case OP_MOD:
+               case OP_BITWISE_AND:
+               case OP_BITWISE_XOR:
+               case OP_BITWISE_OR:
+
+               case OP_EQ:
+               case OP_NEQ:
+               case OP_LSS:
+               case OP_LEQ:
+               case OP_GRT:
+               case OP_GEQ:
+                       push_expr(ctx, fp, oper -> left);
+                       push_expr(ctx, fp, oper -> right);
+                       jvm_generate_operator(ctx, fp, prefix, op);
+                       break;
+
+               case OP_LOGIC_OR:
+                       jvm_generate_logical_or(ctx, fp, oper -> left, oper -> right);
+                       break;
+               case OP_LOGIC_AND:
+                       jvm_generate_logical_and(ctx, fp, oper -> left, oper -> right);
                        break;
                default:
-                       oberon_error(ctx, "push_oper: unk op %i", oper -> op);
+                       oberon_error(ctx, "push_oper: unk op %i", op);
                        break;
        }
 }