Commit f86818ea authored by Matthias Braun's avatar Matthias Braun
Browse files

amd64: support inline assembly.

This first version should perform similar to the support in the ia32
backend, but needs more work to add amd64 specific immediate types.
parent 2794d4cd
......@@ -105,6 +105,17 @@ static const char *get_register_name_8bit(const arch_register_t *reg)
panic("unexpected register number");
}
static const char *get_register_name_8bit_high(const arch_register_t *reg)
{
switch (reg->global_index) {
case REG_RAX: return "ah";
case REG_RBX: return "bh";
case REG_RCX: return "ch";
case REG_RDX: return "dh";
}
panic("unexpected register number");
}
static const char *get_register_name_16bit(const arch_register_t *reg)
{
switch (reg->global_index) {
......@@ -588,6 +599,49 @@ static ir_node *sched_next_block(const ir_node *block)
return (ir_node*)get_irn_link(block);
}
static const char *get_register_name_ir_mode(const arch_register_t *reg,
ir_mode *mode)
{
if (get_mode_arithmetic(mode) != irma_twos_complement)
return reg->name;
switch (get_mode_size_bits(mode)) {
case 8: return get_register_name_8bit(reg);
case 16: return get_register_name_16bit(reg);
case 32: return get_register_name_32bit(reg);
case 64: return reg->name;
default:
panic("unexpected mode size");
}
}
static void emit_amd64_asm_register(const arch_register_t *reg, char modifier,
ir_mode *mode)
{
const char *name;
switch (modifier) {
case '\0':
name = mode != NULL ? get_register_name_ir_mode(reg, mode) : reg->name;
break;
case 'b': name = get_register_name_8bit(reg); break;
case 'h': name = get_register_name_8bit_high(reg); break;
case 'w': name = get_register_name_16bit(reg); break;
case 'k': name = get_register_name_32bit(reg); break;
case 'q': name = reg->name; break;
// gcc also knows 'x' V4SFmode, 't' V8SFmode, 'y' "st(0)" instead of "st",
// 'd' duplicate operand for AVX instruction
default:
panic("invalid asm op modifier");
}
be_emit_char('%');
be_emit_string(name);
}
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);
}
/**
* Emit a Jmp.
*/
......@@ -757,10 +811,11 @@ static void amd64_register_emitters(void)
/* register all emitter functions defined in spec */
amd64_register_spec_emitters();
be_set_emitter(op_amd64_asm, emit_amd64_asm);
be_set_emitter(op_amd64_jcc, emit_amd64_jcc);
be_set_emitter(op_amd64_jmp, emit_amd64_jmp);
be_set_emitter(op_amd64_mov_gp, emit_amd64_mov_gp);
be_set_emitter(op_amd64_jmp_switch, emit_amd64_jmp_switch);
be_set_emitter(op_amd64_mov_gp, emit_amd64_mov_gp);
be_set_emitter(op_be_Copy, emit_be_Copy);
be_set_emitter(op_be_CopyKeep, emit_be_Copy);
be_set_emitter(op_be_IncSP, emit_be_IncSP);
......
......@@ -179,6 +179,14 @@ static int amd64_attrs_equal(const ir_node *a, const ir_node *b)
return attr_a->op_mode == attr_b->op_mode;
}
static int amd64_asm_attrs_equal(const ir_node *a, const ir_node *b)
{
const amd64_asm_attr_t *attr_a = get_amd64_asm_attr_const(a);
const amd64_asm_attr_t *attr_b = get_amd64_asm_attr_const(b);
return amd64_attrs_equal(a, b)
&& x86_asm_attr_equal(&attr_a->asmattr, &attr_b->asmattr);
}
static int amd64_addr_attrs_equal(const ir_node *a, const ir_node *b)
{
const amd64_addr_attr_t *attr_a = get_amd64_addr_attr_const(a);
......
......@@ -67,6 +67,13 @@ static inline amd64_addr_attr_t *get_amd64_addr_attr(ir_node *node)
return (amd64_addr_attr_t*)get_irn_generic_attr(node);
}
static inline const amd64_asm_attr_t *get_amd64_asm_attr_const(
const ir_node *node)
{
assert(is_amd64_asm(node));
return (const amd64_asm_attr_t*)get_irn_generic_attr_const(node);
}
static inline const amd64_addr_attr_t *get_amd64_addr_attr_const(
const ir_node *node)
{
......
......@@ -15,6 +15,7 @@
#include "bearch.h"
#include "compiler.h"
#include "../ia32/x86_cc.h"
#include "../ia32/x86_asm.h"
enum amd64_arch_irn_flags_t {
amd64_arch_irn_flag_commutative_binop = arch_irn_flag_backend << 0,
......@@ -89,6 +90,11 @@ typedef struct {
ENUMBF(amd64_op_mode_t) op_mode : 4;
} amd64_attr_t;
typedef struct {
amd64_attr_t base;
x86_asm_attr_t asmattr;
} amd64_asm_attr_t;
typedef struct {
amd64_attr_t base;
bool needs_frame_ent : 1;
......
......@@ -69,6 +69,9 @@ $default_copy_attr = "amd64_copy_attr";
"init_amd64_attributes(res, irn_flags_, in_reqs, n_res, op_mode);\n"
."\tattr->insn_mode = insn_mode;\n"
."\tattr->addr = addr;",
amd64_asm_attr_t =>
"init_amd64_attributes(res, irn_flags_, in_reqs, n_res, op_mode);\n"
."\tattr->asmattr = *asmattr;\n",
amd64_binop_addr_attr_t =>
"be_info_init_irn(res, irn_flags_, in_reqs, n_res);\n"
."\t*attr = *attr_init;",
......@@ -164,7 +167,14 @@ and => {
attr => "const amd64_binop_addr_attr_t *attr_init",
emit => "and%M %AM",
modified_flags => $status_flags,
},
asm => {
arity => "variable",
out_arity => "variable",
attr_type => "amd64_asm_attr_t",
attr => "const x86_asm_attr_t *asmattr",
fixed => "amd64_op_mode_t op_mode = AMD64_OP_NONE;\n",
},
div => {
......
......@@ -44,6 +44,61 @@ static size_t start_params_offset;
static pmap *node_to_stack;
static be_stackorder_t *stackorder;
/** we don't have a concept of aliasing registers, so enumerate them
* manually for the asm nodes. */
const x86_clobber_name_t amd64_additional_clobber_names[] = {
{ "al", REG_RAX }, { "ah", REG_RAX }, { "ax", REG_RAX },
{ "bl", REG_RBX }, { "bh", REG_RBX }, { "bx", REG_RBX },
{ "cl", REG_RCX }, { "ch", REG_RCX }, { "cx", REG_RCX },
{ "dl", REG_RDX }, { "dh", REG_RDX }, { "dx", REG_RDX },
{ "si", REG_RSI }, { "di", REG_RDI }, { "sp", REG_RSP },
{ "bp", REG_RBP },
{ "eax", REG_RAX }, { "ebx", REG_RBX }, { "ecx", REG_RCX },
{ "edx", REG_RDX }, { "esi", REG_RSI }, { "edi", REG_RDI },
{ "ebp", REG_RBP }, { "esp", REG_RBP },
{ NULL, ~0u }
};
#define GP &amd64_reg_classes[CLASS_amd64_gp]
const x86_asm_constraint_t amd64_asm_constraints[128] = {
['A'] = { MATCH_REG, GP, 1 << REG_GP_RAX | 1 << REG_GP_RDX },
['D'] = { MATCH_REG, GP, 1 << REG_GP_RDI },
['I'] = { MATCH_IMM, GP, 0 },
['J'] = { MATCH_IMM, GP, 0 },
['K'] = { MATCH_IMM, GP, 0 },
['L'] = { MATCH_IMM, GP, 0 },
['M'] = { MATCH_IMM, GP, 0 },
['N'] = { MATCH_IMM, GP, 0 },
['O'] = { MATCH_IMM, GP, 0 },
['R'] = { MATCH_REG, GP, 1 << REG_GP_RAX | 1 << REG_GP_RBX
| 1 << REG_GP_RCX | 1 << REG_GP_RDX | 1 << REG_GP_RSI
| 1 << REG_GP_RDI | 1 << REG_GP_RBP | 1 << REG_GP_RSP },
['S'] = { MATCH_REG, GP, 1 << REG_GP_RSI },
['Q'] = { MATCH_REG, GP, 1 << REG_GP_RAX | 1 << REG_GP_RBX
| 1 << REG_GP_RCX | 1 << REG_GP_RDX },
['V'] = { MATCH_MEM, GP, 0 },
['X'] = { MATCH_ANY, GP, 0 },
['a'] = { MATCH_REG, GP, 1 << REG_GP_RAX },
['b'] = { MATCH_REG, GP, 1 << REG_GP_RBX },
['c'] = { MATCH_REG, GP, 1 << REG_GP_RCX },
['d'] = { MATCH_REG, GP, 1 << REG_GP_RDX },
['g'] = { MATCH_ANY, GP, 0 },
['i'] = { MATCH_IMM, GP, 0 },
['l'] = { MATCH_REG, GP, 1 << REG_GP_RAX | 1 << REG_GP_RBX
| 1 << REG_GP_RCX | 1 << REG_GP_RDX | 1 << REG_GP_RSI
| 1 << REG_GP_RDI | 1 << REG_GP_RBP },
['m'] = { MATCH_MEM, GP, 0 },
['n'] = { MATCH_IMM, GP, 0 },
['o'] = { MATCH_MEM, GP, 0 },
['p'] = { MATCH_REG, GP, 0 },
['q'] = { MATCH_REG, GP, 0 },
['r'] = { MATCH_REG, GP, 0 },
['x'] = { MATCH_REG, &amd64_reg_classes[CLASS_amd64_xmm], 0 },
// see comments in ia32_transform.c about unimplemented stuff.
};
#undef GP
static const arch_register_req_t amd64_requirement_gp = {
.cls = &amd64_reg_classes[CLASS_amd64_gp],
.limited = NULL,
......@@ -2025,6 +2080,32 @@ static ir_node *gen_Cond(ir_node *node)
return new_bd_amd64_jcc(dbgi, block, flags, cc);
}
static ir_node *gen_ASM(ir_node *node)
{
return x86_match_ASM(node, new_bd_amd64_asm, amd64_additional_clobber_names,
amd64_asm_constraints);
}
static ir_node *gen_Proj_ASM(ir_node *node)
{
ir_mode *mode = get_irn_mode(node);
ir_node *pred = get_Proj_pred(node);
ir_node *new_pred = be_transform_node(pred);
unsigned pn = get_Proj_num(node);
if (mode == mode_M) {
pn = arch_get_irn_n_outs(new_pred)-1;
} else if (mode_is_int(mode) || mode_is_reference(mode)) {
mode = mode_gp;
} else if (mode_is_float(mode)) {
mode = amd64_mode_xmm;
} else {
panic("unexpected proj mode at ASM");
}
return new_r_Proj(new_pred, mode, pn);
}
static ir_node *gen_Phi(ir_node *node)
{
ir_mode *mode = get_irn_mode(node);
......@@ -2706,6 +2787,7 @@ static void amd64_register_transformers(void)
be_set_transform_function(op_Address, gen_Address);
be_set_transform_function(op_Alloc, gen_Alloc);
be_set_transform_function(op_And, gen_And);
be_set_transform_function(op_ASM, gen_ASM);
be_set_transform_function(op_Bitcast, gen_Bitcast);
be_set_transform_function(op_Builtin, gen_Builtin);
be_set_transform_function(op_Call, gen_Call);
......@@ -2740,6 +2822,7 @@ static void amd64_register_transformers(void)
be_set_transform_function(op_amd64_l_haddpd, gen_amd64_l_haddpd);
be_set_transform_proj_function(op_Alloc, gen_Proj_Alloc);
be_set_transform_proj_function(op_ASM, gen_Proj_ASM);
be_set_transform_proj_function(op_Builtin, gen_Proj_Builtin);
be_set_transform_proj_function(op_Call, gen_Proj_Call);
be_set_transform_proj_function(op_Cond, be_duplicate_node);
......
......@@ -10,6 +10,12 @@
#ifndef FIRM_BE_AMD64_AMD64_TRANSFORM_H
#define FIRM_BE_AMD64_AMD64_TRANSFORM_H
#include "firm_types.h"
#include "x86_asm.h"
extern const x86_clobber_name_t amd64_additional_clobber_names[];
extern const x86_asm_constraint_t amd64_asm_constraints[128];
void amd64_init_transform(void);
ir_node *amd64_new_spill(ir_node *value, ir_node *after);
......
......@@ -790,8 +790,8 @@ static const backend_params *amd64_get_backend_params(void) {
static int amd64_is_valid_clobber(const char *clobber)
{
(void) clobber;
return 0;
return x86_parse_clobber(&amd64_isa_template.base,
amd64_additional_clobber_names, clobber) != NULL;
}
static void amd64_init_types(void)
......@@ -815,6 +815,7 @@ static void amd64_init(void)
amd64_register_init();
amd64_create_opcodes(&amd64_irn_ops);
amd64_cconv_init();
x86_set_be_asm_constraint_support(amd64_asm_constraints);
}
const arch_isa_if_t amd64_isa_if = {
......
......@@ -12,7 +12,6 @@
#include "betranshlp.h"
#include "beutil.h"
#include "gen_ia32_regalloc_if.h"
#include "ia32_emitter.h"
#include "ia32_new_nodes.h"
#include "irprintf.h"
#include "panic.h"
......
......@@ -66,13 +66,13 @@ typedef void (*emit_register_func)(const arch_register_t *reg, char modifier,
void x86_emit_asm(const ir_node *node, const x86_asm_attr_t *attr,
emit_register_func emit_register);
const arch_register_t *x86_parse_clobber(const arch_env_t *arch_env,
const x86_clobber_name_t *additional_clobber_names, const char *name);
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);
......
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