Commit 774486f3 authored by Matthias Braun's avatar Matthias Braun
Browse files

we can parse lots of assembler constraints now (but not all yet), and emit immediates in asm nodes

[r14275]
parent 4f9258e9
......@@ -1767,7 +1767,8 @@ int ia32_to_appear_in_schedule(void *block_env, const ir_node *irn) {
if(is_ia32_NoReg_GP(irn) || is_ia32_NoReg_VFP(irn) || is_ia32_NoReg_XMM(irn)
|| is_ia32_Unknown_GP(irn) || is_ia32_Unknown_XMM(irn)
|| is_ia32_Unknown_VFP(irn) || is_ia32_ChangeCW(irn))
|| is_ia32_Unknown_VFP(irn) || is_ia32_ChangeCW(irn)
|| is_ia32_Immediate(irn))
return 0;
return 1;
......
......@@ -224,6 +224,7 @@ char *get_unique_label(char *buf, size_t buflen, const char *prefix) {
#undef be_emit_cstring
#define be_emit_cstring(env,x) { be_emit_string_len(env->emit, x, sizeof(x)-1); }
#define be_emit_ident(env,i) be_emit_ident(env->emit,i)
#define be_emit_tarval(env,tv) be_emit_tarval(env->emit,tv)
#define be_emit_write_line(env) be_emit_write_line(env->emit)
#define be_emit_finish_line_gas(env,n) be_emit_finish_line_gas(env->emit,n)
#define be_emit_pad_comment(env) be_emit_pad_comment(env->emit)
......@@ -267,7 +268,7 @@ void ia32_emit_immediate(ia32_emit_env_t *env, const ir_node *node)
switch(get_ia32_immop_type(node)) {
case ia32_ImmConst:
tv = get_ia32_Immop_tarval(node);
be_emit_tarval(env->emit, tv);
be_emit_tarval(env, tv);
return;
case ia32_ImmSymConst:
ent = get_ia32_Immop_symconst(node);
......@@ -275,6 +276,7 @@ void ia32_emit_immediate(ia32_emit_env_t *env, const ir_node *node)
id = get_entity_ld_ident(ent);
be_emit_ident(env, id);
return;
case ia32_ImmAsm:
case ia32_ImmNone:
break;
}
......@@ -1311,6 +1313,25 @@ void emit_Jmp(ia32_emit_env_t *env, const ir_node *node) {
be_emit_finish_line_gas(env, node);
}
static
void emit_ia32_Immediate(ia32_emit_env_t *env, const ir_node *node)
{
ia32_attr_t *attr = get_ia32_attr(node);
if(attr->am_sc != NULL) {
ident *id = get_entity_ld_ident(attr->am_sc);
if(attr->data.am_sc_sign)
be_emit_char(env, '-');
be_emit_ident(env, id);
}
if(attr->cnst_val.tv != NULL) {
if(attr->am_sc != NULL)
be_emit_char(env, '+');
be_emit_tarval(env, attr->cnst_val.tv);
}
}
static
const char* emit_asm_operand(ia32_emit_env_t *env, const ir_node *node,
const char *s)
......@@ -1375,12 +1396,19 @@ const char* emit_asm_operand(ia32_emit_env_t *env, const ir_node *node,
if(num < n_outs) {
reg = get_out_reg(env, node, num);
} else {
int in = num - n_outs;
ir_node *pred;
int in = num - n_outs;
if(in >= get_irn_arity(node)) {
ir_fprintf(stderr, "Warning: Invalid input %d specified in asm "
"op (%+F)\n", num, node);
return s;
}
pred = get_irn_n(node, in);
/* might be an immediate value */
if(is_ia32_Immediate(pred)) {
emit_ia32_Immediate(env, pred);
return s;
}
reg = get_in_reg(env, node, in);
}
if(reg == NULL) {
......
......@@ -132,6 +132,7 @@ static int ia32_dump_node(ir_node *n, FILE *F, dump_reason_t reason) {
ir_mode *mode = NULL;
int bad = 0;
int i, n_res, am_flav, flags;
const ia32_attr_t *attr = get_ia32_attr_const(n);
const arch_register_req_t **reqs;
const arch_register_t **slots;
......@@ -239,6 +240,10 @@ static int ia32_dump_node(ir_node *n, FILE *F, dump_reason_t reason) {
case ia32_ImmSymConst:
fprintf(F, "SymConst");
break;
case ia32_ImmAsm:
fprintf(F, "Asm '%s'\n",
get_id_str(attr->cnst_val.asm_text));
break;
default:
fprintf(F, "unknown (%d)", get_ia32_immop_type(n));
break;
......@@ -422,6 +427,11 @@ ia32_attr_t *get_ia32_attr(const ir_node *node) {
return (ia32_attr_t *)get_irn_generic_attr((ir_node *)node);
}
const ia32_attr_t *get_ia32_attr_const(const ir_node *node) {
assert(is_ia32_irn(node) && "need ia32 node to get ia32 attributes");
return (const ia32_attr_t*) get_irn_generic_attr_const(node);
}
/**
* Gets the type of an ia32 node.
*/
......@@ -1207,6 +1217,9 @@ int ia32_compare_attr(ia32_attr_t *a, ia32_attr_t *b) {
if (a->data.imm_tp == ia32_ImmSymConst
&& a->cnst_val.sc != b->cnst_val.sc)
return 1;
if(a->data.imm_tp == ia32_ImmAsm
&& a->cnst_val.asm_text != b->cnst_val.asm_text)
return 1;
if (a->data.am_flavour != b->data.am_flavour
|| a->data.am_scale != b->data.am_scale
......
......@@ -52,6 +52,8 @@ int ia32_has_x87_register(const ir_node *n);
* Returns the attributes of an ia32 node.
*/
ia32_attr_t *get_ia32_attr(const ir_node *node);
const ia32_attr_t *get_ia32_attr_const(const ir_node *node);
/**
* Gets the type of an ia32 node.
......
......@@ -44,7 +44,8 @@ typedef enum {
typedef enum {
ia32_ImmNone = 0,
ia32_ImmConst = 1,
ia32_ImmSymConst = 2
ia32_ImmSymConst = 2,
ia32_ImmAsm = 3
} ia32_immop_type_t;
typedef enum {
......
......@@ -290,12 +290,13 @@ $fpcw_flags = [ "FP_IM", "FP_DM", "FP_ZM", "FP_OM", "FP_UM", "FP_PM",
%nodes = (
#Immediate => {
# irn_flags => "i",
# reg_req => { out => [ "NoReg_GP" ] },
# mode => $mode_gp,
# attr_type => "ia32_imm_t",
#},
Immediate => {
state => "pinned",
op_flags => "c",
irn_flags => "I",
reg_req => { out => [ "gp_NOREG" ] },
mode => $mode_gp,
},
Asm => {
mode => "mode_T",
......
......@@ -2392,6 +2392,320 @@ static ir_node *gen_Conv(ia32_transform_env_t *env, ir_node *node) {
return res;
}
static
ir_node *try_create_Immediate(ia32_transform_env_t *env, ir_node *node,
unsigned immediate_max)
{
int minus = 0;
tarval *offset = NULL;
int offset_sign = 0;
ir_entity *symconst_ent = NULL;
int symconst_sign = 0;
ir_mode *mode;
ir_node *cnst = NULL;
ir_node *symconst = NULL;
ir_node *res;
ir_graph *irg;
dbg_info *dbgi;
ir_node *block;
ia32_attr_t *attr;
mode = get_irn_mode(node);
if(!mode_is_int(mode) && !mode_is_character(mode) &&
!mode_is_reference(mode)) {
return NULL;
}
if(is_Minus(node)) {
minus = 1;
node = get_Minus_op(node);
}
if(is_Const(node)) {
cnst = node;
symconst = NULL;
offset_sign = minus;
} else if(is_SymConst(node)) {
cnst = NULL;
symconst = node;
symconst_sign = minus;
} else if(is_Add(node)) {
ir_node *left = get_Add_left(node);
ir_node *right = get_Add_right(node);
if(is_Const(left) && is_SymConst(right)) {
cnst = left;
symconst = right;
symconst_sign = minus;
offset_sign = minus;
} else if(is_SymConst(left) && is_Const(right)) {
cnst = right;
symconst = left;
symconst_sign = minus;
offset_sign = minus;
}
} else if(is_Sub(node)) {
ir_node *left = get_Add_left(node);
ir_node *right = get_Add_right(node);
if(is_Const(left) && is_SymConst(right)) {
cnst = left;
symconst = right;
symconst_sign = !minus;
offset_sign = minus;
} else if(is_SymConst(left) && is_Const(right)) {
cnst = right;
symconst = left;
symconst_sign = minus;
offset_sign = !minus;
}
} else {
return NULL;
}
if(cnst != NULL) {
tarval *tv;
tarval *tvu;
long val;
tv = get_Const_tarval(cnst);
if(!tarval_is_long(tv)) {
ir_fprintf(stderr, "Optimisation Warning: tarval from %+F is not a "
"long?\n", cnst);
return NULL;
}
tvu = tarval_convert_to(tv, mode_Iu);
val = get_tarval_long(tvu);
if(val > immediate_max)
return NULL;
offset = tvu;
}
if(symconst != NULL) {
if(immediate_max != 0xffffffff) {
/* we need full 32bits for symconsts */
return NULL;
}
if(get_SymConst_kind(symconst) != symconst_addr_ent)
return NULL;
symconst_ent = get_SymConst_entity(symconst);
}
irg = env->irg;
dbgi = get_irn_dbg_info(node);
block = get_irg_start_block(irg);
res = new_rd_ia32_Immediate(dbgi, irg, block);
arch_set_irn_register(env->cg->arch_env, res, &ia32_gp_regs[REG_GP_NOREG]);
/* make sure we don't schedule stuff before the barrier */
add_irn_dep(res, get_irg_frame(irg));
/* misuse some fields for now... */
attr = get_ia32_attr(res);
attr->am_sc = symconst_ent;
attr->data.am_sc_sign = symconst_sign;
if(offset_sign && offset != NULL) {
offset = tarval_neg(offset);
}
attr->cnst_val.tv = offset;
attr->data.imm_tp = ia32_ImmConst;
return res;
}
typedef struct constraint_t constraint_t;
struct constraint_t {
const arch_register_req_t *req;
unsigned immediate_possible;
unsigned immediate_max;
};
static
void parse_asm_constraint(ia32_transform_env_t *env, ir_node *node,
constraint_t *constraint, const char *c, int is_in)
{
int immediate_possible = 0;
unsigned immediate_max = 0xffffffff;
unsigned limited = 0;
const arch_register_class_t *cls = NULL;
ir_graph *irg;
struct obstack *obst;
arch_register_req_t *req;
unsigned *limited_ptr;
printf("Constraint: %s\n", c);
while(*c != 0) {
switch(*c) {
case ' ':
case '\t':
case '\n':
break;
case 'a':
assert(cls == NULL ||
(cls == &ia32_reg_classes[CLASS_ia32_gp] && limited != 0));
cls = &ia32_reg_classes[CLASS_ia32_gp];
limited |= 1 << REG_EAX;
break;
case 'b':
assert(cls == NULL ||
(cls == &ia32_reg_classes[CLASS_ia32_gp] && limited != 0));
cls = &ia32_reg_classes[CLASS_ia32_gp];
limited |= 1 << REG_EBX;
break;
case 'c':
assert(cls == NULL ||
(cls == &ia32_reg_classes[CLASS_ia32_gp] && limited != 0));
cls = &ia32_reg_classes[CLASS_ia32_gp];
limited |= 1 << REG_ECX;
break;
case 'd':
assert(cls == NULL ||
(cls == &ia32_reg_classes[CLASS_ia32_gp] && limited != 0));
cls = &ia32_reg_classes[CLASS_ia32_gp];
limited |= 1 << REG_EDX;
break;
case 'D':
assert(cls == NULL ||
(cls == &ia32_reg_classes[CLASS_ia32_gp] && limited != 0));
cls = &ia32_reg_classes[CLASS_ia32_gp];
limited |= 1 << REG_EDI;
break;
case 'S':
assert(cls == NULL ||
(cls == &ia32_reg_classes[CLASS_ia32_gp] && limited != 0));
cls = &ia32_reg_classes[CLASS_ia32_gp];
limited |= 1 << REG_ESI;
break;
case 'R':
case 'r':
case 'p':
assert(cls == NULL);
cls = &ia32_reg_classes[CLASS_ia32_gp];
break;
case 'f':
case 't':
case 'u':
assert(cls == NULL);
cls = &ia32_reg_classes[CLASS_ia32_vfp];
break;
case 'x':
assert(cls == NULL);
cls = &ia32_reg_classes[CLASS_ia32_xmm];
break;
case 'I':
assert(!immediate_possible);
immediate_possible = 1;
immediate_max = 31;
break;
case 'J':
assert(!immediate_possible);
immediate_possible = 1;
immediate_max = 63;
break;
case 'n':
case 'i':
assert(!immediate_possible);
immediate_possible = 1;
break;
case 'M':
assert(!immediate_possible);
immediate_possible = 1;
immediate_max = 3;
break;
case 'N':
assert(!immediate_possible);
immediate_possible = 1;
immediate_max = 0xff;
break;
case 'g':
assert(!immediate_possible && cls == NULL);
immediate_possible = 1;
cls = &ia32_reg_classes[CLASS_ia32_gp];
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
/* TODO */
assert(0 && "other_same not implemented yet");
break;
case 'E': /* no float consts yet */
case 'F': /* no float consts yet */
case 's': /* makes no sense on x86 */
case 'X': /* we can't support that in firm */
case 'm':
case 'o':
case 'V':
case '<': /* no autodecrement on x86 */
case '>': /* no autoincrement on x86 */
case 'C': /* sse constant not supported yet */
case 'G': /* 80387 constant not supported yet */
case 'y': /* we don't support mmx registers yet */
case 'Z': /* not available in 32 bit mode */
case 'e': /* not available in 32 bit mode */
case 'K': /* gcc docu is cryptic */
case 'L': /* gcc docu is cryptic */
assert(0);
break;
default:
assert(0);
break;
}
++c;
}
if(immediate_possible && cls == NULL) {
cls = &ia32_reg_classes[CLASS_ia32_gp];
}
assert(!immediate_possible || cls == &ia32_reg_classes[CLASS_ia32_gp]);
assert(cls != NULL);
if(immediate_possible) {
assert(is_in && "imeediates make no sense for output constraints");
printf("Immediate possible 0-%x\n", immediate_max);
}
/* todo: check types (no float input on 'r' constrainted in and such... */
irg = env->irg;
obst = get_irg_obstack(irg);
if(limited != 0) {
req = obstack_alloc(obst, sizeof(req[0]) + sizeof(unsigned));
limited_ptr = (unsigned*) (req+1);
} else {
req = obstack_alloc(obst, sizeof(req[0]));
}
memset(req, 0, sizeof(req[0]));
if(limited != 0) {
req->type = arch_register_req_type_limited;
*limited_ptr = limited;
req->limited = limited_ptr;
} else {
req->type = arch_register_req_type_normal;
}
req->cls = cls;
constraint->req = req;
constraint->immediate_possible = immediate_possible;
constraint->immediate_max = immediate_max;
}
static
ir_node *gen_ASM(ia32_transform_env_t *env, ir_node *node)
{
......@@ -2402,6 +2716,8 @@ ir_node *gen_ASM(ia32_transform_env_t *env, ir_node *node)
ir_node **in;
ir_node *res;
int out_arity;
int n_outs;
int n_clobbers;
ia32_attr_t *attr;
const arch_register_req_t **out_reqs;
const arch_register_req_t **in_reqs;
......@@ -2414,44 +2730,75 @@ ir_node *gen_ASM(ia32_transform_env_t *env, ir_node *node)
/* transform inputs */
arity = get_irn_arity(node);
in = alloca(arity * sizeof(in[0]));
for(i = 0; i < arity; ++i) {
ir_node *pred = get_irn_n(node, i);
ir_node *transformed = transform_node(env, pred);
in[i] = transformed;
}
memset(in, 0, arity * sizeof(in[0]));
out_arity = get_ASM_n_output_constraints(node) + get_ASM_n_clobbers(node);
res = new_rd_ia32_Asm(dbgi, irg, block, arity, in, out_arity);
n_outs = get_ASM_n_output_constraints(node);
n_clobbers = get_ASM_n_clobbers(node);
out_arity = n_outs + n_clobbers;
/* construct register constraints */
obst = get_irg_obstack(irg);
out_reqs = obstack_alloc(obst, out_arity * sizeof(out_reqs[0]));
for(i = 0; i < out_arity; ++i) {
arch_register_req_t *req = obstack_alloc(obst, sizeof(req[0]));
memset(req, 0, sizeof(req[0]));
const char *c;
constraint_t parsed_constr;
/* TODO: parse constraints */
req->type = arch_register_req_type_normal;
req->cls = &ia32_reg_classes[CLASS_ia32_gp];
out_reqs[i] = req;
if(i < n_outs) {
const ir_asm_constraint *constraint;
constraint = & get_ASM_output_constraints(node) [i];
c = get_id_str(constraint->constraint);
} else {
ident *glob_id = get_ASM_clobbers(node) [i - n_outs];
c = get_id_str(glob_id);
}
parse_asm_constraint(env, node, &parsed_constr, c, 0);
out_reqs[i] = parsed_constr.req;
}
set_ia32_out_req_all(res, out_reqs);
in_reqs = obstack_alloc(obst, arity * sizeof(in_reqs[0]));
for(i = 0; i < arity; ++i) {
arch_register_req_t *req = obstack_alloc(obst, sizeof(req[0]));
memset(req, 0, sizeof(req[0]));
const ir_asm_constraint *constraint;
ident *constr_id;
const char *c;
constraint_t parsed_constr;
constraint = & get_ASM_input_constraints(node) [i];
constr_id = constraint->constraint;
c = get_id_str(constr_id);
parse_asm_constraint(env, node, &parsed_constr, c, 1);
in_reqs[i] = parsed_constr.req;
if(parsed_constr.immediate_possible) {
ir_node *pred = get_irn_n(node, i);
ir_node *immediate
= try_create_Immediate(env, pred, parsed_constr.immediate_max);
if(immediate != NULL) {
in[i] = immediate;
}
}
}
/* transform inputs */
for(i = 0; i < arity; ++i) {
ir_node *pred;
ir_node *transformed;
if(in[i] != NULL)
continue;
/* TODO: parse constraints */
req->type = arch_register_req_type_normal;
req->cls = &ia32_reg_classes[CLASS_ia32_gp];
in_reqs[i] = req;
pred = get_irn_n(node, i);
transformed = transform_node(env, pred);
in[i] = transformed;
}
set_ia32_in_req_all(res, in_reqs);
res = new_rd_ia32_Asm(dbgi, irg, block, arity, in, out_arity);
attr = get_ia32_attr(res);
attr->cnst_val.asm_text = get_ASM_text(node);
attr->data.imm_tp = ia32_ImmAsm;
set_ia32_out_req_all(res, out_reqs);
set_ia32_in_req_all(res, in_reqs);
SET_IA32_ORIG_NODE(res, ia32_get_old_node_name(env->cg, node));
......
......@@ -36,7 +36,8 @@ static inline int mov(int val)
int main()
{
//sincostest(0.5);
//outb(123, 42);
outb(123, 42);
outb(12345, 42);
return mov(0);
return mov(0) + inb(12345) + inb(123);
}
Markdown is supported
0% or