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} }