X-Git-Url: https://deadsoftware.ru/gitweb?a=blobdiff_plain;f=src%2Fbackends%2Fjvm%2Fgenerator-jvm.c;h=eb0f3dc16b014bc803edf7307ce29049917efb51;hb=ad7420eb4c7aba592f4d52ecea715b309fd82bf7;hp=dc04ffe3423a03433323e677b23f82cd1e1513a0;hpb=7fc270e5b2a09d5c11b01c48c279c4920d427b0f;p=dsw-obn.git diff --git a/src/backends/jvm/generator-jvm.c b/src/backends/jvm/generator-jvm.c index dc04ffe..eb0f3dc 100644 --- a/src/backends/jvm/generator-jvm.c +++ b/src/backends/jvm/generator-jvm.c @@ -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,17 +608,6 @@ 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) { @@ -620,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; @@ -683,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; } }