const arch_register_req_t *be_create_reg_req(struct obstack *obst, const arch_register_t *reg, bool ignore) { arch_register_class_t const *cls = reg->cls; unsigned *limited = rbitset_obstack_alloc(obst, cls->n_regs); rbitset_set(limited, reg->index); arch_register_req_t *req = OALLOCZ(obst, arch_register_req_t); req->cls = cls; req->limited = limited; req->width = 1; req->ignore = ignore; return req; }
arch_register_req_t const *be_create_reg_req(ir_graph *const irg, arch_register_t const *const reg, bool const ignore) { if (!ignore) return reg->single_req; struct obstack *const obst = be_get_be_obst(irg); arch_register_class_t const *const cls = reg->cls; unsigned *const limited = rbitset_obstack_alloc(obst, cls->n_regs); rbitset_set(limited, reg->index); arch_register_req_t *const req = OALLOCZ(obst, arch_register_req_t); req->cls = cls; req->limited = limited; req->width = 1; req->ignore = ignore; return req; }
x86_cconv_t *ia32_decide_calling_convention(ir_type *function_type, ir_graph *irg) { bool omit_fp = false; if (irg != NULL) { omit_fp = be_options.omit_fp; if (omit_fp) irg_walk_graph(irg, check_omit_fp, NULL, &omit_fp); } mtp_additional_properties mtp = get_method_additional_properties(function_type); (void)mtp; /* TODO: do something with cc_reg_param/cc_this_call */ unsigned *caller_saves = rbitset_malloc(N_IA32_REGISTERS); unsigned *callee_saves = rbitset_malloc(N_IA32_REGISTERS); rbitset_copy(caller_saves, default_caller_saves, N_IA32_REGISTERS); rbitset_copy(callee_saves, default_callee_saves, N_IA32_REGISTERS); /* determine how parameters are passed */ unsigned n_params = get_method_n_params(function_type); unsigned param_regnum = 0; unsigned float_param_regnum = 0; reg_or_stackslot_t *params = XMALLOCNZ(reg_or_stackslot_t, n_params); unsigned n_param_regs = ARRAY_SIZE(default_param_regs); unsigned n_float_param_regs = ARRAY_SIZE(float_param_regs); unsigned stack_offset = 0; for (unsigned i = 0; i < n_params; ++i) { ir_type *param_type = get_method_param_type(function_type, i); reg_or_stackslot_t *param = ¶ms[i]; if (is_aggregate_type(param_type)) { param->type = param_type; param->offset = stack_offset; stack_offset += get_type_size_bytes(param_type); goto align_stack; } ir_mode *mode = get_type_mode(param_type); if (mode_is_float(mode) && float_param_regnum < n_float_param_regs) { param->reg = float_param_regs[float_param_regnum++]; } else if (!mode_is_float(mode) && param_regnum < n_param_regs) { param->reg = default_param_regs[param_regnum++]; } else { param->type = param_type; param->offset = stack_offset; stack_offset += get_type_size_bytes(param_type); align_stack:; /* increase offset by at least IA32_REGISTER_SIZE bytes so * everything is aligned */ unsigned misalign = stack_offset % IA32_REGISTER_SIZE; if (misalign > 0) stack_offset += IA32_REGISTER_SIZE - misalign; } } unsigned n_param_regs_used = param_regnum + float_param_regnum; /* determine how results are passed */ unsigned n_results = get_method_n_ress(function_type); unsigned n_reg_results = 0; reg_or_stackslot_t *results = XMALLOCNZ(reg_or_stackslot_t, n_results); unsigned res_regnum = 0; unsigned res_float_regnum = 0; unsigned n_result_regs = ARRAY_SIZE(result_regs); unsigned n_float_result_regs = ARRAY_SIZE(float_result_regs); for (size_t i = 0; i < n_results; ++i) { ir_type *result_type = get_method_res_type(function_type, i); ir_mode *result_mode = get_type_mode(result_type); reg_or_stackslot_t *result = &results[i]; const arch_register_t *reg; if (mode_is_float(result_mode)) { if (res_float_regnum >= n_float_result_regs) { panic("too many floating points results"); } reg = float_result_regs[res_float_regnum++]; } else { if (res_regnum >= n_result_regs) { panic("too many results"); } reg = result_regs[res_regnum++]; } result->reg = reg; rbitset_clear(caller_saves, reg->global_index); ++n_reg_results; } calling_convention cc = get_method_calling_convention(function_type); x86_cconv_t *cconv = XMALLOCZ(x86_cconv_t); cconv->sp_delta = (cc & cc_compound_ret) && !(cc & cc_reg_param) ? IA32_REGISTER_SIZE : 0; cconv->parameters = params; cconv->n_parameters = n_params; cconv->callframe_size = stack_offset; cconv->n_param_regs = n_param_regs_used; cconv->n_xmm_regs = float_param_regnum; cconv->results = results; cconv->omit_fp = omit_fp; cconv->caller_saves = caller_saves; cconv->callee_saves = callee_saves; cconv->n_reg_results = n_reg_results; if (irg != NULL) { be_irg_t *birg = be_birg_from_irg(irg); size_t n_ignores = ARRAY_SIZE(ignore_regs); struct obstack *obst = &birg->obst; birg->allocatable_regs = rbitset_obstack_alloc(obst, N_IA32_REGISTERS); rbitset_set_all(birg->allocatable_regs, N_IA32_REGISTERS); for (size_t r = 0; r < n_ignores; ++r) { rbitset_clear(birg->allocatable_regs, ignore_regs[r]); } if (!omit_fp) rbitset_clear(birg->allocatable_regs, REG_EBP); } return cconv; }
calling_convention_t *sparc_decide_calling_convention(ir_type *function_type, ir_graph *irg) { bool omit_fp = false; if (irg != NULL) { omit_fp = be_options.omit_fp; /* our current vaarg handling needs the standard space to store the * args 0-5 in it */ if (get_method_variadicity(function_type) == variadicity_variadic) omit_fp = false; if (omit_fp == true) { irg_walk_graph(irg, check_omit_fp, NULL, &omit_fp); } } mtp_additional_properties mtp = get_method_additional_properties(function_type); unsigned *caller_saves = rbitset_malloc(N_SPARC_REGISTERS); if (mtp & mtp_property_returns_twice) { rbitset_copy(caller_saves, default_returns_twice_saves, N_SPARC_REGISTERS); } else { rbitset_copy(caller_saves, default_caller_saves, N_SPARC_REGISTERS); } /* determine how parameters are passed */ int n_params = get_method_n_params(function_type); int regnum = 0; reg_or_stackslot_t *params = XMALLOCNZ(reg_or_stackslot_t, n_params); int n_param_regs = ARRAY_SIZE(param_regs); unsigned stack_offset = 0; for (int i = 0; i < n_params; ++i) { ir_type *param_type = get_method_param_type(function_type,i); ir_mode *mode; int bits; reg_or_stackslot_t *param; if (is_compound_type(param_type)) panic("compound arguments not supported yet"); mode = get_type_mode(param_type); bits = get_mode_size_bits(mode); param = ¶ms[i]; if (i == 0 && (get_method_calling_convention(function_type) & cc_compound_ret)) { assert(mode_is_reference(mode) && bits == 32); /* special case, we have reserved space for this on the between * type */ param->type = param_type; param->offset = -SPARC_MIN_STACKSIZE+SPARC_AGGREGATE_RETURN_OFFSET; continue; } if (regnum < n_param_regs) { const arch_register_t *reg = param_regs[regnum]; if (irg == NULL || omit_fp) reg = map_i_to_o_reg(reg); param->reg0 = reg; param->req0 = reg->single_req; param->reg_offset = regnum; ++regnum; } else { param->type = param_type; param->offset = stack_offset; /* increase offset by at least SPARC_REGISTER_SIZE bytes so everything is aligned */ stack_offset += bits > 8 * SPARC_REGISTER_SIZE ? bits / 8 : SPARC_REGISTER_SIZE; continue; } /* we might need a 2nd 32bit component (for 64bit or double values) */ if (bits > 32) { if (bits > 64) panic("only 32 and 64bit modes supported"); if (regnum < n_param_regs) { const arch_register_t *reg = param_regs[regnum]; if (irg == NULL || omit_fp) reg = map_i_to_o_reg(reg); param->reg1 = reg; param->req1 = reg->single_req; ++regnum; } else { ir_mode *regmode = param_regs[0]->reg_class->mode; ir_type *type = get_type_for_mode(regmode); param->type = type; param->offset = stack_offset; assert(get_mode_size_bits(regmode) == 32); stack_offset += SPARC_REGISTER_SIZE; } } } unsigned n_param_regs_used = regnum; /* determine how results are passed */ int n_results = get_method_n_ress(function_type); unsigned float_regnum = 0; unsigned n_reg_results = 0; unsigned n_float_result_regs = ARRAY_SIZE(float_result_regs); reg_or_stackslot_t *results = XMALLOCNZ(reg_or_stackslot_t, n_results); regnum = 0; for (int i = 0; i < n_results; ++i) { ir_type *result_type = get_method_res_type(function_type, i); ir_mode *result_mode = get_type_mode(result_type); reg_or_stackslot_t *result = &results[i]; if (mode_is_float(result_mode)) { unsigned n_regs = determine_n_float_regs(result_mode); unsigned next_reg = round_up2(float_regnum, n_regs); if (next_reg >= n_float_result_regs) { panic("Too many float results"); } else { const arch_register_t *reg = float_result_regs[next_reg]; rbitset_clear(caller_saves, reg->global_index); result->reg_offset = i; if (n_regs == 1) { result->req0 = reg->single_req; } else if (n_regs == 2) { result->req0 = &float_result_reqs_double[next_reg]; rbitset_clear(caller_saves, reg->global_index+1); } else if (n_regs == 4) { result->req0 = &float_result_reqs_quad[next_reg]; rbitset_clear(caller_saves, reg->global_index+1); rbitset_clear(caller_saves, reg->global_index+2); rbitset_clear(caller_saves, reg->global_index+3); } else { panic("invalid number of registers in result"); } float_regnum = next_reg + n_regs; ++n_reg_results; } } else { if (get_mode_size_bits(result_mode) > 32) { panic("Results with more than 32bits not supported yet"); } if (regnum >= n_param_regs) { panic("Too many results"); } else { const arch_register_t *reg = param_regs[regnum++]; if (irg == NULL || omit_fp) reg = map_i_to_o_reg(reg); result->req0 = reg->single_req; result->reg_offset = i; rbitset_clear(caller_saves, reg->global_index); ++n_reg_results; } } } calling_convention_t *cconv = XMALLOCZ(calling_convention_t); cconv->parameters = params; cconv->param_stack_size = stack_offset; cconv->n_param_regs = n_param_regs_used; cconv->results = results; cconv->omit_fp = omit_fp; cconv->caller_saves = caller_saves; cconv->n_reg_results = n_reg_results; /* setup ignore register array */ if (irg != NULL) { be_irg_t *birg = be_birg_from_irg(irg); size_t n_ignores = ARRAY_SIZE(ignore_regs); struct obstack *obst = &birg->obst; size_t r; birg->allocatable_regs = rbitset_obstack_alloc(obst, N_SPARC_REGISTERS); rbitset_set_all(birg->allocatable_regs, N_SPARC_REGISTERS); for (r = 0; r < n_ignores; ++r) { rbitset_clear(birg->allocatable_regs, ignore_regs[r]); } } return cconv; }
x86_cconv_t *amd64_decide_calling_convention(ir_type *function_type, ir_graph *irg) { bool omit_fp = false; if (irg != NULL) { omit_fp = be_options.omit_fp; if (omit_fp) irg_walk_graph(irg, check_omit_fp, NULL, &omit_fp); } mtp_additional_properties mtp = get_method_additional_properties(function_type); unsigned *caller_saves = rbitset_malloc(N_AMD64_REGISTERS); unsigned *callee_saves = rbitset_malloc(N_AMD64_REGISTERS); if (mtp & mtp_property_returns_twice) panic("amd64: returns_twice calling convention NIY"); rbitset_copy(caller_saves, default_caller_saves, N_AMD64_REGISTERS); rbitset_copy(callee_saves, default_callee_saves, N_AMD64_REGISTERS); /* determine how parameters are passed */ size_t n_params = get_method_n_params(function_type); size_t param_regnum = 0; size_t float_param_regnum = 0; reg_or_stackslot_t *params = XMALLOCNZ(reg_or_stackslot_t, n_params); /* x64 always reserves space to spill the first 4 arguments to have it * easy in case of variadic functions. */ unsigned stack_offset = amd64_use_x64_abi ? 32 : 0; for (size_t i = 0; i < n_params; ++i) { ir_type *param_type = get_method_param_type(function_type,i); if (is_compound_type(param_type)) panic("amd64: compound arguments NIY"); ir_mode *mode = get_type_mode(param_type); int bits = get_mode_size_bits(mode); reg_or_stackslot_t *param = ¶ms[i]; if (mode_is_float(mode) && float_param_regnum < n_float_param_regs) { param->reg = float_param_regs[float_param_regnum++]; if (amd64_use_x64_abi) ++param_regnum; } else if (!mode_is_float(mode) && param_regnum < n_param_regs) { param->reg = param_regs[param_regnum++]; if (amd64_use_x64_abi) ++float_param_regnum; } else { param->type = param_type; param->offset = stack_offset; /* increase offset by at least AMD64_REGISTER_SIZE bytes so * everything is aligned */ stack_offset += MAX(bits / 8, AMD64_REGISTER_SIZE); continue; } } unsigned n_param_regs_used = amd64_use_x64_abi ? param_regnum : param_regnum + float_param_regnum; /* determine how results are passed */ size_t n_results = get_method_n_ress(function_type); unsigned n_reg_results = 0; reg_or_stackslot_t *results = XMALLOCNZ(reg_or_stackslot_t, n_results); unsigned res_regnum = 0; unsigned res_float_regnum = 0; size_t n_result_regs = ARRAY_SIZE(result_regs); size_t n_float_result_regs = ARRAY_SIZE(float_result_regs); for (size_t i = 0; i < n_results; ++i) { ir_type *result_type = get_method_res_type(function_type, i); ir_mode *result_mode = get_type_mode(result_type); reg_or_stackslot_t *result = &results[i]; const arch_register_t *reg; if (mode_is_float(result_mode)) { if (res_float_regnum >= n_float_result_regs) { panic("too many floating points results"); } reg = float_result_regs[res_float_regnum++]; } else { if (res_regnum >= n_result_regs) { panic("too many results"); } reg = result_regs[res_regnum++]; } result->reg = reg; rbitset_clear(caller_saves, reg->global_index); ++n_reg_results; } x86_cconv_t *cconv = XMALLOCZ(x86_cconv_t); cconv->parameters = params; cconv->callframe_size = stack_offset; cconv->n_param_regs = n_param_regs_used; cconv->n_xmm_regs = float_param_regnum; cconv->results = results; cconv->omit_fp = omit_fp; cconv->caller_saves = caller_saves; cconv->callee_saves = callee_saves; cconv->n_reg_results = n_reg_results; if (irg != NULL) { be_irg_t *birg = be_birg_from_irg(irg); size_t n_ignores = ARRAY_SIZE(ignore_regs); struct obstack *obst = &birg->obst; birg->allocatable_regs = rbitset_obstack_alloc(obst, N_AMD64_REGISTERS); rbitset_set_all(birg->allocatable_regs, N_AMD64_REGISTERS); for (size_t r = 0; r < n_ignores; ++r) { rbitset_clear(birg->allocatable_regs, ignore_regs[r]); } if (!omit_fp) rbitset_clear(birg->allocatable_regs, REG_RBP); } return cconv; }