Commit 97c79556 authored by Matthias Braun's avatar Matthias Braun
Browse files

same_as constraints in assembler nodes work now

[r14287]
parent 7ff3f2ca
......@@ -1504,6 +1504,7 @@ static ia32_isa_t ia32_isa_template = {
{ NULL, }, /* emitter environment */
NULL, /* 16bit register names */
NULL, /* 8bit register names */
NULL, /* 8bit register names high */
NULL, /* types */
NULL, /* tv_ents */
(0 |
......@@ -1558,14 +1559,16 @@ static void *ia32_init(FILE *file_handle) {
}
be_emit_init_env(&isa->emit, file_handle);
isa->regs_16bit = pmap_create();
isa->regs_8bit = pmap_create();
isa->types = pmap_create();
isa->tv_ent = pmap_create();
isa->cpu = ia32_init_machine_description();
isa->regs_16bit = pmap_create();
isa->regs_8bit = pmap_create();
isa->regs_8bit_high = pmap_create();
isa->types = pmap_create();
isa->tv_ent = pmap_create();
isa->cpu = ia32_init_machine_description();
ia32_build_16bit_reg_map(isa->regs_16bit);
ia32_build_8bit_reg_map(isa->regs_8bit);
ia32_build_8bit_reg_map_high(isa->regs_8bit_high);
#ifndef NDEBUG
isa->name_obst = xmalloc(sizeof(*isa->name_obst));
......@@ -1601,6 +1604,7 @@ static void ia32_done(void *self) {
pmap_destroy(isa->regs_16bit);
pmap_destroy(isa->regs_8bit);
pmap_destroy(isa->regs_8bit_high);
pmap_destroy(isa->tv_ent);
pmap_destroy(isa->types);
......
......@@ -156,6 +156,7 @@ struct ia32_isa_t {
be_emit_env_t emit;
pmap *regs_16bit; /**< Contains the 16bits names of the gp registers */
pmap *regs_8bit; /**< Contains the 8bits names of the gp registers */
pmap *regs_8bit_high; /**< contains the hight part of the 8 bit names of the gp registers */
pmap *types; /**< A map of modes to primitive types */
pmap *tv_ent; /**< A map of entities that store const tarvals */
ia32_optimize_t opt; /**< contains optimization information */
......
......@@ -1361,6 +1361,7 @@ const char* emit_asm_operand(ia32_emit_env_t *env, const ir_node *node,
return s + 1;
case 'w':
case 'b':
case 'h':
modifier = c;
++s;
break;
......@@ -1428,6 +1429,9 @@ const char* emit_asm_operand(ia32_emit_env_t *env, const ir_node *node,
case 'b':
reg_name = ia32_get_mapped_reg_name(env->isa->regs_8bit, reg);
break;
case 'h':
reg_name = ia32_get_mapped_reg_name(env->isa->regs_8bit_high, reg);
break;
case 'w':
reg_name = ia32_get_mapped_reg_name(env->isa->regs_16bit, reg);
break;
......@@ -1657,13 +1661,6 @@ void emit_ia32_Conv_I2I(ia32_emit_env_t *env, const ir_node *node) {
} else {
assert(0);
}
} else if (REGS_ARE_EQUAL(out_reg, in_reg) && !signed_mode) {
/* argument and result are in the same register */
/* and signedness is ok: -> use and with mask */
int mask = (1 << smaller_bits) - 1;
be_emit_cstring(env, "\tandl $0x");
be_emit_irprintf(env->emit, "%x, ", mask);
ia32_emit_dest_register(env, node, 0);
} else {
const char *sreg = ia32_get_reg_name_for_mode(env, smaller_mode, in_reg);
......
......@@ -137,6 +137,13 @@ void ia32_build_8bit_reg_map(pmap *reg_map) {
pmap_insert(reg_map, &ia32_gp_regs[REG_EDX], "dl");
}
void ia32_build_8bit_reg_map_high(pmap *reg_map) {
pmap_insert(reg_map, &ia32_gp_regs[REG_EAX], "ah");
pmap_insert(reg_map, &ia32_gp_regs[REG_EBX], "bh");
pmap_insert(reg_map, &ia32_gp_regs[REG_ECX], "ch");
pmap_insert(reg_map, &ia32_gp_regs[REG_EDX], "dh");
}
const char *ia32_get_mapped_reg_name(pmap *reg_map, const arch_register_t *reg) {
pmap_entry *e = pmap_find(reg_map, (void *)reg);
......
......@@ -66,6 +66,7 @@ void ia32_build_16bit_reg_map(pmap *reg_map);
* name into a pmap.
*/
void ia32_build_8bit_reg_map(pmap *reg_map);
void ia32_build_8bit_reg_map_high(pmap *reg_map);
/**
* Returns the corresponding mapped name for a register.
......
......@@ -121,6 +121,17 @@ $arch = "ia32";
{ name => "gp_UKNWN", type => 4 | 8 | 16 }, # we need a dummy register for Unknown nodes
{ mode => "mode_Iu" }
],
mmx => [
{ name => "mm0", type => 4 },
{ name => "mm1", type => 4 },
{ name => "mm2", type => 4 },
{ name => "mm3", type => 4 },
{ name => "mm4", type => 4 },
{ name => "mm5", type => 4 },
{ name => "mm6", type => 4 },
{ name => "mm7", type => 4 },
{ mode => "mode_E" }
],
xmm => [
{ name => "xmm0", type => 1 },
{ name => "xmm1", type => 1 },
......
......@@ -2360,7 +2360,36 @@ static ir_node *gen_Conv(ir_node *node) {
}
static
ir_node *try_create_Immediate(ir_node *node, unsigned immediate_max)
int check_immediate_constraint(tarval *tv, char immediate_constraint_type)
{
assert(tarval_is_long(tv));
long val = get_tarval_long(tv);
switch(immediate_constraint_type) {
case 0:
return 1;
case 'I':
return val >= 0 && val <= 32;
case 'J':
return val >= 0 && val <= 63;
case 'K':
return val >= -128 && val <= 127;
case 'L':
return val == 0xff || val == 0xffff;
case 'M':
return val >= 0 && val <= 3;
case 'N':
return val >= 0 && val <= 255;
case 'O':
return val >= 0 && val <= 127;
default:
break;
}
panic("Invalid immediate constraint found");
return 0;
}
ir_node *try_create_Immediate(ir_node *node, char immediate_constraint_type)
{
int minus = 0;
tarval *offset = NULL;
......@@ -2428,26 +2457,18 @@ ir_node *try_create_Immediate(ir_node *node, unsigned immediate_max)
}
if(cnst != NULL) {
tarval *tv;
tarval *tvu;
long val;
tv = get_Const_tarval(cnst);
if(!tarval_is_long(tv)) {
offset = get_Const_tarval(cnst);
if(!tarval_is_long(offset)) {
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)
if(!check_immediate_constraint(offset, immediate_constraint_type))
return NULL;
offset = tvu;
}
if(symconst != NULL) {
if(immediate_max != 0xffffffff) {
if(immediate_constraint_type != 0) {
/* we need full 32bits for symconsts */
return NULL;
}
......@@ -2481,23 +2502,30 @@ ir_node *try_create_Immediate(ir_node *node, unsigned immediate_max)
typedef struct constraint_t constraint_t;
struct constraint_t {
const arch_register_req_t *req;
unsigned immediate_possible;
unsigned immediate_max;
int is_in;
int n_outs;
const arch_register_req_t **out_reqs;
const arch_register_req_t *req;
unsigned immediate_possible;
char immediate_type;
};
static
void parse_asm_constraint(ir_node *node, constraint_t *constraint,
const char *c, int is_in)
void parse_asm_constraint(ir_node *node, int pos, constraint_t *constraint,
const char *c)
{
int immediate_possible = 0;
unsigned immediate_max = 0xffffffff;
char immediate_type = 0;
unsigned limited = 0;
const arch_register_class_t *cls = NULL;
ir_graph *irg;
struct obstack *obst;
arch_register_req_t *req;
unsigned *limited_ptr;
int p;
int same_as = -1;
/* TODO: replace all the asserts with nice error messages */
printf("Constraint: %s\n", c);
......@@ -2544,6 +2572,19 @@ void parse_asm_constraint(ir_node *node, constraint_t *constraint,
cls = &ia32_reg_classes[CLASS_ia32_gp];
limited |= 1 << REG_ESI;
break;
case 'Q':
case 'q': /* q means lower part of the regs only, this makes no
* difference to Q for us (we only assigne whole registers) */
assert(cls == NULL ||
(cls == &ia32_reg_classes[CLASS_ia32_gp] && limited != 0));
cls = &ia32_reg_classes[CLASS_ia32_gp];
limited |= 1 << REG_EAX | 1 << REG_EBX | 1 << REG_ECX |
1 << REG_EDX;
break;
case 'A':
/* AD_REGS */
case 'l':
/* INDEX_REGS */
case 'R':
case 'r':
......@@ -2559,36 +2600,29 @@ void parse_asm_constraint(ir_node *node, constraint_t *constraint,
cls = &ia32_reg_classes[CLASS_ia32_vfp];
break;
case 'Y':
case 'x':
assert(cls == NULL);
/* TODO: check that sse2 is supported */
cls = &ia32_reg_classes[CLASS_ia32_xmm];
break;
case 'I':
assert(!immediate_possible);
immediate_possible = 1;
immediate_max = 31;
break;
case 'J':
case 'K':
case 'L':
case 'M':
case 'N':
case 'O':
assert(!immediate_possible);
immediate_possible = 1;
immediate_max = 63;
immediate_type = *c;
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);
......@@ -2606,8 +2640,14 @@ void parse_asm_constraint(ir_node *node, constraint_t *constraint,
case '7':
case '8':
case '9':
/* TODO */
assert(0 && "other_same not implemented yet");
assert(constraint->is_in && "can only specify same constraint "
"on input");
sscanf(c, "%d%n", &same_as, &p);
if(same_as >= 0) {
c += p;
continue;
}
break;
case 'E': /* no float consts yet */
......@@ -2624,17 +2664,42 @@ void parse_asm_constraint(ir_node *node, constraint_t *constraint,
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);
assert(0 && "asm constraint not supported");
break;
default:
assert(0);
assert(0 && "unknown asm constraint found");
break;
}
++c;
}
if(same_as >= 0) {
const arch_register_req_t *other_constr;
assert(cls == NULL && "same as and register constraint not supported");
assert(!immediate_possible && "same as and immediate constraint not "
"supported");
assert(same_as < constraint->n_outs && "wrong constraint number in "
"same_as constraint");
other_constr = constraint->out_reqs[same_as];
req = obstack_alloc(obst, sizeof(req[0]));
req->cls = other_constr->cls;
req->type = arch_register_req_type_should_be_same;
req->limited = NULL;
req->other_same = pos;
req->other_different = -1;
/* switch constraints. This is because in firm we have same_as
* constraints on the output constraints while in the gcc asm syntax
* they are specified on the input constraints */
constraint->req = other_constr;
constraint->out_reqs[same_as] = req;
constraint->immediate_possible = 0;
return;
}
if(immediate_possible && cls == NULL) {
cls = &ia32_reg_classes[CLASS_ia32_gp];
}
......@@ -2642,8 +2707,8 @@ void parse_asm_constraint(ir_node *node, constraint_t *constraint,
assert(cls != NULL);
if(immediate_possible) {
assert(is_in && "imeediates make no sense for output constraints");
printf("Immediate possible 0-%x\n", immediate_max);
assert(constraint->is_in
&& "imeediates make no sense for output constraints");
}
/* todo: check types (no float input on 'r' constrainted in and such... */
......@@ -2669,26 +2734,32 @@ void parse_asm_constraint(ir_node *node, constraint_t *constraint,
constraint->req = req;
constraint->immediate_possible = immediate_possible;
constraint->immediate_max = immediate_max;
constraint->immediate_type = immediate_type;
}
static
void parse_clobber(ir_node *node, int pos, constraint_t *constraint,
const char *c)
{
panic("Clobbers not supported yet");
}
ir_node *gen_ASM(ir_node *node)
{
int i, arity;
ir_graph *irg = env.irg;
ir_node *block = transform_node(get_nodes_block(node));
dbg_info *dbgi = get_irn_dbg_info(node);
ir_node **in;
ir_node *res;
int out_arity;
int n_outs;
int n_clobbers;
ia32_attr_t *attr;
int i, arity;
ir_graph *irg = env.irg;
ir_node *block = transform_node(get_nodes_block(node));
dbg_info *dbgi = get_irn_dbg_info(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;
struct obstack *obst;
struct obstack *obst;
constraint_t parsed_constraint;
/* assembler could contain float statements */
FP_USED(env.cg);
......@@ -2705,39 +2776,42 @@ ir_node *gen_ASM(ir_node *node)
/* construct register constraints */
obst = get_irg_obstack(irg);
out_reqs = obstack_alloc(obst, out_arity * sizeof(out_reqs[0]));
parsed_constraint.out_reqs = out_reqs;
parsed_constraint.n_outs = n_outs;
parsed_constraint.is_in = 0;
for(i = 0; i < out_arity; ++i) {
const char *c;
constraint_t parsed_constr;
if(i < n_outs) {
const ir_asm_constraint *constraint;
constraint = & get_ASM_output_constraints(node) [i];
c = get_id_str(constraint->constraint);
parse_asm_constraint(node, i, &parsed_constraint, c);
} else {
ident *glob_id = get_ASM_clobbers(node) [i - n_outs];
c = get_id_str(glob_id);
parse_clobber(node, i, &parsed_constraint, c);
}
parse_asm_constraint(node, &parsed_constr, c, 0);
out_reqs[i] = parsed_constr.req;
out_reqs[i] = parsed_constraint.req;
}
in_reqs = obstack_alloc(obst, arity * sizeof(in_reqs[0]));
parsed_constraint.is_in = 1;
for(i = 0; i < arity; ++i) {
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(node, &parsed_constr, c, 1);
in_reqs[i] = parsed_constr.req;
parse_asm_constraint(node, i, &parsed_constraint, c);
in_reqs[i] = parsed_constraint.req;
if(parsed_constr.immediate_possible) {
ir_node *pred = get_irn_n(node, i);
ir_node *immediate
= try_create_Immediate(pred, parsed_constr.immediate_max);
if(parsed_constraint.immediate_possible) {
ir_node *pred = get_irn_n(node, i);
char imm_type = parsed_constraint.immediate_type;
ir_node *immediate = try_create_Immediate(pred, imm_type);
if(immediate != NULL) {
in[i] = immediate;
......
......@@ -32,12 +32,25 @@ static inline int mov(int val)
return res;
}
static inline unsigned short swap16(unsigned short x)
{
__asm__("xchgb %b0, %h0 /* in: %1 out: %0 */" : "=q" (x) : "0" (x));
return x;
}
static inline unsigned int swap32(unsigned int x)
{
__asm__("bswap %0 /* %1 */" : "=r" (x) : "0" (x));
return x;
}
int main()
{
//sincostest(0.5);
outb(123, 42);
outb(12345, 42);
/*outb(123, 42);
outb(12345, 42);*/
printf("Swap16: %d Swap32: %d\n", swap16(12), swap32(123551235));
return mov(0) + inb(12345) + inb(123);
return mov(0) /*+ inb(12345) + inb(123)*/;
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment