Commit 94dd895c authored by Christoph Mallon's avatar Christoph Mallon
Browse files

be: Factorise the code to emit an asm node and use a callback for each backend...

be: Factorise the code to emit an asm node and use a callback for each backend to output the operands.
parent 156f217b
......@@ -14,6 +14,7 @@
#include "amd64_nodes_attr.h"
#include "be_t.h"
#include "beblocksched.h"
#include "bediagnostic.h"
#include "begnuas.h"
#include "beirg.h"
#include "benode.h"
......@@ -210,8 +211,10 @@ static void amd64_emit_immediate64(const amd64_imm64_t *const imm)
}
}
static void amd64_emit_immediate32(const amd64_imm32_t *const imm)
static void amd64_emit_immediate32(bool const prefix, amd64_imm32_t const *const imm)
{
if (prefix)
be_emit_char('$');
if (imm->entity) {
be_gas_emit_entity(imm->entity);
if (imm->offset != 0)
......@@ -284,8 +287,7 @@ static void amd64_emit_am(const ir_node *const node, bool indirect_star)
case AMD64_OP_REG_IMM: {
const amd64_binop_addr_attr_t *const binop_attr
= (const amd64_binop_addr_attr_t*)attr;
be_emit_char('$');
amd64_emit_immediate32(&binop_attr->u.immediate);
amd64_emit_immediate32(true, &binop_attr->u.immediate);
be_emit_cstring(", ");
const arch_register_t *reg = arch_get_irn_register_in(node, 0);
emit_register_mode(reg, binop_attr->base.insn_mode);
......@@ -326,7 +328,7 @@ static void amd64_emit_am(const ir_node *const node, bool indirect_star)
return;
}
case AMD64_OP_UNOP_IMM32:
amd64_emit_immediate32(&attr->addr.immediate);
amd64_emit_immediate32(false, &attr->addr.immediate);
return;
case AMD64_OP_UNOP_ADDR:
if (indirect_star)
......@@ -618,10 +620,59 @@ static void emit_amd64_asm_register(const arch_register_t *reg, char modifier,
be_emit_string(name);
}
static void emit_amd64_asm_operand(ir_node const *const node, char const modifier, unsigned const pos)
{
switch (modifier) {
case '\0':
case 'b':
case 'h':
case 'k':
case 'q':
case 'w':
break;
default:
be_errorf(node, "asm contains unknown modifier '%c'", modifier);
return;
}
amd64_asm_attr_t const *const attr = get_amd64_asm_attr_const(node);
x86_asm_operand_t const *const op = &attr->asmattr.operands[pos];
switch ((x86_asm_operand_kind_t)op->kind) {
case ASM_OP_INVALID:
panic("invalid asm operand");
case ASM_OP_IN_REG: {
arch_register_t const *const reg = arch_get_irn_register_in(node, op->inout_pos);
emit_amd64_asm_register(reg, modifier, op->u.mode);
return;
}
case ASM_OP_OUT_REG: {
arch_register_t const *const reg = arch_get_irn_register_out(node, op->inout_pos);
emit_amd64_asm_register(reg, modifier, op->u.mode);
return;
}
case ASM_OP_MEMORY: {
arch_register_t const *const reg = arch_get_irn_register_in(node, op->inout_pos);
be_emit_irprintf("(%%%s)", reg->name);
return;
}
case ASM_OP_IMMEDIATE: {
amd64_imm32_t const imm = { op->u.imm32.entity, op->u.imm32.offset };
amd64_emit_immediate32(true, &imm);
return;
}
}
panic("invalid asm operand kind");
}
static void emit_amd64_asm(const ir_node *node)
{
const amd64_asm_attr_t *attr = get_amd64_asm_attr_const(node);
x86_emit_asm(node, &attr->asmattr, emit_amd64_asm_register);
amd64_asm_attr_t const *const attr = get_amd64_asm_attr_const(node);
be_emit_asm(node, attr->asmattr.asm_text, ARR_LEN(attr->asmattr.operands), emit_amd64_asm_operand);
}
/**
......
......@@ -9,6 +9,9 @@
* @author Matthias Braun
* @date 12.03.2007
*/
#include <ctype.h>
#include "bediagnostic.h"
#include "bedwarf.h"
#include "beemitter.h"
#include "benode.h"
......@@ -103,3 +106,47 @@ void be_emit_node(ir_node const *const node)
DEBUG_ONLY(if (!emit) panic("no emit handler for node %+F (%+G, graph %+F)", node, node, get_irn_irg(node));)
emit(node);
}
void be_emit_asm(ir_node const *const asmn, ident *const text, unsigned const n_operands, be_emit_asm_operand_func *const emit_asm_operand)
{
be_emit_cstring("#APP");
be_emit_finish_line_gas(asmn);
char const *s = get_id_str(text);
if (s[0] != '\t')
be_emit_char('\t');
char const *last = s;
while ((s = strchr(s, '%'))) {
be_emit_string_len(last, s - last);
++s; /* Skip '%'. */
switch (*s) {
case '%':
be_emit_char(*s++);
break;
default: {
char const modifier = isalpha((unsigned char)*s) ? *s++ : '\0';
unsigned pos;
int p;
if (sscanf(s, "%u%n", &pos, &p) == 1) {
s += p;
if (pos < n_operands) {
emit_asm_operand(asmn, modifier, pos);
} else {
be_errorf(asmn, "asm operand number '%u' out of range", pos);
}
} else {
be_errorf(asmn, "could not parse asm operand number");
}
break;
}
}
last = s;
}
be_emit_string(last);
be_emit_cstring("\n#NO_APP\n");
be_emit_write_line();
}
......@@ -125,4 +125,8 @@ void be_emit_nothing(ir_node const *node);
*/
void be_emit_node(ir_node const *node);
typedef void be_emit_asm_operand_func(ir_node const *asmn, char modifier, unsigned pos);
void be_emit_asm(ir_node const *asmn, ident *text, unsigned n_operands, be_emit_asm_operand_func *emit_asm_operand);
#endif
......@@ -31,6 +31,7 @@
#include "be_t.h"
#include "bearch_ia32_t.h"
#include "beblocksched.h"
#include "bediagnostic.h"
#include "begnuas.h"
#include "besched.h"
#include "bestack.h"
......@@ -189,25 +190,23 @@ static void ia32_emit_entity(ir_entity *entity, int no_pic_adjust)
}
}
static void emit_ia32_Immediate_no_prefix(const ir_node *node)
static void emit_ia32_immediate(bool const prefix, bool const no_pic_adjust, ir_entity *const entity, int32_t const offset)
{
const ia32_immediate_attr_t *attr = get_ia32_immediate_attr_const(node);
ir_entity *const entity = attr->entity;
if (entity != NULL) {
ia32_emit_entity(entity, attr->no_pic_adjust);
if (attr->offset != 0) {
be_emit_irprintf("%+"PRId32, attr->offset);
}
if (prefix)
be_emit_char('$');
if (entity) {
ia32_emit_entity(entity, no_pic_adjust);
if (offset != 0)
be_emit_irprintf("%+"PRId32, offset);
} else {
be_emit_irprintf("0x%"PRIX32, (uint32_t)attr->offset);
be_emit_irprintf("0x%"PRIX32, (uint32_t)offset);
}
}
static void emit_ia32_Immediate(const ir_node *node)
static void emit_ia32_immediate_attr(bool const prefix, ir_node const *const node)
{
be_emit_char('$');
emit_ia32_Immediate_no_prefix(node);
ia32_immediate_attr_t const *const attr = get_ia32_immediate_attr_const(node);
emit_ia32_immediate(prefix, attr->no_pic_adjust, attr->entity, attr->offset);
}
static void ia32_emit_mode_suffix_mode(const ir_mode *mode)
......@@ -494,7 +493,7 @@ emit_AM:
case 'B': {
ir_node const *const src = get_irn_n(node, n_ia32_binary_right);
if (is_ia32_Immediate(src)) {
emit_ia32_Immediate(src);
emit_ia32_immediate_attr(true, src);
be_emit_cstring(", ");
if (get_ia32_op_type(node) == ia32_Normal) {
goto destination_operand;
......@@ -566,9 +565,7 @@ emit_I:
if (attr->entity == NULL && attr->offset == 1)
break;
}
if (!(mod & EMIT_ALTERNATE_AM))
be_emit_char('$');
emit_ia32_Immediate_no_prefix(imm);
emit_ia32_immediate_attr(!(mod & EMIT_ALTERNATE_AM), imm);
if (mod & EMIT_SHIFT_COMMA) {
be_emit_char(',');
}
......@@ -901,13 +898,59 @@ static void emit_ia32_asm_register(const arch_register_t *reg, char modifier,
be_emit_string(name);
}
static void emit_ia32_asm_operand(ir_node const *const node, char const modifier, unsigned const pos)
{
switch (modifier) {
case '\0':
case 'b':
case 'h':
case 'k':
case 'w':
break;
default:
be_errorf(node, "asm contains unknown modifier '%c'", modifier);
return;
}
ia32_asm_attr_t const *const attr = get_ia32_asm_attr_const(node);
x86_asm_operand_t const *const op = &attr->asmattr.operands[pos];
switch ((x86_asm_operand_kind_t)op->kind) {
case ASM_OP_INVALID:
panic("invalid asm operand");
case ASM_OP_IN_REG: {
arch_register_t const *const reg = arch_get_irn_register_in(node, op->inout_pos);
emit_ia32_asm_register(reg, modifier, op->u.mode);
return;
}
case ASM_OP_OUT_REG: {
arch_register_t const *const reg = arch_get_irn_register_out(node, op->inout_pos);
emit_ia32_asm_register(reg, modifier, op->u.mode);
return;
}
case ASM_OP_MEMORY: {
arch_register_t const *const reg = arch_get_irn_register_in(node, op->inout_pos);
be_emit_irprintf("(%%%s)", reg->name);
return;
}
case ASM_OP_IMMEDIATE:
emit_ia32_immediate(true, true, op->u.imm32.entity, op->u.imm32.offset);
return;
}
panic("invalid asm operand kind");
}
/**
* Emits code for an ASM pseudo op.
*/
static void emit_ia32_Asm(const ir_node *node)
{
const ia32_asm_attr_t *attr = get_ia32_asm_attr_const(node);
x86_emit_asm(node, &attr->asmattr, emit_ia32_asm_register);
ia32_asm_attr_t const *const attr = get_ia32_asm_attr_const(node);
be_emit_asm(node, attr->asmattr.asm_text, ARR_LEN(attr->asmattr.operands), emit_ia32_asm_operand);
}
/**
......
......@@ -329,19 +329,6 @@ bool x86_match_immediate(x86_imm32_t *immediate, const ir_node *node,
return true;
}
static void x86_emit_immediate(const x86_imm32_t *immediate)
{
int32_t const offset = immediate->offset;
ir_entity const *const entity = immediate->entity;
if (entity) {
be_gas_emit_entity(entity);
if (offset != 0)
be_emit_irprintf("%+"PRId32, offset);
} else {
be_emit_irprintf("0x%"PRIX32, (uint32_t)offset);
}
}
static void set_operand_if_invalid(x86_asm_operand_t *const op, x86_asm_operand_kind_t const kind, unsigned const pos, ir_asm_constraint const *const constraint)
{
/* Multiple constraints for same pos. This can happen for example when
......@@ -548,129 +535,6 @@ ir_node *x86_match_ASM(const ir_node *node, new_bd_asm_func new_bd_asm,
return new_node;
}
/**
* Emit an inline assembler operand.
* @return pointer to the first char in s NOT in the current operand
*/
static const char* emit_asm_operand(const ir_node *node,
const x86_asm_attr_t *attr,
emit_register_func emit_register,
const char *s)
{
assert(*s == '%');
char c = *(++s);
/* parse modifiers */
char modifier = 0;
switch (c) {
case '\0':
/* TODO: move this warning to the frontend */
be_errorf(node, "asm ends with %%");
be_emit_char('%');
return s;
case '%':
be_emit_char('%');
return s + 1;
case 'w':
case 'b':
case 'h':
case 'k':
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;
default:
be_errorf(node, "asm contains unknown modifier '%c'", c);
++s;
break;
}
/* parse number */
unsigned num;
int p;
if (sscanf(s, "%u%n", &num, &p) != 1) {
be_errorf(node, "could not parse asm operand");
return s;
} else {
s += p;
}
const x86_asm_operand_t *operands = attr->operands;
if (num >= ARR_LEN(operands)) {
be_errorf(node, "asm operand number '%u' out of range", num);
return s;
}
const x86_asm_operand_t *op = &operands[num];
assert(op->kind != ASM_OP_INVALID);
/* immediate? */
if (op->kind == ASM_OP_IMMEDIATE) {
be_emit_char('$');
x86_emit_immediate(&op->u.imm32);
return s;
}
/* get register */
const arch_register_t *reg;
if (op->kind == ASM_OP_OUT_REG) {
reg = arch_get_irn_register_out(node, op->inout_pos);
} else if (op->kind == ASM_OP_IN_REG || op->kind == ASM_OP_MEMORY) {
reg = arch_get_irn_register_in(node, op->inout_pos);
} else {
panic("invalid asm operand");
}
if (reg == NULL) {
be_errorf(node, "no register assigend for asm op %u", num);
return s;
}
/* Emit the register. */
if (op->kind == ASM_OP_MEMORY) {
be_emit_char('(');
emit_register(reg, '\0', NULL);
be_emit_char(')');
} else {
emit_register(reg, modifier, op->u.mode);
}
return s;
}
void x86_emit_asm(const ir_node *node, const x86_asm_attr_t *attr,
emit_register_func emit_register)
{
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, attr, emit_register, s);
} else {
be_emit_char(*s++);
}
}
be_emit_cstring("\n#NO_APP\n");
be_emit_write_line();
}
void x86_set_be_asm_constraint_support(const x86_asm_constraint_list_t *constraints)
{
for (unsigned char c = 0; c < ARRAY_SIZE(*constraints); ++c) {
......
......@@ -76,9 +76,6 @@ static inline bool x86_asm_attr_equal(const x86_asm_attr_t *attr0,
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);
arch_register_t const *x86_parse_clobber(x86_clobber_name_t const *additional_clobber_names, char const *name);
typedef ir_node* (*new_bd_asm_func)(dbg_info *dbgi, ir_node *block, int arity,
......
......@@ -703,77 +703,35 @@ static void emit_be_IncSP(const ir_node *irn)
sparc_emitf(irn, "%s %S0, %d, %D0", insn, offset);
}
static const char *emit_asm_operand(const ir_node *node, const char *s)
{
assert(*s == '%');
char c = *(++s);
/* parse modifiers */
if (c == '\0') {
be_errorf(node, "asm ends with %%");
be_emit_char('%');
return s;
} else if (c == '%') {
be_emit_char('%');
return s+1;
} else if (!is_digit(c)) {
be_errorf(node, "asm contains unknown modifier '%c'", c);
return s+1;
}
/* parse number */
int num = 0;
int p = 0;
sscanf(s, "%d%n", &num, &p);
s += p;
const sparc_asm_attr_t *const attr = get_sparc_asm_attr_const(node);
const sparc_asm_operand_t *const operands = attr->operands;
if ((size_t)num > ARR_LEN(operands)) {
be_errorf(node, "asm operand number '%d' out of range", num);
return s;
static void emit_sparc_asm_operand(ir_node const *const node, char const modifier, unsigned const pos)
{
if (modifier != '\0') {
be_errorf(node, "asm contains unknown modifier '%c'", modifier);
return;
}
const sparc_asm_operand_t *const operand = &operands[num];
const arch_register_t *reg = NULL;
switch (operand->kind) {
sparc_asm_attr_t const *const attr = get_sparc_asm_attr_const(node);
sparc_asm_operand_t const *const op = &attr->operands[pos];
switch (op->kind) {
case ASM_OPERAND_IMMEDIATE:
sparc_emit_immediate(operand->immediate_value,
operand->immediate_value_entity);
return s;
sparc_emit_immediate(op->immediate_value, op->immediate_value_entity);
return;
case ASM_OPERAND_INPUT_VALUE:
reg = arch_get_irn_register_in(node, operand->pos);
break;
sparc_emit_register(arch_get_irn_register_in(node, op->pos));
return;
case ASM_OPERAND_OUTPUT_VALUE:
reg = arch_get_irn_register_out(node, operand->pos);
break;
sparc_emit_register(arch_get_irn_register_out(node, op->pos));
return;
}
/* emit the register */
sparc_emit_register(reg);
return s;
panic("invalid asm operand kind");
}
static void emit_sparc_ASM(const ir_node *node)
{
be_emit_cstring("#APP\n");
be_emit_write_line();
const sparc_asm_attr_t *attr = get_sparc_asm_attr_const(node);
const char *s = get_id_str(attr->text);
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();
sparc_asm_attr_t const *const attr = get_sparc_asm_attr_const(node);
be_emit_asm(node, attr->text, ARR_LEN(attr->operands), emit_sparc_asm_operand);
}
/**
......
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