return NULL;
}
+static asm_constraint_flags_t TEMPLATE_parse_asm_constraint(const void *self,
+ const char **c)
+{
+ (void) self;
+ (void) c;
+ return ASM_CONSTRAINT_FLAG_INVALID;
+}
+
+static bool TEMPLATE_is_valid_clobber(const void *self, const char *clobber)
+{
+ (void) self;
+ (void) clobber;
+ return false;
+}
const arch_isa_if_t TEMPLATE_isa_if = {
TEMPLATE_init,
TEMPLATE_get_backend_params,
TEMPLATE_get_allowed_execution_units,
TEMPLATE_get_machine,
- TEMPLATE_get_backend_irg_list
+ TEMPLATE_get_backend_irg_list,
+ TEMPLATE_parse_asm_constraint,
+ TEMPLATE_is_valid_clobber
};
void be_init_arch_TEMPLATE(void)
return 1;
}
+static asm_constraint_flags_t arm_parse_asm_constraint(const void *self, const char **c)
+{
+ /* asm not supported */
+ (void) self;
+ (void) c;
+ return ASM_CONSTRAINT_FLAG_INVALID;
+}
+
+static bool arm_is_valid_clobber(const void *self, const char *clobber)
+{
+ (void) self;
+ (void) clobber;
+ return false;
+}
+
/**
* Returns the libFirm configuration parameter for this backend.
*/
arm_get_allowed_execution_units,
arm_get_machine,
arm_get_irg_list,
+ arm_parse_asm_constraint,
+ arm_is_valid_clobber
};
void be_init_arch_arm(void)
ir_type *pic_symbols_type;
};
+extern unsigned short asm_constraint_flags[256];
+
+void be_init_default_asm_constraint_flags(void);
+
/**
* Put the registers to be ignored in this IRG into a bitset.
* @param birg The backend IRG data structure.
extern ir_timer_t *t_ra_ssa; /**< timer for ssa destruction */
extern ir_timer_t *t_ra_other; /**< timer for remaining stuff */
+
#endif /* FIRM_BE_BE_T_H */
* @return A flexible array ARR_F containing all desired irgs in the desired order.
*/
ir_graph **(*get_backend_irg_list)(const void *self, ir_graph ***irgs);
+
+ /**
+ * parse an assembler constraint part and set flags according to its nature
+ * advances the *c pointer to point to the last parsed character (so if you
+ * parse a single character don't advance c)
+ */
+ asm_constraint_flags_t (*parse_asm_constraint)(const void *self, const char **c);
+
+ /**
+ * returns true if the string is a valid clobbered (register) in this
+ * backend
+ */
+ bool (*is_valid_clobber)(const void *self, const char *clobber);
};
#define arch_env_done(env) ((env)->impl->done(env))
#define arch_env_get_allowed_execution_units(env,irn) ((env)->impl->get_allowed_execution_units((env), (irn)))
#define arch_env_get_machine(env) ((env)->impl->get_machine(env))
#define arch_env_get_backend_irg_list(env,irgs) ((env)->impl->get_backend_irg_list((env), (irgs)))
+#define arch_env_parse_asm_constraint(env,c) ((env)->impl->parse_asm_constraint((env), (c))
+#define arch_env_is_valid_clobber(env,clobber) ((env)->impl->is_valid_clobber((env), (clobber))
/**
* ISA base class.
static be_module_list_entry_t *isa_ifs = NULL;
+
+unsigned short asm_constraint_flags[256];
+
+void be_init_default_asm_constraint_flags(void)
+{
+ asm_constraint_flags['?'] = ASM_CONSTRAINT_FLAG_NO_SUPPORT;
+ asm_constraint_flags['!'] = ASM_CONSTRAINT_FLAG_NO_SUPPORT;
+ asm_constraint_flags['&'] = ASM_CONSTRAINT_FLAG_NO_SUPPORT
+ | ASM_CONSTRAINT_FLAG_MODIFIER_EARLYCLOBBER;
+ asm_constraint_flags['%'] = ASM_CONSTRAINT_FLAG_NO_SUPPORT
+ | ASM_CONSTRAINT_FLAG_MODIFIER_COMMUTATIVE;
+ asm_constraint_flags['!'] = ASM_CONSTRAINT_FLAG_NO_SUPPORT;
+
+ asm_constraint_flags['='] = ASM_CONSTRAINT_FLAG_MODIFIER_WRITE
+ | ASM_CONSTRAINT_FLAG_MODIFIER_NO_READ;
+ asm_constraint_flags['+'] = ASM_CONSTRAINT_FLAG_MODIFIER_READ
+ | ASM_CONSTRAINT_FLAG_MODIFIER_WRITE;
+
+ asm_constraint_flags['i'] = ASM_CONSTRAINT_FLAG_SUPPORTS_IMMEDIATE;
+ asm_constraint_flags['s'] = ASM_CONSTRAINT_FLAG_SUPPORTS_IMMEDIATE;
+ asm_constraint_flags['E'] = ASM_CONSTRAINT_FLAG_SUPPORTS_IMMEDIATE;
+ asm_constraint_flags['F'] = ASM_CONSTRAINT_FLAG_SUPPORTS_IMMEDIATE;
+ asm_constraint_flags['G'] = ASM_CONSTRAINT_FLAG_SUPPORTS_IMMEDIATE;
+ asm_constraint_flags['H'] = ASM_CONSTRAINT_FLAG_SUPPORTS_IMMEDIATE;
+ asm_constraint_flags['I'] = ASM_CONSTRAINT_FLAG_SUPPORTS_IMMEDIATE;
+ asm_constraint_flags['J'] = ASM_CONSTRAINT_FLAG_SUPPORTS_IMMEDIATE;
+ asm_constraint_flags['K'] = ASM_CONSTRAINT_FLAG_SUPPORTS_IMMEDIATE;
+ asm_constraint_flags['L'] = ASM_CONSTRAINT_FLAG_SUPPORTS_IMMEDIATE;
+ asm_constraint_flags['M'] = ASM_CONSTRAINT_FLAG_SUPPORTS_IMMEDIATE;
+ asm_constraint_flags['N'] = ASM_CONSTRAINT_FLAG_SUPPORTS_IMMEDIATE;
+ asm_constraint_flags['O'] = ASM_CONSTRAINT_FLAG_SUPPORTS_IMMEDIATE;
+ asm_constraint_flags['P'] = ASM_CONSTRAINT_FLAG_SUPPORTS_IMMEDIATE;
+
+ asm_constraint_flags['m'] = ASM_CONSTRAINT_FLAG_SUPPORTS_MEMOP;
+ asm_constraint_flags['o'] = ASM_CONSTRAINT_FLAG_SUPPORTS_MEMOP;
+ asm_constraint_flags['V'] = ASM_CONSTRAINT_FLAG_SUPPORTS_MEMOP;
+ asm_constraint_flags['<'] = ASM_CONSTRAINT_FLAG_SUPPORTS_MEMOP;
+ asm_constraint_flags['>'] = ASM_CONSTRAINT_FLAG_SUPPORTS_MEMOP;
+
+ asm_constraint_flags['p'] = ASM_CONSTRAINT_FLAG_SUPPORTS_REGISTER;
+ asm_constraint_flags['0'] = ASM_CONSTRAINT_FLAG_SUPPORTS_REGISTER;
+ asm_constraint_flags['1'] = ASM_CONSTRAINT_FLAG_SUPPORTS_REGISTER;
+ asm_constraint_flags['2'] = ASM_CONSTRAINT_FLAG_SUPPORTS_REGISTER;
+ asm_constraint_flags['3'] = ASM_CONSTRAINT_FLAG_SUPPORTS_REGISTER;
+ asm_constraint_flags['4'] = ASM_CONSTRAINT_FLAG_SUPPORTS_REGISTER;
+ asm_constraint_flags['5'] = ASM_CONSTRAINT_FLAG_SUPPORTS_REGISTER;
+ asm_constraint_flags['6'] = ASM_CONSTRAINT_FLAG_SUPPORTS_REGISTER;
+ asm_constraint_flags['7'] = ASM_CONSTRAINT_FLAG_SUPPORTS_REGISTER;
+ asm_constraint_flags['8'] = ASM_CONSTRAINT_FLAG_SUPPORTS_REGISTER;
+ asm_constraint_flags['9'] = ASM_CONSTRAINT_FLAG_SUPPORTS_REGISTER;
+
+ asm_constraint_flags['X'] = ASM_CONSTRAINT_FLAG_SUPPORTS_REGISTER
+ | ASM_CONSTRAINT_FLAG_SUPPORTS_MEMOP
+ | ASM_CONSTRAINT_FLAG_SUPPORTS_IMMEDIATE;
+
+ /* these should have been catched by the parsing code already */
+ asm_constraint_flags['#'] = ASM_CONSTRAINT_FLAG_NO_SUPPORT;
+ asm_constraint_flags['*'] = ASM_CONSTRAINT_FLAG_NO_SUPPORT;
+ asm_constraint_flags[' '] = ASM_CONSTRAINT_FLAG_NO_SUPPORT;
+ asm_constraint_flags['\t'] = ASM_CONSTRAINT_FLAG_NO_SUPPORT;
+ asm_constraint_flags['\n'] = ASM_CONSTRAINT_FLAG_NO_SUPPORT;
+ asm_constraint_flags['\r'] = ASM_CONSTRAINT_FLAG_NO_SUPPORT;
+}
+
+asm_constraint_flags_t parse_asm_constraints(const char *constraint)
+{
+ const char *c;
+ asm_constraint_flags_t flags;
+ asm_constraint_flags_t tflags;
+
+ for (c = constraint; *c != '\0'; ++c) {
+ switch (*c) {
+ case '#':
+ /* 'comment' stuff */
+ while(*c != 0 && *c != ',')
+ ++c;
+ break;
+ case '*':
+ /* 'comment' character */
+ ++c;
+ break;
+ case ' ':
+ case '\t':
+ case '\n':
+ case '\r':
+ break;
+ default:
+ tflags = asm_constraint_flags[(int) *c];
+ if (tflags != 0) {
+ flags |= tflags;
+ } else {
+ flags |= isa_if->parse_asm_constraint(isa_if, &c);
+ }
+ break;
+ }
+ }
+
+ if ( ((flags & ASM_CONSTRAINT_FLAG_MODIFIER_WRITE)
+ && (flags & ASM_CONSTRAINT_FLAG_MODIFIER_NO_WRITE))
+ || ((flags & ASM_CONSTRAINT_FLAG_MODIFIER_READ
+ && (flags & ASM_CONSTRAINT_FLAG_MODIFIER_NO_READ)))) {
+ flags |= ASM_CONSTRAINT_FLAG_INVALID;
+ }
+
+ return flags;
+}
+
+bool is_valid_clobber(const char *clobber)
+{
+ /* memory is a valid clobber. (the frontend has to detect this case too,
+ * because it has to add memory edges to the asm) */
+ if (strcmp(clobber, "memory") == 0)
+ return true;
+
+ return isa_if->is_valid_clobber(isa_if, clobber);
+}
+
void be_register_isa_if(const char *name, const arch_isa_if_t *isa)
{
if (isa_if == NULL)
remove_irp_type(env->pic_symbols_type);
set_class_final(env->pic_trampolines_type, 1);
+ memset(asm_constraint_flags, 0, sizeof(asm_constraint_flags));
env->arch_env = arch_env_init(isa_if, file_handle, env);
be_phi_handler_new(env);
#endif
};
+static void init_asm_constraints(void)
+{
+ be_init_default_asm_constraint_flags();
+
+ asm_constraint_flags['a'] = ASM_CONSTRAINT_FLAG_SUPPORTS_REGISTER;
+ asm_constraint_flags['b'] = ASM_CONSTRAINT_FLAG_SUPPORTS_REGISTER;
+ asm_constraint_flags['c'] = ASM_CONSTRAINT_FLAG_SUPPORTS_REGISTER;
+ asm_constraint_flags['d'] = ASM_CONSTRAINT_FLAG_SUPPORTS_REGISTER;
+ asm_constraint_flags['D'] = ASM_CONSTRAINT_FLAG_SUPPORTS_REGISTER;
+ asm_constraint_flags['S'] = ASM_CONSTRAINT_FLAG_SUPPORTS_REGISTER;
+ asm_constraint_flags['Q'] = ASM_CONSTRAINT_FLAG_SUPPORTS_REGISTER;
+ asm_constraint_flags['q'] = ASM_CONSTRAINT_FLAG_SUPPORTS_REGISTER;
+ asm_constraint_flags['A'] = ASM_CONSTRAINT_FLAG_SUPPORTS_REGISTER;
+ asm_constraint_flags['l'] = ASM_CONSTRAINT_FLAG_SUPPORTS_REGISTER;
+ asm_constraint_flags['R'] = ASM_CONSTRAINT_FLAG_SUPPORTS_REGISTER;
+ asm_constraint_flags['r'] = ASM_CONSTRAINT_FLAG_SUPPORTS_REGISTER;
+ asm_constraint_flags['p'] = ASM_CONSTRAINT_FLAG_SUPPORTS_REGISTER;
+ asm_constraint_flags['f'] = ASM_CONSTRAINT_FLAG_SUPPORTS_REGISTER;
+ asm_constraint_flags['t'] = ASM_CONSTRAINT_FLAG_SUPPORTS_REGISTER;
+ asm_constraint_flags['u'] = ASM_CONSTRAINT_FLAG_SUPPORTS_REGISTER;
+ asm_constraint_flags['Y'] = ASM_CONSTRAINT_FLAG_SUPPORTS_REGISTER;
+ asm_constraint_flags['X'] = ASM_CONSTRAINT_FLAG_SUPPORTS_REGISTER;
+ asm_constraint_flags['n'] = ASM_CONSTRAINT_FLAG_SUPPORTS_IMMEDIATE;
+ asm_constraint_flags['g'] = ASM_CONSTRAINT_FLAG_SUPPORTS_IMMEDIATE;
+
+ /* no support for autodecrement/autoincrement */
+ asm_constraint_flags['<'] = ASM_CONSTRAINT_FLAG_NO_SUPPORT;
+ asm_constraint_flags['>'] = ASM_CONSTRAINT_FLAG_NO_SUPPORT;
+ /* no float consts */
+ asm_constraint_flags['E'] = ASM_CONSTRAINT_FLAG_NO_SUPPORT;
+ asm_constraint_flags['F'] = ASM_CONSTRAINT_FLAG_NO_SUPPORT;
+ /* makes no sense on x86 */
+ asm_constraint_flags['s'] = ASM_CONSTRAINT_FLAG_NO_SUPPORT;
+ /* no support for sse consts yet */
+ asm_constraint_flags['C'] = ASM_CONSTRAINT_FLAG_NO_SUPPORT;
+ /* no support for x87 consts yet */
+ asm_constraint_flags['G'] = ASM_CONSTRAINT_FLAG_NO_SUPPORT;
+ /* no support for mmx registers yet */
+ asm_constraint_flags['y'] = ASM_CONSTRAINT_FLAG_NO_SUPPORT;
+ /* not available in 32bit mode */
+ asm_constraint_flags['Z'] = ASM_CONSTRAINT_FLAG_NO_SUPPORT;
+ asm_constraint_flags['e'] = ASM_CONSTRAINT_FLAG_NO_SUPPORT;
+
+ /* no code yet to determine register class needed... */
+ asm_constraint_flags['X'] = ASM_CONSTRAINT_FLAG_NO_SUPPORT;
+}
+
/**
* Initializes the backend ISA.
*/
return NULL;
inited = 1;
+ init_asm_constraints();
set_tarval_output_modes();
isa = xmalloc(sizeof(*isa));
return 0;
}
+static asm_constraint_flags_t ia32_parse_asm_constraint(const void *self, const char **c)
+{
+ (void) self;
+ (void) c;
+
+ /* we already added all our simple flags to the flags modifier list in
+ * init, so this flag we don't know. */
+ return ASM_CONSTRAINT_FLAG_INVALID;
+}
+
+static bool ia32_is_valid_clobber(const void *self, const char *clobber)
+{
+ (void) self;
+
+ return ia32_get_clobber_register(clobber) != NULL;
+}
+
/**
* Returns the libFirm configuration parameter for this backend.
*/
ia32_get_allowed_execution_units,
ia32_get_machine,
ia32_get_irg_list,
+ ia32_parse_asm_constraint,
+ ia32_is_valid_clobber
};
void ia32_init_emitter(void);
/**
* Return true if a mode can be stored in the GP register set
*/
-INLINE int mode_needs_gp_reg(ir_mode *mode) {
+int ia32_mode_needs_gp_reg(ir_mode *mode) {
if(mode == mode_fpcw)
return 0;
if(get_mode_size_bits(mode) > 32)
/**
* Get a primitive type for a mode.
*/
-ir_type *get_prim_type(pmap *types, ir_mode *mode)
+ir_type *ia32_get_prim_type(pmap *types, ir_mode *mode)
{
pmap_entry *e = pmap_find(types, mode);
ir_type *res;
/* mode was not changed */
tp = get_Const_type(cnst);
if (tp == firm_unknown_type)
- tp = get_prim_type(isa->types, mode);
+ tp = ia32_get_prim_type(isa->types, mode);
} else
- tp = get_prim_type(isa->types, mode);
+ tp = ia32_get_prim_type(isa->types, mode);
res = new_entity(get_glob_type(), unique_id(".LC%u"), tp);
src_mode = get_irn_mode(get_Conv_op(node));
dest_mode = get_irn_mode(node);
- return mode_needs_gp_reg(src_mode)
- && mode_needs_gp_reg(dest_mode)
+ return ia32_mode_needs_gp_reg(src_mode)
+ && ia32_mode_needs_gp_reg(dest_mode)
&& get_mode_size_bits(dest_mode) < get_mode_size_bits(src_mode);
}
ir_node *new_node;
/* handle only GP modes for now... */
- if(!mode_needs_gp_reg(mode))
+ if(!ia32_mode_needs_gp_reg(mode))
return NULL;
while(1) {
ir_node *conv_op;
ir_mode *conv_mode;
- if(get_mode_size_bits(mode) != 32 || !mode_needs_gp_reg(mode))
+ if(get_mode_size_bits(mode) != 32 || !ia32_mode_needs_gp_reg(mode))
return 0;
if(!is_Conv(node))
ir_node *new_node = be_duplicate_node(node);
ir_mode *mode = get_irn_mode(new_node);
- if (mode_needs_gp_reg(mode)) {
+ if (ia32_mode_needs_gp_reg(mode)) {
set_irn_mode(new_node, mode_Iu);
}
}
}
- assert(mode_needs_gp_reg(cmp_mode));
+ assert(ia32_mode_needs_gp_reg(cmp_mode));
/* we prefer the Test instruction where possible except cases where
* we can use SourceAM */
ia32_address_t *addr;
assert(ia32_cg_config.use_cmov);
- assert(mode_needs_gp_reg(get_irn_mode(val_true)));
+ assert(ia32_mode_needs_gp_reg(get_irn_mode(val_true)));
addr = &am.addr;
ir_node *flags;
ir_node *new_node;
- assert(mode_needs_gp_reg(mode));
+ assert(ia32_mode_needs_gp_reg(mode));
if (is_Proj(cond)) {
ir_node *cmp = get_Proj_pred(cond);
break;
case 'm':
+ case 'o':
+ case 'V':
/* memory constraint no need to do anything in backend about it
* (the dependencies are already respected by the memory edge of
* the node) */
case 'F': /* no float consts yet */
case 's': /* makes no sense on x86 */
case 'X': /* we can't support that in firm */
- case 'o':
- case 'V':
case '<': /* no autodecrement on x86 */
case '>': /* no autoincrement on x86 */
case 'C': /* sse constant not supported yet */
constraint->immediate_type = immediate_type;
}
-static void parse_clobber(ir_node *node, int pos, constraint_t *constraint,
- const char *clobber)
+const arch_register_t *ia32_get_clobber_register(const char *clobber)
{
- ir_graph *irg = get_irn_irg(node);
- struct obstack *obst = get_irg_obstack(irg);
- const arch_register_t *reg = NULL;
+ const arch_register_t *reg = NULL;
int c;
size_t r;
- arch_register_req_t *req;
const arch_register_class_t *cls;
- unsigned *limited;
-
- (void) pos;
/* TODO: construct a hashmap instead of doing linear search for clobber
* register */
if(reg != NULL)
break;
}
+
+ return reg;
+}
+
+static void parse_clobber(ir_node *node, int pos, constraint_t *constraint,
+ const char *clobber)
+{
+ ir_graph *irg = get_irn_irg(node);
+ struct obstack *obst = get_irg_obstack(irg);
+ const arch_register_t *reg = ia32_get_clobber_register(clobber);
+ arch_register_req_t *req;
+ unsigned *limited;
+
+ (void) pos;
+
if(reg == NULL) {
panic("Register '%s' mentioned in asm clobber is unknown\n", clobber);
return;
req = obstack_alloc(obst, sizeof(req[0]));
memset(req, 0, sizeof(req[0]));
req->type = arch_register_req_type_limited;
- req->cls = cls;
+ req->cls = arch_register_get_class(reg);
req->limited = limited;
constraint->req = req;
add_irn_dep(ret, get_irg_frame(irg));
return ret;
}
- } else if (mode_needs_gp_reg(mode)) {
+ } else if (ia32_mode_needs_gp_reg(mode)) {
return ia32_new_Unknown_gp(env_cg);
} else {
panic("unsupported Unknown-Mode");
ir_mode *mode = get_irn_mode(node);
ir_node *phi;
- if(mode_needs_gp_reg(mode)) {
+ if(ia32_mode_needs_gp_reg(mode)) {
/* we shouldn't have any 64bit stuff around anymore */
assert(get_mode_size_bits(mode) <= 32);
/* all integer operations are on 32bit registers now */
} else {
#endif
ir_mode *mode = get_irn_mode(node);
- if (mode_needs_gp_reg(mode)) {
+ if (ia32_mode_needs_gp_reg(mode)) {
ir_node *new_pred = be_transform_node(pred);
ir_node *block = be_transform_node(get_nodes_block(node));
ir_node *new_proj = new_r_Proj(current_ir_graph, block, new_pred,
/**
* Get a primitive type for a mode.
*/
-ir_type *get_prim_type(pmap *types, ir_mode *mode);
+ir_type *ia32_get_prim_type(pmap *types, ir_mode *mode);
/**
* Return true if a mode can be stored in the GP register set
*/
-INLINE int mode_needs_gp_reg(ir_mode *mode);
+int ia32_mode_needs_gp_reg(ir_mode *mode);
+
+/**
+ * returns register by name (used for determining clobber specifications in
+ * asm instructions)
+ */
+const arch_register_t *ia32_get_clobber_register(const char *clobber);
#endif /* FIRM_BE_IA32_IA32_TRANSFORM_H */
return &p;
}
+static asm_constraint_flags_t ppc32_parse_asm_constraint(const void *self, const char **c)
+{
+ /* no asm support yet */
+ (void) self;
+ (void) c;
+ return ASM_CONSTRAINT_FLAG_INVALID;
+}
+
+static bool ppc32_is_valid_clobber(const void *self, const char *clobber)
+{
+ /* no asm support yet */
+ (void) self;
+ (void) clobber;
+ return false;
+}
+
const arch_isa_if_t ppc32_isa_if = {
ppc32_init,
ppc32_done,
ppc32_get_allowed_execution_units,
ppc32_get_machine,
ppc32_get_irg_list,
+ ppc32_parse_asm_constraint,
+ ppc32_is_valid_clobber
};
void be_init_arch_ppc32(void)