Commit 2794d4cd authored by Matthias Braun's avatar Matthias Braun
Browse files

ia32: generalize ASM node handling so we can reuse it for amd64

parent d0b92253
......@@ -1225,18 +1225,6 @@ static void ia32_prepare_graph(ir_graph *irg)
extern const arch_isa_if_t ia32_isa_if;
static void init_asm_constraints(void)
{
be_set_constraint_support(ASM_CONSTRAINT_FLAG_SUPPORTS_REGISTER, "0123456789ADQRSXYabcdflpqrtu");
be_set_constraint_support(ASM_CONSTRAINT_FLAG_SUPPORTS_IMMEDIATE, "IJKLMNOin");
be_set_constraint_support(ASM_CONSTRAINT_FLAG_SUPPORTS_MEMOP, "Vmo");
asm_constraint_flags_t const g =
ASM_CONSTRAINT_FLAG_SUPPORTS_IMMEDIATE |
ASM_CONSTRAINT_FLAG_SUPPORTS_MEMOP |
ASM_CONSTRAINT_FLAG_SUPPORTS_REGISTER;
be_set_constraint_support(g, "g");
}
/**
* Check if Mux(sel, mux_true, mux_false) would represent a Max or Min operation
*/
......@@ -1440,7 +1428,7 @@ static void ia32_init(void)
{
ia32_setup_cg_config();
init_asm_constraints();
x86_set_be_asm_constraint_support(ia32_asm_constraints);
ia32_mode_fpcw = new_non_arithmetic_mode("fpcw", 16);
ia32_mode_flags = new_non_arithmetic_mode("flags", 32);
......@@ -1540,7 +1528,8 @@ static void ia32_mark_remat(ir_node *node)
static int ia32_is_valid_clobber(const char *clobber)
{
return ia32_get_clobber_register(clobber) != NULL;
return x86_parse_clobber(&ia32_isa_template.base,
ia32_additional_clobber_names, clobber) != NULL;
}
static void ia32_lower_for_target(void)
......
......@@ -903,118 +903,20 @@ static void emit_ia32_Jmp(const ir_node *node)
}
}
/**
* Emit an inline assembler operand.
*
* @param node the ia32_ASM node
* @param s points to the operand (a %c)
*
* @return pointer to the first char in s NOT in the current operand
*/
static const char* emit_asm_operand(const ir_node *node, const char *s)
{
assert(*s == '%');
char c = *(++s);
/* parse modifiers */
char modifier = 0;
switch (c) {
case 0:
ir_fprintf(stderr, "Warning: asm text (%+F) ends with %%\n", node);
be_emit_char('%');
return s;
case '%':
be_emit_char('%');
return s + 1;
case 'w':
case 'b':
case 'h':
modifier = c;
++s;
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
break;
static void emit_ia32_asm_register(const arch_register_t *reg, char modifier,
ir_mode *mode)
{
const char *name;
switch (modifier) {
case '\0': name = get_register_name_mode(reg, mode); break;
case 'b': name = get_register_name_8bit_low(reg); break;
case 'h': name = get_register_name_8bit_high(reg); break;
case 'w': name = get_register_name_16bit(reg); break;
default:
ir_fprintf(stderr,
"Warning: asm text (%+F) contains unknown modifier '%c' for asm op\n",
node, c);
++s;
break;
}
/* parse number */
int num;
int p;
if (sscanf(s, "%d%n", &num, &p) != 1) {
ir_fprintf(stderr, "Warning: Couldn't parse assembler operand (%+F)\n",
node);
return s;
} else {
s += p;
panic("invalid asm op modifier");
}
const ia32_attr_t *ia32_attr = get_ia32_attr_const(node);
const ia32_asm_attr_t *attr = CONST_CAST_IA32_ATTR(ia32_asm_attr_t, ia32_attr);
const ia32_asm_reg_t *asm_regs = attr->register_map;
if (num < 0 || ARR_LEN(asm_regs) <= (size_t)num) {
ir_fprintf(stderr,
"Error: Custom assembler references invalid input/output (%+F)\n",
node);
return s;
}
const ia32_asm_reg_t *asm_reg = &asm_regs[num];
assert(asm_reg->valid);
/* get register */
const arch_register_t *reg;
if (asm_reg->use_input == 0) {
reg = arch_get_irn_register_out(node, asm_reg->inout_pos);
} else {
ir_node *pred = get_irn_n(node, asm_reg->inout_pos);
/* might be an immediate value */
if (is_ia32_Immediate(pred)) {
emit_ia32_Immediate(pred);
return s;
}
reg = arch_get_irn_register(pred);
}
if (reg == NULL) {
ir_fprintf(stderr,
"Warning: no register assigned for %d asm op (%+F)\n",
num, node);
return s;
}
/* Emit the register. */
if (asm_reg->memory) {
be_emit_char('(');
emit_register(reg, NULL);
be_emit_char(')');
} else {
const char *name;
switch (modifier) {
case '\0': name = get_register_name_mode(reg, asm_reg->mode); break;
case 'b': name = get_register_name_8bit_low(reg); break;
case 'h': name = get_register_name_8bit_high(reg); break;
case 'w': name = get_register_name_16bit(reg); break;
default: panic("invalid asm op modifier");
}
be_emit_char('%');
be_emit_string(name);
}
return s;
be_emit_char('%');
be_emit_string(name);
}
/**
......@@ -1022,31 +924,10 @@ static const char* emit_asm_operand(const ir_node *node, const char *s)
*/
static void emit_ia32_Asm(const ir_node *node)
{
const void *gen_attr = get_irn_generic_attr_const(node);
const ia32_asm_attr_t *attr
= CONST_CAST_IA32_ATTR(ia32_asm_attr_t, gen_attr);
ident *asm_text = attr->asm_text;
const char *s = get_id_str(asm_text);
be_emit_cstring("#APP");
be_emit_finish_line_gas(node);
if (s[0] != '\t')
be_emit_char('\t');
while (*s != 0) {
if (*s == '%') {
s = emit_asm_operand(node, s);
} else {
be_emit_char(*s++);
}
}
be_emit_cstring("\n#NO_APP\n");
be_emit_write_line();
const ia32_asm_attr_t *attr = get_ia32_asm_attr_const(node);
x86_emit_asm(node, &attr->asmattr, emit_ia32_asm_register);
}
/**
* Emit movsb/w instructions to make mov count divideable by 4
*/
......
......@@ -945,7 +945,7 @@ static int ia32_asm_attrs_equal(const ir_node *a, const ir_node *b)
const ia32_asm_attr_t *attr_a = get_ia32_asm_attr_const(a);
const ia32_asm_attr_t *attr_b = get_ia32_asm_attr_const(b);
return ia32_attrs_equal_(&attr_a->attr, &attr_b->attr)
&& attr_a->asm_text == attr_b->asm_text;
&& x86_asm_attr_equal(&attr_a->asmattr, &attr_b->asmattr);
}
/**
......
......@@ -15,6 +15,7 @@
#include "bearch.h"
#include "irnode_t.h"
#include "x86_cc.h"
#include "x86_asm.h"
typedef enum {
ia32_Normal,
......@@ -184,25 +185,13 @@ struct ia32_x87_attr_t {
bool pop; /**< Emit a pop suffix. */
};
typedef struct ia32_asm_reg_t ia32_asm_reg_t;
struct ia32_asm_reg_t {
unsigned use_input : 1; /* use input or output pos */
unsigned valid : 1;
unsigned memory : 1;
unsigned dummy_fill : 13;
unsigned inout_pos : 16; /* in/out pos where the
register is assigned */
ir_mode *mode;
};
/**
* The attributes for ASM nodes.
*/
typedef struct ia32_asm_attr_t ia32_asm_attr_t;
struct ia32_asm_attr_t {
ia32_attr_t attr; /**< the generic attribute */
ident *asm_text;
const ia32_asm_reg_t *register_map;
ia32_attr_t attr; /**< the generic attribute */
x86_asm_attr_t asmattr;
};
/**
......
......@@ -346,9 +346,8 @@ Asm => {
arity => "variable",
out_arity => "variable",
attr_type => "ia32_asm_attr_t",
attr => "ident *asm_text, const ia32_asm_reg_t *register_map",
init_attr => "attr->asm_text = asm_text;\n".
"\tattr->register_map = register_map;\n",
attr => "const x86_asm_attr_t *asmattr",
init_attr => "attr->asmattr = *asmattr;",
latency => 10,
modified_flags => $status_flags,
},
......
This diff is collapsed.
......@@ -12,6 +12,10 @@
#define FIRM_BE_IA32_IA32_TRANSFORM_H
#include "firm_types.h"
#include "x86_asm.h"
extern const x86_clobber_name_t ia32_additional_clobber_names[];
extern const x86_asm_constraint_t ia32_asm_constraints[128];
/**
* Transform firm nodes to x86 assembler nodes, ie
......
......@@ -1253,12 +1253,12 @@ static bool is_clobber(ir_node const *const asm_n, ir_node const *const value)
if (arch_register_req_is(req, should_be_same))
return false;
unsigned const num = get_Proj_num(value);
ia32_asm_attr_t const *const attr = get_ia32_asm_attr_const(asm_n);
ia32_asm_reg_t const *const reg_map = attr->register_map;
for (size_t i = 0, n = ARR_LEN(reg_map); i != n; ++i) {
ia32_asm_reg_t const *const reg = &reg_map[i];
if (!reg->use_input && reg->inout_pos == num)
unsigned const num = get_Proj_num(value);
ia32_asm_attr_t const *const attr = get_ia32_asm_attr_const(asm_n);
x86_asm_operand_t const *const operands = attr->asmattr.operands;
for (size_t i = 0, n = ARR_LEN(operands); i != n; ++i) {
x86_asm_operand_t const *const op = &operands[i];
if (op->kind == ASM_OP_OUT_REG && op->inout_pos == num)
return false;
}
......
This diff is collapsed.
#ifndef FIRM_BE_IA32_X86_ASM_H
#define FIRM_BE_IA32_X86_ASM_H
#include <stdbool.h>
#include <stdint.h>
#include "be_types.h"
#include "compiler.h"
#include "firm_types.h"
#include "util.h"
typedef struct x86_imm32_t {
ir_entity *entity;
int32_t offset;
} x86_imm32_t;
typedef enum x86_asm_operand_kind_t {
ASM_OP_INVALID,
ASM_OP_IN_REG,
ASM_OP_OUT_REG,
ASM_OP_MEMORY,
ASM_OP_IMMEDIATE,
} x86_asm_operand_kind_t;
typedef struct x86_asm_operand_t {
ENUMBF(x86_asm_operand_kind_t) kind : 3;
uint8_t inout_pos; /**< in/out pos where register is assigned */
union {
ir_mode *mode;
x86_imm32_t imm32;
} u;
} x86_asm_operand_t;
typedef struct x86_asm_attr_t {
ident *asm_text;
const x86_asm_operand_t *operands;
} x86_asm_attr_t;
typedef struct x86_clobber_name_t {
const char *name;
unsigned index;
} x86_clobber_name_t;
typedef enum x86_asm_constraint_kind_t {
MATCH_INVALID,
MATCH_REG,
MATCH_IMM,
MATCH_MEM,
MATCH_ANY,
} x86_asm_constraint_kind_t;
typedef struct x86_asm_constraint_t {
x86_asm_constraint_kind_t kind;
const arch_register_class_t *cls;
unsigned limited;
} x86_asm_constraint_t;
static inline bool x86_asm_attr_equal(const x86_asm_attr_t *attr0,
const x86_asm_attr_t *attr1)
{
return attr0->asm_text == attr1->asm_text;
}
typedef void (*emit_register_func)(const arch_register_t *reg, char modifier,
ir_mode *mode);
void x86_emit_asm(const ir_node *node, const x86_asm_attr_t *attr,
emit_register_func emit_register);
typedef ir_node* (*new_bd_asm_func)(dbg_info *dbgi, ir_node *block, int arity,
ir_node *in[], int out_arity,
const x86_asm_attr_t *attr);
const arch_register_t *x86_parse_clobber(const arch_env_t *arch_env,
const x86_clobber_name_t *additional_clobber_names, const char *name);
ir_node *x86_match_ASM(const ir_node *node, new_bd_asm_func new_bd_asm,
const x86_clobber_name_t *names,
const x86_asm_constraint_t *constraints);
bool x86_match_immediate(x86_imm32_t *immediate, const ir_node *node,
char constraint);
void x86_set_be_asm_constraint_support(const x86_asm_constraint_t *constraints);
#endif
Markdown is supported
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