summaryrefslogtreecommitdiffhomepage
path: root/ir/be/riscv/riscv_cconv.c
diff options
context:
space:
mode:
Diffstat (limited to 'ir/be/riscv/riscv_cconv.c')
-rw-r--r--ir/be/riscv/riscv_cconv.c29
1 files changed, 22 insertions, 7 deletions
diff --git a/ir/be/riscv/riscv_cconv.c b/ir/be/riscv/riscv_cconv.c
index 2cb74cf..3b5e8ab 100644
--- a/ir/be/riscv/riscv_cconv.c
+++ b/ir/be/riscv/riscv_cconv.c
@@ -6,6 +6,7 @@
#include "be_t.h"
#include "becconv.h"
#include "betranshlp.h"
+#include "bevarargs.h"
#include "gen_riscv_regalloc_if.h"
#include "irgwalk.h"
#include "riscv_bearch_t.h"
@@ -40,8 +41,11 @@ static void check_omit_fp(ir_node *node, void *env)
}
void riscv_determine_calling_convention(riscv_calling_convention_t *const cconv, ir_type *const fun_type,
- ir_graph *const irg)
+ unsigned named_parameters, ir_graph *const irg)
{
+ //int offset = is_method_variadic(fun_type) ? 0 : ARRAY_SIZE(regs_param_gp);
+ int offset = ARRAY_SIZE(regs_param_gp);
+
bool omit_fp = false;
if (irg != NULL) {
omit_fp = be_options.omit_fp;
@@ -54,6 +58,7 @@ void riscv_determine_calling_convention(riscv_calling_convention_t *const cconv,
riscv_reg_or_slot_t *params = NULL;
size_t gp_param = 0;
size_t const n_params = get_method_n_params(fun_type);
+ assert(is_method_variadic(fun_type) || named_parameters == n_params);
if (n_params != 0) {
params = XMALLOCNZ(riscv_reg_or_slot_t, n_params);
@@ -65,18 +70,23 @@ void riscv_determine_calling_convention(riscv_calling_convention_t *const cconv,
} else if (mode_is_float(param_mode)) {
panic("TODO");
} else {
- if (param_type->flags & tf_lowered_dw && gp_param % 2 != 0)
+ if (i >= named_parameters && param_type->flags & tf_lowered_dw && gp_param % 2 != 0) {
+ // variadic arguments with 2 x XLEN size have to be passed in an aligned register pair / stack slots
++gp_param;
+ }
if (gp_param < ARRAY_SIZE(regs_param_gp))
params[i].reg = &riscv_registers[regs_param_gp[gp_param]];
- params[i].offset = (gp_param - ARRAY_SIZE(regs_param_gp)) * RISCV_REGISTER_SIZE;
+ params[i].offset = (gp_param - offset) * RISCV_REGISTER_SIZE;
++gp_param;
}
}
}
- cconv->param_stack_size = gp_param * RISCV_REGISTER_SIZE;
- cconv->n_mem_param = gp_param > ARRAY_SIZE(regs_param_gp) ? gp_param - ARRAY_SIZE(regs_param_gp) : 0;
- cconv->parameters = params;
+
+ unsigned n_mem_param = gp_param > ARRAY_SIZE(regs_param_gp) ? gp_param - offset : 0;
+ cconv->param_stack_size = n_mem_param * RISCV_REGISTER_SIZE;
+ cconv->n_mem_param = n_mem_param;
+ cconv->parameters = params;
+ cconv->va_arg_first_slot = named_parameters;
/* Handle results. */
riscv_reg_or_slot_t *results = NULL;
@@ -122,7 +132,7 @@ void riscv_layout_parameter_entities(riscv_calling_convention_t *const cconv, ir
if (!is_atomic_type(param_type))
panic("unhandled parameter type");
ir_entity *param_ent = param_map[i];
- if (!param->reg) {
+ if (!param->reg || is_method_variadic(fun_type)) {
if (!param_ent)
param_ent = new_parameter_entity(frame_type, i, param_type);
assert(get_entity_offset(param_ent) == INVALID_OFFSET);
@@ -131,6 +141,11 @@ void riscv_layout_parameter_entities(riscv_calling_convention_t *const cconv, ir
param->entity = param_ent;
}
free(param_map);
+
+ if (is_method_variadic(fun_type)) {
+ int const offset = (cconv->va_arg_first_slot - RISCV_N_PARAM_REGS) * RISCV_REGISTER_SIZE;
+ cconv->va_start_addr = be_make_va_start_entity(frame_type, offset);
+ }
}
void riscv_free_calling_convention(riscv_calling_convention_t *const cconv)