On Aug 8, 2012, at 11:16 AM, Nathan Froyd wrote:
> On Wed, Aug 08, 2012 at 10:52:28AM -0700, Mike Stump wrote:
>> As we move to C++, I'd love for port maintainers to be able to get together 
>> and hoist _up_ code from the port so other ports can use it and thus, have 
>> more sharing.  We make heavily stylized uses, which could be wrapped into a 
>> prettier api, given a reasonably powerful language.  C++ might be powerful 
>> enough.  I'd love to see someone improve the FIXED_REGISTERS, 
>> REGISTER_NAMES, REG_CLASS_CONTENTS, REGNO_REG_CLASS, 
>> REGNO_GLOBAL_BASE_REG_P, CLASS_MAX_NREGS experience, as the current api 
>> sucks; for example.  I dread the slightest change to any of my registers, as 
>> the change ripples throughout a ton of disparate places, and it is currently 
>> too easy to forget one of them.  Bonus points for cleaning up 
>> TARGET_SECONDARY_RELOAD at the same time as the above.  I find that api 
>> sucks in ways I can't begin to describe.
> 
> Would a registers.md for defining registers and register classes
> (and maybe things like FIXED_REGISTERS and the like) be a good
> start for you, or do you want something more developed first?

I think I'd rather have a nice general purpose C++ library that has a nice api 
that can generate code.  Longer term, it'd be nice to refactor all the gen*.c 
code to use the library.  The problem with the current gen*.c scheme is there 
is no flexibility to do anything that wasn't preconceived.  So, for example, 
mode iterators had to be added, a user of the library, can't just slot in 20 
lines and have them.  I had mode iterators in a port I did, a long time before 
we had them in gcc, but, since there wasn't a way to slot them in, that meant 
no one had them for years and years.  Sad.  I can't just slot in 100 lines to 
'solve' the register issue.  I'd like, not a solution to the register problem, 
but, rather a library, that is compete enough, to let me solve the register 
problem.

The register case, maybe is too trivial to show what I mean, for example, here 
is 113 lines that solves a part of the problem.  Not a big deal, but, we don't 
have an easy enough way to do this and a culture that encourages innovative 
solutions.  20 years later, and the same old gross api still is the only way to 
do it.  Consider the below code.  Notice that I can do, pretty much anything I 
need with it.  At first, it didn't generate FIXED_REGISTERS, then, a few 
trivial lines later, it did.  The it didn't handle aliases, then a few lines 
later, then it did.  The bits are trivial and obvious for anyone to add.  The 
api is nice and flexible and can sport many different ways to doing things, 
and, even if all of them are compete failures, one can _always_ layer 
_anything_ they want on top of the trivial interface and do anything they want 
to solve the problem they face.  Notice the addition of regs, you can now do an 
entire register file with 1 line.  My feeling is that we should have a 
recommend best practice.  Those ports that don't, or didn't follow the best 
practice, are larger; those that do, are smaller.  In this case, the best 
practice, if regs is it, is 1 line.  You can add aliases, easy to use register 
names for parameters, with those being preferred, the usual names for the rest 
of them and so on.

Also, if all the ports switched to it, then one can actually change 
FIXED_REGISTERS to be completely different, merely by changing the 
implementation of the api, once.  One can move a register around, thus 
renumbering all the register, and reordering all the bits in the bits array, 
without any carefulness or fear.  One can add a new register, without fear of 
missing anything, anywhere (within the scope of the generated code).  If one 
wanted to add support for MODE_OK, or NREGS, or CANNOT_CONVERT, again, trivial 
to do, and possible to do in an incremental fashion.  Notice how I added 
aliases, while still retaining compatibility with existing users of the api.  
Want to add FRAME_POINTER_REGNUM support, easy to do, just invent an nice api 
you like, and bolt it in.  Want to revamp an api, easy put them in a namespace 
and put in a using regs_v1, newer code can do a using reg_v2.  Eventually 
regs_v1 can be deleted, or not, or even moved into the last port file that uses 
it.

Now, imagine a nice pretty api for secondary_reload.  :-)  Or vectors, or move 
instructions, or legitimate or legitimize... or  imagine what:

gen_const_int_pred(1, 4, 8, 14, 22, 32, 48, 64);

could do.  (Hint, generate predicates with stylized names for all of the given 
N-bit constants.)  Much nicer, less typing, easier to maintain...  We know 
exactly how to write the above, but only in a real language, C++ should be 
sufficient.  genpred.c will _never_ and can never do this, no matter that it is 
what, five lines of code, given the stuff on which to build this on top of.  
This is _why_ the gen*.c things are the wrong architecture.


#include <stdio.h>
#include <strings.h>

enum { BITS_PER = 64 };
enum style {
  Fixed,
  Saved,
  Vol };

class r {
  enum { N = 1024 };
  static int count;
  static const char *names[N];
  static int fixed[N];
  static const char *alias[N];
 public:
  r(const char *name, enum style s, const char *a = 0) {
    names[count] = name;
    if (s == Fixed)
      fixed[count] = 1;
    alias[count] = a;
    ++count;
  }
  r(const r &o) { }
  static int get_count() { return count; }
  static const char *get_name(int i) { return names[i]; }
  static const char *get_alias(int i) { return alias[i]; }
  static int get_fixed(int i) { return fixed[i]; }
};

const char *rn(int i, const char *prefix = "%r") {
  char buf[30];
  sprintf (buf, "%s%d", prefix, i);
  return strdup (buf);
}

int r::count = 0;
const char *r::names[sizeof (r::names)/sizeof(r::names[0])];
const char *r::alias[sizeof (r::alias)/sizeof(r::alias[0])];
int r::fixed[sizeof (r::fixed)/sizeof(r::fixed[0])];

class fr : public r {
public:
  fr(const char *name) : r(name, Fixed) { }
  fr(const fr &o) : r(o) { }
};

class vr : public r {
public:
  vr(const char *name, const char *a = 0) : r(name, Vol, a) { }
  vr(const fr &o) : r(o) { }
};

int main() {
  printf("#define REGISTER_NAMES \\\n");
  printf("  {");
  for (int i = 0; i < r::get_count(); ++i)
    {
      printf(" \"%s\"", r::get_name(i));
      if (i < r::get_count()-1)
        printf(",");
    }
  printf(" }\n");
  printf("\n");

  printf("#define FIXED_REGISTERS \\\n");
  printf("  {");
  long l = 0;
  int i;
  for (i = 0; i < r::get_count(); ++i)
    {
      l <<= 1;
      l |= r::get_fixed (i);
      
      if (i%BITS_PER == (BITS_PER-1))
        {
          printf(" 0x%lx", l);
          l = 0;
          if (i < r::get_count()-1)
            printf(",");
        }
    }
  if (i%BITS_PER != (BITS_PER-1))
    printf(" 0x%lx", l);
  printf(" }\n");
  printf("\n");

  printf("#define ADDITIONAL_REGISTER_NAMES \\\n");
  printf("  {");
  bool need = false;
  for (int i = 0; i < r::get_count(); ++i)
    {
      if (r::get_alias(i))
        {
          if (need)
            printf(",");
          printf(" {\"%s\", %d}", r::get_alias(i), i);
          need = 1;
        }
    }
  printf(" }\n");
  printf("\n");
}

class regs {
public:
  regs(int parms, int vol, int total) {
    for (int i=0; i<parms; ++i)
      vr(rn(i, "%a"), rn(i));
    for (int i=parms; i<vol; ++i)
      vr(rn(i));
    for (int i=vol; i<total; ++i)
      r(rn(i), Saved);
  }
};





regs gprs(4, 8, 32);

fr fregs[] = { "fr1", "fr2", "fr3", "fr4" };
vr vregs[] = { "vr1", "vr2", "vr3", "vr4" };
r r1("r1", Fixed);
r r2("r2", Fixed);
r r3("r3", Vol);
r r4("r4", Saved);
r r5("r5", Fixed);
r r6("r6", Fixed);
r r7("r7", Fixed);
r r8("r8", Fixed);
r r9("r9", Fixed);
r r10("r10", Fixed);
r r11("r11", Fixed);
r r12("r12", Fixed);
r r13("r13", Fixed);
fr fr1("fr1");
fr fr2("fr2");
fr fr3("fr3");


class gen {
public:
  gen() {
    for (int i = 0; i < 64; ++i)
      {
        fr (rn(i));
      }
  }
} a;





when run, this produces:

$ g++ reg.c && ./a.out
#define REGISTER_NAMES \
  { "%a0", "%a1", "%a2", "%a3", "%r4", "%r5", "%r6", "%r7", "%r8", "%r9", 
"%r10", "%r11", "%r12", "%r13", "%r14", "%r15", "%r16", "%r17", "%r18", "%r19", 
"%r20", "%r21", "%r22", "%r23", "%r24", "%r25", "%r26", "%r27", "%r28", "%r29", 
"%r30", "%r31", "fr1", "fr2", "fr3", "fr4", "vr1", "vr2", "vr3", "vr4", "r1", 
"r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r13", 
"fr1", "fr2", "fr3", "%r0", "%r1", "%r2", "%r3", "%r4", "%r5", "%r6", "%r7", 
"%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15", "%r16", "%r17", 
"%r18", "%r19", "%r20", "%r21", "%r22", "%r23", "%r24", "%r25", "%r26", "%r27", 
"%r28", "%r29", "%r30", "%r31", "%r32", "%r33", "%r34", "%r35", "%r36", "%r37", 
"%r38", "%r39", "%r40", "%r41", "%r42", "%r43", "%r44", "%r45", "%r46", "%r47", 
"%r48", "%r49", "%r50", "%r51", "%r52", "%r53", "%r54", "%r55", "%r56", "%r57", 
"%r58", "%r59", "%r60", "%r61", "%r62", "%r63" }

#define FIXED_REGISTERS \
  { 0xf0cfffff, 0xffffffffffffff }

#define ADDITIONAL_REGISTER_NAMES \
  { {"%r0", 0}, {"%r1", 1}, {"%r2", 2}, {"%r3", 3} }

Reply via email to