diff --git a/.travis.yml b/.travis.yml index 408e5d59b..765b5cea1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,12 +1,13 @@ matrix: include: - os: linux - - os: osx addons: apt: packages: - ed + - openbios-ppc + - qemu-user git: depth: 10 diff --git a/README b/README index 701581f17..830c86cfc 100644 --- a/README +++ b/README @@ -2,7 +2,7 @@ =================================== © 1987-2005 Vrije Universiteit, Amsterdam - 2016-08-02 + 2016-11-26 INTRODUCTION @@ -19,6 +19,7 @@ probably broken. However, what's there should be sufficient to get things done and to evaluate how the full 6.1 release should work. + SUPPORT ======= @@ -31,10 +32,12 @@ Platforms: pc86 produces bootable floppy disk images for 8086 PCs linux386 produces ELF executables for PC Linux systems linux68k produces ELF executables for m68020 Linux systems +linuxppc produces ELF executables for PowerPC Linux systems cpm produces i80 CP/M .COM files rpi produces Raspberry Pi GPU binaries + INSTALLATION ============ @@ -55,6 +58,11 @@ Requirements: - (optionally) ninja; if you've got this, this will be autodetected and give you faster builds. +- (optionally) the qemu suite: if you have this installed, the build system + will detect it automatically and run the test suites for the supported + architectures. Get both the qemu-system-* platform emulators and the qemu-* + userland emulators (only works on Linux). + - about 40MB free in /tmp (or some other temporary directory). - about 6MB in the target directory. @@ -89,6 +97,7 @@ Instructions: The ACK should now be ready to use. + USAGE ===== @@ -155,6 +164,8 @@ There are some things you should be aware of. interpreter and the assembler-linkers. Only some of it builds. Look for build.lua files. + + DISCLAIMER ========== @@ -177,6 +188,6 @@ You can find the mailing list on the project's web site: Please enjoy. -David Given (dtrg on Sourceforge) +David Given (davidgiven on Github) dg@cowlark.com -2016-08-02 +2016-11-26 diff --git a/build.lua b/build.lua index 65ae6cb26..9bde044cf 100644 --- a/build.lua +++ b/build.lua @@ -11,14 +11,25 @@ vars.plats = { "linuxppc", "osx386", "osxppc", + "qemuppc", "pc86", "rpi", } +vars.plats_with_tests = { + "linux386", + "linuxppc", + "qemuppc", + "pc86", +} local plat_packages = {} +local test_packages = {} for _, p in ipairs(vars.plats) do plat_packages[#plat_packages+1] = "plat/"..p.."+pkg" end +for _, p in ipairs(vars.plats_with_tests) do + test_packages[#test_packages+1] = "plat/"..p.."/tests+tests" +end installable { name = "ack", @@ -36,6 +47,9 @@ installable { "util/opt+pkg", "examples+pkg", plat_packages + }, + deps = { + test_packages } } diff --git a/examples/paranoia.c b/examples/paranoia.c index f7020f71e..8a25800d9 100644 --- a/examples/paranoia.c +++ b/examples/paranoia.c @@ -15,6 +15,7 @@ This is a public domain adventure and may not be sold for profit */ +#include #include #define MOXIE 13 @@ -32,7 +33,9 @@ int plato_clone=3; int blast_door=0; int killer_count=0; -char get_char() +void character(void); + +char get_char(void) { char c; fflush(stdout); @@ -41,7 +44,7 @@ char get_char() return c; } -more() +void more(void) { printf("---------- More ----------"); #ifdef DEBUG @@ -55,8 +58,7 @@ more() }; } -new_clone(resume) -int resume; +int new_clone(int resume) { printf("\nClone %d just died.\n",clone); if (++clone>6) @@ -75,15 +77,14 @@ int resume; } } -dice_roll(number,faces) -int number, faces; +int dice_roll(int number, int faces) { int i,total=0; for(i=number;i>0;i--) total+= rand()%faces+1; return total; } -instructions() +void instructions(void) { printf("\n\n\n\nWelcome to Paranoia!\n\n"); printf("HOW TO PLAY:\n\n"); @@ -104,7 +105,7 @@ instructions() printf(" If not, you can try again later.\n"); } -character() +void character(void) { printf("===============================================================================\n"); printf("The Character : Philo-R-DMD %d\n", clone); @@ -130,9 +131,7 @@ character() printf("===============================================================================\n"); } -choose(a,aptr,b,bptr) -int a,b; -char *aptr, *bptr; +int choose(int a, char* aptr, int b, char* bptr) { printf("\nSelect \'a\' or \'b\' :\n"); printf(" a - %s.\n b - %s.\n", aptr, bptr); @@ -140,7 +139,7 @@ char *aptr, *bptr; else return b; } -page1() +int page1(void) { printf(" You wake up face down on the red and pink checked E-Z-Kleen linoleum floor.\n"); printf(" You recognise the pattern, it\'s the type preferred in the internal security\nbriefing cells. When you finally look around you, you see that you are alone\n"); @@ -148,7 +147,7 @@ page1() return 57; } -page2() +int page2(void) { printf("\"Greetings,\" says the kindly Internal Security self incrimination expert who\n"); printf("meets you at the door, \"How are we doing today?\" He offers you a doughnut\n"); @@ -166,7 +165,7 @@ page2() else return new_clone(32); } -page3() +int page3(void) { printf("You walk to the nearest Computer terminal and request more information about\n"); printf("Christmas. The Computer says, \"That is an A-1 ULTRAVIOLET ONLY IMMEDIATE\n"); @@ -174,7 +173,7 @@ page3() return choose(4,"You give your correct clearance",5,"You lie and claim Ultraviolet clearance"); } -page4() +int page4(void) { printf("\"That is classified information, Troubleshooter, thank you for your inquiry.\n"); printf(" Please report to an Internal Security self incrimination station as soon as\n"); @@ -182,7 +181,7 @@ page4() return 9; } -page5() +int page5(void) { printf("The computer says, \"Troubleshooter, you are not wearing the correct colour\n"); printf("uniform. You must put on an Ultraviolet uniform immediately. I have seen to\n"); @@ -193,7 +192,7 @@ page5() return choose(6, "You open the package and put on the uniform", 7, "You finally come to your senses and run for it"); } -page6() +int page6(void) { printf("The uniform definitely makes you look snappy and pert. It really looks\n"); printf("impressive, and even has the new lopsided lapel fashion that you admire so\n"); @@ -205,7 +204,7 @@ page6() return 8; } -page7() +int page7(void) { printf("The corridor lights dim and are replaced by red battle lamps as the Security\n"); printf("Breach alarms howl all around you. You run headlong down the corridor and\n"); @@ -232,7 +231,7 @@ page7() return 8; } -page8() +int page8(void) { printf("\"Now, about your question, citizen. Christmas was an old world marketing ploy\n"); printf("to induce lower clearance citizens to purchase vast quantities of goods, thus\n"); @@ -249,7 +248,7 @@ page8() return 10; } -page9() +int page9(void) { int choice; printf("As you walk toward the tubecar that will take you to GDH7-beta, you pass one\n"); @@ -262,7 +261,7 @@ page9() return choice; } -page10() +int page10(void) { int choice; printf("You stroll briskly down the corridor, up a ladder, across an unrailed catwalk,\n"); @@ -290,7 +289,7 @@ page10() } } -page11() +int page11(void) { printf("The printing on the folder says \"Experimental Self Briefing.\"\n"); printf("You open it and begin to read the following:\n"); @@ -321,7 +320,7 @@ page11() return choose(3,"You wish to ask The Computer for more information about Christmas",10,"You have decided to go directly to Goods Distribution Hall 7-beta"); } -page12() +int page12(void) { printf("You walk up to the door and push the button labelled \"push to exit.\"\n"); printf("Within seconds a surly looking guard shoves his face into the small plexiglass\n"); @@ -333,7 +332,7 @@ page12() return choose(11,"You sit down at the table and read the Orange packet",57,"You stare around the room some more"); } -page13() +int page13(void) { printf("You step into the shiny plasteel tubecar, wondering why the shape has always\n"); printf("reminded you of bullets. The car shoots forward the instant your feet touch\n"); @@ -346,7 +345,7 @@ page13() return 14; } -page14() +int page14(void) { printf("You manage to pull yourself out of the tubecar and look around. Before you is\n"); printf("one of the most confusing things you have ever seen, a hallway that is\n"); @@ -360,7 +359,7 @@ page14() return 22; } -page15() +int page15(void) { printf("You are set upon by a runty robot with a queer looking face and two pointy\n"); printf("rubber ears poking from beneath a tattered cap. \"Hey mister,\" it says,\n"); @@ -384,7 +383,7 @@ page15() } } -page16() +int page16(void) { printf("The doll is a good buy for fifty credits; it will make a fine Christmas present\n"); printf("for one of your friends. After the sale the robot rolls away. You can use\n"); @@ -395,7 +394,7 @@ page16() return 22; } -page17() +int page17(void) { int i, robot_hp=15; printf("You whip out your laser and shoot the robot, but not before it squeezes the\n"); @@ -432,7 +431,7 @@ page17() return 22; } -page18() +int page18(void) { printf("You walk to the centre of the hall, ogling like an infrared fresh from the\n"); printf("clone vats. Towering before you is the most unearthly thing you have ever\n"); @@ -448,7 +447,7 @@ page18() else return 20; } -page19() +int page19(void) { printf("Quickly you regain your balance, whirl and fire your laser into the Ultraviolet\n"); printf("citizen behind you. For a moment your heart leaps to your throat, then you\n"); @@ -461,7 +460,7 @@ page19() return choose(34,"You search the body, keeping an eye open for Internal Security",22,"You run away like the cowardly dog you are"); } -page20() +int page20(void) { printf("Oh no! you can\'t keep your balance. You\'re falling, falling head first into\n"); printf("the Christmas beast\'s gaping maw. It\'s a valiant struggle; you think you are\n"); @@ -473,7 +472,7 @@ page20() return 22; } -page21() +int page21(void) { printf("You have been wasting the leading citizens of Alpha Complex at a prodigious\n"); printf("rate. This has not gone unnoticed by the Internal Security squad at GDH7-beta.\n"); @@ -482,7 +481,7 @@ page21() return new_clone(45); } -page22() +int page22(void) { printf("You are searching Goods Distribution Hall 7-beta.\n"); switch(dice_roll(1,4)) @@ -494,7 +493,7 @@ page22() } } -page23() +int page23(void) { printf("You go to the nearest computer terminal and declare yourself a mutant.\n"); printf("\"A mutant, he\'s a mutant,\" yells a previously unnoticed infrared who had\n"); @@ -503,7 +502,7 @@ page23() return choose(28,"You tell them that it was really only a bad joke",24,"You want to fight it out, one against twelve"); } -page24() +int page24(void) { printf("Golly, I never expected someone to pick this. I haven\'t even designed\n"); printf("the 12 citizens who are going to make a sponge out of you. Tell you what,\n"); @@ -511,7 +510,7 @@ page24() return choose(28,"You change your mind and say it was only a bad joke",25,"You REALLY want to shoot it out"); } -page25() +int page25(void) { printf("Boy, you really can\'t take a hint!\n"); printf("They\'re closing in. Their trigger fingers are twitching, they\'re about to\n"); @@ -519,7 +518,7 @@ page25() return choose(28,"You tell them it was all just a bad joke",26,"You are going to shoot"); } -page26() +int page26(void) { printf("You can read the cold, sober hatred in their eyes (They really didn\'t think\n"); printf("it was funny), as they tighten the circle around you. One of them shoves a\n"); @@ -529,19 +528,19 @@ page26() return new_clone(32); } -page27() +int page27(void) { /* doesn't exist. Can't happen with computer version. designed to catch dice cheats */ } -page28() +int page28(void) { printf("They don\'t think it\'s funny.\n"); return 26; } -page29() +int page29(void) { printf("\"Psst, hey citizen, come here. Pssfft,\" you hear. When you peer around\n"); printf("you can see someone\'s dim outline in the shadows. \"I got some information\n"); @@ -559,7 +558,7 @@ page29() } } -page30() +int page30(void) { printf("You step into the shadows and offer the man a thirty credit bill. \"Just drop\n"); printf("it on the floor,\" he says. \"So you\'re looking for the Master Retailer, pssfft?\n"); @@ -586,7 +585,7 @@ page30() } } -page31() +int page31(void) { printf("Like any good troubleshooter you make the least expensive decision and threaten\n"); printf("him for information. With lightning like reflexes you whip out your laser and\n"); @@ -599,7 +598,7 @@ page31() return choose(30,"You pay the 30 credits",22,"You pssfft go away stupid"); } -page32() +int page32(void) { printf("Finally it\'s your big chance to prove that you\'re as good a troubleshooter\n"); printf("as your previous clone. You walk briskly to mission briefing and pick up your\n"); @@ -609,7 +608,7 @@ page32() return 22; } -page33() +int page33(void) { blast_door=1; printf("You release the megabolts on the blast door, then strain against it with your\n"); @@ -622,7 +621,7 @@ page33() else return 36; } -page34() +int page34(void) { printf("You have found a sealed envelope on the body. You open it and read:\n"); printf("\"WARNING: Ultraviolet Clearance ONLY. DO NOT READ.\n"); @@ -650,7 +649,7 @@ page34() return choose(46,"You rush off to the nearest computer terminal to expose the commies",22,"You wander off to look for more evidence"); } -page35() +int page35(void) { printf("\"Oh master,\" you hear through the gun barrel, \"where have you been? It is\n"); printf("time for the great Christmas gifting ceremony. You had better hurry and get\n"); @@ -669,7 +668,7 @@ page35() return new_clone(32); } -page36() +int page36(void) { printf("\"Congratulations, troubleshooter, you have successfully found the lair of the\n"); printf("Master Retailer and completed the Troubleshooter Training Course test mission,\"\n"); @@ -692,7 +691,7 @@ page36() } } -page37() +int page37(void) { printf("\"Come with me please, Troubleshooter,\" says the Green clearance technician\n"); printf("after he has dislodged your head from the cannon. \"You have been participating\n"); @@ -708,7 +707,7 @@ page37() return 38; } -page38() +int page38(void) { printf("\"I am Plato-B-PHI%d, head of mutant propaganda here at the training course.\n",plato_clone); printf("If you have any questions about mutants please come to me. Today I will be\n"); @@ -725,7 +724,7 @@ page38() return choose(39,"You volunteer for the test",40,"You duck behind a chair and hope the instructor doesn\'t notice you"); } -page39() +int page39(void) { printf("You bravely volunteer to test the mutant detection gun. You stand up and walk\n"); printf("down the steps to the podium, passing a very relieved Troubleshooter along the\n"); @@ -743,7 +742,7 @@ page39() return 41; } -page40() +int page40(void) { printf("You breathe a sigh of relief as Plato-B-PHI picks on the other Troubleshooter.\n"); printf("\"You down here in the front,\" says the instructor pointing at the other\n"); @@ -775,7 +774,7 @@ page40() } } -page41() +int page41(void) { printf("You stumble down the hallway of the Troubleshooter Training Course looking for\n"); printf("your next class. Up ahead you see one of the instructors waving to you. When\n"); @@ -789,7 +788,7 @@ page41() return choose(42,"You respond with the proper Illuminati code phrase, \"Ewige Blumenkraft\"",43,"You ignore this secret society contact"); } -page42() +int page42(void) { printf("\"Aha, so you are a member of the elitist Illuminati secret society,\" he says\n"); printf("loudly, \"that is most interesting.\" He turns to the large class already\n"); @@ -799,7 +798,7 @@ page42() return choose(51,"You run for it",52,"You wait for the guard"); } -page43() +int page43(void) { printf("You sit through a long lecture on how to recognise and infiltrate secret\n"); printf("societies, with an emphasis on mimicking secret handshakes. The basic theory,\n"); @@ -815,7 +814,7 @@ page43() return choose(44,"You go looking for a computer terminal",55,"You go to the graduation ceremony immediately"); } -page44() +int page44(void) { printf("You walk down to a semi-secluded part of the training course complex and\n"); printf("activate a computer terminal. \"AT YOUR SERVICE\" reads the computer screen.\n"); @@ -833,7 +832,7 @@ page44() } } -page45() +int page45(void) { printf("\"Hrank Hrank,\" snorts the alarm in your living quarters. Something is up.\n"); printf("You look at the monitor above the bathroom mirror and see the message you have\n"); @@ -847,7 +846,7 @@ page45() return 10; } -page46() +int page46(void) { printf("\"Why do you ask about the communists, Troubleshooter? It is not in the\n"); printf("interest of your continued survival to be asking about such topics,\" says\n"); @@ -855,7 +854,7 @@ page46() return choose(53,"You insist on talking about the communists",54,"You change the subject"); } -page47() +int page47(void) { printf("The Computer orders the entire Vulture squadron to terminate the Troubleshooter\n"); printf("Training Course. Unfortunately you too are terminated for possessing\n"); @@ -867,7 +866,7 @@ page47() return 0; } -page48() +int page48(void) { printf("The tubecar shoots forward as you enter, slamming you back into a pile of\n"); printf("garbage. The front end rotates upward and you, the garbage and the garbage\n"); @@ -877,14 +876,14 @@ page48() return new_clone(45); } -page49() +int page49(void) { printf("The instructor drags your inert body into a specimen detainment cage.\n"); printf("\"He\'ll make a good subject for tomorrow\'s mutant dissection class,\" you hear.\n"); return new_clone(32); } -page50() +int page50(void) { printf("You put down the other Troubleshooter, and then wisely decide to drill a few\n"); printf("holes in the instructor as well; the only good witness is a dead witness.\n"); @@ -893,27 +892,27 @@ page50() return 41; } -page51() +int page51(void) { printf("You run for it, but you don\'t run far. Three hundred strange and exotic\n"); printf("weapons turn you into a freeze dried cloud of soot.\n"); return new_clone(32); } -page52() +int page52(void) { printf("You wisely wait until the instructor returns with a Blue Internal Security\n"); printf("guard. The guard leads you to an Internal Security self incrimination station.\n"); return 2; } -page53() +int page53(void) { printf("You tell The Computer about:\n"); return choose(47,"The commies who have infiltrated the Troubleshooter Training Course\n and the impending People\'s Revolution",54,"Something less dangerous"); } -page54() +int page54(void) { printf("\"Do not try to change the subject, Troubleshooter,\" says The Computer.\n"); printf("\"It is a serious crime to ask about the communists. You will be terminated\n"); @@ -927,7 +926,7 @@ page54() else return new_clone(32); } -page55() +int page55(void) { printf("You and 300 other excited graduates are marched from the lecture hall and into\n"); printf("a large auditorium for the graduation exercise. The auditorium is\n"); @@ -955,7 +954,7 @@ page55() return 0; } -page56() +int page56(void) { printf("That familiar strange feeling of deja\'vu envelops you again. It is hard to\n"); printf("say, but whatever is on the other side of the door does not seem to be intended\n"); @@ -963,15 +962,14 @@ page56() return choose(33,"You open the door and step through",22,"You go looking for more information"); } -page57() +int page57(void) { printf("In the centre of the room is a table and a single chair. There is an Orange\n"); printf("folder on the table top, but you can\'t make out the lettering on it.\n"); return choose(11,"You sit down and read the folder",12,"You leave the room"); } -next_page(this_page) -int this_page; +int next_page(int this_page) { printf("\n"); switch (this_page) @@ -1038,10 +1036,11 @@ int this_page; } } -main() +int main(int argc, const char* argv[]) { /* srand(time(0)); */ instructions(); more(); character(); more(); while((page=next_page(page))!=0) more(); + return 0; } diff --git a/first/ackbuilder.lua b/first/ackbuilder.lua index f240f232c..81e86b528 100644 --- a/first/ackbuilder.lua +++ b/first/ackbuilder.lua @@ -451,7 +451,7 @@ loadtarget = function(targetname) target = targets[targetname] if not target then error(string.format("build file '%s' contains no target '%s'", - filename, targetpart)) + filepart, targetpart)) end end @@ -729,9 +729,10 @@ definerule("simplerule", definerule("installable", { map = { type="targets", default={} }, + deps = { type="targets", default={} }, }, function (e) - local deps = {} + local deps = filenamesof(e.deps) local commands = {} local srcs = {} local outs = {} diff --git a/first/build.lua b/first/build.lua index 3240f9f1a..85df519a8 100644 --- a/first/build.lua +++ b/first/build.lua @@ -226,6 +226,7 @@ definerule("cprogram", }, function (e) local libs = matching(filenamesof(e.deps), "%.a$") + local srcs = {} if (#e.srcs > 0) then for _, f in pairs( matching( @@ -240,7 +241,7 @@ definerule("cprogram", "%.a$" ) ) do - libs[#libs+1] = f + srcs[#srcs+1] = f end end @@ -248,7 +249,7 @@ definerule("cprogram", name = e.name, cwd = e.cwd, deps = e.deps, - ins = libs, + ins = { srcs, libs }, outleaves = { e.name }, commands = e.commands, } diff --git a/first/lua-5.1/lposix.c b/first/lua-5.1/lposix.c index ebe6b9c03..4bdf9328f 100644 --- a/first/lua-5.1/lposix.c +++ b/first/lua-5.1/lposix.c @@ -702,6 +702,7 @@ static int Pgetpid(lua_State *L) /** getpid([options]) */ } +#if 0 static int Phostid(lua_State *L) /** hostid() */ { char b[32]; @@ -709,6 +710,7 @@ static int Phostid(lua_State *L) /** hostid() */ lua_pushstring(L, b); return 1; } +#endif static int Pttyname(lua_State *L) /** ttyname([fd]) */ @@ -1060,7 +1062,7 @@ static const luaL_reg R[] = {"getpasswd", Pgetpasswd}, {"getpid", Pgetpid}, {"glob", Pglob}, - {"hostid", Phostid}, + //{"hostid", Phostid}, {"kill", Pkill}, {"link", Plink}, {"mkdir", Pmkdir}, diff --git a/lang/basic/lib/error.c b/lang/basic/lib/error.c index b2d893adc..becc69d7a 100644 --- a/lang/basic/lib/error.c +++ b/lang/basic/lib/error.c @@ -1,6 +1,9 @@ #include #include +int _errsym; +int _erlsym; + /* error takes an error value in the range of 0-255 */ /* and generates a trap */ @@ -52,9 +55,6 @@ char *errortable[255]={ error(index) int index; { - extern int _errsym; - extern int _erlsym; - _setline(); if( index<0 || index >40 ) printf("LINE %d:ERROR %d: Unprintable error\n",_erlsym,index); diff --git a/lang/basic/src/eval.c b/lang/basic/src/eval.c index ed5b6f499..f1f762b05 100644 --- a/lang/basic/src/eval.c +++ b/lang/basic/src/eval.c @@ -31,6 +31,7 @@ int ltype,rtype; +void conversion(oldtype,newtype) int oldtype,newtype; { @@ -71,6 +72,7 @@ int oldtype,newtype; +void extraconvert(oldtype,newtype,topstack) int oldtype,newtype,topstack; { @@ -509,6 +511,7 @@ endarrayload() +void loadarray(type) int type; { diff --git a/lang/basic/src/gencode.c b/lang/basic/src/gencode.c index 8c7a50e95..8fb611dc0 100644 --- a/lang/basic/src/gencode.c +++ b/lang/basic/src/gencode.c @@ -617,11 +617,7 @@ prologcode() C_df_dnam("_iomode"); C_rom_scon("O",(arith)2); C_exa_dnam("_errsym"); - C_df_dnam("_errsym"); - C_bss_cst((arith)BEMINTSIZE,(arith)0,1); C_exa_dnam("_erlsym"); - C_df_dnam("_erlsym"); - C_bss_cst((arith)BEMINTSIZE,(arith)0,1); } diff --git a/lang/basic/src/symbols.c b/lang/basic/src/symbols.c index 30c3b5e8b..96d148ae3 100644 --- a/lang/basic/src/symbols.c +++ b/lang/basic/src/symbols.c @@ -68,6 +68,7 @@ char *str; +void dcltype(s) Symbol *s; { diff --git a/lang/basic/src/util.c b/lang/basic/src/util.c index 8255b39a1..ff98cf82b 100644 --- a/lang/basic/src/util.c +++ b/lang/basic/src/util.c @@ -16,6 +16,7 @@ int errorcnt; +void warning(str) char *str; { diff --git a/lang/cem/cemcom.ansi/LLlex.c b/lang/cem/cemcom.ansi/LLlex.c index 07a79ad8e..d0632536d 100644 --- a/lang/cem/cemcom.ansi/LLlex.c +++ b/lang/cem/cemcom.ansi/LLlex.c @@ -52,6 +52,8 @@ extern int lint_skip_comment; static struct token LexStack[MAX_LL_DEPTH]; static LexSP = 0; +void skipcomment(); + /* In PushLex() the actions are taken in order to initialise or re-initialise the lexical scanner. E.g. at the invocation of a sub-parser that uses LLlex(), the @@ -442,6 +444,7 @@ garbage: } #ifndef NOPP +void skipcomment() { /* The last character read has been the '*' of '/_*'. The diff --git a/lang/cem/cemcom.ansi/arith.c b/lang/cem/cemcom.ansi/arith.c index d5f3af3e7..317107a43 100644 --- a/lang/cem/cemcom.ansi/arith.c +++ b/lang/cem/cemcom.ansi/arith.c @@ -30,6 +30,7 @@ extern char options[]; extern arith flt_flt2arith(); extern label code_string(); +void arithbalance(e1p, oper, e2p) /* 3.1.2.5 */ register struct expr **e1p, **e2p; int oper; @@ -523,6 +524,7 @@ opnd2logical(expp, oper) } } +void opnd2test(expp, oper) register struct expr **expp; { @@ -548,6 +550,7 @@ opnd2test(expp, oper) ch3bin(expp, NOTEQUAL, intexpr((arith)0, INT)); } +void any2opnd(expp, oper) register struct expr **expp; { diff --git a/lang/cem/cemcom.ansi/ch3.c b/lang/cem/cemcom.ansi/ch3.c index bebe77efa..eef806776 100644 --- a/lang/cem/cemcom.ansi/ch3.c +++ b/lang/cem/cemcom.ansi/ch3.c @@ -23,11 +23,14 @@ extern char options[]; extern char *symbol2str(); extern struct type *qualifier_type(); +void ch3cast(); + /* Most expression-handling routines have a pointer to a (struct type *) as first parameter. The object under the pointer gets updated in the process. */ +void ch3sel(expp, oper, idf) struct expr **expp; struct idf *idf; @@ -169,6 +172,7 @@ ch3incr(expp, oper) ch3asgn(expp, oper, intexpr((arith)1, INT)); } +void ch3cast(expp, oper, tp) register struct expr **expp; register struct type *tp; diff --git a/lang/cem/cemcom.ansi/ch3bin.c b/lang/cem/cemcom.ansi/ch3bin.c index 8145b933d..ba75c112c 100644 --- a/lang/cem/cemcom.ansi/ch3bin.c +++ b/lang/cem/cemcom.ansi/ch3bin.c @@ -19,6 +19,8 @@ extern char options[]; extern char *symbol2str(); +void pntminuspnt(); + /* This chapter asks for the repeated application of code to handle an operation that may be executed at compile time or at run time, depending on the constancy of the operands. @@ -32,6 +34,7 @@ extern char *symbol2str(); #define commutative_binop(expp, oper, expr) mk_binop(expp, oper, expr, 1) #define non_commutative_relop(expp, oper, expr) mk_binop(expp, oper, expr, 1) +void ch3bin(expp, oper, expr) register struct expr **expp; struct expr *expr; @@ -292,6 +295,7 @@ ch3bin(expp, oper, expr) } } +void pntminuspnt(expp, oper, expr) register struct expr **expp, *expr; { diff --git a/lang/cem/cemcom.ansi/code.c b/lang/cem/cemcom.ansi/code.c index 1beeb12c4..abfd2b2b2 100644 --- a/lang/cem/cemcom.ansi/code.c +++ b/lang/cem/cemcom.ansi/code.c @@ -64,6 +64,8 @@ extern char options[]; extern char *symbol2str(); extern char *source; +void loc_init(); + #ifndef LINT init_code(dst_file) char *dst_file; @@ -415,6 +417,7 @@ do_return_expr(expr) return_expr_occurred = 1; } +void code_declaration(idf, expr, lvl, sc) register struct idf *idf; /* idf to be declared */ struct expr *expr; /* initialisation; NULL if absent */ @@ -527,6 +530,7 @@ code_declaration(idf, expr, lvl, sc) } } +void loc_init(expr, id) struct expr *expr; struct idf *id; @@ -721,6 +725,7 @@ code_break() it generates a branch instruction to the continue label of the innermost statement in which continue has a meaning. */ +void code_continue() { register struct stmt_block *stmt_block = stmt_stack; diff --git a/lang/cem/cemcom.ansi/domacro.c b/lang/cem/cemcom.ansi/domacro.c index 4173a11b2..d0fe7a96d 100644 --- a/lang/cem/cemcom.ansi/domacro.c +++ b/lang/cem/cemcom.ansi/domacro.c @@ -34,6 +34,9 @@ char ifstack[IFDEPTH]; /* if-stack: the content of an entry is */ int nestlevel = -1; +void macro_def(); +void do_define(); + struct idf * GetIdentifier(skiponerr) int skiponerr; /* skip the rest of the line on error */ @@ -145,6 +148,7 @@ domacro() int lint_skip_comment; #endif +void skip_block(to_endif) int to_endif; { @@ -347,6 +351,7 @@ do_include() } } +void do_define() { /* do_define() interprets a #define control line. @@ -574,6 +579,7 @@ getparams(buf, parbuf) /*NOTREACHED*/ } +void macro_def(id, text, nformals, length, flags) register struct idf *id; char *text; diff --git a/lang/cem/cemcom.ansi/error.c b/lang/cem/cemcom.ansi/error.c index 10b237db4..6f2283b74 100644 --- a/lang/cem/cemcom.ansi/error.c +++ b/lang/cem/cemcom.ansi/error.c @@ -57,7 +57,7 @@ extern char loptions[]; expression, whereas other errors use the information in the token. */ -static _error(); +static void _error(); #if __STDC__ /*VARARGS*/ @@ -521,7 +521,7 @@ fatal(va_alist) /* fmt, args */ } #endif -static +static void _error(class, fn, ln, fmt, ap) int class; char *fn; diff --git a/lang/cem/cemcom.ansi/eval.c b/lang/cem/cemcom.ansi/eval.c index 16f19c0ad..f678682c2 100644 --- a/lang/cem/cemcom.ansi/eval.c +++ b/lang/cem/cemcom.ansi/eval.c @@ -37,6 +37,9 @@ arith NewLocal(); /* util.c */ #define LocalPtrVar() NewLocal(pointer_size, pointer_align, reg_pointer, REGISTER) extern int err_occurred; /* error.c */ +void store_val(); +void load_val(); + /* EVAL() is the main expression-tree evaluator, which turns any legal expression tree into EM code. parameters.h: @@ -63,6 +66,7 @@ extern int err_occurred; /* error.c */ labels, in case they are specified (i.e. are non-zero) */ +void EVAL(expr, val, code, true_label, false_label) register struct expr *expr; int val, code; @@ -836,6 +840,7 @@ ptr_add(size) - into a local static variable - absolute addressing */ +void store_val(vl, tp) register struct value *vl; register struct type *tp; @@ -907,6 +912,7 @@ store_val(vl, tp) - static variable - local variable */ +void load_val(expr, rlval) register struct expr *expr; /* expression containing the value */ int rlval; /* generate either LVAL or RVAL */ diff --git a/lang/cem/cemcom.ansi/expr.c b/lang/cem/cemcom.ansi/expr.c index 6d8c1e23d..3a7e3c494 100644 --- a/lang/cem/cemcom.ansi/expr.c +++ b/lang/cem/cemcom.ansi/expr.c @@ -369,6 +369,7 @@ new_oper(tp, e1, oper, e2) return expr; } +void chk_cst_expr(expp) struct expr **expp; { diff --git a/lang/cem/cemcom.ansi/idf.c b/lang/cem/cemcom.ansi/idf.c index eb43e34bb..4edc88456 100644 --- a/lang/cem/cemcom.ansi/idf.c +++ b/lang/cem/cemcom.ansi/idf.c @@ -37,6 +37,8 @@ extern char *symbol2str(); #include +void global_redecl(); + struct idf * gen_idf() { @@ -248,6 +250,7 @@ declare_idf(ds, dc, lvl) } } +int actual_declaration(sc, tp) int sc; struct type *tp; @@ -269,6 +272,7 @@ actual_declaration(sc, tp) return 1; } +void global_redecl(idf, new_sc, tp) register struct idf *idf; struct type *tp; @@ -393,6 +397,7 @@ declare_params(dc) } } +void idf_initialized(idf) register struct idf *idf; { @@ -429,6 +434,7 @@ declare_enum(tp, idf, l) idf->id_def->df_address = l; } +void check_formals(idf, dc) struct idf *idf; struct declarator *dc; diff --git a/lang/cem/cemcom.ansi/init.c b/lang/cem/cemcom.ansi/init.c index bb1fd5559..3b3403aa4 100644 --- a/lang/cem/cemcom.ansi/init.c +++ b/lang/cem/cemcom.ansi/init.c @@ -7,6 +7,7 @@ #include #include +#include #include "parameters.h" #ifndef NOPP @@ -44,7 +45,7 @@ init_pp() "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; - long clock, sys_time(); + time_t clock; static char dbuf[30]; static char tbuf[30]; struct tm *tp; @@ -70,7 +71,7 @@ init_pp() /* Initialize __LINE__, __FILE__, __DATE__, __TIME__, and __STDC__ macro definitions. */ - clock = sys_time(); + clock = time(NULL); tp = localtime(&clock); /* __DATE__ */ diff --git a/lang/cem/cemcom.ansi/ival.g b/lang/cem/cemcom.ansi/ival.g index b085ebc73..757bb721b 100644 --- a/lang/cem/cemcom.ansi/ival.g +++ b/lang/cem/cemcom.ansi/ival.g @@ -46,6 +46,11 @@ static int pack_level; struct type **gen_tphead(), **gen_tpmiddle(); struct sdef *gen_align_to_next(); struct e_stack *p_stack; + +void pad(); +void gen_simple_exp(); +void gen_tpcheck(); + } /* initial_value recursively guides the initialisation expression. @@ -122,6 +127,7 @@ initial_value_list(register struct type **tpp; struct expr **expp;) ; { +void gen_tpcheck(tpp) struct type **tpp; { @@ -147,6 +153,7 @@ gen_tpcheck(tpp) } } +void gen_simple_exp(tpp, expp) struct type **tpp; struct expr **expp; @@ -465,6 +472,7 @@ check_and_pad(expp, tpp) /* pad() fills an element of type tp with zeroes. If the element is an aggregate, pad() is called recursively. */ +void pad(tpx) struct type *tpx; { diff --git a/lang/cem/cemcom.ansi/main.c b/lang/cem/cemcom.ansi/main.c index 556e23495..1bb72ae85 100644 --- a/lang/cem/cemcom.ansi/main.c +++ b/lang/cem/cemcom.ansi/main.c @@ -46,6 +46,8 @@ struct sp_id special_ids[] = { {0, 0} }; +void dependency(); + #ifndef NOCROSS arith short_size = SZ_SHORT, @@ -181,6 +183,7 @@ char *s; } } +void dependency(s, source) char *s, *source; { diff --git a/lang/cem/cemcom.ansi/proto.c b/lang/cem/cemcom.ansi/proto.c index 1f7f6bf6d..b237f3433 100644 --- a/lang/cem/cemcom.ansi/proto.c +++ b/lang/cem/cemcom.ansi/proto.c @@ -26,6 +26,7 @@ extern char options[]; +void check_for_void(pl) register struct proto *pl; { @@ -261,6 +262,7 @@ declare_protos(dc) } +void update_proto(tp, otp) register struct type *tp, *otp; { @@ -312,6 +314,7 @@ update_proto(tp, otp) /* struct/union and enum tags can be declared inside prototypes * remove them from the symbol-table */ +void remove_proto_tag(tp) struct type *tp; { @@ -380,6 +383,7 @@ remove_proto_idfs(pl) } } +void call_proto(expp) register struct expr **expp; { diff --git a/lang/cem/cemcom.ansi/replace.c b/lang/cem/cemcom.ansi/replace.c index cde3aaf43..50978be3c 100644 --- a/lang/cem/cemcom.ansi/replace.c +++ b/lang/cem/cemcom.ansi/replace.c @@ -26,6 +26,10 @@ extern int InputLevel; struct repl *ReplaceList; /* list of currently active macros */ extern char *strcat(), *strcpy(); +void macro2buffer(); +void getactuals(); +void expand_defined(); + int replace(idf) register struct idf *idf; @@ -172,6 +176,7 @@ expand_macro(repl, idf) return 1; } +void expand_defined(repl) register struct repl *repl; { @@ -211,6 +216,7 @@ newarg(args) args->a_rawptr = args->a_rawbuf = Malloc(args->a_rawsize = ARGBUF); } +void getactuals(repl, idf) struct repl *repl; register struct idf *idf; @@ -529,6 +535,7 @@ macro_func(idef) } } +void macro2buffer(repl, idf, args) register struct repl *repl; register struct idf *idf; diff --git a/lang/cem/cemcom.ansi/stab.c b/lang/cem/cemcom.ansi/stab.c index 8c00838e3..f80b360b4 100644 --- a/lang/cem/cemcom.ansi/stab.c +++ b/lang/cem/cemcom.ansi/stab.c @@ -72,7 +72,7 @@ adds_db_str(s) while (*s) addc_db_str(*s++); } -static +static void stb_type(tp) register struct type *tp; { diff --git a/lang/cem/cemcom.ansi/stack.c b/lang/cem/cemcom.ansi/stack.c index 49dfbfab4..c8616b86e 100644 --- a/lang/cem/cemcom.ansi/stack.c +++ b/lang/cem/cemcom.ansi/stack.c @@ -57,6 +57,7 @@ stack_level() { #endif /* LINT */ } +void stack_idf(idf, stl) struct idf *idf; register struct stack_level *stl; diff --git a/lang/cem/cemcom.ansi/switch.c b/lang/cem/cemcom.ansi/switch.c index 856e1b115..3cce2c622 100644 --- a/lang/cem/cemcom.ansi/switch.c +++ b/lang/cem/cemcom.ansi/switch.c @@ -159,6 +159,7 @@ code_endswitch() unstack_stmt(); } +void code_case(expr) struct expr *expr; { @@ -227,6 +228,7 @@ code_case(expr) } } +void code_default() { register struct switch_hdr *sh = switch_stack; diff --git a/lang/cem/cemcom.ansi/util.c b/lang/cem/cemcom.ansi/util.c index 7326f04ec..273fa8d78 100644 --- a/lang/cem/cemcom.ansi/util.c +++ b/lang/cem/cemcom.ansi/util.c @@ -163,6 +163,7 @@ LocalFinish() #endif } +void RegisterAccount(offset, size, regtype, sc) arith offset, size; { diff --git a/lang/cem/cpp.ansi/LLlex.c b/lang/cem/cpp.ansi/LLlex.c index 3cd162898..dbf8d9ea1 100644 --- a/lang/cem/cpp.ansi/LLlex.c +++ b/lang/cem/cpp.ansi/LLlex.c @@ -35,6 +35,8 @@ extern arith char_constant(); #define FLG_ESEEN 0x01 /* possibly a floating point number */ #define FLG_DOTSEEN 0x02 /* certainly a floating point number */ +void skipcomment(); + int LLlex() { @@ -325,6 +327,7 @@ garbage: /*NOTREACHED*/ } +void skipcomment() { /* The last character read has been the '*' of '/_*'. The diff --git a/lang/cem/cpp.ansi/domacro.c b/lang/cem/cpp.ansi/domacro.c index a5cc9407d..306ed32cc 100644 --- a/lang/cem/cpp.ansi/domacro.c +++ b/lang/cem/cpp.ansi/domacro.c @@ -32,6 +32,9 @@ int svnestlevel[30] = {-1}; int nestcount; extern int do_preprocess; +void macro_def(); +void do_define(); + char * GetIdentifier(skiponerr) int skiponerr; /* skip the rest of the line on error */ @@ -148,6 +151,7 @@ domacro() } } +void skip_block(to_endif) int to_endif; { @@ -327,6 +331,7 @@ do_include() } } +void do_define() { /* do_define() interprets a #define control line. @@ -566,6 +571,7 @@ getparams(buf, parbuf) /*NOTREACHED*/ } +void macro_def(id, text, nformals, length, flags) register struct idf *id; char *text; diff --git a/lang/cem/cpp.ansi/init.c b/lang/cem/cpp.ansi/init.c index a9cba4dba..3953609b5 100644 --- a/lang/cem/cpp.ansi/init.c +++ b/lang/cem/cpp.ansi/init.c @@ -7,6 +7,7 @@ #include #include +#include #include "system.h" #include "alloc.h" #include "time.h" @@ -42,7 +43,7 @@ init_pp() "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; - long clock, sys_time(); + time_t clock; static char dbuf[30]; static char tbuf[30]; struct tm *tp; @@ -68,7 +69,7 @@ init_pp() /* Initialize __LINE__, __FILE__, __DATE__, __TIME__, and __STDC__ macro definitions. */ - clock = sys_time(); + clock = time(NULL); tp = localtime(&clock); /* __DATE__ */ diff --git a/lang/cem/cpp.ansi/main.c b/lang/cem/cpp.ansi/main.c index db444ae80..225562be0 100644 --- a/lang/cem/cpp.ansi/main.c +++ b/lang/cem/cpp.ansi/main.c @@ -32,6 +32,8 @@ char *prog_name; extern char **inctable; extern int inc_max, inc_total; +void dependency(); + main(argc, argv) char *argv[]; { @@ -140,6 +142,7 @@ add_dependency(s) } } +void dependency(s, source) char *s, *source; { diff --git a/lang/cem/cpp.ansi/preprocess.c b/lang/cem/cpp.ansi/preprocess.c index 7c3840d80..3d26b18e0 100644 --- a/lang/cem/cpp.ansi/preprocess.c +++ b/lang/cem/cpp.ansi/preprocess.c @@ -102,6 +102,7 @@ do_pragma() char Xbuf[256]; +void preprocess(fn) char *fn; { diff --git a/lang/cem/cpp.ansi/replace.c b/lang/cem/cpp.ansi/replace.c index 255902f68..cd7d60696 100644 --- a/lang/cem/cpp.ansi/replace.c +++ b/lang/cem/cpp.ansi/replace.c @@ -26,6 +26,10 @@ extern char *strcat(); extern int InputLevel; struct repl *ReplaceList; /* list of currently active macros */ +void expand_defined(); +void getactuals(); +void macro2buffer(); + int replace(idf) register struct idf *idf; @@ -165,6 +169,7 @@ expand_macro(repl, idf) return 1; } +void expand_defined(repl) register struct repl *repl; { @@ -208,6 +213,7 @@ newarg(args) args->a_rawptr = args->a_rawbuf = Malloc((unsigned)(args->a_rawsize = ARGBUF)); } +void getactuals(repl, idf) struct repl *repl; register struct idf *idf; @@ -522,6 +528,7 @@ macro_func(idef) } } +void macro2buffer(repl, idf, args) register struct repl *repl; register struct idf *idf; diff --git a/lang/cem/libcc.ansi/malloc/calloc.c b/lang/cem/libcc.ansi/malloc/calloc.c new file mode 100644 index 000000000..2e9d3be16 --- /dev/null +++ b/lang/cem/libcc.ansi/malloc/calloc.c @@ -0,0 +1,23 @@ +#include +#include +#include + +void* calloc(size_t nmemb, size_t size) +{ + size_t bytes = nmemb * size; + void* ptr; + + /* Test for overflow. + * See http://stackoverflow.com/questions/1815367/multiplication-of-large-numbers-how-to-catch-overflow + */ + + if ((nmemb == 0) || (size == 0) || (nmemb > (SIZE_MAX / size))) + return NULL; + + ptr = malloc(bytes); + if (!ptr) + return NULL; + + memset(ptr, 0, bytes); + return ptr; +} diff --git a/lang/m2/comp/LLlex.c b/lang/m2/comp/LLlex.c index 1eacae76f..083947161 100644 --- a/lang/m2/comp/LLlex.c +++ b/lang/m2/comp/LLlex.c @@ -180,6 +180,7 @@ getch() return ch; } +void CheckForLineDirective() { register int ch = getch(); diff --git a/lang/m2/comp/casestat.C b/lang/m2/comp/casestat.C index d227e3117..a4c2285d2 100644 --- a/lang/m2/comp/casestat.C +++ b/lang/m2/comp/casestat.C @@ -54,6 +54,9 @@ struct case_entry { arith ce_low, ce_up; /* lower and upper bound of range */ }; +void AddCases(); +void AddOneCase(); + /* STATICALLOCDEF "case_entry" 20 */ /* The constant DENSITY determines when CSA and when CSB instructions @@ -237,6 +240,7 @@ FreeSh(sh) free_switch_hdr(sh); } +void AddCases(sh, node, lbl) struct switch_hdr *sh; register t_node *node; @@ -264,6 +268,7 @@ AddCases(sh, node, lbl) AddOneCase(sh, node, node, lbl); } +void AddOneCase(sh, lnode, rnode, lbl) register struct switch_hdr *sh; t_node *lnode, *rnode; diff --git a/lang/m2/comp/chk_expr.c b/lang/m2/comp/chk_expr.c index 7dbe5abc6..e87725688 100644 --- a/lang/m2/comp/chk_expr.c +++ b/lang/m2/comp/chk_expr.c @@ -53,6 +53,7 @@ df_error(nd, mess, edf) else node_error(nd, mess); } +void MkCoercion(pnd, tp) t_node **pnd; register t_type *tp; diff --git a/lang/m2/comp/code.c b/lang/m2/comp/code.c index f74231cb0..a6d283af6 100644 --- a/lang/m2/comp/code.c +++ b/lang/m2/comp/code.c @@ -37,6 +37,10 @@ extern char options[]; extern t_desig null_desig; int fp_used; +void RangeCheck(); +void CodeParameters(); +void CodeCall(); + CodeConst(cst, size) arith cst; int size; @@ -55,6 +59,7 @@ CodeConst(cst, size) } } +void CodeString(nd) register t_node *nd; { @@ -288,6 +293,7 @@ CodeCoercion(t1, t2) } } +void CodeCall(nd) register t_node *nd; { @@ -355,6 +361,7 @@ CodeCall(nd) DoLineno(nd); } +void CodeParameters(param, arg) t_param *param; register t_node *arg; @@ -672,6 +679,7 @@ needs_rangecheck(tpl, tpr) return 0; } +void RangeCheck(tpl, tpr) register t_type *tpl, *tpr; { diff --git a/lang/m2/comp/cstoper.c b/lang/m2/comp/cstoper.c index c55d4389f..b7b13f9a4 100644 --- a/lang/m2/comp/cstoper.c +++ b/lang/m2/comp/cstoper.c @@ -45,6 +45,8 @@ arith min_int[] = { 0L, -128L, -32768L, 0L, -2147483647L-1 }; extern char options[]; +void CutSize(); + overflow(expp) t_node *expp; { @@ -160,6 +162,7 @@ divide(pdiv, prem) #endif } +void cstibin(expp) t_node **expp; { @@ -351,6 +354,7 @@ cstfbin(expp) CutSize(exp); } +void cstubin(expp) t_node **expp; { @@ -457,6 +461,7 @@ cstubin(expp) CutSize(exp); } +void cstset(expp) t_node **expp; { @@ -648,6 +653,7 @@ cstcall(expp, call) } } +void CutSize(expr) register t_node *expr; { diff --git a/lang/m2/comp/desig.c b/lang/m2/comp/desig.c index f2ea83a81..2a6ae34be 100644 --- a/lang/m2/comp/desig.c +++ b/lang/m2/comp/desig.c @@ -533,6 +533,7 @@ CodeFieldDesig(df, ds) } } +void CodeVarDesig(df, ds) register t_def *df; register t_desig *ds; diff --git a/lang/m2/comp/enter.c b/lang/m2/comp/enter.c index 12f3e4e9d..ecd004fde 100644 --- a/lang/m2/comp/enter.c +++ b/lang/m2/comp/enter.c @@ -247,6 +247,7 @@ EnterParamList(ppr, Idlist, type, VARp, off) STATIC t_def *DoImport(); +void ImportEffects(idef, scope, flag) register t_def *idef; t_scope *scope; @@ -481,6 +482,7 @@ CheckForImports(df) } } +void EnterFromImportList(idlist, FromDef, FromId) register t_node *idlist; register t_def *FromDef; diff --git a/lang/m2/comp/error.c b/lang/m2/comp/error.c index 410f7d15f..26b5512b4 100644 --- a/lang/m2/comp/error.c +++ b/lang/m2/comp/error.c @@ -61,6 +61,8 @@ extern char *symbol2str(); node, whereas other errors use the information in the token. */ +void _error(); + #if __STDC__ #ifdef DEBUG /*VARARGS*/ @@ -318,6 +320,7 @@ crash(va_alist) } #endif +void _error(class, node, fmt, ap, warn_class) int class; t_node *node; diff --git a/lang/m2/comp/node.c b/lang/m2/comp/node.c index 910769e0d..43db6a239 100644 --- a/lang/m2/comp/node.c +++ b/lang/m2/comp/node.c @@ -81,6 +81,7 @@ dot2leaf(class) return nd; } +void FreeNode(nd) register t_node *nd; { diff --git a/lang/m2/comp/stab.c b/lang/m2/comp/stab.c index 5aae2a1e5..4f4e2e3ac 100644 --- a/lang/m2/comp/stab.c +++ b/lang/m2/comp/stab.c @@ -71,7 +71,7 @@ adds_db_str(s) while (*s) addc_db_str(*s++); } -static +static void stb_type(tp, assign_num) register t_type *tp; { diff --git a/lang/m2/comp/type.c b/lang/m2/comp/type.c index 247e5e280..b70f2b4b1 100644 --- a/lang/m2/comp/type.c +++ b/lang/m2/comp/type.c @@ -74,6 +74,8 @@ t_type *std_type, *error_type; +void ArraySizes(); + t_type * construct_type(fund, tp) int fund; @@ -576,6 +578,7 @@ ArrayElSize(tp) } } +void ArraySizes(tp) register t_type *tp; { diff --git a/lang/m2/comp/walk.c b/lang/m2/comp/walk.c index de9a63552..93cc3308b 100644 --- a/lang/m2/comp/walk.c +++ b/lang/m2/comp/walk.c @@ -64,7 +64,7 @@ static int WalkDef(); static int stabdef(); #endif static int MkCalls(); -static int UseWarnings(); +static void UseWarnings(); #define NO_EXIT_LABEL ((label) 0) #define RETURN_LABEL ((label) 1) @@ -72,6 +72,8 @@ static int UseWarnings(); #define REACH_FLAG 1 #define EXIT_FLAG 2 +void DoAssign(); + int LblWalkNode(lbl, nd, exit, reach) label lbl, exit; @@ -995,6 +997,7 @@ node_warning(nd, W_OLDFASHIONED, "compatibility required in FOR statement"); return 1; } +void DoAssign(nd) register t_node *nd; { @@ -1057,7 +1060,7 @@ RegisterMessage(df) } } -static +static void df_warning(nd, df, warning) t_node *nd; t_def *df; @@ -1080,7 +1083,7 @@ df_warning(nd, df, warning) } } -static +static void UseWarnings(df) register t_def *df; { diff --git a/lang/pc/comp/LLlex.c b/lang/pc/comp/LLlex.c index 6074870f7..7bd857a2b 100644 --- a/lang/pc/comp/LLlex.c +++ b/lang/pc/comp/LLlex.c @@ -120,7 +120,7 @@ CommentOptions() } -STATIC +STATIC void SkipComment() { /* Skip ISO-Pascal comments (* ... *) or { ... }. @@ -216,6 +216,7 @@ register int delim; static char *s_error = "illegal line directive"; +void CheckForLineDirective() { register int ch; diff --git a/lang/pc/comp/body.c b/lang/pc/comp/body.c index f2f7a1a04..091ab6927 100644 --- a/lang/pc/comp/body.c +++ b/lang/pc/comp/body.c @@ -47,6 +47,7 @@ MarkDef(nd, flags, on) } } +void AssertStat(expp, line) register struct node *expp; unsigned short line; @@ -69,6 +70,7 @@ AssertStat(expp, line) } } +void AssignStat(left, right) register struct node *left, *right; { @@ -131,6 +133,7 @@ AssignStat(left, right) FreeNode(right); } +void ProcStat(nd) register struct node *nd; { @@ -142,6 +145,7 @@ ProcStat(nd) } } +void ChkForStat(nd) register struct node *nd; { @@ -202,6 +206,7 @@ ChkForStat(nd) return; } +void EndForStat(nd) register struct node *nd; { @@ -283,6 +288,7 @@ CodeEndFor(nd, stepsize, l1, l2, tmp2) C_asp(int_size); } +void WithStat(nd) struct node *nd; { diff --git a/lang/pc/comp/casestat.C b/lang/pc/comp/casestat.C index 61eba13f7..554a6216d 100644 --- a/lang/pc/comp/casestat.C +++ b/lang/pc/comp/casestat.C @@ -40,6 +40,7 @@ struct case_entry { */ #define compact(nr, low, up) (nr != 0 && (up - low) / nr <= DENSITY) +void CaseExpr(nd) struct node *nd; { @@ -62,6 +63,7 @@ CaseExpr(nd) } } +void CaseEnd(nd, exit_label) struct node *nd; label exit_label; diff --git a/lang/pc/comp/chk_expr.c b/lang/pc/comp/chk_expr.c index 1c5cb58ea..a9e8ba73a 100644 --- a/lang/pc/comp/chk_expr.c +++ b/lang/pc/comp/chk_expr.c @@ -1183,13 +1183,6 @@ ChkStandard(expp,left) expp->nd_type = NULLTYPE; break; - case R_MARK: - case R_RELEASE: - if( !(left = getarg(&arg, T_POINTER, 1, name, NULLTYPE)) ) - return 0; - expp->nd_type = NULLTYPE; - break; - case R_HALT: if( !arg->nd_right ) /* insert 0 parameter */ arg->nd_right = ZeroParam(); diff --git a/lang/pc/comp/code.c b/lang/pc/comp/code.c index 17f0f7c32..5cdc6644a 100644 --- a/lang/pc/comp/code.c +++ b/lang/pc/comp/code.c @@ -24,6 +24,11 @@ int fp_used; +void Long2Int(); +void Int2Long(); +void genrck(); +void CodeCall(); + CodeFil() { if ( !options['L'] ) @@ -791,6 +796,7 @@ CodePString(nd, tp) C_loi(tp->tp_size); } +void CodeCall(nd) register struct node *nd; { @@ -1070,16 +1076,6 @@ CodeStd(nd) C_asp(pointer_size + word_size); break; - case R_MARK: - case R_RELEASE: - CodeDAddress(left); - if( req == R_MARK ) - C_cal("_sav"); - else - C_cal("_rst"); - C_asp(pointer_size); - break; - case R_HALT: if( left ) CodePExpr(left); @@ -1095,6 +1091,7 @@ CodeStd(nd) } } +void Long2Int() { /* convert a long to integer */ @@ -1106,6 +1103,7 @@ Long2Int() C_cii(); } +void Int2Long() { /* convert integer to long */ @@ -1160,6 +1158,7 @@ RangeCheck(tpl, tpr) } } +void genrck(tp) register struct type *tp; { diff --git a/lang/pc/comp/cstoper.c b/lang/pc/comp/cstoper.c index be9dbc387..c4196e522 100644 --- a/lang/pc/comp/cstoper.c +++ b/lang/pc/comp/cstoper.c @@ -66,6 +66,7 @@ cstunary(expp) expp->nd_right = NULLNODE; } +void cstbin(expp) register struct node *expp; { @@ -195,6 +196,7 @@ cstbin(expp) expp->nd_left = expp->nd_right = NULLNODE; } +void cstset(expp) register struct node *expp; { diff --git a/lang/pc/comp/def.c b/lang/pc/comp/def.c index dfc33f459..745bb48e0 100644 --- a/lang/pc/comp/def.c +++ b/lang/pc/comp/def.c @@ -116,6 +116,7 @@ define(id, scope, kind) return MkDef(id, scope, kind); } +void DoDirective(directive, nd, tp, scl, function) struct idf *directive; struct node *nd; diff --git a/lang/pc/comp/desig.c b/lang/pc/comp/desig.c index 68c5512a9..566bb36a4 100644 --- a/lang/pc/comp/desig.c +++ b/lang/pc/comp/desig.c @@ -26,6 +26,7 @@ struct desig InitDesig = {DSG_INIT, 0, 0, NULLDEF, 0}; struct withdesig *WithDesigs; +void CodeValue(); STATIC int properly(ds, size, al) @@ -71,6 +72,7 @@ CodeCopy(lhs, rhs, sz, psize) C_sti(sz); } +void CodeMove(rhs, left, rtp) register struct desig *rhs; register struct node *left; @@ -150,6 +152,7 @@ CodeMove(rhs, left, rtp) } } +void CodeValue(ds, tp) register struct desig *ds; register struct type *tp; @@ -366,6 +369,7 @@ CodeFieldDesig(df, ds) ds->dsg_packed = df->fld_flags & F_PACKED; } +void CodeVarDesig(df, ds) register struct def *df; register struct desig *ds; diff --git a/lang/pc/comp/error.c b/lang/pc/comp/error.c index 8a381c6fe..dd75c79e6 100644 --- a/lang/pc/comp/error.c +++ b/lang/pc/comp/error.c @@ -39,6 +39,8 @@ int err_occurred; extern char *symbol2str(); +void _error(); + /* There are three general error-message functions: lexerror() lexical and pre-processor error messages error() syntactic and pre-processor messagese @@ -304,6 +306,7 @@ crash(va_alist) } #endif +void _error(class, node, fmt, ap) int class; struct node *node; diff --git a/lang/pc/comp/label.c b/lang/pc/comp/label.c index 73745ba21..b303b7dc5 100644 --- a/lang/pc/comp/label.c +++ b/lang/pc/comp/label.c @@ -12,6 +12,8 @@ #include "scope.h" #include "type.h" +void CodeLabel(); + DeclLabel(nd) struct node *nd; @@ -103,6 +105,7 @@ TstLabel(nd, Slevel) CodeLabel(df, 1); } +void DefLabel(nd, Slevel) register struct node *nd; { @@ -139,6 +142,7 @@ DefLabel(nd, Slevel) } } +void CodeLabel(df, local) register struct def *df; { diff --git a/lang/pc/comp/main.c b/lang/pc/comp/main.c index cef708fcd..46eabf855 100644 --- a/lang/pc/comp/main.c +++ b/lang/pc/comp/main.c @@ -189,10 +189,6 @@ AddRequired() /* DYNAMIC ALLOCATION PROCEDURES */ (void) Enter("new", D_PROCEDURE, std_type, R_NEW); (void) Enter("dispose", D_PROCEDURE, std_type, R_DISPOSE); - if( !options['s'] ) { - (void) Enter("mark", D_PROCEDURE, std_type, R_MARK); - (void) Enter("release", D_PROCEDURE, std_type, R_RELEASE); - } /* MISCELLANEOUS PROCEDURE(S) */ if( !options['s'] ) diff --git a/lang/pc/comp/node.c b/lang/pc/comp/node.c index 889e855f8..1d8a491f0 100644 --- a/lang/pc/comp/node.c +++ b/lang/pc/comp/node.c @@ -42,6 +42,7 @@ MkLeaf(class, token) return nd; } +void FreeNode(nd) register struct node *nd; { diff --git a/lang/pc/comp/progs.c b/lang/pc/comp/progs.c index 173767526..6ed227eb9 100644 --- a/lang/pc/comp/progs.c +++ b/lang/pc/comp/progs.c @@ -15,6 +15,8 @@ static int inpflag = 0; /* input mentioned in heading ? */ static int outpflag = 0; /* output mentioned in heading ? */ static label extfl_label; /* label of array of file pointers */ +void make_extfl_args(); + set_inp() { inpflag = 1; @@ -25,6 +27,7 @@ set_outp() outpflag = 1; } +void make_extfl() { if( err_occurred ) return; @@ -54,6 +57,7 @@ make_extfl() make_extfl_args( GlobalScope->sc_def ); } +void make_extfl_args(df) register struct def *df; { diff --git a/lang/pc/comp/readwrite.c b/lang/pc/comp/readwrite.c index 7b62aaede..35ed8860d 100644 --- a/lang/pc/comp/readwrite.c +++ b/lang/pc/comp/readwrite.c @@ -19,6 +19,12 @@ extern char *sprint(); +void CodeRead(); +void CodeReadln(); +void CodeWrite(); +void CodeWriteln(); + +void ChkRead(arg) register struct node *arg; { @@ -86,6 +92,7 @@ ChkRead(arg) } } +void ChkReadln(arg) register struct node *arg; { @@ -142,6 +149,7 @@ ChkReadln(arg) CodeReadln(file); } +void ChkWrite(arg) register struct node *arg; { @@ -183,6 +191,7 @@ ChkWrite(arg) } } +void ChkWriteln(arg) register struct node *arg; { @@ -318,6 +327,7 @@ ChkStdInOut(name, st_out) return nd; } +void CodeRead(file, arg) register struct node *file, *arg; { @@ -376,6 +386,7 @@ CodeRead(file, arg) } } +void CodeReadln(file) struct node *file; { @@ -386,6 +397,7 @@ CodeReadln(file) C_asp(pointer_size); } +void CodeWrite(file, arg) register struct node *file, *arg; { @@ -472,6 +484,7 @@ CodeWrite(file, arg) } } +void CodeWriteln(file) register struct node *file; { diff --git a/lang/pc/comp/required.h b/lang/pc/comp/required.h index 20b9a5fad..e8a4becbe 100644 --- a/lang/pc/comp/required.h +++ b/lang/pc/comp/required.h @@ -1,48 +1,51 @@ /* REQUIRED PROCEDURES AND FUNCTIONS */ -/* PROCEDURES */ -/* FILE HANDLING */ -#define R_REWRITE 1 -#define R_PUT 2 -#define R_RESET 3 -#define R_GET 4 -#define R_PAGE 5 +enum +{ + R__UNUSED = 0, -/* DYNAMIC ALLOCATION */ -#define R_NEW 6 -#define R_DISPOSE 7 -#define R_MARK 8 -#define R_RELEASE 9 + /* PROCEDURES */ + /* FILE HANDLING */ + R_REWRITE, + R_PUT, + R_RESET, + R_GET, + R_PAGE, -/* MISCELLANEOUS PROCEDURE(S) */ -#define R_HALT 10 + /* DYNAMIC ALLOCATION */ + R_NEW, + R_DISPOSE, -/* TRANSFER */ -#define R_PACK 11 -#define R_UNPACK 12 + /* MISCELLANEOUS PROCEDURE(S) */ + R_HALT, -/* FUNCTIONS */ -/* ARITHMETIC */ -#define R_ABS 13 -#define R_SQR 14 -#define R_SIN 15 -#define R_COS 16 -#define R_EXP 17 -#define R_LN 18 -#define R_SQRT 19 -#define R_ARCTAN 20 + /* TRANSFER */ + R_PACK, + R_UNPACK, -/* TRANSFER */ -#define R_TRUNC 21 -#define R_ROUND 22 + /* FUNCTIONS */ + /* ARITHMETIC */ + R_ABS, + R_SQR, + R_SIN, + R_COS, + R_EXP, + R_LN, + R_SQRT, + R_ARCTAN, -/* ORDINAL */ -#define R_ORD 23 -#define R_CHR 24 -#define R_SUCC 25 -#define R_PRED 26 + /* TRANSFER */ + R_TRUNC, + R_ROUND, -/* BOOLEAN */ -#define R_ODD 27 -#define R_EOF 28 -#define R_EOLN 29 + /* ORDINAL */ + R_ORD, + R_CHR, + R_SUCC, + R_PRED, + + /* BOOLEAN */ + R_ODD, + R_EOF, + R_EOLN, +}; diff --git a/lang/pc/comp/stab.c b/lang/pc/comp/stab.c index d5e4ee3fb..0b8c52f23 100644 --- a/lang/pc/comp/stab.c +++ b/lang/pc/comp/stab.c @@ -71,7 +71,7 @@ adds_db_str(s) while (*s) addc_db_str(*s++); } -static +static void stb_type(tp, assign_num) register struct type *tp; { @@ -247,6 +247,7 @@ stb_addtp(s, tp) (arith) 0); } +void stb_string(df, kind) register struct def *df; long kind; diff --git a/lang/pc/comp/type.c b/lang/pc/comp/type.c index b5662c658..faca8fee5 100644 --- a/lang/pc/comp/type.c +++ b/lang/pc/comp/type.c @@ -51,6 +51,8 @@ struct type *void_type, *error_type; +void ArraySizes(); + CheckTypeSizes() { /* first, do some checking @@ -442,6 +444,7 @@ ArrayElSize(tp, packed) return algn; } +void ArraySizes(tp) register struct type *tp; { @@ -489,6 +492,7 @@ ArraySizes(tp) C_rom_cst(tp->arr_elsize); } +void FreeForward(for_type) register struct forwtype *for_type; { diff --git a/lang/pc/libpc/build.lua b/lang/pc/libpc/build.lua index 61c4f7a3e..7845991e5 100644 --- a/lang/pc/libpc/build.lua +++ b/lang/pc/libpc/build.lua @@ -11,7 +11,6 @@ for _, plat in ipairs(vars.plats) do "./fif.e", "./gto.e", "./hol0.e", - "./sav.e", "./sig.e", "./trap.e", "./trp.e", diff --git a/lang/pc/libpc/dis.c b/lang/pc/libpc/dis.c deleted file mode 100644 index c6a9bd2e7..000000000 --- a/lang/pc/libpc/dis.c +++ /dev/null @@ -1,101 +0,0 @@ -/* - * File: - dis.c - * - * dispose() built in standard procedure in Pascal (6.6.5.3) - * - * Re-implementation of storage allocator for Ack Pascal compiler - * under Linux, and other UNIX-like systems. - * - * Written by Erik Backerud, 2010-10-01 - * - * Original copyright and author info below: - */ -/* $Id$ */ -/* - * (c) copyright 1983 by the Vrije Universiteit, Amsterdam, The Netherlands. - * - * This product is part of the Amsterdam Compiler Kit. - * - * Permission to use, sell, duplicate or disclose this software must be - * obtained in writing. Requests for such permissions may be sent to - * - * Dr. Andrew S. Tanenbaum - * Wiskundig Seminarium - * Vrije Universiteit - * Postbox 7161 - * 1007 MC Amsterdam - * The Netherlands - * - */ - -/* Author: J.W. Stevenson */ - -#include - -#define assert() /* nothing */ - -/* - * use a singly linked list of free blocks. - */ -struct adm { - struct adm *next; - int size; -}; - -struct adm *freep = 0; /* first element on free list */ - -extern void _trp(int); - -/* - * Dispose - * Called with two arguments: - * n the size of the block to be freed, in bytes, - * pp address of pointer to data. - */ -void -_dis(int n, struct adm **pp) -{ - struct adm *block; /* the block of data being freed (inc. header) */ - struct adm *p, *q; - - if (*pp == 0) { - _trp(EFREE); - } - block = *pp - 1; - if (freep == 0) { - freep = block; - block->next = 0; - } else { - q = 0; /* trail one behind */ - for (p = freep; p < block; p = p->next) { - if (p == 0) { /* We reached the end of the free list. */ - break; - } - q = p; - /* check if block is contained in the free block p */ - if (p+p->size > block) { - _trp(EFREE); - } - } - if (p == block) { /* this block already freed */ - _trp(EFREE); - } - if (q == 0) { /* block is first */ - freep = block; - block->next = p; - } else { - q->next = block; - } - block->next = p; - /* merge with successor on free list? */ - if (block + block->size == p) { - block->size = block->size + p->size; - block->next = p->next; - } - /* merge with preceding block on free list? */ - if (q != 0 && q+q->size == block) { - q->size = q->size + block->size; - q->next = block->next; - } - } -} /* _dis */ diff --git a/lang/pc/libpc/new.c b/lang/pc/libpc/new.c index 427cb850c..b3425c176 100644 --- a/lang/pc/libpc/new.c +++ b/lang/pc/libpc/new.c @@ -1,120 +1,20 @@ -/* - * File: - new.c - * - * new() built in standard procedure in Pascal (6.6.5.3) - * - * Re-implementation of storage allocator for Ack Pascal compiler - * under Linux, and other UNIX-like systems. - * - * Written by Erik Backerud, 2010-10-01 - * - * Original copyright and author info below: - */ -/* $Id$ */ -/* - * (c) copyright 1983 by the Vrije Universiteit, Amsterdam, The Netherlands. - * - * This product is part of the Amsterdam Compiler Kit. - * - * Permission to use, sell, duplicate or disclose this software must be - * obtained in writing. Requests for such permissions may be sent to - * - * Dr. Andrew S. Tanenbaum - * Wiskundig Seminarium - * Vrije Universiteit - * Postbox 7161 - * 1007 MC Amsterdam - * The Netherlands - * - */ - -/* Author: J.W. Stevenson */ +#include #include #include -#define assert(x) /* nothing */ -#define UNDEF 0x8000 -#define NALLOC (1024) /* request this many units from OS */ - - -/* - * use a singly linked list of free blocks. - */ -struct adm { - struct adm *next; - int size; -}; - -extern struct adm *freep; - extern void _trp(int); /* called on error */ -extern void _dis(int, struct adm **); - - -/* - * Helper function to request 'nu' units of memory from the OS. - * A storage unit is sizeof(struct adm). Typically 8 bytes - * on a 32-bit machine like i386 etc. - */ -static struct adm * -morecore(unsigned nu) +void _new(int n, void** ptr) { - char *cp, *sbrk(int); - struct adm *up; - - if (nu < NALLOC) - nu = NALLOC; - cp = sbrk(nu * sizeof(struct adm)); - if (cp == (char *) -1) /* no space at all */ - return 0; - up = (struct adm*) cp; - up->size = nu; - up = up + 1; - _dis((nu - 1) * sizeof(struct adm), &up); - return freep; -} /* morecore */ - -/* - * Dispose - * Called with two arguments: - * n the size of the block to be freed, in bytes, - * pp address of pointer to data. - */ -void -_new(int n, struct adm **pp) -{ - int nunits; /* the unit of storage is sizeof(struct adm) */ - struct adm *p,*q; - - /* round up size of request */ - nunits = (n + sizeof(struct adm) - 1) / sizeof(struct adm) + 1; - - q = 0; - for (p = freep; ; p = p->next) { - if (p == 0) { - p = morecore(nunits); - if (p == 0) + void* p = malloc(n); + if (!p) _trp(EHEAP); - q = 0; - } - if (p->size >= nunits) { - if (p->size == nunits) { /* exact fit */ - if (q == 0) { /* first element on free list. */ - freep = p->next; - } else { - q->next = p->next; - } - } else { /* allocate tail end */ - q = p; - q->size = q->size - nunits; - p = q + q->size; - p->next = 0; - p->size = nunits; - } - break; - } - q = p; - } - *pp = p + 1; -} /* _new */ + + *ptr = p; +} + +void _dis(int n, void** ptr) +{ + free(*ptr); + *ptr = NULL; +} \ No newline at end of file diff --git a/lang/pc/libpc/sav.e b/lang/pc/libpc/sav.e deleted file mode 100644 index 3f5362f1c..000000000 --- a/lang/pc/libpc/sav.e +++ /dev/null @@ -1,49 +0,0 @@ -# -; $Id$ -; (c) copyright 1983 by the Vrije Universiteit, Amsterdam, The Netherlands. -; -; This product is part of the Amsterdam Compiler Kit. -; -; Permission to use, sell, duplicate or disclose this software must be -; obtained in writing. Requests for such permissions may be sent to -; -; Dr. Andrew S. Tanenbaum -; Wiskundig Seminarium -; Vrije Universiteit -; Postbox 7161 -; 1007 MC Amsterdam -; The Netherlands -; - -/* Author: J.W. Stevenson */ - - - mes 2,EM_WSIZE,EM_PSIZE - -#define PTRAD 0 - -#define HP 2 - -; _sav called with one parameter: -; - address of pointer variable (PTRAD) - - exp $_sav - pro $_sav,0 - lor HP - lal PTRAD - loi EM_PSIZE - sti EM_PSIZE - ret 0 - end ? - -; _rst is called with one parameter: -; - address of pointer variable (PTRAD) - - exp $_rst - pro $_rst,0 - lal PTRAD - loi EM_PSIZE - loi EM_PSIZE - str HP - ret 0 - end ? diff --git a/mach/i386/as/mach5.c b/mach/i386/as/mach5.c index 9853c6c0c..8d638c922 100644 --- a/mach/i386/as/mach5.c +++ b/mach/i386/as/mach5.c @@ -38,6 +38,7 @@ ea_1_16(param) } } +void ea_1(param) { if (! address_long) { ea_1_16(param); @@ -134,6 +135,7 @@ regsize(sz) } } +void indexed() { if (address_long) { mod_2 = 0; diff --git a/mach/i386/ncg/mach.c b/mach/i386/ncg/mach.c index e3b74053a..7514d6775 100644 --- a/mach/i386/ncg/mach.c +++ b/mach/i386/ncg/mach.c @@ -61,6 +61,7 @@ string holstr(n) word n; { full lbytes; #endif +void prolog(nlocals) full nlocals; { fputs("push ebp\nmov ebp,esp\n", codefile); @@ -179,6 +180,7 @@ mach_option(s) } #endif /* MACH_OPTIONS */ +void mes(type) word type ; { int argt, a1, a2 ; diff --git a/mach/i80/ncg/mach.c b/mach/i80/ncg/mach.c index 7cf0b92a5..9f952f0d9 100644 --- a/mach/i80/ncg/mach.c +++ b/mach/i80/ncg/mach.c @@ -54,6 +54,7 @@ con_float() { } +void prolog(nlocals) full nlocals; { fprintf(codefile,"\tpush\tb\n\tlxi\th,0\n\tdad\tsp\n\tmov\tb,h\n\tmov\tc,l\n"); @@ -67,6 +68,7 @@ prolog(nlocals) full nlocals; { } } +void mes(type) word type ; { int argt ; diff --git a/mach/i86/ncg/mach.c b/mach/i86/ncg/mach.c index e222522ad..a305d6d9a 100644 --- a/mach/i86/ncg/mach.c +++ b/mach/i86/ncg/mach.c @@ -61,6 +61,7 @@ string holstr(n) word n; { full lbytes; #endif +void prolog(nlocals) full nlocals; { fputs("\tpush\tbp\n\tmov\tbp,sp\n", codefile); @@ -157,6 +158,7 @@ regreturn() } #endif /* REGVARS */ +void mes(type) word type ; { int argt ; diff --git a/mach/m68020/as/mach5.c b/mach/m68020/as/mach5.c index 12ccf087a..e623bd01f 100644 --- a/mach/m68020/as/mach5.c +++ b/mach/m68020/as/mach5.c @@ -21,6 +21,8 @@ * then emitted in one go, by emit_instr(). */ +void move_special(); + emit_instr() { register instr_t *ip; @@ -70,6 +72,7 @@ long words; T_EMIT2((short)(words), 0, 0, 0); } +void ea_1(sz, bits) { /* Because displacements come in three sizes (null displacement, @@ -242,6 +245,7 @@ badoperand() serror("bad operand(s)"); } +void shift_op(opc, sz) { if (mrg_1 < 010 && mrg_2 < 010) { @@ -263,6 +267,7 @@ shift_op(opc, sz) ea_2(SIZE_W, MEM|ALT); } +void bitop(opc) { register bits; @@ -291,6 +296,7 @@ bitfield(opc, extension) ea_2(SIZE_L, (mrg_2 < 010) ? 0 : (CTR | ALT)); } +void add(opc, sz) { if ((mrg_2 & 070) == 010) @@ -326,6 +332,7 @@ add(opc, sz) badoperand(); } +void and(opc, sz) { if (mrg_1 == 074 && mrg_2 >= 076) { /* ccr or sr */ @@ -370,6 +377,7 @@ from_dreg(opc, sz, bits) return(1); } +void cmp(sz) { register opc; @@ -416,6 +424,7 @@ link_instr(sz, areg) ea_2(sz, 0); } +void move(sz) { register opc; @@ -448,6 +457,7 @@ move(sz) ea_2(sz, ALT); } +void move_special(sz) { if (mrg_2 >= 076) { @@ -514,6 +524,7 @@ reverse(regs, max) return regs; } +void movep(sz) { checksize(sz, 2|4); @@ -530,6 +541,7 @@ movep(sz) badoperand(); } +void branch(opc, exp) expr_t exp; { @@ -566,6 +578,7 @@ expr_t exp; T_EMIT4(exp.val, exp.typ, RELPC|RELO4, relonami); } +void cpbcc(opc, exp) expr_t exp; { @@ -593,6 +606,7 @@ expr_t exp; T_EMIT4(exp.val, exp.typ, RELPC|RELO4, relonami); } +void ea7071(sz) { mrg_2 = 071; @@ -671,6 +685,7 @@ ea7071(sz) mrg_2 = 070; } +void fbranch(opc, exp) expr_t exp; { diff --git a/mach/m68020/ncg/mach.c b/mach/m68020/ncg/mach.c index 6759772f7..915b4f6e2 100644 --- a/mach/m68020/ncg/mach.c +++ b/mach/m68020/ncg/mach.c @@ -187,6 +187,7 @@ regsave(s,off,size) fprintf(codefile, "!Local %ld into %s\n",off,s); } +void prolog(n) full n; { nlocals = n; @@ -207,6 +208,7 @@ mach_option(s) } #endif /* MACH_OPTIONS */ +void mes(type) word type ; { int argt, a1, a2 ; diff --git a/mach/powerpc/as/mach0.c b/mach/powerpc/as/mach0.c index 3a42f1dd8..325c08910 100644 --- a/mach/powerpc/as/mach0.c +++ b/mach/powerpc/as/mach0.c @@ -19,6 +19,8 @@ #undef word_t #define word_t long +typedef uint32_t quad; + #undef ALIGNWORD #define ALIGNWORD 4 diff --git a/mach/powerpc/as/mach2.c b/mach/powerpc/as/mach2.c index 7cd4a4ff4..96d6690df 100644 --- a/mach/powerpc/as/mach2.c +++ b/mach/powerpc/as/mach2.c @@ -49,6 +49,7 @@ %token OP_RS_RA_NB %token OP_RS_RA_RB %token OP_RS_RA_RB_C +%token OP_RS_RA_RA_C %token OP_RS_RA_RB_MB5_ME5_C %token OP_RS_RA_RB_MB6_C %token OP_RS_RA_RB_ME6_C @@ -80,6 +81,7 @@ %token OP_TO_RA_RB %token OP_TO_RA_SI +%token OP_LA %token OP_LI32 /* Other token types */ diff --git a/mach/powerpc/as/mach3.c b/mach/powerpc/as/mach3.c index 153e5d4d2..0f0bfdae7 100644 --- a/mach/powerpc/as/mach3.c +++ b/mach/powerpc/as/mach3.c @@ -99,6 +99,9 @@ /* Special instructions */ 0, OP_LI32, 0, "li32", +0, OP_LA, 0, "la", +0, OP_LA, 0, "li", +0, OP_RS_RA_RA_C, 31<<26 | 444<<1, "mr", /* Branch processor instructions (page 20) */ diff --git a/mach/powerpc/as/mach4.c b/mach/powerpc/as/mach4.c index 2fe584992..3f79ca86c 100644 --- a/mach/powerpc/as/mach4.c +++ b/mach/powerpc/as/mach4.c @@ -44,6 +44,7 @@ operation | OP_RS_RA_UI_CC C GPR ',' GPR ',' e16 { emit4($1 | ($5<<21) | ($3<<16) | $7); } | OP_RS_RA_RB GPR ',' GPR ',' GPR { emit4($1 | ($2<<21) | ($4<<16) | ($6<<11)); } | OP_RS_RA_RB_C c GPR ',' GPR ',' GPR { emit4($1 | $2 | ($5<<21) | ($3<<16) | ($7<<11)); } + | OP_RS_RA_RA_C c GPR ',' GPR { emit4($1 | $2 | ($5<<21) | ($3<<16) | ($5<<11)); } | OP_RS_RA_RB_MB5_ME5_C c GPR ',' GPR ',' GPR ',' u5 ',' u5 { emit4($1 | $2 | ($5<<21) | ($3<<16) | ($7<<11) | ($9<<6) | ($11<<1)); } | OP_RS_RA_RB_MB6_C c GPR ',' GPR ',' GPR ',' u6 { emit4($1 | $2 | ($5<<21) | ($3<<16) | ($7<<11) | (($9&0x1F)<<6) | (($9&0x20)>>0)); } | OP_RS_RA_RB_ME6_C c GPR ',' GPR ',' GPR ',' u6 { emit4($1 | $2 | ($5<<21) | ($3<<16) | ($7<<11) | (($9&0x1F)<<6) | (($9&0x20)>>0)); } @@ -196,9 +197,16 @@ bda li32 : GPR ',' expr { - newrelo($3.typ, RELOPPC | FIXUPFLAGS); - emit4((15<<26) | ($1<<21) | (0<<16) | ($3.val >> 16)); /* addis */ - emit4((24<<26) | ($1<<21) | ($1<<16) | ($3.val & 0xffff)); /* ori */ + quad type = $3.typ & S_TYP; + quad val = $3.val; + if ((type == S_ABS) && (val <= 0xffff)) + emit4((14<<26) | ($1<<21) | (0<<16) | val); /* addi */ + else + { + newrelo($3.typ, RELOPPC | FIXUPFLAGS); + emit4((15<<26) | ($1<<21) | (0<<16) | (val >> 16)); /* addis */ + emit4((24<<26) | ($1<<21) | ($1<<16) | (val & 0xffff)); /* ori */ + } } ; diff --git a/mach/powerpc/libem/build.lua b/mach/powerpc/libem/build.lua index 56278aa55..318be381d 100644 --- a/mach/powerpc/libem/build.lua +++ b/mach/powerpc/libem/build.lua @@ -1,12 +1,19 @@ for _, plat in ipairs(vars.plats) do + acklibrary { + name = "headers_"..plat, + hdrs = { "./*.h" } + } + acklibrary { name = "lib_"..plat, srcs = { "./*.s", + "./*.e", }, vars = { plat = plat }, deps = { - "h+emheaders" + "h+emheaders", + "+headers_"..plat, } } end diff --git a/mach/powerpc/libem/csa.s b/mach/powerpc/libem/csa.s index 64954ff4e..88e6e176a 100644 --- a/mach/powerpc/libem/csa.s +++ b/mach/powerpc/libem/csa.s @@ -12,11 +12,14 @@ ! address and jumps to it. ! traps if resulting address is zero ! -! On entry: r3 = address of CSA table -! r4 = value +! Stack: ( value tableaddr -- ) .define .csa .csa: + lwz r3, 0(sp) + lwz r4, 4(sp) + addi sp, sp, 8 + lwz r5, 0(r3) ! load default mtspr ctr, r5 diff --git a/mach/powerpc/libem/csb.s b/mach/powerpc/libem/csb.s index cbedc8c11..a8df85d7f 100644 --- a/mach/powerpc/libem/csb.s +++ b/mach/powerpc/libem/csb.s @@ -12,11 +12,14 @@ ! address and jumps to it. ! traps if resulting address is zero ! -! On entry: r3 = address of CSB table -! r4 = value +! Stack: ( value tableaddr -- ) .define .csb .csb: + lwz r3, 0(sp) + lwz r4, 4(sp) + addi sp, sp, 8 + lwz r5, 0(r3) ! load default mtspr ctr, r5 diff --git a/mach/powerpc/libem/inn.s b/mach/powerpc/libem/inn.s new file mode 100644 index 000000000..f5ae4c63e --- /dev/null +++ b/mach/powerpc/libem/inn.s @@ -0,0 +1,26 @@ +#include "powerpc.h" + +.sect .text + +/* Tests a bit in a bitset on the stack. + * + * Stack: ( bitset bitnum setsize -- bool ) + */ + +.define .inn +.inn: + lwz r3, 0(sp) /* r3 = size (bytes) */ + lwz r4, 4(sp) /* r4 = bit number */ + addi r5, sp, 8 /* r5 = base address of bit set */ + + srawi r6, r4, 3 /* r6 = byte address into set */ + andi. r7, r4, 7 /* r7 = bit within byte */ + + lbzx r8, r5, r6 /* r8 = individual byte from set */ + sraw r8, r8, r7 + rlwinm r8, r8, 0, 31, 31 + + addi sp, sp, 8 /* retract over the two words */ + add sp, sp, r3 /* retract over bitfield */ + stwu r8, -4(sp) /* push result */ + bclr ALWAYS, 0, 0 /* return */ diff --git a/mach/powerpc/mcg/platform.c b/mach/powerpc/mcg/platform.c new file mode 100644 index 000000000..65b158cac --- /dev/null +++ b/mach/powerpc/mcg/platform.c @@ -0,0 +1,333 @@ +#include "mcg.h" + +/* mcg stack frames are laid out as: + * + * | ...params... + * | --------------- <- ab + * | old FR + * | old FP + * | --------------- <- fp (a.k.a. lb) + * | locals + * | --------------- + * | spills + * | --------------- <- sb + * | saved regs + * | --------------- <- sp, rb + * V ...user area... + * + * st indexes up; lb indexes down. + * + * Note that [fp] == old_fp and ab == fp + 8. + */ + +static ARRAYOF(struct hreg) saved_regs; + +void platform_calculate_offsets(void) +{ + int i; + + saved_regs.count = 0; + for (i=0; iusedregs.count; i++) + { + struct hreg* hreg = current_proc->usedregs.item[i]; + + if (!(hreg->attrs & burm_volatile_ATTR) && + ((hreg->attrs & burm_long_ATTR) || (hreg->attrs & burm_double_ATTR))) + { + hreg->offset = current_proc->saved_size; + current_proc->saved_size += 8; + array_append(&saved_regs, hreg); + } + } + for (i=0; iusedregs.count; i++) + { + struct hreg* hreg = current_proc->usedregs.item[i]; + + if (!(hreg->attrs & burm_volatile_ATTR) && + ((hreg->attrs & burm_int_ATTR) || (hreg->attrs & burm_float_ATTR))) + { + hreg->offset = current_proc->saved_size; + current_proc->saved_size += 4; + array_append(&saved_regs, hreg); + } + } + + current_proc->fp_to_ab = 8; + current_proc->fp_to_lb = 0; + current_proc->fp_to_sb = -(current_proc->locals_size + current_proc->spills_size); + current_proc->fp_to_rb = current_proc->fp_to_sb - current_proc->saved_size; +} + +struct hop* platform_prologue(void) +{ + int i; + int spoffset = current_proc->saved_size + current_proc->spills_size + + current_proc->locals_size; + struct hop* hop = new_hop(current_proc->entry, NULL); + + hop_add_insel(hop, "! locals_size = %d", current_proc->locals_size); + hop_add_insel(hop, "! spills_size = %d", current_proc->spills_size); + hop_add_insel(hop, "! saved_size = %d", current_proc->saved_size); + hop_add_insel(hop, "! params @ fp+%d", current_proc->fp_to_ab); + hop_add_insel(hop, "! lr @ fp+4"); + hop_add_insel(hop, "! fp @ fp+0"); + hop_add_insel(hop, "! locals @ fp-%d to fp+0", + current_proc->locals_size); + hop_add_insel(hop, "! spills @ fp-%d to fp-%d", + -current_proc->fp_to_sb, current_proc->locals_size); + for (i=saved_regs.count-1; i>=0; i--) + { + struct hreg* hreg = saved_regs.item[i]; + hop_add_insel(hop, "! %s @ fp-%d", + hreg->id, -(current_proc->fp_to_rb + hreg->offset)); + } + + hop_add_insel(hop, "addi sp, sp, %d", -(spoffset + 8)); + hop_add_insel(hop, "mfspr r0, lr"); + hop_add_insel(hop, "stw fp, %d(sp)", spoffset + 0); + hop_add_insel(hop, "stw r0, %d(sp)", spoffset + 4); + hop_add_insel(hop, "addi fp, sp, %d", spoffset); + + /* Saved reg offsets are negative. */ + for (i=0; iattrs & burm_int_ATTR) + hop_add_insel(hop, "stw %H, %d(fp)", + hreg, current_proc->fp_to_rb + hreg->offset); + else if (hreg->attrs & burm_float_ATTR) + hop_add_insel(hop, "stfs %H, %d(fp)", + hreg, current_proc->fp_to_rb + hreg->offset); + } + return hop; +} + +struct hop* platform_epilogue(void) +{ + struct hop* hop = new_hop(current_proc->exit, NULL); + int i; + + for (i=0; iattrs & burm_int_ATTR) + hop_add_insel(hop, "lwz %H, %d(fp)", + hreg, current_proc->fp_to_rb + hreg->offset); + else if (hreg->attrs & burm_float_ATTR) + hop_add_insel(hop, "lfs %H, %d(fp)", + hreg, current_proc->fp_to_rb + hreg->offset); + } + + hop_add_insel(hop, "lwz r0, 4(fp)"); + hop_add_insel(hop, "mtspr lr, r0"); + hop_add_insel(hop, "lwz r0, 0(fp)"); /* load old fp */ + hop_add_insel(hop, "addi sp, fp, %d", current_proc->fp_to_ab); + hop_add_insel(hop, "mr fp, r0"); + hop_add_insel(hop, "bclr 20, 0, 0"); + + return hop; +} + +struct hop* platform_move(struct basicblock* bb, struct hreg* src, struct hreg* dest) +{ + struct hop* hop = new_hop(bb, NULL); + + if ((src->attrs & TYPE_ATTRS) != (dest->attrs & TYPE_ATTRS)) + { + assert(!src->is_stacked); + assert(!dest->is_stacked); + + switch (src->attrs & TYPE_ATTRS) + { + case burm_int_ATTR: + hop_add_insel(hop, "stwu %H, -4(sp)", src); + break; + + case burm_long_ATTR: + hop_add_insel(hop, "stwu %0H, -4(sp)", src); + hop_add_insel(hop, "stwu %1H, -4(sp)", src); + break; + + case burm_float_ATTR: + hop_add_insel(hop, "stfsu %H, -4(sp)", src); + break; + + case burm_double_ATTR: + hop_add_insel(hop, "stfdu %H, -8(sp)", src); + break; + + default: + goto nomove; + } + + switch (dest->attrs & TYPE_ATTRS) + { + case burm_int_ATTR: + hop_add_insel(hop, "lwz %H, 0(sp)", dest); + break; + + case burm_long_ATTR: + hop_add_insel(hop, "lwz %0H, 4(sp)", dest); + hop_add_insel(hop, "lwz %1H, 0(sp)", dest); + break; + + case burm_float_ATTR: + hop_add_insel(hop, "lfs %H, 0(sp)", dest); + break; + + case burm_double_ATTR: + hop_add_insel(hop, "lfd %H, 0(sp)", dest); + break; + + default: + goto nomove; + } + + switch (dest->attrs & TYPE_ATTRS) + { + case burm_int_ATTR: + case burm_float_ATTR: + hop_add_insel(hop, "addi sp, sp, 4"); + break; + + case burm_double_ATTR: + case burm_long_ATTR: + hop_add_insel(hop, "addi sp, sp, 8"); + break; + + default: + goto nomove; + } + } + else + { + uint32_t type = src->attrs & TYPE_ATTRS; + + if (!src->is_stacked && dest->is_stacked) + { + switch (type) + { + case burm_int_ATTR: + hop_add_insel(hop, "stw %H, %S(fp) ! %H", src, dest, dest); + break; + + case burm_float_ATTR: + hop_add_insel(hop, "stfs %H, %S(fp) ! %H", src, dest, dest); + break; + + case burm_long_ATTR: + hop_add_insel(hop, "stw %0H, 4+%S(fp) ! %H", src, dest, dest); + hop_add_insel(hop, "stw %1H, 0+%S(fp) ! %H", src, dest, dest); + break; + + case burm_double_ATTR: + hop_add_insel(hop, "stfd %H, %S(fp) ! %H", src, dest, dest); + break; + + default: + goto nomove; + } + } + else if (src->is_stacked && !dest->is_stacked) + { + switch (type) + { + case burm_int_ATTR: + hop_add_insel(hop, "lwz %H, %S(fp) ! %H", dest, src, src); + break; + + case burm_float_ATTR: + hop_add_insel(hop, "lfs %H, %S(fp) ! %H", dest, src, src); + break; + + case burm_double_ATTR: + hop_add_insel(hop, "lfd %H, %S(fp) ! %H", dest, src, src); + break; + + default: + goto nomove; + } + } + else if (!src->is_stacked && !dest->is_stacked) + { + switch (type) + { + case burm_int_ATTR: + hop_add_insel(hop, "mr %H, %H", dest, src); + break; + + case burm_long_ATTR: + hop_add_insel(hop, "mr %0H, %0H", dest, src); + hop_add_insel(hop, "mr %1H, %1H", dest, src); + break; + + case burm_float_ATTR: + case burm_double_ATTR: + hop_add_insel(hop, "fmr %H, %H", dest, src); + break; + + default: + goto nomove; + } + } + else + goto nomove; + } + + return hop; + +nomove: + fatal("cannot move %s to %s", src->id, dest->id); +} + +struct hop* platform_swap(struct basicblock* bb, struct hreg* src, struct hreg* dest) +{ + struct hop* hop = new_hop(bb, NULL); + + assert(!src->is_stacked); + assert(!dest->is_stacked); + assert((src->attrs & TYPE_ATTRS) == (dest->attrs & TYPE_ATTRS)); + + switch (src->attrs & TYPE_ATTRS) + { + case burm_int_ATTR: + hop_add_insel(hop, "mr r0, %H", src); + hop_add_insel(hop, "mr %H, %H", src, dest); + hop_add_insel(hop, "mr %H, r0", dest); + break; + + case burm_long_ATTR: + hop_add_insel(hop, "mr r0, %0H", src); + hop_add_insel(hop, "mr %0H, %0H", src, dest); + hop_add_insel(hop, "mr %0H, r0", dest); + + hop_add_insel(hop, "mr r0, %1H", src); + hop_add_insel(hop, "mr %1H, %1H", src, dest); + hop_add_insel(hop, "mr %1H, r0", dest); + break; + + case burm_float_ATTR: + case burm_double_ATTR: + hop_add_insel(hop, "fmr f0, %H", src); + hop_add_insel(hop, "fmr %H, %H", src, dest); + hop_add_insel(hop, "fmr %H, f0", dest); + break; + } + + return hop; +} + +const char* platform_label(const char* label) +{ + /* Labels starting with . are internal, not exported, and don't need mangling. */ + + if (label[0] == '.') + return label; + + /* Otherwise, mangle. */ + + return aprintf("_%s", label); +} + +/* vim: set sw=4 ts=4 expandtab : */ + diff --git a/mach/powerpc/mcg/table b/mach/powerpc/mcg/table new file mode 100644 index 000000000..8511dbb5b --- /dev/null +++ b/mach/powerpc/mcg/table @@ -0,0 +1,794 @@ +REGISTERS + + /* Registers are allocated top down; the order here is odd in order to make + * sure that non-volatile registers get allocated from r31 (or f31) down. + * + * Attributes may have at most one of: int, float, long, double. These + * indicate that the register is used to store a value of that type. If + * your register can store more than one type, create an alias. Registers + * with none of these cannot be copied by the code generator (and so cannot + * be moved from register to register or spilt). + */ + + r12 int volatile; + r11 int volatile; + r10 int volatile; + r9 int volatile; + r8 int volatile; + r7 int volatile; + r6 int volatile; + r5 int volatile; + r4 int volatile; + r3 int volatile iret; + + r31 int; + r30 int; + r29 int; + r28 int; + r27 int; + r26 int; + r25 int; + r24 int; + r23 int; + r22 int; + r21 int; + r20 int; + r19 int; + r18 int; + r17 int; + r16 int; + r15 int; + r14 int; + r13 int; + + r11r12 named("r11", "r12") aliases(r11, r12) long volatile; + r9r10 named("r9", "r10") aliases(r9, r10) long volatile; + r7r8 named("r7", "r8") aliases(r7, r8) long volatile; + r5r6 named("r5", "r6") aliases(r6, r6) long volatile; + r3r4 named("r3", "r4") aliases(r3, r4) long volatile lret; + + r29r30 named("r29", "r30") aliases(r29, r30) long; + r27r28 named("r27", "r28") aliases(r27, r28) long; + r25r26 named("r25", "r26") aliases(r25, r26) long; + r23r24 named("r23", "r24") aliases(r23, r24) long; + r21r22 named("r21", "r22") aliases(r21, r22) long; + r19r20 named("r19", "r20") aliases(r19, r20) long; + r17r18 named("r17", "r18") aliases(r17, r18) long; + r15r16 named("r15", "r16") aliases(r15, r16) long; + r13r14 named("r13", "r14") aliases(r13, r14) long; + + f14 float volatile; + f13 float volatile; + f12 float volatile; + f11 float volatile; + f10 float volatile; + f9 float volatile; + f8 float volatile; + f7 float volatile; + f6 float volatile; + f5 float volatile; + f4 float volatile; + f3 float volatile fret; + f2 float volatile; + f1 float volatile; + f0 float volatile; + + f31 float; + f30 float; + f29 float; + f28 float; + f27 float; + f26 float; + f25 float; + f24 float; + f23 float; + f22 float; + f21 float; + f20 float; + f19 float; + f18 float; + f17 float; + f16 float; + f15 float; + + d14 named("f14") aliases(f14) double volatile; + d13 named("f13") aliases(f13) double volatile; + d12 named("f12") aliases(f12) double volatile; + d11 named("f11") aliases(f11) double volatile; + d10 named("f10") aliases(f10) double volatile; + d9 named("f9") aliases(f9) double volatile; + d8 named("f8") aliases(f8) double volatile; + d7 named("f7") aliases(f7) double volatile; + d6 named("f6") aliases(f6) double volatile; + d5 named("f5") aliases(f5) double volatile; + d4 named("f4") aliases(f4) double volatile; + d3 named("f3") aliases(f3) double volatile dret; + d2 named("f2") aliases(f2) double volatile; + d1 named("f1") aliases(f1) double volatile; + d0 named("f0") aliases(f0) double volatile; + + d31 named("f31") aliases(f31) double; + d30 named("f30") aliases(f30) double; + d29 named("f29") aliases(f29) double; + d28 named("f28") aliases(f28) double; + d27 named("f27") aliases(f27) double; + d26 named("f26") aliases(f26) double; + d25 named("f25") aliases(f25) double; + d24 named("f24") aliases(f24) double; + d23 named("f23") aliases(f23) double; + d22 named("f22") aliases(f22) double; + d21 named("f21") aliases(f21) double; + d20 named("f20") aliases(f20) double; + d19 named("f19") aliases(f19) double; + d18 named("f18") aliases(f18) double; + d17 named("f17") aliases(f17) double; + d16 named("f16") aliases(f16) double; + d15 named("f15") aliases(f15) double; + + cr0 cr; + + + +DECLARATIONS + + cr; + ubyteX; /* bottom 8 bits valid, the rest undefined */ + ubyte0; /* bottom 8 bits valid, the rest 0 */ + ushortX; /* bottom 16 bits valid, the rest undefined */ + ushort0; /* bottom 16 bits valid, the rest 0 */ + + address fragment; + + + +PATTERNS + +/* Special */ + + PAIR(BLOCK.I, BLOCK.I); + + + +/* Miscellaneous special things */ + + PUSH.I(in:(int)reg) + emit "stwu %in, -4(sp)" + cost 4; + + PUSH.L(in:(long)reg) + emit "stwu %in.0, -4(sp)" + emit "stwu %in.1, -4(sp)" + cost 8; + + PUSH.D(in:(double)reg) + emit "stfdu %in, -8(sp)" + cost 4; + + out:(int)reg = POP.I + emit "lwz %out, 0(sp)" + emit "addi sp, sp, 4" + cost 8; + + out:(long)reg = POP.L + emit "lwz %out.0, 4(sp)" + emit "lwz %out.1, 0(sp)" + emit "addi sp, sp, 8" + cost 12; + + out:(float)reg = POP.F + emit "lfs %out, 0(sp)" + emit "addi sp, sp, 4" + cost 8; + + out:(double)reg = POP.D + emit "lfd %out, 0(sp)" + emit "addi sp, sp, 8" + cost 8; + + SETRET.I(in:(iret)reg) + emit "! setret4" + cost 1; + + SETRET.L(in:(lret)reg) + emit "! setret8" + cost 1; + + STACKADJUST.I(delta:CONST.I) + when signed_constant(%delta, 16) + emit "addi sp, sp, $delta" + cost 4; + + STACKADJUST.I(in:(int)reg) + emit "add sp, sp, %in" + cost 4; + + STACKADJUST.I(NEG.I(in:(int)reg)) + emit "subf sp, %in, sp" + cost 4; + + out:(int)reg = GETFP.I + emit "mr %out, fp" + cost 4; + + SETFP.I(in:(int)reg) + emit "mr fp, %in" + cost 4; + + out:(int)reg = CHAINFP.I(in:(int)reg) + emit "lwz %out, 0(%in)" + cost 4; + + out:(int)reg = FPTOAB.I(GETFP.I) + emit "addi %out, fp, 8" + cost 4; + + out:(int)reg = FPTOAB.I(in:(int)reg) + emit "addi %out, %in, 8" + cost 4; + + out:(int)reg = FPTOLB.I(in:(int)reg) + with %out == %in + cost 1; + + out:(int)reg = GETSP.I + emit "mr %out, sp" + cost 4; + + SETSP.I(in:(int)reg) + emit "mr sp, %in" + cost 4; + + out:(int)reg = ANY.I + cost 1; + + out:(int)reg = COPYF.I(in:(float)reg) + emit "stfsu %in, -4(sp)" + emit "lwz %out, 0(sp)" + emit "addi sp, sp, 4" + cost 12; + + out:(double)reg = COPYL.D(in:(long)reg) + emit "stwu %in.0, -4(sp)" + emit "stwu %in.1, -4(sp)" + emit "lfd %out, 0(sp)" + emit "addi sp, sp, 8" + cost 16; + + out:(long)reg = COPYD.L(in:(double)reg) + emit "stfdu %in, -8(sp)" + emit "lwz %out.0, 4(sp)" + emit "lwz %out.1, 0(sp)" + emit "addi sp, sp, 8" + cost 16; + + + +/* Memory operations */ + + /* Stores */ + + STORE.D(addr:address, value:(double)reg) + emit "stfd %value, %addr" + cost 4; + + STORE.L(addr:address, value:(long)reg) + emit "stw %value.0, 4+%addr" + emit "stw %value.1, 0+%addr" + cost 8; + + STORE.I(addr:address, value:(int)reg) + emit "stw %value, %addr" + cost 4; + + STOREH.I(addr:address, value:(int)ushortX) + emit "sth %value, %addr" + cost 4; + + STOREH.I(ADD.I(left:(int)reg, right:(int)reg), value:(int)ushortX) + emit "sthx %value, %left, %right" + cost 4; + + STOREB.I(addr:address, value:(int)ushortX) + emit "sth %value, %addr" + cost 4; + + STOREB.I(addr:address, value:(int)ubyteX) + emit "stb %value, %addr" + cost 4; + + STOREB.I(ADD.I(left:(int)reg, right:(int)reg), value:(int)ubyteX) + emit "stbx %value, %left, %right" + cost 4; + + /* Loads */ + + out:(int)reg = LOAD.I(addr:address) + emit "lwz %out, %addr" + cost 4; + + out:(long)reg = LOAD.L(addr:address) + emit "lwz %out.0, 4+%addr" + emit "lwz %out.1, 0+%addr" + cost 8; + + out:(int)ushort0 = LOADH.I(addr:address) + emit "lhz %out, %addr" + cost 4; + + out:(int)ubyte0 = LOADB.I(addr:address) + emit "lbz %out, %addr" + cost 4; + + /* ubyte intrinsics */ + + out:(int)ubyteX = in:(int)ubyte0 + with %out == %in + emit "! ubyte0 -> ubyteX" + cost 1; + + out:(int)ubyte0 = in:(int)ubyteX + emit "andi %out, %in, 0xff ! ubyteX -> ubyte0" + cost 4; + + out:(int)reg = in:(int)ubyte0 + with %out == %in + emit "! ubyte0 -> reg" + cost 4; + + out:(int)ubyteX = in:(int)reg + with %out == %in + emit "! reg -> ubyteX" + cost 1; + + /* ushort intrinsics */ + + out:(int)ushortX = in:(int)ushort0 + with %out == %in + emit "! ushort0 -> ushortX" + cost 1; + + out:(int)ushort0 = in:(int)ushortX + emit "andi %out, %in, 0xff ! ushortX -> ushort0" + cost 4; + + out:(int)reg = in:(int)ushort0 + with %out == %in + emit "! ushort0 -> reg" + cost 4; + + out:(int)ushortX = in:(int)reg + with %out == %in + emit "! reg -> ushortX" + cost 1; + + +/* Extensions and conversions */ + + out:(int)reg = EXTENDB.I(in:(int)reg) + emit "extsb %out, %in" + cost 4; + + out:(int)reg = EXTENDH.I(in:(int)reg) + emit "extsh %out, %in" + cost 4; + + out:(int)reg = FROMSI.I(in:(int)reg) + with %out == %in + emit "! FROMSI.I(int) -> int" + cost 1; + + out:(int)reg = FROMUI.I(in:(int)reg) + with %out == %in + emit "! FROMUI.I(int) -> int" + cost 1; + + out:(long)reg = FROMSI.L(in:(int)reg) + emit "mr %out.0, %in" + emit "srawi %out.1, %out.0, 31" + cost 8; + + out:(long)reg = FROMUI.L(in:(int)reg) + emit "mr %out.0, %in" + emit "li32 %out.1, 0" + cost 8; + + out:(iret)reg = FROMSF.I(in:(dret)reg) + with corrupted(volatile) + emit "bl .fromf2i" + cost 4; + + out:(int)reg = FROMSD.I(in:(double)reg) + with preserved(%in) + emit "fctiwz %in, %in" + emit "stfdu %in, -8(sp)" + emit "lwz %out, 4(sp)" + emit "addi sp, sp, 8" + cost 16; + + out:(int)reg = FROMUD.I(in:(double)reg) + with corrupted(volatile) + emit "stfdu %in, -8(sp)" + emit "bl .cfu8" + emit "lwz %out, 0(sp)" + emit "addi sp, sp, 4" + cost 16; + + out:(lret)reg = FROMSF.L(in:(fret)reg) + with corrupted(volatile) + emit "bl .fromf2l" + cost 4; + + out:(lret)reg = FROMUF.I(in:(fret)reg) + with corrupted(volatile) + emit "bl .fromf2l" + cost 4; + + out:(double)reg = FROMSI.D(in:(int)reg) + with corrupted(volatile) + emit "stwu %in, -4(sp)" + emit "bl .cif8" + emit "lfd %out, 0(sp)" + emit "addi sp, sp, 8" + cost 4; + + out:(fret)reg = FROMUI.F(in:(iret)reg) + with corrupted(volatile) + emit "bl .fromui2f" + cost 4; + + out:(double)reg = FROMUI.D(in:(int)reg) + with corrupted(volatile) + emit "stwu %in, -4(sp)" + emit "bl .cuf8" + emit "lfd %out, 0(sp)" + emit "addi sp, sp, 8" + cost 4; + + out:(lret)reg = FROMIPAIR.L(in1:(int)reg, in2:(int)reg) + emit "mr %out.0, %in1" + emit "mr %out.1, %in2" + cost 8; + + out:(int)reg = FROML0.I(in:(long)reg) + emit "mr %out, %in.0" + cost 4; + + out:(int)reg = FROML1.I(in:(long)reg) + emit "mr %out, %in.1" + cost 4; + + + +/* Locals */ + + out:(int)reg = in:LOCAL.I + emit "addi %out, fp, $in" + cost 4; + + address = in:LOCAL.I + emit "$in(fp)"; + + + + +/* Memory addressing modes */ + + address = ADD.I(addr:(int)reg, offset:CONST.I) + when signed_constant(%offset, 16) + emit "$offset(%addr)"; + + address = addr:(int)reg + emit "0(%addr)"; + + + +/* Branches */ + + JUMP(addr:BLOCK.I) + emit "b $addr" + cost 4; + + FARJUMP(addr:LABEL.I) + with corrupted(volatile) + emit "b $addr" + cost 4; + + JUMP(dest:(int)reg) + emit "mtspr ctr, %dest" + emit "bcctrl 20, 0, 0" + cost 8; + + CJUMPEQ(value:(cr)cr, PAIR(true:BLOCK.I, false:BLOCK.I)) + emit "bc 12, 2, $true" /* IFTRUE EQ */ + emit "b $false" + cost 8; + + CJUMPLE(value:(cr)cr, PAIR(true:BLOCK.I, false:BLOCK.I)) + emit "bc 4, 1, $true" /* IFFALSE GT */ + emit "b $false" + cost 8; + + CJUMPLT(value:(cr)cr, PAIR(true:BLOCK.I, false:BLOCK.I)) + emit "bc 12, 0, $true" /* IFTRUE LT */ + emit "b $false" + cost 8; + + #define CALLLABEL(insn) \ + insn (dest:LABEL.I) \ + with corrupted(volatile) \ + emit "bl $dest" \ + cost 4; + + CALLLABEL(CALL) + out:(iret)reg = CALLLABEL(CALL.I) + out:(lret)reg = CALLLABEL(CALL.L) + + #define CALLINDIRECT(insn) \ + insn (dest:(int)reg) \ + with corrupted(volatile) \ + emit "mtspr ctr, %dest" \ + emit "bcctrl 20, 0, 0" \ + cost 8; + + CALLINDIRECT(CALL) + out:(iret)reg = CALLINDIRECT(CALL.I) + out:(lret)reg = CALLINDIRECT(CALL.L) + + JUMP(dest:LABEL.I) + emit "b $dest" + cost 4; + + + +/* Comparisons */ + + cr:(cr)cr = COMPARESI.I(left:(int)reg, right:(int)reg) + emit "cmp %cr, 0, %left, %right" + cost 4; + + cr:(cr)cr = COMPARESI.I(left:(int)reg, right:CONST.I) + when signed_constant(%right, 16) + emit "cmpi %cr, 0, %left, $right" + cost 4; + + cr:(cr)cr = COMPAREUI.I(left:(int)reg, right:(int)reg) + emit "cmpl %cr, 0, %left, %right" + cost 4; + + cr:(cr)cr = COMPAREUI.I(left:(int)reg, right:CONST.I) + when signed_constant(%right, 16) + emit "cmpli %cr, 0, %left, $right" + cost 4; + + out:(cr)cr = COMPARESI.I(in:(cr)cr, result:CONST.I) + when specific_constant(%result, 0) + with %out == %in + emit "! COMPARESI.I(cr, 0)" + cost 4; + + + +/* Booleans */ + + out:(int)reg = IFEQ.I(in:(cr)cr) + emit "mfcr %out" /* get cr0 */ + emit "rlwinm %out, %out, [32-2], 2, 31" /* extract just EQ */ + cost 8; + + out:(int)reg = IFEQ.I(in:(int)reg) + emit "cntlzw %out, %in" /* returns 0..32 */ + emit "rlwinm %out, %out, [32-5], 5, 31" /* if 32, return 1, otherwise 0 */ + cost 8; + + out:(int)reg = IFLT.I(in:(cr)cr) + emit "mfcr %out" /* get cr0 */ + emit "andi. %out, %out, 1" /* leave just LT */ + cost 8; + + out:(int)reg = IFLE.I(in:(cr)cr) + emit "mfcr %out" /* get cr0 */ + emit "andi. %out, %out, 5" /* leave just LT and EQ */ + emit "cntlzw %out, %out" /* returns 0..32 */ + emit "rlwinm %out, %out, [32-5], 5, 31" /* if 32, return 1, otherwise 0 */ + emit "xori %out, %out, 1" /* negate */ + cost 8; + + + +/* Conversions */ + +#if 0 + out:(int)reg = CIU44(in:(int)reg) + with %out == %in + emit "! ciu44" + cost 4; + + out:(int)reg = CUI44(in:(int)reg) + with %out == %in + emit "! cui44" + cost 4; +#endif + +/* ALU operations */ + + #define ALUR(name, instr) \ + out:(int)reg = name(left:(int)reg, right:(int)reg) \ + emit instr " %out, %left, %right" \ + cost 4; \ + + #define ALUC(name, instr) \ + out:(int)reg = name(left:(int)reg, right:CONST.I) \ + when signed_constant(%right, 16) \ + emit instr " %out, %left, $right" \ + cost 4; \ + + #define ALUC_reversed(name, instr) \ + out:(int)reg = name(left:CONST.I, right:(int)reg) \ + when signed_constant(%left, 16) \ + emit instr " %out, %right, $left" \ + cost 4; \ + + #define ALUCC(name, instr) \ + ALUC(name, instr) \ + ALUC_reversed(name, instr) + + ALUR(ADD.I, "add") + ALUCC(ADD.I, "addi") + + out:(int)reg = SUB.I(left:(int)reg, right:(int)reg) + emit "subf %out, %right, %left" + cost 4; + + out:(int)reg = SUB.I(left:(int)reg, right:CONST.I) + emit "addi %out, %left, -[$right]" + cost 4; + + out:(int)reg = MOD.I(left:(int)reg, right:(int)reg) + with preserved(%left), preserved(%right) + emit "divw %out, %left, %right" + emit "mullw %out, %out, %right" + emit "subf %out, %out, %left" + cost 12; + + out:(int)reg = MODU.I(left:(int)reg, right:(int)reg) + with preserved(%left), preserved(%right) + emit "divwu %out, %left, %right" + emit "mullw %out, %out, %right" + emit "subf %out, %out, %left" + cost 12; + + ALUR(MUL.I, "mullw") + ALUCC(MUL.I, "mulli") + + ALUR(DIV.I, "divw") + ALUR(DIVU.I, "divwu") + + ALUR(ASL.I, "slw") + ALUR(ASR.I, "sraw") + + ALUR(LSL.I, "slw") + ALUR(LSR.I, "srw") + + out:(int)reg = NEG.I(left:(int)reg) + emit "neg %out, %left" + cost 4; + + out:(int)reg = NOT.I(left:(int)reg) + emit "cntlzw %out, %left" + emit "rlwinm %out, %out, 32-5, 5, 31" + cost 8; + + ALUR(AND.I, "and") + ALUCC(AND.I, "andi.") + + ALUR(OR.I, "or") + ALUCC(OR.I, "ori") + + ALUR(EOR.I, "xor") + ALUCC(EOR.I, "xori") + + out:(int)reg = value:LABEL.I + emit "li32 %out, $value" + cost 4; + + out:(int)reg = value:BLOCK.I + emit "li32 %out, $value" + cost 4; + + out:(int)reg = value:CONST.I + emit "li32 %out, $value" + cost 8; + + +/* FPU operations */ + + #define FPU4R(name, instr) \ + out:(float)reg = name(left:(float)reg, right:(float)reg) \ + emit instr " %out, %left, %right" \ + cost 4; \ + + #define FPU8R(name, instr) \ + out:(double)reg = name(left:(double)reg, right:(double)reg) \ + emit instr " %out, %left, %right" \ + cost 4; \ + + out:(float)reg = LOAD.F(addr:address) + emit "lfs %out, %addr" + cost 4; + + out:(double)reg = LOAD.D(addr:address) + emit "lfd %out, %addr" + cost 4; + + out:(float)reg = in:CONST.F + when specific_constant(%in, 0) + emit "li32 r0, .fd_00000000" + emit "lfs %out, 0(r0)" + cost 12; + + FPU4R(ADDF.F, "fadds") + FPU8R(ADDF.D, "fadd") + + FPU4R(SUBF.F, "fsubs") + FPU8R(SUBF.D, "fsub") + + FPU4R(MULF.F, "fmuls") + FPU8R(MULF.D, "fmul") + + FPU4R(DIVF.F, "fdivs") + FPU8R(DIVF.D, "fdiv") + + #define FMALEFT(type, insn, add, mul) \ + out:(type)reg = add(mul(m1:(type)reg, m2:(type)reg), m3:(type)reg) \ + emit insn " %out, %m1, %m2, %m3" \ + cost 4; \ + + #define FMARIGHT(type, insn, add, mul) \ + out:(type)reg = add(m3:(type)reg, mul(m1:(type)reg, m2:(type)reg)) \ + emit insn " %out, %m1, %m2, %m3" \ + cost 4; \ + + FMALEFT( double, "fmadd", ADDF.D, MULF.D) + FMARIGHT(double, "fmadd", ADDF.D, MULF.D) + FMALEFT( float, "fmadds", ADDF.F, MULF.F) + FMARIGHT(float, "fmadds", ADDF.F, MULF.F) + + FMALEFT( double, "fmsub", SUBF.D, MULF.D) + FMALEFT( float, "fmsubs", SUBF.F, MULF.F) + + FMARIGHT(double, "fnmadd", SUBF.D, MULF.D) + FMARIGHT(float, "fnmadds", SUBF.F, MULF.F) + + #define FMANEGLEFT(type, insn, neg, add, mul) \ + out:(type)reg = neg(add(mul(m1:(type)reg, m2:(type)reg), m3:(type)reg)) \ + emit insn " %out, %m1, %m2, %m3" \ + cost 4; \ + + #define FMANEGRIGHT(type, insn, neg, add, mul) \ + out:(type)reg = neg(add(m3:(type)reg, mul(m1:(type)reg, m2:(type)reg))) \ + emit insn " %out, %m1, %m2, %m3" \ + cost 4; \ + + FMANEGLEFT( double, "fnmsub", NEGF.D, ADDF.D, MULF.D) + FMANEGRIGHT(double, "fnmsub", NEGF.D, ADDF.D, MULF.D) + FMANEGLEFT( float, "fnmsub", NEGF.F, ADDF.F, MULF.F) + FMANEGRIGHT(float, "fnmsub", NEGF.F, ADDF.F, MULF.F) + + out:(float)reg = NEGF.F(left:(float)reg) + emit "fneg %out, %left" + cost 4; + + out:(double)reg = NEGF.D(left:(double)reg) + emit "fneg %out, %left" + cost 4; + + cr:(cr)cr = COMPAREF.I(left:(float)reg, right:(float)reg) + emit "fcmpu %cr, %left, %right" + cost 4; + + cr:(cr)cr = COMPARED.I(left:(double)reg, right:(double)reg) + emit "fcmpu %cr, %left, %right" + cost 4; + +/* vim: set sw=4 ts=4 expandtab : */ + diff --git a/mach/powerpc/ncg/mach.c b/mach/powerpc/ncg/mach.c index 39c6362e6..e4ab3c078 100644 --- a/mach/powerpc/ncg/mach.c +++ b/mach/powerpc/ncg/mach.c @@ -56,6 +56,7 @@ con_mult(word sz) #define FL_MSB_AT_LOW_ADDRESS 1 #include +void prolog(full nlocals) { int ss = nlocals + 8; @@ -68,6 +69,7 @@ prolog(full nlocals) framesize = nlocals; } +void mes(word type) { int argt ; diff --git a/mach/powerpc/ncg/table b/mach/powerpc/ncg/table index ed107aceb..77fdaedf1 100644 --- a/mach/powerpc/ncg/table +++ b/mach/powerpc/ncg/table @@ -328,6 +328,7 @@ INSTRUCTIONS lhax GPR:wo, GPR:ro, GPR:ro cost(4, 3). lhz GPR:wo, GPRINDIRECT:ro cost(4, 3). lhzx GPR:wo, GPR:ro, GPR:ro cost(4, 3). + li32 GPR:wo, CONST:ro cost(8, 2). li32 GPR:wo, LABEL:ro cost(8, 2). lwzu GPR:wo, GPRINDIRECT:ro cost(4, 3). lwzx GPR:wo, GPR:ro, GPR:ro cost(4, 3). @@ -1637,14 +1638,13 @@ PATTERNS gen bl {LABEL, ".set"} - pat inn defined($1) /* Test for set bit */ - leaving - set INT32 - and INT32 - - pat inn !defined($1) /* Test for set bit (variable) */ - with GPR3 STACK + pat inn /* Test for set bit */ + with STACK + kills ALL + uses REG gen + li32 %a, {CONST, $1} + stwu %a, {GPRINDIRECT, SP, 0-4} bl {LABEL, ".inn"} @@ -1898,12 +1898,12 @@ PATTERNS addi SP, SP, {CONST, 12} pat csa /* Array-lookup switch */ - with GPR3 GPR4 STACK + with STACK gen b {LABEL, ".csa"} pat csb /* Table-lookup switch */ - with GPR3 GPR4 STACK + with STACK gen b {LABEL, ".csb"} diff --git a/mach/powerpc/top/table b/mach/powerpc/top/table index e735afee6..acbe543a7 100644 --- a/mach/powerpc/top/table +++ b/mach/powerpc/top/table @@ -1,7 +1,8 @@ -/* 68020 desciptor table for ACK target optimizer */ +/* PowerPC desciptor table for ACK target optimizer */ MAXOP 3; +LABEL_STARTER '.'; %%; @@ -15,6 +16,14 @@ X, Y, Z { TRUE }; addi X, X, 0 -> ; addis X, X, 0 -> ; +mr X, X -> ; +fmr X, X -> ; + or X, Y, Z : or. X, X, X -> or. X, Y, Z ; +b X : labdef X -> labdef X ; + +/* IFFALSE=4, IFTRUE=12, ALWAYS=20 */ +/* LT=0, GT=1, EQ=2, OV=3 */ + %%; diff --git a/mach/proto/as/comm0.h b/mach/proto/as/comm0.h index 4996350ac..dedafa4c7 100644 --- a/mach/proto/as/comm0.h +++ b/mach/proto/as/comm0.h @@ -8,6 +8,8 @@ * All preprocessor based options/constants/functions */ +#include + /* ========== ON/OFF options (use #define in mach0.c) ========== */ /* diff --git a/mach/proto/as/comm4.c b/mach/proto/as/comm4.c index 9adff1ebf..473cb12e2 100644 --- a/mach/proto/as/comm4.c +++ b/mach/proto/as/comm4.c @@ -18,6 +18,9 @@ extern YYSTYPE yylval; +void setupoutput(); +void commfinish(); + /* ========== Machine independent C routines ========== */ void stop() { @@ -458,6 +461,7 @@ char *s; #endif } +void setupoutput() { register sect_t *sp; @@ -493,6 +497,7 @@ setupoutput() outhead.oh_nchar = off; /* see newsymb() */ } +void commfinish() { #ifndef ASLD diff --git a/mach/proto/as/comm5.c b/mach/proto/as/comm5.c index 276cc2f0c..7dee7c1a9 100644 --- a/mach/proto/as/comm5.c +++ b/mach/proto/as/comm5.c @@ -11,6 +11,8 @@ extern YYSTYPE yylval; +void putval(); + yylex() { register c; @@ -68,6 +70,7 @@ yylex() return(c); } +void putval(c) { register valu_t v; diff --git a/mach/proto/as/comm6.c b/mach/proto/as/comm6.c index f5bd87f39..9cb943cba 100644 --- a/mach/proto/as/comm6.c +++ b/mach/proto/as/comm6.c @@ -12,6 +12,10 @@ #include "comm1.h" #include "y.tab.h" +void switchsect(); +void newsymb(); +void newident(); + newequate(ip, typ) register item_t *ip; register int typ; @@ -34,6 +38,7 @@ register int typ; newident(ip, typ); } +void newident(ip, typ) register item_t *ip; { @@ -74,6 +79,7 @@ register item_t *ip; ); } +void newlabel(ip) register item_t *ip; { @@ -183,6 +189,7 @@ valu_t val; } } +void switchsect(newtyp) int newtyp; { @@ -242,6 +249,7 @@ valu_t bytes; } #ifdef RELOCATION +void newrelo(s, n) { int iscomm; @@ -326,6 +334,7 @@ new_string(s) return r; } +void newsymb(name, type, desc, valu) register char *name; valu_t valu; diff --git a/mach/proto/mcg/basicblock.c b/mach/proto/mcg/basicblock.c new file mode 100644 index 000000000..aa0a729e0 --- /dev/null +++ b/mach/proto/mcg/basicblock.c @@ -0,0 +1,42 @@ +#include "mcg.h" + +static void init_idf(); +static struct idf* str2idf(char* tg, int cp); + +#define IDF_TYPE struct basicblock* +#define IDF_NAME block +#include +#include + +static int next_id = 0; + +void bb_init(void) +{ + init_idf(); +} + +struct basicblock* bb_get(const char* name) +{ + struct idf* p; + + if (!name) + name = aprintf(".anon_bb_%d", next_id++); + p = str2idf((char*) name, 0); + if (!p->block) + { + p->block = calloc(1, sizeof(*p->block)); + p->block->name = name; + } + return p->block; +} + +void bb_alias(struct basicblock* block, const char* name) +{ + struct idf* p = str2idf((char*) name, -1); + assert(p == NULL); + + p = str2idf((char*) name, 0); + p->block = block; +} + +/* vim: set sw=4 ts=4 expandtab : */ diff --git a/mach/proto/mcg/basicblock.h b/mach/proto/mcg/basicblock.h new file mode 100644 index 000000000..362a05f7f --- /dev/null +++ b/mach/proto/mcg/basicblock.h @@ -0,0 +1,43 @@ +#ifndef BASICBLOCK_H +#define BASICBLOCK_H + +struct phi +{ + struct basicblock* prev; /* Predecessor that this phi is referring to */ + struct ir* ir; /* IR of variable definition */ +}; + +struct basicblock +{ + const char* name; + ARRAYOF(struct em) ems; + ARRAYOF(struct ir) irs; + ARRAYOF(struct hop) hops; + + ARRAYOF(struct basicblock) prevs; + ARRAYOF(struct basicblock) nexts; + int order; /* used by dominance graph code */ + + PMAPOF(struct vreg, struct phi) phis; + + /* Used by liveness calculation. */ + ARRAYOF(struct vreg) liveins; + ARRAYOF(struct vreg) liveouts; + + /* Register assignments on entry and exit. */ + register_assignment_t regsin; + register_assignment_t* regsout; /* points at regsout of the last insn. */ + + bool is_fake : 1; + bool is_root : 1; + bool is_terminated : 1; +}; + +extern void bb_init(void); +extern struct basicblock* bb_get(const char* name); +extern void bb_alias(struct basicblock* block, const char* name); + +#endif + +/* vim: set sw=4 ts=4 expandtab : */ + diff --git a/mach/proto/mcg/build.lua b/mach/proto/mcg/build.lua new file mode 100644 index 000000000..387d14d26 --- /dev/null +++ b/mach/proto/mcg/build.lua @@ -0,0 +1,51 @@ +include("util/mcgg/build.lua") + +definerule("build_mcg", + { + arch = { type="string" } + }, + function(e) + -- Remember this is executed from the caller's directory; local + -- target names will resolve there + local headers = clibrary { + name = e.name.."/headers", + srcs = {}, + hdrs = { + "mach/proto/mcg/*.h", + "mach/"..e.arch.."/mcg/*.h", + } + } + + local tables = mcgg { + name = e.name.."/tables", + srcs = { "mach/"..e.arch.."/mcg/table" } + } + + return cprogram { + name = e.name, + srcs = { + "mach/proto/mcg/*.c", + "mach/"..e.arch.."/mcg/platform.c", + matching(filenamesof(tables), "%.c$") + }, + deps = { + "h+emheaders", + "modules+headers", + "modules/src/alloc+lib", + "modules/src/data+lib", + "modules/src/em_code+lib_k", + "modules/src/em_data+lib", + "modules/src/flt_arith+lib", + "modules/src/idf+lib", + "modules/src/object+lib", + "modules/src/read_em+lib_kv", + "modules/src/string+lib", + "modules/src/system+lib", + "util/mcgg+lib", + headers, + tables, -- for .h file + } + } + end +) + diff --git a/mach/proto/mcg/data.c b/mach/proto/mcg/data.c new file mode 100644 index 000000000..13352ed37 --- /dev/null +++ b/mach/proto/mcg/data.c @@ -0,0 +1,160 @@ +#include "mcg.h" +#include + +#define IEEEFLOAT +#define FL_MSL_AT_LOW_ADDRESS 1 +#define FL_MSW_AT_LOW_ADDRESS 1 +#define FL_MSB_AT_LOW_ADDRESS 1 + +#include "con_float" + +static struct symbol* pending; + +void data_label(const char* label) +{ + if (pending) + fatal("two consecutive data labels ('%s' and '%s')", + pending->name, label); + + pending = symbol_get(label); + if (pending->is_defined) + fatal("label '%s' defined twice", pending->name); + pending->is_defined = true; +} + +static const char* section_to_str(int section) +{ + switch (section) + { + case SECTION_ROM: return ".rom"; + case SECTION_DATA: return ".data"; + case SECTION_BSS: return ".bss"; + case SECTION_TEXT: return ".text"; + default: return "unknown"; + } +} + +static void emit_header(int desired_section) +{ + if (pending) + { + if (pending->section == SECTION_UNKNOWN) + pending->section = desired_section; + else if (pending->section != desired_section) + fatal("label '%s' can't change sections", pending->name); + + fprintf(outputfile, "\n.sect %s\n", section_to_str(pending->section)); + fprintf(outputfile, "%s:\n", platform_label(pending->name)); + pending = NULL; + } +} + +static void writehex(arith data, int size) +{ + if (data < 0) + fprintf(outputfile, "-0x%0*lx", size*2, -data); + else + fprintf(outputfile, "0x%0*lx", size*2, data); +} + +void data_int(arith data, size_t size, bool is_ro) +{ + emit_header(is_ro ? SECTION_ROM : SECTION_DATA); + assert((size == 1) || (size == 2) || (size == 4) || (size == 8)); + fprintf(outputfile, "\t.data%d ", size); + writehex(data, size); + fprintf(outputfile, "\n"); +} + + +void data_float(const char* data, size_t size, bool is_ro) +{ + unsigned char buffer[8]; + int i; + + emit_header(is_ro ? SECTION_ROM : SECTION_DATA); + assert((size == 4) || (size == 8)); + + i = float_cst(data, size, (char*) buffer); + if ((i != 0) && (i != 2)) /* 2 == overflow */ + fatal("cannot parse floating point constant %s sz %d", data, size); + + fprintf(outputfile, "\t!float %s sz %d\n", data, size); + fprintf(outputfile, "\t.data1 "); + writehex(buffer[0], 1); + for (i=1; iopcode == IR_BLOCK) + { + array_appendu(&caller->nexts, ir->u.bvalue); + array_appendu(&ir->u.bvalue->prevs, caller); + pmap_add(&cfg.graph, caller, ir->u.bvalue); + } + return false; +} + +static void update_block_pointers_from_ir(void) +{ + int i, j; + + for (i=0; iblocks.count; i++) + { + struct basicblock* bb = current_proc->blocks.item[i]; + bb->prevs.count = bb->nexts.count = 0; + } + + for (i=0; iblocks.count; i++) + { + struct basicblock* bb = current_proc->blocks.item[i]; + for (j=0; jirs.count; j++) + ir_walk(bb->irs.item[j], collect_outputs_cb, bb); + } + + for (i=0; iblocks.count; i++) + { + struct basicblock* bb = current_proc->blocks.item[i]; + + for (j=0; jnexts.count; j++) + { + tracef('D', "D: cfg graph %s -> %s\n", + bb->name, + bb->nexts.item[j]->name); + } + } +} + +static void recursively_walk_cfg_graph(struct basicblock* bb) +{ + int i; + + if (array_contains(&cfg.postorder, bb) || array_contains(&pending, bb)) + return; + + array_appendu(&cfg.preorder, bb); + array_appendu(&pending, bb); + + for (i=0; inexts.count; i++) + recursively_walk_cfg_graph(bb->nexts.item[i]); + + array_remove(&pending, bb); + bb->order = cfg.postorder.count; + array_appendu(&cfg.postorder, bb); +} + +static void walk_cfg_graph(void) +{ + int i; + + cfg.preorder.count = 0; + cfg.postorder.count = 0; + pending.count = 0; + recursively_walk_cfg_graph(cfg.entry); + + for (i=0; iname); + } +} + +static struct basicblock* intersect(struct basicblock* p1, struct basicblock* p2) +{ + while (p1 != p2) + { + while (p1->order < p2->order) + p1 = pmap_findleft(&dominance.graph, p1); + + while (p2->order < p1->order) + p2 = pmap_findleft(&dominance.graph, p2); + } + + return p1; +} + +static void calculate_dominance_graph(void) +{ + /* This is the algorithm described here: + * + * Cooper, Keith D., Timothy J. Harvey, and Ken Kennedy. + * "A simple, fast dominance algorithm." + * Software Practice & Experience 4.1-10 (2001): 1-8. + * + * https://www.cs.rice.edu/~keith/EMBED/dom.pdf + */ + + int i, j; + bool changed; + + dominance.graph.count = 0; + + /* The entry block dominates itself. */ + + pmap_put(&dominance.graph, cfg.entry, cfg.entry); + + do + { + changed = false; + + for (i = cfg.postorder.count-2; i >= 0; i--) + { + struct basicblock* b = cfg.postorder.item[i]; + struct basicblock* new_idom = NULL; + for (j=0; jprevs.count; j++) + { + struct basicblock* p = b->prevs.item[j]; + + /* Skip unprocessed blocks. */ + if (!pmap_findleft(&dominance.graph, p)) + continue; + + if (!new_idom) + new_idom = p; + else if (pmap_findleft(&dominance.graph, p)) + new_idom = intersect(p, new_idom); + } + + if (pmap_findleft(&dominance.graph, b) != new_idom) + { + pmap_put(&dominance.graph, b, new_idom); + changed = true; + } + } + } + while (changed); + + for (i=0; i %s\n", + dominance.graph.item[i].right->name, + dominance.graph.item[i].left->name); + } +} + +static void recursively_walk_dominance_graph(struct basicblock* bb) +{ + int i; + + if (array_contains(&dominance.postorder, bb) || array_contains(&pending, bb)) + return; + + array_appendu(&dominance.preorder, bb); + array_appendu(&pending, bb); + + for (i=0; iname); + } +} + +void update_graph_data(void) +{ + cfg.entry = current_proc->blocks.item[0]; + cfg.graph.count = 0; + update_block_pointers_from_ir(); + + walk_cfg_graph(); + assert(cfg.postorder.count == current_proc->blocks.count); + assert(cfg.preorder.count == current_proc->blocks.count); + + calculate_dominance_graph(); + + walk_dominance_graph(); + assert(dominance.postorder.count == dominance.graph.count); + assert(dominance.preorder.count == dominance.graph.count); +} + +/* vim: set sw=4 ts=4 expandtab : */ + diff --git a/mach/proto/mcg/graph.h b/mach/proto/mcg/graph.h new file mode 100644 index 000000000..ed8e8ba21 --- /dev/null +++ b/mach/proto/mcg/graph.h @@ -0,0 +1,27 @@ +#ifndef GRAPH_H +#define GRAPH_H + +struct graph_data +{ + struct basicblock* entry; + PMAPOF(struct basicblock, struct basicblock) graph; + ARRAYOF(struct basicblock) preorder; + ARRAYOF(struct basicblock) postorder; +}; + +struct dominance_data +{ + PMAPOF(struct basicblock, struct basicblock) graph; + ARRAYOF(struct basicblock) preorder; + ARRAYOF(struct basicblock) postorder; +}; + +extern struct graph_data cfg; +extern struct dominance_data dominance; + +extern void update_graph_data(void); + +#endif + +/* vim: set sw=4 ts=4 expandtab : */ + diff --git a/mach/proto/mcg/hop.c b/mach/proto/mcg/hop.c new file mode 100644 index 000000000..77c6dc260 --- /dev/null +++ b/mach/proto/mcg/hop.c @@ -0,0 +1,328 @@ +#include "mcg.h" + +static int hop_count = 1; +static struct hop* current_hop; +static char* buffer = NULL; +static int bufferlen = 0; +static int buffersize = 0; + +static const struct burm_emitter_data emitter_data; + +struct hop* new_hop(struct basicblock* bb, struct ir* ir) +{ + struct hop* hop = calloc(1, sizeof *hop); + hop->id = hop_count++; + hop->bb = bb; + hop->ir = ir; + return hop; +} + +static struct insel* new_insel(enum insel_type type) +{ + struct insel* insel = calloc(1, sizeof(*insel)); + insel->type = type; + return insel; +} + +void hop_add_string_insel(struct hop* hop, const char* string) +{ + struct insel* insel = new_insel(INSEL_STRING); + insel->u.string = string; + array_append(&hop->insels, insel); +} + +void hop_add_hreg_insel(struct hop* hop, struct hreg* hreg, int index) +{ + struct insel* insel = new_insel(INSEL_HREG); + insel->u.hreg = hreg; + insel->index = index; + array_append(&hop->insels, insel); +} + +void hop_add_vreg_insel(struct hop* hop, struct vreg* vreg, int index) +{ + struct insel* insel = new_insel(INSEL_VREG); + insel->u.vreg = vreg; + insel->index = index; + array_append(&hop->insels, insel); +} + +void hop_add_value_insel(struct hop* hop, struct ir* ir) +{ + struct insel* insel = new_insel(INSEL_VALUE); + insel->u.value = ir; + array_append(&hop->insels, insel); +} + +void hop_add_st_offset_insel(struct hop* hop, struct hreg* hreg) +{ + struct insel* insel = new_insel(INSEL_ST_OFFSET); + insel->u.hreg = hreg; + array_append(&hop->insels, insel); +} + +void hop_add_ab_offset_insel(struct hop* hop, int offset) +{ + struct insel* insel = new_insel(INSEL_AB_OFFSET); + insel->u.offset = offset; + array_append(&hop->insels, insel); +} + +void hop_add_lb_offset_insel(struct hop* hop, int offset) +{ + struct insel* insel = new_insel(INSEL_LB_OFFSET); + insel->u.offset = offset; + array_append(&hop->insels, insel); +} + +void hop_add_eoi_insel(struct hop* hop) +{ + struct insel* insel = new_insel(INSEL_EOI); + array_append(&hop->insels, insel); +} + +void hop_add_insel(struct hop* hop, const char* fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + + while (*fmt) + { + if (*fmt == '%') + { + int index = 0; + fmt += 2; + again: + switch (fmt[-1]) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + index = fmt[-1] - '0'; + fmt++; + goto again; + + case 'd': + hop_add_string_insel(hop, aprintf("%d", va_arg(ap, int))); + break; + + case 's': + hop_add_string_insel(hop, va_arg(ap, const char*)); + break; + + case 'S': + hop_add_st_offset_insel(hop, va_arg(ap, struct hreg*)); + break; + + case 'A': + hop_add_ab_offset_insel(hop, va_arg(ap, int)); + break; + + case 'L': + hop_add_lb_offset_insel(hop, va_arg(ap, int)); + break; + + case 'H': + hop_add_hreg_insel(hop, va_arg(ap, struct hreg*), index); + break; + + case 'V': + hop_add_vreg_insel(hop, va_arg(ap, struct vreg*), index); + break; + } + } + else + { + const char* end = strchr(fmt, '%'); + const char* s; + if (end) + { + int len = end - fmt; + s = strndup(fmt, len); + fmt = end; + } + else + { + s = fmt; + fmt += strlen(fmt); + } + + hop_add_string_insel(hop, s); + } + } + + hop_add_eoi_insel(hop); + va_end(ap); +} + +static void print_header(char k, struct hop* hop) +{ + int i; + + tracef(k, "%c: %d", k, hop->id); + if (hop->ir) + tracef(k, " from $%d", hop->ir->id); + tracef(k, ":"); + + for (i=0; iins.count; i++) + tracef(k, " r%%%d", hop->ins.item[i]->id); + for (i=0; ithroughs.count; i++) + tracef(k, " =%%%d", hop->throughs.item[i]->id); + for (i=0; iouts.count; i++) + tracef(k, " w%%%d", hop->outs.item[i]->id); + tracef(k, " "); +} + +static char* appendf(const char* fmt, ...) +{ + int n; + char* p; + va_list ap; + + va_start(ap, fmt); + n = bufferlen + vsnprintf(NULL, 0, fmt, ap) + 1; + va_end(ap); + + if (n > buffersize) + { + buffersize *= 2; + if (buffersize < n) + buffersize = n*2; + buffer = realloc(buffer, buffersize); + } + + va_start(ap, fmt); + vsprintf(buffer+bufferlen, fmt, ap); + va_end(ap); + + bufferlen = n - 1; /* remember the \0 at the end */ + return p; +} + +char* hop_render(struct hop* hop) +{ + int i; + + appendf(""); /* ensure the buffer has been allocated */ + bufferlen = 0; + buffer[0] = '\0'; + + for (i=0; iinsels.count; i++) + { + struct insel* insel = hop->insels.item[i]; + + switch (insel->type) + { + case INSEL_EOI: + appendf("\n"); + break; + + case INSEL_HREG: + { + struct hreg* hreg = insel->u.hreg; + if (hreg->brd) + appendf("%s", hreg->brd->names[insel->index]); + else + appendf("%s.%d", hreg->id, insel->index); + break; + } + + case INSEL_VREG: + { + struct vreg* vreg = insel->u.vreg; + struct hreg* hreg = pmap_findright(&hop->regsin, vreg); + if (!hreg) + hreg = pmap_findright(&hop->regsout, vreg); + if (hreg) + appendf("%s", hreg->brd->names[insel->index]); + else + appendf("%%%d.%d", vreg->id, insel->index); + break; + } + + case INSEL_STRING: + appendf("%s", insel->u.string); + break; + + case INSEL_ST_OFFSET: + appendf("%d", current_proc->fp_to_sb + insel->u.hreg->offset); + break; + + case INSEL_AB_OFFSET: + appendf("%d", current_proc->fp_to_ab + insel->u.offset); + break; + + case INSEL_LB_OFFSET: + appendf("%d", current_proc->fp_to_lb + insel->u.offset); + break; + + case INSEL_VALUE: + { + struct ir* ir = insel->u.value; + switch (ir->opcode) + { + case IR_BLOCK: + appendf("%s", platform_label(ir->u.bvalue->name)); + break; + + case IR_LABEL: + appendf("%s", platform_label(ir->u.lvalue)); + break; + + case IR_LOCAL: + if (ir->u.ivalue >= 0) + appendf("%d", current_proc->fp_to_ab + ir->u.ivalue); + else + appendf("%d", current_proc->fp_to_lb + ir->u.ivalue); + break; + + case IR_CONST: + appendf("%d", ir->u.ivalue); + break; + + default: + assert(false); + } + break; + } + + default: + assert(false); + } + } + + return buffer; +} + +void hop_print(char k, struct hop* hop) +{ + int i; + bool soi = false; + char* p; + + hop_render(hop); + + p = strtok(buffer, "\n"); + print_header(k, hop); + while (p) + { + tracef(k, "%s", p); + p = strtok(NULL, "\n"); + if (p) + { + tracef(k, "\n"); + print_header(k, hop); + } + } + tracef(k, "\n"); +} + +/* vim: set sw=4 ts=4 expandtab : */ + diff --git a/mach/proto/mcg/hop.h b/mach/proto/mcg/hop.h new file mode 100644 index 000000000..21c7e9293 --- /dev/null +++ b/mach/proto/mcg/hop.h @@ -0,0 +1,75 @@ +#ifndef HOP_H +#define HOP_H + +enum insel_type +{ + INSEL_STRING, + INSEL_HREG, + INSEL_VREG, + INSEL_VALUE, + INSEL_ST_OFFSET, + INSEL_AB_OFFSET, + INSEL_LB_OFFSET, + INSEL_EOI +}; + +struct insel +{ + enum insel_type type; + int index; + union + { + const char* string; + struct hreg* hreg; + struct vreg* vreg; + struct ir* value; + int offset; + } + u; +}; + +struct constraint +{ + uint32_t attrs; + bool preserved; + struct vreg* equals_to; +}; + +struct hop +{ + int id; + struct basicblock* bb; + struct ir* ir; + const struct burm_instruction_data* insndata; + ARRAYOF(struct insel) insels; + struct vreg* output; + + PMAPOF(struct vreg, struct constraint) constraints; + + ARRAYOF(struct vreg) ins; + ARRAYOF(struct vreg) outs; + ARRAYOF(struct vreg) throughs; + register_assignment_t regsin; + register_assignment_t regsout; +}; + +extern struct hop* new_hop(struct basicblock* bb, struct ir* ir); + +extern void hop_add_string_insel(struct hop* hop, const char* string); +extern void hop_add_hreg_insel(struct hop* hop, struct hreg* hreg, int index); +extern void hop_add_vreg_insel(struct hop* hop, struct vreg* vreg, int index); +extern void hop_add_value_insel(struct hop* hop, struct ir* ir); +extern void hop_add_st_offset_insel(struct hop* hop, struct hreg* hreg); +extern void hop_add_ab_offset_insel(struct hop* hop, int offset); +extern void hop_add_lb_offset_insel(struct hop* hop, int offset); +extern void hop_add_eoi_insel(struct hop* hop); + +extern void hop_add_insel(struct hop* hop, const char* fmt, ...); + +extern char* hop_render(struct hop* hop); +extern void hop_print(char k, struct hop* hop); + +#endif + +/* vim: set sw=4 ts=4 expandtab : */ + diff --git a/mach/proto/mcg/ir.c b/mach/proto/mcg/ir.c new file mode 100644 index 000000000..e30e82a2b --- /dev/null +++ b/mach/proto/mcg/ir.c @@ -0,0 +1,172 @@ +#include "mcg.h" + +static int next_id = 0; + +struct ir* new_ir0(int opcode, int size) +{ + struct ir* ir = calloc(sizeof(struct ir), 1); + ir->id = next_id++; + ir->opcode = opcode; + ir->size = size; + return ir; +} + +struct ir* new_ir1(int opcode, int size, + struct ir* left) +{ + struct ir* ir = new_ir0(opcode, size); + ir->left = left; + return ir; +} + +struct ir* new_ir2(int opcode, int size, + struct ir* left, struct ir* right) +{ + struct ir* ir = new_ir0(opcode, size); + ir->left = left; + ir->right = right; + return ir; +} + +struct ir* new_labelir(const char* label) +{ + struct ir* ir = new_ir0(IR_LABEL, EM_pointersize); + ir->u.lvalue = label; + return ir; +} + +struct ir* new_constir(int size, arith value) +{ + struct ir* ir = new_ir0(IR_CONST, size); + ir->u.ivalue = value; + return ir; +} + +struct ir* new_wordir(arith value) +{ + return new_constir(EM_wordsize, value); +} + +struct ir* new_bbir(struct basicblock* bb) +{ + struct ir* ir = new_ir0(IR_BLOCK, EM_pointersize); + ir->u.bvalue = bb; + return ir; +} + +struct ir* new_anyir(int size) +{ + return new_ir0(IR_ANY, size); +} + +struct ir* new_localir(int offset) +{ + struct ir* ir = new_ir0(IR_LOCAL, EM_pointersize); + ir->u.ivalue = offset; + return ir; +} + +struct ir* ir_walk(struct ir* ir, ir_walker_t* cb, void* user) +{ + assert(ir->root); + if (cb(ir, user)) + return ir; + + if (ir->left && (ir->left->root == ir->root)) + { + struct ir* irr = ir_walk(ir->left, cb, user); + if (irr) + return irr; + } + + if (ir->right && (ir->right->root == ir->root)) + { + struct ir* irr = ir_walk(ir->right, cb, user); + if (irr) + return irr; + } + + return NULL; +} + +static bool finder_cb(struct ir* ir, void* user) +{ + int opcode = *(int*)user; + if (ir->opcode == opcode) + return true; + return false; +} + +struct ir* ir_find(struct ir* ir, int opcode) +{ + return ir_walk(ir, finder_cb, &opcode); +} + +static void print_expr(char k, const struct ir* ir) +{ + tracef(k, "%s", ir_data[ir->opcode].name); + if (ir->type) + tracef(k, ".%c", ir->type); + else if (ir->size) + tracef(k, "%d", ir->size); + tracef(k, "("); + + switch (ir->opcode) + { + case IR_CONST: + case IR_LOCAL: + tracef(k, "%d", ir->u.ivalue); + break; + + case IR_LABEL: + tracef(k, "%s", ir->u.lvalue); + break; + + case IR_BLOCK: + tracef(k, "%s", ir->u.bvalue->name); + break; + + case IR_PHI: + { + int i; + + for (i=0; iu.phivalue.count; i++) + { + if (i > 0) + tracef(k, ", "); + tracef(k, "%s=>$%d", + ir->u.phivalue.item[i].left->name, + ir->u.phivalue.item[i].right->id); + } + break; + } + + default: + if (ir->left) + { + if (ir->left->root != ir->root) + tracef(k, "$%d", ir->left->id); + else + print_expr(k, ir->left); + } + if (ir->right) + { + tracef(k, ", "); + if (ir->right->root != ir->root) + tracef(k, "$%d", ir->right->id); + else + print_expr(k, ir->right); + } + } + + tracef(k, ")"); +} + +void ir_print(char k, const struct ir* ir) +{ + tracef(k, "%c: $%d = ", k, ir->id); + print_expr(k, ir); + tracef(k, "\n"); +} + +/* vim: set sw=4 ts=4 expandtab : */ diff --git a/mach/proto/mcg/ir.h b/mach/proto/mcg/ir.h new file mode 100644 index 000000000..10fa83a48 --- /dev/null +++ b/mach/proto/mcg/ir.h @@ -0,0 +1,52 @@ +#ifndef IR_H +#define IR_H + +#include "ircodes.h" + +struct ir +{ + int id; + enum ir_opcode opcode; + int size; + char type; + struct ir* left; + struct ir* right; + struct ir* root; + union + { + arith ivalue; + int rvalue; + const char* lvalue; + struct basicblock* bvalue; + PMAPOF(struct basicblock, struct ir) phivalue; + } u; + + ARRAYOF(struct ir) uses; /* all places this IR is used */ + + struct vreg* result; /* vreg containing IR result */ +}; + +extern const char* ir_names[]; + +extern struct ir* new_ir0(int opcode, int size); +extern struct ir* new_ir1(int opcode, int size, + struct ir* c1); +extern struct ir* new_ir2(int opcode, int size, + struct ir* c1, struct ir* c2); + +extern struct ir* new_labelir(const char* label); +extern struct ir* new_wordir(arith value); +extern struct ir* new_constir(int size, arith value); +extern struct ir* new_bbir(struct basicblock* bb); +extern struct ir* new_anyir(int size); +extern struct ir* new_localir(int offset); + +typedef bool ir_walker_t(struct ir* node, void* user); +extern struct ir* ir_walk(struct ir* ir, ir_walker_t* callback, void* user); +extern struct ir* ir_find(struct ir* ir, int opcode); + +extern void ir_print(char k, const struct ir* ir); + +#endif + +/* vim: set sw=4 ts=4 expandtab : */ diff --git a/mach/proto/mcg/main.c b/mach/proto/mcg/main.c new file mode 100644 index 000000000..cf8a4435f --- /dev/null +++ b/mach/proto/mcg/main.c @@ -0,0 +1,137 @@ +#include "mcg.h" +#include +#include + +static const char* tracechars = NULL; + +FILE* outputfile = NULL; +FILE* dominance_dot_file = NULL; +FILE* cfg_dot_file = NULL; + +bool tracing(char k) +{ + if (k == '!') + return true; + if (!tracechars) + return false; + + return index(tracechars, k); +} + +void tracef(char k, const char* fmt, ...) +{ + va_list ap; + + if (tracing(k)) + { + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + } +} + +static bool find_procedures_cb(struct symbol* symbol, void* user) +{ + if (symbol->proc) + procedure_compile(symbol->proc); + return false; +} + +int main(int argc, char* const argv[]) +{ + const char* inputfilename = NULL; + const char* outputfilename = NULL; + FILE* output; + + program_name = argv[0]; + + opterr = 1; + for (;;) + { + int c = getopt(argc, argv, "-d:D:C:o:"); + if (c == -1) + break; + + switch (c) + { + case 'C': + cfg_dot_file = fopen(optarg, "w"); + if (!cfg_dot_file) + fatal("couldn't open output file '%s': %s", + optarg, strerror(errno)); + fprintf(cfg_dot_file, "digraph {\n"); + break; + + case 'D': + dominance_dot_file = fopen(optarg, "w"); + if (!dominance_dot_file) + fatal("couldn't open output file '%s': %s", + optarg, strerror(errno)); + fprintf(dominance_dot_file, "digraph {\n"); + break; + + case 'd': + tracechars = optarg; + break; + + case 'o': + if (outputfilename) + fatal("already specified an output file"); + outputfilename = optarg; + break; + + case 1: + if (inputfilename) + fatal("unexpected argument '%s'", optarg); + inputfilename = optarg; + } + } + + symbol_init(); + + if (!EM_open((char*) inputfilename)) + fatal("couldn't open input '%s': %s", + inputfilename ? inputfilename : "", EM_error); + + if (outputfilename) + { + outputfile = fopen(outputfilename, "w"); + if (!outputfile) + fatal("couldn't open output '%s': %s", + outputfilename, strerror(errno)); + } + else + outputfile = stdout; + + fprintf(outputfile, ".sect .text\n.sect .rom\n.sect .data\n.sect .bss\n"); + + /* Reads in the EM, outputs the data sections, parses any code and + * generates IR trees. */ + + parse_em(); + + /* For every procedure, go ahead and do the compilation proper. We do this + * now so that we know that all the data has been read correctly and our + * symbol table is complete (we may need to refer to it). */ + + symbol_walk(find_procedures_cb, NULL); + + if (outputfilename) + fclose(outputfile); + EM_close(); + + if (cfg_dot_file) + { + fprintf(cfg_dot_file, "}\n"); + fclose(cfg_dot_file); + } + if (dominance_dot_file) + { + fprintf(dominance_dot_file, "}\n"); + fclose(dominance_dot_file); + } + + return 0; +} + +/* vim: set sw=4 ts=4 expandtab : */ diff --git a/mach/proto/mcg/mcg.h b/mach/proto/mcg/mcg.h new file mode 100644 index 000000000..540f5799c --- /dev/null +++ b/mach/proto/mcg/mcg.h @@ -0,0 +1,136 @@ +#ifndef MCG_H +#define MCG_H + +#include +#include +#include +#include +#include +#include +#include +#include "flt_arith.h" +#include "em_arith.h" +#include "em_label.h" +#include "em.h" +#include "em_comp.h" +#include "em_pseu.h" +#include "em_mnem.h" +#include "em_flag.h" +#include "em_ptyp.h" +#include "array.h" +#include "imap.h" +#include "pmap.h" +#include "diagnostics.h" +#include "astring.h" +#include "ir.h" +#include "mcgg.h" +#include "reg.h" +#include "hop.h" +#include "basicblock.h" +#include "procedure.h" +#include "graph.h" +#include "tables.h" + +extern char em_pseu[][4]; +extern char em_mnem[][4]; +extern char em_flag[]; + +enum { + SECTION_UNKNOWN = 0, + SECTION_ROM, + SECTION_DATA, + SECTION_BSS, + SECTION_TEXT +}; + +struct symbol +{ + const char* name; + int section; + struct procedure* proc; + bool is_defined : 1; + bool is_exported : 1; + bool is_proc : 1; +}; + +enum +{ + PARAM_NONE, + PARAM_IVALUE, + PARAM_LVALUE, + PARAM_BVALUE, +}; + +struct em +{ + int opcode; + int paramtype; + union { + arith ivalue; + struct { + const char* label; + arith offset; + } lvalue; + struct { + struct basicblock* left; + struct basicblock* right; + } bvalue; + } u; +}; + +extern const char* aprintf(const char* fmt, ...); +extern void tracef(char k, const char* fmt, ...); +extern bool tracing(char k); + +extern void parse_em(void); + +extern void symbol_init(void); +extern bool symbol_exists(const char* name); +extern struct symbol* symbol_get(const char* name); +extern void symbol_declare(const char* name, bool is_exported, bool is_proc); + +typedef bool symbol_walker_t(struct symbol* symbol, void* user); +extern struct symbol* symbol_walk(symbol_walker_t* walker, void* user); + +extern void data_label(const char* name); +extern void data_int(arith data, size_t size, bool is_ro); +extern void data_float(const char* data, size_t size, bool is_ro); +extern void data_block(const uint8_t* data, size_t size, bool is_ro); +extern void data_offset(const char* label, arith offset, bool is_ro); +extern void data_bss(arith size, int init); + +extern void tb_filestart(void); +extern void tb_fileend(void); +extern void tb_procedure(void); +extern void tb_regvar(struct procedure* proc, arith offset, int size, int type, int priority); + +extern void pass_convert_locals_to_ssa(void); +extern void pass_convert_stack_ops(void); +extern void pass_eliminate_trivial_blocks(void); +extern void pass_find_phi_congruence_groups(void); +extern void pass_group_irs(void); +extern void pass_infer_types(void); +extern void pass_insert_moves(void); +extern void pass_instruction_selector(void); +extern void pass_live_vreg_analysis(void); +extern void pass_add_prologue_epilogue(void); +extern void pass_register_allocator(void); +extern void pass_remove_dead_blocks(void); +extern void pass_remove_dead_phis(void); +extern void pass_split_critical_edges(void); +extern void pass_wire_up_return_values(void); + +extern void platform_calculate_offsets(void); +extern struct hop* platform_prologue(void); +extern struct hop* platform_epilogue(void); +extern struct hop* platform_move(struct basicblock* bb, struct hreg* src, struct hreg* dest); +extern struct hop* platform_swap(struct basicblock* bb, struct hreg* src, struct hreg* dest); +extern const char* platform_label(const char* label); + +extern FILE* outputfile; +extern FILE* dominance_dot_file; +extern FILE* cfg_dot_file; + +#endif + +/* vim: set sw=4 ts=4 expandtab : */ diff --git a/mach/proto/mcg/mcgg_generated_footer.h b/mach/proto/mcg/mcgg_generated_footer.h new file mode 100644 index 000000000..6de0c5277 --- /dev/null +++ b/mach/proto/mcg/mcgg_generated_footer.h @@ -0,0 +1,55 @@ +static void dumpCover(NODEPTR_TYPE p, int goalnt, int indent) { +#ifdef TRACE + int eruleno = burm_rule(STATE_LABEL(p), goalnt); + const short *nts = burm_nts[eruleno]; + NODEPTR_TYPE kids[10]; + int i; + + for (i = 0; i < indent; i++) + fprintf(stderr, " "); + fprintf(stderr, "%s\n", burm_string[eruleno]); + burm_kids(p, eruleno, kids); + for (i = 0; nts[i]; i++) + { + if (kids[i]) + dumpCover(kids[i], nts[i], indent + 1); + else + fprintf(stderr, "failed!\n"); + } +#endif +} + +#if 0 +static NODEPTR_TYPE tree(int op, NODEPTR_TYPE l, NODEPTR_TYPE r) { + NODEPTR_TYPE p = malloc(sizeof *p); + + assert(p); + p->op = op; + p->kids[0] = l; p->kids[1] = r; + return p; +} + +int main(void) { + NODEPTR_TYPE p; + + p = tree(STORE4, + tree(ADD4, + tree(LABEL4, 0, 0), + tree(CONST4, 0, 0) + ), + tree(ADD4, + tree(LOAD4, + tree(LABEL4, 0, 0), + 0 + ), + tree(CONST4, 0, 0) + ) + ); + burm_label(p); + dumpCover(p, 1, 0); + return 0; +} +#endif + +/* vim: set sw=4 ts=4 expandtab : */ + diff --git a/mach/proto/mcg/mcgg_generated_header.h b/mach/proto/mcg/mcgg_generated_header.h new file mode 100644 index 000000000..f0bfa99a0 --- /dev/null +++ b/mach/proto/mcg/mcgg_generated_header.h @@ -0,0 +1,15 @@ +#include "mcg.h" +#include "mcgg.h" + +#define PANIC printf + +#define burm_assert(b, s) assert(b) + +extern void burm_panic_cannot_match(NODEPTR_TYPE node); + +extern bool burm_predicate_signed_constant(struct burm_node* node, arith size); +extern bool burm_predicate_unsigned_constant(struct burm_node* node, arith size); +extern bool burm_predicate_specific_constant(struct burm_node* node, arith value); + +/* vim: set sw=4 ts=4 expandtab : */ + diff --git a/mach/proto/mcg/parse_em.c b/mach/proto/mcg/parse_em.c new file mode 100644 index 000000000..b66b177c4 --- /dev/null +++ b/mach/proto/mcg/parse_em.c @@ -0,0 +1,483 @@ +#include "mcg.h" + +static struct e_instr em; +static struct basicblock* code_bb; +static struct basicblock* data_bb; + +static void queue_insn_label(int opcode, const char* label, arith offset); + +static const char* type_to_str(int type) +{ + switch (type) + { + case EM_MNEM: return "EM_MNEM"; + case EM_PSEU: return "EM_PSEU"; + case EM_STARTMES: return "EM_STARTMES"; + case EM_MESARG: return "EM_MESARG"; + case EM_ENDMES: return "EM_ENDMES"; + case EM_DEFILB: return "EM_DEFILB"; + case EM_DEFDLB: return "EM_DEFDLB"; + case EM_DEFDNAM: return "EM_DEFDNAM"; + case EM_ERROR: return "EM_ERROR"; + case EM_FATAL: return "EM_FATAL"; + case EM_EOF: return "EM_EOF"; + } + + assert(0 && "invalid EM type"); +} + +static const char* argtype_to_str(int type) +{ + if (type == 0) return "..."; + if (type == ilb_ptyp) return "ilb"; + if (type == nof_ptyp) return "nof"; + if (type == sof_ptyp) return "sof"; + if (type == cst_ptyp) return "cst"; + if (type == pro_ptyp) return "pro"; + if (type == str_ptyp) return "str"; + if (type == ico_ptyp) return "ico"; + if (type == uco_ptyp) return "uco"; + if (type == fco_ptyp) return "fco"; + return "???"; +} + +static void unknown_type(const char* s) +{ + fatal("%s with unknown type '%s'", + s, + argtype_to_str(em.em_arg.ema_argtype)); +} + +static const char* ilabel_to_str(label l) +{ + assert(current_proc != NULL); + return aprintf(".%s_I%d", current_proc->name, l); +} + +static const char* dlabel_to_str(label l) +{ + return aprintf(".D%d", l); +} + +static void terminate_block(void) +{ + code_bb->is_terminated = true; + code_bb = NULL; +} + +static struct em* new_insn(int opcode) +{ + struct em* em = calloc(sizeof(struct em), 1); + em->opcode = opcode; + return em; +} + +static void queue_insn_simple(int opcode) +{ + struct em* em = new_insn(opcode); + em->paramtype = PARAM_NONE; + array_append(&code_bb->ems, em); + + switch (opcode) + { + case op_bra: + terminate_block(); + break; + } +} + +static void queue_insn_value(int opcode, arith value) +{ + struct em* em = new_insn(opcode); + em->paramtype = PARAM_IVALUE; + em->u.ivalue = value; + array_append(&code_bb->ems, em); + + switch (opcode) + { + case op_csa: + case op_csb: + case op_ret: + terminate_block(); + break; + } +} + +static void queue_insn_label(int opcode, const char* label, arith offset) +{ + struct em* em = new_insn(opcode); + em->paramtype = PARAM_LVALUE; + em->u.lvalue.label = label; + em->u.lvalue.offset = offset; + array_append(&code_bb->ems, em); + + switch (opcode) + { + case op_bra: + terminate_block(); + break; + } +} + +static void queue_insn_block(int opcode, struct basicblock* left, struct basicblock* right) +{ + struct em* em = new_insn(opcode); + em->paramtype = PARAM_BVALUE; + em->u.bvalue.left = left; + em->u.bvalue.right = right; + array_append(&code_bb->ems, em); + + terminate_block(); +} + +static void change_basicblock(struct basicblock* newbb) +{ + array_appendu(¤t_proc->blocks, newbb); + + if (code_bb && !code_bb->is_terminated) + queue_insn_block(op_bra, newbb, NULL); + + code_bb = newbb; +} + +static void queue_insn_ilabel(int opcode, int label) +{ + const char* name = ilabel_to_str(em.em_ilb); + struct basicblock* left = bb_get(name); + + switch (opcode) + { + case op_bra: + queue_insn_block(em.em_opcode, left, NULL); + break; + + case op_zeq: + case op_zne: + case op_zlt: + case op_zle: + case op_zgt: + case op_zge: + case op_beq: + case op_bne: + case op_blt: + case op_ble: + case op_bgt: + case op_bge: + { + struct basicblock* bb = bb_get(NULL); + queue_insn_block(em.em_opcode, left, bb); + change_basicblock(bb); + break; + } + + default: + fatal("parse_em: unhandled conditional '%s'", + em_mnem[opcode - sp_fmnem]); + } +} + +static void queue_ilabel(arith label) +{ + change_basicblock(bb_get(ilabel_to_str(label))); +} + +static void parse_pseu(void) +{ + switch (em.em_opcode) + { + case ps_exp: /* external proc */ + case ps_exa: /* external array */ + case ps_inp: /* internal proc */ + case ps_ina: /* internal array */ + { + bool export = (em.em_opcode == ps_exp) || (em.em_opcode == ps_exa); + bool proc = (em.em_opcode == ps_exp) || (em.em_opcode == ps_inp); + + switch (em.em_arg.ema_argtype) + { + case pro_ptyp: + symbol_declare(strdup(em.em_pnam), export, proc); + break; + + case sof_ptyp: + assert(em.em_off == 0); + symbol_declare(strdup(em.em_dnam), export, proc); + break; + + case nof_ptyp: + assert(em.em_off == 0); + symbol_declare(dlabel_to_str(em.em_dlb), export, proc); + break; + + default: + unknown_type("exp, exa, inp, ina"); + } + break; + } + + case ps_con: /* .data */ + case ps_rom: /* .rom */ + { + bool ro = (em.em_opcode == ps_rom); + + switch (em.em_arg.ema_argtype) + { + case ico_ptyp: + case uco_ptyp: + { + arith val = atol(em.em_string); + data_int(val, em.em_size, ro); + break; + } + + case fco_ptyp: + { + data_float(em.em_string, em.em_size, ro); + break; + } + + case str_ptyp: + data_block(strdup(em.em_string), em.em_size, ro); + break; + + case cst_ptyp: + data_int(em.em_cst, EM_wordsize, ro); + break; + + case nof_ptyp: + data_offset(dlabel_to_str(em.em_dlb), em.em_off, ro); + break; + + case sof_ptyp: + case pro_ptyp: + data_offset(strdup(em.em_dnam), em.em_off, ro); + break; + + case ilb_ptyp: + { + const char* label = ilabel_to_str(em.em_ilb); + + /* This is really hacky; to handle basic block flow + * descriptor blocks, we need to track which bbs a descriptor + * can exit to. So we create fake bb objects for each + * block, purely to track this. + */ + + if (data_bb) + { + struct em* em = new_insn(op_bra); + em->paramtype = PARAM_BVALUE; + em->u.bvalue.left = bb_get(label); + array_append(&data_bb->ems, em); + } + + data_offset(label, 0, ro); + break; + } + + default: + unknown_type("con, rom"); + } + break; + } + + case ps_bss: + { + switch (em.em_arg.ema_argtype) + { + case cst_ptyp: + data_bss(EM_bsssize, em.em_cst); + break; + + case ico_ptyp: + case uco_ptyp: + { + arith val = atol(em.em_string); + data_int(val, em.em_size, false); + break; + } + + case sof_ptyp: + data_offset(strdup(em.em_dnam), em.em_off, false); + break; + + default: + unknown_type("bss"); + } + break; + } + + case ps_pro: /* procedure start */ + { + struct symbol* symbol; + + current_proc = calloc(sizeof(struct procedure), 1); + current_proc->name = strdup(em.em_pnam); + current_proc->entry = bb_get(current_proc->name); + current_proc->locals_size = em.em_nlocals; + code_bb = current_proc->entry; + code_bb->is_root = true; + array_append(¤t_proc->blocks, code_bb); + + symbol = symbol_get(current_proc->name); + symbol->section = SECTION_TEXT; + symbol->proc = current_proc; + symbol->is_proc = true; + break; + } + + case ps_end: /* procedure end */ + tb_procedure(); + + current_proc = NULL; + code_bb = NULL; + break; + + default: + fatal("unknown pseudo with opcode %d\n", em.em_opcode); + } +} + +static arith mes_get_cst(void) +{ + EM_getinstr(&em); + if (em.em_type != EM_MESARG) + fatal("malformed MES"); + return em.em_cst; +} + +static void parse_mes(void) +{ + assert(em.em_arg.ema_argtype == cst_ptyp); + switch (em.em_cst) + { + case 0: /* error */ + fatal("MES 0 received (explicit halt)"); + + case 3: /* register variable */ + { + /* ego will sometimes generate 'mes 3' pseudos with no actual + * parameters. Detect and ignore these. */ + + EM_getinstr(&em); + if (em.em_type == EM_MESARG) + { + arith offset = em.em_cst; + int size = mes_get_cst(); + int type = mes_get_cst(); + int priority = mes_get_cst(); + tb_regvar(current_proc, offset, size, type, priority); + } + break; + } + } + + while ((em.em_type == EM_STARTMES) || (em.em_type == EM_MESARG)) + EM_getinstr(&em); + + if (em.em_type != EM_ENDMES) + fatal("malformed MES"); +} + +static void create_data_label(const char* label) +{ + data_label(label); + if (current_proc) + { + data_bb = bb_get(label); + data_bb->is_fake = true; + array_append(¤t_proc->blocks, data_bb); + } +} + +void parse_em(void) +{ + EM_getinstr(&em); + tb_filestart(); + + while (em.em_type != EM_EOF) + { + switch (em.em_type) + { + case EM_PSEU: + parse_pseu(); + break; + + case EM_DEFILB: + queue_ilabel(em.em_ilb); + break; + + case EM_DEFDLB: + create_data_label(dlabel_to_str(em.em_dlb)); + break; + + case EM_DEFDNAM: + create_data_label(strdup(em.em_dnam)); + break; + + case EM_STARTMES: + parse_mes(); + break; + + case EM_MNEM: + if (code_bb) + { + int flags = em_flag[em.em_opcode - sp_fmnem]; + + if (flags & EM_PAR) + { + switch (em.em_argtype) + { + case 0: + /* This is an instruction which would normally + * take a size, but the size is provided on the + * stack. We hates them. */ + queue_insn_simple(em.em_opcode); + break; + + case ilb_ptyp: + queue_insn_ilabel(em.em_opcode, em.em_ilb); + break; + + case nof_ptyp: + queue_insn_label(em.em_opcode, + dlabel_to_str(em.em_dlb), em.em_off); + break; + + case sof_ptyp: + queue_insn_label(em.em_opcode, + strdup(em.em_dnam), em.em_off); + break; + + case pro_ptyp: + queue_insn_label(em.em_opcode, + strdup(em.em_pnam), 0); + break; + + case cst_ptyp: + if ((flags & EM_PAR) == PAR_B) + queue_insn_ilabel(em.em_opcode, em.em_ilb); + else + queue_insn_value(em.em_opcode, em.em_cst); + break; + + default: + unknown_type("instruction"); + } + } + else + queue_insn_simple(em.em_opcode); + } + break; + + default: + fatal("unrecognised instruction type '%d'", em.em_type); + } + + EM_getinstr(&em); + } + + tb_fileend(); +} + +/* vim: set sw=4 ts=4 expandtab : */ diff --git a/mach/proto/mcg/pass_convertstackops.c b/mach/proto/mcg/pass_convertstackops.c new file mode 100644 index 000000000..49da42226 --- /dev/null +++ b/mach/proto/mcg/pass_convertstackops.c @@ -0,0 +1,135 @@ +#include "mcg.h" + +static PMAPOF(struct basicblock, struct ir) pops; +static PMAPOF(struct basicblock, struct ir) pushes; + +static struct ir* get_last_push(struct basicblock* bb) +{ + int i; + + for (i=bb->irs.count-1; i>=0; i--) + { + struct ir* ir = bb->irs.item[i]; + + if (ir->opcode == IR_PUSH) + return ir; + if (ir_find(ir, IR_POP)) + return NULL; + } + + return NULL; +} + +static struct ir* get_first_pop(struct basicblock* bb) +{ + int i; + + for (i=0; iirs.count; i++) + { + struct ir* irr; + struct ir* ir = bb->irs.item[i]; + + if (ir->opcode == IR_PUSH) + return NULL; + + irr = ir_find(ir, IR_POP); + if (irr) + return irr; + } + + return NULL; +} + +static void convert_block(struct basicblock* bb) +{ + int i, j; + struct ir* ir; + + pushes.count = pops.count = 0; + for (;;) + { + struct ir* lastpush = get_last_push(bb); + if (!lastpush) + return; + + /* Abort unless *every* successor block of this one starts with a pop + * of the same size... */ + + for (i=0; inexts.count; i++) + { + struct basicblock* outbb = bb->nexts.item[i]; + + ir = get_first_pop(outbb); + if (!ir || (ir->size != lastpush->size)) + return; + pmap_add(&pops, outbb, ir); + + /* Also abort unless *every* predecessor block of the one we've + * just found *also* ends in a push of the same size. */ + + for (j=0; jprevs.count; j++) + { + struct basicblock* inbb = outbb->prevs.item[j]; + + ir = get_last_push(inbb); + if (!ir || (ir->size != lastpush->size)) + return; + pmap_add(&pushes, inbb, ir); + } + } + + /* If we didn't actually find anything, give up. */ + + if ((pushes.count == 0) || (pops.count == 0)) + return; + + /* Okay, now we can wire them all up. */ + + for (i=0; iopcode = IR_NOP; + } + + for (i=0; i 0); + if (pushes.count == 1) + { + /* The push happened in exactly one place; that means we don't need a phi and can + * just import the value directly. */ + + struct ir* src = pushes.item[0].right; + ir->opcode = IR_NOP; + ir->left = src; + } + else + { + /* The push could have happened in one of several places; we need a phi. */ + + struct ir* phi = new_ir0(IR_PHI, ir->size); + for (j=0; ju.phivalue, + pushes.item[j].left, + pushes.item[j].right); + } + phi->root = phi; + *ir = *phi; + } + } + } +} + +void pass_convert_stack_ops(void) +{ + int i; + + for (i=0; iopcode == IR_BLOCK) + { + struct basicblock* bb = ir->u.bvalue; + if (!bb->is_fake + && (bb->irs.count > 0) + && (bb->irs.item[0]->opcode == IR_JUMP) + && (bb->irs.item[0]->left->opcode == IR_BLOCK)) + { + ir->u.bvalue = bb->irs.item[0]->left->u.bvalue; + } + } + + return false; +} + +static void rewrite_jumps(struct basicblock* bb) +{ + int i; + + for (i=0; iirs.count; i++) + { + struct ir* ir = bb->irs.item[i]; + ir_walk(ir, rewrite_jumps_cb, NULL); + } +} + +void pass_eliminate_trivial_blocks(void) +{ + int i; + + for (i=0; iblocks.count; i++) + { + struct basicblock* bb = current_proc->blocks.item[i]; + rewrite_jumps(bb); + } +} + +/* vim: set sw=4 ts=4 expandtab : */ diff --git a/mach/proto/mcg/pass_groupirs.c b/mach/proto/mcg/pass_groupirs.c new file mode 100644 index 000000000..57b850a9b --- /dev/null +++ b/mach/proto/mcg/pass_groupirs.c @@ -0,0 +1,95 @@ +#include "mcg.h" + +static ARRAYOF(struct ir) allirs; +static ARRAYOF(struct ir) rootirs; + +static void addall(struct ir* ir) +{ + if (array_appendu(&allirs, ir)) + return; + + if (ir->left) + addall(ir->left); + if (ir->right) + addall(ir->right); +} + +static void collect_irs(void) +{ + int i; + + allirs.count = rootirs.count = 0; + for (i=0; iblocks.count; i++) + { + struct basicblock* bb = current_proc->blocks.item[i]; + int j; + + for (j=0; jirs.count; j++) + { + struct ir* ir = bb->irs.item[j]; + addall(ir); + array_append(&rootirs, ir); + } + } +} + +static void clear_roots(void) +{ + int i; + + for (i=0; iroot = NULL; + } +} + +static void find_roots(void) +{ + int i; + + for (i=0; iroot); + ir->root = ir; + } +} + +static void recursively_mark_root(struct ir* node, struct ir* root) +{ + if (node != root) + { + if (node->root) + return; + node->root = root; + } + + if (node->left) + recursively_mark_root(node->left, root); + if (node->right) + recursively_mark_root(node->right, root); +} + +static void find_non_roots(void) +{ + int i; + + for (i=0; iname, cost, bestcost); +} + +void burm_panic_cannot_match(struct burm_node* node) +{ + fprintf(stderr, "could not find any patterns to match:\n"); + ir_print('!', node->ir); + fprintf(stderr, "aborting!\n"); + exit(1); +} + +static void emit_return_reg(int index) +{ + hop_add_vreg_insel(current_hop, current_hop->output, index); +} + +static struct vreg* find_vreg_of_child(int child) +{ + struct insn* insn = current_insn->children[child]; + + if (insn->hop) + return insn->hop->output; + else + return insn->ir->result; +} + +static void emit_reg(int child, int index) +{ + struct vreg* vreg = find_vreg_of_child(child); + + if (vreg) + { + hop_add_vreg_insel(current_hop, vreg, index); + array_appendu(&vreg->used, current_hop); + } +} + +static void emit_string(const char* data) +{ + hop_add_string_insel(current_hop, data); +} + +static void emit_fragment(int child) +{ + emit(current_insn->children[child]); +} + +static void emit_value(int child) +{ + hop_add_value_insel(current_hop, current_insn->children[child]->ir); +} + +static void emit_eoi(void) +{ + hop_add_eoi_insel(current_hop); +} + +static struct constraint* get_constraint(struct vreg* vreg) +{ + struct constraint* c = pmap_findleft(¤t_hop->constraints, vreg); + if (!c) + { + c = calloc(1, sizeof(*c)); + pmap_put(¤t_hop->constraints, vreg, c); + } + return c; +} + +static void constrain_input_reg(int child, uint32_t attr) +{ + struct vreg* vreg = find_vreg_of_child(child); + struct constraint* c; + + assert(vreg); + + array_appendu(¤t_hop->ins, vreg); + get_constraint(vreg)->attrs = attr; +} + +static void constrain_input_reg_preserved(int child) +{ + struct vreg* vreg = find_vreg_of_child(child); + struct constraint* c; + + assert(vreg); + array_appendu(¤t_hop->throughs, vreg); + get_constraint(vreg)->preserved = true; +} + +static uint32_t find_type_from_constraint(uint32_t attr) +{ + /* Looks through the registers and finds a concrete register implementing + * that attribute, and returns the type. We assume that all registers + * implementing an attribute (which anyone is going to ask for, 'volatile' + * doesn't count) will have the same type. TODO: mcgg should check for + * this. */ + + const struct burm_register_data* brd = burm_register_data; + while (brd->id) + { + if (brd->attrs & attr) + { + const uint32_t type_attrs = + (burm_int_ATTR | burm_float_ATTR | + burm_long_ATTR | burm_double_ATTR); + + if (brd->attrs & type_attrs) + return brd->attrs & type_attrs; + return attr; + } + brd++; + } + + fatal("unable to find a register matching attribute 0x%x", attr); + return 0; +} + +static void constrain_output_reg(uint32_t attr) +{ + struct vreg* vreg = current_hop->output; + + if (!vreg) + current_hop->output = vreg = new_vreg(); + + array_appendu(¤t_hop->outs, vreg); + vreg->defined = current_hop; + vreg->type = find_type_from_constraint(attr); + + get_constraint(vreg)->attrs = attr; +} + +static void constrain_output_reg_equal_to(int child) +{ + struct vreg* vreg = find_vreg_of_child(child); + + get_constraint(current_hop->output)->equals_to = vreg; +} + +static const struct burm_emitter_data emitter_data = +{ + &emit_string, + &emit_fragment, + &emit_return_reg, + &emit_reg, + &emit_value, + &emit_eoi, + &constrain_input_reg, + &constrain_input_reg_preserved, + &constrain_output_reg, + &constrain_output_reg_equal_to, +}; + +static void emit(struct insn* insn) +{ + struct insn* old = current_insn; + current_insn = insn; + + insn->insndata->emitter(&emitter_data); + + current_insn = old; +} + +static struct insn* walk_instructions(struct burm_node* node, int goal) +{ + struct insn* insn = calloc(1, sizeof(*insn)); + int i; + + insn->ir = node->ir; + insn->num_children = 0; + + if (goal) + { + int insn_no = burm_rule(node->state_label, goal); + const short* nts = burm_nts[insn_no]; + struct burm_node* children[MAX_CHILDREN] = {0}; + + insn->insndata = &burm_instruction_data[insn_no]; + + burm_kids(node, insn_no, children); + + i = 0; + for (;;) + { + if (!children[i]) + break; + + insn->children[i] = walk_instructions(children[i], nts[i]); + insn->num_children++; + i++; + } + + tracef('I', "I: $%d goal %d %s selected %d: %s\n", + node->ir->id, + goal, + insn->insndata->is_fragment ? "fragment" : "instruction", + insn_no, + insn->insndata->name); + + if (!insn->insndata->is_fragment) + { + insn->hop = current_hop = new_hop(current_bb, insn->ir); + current_hop->insndata = insn->insndata; + emit(insn); + + if (!current_hop->output) + { + switch (node->label) + { + case ir_to_esn(IR_REG, 0): + current_hop->output = node->ir->result; + assert(current_hop->output != NULL); + break; + + case ir_to_esn(IR_NOP, 'I'): + case ir_to_esn(IR_NOP, 'F'): + case ir_to_esn(IR_NOP, 'L'): + case ir_to_esn(IR_NOP, 'D'): + current_hop->output = node->left->ir->result; + assert(current_hop->output != NULL); + break; + } + } + + hop_print('I', current_hop); + array_append(¤t_bb->hops, current_hop); + + if ((goal != burm_stmt_NT) && !insn->ir->result) + insn->ir->result = insn->hop->output; + } + } + + return insn; +} + +static struct burm_node* build_shadow_tree(struct ir* root, struct ir* ir) +{ + struct burm_node* node = calloc(1, sizeof(*node)); + node->ir = ir; + + if (ir->root == root) + { + node->label = ir_to_esn(ir->opcode, ir->type); + + if (ir->left) + node->left = build_shadow_tree(root, ir->left); + + if (ir->right) + node->right = build_shadow_tree(root, ir->right); + } + else + node->label = ir_to_esn(IR_REG, 0); + + return node; +} + +static void select_instructions(void) +{ + int i; + + tracef('I', "I: BLOCK: %s\n", current_bb->name); + + for (i=0; iirs.count; i++) + { + struct burm_node* shadow; + int insnno; + + current_ir = current_bb->irs.item[i]; + + if (current_ir->opcode == IR_PHI) + { + int j; + + current_ir->result = new_vreg(); + tracef('I', "I: $%d is phi:", current_ir->result->id); + for (j=0; ju.phivalue.count; j++) + { + struct basicblock* parentbb = current_ir->u.phivalue.item[j].left; + struct ir* parentir = current_ir->u.phivalue.item[j].right; + struct phi* phi = calloc(1, sizeof(*phi)); + tracef('I', " %s=>$%d", parentbb->name, parentir->id); + + phi->prev = parentbb; + phi->ir = parentir; + pmap_add(¤t_bb->phis, current_ir->result, phi); + } + tracef('I', "\n"); + } + else + { + ir_print('I', current_ir); + shadow = build_shadow_tree(current_ir, current_ir); + burm_label(shadow); + + insnno = burm_rule(shadow->state_label, 1); + if (!insnno) + burm_panic_cannot_match(shadow); + + walk_instructions(shadow, burm_stmt_NT); + } + } +} + +void pass_instruction_selector(void) +{ + int i; + + for (i=0; iphis.count; j++) + { + struct vreg* vreg = bb->phis.item[j].left; + struct phi* phi = bb->phis.item[j].right; + + assert(array_contains(&bb->prevs, phi->prev)); + array_appendu(&phi->prev->liveouts, phi->ir->result); + } + } +} + +static void propagate_liveness(struct basicblock* bb) +{ + static ARRAYOF(struct vreg) current; + int i; + + current.count = 0; + array_appendall(¤t, &bb->liveouts); + + for (i=bb->hops.count-1; i>=0; i--) + { + struct hop* hop = bb->hops.item[i]; + + array_removeall(¤t, &hop->outs); + finished &= array_appendallu(&hop->throughs, ¤t); + array_appendallu(¤t, &hop->ins); + } + + for (i=0; iphis.count; i++) + array_remove(¤t, bb->phis.item[i].left); + + finished &= array_appendallu(&bb->liveins, ¤t); + + for (i=0; iprevs.count; i++) + { + struct basicblock* prev = bb->prevs.item[i]; + finished &= array_appendallu(&prev->liveouts, ¤t); + } +} + +void pass_live_vreg_analysis(void) +{ + int i; + + preload_blocks(); + + do + { + finished = true; + + tracef('L', "L: beginning liveness pass\n"); + for (i=0; iliveins.count == 0); +} + +/* vim: set sw=4 ts=4 expandtab : */ + diff --git a/mach/proto/mcg/pass_phigroups.c b/mach/proto/mcg/pass_phigroups.c new file mode 100644 index 000000000..dfff73faa --- /dev/null +++ b/mach/proto/mcg/pass_phigroups.c @@ -0,0 +1,103 @@ +#include "mcg.h" + +static PMAPOF(struct vreg, struct vreg) phimap; + +static void make_phimap(void) +{ + int i, j; + + phimap.count = 0; + for (i=0; iphis.count; j++) + { + struct vreg* vreg = bb->phis.item[j].left; + struct phi* phi = bb->phis.item[j].right; + struct vreg* prevvreg = phi->ir->result; + + pmap_add(&phimap, vreg, prevvreg); + } + } +} + +static void recursively_associate_group(struct phicongruence* c, struct vreg* vreg) +{ + int i; + + vreg->congruence = c; + array_appendu(&c->vregs, vreg); + tracef('V', "V: %%%d is a member of congruence group %d\n", + vreg->id, c->id); + + if (vreg->defined) + { + struct constraint* constraint = pmap_findleft(&vreg->defined->constraints, vreg); + if (c->type == 0) + c->type = vreg->type; + + assert(c->type == vreg->type); + + array_appendu(&c->definitions, vreg->defined); + } + + for (;;) + { + struct vreg* child = pmap_findleft(&phimap, vreg); + if (!child) + break; + + pmap_remove(&phimap, vreg, child); + recursively_associate_group(c, child); + } + + for (;;) + { + struct vreg* child = pmap_findright(&phimap, vreg); + if (!child) + break; + + pmap_remove(&phimap, child, vreg); + recursively_associate_group(c, child); + } +} + +static void update_vreg_types(struct phicongruence* c) +{ + int i; + + for (i=0; ivregs.count; i++) + { + struct vreg* vreg = c->vregs.item[i]; + + if (vreg->type == 0) + vreg->type = c->type; + assert(vreg->type == c->type); + assert(vreg->type != 0); + } +} + +static void associate_groups(void) +{ + static int number = 0; + + while (phimap.count > 0) + { + struct phicongruence* c = calloc(1, sizeof(*c)); + c->id = number++; + recursively_associate_group(c, phimap.item[0].left); + update_vreg_types(c); + } +} + +void pass_find_phi_congruence_groups(void) +{ + make_phimap(); + associate_groups(); +} + +/* vim: set sw=4 ts=4 expandtab : */ + + + diff --git a/mach/proto/mcg/pass_prologueepilogue.c b/mach/proto/mcg/pass_prologueepilogue.c new file mode 100644 index 000000000..3b0c517cb --- /dev/null +++ b/mach/proto/mcg/pass_prologueepilogue.c @@ -0,0 +1,44 @@ +#include "mcg.h" + +void pass_add_prologue_epilogue(void) +{ + int i, j, k; + + current_proc->usedregs.count = 0; + for (i=0; ihops.count; j++) + { + struct hop* hop = bb->hops.item[j]; + + for (k=0; kregsin.count; k++) + { + struct hreg* hreg = hop->regsin.item[k].left; + if (!hreg->is_stacked) + array_appendu(¤t_proc->usedregs, hreg); + } + + for (k=0; kregsout.count; k++) + { + struct hreg* hreg = hop->regsout.item[k].left; + if (!hreg->is_stacked) + array_appendu(¤t_proc->usedregs, hreg); + } + } + } + + platform_calculate_offsets(); + + array_insert(¤t_proc->entry->hops, platform_prologue(), 0); + + if (current_proc->exit) + { + current_proc->exit->hops.count = 0; + array_append(¤t_proc->exit->hops, platform_epilogue()); + } +} + +/* vim: set sw=4 ts=4 expandtab : */ + diff --git a/mach/proto/mcg/pass_registerallocator.c b/mach/proto/mcg/pass_registerallocator.c new file mode 100644 index 000000000..a5436bc73 --- /dev/null +++ b/mach/proto/mcg/pass_registerallocator.c @@ -0,0 +1,771 @@ +#include "mcg.h" + +struct assignment +{ + struct vreg* in; + struct vreg* out; +}; + +static ARRAYOF(struct hreg) hregs; + +static PMAPOF(struct vreg, struct hreg) evicted; +static struct hop* current_hop; +static register_assignment_t* current_ins; +static register_assignment_t* current_outs; + +static int insert_moves(struct basicblock* bb, int index, + register_assignment_t* srcregs, register_assignment_t* destregs); + +static bool type_match(struct hreg* hreg, struct vreg* vreg); + +static void populate_hregs(void) +{ + int i; + const struct burm_register_data* brd = burm_register_data; + + hregs.count = 0; + while (brd->id) + { + array_append(&hregs, new_hreg(brd)); + brd++; + } + + /* Wire up the register aliases. */ + + for (i=0; ibrd->aliases; + + while (*alias) + { + int index = *alias - burm_register_data; + array_append(&hreg->aliases, hregs.item[index]); + alias++; + } + } +} + +static void wire_up_blocks_ins_outs(void) +{ + int i, j; + + for (i=0; ihops.count >= 1); + bb->regsout = &bb->hops.item[bb->hops.count-1]->regsout; + } +} + +static bool register_used(register_assignment_t* regs, struct hreg* hreg) +{ + int i; + + for (i=0; ialiases.count; i++) + { + struct hreg* alias = hreg->aliases.item[i]; + if (pmap_findleft(regs, alias)) + return true; + } + + return false; +} + +static struct hreg* allocate_phi_hreg(register_assignment_t* regs, + struct vreg* vreg, uint32_t type) +{ + int i; + + /* We need a new register at the beginning of the block to put a phi value + * into. */ + + for (i=0; iattrs & type)) + { + /* This one is unused. Use it. */ + return hreg; + } + } + + /* We'll need to allocate a new stack slot for it. */ + assert(false); +} + +static struct hreg* evict(struct vreg* vreg) +{ + int i; + + /* Look for a through register which matches our requirements. We should be + * doing some calculation here to figure out the cheapest register to + * evict, but for now we're picking the first one. FIXME. */ + + for (i=0; iattrs & vreg->type) + { + if (!candidatein && + !candidateout && + !register_used(current_ins, hreg) && + !register_used(current_outs, hreg)) + { + /* This hreg is unused, so we don't need to evict anything. + * Shouldn't really happen in real life. */ + return hreg; + } + if (candidatein && candidateout && (candidatein == candidateout)) + { + /* This is a through register. */ + tracef('R', "R: evicting %%%d from %s\n", candidatein->id, hreg->id); + pmap_put(&evicted, candidatein, hreg); + pmap_remove(current_ins, hreg, candidatein); + pmap_remove(current_outs, hreg, candidatein); + return hreg; + } + } + } + + /* Couldn't find anything to evict */ + assert(false); +} + +static bool constraints_match(struct hreg* hreg, struct vreg* vreg) +{ + struct constraint* c = pmap_findleft(¤t_hop->constraints, vreg); + if (c) + return (hreg->attrs & c->attrs); + return true; +} + +static bool allocatable_stackable_input(struct hreg* hreg, struct vreg* vreg) +{ + return !register_used(current_ins, hreg) && + (hreg->attrs & vreg->type); +} + +static bool allocatable_stackable_output(struct hreg* hreg, struct vreg* vreg) +{ + return !register_used(current_outs, hreg) && + (hreg->attrs & vreg->type); +} + +static bool allocatable_input(struct hreg* hreg, struct vreg* vreg) +{ + return allocatable_stackable_input(hreg, vreg) && + constraints_match(hreg, vreg) && + !hreg->is_stacked; +} + +static bool allocatable_output(struct hreg* hreg, struct vreg* vreg) +{ + return allocatable_stackable_output(hreg, vreg) && + constraints_match(hreg, vreg) && + !hreg->is_stacked; +} + +static bool allocatable_through(struct hreg* hreg, struct vreg* vreg) +{ + return allocatable_stackable_input(hreg, vreg) && + allocatable_stackable_output(hreg, vreg) && + !(hreg->attrs & current_hop->insndata->corrupts); +} + +static struct hreg* find_input_reg(struct vreg* vreg) +{ + int i; + struct hreg* hreg = NULL; + + for (i=0; iis_stacked) + { + /* This vreg is stacked; we need to put it in a register. That's + * slightly exciting because the vreg might be a through, which + * means we need an output register too... which we might not be + * able to allocate. */ + + if (array_contains(¤t_hop->throughs, vreg)) + { + struct hreg* src = hreg; + hreg = find_through_reg(vreg); + assert(hreg); + pmap_remove(current_ins, src, vreg); + pmap_remove(current_outs, src, vreg); + pmap_add(current_ins, hreg, vreg); + pmap_add(current_outs, hreg, vreg); + return; + } + else + { + /* Not a through. */ + pmap_remove(current_ins, hreg, vreg); + hreg = NULL; + } + } + else if (pmap_findleft(current_ins, hreg) == vreg) + { + /* Yup, already there. */ + } + else if (allocatable_input(hreg, vreg)) + { + /* The register is free. */ + } + else + { + /* Can't honour the hint. */ + hreg = NULL; + } + } + + if (!hreg) + { + /* Find an unused input register of the right class. */ + + hreg = find_input_reg(vreg); + if (!hreg) + hreg = evict(vreg); + } + + pmap_add(current_ins, hreg, vreg); +} + +static void add_output_register(struct vreg* vreg) +{ + struct hreg* hreg; + int i; + struct constraint* c; + + /* Is this register supposed to be the same as one of the input registers? + * */ + + c = pmap_findleft(¤t_hop->constraints, vreg); + if (c->equals_to) + { + tracef('R', "R: output equality constraint of %%%d to %%%d\n", + vreg->id, c->equals_to->id); + + /* This output register is constrained to be in the same hreg as an + * input register (most likely for a 2op instruction). */ + + hreg = pmap_findright(current_ins, c->equals_to); + + /* If this register is currently unused as an output, use it. */ + + if (allocatable_output(hreg, c->equals_to)) + { + pmap_add(current_outs, hreg, vreg); + return; + } + + /* Okay, something's in it. Most likely it's a through being used as an + * input register. Trying to evict it would be pointless as that would + * also evict the input. So, we're going to have to do this the hard + * way: we try to allocate a matched set of input and output registers. + * */ + + hreg = find_through_reg(vreg); + if (!hreg) + hreg = evict(vreg); + + pmap_add(current_outs, hreg, vreg); + tracef('R', "R: output equality constraint requires extra move of %%%d => %s\n", + c->equals_to->id, hreg->id); + pmap_add(current_ins, hreg, c->equals_to); + } + else + { + /* This is an ordinary new register. */ + + hreg = find_output_reg(vreg); + if (!hreg) + hreg = evict(vreg); + + pmap_add(current_outs, hreg, vreg); + } +} + +static void add_through_register(struct vreg* vreg, struct hreg* hreg) +{ + /* Register hint for an input? */ + + if (hreg) + { + bool unused = allocatable_through(hreg, vreg); + struct vreg* inuse = pmap_findleft(current_ins, hreg); + struct vreg* outuse = pmap_findleft(current_outs, hreg); + + if (unused || ((inuse == vreg) && (outuse == vreg))) + { + /* Input and output are either free or already assigned to this + * vreg. */ + } + else + { + /* Nope, can't honour the hint. Mark the register as evicted; we'll + * put it in something later (probably a stack slot). */ + + tracef('R', "R: cannot place %%%d in %s, evicting\n", vreg->id, hreg->id); + pmap_put(&evicted, vreg, hreg); + pmap_remove(current_ins, hreg, vreg); + pmap_remove(current_outs, hreg, vreg); + return; + } + } + + assert(hreg); + pmap_put(current_ins, hreg, vreg); + pmap_put(current_outs, hreg, vreg); +} + +static void find_new_home_for_evicted_register(struct vreg* vreg, struct hreg* src) +{ + uint32_t srctype = vreg->type; + struct hreg* hreg; + int i; + + /* Find an unused output register of the right class which is not also + * being used as an input register. */ + + hreg = NULL; + for (i=0; iattrs & srctype) && + allocatable_through(hreg, vreg)) + { + goto found; + } + } + + /* No more registers --- allocate a stack slot. */ + + hreg = new_stacked_hreg(srctype); + array_append(&hregs, hreg); + +found: + tracef('R', "R: evicted %%%d moving to %s\n", vreg->id, hreg->id); + pmap_add(current_ins, hreg, vreg); + pmap_add(current_outs, hreg, vreg); +} + +static void select_registers(struct hop* hop, + register_assignment_t* old, register_assignment_t* in, register_assignment_t* out) +{ + int i; + + current_hop = hop; + current_ins = in; + current_outs = out; + evicted.count = 0; + + /* First, any vregs passing through the instruction stay in the same + * registers they are currently in. */ + + for (i=0; ithroughs.count; i++) + { + struct vreg* vreg = hop->throughs.item[i]; + struct hreg* hreg = pmap_findright(old, vreg); + add_through_register(vreg, hreg); + } + + /* Any registers being *read* by the instruction should also stay where + * they are. (This is likely to duplicate some throughs.) */ + + for (i=0; iins.count; i++) + { + struct vreg* vreg = hop->ins.item[i]; + struct hreg* hreg = pmap_findright(old, vreg); + add_input_register(vreg, hreg); + } + + /* Any output registers will be *new* vregs (because SSA). So, allocate + * new hregs for them. */ + + for (i=0; iouts.count; i++) + { + struct vreg* vreg = hop->outs.item[i]; + add_output_register(vreg); + } + + /* Any evicted registers now need to go somewhere (potentially, the stack). + * */ + + for (i=0; iregsin; + + tracef('R', "R: considering block %s\n", bb->name); + + /* Attempt to import any block input registers from a predecessor. At + * least one predecessor should export it; our graph traversal order + * guarantees it. */ + + for (j=0; jliveins.count; j++) + { + struct vreg* vreg = bb->liveins.item[j]; + for (k=0; kprevs.count; k++) + { + struct basicblock* prevbb = bb->prevs.item[k]; + struct hreg* hreg = pmap_findright(prevbb->regsout, vreg); + if (hreg) + { + tracef('R', "R: import hreg %s for input %%%d from %s\n", + hreg->id, vreg->id, prevbb->name); + assert(!pmap_findleft(old, hreg)); + pmap_put(old, hreg, vreg); + goto nextvreg; + } + } + + fatal("couldn't find a register assignment for $%d", vreg->id); + nextvreg:; + } + + /* And now do the same for the phis. Unlike input vregs, a phi can + * import a vreg from multiple locations. However, we don't care which + * one we find, as this is just a hint. Picking the same register as a + * predecessor helps reduce the number of copies the SSA deconstruction + * pass will need to insert. */ + + for (j=0; jphis.count; j++) + { + struct vreg* vreg = bb->phis.item[j].left; + struct phi* phi = bb->phis.item[j].right; + if (!pmap_findright(old, vreg)) + { + /* This variable isn't allocated yet. */ + + struct hreg* hreg = pmap_findright( + phi->prev->regsout, phi->ir->result); + if (hreg && !pmap_findleft(old, hreg)) + { + tracef('R', "R: import hreg %s for %%%d, imported from %s %%%d\n", + hreg->id, vreg->id, + phi->prev->name, phi->ir->id); + pmap_put(old, hreg, vreg); + } + } + } + + /* It's possible for the previous stage to fail because in in has + * clobbered the physical register we were wanting. So we need to + * allocate a new register for that phi value. + */ + + for (j=0; jphis.count; j++) + { + struct vreg* vreg = bb->phis.item[j].left; + struct phi* phi = bb->phis.item[j].right; + if (!pmap_findright(old, vreg)) + { + struct phicongruence* c = vreg->congruence; + struct hreg* hreg = allocate_phi_hreg(old, vreg, c->type); + + tracef('R', "R: import fallback hreg %s for %%%d, imported from %s %%%d\n", + hreg->id, vreg->id, + phi->prev->name, phi->ir->id); + pmap_add(old, hreg, vreg); + } + } + + for (j=0; jhops.count; j++) + { + struct hop* hop = bb->hops.item[j]; + register_assignment_t* in = &hop->regsin; + register_assignment_t* out = &hop->regsout;; + + hop_print('R', hop); + + select_registers(hop, old, in, out); + + tracef('R', "R: %d from $%d: [", hop->id, hop->ir->id); + for (k=0; kregsin.count; k++) + { + struct hreg* hreg = hop->regsin.item[k].left; + struct vreg* vreg = hop->regsin.item[k].right; + if (k != 0) + tracef('R', " "); + tracef('R', "%%%d=>%s", vreg->id, hreg->id); + } + tracef('R', "] ["); + for (k=0; kregsout.count; k++) + { + struct hreg* hreg = hop->regsout.item[k].left; + struct vreg* vreg = hop->regsout.item[k].right; + if (k != 0) + tracef('R', " "); + tracef('R', "%%%d=>%s", vreg->id, hreg->id); + } + tracef('R', "]\n"); + + j += insert_moves(bb, j, old, in); + + old = out; + } + } +} + +/* returns the number of instructions inserted */ +static int insert_moves(struct basicblock* bb, int index, + register_assignment_t* srcregs, register_assignment_t* destregs) +{ + int i; + int inserted = 0; + static PMAPOF(struct hreg, struct hreg) copies; + + copies.count = 0; + for (i=0; icount; i++) + { + struct hreg* dest = destregs->item[i].left; + struct vreg* vreg = destregs->item[i].right; + struct hreg* src = pmap_findright(srcregs, vreg); + assert(src != NULL); + + pmap_add(&copies, src, dest); + } + + while (copies.count > 0) + { + struct hreg* src; + struct hreg* dest; + struct hreg* other; + struct hop* hop; + + /* Try and find a destination which isn't a source. */ + + src = NULL; + for (i=0; idest, other->src) */ + hop = platform_swap(bb, src, dest); + pmap_remove(&copies, src, dest); + + /* Now src and dest are swapped. We know that the old src is in the right place + * and now contains dest. Any copies from the old dest (now containing src) must + * be patched to point at the old src. */ + + for (i=0; ihops, hop, index + inserted); + inserted++; + } + + return inserted; +} + +static void insert_phi_copies(void) +{ + int i, j, k; + + /* If we're importing an hreg from a parent block via a phi, insert a move + * at the end of the parent block to put the result into the right + * register. */ + + for (i=0; iprevs.count; j++) + { + struct basicblock* prevbb = bb->prevs.item[j]; + static register_assignment_t destregs; + + tracef('R', "R: inserting phis for %s -> %s\n", + prevbb->name, bb->name); + destregs.count = 0; + for (k=0; kphis.count; k++) + { + struct vreg* vreg = bb->phis.item[k].left; + struct phi* phi = bb->phis.item[k].right; + struct hreg* src = pmap_findright(prevbb->regsout, phi->ir->result); + struct hreg* dest = pmap_findright(&bb->regsin, vreg); + + if ((phi->prev == prevbb) && dest) + { + /* We inserted critical edges to guarantee this. */ + assert(prevbb->nexts.count == 1); + + tracef('R', "R: phi map %%%d (%s) -> %%%d (%s)\n", + phi->ir->result->id, src->id, + vreg->id, dest->id); + + pmap_put(&destregs, dest, phi->ir->result); + } + } + + /* Add any non-phi inputs. */ + + for (k=0; kregsin.count; k++) + { + struct hreg*hreg = bb->regsin.item[k].left; + struct vreg* vreg = bb->regsin.item[k].right; + struct hreg* src = pmap_findright(prevbb->regsout, vreg); + if (!pmap_findleft(&bb->phis, vreg)) + { + tracef('R', "R: input map %%%d (%s) -> (%s)\n", + vreg->id, src->id, hreg->id); + + pmap_add(&destregs, hreg, vreg); + } + } + + /* The last instruction of a block should be the jump that sends us + * to the next block. Insert the moves before then. */ + + insert_moves(prevbb, prevbb->hops.count-1, prevbb->regsout, &destregs); + } + } +} + +static int pack_stackframe(int stacksize, int size, uint32_t attr) +{ + int i; + + for (i=0; iis_stacked && (hreg->attrs & attr)) + { + hreg->offset = stacksize; + stacksize += size; + } + } + + return stacksize; +} + +static void layout_stack_frame(void) +{ + int stacksize = 0; + stacksize = pack_stackframe(stacksize, EM_wordsize*2, burm_double_ATTR); + stacksize = pack_stackframe(stacksize, EM_wordsize*2, burm_long_ATTR); + stacksize = pack_stackframe(stacksize, EM_wordsize*1, burm_float_ATTR); + stacksize = pack_stackframe(stacksize, EM_wordsize*1, burm_int_ATTR); + current_proc->spills_size = stacksize; +} + +void pass_register_allocator(void) +{ + populate_hregs(); + wire_up_blocks_ins_outs(); + + assign_hregs_to_vregs(); + insert_phi_copies(); + layout_stack_frame(); +} + +/* vim: set sw=4 ts=4 expandtab : */ + diff --git a/mach/proto/mcg/pass_removedeadblocks.c b/mach/proto/mcg/pass_removedeadblocks.c new file mode 100644 index 000000000..8a9a07fb4 --- /dev/null +++ b/mach/proto/mcg/pass_removedeadblocks.c @@ -0,0 +1,40 @@ +#include "mcg.h" + +static ARRAYOF(struct basicblock) used; + +static void walk_blocks(struct basicblock* bb); + +static bool walk_blocks_cb(struct ir* ir, void* user) +{ + if (ir->opcode == IR_BLOCK) + walk_blocks(ir->u.bvalue); + return false; +} + +static void walk_blocks(struct basicblock* bb) +{ + int i; + + if (!array_contains(&used, bb)) + { + array_append(&used, bb); + + for (i=0; iirs.count; i++) + ir_walk(bb->irs.item[i], walk_blocks_cb, NULL); + } +} + +void pass_remove_dead_blocks(void) +{ + int i, j; + + used.count = 0; + walk_blocks(current_proc->blocks.item[0]); + + current_proc->blocks.count = 0; + for (i=0; iblocks, used.item[i]); +} + +/* vim: set sw=4 ts=4 expandtab : */ + diff --git a/mach/proto/mcg/pass_removedeadphis.c b/mach/proto/mcg/pass_removedeadphis.c new file mode 100644 index 000000000..b8b61fbbd --- /dev/null +++ b/mach/proto/mcg/pass_removedeadphis.c @@ -0,0 +1,88 @@ +#include "mcg.h" + +static ARRAYOF(struct ir) phis; +static bool changed; + +static void collect_phis(struct basicblock* bb) +{ + int i; + + for (i=0; iirs.count; i++) + { + struct ir* ir = bb->irs.item[i]; + if (ir->opcode == IR_PHI) + array_append(&phis, ir); + } +} + +static bool ir_walker_cb(struct ir* ir, void* user) +{ + if (ir->left) + array_remove(&phis, ir->left); + if (ir->right) + array_remove(&phis, ir->right); + + return false; +} + +static void remove_referenced_phis(struct basicblock* bb) +{ + int i, j; + + for (i=0; iirs.count; i++) + { + struct ir* ir = bb->irs.item[i]; + switch (ir->opcode) + { + case IR_PHI: + for (j=0; ju.phivalue.count; j++) + array_remove(&phis, ir->u.phivalue.item[j].right); + break; + + default: + ir_walk(ir, ir_walker_cb, NULL); + break; + } + } +} + +static void purge_unused_phis(struct basicblock* bb) +{ + int i; + + for (i=0; iirs.count; i++) + { + struct ir* ir = bb->irs.item[i]; + if ((ir->opcode == IR_PHI) && (array_contains(&phis, ir))) + { + array_remove(&bb->irs, ir); + i--; + changed = true; + } + } +} + +void pass_remove_dead_phis(void) +{ + int i; + + do + { + changed = false; + + phis.count = 0; + for (i=0; iirs.count - 1; + + while (index >= 0) + { + struct ir* ir = bb->irs.item[index]; + switch (ir->opcode) + { + case IR_CALL: + ir->size = lfr->size; + *callbb = bb; + *callir = ir; + return; + + case IR_STACKADJUST: + case IR_GETRET: + case IR_JUMP: + /* lfr value preserved */ + break; + + default: + /* lfr value has been corrupted. */ + fatal("lfr reading corrupted value in %s", bb->name); + } + + index--; + } + + /* Our search hit the top of the block; we need to import the + * lfr value from a previous block. */ + + if (bb->prevs.count == 1) + { + /* Only a single predecessor, so no phi is necessary. */ + + find_call(bb->prevs.item[0], -1, lfr, callbb, callir); + } + else + { + /* We have multiple predecessors. This means that the lfr value may + * come from any of these blocks. We need a phi. */ + + int i; + struct ir* phi = new_ir0(IR_PHI, lfr->size); + + phi->root = phi; + array_insert(&bb->irs, phi, 0); + + for (i=0; iprevs.count; i++) + { + struct basicblock* prev = bb->prevs.item[i]; + struct basicblock* parentbb; + struct ir* parentir; + + find_call(prev, -1, phi, &parentbb, &parentir); + + pmap_add(&phi->u.phivalue, parentbb, parentir); + } + + *callbb = bb; + *callir = phi; + } +} + +static void wire_up_ir(struct basicblock* bb, int index) +{ + struct ir* lfr = bb->irs.item[index]; + struct basicblock* callbb; + struct ir* callir; + + find_call(bb, index, lfr, &callbb, &callir); + + lfr->left = callir; + lfr->opcode = IR_NOP; +} + +void pass_wire_up_return_values(void) +{ + int i, j; + + for (i=0; iirs.count; j++) + { + struct ir* ir = bb->irs.item[j]; + if (ir->opcode == IR_GETRET) + wire_up_ir(bb, j); + } + } +} + +/* vim: set sw=4 ts=4 expandtab : */ diff --git a/mach/proto/mcg/pass_splitcriticaledges.c b/mach/proto/mcg/pass_splitcriticaledges.c new file mode 100644 index 000000000..27e832e44 --- /dev/null +++ b/mach/proto/mcg/pass_splitcriticaledges.c @@ -0,0 +1,103 @@ +#include "mcg.h" + +/* Insert empty nodes at certain places in the basic block graph so that when + * we convert out of SSA form, we have somewhere to insert copies. This is + * necessary for correctness in certain circumstances. The best explanation of + * why I've found is here, starting at the bottom of page 23. + * + * Briggs, Preston, et al. + * "Practical improvements to the construction and destruction of static single assignment form." + * Software-Practice and experience 28.8 (1998): 859-882. + * + * http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.25.749 + */ + +struct rewrite_params +{ + struct basicblock* find; + struct basicblock* replace; +}; + +static bool find_replace_cb(struct ir* ir, void* user) +{ + struct rewrite_params* rwp = user; + + if ((ir->opcode == IR_BLOCK) && (ir->u.bvalue == rwp->find)) + ir->u.bvalue = rwp->replace; + + return false; +} + +static void split_edge(struct basicblock* source, struct basicblock* sink) +{ + int i; + struct rewrite_params rwp; + struct basicblock* bb = bb_get(NULL); + + struct ir* jump = + new_ir1( + IR_JUMP, 0, + new_bbir(sink) + ); + + jump->root = jump->left->root = jump; + array_append(&bb->irs, jump); + + rwp.find = sink; + rwp.replace = bb; + + for (i=0; iirs.count; i++) + ir_walk(source->irs.item[i], find_replace_cb, &rwp); + + array_remove(&source->nexts, sink); + array_append(&source->nexts, bb); + + array_append(&bb->prevs, source); + array_append(&bb->nexts, sink); + + array_remove(&sink->prevs, source); + array_append(&sink->prevs, bb); + + array_append(¤t_proc->blocks, bb); +} + +static bool consider_edges_leading_from(struct basicblock* bb) +{ + bool changed = false; + + if (bb->nexts.count > 1) + { + int i; + + for (i=0; inexts.count; i++) + { + struct basicblock* next = bb->nexts.item[i]; + if (next->prevs.count > 1) + { + split_edge(bb, next); + changed = true; + } + } + } + + return changed; +} + +void pass_split_critical_edges(void) +{ + int i; + bool changed; + + do + { + changed = false; + + for (i=0; iblocks.count; i++) + changed |= consider_edges_leading_from(current_proc->blocks.item[i]); + + } + while (changed); +} + +/* vim: set sw=4 ts=4 expandtab : */ + diff --git a/mach/proto/mcg/pass_ssa.c b/mach/proto/mcg/pass_ssa.c new file mode 100644 index 000000000..e0f835f17 --- /dev/null +++ b/mach/proto/mcg/pass_ssa.c @@ -0,0 +1,234 @@ +#include "mcg.h" + +static PMAPOF(struct basicblock, struct basicblock) dominancefrontiers; + +static struct local* current_local; +static ARRAYOF(struct basicblock) defining; +static ARRAYOF(struct basicblock) needsphis; +static ARRAYOF(struct ir) definitions; +static ARRAYOF(struct basicblock) rewritten; + +static void calculate_dominance_frontier_graph(void) +{ + /* This is the algorithm described here: + * + * Cooper, Keith D., Timothy J. Harvey, and Ken Kennedy. + * "A simple, fast dominance algorithm." + * Software Practice & Experience 4.1-10 (2001): 1-8. + * + * https://www.cs.rice.edu/~keith/EMBED/dom.pdf + */ + + int i, j; + + dominancefrontiers.count = 0; + + for (i=0; iprevs.count >= 2) + { + for (j=0; jprevs.count; j++) + { + struct basicblock* runner = b->prevs.item[j]; + while (runner != dominator) + { + tracef('S', "S: %s is in %s's dominance frontier\n", + b->name, runner->name); + pmap_add(&dominancefrontiers, runner, b); + runner = pmap_findleft(&dominance.graph, runner); + } + } + } + } + +} + +static bool is_local(struct ir* ir) +{ + return ((ir->opcode == IR_LOAD) && + (ir->left->opcode == IR_LOCAL) && + (ir->left->u.ivalue == current_local->offset)); +} + +static bool rewrite_loads_cb(struct ir* ir, void* user) +{ + struct ir* definition = user; + + /* Rewrite in place where possible. */ + + if (ir->left && is_local(ir->left)) + ir->left = definition; + if (ir->right && is_local(ir->right)) + ir->right = definition; + + /* Otherwise, go via a IR_NOP (which should, with luck, turn into no code). */ + if (is_local(ir)) + { + ir->opcode = IR_NOP; + ir->left = definition; + ir->right = NULL; + } + + return false; +} + +/* Walks the tree, rewriting IRs to push new definitions downwards. */ + +static void recursively_rewrite_tree(struct basicblock* bb) +{ + int i; + int defcount = definitions.count; + + if (array_contains(&rewritten, bb)) + return; + array_appendu(&rewritten, bb); + + for (i=0; iirs.count; i++) + { + struct ir* ir = bb->irs.item[i]; + + if (definitions.count > 0) + { + ir_walk(ir, rewrite_loads_cb, definitions.item[definitions.count-1]); + } + + if (((ir->opcode == IR_STORE) && + (ir->left->opcode == IR_LOCAL) && + (ir->left->u.ivalue == current_local->offset) + ) || + ((i == 0) && + (ir->opcode == IR_PHI) && + array_contains(&needsphis, bb))) + { + /* This is a definition. */ + + if (ir->opcode == IR_STORE) + { + ir->opcode = IR_NOP; + ir->left = ir->right; + ir->right = NULL; + } + array_push(&definitions, ir); + } + } + + for (i=0; inexts.count; i++) + { + struct basicblock* nextbb = bb->nexts.item[i]; + struct ir* ir = nextbb->irs.item[0]; + + if ((definitions.count > 0) && + (ir->opcode == IR_PHI) && + array_contains(&needsphis, nextbb)) + { + pmap_add(&ir->u.phivalue, + bb, definitions.item[definitions.count-1]); + } + + recursively_rewrite_tree(nextbb); + } + + definitions.count = defcount; +} + +static void ssa_convert(void) +{ + int i, j; + + /* If this is a parameter, synthesise a load/store at the beginning of the + * program to force it into a register. (Unless it's written to it'll + * always be read from the frame.) */ + + if (current_local->offset >= 0) + { + struct ir* ir = new_ir2( + IR_STORE, current_local->size, + new_localir(current_local->offset), + new_ir1( + IR_LOAD, current_local->size, + new_localir(current_local->offset) + ) + ); + + ir->root = ir; + ir->left->root = ir; + ir->right->root = ir; + ir->right->left->root = ir; + array_insert(&cfg.entry->irs, ir, 0); + } + + defining.count = 0; + needsphis.count = 0; + + /* Find everwhere where the variable is *defined*. */ + + for (i=0; iirs.count; j++) + { + struct ir* ir = bb->irs.item[j]; + if ((ir->opcode == IR_STORE) && + (ir->left->opcode == IR_LOCAL) && + (ir->left->u.ivalue == current_local->offset)) + { + array_appendu(&defining, bb); + } + } + } + + /* Every block which is in one of the defining block's dominance frontiers + * requires a phi. Remember that adding a phi also adds a definition. */ + + for (i=0; ioffset, bb->name); + for (j=0; joffset, dominates->name); + } + } + } + + /* Add empty phi nodes. */ + + for (i=0; isize); + ir->root = ir; + array_insert(&bb->irs, ir, 0); + } + + /* Now do the rewriting by walking the tree, pushing definitions down the tree. */ + + definitions.count = 0; + rewritten.count = 0; + recursively_rewrite_tree(cfg.entry); +} + +void pass_convert_locals_to_ssa(void) +{ + int i; + + calculate_dominance_frontier_graph(); + + for (i=0; ilocals.count; i++) + { + current_local = current_proc->locals.item[i].right; + if (current_local->is_register) + ssa_convert(); + } +} + +/* vim: set sw=4 ts=4 expandtab : */ + + diff --git a/mach/proto/mcg/pass_typeinference.c b/mach/proto/mcg/pass_typeinference.c new file mode 100644 index 000000000..f3b123e25 --- /dev/null +++ b/mach/proto/mcg/pass_typeinference.c @@ -0,0 +1,321 @@ +#include "mcg.h" + +static bool changed; +static ARRAYOF(struct ir) irs; + +static void addall(struct ir* ir) +{ + if (array_appendu(&irs, ir)) + return; + + if (ir->left) + addall(ir->left); + if (ir->right) + addall(ir->right); +} + +static void collect_irs(void) +{ + int i; + + irs.count = 0; + for (i=0; iirs.count; j++) + addall(bb->irs.item[j]); + } +} + +static char effective_type(struct ir* ir, char type) +{ + switch (type) + { + case 'I': + case 'F': + case 'L': + case 'D': + return type; + + case 'i': + if (ir->size == EM_wordsize) + return 'I'; + else if (ir->size == (EM_wordsize*2)) + return 'L'; + break; + + case 'f': + if (ir->size == EM_wordsize) + return 'F'; + else if (ir->size == (EM_wordsize*2)) + return 'D'; + break; + } + + return 0; +} + +static void scan_irs(void) +{ + int i; + + for (i=0; iopcode == IR_PHI) + { + int j; + + /* Phis are special. We treat them as ?=? for every import value. + * */ + + if (ir->type) + { + /* Push this type to all our children. */ + + for (j=0; ju.phivalue.count; j++) + { + struct ir* child = ir->u.phivalue.item[j].right; + if (!child->type) + { + child->type = ir->type; + changed = true; + } + } + } + else + { + /* Pull our type from the first child with a set type; we + * ignore the rest, as the next iteration will push our type to + * them. It's possible for our children to have conflicting + * types. There's not much we can do about that so we just have + * to live with it and intelligently insert casts. */ + + for (j=0; ju.phivalue.count; j++) + { + struct ir* child = ir->u.phivalue.item[j].right; + if (child->type) + { + /* Found one! */ + ir->type = child->type; + changed = true; + break; + } + } + } + } + else + { + const struct ir_data* ird = &ir_data[ir->opcode]; + + if (!ir->type) + { + char etype = effective_type(ir, ird->returntype); + if (etype) + { + ir->type = etype; + changed = true; + } + } + + if (ir->left && !ir->left->type) + { + const struct ir_data* leftird = &ir_data[ir->left->opcode]; + if (leftird->returntype == '?') + { + char etype = effective_type(ir, ird->lefttype); + if (etype) + { + ir->left->type = etype; + changed = true; + } + } + } + + if (ir->right && !ir->right->type) + { + const struct ir_data* rightird = &ir_data[ir->right->opcode]; + if (rightird->returntype == '?') + { + char etype = effective_type(ir, ird->righttype); + if (etype) + { + ir->right->type = etype; + changed = true; + } + } + } + + if (!ir->type && (ird->returntype == '?')) + { + if ((ird->lefttype == '?') && ir->left->type) + { + ir->type = ir->left->type; + changed = true; + } + + if ((ird->righttype == '?') && ir->right->type) + { + ir->type = ir->right->type; + changed = true; + } + } + + if (ir->type && (ird->lefttype == '?') && !ir->left->type) + { + ir->left->type = ir->type; + changed = true; + } + + if (ir->type && (ird->righttype == '?') && !ir->right->type) + { + ir->right->type = ir->type; + changed = true; + } + } + } +} + +static void propagate_types(void) +{ + do + { + changed = false; + + scan_irs(); + } + while (changed); +} + +static void assign_fallback_types(void) +{ + int i; + + for (i=0; iopcode]; + + if (!ir->type && (ird->returntype == '?')) + ir->type = effective_type(ir, 'i'); + } +} + +static struct ir* new_copy(char wanted, char real, struct ir* ir) +{ + struct ir* copy; + int opcode; + + if ((wanted == 'F') && (real == 'I')) + opcode = IR_COPYI; + else if ((wanted == 'D') && (real == 'L')) + opcode = IR_COPYL; + else if ((wanted == 'I') && (real == 'F')) + opcode = IR_COPYF; + else if ((wanted == 'L') && (real == 'D')) + opcode = IR_COPYD; + else + fatal("type mismatch: parent IR $%d wanted %c, child IR provided %c", + ir->id, wanted, real); + + copy = new_ir1(opcode, ir->size, ir); + copy->type = wanted; + return copy; +} + +static void insert_copy(struct ir* ir, struct ir** child, char returntype, char childtype) +{ + if (*child) + { + char wanted; + char real; + + if ((returntype == '?') && (childtype == '?')) + { + wanted = ir->type; + real = (*child)->type; + } + else + { + wanted = effective_type(ir, childtype); + real = (*child)->type; + } + + if (wanted) + { + if (wanted != real) + { + struct ir* copy = new_copy(wanted, real, *child); + copy->root = ir->root; + *child = copy; + } + } + } +} + +static void insert_ir_copies(void) +{ + int i; + + /* Insert copies for normal IR nodes. */ + + for (i=0; iopcode]; + + insert_copy(ir, &ir->left, ird->returntype, ird->lefttype); + insert_copy(ir, &ir->right, ird->returntype, ird->righttype); + } +} + +static void insert_phi_copies(void) +{ + int i, j; + + /* If the child of a phi isn't the same type as the phi itself, we need to + * insert the copy at the end of the block that exported the value. */ + + for (i=0; iu.phivalue.count; j++) + { + struct ir* childir = ir->u.phivalue.item[j].right; + int wanted = ir->type; + int real = childir->type; + if (wanted != real) + { + struct basicblock* childbb = ir->u.phivalue.item[j].left; + struct ir* copy = new_copy(wanted, real, childir); + copy->root = copy; + + /* The copy gets inserted as the second last item of the child + * basic block. That way it'll happen before the final jump + * that exits the block. */ + + array_insert(&childbb->irs, copy, childbb->irs.count-1); + + /* And replace the value in the phi with our copy. */ + + ir->u.phivalue.item[j].right = copy; + } + } + } +} + +void pass_infer_types(void) +{ + collect_irs(); + propagate_types(); + assign_fallback_types(); + insert_ir_copies(); + insert_phi_copies(); +} + +/* vim: set sw=4 ts=4 expandtab : */ + diff --git a/mach/proto/mcg/predicates.c b/mach/proto/mcg/predicates.c new file mode 100644 index 000000000..427a59836 --- /dev/null +++ b/mach/proto/mcg/predicates.c @@ -0,0 +1,32 @@ +#include "mcg.h" + +bool burm_predicate_signed_constant(struct burm_node* node, arith size) +{ + struct ir* ir = node->ir; + arith pivot = 1<<(size-1); + arith mask = ~((1<opcode == IR_CONST); + + return ((ir->u.ivalue + pivot) & mask) == 0; +} + +bool burm_predicate_unsigned_constant(struct burm_node* node, arith size) +{ + struct ir* ir = node->ir; + arith mask = ~((1<opcode == IR_CONST); + + return (ir->u.ivalue & mask) == 0; +} + +bool burm_predicate_specific_constant(struct burm_node* node, arith val) +{ + struct ir* ir = node->ir; + assert(ir->opcode == IR_CONST); + + return ir->u.ivalue == val; +} + +/* vim: set sw=4 ts=4 expandtab : */ + + diff --git a/mach/proto/mcg/procedure.c b/mach/proto/mcg/procedure.c new file mode 100644 index 000000000..f819c56e3 --- /dev/null +++ b/mach/proto/mcg/procedure.c @@ -0,0 +1,209 @@ +#include "mcg.h" + +struct procedure* current_proc; + +static void print_blocks(char k) +{ + int i; + + tracef(k, "%c: procedure %s\n", k, current_proc->name); + for (i=0; iblocks.count; i++) + { + struct basicblock* bb = current_proc->blocks.item[i]; + int j; + + tracef(k, "%c:\n", k); + tracef(k, "%c: %sBLOCK: %s\n", k, + bb->is_fake ? "FAKE " : "", + bb->name); + + if (bb->prevs.count > 0) + { + tracef(k, "%c: FROM:", k); + for (j=0; jprevs.count; j++) + tracef(k, " %s", bb->prevs.item[j]->name); + tracef(k, "\n"); + } + + if (bb->nexts.count > 0) + { + tracef(k, "%c: TO:", k); + for (j=0; jnexts.count; j++) + tracef(k, " %s", bb->nexts.item[j]->name); + tracef(k, "\n"); + } + + for (j=0; jirs.count; j++) + ir_print(k, bb->irs.item[j]); + } +} + +static void print_hops(char k) +{ + int i; + + tracef(k, "%c: procedure %s\n", k, current_proc->name); + for (i=0; iis_fake ? "FAKE " : "", + bb->name); + + if (bb->prevs.count > 0) + { + tracef(k, "%c: FROM:", k); + for (j=0; jprevs.count; j++) + tracef(k, " %s", bb->prevs.item[j]->name); + tracef(k, "\n"); + } + + if (bb->nexts.count > 0) + { + tracef(k, "%c: TO:", k); + for (j=0; jnexts.count; j++) + tracef(k, " %s", bb->nexts.item[j]->name); + tracef(k, "\n"); + } + + if (bb->liveins.count > 0) + { + tracef(k, "%c: INS:", k); + for (j=0; jliveins.count; j++) + tracef(k, " %%%d", bb->liveins.item[j]->id); + tracef(k, "\n"); + } + + if (bb->liveouts.count > 0) + { + tracef(k, "%c: OUTS:", k); + for (j=0; jliveouts.count; j++) + tracef(k, " %%%d", bb->liveouts.item[j]->id); + tracef(k, "\n"); + } + + if (bb->phis.count > 0) + { + tracef(k, "%c: PHIS:", k); + for (j=0; jphis.count; j++) + { + struct vreg* vreg = bb->phis.item[j].left; + struct phi* phi = bb->phis.item[j].right; + + tracef(k, " %%%d(via %s)=>%%%d", + phi->ir->result->id, + phi->prev->name, + vreg->id); + } + tracef(k, "\n"); + } + + for (j=0; jhops.count; j++) + hop_print(k, bb->hops.item[j]); + } +} + +static void emit_procedure(struct procedure* proc) +{ + int i, j; + + fprintf(outputfile, "\n.sect .text\n"); + for (i=0; iname)); + for (j=0; jhops.count; j++) + { + struct hop* hop = bb->hops.item[j]; + fprintf(outputfile, "%s", hop_render(hop)); + } + } +} + +static void write_cfg_graph(const char* name) +{ + int i; + + fprintf(cfg_dot_file, "subgraph \"%s\" {\n", name); + fprintf(cfg_dot_file, "\t\"%s\" [color=red];\n", cfg.entry->name); + + for (i=0; i \"%s\";\n", + cfg.graph.item[i].left->name, + cfg.graph.item[i].right->name); + } + + fprintf(cfg_dot_file, "}\n"); +} + +static void write_dominance_graph(const char* name) +{ + int i; + + fprintf(dominance_dot_file, "subgraph \"%s\" {\n", name); + fprintf(dominance_dot_file, "\t\"%s\" [color=green];\n", cfg.entry->name); + + for (i=0; i \"%s\";\n", + dominance.graph.item[i].right->name, + dominance.graph.item[i].left->name); + } + + fprintf(dominance_dot_file, "}\n"); +} + +void procedure_compile(struct procedure* proc) +{ + current_proc = proc; + + pass_group_irs(); + print_blocks('1'); + + /* Passes from here on must preserve IR grouping */ + + pass_eliminate_trivial_blocks(); + pass_remove_dead_blocks(); + + print_blocks('2'); + update_graph_data(); + pass_split_critical_edges(); + update_graph_data(); + + /* Passes from here on can't alter the BB graph without also updating prevs + * and nexts (and then calling update_graph_data()). */ + + print_blocks('3'); + pass_wire_up_return_values(); + pass_convert_stack_ops(); + print_blocks('4'); + pass_convert_locals_to_ssa(); + print_blocks('5'); + pass_remove_dead_phis(); + pass_infer_types(); + print_blocks('6'); + + pass_instruction_selector(); + print_hops('7'); + pass_find_phi_congruence_groups(); + pass_live_vreg_analysis(); + print_hops('8'); + pass_register_allocator(); + pass_add_prologue_epilogue(); + print_hops('9'); + + emit_procedure(proc); + + if (cfg_dot_file) + write_cfg_graph(proc->name); + if (dominance_dot_file) + write_dominance_graph(proc->name); +} + +/* vim: set sw=4 ts=4 expandtab : */ + diff --git a/mach/proto/mcg/procedure.h b/mach/proto/mcg/procedure.h new file mode 100644 index 000000000..226db804c --- /dev/null +++ b/mach/proto/mcg/procedure.h @@ -0,0 +1,35 @@ +#ifndef PROCEDURE_H +#define PROCEDURE_H + +struct local +{ + int size; + int offset; + bool is_register; +}; + +struct procedure +{ + const char* name; + struct basicblock* entry; + struct basicblock* exit; + int locals_size; + int spills_size; + int saved_size; + int fp_to_ab; /* argument base (indexes up) */ + int fp_to_lb; /* locals base (indexes down) */ + int fp_to_sb; /* spill base (indexes up) */ + int fp_to_rb; /* saved registers base (indexes up) */ + ARRAYOF(struct basicblock) blocks; + IMAPOF(struct local) locals; + ARRAYOF(struct hreg) usedregs; +}; + +extern void procedure_compile(struct procedure* proc); +extern void procedure_update_bb_graph(struct procedure* proc); + +extern struct procedure* current_proc; + +#endif + +/* vim: set sw=4 ts=4 expandtab : */ diff --git a/mach/proto/mcg/reg.c b/mach/proto/mcg/reg.c new file mode 100644 index 000000000..d40deb171 --- /dev/null +++ b/mach/proto/mcg/reg.c @@ -0,0 +1,36 @@ +#include "mcg.h" + +static int vreg_count = 1; + +struct vreg* new_vreg(void) +{ + struct vreg* vreg = calloc(1, sizeof *vreg); + vreg->id = vreg_count++; + return vreg; +} + +struct hreg* new_hreg(const struct burm_register_data* brd) +{ + struct hreg* hreg = calloc(1, sizeof *hreg); + hreg->id = brd->id; + hreg->brd = brd; + hreg->attrs = brd->attrs; + hreg->is_stacked = false; + /* The aliases array needs to be initialised later. */ + return hreg; +} + +struct hreg* new_stacked_hreg(uint32_t attrs) +{ + static int hreg_count = 1; + struct hreg* hreg = calloc(1, sizeof *hreg); + hreg->id = aprintf("stacked_%d_id_%d", attrs, hreg_count++); + hreg->attrs = attrs; + hreg->is_stacked = true; + hreg->offset = -1; + array_append(&hreg->aliases, hreg); + return hreg; +} + +/* vim: set sw=4 ts=4 expandtab : */ + diff --git a/mach/proto/mcg/reg.h b/mach/proto/mcg/reg.h new file mode 100644 index 000000000..00c8220b5 --- /dev/null +++ b/mach/proto/mcg/reg.h @@ -0,0 +1,42 @@ +#ifndef REG_H +#define REG_H + +#define WITH_ATTR(a) (1<<(a)) + +struct phicongruence +{ + int id; + ARRAYOF(struct vreg) vregs; + ARRAYOF(struct hop) definitions; + uint32_t type; +}; + +struct hreg +{ + const char* id; + const struct burm_register_data* brd; + uint32_t attrs; + bool is_stacked; + int offset; + ARRAYOF(struct hreg) aliases; +}; + +struct vreg +{ + int id; + uint32_t type; + struct phicongruence* congruence; + struct hop* defined; + ARRAYOF(struct hop) used; +}; + +typedef PMAPOF(struct hreg, struct vreg) register_assignment_t; + +extern struct vreg* new_vreg(void); + +extern struct hreg* new_hreg(const struct burm_register_data* brd); +extern struct hreg* new_stacked_hreg(uint32_t type); + +#endif + +/* vim: set sw=4 ts=4 expandtab : */ diff --git a/mach/proto/mcg/symbol.c b/mach/proto/mcg/symbol.c new file mode 100644 index 000000000..ac5e78ce4 --- /dev/null +++ b/mach/proto/mcg/symbol.c @@ -0,0 +1,65 @@ +#include "mcg.h" + +static void init_idf(); +static struct idf* str2idf(char* tg, int cp); + +#define IDF_TYPE struct symbol +#define IDF_NAME symbol +#include +#include + +void symbol_init(void) +{ + init_idf(); +} + +bool symbol_exists(const char* name) +{ + return !!findidf((char*) name); +} + +struct symbol* symbol_get(const char* name) +{ + struct idf* p = str2idf((char*) name, 0); + p->symbol.name = p->id_text; + return &p->symbol; +} + +void symbol_declare(const char* name, bool is_exported, bool is_proc) +{ + struct symbol* s = symbol_get(name); + s->is_exported = is_exported; + + if (is_proc) + { + if (s->section == SECTION_UNKNOWN) + s->section = SECTION_TEXT; + else if (s->section != SECTION_TEXT) + fatal("section mismatch for '%s'", name); + } + + if (is_exported) + fprintf(outputfile, ".extern %s\n", platform_label(name)); +} + +struct symbol* symbol_walk(symbol_walker_t* cb, void* user) +{ + int i; + + for (i=0; isymbol; + if (cb(symbol, user)) + return symbol; + idf = idf->id_next; + } + } + + return NULL; +} + +/* vim: set sw=4 ts=4 expandtab : */ + diff --git a/mach/proto/mcg/treebuilder.c b/mach/proto/mcg/treebuilder.c new file mode 100644 index 000000000..2ead527fc --- /dev/null +++ b/mach/proto/mcg/treebuilder.c @@ -0,0 +1,1681 @@ +#include "mcg.h" + +static struct basicblock* current_bb; + +static int stackptr; +static struct ir* stack[64]; + +static struct ir* convert(struct ir* src, int srcsize, int destsize, int opcode); +static struct ir* appendir(struct ir* ir); +static void insn_ivalue(int opcode, arith value); + +static void reset_stack(void) +{ + stackptr = 0; +} + +static void push(struct ir* ir) +{ + if (stackptr == sizeof(stack)/sizeof(*stack)) + fatal("stack overflow"); + +#if 0 + /* If we try to push something which is too small, convert it to a word + * first. */ + + if (ir->size < EM_wordsize) + ir = convertu(ir, EM_wordsize); +#endif + + stack[stackptr++] = ir; +} + +static struct ir* pop(int size) +{ + if (size < EM_wordsize) + size = EM_wordsize; + + if (stackptr == 0) + { + /* Nothing in our fake stack, so we have to read from the real stack. */ + + if (size < EM_wordsize) + size = EM_wordsize; + return + appendir( + new_ir0( + IR_POP, size + ) + ); + } + else + { + struct ir* ir = stack[--stackptr]; + +#if 0 + /* If we try to pop something which is smaller than a word, convert it first. */ + + if (size < EM_wordsize) + ir = convertu(ir, size); +#endif + + if (ir->size != size) + { + if ((size == (EM_wordsize*2)) && (ir->size == EM_wordsize)) + { + /* Tried to read a long, but we got an int. Assemble the long + * out of two ints. Note that EM doesn't specify an order. */ + return + new_ir2( + IR_FROMIPAIR, size, + ir, + pop(EM_wordsize) + ); + } + else if ((size == EM_wordsize) && (ir->size == (EM_wordsize*2))) + { + /* Tried to read an int, but we got a long. */ + push( + new_ir1( + IR_FROML1, EM_wordsize, + ir + ) + ); + + return + new_ir1( + IR_FROML0, EM_wordsize, + ir + ); + } + else + fatal("expected an item on stack of size %d, but got %d\n", size, ir->size); + } + return ir; + } +} + +static void print_stack(void) +{ + int i; + + tracef('E', "E: stack:"); + for (i=0; iid, ir->size); + } + tracef('E', " (top)\n"); +} + +static struct ir* appendir(struct ir* ir) +{ + int i; + + assert(current_bb != NULL); + array_appendu(¤t_bb->irs, ir); + + ir_print('0', ir); + return ir; +} + +static void materialise_stack(void) +{ + int i; + + for (i=0; isize, + ir + ) + ); + } + + reset_stack(); +} + +void tb_filestart(void) +{ +} + +void tb_fileend(void) +{ +} + +void tb_regvar(struct procedure* procedure, arith offset, int size, int type, int priority) +{ + struct local* local = calloc(1, sizeof(*local)); + local->size = size; + local->offset = offset; + local->is_register = true; + imap_put(&procedure->locals, offset, local); +} + +static struct ir* address_of_external(const char* label, arith offset) +{ + if (offset != 0) + return + new_ir2( + IR_ADD, EM_pointersize, + new_labelir(label), + new_wordir(offset) + ); + else + return + new_labelir(label); +} + +static struct ir* convert(struct ir* src, int srcsize, int destsize, int opcode) +{ + if (srcsize == 1) + { + if ((opcode == IR_FROMSI) || (opcode == IR_FROMSL)) + { + src = new_ir1( + IR_EXTENDB, EM_wordsize, + src + ); + } + srcsize = EM_wordsize; + } + + if ((srcsize == 2) && (srcsize != EM_wordsize)) + { + if ((opcode == IR_FROMSI) || (opcode == IR_FROMSL)) + { + src = new_ir1( + IR_EXTENDH, EM_wordsize, + src + ); + } + srcsize = EM_wordsize; + } + + if (src->size == EM_wordsize) + {} + else if (src->size == (2*EM_wordsize)) + opcode++; + else + fatal("can't convert from %d to %d", src->size, destsize); + + return + new_ir1( + opcode, destsize, + src + ); +} + +static struct ir* compare(struct ir* left, struct ir* right, + int size, int opcode) +{ + if (size == EM_wordsize) + {} + else if (size == (2*EM_wordsize)) + opcode++; + else + fatal("can't compare things of size %d", size); + + return + new_ir2( + opcode, EM_wordsize, + left, right + ); +} + +static struct ir* store(int size, struct ir* address, int offset, struct ir* value) +{ + int opcode; + + if (size == 1) + { + opcode = IR_STOREB; + size = EM_wordsize; + } + else if ((size < EM_wordsize) && (size == 2)) + { + opcode = IR_STOREH; + size = EM_wordsize; + } + else + opcode = IR_STORE; + + if (offset > 0) + address = new_ir2( + IR_ADD, EM_pointersize, + address, new_wordir(offset) + ); + + return + new_ir2( + opcode, size, + address, value + ); +} + +static struct ir* load(int size, struct ir* address, int offset) +{ + int opcode; + + if (size == 1) + { + opcode = IR_LOADB; + size = EM_wordsize; + } + else if ((size < EM_wordsize) && (size == 2)) + { + opcode = IR_LOADH; + size = EM_wordsize; + } + else + opcode = IR_LOAD; + + if (offset > 0) + address = new_ir2( + IR_ADD, EM_pointersize, + address, new_wordir(offset) + ); + + return + new_ir1( + opcode, size, + address + ); +} + +static struct ir* tristate_compare(int size, int opcode) +{ + struct ir* right = pop(size); + struct ir* left = pop(size); + + return compare(left, right, size, opcode); +} + +static struct ir* tristate_compare0(int size, int opcode) +{ + struct ir* right = new_wordir(0); + struct ir* left = pop(size); + + return compare(left, right, size, opcode); +} + +static void simple_convert(int opcode) +{ + struct ir* destsize = pop(EM_wordsize); + struct ir* srcsize = pop(EM_wordsize); + struct ir* value; + + assert(srcsize->opcode == IR_CONST); + assert(destsize->opcode == IR_CONST); + + value = pop(srcsize->u.ivalue); + push( + convert(value, srcsize->u.ivalue, destsize->u.ivalue, opcode) + ); +} + +static void simple_branch2(int opcode, int size, + struct basicblock* truebb, struct basicblock* falsebb, + int irop) +{ + struct ir* right = pop(size); + struct ir* left = pop(size); + + materialise_stack(); + appendir( + new_ir2( + irop, 0, + compare(left, right, size, IR_COMPARESI), + new_ir2( + IR_PAIR, 0, + new_bbir(truebb), + new_bbir(falsebb) + ) + ) + ); +} + +static void compare0_branch2(int opcode, + struct basicblock* truebb, struct basicblock* falsebb, + int irop) +{ + push( + new_wordir(0) + ); + + simple_branch2(opcode, EM_wordsize, truebb, falsebb, irop); +} + +static void simple_test(int size, int irop) +{ + push( + new_ir1( + irop, EM_wordsize, + tristate_compare0(size, IR_COMPARESI) + ) + ); +} + +static void simple_test_neg(int size, int irop) +{ + simple_test(size, irop); + + push( + new_ir1( + IR_NOT, EM_wordsize, + pop(EM_wordsize) + ) + ); +} + +static void helper_function(const char* name) +{ + /* Delegates to a helper function; these leave their result on the stack + * rather than returning values through lfr. */ + + materialise_stack(); + appendir( + new_ir1( + IR_CALL, 0, + new_labelir(name) + ) + ); +} + +static void insn_simple(int opcode) +{ + switch (opcode) + { + case op_bra: + { + struct ir* dest = pop(EM_pointersize); + + materialise_stack(); + appendir( + new_ir1( + IR_JUMP, 0, + dest + ) + ); + break; + } + + case op_cii: simple_convert(IR_FROMSI); break; + case op_ciu: simple_convert(IR_FROMSI); break; + case op_cui: simple_convert(IR_FROMUI); break; + case op_cfu: simple_convert(IR_FROMUF); break; + case op_cfi: simple_convert(IR_FROMSF); break; + case op_cif: simple_convert(IR_FROMSI); break; + case op_cuf: simple_convert(IR_FROMUI); break; + case op_cff: simple_convert(IR_FROMSF); break; + + case op_cmp: + push( + tristate_compare(EM_pointersize, IR_COMPAREUI) + ); + break; + + case op_teq: simple_test( EM_wordsize, IR_IFEQ); break; + case op_tne: simple_test_neg(EM_wordsize, IR_IFEQ); break; + case op_tlt: simple_test( EM_wordsize, IR_IFLT); break; + case op_tge: simple_test_neg(EM_wordsize, IR_IFLT); break; + case op_tle: simple_test( EM_wordsize, IR_IFLE); break; + case op_tgt: simple_test_neg(EM_wordsize, IR_IFLE); break; + + case op_cai: + { + struct ir* dest = pop(EM_pointersize); + + materialise_stack(); + appendir( + new_ir1( + IR_CALL, 0, + dest + ) + ); + break; + } + + case op_inc: + { + push( + new_ir2( + IR_ADD, EM_wordsize, + pop(EM_wordsize), + new_wordir(1) + ) + ); + break; + } + + case op_dec: + { + push( + new_ir2( + IR_SUB, EM_wordsize, + pop(EM_wordsize), + new_wordir(1) + ) + ); + break; + } + + case op_lim: + { + push( + new_ir1( + (EM_wordsize == 2) ? IR_LOAD : IR_LOADH, EM_wordsize, + new_labelir(".ignmask") + ) + ); + break; + } + + case op_sim: + { + appendir( + new_ir2( + (EM_wordsize == 2) ? IR_STORE : IR_STOREH, EM_wordsize, + new_labelir(".ignmask"), + pop(EM_wordsize) + ) + ); + break; + } + + case op_trp: helper_function(".trp"); break; + case op_sig: helper_function(".sig"); break; + + case op_rtt: + { + insn_ivalue(op_ret, 0); + break; + } + + /* FIXME: These instructions are really complex and barely used + * (Modula-2 bitset support, I believe). Leave them until later. */ + case op_set: helper_function(".unimplemented_set"); break; + case op_ior: helper_function(".unimplemented_ior"); break; + + case op_dch: + push( + new_ir1( + IR_CHAINFP, EM_pointersize, + pop(EM_pointersize) + ) + ); + break; + + case op_lpb: + push( + new_ir1( + IR_FPTOAB, EM_pointersize, + pop(EM_pointersize) + ) + ); + break; + + case op_lni: + { + /* Increment line number --- ignore. */ + break; + } + + default: + fatal("treebuilder: unknown simple instruction '%s'", + em_mnem[opcode - sp_fmnem]); + } +} + +static void insn_bvalue(int opcode, struct basicblock* leftbb, struct basicblock* rightbb) +{ + switch (opcode) + { + case op_zeq: compare0_branch2(opcode, leftbb, rightbb, IR_CJUMPEQ); break; + case op_zlt: compare0_branch2(opcode, leftbb, rightbb, IR_CJUMPLT); break; + case op_zle: compare0_branch2(opcode, leftbb, rightbb, IR_CJUMPLE); break; + + case op_zne: compare0_branch2(opcode, rightbb, leftbb, IR_CJUMPEQ); break; + case op_zge: compare0_branch2(opcode, rightbb, leftbb, IR_CJUMPLT); break; + case op_zgt: compare0_branch2(opcode, rightbb, leftbb, IR_CJUMPLE); break; + + case op_beq: simple_branch2(opcode, EM_wordsize, leftbb, rightbb, IR_CJUMPEQ); break; + case op_blt: simple_branch2(opcode, EM_wordsize, leftbb, rightbb, IR_CJUMPLT); break; + case op_ble: simple_branch2(opcode, EM_wordsize, leftbb, rightbb, IR_CJUMPLE); break; + + case op_bne: simple_branch2(opcode, EM_wordsize, rightbb, leftbb, IR_CJUMPEQ); break; + case op_bge: simple_branch2(opcode, EM_wordsize, rightbb, leftbb, IR_CJUMPLT); break; + case op_bgt: simple_branch2(opcode, EM_wordsize, rightbb, leftbb, IR_CJUMPLE); break; + + case op_bra: + { + materialise_stack(); + + appendir( + new_ir1( + IR_JUMP, 0, + new_bbir(leftbb) + ) + ); + break; + } + + case op_lae: + push( + new_bbir(leftbb) + ); + break; + + default: + fatal("treebuilder: unknown bvalue instruction '%s'", + em_mnem[opcode - sp_fmnem]); + } +} + +static void simple_alu1(int opcode, int size, int irop) +{ + struct ir* val = pop(size); + + push( + new_ir1( + irop, size, + val + ) + ); +} + +static void simple_alu2(int opcode, int size, int irop) +{ + struct ir* right = pop(size); + struct ir* left = pop(size); + + push( + new_ir2( + irop, size, + left, right + ) + ); +} + +static struct ir* extract_block_refs(struct basicblock* bb) +{ + struct ir* outir = NULL; + int i; + + for (i=0; iems.count; i++) + { + struct em* em = bb->ems.item[i]; + assert(em->opcode == op_bra); + assert(em->paramtype == PARAM_BVALUE); + + outir = new_ir2( + IR_PAIR, 0, + new_bbir(em->u.bvalue.left), + outir + ); + } + + return outir; +} + +static void change_by(struct ir* address, int amount) +{ + appendir( + store( + EM_wordsize, address, 0, + new_ir2( + IR_ADD, EM_wordsize, + load( + EM_wordsize, address, 0 + ), + new_wordir(amount) + ) + ) + ); +} + +static struct ir* ptradd(struct ir* address, int offset) +{ + if (offset == 0) + return address; + + return + new_ir2( + IR_ADD, EM_pointersize, + address, + new_wordir(offset) + ); +} + +static void blockmove(struct ir* dest, struct ir* src, struct ir* size) +{ + /* memmove stack: ( size src dest -- ) */ + push(size); + push(src); + push(dest); + + materialise_stack(); + appendir( + new_ir1( + IR_CALL, 0, + new_labelir("memmove") + ) + ); + appendir( + new_ir1( + IR_STACKADJUST, EM_pointersize, + new_wordir(EM_pointersize*2 + EM_wordsize) + ) + ); +} + +static void insn_ivalue(int opcode, arith value) +{ + switch (opcode) + { + case op_adi: simple_alu2(opcode, value, IR_ADD); break; + case op_sbi: simple_alu2(opcode, value, IR_SUB); break; + case op_mli: simple_alu2(opcode, value, IR_MUL); break; + case op_dvi: simple_alu2(opcode, value, IR_DIV); break; + case op_rmi: simple_alu2(opcode, value, IR_MOD); break; + case op_sli: simple_alu2(opcode, value, IR_ASL); break; + case op_sri: simple_alu2(opcode, value, IR_ASR); break; + case op_ngi: simple_alu1(opcode, value, IR_NEG); break; + + case op_adu: simple_alu2(opcode, value, IR_ADD); break; + case op_sbu: simple_alu2(opcode, value, IR_SUB); break; + case op_mlu: simple_alu2(opcode, value, IR_MUL); break; + case op_slu: simple_alu2(opcode, value, IR_LSL); break; + case op_sru: simple_alu2(opcode, value, IR_LSR); break; + case op_rmu: simple_alu2(opcode, value, IR_MODU); break; + case op_dvu: simple_alu2(opcode, value, IR_DIVU); break; + + case op_and: simple_alu2(opcode, value, IR_AND); break; + case op_ior: simple_alu2(opcode, value, IR_OR); break; + case op_xor: simple_alu2(opcode, value, IR_EOR); break; + case op_com: simple_alu1(opcode, value, IR_NOT); break; + + case op_adf: simple_alu2(opcode, value, IR_ADDF); break; + case op_sbf: simple_alu2(opcode, value, IR_SUBF); break; + case op_mlf: simple_alu2(opcode, value, IR_MULF); break; + case op_dvf: simple_alu2(opcode, value, IR_DIVF); break; + case op_ngf: simple_alu1(opcode, value, IR_NEGF); break; + + case op_cmu: /* fall through */ + case op_cms: push(tristate_compare(value, IR_COMPAREUI)); break; + case op_cmi: push(tristate_compare(value, IR_COMPARESI)); break; + case op_cmf: push(tristate_compare(value, IR_COMPAREF)); break; + + case op_lol: + push( + load( + EM_wordsize, + new_localir(value), 0 + ) + ); + break; + + case op_ldl: + push( + load( + EM_wordsize*2, + new_localir(value), 0 + ) + ); + break; + + case op_stl: + appendir( + store( + EM_wordsize, + new_localir(value), 0, + pop(EM_wordsize) + ) + ); + break; + + case op_sdl: + appendir( + store( + EM_wordsize*2, + new_localir(value), 0, + pop(EM_wordsize*2) + ) + ); + break; + + case op_lal: + push( + new_localir(value) + ); + break; + + case op_lil: + push( + load( + EM_wordsize, + load( + EM_pointersize, + new_localir(value), 0 + ), 0 + ) + ); + break; + + case op_sil: + appendir( + store( + EM_wordsize, + load( + EM_pointersize, + new_localir(value), 0 + ), 0, + pop(EM_wordsize) + ) + ); + break; + + case op_inl: + change_by(new_localir(value), 1); + break; + + case op_del: + change_by(new_localir(value), -1); + break; + + case op_zrl: + appendir( + store( + EM_wordsize, + new_localir(value), 0, + new_wordir(0) + ) + ); + break; + + case op_zrf: + { + struct ir* ir = new_constir(value, 0); + ir->opcode = IR_CONST; + push(ir); + break; + } + + case op_loe: + push( + load( + EM_wordsize, + new_labelir(".hol0"), value + ) + ); + break; + + case op_lae: + push( + new_ir2( + IR_ADD, EM_pointersize, + new_labelir(".hol0"), + new_wordir(value) + ) + ); + break; + + case op_ste: + appendir( + store( + EM_wordsize, + new_labelir(".hol0"), value, + pop(EM_wordsize) + ) + ); + break; + + case op_zre: + appendir( + store( + EM_wordsize, + new_labelir(".hol0"), value, + new_wordir(0) + ) + ); + break; + + case op_loc: + push( + new_wordir(value) + ); + break; + + case op_loi: + { + struct ir* ptr = pop(EM_pointersize); + int offset = 0; + + /* FIXME: this is awful; need a better way of dealing with + * non-standard EM sizes. */ + if (value > (EM_wordsize*2)) + appendir(ptr); + + while (value > 0) + { + int s; + if (value > (EM_wordsize*2)) + s = EM_wordsize*2; + else + s = value; + + push( + load( + s, + ptr, offset + ) + ); + + value -= s; + offset += s; + } + + assert(value == 0); + break; + } + + case op_lof: + { + struct ir* ptr = pop(EM_pointersize); + + push( + load( + EM_wordsize, + ptr, value + ) + ); + break; + } + + case op_ldf: + { + struct ir* ptr = pop(EM_pointersize); + + push( + load( + EM_wordsize*2, + ptr, value + ) + ); + break; + } + + case op_sti: + { + struct ir* ptr = pop(EM_pointersize); + int offset = 0; + + /* FIXME: this is awful; need a better way of dealing with + * non-standard EM sizes. */ + if (value > (EM_wordsize*2)) + appendir(ptr); + + while (value > 0) + { + int s; + if (value > (EM_wordsize*2)) + s = EM_wordsize*2; + else + s = value; + + appendir( + store( + s, + ptr, offset, + pop(s) + ) + ); + + value -= s; + offset += s; + } + + assert(value == 0); + break; + } + + case op_stf: + { + struct ir* ptr = pop(EM_pointersize); + struct ir* val = pop(EM_wordsize); + + appendir( + store( + EM_wordsize, + ptr, value, + val + ) + ); + break; + } + + case op_sdf: + { + struct ir* ptr = pop(EM_pointersize); + struct ir* val = pop(EM_wordsize*2); + + appendir( + store( + EM_wordsize*2, + ptr, value, + val + ) + ); + break; + } + + case op_ads: + { + struct ir* off = pop(value); + struct ir* ptr = pop(EM_pointersize); + + if (value != EM_pointersize) + off = convert(off, value, EM_pointersize, IR_FROMUI); + + push( + new_ir2( + IR_ADD, EM_pointersize, + ptr, off + ) + ); + break; + } + + case op_adp: + { + struct ir* ptr = pop(EM_pointersize); + + push( + new_ir2( + IR_ADD, EM_pointersize, + ptr, + new_wordir(value) + ) + ); + break; + } + + case op_sbs: + { + struct ir* right = pop(EM_pointersize); + struct ir* left = pop(EM_pointersize); + + struct ir* delta = + new_ir2( + IR_SUB, EM_pointersize, + left, right + ); + + if (value != EM_pointersize) + delta = convert(delta, EM_pointersize, value, IR_FROMUI); + + push(delta); + break; + } + + case op_dup: + { + struct ir* v = pop(value); + appendir(v); + push(v); + push(v); + break; + } + + case op_exg: + { + struct ir* v1 = pop(value); + struct ir* v2 = pop(value); + push(v1); + push(v2); + break; + } + + case op_asp: + { + switch (value) + { + case 0: + break; + + case -1: + case -2: + case -4: + case -8: + push(new_anyir(-value)); + break; + + default: + while ((value > 0) && (stackptr > 0)) + { + struct ir* ir = pop(stack[stackptr-1]->size); + value -= ir->size; + } + + if (value != 0) + { + appendir( + new_ir1( + IR_STACKADJUST, EM_pointersize, + new_wordir(value) + ) + ); + } + break; + } + break; + } + + case op_ass: + appendir( + new_ir1( + IR_STACKADJUST, EM_pointersize, + pop(value) + ) + ); + break; + + case op_ret: + { + if (value > 0) + { + struct ir* retval = pop(value); + materialise_stack(); + appendir( + new_ir1( + IR_SETRET, value, + retval + ) + ); + } + + if (!current_proc->exit) + { + current_proc->exit = bb_get(NULL); + array_append(¤t_proc->blocks, current_proc->exit); + + /* This is actually ignored --- the entire block gets special + * treatment. But a lot of the rest of the code assumes that + * all basic blocks have one instruction, so we insert one. */ + + array_append(¤t_proc->exit->irs, + new_ir0( + IR_RET, 0 + ) + ); + } + + appendir( + new_ir1( + IR_JUMP, 0, + new_bbir(current_proc->exit) + ) + ); + break; + } + + case op_lfr: + { + push( + appendir( + new_ir0( + IR_GETRET, value + ) + ) + ); + break; + } + + case op_csa: + case op_csb: + { + const char* helper = aprintf(".%s", + (opcode == op_csa) ? "csa" : "csb"); + struct ir* descriptor = pop(EM_pointersize); + + if (descriptor->opcode != IR_LABEL) + fatal("csa/csb are only supported if they refer " + "directly to a descriptor block"); + + push(descriptor); + materialise_stack(); + appendir( + new_ir2( + IR_FARJUMP, 0, + new_labelir(helper), + extract_block_refs(bb_get(descriptor->u.lvalue)) + ) + ); + break; + } + + case op_sar: + case op_lar: + case op_aar: + { + const char* helper; + if (value != EM_wordsize) + fatal("sar/lar/aar are only supported when using " + "word-size descriptors"); + + switch (opcode) + { + case op_sar: helper = ".sar4"; break; + case op_lar: helper = ".lar4"; break; + case op_aar: helper = ".aar4"; break; + } + + materialise_stack(); + /* No push here, because the helper function leaves the result on + * the physical stack (which is very dubious). */ + appendir( + new_ir1( + IR_CALL, 0, + new_labelir(helper) + ) + ); + break; + } + + case op_lxl: + { + struct ir* ir; + + /* Walk the static chain. */ + + ir = new_ir0( + IR_GETFP, EM_pointersize + ); + + while (value--) + { + ir = new_ir1( + IR_CHAINFP, EM_pointersize, + ir + ); + } + + push(ir); + break; + } + + case op_lxa: + { + struct ir* ir; + + /* Walk the static chain. */ + + ir = new_ir0( + IR_GETFP, EM_pointersize + ); + + while (value--) + { + ir = new_ir1( + IR_CHAINFP, EM_pointersize, + ir + ); + } + + push( + new_ir1( + IR_FPTOAB, EM_pointersize, + ir + ) + ); + break; + } + + case op_fef: + { + struct ir* f = pop(value); + + /* fef is implemented by calling a helper function which then mutates + * the stack. We read the return values off the stack when retracting + * the stack pointer. */ + + push(f); + push(new_wordir(0)); + + materialise_stack(); + appendir( + new_ir1( + IR_CALL, 0, + new_labelir((value == 4) ? ".fef4" : ".fef8") + ) + ); + + /* exit, leaving an int and then a float (or double) on the stack. */ + break; + } + + case op_fif: + { + /* fif is implemented by calling a helper function which then mutates + * the stack. We read the return values off the stack when retracting + * the stack pointer. */ + + /* We start with two floats on the stack. */ + + materialise_stack(); + appendir( + new_ir1( + IR_CALL, 0, + new_labelir((value == 4) ? ".fif4" : ".fif8") + ) + ); + + /* exit, leaving two floats (or doubles) on the stack. */ + break; + } + + case op_lor: + { + switch (value) + { + case 0: + push( + appendir( + new_ir1( + IR_FPTOLB, EM_pointersize, + new_ir0( + IR_GETFP, EM_pointersize + ) + ) + ) + ); + break; + + case 1: + push( + appendir( + new_ir0( + IR_GETSP, EM_pointersize + ) + ) + ); + break; + + case 2: + helper_function(".unimplemented_lor_2"); + break; + + default: + fatal("'lor %d' not supported", value); + } + + break; + } + + case op_str: + { + switch (value) + { + case 0: + appendir( + new_ir1( + IR_SETFP, EM_pointersize, + pop(EM_pointersize) + ) + ); + break; + + case 1: + appendir( + new_ir1( + IR_SETSP, EM_pointersize, + pop(EM_pointersize) + ) + ); + break; + + case 2: + helper_function(".unimplemented_str_2"); + break; + + default: + fatal("'str %d' not supported", value); + } + + break; + } + + case op_blm: + { + /* Input stack: ( src dest -- ) */ + struct ir* dest = pop(EM_pointersize); + struct ir* src = pop(EM_pointersize); + blockmove(dest, src, new_wordir(value)); + break; + } + + case op_bls: + { + /* Input stack: ( src dest size -- ) */ + struct ir* dest = pop(EM_pointersize); + struct ir* src = pop(EM_pointersize); + struct ir* size = pop(EM_wordsize); + blockmove(dest, src, size); + break; + } + + case op_los: + { + /* Copy an arbitrary amount to the stack. */ + struct ir* bytes = pop(EM_wordsize); + struct ir* address = pop(EM_pointersize); + + materialise_stack(); + appendir( + new_ir1( + IR_STACKADJUST, EM_pointersize, + new_ir1( + IR_NEG, EM_wordsize, + bytes + ) + ) + ); + + push( + new_ir0( + IR_GETSP, EM_pointersize + ) + ); + push(address); + push(bytes); + materialise_stack(); + appendir( + new_ir1( + IR_CALL, 0, + new_labelir("memcpy") + ) + ); + appendir( + new_ir1( + IR_STACKADJUST, EM_pointersize, + new_wordir(EM_pointersize*2 + EM_wordsize) + ) + ); + break; + } + + case op_sts: + { + /* Copy an arbitrary amount from the stack. */ + struct ir* bytes = pop(EM_wordsize); + struct ir* dest = pop(EM_pointersize); + struct ir* src; + + materialise_stack(); + src = appendir( + new_ir0( + IR_GETSP, EM_pointersize + ) + ); + + push(dest); + push(src); + push(bytes); + materialise_stack(); + appendir( + new_ir1( + IR_CALL, 0, + new_labelir("memcpy") + ) + ); + appendir( + new_ir1( + IR_STACKADJUST, EM_pointersize, + new_ir2( + IR_ADD, EM_wordsize, + new_wordir(EM_pointersize*2 + EM_wordsize), + bytes + ) + ) + ); + break; + } + + /* FIXME: These instructions are really complex and barely used + * (Modula-2 bitset support, I believe). Leave them until leter. */ + case op_inn: + { + push( + new_wordir(value) + ); + + helper_function(".inn"); + break; + } + + case op_lin: + { + /* Set line number --- ignore. */ + break; + } + + default: + fatal("treebuilder: unknown ivalue instruction '%s'", + em_mnem[opcode - sp_fmnem]); + } +} + +static void insn_lvalue(int opcode, const char* label, arith offset) +{ + switch (opcode) + { + case op_lpi: + case op_lae: + push( + address_of_external(label, offset) + ); + break; + + case op_loe: + push( + new_ir1( + IR_LOAD, EM_wordsize, + address_of_external(label, offset) + ) + ); + break; + + case op_lde: + push( + new_ir1( + IR_LOAD, EM_wordsize*2, + address_of_external(label, offset) + ) + ); + break; + + case op_ste: + appendir( + new_ir2( + IR_STORE, EM_wordsize, + address_of_external(label, offset), + pop(EM_wordsize) + ) + ); + break; + + case op_sde: + appendir( + new_ir2( + IR_STORE, EM_wordsize*2, + address_of_external(label, offset), + pop(EM_wordsize*2) + ) + ); + break; + + case op_zre: + appendir( + new_ir2( + IR_STORE, EM_wordsize, + address_of_external(label, offset), + new_wordir(0) + ) + ); + break; + + case op_ine: + appendir( + new_ir2( + IR_STORE, EM_wordsize, + address_of_external(label, offset), + new_ir2( + IR_ADD, EM_wordsize, + new_ir1( + IR_LOAD, EM_wordsize, + address_of_external(label, offset) + ), + new_wordir(1) + ) + ) + ); + break; + + case op_dee: + appendir( + new_ir2( + IR_STORE, EM_wordsize, + address_of_external(label, offset), + new_ir2( + IR_ADD, EM_wordsize, + new_ir1( + IR_LOAD, EM_wordsize, + address_of_external(label, offset) + ), + new_wordir(-1) + ) + ) + ); + break; + + case op_cal: + assert(offset == 0); + materialise_stack(); + appendir( + new_ir1( + IR_CALL, 0, + new_labelir(label) + ) + ); + break; + + case op_bra: + assert(offset == 0); + materialise_stack(); + appendir( + new_ir1( + IR_JUMP, 0, + new_labelir(label) + ) + ); + break; + + case op_gto: + { + struct ir* descriptor = pop(EM_pointersize); + + appendir( + new_ir1( + IR_SETSP, EM_pointersize, + load(EM_pointersize, descriptor, EM_pointersize*2) + ) + ); + appendir( + new_ir1( + IR_SETFP, EM_pointersize, + load(EM_pointersize, descriptor, EM_pointersize*1) + ) + ); + appendir( + new_ir1( + IR_JUMP, 0, + load(EM_pointersize, descriptor, EM_pointersize*0) + ) + ); + break; + } + + case op_fil: + { + /* Set filename --- ignore. */ + break; + } + + default: + fatal("treebuilder: unknown lvalue instruction '%s'", + em_mnem[opcode - sp_fmnem]); + } +} + +static void generate_tree(struct basicblock* bb) +{ + int i; + + tracef('0', "0: block %s\n", bb->name); + + current_bb = bb; + reset_stack(); + + for (i=0; iems.count; i++) + { + struct em* em = bb->ems.item[i]; + tracef('E', "E: read %s ", em_mnem[em->opcode - sp_fmnem]); + switch (em->paramtype) + { + case PARAM_NONE: + tracef('E', "\n"); + insn_simple(em->opcode); + break; + + case PARAM_IVALUE: + tracef('E', "value=%d\n", em->u.ivalue); + insn_ivalue(em->opcode, em->u.ivalue); + break; + + case PARAM_LVALUE: + tracef('E', "label=%s offset=%d\n", + em->u.lvalue.label, em->u.lvalue.offset); + insn_lvalue(em->opcode, em->u.lvalue.label, em->u.lvalue.offset); + break; + + case PARAM_BVALUE: + tracef('E', "true=%s", em->u.bvalue.left->name); + if (em->u.bvalue.right) + tracef('E', " false=%s", em->u.bvalue.right->name); + tracef('E', "\n"); + insn_bvalue(em->opcode, em->u.bvalue.left, em->u.bvalue.right); + break; + + default: + assert(0); + } + + if (tracing('E')) + print_stack(); + } + + /* Yes, we are allowed to leave stuff on the stack at the end of the procedure. + * It's discarded as part of the function return. */ +} + +void tb_procedure(void) +{ + int i; + + for (i=0; iblocks.count; i++) + generate_tree(current_proc->blocks.item[i]); +} + +/* vim: set sw=4 ts=4 expandtab : */ diff --git a/mach/proto/ncg/compute.c b/mach/proto/ncg/compute.c index f407aa8ae..d32417e68 100644 --- a/mach/proto/ncg/compute.c +++ b/mach/proto/ncg/compute.c @@ -120,6 +120,7 @@ string tostring(n) register word n; { return(mystrcpy(buf)); } +void compute(node, presult) register node_p node; register result_t *presult; { result_t leaf1,leaf2; register token_p tp; diff --git a/mach/proto/ncg/data.h b/mach/proto/ncg/data.h index c1d0e183e..ddd232b98 100644 --- a/mach/proto/ncg/data.h +++ b/mach/proto/ncg/data.h @@ -12,13 +12,13 @@ typedef struct cost { typedef struct { string ea_str; word ea_off; -} addr_t; +} address_t; typedef struct { int t_token; /* kind of token, -1 for register */ union { word aw; /* integer type */ - addr_t aa; /* address type */ + address_t aa; /* address type */ int ar; /* register type */ } t_att[TOKENSIZE]; } token_t,*token_p; diff --git a/mach/proto/ncg/equiv.c b/mach/proto/ncg/equiv.c index a78123180..ace068882 100644 --- a/mach/proto/ncg/equiv.c +++ b/mach/proto/ncg/equiv.c @@ -29,6 +29,8 @@ int maxindex; int regclass[NREGS]; struct perm *perms; +void permute(); + struct perm * tuples(regls,nregneeded) rl_p *regls; { int class=0; @@ -64,6 +66,7 @@ tuples(regls,nregneeded) rl_p *regls; { return(perms); } +void permute(index) { register struct perm *pp; register rl_p rlp; diff --git a/mach/proto/ncg/fillem.c b/mach/proto/ncg/fillem.c index 516239b3d..447faeb41 100644 --- a/mach/proto/ncg/fillem.c +++ b/mach/proto/ncg/fillem.c @@ -83,6 +83,13 @@ extern short em_ptyp[]; extern double atof(); void prolog(full nlocals); +void mes(); +void bss(); +void savelab(); +void dumplab(); +void part_flush(); +void xdumplab(); +void switchseg(); /* Own version of atol that continues computing on overflow. We don't know that about the ANSI C one. @@ -136,6 +143,7 @@ in_start() { in_finish() { } +void fillemlines() { register int t,i; register struct emline *lp; @@ -226,6 +234,7 @@ fillemlines() { } } +void dopseudo() { register b,t; register full n; @@ -605,6 +614,7 @@ char *strarg(t) { return(mystrcpy(argstr)); } +void bss(n,t,b) full n; { register long s = 0; @@ -677,6 +687,7 @@ swtxt() { switchseg(SEGTXT); } +void switchseg(s) { if (s == curseg) @@ -686,6 +697,7 @@ switchseg(s) { fprintf(codefile,"%s\n",segname[s]); } +void savelab() { register char *p,*q; @@ -700,6 +712,7 @@ savelab() { ; } +void dumplab() { if (labstr[0] == 0) @@ -709,6 +722,7 @@ dumplab() { labstr[0] = 0; } +void xdumplab() { if (labstr[0] == 0) @@ -717,6 +731,7 @@ xdumplab() { newdlb(labstr); } +void part_flush() { /* diff --git a/mach/proto/ncg/gencode.c b/mach/proto/ncg/gencode.c index b9b89022c..68676868e 100644 --- a/mach/proto/ncg/gencode.c +++ b/mach/proto/ncg/gencode.c @@ -72,7 +72,7 @@ genstr(stringno) { fputs(codestrings[stringno],codefile); } -string ad2str(ad) addr_t ad; { +string ad2str(ad) address_t ad; { static char buf[100]; if (ad.ea_str==0) @@ -87,7 +87,7 @@ string ad2str(ad) addr_t ad; { return(mystrcpy(buf)); } -praddr(ad) addr_t ad; { +praddr(ad) address_t ad; { if (ad.ea_str==0 || *(ad.ea_str) == '\0') fprintf(codefile,WRD_FMT,ad.ea_off); @@ -108,6 +108,7 @@ gennl() { putc('\n',codefile); } +void prtoken(tp,leadingchar) token_p tp; { register c; register char *code; diff --git a/mach/proto/ncg/label.c b/mach/proto/ncg/label.c index 88e36ee2e..0c192589c 100644 --- a/mach/proto/ncg/label.c +++ b/mach/proto/ncg/label.c @@ -7,6 +7,7 @@ static label_p label_list = (label_p)0; extern char *myalloc(); +void add_label(num, height, flth) { register label_p lbl = (label_p)0; diff --git a/mach/proto/ncg/regvar.c b/mach/proto/ncg/regvar.c index dd791d60a..4c11da2b1 100644 --- a/mach/proto/ncg/regvar.c +++ b/mach/proto/ncg/regvar.c @@ -42,6 +42,7 @@ linkreg(of,sz,tp,sc) long of; { return(rvlp); } +void tryreg(rvlp,typ) register struct regvar *rvlp; { int score; register i; diff --git a/mach/proto/ncg/result.h b/mach/proto/ncg/result.h index 7ceb2f114..fdb9e16e1 100644 --- a/mach/proto/ncg/result.h +++ b/mach/proto/ncg/result.h @@ -9,7 +9,7 @@ struct result { union { word e_con; int e_reg; - addr_t e_addr; + address_t e_addr; } e_v; /* value */ }; diff --git a/mach/proto/ncg/salloc.c b/mach/proto/ncg/salloc.c index 1826f1793..e110d75ad 100644 --- a/mach/proto/ncg/salloc.c +++ b/mach/proto/ncg/salloc.c @@ -32,6 +32,8 @@ static char rcsid[] = "$Id$"; char *stab[MAXSTAB]; int nstab=0; +void chkstr(); + string myalloc(size) { register string p; @@ -72,6 +74,7 @@ compar(p1,p2) char **p1,**p2; { return(1); } +void garbage_collect() { register i; struct emline *emlp; @@ -116,6 +119,7 @@ garbage_collect() { nstab = fillp-stab; } +void chkstr(str,used) string str; char used[]; { register low,middle,high; diff --git a/mach/proto/ncg/state.c b/mach/proto/ncg/state.c index 23d074bc7..4656ba872 100644 --- a/mach/proto/ncg/state.c +++ b/mach/proto/ncg/state.c @@ -23,6 +23,8 @@ static char rcsid[] = "$Id$"; extern int nstab; /* salloc.c */ +void bmove(); + savestatus(sp) register state_p sp; { sp->st_sh = stackheight; @@ -57,6 +59,7 @@ restorestatus(sp) register state_p sp; { popstr(sp->st_ns); } +void bmove(from,to,nbytes) register short *from,*to; register nbytes; { if (nbytes<=0) diff --git a/mach/proto/ncg/subr.c b/mach/proto/ncg/subr.c index 7d99ebcee..0f1b8edc4 100644 --- a/mach/proto/ncg/subr.c +++ b/mach/proto/ncg/subr.c @@ -49,6 +49,7 @@ match(tp,tep,optexp) register token_p tp; register set_p tep; { return(result.e_v.e_con); } +void instance(instno,token) register token_p token; { register inst_p inp; int i; @@ -145,6 +146,7 @@ instance(instno,token) register token_p token; { } } +void cinstance(instno,token,tp,regno) register token_p token,tp; { register inst_p inp; int i; diff --git a/mach/proto/top/top.c b/mach/proto/top/top.c index 5a9f842f8..5d57fa1de 100644 --- a/mach/proto/top/top.c +++ b/mach/proto/top/top.c @@ -23,6 +23,9 @@ struct variable ANY; /* ANY symbol matching any instruction */ char *REST; /* Opcode of first instruction not matched by current pattern */ +void labeldef(); +void set_opcode(); + #include "gen.c" @@ -170,6 +173,7 @@ write_first(w) /* Try to recognize the opcode part of an instruction */ +void set_opcode(ip) register instr_p ip; { @@ -318,6 +322,7 @@ bool split_operands(ip) +void labeldef(ip) register instr_p ip; { @@ -325,7 +330,7 @@ labeldef(ip) int oplen; p = ip->rest_line; - while( *p != LABEL_TERMINATOR) p++; + while(*p && (*p != LABEL_TERMINATOR)) p++; oplen = p - ip->rest_line; if (oplen == 0 || oplen > MAXOPLEN) return; strncpy(ip->op[0],ip->rest_line,oplen); diff --git a/mach/vc4/ncg/mach.c b/mach/vc4/ncg/mach.c index 124e8a965..8832f744f 100644 --- a/mach/vc4/ncg/mach.c +++ b/mach/vc4/ncg/mach.c @@ -54,7 +54,7 @@ void prolog(full nlocals) framesize = nlocals; } -mes(word type) +void mes(word type) { int argt ; diff --git a/modules/h/em_label.h b/modules/h/em_label.h index f267364a3..018b0d345 100644 --- a/modules/h/em_label.h +++ b/modules/h/em_label.h @@ -4,4 +4,5 @@ */ /* $Id$ */ -#define label unsigned int +typedef unsigned int label; + diff --git a/modules/src/data/array.c b/modules/src/data/array.c new file mode 100644 index 000000000..2847bbdd4 --- /dev/null +++ b/modules/src/data/array.c @@ -0,0 +1,127 @@ +#include +#include +#include +#include +#include "array.h" + +static void extend(struct array* array) +{ + if (array->count == array->max) + { + int newmax = (array->max == 0) ? 8 : (array->max * 2); + struct array* newarray = realloc(array->item, newmax * sizeof(*newarray)); + + array->max = newmax; + array->item = newarray; + } +} + +void array_append(void* arrayp, void* value) +{ + struct array* array = arrayp; + + extend(array); + array->item[array->count] = value; + array->count++; +} + +int array_indexof(void* arrayp, void* value) +{ + struct array* array = arrayp; + int i; + + for (i=0; icount; i++) + if (array->item[i] == value) + return i; + + return -1; +} + +bool array_contains(void* arrayp, void* value) +{ + return (array_indexof(arrayp, value) != -1); +} + +bool array_appendu(void* arrayp, void* value) +{ + if (array_contains(arrayp, value)) + return true; + + array_append(arrayp, value); + return false; +} + +void array_insert(void* arrayp, void* value, int before) +{ + struct array* array = arrayp; + + extend(array); + memmove(&array->item[before+1], &array->item[before], + (array->count-before) * sizeof(*array)); + array->item[before] = value; + array->count++; +} + +void array_remove(void* arrayp, void* value) +{ + struct array* array = arrayp; + int i; + + for (i=0; icount; i++) + { + if (array->item[i] == value) + { + while (i < (array->count-1)) + { + array->item[i] = array->item[i+1]; + i++; + } + array->count--; + return; + } + } +} + +void* array_pop(void* arrayp) +{ + struct array* array = arrayp; + + assert(array->count > 0); + return array->item[array->count--]; +} + +void array_appendall(void* arrayp, void* srcp) +{ + struct array* array = arrayp; + struct array* src = srcp; + int i; + + for (i=0; icount; i++) + array_append(array, src->item[i]); +} + +void array_removeall(void* arrayp, void* srcp) +{ + struct array* array = arrayp; + struct array* src = srcp; + int i; + + for (i=0; icount; i++) + array_remove(array, src->item[i]); +} + +bool array_appendallu(void* arrayp, void* srcp) +{ + struct array* array = arrayp; + struct array* src = srcp; + bool unchanged = true; + int i; + + for (i=0; icount; i++) + unchanged &= array_appendu(array, src->item[i]); + + return unchanged; +} + +/* vim: set sw=4 ts=4 expandtab : */ + diff --git a/modules/src/data/array.h b/modules/src/data/array.h new file mode 100644 index 000000000..6ec497566 --- /dev/null +++ b/modules/src/data/array.h @@ -0,0 +1,37 @@ +#ifndef ARRAY_H +#define ARRAY_H + +/* Danger, Will Robinson! The type and the macro must be compatible. */ + +struct array +{ + void** item; + int count; + int max; +}; + +#define ARRAYOF(TYPE) \ + struct { \ + TYPE** item; \ + int count; \ + int max; \ + } + +extern void array_append(void* array, void* value); +extern bool array_appendu(void* array, void* value); +extern void array_insert(void* array, void* value, int before); +extern void array_remove(void* array, void* value); +extern bool array_contains(void* array, void* value); +extern int array_indexof(void* array, void* value); + +#define array_push(a, v) array_append(a, v) +extern void* array_pop(void* array); + +extern void array_appendall(void* dest, void* src); +extern void array_removeall(void* dest, void* src); + +/* Returns false if *any* items were added. */ +extern bool array_appendallu(void* dest, void* src); + +#endif + diff --git a/modules/src/data/astring.c b/modules/src/data/astring.c new file mode 100644 index 000000000..7da06e9fa --- /dev/null +++ b/modules/src/data/astring.c @@ -0,0 +1,27 @@ +#include +#include +#include + +const char* aprintf(const char* fmt, ...) +{ + int n; + char* p; + va_list ap; + + va_start(ap, fmt); + n = vsnprintf(NULL, 0, fmt, ap) + 1; + va_end(ap); + + p = malloc(n); + if (!p) + return NULL; + + va_start(ap, fmt); + vsnprintf(p, n, fmt, ap); + va_end(ap); + + return p; +} + +/* vim: set sw=4 ts=4 expandtab : */ + diff --git a/modules/src/data/astring.h b/modules/src/data/astring.h new file mode 100644 index 000000000..483c0287d --- /dev/null +++ b/modules/src/data/astring.h @@ -0,0 +1,9 @@ +#ifndef ASTRING_H +#define ASTRING_H + +extern const char* aprintf(const char* fmt, ...); + +#endif + +/* vim: set sw=4 ts=4 expandtab : */ + diff --git a/modules/src/data/build.lua b/modules/src/data/build.lua new file mode 100644 index 000000000..9f5941808 --- /dev/null +++ b/modules/src/data/build.lua @@ -0,0 +1,7 @@ +clibrary { + name = "lib", + srcs = { "./*.c" }, + hdrs = { "./*.h" }, + deps = { "./*.h" }, +} + diff --git a/modules/src/data/diagnostics.c b/modules/src/data/diagnostics.c new file mode 100644 index 000000000..32ac6a0ee --- /dev/null +++ b/modules/src/data/diagnostics.c @@ -0,0 +1,38 @@ +#include +#include +#include +#include "diagnostics.h" + +const char* program_name = NULL; + +void warning(const char* msg, ...) +{ + va_list ap; + va_start(ap, msg); + + if (program_name) + fprintf(stderr, "%s: ", program_name); + fprintf(stderr, "warning: "); + vfprintf(stderr, msg, ap); + fprintf(stderr, "\n"); + + va_end(ap); +} + +void fatal(const char* msg, ...) +{ + va_list ap; + va_start(ap, msg); + + if (program_name) + fprintf(stderr, "%s: ", program_name); + fprintf(stderr, "fatal: "); + vfprintf(stderr, msg, ap); + fprintf(stderr, "\n"); + + va_end(ap); + abort(); +} + +/* vim: set sw=4 ts=4 expandtab : */ + diff --git a/modules/src/data/diagnostics.h b/modules/src/data/diagnostics.h new file mode 100644 index 000000000..7c2908fa0 --- /dev/null +++ b/modules/src/data/diagnostics.h @@ -0,0 +1,12 @@ +#ifndef DIAGNOSTICS_H +#define DIAGNOSTICS_H + +extern const char* program_name; + +extern void warning(const char* fmt, ...); +extern void fatal(const char* fmt, ...); + +#endif + +/* vim: set sw=4 ts=4 expandtab : */ + diff --git a/modules/src/data/imap.c b/modules/src/data/imap.c new file mode 100644 index 000000000..81982a704 --- /dev/null +++ b/modules/src/data/imap.c @@ -0,0 +1,74 @@ +#include +#include +#include "imap.h" + +static void append(void* mapp, int left, void* right) +{ + struct imap* map = mapp; + struct imap_node* node; + + if (map->count == map->max) + { + int newmax = (map->max == 0) ? 8 : (map->max * 2); + struct imap_node* newarray = realloc(map->item, newmax * sizeof(*newarray)); + + map->max = newmax; + map->item = newarray; + } + + node = &map->item[map->count]; + map->count++; + + node->left = left; + node->right = right; +} + +void imap_put(void* mapp, int left, void* right) +{ + struct imap* map = mapp; + int i; + + for (i=0; icount; i++) + { + struct imap_node* node = &map->item[i]; + if (node->left == left) + { + node->right = right; + return; + } + } + + append(map, left, right); +} + +void imap_add(void* mapp, int left, void* right) +{ + struct imap* map = mapp; + int i; + + for (i=0; icount; i++) + { + struct imap_node* node = &map->item[i]; + if ((node->left == left) && (node->right == right)) + return; + } + + append(map, left, right); +} + +void* imap_get(void* mapp, int left) +{ + struct imap* map = mapp; + int i; + + for (i=0; icount; i++) + { + struct imap_node* node = &map->item[i]; + if (node->left == left) + return node->right; + } + + return NULL; +} + + diff --git a/modules/src/data/imap.h b/modules/src/data/imap.h new file mode 100644 index 000000000..cb312e16c --- /dev/null +++ b/modules/src/data/imap.h @@ -0,0 +1,31 @@ +#ifndef IMAP_H +#define IMAP_H + +struct imap_node +{ + int left; + void* right; +}; + +/* Danger, Will Robinson! The type and the macro must be compatible. */ + +struct imap +{ + struct imap_node* item; + int count; + int max; +}; + +#define IMAPOF(RIGHT) \ + struct { \ + struct { int left; RIGHT* right; }* item; \ + int count; \ + int max; \ + } + +extern void imap_put(void* map, int left, void* right); +extern void imap_add(void* map, int left, void* right); +extern void* imap_get(void* map, int left); + +#endif + diff --git a/modules/src/data/pmap.c b/modules/src/data/pmap.c new file mode 100644 index 000000000..fffba7e90 --- /dev/null +++ b/modules/src/data/pmap.c @@ -0,0 +1,107 @@ +#include +#include +#include +#include "pmap.h" + +static void append(void* mapp, void* left, void* right) +{ + struct pmap* map = mapp; + struct pmap_node* node; + + if (map->count == map->max) + { + int newmax = (map->max == 0) ? 8 : (map->max * 2); + struct pmap_node* newarray = realloc(map->item, newmax * sizeof(*newarray)); + + map->max = newmax; + map->item = newarray; + } + + node = &map->item[map->count]; + map->count++; + + node->left = left; + node->right = right; +} + +void pmap_put(void* mapp, void* left, void* right) +{ + struct pmap* map = mapp; + int i; + + for (i=0; icount; i++) + { + struct pmap_node* node = &map->item[i]; + if (node->left == left) + { + node->right = right; + return; + } + } + + append(map, left, right); +} + +void pmap_add(void* mapp, void* left, void* right) +{ + struct pmap* map = mapp; + int i; + + for (i=0; icount; i++) + { + struct pmap_node* node = &map->item[i]; + if ((node->left == left) && (node->right == right)) + return; + } + + append(map, left, right); +} + +void pmap_remove(void* mapp, void* left, void* right) +{ + struct pmap* map = mapp; + int i; + + for (i=0; icount; i++) + { + struct pmap_node* node = &map->item[i]; + if ((node->left == left) && (node->right == right)) + { + memmove(node, node+1, sizeof(*node) * (map->count - i - 1)); + map->count--; + return; + } + } +} + +void* pmap_findleft(void* mapp, void* left) +{ + struct pmap* map = mapp; + int i; + + for (i=0; icount; i++) + { + struct pmap_node* node = &map->item[i]; + if (node->left == left) + return node->right; + } + + return NULL; +} + +void* pmap_findright(void* mapp, void* right) +{ + struct pmap* map = mapp; + int i; + + for (i=0; icount; i++) + { + struct pmap_node* node = &map->item[i]; + if (node->right == right) + return node->left; + } + + return NULL; +} + + diff --git a/modules/src/data/pmap.h b/modules/src/data/pmap.h new file mode 100644 index 000000000..a7980a3a3 --- /dev/null +++ b/modules/src/data/pmap.h @@ -0,0 +1,33 @@ +#ifndef PMAP_H +#define PMAP_H + +struct pmap_node +{ + void* left; + void* right; +}; + +/* Danger, Will Robinson! The type and the macro must be compatible. */ + +struct pmap +{ + struct pmap_node* item; + int count; + int max; +}; + +#define PMAPOF(LEFT, RIGHT) \ + struct { \ + struct { LEFT* left; RIGHT* right; }* item; \ + int count; \ + int max; \ + } + +extern void pmap_put(void* map, void* left, void* right); +extern void pmap_add(void* map, void* left, void* right); +extern void pmap_remove(void* map, void* left, void* right); +extern void* pmap_findleft(void* map, void* left); +extern void* pmap_findright(void* map, void* right); + +#endif + diff --git a/modules/src/data/smap.c b/modules/src/data/smap.c new file mode 100644 index 000000000..312241a20 --- /dev/null +++ b/modules/src/data/smap.c @@ -0,0 +1,74 @@ +#include +#include +#include +#include "smap.h" + +static void append(void* mapp, const char* left, void* right) +{ + struct smap* map = mapp; + struct smap_node* node; + + if (map->count == map->max) + { + int newmax = (map->max == 0) ? 8 : (map->max * 2); + struct smap_node* newarray = realloc(map->item, newmax * sizeof(*newarray)); + + map->max = newmax; + map->item = newarray; + } + + node = &map->item[map->count]; + map->count++; + + node->left = left; + node->right = right; +} + +void smap_put(void* mapp, const char* left, void* right) +{ + struct smap* map = mapp; + int i; + + for (i=0; icount; i++) + { + struct smap_node* node = &map->item[i]; + if (strcmp(node->left, left) == 0) + { + node->right = right; + return; + } + } + + append(map, left, right); +} + +void smap_add(void* mapp, const char* left, void* right) +{ + struct smap* map = mapp; + int i; + + for (i=0; icount; i++) + { + struct smap_node* node = &map->item[i]; + if ((strcmp(node->left, left) == 0) && (node->right == right)) + return; + } + + append(map, left, right); +} + +void* smap_get(void* mapp, const char* left) +{ + struct smap* map = mapp; + int i; + + for (i=0; icount; i++) + { + struct smap_node* node = &map->item[i]; + if (strcmp(node->left, left) == 0) + return node->right; + } + + return NULL; +} + diff --git a/modules/src/data/smap.h b/modules/src/data/smap.h new file mode 100644 index 000000000..7ccdb51de --- /dev/null +++ b/modules/src/data/smap.h @@ -0,0 +1,31 @@ +#ifndef SMAP_H +#define SMAP_H + +struct smap_node +{ + const char* left; + void* right; +}; + +/* Danger, Will Robinson! The type and the macro must be compatible. */ + +struct smap +{ + struct smap_node* item; + int count; + int max; +}; + +#define SMAPOF(RIGHT) \ + struct { \ + struct { const char* left; RIGHT* right; }* item; \ + int count; \ + int max; \ + } + +extern void smap_put(void* map, const char* left, void* right); +extern void smap_add(void* map, const char* left, void* right); +extern void* smap_get(void* map, const char* left); + +#endif + diff --git a/modules/src/data/stringlist.c b/modules/src/data/stringlist.c new file mode 100644 index 000000000..28322bf98 --- /dev/null +++ b/modules/src/data/stringlist.c @@ -0,0 +1,43 @@ +#include +#include "stringlist.h" + +void stringlist_add(struct stringlist* list, const char* data) +{ + struct stringfragment* f = calloc(1, sizeof *f); + f->data = data; + + if (!list->last) + list->first = list->last = f; + else + { + list->last->next = f; + list->last = f; + } +} + +void stringlist_addall(struct stringlist* list, struct stringlist* src) +{ + struct stringfragment* f = src->first; + + while (f) + { + stringlist_add(list, f->data); + f = f->next; + } +} + +void stringlist_free(struct stringlist* list) +{ + struct stringfragment* f = list->first; + + while (f) + { + struct stringfragment* next = f->next; + free(f); + f = next; + } +} + +/* vim: set sw=4 ts=4 expandtab : */ + + diff --git a/modules/src/data/stringlist.h b/modules/src/data/stringlist.h new file mode 100644 index 000000000..493d7ff1e --- /dev/null +++ b/modules/src/data/stringlist.h @@ -0,0 +1,23 @@ +#ifndef STRINGLIST_H +#define STRINGLIST_H + +struct stringfragment +{ + const char* data; + struct stringfragment* next; +}; + +struct stringlist +{ + struct stringfragment* first; + struct stringfragment* last; +}; + +extern void stringlist_add(struct stringlist* list, const char* data); +extern void stringlist_addall(struct stringlist* list, struct stringlist* src); +extern void stringlist_free(struct stringlist* list); + +#endif + +/* vim: set sw=4 ts=4 expandtab : */ + diff --git a/modules/src/idf/idf_pkg.body b/modules/src/idf/idf_pkg.body index 4b71bfaaa..8f970aef7 100644 --- a/modules/src/idf/idf_pkg.body +++ b/modules/src/idf/idf_pkg.body @@ -1,15 +1,15 @@ /* SYMBOL TABLE HANDLING */ -#include +#include -#define IDF_HASHSIZE 307 /* size of hashtable, must be odd */ +#define IDF_HASHSIZE 307 /* size of hashtable, must be odd */ -#define IDF_STARTHASH(hs) (hs = 0) -#define IDF_ENHASH(hs,ch) (hs = (hs << 2) + ch) -#define IDF_STOPHASH(hs) (hs = hs % IDF_HASHSIZE) +#define IDF_STARTHASH(hs) (hs = 0) +#define IDF_ENHASH(hs, ch) (hs = (hs << 2) + ch) +#define IDF_STOPHASH(hs) (hs = hs % IDF_HASHSIZE) -static struct idf *IDF_hashtable[IDF_HASHSIZE]; - /* All identifiers can in principle be reached through +static struct idf* IDF_hashtable[IDF_HASHSIZE]; +/* All identifiers can in principle be reached through IDF_hashtable; IDF_hashtable[hc] is the start of a chain of idf's whose tags all hash to hc. Any identifier is entered into this @@ -17,69 +17,71 @@ static struct idf *IDF_hashtable[IDF_HASHSIZE]; (variable, selector, structure tag, etc.). */ -_PROTOTYPE(static struct idf *IDF_new, (char *, int, int)); +static struct idf* IDF_new(char* tg, int size, int cpy); -void -init_idf() +void init_idf() { } -static struct idf * -IDF_new(tg, size, cpy) - register char *tg; - register int size; +static struct idf* IDF_new(char* tg, int size, int cpy) { static int nidf; - static struct idf *pidf; + static struct idf* pidf; static struct idf null_idf; - register struct idf *id; + register struct idf* id; #define NIDS 50 -#define IBUFSIZ 2048 +#define IBUFSIZ 2048 static unsigned int icnt; - static char *ip; - register char *p; + static char* ip; + register char* p; - - if (! nidf--) { + if (!nidf--) + { nidf += NIDS; - pidf = (struct idf *) Malloc(NIDS * sizeof (struct idf)); + pidf = (struct idf*)Malloc(NIDS * sizeof(struct idf)); } id = pidf; pidf++; *id = null_idf; - if (cpy) { - if (size > icnt) { - icnt = size > IBUFSIZ ? size : IBUFSIZ; + if (cpy) + { + if (size > icnt) + { + icnt = size > IBUFSIZ ? size : IBUFSIZ; p = Malloc(icnt); } - else p = ip; + else + p = ip; icnt -= size; id->id_text = p; - while (size--) { + while (size--) + { *p++ = *tg++; } ip = p; } - else id->id_text = tg; + else + id->id_text = tg; return id; } -#ifdef IDF_DEBUG -void -hash_stat() +#ifdef IDF_DEBUG +void hash_stat(void) { register int i; int total_count = 0; print("Hash table tally:\n"); - for (i = 0; i < IDF_HASHSIZE; i++) { - register struct idf *notch = IDF_hashtable[i]; + for (i = 0; i < IDF_HASHSIZE; i++) + { + register struct idf* notch = IDF_hashtable[i]; register int cnt = 0; - print ("%d ", i); - while (notch) { + print("%d ", i); + while (notch) + { cnt++; print("'%s' ", notch->id_text); notch = notch->id_next; @@ -91,40 +93,38 @@ hash_stat() print("End hash table tally\n"); } -void -idfappfun(fun, opt) - int (*fun)(); - int opt; +void idfappfun(int (*fun)(), int opt) { - register int i; + register int i; - for (i = 0; i < IDF_HASHSIZE; i++) { - register struct idf *notch = IDF_hashtable[i]; + for (i = 0; i < IDF_HASHSIZE; i++) + { + register struct idf* notch = IDF_hashtable[i]; - while (notch) { + while (notch) + { (*fun)(notch, opt); notch = notch->id_next; } } } -#endif /* IDF_DEBUG */ +#endif /* IDF_DEBUG */ -struct idf * -str2idf(tg, cpy) - char tg[]; +struct idf* str2idf(char tg[], int cpy) { /* str2idf() returns an entry in the symbol table for the identifier tg. If necessary, an entry is created. */ - register char *cp = tg; - struct idf **hook; - register struct idf *notch; + register char* cp = tg; + struct idf** hook; + register struct idf* notch; register unsigned int hash; register int c; int size; IDF_STARTHASH(hash); - while (c = *cp++) { + while (c = *cp++) + { IDF_ENHASH(hash, c); } IDF_STOPHASH(hash); @@ -137,25 +137,31 @@ str2idf(tg, cpy) */ hook = &IDF_hashtable[hash]; - while ((notch = *hook)) { - register char *s1 = tg; + while ((notch = *hook)) + { + register char* s1 = tg; cp = notch->id_text; - while (!(c = (*s1 - *cp++))) { - if (*s1++ == '\0') { + while (!(c = (*s1 - *cp++))) + { + if (*s1++ == '\0') + { break; } } - if (c == 0) return notch; - if (c < 0) break; + if (c == 0) + return notch; + if (c < 0) + break; hook = ¬ch->id_next; } /* a new struct idf must be inserted at the hook */ - if (cpy < 0) return 0; + if (cpy < 0) + return 0; notch = IDF_new(tg, size, cpy); notch->id_next = *hook; - *hook = notch; /* hooked in */ + *hook = notch; /* hooked in */ return notch; } diff --git a/modules/src/idf/idf_pkg.spec b/modules/src/idf/idf_pkg.spec index 42d65d25f..3db6b9d5f 100644 --- a/modules/src/idf/idf_pkg.spec +++ b/modules/src/idf/idf_pkg.spec @@ -27,7 +27,7 @@ struct idf { Initializes the namelist. */ -_PROTOTYPE(void init_idf, (void)); +extern void init_idf(void); /* struct idf * str2idf(tg, cp) char *tg; @@ -40,6 +40,6 @@ _PROTOTYPE(void init_idf, (void)); If cp < 0, the string is not entered, but only looked for. */ -_PROTOTYPE(struct idf *str2idf, (char *, int)); +struct idf *str2idf(char* tg, int cp); #define findidf(tg) str2idf(tg, -1) diff --git a/modules/src/system/system.3 b/modules/src/system/system.3 index 58557489c..c58c168bb 100644 --- a/modules/src/system/system.3 +++ b/modules/src/system/system.3 @@ -4,7 +4,7 @@ sys_open, sys_close, sys_read, sys_write, sys_reset, sys_access, sys_modtime, sys_remove, sys_rename, sys_filesize, sys_chmode, sys_lock, sys_unlock, -sys_break, sys_stop, sys_time \- system call interface +sys_break, sys_stop \- system call interface .SH SYNOPSIS .nf .B #include @@ -67,8 +67,6 @@ sys_break, sys_stop, sys_time \- system call interface .B void sys_stop(how) .B int how; .PP -.B long sys_time(); -.PP .B long sys_modtime(path) .B char *path; .fi diff --git a/modules/src/system/system.h b/modules/src/system/system.h index 8f8bce45c..8a5825173 100644 --- a/modules/src/system/system.h +++ b/modules/src/system/system.h @@ -50,7 +50,6 @@ _PROTOTYPE(int sys_unlock, (char *)); #endif _PROTOTYPE(char *sys_break, (int)); _PROTOTYPE(void sys_stop, (int)); -_PROTOTYPE(long sys_time, (void)); _PROTOTYPE(long sys_modtime, (char *)); /* standard file decsriptors */ diff --git a/modules/src/system/time.c b/modules/src/system/time.c deleted file mode 100644 index e06a9fa00..000000000 --- a/modules/src/system/time.c +++ /dev/null @@ -1,15 +0,0 @@ -/* - * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands. - * See the copyright notice in the ACK home directory, in the file "Copyright". - */ -/* $Id$ */ - -#include "system.h" - -long time(); - -long -sys_time() -{ - return time((long *) 0); -} diff --git a/plat/build.lua b/plat/build.lua index dc0e87c5e..85ba61bc9 100644 --- a/plat/build.lua +++ b/plat/build.lua @@ -1,5 +1,6 @@ include("mach/proto/as/build.lua") include("mach/proto/ncg/build.lua") +include("mach/proto/mcg/build.lua") include("mach/proto/top/build.lua") definerule("ackfile", @@ -61,11 +62,23 @@ definerule("ackprogram", deps = { type="targets", default={} }, }, function (e) + -- This bit is a hack. We *don't* want to link the language libraries here, + -- because the ack driver is going to pick the appropriate library itself and + -- we don't want more than one. But we still need to depend on them, so we use + -- a nasty hack. + + local platstamp = normalrule { + name = e.name.."/platstamp", + ins = { "plat/"..e.vars.plat.."+pkg" }, + outleaves = { "stamp" }, + commands = { "touch %{outs}" } + } + return cprogram { name = e.name, srcs = e.srcs, deps = { - "plat/"..e.vars.plat.."+pkg", + platstamp, "util/ack+pkg", "util/led+pkg", e.deps diff --git a/plat/cpm/include/unistd.h b/plat/cpm/include/unistd.h index 2af9db921..ea4f51c0f 100644 --- a/plat/cpm/include/unistd.h +++ b/plat/cpm/include/unistd.h @@ -37,7 +37,7 @@ extern char** environ; extern void _exit(int); extern pid_t getpid(void); -extern void* sbrk(intptr_t increment); +extern void* sbrk(int increment); extern int isatty(int d); extern off_t lseek(int fildes, off_t offset, int whence); extern int close(int d); diff --git a/plat/cpm/libsys/brk.c b/plat/cpm/libsys/brk.c index e29dc565b..0b83b2523 100644 --- a/plat/cpm/libsys/brk.c +++ b/plat/cpm/libsys/brk.c @@ -28,7 +28,7 @@ int brk(void* newend) return 0; } -void* sbrk(intptr_t increment) +void* sbrk(int increment) { char* old; diff --git a/plat/linux/libsys/_hol0.s b/plat/linux/libsys/_hol0.s index fcb58727b..d3d16db72 100644 --- a/plat/linux/libsys/_hol0.s +++ b/plat/linux/libsys/_hol0.s @@ -10,11 +10,12 @@ .sect .data .sect .bss -.sect .text - -! ! This data block is used to store information about the current line number ! and file. .define hol0 -.comm hol0, 8 +.define .hol0 +.sect .bss +hol0: +.hol0: + .space 8 diff --git a/plat/linux/libsys/brk.c b/plat/linux/libsys/brk.c deleted file mode 100644 index 7ce5c5fc8..000000000 --- a/plat/linux/libsys/brk.c +++ /dev/null @@ -1,17 +0,0 @@ -/* $Source: /cvsroot/tack/Ack/plat/linux386/libsys/brk.c,v $ - * $State: Exp $ - * $Revision: 1.1 $ - */ - -#include -#include -#include -#include "libsys.h" - -int brk(void* end) -{ - int e = _syscall(__NR_brk, (quad) end, 0, 0); - if (e == -1) - errno = ENOMEM; - return e; -} diff --git a/plat/linux/libsys/sbrk.c b/plat/linux/libsys/sbrk.c index 35810ef89..f790a17cb 100644 --- a/plat/linux/libsys/sbrk.c +++ b/plat/linux/libsys/sbrk.c @@ -12,11 +12,20 @@ static char* current = NULL; -void* sbrk(intptr_t increment) +int brk(void* end) +{ + int e = _syscall(__NR_brk, (quad) end, 0, 0); + if (e == -1) + errno = ENOMEM; + else + current = end; + return e; +} + +void* sbrk(int increment) { char* old; char* new; - char* actual; if (!current) current = (char*) _syscall(__NR_brk, 0, 0, 0); @@ -25,15 +34,21 @@ void* sbrk(intptr_t increment) return current; old = current; + new = old + increment; - actual = (char*) _syscall(__NR_brk, (quad) new, 0, 0); - if (actual < new) - { - errno = ENOMEM; - return OUT_OF_MEMORY; - } + if ((increment > 0) && (new <= old)) + goto out_of_memory; + else if ((increment < 0) && (new >= old)) + goto out_of_memory; + + if (brk(new) < 0) + goto out_of_memory; - current = actual; return old; + +out_of_memory: + errno = ENOMEM; + return OUT_OF_MEMORY; } + diff --git a/plat/linux386/build-tools.lua b/plat/linux386/build-tools.lua index d711f85fd..31b8a7388 100644 --- a/plat/linux386/build-tools.lua +++ b/plat/linux386/build-tools.lua @@ -16,6 +16,7 @@ return installable { ["$(PLATDEP)/linux386/as"] = "+as", ["$(PLATDEP)/linux386/ncg"] = "+ncg", ["$(PLATIND)/descr/linux386"] = "./descr", + "util/amisc+aelflod-pkg", "util/opt+pkg", } } diff --git a/plat/linux386/include/unistd.h b/plat/linux386/include/unistd.h index 715e321d7..35dc8dde7 100644 --- a/plat/linux386/include/unistd.h +++ b/plat/linux386/include/unistd.h @@ -67,7 +67,7 @@ extern char** environ; extern void _exit(int); extern pid_t getpid(void); extern int brk(void* ptr); -extern void* sbrk(intptr_t increment); +extern void* sbrk(int increment); extern int isatty(int d); /* Signal handling */ diff --git a/plat/linux386/tests/build.lua b/plat/linux386/tests/build.lua new file mode 100644 index 000000000..afd12fdce --- /dev/null +++ b/plat/linux386/tests/build.lua @@ -0,0 +1,7 @@ +include("tests/plat/build.lua") + +plat_testsuite { + name = "tests", + plat = "linux386", + method = "qemu-i386" +} diff --git a/plat/linux68k/build-tools.lua b/plat/linux68k/build-tools.lua index 944e57f47..03d659a15 100644 --- a/plat/linux68k/build-tools.lua +++ b/plat/linux68k/build-tools.lua @@ -16,6 +16,7 @@ return installable { ["$(PLATDEP)/linux68k/as"] = "+as", ["$(PLATDEP)/linux68k/ncg"] = "+ncg", ["$(PLATIND)/descr/linux68k"] = "./descr", + "util/amisc+aelflod-pkg", "util/opt+pkg", } } diff --git a/plat/linux68k/include/unistd.h b/plat/linux68k/include/unistd.h index 5cbdc1b5d..307192f77 100644 --- a/plat/linux68k/include/unistd.h +++ b/plat/linux68k/include/unistd.h @@ -65,7 +65,7 @@ extern char** environ; extern void _exit(int); extern pid_t getpid(void); extern int brk(void* ptr); -extern void* sbrk(intptr_t increment); +extern void* sbrk(int increment); extern int isatty(int d); /* Signal handling */ diff --git a/plat/linuxppc/build-tools.lua b/plat/linuxppc/build-tools.lua index 4d0f0048d..e48524cc9 100644 --- a/plat/linuxppc/build-tools.lua +++ b/plat/linuxppc/build-tools.lua @@ -5,17 +5,30 @@ build_as { arch = "powerpc", } +build_mcg { + name = "mcg", + arch = "powerpc", +} + build_ncg { name = "ncg", arch = "powerpc", } +build_top { + name = "top", + arch = "powerpc", +} + return installable { name = "tools", map = { ["$(PLATDEP)/linuxppc/as"] = "+as", ["$(PLATDEP)/linuxppc/ncg"] = "+ncg", + ["$(PLATDEP)/linuxppc/mcg"] = "+mcg", + ["$(PLATDEP)/linuxppc/top"] = "+top", ["$(PLATIND)/descr/linuxppc"] = "./descr", + "util/amisc+aelflod-pkg", "util/opt+pkg", } } diff --git a/plat/linuxppc/descr b/plat/linuxppc/descr index 3086a826c..12bece6e9 100644 --- a/plat/linuxppc/descr +++ b/plat/linuxppc/descr @@ -39,16 +39,15 @@ name be stdout need .e end -# FIXME(dtrg): not working yet -#name asopt -# from .s -# to .so -# program {EM}/lib/ack/{PLATFORM}/top -# args -# optimizer -# stdin -# stdout -#end +name asopt + from .s + to .so + program {EM}/lib/ack/{PLATFORM}/top + args + optimizer + stdin + stdout +end name as from .s.so to .o diff --git a/plat/linuxppc/include/unistd.h b/plat/linuxppc/include/unistd.h index 5cbdc1b5d..307192f77 100644 --- a/plat/linuxppc/include/unistd.h +++ b/plat/linuxppc/include/unistd.h @@ -65,7 +65,7 @@ extern char** environ; extern void _exit(int); extern pid_t getpid(void); extern int brk(void* ptr); -extern void* sbrk(intptr_t increment); +extern void* sbrk(int increment); extern int isatty(int d); /* Signal handling */ diff --git a/plat/linuxppc/tests/build.lua b/plat/linuxppc/tests/build.lua new file mode 100644 index 000000000..7601ab0be --- /dev/null +++ b/plat/linuxppc/tests/build.lua @@ -0,0 +1,7 @@ +include("tests/plat/build.lua") + +plat_testsuite { + name = "tests", + plat = "linuxppc", + method = "qemu-ppc" +} diff --git a/plat/pc86/README b/plat/pc86/README index 689c70844..dcbe0ba27 100644 --- a/plat/pc86/README +++ b/plat/pc86/README @@ -23,6 +23,9 @@ are stubs required to make the demo apps link. File descriptors 0, 1 and 2 represent the console. All reads block. There's enough TTY emulation to allow \n conversion and local echo (but it can't be turned off). +Console output is echoed to the serial port (without any setup). This is used +by qemu for running tests. + Example command line ==================== diff --git a/plat/pc86/boot.s b/plat/pc86/boot.s index 534809697..51b288e75 100644 --- a/plat/pc86/boot.s +++ b/plat/pc86/boot.s @@ -23,7 +23,7 @@ ! If you ever need to change the boot code, this needs adjusting. I recommend ! a hex editor. -PADDING = 0xB7 +PADDING = 0xB3 ! Some definitions. @@ -271,9 +271,12 @@ finished: ! Push standard parameters onto the stack and go. - push envp ! envp - push argv ! argv - push 1 ! argc + mov ax, envp + push ax + mov ax, argv + push ax + mov ax, 1 + push ax call __m_a_i_n ! fall through into the exit routine. diff --git a/plat/pc86/include/unistd.h b/plat/pc86/include/unistd.h index 2af9db921..174c43ad0 100644 --- a/plat/pc86/include/unistd.h +++ b/plat/pc86/include/unistd.h @@ -37,7 +37,8 @@ extern char** environ; extern void _exit(int); extern pid_t getpid(void); -extern void* sbrk(intptr_t increment); +extern int brk(void* addr); +extern void* sbrk(int increment); extern int isatty(int d); extern off_t lseek(int fildes, off_t offset, int whence); extern int close(int d); diff --git a/plat/pc86/libsys/_sys_rawwrite.s b/plat/pc86/libsys/_sys_rawwrite.s index 75f75aae1..ae477c6d2 100644 --- a/plat/pc86/libsys/_sys_rawwrite.s +++ b/plat/pc86/libsys/_sys_rawwrite.s @@ -21,9 +21,18 @@ __sys_rawwrite: push bp mov bp, sp + ! Write to the BIOS console. + movb al, 4(bp) movb ah, 0x0E mov bx, 0x0007 int 0x10 + + ! Also write to the serial port (used by the test suite). + + movb ah, 0x01 + xor dx, dx + int 0x14 + jmp .cret \ No newline at end of file diff --git a/plat/pc86/libsys/brk.c b/plat/pc86/libsys/brk.c index 02e213399..293703234 100644 --- a/plat/pc86/libsys/brk.c +++ b/plat/pc86/libsys/brk.c @@ -22,22 +22,38 @@ int brk(void* newend) if ((p > (&dummy - STACK_BUFFER)) || (p < _end)) + { + errno = ENOMEM; return -1; + } current = p; return 0; } -void* sbrk(intptr_t increment) +void* sbrk(int increment) { char* old; - + char* new; + if (increment == 0) return current; old = current; - if (brk(old + increment) < 0) - return OUT_OF_MEMORY; + + new = old + increment; + + if ((increment > 0) && (new <= old)) + goto out_of_memory; + else if ((increment < 0) && (new >= old)) + goto out_of_memory; + + if (brk(new) < 0) + goto out_of_memory; return old; + +out_of_memory: + errno = ENOMEM; + return OUT_OF_MEMORY; } diff --git a/plat/pc86/tests/build.lua b/plat/pc86/tests/build.lua new file mode 100644 index 000000000..fe871e450 --- /dev/null +++ b/plat/pc86/tests/build.lua @@ -0,0 +1,7 @@ +include("tests/plat/build.lua") + +plat_testsuite { + name = "tests", + plat = "pc86", + method = "qemu-system-i386" +} diff --git a/plat/qemuppc/README b/plat/qemuppc/README new file mode 100644 index 000000000..412e33ad1 --- /dev/null +++ b/plat/qemuppc/README @@ -0,0 +1,42 @@ +# $Source: /cvsroot/tack/Ack/plat/linux386/README,v $ +# $State: Exp $ +# $Revision: 1.2 $ + + +The linux386 platform +===================== + +linux386 is an i386-based BSP that produces Linux ELF executables. + +This port only implements a very limited number of system calls; basically, +just enough to make the demo apps run. Adding more is easy, but there are some +subtleties that require more thought. The port should be considered only in +proof-of-concept stage right now. + +Important note: you *can't* link access ELF shared libraries from these +executables. In other words, you have to all your work from inside ACK. + +IEEE floating point is available, but requires an FPU. + +The executables are generated with aelfslod and are extremely simple; there's +one rwx ELF section which contains all the application's code and data. This +is not optimal, but it does work. + + +Bugs +==== + +isatty() is a stub and always returns 0. + + +Example command line +==================== + +ack -mlinux386 -O -o linux386.exe examples/paranoia.c + +The file linux386.exe can then be run on a i386 Linux machine (or on an +emulation thereof). + + +David Given +dg@cowlark.com diff --git a/plat/qemuppc/boot.s b/plat/qemuppc/boot.s new file mode 100644 index 000000000..2dd9a4c5c --- /dev/null +++ b/plat/qemuppc/boot.s @@ -0,0 +1,88 @@ +# +! $Source: /cvsroot/tack/Ack/plat/linux386/boot.s,v $ +! $State: Exp $ +! $Revision: 1.3 $ + +! Declare segments (the order is important). + +.sect .text +.sect .rom +.sect .data +.sect .bss + +.sect .text + +begtext: + ! This code is placed at the beginning of the ELF executable and is the + ! first thing that runs. + ! + ! On entry, the stack looks like this: + ! + ! sp+... NULL + ! sp+8+(4*argc) env (X quads) + ! sp+4+(4*argc) NULL + ! sp+4 argv (argc quads) + ! sp argc + ! + ! The ACK actually expects: + ! + ! sp+8 argc + ! sp+4 ptr to argv + ! sp ptr to env + + li32 r3, __openfirmware_ptr + stw r5, 0(r3) + + li32 r3, envp + stwu r3, -4(sp) + + li32 r3, argv + stwu r3, -4(sp) + + li32 r3, 1 ! argc + stwu r3, -4(sp) + + bl _openfirmware_init + bl __m_a_i_n + ! falls through + +.define __exit +.extern __exit +.define EXIT +.extern EXIT +__exit: +EXIT: + b EXIT + +.define _openfirmware_call +.extern _openfirmware_call +_openfirmware_call: + lwz r3, 0(sp) + li32 r4, __openfirmware_ptr + lwz r4, 0(r4) + mtspr ctr, r4 + bcctr 20, 0, 0 + +! Define symbols at the beginning of our various segments, so that we can find +! them. (Except .text, which has already been done.) + +.sect .data; begdata: +.sect .rom; begrom: +.sect .bss; begbss: + +! Some magic data. All EM systems need these. + +.define _errno +.comm _errno, 4 ! Posix errno storage + +! The argv and env arrays. + +.sect .rom +argv: .data4 exename, 0 +envp: .data4 0 +exename: .asciz 'qemuppc.img' + +.define .trppc, .ignmask +.comm .trppc, 4 ! ptr to user trap handler +.comm .ignmask, 4 ! user trap ignore mask +.comm __openfirmware_ptr, 4 ! OpenFirmware entry point diff --git a/plat/qemuppc/build-pkg.lua b/plat/qemuppc/build-pkg.lua new file mode 100644 index 000000000..0478bbd4d --- /dev/null +++ b/plat/qemuppc/build-pkg.lua @@ -0,0 +1,26 @@ +include("plat/build.lua") + +ackfile { + name = "boot", + srcs = { "./boot.s" }, + vars = { plat = "qemuppc" } +} + +build_plat_libs { + name = "libs", + arch = "powerpc", + plat = "qemuppc", +} + +installable { + name = "pkg", + map = { + "+tools", + "+libs", + "./include+pkg", + "util/amisc+aslod-pkg", + ["$(PLATIND)/qemuppc/boot.o"] = "+boot", + ["$(PLATIND)/qemuppc/libsys.a"] = "./libsys+lib", + } +} + diff --git a/plat/qemuppc/build-tools.lua b/plat/qemuppc/build-tools.lua new file mode 100644 index 000000000..e4f3f534b --- /dev/null +++ b/plat/qemuppc/build-tools.lua @@ -0,0 +1,33 @@ +include("plat/build.lua") + +build_as { + name = "as", + arch = "powerpc", +} + +build_mcg { + name = "mcg", + arch = "powerpc", +} + +build_ncg { + name = "ncg", + arch = "powerpc", +} + +build_top { + name = "top", + arch = "powerpc", +} + +return installable { + name = "tools", + map = { + ["$(PLATDEP)/qemuppc/as"] = "+as", + ["$(PLATDEP)/qemuppc/ncg"] = "+ncg", + ["$(PLATDEP)/qemuppc/mcg"] = "+mcg", + ["$(PLATDEP)/qemuppc/top"] = "+top", + ["$(PLATIND)/descr/qemuppc"] = "./descr", + "util/opt+pkg", + } +} diff --git a/plat/qemuppc/descr b/plat/qemuppc/descr new file mode 100644 index 000000000..c0bc1eab0 --- /dev/null +++ b/plat/qemuppc/descr @@ -0,0 +1,88 @@ +# plat/linuxppc/descr + +var w=4 +var wa=4 +var p={w} +var pa={w} +var s=2 +var sa={s} +var l={w} +var la={w} +var f={w} +var fa={w} +var d=8 +var da={d} +var x=8 +var xa={x} +var ARCH=powerpc +var PLATFORM=qemuppc +var PLATFORMDIR={EM}/share/ack/{PLATFORM} +var CPP_F=-D__unix +var ALIGN=-a0:4 -a1:4 -a2:4 -a3:4 -b0:0x01000000 +var C_LIB={PLATFORMDIR}/libc-ansi.a +# bitfields reversed for compatibility with (g)cc. +var CC_ALIGN=-Vr +var OLD_C_LIB={C_LIB} +var MACHOPT_F= + +# Override the setting in fe so that files compiled for qemuppc can see +# the platform-specific headers. + +var C_INCLUDES=-I{PLATFORMDIR}/include -I{EM}/share/ack/include/ansi + +name be + from .m.g + to .s + program {EM}/lib/ack/{PLATFORM}/mcg + mapflag -gdb GF=-gdb + args {GF?} < + stdout + need .e +end +name asopt + from .s + to .so + program {EM}/lib/ack/{PLATFORM}/top + args + optimizer + stdin + stdout +end +name as + from .s.so + to .o + program {EM}/lib/ack/{PLATFORM}/as + args - -o > < + prep cond +end +name led + from .o.a + to .out + program {EM}/lib/ack/em_led + mapflag -l* LNAME={PLATFORMDIR}/lib* + mapflag -fp FLOATS={EM}/{LIB}fp + args {ALIGN} {SEPID?} \ + (.e:{HEAD}={PLATFORMDIR}/boot.o) \ + ({RTS}:.ocm.b={PLATFORMDIR}/c-ansi.o) \ + ({RTS}:.c={PLATFORMDIR}/c-ansi.o) \ + ({RTS}:.mod={PLATFORMDIR}/modula2.o) \ + ({RTS}:.p={PLATFORMDIR}/pascal.o) \ + -o > < \ + (.p:{TAIL}={PLATFORMDIR}/libpascal.a) \ + (.b:{TAIL}={PLATFORMDIR}/libbasic.a) \ + (.mod:{TAIL}={PLATFORMDIR}/libmodula2.a) \ + (.ocm:{TAIL}={PLATFORMDIR}/liboccam.a) \ + (.ocm.b.mod.c.p:{TAIL}={PLATFORMDIR}/libc.a) \ + {FLOATS?} \ + (.e:{TAIL}={PLATFORMDIR}/libem.a \ + {PLATFORMDIR}/libsys.a \ + {PLATFORMDIR}/libend.a) + linker +end +name cv + from .out + to .exe + program {EM}/bin/aslod + args < > + outfile qemuppc.img +end diff --git a/plat/qemuppc/include/ack/config.h b/plat/qemuppc/include/ack/config.h new file mode 100644 index 000000000..f58ee3a43 --- /dev/null +++ b/plat/qemuppc/include/ack/config.h @@ -0,0 +1,14 @@ +/* $Source: /cvsroot/tack/Ack/plat/linux386/include/ack/config.h,v $ + * $State: Exp $ + * $Revision: 1.1 $ + */ + +#ifndef _ACK_CONFIG_H +#define _ACK_CONFIG_H + +/* We're providing a time() system call rather than wanting a wrapper around + * gettimeofday() in the libc. */ + +#define ACKCONF_TIME_IS_A_SYSCALL + +#endif diff --git a/plat/qemuppc/include/build.lua b/plat/qemuppc/include/build.lua new file mode 100644 index 000000000..dc1b0bb43 --- /dev/null +++ b/plat/qemuppc/include/build.lua @@ -0,0 +1,24 @@ +include("plat/build.lua") + +headermap = {} +packagemap = {} + +local function addheader(h) + headermap[h] = "./"..h + packagemap["$(PLATIND)/qemuppc/include/"..h] = "./"..h +end + +addheader("ack/config.h") +addheader("sys/ioctl.h") +addheader("unistd.h") + +acklibrary { + name = "headers", + hdrs = headermap +} + +installable { + name = "pkg", + map = packagemap +} + diff --git a/plat/qemuppc/include/sys/ioctl.h b/plat/qemuppc/include/sys/ioctl.h new file mode 100644 index 000000000..af41165d7 --- /dev/null +++ b/plat/qemuppc/include/sys/ioctl.h @@ -0,0 +1,76 @@ +/* $Source: /cvsroot/tack/Ack/plat/linux386/include/sys/ioctl.h,v $ + * $State: Exp $ + * $Revision: 1.1 $ + */ + +#ifndef _SYS_IOCTL_H +#define _SYS_IOCTL_H + +/* These are copied from the ioctl_list(2) man page. */ + +/* */ + +#define FIOSETOWN 0x00008901 +#define SIOCSPGRP 0x00008902 +#define FIOGETOWN 0x00008903 +#define SIOCGPGRP 0x00008904 +#define SIOCATMARK 0x00008905 +#define SIOCGSTAMP 0x00008906 + +/* */ + +#define TCGETS 0x00005401 +#define TCSETS 0x00005402 +#define TCSETSW 0x00005403 +#define TCSETSF 0x00005404 +#define TCGETA 0x00005405 +#define TCSETA 0x00005406 +#define TCSETAW 0x00005407 +#define TCSETAF 0x00005408 +#define TCSBRK 0x00005409 +#define TCXONC 0x0000540A +#define TCFLSH 0x0000540B +#define TIOCEXCL 0x0000540C +#define TIOCNXCL 0x0000540D +#define TIOCSCTTY 0x0000540E +#define TIOCGPGRP 0x0000540F +#define TIOCSPGRP 0x00005410 +#define TIOCOUTQ 0x00005411 +#define TIOCSTI 0x00005412 +#define TIOCGWINSZ 0x00005413 +#define TIOCSWINSZ 0x00005414 +#define TIOCMGET 0x00005415 +#define TIOCMBIS 0x00005416 +#define TIOCMBIC 0x00005417 +#define TIOCMSET 0x00005418 +#define TIOCGSOFTCAR 0x00005419 +#define TIOCSSOFTCAR 0x0000541A +#define FIONREAD 0x0000541B +#define TIOCINQ 0x0000541B +#define TIOCLINUX 0x0000541C +#define TIOCCONS 0x0000541D +#define TIOCGSERIAL 0x0000541E +#define TIOCSSERIAL 0x0000541F +#define TIOCPKT 0x00005420 +#define FIONBIO 0x00005421 +#define TIOCNOTTY 0x00005422 +#define TIOCSETD 0x00005423 +#define TIOCGETD 0x00005424 +#define TCSBRKP 0x00005425 +#define TIOCTTYGSTRUCT 0x00005426 +#define FIONCLEX 0x00005450 +#define FIOCLEX 0x00005451 +#define FIOASYNC 0x00005452 +#define TIOCSERCONFIG 0x00005453 +#define TIOCSERGWILD 0x00005454 +#define TIOCSERSWILD 0x00005455 +#define TIOCGLCKTRMIOS 0x00005456 +#define TIOCSLCKTRMIOS 0x00005457 +#define TIOCSERGSTRUCT 0x00005458 +#define TIOCSERGETLSR 0x00005459 +#define TIOCSERGETMULTI 0x0000545A +#define TIOCSERSETMULTI 0x0000545B + + + +#endif diff --git a/plat/qemuppc/include/unistd.h b/plat/qemuppc/include/unistd.h new file mode 100644 index 000000000..307192f77 --- /dev/null +++ b/plat/qemuppc/include/unistd.h @@ -0,0 +1,123 @@ +/* + * unistd.h - standard system calls + */ +/* $Id$ */ + +#ifndef _UNISTD_H +#define _UNISTD_H + +#include +#include + +/* Types */ + +typedef int pid_t; +typedef int mode_t; + +typedef long suseconds_t; + +/* Time handling. */ + +struct timeval +{ + time_t tv_sec; + suseconds_t tv_usec; +}; + +struct timezone +{ + int tz_minuteswest; + int tz_dsttime; +}; /* obsolete, unused */ + +extern int gettimeofday(struct timeval* tv, struct timezone* tz); +extern int settimeofday(const struct timeval* tv, const struct timezone* tz); + +/* File access. */ + +enum +{ + O_ACCMODE = 0x3, + + O_RDONLY = 0, + O_WRONLY = 1, + O_RDWR = 2, + + O_CREAT = 0x10, + O_TRUNC = 0x20, + O_APPEND = 0x40 +}; + +extern int open(const char* path, int access, ...); +extern int creat(const char* path, mode_t mode); +extern int close(int d); +extern int read(int fd, void* buffer, size_t count); +extern int write(int fd, void* buffer, size_t count); +extern off_t lseek(int fildes, off_t offset, int whence); +extern int fcntl(int fd, int op, ...); + +/* Special variables */ + +extern char** environ; + +/* Implemented system calls */ + +extern void _exit(int); +extern pid_t getpid(void); +extern int brk(void* ptr); +extern void* sbrk(int increment); +extern int isatty(int d); + +/* Signal handling */ + +typedef int sig_atomic_t; + +#define SIG_ERR ((sighandler_t) -1) /* Error return. */ +#define SIG_DFL ((sighandler_t) 0) /* Default action. */ +#define SIG_IGN ((sighandler_t) 1) /* Ignore signal. */ + +#define SIGHUP 1 /* Hangup (POSIX). */ +#define SIGINT 2 /* Interrupt (ANSI). */ +#define SIGQUIT 3 /* Quit (POSIX). */ +#define SIGILL 4 /* Illegal instruction (ANSI). */ +#define SIGTRAP 5 /* Trace trap (POSIX). */ +#define SIGABRT 6 /* Abort (ANSI). */ +#define SIGIOT 6 /* IOT trap (4.2 BSD). */ +#define SIGBUS 7 /* BUS error (4.2 BSD). */ +#define SIGFPE 8 /* Floating-point exception (ANSI). */ +#define SIGKILL 9 /* Kill, unblockable (POSIX). */ +#define SIGUSR1 10 /* User-defined signal 1 (POSIX). */ +#define SIGSEGV 11 /* Segmentation violation (ANSI). */ +#define SIGUSR2 12 /* User-defined signal 2 (POSIX). */ +#define SIGPIPE 13 /* Broken pipe (POSIX). */ +#define SIGALRM 14 /* Alarm clock (POSIX). */ +#define SIGTERM 15 /* Termination (ANSI). */ +#define SIGSTKFLT 16 /* Stack fault. */ +#define SIGCLD SIGCHLD /* Same as SIGCHLD (System V). */ +#define SIGCHLD 17 /* Child status has changed (POSIX). */ +#define SIGCONT 18 /* Continue (POSIX). */ +#define SIGSTOP 19 /* Stop, unblockable (POSIX). */ +#define SIGTSTP 20 /* Keyboard stop (POSIX). */ +#define SIGTTIN 21 /* Background read from tty (POSIX). */ +#define SIGTTOU 22 /* Background write to tty (POSIX). */ +#define SIGURG 23 /* Urgent condition on socket (4.2 BSD). */ +#define SIGXCPU 24 /* CPU limit exceeded (4.2 BSD). */ +#define SIGXFSZ 25 /* File size limit exceeded (4.2 BSD). */ +#define SIGVTALRM 26 /* Virtual alarm clock (4.2 BSD). */ +#define SIGPROF 27 /* Profiling alarm clock (4.2 BSD). */ +#define SIGWINCH 28 /* Window size change (4.3 BSD, Sun). */ +#define SIGPOLL SIGIO /* Pollable event occurred (System V). */ +#define SIGIO 29 /* I/O now possible (4.2 BSD). */ +#define SIGPWR 30 /* Power failure restart (System V). */ +#define SIGSYS 31 /* Bad system call. */ +#define SIGUNUSED 31 + +#define _NSIG 32 /* Biggest signal number + 1 + (not including real-time signals). */ +typedef void (*sighandler_t)(int); +extern sighandler_t signal(int signum, sighandler_t handler); +extern int raise(int signum); + + + +#endif diff --git a/plat/qemuppc/libsys/_hol0.s b/plat/qemuppc/libsys/_hol0.s new file mode 100644 index 000000000..d3d16db72 --- /dev/null +++ b/plat/qemuppc/libsys/_hol0.s @@ -0,0 +1,21 @@ +# +! $Source: /cvsroot/tack/Ack/plat/linux386/libsys/_hol0.s,v $ +! $State: Exp $ +! $Revision: 1.1 $ + +! Declare segments (the order is important). + +.sect .text +.sect .rom +.sect .data +.sect .bss + +! This data block is used to store information about the current line number +! and file. + +.define hol0 +.define .hol0 +.sect .bss +hol0: +.hol0: + .space 8 diff --git a/plat/qemuppc/libsys/brk.c b/plat/qemuppc/libsys/brk.c new file mode 100644 index 000000000..7d49fa960 --- /dev/null +++ b/plat/qemuppc/libsys/brk.c @@ -0,0 +1,59 @@ +/* $Source$ + * $State$ + * $Revision$ + */ + +#include +#include +#include + +#define OUT_OF_MEMORY (void*)(-1) /* sbrk returns this on failure */ +#define STACK_BUFFER 128 /* number of bytes to leave for stack */ + +extern char _end[1]; +static char* current = _end; + +int brk(void* newend) +{ + /* This variable is used to figure out the current stack pointer, + * by taking its address. */ + char dummy; + char* p = newend; + + if ((p > (&dummy - STACK_BUFFER)) || + (p < _end)) + { + errno = ENOMEM; + return -1; + } + + current = p; + return 0; +} + +void* sbrk(int increment) +{ + char* old; + char* new; + + if (increment == 0) + return current; + + old = current; + + new = old + increment; + + if ((increment > 0) && (new <= old)) + goto out_of_memory; + else if ((increment < 0) && (new >= old)) + goto out_of_memory; + + if (brk(new) < 0) + goto out_of_memory; + + return old; + +out_of_memory: + errno = ENOMEM; + return OUT_OF_MEMORY; +} diff --git a/plat/qemuppc/libsys/build.lua b/plat/qemuppc/libsys/build.lua new file mode 100644 index 000000000..7281bbc61 --- /dev/null +++ b/plat/qemuppc/libsys/build.lua @@ -0,0 +1,16 @@ +acklibrary { + name = "lib", + srcs = { + "./*.s", + "./*.c", + }, + deps = { + "lang/cem/libcc.ansi/headers+headers", + "plat/qemuppc/include+headers", + "mach/powerpc/libem+headers_qemuppc", + }, + vars = { + plat = "qemuppc" + } +} + \ No newline at end of file diff --git a/plat/qemuppc/libsys/close.c b/plat/qemuppc/libsys/close.c new file mode 100644 index 000000000..1c570029b --- /dev/null +++ b/plat/qemuppc/libsys/close.c @@ -0,0 +1,14 @@ +/* $Source$ + * $State$ + * $Revision$ + */ + +#include +#include +#include + +int close(int fd) +{ + errno = EBADF; + return -1; +} diff --git a/plat/qemuppc/libsys/creat.c b/plat/qemuppc/libsys/creat.c new file mode 100644 index 000000000..34ace747c --- /dev/null +++ b/plat/qemuppc/libsys/creat.c @@ -0,0 +1,15 @@ +/* $Source$ + * $State$ + * $Revision$ + */ + +#include +#include +#include +#include "libsys.h" + +int open(const char* path, int access, ...) +{ + errno = EACCES; + return -1; +} diff --git a/plat/qemuppc/libsys/getpid.c b/plat/qemuppc/libsys/getpid.c new file mode 100644 index 000000000..5e6eb003e --- /dev/null +++ b/plat/qemuppc/libsys/getpid.c @@ -0,0 +1,13 @@ +/* $Source$ + * $State$ + * $Revision$ + */ + +#include +#include +#include + +pid_t getpid(void) +{ + return 0; +} diff --git a/plat/qemuppc/libsys/isatty.c b/plat/qemuppc/libsys/isatty.c new file mode 100644 index 000000000..8bee360e0 --- /dev/null +++ b/plat/qemuppc/libsys/isatty.c @@ -0,0 +1,8 @@ +#include +#include +#include + +int isatty(int fd) +{ + return 1; +} diff --git a/plat/qemuppc/libsys/kill.c b/plat/qemuppc/libsys/kill.c new file mode 100644 index 000000000..4a179c47c --- /dev/null +++ b/plat/qemuppc/libsys/kill.c @@ -0,0 +1,14 @@ +/* $Source$ + * $State$ + * $Revision$ + */ + +#include +#include +#include + +int kill(pid_t pid, int sig) +{ + errno = EINVAL; + return -1; +} diff --git a/plat/qemuppc/libsys/libsys.h b/plat/qemuppc/libsys/libsys.h new file mode 100644 index 000000000..cf9878b87 --- /dev/null +++ b/plat/qemuppc/libsys/libsys.h @@ -0,0 +1,13 @@ +#ifndef LIBSYS_H +#define LIBSYS_H + +extern uint32_t openfirmware_call(void* array); + +extern void _sys_rawwrite(unsigned char b); +extern unsigned char _sys_rawread(void); + +extern void _sys_write_tty(char c); + +/* extern int _sys_ttyflags; */ + +#endif diff --git a/plat/qemuppc/libsys/lseek.c b/plat/qemuppc/libsys/lseek.c new file mode 100644 index 000000000..ecbc4b520 --- /dev/null +++ b/plat/qemuppc/libsys/lseek.c @@ -0,0 +1,14 @@ +/* $Source$ + * $State$ + * $Revision$ + */ + +#include +#include +#include + +off_t lseek(int fd, off_t offset, int whence) +{ + errno = EINVAL; + return -1; +} diff --git a/plat/qemuppc/libsys/open.c b/plat/qemuppc/libsys/open.c new file mode 100644 index 000000000..8f18317c5 --- /dev/null +++ b/plat/qemuppc/libsys/open.c @@ -0,0 +1,14 @@ +/* $Source$ + * $State$ + * $Revision$ + */ + +#include +#include +#include +#include "libsys.h" + +int creat(const char* path, int mode) +{ + return open(path, O_CREAT|O_WRONLY|O_TRUNC, mode); +} diff --git a/plat/qemuppc/libsys/openfirmware.c b/plat/qemuppc/libsys/openfirmware.c new file mode 100644 index 000000000..ad0c282ee --- /dev/null +++ b/plat/qemuppc/libsys/openfirmware.c @@ -0,0 +1,80 @@ +#include +#include +#include +#include "libsys.h" + +static void* stdout_handle; + +static void* of_finddevice(const char* name) +{ + struct + { + const char* method; + int ins, outs; + const char* name; + void* phandle; + } args; + + args.method = "finddevice"; + args.ins = 1; + args.outs = 1; + args.name = name; + openfirmware_call(&args); + return args.phandle; +} + +static int of_getprop(void* phandle, const char* name, void* dest, int destlen) +{ + struct + { + const char* method; + int ins, outs; + void* phandle; + const char* name; + void* dest; + int destlen; + int flag; + } args; + + args.method = "getprop"; + args.ins = 4; + args.outs = 1; + args.phandle = phandle; + args.name = name; + args.dest = dest; + args.destlen = destlen; + openfirmware_call(&args); + return args.flag; +} + +void openfirmware_init(void) +{ + void* chosen = of_finddevice("/chosen"); + of_getprop(chosen, "stdout", &stdout_handle, sizeof(stdout_handle)); +} + +unsigned char _sys_rawread(void) +{ + return 0; +} + +void _sys_rawwrite(unsigned char c) +{ + struct + { + const char* method; + int ins, outs; + void* ihandle; + void* address; + int len; + int actual; + } args; + + args.method = "write"; + args.ins = 3; + args.outs = 1; + args.ihandle = stdout_handle; + args.address = &c; + args.len = 1; + openfirmware_call(&args); +} diff --git a/plat/qemuppc/libsys/read.c b/plat/qemuppc/libsys/read.c new file mode 100644 index 000000000..21fe90ebb --- /dev/null +++ b/plat/qemuppc/libsys/read.c @@ -0,0 +1,38 @@ +#include +#include +#include +#include "libsys.h" + +int read(int fd, void* buffer, size_t count) +{ + char i; + + /* We're only allowed to read from fd 0, 1 or 2. */ + + if ((fd < 0) || (fd > 2)) + { + errno = EBADF; + return -1; + } + + /* Empty buffer? */ + + if (count == 0) + return 0; + + /* Read one byte. */ + + i = _sys_rawread(); +#if 0 + if ((i == '\r') && !(_sys_ttyflags & RAW)) + i = '\n'; + if (_sys_ttyflags & ECHO) + _sys_write_tty(i); +#endif + if (i == '\r') + i = '\n'; + _sys_write_tty(i); + + *(char*)buffer = i; + return 1; +} diff --git a/plat/qemuppc/libsys/signal.c b/plat/qemuppc/libsys/signal.c new file mode 100644 index 000000000..a87b9ced2 --- /dev/null +++ b/plat/qemuppc/libsys/signal.c @@ -0,0 +1,15 @@ +/* $Source$ + * $State$ + * $Revision$ + */ + +#include +#include +#include +#include +#include "libsys.h" + +sighandler_t signal(int signum, sighandler_t handler) +{ + return SIG_DFL; +} diff --git a/plat/qemuppc/libsys/time.c b/plat/qemuppc/libsys/time.c new file mode 100644 index 000000000..5ef17b841 --- /dev/null +++ b/plat/qemuppc/libsys/time.c @@ -0,0 +1,17 @@ +/* $Source$ + * $State$ + * $Revision$ + */ + +#include +#include +#include +#include +#include "libsys.h" + +time_t time(time_t* t) +{ + if (t) + *t = 0; + return 0; +} diff --git a/plat/qemuppc/libsys/trap.s b/plat/qemuppc/libsys/trap.s new file mode 100644 index 000000000..f05b907d0 --- /dev/null +++ b/plat/qemuppc/libsys/trap.s @@ -0,0 +1,69 @@ +# +! $Source: /cvsroot/tack/Ack/plat/linux386/libsys/_syscall.s,v $ +! $State: Exp $ +! $Revision: 1.1 $ + +! Declare segments (the order is important). + +.sect .text +.sect .rom +.sect .data +.sect .bss + +.sect .text + +#define IFFALSE 4 +#define IFTRUE 12 +#define ALWAYS 20 + +#define LT 0 +#define GT 1 +#define EQ 2 +#define OV 3 + +EARRAY = 0 +ERANGE = 1 +ESET = 2 +EIOVFL = 3 +EFOVFL = 4 +EFUNFL = 5 +EIDIVZ = 6 +EFDIVZ = 7 +EIUND = 8 +EFUND = 9 +ECONV = 10 +ESTACK = 16 +EHEAP = 17 +EILLINS = 18 +EODDZ = 19 +ECASE = 20 +EMEMFLT = 21 +EBADPTR = 22 +EBADPC = 23 +EBADLAE = 24 +EBADMON = 25 +EBADLIN = 26 +EBADGTO = 27 +EUNIMPL = 63 ! unimplemented em-instruction called + +.define .trap_ecase +.trap_ecase: + b .trp + +.define .trap_earray +.trap_earray: + b .trp + +.define .trp +.define .trap +.trp: +.trap: + b .trp ! spin forever + +.define .sig +.sig: + lwz r3, 0(sp) + li32 r4, .trppc + stw r3, 0(r4) + bclr ALWAYS, 0, 0 ! return + \ No newline at end of file diff --git a/plat/qemuppc/libsys/write.c b/plat/qemuppc/libsys/write.c new file mode 100644 index 000000000..8d2dd0d74 --- /dev/null +++ b/plat/qemuppc/libsys/write.c @@ -0,0 +1,48 @@ +/* $Source$ + * $State$ + * $Revision$ + */ + +#include +#include +#include +#include "libsys.h" + +void _sys_write_tty(char c) +{ + _sys_rawwrite(c); +#if 0 + if ((c == '\n') && !(_sys_ttyflags & RAW)) + _sys_rawwrite('\r'); +#endif + if (c == '\n') + _sys_rawwrite('\r'); +} + +int write(int fd, void* buffer, size_t count) +{ + int i; + char* p = buffer; + + /* We're only allowed to write to fd 0, 1 or 2. */ + + if ((fd < 0) || (fd > 2)) + { + errno = EBADF; + return -1; + } + + /* Write all data. */ + + i = 0; + while (i < count) + { + _sys_write_tty(*p++); + + i++; + } + + /* No failures. */ + + return count; +} diff --git a/plat/qemuppc/tests/build.lua b/plat/qemuppc/tests/build.lua new file mode 100644 index 000000000..6581d93ef --- /dev/null +++ b/plat/qemuppc/tests/build.lua @@ -0,0 +1,7 @@ +include("tests/plat/build.lua") + +plat_testsuite { + name = "tests", + plat = "qemuppc", + method = "qemu-system-ppc" +} diff --git a/plat/rpi/include/unistd.h b/plat/rpi/include/unistd.h index a4d0c4507..196b823c4 100644 --- a/plat/rpi/include/unistd.h +++ b/plat/rpi/include/unistd.h @@ -59,7 +59,7 @@ extern char** environ; extern void _exit(int); extern pid_t getpid(void); -extern void* sbrk(intptr_t increment); +extern void* sbrk(int increment); extern int isatty(int d); extern off_t lseek(int fildes, off_t offset, int whence); extern int close(int d); diff --git a/plat/rpi/libsys/brk.c b/plat/rpi/libsys/brk.c index 36c7d4a6f..171b8e5cf 100644 --- a/plat/rpi/libsys/brk.c +++ b/plat/rpi/libsys/brk.c @@ -30,7 +30,7 @@ int brk(void* newend) return 0; } -void* sbrk(intptr_t increment) +void* sbrk(int increment) { char* old; diff --git a/tests/plat/_dummy.c b/tests/plat/_dummy.c new file mode 100644 index 000000000..a4693300f --- /dev/null +++ b/tests/plat/_dummy.c @@ -0,0 +1,9 @@ +#include "test.h" + +/* Bypasses the CRT, so there's no stdio or BSS initialisation. */ +void _m_a_i_n(void) +{ + ASSERT(0 == 0); + finished(); +} + diff --git a/tests/plat/brk_c.c b/tests/plat/brk_c.c new file mode 100644 index 000000000..434cec50b --- /dev/null +++ b/tests/plat/brk_c.c @@ -0,0 +1,46 @@ +#include +#include +#include +#include +#include +#include "test.h" + +int main(int argc, const char* argv[]) +{ + char* o; + char* p; + + p = sbrk(0); + ASSERT(p == sbrk(0)); + ASSERT(p == sbrk(8)); + ASSERT(p != sbrk(0)); + ASSERT(p != sbrk(-8)); + ASSERT(p == sbrk(0)); + + errno = 0; + o = sbrk(INT_MAX); + if (o == (char*)-1) + ASSERT(ENOMEM == errno); + else + { + ASSERT(0 == errno); + p = sbrk(0); + ASSERT(p > o); + brk(o); + } + + errno = 0; + o = sbrk(INT_MIN); + if (o == (char*)-1) + ASSERT(ENOMEM == errno); + else + { + ASSERT(0 == errno); + p = sbrk(0); + ASSERT(p < o); + brk(o); + } + + finished(); +} + diff --git a/tests/plat/build.lua b/tests/plat/build.lua new file mode 100644 index 000000000..3873ed9a5 --- /dev/null +++ b/tests/plat/build.lua @@ -0,0 +1,64 @@ +include("plat/build.lua") + +definerule("plat_testsuite", + { + plat = { type="string" }, + method = { type="string" }, + }, + function(e) + -- Remember this is executed from the caller's directory; local + -- target names will resolve there. + local testfiles = filenamesof( + "tests/plat/*.c", + "tests/plat/*.e", + "tests/plat/*.p" + ) + + acklibrary { + name = "lib", + srcs = { "tests/plat/lib/test.c" }, + hdrs = { "tests/plat/lib/test.h" }, + vars = { plat = e.plat }, + } + + local tests = {} + for _, f in ipairs(testfiles) do + local fs = replace(basename(f), "%..$", "") + local _, _, lang = fs:find("_(.)$") + if not lang then + lang = "e" + end + + local bin = ackprogram { + name = fs.."_bin", + srcs = { f }, + deps = { "+lib" }, + vars = { + plat = e.plat, + lang = lang, + ackcflags = "-O0" + } + } + + tests[#tests+1] = normalrule { + name = fs, + outleaves = { "stamp" }, + ins = { + bin, + "tests/plat/testdriver.sh" + }, + commands = { + "%{ins[2]} "..e.method.." %{ins[1]} 5", + "touch %{outs}" + } + } + end + + return normalrule { + name = e.name, + outleaves = { "stamp" }, + ins = tests, + commands = { "touch %{outs}" } + } + end +) \ No newline at end of file diff --git a/tests/plat/calloc_c.c b/tests/plat/calloc_c.c new file mode 100644 index 000000000..518aa7e49 --- /dev/null +++ b/tests/plat/calloc_c.c @@ -0,0 +1,23 @@ +#include +#include +#include +#include "test.h" + +int main(int argc, const char* argv[]) +{ + const char* p; + int i; + + ASSERT(0 == calloc(0, 0)); + ASSERT(0 == calloc(0, 1)); + ASSERT(0 == calloc(1, 0)); + ASSERT(0 == calloc(SIZE_MAX/2, 3)); + ASSERT(0 == calloc(SIZE_MAX/2, 2)); + ASSERT(0 != calloc(1, 1)); + + p = calloc(10, 1); + for (i=0; i<10; i++) + ASSERT(0 == p[i]); + + finished(); +} diff --git a/tests/plat/csa_e.c b/tests/plat/csa_e.c new file mode 100644 index 000000000..355b75ee7 --- /dev/null +++ b/tests/plat/csa_e.c @@ -0,0 +1,26 @@ +#include "test.h" + +int csa(int i) +{ + switch (i) + { + case 2: return 2; + case 3: return 3; + case 4: return 4; + default: return 0; + } +} + +/* Bypasses the CRT, so there's no stdio or BSS initialisation. */ +void _m_a_i_n(void) +{ + ASSERT(csa(0) == 0); + ASSERT(csa(1) == 0); + ASSERT(csa(2) == 2); + ASSERT(csa(3) == 3); + ASSERT(csa(4) == 4); + ASSERT(csa(5) == 0); + ASSERT(csa(6) == 0); + + finished(); +} \ No newline at end of file diff --git a/tests/plat/csb_e.c b/tests/plat/csb_e.c new file mode 100644 index 000000000..c86d31fa6 --- /dev/null +++ b/tests/plat/csb_e.c @@ -0,0 +1,26 @@ +#include "test.h" + +int csa(int i) +{ + switch (i) + { + case 200: return 200; + case 300: return 300; + case 400: return 400; + default: return 0; + } +} + +/* Bypasses the CRT, so there's no stdio or BSS initialisation. */ +void _m_a_i_n(void) +{ + ASSERT(csa(0) == 0); + ASSERT(csa(100) == 0); + ASSERT(csa(200) == 200); + ASSERT(csa(300) == 300); + ASSERT(csa(400) == 400); + ASSERT(csa(500) == 0); + ASSERT(csa(600) == 0); + + finished(); +} \ No newline at end of file diff --git a/tests/plat/doublecmp_e.c b/tests/plat/doublecmp_e.c new file mode 100644 index 000000000..f6c1582dc --- /dev/null +++ b/tests/plat/doublecmp_e.c @@ -0,0 +1,20 @@ +#include "test.h" + +/* Constants in globals to defeat constant folding. */ +double one = 1.0; +double zero = 0.0; + +/* Bypasses the CRT, so there's no stdio or BSS initialisation. */ +void _m_a_i_n(void) +{ + ASSERT(zero == zero); + ASSERT(one != zero); + ASSERT(zero < one); + ASSERT(zero <= one); + ASSERT(zero <= zero); + ASSERT(one > zero); + ASSERT(one >= zero); + ASSERT(one >= one); + + finished(); +} \ No newline at end of file diff --git a/tests/plat/from_d_to_si_e.c b/tests/plat/from_d_to_si_e.c new file mode 100644 index 000000000..7f51e6c5b --- /dev/null +++ b/tests/plat/from_d_to_si_e.c @@ -0,0 +1,21 @@ +#include +#include "test.h" + +/* Constants in globals to defeat constant folding. */ +double one = 1.0; +double zero = 0.0; +double minusone = -1.0; +double big = (double)INT_MAX; +double minusbig = (double)INT_MIN; + +/* Bypasses the CRT, so there's no stdio or BSS initialisation. */ +void _m_a_i_n(void) +{ + ASSERT((int)zero == 0); + ASSERT((int)one == 1); + ASSERT((int)minusone == -1); + ASSERT((int)big == INT_MAX); + ASSERT((int)minusbig == INT_MIN); + + finished(); +} \ No newline at end of file diff --git a/tests/plat/from_d_to_ui_e.c b/tests/plat/from_d_to_ui_e.c new file mode 100644 index 000000000..811780b87 --- /dev/null +++ b/tests/plat/from_d_to_ui_e.c @@ -0,0 +1,17 @@ +#include +#include "test.h" + +/* Constants in globals to defeat constant folding. */ +double one = 1.0; +double zero = 0.0; +double big = (double)UINT_MAX; + +/* Bypasses the CRT, so there's no stdio or BSS initialisation. */ +void _m_a_i_n(void) +{ + ASSERT((unsigned int)zero == 0); + ASSERT((unsigned int)one == 1); + ASSERT((unsigned int)big == UINT_MAX); + + finished(); +} \ No newline at end of file diff --git a/tests/plat/from_si_to_d_e.c b/tests/plat/from_si_to_d_e.c new file mode 100644 index 000000000..b6c7a25ba --- /dev/null +++ b/tests/plat/from_si_to_d_e.c @@ -0,0 +1,21 @@ +#include +#include "test.h" + +/* Constants in globals to defeat constant folding. */ +int one = 1; +int zero = 0; +int minusone = -1; +int big = INT_MAX; +int minusbig = INT_MIN; + +/* Bypasses the CRT, so there's no stdio or BSS initialisation. */ +void _m_a_i_n(void) +{ + ASSERT((double)zero == 0.0); + ASSERT((double)one == 1.0); + ASSERT((double)minusone == -1.0); + ASSERT((double)big == (double)INT_MAX); + /* ASSERT((double)minusbig == (double)INT_MIN); FIXME: fails for now */ + + finished(); +} \ No newline at end of file diff --git a/tests/plat/from_ui_to_d_e.c b/tests/plat/from_ui_to_d_e.c new file mode 100644 index 000000000..b8e017c99 --- /dev/null +++ b/tests/plat/from_ui_to_d_e.c @@ -0,0 +1,17 @@ +#include +#include "test.h" + +/* Constants in globals to defeat constant folding. */ +unsigned int one_u = 1; +unsigned int zero_u = 0; +unsigned int big_u = UINT_MAX; + +/* Bypasses the CRT, so there's no stdio or BSS initialisation. */ +void _m_a_i_n(void) +{ + ASSERT((double)zero_u == 0.0); + ASSERT((double)one_u == 1.0); + ASSERT((double)big_u == (double)UINT_MAX); + + finished(); +} \ No newline at end of file diff --git a/tests/plat/inn_e.e b/tests/plat/inn_e.e new file mode 100644 index 000000000..7d27abf42 --- /dev/null +++ b/tests/plat/inn_e.e @@ -0,0 +1,84 @@ +# + mes 2, EM_WSIZE, EM_PSIZE + + exp $_m_a_i_n + pro $_m_a_i_n, 0 + + /* Test non-existent bit */ + +.1 + rom 0I1, 0I1, 0I1, 0I1 + loe .1 + loc 1 /* bit number */ + inn EM_WSIZE + zeq *1 + + loc __LINE__ + cal $fail + ass EM_WSIZE +1 + + /* Test existent bit */ + +.2 + rom 2I1, 0I1, 0I1, 0I1 + loe .2 + loc 1 /* bit number */ + inn EM_WSIZE + zne *2 + + loc __LINE__ + cal $fail + ass EM_WSIZE +2 + + /* Test non-existent high bit */ + +.3 + rom 0I1, 0I1, 0I1, 0I1 + rom 0I1, 0I1, 0I1, 0I1 +.31 + rom (EM_WSIZE*8)+1 /* to defeat constant folding */ + + lae .3 + loi EM_WSIZE*2 + loe .31 /* bit number */ + inn EM_WSIZE*2 + zeq *3 + + loc __LINE__ + cal $fail + ass EM_WSIZE +3 + + /* Test existent high bit */ + +.4 +#if EM_WSIZE == 2 + rom 0I1, 0I1 + rom 2I1, 0I1 +#elif EM_WSIZE == 4 + rom 0I1, 0I1, 0I1, 0I1 + rom 2I1, 0I1, 0I1, 0I1 +#else + #error Unknown word size +#endif + +.41 + rom (EM_WSIZE*8)+1 /* to defeat constant folding */ + + lae .4 + loi EM_WSIZE*2 + loe .41 /* bit number */ + inn EM_WSIZE*2 + zne *4 + + loc __LINE__ + cal $fail + ass EM_WSIZE +4 + + cal $finished + ret 0 + + end diff --git a/tests/plat/intadd_e.c b/tests/plat/intadd_e.c new file mode 100644 index 000000000..8e4868a62 --- /dev/null +++ b/tests/plat/intadd_e.c @@ -0,0 +1,31 @@ +#include "test.h" + +/* Constants in globals to defeat constant folding. */ +int two = 2; +int one = 1; +int zero = 0; +int minusone = -1; + +/* Bypasses the CRT, so there's no stdio or BSS initialisation. */ +void _m_a_i_n(void) +{ + ASSERT((two + one) == 3); + ASSERT((two + minusone) == 1); + + ASSERT((two + 1) == 3); + ASSERT((two + -1) == 1); + + ASSERT((1 + two) == 3); + ASSERT((-1 + two) == 1); + + ASSERT(((unsigned int)two + (unsigned int)one) == 3); + ASSERT(((unsigned int)two + (unsigned int)minusone) == 1); + + ASSERT(((unsigned int)two + (unsigned int) 1) == 3); + ASSERT(((unsigned int)two + (unsigned int)-1) == 1); + + ASSERT(((unsigned int)1 + (unsigned int)two) == 3); + ASSERT(((unsigned int)-1 + (unsigned int)two) == 1); + + finished(); +} \ No newline at end of file diff --git a/tests/plat/intcmp_e.c b/tests/plat/intcmp_e.c new file mode 100644 index 000000000..dd7f1da75 --- /dev/null +++ b/tests/plat/intcmp_e.c @@ -0,0 +1,65 @@ +#include "test.h" + +/* Constants in globals to defeat constant folding. */ +int one = 1; +int zero = 0; + +/* Bypasses the CRT, so there's no stdio or BSS initialisation. */ +void _m_a_i_n(void) +{ + ASSERT(zero == zero); + ASSERT(one != zero); + ASSERT(zero < one); + ASSERT(zero <= one); + ASSERT(zero <= zero); + ASSERT(one > zero); + ASSERT(one >= zero); + ASSERT(one >= one); + + ASSERT(zero == 0); + ASSERT(one != 0); + ASSERT(zero < 1); + ASSERT(zero <= 1); + ASSERT(zero <= 0); + ASSERT(one > 0); + ASSERT(one >= 0); + ASSERT(one >= 1); + + ASSERT(0 == zero); + ASSERT(1 != zero); + ASSERT(0 < one); + ASSERT(0 <= one); + ASSERT(0 <= zero); + ASSERT(1 > zero); + ASSERT(1 >= zero); + ASSERT(1 >= one); + + ASSERT((unsigned int)zero == (unsigned int)zero); + ASSERT((unsigned int)one != (unsigned int)zero); + ASSERT((unsigned int)zero < (unsigned int)one); + ASSERT((unsigned int)zero <= (unsigned int)one); + ASSERT((unsigned int)zero <= (unsigned int)zero); + ASSERT((unsigned int)one > (unsigned int)zero); + ASSERT((unsigned int)one >= (unsigned int)zero); + ASSERT((unsigned int)one >= (unsigned int)one); + + ASSERT((unsigned int)zero == (unsigned int)0); + ASSERT((unsigned int)one != (unsigned int)0); + ASSERT((unsigned int)zero < (unsigned int)1); + ASSERT((unsigned int)zero <= (unsigned int)1); + ASSERT((unsigned int)zero <= (unsigned int)0); + ASSERT((unsigned int)one > (unsigned int)0); + ASSERT((unsigned int)one >= (unsigned int)0); + ASSERT((unsigned int)one >= (unsigned int)1); + + ASSERT((unsigned int)0 == (unsigned int)zero); + ASSERT((unsigned int)1 != (unsigned int)zero); + ASSERT((unsigned int)0 < (unsigned int)one); + ASSERT((unsigned int)0 <= (unsigned int)one); + ASSERT((unsigned int)0 <= (unsigned int)zero); + ASSERT((unsigned int)1 > (unsigned int)zero); + ASSERT((unsigned int)1 >= (unsigned int)zero); + ASSERT((unsigned int)1 >= (unsigned int)one); + + finished(); +} \ No newline at end of file diff --git a/tests/plat/intdiv_e.c b/tests/plat/intdiv_e.c new file mode 100644 index 000000000..c90964ced --- /dev/null +++ b/tests/plat/intdiv_e.c @@ -0,0 +1,28 @@ +#include "test.h" + +/* Constants in globals to defeat constant folding. */ +int three = 3; +int two = 2; +int one = 1; +int zero = 0; + +/* Bypasses the CRT, so there's no stdio or BSS initialisation. */ +void _m_a_i_n(void) +{ + ASSERT((three / two) == 1); + ASSERT((-three / two) == -1); + ASSERT((-three / -two) == 1); + ASSERT((three / -two) == -1); + + ASSERT((three / 2) == 1); + ASSERT((-three / 2) == -1); + ASSERT((-three / -2) == 1); + ASSERT((three / -2) == -1); + + ASSERT((3 / two) == 1); + ASSERT((-3 / two) == -1); + ASSERT((-3 / -two) == 1); + ASSERT((3 / -two) == -1); + + finished(); +} \ No newline at end of file diff --git a/tests/plat/intrem_e.c b/tests/plat/intrem_e.c new file mode 100644 index 000000000..40f68d654 --- /dev/null +++ b/tests/plat/intrem_e.c @@ -0,0 +1,28 @@ +#include "test.h" + +/* Constants in globals to defeat constant folding. */ +int three = 3; +int two = 2; +int one = 1; +int zero = 0; + +/* Bypasses the CRT, so there's no stdio or BSS initialisation. */ +void _m_a_i_n(void) +{ + ASSERT((three % two) == 1); + ASSERT((-three % two) == -1); + ASSERT((-three % -two) == -1); + ASSERT((three % -two) == 1); + + ASSERT((three % 2) == 1); + ASSERT((-three % 2) == -1); + ASSERT((-three % -2) == -1); + ASSERT((three % -2) == 1); + + ASSERT((3 % two) == 1); + ASSERT((-3 % two) == -1); + ASSERT((-3 % -two) == -1); + ASSERT((3 % -two) == 1); + + finished(); +} \ No newline at end of file diff --git a/tests/plat/intshift_e.c b/tests/plat/intshift_e.c new file mode 100644 index 000000000..3cc6d52f9 --- /dev/null +++ b/tests/plat/intshift_e.c @@ -0,0 +1,53 @@ +#include +#include "test.h" + +/* Constants in globals to defeat constant folding. */ +int one = 1; +int zero = 0; +int minusone = -1; + +/* Bypasses the CRT, so there's no stdio or BSS initialisation. */ +void _m_a_i_n(void) +{ + ASSERT((one <>zero) == 1); + ASSERT((one >>one) == 0); + ASSERT((minusone>>zero) == -1); + ASSERT((minusone>>one) == -1); + + ASSERT(((unsigned int)one >>(unsigned int)zero) == 1); + ASSERT(((unsigned int)one >>(unsigned int)one) == 0); + ASSERT(((unsigned int)minusone>>(unsigned int)zero) == UINT_MAX); + ASSERT(((unsigned int)minusone>>(unsigned int)one) == (UINT_MAX>>1)); + + ASSERT((one <<0) == 1); + ASSERT((one <<1) == 2); + ASSERT((minusone<<0) == -1); + ASSERT((minusone<<1) == -2); + + ASSERT(((unsigned int)one <<(unsigned int)0) == 1); + ASSERT(((unsigned int)one <<(unsigned int)1) == 2); + ASSERT(((unsigned int)minusone<<(unsigned int)0) == -1); + ASSERT(((unsigned int)minusone<<(unsigned int)1) == -2); + + ASSERT((one >>0) == 1); + ASSERT((one >>1) == 0); + ASSERT((minusone>>0) == -1); + ASSERT((minusone>>1) == -1); + + ASSERT(((unsigned int)one >>(unsigned int)0) == 1); + ASSERT(((unsigned int)one >>(unsigned int)1) == 0); + ASSERT(((unsigned int)minusone>>(unsigned int)0) == UINT_MAX); + ASSERT(((unsigned int)minusone>>(unsigned int)1) == (UINT_MAX>>1)); + + finished(); +} \ No newline at end of file diff --git a/tests/plat/intsub_e.c b/tests/plat/intsub_e.c new file mode 100644 index 000000000..d8f67d3a3 --- /dev/null +++ b/tests/plat/intsub_e.c @@ -0,0 +1,32 @@ +#include +#include "test.h" + +/* Constants in globals to defeat constant folding. */ +int two = 2; +int one = 1; +int zero = 0; +int minusone = -1; + +/* Bypasses the CRT, so there's no stdio or BSS initialisation. */ +void _m_a_i_n(void) +{ + ASSERT((two - one) == 1); + ASSERT((one - two) == -1); + + ASSERT((two - 1) == 1); + ASSERT((one - 2) == -1); + + ASSERT((2 - one) == 1); + ASSERT((1 - two) == -1); + + ASSERT(((unsigned int)two - (unsigned int)one) == 1); + ASSERT(((unsigned int)one - (unsigned int)two) == UINT_MAX); + + ASSERT(((unsigned int)two - (unsigned int)1) == 1); + ASSERT(((unsigned int)one - (unsigned int)2) == UINT_MAX); + + ASSERT(((unsigned int)2 - (unsigned int)one) == 1); + ASSERT(((unsigned int)1 - (unsigned int)two) == UINT_MAX); + + finished(); +} \ No newline at end of file diff --git a/tests/plat/lib/build.lua b/tests/plat/lib/build.lua new file mode 100644 index 000000000..be9928c84 --- /dev/null +++ b/tests/plat/lib/build.lua @@ -0,0 +1,7 @@ +include("plat/build.lua") + +acklibrary { + name = "lib", + srcs = { "./test.c" }, + hdrs = { "./test.h" }, +} diff --git a/tests/plat/lib/test.c b/tests/plat/lib/test.c new file mode 100644 index 000000000..df00e1089 --- /dev/null +++ b/tests/plat/lib/test.c @@ -0,0 +1,32 @@ +#include "test.h" + +/* No CRT in this file (this includes stdio and stdlib!). */ + +void finished(void) +{ + static const char s[] = "@@FINISHED\n"; + write(1, s, sizeof(s)); + _exit(0); +} + +void writehex(uint32_t code) +{ + char buf[8]; + char* p = &buf[sizeof(buf)]; + + do + { + *--p = "0123456789abcdef"[code & 0xf]; + code >>= 4; + } + while (code > 0); + + write(1, p, buf + sizeof(buf) - p); +} + +void fail(uint32_t code) +{ + write(1, "@@FAIL 0x", 10); + writehex(code); + write(1, "\n", 1); +} diff --git a/tests/plat/lib/test.h b/tests/plat/lib/test.h new file mode 100644 index 000000000..db16506f9 --- /dev/null +++ b/tests/plat/lib/test.h @@ -0,0 +1,14 @@ +#ifndef TEST_H +#define TEST_H + +#include +#include + +extern void finished(void); +extern void writehex(uint32_t code); +extern void fail(uint32_t code); + +#define ASSERT(condition) \ + do { if (!(condition)) fail(__LINE__); } while(0) + +#endif diff --git a/tests/plat/newdispose_p.p b/tests/plat/newdispose_p.p new file mode 100644 index 000000000..36f09e99b --- /dev/null +++ b/tests/plat/newdispose_p.p @@ -0,0 +1,34 @@ +# +(*$U+ -- enables underscores in identifiers *) + +program markrelease; + +type + iptr = ^integer; + +var + ptr1 : iptr; + ptr2 : iptr; + +procedure finished; + extern; + +procedure fail(line: integer); + extern; + +#define ASSERT(cond) \ + if (not (cond)) then fail(__LINE__) + +begin + New(ptr1); + New(ptr2); + ASSERT(ptr1 <> ptr2); + + Dispose(ptr1); + Dispose(ptr2); + (* Not required by the Pascal standard, but our implementation sets the + * pointers to NULL after freeing them. *) + ASSERT(ptr1 = ptr2); + + finished +end. diff --git a/tests/plat/testdriver.sh b/tests/plat/testdriver.sh new file mode 100755 index 000000000..272c6b2b7 --- /dev/null +++ b/tests/plat/testdriver.sh @@ -0,0 +1,51 @@ +#!/bin/sh +method=$1 +img=$2 +timeout=$3 + +pipe=/tmp/$$.testdriver.pipe +mknod $pipe p +trap "rm -f $pipe" EXIT + +result=/tmp/$$.testdriver.result +trap "rm -f $result" EXIT + +pidfile=/tmp/$$.testdriver.pid +trap "rm -f $pidfile" EXIT + +case $method in + qemu-system-*) + if ! command -v $method >/dev/null 2>&1 ; then + echo "Warning: $method not installed, skipping test" + exit 0 + fi + + case $method in + qemu-system-i386) img="-drive file=$img,if=floppy,format=raw" ;; + qemu-system-ppc) img="-kernel $img" ;; + esac + + ( $method -nographic $img 2>&1 & echo $! > $pidfile ) \ + | tee $result \ + | ( timeout $timeout grep -l -q @@FINISHED ; echo ) \ + | ( read dummy && kill $(cat $pidfile) ) + + ;; + + qemu-*) + if ! command -v $method >/dev/null 2>&1 ; then + echo "Warning: $method not installed, skipping test" + exit 0 + fi + + $method $img > $result + ;; + + *) + echo "Error: $method not known by testdriver" + exit 1 + ;; +esac + +( grep -q @@FAIL $result || ! grep -q @@FINISHED $result ) && cat $result && exit 1 +exit 0 diff --git a/util/LLgen/build.lua b/util/LLgen/build.lua index 44abc871c..9cde5630c 100644 --- a/util/LLgen/build.lua +++ b/util/LLgen/build.lua @@ -1,3 +1,8 @@ +clibrary { + name = "headers", + hdrs = { "./src/*.h" } +} + cprogram { name = "llgen", @@ -6,6 +11,7 @@ cprogram { -- do this. srcs = { "./src/*.c" }, + deps = { "+headers" }, vars = { ["+cflags"] = { "-DLIBDIR=\\\""..posix.getcwd().."/"..cwd().."/lib\\\"", diff --git a/util/LLgen/src/check.c b/util/LLgen/src/check.c index 21d8a9f93..6efe80c02 100644 --- a/util/LLgen/src/check.c +++ b/util/LLgen/src/check.c @@ -40,9 +40,9 @@ STATIC prline(); STATIC printset(); STATIC int check(); STATIC moreverbose(); -STATIC prrule(); +STATIC void prrule(p_gram p); STATIC cfcheck(); -STATIC resolve(); +STATIC void resolve(p_gram p); STATIC propagate(); STATIC spaces(); @@ -283,7 +283,7 @@ moreverbose(t) register p_set t; { } STATIC -prrule(p) register p_gram p; { +void prrule(p_gram p) { /* * Create a verbose printout of grammar rule p */ @@ -420,7 +420,7 @@ cfcheck(s1,s2,flag) p_set s1,s2; { } STATIC -resolve(p) register p_gram p; { +void resolve(p_gram p) { /* * resolve conflicts, as specified by the user */ diff --git a/util/LLgen/src/compute.c b/util/LLgen/src/compute.c index c17d99d73..c16c6725c 100644 --- a/util/LLgen/src/compute.c +++ b/util/LLgen/src/compute.c @@ -41,7 +41,7 @@ typedef struct lngth { /* Defined in this file : */ extern do_compute(); STATIC createsets(); -STATIC walk(); +STATIC void walk(); STATIC co_trans(); STATIC int nempty(); extern empty(); @@ -49,15 +49,15 @@ STATIC int nfirst(); STATIC first(); STATIC int nfollow(); STATIC follow(); -STATIC co_dirsymb(); +STATIC void co_dirsymb(); STATIC co_others(); STATIC do_lengthcomp(); -STATIC complength(); -STATIC add(); +STATIC void complength(); +STATIC void add(); STATIC int compare(); -STATIC setdefaults(); +STATIC void setdefaults(); STATIC do_contains(); -STATIC contains(); +STATIC void contains(); STATIC int nsafes(); STATIC int do_safes(); #ifdef NON_CORRECTING @@ -208,7 +208,7 @@ createsets() { } } -STATIC +STATIC void walk(u, p) p_set u; register p_gram p; { /* * Walk through the grammar rule p, allocating sets @@ -658,7 +658,7 @@ nc_follow(setp,p) p_set setp; register p_gram p; { #endif -STATIC +STATIC void co_dirsymb(setp,p) p_set setp; register p_gram p; { /* * Walk the rule p, doing the work for alternations @@ -777,7 +777,7 @@ do_lengthcomp() { free ((p_mem) length); } -STATIC +STATIC void complength(p,le) register p_gram p; p_length le; { /* * Walk grammar rule p, computing minimum lengths @@ -862,7 +862,7 @@ complength(p,le) register p_gram p; p_length le; { } } -STATIC +STATIC void add(a, c, v) register p_length a; { if (a->cnt == INFINITY || c == INFINITY) { @@ -879,7 +879,7 @@ compare(a, b) register p_length a, b; { return a->val - b->val; } -STATIC +STATIC void setdefaults(p) register p_gram p; { for (;;) { switch(g_gettype(p)) { @@ -949,7 +949,7 @@ do_contains(n) register p_nont n; { } } -STATIC +STATIC void contains(p,set) register p_gram p; register p_set set; { /* * Does the real computation of the contains-sets diff --git a/util/LLgen/src/gencode.c b/util/LLgen/src/gencode.c index 94dd312ca..484319511 100644 --- a/util/LLgen/src/gencode.c +++ b/util/LLgen/src/gencode.c @@ -57,24 +57,24 @@ STATIC genncrecovery(); #endif STATIC string genname(); STATIC generate(); -STATIC prset(); -STATIC macro(); +STATIC void prset(); +STATIC void macro(); STATIC controlline(); STATIC getparams(); STATIC getansiparams(); STATIC genprototypes(); STATIC gettok(); -STATIC rulecode(); +STATIC void rulecode(); STATIC int * dopush(); STATIC int * mk_tokenlist(); -STATIC getaction(); -STATIC alternation(); +STATIC void getaction(); +STATIC void alternation(); STATIC codeforterm(); STATIC genswhead(); STATIC gencases(); STATIC genpush(); STATIC genpop(); -STATIC genincrdecr(); +STATIC void genincrdecr(); STATIC add_cases(); STATIC int analyze_switch(); STATIC out_list(); @@ -414,7 +414,7 @@ generate(f) p_file f; { } } -STATIC +STATIC void prset(p) p_set p; { register int k; register unsigned i; @@ -435,7 +435,7 @@ prset(p) p_set p; { /* NOTREACHED */ } -STATIC +STATIC void macro(s,n) string s; p_nont n; { int i; @@ -625,7 +625,7 @@ gettok() { } } -STATIC +STATIC void rulecode(p,safety,mustscan,mustpop) register p_gram p; { /* * Code for a production rule. @@ -735,7 +735,7 @@ rulecode(p,safety,mustscan,mustpop) register p_gram p; { } } -STATIC +STATIC void alternation(pp, safety, mustscan, mustpop, lb) p_gram pp; { @@ -956,7 +956,7 @@ dopush(p,safety,toplevel,pp) register p_gram p; int **pp; { # define max(a,b) ((a) < (b) ? (b) : (a)) -STATIC +STATIC void getaction(flag) { /* Read an action from the action file. * flag = 1 if it is an action, @@ -1252,7 +1252,7 @@ genpush(d) { genincrdecr("incr", d); } -STATIC +STATIC void genincrdecr(s, d) string s; { if (d == NOPOP) return; if (d >= 0) { diff --git a/util/LLgen/src/main.c b/util/LLgen/src/main.c index 733c0d81a..ca4b05f22 100644 --- a/util/LLgen/src/main.c +++ b/util/LLgen/src/main.c @@ -36,7 +36,7 @@ extern error(); extern fatal(); extern comfatal(); extern copyfile(); -extern install(); +extern void install(); extern char *mktemp(); extern char *sbrk(); @@ -279,6 +279,7 @@ error(lineno,s,t,u) string s,t,u; { } /* VARARGS1 */ +void warning(lineno,s,t,u) string s,t,u; { /* * Just a warning @@ -327,6 +328,7 @@ copyfile(file) string file; { fclose(f); } +void install(target, source) string target, source; { /* * Copy the temporary file generated from source to target diff --git a/util/LLgen/src/reach.c b/util/LLgen/src/reach.c index a950539d2..a8ca81a47 100644 --- a/util/LLgen/src/reach.c +++ b/util/LLgen/src/reach.c @@ -29,7 +29,7 @@ static string rcsid8 = "$Id$"; /* In this file the following routines are defined: */ extern co_reach(); STATIC reachable(); -STATIC reachwalk(); +STATIC void reachwalk(); co_reach() { /* @@ -94,7 +94,7 @@ reachable(p) register p_nont p; { } } -STATIC +STATIC void reachwalk(p) register p_gram p; { /* * Walk through rule p, looking for nonterminals. diff --git a/util/LLgen/src/savegram.c b/util/LLgen/src/savegram.c index 625dc1bab..a32935ecc 100644 --- a/util/LLgen/src/savegram.c +++ b/util/LLgen/src/savegram.c @@ -41,8 +41,8 @@ extern p_set start_firsts; extern p_set setalloc(); extern p_gram search(); -STATIC save_rule(); -STATIC save_set(); +STATIC void save_rule(); +STATIC void save_set(); /* t_list will contain terms to be `flattened' */ static struct t_list { @@ -267,7 +267,7 @@ save_grammar(f) FILE *f; { fprintf(fgram, "#define LLNNONTERMINALS %d\n", nt_highest - assval + 1); } -STATIC +STATIC void save_rule(p, tail) register p_gram p; int tail; { /* Walk through rule p, saving it. The non-terminal tail is @@ -363,7 +363,7 @@ save_rule(p, tail) register p_gram p; int tail; { } } -STATIC +STATIC void save_set(p) p_set p; { register int k; register unsigned i; diff --git a/util/LLgen/src/tokens.c b/util/LLgen/src/tokens.c index 8fa2b3613..6526ec1a3 100644 --- a/util/LLgen/src/tokens.c +++ b/util/LLgen/src/tokens.c @@ -92,13 +92,13 @@ extern int scanner(); extern LLmessage(); extern int input(); extern unput(); -extern skipcomment(); +extern void skipcomment(); # ifdef LINE_DIRECTIVE STATIC linedirective(); # endif STATIC string cpy(); STATIC string vallookup(); -STATIC copyact(); +STATIC void copyact(); static int nparams; # line 75 "tokens.g" @@ -144,7 +144,7 @@ static t_token savedtok; /* to save lextoken in case of an insertion */ static int nostartline; /* = 0 if at the start of a line */ # endif -STATIC +STATIC void copyact(ch1,ch2,flag,level) char ch1,ch2; { /* * Copy an action to file f. Opening bracket is ch1, closing bracket @@ -419,7 +419,7 @@ unput(c) { backupc = c; } -skipcomment(flag) { +void skipcomment(flag) { /* * Skip comment. If flag != 0, the comment is inside a fragment * of C-code, so keep it. diff --git a/util/LLgen/src/tokens.g b/util/LLgen/src/tokens.g index fbdd83d2d..51b83fcb3 100644 --- a/util/LLgen/src/tokens.g +++ b/util/LLgen/src/tokens.g @@ -33,13 +33,13 @@ extern int scanner(); extern LLmessage(); extern int input(); extern unput(); -extern skipcomment(); +extern void skipcomment(); # ifdef LINE_DIRECTIVE STATIC linedirective(); # endif STATIC string cpy(); STATIC string vallookup(); -STATIC copyact(); +STATIC void copyact(); static int nparams; } @@ -114,7 +114,7 @@ static t_token savedtok; /* to save lextoken in case of an insertion */ static int nostartline; /* = 0 if at the start of a line */ # endif -STATIC +STATIC void copyact(ch1,ch2,flag,level) char ch1,ch2; { /* * Copy an action to file f. Opening bracket is ch1, closing bracket @@ -389,6 +389,7 @@ unput(c) { backupc = c; } +void skipcomment(flag) { /* * Skip comment. If flag != 0, the comment is inside a fragment diff --git a/util/ack/files.c b/util/ack/files.c index b47376b24..f2dbc8ed2 100644 --- a/util/ack/files.c +++ b/util/ack/files.c @@ -143,6 +143,7 @@ rmfile(file) path *file ; { } } +void rmtemps() { /* Called in case of disaster, always remove the current output file! */ diff --git a/util/ack/grows.c b/util/ack/grows.c index ca089d48c..81c3c002d 100644 --- a/util/ack/grows.c +++ b/util/ack/grows.c @@ -50,6 +50,7 @@ gr_cat(id,string) growstring *id ; char *string ; { } } +void gr_throw(id) register growstring *id ; { /* Throw the string away */ if ( id->gr_max==0 ) return ; diff --git a/util/ack/grows.h b/util/ack/grows.h index 558387488..9b9511049 100644 --- a/util/ack/grows.h +++ b/util/ack/grows.h @@ -20,7 +20,7 @@ typedef struct { /* Routines used */ -extern int gr_throw() ; /* To free the core */ +extern void gr_throw() ; /* To free the core */ extern int gr_add() ; /* To add one character */ extern int gr_cat() ; /* concatenate the contents and the string */ extern int gr_init() ; /* Initialize the bookkeeping */ diff --git a/util/ack/main.c b/util/ack/main.c index 82c18888e..99e27dceb 100644 --- a/util/ack/main.c +++ b/util/ack/main.c @@ -24,6 +24,8 @@ static int arg_count; extern char *getenv(); +void vieuwargs(); + main(argc,argv) char **argv ; { register list_elem *elem ; register char *frontend ; @@ -136,6 +138,7 @@ varinit() { /************************* flag processing ***********************/ +void vieuwargs(argc,argv) char **argv ; { register char *argp; register int nextarg ; diff --git a/util/ack/mktables.c b/util/ack/mktables.c index 1946d09ee..214b93606 100644 --- a/util/ack/mktables.c +++ b/util/ack/mktables.c @@ -22,6 +22,8 @@ FILE *dmach ; int offset ; +void readm(); + main(argc,argv) char **argv ; { register i ; @@ -70,6 +72,7 @@ FILE *do_open(file) char *file ; { return fopen(dname,"r"); } +void readm() { register int i ; register int token ; diff --git a/util/ack/rmach.c b/util/ack/rmach.c index 38b2a54b3..1e33e8713 100644 --- a/util/ack/rmach.c +++ b/util/ack/rmach.c @@ -55,6 +55,7 @@ int getinchar() ; static char *ty_name ; static char *bol ; +void open_in(); static char *inname ; @@ -263,6 +264,7 @@ static FILE *infile ; static char *inptr ; char *em_dir = EM_DIR; +void open_in(name) register char *name ; { register dmach *cmac ; diff --git a/util/ack/scan.c b/util/ack/scan.c index c4388b152..d020e6a5b 100644 --- a/util/ack/scan.c +++ b/util/ack/scan.c @@ -15,6 +15,8 @@ static char rcs_id[] = "$Id$" ; #endif +void try(); + enum f_path getpath(first) register trf **first ; { /* Try to find a transformation path */ @@ -61,6 +63,7 @@ start_scan() { last_ocount= 0 ; } +void try(f_scan,suffix) list_elem *f_scan; char *suffix; { register list_elem *scan ; register trf *trafo ; diff --git a/util/ack/trans.c b/util/ack/trans.c index 135b4c151..3cb2d7ea8 100644 --- a/util/ack/trans.c +++ b/util/ack/trans.c @@ -28,6 +28,10 @@ static int touch_tail= NO ; char *headvar(),*tailvar() ; +void condit(); +void doassign(); +void set_Rflag(); + int transform(phase) register trf *phase ; { int ok ; @@ -153,6 +157,7 @@ transini() { setpvar(keeps(TAIL),tailvar) ; } +void set_Rflag(argp) register char *argp ; { register char *eos ; register list_elem *prog ; @@ -413,6 +418,7 @@ growstring scanexpr(line) char *line ; { return result ; } +void condit(line,fsuff,lsuff,tailval) growstring *line ; list_head *fsuff, *lsuff; char *tailval ; @@ -504,6 +510,7 @@ int mapexpand(mapentry,cflag) return 1 ; } +void doassign(line,star,length) char *line, *star ; { growstring varval, name, temp ; register char *ptr ; @@ -598,6 +605,7 @@ char *c_rep(string,place,rep) char *string, *place, *rep ; { static list_head *curargs ; static list_head *comb_args ; +void addargs(string) char *string ; { register char *temp, *repc ; register list_elem *elem ; diff --git a/util/ack/util.c b/util/ack/util.c index a3d2d0511..419f087e3 100644 --- a/util/ack/util.c +++ b/util/ack/util.c @@ -32,6 +32,9 @@ extern int n_error; # define STDOUT stderr #endif +void fuerror(const char* fmt, ...); +void werror(const char* fmt, ...); + char *basename(string) char *string ; { static char retval[256] ; char *last_dot, *last_start ; diff --git a/util/amisc/aelflod.1 b/util/amisc/aelflod.1 index 6e22d53d2..24001ba2d 100644 --- a/util/amisc/aelflod.1 +++ b/util/amisc/aelflod.1 @@ -2,7 +2,7 @@ .SH NAME aelflod \- ACK ELF loader .SH SYNOPSIS -aelflod [-h] inputfile outputfile +aelflod [-h] [-v] inputfile outputfile .SH DESCRIPTION .I aelflod converts an absolute ack.out file into a simple binary memory diff --git a/util/amisc/aelflod.c b/util/amisc/aelflod.c index 398b223b2..e3692ac01 100644 --- a/util/amisc/aelflod.c +++ b/util/amisc/aelflod.c @@ -1,7 +1,4 @@ /* - * $Source$ - * $State$ - * * Simple tool to produce an utterly basic ELF executable * from an absolute ack.out file. Suitable for operating * systems like Linux. @@ -24,6 +21,7 @@ #include #include #include +#include #include #include #include "out.h" @@ -68,6 +66,8 @@ const char elf_le_ident_string[] = { char hdr[HDR_LENGTH] ; +bool verbose = false; + /* Segment numbers understood by aelflod. */ enum { @@ -299,6 +299,10 @@ int main(int argc, char* argv[]) elfmachine = atoi(&argv[1][2]); break; + case 'v': + verbose = true; + break; + default: syntaxerror: fatal("syntax error --- try -h for help"); @@ -451,8 +455,9 @@ int main(int argc, char* argv[]) /* Summarise what we've done. */ + if (verbose) { - long ss = 0; + uint32_t ss = 0; printf(" address length\n"); printf(" ehdr : %08"PRIx32" %08"PRIx32"\n", outsect[TEXT].os_base & ~0x1FFF, codeoffset); printf(" text : %08"PRIx32" %08"PRIx32"\n", outsect[TEXT].os_base, outsect[TEXT].os_size); @@ -463,7 +468,7 @@ int main(int argc, char* argv[]) ss += outsect[ROM].os_size; ss += outsect[DATA].os_size; ss += outsect[BSS].os_size; - printf("TOTAL : %08lX\n", ss); + printf("TOTAL : %08"PRIx32"\n", ss); } return 0; diff --git a/util/amisc/anm.c b/util/amisc/anm.c index 161f6587f..f2469f772 100644 --- a/util/amisc/anm.c +++ b/util/amisc/anm.c @@ -35,6 +35,8 @@ long s_base[S_MAX]; /* for specially encoded bases */ char *filename; int narg; +void do_file(); + main(argc, argv) char **argv; { @@ -134,6 +136,7 @@ process(fd) } } +void do_file(fd) int fd; { diff --git a/util/amisc/aslod.1 b/util/amisc/aslod.1 index 7e291838f..a786b13e6 100644 --- a/util/amisc/aslod.1 +++ b/util/amisc/aslod.1 @@ -2,7 +2,7 @@ .SH NAME aslod \- ACK simple loader .SH SYNOPSIS -aslod [-h] inputfile outputfile +aslod [-h] [-v] inputfile outputfile .SH DESCRIPTION .I aslod converts an absolute ack.out file into a simple binary memory diff --git a/util/amisc/aslod.c b/util/amisc/aslod.c index 307f72cb1..afc8f8c3e 100644 --- a/util/amisc/aslod.c +++ b/util/amisc/aslod.c @@ -14,14 +14,12 @@ * CVS...) * * dtrg, 2006-10-17 - * - * $Source$ - * $State$ */ #include #include #include +#include #include #include #include @@ -53,6 +51,8 @@ FILE* output; /* Output stream */ char hdr[HDR_LENGTH] ; +bool verbose = false; + /* Segment numbers understood by aslod. */ enum { @@ -206,6 +206,10 @@ int main(int argc, char* argv[]) program); exit(0); + case 'v': + verbose = true; + break; + default: syntaxerror: fatal("syntax error --- try -h for help"); @@ -301,8 +305,9 @@ int main(int argc, char* argv[]) /* Summarise what we've done. */ + if (verbose) { - long ss = 0; + uint32_t ss = 0; printf(" base : %08"PRIx32"\n", outsect[TEXT].os_base) ; printf(" text = %08"PRIx32"\n", outsect[TEXT].os_size); printf(" rom = %08"PRIx32"\n", outsect[ROM].os_size); @@ -312,7 +317,7 @@ int main(int argc, char* argv[]) ss += outsect[ROM].os_size; ss += outsect[DATA].os_size; ss += outsect[BSS].os_size; - printf("TOTAL = %08lX\n", ss); + printf("TOTAL = %08"PRIx32"\n", ss); } return 0; diff --git a/util/arch/archiver.c b/util/arch/archiver.c index 38958ea5e..bae09a168 100644 --- a/util/arch/archiver.c +++ b/util/arch/archiver.c @@ -109,6 +109,10 @@ char *temp_arch = &temp_buf[0]; extern char *mktemp(); extern char *ctime(); +void do_object(); +void write_symdef(); +void add(); + usage() { error(TRUE, "usage: %s [qdprtxl][vlc] archive [file] ...\n", @@ -437,6 +441,7 @@ register char *argv[]; close(ar_fd); } +void add(name, fd, mess) char *name; int fd; @@ -630,6 +635,7 @@ char *s, *name; * then 4 bytes giving the size of the string table, followed by the string * table itself. */ +void write_symdef() { register struct ranlib *ran; @@ -683,6 +689,7 @@ is_outhead(headp) return !BADMAGIC(*headp) && headp->oh_nname != 0; } +void do_object(f, size) long size; { diff --git a/util/ego/bo/bo.c b/util/ego/bo/bo.c index c093fe8ab..9024e7b56 100644 --- a/util/ego/bo/bo.c +++ b/util/ego/bo/bo.c @@ -150,7 +150,7 @@ STATIC bo_optloop(p,b,x,bra,bcc) -STATIC bo_tryloop(p,loop) +STATIC void bo_tryloop(p,loop) proc_p p; lset loop; { @@ -207,6 +207,7 @@ STATIC mv_code(b1,b2) } } +void bo_switch(b) bblock_p b; { @@ -303,6 +304,7 @@ STATIC bo_cleanproc(p) } } +void bo_optimize(p) proc_p p; { diff --git a/util/ego/ca/ca.c b/util/ego/ca/ca.c index acfba4829..095736665 100644 --- a/util/ego/ca/ca.c +++ b/util/ego/ca/ca.c @@ -130,7 +130,7 @@ STATIC int makedmap(dbl) return cnt; } -STATIC getdnames(dumpd) +STATIC void getdnames(dumpd) FILE* dumpd; { /* Read the names of the datalabels from @@ -151,7 +151,7 @@ STATIC getdnames(dumpd) } } -STATIC getpnames(dumpp) +STATIC void getpnames(dumpp) FILE* dumpp; { /* Read the names of the procedures from diff --git a/util/ego/cf/cf_loop.c b/util/ego/cf/cf_loop.c index b3b2d5c70..61184eddc 100644 --- a/util/ego/cf/cf_loop.c +++ b/util/ego/cf/cf_loop.c @@ -298,7 +298,7 @@ STATIC mark_succ(b,lp) } -STATIC mark_blocks(lp) +STATIC void mark_blocks(lp) loop_p lp; { /* Mark the strong and firm blocks of a loop. diff --git a/util/ego/cj/cj.c b/util/ego/cj/cj.c index 2ae26f3da..1447af8a7 100644 --- a/util/ego/cj/cj.c +++ b/util/ego/cj/cj.c @@ -56,7 +56,7 @@ STATIC int Scj; /* number of optimizations found */ -STATIC showinstr(); +STATIC void showinstr(); @@ -289,6 +289,7 @@ STATIC bool try_pred(b) +void cj_optimize(p) proc_p p; { @@ -334,7 +335,7 @@ main(argc,argv) extern char em_mnem[]; /* The mnemonics of the EM instructions. */ -STATIC showinstr(lnp) line_p lnp; { +STATIC void showinstr(lnp) line_p lnp; { /* Makes the instruction in `lnp' human readable. Only lines that * can occur in expressions that are going to be eliminated are diff --git a/util/ego/cs/cs.c b/util/ego/cs/cs.c index 21e6b488f..df651c9c4 100644 --- a/util/ego/cs/cs.c +++ b/util/ego/cs/cs.c @@ -34,7 +34,7 @@ STATIC cs_clear() start_valnum(); } -STATIC cs_optimize(p) +STATIC void cs_optimize(p) proc_p p; { /* Optimize all basic blocks of one procedure. */ diff --git a/util/ego/cs/cs_avail.c b/util/ego/cs/cs_avail.c index d97a19b41..1f766a85c 100644 --- a/util/ego/cs/cs_avail.c +++ b/util/ego/cs/cs_avail.c @@ -75,7 +75,7 @@ STATIC bool same_avail(kind, avp1, avp2) /* NOTREACHED */ } -STATIC check_local(avp) +STATIC void check_local(avp) avail_p avp; { /* Check if the local in which the result of avp was stored, diff --git a/util/ego/cs/cs_debug.c b/util/ego/cs/cs_debug.c index bfa0dc66d..bf43d8c12 100644 --- a/util/ego/cs/cs_debug.c +++ b/util/ego/cs/cs_debug.c @@ -17,7 +17,7 @@ extern char em_mnem[]; /* The mnemonics of the EM instructions. */ -STATIC showinstr(lnp) +STATIC void showinstr(lnp) line_p lnp; { /* Makes the instruction in `lnp' human readable. Only lines that diff --git a/util/ego/cs/cs_kill.c b/util/ego/cs/cs_kill.c index 7c9e90064..520366f23 100644 --- a/util/ego/cs/cs_kill.c +++ b/util/ego/cs/cs_kill.c @@ -234,7 +234,7 @@ STATIC kill_local(enp, indir) } } -STATIC kill_sim() +STATIC void kill_sim() { /* A store is done into the ENIGNMASK. */ diff --git a/util/ego/cs/cs_stack.c b/util/ego/cs/cs_stack.c index 5b3743434..7927438a5 100644 --- a/util/ego/cs/cs_stack.c +++ b/util/ego/cs/cs_stack.c @@ -39,6 +39,7 @@ Push(tkp) #define WORD_MULTIPLE(n) ((n / ws) * ws + ( n % ws ? ws : 0 )) +void Pop(tkp, size) token_p tkp; offset size; diff --git a/util/ego/ic/ic_lib.c b/util/ego/ic/ic_lib.c index 638038afc..7721bf27e 100644 --- a/util/ego/ic/ic_lib.c +++ b/util/ego/ic/ic_lib.c @@ -33,7 +33,7 @@ STATIC skip_string(n) } } -STATIC skip_arguments() +STATIC void skip_arguments() { /* Skip the arguments of a MES pseudo. The argument * list is terminated by a sp_cend byte. diff --git a/util/ego/il/il1_aux.c b/util/ego/il/il1_aux.c index 76e8ae2f3..d8da36dea 100644 --- a/util/ego/il/il1_aux.c +++ b/util/ego/il/il1_aux.c @@ -89,6 +89,7 @@ remov_formals(p) +void rem_indir_acc(p) proc_p p; { diff --git a/util/ego/il/il1_aux.h b/util/ego/il/il1_aux.h index 8b9db59d7..af8fe1ecf 100644 --- a/util/ego/il/il1_aux.h +++ b/util/ego/il/il1_aux.h @@ -18,7 +18,7 @@ extern rem_actuals(); /* (actual_p atcs) extern remov_formals(); /* (proc_p p) * Remove the formals-list of p from core. */ -extern rem_indir_acc(); /* (proc_p p) +extern void rem_indir_acc(); /* (proc_p p) * Remove formal that may be accessed * indirectly from formal lists of p */ diff --git a/util/ego/il/il1_cal.c b/util/ego/il/il1_cal.c index 69d12002e..1d0a2dc95 100644 --- a/util/ego/il/il1_cal.c +++ b/util/ego/il/il1_cal.c @@ -60,7 +60,7 @@ STATIC bool chck_asp(p,l) -STATIC inc_count(caller,callee) +STATIC void inc_count(caller,callee) proc_p caller, callee; { /* Update the call-count information. diff --git a/util/ego/il/il1_formal.c b/util/ego/il/il1_formal.c index c906f2580..94e2e32f7 100644 --- a/util/ego/il/il1_formal.c +++ b/util/ego/il/il1_formal.c @@ -103,6 +103,7 @@ STATIC inc_use(f,b) +void formal(p,b,off,type,usage) proc_p p; bblock_p b; diff --git a/util/ego/il/il1_formal.h b/util/ego/il/il1_formal.h index 7df35c1bb..bd2aea74d 100644 --- a/util/ego/il/il1_formal.h +++ b/util/ego/il/il1_formal.h @@ -8,7 +8,7 @@ * I L 1 _ F O R M A L . C */ -extern formal(); /* (proc_p p; bblock_p b; offset off; +extern void formal(); /* (proc_p p; bblock_p b; offset off; * int type, usage) * Analyze a reference to a parameter of p. * The type denotes its size (single,double, diff --git a/util/ego/il/il3_change.c b/util/ego/il/il3_change.c index 6347167c3..4528e8502 100644 --- a/util/ego/il/il3_change.c +++ b/util/ego/il/il3_change.c @@ -201,7 +201,7 @@ line_p make_label(l,p) /* modify */ -STATIC act_info(off,acts,ab_off,act_out,off_out) +STATIC void act_info(off,acts,ab_off,act_out,off_out) offset off, ab_off, *off_out; actual_p acts, *act_out; { @@ -499,6 +499,7 @@ STATIC line_p first_nonpseudo(l) +void insert(text,l,firstline) line_p text,l,firstline; { diff --git a/util/ego/il/il3_change.h b/util/ego/il/il3_change.h index 9899c8664..95c14f11c 100644 --- a/util/ego/il/il3_change.h +++ b/util/ego/il/il3_change.h @@ -35,7 +35,7 @@ extern mod_actuals(); /* (call_p nc,c; line_p lab; * call nc the same way as the text of * call c would be modified. */ -extern insert(); /* (line_p text,l,firstline) +extern void insert(); /* (line_p text,l,firstline) * Insert the modified EM text. * Pseudos are put after the pseudos * of the caller. diff --git a/util/ego/il/il_aux.c b/util/ego/il/il_aux.c index 2bb5e4564..d35120eb4 100644 --- a/util/ego/il/il_aux.c +++ b/util/ego/il/il_aux.c @@ -149,6 +149,7 @@ STATIC short remlines(l) +void remunit(kind,p,l) short kind; proc_p p; diff --git a/util/ego/lv/lv.c b/util/ego/lv/lv.c index 9fe50befd..6a640a1cb 100644 --- a/util/ego/lv/lv.c +++ b/util/ego/lv/lv.c @@ -591,6 +591,7 @@ lv_flags(p) } +void lv_optimize(p) proc_p p; { diff --git a/util/ego/ra/ra.c b/util/ego/ra/ra.c index fdb345f0b..fd05cdef0 100644 --- a/util/ego/ra/ra.c +++ b/util/ego/ra/ra.c @@ -349,6 +349,7 @@ ra_initialize() } +void ra_optimize(p) proc_p p; { diff --git a/util/ego/ra/ra_items.c b/util/ego/ra/ra_items.c index 05e16756c..a7411befb 100644 --- a/util/ego/ra/ra_items.c +++ b/util/ego/ra/ra_items.c @@ -260,7 +260,7 @@ STATIC init_item(a,b) -STATIC add_item(item,t,items) +STATIC void add_item(item,t,items) item_p item; time_p t; item_p items[]; diff --git a/util/ego/ra/ra_xform.c b/util/ego/ra/ra_xform.c index 28c295f0d..fea3e0757 100644 --- a/util/ego/ra/ra_xform.c +++ b/util/ego/ra/ra_xform.c @@ -551,6 +551,8 @@ rem_locals(p,allocs) } p->p_localbytes = nrlocals; } + +void rem_formals(p,allocs) proc_p p; alloc_p allocs; diff --git a/util/ego/share/locals.c b/util/ego/share/locals.c index b8b92f253..7da423b7f 100644 --- a/util/ego/share/locals.c +++ b/util/ego/share/locals.c @@ -29,7 +29,7 @@ short nrglobals; short nrlocals; local_p *locals; /* dynamic array */ -STATIC localvar(off,size,locs,reg,score) +STATIC void localvar(off,size,locs,reg,score) offset off; short size; local_p *locs; @@ -90,7 +90,7 @@ STATIC check_message(l,locs) -STATIC check_local_use(l,locs) +STATIC void check_local_use(l,locs) line_p l; local_p *locs; { @@ -186,7 +186,7 @@ make_localtab(p) -find_local(off,nr_out,found_out) +void find_local(off,nr_out,found_out) offset off; short *nr_out; bool *found_out; @@ -211,7 +211,7 @@ find_local(off,nr_out,found_out) -var_nr(l,nr_out,found_out) +void var_nr(l,nr_out,found_out) line_p l; short *nr_out; bool *found_out; diff --git a/util/ego/share/locals.h b/util/ego/share/locals.h index f71512ee5..60792372f 100644 --- a/util/ego/share/locals.h +++ b/util/ego/share/locals.h @@ -17,11 +17,11 @@ extern make_localtab(); /* (proc_p p) * these variables ('locals') and count them * ('nrlocals'). Also collect register messages. */ -extern var_nr(); /* (line_p l; short *nr_out;bool *found_out) +extern void var_nr(); /* (line_p l; short *nr_out;bool *found_out) * Compute the 'variable number' of the * variable referenced by EM instruction l. */ -extern find_local(); /* (offset off; short *nr_out; bool *found_out) +extern void find_local(); /* (offset off; short *nr_out; bool *found_out) * Try to find the local variable at the given * offset. Return its local-number. */ diff --git a/util/ego/share/put.c b/util/ego/share/put.c index 732377933..9cbfe7339 100644 --- a/util/ego/share/put.c +++ b/util/ego/share/put.c @@ -377,6 +377,7 @@ STATIC outlset(s,p) +void putunit(kind,p,l,gf,lf) short kind; proc_p p; diff --git a/util/ego/share/put.h b/util/ego/share/put.h index 2df761328..c6287cdaf 100644 --- a/util/ego/share/put.h +++ b/util/ego/share/put.h @@ -28,7 +28,7 @@ extern putptable(); /* (proc_p head, FILE *pf, bool all) * the fields computed by CF will not be * written (used by the IC phase). */ -extern putunit(); /* (short kind; proc_p p; line_p l; +extern void putunit(); /* (short kind; proc_p p; line_p l; * FILE *gf, *lf) * If kind = LTEXT, then write * the control flow graph to file gf, diff --git a/util/ego/sp/sp.c b/util/ego/sp/sp.c index dcc0a99f9..b04895647 100644 --- a/util/ego/sp/sp.c +++ b/util/ego/sp/sp.c @@ -193,6 +193,7 @@ STATIC mark_unsave_blocks(p) } +void sp_optimize(p) proc_p p; { diff --git a/util/ego/sr/sr.c b/util/ego/sr/sr.c index fcc9b413e..5f2194ed1 100644 --- a/util/ego/sr/sr.c +++ b/util/ego/sr/sr.c @@ -218,6 +218,7 @@ STATIC sr_cleanproc(p) } +void sr_optimize(p) proc_p p; { diff --git a/util/ego/sr/sr_cand.c b/util/ego/sr/sr_cand.c index ea478c01a..45babca7e 100644 --- a/util/ego/sr/sr_cand.c +++ b/util/ego/sr/sr_cand.c @@ -131,7 +131,7 @@ STATIC bool not_dismissed(lnp) } -STATIC try_cand(lnp,b) +STATIC void try_cand(lnp,b) line_p lnp; bblock_p b; { diff --git a/util/ego/sr/sr_iv.c b/util/ego/sr/sr_iv.c index 88af2e0d1..43e4b89c1 100644 --- a/util/ego/sr/sr_iv.c +++ b/util/ego/sr/sr_iv.c @@ -116,7 +116,7 @@ STATIC int sign(lnp) } -STATIC try_patterns(lnp) +STATIC void try_patterns(lnp) line_p lnp; { /* lnp is a STL x; try to recognize diff --git a/util/ego/sr/sr_reduce.c b/util/ego/sr/sr_reduce.c index 5b8e78295..d5ae81bb0 100644 --- a/util/ego/sr/sr_reduce.c +++ b/util/ego/sr/sr_reduce.c @@ -544,7 +544,7 @@ STATIC reduce(code,vars) -STATIC try_multiply(lp,ivs,vars,b,mul) +STATIC void try_multiply(lp,ivs,vars,b,mul) loop_p lp; lset ivs,vars; bblock_p b; @@ -606,7 +606,7 @@ STATIC try_multiply(lp,ivs,vars,b,mul) -STATIC try_leftshift(lp,ivs,vars,b,shft) +STATIC void try_leftshift(lp,ivs,vars,b,shft) loop_p lp; lset ivs,vars; bblock_p b; @@ -657,7 +657,7 @@ STATIC try_leftshift(lp,ivs,vars,b,shft) } -STATIC try_array(lp,ivs,vars,b,arr) +STATIC void try_array(lp,ivs,vars,b,arr) loop_p lp; lset ivs,vars; bblock_p b; diff --git a/util/ego/sr/sr_xform.c b/util/ego/sr/sr_xform.c index ca1c521b7..7adc32121 100644 --- a/util/ego/sr/sr_xform.c +++ b/util/ego/sr/sr_xform.c @@ -138,6 +138,7 @@ STATIC adjust_jump(newtarg,oldtarg,c) } +void make_header(lp) loop_p lp; { diff --git a/util/ego/sr/sr_xform.h b/util/ego/sr/sr_xform.h index 9bf1f3bd7..a6065c90d 100644 --- a/util/ego/sr/sr_xform.h +++ b/util/ego/sr/sr_xform.h @@ -16,7 +16,7 @@ extern line_p move_pointer(); /* (offset tmp; int dir ) */ * onto/from the stack, depending on dir(ection). * We accept all kinds of pointer sizes. */ -extern make_header() ; /* (loop_p lp) */ +extern void make_header() ; /* (loop_p lp) */ /* Make sure that the loop has a header block, i.e. a block * has the loop entry block as its only successor and * that dominates the loop entry block. diff --git a/util/ego/ud/ud.c b/util/ego/ud/ud.c index 610fd7a5e..afcba53a5 100644 --- a/util/ego/ud/ud.c +++ b/util/ego/ud/ud.c @@ -531,6 +531,7 @@ STATIC ud_cleanup(p) } +void ud_optimize(p) proc_p p; { diff --git a/util/ego/ud/ud_const.c b/util/ego/ud/ud_const.c index 9e854bd38..d1a2a438f 100644 --- a/util/ego/ud/ud_const.c +++ b/util/ego/ud/ud_const.c @@ -131,7 +131,7 @@ bool affected(use,v,l) -STATIC search_backwards(use,v,found,def) +STATIC void search_backwards(use,v,found,def) line_p use, *def; short v; bool *found; diff --git a/util/ego/ud/ud_copy.c b/util/ego/ud/ud_copy.c index 3761dba2d..213f7252a 100644 --- a/util/ego/ud/ud_copy.c +++ b/util/ego/ud/ud_copy.c @@ -42,7 +42,7 @@ short nrcopies; /* number of copies in the current procedure #define COUNT 0 #define MAP 1 -STATIC traverse_defs(p,action) +STATIC void traverse_defs(p,action) proc_p p; int action; { @@ -121,7 +121,7 @@ STATIC bool is_changed(varl,start,stop) -STATIC gen_kill_copies(p) +STATIC void gen_kill_copies(p) proc_p p; { /* Compute C_GEN and C_KILL for every basic block diff --git a/util/ego/ud/ud_defs.c b/util/ego/ud/ud_defs.c index f6272acf8..875d01425 100644 --- a/util/ego/ud/ud_defs.c +++ b/util/ego/ud/ud_defs.c @@ -249,7 +249,7 @@ STATIC impl_globl_defs(p,gen_p) -STATIC impl_gen_defs(l,gen_p) +STATIC void impl_gen_defs(l,gen_p) line_p l; cset *gen_p; { diff --git a/util/led/extract.c b/util/led/extract.c index 3b0983c9d..5878d527d 100644 --- a/util/led/extract.c +++ b/util/led/extract.c @@ -23,6 +23,9 @@ static redefine(); static transfer(); extern ind_t savechar(); + +void namerelocate(); + /* * Get section sizes and symboltable information from present module. */ @@ -149,6 +152,7 @@ process(head) * Otherwise we just add the accumulated size of all normal parts in preceding * sections with the same size. */ +void namerelocate(name) register struct outname *name; { diff --git a/util/led/main.c b/util/led/main.c index 7b0fced7a..4ea0b0d05 100644 --- a/util/led/main.c +++ b/util/led/main.c @@ -36,9 +36,9 @@ static void setbase(int, uint32_t); static struct outname *makename(); static pass1(); static evaluate(); -static norm_commons(); +static void norm_commons(); static complete_sections(); -static change_names(); +static void change_names(); static bool setbit(); static bool tstbit(); static second_pass(); @@ -47,6 +47,8 @@ static pass2(); static do_statistics(); #endif +void addbase(); + main(argc, argv) int argc; char **argv; @@ -387,7 +389,7 @@ long sect_comm[MAXSECT]; * just like "normal" names. We also count the total size of common names * within each section to be able to compute the final size in the machine. */ -static +static void norm_commons() { register struct outname *name; @@ -484,7 +486,7 @@ complete_sections() * For each name we add the base of its section to its value, unless * the output has to be able to be linked again, as indicated by RFLAG. */ -static +static void change_names() { register int cnt; @@ -557,6 +559,7 @@ tstbit(indx, string) /* * Add the base of the section of a name to its value. */ +void addbase(name) struct outname *name; { diff --git a/util/led/memory.c b/util/led/memory.c index b99447172..6349c826a 100644 --- a/util/led/memory.c +++ b/util/led/memory.c @@ -519,6 +519,7 @@ core_free(piece, p) * Reset index into piece of memory for modules and * take care that the allocated pieces will not be moved. */ +void freeze_core() { register int i; diff --git a/util/led/output.c b/util/led/output.c index cb7abceb2..0ee622e3a 100644 --- a/util/led/output.c +++ b/util/led/output.c @@ -10,7 +10,7 @@ static char rcsid[] = "$Id$"; #include "const.h" #include "memory.h" -static generate_section_names(); +static void generate_section_names(); extern struct outhead outhead; extern bool incore; @@ -51,7 +51,7 @@ beginoutput() * Generate names for all sections and put them after the global names. * Section names are used for relocation. */ -static +static void generate_section_names() { register struct outname *name; diff --git a/util/led/save.c b/util/led/save.c index a311d0413..3804413d9 100644 --- a/util/led/save.c +++ b/util/led/save.c @@ -22,6 +22,7 @@ static char rcsid[] = "$Id$"; extern bool incore; extern char *core_alloc(); +void savemagic() { register char *p; @@ -35,6 +36,7 @@ savemagic() } } +void savehdr(hdr) struct ar_hdr *hdr; { @@ -91,6 +93,7 @@ savechar(piece, off) * allocation, but the string of which name->on_foff is the offset may be * destroyed, so we save that first. */ +void savelocal(name) struct outname *name; { diff --git a/util/mcgg/LICENSE b/util/mcgg/LICENSE new file mode 100644 index 000000000..b21f90758 --- /dev/null +++ b/util/mcgg/LICENSE @@ -0,0 +1,20 @@ +Copyright (c) 1993,1994,1995,1996 David R. Hanson. + +Permission is hereby granted, free of charge, to any person obtaining a copy of this +software and associated documentation files (the "Software"), to deal in the Software +without restriction, including without limitation the rights to use, copy, modify, +merge, publish, distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be included in all copies +or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE +OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + diff --git a/util/mcgg/README b/util/mcgg/README new file mode 100644 index 000000000..21c982457 --- /dev/null +++ b/util/mcgg/README @@ -0,0 +1,12 @@ +mcgg is very heavily based on the iburg code generator by C. W. Fraser, D. R. +Hanson and T. A. Proebsting, described in ACM Letters on Prog. Languages and +Systems 1, 3 (Sep. 1992), 213-226: + +http://storage.webhop.net/documents/iburg.pdf + +For the original source, see the iburg-import branch (this is the version with +all the mcgg extensions). + +iburg is licensed under the MIT open source license; see the LICENSE file. + + diff --git a/util/mcgg/UPSTREAM b/util/mcgg/UPSTREAM new file mode 100644 index 000000000..9cd9ae41e --- /dev/null +++ b/util/mcgg/UPSTREAM @@ -0,0 +1,6 @@ +This is a copy of iburg from head of git here: + +https://github.com/drh/iburg + +Version: 2151dd7d126e2f804b822bb78059c870a3a15f5e + diff --git a/util/mcgg/build.lua b/util/mcgg/build.lua new file mode 100644 index 000000000..f8055050c --- /dev/null +++ b/util/mcgg/build.lua @@ -0,0 +1,91 @@ +include("first/yacc.lua") + +flex { + name = "flex", + srcs = { "./*.l" }, +} + +yacc { + name = "yacc", + srcs = { "./*.y" }, +} + +normalrule { + name = "ircodes", + outleaves = { "ircodes-dyn.h", "ircodes.c" }, + ins = { + "./ircodes.sh", + "./ir.dat" + }, + commands = { + "%{ins[1]} %{ins[2]} %{outs[1]} %{outs[2]}" + } +} + +clibrary { + name = "lib", + srcs = { + matching(filenamesof("+ircodes"), "%.c$"), + }, + deps = { + "+ircodes", + "./ircodes.h" + }, + hdrs = { + matching(filenamesof("+ircodes"), "%.h$"), + "./ircodes.h", + "./mcgg.h" + } +} + +cprogram { + name = "mcgg", + srcs = { + "./*.c", + matching(filenamesof("+flex"), "%.c$"), + matching(filenamesof("+yacc"), "%.c$") + }, + deps = { + "./iburg.h", + "+lib", + "+yacc", + "modules/src/data+lib", + "modules+headers", + } +} + +definerule("mcgg", + { + srcs = { type="targets" } + }, + function(e) + -- Remember this is executed from the caller's directory; local + -- target names will resolve there + if (#e.srcs ~= 1) then + error("you must supply exactly one input file") + end + + local cpptable = cppfile { + name = e.name.."/cpptable", + outleaf = "cpptable", + srcs = e.srcs + } + + return normalrule { + name = e.name, + cwd = e.cwd, + outleaves = { + "tables.c", + "tables.h", + }, + ins = { + "util/mcgg+mcgg", + cpptable + }, + commands = { + "%{ins[1]} -i %{ins[2]} -o %{outs[1]} -h %{outs[2]}", + } + } + end +) + diff --git a/util/mcgg/gram.y b/util/mcgg/gram.y new file mode 100644 index 000000000..891030a10 --- /dev/null +++ b/util/mcgg/gram.y @@ -0,0 +1,234 @@ +%{ +#include +#include +#include +#include +#include +#include +#include "iburg.h" +#include "astring.h" + +#define YYDEBUG 1 + +extern int yylex(void); + +%} +%union { + arith n; + const char* string; + Nonterm nonterm; + Tree tree; + Rule rule; + struct reg* reg; + struct stringlist* stringlist; + struct terminfo terminfo; + struct expr* expr; + struct constraint* constraint; +} + +%term ALIASES +%term COPY +%term CORRUPTED +%term COST +%term DECLARATIONS +%term EMIT +%term EQUALS +%term FRAGMENT +%term NAMED +%term NOTEQUALS +%term PATTERNS +%term PREFERS +%term PRESERVED +%term REGISTERS +%term WHEN +%term WITH + +%token INT +%token ID +%token QFRAGMENT + +%type constraint +%type constraints +%type predicate +%type predicate_arg +%type predicate_args +%type declaration +%type register +%type pattern +%type pattern_constraints +%type pattern_emit +%type nodename +%type aliases +%type names +%type qfragments +%type terminfo +%type rhs +%% + +spec + : REGISTERS registers + DECLARATIONS declarations + PATTERNS patterns + ; + +registers + : /* nothing */ + | registers register ';' + | register ';' + ; + +register + : ID { $$ = makereg($1); } + | register NAMED '(' names ')' { $$ = $1; setregnames($$, $4); } + | register ALIASES '(' aliases ')' { $$ = $1; addregaliases($$, $4); } + | register ID { $$ = $1; addregattr($1, $2); } + ; + +names + : QFRAGMENT { $$ = calloc(1, sizeof(*$$)); stringlist_add($$, $1); } + | names ',' QFRAGMENT { $$ = $1; stringlist_add($$, $3); } + ; + +aliases + : ID { $$ = calloc(1, sizeof(*$$)); stringlist_add($$, $1); } + | aliases ',' ID { $$ = $1; stringlist_add($$, $3); } + ; + +declarations + : /* nothing */ + | declarations declaration ';' + | declaration ';' + ; + +declaration + : ID { $$ = nonterm($1, true); } + | declaration FRAGMENT { $$ = $1; $$->is_fragment = true; } + ; + +patterns + : /* nothing */ + | patterns pattern ';' + | patterns ';' + ; + +pattern + : terminfo '=' rhs { nonterm($1.name, false); $$ = rule(&$1, $3); } + | rhs { $$ = rule(NULL, $1); } + | pattern PREFERS predicate { $$ = $1; array_append(&$$->prefers, $3); } + | pattern WHEN predicate { $$ = $1; array_append(&$$->requires, $3); } + | pattern COST INT { $$ = $1; $$->cost = $3; } + | pattern_constraints { $$ = $1; } + | pattern_emit { $$ = $1; } + ; + +rhs + : terminfo { $$ = tree(&$1, NULL, NULL); } + | terminfo '(' rhs ')' { $$ = tree(&$1, $3, NULL); } + | terminfo '(' rhs ',' rhs ')' { $$ = tree(&$1, $3, $5); } + ; + +terminfo + : nodename { $$.name = $1; } + | '(' ID ')' nodename { $$.attr = $2; $$.name = $4; } + | ID ':' nodename { $$.label = $1; $$.name = $3; } + | ID ':' '(' ID ')' nodename { $$.label = $1; $$.attr = $4; $$.name = $6; } + ; + +nodename + : ID { $$ = $1; } + | ID '.' ID { $$ = aprintf("%s.%s", $1, $3); } + ; + +pattern_emit + : pattern EMIT qfragments { + $$ = $1; + if (!$$->lhs->is_fragment) + stringlist_add($3, "\n"); + stringlist_addall(&$$->code, $3); + } + ; + +pattern_constraints + : pattern WITH constraints { + struct constraint* c = $3; + $$ = $1; + while (c) + { + array_append(&$$->constraints, c); + c = c->next; + } + } + ; + +constraints + : constraint { $$ = $1; } + | constraints ',' constraint { $$ = $3; $$->next = $1; } + ; + +constraint + : '(' constraint ')' { $$ = $2; } + | '%' ID EQUALS '%' ID { $$ = calloc(1, sizeof(*$$)); + $$->type = CONSTRAINT_EQUALS; $$->left = $2; $$->right = $5; } + | CORRUPTED '(' ID ')' { $$ = calloc(1, sizeof(*$$)); + $$->type = CONSTRAINT_CORRUPTED_ATTR; $$->left = $3; } + | PRESERVED '(' '%' ID ')' { $$ = calloc(1, sizeof(*$$)); + $$->type = CONSTRAINT_PRESERVED; $$->left = $4; } + ; + +qfragments + : /* nothing */ { $$ = calloc(1, sizeof *$$); } + | qfragments QFRAGMENT { $$ = $1; stringlist_add($$, $2); } + ; + +predicate + : ID '(' predicate_args ')' { + $$ = calloc(1, sizeof *$$); + $$->type = PREDICATE_FUNCTION; + $$->u.name = $1; + $$->next = $3; + } + ; + +predicate_args + : /* nothing */ { $$ = NULL; } + | predicate_arg { $$ = $1; } + | predicate_arg ',' predicate_args { $$ = $1; $$->next = $3; } + ; + +predicate_arg + : '%' ID { $$ = calloc(1, sizeof *$$); $$->type = PREDICATE_NODE; $$->u.name = $2; } + | INT { $$ = calloc(1, sizeof *$$); $$->type = PREDICATE_NUMBER; $$->u.number = $1; } + ; + +%% +#include +#include + +int errcnt = 0; +static char buf[BUFSIZ], *bp = buf; +static int ppercent = 0; + +void yyerror(char *fmt, ...) { + va_list ap; + + va_start(ap, fmt); + if (yylineno > 0) + fprintf(stderr, "line %d: ", yylineno); + vfprintf(stderr, fmt, ap); + if (fmt[strlen(fmt)-1] != '\n') + fprintf(stderr, "\n"); + errcnt++; + exit(1); +} + +void yywarn(char *fmt, ...) { + va_list ap; + + va_start(ap, fmt); + if (yylineno > 0) + fprintf(stderr, "line %d: ", yylineno); + fprintf(stderr, "warning: "); + vfprintf(stderr, fmt, ap); +} + +/* vim: set sw=4 ts=4 expandtab : */ diff --git a/util/mcgg/iburg.c b/util/mcgg/iburg.c new file mode 100644 index 000000000..23705c7d8 --- /dev/null +++ b/util/mcgg/iburg.c @@ -0,0 +1,1478 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "iburg.h" +#include "ircodes.h" +#include "astring.h" +#include "smap.h" +#include "mcgg.h" + +static char rcsid[] = "$Id$"; + +int maxcost = SHRT_MAX / 2; + +FILE* infp = NULL; +FILE* outfp = NULL; +FILE* hdrfp = NULL; + +static char* prefix = "burm"; +static int Tflag = 1; /* tracing */ +static int ntnumber = 0; +static Nonterm start = 0; +static Term terms; +static Nonterm nts; +static Rule rules; +static int nrules; + +static SMAPOF(struct reg) registers; +static SMAPOF(struct regattr) registerattrs; + +static void print(const char* fmt, ...); +static void printh(const char* fmt, ...); +static void registerterminals(void); +static struct regattr* makeregattr(const char* id); +static void emitclosure(Nonterm nts); +static void emitcost(Tree t, const char* v); +static void emitcostcalc(Rule r); +static void emitdefs(Nonterm nts, int ntnumber); +static void emitfuncs(void); +static void emitheader(void); +static void emitinsndata(Rule rules); +static void emitkids(Rule rules, int nrules); +static void emitlabel(Nonterm start); +static void emitleaf(Term p, int ntnumber); +static void emitnts(Rule rules, int nrules); +static void emitpredicatedefinitions(Rule rules); +static void emitrecord(char* pre, Rule r, int cost); +static void emitregisterattrs(); +static void emitregisters(); +static void emitrule(Nonterm nts); +static void emitstate(Term terms, Nonterm start, int ntnumber); +static void emitstring(Rule rules); +static void emitstruct(Nonterm nts, int ntnumber); +static void emitterms(Term terms); +static void emittest(Tree t, const char* v, const char* suffix); + +extern int yy_flex_debug; + +int main(int argc, char* argv[]) +{ + int c, i; + Nonterm p; + + #if 0 + extern int yydebug; + yydebug = 1; + #endif + + infp = stdin; + outfp = stdout; + hdrfp = NULL; + yy_flex_debug = 0; + + for (;;) + { + int opt = getopt(argc, argv, "p:i:o:h:yf"); + if (opt == -1) + break; + + switch (opt) + { + case 'p': + prefix = optarg; + break; + + case 'i': + infp = fopen(optarg, "r"); + if (!infp) + { + yyerror("cannot open input file: %s\n", strerror(errno)); + exit(1); + } + break; + + case 'o': + outfp = fopen(optarg, "w"); + if (!outfp) + { + yyerror("cannot open output file: %s\n", strerror(errno)); + exit(1); + } + break; + + case 'h': + hdrfp = fopen(optarg, "w"); + if (!hdrfp) + { + yyerror("cannot open output header file: %s\n", strerror(errno)); + exit(1); + } + break; + + case 'y': + { + extern int yydebug; + yydebug = 1; + break; + } + + case 'f': + { + yy_flex_debug = 1; + break; + } + + default: + yyerror("usage: %s [-p prefix] < input > output\n", argv[0]); + exit(1); + } + } + + emitheader(); + registerterminals(); + + start = nonterm("stmt", true); + + /* Define some standard terms. */ + + { + const static struct terminfo reg = { "reg", NULL, "" }; + const static struct terminfo REG = { "REG", NULL, NULL }; + const static struct terminfo NOPI = { "NOP.I", NULL, NULL }; + const static struct terminfo NOPF = { "NOP.F", NULL, NULL }; + const static struct terminfo NOPL = { "NOP.L", NULL, NULL }; + const static struct terminfo NOPD = { "NOP.D", NULL, NULL }; + const static struct terminfo RET = { "RET", NULL, NULL }; + + nonterm("reg", true); + + rule(NULL, tree(®, NULL, NULL))->cost = 1; + rule(®, tree(®, NULL, NULL))->cost = 1; + rule(®, tree(&NOPI, tree(®, NULL, NULL), NULL))->cost = 1; + rule(®, tree(&NOPF, tree(®, NULL, NULL), NULL))->cost = 1; + rule(®, tree(&NOPL, tree(®, NULL, NULL), NULL))->cost = 1; + rule(®, tree(&NOPD, tree(®, NULL, NULL), NULL))->cost = 1; + rule(NULL, tree(&RET, NULL, NULL))->cost = 1; + } + + yyin = infp; + yyparse(); + + emitregisterattrs(); + emitregisters(); + emitdefs(nts, ntnumber); + emitstruct(nts, ntnumber); + emitnts(rules, nrules); + emitterms(terms); + emitstring(rules); + emitrule(nts); + emitclosure(nts); + emitpredicatedefinitions(rules); + emitinsndata(rules); + if (start) + emitstate(terms, start, ntnumber); + print("#ifdef STATE_LABEL\n"); + if (start) + emitlabel(start); + emitkids(rules, nrules); + emitfuncs(); + print("#endif\n"); + print("#include \"mcgg_generated_footer.h\"\n"); + printh("#endif\n"); + + if (outfp) + fclose(outfp); + if (hdrfp) + fclose(hdrfp); + + return errcnt > 0; +} + +static void registerterminal(const struct ir_data* data, int iropcode, char type) +{ + const char* s = (type == 0) ? data->name : aprintf("%s.%c", data->name, type); + int esn = ir_to_esn(iropcode, type); + + term(s, esn); +} + +static void registerterminals(void) +{ + int i; + + for (i=0; ilink) + if (strcmp(name, p->sym.name) == 0) + return &p->sym; + return 0; +} + +/* install - install symbol name */ +static void* install(const char* name) +{ + struct entry* p = calloc(1, sizeof *p); + int i = hash(name) % HASHSIZE; + + p->sym.name = name; + p->link = table[i]; + table[i] = p; + return &p->sym; +} + +struct reg* makereg(const char* id) +{ + struct reg* p = smap_get(®isters, id); + static int number = 0; + + if (p) + yyerror("redefinition of '%s'", id); + p = calloc(1, sizeof(*p)); + p->name = id; + p->number = number++; + array_append(&p->aliases, p); + smap_put(®isters, id, p); + + return p; +} + +void setregnames(struct reg* reg, struct stringlist* names) +{ + if (reg->names) + yyerror("you can only set one set of register names"); + + reg->names = names; +} + +struct regattr* makeregattr(const char* id) +{ + struct regattr* p = smap_get(®isterattrs, id); + static int number = 0; + + if (p) + yyerror("redefinition of '%s'", id); + p = calloc(1, sizeof(*p)); + p->name = id; + p->number = number++; + smap_put(®isterattrs, id, p); + + return p; +} + +void addregattr(struct reg* reg, const char* id) +{ + struct regattr* p = smap_get(®isterattrs, id); + + if (!p) + p = makeregattr(id); + + reg->attrs |= 1<<(p->number); +} + +void addregalias(struct reg* r1, struct reg* r2) +{ + if (!array_appendu(&r1->aliases, r2)) + { + int i; + + for (i=0; ialiases.count; i++) + addregalias(r1->aliases.item[i], r2); + } +} + +void addregaliases(struct reg* reg, struct stringlist* aliases) +{ + struct stringfragment* f = aliases->first; + + while (f) + { + struct reg* r = smap_get(®isters, f->data); + if (!r) + yyerror("register '%s' is not defined here", f->data); + + array_appendu(®->aliases, r); + array_appendu(&r->aliases, reg); + + f = f->next; + } +} + +struct regattr* getregattr(const char* id) +{ + struct regattr* p = smap_get(®isterattrs, id); + if (!p) + yyerror("'%s' is not the name of a register class", id); + return p; +} + +/* nonterm - create a new terminal id, if necessary */ +Nonterm nonterm(const char* id, bool allocate) +{ + Nonterm p = lookup(id); + Nonterm* q = &nts; + + if (p && p->kind == NONTERM) + return p; + if (p) + yyerror("redefinition of '%s' as something else\n", id); + if (!allocate) + yyerror("'%s' has not been declared\n", id); + + p = install(id); + p->kind = NONTERM; + p->number = ++ntnumber; + if (p->number == 1) + start = p; + while (*q && (*q)->number < p->number) + q = &(*q)->link; + assert(*q == 0 || (*q)->number != p->number); + p->link = *q; + *q = p; + return p; +} + +/* term - create a new terminal id with external symbol number esn */ +Term term(const char* id, int esn) +{ + Term p = lookup(id); + Term* q = &terms; + + if (p) + yyerror("redefinition of '%s'\n", id); + + p = install(id); + p->kind = TERM; + p->esn = esn; + p->arity = -1; + while (*q && (*q)->esn < p->esn) + q = &(*q)->link; + if (*q && (*q)->esn == p->esn) + yyerror("duplicate external symbol number `%s=%d'\n", + p->name, p->esn); + p->link = *q; + *q = p; + return p; +} + +/* tree - create & initialize a tree node with the given fields */ +Tree tree(const struct terminfo* ti, Tree left, Tree right) +{ + Tree t = calloc(1, sizeof *t); + Term p = lookup(ti->name); + int arity = 0; + + if (left && right) + arity = 2; + else if (left) + arity = 1; + if (p == NULL && arity > 0) + { + yyerror("undefined terminal `%s'\n", ti->name); + p = term(ti->name, -1); + } + else if (p == NULL && arity == 0) + p = (Term)nonterm(ti->name, false); + else if (p && p->kind == NONTERM && arity > 0) + { + yyerror("`%s' is a non-terminal\n", ti->name); + p = term(ti->name, -1); + } + if (p->kind == TERM && p->arity == -1) + p->arity = arity; + if (p->kind == TERM && arity != p->arity) + yyerror("inconsistent arity for terminal `%s'\n", ti->name); + t->op = p; + t->nterms = p->kind == TERM; + if (t->left = left) + t->nterms += left->nterms; + if (t->right = right) + t->nterms += right->nterms; + + /* Special rules that have no output register attribute use "" as the + * attribute name; these can't be made by the grammar. */ + + t->label = ti->label; + if ((p->kind == TERM) && (ti->attr)) + yyerror("can't specify an input register attribute for terminal '%s'", ti->name); + if (p->kind == NONTERM) + { + Nonterm nt = (Nonterm)p; + if (nt->is_fragment && ti->attr) + yyerror("can't specify an input register attribute for fragment '%s'", ti->name); + if (!nt->is_fragment && !ti->attr) + yyerror("must specify an input register attribute for non-fragment '%s'", ti->name); + + if (ti->attr && ti->attr[0]) + { + t->attr = smap_get(®isterattrs, ti->attr); + if (!t->attr) + yyerror("'%s' doesn't seem to be a known register attribute", ti->attr); + } + } + return t; +} + +/* rule - create & initialize a rule with the given fields */ +Rule rule(const struct terminfo* ti, Tree pattern) +{ + static int number = 1; + static const struct terminfo stmt = { "stmt", NULL, NULL }; + Rule r = calloc(1, sizeof *r); + Rule *q; + Term p = pattern->op; + + if (!ti) + ti = &stmt; + + nrules++; + r->lineno = yylineno; + r->lhs = nonterm(ti->name, false); + r->packed = ++r->lhs->lhscount; + for (q = &r->lhs->rules; *q; q = &(*q)->decode) + ; + *q = r; + r->pattern = pattern; + r->ern = number++; + if (p->kind == TERM) + { + r->next = p->rules; + p->rules = r; + } + else if (pattern->left == NULL && pattern->right == NULL) + { + Nonterm p = pattern->op; + r->chain = p->chain; + p->chain = r; + } + for (q = &rules; *q && (*q)->ern < r->ern; q = &(*q)->link) + ; + if (*q && (*q)->ern == r->ern) + yyerror("duplicate external rule number `%d'\n", r->ern); + r->link = *q; + *q = r; + + r->label = ti->label; + if (r->lhs->is_fragment && ti->attr) + yyerror("can't specify an output register attribute for a fragment"); + if (!r->lhs->is_fragment && !ti->attr && (r->lhs->number != NONTERM_STMT)) + yyerror("must specify an output register attribute for non-fragments"); + + /* Special rules that have no output register attribute use "" as the + * attribute name; these can't be made by the grammar. */ + + if (ti->attr && ti->attr[0]) + { + r->attr = smap_get(®isterattrs, ti->attr); + if (!r->attr) + yyerror("'%s' doesn't seem to be a known register attribute", ti->attr); + } + + return r; +} + +/* print - formatted output */ + +static void printto(FILE* fp, const char* fmt, va_list ap) +{ + if (!fp) + return; + + for (; *fmt; fmt++) + if (*fmt == '%') + switch (*++fmt) + { + case 'd': + fprintf(fp, "%d", va_arg(ap, int)); + break; + + case 'x': + fprintf(fp, "%x", va_arg(ap, uint32_t)); + break; + + case 's': + fputs(va_arg(ap, char*), fp); + break; + + case 'P': + fprintf(fp, "%s_", prefix); + break; + + case 'T': + { + Tree t = va_arg(ap, Tree); + print("%S", t->op); + if (t->left && t->right) + print("(%T,%T)", t->left, t->right); + else if (t->left) + print("(%T)", t->left); + break; + } + + case 'R': + { + Rule r = va_arg(ap, Rule); + print("%S: %T", r->lhs, r->pattern); + break; + } + + case 'S': + fputs(va_arg(ap, Term)->name, fp); + break; + + case '1': + case '2': + case '3': + case '4': + case '5': + { + int n = *fmt - '0'; + while (n-- > 0) + putc('\t', fp); + break; + } + + default: + putc(*fmt, fp); + break; + } + else + putc(*fmt, fp); +} + +static void print(const char* fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + printto(outfp, fmt, ap); + va_end(ap); +} + +static void printh(const char* fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + printto(hdrfp, fmt, ap); + va_end(ap); +} + +static void emitregisterattrs(void) +{ + int i; + + print("const char* %Pregister_class_names[] = {\n"); + for (i=0; inumber == i); + + print("%1\"%s\",\n", rc->name); + printh("#define %P%s_ATTR (1U<<%d)\n", rc->name, rc->number); + } + print("};\n\n"); + printh("\n"); +} + +static void emitregisters(void) +{ + int i, j; + + for (i=0; iname); + for (j=0; jaliases.count; j++) + print("&%Pregister_data[%d], ", r->aliases.item[j]->number); + print("NULL\n};\n"); + } + + for (i=0; iname); + if (r->names) + { + struct stringfragment* f = r->names->first; + while (f) + { + print("\"%s\", ", f->data); + f = f->next; + } + } + else + print("\"%s\", ", r->name); + print("NULL\n};\n"); + } + + print("const struct %Pregister_data %Pregister_data[] = {\n"); + for (i=0; inumber == i); + + print("%1{ \"%s\", 0x%x, %Pregister_names_%d_%s, %Pregister_aliases_%d_%s },\n", + r->name, r->attrs, i, r->name, i, r->name); + } + print("%1{ NULL }\n"); + print("};\n\n"); +} + +/* emitcase - emit one case in function state */ +static void emitcase(Term p, int ntnumber) +{ + Rule r; + + if (!p->rules) + return; + + print("%1case %d: /* %S */\n", p->esn, p); + switch (p->arity) + { + case 0: + case -1: + break; + case 1: + print("%2assert(l);\n"); + break; + case 2: + print("%2assert(l && r);\n"); + break; + default: + assert(0); + } + for (r = p->rules; r; r = r->next) + { + switch (p->arity) + { + case 0: + case -1: + print("%2{%1/* %R */\n%3c = ", r); + emitcostcalc(r); + break; + case 1: + if (r->pattern->nterms > 1) + { + print("%2if (%1/* %R */\n", r); + emittest(r->pattern->left, "l", " "); + print("%2) {\n%3c = "); + } + else + { + print("%2{%1/* %R */\n%3c = ", r); + } + emitcostcalc(r); + emitcost(r->pattern->left, "l"); + break; + case 2: + if (r->pattern->nterms > 1) + { + print("%2if (%1/* %R */\n", r); + emittest(r->pattern->left, "l", + r->pattern->right->nterms ? " && " : " "); + emittest(r->pattern->right, "r", " "); + print("%2) {\n%3c = "); + } + else + { + print("%2{%1/* %R */\n%3c = ", r); + } + emitcostcalc(r); + emitcost(r->pattern->left, "l"); + emitcost(r->pattern->right, "r"); + break; + default: + assert(0); + } + print("%d);\n", r->cost); + emitrecord("\t\t\t", r, 0); + print("%2}\n"); + } + print("%2break;\n"); +} + +/* emitclosure - emit the closure functions */ +static void emitclosure(Nonterm nts) +{ + Nonterm p; + + for (p = nts; p; p = p->link) + if (p->chain) + print("static void %Pclosure_%S(struct %Pstate *, int);\n", p); + print("\n"); + for (p = nts; p; p = p->link) + if (p->chain) + { + Rule r; + print("static void %Pclosure_%S(struct %Pstate *p, int c) {\n", p); + for (r = p->chain; r; r = r->chain) + emitrecord("\t", r, r->cost); + print("}\n\n"); + } +} + +/* emitcost - emit cost computation for tree t */ +static void emitcost(Tree t, const char* v) +{ + Nonterm p = t->op; + + if (p->kind == TERM) + { + if (t->left) + emitcost(t->left, aprintf("%s->left", v)); + if (t->right) + emitcost(t->right, aprintf("%s->right", v)); + } + else + print("%s->cost[%P%S_NT] + ", v, p); +} + +/* emitdefs - emit non-terminal defines and data structures */ +static void emitdefs(Nonterm nts, int ntnumber) +{ + Nonterm p; + + printh("enum {\n"); + for (p = nts; p; p = p->link) + printh("%1%P%S_NT = %d,\n", p, p->number); + printh("%1%Pmax_nt = %d\n", ntnumber); + printh("};\n\n"); + + print("const char *%Pntname[] = {\n%10,\n"); + for (p = nts; p; p = p->link) + print("%1\"%S\",\n", p); + print("%10\n};\n\n"); +} + +/* emitfuncs - emit functions to access node fields */ +static void emitfuncs(void) +{ + print("int %Pop_label(NODEPTR_TYPE p) {\n" + "%1%Passert(p, PANIC(\"NULL tree in %Pop_label\\n\"));\n" + "%1return OP_LABEL(p);\n}\n\n"); + print("STATE_TYPE %Pstate_label(NODEPTR_TYPE p) {\n" + "%1%Passert(p, PANIC(\"NULL tree in %Pstate_label\\n\"));\n" + "%1return STATE_LABEL(p);\n}\n\n"); + print("NODEPTR_TYPE %Pchild(NODEPTR_TYPE p, int index) {\n" + "%1%Passert(p, PANIC(\"NULL tree in %Pchild\\n\"));\n" + "%1switch (index) {\n%1case 0:%1return LEFT_CHILD(p);\n" + "%1case 1:%1return RIGHT_CHILD(p);\n%1}\n" + "%1%Passert(0, PANIC(\"Bad index %%d in %Pchild\\n\", index));\n%1return 0;\n}\n\n"); +} + +/* emitheader - emit initial definitions */ +static void emitheader(void) +{ + print("#include \"mcgg_generated_header.h\"\n"); + if (Tflag) + print("static NODEPTR_TYPE %Pnp;\n\n"); + + printh("#ifndef MCG_DEFS_H\n"); + printh("#define MCG_DEFS_H\n\n"); +} + +/* computekids - compute paths to kids in tree t */ +static char* computekids(Tree node, const char* v, char* bp, int* ip) +{ + Term t = node->op; + + if (!node->left && !node->right) + { + sprintf(bp, "\t\tkids[%d] = %s;\n", (*ip)++, v); + bp += strlen(bp); + } + + if (t->kind == TERM) + { + if (t->arity >= 1) + bp = computekids(node->left, aprintf("LEFT_CHILD(%s)", v), bp, ip); + if (t->arity == 2) + bp = computekids(node->right, aprintf("RIGHT_CHILD(%s)", v), bp, ip); + } + return bp; +} + +/* emitkids - emit burm_kids */ +static void emitkids(Rule rules, int nrules) +{ + int i; + Rule r, * rc = calloc(nrules+1, sizeof *rc); + char** str = calloc(nrules+1, sizeof *str); + + for (i = 0, r = rules; r; r = r->link) + { + int j = 0; + char buf[1024], * bp = buf; + *computekids(r->pattern, "p", bp, &j) = 0; + for (j = 0; str[j] && strcmp(str[j], buf); j++) + ; + if (str[j] == NULL) + str[j] = strdup(buf); + r->kids = rc[j]; + rc[j] = r; + } + print("NODEPTR_TYPE *%Pkids(NODEPTR_TYPE p, int eruleno, NODEPTR_TYPE kids[]) {\n" + "%1%Passert(p, PANIC(\"NULL tree in %Pkids\\n\"));\n" + "%1%Passert(kids, PANIC(\"NULL kids in %Pkids\\n\"));\n" + "%1switch (eruleno) {\n"); + for (i = 0; r = rc[i]; i++) + { + for (; r; r = r->kids) + print("%1case %d: /* %R */\n", r->ern, r); + print("%s%2break;\n", str[i]); + } + print("%1default:\n%2%Passert(0, PANIC(\"Bad external rule number %%d in %Pkids\\n\", eruleno));\n%1}\n%1return kids;\n}\n\n"); +} + +/* emitlabel - emit the labelling functions */ +static void emitlabel(Nonterm start) +{ + print("static void %Plabel1(NODEPTR_TYPE p) {\n" + "%1%Passert(p, PANIC(\"NULL tree in %Plabel\\n\"));\n" + "%1switch (%Parity[OP_LABEL(p)]) {\n" + "%1case 0:\n"); + if (Tflag) + print("%2%Pnp = p;\n"); + print("%2STATE_LABEL(p) = %Pstate(p, 0, 0);\n%2break;\n" + "%1case 1:\n%2%Plabel1(LEFT_CHILD(p));\n"); + if (Tflag) + print("%2%Pnp = p;\n"); + print("%2STATE_LABEL(p) = %Pstate(p,\n" + "%3STATE_LABEL(LEFT_CHILD(p)), 0);\n%2break;\n" + "%1case 2:\n%2%Plabel1(LEFT_CHILD(p));\n%2%Plabel1(RIGHT_CHILD(p));\n"); + if (Tflag) + print("%2%Pnp = p;\n"); + print("%2STATE_LABEL(p) = %Pstate(p,\n" + "%3STATE_LABEL(LEFT_CHILD(p)),\n%3STATE_LABEL(RIGHT_CHILD(p)));\n%2break;\n" + "%1}\n}\n\n"); + print( + "STATE_TYPE %Plabel(NODEPTR_TYPE p) {\n%1%Plabel1(p);\n" + "%1return ((struct %Pstate *)STATE_LABEL(p))->rule.%P%S ? STATE_LABEL(p) : 0;\n" + "}\n\n", + start); +} + +/* closure - fill in cost & rule with results of chain rules w/p as rhs */ +static void closure(int cost[], Rule rule[], Nonterm p, int c) +{ + Rule r; + + for (r = p->chain; r; r = r->chain) + if (c + r->cost < cost[r->lhs->number]) + { + cost[r->lhs->number] = c + r->cost; + rule[r->lhs->number] = r; + closure(cost, rule, r->lhs, c + r->cost); + } +} + +/* computents - fill in bp with burm_nts vector for tree t */ +static char* computents(Tree t, char* bp) +{ + if (t) + { + Nonterm p = t->op; + if (!t->left && !t->right) + { + if (p->kind == NONTERM) + sprintf(bp, "%s_%s_NT, ", prefix, p->name); + else + sprintf(bp, "0, "); + bp += strlen(bp); + } + else + bp = computents(t->right, computents(t->left, bp)); + } + return bp; +} + +/* emitnts - emit burm_nts ragged array */ +static void emitnts(Rule rules, int nrules) +{ + Rule r; + int i, j, * nts = calloc(nrules, sizeof *nts); + char** str = calloc(nrules, sizeof *str); + + for (i = 0, r = rules; r; r = r->link) + { + char buf[1024]; + *computents(r->pattern, buf) = 0; + for (j = 0; str[j] && strcmp(str[j], buf); j++) + ; + if (str[j] == NULL) + { + print("static const short %Pnts_%d[] = { %s0 };\n", j, buf); + str[j] = strdup(buf); + } + nts[i++] = j; + } + print("\nconst short *%Pnts[] = {\n"); + for (i = j = 0, r = rules; r; r = r->link) + { + for (; j < r->ern; j++) + print("%10,%1/* %d */\n", j); + print("%1%Pnts_%d,%1/* %d */\n", nts[i++], j++); + } + print("};\n\n"); +} + +/* emitrecord - emit code that tests for a winning match of rule r */ +static void emitrecord(char* pre, Rule r, int cost) +{ + print("%sif (", pre); + if (Tflag) + print("%Ptrace(%Pnp, %d, c + %d, p->cost[%P%S_NT]), ", + r->ern, cost, r->lhs); + print("c + %d < p->cost[%P%S_NT]) {\n" + "%s%1p->cost[%P%S_NT] = c + %d;\n%s%1p->rule.%P%S = %d;\n", + cost, r->lhs, pre, r->lhs, cost, pre, r->lhs, + r->packed); + if (r->lhs->chain) + print("%s%1%Pclosure_%S(p, c + %d);\n", pre, r->lhs, cost); + print("%s}\n", pre); +} + +/* emitrule - emit decoding vectors and burm_rule */ +static void emitrule(Nonterm nts) +{ + Nonterm p; + + for (p = nts; p; p = p->link) + { + Rule r; + print("static const short %Pdecode_%S[] = {\n%10,\n", p); + for (r = p->rules; r; r = r->decode) + print("%1%d,\n", r->ern); + print("};\n\n"); + } + print("int %Prule(STATE_TYPE state, int goalnt) {\n" + "%1%Passert(goalnt >= 1 && goalnt <= %d, PANIC(\"Bad goal nonterminal %%d in %Prule\\n\", goalnt));\n" + "%1if (!state)\n%2return 0;\n%1switch (goalnt) {\n", + ntnumber); + for (p = nts; p; p = p->link) + print("%1case %P%S_NT:" + "%1return %Pdecode_%S[((struct %Pstate *)state)->rule.%P%S];\n", + p, p, p); + print("%1default:\n%2%Passert(0, PANIC(\"Bad goal nonterminal %%d in %Prule\\n\", goalnt));\n%1}\n%1return 0;\n}\n\n"); +} + +static void print_path(uint32_t path) +{ + int i = 0; + + while (path > 0) + { + switch (path % 3) + { + case 1: print("LEFT_CHILD("); break; + case 2: print("RIGHT_CHILD("); break; + } + path /= 3; + i++; + } + + print("node"); + + while (i > 0) + { + print(")"); + i--; + } +} + +static const uint32_t PATH_MISSING = 0xffffffff; + +static uint32_t find_label(Tree root, const char* name, uint32_t path, Tree* found) +{ + uint32_t p; + + if (root->label && (strcmp(root->label, name) == 0)) + { + if (found) + *found = root; + return path; + } + + p = PATH_MISSING; + if (root->left && (p == PATH_MISSING)) + p = find_label(root->left, name, path*3 + 1, found); + if (root->right && (p == PATH_MISSING)) + p = find_label(root->right, name, path*3 + 2, found); + return p; +} + +static void label_not_found(Rule rule, const char* label) +{ + yylineno = rule->lineno; + yyerror("label '%s' not found", label); + exit(1); +} + +static bool find_child_index(Tree node, const char* name, int* index, Tree* found) +{ + /* This must return the same ordering as the burm_kids() function uses. */ + + if (node->label && strcmp(node->label, name) == 0) + { + if (found) + *found = node; + return true; + } + + if (!node->left && !node->right) + (*index)++; + + if (node->left && find_child_index(node->left, name, index, found)) + return true; + if (node->right && find_child_index(node->right, name, index, found)) + return true; + return false; +} + +static void emit_predicate_expr(Rule r, struct expr* p) +{ + bool first = true; + + assert(p->type == PREDICATE_FUNCTION); + print("%1if (%Ppredicate_%s(", p->u.name); + + p = p->next; + while (p) + { + if (!first) + print(", "); + else + first = false; + + switch (p->type) + { + case PREDICATE_NODE: + { + uint32_t path = find_label(r->pattern, p->u.name, 0, NULL); + if (path == PATH_MISSING) + label_not_found(r, p->u.name); + + print_path(path); + break; + } + + case PREDICATE_NUMBER: + { + print("%d", p->u.number); + break; + } + } + + p = p->next; + } + + print("))"); +} + +/* emitpredicates - emit predicates for rules */ +static void emitpredicatedefinitions(Rule r) +{ + int i; + + while (r) + { + print("/* %R */\n", r); + print("static int %Padjust_cost_%d(NODEPTR_TYPE node, int cost) {\n", r->ern); + + for (i=0; iprefers.count; i++) + { + emit_predicate_expr(r, r->prefers.item[i]); + print(" cost -= 1;\n"); + } + + for (i=0; irequires.count; i++) + { + emit_predicate_expr(r, r->requires.item[i]); + print(" {} else return %d;\n", maxcost); + } + + print("%1if (cost > %d) return %d;\n", maxcost, maxcost); + print("%1if (cost < 1) return 1;\n"); + print("%1return cost;\n"); + print("}\n\n"); + r = r->link; + } +} + +static void emit_input_regs(Tree node, int* index) +{ + /* This must return the same ordering as the burm_kids() function uses. */ + + Nonterm nt = node->op; + if ((nt->kind == NONTERM) && !nt->is_fragment && !node->left && !node->right) + { + if (node->attr) + { + uint32_t attr = 1<attr->number; + print("%1data->constrain_input_reg(%d, 0x%x /* %s */);\n", + *index, attr, node->attr->name); + } + } + + if (!node->left && !node->right) + (*index)++; + + if (node->left) + emit_input_regs(node->left, index); + if (node->right) + emit_input_regs(node->right, index); +} + +static void emit_output_constraints(Rule r) +{ + int i; + struct constraint* outputc = NULL; + + for (i=0; iconstraints.count; i++) + { + struct constraint* c = r->constraints.item[i]; + + if (c->type == CONSTRAINT_EQUALS) + { + if (strcmp(c->left, r->label) != 0) + yyerror("equality register constraints must have an output register on the left hand side"); + if (outputc != NULL) + yyerror("you can't specify more than one output register constraint"); + outputc = c; + } + } + + if (outputc) + { + int index = 0; + + if (!find_child_index(r->pattern, outputc->right, &index, NULL)) + label_not_found(r, outputc->right); + + print("%1data->constrain_output_reg_equal_to(%d);\n", index); + } +} + +static void emit_input_constraints(Rule r) +{ + int i; + for (i=0; iconstraints.count; i++) + { + int index; + struct constraint* c = r->constraints.item[i]; + + if (c->type == CONSTRAINT_PRESERVED) + { + if (strcmp(c->left, r->label) == 0) + yyerror("cannot preserve an output register!"); + + index = 0; + if (!find_child_index(r->pattern, c->left, &index, NULL)) + label_not_found(r, c->left); + + print("%1data->constrain_input_reg_preserved(%d);\n", index); + } + } +} + +/* emitinsndata - emit the code generation data */ +static void emitinsndata(Rule rules) +{ + int k; + Rule r; + + r = rules; + while (r) + { + struct stringfragment* f = r->code.first; + yylineno = r->lineno; + + if (!f) + { + /* This instruction has no code; make sure it's not a fragment. */ + if (r->lhs->is_fragment) + { + yylineno = r->lineno; + yyerror("rule is a fragment, but doesn't emit anything"); + } + } + + print("/* %R */\n", r); + print("static void %Pemitter_%d(const struct %Pemitter_data* data) {\n", r->ern); + + if (r->attr) + print("%1data->constrain_output_reg(0x%x /* %s */);\n", + 1<attr->number, r->attr->name); + + { + int index = 0; + emit_input_regs(r->pattern, &index); + } + + emit_output_constraints(r); + emit_input_constraints(r); + + while (f) + { + char* data = strdup(f->data); + int type = *data++; + char* label = strtok(data, "."); + char* nameindex_s = strtok(NULL, "."); + int nameindex = nameindex_s ? atoi(nameindex_s) : 0; + + switch (type) + { + case '%': + { + if (r->label && (strcmp(label, r->label) == 0)) + print("%1data->emit_return_reg(%d);\n", nameindex); + else + { + Tree node; + int index = 0; + if (!find_child_index(r->pattern, label, &index, &node)) + label_not_found(r, label); + Nonterm nt = node->op; + + if (nt->kind == NONTERM) + { + if (nt->is_fragment) + print("%1data->emit_fragment(%d);\n", index); + else + print("%1data->emit_reg(%d, %d);\n", index, nameindex); + } + else + print("%1data->emit_reg(%d, %d);\n", index, nameindex); + } + break; + } + + case '$': + { + int index = 0; + if (!find_child_index(r->pattern, label, &index, NULL)) + label_not_found(r, label); + + if (nameindex != 0) + yyerror("indices other than 0 make no sense for $-values"); + + print("%1data->emit_value(%d);\n", index); + break; + } + + case '\n': + assert(f->data[1] == 0); + print("%1data->emit_eoi();\n"); + break; + + default: + print("%1data->emit_string(\"%s\");\n", f->data); + } + + f = f->next; + } + + print("}\n\n"); + r = r->link; + } + + r = rules; + print("const struct %Pinstruction_data %Pinstruction_data[] = {\n"); + k = 0; + while (r) + { + for (; k < r->ern; k++) + print("%1{ 0 }, /* %d */\n", k); + k++; + + print("%1{ /* %d: %R */\n", r->ern, r); + + print("%2\"%R\",\n", r); + + print("%2&%Pemitter_%d,\n", r->ern); + + print("%2%s,\n", r->lhs->is_fragment ? "true" : "false"); + + { + int i; + uint32_t attrs = 0; + + for (i=0; iconstraints.count; i++) + { + struct constraint* c = r->constraints.item[i]; + + if (c->type == CONSTRAINT_CORRUPTED_ATTR) + { + struct regattr* p = smap_get(®isterattrs, c->left); + if (!p) + yyerror("no such register attribute '%s'", c->left); + + attrs |= 1<<(p->number); + } + } + + print("%2%d, /* corruption attrs */\n", attrs); + } + + print("%1},\n"); + r = r->link; + } + print("};\n\n"); +} + +/* emitcost - emit a cost calculation via a predicate */ +static void emitcostcalc(Rule r) +{ + print("%Padjust_cost_%d(node, ", r->ern); +} + +/* emitstate - emit state function */ +static void emitstate(Term terms, Nonterm start, int ntnumber) +{ + int i; + Term p; + + print("STATE_TYPE %Pstate(NODEPTR_TYPE node, STATE_TYPE left, STATE_TYPE right) {\n%1int c;\n" + "%1int op = OP_LABEL(node);\n" + "%1struct %Pstate* p;\n" + "%1struct %Pstate* l = (struct %Pstate *)left;\n" + "%1struct %Pstate* r = (struct %Pstate *)right;\n" + "\n" + "%1assert(sizeof (STATE_TYPE) >= sizeof (void *));\n%1"); + print("%1p = malloc(sizeof *p);\n" + "%1p->op = op;\n" + "%1p->left = l;\n" + "%1p->right = r;\n" + "%1p->rule.%P%S = 0;\n", + start); + for (i = 1; i <= ntnumber; i++) + print("%1p->cost[%d] =\n", i); + print("%2%d;\n" + "%1switch (op) {\n", maxcost); + for (p = terms; p; p = p->link) + emitcase(p, ntnumber); + print("%1default:\n" + "%2%Ppanic_cannot_match(node);\n" + "%1}\n" + "%1return (STATE_TYPE)p;\n}\n\n"); +} + +/* emitstring - emit array of rules and costs */ +static void emitstring(Rule rules) +{ + Rule r; + int k; + + print("static const short %Pcost[][4] = {\n"); + for (k = 0, r = rules; r; r = r->link) + { + for (; k < r->ern; k++) + print("%1{ 0 },%1/* %d */\n", k); + print("%1{ %d },%1/* %d = %R */\n", r->cost, k++, r); + } + print("};\n\n"); +} + +/* emitstruct - emit the definition of the state structure */ +static void emitstruct(Nonterm nts, int ntnumber) +{ + print("struct %Pstate {\n%1int op;\n%1struct %Pstate *left, *right;\n" + "%1short cost[%d];\n%1struct {\n", + ntnumber + 1); + for (; nts; nts = nts->link) + { + int n = 1, m = nts->lhscount; + while (m >>= 1) + n++; + print("%2unsigned %P%S:%d;\n", nts, n); + } + print("%1} rule;\n};\n\n"); +} + +/* emitterms - emit terminal data structures */ +static void emitterms(Term terms) +{ + Term p; + int k; + + print("static const char %Parity[] = {\n"); + for (k = 0, p = terms; p; p = p->link) + { + for (; k < p->esn; k++) + print("%10,%1/* %d */\n", k); + print("%1%d,%1/* %d=%S */\n", p->arity < 0 ? 0 : p->arity, k++, p); + } + print("};\n\n"); + + print("static const char *%Popname[] = {\n"); + for (k = 0, p = terms; p; p = p->link) + { + for (; k < p->esn; k++) + print("%1/* %d */%10,\n", k); + print("%1/* %d */%1\"%S\",\n", k++, p); + } + print("};\n\n"); +} + +/* emittest - emit clause for testing a match */ +static void emittest(Tree t, const char* v, const char* suffix) +{ + Term p = t->op; + + if (p->kind == TERM) + { + print("%3%s->op == %d%s/* %S */\n", v, p->esn, + t->nterms > 1 ? " && " : suffix, p); + if (t->left) + emittest(t->left, aprintf("%s->left", v), + t->right && t->right->nterms ? " && " : suffix); + if (t->right) + emittest(t->right, aprintf("%s->right", v), suffix); + } +} diff --git a/util/mcgg/iburg.h b/util/mcgg/iburg.h new file mode 100644 index 000000000..739641d4d --- /dev/null +++ b/util/mcgg/iburg.h @@ -0,0 +1,160 @@ +#ifndef BURG_INCLUDED +#define BURG_INCLUDED + +#include "em_arith.h" +#include "stringlist.h" +#include "array.h" + +extern char* stringf(char* fmt, ...); + +typedef enum +{ + TERM = 1, + NONTERM, + REG, + REGCLASS +} Kind; +typedef struct rule* Rule; +typedef struct term* Term; + +enum +{ + CONSTRAINT_EQUALS, + CONSTRAINT_CORRUPTED_ATTR, + CONSTRAINT_PRESERVED, +}; + +struct constraint +{ + int type; + const char* left; + const char* right; + struct constraint* next; +}; + +enum +{ + PREDICATE_FUNCTION, + PREDICATE_NODE, + PREDICATE_NUMBER +}; + +struct expr +{ + int type; + struct expr* next; + union + { + const char* name; + arith number; + } u; +}; + +struct terminfo +{ + const char* name; + const char* label; + const char* attr; +}; + +struct reg +{ + const char* name; /* friendly register name */ + int number; /* identifying number */ + uint32_t attrs; /* bitfield of register attributes */ + struct stringlist* names; /* register names */ + ARRAYOF(struct reg) aliases; /* registers that this one aliases */ +}; + +struct regattr +{ + const char* name; /* class name */ + int number; /* identifying number */ +}; + +extern struct reg* makereg(const char* name); +extern void setregnames(struct reg* reg, struct stringlist* names); +extern void addregattr(struct reg* reg, const char* regattr); +extern void addregaliases(struct reg* reg, struct stringlist* aliases); +extern struct regattr* getregattr(const char* name); + +struct term +{ /* terminals: */ + char* name; /* terminal name */ + Kind kind; /* TERM */ + int esn; /* external symbol number */ + int arity; /* operator arity */ + Term link; /* next terminal in esn order */ + Rule rules; /* rules whose pattern starts with term */ +}; + +typedef struct nonterm* Nonterm; +struct nonterm +{ /* non-terminals: */ + char* name; /* non-terminal name */ + Kind kind; /* NONTERM */ + int number; /* identifying number */ + int lhscount; /* # times nt appears in a rule lhs */ + int reached; /* 1 iff reached from start non-terminal */ + Rule rules; /* rules w/non-terminal on lhs */ + Rule chain; /* chain rules w/non-terminal on rhs */ + Nonterm link; /* next terminal in number order */ + bool is_fragment; /* these instructions are all fragments */ +}; +extern void* lookup(const char* name); +extern Nonterm nonterm(const char* id, bool allocate); +extern Term term(const char* id, int esn); + +typedef struct tree* Tree; +struct tree +{ /* tree patterns: */ + void* op; /* a terminal or non-terminal */ + const char* label; /* user label for this node */ + Tree left, right; /* operands */ + int nterms; /* number of terminal nodes in this tree */ + struct regattr* attr; /* input register attribute */ +}; +extern Tree tree(const struct terminfo* ti, Tree left, Tree right); + +struct rule +{ /* rules: */ + Nonterm lhs; /* lefthand side non-terminal */ + Tree pattern; /* rule pattern */ + int lineno; /* line number where allocated */ + int ern; /* external rule number */ + int packed; /* packed external rule number */ + int cost; /* associated cost */ + const char* label; /* label for LHS */ + struct regattr* attr; /* register attribute of result */ + Rule link; /* next rule in ern order */ + Rule next; /* next rule with same pattern root */ + Rule chain; /* next chain rule with same rhs */ + Rule decode; /* next rule with same lhs */ + Rule kids; /* next rule with same burm_kids pattern */ + ARRAYOF(struct expr) prefers; /* C predicates */ + ARRAYOF(struct expr) requires; /* C predicates */ + ARRAYOF(struct constraint) constraints; /* register constraints */ + struct stringlist code; /* compiler output code strings */ +}; +extern Rule rule(const struct terminfo* ti, Tree pattern); +extern int maxcost; /* maximum cost */ + +/* gram.y: */ +void yyerror(char* fmt, ...); +int yyparse(void); +void yywarn(char* fmt, ...); +extern int errcnt; +extern FILE* infp; +extern FILE* outfp; +extern FILE* hdrfp; + +/* Stupid flex imports --- why mo header file? */ + +extern FILE* yyin; +extern int yylineno; + +extern void printlineno(void); + +#include "mcgg.h" + +#endif diff --git a/util/mcgg/ir.dat b/util/mcgg/ir.dat new file mode 100644 index 000000000..4b7c4e920 --- /dev/null +++ b/util/mcgg/ir.dat @@ -0,0 +1,123 @@ +# Types: +# +# I, F, L, D: int, float, long, double +# i, F: int, float; promoted to long, double based on size +# .: ignore this parameter +# ?: pull/push types from other ? parameters + +# Simple terminals +S ?=.. CONST +V ?=.. REG +S ?=?. NOP +S I=.. LABEL +S I=.. BLOCK +V ?=.. PAIR +S ?=.. ANY +S ?=.. LOCAL +V ?=.. PHI + +# Magic stack operations +S ?=?. PUSH +S ?=.. POP + +# Memory operations +S ?=I. LOAD +S I=I. LOADB +S I=I. LOADH +S ?=I? STORE +S ?=I? STOREB +S ?=I? STOREH + +# Arithemetic operations +S i=ii ADD +S i=ii SUB +S i=ii MUL +S i=ii DIV +S i=ii DIVU +S i=ii MOD +S i=ii MODU +S i=ii NEG + +S f=ff ADDF +S f=ff SUBF +S f=ff MULF +S f=ff DIVF +S f=ff NEGF + +S i=ii AND +S i=ii OR +S i=ii EOR +S i=ii NOT +S i=ii ASL +S i=ii ASR +S i=ii LSL +S i=ii LSR + +# Bitwise conversions +# (Remember, these don't change the value, merely move it) +# (order is important here; the 8-byte version of each must immediate succeed +# the 4-byte version) +S F=I. COPYI +S I=F. COPYF +S D=L. COPYL +S L=D. COPYD + +# Semantic conversions +# (order is important here; the 8-byte version of each must immediate succeed +# the 4-byte version) +S ?=I. FROMUI +S ?=L. FROMUL +S ?=I. FROMSI +S ?=L. FROMSL +S ?=F. FROMUF +S ?=D. FROMUD +S ?=F. FROMSF +S ?=D. FROMSD +S L=II FROMIPAIR +S I=L. FROML0 +S I=L. FROML1 + +# The H versions are only used if wordsize > 2 +S I=I. EXTENDB +S I=I. EXTENDH +S I=I. TRUNCATEB +S I=I. TRUNCATEH + +# Tristate comparisons +# (order is important here; the 8-byte version of each must immediate succeed +# the 4-byte version) +S I=II COMPARESI +S I=LL COMPARESL +S I=II COMPAREUI +S I=LL COMPAREUL +S I=FF COMPAREF +S I=DD COMPARED + +# Tristate to boolean conversion +S I=I. IFEQ +S I=I. IFLT +S I=I. IFLE + +# Procedures +S i=I. CALL +S i=?. GETRET +S ?=i. SETRET + +# Flow control --- these never return +V .=i. JUMP +V .=i. FARJUMP +V .=i. CJUMPEQ +V .=i. CJUMPLT +V .=i. CJUMPLE +V .=.. RET + +# Special +S ?=i. STACKADJUST +S i=.. GETFP +S ?=i. SETFP +S i=.. GETSP +S ?=i. SETSP +S i=i. CHAINFP +S i=i. FPTOAB +S i=i. FPTOLB + diff --git a/util/mcgg/ircodes.h b/util/mcgg/ircodes.h new file mode 100644 index 000000000..d9c05126f --- /dev/null +++ b/util/mcgg/ircodes.h @@ -0,0 +1,28 @@ +#ifndef IRCODES_H +#define IRCODES_H + +enum +{ + IRF_SIZED = 1, +}; + +struct ir_data +{ + const char* name; + int flags; + char returntype; + char lefttype; + char righttype; +}; + +extern const struct ir_data ir_data[]; + +#define TYPE_ATTRS \ + (burm_int_ATTR | burm_long_ATTR | burm_float_ATTR | burm_double_ATTR) + +#include "ircodes-dyn.h" + +#endif + +/* vim: set sw=4 ts=4 expandtab : */ + diff --git a/util/mcgg/ircodes.sh b/util/mcgg/ircodes.sh new file mode 100755 index 000000000..ff2df4845 --- /dev/null +++ b/util/mcgg/ircodes.sh @@ -0,0 +1,52 @@ +#!/bin/sh + +in=$1 +header=$2 +source=$3 + +awk -f - $in >$header << "EOF" + BEGIN { + print "enum ir_opcode {" + } + + /^ *[^# ]+/ { + print "\tIR_" $3 "," + } + + END { + print "\tIR__COUNT" + print "};" + } +EOF + +awk -f - $in >$source << "EOF" + BEGIN { + print "#include \"ircodes.h\"" + print "const struct ir_data ir_data[IR__COUNT] = {" + } + + function char_to_flags(c) { + if (c == "S") return "IRF_SIZED" + return "0" + } + + function char_to_type(c) { + if (c ~ /[A-Za-z]/) return "'"c"'" + if (c == "?") return "'?'" + if (c == ".") return "0" + } + + /^ *[^# ]+/ { + printf("\t{ \"%s\", ", $3) + printf("%s, ", char_to_flags(substr($1, 1, 1))) + printf("%s, ", char_to_type(substr($2, 1, 1))) + printf("%s, ", char_to_type(substr($2, 3, 1))) + printf("%s, ", char_to_type(substr($2, 4, 1))) + printf(" },\n") + } + + END { + print "};" + } +EOF + diff --git a/util/mcgg/mcgg.h b/util/mcgg/mcgg.h new file mode 100644 index 000000000..c0c930a27 --- /dev/null +++ b/util/mcgg/mcgg.h @@ -0,0 +1,83 @@ +#ifndef MCGG_H +#define MCGG_H + +/* Excruciating macro which packs ir opcodes and sizes into an int for iburg's benefit. + * + * Types are mapped to: I=1, F=2, L=3, D=4 + */ +#define ir_to_esn(iropcode, type) \ + ((iropcode)*5 + \ + (((type) == 'I') ? 1 : \ + ((type) == 'F') ? 2 : \ + ((type) == 'L') ? 3 : \ + ((type) == 'D') ? 4 : 0)) + +#define STATE_TYPE void* + +#define STATE_LABEL(p) ((p)->state_label) +#define OP_LABEL(p) ((p)->label) +#define LEFT_CHILD(p) ((p)->left) +#define RIGHT_CHILD(p) ((p)->right) + +struct burm_node +{ + int label; + void* state_label; + struct burm_node* left; + struct burm_node* right; + struct ir* ir; +}; + +typedef struct burm_node* NODEPTR_TYPE; + +extern void* burm_label(NODEPTR_TYPE node); +extern int burm_rule(void* state, int goalnt); +extern const short *burm_nts[]; +extern NODEPTR_TYPE* burm_kids(NODEPTR_TYPE p, int eruleno, NODEPTR_TYPE kids[]); +extern void burm_trace(NODEPTR_TYPE p, int ruleno, int cost, int bestcost); + +struct burm_emitter_data +{ + void (*emit_string)(const char* data); + void (*emit_fragment)(int child); + void (*emit_return_reg)(int index); + void (*emit_reg)(int child, int index); + void (*emit_value)(int child); + void (*emit_eoi)(void); + void (*constrain_input_reg)(int child, uint32_t attr); + void (*constrain_input_reg_preserved)(int child); + void (*constrain_output_reg)(uint32_t attr); + void (*constrain_output_reg_equal_to)(int child); +}; + +typedef void burm_emitter_t(const struct burm_emitter_data* data); + +struct burm_instruction_data +{ + const char* name; + burm_emitter_t* emitter; + bool is_fragment; + uint32_t corrupts; +}; + +extern const struct burm_instruction_data burm_instruction_data[]; + +struct burm_register_data +{ + const char* id; + uint32_t attrs; + const char** names; + const struct burm_register_data** aliases; +}; + +extern const struct burm_register_data burm_register_data[]; +extern const char* burm_register_class_names[]; + +enum +{ + NONTERM_STMT = 1 +}; + +#endif + +/* vim: set sw=4 ts=4 expandtab : */ diff --git a/util/mcgg/scan.l b/util/mcgg/scan.l new file mode 100644 index 000000000..447a7d395 --- /dev/null +++ b/util/mcgg/scan.l @@ -0,0 +1,64 @@ +%{ +#include +#include +#include "iburg.h" +#include "y.tab.h" + +static int braces = 0; + +%} +%option warn +%option nodefault +%option noyywrap +%option yylineno +%option debug + +%x QSTRING +%x COMMENT + +%% + +"\"" BEGIN(QSTRING); +"\"" BEGIN(INITIAL); + +[%$][a-zA-Z_][a-zA_Z_0-9]+(\.[0-9]+)? { + yylval.string = strdup(yytext); + return QFRAGMENT; + } + +[^\r\n%$"]+ { + yylval.string = strdup(yytext); + return QFRAGMENT; + } + +"/*" BEGIN(COMMENT); +"*/" BEGIN(INITIAL); +[^*]* ; +"*" ; + +"DECLARATIONS" return DECLARATIONS; +"PATTERNS" return PATTERNS; +"REGISTERS" return REGISTERS; +"aliases" return ALIASES; +"corrupted" return CORRUPTED; +"cost" return COST; +"emit" return EMIT; +"fragment" return FRAGMENT; +"named" return NAMED; +"prefers" return PREFERS; +"preserved" return PRESERVED; +"when" return WHEN; +"with" return WITH; +"==" return EQUALS; +"!=" return NOTEQUALS; + +"//"[^\n]*\n ; + +[A-Za-z_][A-Za-z0-9_]* { yylval.string = strdup(yytext); return ID; } +-?[0-9]+ { yylval.n = atoi(yytext); return INT; } +-?0x[0-9a-fA-F]+ { yylval.n = strtol(yytext, NULL, 0); return INT; } +[ \t\r\n]* ; +. return yytext[0]; + +%% +/* vim: set sw=4 ts=4 expandtab : */ diff --git a/util/ncgg/coerc.c b/util/ncgg/coerc.c index 893f81be3..d6334d5a3 100644 --- a/util/ncgg/coerc.c +++ b/util/ncgg/coerc.c @@ -24,6 +24,7 @@ int nmoves; move_t l_moves[MAXMOVES]; short posmoves[MAXREGS+MAXTOKENS][SETSIZE]; +void n_move(s1,e1,s2,e2,vi) struct varinfo *vi; { register move_p mp; register i,j; @@ -81,6 +82,7 @@ int ntests; test_t l_tests[MAXTESTS]; short postests[SETSIZE]; +void n_test(s,e,vi) struct varinfo *vi; { register test_p tp; register i; @@ -162,6 +164,7 @@ n_stack(s,e,p,vi) struct varinfo *vi; { sp[i] |= l_sets[s].set_val[i]; } +void checkstacking(sp) register short *sp; { register i; register short *chkset; @@ -186,6 +189,7 @@ set_t unstackset; /*VARARGS5*/ +void n_coerc(ti,be,al,ge,rp,in) struct varinfo *al,*ge,*rp; iocc_t in; { register c3_p c3p; register i; diff --git a/util/ncgg/output.c b/util/ncgg/output.c index 50458e369..77e3eb41f 100644 --- a/util/ncgg/output.c +++ b/util/ncgg/output.c @@ -662,6 +662,7 @@ finishio() { outars(); } +void codecoco(cocono) { if (cocono== -1) diff --git a/util/ncgg/set.c b/util/ncgg/set.c index cb31c3594..d2d9b0d8f 100644 --- a/util/ncgg/set.c +++ b/util/ncgg/set.c @@ -85,7 +85,7 @@ set_t ident_to_set(name) char *name; { return(result); } -static +static void checksize(s) register set_p s; { diff --git a/util/ncgg/subr.c b/util/ncgg/subr.c index 90bf44eb2..08c7c650f 100644 --- a/util/ncgg/subr.c +++ b/util/ncgg/subr.c @@ -175,6 +175,7 @@ n_prop(name,size) char *name; int size; { l_props[propno].pr_size = size; } +void prophall(n) { register i; short hallset[SETSIZE]; @@ -279,6 +280,7 @@ setallreg(vi) struct varinfo *vi; { } } +void freevi(vip) register struct varinfo *vip; { register i; diff --git a/util/opt/cleanup.c b/util/opt/cleanup.c index 2c1f912eb..f09feeb7b 100644 --- a/util/opt/cleanup.c +++ b/util/opt/cleanup.c @@ -20,6 +20,7 @@ static char rcsid[] = "$Id$"; */ +void cleanup() { FILE *infile; register c; diff --git a/util/opt/flow.c b/util/opt/flow.c index 77f6042c2..73ae715af 100644 --- a/util/opt/flow.c +++ b/util/opt/flow.c @@ -21,6 +21,8 @@ static char rcsid[] = "$Id$"; * Author: Hans van Staveren */ +void reach(); + flow() { findreach(); /* determine reachable labels */ @@ -51,6 +53,7 @@ findreach() { } } +void reach(lnp) register line_p lnp; { register num_p np; diff --git a/util/opt/getline.c b/util/opt/getline.c index c3ed1bb78..9ecdf08fd 100644 --- a/util/opt/getline.c +++ b/util/opt/getline.c @@ -188,6 +188,7 @@ int table2() { return(table3(n)); } +void getlines() { register line_p lnp; register instr; diff --git a/util/opt/reg.c b/util/opt/reg.c index 00fc2e3b2..6066c9f19 100644 --- a/util/opt/reg.c +++ b/util/opt/reg.c @@ -21,6 +21,7 @@ static char rcsid[] = "$Id$"; * Author: Hans van Staveren */ +void regvar(ap) register arg_p ap; { register reg_p rp; register i; @@ -96,6 +97,7 @@ outtes() { } } +void incregusage(off) offset off; { register reg_p rp; diff --git a/util/opt/tes.c b/util/opt/tes.c index ab6ce3bbd..b3d4efda1 100644 --- a/util/opt/tes.c +++ b/util/opt/tes.c @@ -68,6 +68,7 @@ tes_pseudos() } } +void tes_instr(lnp, x, y) line_p lnp, x, y; {