Commit 78087bf5 authored by Christoph Mallon's avatar Christoph Mallon
Browse files

be: Factorise code to parse asm constraints.

* This also resolves an out-of-bounds access when a '#' is encountered.
* This also corrects a wrong format specifier in a panic message in the x86 backend.
parent 3c223b1b
......@@ -11,6 +11,7 @@
#include "beemitter.h"
#include "ident_t.h"
#include "panic.h"
#include "util.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)
......@@ -55,6 +56,97 @@ arch_register_req_t const *be_make_register_req(struct obstack *obst, be_asm_con
return req;
}
void be_parse_asm_constraints_internal(be_asm_constraint_t *const constraint, ident *const constraint_text, bool const is_output, parse_constraint_letter_func_t *const parse_constraint_letter, void const *const env)
{
memset(constraint, 0, sizeof(*constraint));
constraint->same_as = -1;
char const *i = get_id_str(constraint_text);
/* a memory constraint: no need to do anything in backend about it
* (dependencies are already respected by the memory edge of the node) */
if (*i == '\0')
return;
/* TODO: improve error messages with node and source info. (As users can
* easily hit these) */
char immediate_type = '\0';
unsigned limited = 0;
arch_register_class_t const *cls = NULL;
bool memory_possible = false;
bool all_registers_allowed = false;
int same_as = -1;
while (*i != '\0') {
char const l = *i++;
switch (l) {
/* Skip spaces, out/in-out marker. */
case ' ':
case '\t':
case '\n':
case '=':
case '+':
case '&':
case '*':
break;
case '#':
while (*i != '\0' && *i != ',')
++i;
break;
default:
if (is_digit(l)) {
if (is_output)
panic("can only specify same constraint on input");
int p;
sscanf(i - 1, "%d%n", &same_as, &p);
if (same_as >= 0)
i += p;
} else {
be_asm_constraint_t new_constraint;
memset(&new_constraint, 0, sizeof(new_constraint));
parse_constraint_letter(env, &new_constraint, l);
limited |= new_constraint.allowed_registers;
all_registers_allowed |= new_constraint.all_registers_allowed;
memory_possible |= new_constraint.memory_possible;
arch_register_class_t const *const new_cls = new_constraint.cls;
if (new_cls) {
if (cls && cls != new_cls)
panic("multiple register classes not supported");
cls = new_cls;
}
char const new_imm = new_constraint.immediate_type;
if (new_imm != '\0') {
if (immediate_type != '\0' && immediate_type != new_imm)
panic("multiple immediate types not supported");
immediate_type = new_imm;
}
}
break;
}
}
if (same_as >= 0) {
if (cls)
panic("same as and register constraint not supported");
if (immediate_type != '\0')
panic("same as and immediate constraint not supported");
}
if (!cls && same_as < 0 && !memory_possible)
panic("no constraint specified for assembler input");
constraint->same_as = same_as;
constraint->cls = cls;
constraint->allowed_registers = limited;
constraint->all_registers_allowed = all_registers_allowed;
constraint->memory_possible = memory_possible;
constraint->immediate_type = immediate_type;
}
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");
......
......@@ -28,6 +28,10 @@ typedef struct 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 parse_constraint_letter_func_t(void const *env, be_asm_constraint_t*, char l);
void be_parse_asm_constraints_internal(be_asm_constraint_t *constraint, ident *constraint_text, bool is_output, parse_constraint_letter_func_t *parse_constraint_letter, void const *env);
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);
......
......@@ -42,131 +42,52 @@ arch_register_t const *x86_parse_clobber(x86_clobber_name_t const *const additio
return NULL;
}
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)
static void x86_parse_constraint_letter(void const *const env, be_asm_constraint_t* const c, char const l)
{
memset(constraint, 0, sizeof(constraint[0]));
constraint->same_as = -1;
unsigned char const *c = (const unsigned char*)get_id_str(constraint_text);
/* a memory constraint: no need to do anything in backend about it
* (dependencies are already respected by the memory edge of the node) */
if (*c == 0)
x86_asm_constraint_list_t const *const constraints = (x86_asm_constraint_list_t const*)env;
unsigned char const u = (unsigned char)l;
if (u >= ARRAY_SIZE(*constraints))
panic("Unknown asm constraint '%c'", l);
x86_asm_constraint_t const *const constraint = &(*constraints)[u];
switch (constraint->kind) {
case MATCH_REG:
c->cls = constraint->cls;
if (constraint->limited == 0)
c->all_registers_allowed = true;
else
c->allowed_registers = constraint->limited;
return;
/* TODO: improve error messages with node and source info. (As users can
* easily hit these) */
char immediate_type = '\0';
unsigned limited = 0;
arch_register_class_t const *cls = NULL;
bool memory_possible = false;
bool all_registers_allowed = false;
int same_as = -1;
for ( ; *c != 0; ++c) {
arch_register_class_t const *new_cls = NULL;
char new_imm = '\0';
switch (*c) {
/* Skip spaces, out/in-out marker. */
case ' ':
case '\t':
case '\n':
case '=':
case '+':
case '&':
case '*':
break;
case '#':
while (*c != '\0' && *c != ',')
++c;
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9': {
if (is_output)
panic("can only specify same constraint on input");
int p;
sscanf((const char*)c, "%d%n", &same_as, &p);
if (same_as >= 0) {
c += p-1; /* loop will do +1 */
continue;
}
break;
}
default:
if (*c >= ARRAY_SIZE(*constraints))
panic("Unknown asm constraint '%c'", *c);
const x86_asm_constraint_t *constraint = &(*constraints)[*c];
switch (constraint->kind) {
case MATCH_REG:
new_cls = constraint->cls;
if (constraint->limited == 0)
all_registers_allowed = true;
else
limited |= constraint->limited;
goto fine;
case MATCH_MEM:
/* memory constraint no need to do anything in backend about it
* (dependencies are already respected by the memory edge of the
* node) */
memory_possible = true;
goto fine;
case MATCH_IMM:
new_cls = constraint->cls;
new_imm = *c;
goto fine;
case MATCH_ANY:
new_imm = *c;
new_cls = constraint->cls;
memory_possible = true;
all_registers_allowed = true;
goto fine;
case MATCH_INVALID:
break;
}
panic("Unknown asm constraint '%s'", *c);
fine:
break;
}
case MATCH_MEM:
/* memory constraint no need to do anything in backend about it
* (dependencies are already respected by the memory edge of the
* node) */
c->memory_possible = true;
return;
if (new_cls != NULL) {
if (cls != NULL && cls != new_cls)
panic("multiple register classes not supported");
cls = new_cls;
}
case MATCH_IMM:
c->cls = constraint->cls;
c->immediate_type = l;
return;
if (new_imm != '\0') {
if (immediate_type != '\0' && immediate_type != new_imm)
panic("multiple immediate types not supported");
immediate_type = new_imm;
}
}
case MATCH_ANY:
c->cls = constraint->cls;
c->immediate_type = l;
c->memory_possible = true;
c->all_registers_allowed = true;
return;
if (same_as >= 0) {
if (cls != NULL)
panic("same as and register constraint not supported");
if (immediate_type != '\0')
panic("same as and immediate constraint not supported");
case MATCH_INVALID:
break;
}
panic("Unknown asm constraint '%c'", l);
}
if (cls == NULL && same_as < 0 && !memory_possible)
panic("no constraint specified for assembler input");
constraint->same_as = same_as;
constraint->cls = cls;
constraint->allowed_registers = limited;
constraint->all_registers_allowed = all_registers_allowed;
constraint->memory_possible = memory_possible;
constraint->immediate_type = immediate_type;
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)
{
be_parse_asm_constraints_internal(constraint, constraint_text, is_output, &x86_parse_constraint_letter, constraints);
}
static bool can_match(const arch_register_req_t *in,
......
......@@ -186,115 +186,36 @@ static bool needs_extension(ir_node *op)
return !be_upper_bits_clean(op, mode);
}
static void parse_asm_constraints(be_asm_constraint_t *const constraint, ident *const constraint_text, bool const is_output)
static void sparc_parse_constraint_letter(void const *const env, be_asm_constraint_t* const c, char const l)
{
memset(constraint, 0, sizeof(constraint[0]));
constraint->same_as = -1;
char const *c = get_id_str(constraint_text);
if (*c == '\0') {
/* a memory constraint: no need to do anything in backend about it
* (the dependencies are already respected by the memory edge of
* the node) */
return;
}
char immediate_type = '\0';
arch_register_class_t const *cls = NULL;
bool all_registers_allowed = false;
int same_as = -1;
while (*c != 0) {
arch_register_class_t const *new_cls = NULL;
char new_imm = '\0';
switch (*c) {
/* Skip spaces, out/in-out marker */
case ' ':
case '\t':
case '\n':
case '=':
case '+':
case '&':
case '*':
break;
case '#':
while (*c != 0 && *c != ',')
++c;
break;
case 'r':
new_cls = &sparc_reg_classes[CLASS_sparc_gp];
all_registers_allowed = true;
break;
case 'e':
case 'f':
new_cls = &sparc_reg_classes[CLASS_sparc_fp];
all_registers_allowed = true;
break;
case 'I':
case 'i':
new_cls = &sparc_reg_classes[CLASS_sparc_gp];
new_imm = *c;
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9': {
if (is_output)
panic("can only specify same constraint on input");
int p;
sscanf(c, "%d%n", &same_as, &p);
if (same_as >= 0) {
c += p;
continue;
}
break;
}
default:
panic("unknown asm constraint '%c'", *c);
}
(void)env;
if (new_cls) {
if (!cls) {
cls = new_cls;
} else if (cls != new_cls) {
panic("multiple register classes not supported");
}
}
switch (l) {
case 'r':
c->cls = &sparc_reg_classes[CLASS_sparc_gp];
c->all_registers_allowed = true;
break;
if (new_imm != '\0') {
if (immediate_type == '\0') {
immediate_type = new_imm;
} else if (immediate_type != new_imm) {
panic("multiple immediate types not supported");
}
}
case 'e':
case 'f':
c->cls = &sparc_reg_classes[CLASS_sparc_fp];
c->all_registers_allowed = true;
break;
++c;
}
case 'I':
case 'i':
c->cls = &sparc_reg_classes[CLASS_sparc_gp];
c->immediate_type = l;
break;
if (same_as >= 0) {
if (cls != NULL)
panic("same as and register constraint not supported");
if (immediate_type != '\0')
panic("same as and immediate constraint not supported");
default:
panic("unknown asm constraint '%c'", l);
}
}
if (!cls && same_as < 0)
panic("no constraint specified for assembler input");
constraint->same_as = same_as;
constraint->cls = cls;
constraint->all_registers_allowed = all_registers_allowed;
constraint->immediate_type = immediate_type;
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, &sparc_parse_constraint_letter, NULL);
}
static const arch_register_t *find_register(const char *name)
......
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