summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--ir/be/riscv/riscv_bearch.c50
-rw-r--r--ir/be/riscv/riscv_bearch_t.h1
-rw-r--r--ir/be/riscv/riscv_cconv.c29
-rw-r--r--ir/be/riscv/riscv_cconv.h4
-rw-r--r--ir/be/riscv/riscv_transform.c134
-rw-r--r--ir/tr/type.c5
-rw-r--r--ir/tr/type_t.h9
7 files changed, 205 insertions, 27 deletions
diff --git a/ir/be/riscv/riscv_bearch.c b/ir/be/riscv/riscv_bearch.c
index da9f781..cb8fed8 100644
--- a/ir/be/riscv/riscv_bearch.c
+++ b/ir/be/riscv/riscv_bearch.c
@@ -16,6 +16,7 @@
#include "bestack.h"
#include "betranshlp.h"
#include "beutil.h"
+#include "bevarargs.h"
#include "gen_riscv_new_nodes.h"
#include "gen_riscv_regalloc_if.h"
#include "irarch.h"
@@ -27,6 +28,7 @@
#include "lower_builtins.h"
#include "lower_calls.h"
#include "lowering.h"
+#include "platform_t.h"
#include "riscv_emitter.h"
#include "riscv_lower64.h"
#include "riscv_transform.h"
@@ -85,6 +87,7 @@ static void riscv_init(void)
ir_target.allow_ifconv = riscv_ifconv;
ir_target.float_int_overflow = ir_overflow_indefinite;
+ ir_platform_set_va_list_type_pointer();
}
static void riscv_finish(void)
@@ -179,7 +182,7 @@ static ir_node *riscv_new_IncSP(ir_node *const block, ir_node *const sp, int con
return be_new_IncSP(block, sp, offset, align);
}
-static void riscv_introduce_prologue(ir_graph *const irg, unsigned const size, bool omit_fp)
+static void riscv_introduce_prologue(ir_graph *const irg, unsigned size, bool omit_fp, bool is_variadic)
{
ir_node *const start = get_irg_start(irg);
ir_node *const block = get_nodes_block(start);
@@ -196,6 +199,7 @@ static void riscv_introduce_prologue(ir_graph *const irg, unsigned const size, b
unsigned aligned = round_up2(size, 1u << RISCV_PO2_STACK_ALIGNMENT);
+ int fp_save_offset = is_variadic ? -(RISCV_N_PARAM_REGS + 1) * RISCV_REGISTER_SIZE : -RISCV_REGISTER_SIZE;
if (!is_simm12(aligned)) {
/* if desired size is not as 12 bit immediate encodeable, first compute the large offset in t0 */
riscv_hi_lo_imm imm = calc_hi_lo(aligned);
@@ -218,7 +222,7 @@ static void riscv_introduce_prologue(ir_graph *const irg, unsigned const size, b
sched_add_after(res, add);
/* save fp to stack */
- ir_node *const store_fp = new_bd_riscv_sw(NULL, block, mem, add, start_fp, NULL, -RISCV_REGISTER_SIZE);
+ ir_node *const store_fp = new_bd_riscv_sw(NULL, block, mem, add, start_fp, NULL, fp_save_offset);
sched_add_after(add, store_fp);
edges_reroute_except(mem, store_fp, store_fp);
@@ -229,7 +233,7 @@ static void riscv_introduce_prologue(ir_graph *const irg, unsigned const size, b
edges_reroute_except(start_fp, curr_fp, store_fp);
} else {
/* save fp to stack */
- ir_node *const store_fp = new_bd_riscv_sw(NULL, block, mem, start_sp, start_fp, NULL, aligned - RISCV_REGISTER_SIZE);
+ ir_node *const store_fp = new_bd_riscv_sw(NULL, block, mem, start_sp, start_fp, NULL, aligned + fp_save_offset);
sched_add_after(inc_sp, store_fp);
edges_reroute_except(mem, store_fp, store_fp);
@@ -248,7 +252,7 @@ static void riscv_introduce_prologue(ir_graph *const irg, unsigned const size, b
}
}
-static void riscv_introduce_epilogue(ir_node *const ret, unsigned const size, bool omit_fp)
+static void riscv_introduce_epilogue(ir_node *const ret, unsigned const size, bool omit_fp, bool is_variadic)
{
ir_node *const block = get_nodes_block(ret);
if (!omit_fp) {
@@ -257,7 +261,8 @@ static void riscv_introduce_epilogue(ir_node *const ret, unsigned const size, bo
ir_node *curr_mem = get_irn_n(ret, n_riscv_ret_mem);
/* restore old fp */
- ir_node *const load_old_fp = new_bd_riscv_lw(NULL, block, curr_mem, curr_fp, NULL, -RISCV_REGISTER_SIZE);
+ int fp_save_offset = is_variadic ? -(RISCV_N_PARAM_REGS + 1) * RISCV_REGISTER_SIZE : -RISCV_REGISTER_SIZE;
+ ir_node *const load_old_fp = new_bd_riscv_lw(NULL, block, curr_mem, curr_fp, NULL, fp_save_offset);
curr_mem = be_new_Proj(load_old_fp, pn_riscv_lw_M);
ir_node *const old_fp = be_new_Proj_reg(load_old_fp, pn_riscv_lw_res, &riscv_registers[REG_T0]);
sched_add_before(ret, load_old_fp);
@@ -287,8 +292,11 @@ static void riscv_introduce_epilogue(ir_node *const ret, unsigned const size, bo
static void riscv_introduce_prologue_epilogue(ir_graph *const irg, bool omit_fp)
{
ir_type *const frame = get_irg_frame_type(irg);
+ ir_entity *const fun_ent = get_irg_entity(irg);
+ ir_type *fun_type = get_entity_type(fun_ent);
unsigned size = get_type_size(frame);
- if (size == 0 && omit_fp)
+ bool is_variadic = is_method_variadic(fun_type);
+ if (size == 0 && omit_fp && !is_variadic)
return;
if (!omit_fp) {
@@ -296,12 +304,16 @@ static void riscv_introduce_prologue_epilogue(ir_graph *const irg, bool omit_fp)
size += RISCV_REGISTER_SIZE;
}
+ if (is_variadic) {
+ size += 32;
+ }
+
foreach_irn_in(get_irg_end_block(irg), i, ret) {
assert(is_riscv_ret(ret));
- riscv_introduce_epilogue(ret, size, omit_fp);
+ riscv_introduce_epilogue(ret, size, omit_fp, is_variadic);
}
- riscv_introduce_prologue(irg, size, omit_fp);
+ riscv_introduce_prologue(irg, size, omit_fp, is_variadic);
}
static void riscv_sp_sim(ir_node *const node, stack_pointer_state_t *const state)
@@ -340,8 +352,11 @@ static void riscv_sp_sim(ir_node *const node, stack_pointer_state_t *const state
}
imm->val += get_entity_offset(ent);
}
+ break;
}
-
+ case iro_riscv_SubSP:
+ case iro_riscv_SubSPimm:
+ state->align_padding = 0;
default:
break;
}
@@ -376,7 +391,10 @@ static void riscv_generate_code(FILE *const output, char const *const cup_name)
ir_type *const frame = get_irg_frame_type(irg);
be_sort_frame_entities(frame, omit_fp);
- be_layout_frame_type(frame, 0, 0);
+ ir_entity *const fun_ent = get_irg_entity(irg);
+ ir_type *fun_type = get_entity_type(fun_ent);
+ int begin = is_method_variadic(fun_type) ? -(RISCV_REGISTER_SIZE * RISCV_N_PARAM_REGS) : 0;
+ be_layout_frame_type(frame, begin, 0);
riscv_introduce_prologue_epilogue(irg, omit_fp);
be_fix_stack_nodes(irg, &riscv_registers[REG_SP]);
@@ -393,6 +411,12 @@ static void riscv_generate_code(FILE *const output, char const *const cup_name)
be_finish();
}
+static void riscv32_lower_va_arg(ir_node *node)
+{
+ be_default_lower_va_arg(node, false, 4);
+ //TODO RISC-V specific implementation needed due to alignment of variadic arguments
+}
+
static void riscv_lower_for_target(void)
{
ir_arch_lower(&riscv_arch_dep);
@@ -411,8 +435,12 @@ static void riscv_lower_for_target(void)
static ir_builtin_kind const supported[] = {
ir_bk_saturating_increment,
+ ir_bk_va_start
};
- lower_builtins(ARRAY_SIZE(supported), supported, NULL);
+ lower_builtins(ARRAY_SIZE(supported), supported, riscv32_lower_va_arg);
+ foreach_irp_irg(i, irg) {
+ be_after_transform(irg, "lower-builtins");
+ }
ir_mode *const mode_gp = riscv_reg_classes[CLASS_riscv_gp].mode;
foreach_irp_irg(i, irg) {
diff --git a/ir/be/riscv/riscv_bearch_t.h b/ir/be/riscv/riscv_bearch_t.h
index 6b5ccec..cc1a187 100644
--- a/ir/be/riscv/riscv_bearch_t.h
+++ b/ir/be/riscv/riscv_bearch_t.h
@@ -9,6 +9,7 @@
#define RISCV_MACHINE_SIZE 32
#define RISCV_PO2_STACK_ALIGNMENT 4
#define RISCV_REGISTER_SIZE 4
+#define RISCV_N_PARAM_REGS 8
#include <stdbool.h>
#include <stdint.h>
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)
diff --git a/ir/be/riscv/riscv_cconv.h b/ir/be/riscv/riscv_cconv.h
index 6763d1c..5e978c6 100644
--- a/ir/be/riscv/riscv_cconv.h
+++ b/ir/be/riscv/riscv_cconv.h
@@ -20,11 +20,13 @@ typedef struct riscv_calling_convention_t {
save/restore) */
unsigned param_stack_size;
unsigned n_mem_param;
+ unsigned va_arg_first_slot;
riscv_reg_or_slot_t *parameters;
riscv_reg_or_slot_t *results;
+ ir_entity *va_start_addr;
} riscv_calling_convention_t;
-void riscv_determine_calling_convention(riscv_calling_convention_t *cconv, ir_type *fun_type, ir_graph *irg);
+void riscv_determine_calling_convention(riscv_calling_convention_t *cconv, ir_type *fun_type, unsigned named_parameters, ir_graph *irg);
void riscv_layout_parameter_entities(riscv_calling_convention_t *cconv, ir_graph *irg);
diff --git a/ir/be/riscv/riscv_transform.c b/ir/be/riscv/riscv_transform.c
index a9e68ab..8ef9a15 100644
--- a/ir/be/riscv/riscv_transform.c
+++ b/ir/be/riscv/riscv_transform.c
@@ -25,6 +25,19 @@ static const unsigned ignore_regs[] = {
REG_T0,
};
+static unsigned const regs_param_gp[] = {
+ REG_A0,
+ REG_A1,
+ REG_A2,
+ REG_A3,
+ REG_A4,
+ REG_A5,
+ REG_A6,
+ REG_A7,
+};
+
+static ir_node *initial_va_list;
+
static unsigned const callee_saves[] = {
REG_FP,
REG_S1,
@@ -377,6 +390,21 @@ static ir_node *gen_saturating_increment(ir_node *const node)
return addu;
}
+static ir_node *gen_va_start(ir_node *node)
+{
+ if (initial_va_list == NULL) {
+ dbg_info *dbgi = get_irn_dbg_info(node);
+ ir_graph *irg = get_irn_irg(node);
+ ir_node *block = get_irg_start_block(irg);
+ ir_entity *entity = cur_cconv.va_start_addr;
+ ir_node *frame = cur_cconv.omit_fp ? get_Start_sp(irg): get_Start_fp(irg);
+ ir_node *ap = new_bd_riscv_FrameAddr(dbgi, block, frame, entity, 0);
+ arch_add_irn_flags(ap, (arch_irn_flags_t)riscv_arch_irn_flag_ignore_fp_offset_fix);
+ initial_va_list = ap;
+ }
+ return initial_va_list;
+}
+
static ir_node *gen_Builtin(ir_node *const node)
{
ir_builtin_kind const kind = get_Builtin_kind(node);
@@ -399,8 +427,9 @@ static ir_node *gen_Builtin(ir_node *const node)
case ir_bk_return_address:
case ir_bk_trap:
case ir_bk_va_arg:
- case ir_bk_va_start:
TODO(node);
+ case ir_bk_va_start:
+ return gen_va_start(node);
}
panic("unexpected Builtin");
}
@@ -428,9 +457,16 @@ static ir_node *gen_Call(ir_node *const node)
ir_type *const fun_type = get_Call_type(node);
record_returns_twice(irg, fun_type);
+ unsigned named_params = get_method_n_params(fun_type);
+ if (callee) {
+ ir_type *const callee_type = get_entity_type(callee);
+ if (is_Method_type(callee_type) && is_method_variadic(callee_type)) {
+ named_params = get_method_variadic_index(callee_type);
+ }
+ }
riscv_calling_convention_t cconv;
- riscv_determine_calling_convention(&cconv, fun_type, NULL);
+ riscv_determine_calling_convention(&cconv, fun_type, named_params, NULL);
ir_node *mems[1 + cconv.n_mem_param];
unsigned m = 0;
@@ -815,6 +851,7 @@ static ir_node *gen_Proj_Builtin(ir_node *const node)
ir_node *const pred = get_Proj_pred(node);
ir_node *const new_pred = be_transform_node(pred);
ir_builtin_kind const kind = get_Builtin_kind(pred);
+ unsigned const pn = get_Proj_num(node);
switch (kind) {
case ir_bk_saturating_increment:
assert(get_Proj_num(node) == pn_Builtin_max + 1);
@@ -835,9 +872,16 @@ static ir_node *gen_Proj_Builtin(ir_node *const node)
case ir_bk_prefetch:
case ir_bk_return_address:
case ir_bk_trap:
+ TODO(node);
case ir_bk_va_arg:
+ break;
case ir_bk_va_start:
- TODO(node);
+ if (pn == pn_Builtin_M) {
+ return be_transform_node(get_Builtin_mem(pred));
+ } else {
+ assert(pn == pn_Builtin_max+1);
+ return new_pred;
+ }
}
panic("unexpected Builtin");
}
@@ -910,7 +954,8 @@ static ir_node *gen_Proj_Proj_Call(ir_node *const node)
ir_type *const fun_type = get_Call_type(ocall);
riscv_calling_convention_t cconv;
- riscv_determine_calling_convention(&cconv, fun_type, NULL);
+ //get_method_n_params is not correct but irrelevant in this case
+ riscv_determine_calling_convention(&cconv, fun_type, get_method_n_params(fun_type), NULL);
ir_node *const call = be_transform_node(ocall);
unsigned const num = get_Proj_num(node);
@@ -1131,7 +1176,13 @@ static ir_node *gen_Store(ir_node *const node)
ir_node *const mem = be_transform_node(get_Store_mem(node));
ir_node *const val = be_transform_node(old_val);
riscv_addr const addr = make_addr(get_Store_ptr(node));
- return cons(dbgi, block, mem, addr.base, val, addr.ent, addr.val);
+ ir_node *const store = cons(dbgi, block, mem, addr.base, val, addr.ent, addr.val);
+
+ if (addr.ent && is_parameter_entity(addr.ent) ) {
+ arch_add_irn_flags(store, (arch_irn_flags_t)riscv_arch_irn_flag_ignore_fp_offset_fix);
+ }
+
+ return store;
}
TODO(node);
}
@@ -1234,6 +1285,48 @@ static void riscv_register_transformers(void)
be_set_transform_proj_function(op_Store, gen_Proj_Store);
}
+static bool riscv_variadic_fixups(ir_graph *const irg)
+{
+ ir_entity *entity = get_irg_entity(irg);
+ ir_type *mtp = get_entity_type(entity);
+ if (!is_method_variadic(mtp))
+ return false;
+
+ size_t const n_params = get_method_n_params(mtp);
+ if (n_params >= ARRAY_SIZE(regs_param_gp))
+ return false;
+ size_t const n_ress = get_method_n_ress(mtp);
+ size_t const new_n_params = ARRAY_SIZE(regs_param_gp);
+ unsigned const cc_mask = get_method_calling_convention(mtp);
+ mtp_additional_properties const props = get_method_additional_properties(mtp);
+ ir_type *const new_mtp = new_type_method(new_n_params, n_ress, true, cc_mask, props);
+
+ // preserve information about the number of named parameters
+ set_method_variadic_index(new_mtp, get_method_variadic_index(mtp));
+
+ type_dbg_info *const dbgi = get_type_dbg_info(mtp);
+ set_type_dbg_info(new_mtp, dbgi);
+
+ for (size_t i = 0; i < n_ress; ++i) {
+ ir_type *type = get_method_res_type(mtp, i);
+ set_method_res_type(new_mtp, i, type);
+ }
+ for (size_t i = 0; i < n_params; ++i) {
+ ir_type *type = get_method_param_type(mtp, i);
+ set_method_param_type(new_mtp, i, type);
+ }
+ ir_type *const frame_type = get_irg_frame_type(irg);
+ ir_mode *const gp_reg_mode = riscv_reg_classes[CLASS_riscv_gp].mode;
+ ir_type *const gp_reg_type = get_type_for_mode(gp_reg_mode);
+ for (size_t i = n_params; i < new_n_params; ++i) {
+ set_method_param_type(new_mtp, i, gp_reg_type);
+ new_parameter_entity(frame_type, i, gp_reg_type);
+ }
+
+ set_entity_type(entity, new_mtp);
+ return true;
+}
+
static void riscv_set_allocatable_regs(ir_graph *const irg)
{
be_irg_t *const birg = be_birg_from_irg(irg);
@@ -1258,12 +1351,37 @@ void riscv_transform_graph(ir_graph *const irg)
be_stack_init(&stack_env);
ir_entity *const fun_ent = get_irg_entity(irg);
- ir_type *const fun_type = get_entity_type(fun_ent);
- riscv_determine_calling_convention(&cur_cconv, fun_type, irg);
+ ir_type *fun_type = get_entity_type(fun_ent);
+ unsigned named_params = is_method_variadic(fun_type) ? (unsigned) get_method_variadic_index(fun_type)
+ : get_method_n_params(fun_type);
+
+ if(riscv_variadic_fixups(irg)) {
+ fun_type = get_entity_type(fun_ent);
+ }
+ riscv_determine_calling_convention(&cur_cconv, fun_type, named_params, irg);
riscv_layout_parameter_entities(&cur_cconv, irg);
- be_add_parameter_entity_stores(irg);
+
+ ir_entity *need_stores[ARRAY_SIZE(regs_param_gp)];
+ unsigned n_stores = 0;
+ ir_entity *entity;
+ if (is_method_variadic(fun_type)) {
+ for (size_t i = 0; i < ARRAY_SIZE(regs_param_gp); ++i) {
+ riscv_reg_or_slot_t const *const param = &cur_cconv.parameters[i];
+ entity = param->entity;
+ if (entity == NULL)
+ continue;
+ assert(n_stores < ARRAY_SIZE(regs_param_gp));
+ need_stores[n_stores++] = entity;
+ }
+ be_add_parameter_entity_stores_list(irg, n_stores, need_stores);
+ //TODO optimize?
+ } else {
+ be_add_parameter_entity_stores(irg);
+ }
+
be_transform_graph(irg, NULL);
riscv_free_calling_convention(&cur_cconv);
be_stack_finish(&stack_env);
+ initial_va_list = NULL;
}
diff --git a/ir/tr/type.c b/ir/tr/type.c
index 581b3cc..7d34783 100644
--- a/ir/tr/type.c
+++ b/ir/tr/type.c
@@ -617,6 +617,11 @@ int get_method_variadic_index(ir_type const *const method) {
return method->attr.method.variadic;
}
+void set_method_variadic_index(ir_type *const method, int variadic_index) {
+ assert(is_Method_type(method) && variadic_index >= -1);
+ method->attr.method.variadic = variadic_index;
+}
+
mtp_additional_properties (get_method_additional_properties)(const ir_type *method)
{
return get_method_additional_properties_(method);
diff --git a/ir/tr/type_t.h b/ir/tr/type_t.h
index 35bfb3f..dfa357d 100644
--- a/ir/tr/type_t.h
+++ b/ir/tr/type_t.h
@@ -318,6 +318,15 @@ static inline size_t get_method_n_ress_(const ir_type *method)
int get_method_variadic_index(ir_type const *const method);
+/**
+ * Set the variadic index of a method.
+ * Values >= 0 represent the index of the first variadic parameter which equals the number of named parameters.
+ * A value of -1 marks the method as not variadic.
+ * @param method
+ * @param variadic_index >= -1
+ */
+void set_method_variadic_index(ir_type *const method, int variadic_index);
+
static inline mtp_additional_properties get_method_additional_properties_(const ir_type *method)
{
assert(is_Method_type(method));