Commit 72599823 authored by Christoph Mallon's avatar Christoph Mallon
Browse files

mips: Handle inline asm with contraints 'IJKLMNOPRcdgimnrvy' and modifier 'z'.

Now 'int main(void) { int i = 23, v; asm("lw\t%0, %1\n\taddiu\t%0, %0, %2" : "=r" (v) : "R" (i), "I" (-23)); return v; }' can be translated.
parent fc4f3bda
......@@ -55,11 +55,20 @@ static backend_params mips_backend_params = {
.float_int_overflow = ir_overflow_indefinite,
};
static void mips_init_asm_constraints(void)
{
be_set_constraint_support(ASM_CONSTRAINT_FLAG_SUPPORTS_MEMOP, "Rm");
be_set_constraint_support(ASM_CONSTRAINT_FLAG_SUPPORTS_REGISTER, "cdrvy");
be_set_constraint_support(ASM_CONSTRAINT_FLAG_SUPPORTS_ANY, "g");
be_set_constraint_support(ASM_CONSTRAINT_FLAG_SUPPORTS_IMMEDIATE, "IJKLMNOPin");
}
static void mips_init(void)
{
ir_mode *const ptr_mode = new_reference_mode("p32", MIPS_MACHINE_SIZE, MIPS_MACHINE_SIZE);
set_modeP(ptr_mode);
mips_init_asm_constraints();
mips_create_opcodes();
mips_register_init();
}
......
......@@ -10,6 +10,7 @@
#include "be_t.h"
#include "bearch.h"
#include "beblocksched.h"
#include "bediagnostic.h"
#include "beemithlp.h"
#include "beemitter.h"
#include "begnuas.h"
......@@ -22,22 +23,27 @@
#include "panic.h"
#include "util.h"
static void emit_immediate(char const *const prefix, ir_node const *const node)
static void emit_immediate_val(char const *const prefix, ir_entity *const ent, int32_t const val)
{
mips_immediate_attr_t const *const imm = get_mips_immediate_attr_const(node);
if (imm->ent) {
if (ent) {
if (prefix)
be_emit_irprintf("%s(", prefix);
be_gas_emit_entity(imm->ent);
if (imm->val != 0)
be_emit_irprintf("%+" PRId32, imm->val);
be_gas_emit_entity(ent);
if (val != 0)
be_emit_irprintf("%+" PRId32, val);
if (prefix)
be_emit_char(')');
} else {
be_emit_irprintf("%" PRId32, imm->val);
be_emit_irprintf("%" PRId32, val);
}
}
static void emit_immediate(char const *const prefix, ir_node const *const node)
{
mips_immediate_attr_t const *const imm = get_mips_immediate_attr_const(node);
emit_immediate_val(prefix, imm->ent, imm->val);
}
static void emit_register(arch_register_t const *const reg)
{
be_emit_char('$');
......@@ -91,6 +97,48 @@ unknown:
}
}
static void emit_mips_asm_operand(ir_node const *const node, char const modifier, unsigned const pos)
{
be_asm_attr_t const *const attr = get_be_asm_attr_const(node);
mips_asm_operand_t const *const op = &((mips_asm_operand_t const*)attr->operands)[pos];
/* modifiers:
* z: print normally, except immediate 0 as '$zero' */
if (!be_is_valid_asm_operand_kind(node, modifier, pos, op->kind, "z", "", ""))
return;
switch (op->kind) {
case BE_ASM_OPERAND_INVALID:
panic("invalid asm operand");
case BE_ASM_OPERAND_INPUT_VALUE:
emit_register(arch_get_irn_register_in(node, op->pos));
return;
case BE_ASM_OPERAND_OUTPUT_VALUE:
emit_register(arch_get_irn_register_out(node, op->pos));
return;
case BE_ASM_OPERAND_IMMEDIATE:
if (modifier == 'z' && op->val == 0 && !op->ent)
emit_register(&mips_registers[REG_ZERO]);
else
emit_immediate_val(NULL, op->ent, op->val);
return;
case BE_ASM_OPERAND_MEMORY:
be_emit_char('(');
emit_register(arch_get_irn_register_in(node, op->pos));
be_emit_char(')');
return;
}
panic("invalid asm operand kind");
}
static void emit_be_ASM(const ir_node *node)
{
be_emit_asm(node, &emit_mips_asm_operand);
}
static void emit_be_Copy(ir_node const *const node)
{
ir_node *const op = be_get_Copy_op(node);
......@@ -167,6 +215,7 @@ static void mips_register_emitters(void)
be_init_emitters();
mips_register_spec_emitters();
be_set_emitter(op_be_Asm, emit_be_ASM);
be_set_emitter(op_be_Copy, emit_be_Copy);
be_set_emitter(op_be_IncSP, emit_be_IncSP);
be_set_emitter(op_be_Perm, emit_be_Perm);
......
......@@ -8,6 +8,7 @@
#include <stdint.h>
#include "beasm.h"
#include "benode.h"
#include "irnode_t.h"
......@@ -30,6 +31,13 @@ static inline mips_cond_t mips_negate_cond(mips_cond_t const c)
return (mips_cond_t)(c ^ 1U);
}
typedef struct mips_asm_operand_t {
be_asm_operand_kind_t kind;
unsigned pos;
int32_t val;
ir_entity *ent;
} mips_asm_operand_t;
typedef struct mips_cond_attr_t {
mips_attr_t attr;
mips_cond_t cond;
......
......@@ -78,6 +78,11 @@ static inline bool is_uimm16(long const val)
return 0 <= val && val < 65536;
}
static inline bool is_imm_lui(long const val)
{
return (val & 0xFFFFU) == 0;
}
typedef struct mips_addr {
ir_node *base;
ir_entity *ent;
......@@ -104,6 +109,167 @@ static ir_node *make_address(ir_node const *const node, ir_entity *const ent, in
return new_bd_mips_addiu(dbgi, block, lui, ent, val);
}
static void mips_parse_constraint_letter(void const *const env, be_asm_constraint_t* const c, char const l)
{
(void)env;
switch (l) {
case 'c':
c->cls = &mips_reg_classes[CLASS_mips_gp];
c->allowed_registers = 1U << REG_GP_T9;
break;
case 'g':
c->all_registers_allowed = true;
c->memory_possible = true;
/* FALLTHROUGH */
case 'I':
case 'J':
case 'K':
case 'L':
case 'M':
case 'N':
case 'O':
case 'P':
case 'i':
case 'n':
c->cls = &mips_reg_classes[CLASS_mips_gp];
c->immediate_type = l;
break;
case 'R':
case 'm':
c->memory_possible = true;
break;
case 'd':
case 'r':
case 'y':
c->cls = &mips_reg_classes[CLASS_mips_gp];
c->all_registers_allowed = true;
break;
case 'v':
c->cls = &mips_reg_classes[CLASS_mips_gp];
c->allowed_registers = 1U << REG_GP_V1;
break;
default:
panic("unknown asm constraint '%c'", l);
}
}
static bool mips_check_immediate_constraint(long const val, char const imm_type)
{
switch (imm_type) {
case 'I': return is_simm16(val);
case 'J': return val == 0;
case 'K': return is_uimm16(val);
case 'L': return is_imm_lui(val);
case 'M': return !is_simm16(val) && !is_uimm16(val) && !is_imm_lui(val);
case 'N': return -65535 <= val && val < 0;
case 'O': return -16384 <= val && val < 16384;
case 'P': return 1 <= val && val < 65536;
case 'g':
case 'i':
case 'n': return true;
}
panic("invalid immediate constraint found");
}
static bool mips_match_immediate(mips_asm_operand_t *const operand, ir_node *const node, char const imm_type)
{
ir_tarval *offset;
ir_entity *entity;
unsigned reloc_kind;
if (!be_match_immediate(node, &offset, &entity, &reloc_kind))
return false;
assert(reloc_kind == 0);
if (entity && imm_type != 'g' && imm_type != 'i')
return false;
long value;
if (offset) {
value = get_tarval_long(offset);
if (!mips_check_immediate_constraint(value, imm_type))
return false;
} else {
value = 0;
}
operand->kind = BE_ASM_OPERAND_IMMEDIATE;
operand->val = value;
operand->ent = entity;
return true;
}
static void parse_asm_constraints(be_asm_constraint_t *const constraint, ident *const constraint_text, bool const is_output)
{
be_parse_asm_constraints_internal(constraint, constraint_text, is_output, &mips_parse_constraint_letter, NULL);
}
static ir_node *gen_ASM(ir_node *const node)
{
if (get_ASM_n_clobbers(node) != 0)
panic("TODO");
unsigned const n_operands = be_count_asm_operands(node);
ir_graph *const irg = get_irn_irg(node);
struct obstack *const obst = get_irg_obstack(irg);
mips_asm_operand_t *const operands = NEW_ARR_DZ(mips_asm_operand_t, obst, n_operands);
arch_register_req_t const **out_reqs = NEW_ARR_F(arch_register_req_t const*, 0);
ir_asm_constraint const *const out_constraints = get_ASM_output_constraints(node);
size_t const const n_out_constraints = get_ASM_n_output_constraints(node);
for (size_t o = 0; o != n_out_constraints; ++o) {
ir_asm_constraint const *const constraint = &out_constraints[o];
be_asm_constraint_t parsed_constraint;
parse_asm_constraints(&parsed_constraint, constraint->constraint, true);
arch_register_req_t const *const req = be_make_register_req(obst, &parsed_constraint, n_out_constraints, out_reqs, o);
ARR_APP1(arch_register_req_t const*, out_reqs, req);
mips_asm_operand_t *const operand = &operands[constraint->pos];
operand->kind = BE_ASM_OPERAND_OUTPUT_VALUE;
operand->pos = o;
}
ir_node **in = NEW_ARR_F(ir_node*, 0);
arch_register_req_t const **in_reqs = NEW_ARR_F(arch_register_req_t const*, 0);
ir_asm_constraint const *const in_constraints = get_ASM_input_constraints(node);
int const n_inputs = get_ASM_n_inputs(node);
for (int i = 0; i < n_inputs; ++i) {
ir_node *const pred = get_ASM_input(node, i);
ir_asm_constraint const *const constraint = &in_constraints[i];
be_asm_constraint_t parsed_constraint;
parse_asm_constraints(&parsed_constraint, constraint->constraint, false);
mips_asm_operand_t *const operand = &operands[constraint->pos];
char const imm_type = parsed_constraint.immediate_type;
if (imm_type != '\0' && mips_match_immediate(operand, pred, imm_type))
continue;
ir_node *const new_pred = be_transform_node(pred);
be_asm_operand_kind_t kind = BE_ASM_OPERAND_INPUT_VALUE;
arch_register_req_t const *req = be_make_register_req(obst, &parsed_constraint, n_out_constraints, out_reqs, i);
if (req == arch_no_register_req) {
kind = BE_ASM_OPERAND_MEMORY;
req = arch_get_irn_register_req(new_pred)->cls->class_req;
}
operand->kind = kind;
operand->pos = ARR_LEN(in);
ARR_APP1(ir_node*, in, new_pred);
ARR_APP1(arch_register_req_t const*, in_reqs, req);
}
return be_make_asm(node, in, in_reqs, out_reqs, operands);
}
static ir_node *gen_Add(ir_node *const node)
{
ir_tarval *tv;
......@@ -869,6 +1035,7 @@ static void mips_register_transformers(void)
{
be_start_transform_setup();
be_set_transform_function(op_ASM, gen_ASM);
be_set_transform_function(op_Add, gen_Add);
be_set_transform_function(op_Address, gen_Address);
be_set_transform_function(op_And, gen_And);
......
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