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

be: Factorise code to make a register requirement for an asm operand.

Now we get a nice abort instead of silently generating invalid code, when a sparc immediate constraint cannot be fulfilled.
parent a6da8020
......@@ -5,10 +5,52 @@
#include <ctype.h>
#include "bearch.h"
#include "beasm.h"
#include "bediagnostic.h"
#include "beemitter.h"
#include "ident_t.h"
#include "panic.h"
#include "xmalloc.h"
arch_register_req_t const *be_make_register_req(struct obstack *obst, be_asm_constraint_t const *const c, int const n_outs, arch_register_req_t const **const out_reqs, int const pos)
{
int const same_as = c->same_as;
if (same_as >= 0) {
if (same_as >= n_outs)
panic("invalid output number in same_as constraint");
arch_register_req_t *const req = OALLOC(obst, arch_register_req_t);
arch_register_req_t const *const other = out_reqs[same_as];
*req = *other;
req->type |= arch_register_req_type_should_be_same;
req->other_same = 1U << pos;
/* 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. */
out_reqs[same_as] = req;
return other;
}
/* Pure memory ops. */
if (!c->cls)
return arch_no_register_req;
if (c->all_registers_allowed)
return c->cls->class_req;
arch_register_req_t *const req = (arch_register_req_t*)obstack_alloc(obst, sizeof(*req) + sizeof(unsigned));
unsigned *const limited = (unsigned*)(req + 1);
*limited = c->allowed_registers;
memset(req, 0, sizeof(*req));
req->type = arch_register_req_type_limited;
req->cls = c->cls;
req->limited = limited;
req->width = 1;
return req;
}
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)
{
......
......@@ -10,7 +10,23 @@
#ifndef FIRM_BE_BEASM_H
#define FIRM_BE_BEASM_H
#include "be_types.h"
#include "firm_types.h"
#include "obstack.h"
/**
* An assembler constraint.
*/
typedef struct be_asm_constraint_t {
arch_register_class_t const *cls;
unsigned allowed_registers;
bool all_registers_allowed;
bool memory_possible;
char immediate_type;
int same_as;
} be_asm_constraint_t;
arch_register_req_t const *be_make_register_req(struct obstack *obst, be_asm_constraint_t const *c, int n_outs, arch_register_req_t const **out_reqs, int pos);
typedef void be_emit_asm_operand_func(ir_node const *asmn, char modifier, unsigned pos);
......
......@@ -16,6 +16,7 @@
#include "array.h"
#include "bearch.h"
#include "beasm.h"
#include "beemitter.h"
#include "bediagnostic.h"
#include "begnuas.h"
......@@ -28,59 +29,6 @@
#include "panic.h"
#include "util.h"
/**
* An assembler constraint.
*/
typedef struct parsed_constraint_t {
const arch_register_class_t *cls;
unsigned allowed_registers;
bool all_registers_allowed;
bool memory_possible;
char immediate_type;
int same_as;
} parsed_constraint_t;
static arch_register_req_t const *x86_make_register_req(struct obstack *obst,
parsed_constraint_t const *const c, int const n_outs,
arch_register_req_t const **const out_reqs, int const pos)
{
int const same_as = c->same_as;
if (same_as >= 0) {
if (same_as >= n_outs)
panic("invalid output number in same_as constraint");
arch_register_req_t *const req = OALLOC(obst, arch_register_req_t);
arch_register_req_t const *const other = out_reqs[same_as];
*req = *other;
req->type |= arch_register_req_type_should_be_same;
req->other_same = 1U << pos;
/* 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. */
out_reqs[same_as] = req;
return other;
}
/* Pure memory ops. */
if (c->cls == NULL)
return arch_no_register_req;
if (c->all_registers_allowed)
return c->cls->class_req;
arch_register_req_t *const req = (arch_register_req_t*)obstack_alloc(obst, sizeof(req[0]) + sizeof(unsigned));
unsigned *const limited = (unsigned*)(req + 1);
*limited = c->allowed_registers;
memset(req, 0, sizeof(req[0]));
req->type = arch_register_req_type_limited;
req->cls = c->cls;
req->limited = limited;
req->width = 1;
return req;
}
arch_register_t const *x86_parse_clobber(x86_clobber_name_t const *const additional_clobber_names, char const *const clobber)
{
arch_register_t const *reg = arch_find_register(clobber);
......@@ -94,10 +42,7 @@ arch_register_t const *x86_parse_clobber(x86_clobber_name_t const *const additio
return NULL;
}
static void parse_asm_constraints(parsed_constraint_t *const constraint,
const x86_asm_constraint_list_t *constraints,
ident *const constraint_text,
bool const is_output)
static void parse_asm_constraints(be_asm_constraint_t *const constraint, x86_asm_constraint_list_t const *const constraints, ident *const constraint_text, bool const is_output)
{
memset(constraint, 0, sizeof(constraint[0]));
constraint->same_as = -1;
......@@ -350,11 +295,11 @@ ir_node *x86_match_ASM(const ir_node *node, new_bd_asm_func new_bd_asm,
for (unsigned o = 0; o < n_out_constraints; ++o) {
ir_asm_constraint const *const constraint = &out_constraints[o];
parsed_constraint_t parsed_constraint;
be_asm_constraint_t parsed_constraint;
parse_asm_constraints(&parsed_constraint, constraints,
constraint->constraint, true);
arch_register_req_t const *const req = x86_make_register_req(obst, &parsed_constraint, n_out_constraints, out_reqs, o);
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);
x86_asm_operand_t *const op = &operands[constraint->pos];
......@@ -383,7 +328,7 @@ ir_node *x86_match_ASM(const ir_node *node, new_bd_asm_func new_bd_asm,
for (int i = 0; i < n_inputs; ++i) {
ir_asm_constraint const *const constraint = &in_constraints[i];
parsed_constraint_t parsed_constraint;
be_asm_constraint_t parsed_constraint;
parse_asm_constraints(&parsed_constraint, constraints,
constraint->constraint, false);
......@@ -411,7 +356,7 @@ ir_node *x86_match_ASM(const ir_node *node, new_bd_asm_func new_bd_asm,
ir_node *const new_pred = be_transform_node(pred);
unsigned const in_pos = ARR_LEN(in_reqs);
arch_register_req_t const *req = x86_make_register_req(obst, &parsed_constraint, n_out_constraints, out_reqs, in_pos);
arch_register_req_t const *req = be_make_register_req(obst, &parsed_constraint, n_out_constraints, out_reqs, in_pos);
set_operand_if_invalid(op, ASM_OP_IN_REG, in_pos, constraint);
......
......@@ -24,6 +24,7 @@
#include "panic.h"
#include "util.h"
#include "beasm.h"
#include "benode.h"
#include "beirg.h"
#include "beutil.h"
......@@ -185,19 +186,7 @@ static bool needs_extension(ir_node *op)
return !be_upper_bits_clean(op, mode);
}
/**
* An assembler constraint.
*/
typedef struct constraint_t {
const arch_register_class_t *cls;
char all_registers_allowed;
char immediate_type;
int same_as;
} constraint_t;
static void parse_asm_constraints(constraint_t *const constraint,
ident *const constraint_text,
bool const is_output)
static void parse_asm_constraints(be_asm_constraint_t *const constraint, ident *const constraint_text, bool const is_output)
{
memset(constraint, 0, sizeof(constraint[0]));
constraint->same_as = -1;
......@@ -318,32 +307,6 @@ static const arch_register_t *find_register(const char *name)
return NULL;
}
static arch_register_req_t const *make_register_req(ir_graph *const irg,
constraint_t const *const c, int const n_outs,
arch_register_req_t const **const out_reqs, int const pos)
{
int const same_as = c->same_as;
if (same_as >= 0) {
if (same_as >= n_outs)
panic("invalid output number in same_as constraint");
struct obstack *const obst = get_irg_obstack(irg);
arch_register_req_t *const req = OALLOC(obst, arch_register_req_t);
arch_register_req_t const *const other = out_reqs[same_as];
*req = *other;
req->type |= arch_register_req_type_should_be_same;
req->other_same = 1U << pos;
/* 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. */
out_reqs[same_as] = req;
return other;
}
return c->cls->class_req;
}
void sparc_init_asm_constraints(void)
{
be_set_constraint_support(ASM_CONSTRAINT_FLAG_SUPPORTS_REGISTER, "0123456789efr");
......@@ -442,13 +405,11 @@ static ir_node *gen_ASM(ir_node *node)
for (out_idx = 0; out_idx < n_out_constraints; ++out_idx) {
const ir_asm_constraint *constraint = &out_constraints[out_idx];
unsigned pos = constraint->pos;
constraint_t parsed_constraint;
be_asm_constraint_t parsed_constraint;
parse_asm_constraints(&parsed_constraint, constraint->constraint, true);
assert(parsed_constraint.immediate_type == 0);
arch_register_req_t const *const req
= make_register_req(irg, &parsed_constraint, n_out_constraints,
out_reg_reqs, out_idx);
arch_register_req_t const *const req = be_make_register_req(obst, &parsed_constraint, n_out_constraints, out_reg_reqs, out_idx);
out_reg_reqs[out_idx] = req;
/* TODO: adjust register_req for clobbers */
......@@ -469,7 +430,7 @@ static ir_node *gen_ASM(ir_node *node)
const ir_asm_constraint *constraint = &in_constraints[i];
unsigned pos = constraint->pos;
constraint_t parsed_constraint;
be_asm_constraint_t parsed_constraint;
parse_asm_constraints(&parsed_constraint, constraint->constraint, false);
sparc_asm_operand_t *const operand = &operands[pos];
......@@ -479,7 +440,7 @@ static ir_node *gen_ASM(ir_node *node)
if (imm_type != '\0' && sparc_match_immediate(operand, pred, imm_type))
continue;
arch_register_req_t const *const req = make_register_req(irg, &parsed_constraint, n_out_constraints, out_reg_reqs, i);
arch_register_req_t const *const req = be_make_register_req(obst, &parsed_constraint, n_out_constraints, out_reg_reqs, i);
in_reg_reqs[i] = req;
int op_pos = n_ins++;
......
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