Commit fd5331da authored by Matthias Braun's avatar Matthias Braun
Browse files

arm: implement calling conventions for float and double parameter

[r27737]
parent ce972cd9
......@@ -40,10 +40,13 @@ calling_convention_t *decide_calling_convention(ir_type *function_type)
= sizeof(param_regs)/sizeof(param_regs[0]);
int n_result_regs
= sizeof(result_regs)/sizeof(result_regs[0]);
int n_float_result_regs
= sizeof(float_result_regs)/sizeof(float_result_regs[0]);
int n_params;
int n_results;
int i;
int regnum;
int float_regnum;
calling_convention_t *cconv;
/* determine how parameters are passed */
......@@ -56,15 +59,15 @@ calling_convention_t *decide_calling_convention(ir_type *function_type)
ir_mode *mode = get_type_mode(param_type);
int bits = get_mode_size_bits(mode);
reg_or_stackslot_t *param = &params[i];
param->type = param_type;
if (regnum < n_param_regs) {
const arch_register_t *reg = param_regs[regnum++];
param->reg0 = reg;
} else {
param->type = param_type;
param->offset = stack_offset;
/* increase offset 4 bytes so everything is aligned */
stack_offset += 4;
stack_offset += bits > 32 ? bits/8 : 4;
continue;
}
......@@ -81,28 +84,39 @@ calling_convention_t *decide_calling_convention(ir_type *function_type)
ir_type *type = get_type_for_mode(mode);
param->type = type;
param->offset = stack_offset;
assert(get_mode_size_bits(mode) == 32);
stack_offset += 4;
}
}
}
n_results = get_method_n_ress(function_type);
regnum = 0;
results = XMALLOCNZ(reg_or_stackslot_t, n_results);
n_results = get_method_n_ress(function_type);
regnum = 0;
float_regnum = 0;
results = XMALLOCNZ(reg_or_stackslot_t, n_results);
for (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 (get_mode_size_bits(result_mode) > 32) {
panic("Results with more than 32bits not supported by arm backend yet");
}
if (regnum >= n_result_regs) {
panic("Too many results for arm backend");
if (mode_is_float(result_mode)) {
if (float_regnum >= n_float_result_regs) {
panic("Too many float results for arm backend");
} else {
const arch_register_t *reg = float_result_regs[float_regnum++];
result->reg0 = reg;
}
} else {
const arch_register_t *reg = result_regs[regnum++];
result->reg0 = reg;
if (get_mode_size_bits(result_mode) > 32) {
panic("Results with more than 32bits not supported by arm backend yet");
}
if (regnum >= n_result_regs) {
panic("Too many results for arm backend");
} else {
const arch_register_t *reg = result_regs[regnum++];
result->reg0 = reg;
}
}
}
......
......@@ -47,7 +47,16 @@ static const arch_register_t *const caller_saves[] = {
&arm_gp_regs[REG_R1],
&arm_gp_regs[REG_R2],
&arm_gp_regs[REG_R3],
&arm_gp_regs[REG_LR]
&arm_gp_regs[REG_LR],
&arm_fpa_regs[REG_F0],
&arm_fpa_regs[REG_F1],
&arm_fpa_regs[REG_F2],
&arm_fpa_regs[REG_F3],
&arm_fpa_regs[REG_F4],
&arm_fpa_regs[REG_F5],
&arm_fpa_regs[REG_F6],
&arm_fpa_regs[REG_F7],
};
static const arch_register_t* const param_regs[] = {
......@@ -64,6 +73,11 @@ static const arch_register_t* const result_regs[] = {
&arm_gp_regs[REG_R3]
};
static const arch_register_t* const float_result_regs[] = {
&arm_fpa_regs[REG_F0],
&arm_fpa_regs[REG_F1]
};
/** information about a single parameter or result */
typedef struct reg_or_stackslot_t
{
......
......@@ -134,27 +134,18 @@ static const arch_register_t *get_out_reg(const ir_node *node, int pos)
return reg;
}
/**
* Emit the name of the source register at given input position.
*/
void arm_emit_source_register(const ir_node *node, int pos)
{
const arch_register_t *reg = get_in_reg(node, pos);
be_emit_string(arch_register_get_name(reg));
}
/**
* Emit the name of the destination register at given output position.
*/
void arm_emit_dest_register(const ir_node *node, int pos)
{
const arch_register_t *reg = get_out_reg(node, pos);
be_emit_string(arch_register_get_name(reg));
}
/**
* Emit a node's offset.
*/
void arm_emit_offset(const ir_node *node)
{
const arm_load_store_attr_t *attr = get_arm_load_store_attr_const(node);
......@@ -178,20 +169,16 @@ static void arm_emit_fpa_postfix(const ir_mode *mode)
be_emit_char(c);
}
/**
* Emit the instruction suffix depending on the mode.
*/
void arm_emit_mode(const ir_node *node)
void arm_emit_float_load_store_mode(const ir_node *node)
{
ir_mode *mode;
const arm_load_store_attr_t *attr = get_arm_load_store_attr_const(node);
arm_emit_fpa_postfix(attr->load_store_mode);
}
if (is_arm_irn(node)) {
const arm_attr_t *attr = get_arm_attr_const(node);
mode = attr->op_mode ? attr->op_mode : get_irn_mode(node);
} else {
mode = get_irn_mode(node);
}
arm_emit_fpa_postfix(mode);
void arm_emit_float_arithmetic_mode(const ir_node *node)
{
const arm_farith_attr_t *attr = get_arm_farith_attr_const(node);
arm_emit_fpa_postfix(attr->mode);
}
void arm_emit_symconst(const ir_node *node)
......@@ -374,13 +361,13 @@ static void emit_arm_FrameAddr(const ir_node *irn)
/**
* Emit a floating point fpa constant.
*/
static void emit_arm_fpaConst(const ir_node *irn)
static void emit_arm_fConst(const ir_node *irn)
{
sym_or_tv_t key, *entry;
unsigned label;
ir_mode *mode;
key.u.tv = get_fpaConst_value(irn);
key.u.tv = get_fConst_value(irn);
key.is_entity = false;
key.label = 0;
entry = (sym_or_tv_t *)set_insert(sym_or_tv, &key, sizeof(key), HASH_PTR(key.u.generic));
......@@ -795,7 +782,6 @@ static void emit_be_Copy(const ir_node *irn)
if (mode_is_float(mode)) {
if (USE_FPA(cg->isa)) {
be_emit_cstring("\tmvf");
arm_emit_mode(irn);
be_emit_char(' ');
arm_emit_dest_register(irn, 0);
be_emit_cstring(", ");
......@@ -912,32 +898,6 @@ static void emit_arm_Jmp(const ir_node *node)
be_emit_finish_line_gas(node);
}
static void emit_arm_fpaDbl2GP(const ir_node *irn)
{
be_emit_cstring("\tstfd ");
arm_emit_source_register(irn, 0);
be_emit_cstring(", [sp, #-8]!");
be_emit_pad_comment();
be_emit_cstring("/* Push fp to stack */");
be_emit_finish_line_gas(NULL);
be_emit_cstring("\tldmfd sp!, {");
arm_emit_dest_register(irn, 1);
be_emit_cstring(", ");
arm_emit_dest_register(irn, 0);
be_emit_char('}');
be_emit_pad_comment();
be_emit_cstring("/* Pop destination */");
be_emit_finish_line_gas(irn);
}
static void emit_arm_LdTls(const ir_node *irn)
{
(void) irn;
panic("TLS not supported for this target");
/* Er... our gcc does not support it... Install a newer toolchain. */
}
static void emit_nothing(const ir_node *irn)
{
(void) irn;
......@@ -969,28 +929,26 @@ static void arm_register_emitters(void)
arm_register_spec_emitters();
/* custom emitter */
set_emitter(op_arm_B, emit_arm_B);
set_emitter(op_arm_CopyB, emit_arm_CopyB);
set_emitter(op_arm_fpaConst, emit_arm_fpaConst);
set_emitter(op_arm_fpaDbl2GP, emit_arm_fpaDbl2GP);
set_emitter(op_arm_FrameAddr, emit_arm_FrameAddr);
set_emitter(op_arm_Jmp, emit_arm_Jmp);
set_emitter(op_arm_LdTls, emit_arm_LdTls);
set_emitter(op_arm_SwitchJmp, emit_arm_SwitchJmp);
set_emitter(op_arm_SymConst, emit_arm_SymConst);
set_emitter(op_be_Call, emit_be_Call);
set_emitter(op_be_Copy, emit_be_Copy);
set_emitter(op_be_CopyKeep, emit_be_Copy);
set_emitter(op_be_IncSP, emit_be_IncSP);
set_emitter(op_be_MemPerm, emit_be_MemPerm);
set_emitter(op_be_Perm, emit_be_Perm);
set_emitter(op_be_Return, emit_be_Return);
set_emitter(op_arm_B, emit_arm_B);
set_emitter(op_arm_CopyB, emit_arm_CopyB);
set_emitter(op_arm_fConst, emit_arm_fConst);
set_emitter(op_arm_FrameAddr, emit_arm_FrameAddr);
set_emitter(op_arm_Jmp, emit_arm_Jmp);
set_emitter(op_arm_SwitchJmp, emit_arm_SwitchJmp);
set_emitter(op_arm_SymConst, emit_arm_SymConst);
set_emitter(op_be_Call, emit_be_Call);
set_emitter(op_be_Copy, emit_be_Copy);
set_emitter(op_be_CopyKeep, emit_be_Copy);
set_emitter(op_be_IncSP, emit_be_IncSP);
set_emitter(op_be_MemPerm, emit_be_MemPerm);
set_emitter(op_be_Perm, emit_be_Perm);
set_emitter(op_be_Return, emit_be_Return);
/* no need to emit anything for the following nodes */
set_emitter(op_Phi, emit_nothing);
set_emitter(op_be_Keep, emit_nothing);
set_emitter(op_be_Start, emit_nothing);
set_emitter(op_be_Barrier, emit_nothing);
set_emitter(op_Phi, emit_nothing);
set_emitter(op_be_Keep, emit_nothing);
set_emitter(op_be_Start, emit_nothing);
set_emitter(op_be_Barrier, emit_nothing);
}
/**
......@@ -1109,9 +1067,6 @@ static int cmp_sym_or_tv(const void *elt, const void *key, size_t size)
return p1->u.generic != p2->u.generic;
}
/**
* Main driver. Emits the code for one routine.
*/
void arm_gen_routine(const arm_code_gen_t *arm_cg, ir_graph *irg)
{
ir_node **blk_sched;
......
......@@ -35,7 +35,8 @@
#include "bearch_arm_t.h"
void arm_emit_mode(const ir_node *node);
void arm_emit_float_load_store_mode(const ir_node *node);
void arm_emit_float_arithmetic_mode(const ir_node *node);
void arm_emit_symconst(const ir_node *node);
void arm_emit_source_register(const ir_node *node, int pos);
void arm_emit_dest_register(const ir_node *node, int pos);
......
......@@ -72,7 +72,8 @@ static bool arm_has_symconst_attr(const ir_node *node)
static bool has_load_store_attr(const ir_node *node)
{
return is_arm_Ldr(node) || is_arm_Str(node) || is_arm_LinkLdrPC(node);
return is_arm_Ldr(node) || is_arm_Str(node) || is_arm_LinkLdrPC(node)
|| is_arm_Ldf(node) || is_arm_Stf(node);
}
static bool has_shifter_operand(const ir_node *node)
......@@ -88,6 +89,11 @@ static bool has_cmp_attr(const ir_node *node)
return is_arm_Cmp(node) || is_arm_Tst(node);
}
static bool has_farith_attr(const ir_node *node)
{
return is_arm_Dvf(node) || is_arm_Adf(node);
}
/**
* Dumper interface for dumping arm nodes in vcg.
* @param F the output file
......@@ -197,6 +203,10 @@ static void arm_dump_node(FILE *F, ir_node *n, dump_reason_t reason)
fputc('\n', F);
fprintf(F, "frame offset = %d\n", attr->fp_offset);
}
if (has_farith_attr(n)) {
const arm_farith_attr_t *attr = get_arm_farith_attr_const(n);
ir_fprintf(F, "arithmetic mode = %+F\n", attr->mode);
}
break;
}
}
......@@ -230,21 +240,28 @@ const arm_SymConst_attr_t *get_arm_SymConst_attr_const(const ir_node *node)
return get_irn_generic_attr_const(node);
}
static const arm_fpaConst_attr_t *get_arm_fpaConst_attr_const(
const ir_node *node)
static const arm_fConst_attr_t *get_arm_fConst_attr_const(const ir_node *node)
{
const arm_attr_t *attr = get_arm_attr_const(node);
const arm_fpaConst_attr_t *fpa_attr = CONST_CAST_ARM_ATTR(arm_fpaConst_attr_t, attr);
assert(is_arm_fConst(node));
return get_irn_generic_attr_const(node);
}
return fpa_attr;
static arm_fConst_attr_t *get_arm_fConst_attr(ir_node *node)
{
assert(is_arm_fConst(node));
return get_irn_generic_attr(node);
}
static arm_fpaConst_attr_t *get_arm_fpaConst_attr(ir_node *node)
arm_farith_attr_t *get_arm_farith_attr(ir_node *node)
{
arm_attr_t *attr = get_arm_attr(node);
arm_fpaConst_attr_t *fpa_attr = CAST_ARM_ATTR(arm_fpaConst_attr_t, attr);
assert(has_farith_attr(node));
return get_irn_generic_attr(node);
}
return fpa_attr;
const arm_farith_attr_t *get_arm_farith_attr_const(const ir_node *node)
{
assert(has_farith_attr(node));
return get_irn_generic_attr_const(node);
}
arm_CondJmp_attr_t *get_arm_CondJmp_attr(ir_node *node)
......@@ -289,15 +306,15 @@ void set_arm_req_in(ir_node *node, const arch_register_req_t *req, int pos)
attr->in_req[pos] = req;
}
tarval *get_fpaConst_value(const ir_node *node)
tarval *get_fConst_value(const ir_node *node)
{
const arm_fpaConst_attr_t *attr = get_arm_fpaConst_attr_const(node);
const arm_fConst_attr_t *attr = get_arm_fConst_attr_const(node);
return attr->tv;
}
void set_fpaConst_value(ir_node *node, tarval *tv)
void set_fConst_value(ir_node *node, tarval *tv)
{
arm_fpaConst_attr_t *attr = get_arm_fpaConst_attr(node);
arm_fConst_attr_t *attr = get_arm_fConst_attr(node);
attr->tv = tv;
}
......@@ -351,7 +368,6 @@ static void init_arm_attributes(ir_node *node, int flags,
arch_irn_set_flags(node, flags);
attr->in_req = in_reqs;
attr->instr_fl = 0;
info = be_get_info(node);
info->out_infos = NEW_ARR_D(reg_out_info_t, obst, n_res);
......@@ -397,6 +413,12 @@ static void init_arm_SymConst_attributes(ir_node *res, ir_entity *entity,
attr->fp_offset = symconst_offset;
}
static void init_arm_farith_attributes(ir_node *res, ir_mode *mode)
{
arm_farith_attr_t *attr = get_irn_generic_attr(res);
attr->mode = mode;
}
static void init_arm_CopyB_attributes(ir_node *res, unsigned size)
{
arm_CopyB_attr_t *attr = get_irn_generic_attr(res);
......@@ -405,9 +427,9 @@ static void init_arm_CopyB_attributes(ir_node *res, unsigned size)
static int cmp_attr_arm(ir_node *a, ir_node *b)
{
arm_attr_t *attr_a = get_irn_generic_attr(a);
arm_attr_t *attr_b = get_irn_generic_attr(b);
return attr_a->instr_fl != attr_b->instr_fl;
(void) a;
(void) b;
return 0;
}
static int cmp_attr_arm_SymConst(ir_node *a, ir_node *b)
......@@ -453,16 +475,16 @@ static int cmp_attr_arm_SwitchJmp(ir_node *a, ir_node *b)
return 1;
}
static int cmp_attr_arm_fpaConst(ir_node *a, ir_node *b)
static int cmp_attr_arm_fConst(ir_node *a, ir_node *b)
{
const arm_fpaConst_attr_t *attr_a;
const arm_fpaConst_attr_t *attr_b;
const arm_fConst_attr_t *attr_a;
const arm_fConst_attr_t *attr_b;
if (cmp_attr_arm(a, b))
return 1;
attr_a = get_arm_fpaConst_attr_const(a);
attr_b = get_arm_fpaConst_attr_const(b);
attr_a = get_arm_fConst_attr_const(a);
attr_b = get_arm_fConst_attr_const(b);
return attr_a->tv != attr_b->tv;
}
......@@ -551,6 +573,19 @@ static int cmp_attr_arm_cmp(ir_node *a, ir_node *b)
return 0;
}
static int cmp_attr_arm_farith(ir_node *a, ir_node *b)
{
const arm_farith_attr_t *attr_a;
const arm_farith_attr_t *attr_b;
if (cmp_attr_arm(a, b))
return 1;
attr_a = get_arm_farith_attr_const(a);
attr_b = get_arm_farith_attr_const(b);
return attr_a->mode != attr_b->mode;
}
/** copies the ARM attributes of a node. */
static void arm_copy_attr(ir_graph *irg, const ir_node *old_node,
ir_node *new_node)
......
......@@ -62,6 +62,9 @@ const arm_shifter_operand_t *get_arm_shifter_operand_attr_const(const ir_node *n
arm_cmp_attr_t *get_arm_cmp_attr(ir_node *node);
const arm_cmp_attr_t *get_arm_cmp_attr_const(const ir_node *node);
arm_farith_attr_t *get_arm_farith_attr(ir_node *node);
const arm_farith_attr_t *get_arm_farith_attr_const(const ir_node *node);
void set_arm_in_req_all(ir_node *node, const arch_register_req_t **reqs);
/**
......@@ -75,14 +78,14 @@ const arch_register_req_t *get_arm_in_req(const ir_node *node, int pos);
void set_arm_req_in(ir_node *node, const arch_register_req_t *req, int pos);
/**
* Return the tarval of a fpaConst
* Return the tarval of a fConst
*/
tarval *get_fpaConst_value(const ir_node *node);
tarval *get_fConst_value(const ir_node *node);
/**
* Sets the tarval of a fpaConst
* Sets the tarval of a fConst
*/
void set_fpaConst_value(ir_node *node, tarval *tv);
void set_fConst_value(ir_node *node, tarval *tv);
/**
* Returns the compare kind
......
......@@ -48,13 +48,6 @@ typedef enum arm_shift_modifier_t {
ARM_SHF_RRX, /**< rotate right through carry bits */
} arm_shift_modifier_t;
/** fpa immediate bit */
#define ARM_FPA_IMM (1 << 3) /**< fpa floating point immediate */
#define ARM_GET_FPA_IMM(attr) ((attr)->instr_fl & ARM_FPA_IMM)
#define ARM_SET_FPA_IMM(attr) ((attr)->instr_fl |= ARM_FPA_IMM)
#define ARM_CLR_FPA_IMM(attr) ((attr)->instr_fl &= ~ARM_FPA_IMM)
/** Encoding for fpa immediates */
enum fpa_immediates {
fpa_null = 0,
......@@ -70,13 +63,9 @@ enum fpa_immediates {
/** Generic ARM node attributes. */
typedef struct arm_attr_t {
except_attr exc; /**< the exception attribute. MUST be the first one. */
except_attr exc; /**< the exception attribute. MUST be the first one. */
const arch_register_req_t **in_req; /**< register requirements for arguments */
ir_mode *op_mode; /**< operation mode if different from node's mode (used for fpa nodes) */
unsigned instr_fl; /**< deprecated (was sometimes used for shift modifiers) */
bool is_load_store : 1;
bool is_load_store : 1;
} arm_attr_t;
/**
......@@ -130,16 +119,22 @@ typedef struct arm_SwitchJmp_attr_t {
} arm_SwitchJmp_attr_t;
/** CopyB attributes */
typedef struct {
typedef struct arm_CopyB_attr_t {
arm_attr_t base;
unsigned size;
} arm_CopyB_attr_t;
/** Attributes for a fpaConst */
typedef struct arm_fpaConst_attr_t {
/** Attributes for a fConst */
typedef struct arm_fConst_attr_t {
arm_attr_t base;
tarval *tv; /**< the tarval representing the FP const */
} arm_fpaConst_attr_t;
} arm_fConst_attr_t;
/** attributes for floatingpoint arithmetic operations */
typedef struct arm_farith_attr_t {
arm_attr_t base;
ir_mode *mode; /* operation mode */
} arm_farith_attr_t;
/**
* Return the fpa immediate from the encoding.
......
# Creation: 2006/02/13
# Arm Architecure Specification
# Author: Matthias Braun, Michael Beck, Oliver Richter, Tobias Gneist
# $Id$
# the cpu architecture (ia32, ia64, mips, sparc, ppc, ...)
$arch = "arm";
#
# Modes
#
$mode_gp = "mode_Iu";
$mode_flags = "mode_Bu";
$mode_fpa = "mode_E";
$mode_gp = "mode_Iu";
$mode_flags = "mode_Bu";
$mode_fp = "mode_E";
# register types:
$normal = 0; # no special type
......@@ -41,7 +41,7 @@ $state = 32; # register represents a state
{ name => "pc", type => $ignore }, # this is our program counter
{ mode => $mode_gp }
],
fpa => [
fpa => [
{ name => "f0", type => $caller_save },
{ name => "f1", type => $caller_save },
{ name => "f2", type => $caller_save },
......@@ -50,7 +50,7 @@ $state = 32; # register represents a state
{ name => "f5", type => $caller_save },
{ name => "f6", type => $caller_save },
{ name => "f7", type => $caller_save },
{ mode => $mode_fpa }
{ mode => $mode_fp }
],
flags => [
{ name => "fl", type => 0 },
......@@ -59,7 +59,8 @@ $state = 32; # register represents a state
);
%emit_templates = (
M => "${arch}_emit_mode(node);",
FM => "${arch}_emit_float_load_store_mode(node);",
AM => "${arch}_emit_float_arithmetic_mode(node);",
LM => "${arch}_emit_load_mode(node);",
SM => "${arch}_emit_store_mode(node);",
SO => "${arch}_emit_shifter_operand(node);",
......@@ -85,7 +86,7 @@ $default_copy_attr = "arm_copy_attr";
"\tinit_arm_SymConst_attributes(res, entity, symconst_offset);",
arm_CondJmp_attr_t => "\tinit_arm_attributes(res, flags, in_reqs, exec_units, n_res);",
arm_SwitchJmp_attr_t => "\tinit_arm_attributes(res, flags, in_reqs, exec_units, n_res);",
arm_fpaConst_attr_t => "\tinit_arm_attributes(res, flags, in_reqs, exec_units, n_res);",
arm_fConst_attr_t => "\tinit_arm_attributes(res, flags, in_reqs, exec_units, n_res);",
arm_load_store_attr_t =>
"\tinit_arm_attributes(res, flags, in_reqs, exec_units, n_res);\n".
"\tinit_arm_load_store_attributes(res, ls_mode, entity, entity_sign, offset, is_frame_entity);",
......@@ -93,6 +94,9 @@ $default_copy_attr = "arm_copy_attr";
"\tinit_arm_attributes(res, flags, in_reqs, exec_units, n_res);\n",
arm_cmp_attr_t =>
"\tinit_arm_attributes(res, flags, in_reqs, exec_units, n_res);\n",
arm_farith_attr_t =>
"\tinit_arm_attributes(res, flags, in_reqs, exec_units, n_res);\n".
"\tinit_arm_farith_attributes(res, op_mode);",
arm_CopyB_attr_t =>
"\tinit_arm_attributes(res, flags, in_reqs, exec_units, n_res);\n".
"\tinit_arm_CopyB_attributes(res, size);",
......@@ -103,11 +107,12 @@ $default_copy_attr = "arm_copy_attr";
arm_SymConst_attr_t => "cmp_attr_arm_SymConst",
arm_CondJmp_attr_t => "cmp_attr_arm_CondJmp",
arm_SwitchJmp_attr_t => "cmp_attr_arm_SwitchJmp",
arm_fpaConst_attr_t => "cmp_attr_arm_fpaConst",
arm_fConst_attr_t => "cmp_attr_arm_fConst",
arm_load_store_attr_t => "cmp_attr_arm_load_store",
arm_shifter_operand_t => "cmp_attr_arm_shifter_operand",
arm_CopyB_attr_t => "cmp_attr_arm_CopyB",
arm_cmp_attr_t => "cmp_attr_arm_cmp",
arm_farith_attr_t => "cmp_attr_arm_farith",
);
my %unop_shifter_operand_constructors = (
......@@ -299,16 +304,6 @@ Mvn => {
constructors => \%unop_shifter_operand_constructors,
},