This is the mail archive of the
gcc@gcc.gnu.org
mailing list for the GCC project.
Extending constraints using register subclasses
- From: Jamie Prescott <jpresss at yahoo dot com>
- To: gcc at gcc dot gnu dot org
- Date: Mon, 11 May 2009 16:45:26 -0700 (PDT)
- Subject: Extending constraints using register subclasses
Hi!
I wanted to add finer (one per) register subclasses, so that I can more finely control
the register placement inside the inline assembly.
These are the relevant definitions inside my include file:
enum reg_class
{
NO_REGS = 0,
GENERAL_REGS,
X_REGS,
R0_REG, R1_REG, R2_REG, R3_REG,
R4_REG, R5_REG, R6_REG, R7_REG,
X0_REG, X1_REG, X2_REG, X3_REG,
X4_REG, X5_REG, X6_REG, X7_REG,
ALL_REGS,
LIM_REG_CLASSES
};
#define N_REG_CLASSES ((int) LIM_REG_CLASSES)
/* Give names of register classes as strings for dump file. */
#define REG_CLASS_NAMES \
{ \
"NO_REGS", \
"GENERAL_REGS", \
"X_REGS", \
"R0_REG", "R1_REG", "R2_REG", "R3_REG", \
"R4_REG", "R5_REG", "R6_REG", "R7_REG", \
"X0_REG", "X1_REG", "X2_REG", "X3_REG", \
"X4_REG", "X5_REG", "X6_REG", "X7_REG", \
"ALL_REGS", \
"LIM_REGS" \
}
/* Define which registers fit in which classes.
This is an initializer for a vector of HARD_REG_SET
of length N_REG_CLASSES. */
#define REG_CLASS_CONTENTS \
{ \
{ 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, /* NO_REGS */ \
{ 0xffffffff, 0x007fffff, 0x00000000, 0x00000000 }, /* GENERAL_REGS */ \
{ 0x00000000, 0xff800000, 0xffffffff, 0x007fffff }, /* X_REGS */ \
{ 0x00000001, 0x00000000, 0x00000000, 0x00000000 }, /* R0_REG */ \
{ 0x00000002, 0x00000000, 0x00000000, 0x00000000 }, /* R1_REG */ \
{ 0x00000004, 0x00000000, 0x00000000, 0x00000000 }, /* R2_REG */ \
{ 0x00000008, 0x00000000, 0x00000000, 0x00000000 }, /* R3_REG */ \
{ 0x00000010, 0x00000000, 0x00000000, 0x00000000 }, /* R4_REG */ \
{ 0x00000020, 0x00000000, 0x00000000, 0x00000000 }, /* R5_REG */ \
{ 0x00000040, 0x00000000, 0x00000000, 0x00000000 }, /* R6_REG */ \
{ 0x00000080, 0x00000000, 0x00000000, 0x00000000 }, /* R7_REG */ \
{ 0x00000000, 0x00800000, 0x00000000, 0x00000000 }, /* X0_REG */ \
{ 0x00000000, 0x01000000, 0x00000000, 0x00000000 }, /* X1_REG */ \
{ 0x00000000, 0x02000000, 0x00000000, 0x00000000 }, /* X2_REG */ \
{ 0x00000000, 0x04000000, 0x00000000, 0x00000000 }, /* X3_REG */ \
{ 0x00000000, 0x08000000, 0x00000000, 0x00000000 }, /* X4_REG */ \
{ 0x00000000, 0x10000000, 0x00000000, 0x00000000 }, /* X5_REG */ \
{ 0x00000000, 0x20000000, 0x00000000, 0x00000000 }, /* X6_REG */ \
{ 0x00000000, 0x40000000, 0x00000000, 0x00000000 }, /* X7_REG */ \
{ 0xffffffff, 0xffffffff, 0xffffffff, 0x007fffff }, /* ALL_REGS */ \
}
/* The same information, inverted:
Return the class number of the smallest class containing
reg number REGNO. This could be a conditional expression
or could index an array. */
#define REGNO_REG_CLASS(REGNO) xxx_regno_reg_class(REGNO)
/* The class value for index registers, and the one for base regs. */
#define INDEX_REG_CLASS NO_REGS
#define BASE_REG_CLASS GENERAL_REGS
#define CLASS_REG_SIZE(CLASS) xxx_class_reg_size(CLASS)
#define CONSTRAINT_LEN(C, STR) \
((((STR)[0] == 'a' || (STR)[0] == 'b') && (STR)[1] >= '0' && (STR)[1] <= '7') ? 2: \
DEFAULT_CONSTRAINT_LEN(C, STR))
/* Get reg_class from a letter and string, such as appears in the machine description. */
#define REG_CLASS_FROM_CONSTRAINT(CHAR, STR) \
xxx_reg_class_from_constraint(CHAR, STR)
I then have this inside my main C file:
int
xxx_reg_class_from_constraint(int c, char const *str)
{
if (str[0] == 'a' && str[1] >= '0' && str[1] <= '7')
return R0_REG + (str[1] - '0');
if (str[0] == 'b' && str[1] >= '0' && str[1] <= '7')
return X0_REG + (str[1] - '0');
return c == 'r' ? GENERAL_REGS: (c == 'x' ? X_REGS: NO_REGS);
}
int
xxx_regno_reg_class(int regno)
{
if (regno >= 0 && regno <= 7)
return R0_REG + regno;
if (regno >= XXX_FIRST_XREG && regno <= XXX_FIRST_XREG + 7)
return X0_REG + (regno - XXX_FIRST_XREG);
return XXX_REG_32BIT(regno) ? GENERAL_REGS:
(XXX_REG_XREG(regno) ? X_REGS: NO_REGS);
}
int
xxx_class_reg_size(enum reg_class rcls)
{
if (rcls == GENERAL_REGS ||
(rcls >= R0_REG && rcls <= R7_REG))
return 4;
if (rcls == X_REGS ||
(rcls >= X0_REG && rcls <= X7_REG))
return 8;
return 0;
}
But upon something like this:
static inline void *test_copy(void *dst, void const *src, int n)
{
asm volatile ("mcopy\n\t"
:: "a0" (dst), "a1" (src), "a2" (n));
return dst;
}
I get an 'error: 'asm' operand has impossible constraints'.
My doubt is, inside the RTLs I only have 'r' and 'x' general classes listed, of which the
a0..7 and b0..7 are part of, do I have to explicitly list a0..7 and b0..7 in every RTL, or
GCC is smart enough to see that a contraint 'r' maps to a register class of which a0..7
are part of?
- Jamie