12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536 |
- /*
- * GTools C compiler
- * =================
- * source file :
- * code generator for the 68000
- *
- * Copyright 2001-2004 Paul Froissart.
- * Credits to Christoph van Wuellen and Matthew Brandt.
- * All commercial rights reserved.
- *
- * This compiler may be redistributed as long there is no
- * commercial interest. The compiler must not be redistributed
- * without its full sources. This notice must stay intact.
- */
- #include "define.h"
- _FILE(__FILE__)
- #include "c.h"
- #include "expr.h"
- #include "gen.h"
- #include "cglbdec.h"
- #ifndef NOFLOAT
- #include "ffplib.h"
- #endif
- #ifdef VCG
- extern int vcg_lvl;
- #endif
- #ifdef MC680X0
- readonly struct amode push = {am_adec, 0, init_reg_t(STACKPTR - AREGBASE), nil_reg_t, 0},
- pop = {am_ainc, 0, init_reg_t(STACKPTR - AREGBASE), nil_reg_t, 0};
- #endif
- XLST_TYPE act_scratch CGLOB;
- #ifdef FLINE_RC
- int fline_rc CGLOB;
- #endif
- /*
- * this module contains all of the code generation routines for evaluating
- * expressions and conditions.
- */
- #ifdef MC680X0
- void swap_nodes(struct enode *node);
- void opt_compare(struct enode *node);
- struct amode *mk_scratch(long size) {
- /*
- * returns addressing mode of form offset(FRAMEPTR)
- * size is rounded up to AL_DEFAULT
- */
- struct amode *ap;
- /* round up the request */
- if (size % AL_DEFAULT)
- size += AL_DEFAULT - (size % AL_DEFAULT);
- /* allocate the storage */
- act_scratch += size;
- /*
- * The next statement could be deferred and put into the
- * routine checkstack(), but this is just safer.
- */
- if (act_scratch > max_scratch)
- max_scratch = act_scratch;
- ap = (struct amode *) xalloc((int) sizeof(struct amode),AMODE+MK_SCRATCH);
- ap->mode = am_indx;
- ap->preg = FRAMEPTR - AREGBASE;
- ap->offset = mk_icon((long) -(lc_auto+act_scratch));
- return ap;
- }
- struct amode *mk_label(unsigned int lab) {
- /*
- * construct a reference node for an internal label number.
- */
- struct enode *lnode;
- struct amode *ap;
- lnode = mk_node(en_labcon, NIL_ENODE, NIL_ENODE);
- lnode->v.enlab = lab;
- ap = (struct amode *) xalloc((int) sizeof(struct amode),AMODE+MK_LABEL);
- ap->mode = am_direct;
- ap->offset = lnode;
- return ap;
- }
- struct amode *mk_immed(long i) {
- /*
- * make a node to reference an immediate value i.
- */
- struct amode *ap;
- struct enode *ep;
- ep = mk_icon(i);
- /* ep = mk_icon(0l);
- ep->v.i = i;*/
- ap = (struct amode *) xalloc((int) sizeof(struct amode), AMODE+MK_IMMED);
- ap->mode = am_immed;
- ap->offset = ep;
- return ap;
- }
- struct amode *mk_offset(struct enode *node) {
- /*
- * make a direct reference to a node.
- */
- struct amode *ap;
- ap = (struct amode *) xalloc((int) sizeof(struct amode), AMODE+MK_OFFSET);
- ap->mode = am_direct;
- ap->offset = node;
- return ap;
- }
- struct amode *mk_legal(struct amode *ap, int flags, long size) {
- /*
- * mk_legal will coerce the addressing mode in ap1 into a mode that is
- * satisfactory for the flag word.
- */
- struct amode *ap2;
- if (flags & F_NOVALUE) {
- freeop(ap);
- return 0;
- }
- if (size==1)
- flags &= ~F_AREG;
- switch (ap->mode) {
- case am_immed:
- if (!(flags & F_DEREF) && ap->offset
- #ifdef EXE_OUT
- //&& !exestub_mode -> because it remains profitable to do this
- // even with very efficient relocations...
- #endif
- && (ap->offset->nodetype == en_nacon
- || ap->offset->nodetype == en_labcon)
- #ifdef AS
- && !external(ap->offset->v.enlab)
- #else
- #if defined(PC) && !defined(DISABLE_OPTS)
- && ((long)ap->offset->v.ensp>0x1000 ? internal(ap->offset->v.ensp) : 1)
- #endif
- #endif
- ) {
- ap->mode = am_direct;
- ap2 = temp_addr(); /* allocate to areg */
- g_code(op_lea, 0, ap, ap2);
- if (flags & F_AREG)
- return ap2;
- freeop(ap2);
- ap = temp_data();
- g_code(op_move, (int) (size+(size&1)), ap2, ap); /* if we want a byte, do a move.w, not a move.b */
- if (flags & F_DREG)
- return ap;
- ierr(MK_LEGAL,1);
- }
- if (flags & F_IMMED) {
- return ap; /* mode ok */
- }
- break;
- case am_areg:
- if (flags & F_AREG && (!(flags & F_VOL) || ap->preg <= MAX_ADDR))
- return ap;
- break;
- case am_dreg:
- if (flags & F_DREG && (!(flags & F_VOL) || ap->preg <= MAX_DATA))
- return ap;
- break;
- case am_direct:
- /* infunc("DrawColorLine")
- bkpt();*/
- if (!(flags & F_SRCOP) && !(flags & F_DEREF) && ap->offset
- #ifdef EXE_OUT
- //&& !exestub_mode -> because it remains rentable to do this
- // even with very efficient relocations...
- #endif
- && (ap->offset->nodetype == en_nacon
- || ap->offset->nodetype == en_labcon)
- #ifdef AS
- && !external(ap->offset->v.enlab)
- #else
- #if defined(PC) && !defined(DISABLE_OPTS)
- && ((long)ap->offset->v.ensp>0x1000 ? internal(ap->offset->v.ensp) : 1)
- #endif
- #endif
- && (flags & F_MEM)
- ) {
- ap2 = temp_addr(); // allocate to areg
- g_code(op_lea, 0, ap, ap2);
- ap2 = copy_addr(ap2);
- ap2->mode = am_ind;
- // if (flags & F_MEM)
- return ap2;
- /* freeop(ap2);
- if ((flags&(F_AREG|F_DEREF))==(F_AREG|F_DEREF) || !(flags&F_DREG))
- ap=temp_addr();
- else ap=temp_data();
- // ap = temp_data();
- g_code(op_move, (int) size, ap2, ap);
- // if (flags & F_DREG)
- return ap;
- ierr(MK_LEGAL,2);*/
- }
- /* FALL THROUGH */
- case am_ind:
- case am_indx:
- case am_indx2:
- case am_indx3:
- case am_ainc:
- if (flags & F_MEM)
- return ap;
- break;
- }
- if ((flags & F_DREG) && (flags & F_AREG)) {
- /* decide which mode is better */
- if (ap->mode == am_immed) {
- if (isbyte(ap->offset))
- flags &= F_DREG;
- else if (isshort(ap->offset) && size == 4)
- flags &= F_AREG;
- }
- }
- if (flags & F_DREG) {
- freeop(ap); /* maybe we can use it... */
- ap2 = temp_data(); /* allocate to dreg */
- g_code(op_move, (int) size, ap, ap2);
- return ap2;
- }
- if (!(flags & F_AREG))
- ierr(MK_LEGAL,3);
- if (size < 2)
- ierr(MK_LEGAL,4);
- freeop(ap);
- ap2 = temp_addr();
- g_code(op_move, (int) size, ap, ap2);
- return ap2;
- }
- int isshort(struct enode *node) {
- /*
- * return true if the node passed can be generated as a short offset.
- */
- return node->nodetype == en_icon &&
- (node->v.i >= -32768 && node->v.i <= 32767);
- }
- int isbyte(struct enode *node) {
- return node->nodetype == en_icon &&
- (node->v.i >= -128 && node->v.i <= 127);
- }
- struct amode *copy_addr(struct amode *ap) {
- /*
- * copy an address mode structure.
- */
- struct amode *newap;
- if (ap == 0)
- ierr(COPY_ADDR,1);
- newap = (struct amode *) xalloc((int) sizeof(struct amode), AMODE+COPY_ADDR);
- *newap = *ap;
- return newap;
- }
- struct amode *g_index(struct enode *node) {
- /*
- * generate code to evaluate an index node and return the addressing
- * mode of the result.
- */
- struct amode *ap1, *ap2;
- char size=4;
- #ifndef FORBID_TABLES
- if (node->v.p[0]->nodetype == en_tempref &&
- node->v.p[1]->nodetype == en_tempref &&
- (node->v.p[0]->v.i >= AREGBASE || node->v.p[1]->v.i >= AREGBASE)) {
- /* both nodes are registers, one is address */
- if (node->v.p[0]->v.i < AREGBASE) { /* first node is data register */
- ap1 = g_expr(node->v.p[1], F_AREG);
- ap1 = copy_addr(ap1);
- ap1->sreg = (reg_t)node->v.p[0]->v.i;
- ap1->mode = am_indx2; /* 0(Ax,Dx) */
- ap1->slen = 4;
- ap1->offset = mk_icon(0l);
- return ap1;
- } else { /* first node is address register */
- ap1 = g_expr(node->v.p[0], F_AREG);
- ap2 = g_expr(node->v.p[1], F_AREG | F_DREG);
- validate(ap1);
- ap1 = copy_addr(ap1);
- if (ap2->mode == am_dreg) {
- /* 0(Ax,Dx) */
- ap1->mode = am_indx2;
- ap1->sreg = ap2->preg;
- ap1->slen = 4;
- } else {
- /* 0(Ax,Ay) */
- ap1->mode = am_indx3;
- ap1->sreg = ap2->preg;
- ap1->slen = 4;
- }
- ap1->offset = mk_icon(0l);
- return ap1;
- }
- }
- #endif
- /* The general case (no tempref) */
- /* put address temprefs first place, data temprefs second place */
- if (node->v.p[1]->nodetype == en_tempref && node->v.p[1]->v.i >= AREGBASE)
- swap_nodes(node);
- else if (node->v.p[0]->nodetype == en_tempref && node->v.p[0]->v.i < AREGBASE)
- swap_nodes(node);
- else if (node->v.p[1]->etype==bt_pointer && node->v.p[0]->etype!=bt_pointer)
- swap_nodes(node);
- ap1 = g_expr(node->v.p[0], F_AREG | F_IMMED);
- if (ap1->mode == am_areg) {
- struct enode *ep=node->v.p[1],*tempep=ep;
- while (tempep->nodetype==en_cast) /* avoid useless op_ext's */
- if ((tempep=tempep->v.p[0])->esize==2)
- size=2, ep=tempep;
- ap2 = g_expr(ep, F_AREG | F_DREG | F_IMMED);
- validate(ap1);
- } else {
- ap2 = ap1;
- ap1 = g_expr(node->v.p[1], F_AREG/* | F_IMMED*/);
- validate(ap2);
- }
- /*
- * possible combinations:
- *
- * F_AREG + F_IMMED, F_AREG + F_DREG and F_AREG + F_AREG
- * (F_IMMED + F_IMMED is now impossible, since it would mean a bug
- * in the optimizer, and it does no harm except for optimization
- * if such a bug does exist)
- */
- /* watch out for: tempref(addr) + temp_addr, tempref(addr) + temp_data */
- if (/*ap1->mode == am_areg && */ap1->preg > MAX_ADDR) {
- /* ap1 = tempref address register */
- ap1 = copy_addr(ap1);
- #ifndef FORBID_TABLES
- if (ap2->mode == am_dreg) {
- /* 0(Ax,Dy) */
- ap1->mode = am_indx2;
- ap1->sreg = ap2->preg;
- ap1->slen = size;
- ap1->deep = ap2->deep;
- ap1->offset = mk_icon(0l);
- return ap1;
- }
- if (ap2->mode == am_areg) {
- /* 0(Ax,Ay) */
- ap1->mode = am_indx3;
- ap1->sreg = ap2->preg;
- ap1->slen = size;
- ap1->deep = ap2->deep;
- ap1->offset = mk_icon(0l);
- return ap1;
- }
- #endif
- #ifndef FORBID_TABLES
- if (ap2->mode == am_immed && /* if FORBID_TABLES, then we */
- (!isshort(ap2->offset))) /* always want ap1 to be F_VOL */
- #endif
- /* we want to add to ap1 later... */
- ap1 = mk_legal(ap1, F_AREG | F_VOL, 4l);
- }
- /* watch out for: temp_addr + tempref(data) */
- #ifndef FORBID_TABLES
- if (/*ap1->mode == am_areg && */ap2->mode == am_dreg && ap2->preg > MAX_DATA) {
- ap1 = copy_addr(ap1);
- ap1->mode = am_indx2;
- ap1->sreg = ap2->preg;
- ap1->slen = size;
- ap1->offset = mk_icon(0l);
- return ap1;
- }
- #endif
- /* if (ap1->mode == am_immed && ap2->mode == am_immed) {
- ap1 = copy_addr(ap1);
- ap1->offset = mk_node(en_add, ap1->offset, ap2->offset);
- ap1->mode = am_direct;
- return ap1;
- }*/
- if (ap2->mode == am_immed && isshort(ap2->offset)) {
- ap1 = mk_legal(ap1, F_AREG, 4l);
- ap1 = copy_addr(ap1);
- ap1->mode = am_indx;
- ap1->offset = ap2->offset;
- return ap1;
- }
- /* ap1 is volatile ... */
- g_code(op_add, size, ap2, ap1);/* add left to address reg */
- ap1 = copy_addr(ap1);
- ap1->mode = am_ind; /* mk_ indirect */
- freeop(ap2); /* release any temps in ap2 */
- return ap1; /* return indirect */
- }
- struct amode *g_deref(struct enode *node, enum(e_bt) type, int flags, long size) {
- /*
- * return the addressing mode of a dereferenced node.
- */
- struct amode *ap1;
- /*
- * If a reference to an aggregate is required, return a pointer to the
- * struct instead
- */
- if (bt_aggregate(type)) {
- return g_expr(node, /*F_ALL*/flags); // possibly BUGGY
- }
- #ifdef PREFER_POS_VALUES
- if (node->nodetype == en_sub && node->v.p[1]->nodetype==en_icon)
- node->nodetype = en_add, node->v.p[1]->v.i=-node->v.p[1]->v.i;
- #endif
- if (node->nodetype == en_add) {
- return g_index(node);
- }
- if (node->nodetype == en_autocon) {
- #ifdef BIGSTACK
- if (node->v.i >= -32768 && node->v.i <= 32767) {
- #endif
- ap1 = (struct amode *) xalloc((int) sizeof(struct amode),
- AMODE+G_DEREF);
- ap1->mode = am_indx;
- ap1->preg = FRAMEPTR-AREGBASE;
- ap1->offset = mk_icon((long) node->v.i);
- #ifdef BIGSTACK
- } else {
- ap1 = temp_addr();
- g_code(op_move, 4, mk_immed((long) node->v.i), ap1);
- g_code(op_add, 4, mk_reg(FRAMEPTR), ap1);
- ap1 = copy_addr(ap1);
- ap1->mode = am_ind;
- }
- #endif
- return ap1;
- }
- /* if (lineid==309)
- bkpt();*/
- /* special 68000 instructions */
- if (node->nodetype == en_ainc
- && (size ==1 || size ==2 || size ==4)
- && node->v.p[1]->v.i == size
- && node->v.p[0]->nodetype == en_tempref
- && node->v.p[0]->v.i >= AREGBASE
- && !(flags & F_USES)) {
- /* (An)+ */
- ap1 = (struct amode *) xalloc((int) sizeof(struct amode), AMODE+G_DEREF);
- ap1->mode = am_ainc;
- ap1->preg = (reg_t)(node->v.p[0]->v.i - AREGBASE);
- return ap1;
- }
- if (node->nodetype == en_assub
- && (size ==1 || size ==2 || size ==4)
- && node->v.p[1]->v.i == -size
- && node->v.p[0]->nodetype == en_tempref
- && node->v.p[0]->v.i >= AREGBASE
- && !(flags & F_USES)) {
- /* -(An) */
- ap1 = (struct amode *) xalloc((int) sizeof(struct amode), AMODE+G_DEREF);
- ap1->mode = am_adec;
- ap1->preg = (reg_t)(node->v.p[0]->v.i - AREGBASE);
- return ap1;
- }
- ap1 = g_expr(node, F_AREG | F_IMMED | F_DEREF); /* generate address */
- ap1 = copy_addr(ap1);
- #ifdef PC
- if (ap1->mode != am_areg && ap1->mode != am_immed)
- ierr(G_DEREF,1);
- #endif
- am_doderef(ap1->mode);
- return mk_legal(ap1,flags,size); // mk_legal was missing here : F_VOL wasn't
- // taken into a count...
- }
- struct amode *g_fderef(struct enode *node, struct amode *ap0, int flags) {
- /*
- * get a bitfield value
- */
- struct amode *ap, *ap1;
- long mask;
- int width = node->bit_width;
- int offs = (node->esize<<3)-node->bit_offset-width;
- if (!ap0)
- ap = g_deref(node->v.p[0], node->etype, flags, node->esize);
- else ap = ap0;
- ap = mk_legal(ap, F_DREG|F_VOL, node->esize);
- if (offs > 0) {
- if (offs <= 8) {
- /* can shift with quick constant */
- g_code(op_lsr, (int) node->esize,
- mk_immed((long) offs), ap);
- } else {
- /* must load constant first */
- ap1 = temp_data();
- g_code(op_moveq, 0, mk_immed((long) offs), ap1);
- g_code(op_lsr, (int) node->esize, ap1, ap);
- freeop(ap1);
- }
- }
- /*mask = 0;
- while (width--)
- mask = mask + mask + 1;*/
- mask = (1<<width)-1;
- g_code(op_and, (int) node->esize, mk_immed(mask), ap);
- return mk_legal(ap, flags, node->esize);
- }
- struct amode *g_unary(struct enode *node, int flags, enum(e_op) op) {
- /*
- * generate code to evaluate a unary minus or complement. float: unary minus
- * calls a library function
- */
- struct amode *ap;
- #ifdef DOUBLE
- long i;
- #endif
- if (flags & F_NOVALUE) {
- return g_expr(node->v.p[0], flags);
- }
- switch (node->etype) {
- case bt_uchar:
- case bt_char:
- case bt_short:
- case bt_ushort:
- case bt_long:
- case bt_ulong:
- case bt_pointer:
- ap = g_expr(node->v.p[0], F_DREG | F_VOL);
- g_code(op, (int) node->esize, ap, NIL_AMODE);
- return mk_legal(ap, flags, node->esize);
- #ifndef NOFLOAT
- case bt_float:
- #ifdef DOUBLE
- case bt_double:
- #endif
- if (op == op_neg) {
- #ifdef DOUBLE
- temp_inv();
- i = push_param(node->v.p[0]);
- call_library(str(ffpneg));
- return func_result(flags, i);
- #else
- int null_lab = nxtlabel();
- struct amode *ap = g_expr(node->v.p[0], F_DREG | F_VOL);
- g_code(op_tst, 4, ap, NIL_AMODE);
- g_code(op_beq, 0, mk_label(null_lab), NIL_AMODE);
- g_code(op_neg, 4, ap, NIL_AMODE);
- g_label(null_lab);
- return mk_legal(ap, flags, node->esize);
- #endif
- }
- #endif
- }
- ierr(G_UNARY,1);
- /* NOTREACHED */
- return 0; // make the compiler happy
- }
- struct amode *g_addsub(struct enode *node, int flags, enum(e_op) op) {
- /*
- * generate code to evaluate a binary node and return the addressing mode of
- * the result.
- */
- struct amode *ap1, *ap2;
- long i;
- if (flags & F_NOVALUE) {
- g_expr(node->v.p[0], flags);
- return g_expr(node->v.p[1], flags);
- }
- switch (node->etype) {
- case bt_uchar:
- case bt_char:
- case bt_short:
- case bt_ushort:
- case bt_long:
- case bt_ulong:
- case bt_pointer:
- flags &= (F_DREG | F_AREG);
- #ifdef LONG_ADDS_IN_AREG
- if (node->v.p[1]->nodetype==en_icon && node->esize==4
- #if 1
- && !((unsigned long)(i=node->v.p[1]->v.i)+8<=16)
- && (long)(short)i==i
- #else
- && (i=node->v.p[1]->v.i,(long)(short)i==i)
- #endif
- && (flags&F_AREG))
- flags = F_AREG;
- #endif
- #ifdef TWOBYTE_ARRAY_EXTRA_OPT
- if (node->v.p[1]->nodetype==en_lsh && node->v.p[1]->v.p[1]->nodetype==en_icon
- && node->v.p[1]->v.p[1]->v.i==1) {
- ap1 = g_expr(node->v.p[0], F_VOL | flags);
- ap2 = g_expr(node->v.p[1]->v.p[0], F_ALL | F_SRCOP | F_USES);
- validate(ap1); /* in case push occurred */
- g_code(op, (int) node->esize, ap2, ap1);
- g_code(op, (int) node->esize, ap2, ap1);
- } else {
- #endif
- ap1 = g_expr(node->v.p[0], F_VOL | flags);
- ap2 = g_expr(node->v.p[1], F_ALL | F_SRCOP);
- validate(ap1); /* in case push occurred */
- g_code(op, (int) node->esize, ap2, ap1);
- #ifdef TWOBYTE_ARRAY_EXTRA_OPT
- }
- #endif
- freeop(ap2);
- return mk_legal(ap1, flags, node->esize);
- #ifndef NOFLOAT
- case bt_double:
- temp_inv();
- i = push_param(node->v.p[1]);
- i += push_param(node->v.p[0]);
- switch (op) {
- case op_add:
- call_library(str(ffpadd));
- break;
- case op_sub:
- call_library(str(ffpsub));
- break;
- }
- return func_result(flags, i);
- #endif
- }
- ierr(G_ADDSUB,1);
- /* NOTREACHED */
- return 0; // make the compiler happy
- }
- struct amode *g_xbin(struct enode *node, int flags, enum(e_op) op) {
- /*
- * generate code to evaluate a restricted binary node and return the
- * addressing mode of the result.
- * these are bitwise operators so don't care about the type.
- * This needs to be revised with scalar types longer than 32 bit
- */
- struct amode *ap1, *ap2;
- ap1 = g_expr(node->v.p[0], F_VOL | F_DREG);
- ap2 = g_expr(node->v.p[1], F_DREG);
- validate(ap1); /* in case push occurred */
- g_code(op, (int) node->esize, ap2, ap1);
- freeop(ap2);
- return mk_legal(ap1, flags, node->esize);
- }
- struct amode *g_shift(struct enode *node, int flags, enum(e_op) op);
- int equalnode(struct enode *node1, struct enode *node2);
- struct amode *g_ybin(struct enode *node, int flags, enum(e_op) op) {
- /*
- * generate code to evaluate a restricted binary node and return the
- * addressing mode of the result.
- */
- struct amode *ap1, *ap2;
- #ifdef GENERATE_ROL_ROR
- if (
- (op==op_or || op==op_eor) &&
- node->v.p[0]->nodetype==en_lsh && node->v.p[1]->nodetype==en_rsh && bt_uns(node->v.p[1]->etype) &&
- node->v.p[0]->v.p[1]->nodetype==en_icon && node->v.p[1]->v.p[1]->nodetype==en_icon &&
- equalnode(node->v.p[0]->v.p[0],node->v.p[1]->v.p[0])
- ) {
- long lsh = node->v.p[0]->v.p[1]->v.i;
- long rsh = node->v.p[1]->v.p[1]->v.i;
- long sz = lsh+rsh;
- if (lsh>=0 && rsh>=0 && sz==8*node->esize) {
- int need_swap = 0;
- if (lsh>8 && rsh>8) {
- need_swap = 1;
- if (lsh>=16)
- lsh-=16,rsh+=16;
- else
- rsh-=16,lsh+=16;
- }
- if (!lsh || !rsh) {
- ap1 = g_expr(node->v.p[0]->v.p[0], F_DREG | F_VOL);
- } else {
- int shift_left = lsh<=8;
- struct enode *ep1,*ep2;
- ep1 = mk_icon(shift_left?lsh:rsh);
- ep1->etype = bt_uchar;
- ep1->esize = 1;
- ep2 = mk_node(en_lsh, node->v.p[0]->v.p[0], ep1);
- ep2->etype = node->etype;
- ep2->esize = node->esize;
- ap1 = g_shift(ep2, F_DREG|F_VOL, shift_left?op_rol:op_ror);
- }
- if (need_swap)
- g_code(op_swap, (int)node->esize, ap1, NIL_AMODE);
- return mk_legal(ap1, flags, node->esize);
- } else {
- // we could do better, but hey, we're lazy, aren't we?
- }
- }
- #endif
- ap1 = g_expr(node->v.p[0], F_VOL | F_DREG);
- ap2 = g_expr(node->v.p[1], (F_ALL & ~F_AREG) | F_SRCOP);
- validate(ap1); /* in case push occurred */
- g_code(op, (int) node->esize, ap2, ap1);
- freeop(ap2);
- return mk_legal(ap1, flags, node->esize);
- }
- #ifdef VCG
- typedef struct amode *(*COMMUTATIVE_G)(struct enode *node,int flags,enum(e_op) op);
- typedef struct amode *(*REVERSAL_G)(struct amode *ap, struct enode *ep,int flags);
- //struct amode *symmetric(struct amode *ap, struct enode *ep,int flags) {
- // if (ap==NULL) return (struct amode *)(void *)flags;
- // return ap;
- //}
- //struct amode *antisymmetric(struct amode *ap, struct enode *ep,int flags) {
- // if (ap==NULL) return (struct amode *)(void *)(F_DREG|F_VOL);
- // g_code(op_neg, ep->esize, ap, NIL_AMODE);
- // return mk_legal(ap,flags,ep->esize);
- //}
- enum { symmetric = 0 }; // antisymmetric is not supported
- struct amode *g_commute(void *func,struct enode *node,int flags,enum(e_op) op,int dummy/*void *reversal*/) {
- if (vcg_init()) {
- struct amode *ap = NULL;
- struct enode *n0=node->v.p[0],*n1=node->v.p[1];
- int o1,o2;
- //struct amode *ap;
- ((COMMUTATIVE_G)func)(node,flags,op);
- o1=vcg_done();
- node->v.p[0]=n1,node->v.p[1]=n0;
- vcg_init();
- ((COMMUTATIVE_G)func)(node,flags,op);
- //((REVERSAL_G)reversal)(((COMMUTATIVE_G)func)
- // (node,(int)((REVERSAL_G)reversal)(NULL,node,flags),op),node,flags);
- o2=vcg_done();
- if (o2<=o1)
- ap = ((COMMUTATIVE_G)func)(node,flags,op);
- //ap = ((REVERSAL_G)reversal)(((COMMUTATIVE_G)func)
- // (node,(int)((REVERSAL_G)reversal)(NULL,node,flags),op),node,flags);
- node->v.p[0]=n0,node->v.p[1]=n1; /* always restore the original node, even when reverse is better! */
- if (ap)
- return ap;
- }
- return ((COMMUTATIVE_G)func)(node,flags,op);
- }
- #endif
- struct amode *g_shift(struct enode *node, int flags, enum(e_op) op) {
- /*
- * generate code to evaluate a shift node and return the address mode of the
- * result.
- */
- struct amode *ap1,*ap2;
- if (op == op_lsl && node->v.p[1]->nodetype == en_icon
- && (node->v.p[1]->v.i == 1
- #ifndef HARDCORE_FOR_UNPACKED_SIZE
- #ifdef SPEED_OPT
- || ((speed_opt_value>=0
- #ifdef EXE_OUT
- || exestub_mode
- #endif
- ) && node->v.p[1]->v.i == 2)
- #else
- || node->v.p[1]->v.i == 2
- #endif
- #endif
- )) {
- int i;
- ap1 = g_expr(node->v.p[0], F_VOL | (flags & (F_DREG | F_AREG)));
- i = node->v.p[1]->v.i-1;
- do
- g_code(op_add, (int) node->esize, ap1, ap1);
- while (i--);
- } else {
- ap1 = g_expr(node->v.p[0], F_DREG | F_VOL);
- ap2 = g_expr(node->v.p[1], F_DREG | F_IMMED);
- validate(ap1);
- /* quick constant only legal if 1<=const<=8 */
- if (ap2->mode == am_immed && ap2->offset->nodetype == en_icon
- && (ap2->offset->v.i > 8 || ap2->offset->v.i < 1)) {
- if (ap2->offset->v.i <= 0 || ap2->offset->v.i > 32)
- uwarn("shift constant out of range");
- #ifdef USE_SWAP_FOR_SHIFT16
- if ((unsigned int)ap2->offset->v.i <= 16 && node->esize==4) {
- /* validate(ap1); -> useless since ap2 is am_immed :) */
- g_code(op_swap, 0, ap1, NIL_AMODE);
- if ((ap2->offset->v.i -= 16)) {
- ap2 = mk_immed(-ap2->offset->v.i);
- op = (op==op_lsl?op_ror:op_rol); /* since op might be op_asr too */
- g_code(op, (int) node->esize, ap2, ap1);
- }
- #error The following bugs... ((long)x)<<16 => ext/swap/ext #roll#
- /* to be improved since it normally results from 'long' shifts and surrounding
- g_cast does not recurse down to the shift node...
- The current optimization is nevertheless useful with respect to speed. */
- if (node->esize==4) g_code(op_ext, (int) node->esize, ap1, NIL_AMODE);
- goto ok_shift;
- } else
- #endif
- ap2 = mk_legal(ap2, F_DREG, 1l);
- }
- g_code(op, (int) node->esize, ap2, ap1);
- #ifdef USE_SWAP_FOR_SHIFT16
- ok_shift:
- #endif
- freeop(ap2);
- }
- return mk_legal(ap1, flags, node->esize);
- }
- struct amode *g_div(struct enode *node, int flags) {
- /*
- * generate code to evaluate a divide operator
- */
- struct amode *ap1, *ap2;
- long i;
- switch (node->etype) {
- case bt_short:
- case bt_ushort:
- ap1 = g_expr(node->v.p[0], F_DREG | F_VOL);
- ap2 = g_expr(node->v.p[1], F_ALL | F_SRCOP);
- validate(ap1);
- if (node->etype == bt_short) {
- g_code(op_ext, 4, ap1, NIL_AMODE);
- g_code(op_divs, 0, ap2, ap1);
- } else {
- g_code(op_and, 4, mk_immed(65535l), ap1);
- g_code(op_divu, 0, ap2, ap1);
- }
- freeop(ap2);
- return mk_legal(ap1, flags, 2l);
- case bt_long:
- case bt_ulong:
- case bt_double:
- temp_inv();
- i = push_param(node->v.p[1]);
- i += push_param(node->v.p[0]);
- switch (node->etype) {
- case bt_long:
- call_library("__divsi3");
- break;
- case bt_ulong:
- case bt_pointer:
- call_library("__udivsi3");
- break;
- #ifndef NOFLOAT
- case bt_double:
- call_library(str(ffpdiv));
- break;
- #endif
- }
- return func_result(flags, i);
- }
- ierr(G_DIV,1);
- /* NOTREACHED */
- return 0; // make the compiler happy
- }
- struct amode *g_mod(struct enode *node, int flags) {
- /*
- * generate code to evaluate a mod operator
- */
- struct amode *ap1, *ap2;
- long i;
- switch (node->etype) {
- case bt_short:
- case bt_ushort:
- ap1 = g_expr(node->v.p[0], F_DREG | F_VOL);
- ap2 = g_expr(node->v.p[1], F_ALL | F_SRCOP);
- validate(ap1);
- if (node->etype == bt_short) {
- g_code(op_ext, 4, ap1, NIL_AMODE);
- g_code(op_divs, 0, ap2, ap1);
- } else {
- g_code(op_and, 4, mk_immed(65535l), ap1);
- g_code(op_divu, 0, ap2, ap1);
- }
- g_code(op_swap, 0, ap1, NIL_AMODE);
- freeop(ap2);
- return mk_legal(ap1, flags, 2l);
- case bt_long:
- case bt_ulong:
- temp_inv();
- i = push_param(node->v.p[1]);
- i += push_param(node->v.p[0]);
- if (node->etype == bt_long)
- call_library("__modsi3");
- else
- call_library("__umodsi3");
- return func_result(flags, i);
- }
- ierr(G_MOD,1);
- /* NOTREACHED */
- return 0; // make the compiler happy
- }
- void swap_nodes(struct enode *node) {
- /*
- * exchange the two operands in a node.
- */
- struct enode *temp;
- temp = node->v.p[0];
- node->v.p[0] = node->v.p[1];
- node->v.p[1] = temp;
- }
- struct amode *g_mul(struct enode *node, int flags) {
- struct amode *ap1, *ap2;
- #ifdef OLD_GCCLIKE_MULSI3
- long i;
- #endif
- /* switch (node->etype) {
- case bt_long:
- case bt_ulong:
- if (node->v.p[0]->nodetype == en_icon)
- swap_nodes(node);
- ap1 = g_expr(node->v.p[0], F_DREG | F_VOL);
- ap2 = g_expr(node->v.p[1], F_ALL | F_SRCOP);
- validate(ap1);
- if (node->etype == bt_long)
- g_code(op_muls, 0, ap2, ap1);
- else
- g_code(op_mulu, 0, ap2, ap1);
- freeop(ap2);
- return mk_legal(ap1, flags, 2l);
- case bt_pointer:
- case bt_double:
- temp_inv();
- i = push_param(node->v.p[1]);
- i += push_param(node->v.p[0]);
- if (node->etype == bt_ulong)
- call_library(".ulmul"); // obsolete
- else if (node->etype == bt_double)
- call_library(".fpmult"); // obsolete
- else
- call_library(".lmul"); // obsolete
- return func_result(flags, i);
- }*/
- switch (node->etype) {
- case bt_short:
- case bt_ushort:
- if (node->v.p[0]->nodetype == en_icon)
- swap_nodes(node);
- ap1 = g_expr(node->v.p[0], F_DREG | F_VOL);
- ap2 = g_expr(node->v.p[1], F_ALL | F_SRCOP);
- validate(ap1);
- if (node->v.p[0]->etype == bt_short)
- g_code(op_muls, 0, ap2, ap1);
- else
- g_code(op_mulu, 0, ap2, ap1);
- freeop(ap2);
- return mk_legal(ap1, flags, 2l);
- case bt_ulong:
- case bt_long:
- case bt_pointer:
- case bt_double:
- temp_inv();
- #ifdef OLD_GCCLIKE_MULSI3
- i = push_param(node->v.p[1]);
- i += push_param(node->v.p[0]);
- #ifndef NOFLOAT
- if (node->etype == bt_double)
- call_library(str(ffpmul));
- else
- #endif
- call_library("__mulsi3"); /* it's the same function for ulong & long :) */
- return func_result(flags, i);
- #else
- { char *libfunc="__mulsi3_rp";
- if (tst_ushort(node->v.p[0]))
- swap_nodes(node);
- if (tst_ushort(node->v.p[1])) { /* favour ushort rather than short! */
- node->v.p[1]->etype=bt_ushort;
- node->v.p[1]->esize=2;
- libfunc="__mulsi3ui2_rp";
- } else {
- if (tst_short(node->v.p[0]))
- swap_nodes(node);
- if (tst_short(node->v.p[1])) {
- node->v.p[1]->etype=bt_short;
- node->v.p[1]->esize=2;
- libfunc="__mulsi3si2_rp";
- }
- }
- ap1 = g_expr(node->v.p[0], F_DREG | F_VOL); /* put it in D0 */
- ap2 = g_expr(node->v.p[1], F_DREG | F_VOL); /* put it in D1 */
- validate(ap1);
- call_library(libfunc);
- freeop(ap2);
- return mk_legal(ap1, flags, 4l);
- }
- #endif
- }
- ierr(G_MUL,1);
- /* NOTREACHED */
- return 0; // make the compiler happy
- }
- /*
- * Returns a complexity measure (in terms of time) of the given node, if it's constant.
- * If it's not, returns -128.
- */
- int complexity(struct enode *ep) {
- int comp=1;
- if (!ep) return 0;
- restart:
- switch (ep->nodetype) {
- case en_icon:
- if (ep->v.i) comp++;
- case en_tempref:
- comp--;
- case en_fcon:
- case en_nacon:
- case en_labcon:
- case en_autocon:
- return comp;
- case en_fcall:
- case en_assign:
- case en_asadd: case en_assub:
- case en_asmul: case en_asmod: case en_asdiv:
- case en_aslsh: case en_asrsh:
- case en_asand: case en_asor: case en_asxor:
- case en_ainc: case en_adec:
- case en_alloca:
- return -128;
- case en_cond:
- // msg("DEBUG: complexity\n");
- return -128;
- case en_compound:
- // msg("DEBUG: complexity\n");
- return -128;
- case en_mod: case en_div:
- comp+=2;
- case en_mul:
- comp+=2;
- case en_void:
- case en_add: case en_sub:
- case en_lsh: case en_rsh:
- case en_and: case en_or: case en_xor:
- case en_eq: case en_ne:
- case en_lt: case en_le: case en_gt: case en_ge:
- case en_land: case en_lor:
- comp+=complexity(ep->v.p[0]);
- if (comp<0) return -128;
- {
- int comp2=complexity(ep->v.p[1]);
- if (comp2<0) return -128;
- return comp+comp2;
- }
- case en_ref:
- case en_fieldref:
- case en_deref:
- case en_uminus: case en_not:
- case en_compl:
- case en_cast:
- comp++;
- ep=ep->v.p[0];
- goto restart;
- default:
- fatal("COMPLEXITY");
- return 0; // make the compiler happy
- }
- }
- struct amode *g_hook(struct enode *node, int flags) {
- /*
- * generate code to evaluate a condition operator node (?:)
- */
- struct amode *ap1, *ap2;
- unsigned int false_label, end_label;
- int flagx;
- int result_is_void;
- long size=node->esize;
- struct enode *vnode=node->v.p[1];
- #ifdef VCG
- int alternatives = complexity(node->v.p[0]);
- int best_flagx;
- unsigned int cost1=-1,cost2=-1;
- #endif
- end_label = nxtlabel();
- result_is_void = (node->etype == bt_void);
- if (bt_aggregate(node->etype)) {
- size = 4;
- }
- if (!result_is_void) {
- flagx = (flags & (F_DREG | F_AREG)) == F_AREG ?
- F_AREG | F_VOL : F_DREG | F_VOL;
- #ifdef VCG
- best_flagx = vcg_lvl?-1:flagx;
- #endif
- } else {
- #ifdef VCG
- best_flagx =
- #endif
- flagx = F_ALL | F_SRCOP | F_NOVALUE;
- }
- // temp_inv(); /* I do not think I can avoid that */
- #ifdef VCG
- best_flagx=flagx;
- while (1) {
- if (best_flagx<0)
- vcg_init(); // always succeeds, otherwise best_flagx would be flagx
- #endif
- if (vnode->v.p[0]) {
- /* all scratch registers are void */
- #ifdef OPTIMIZED_HOOK
- struct ocode *old_peep_tail=peep_tail;
- int old_max_reg=max_reg;
- max_reg=0;
- #endif
- #ifdef VCG
- if (vcg_lvl && alternatives IS_VALID) {
- int alt1,alt2,norm;
- if (complexity(vnode->v.p[1])>=0) {
- vcg_init();
- ap1 = g_expr(vnode->v.p[1], flagx);
- falsejp(node->v.p[0], end_label);
- if (ap_hasbeenpushed(ap1)) {
- validate(ap1);
- freeop(ap1);
- vcg_done();
- best_flagx=0;
- goto classic_fashion;
- }
- freeop(ap1);
- alt1=vcg_cost()>>3;
- ap2 = g_expr(vnode->v.p[0], flagx);
- alt1+=vcg_done();
- } else alt1=32767;
- swap_nodes(vnode);
- if (complexity(vnode->v.p[1])>=0) {
- vcg_init();
- ap1 = g_expr(vnode->v.p[1], flagx);
- truejp(node->v.p[0], end_label);
- if (ap_hasbeenpushed(ap1))
- ierr(G_HOOK,3);
- freeop(ap1);
- alt2=vcg_cost()>>3;
- ap2 = g_expr(vnode->v.p[0], flagx);
- alt2+=vcg_done();
- } else alt2=32767;
- swap_nodes(vnode);
- vcg_init();
- false_label = nxtlabel();
- falsejp(node->v.p[0], false_label);
- norm=vcg_cost()>>3;
- ap1 = g_expr(vnode->v.p[0], flagx);
- freeop(ap1);
- g_code(op_bra, 0, mk_label(end_label), NIL_AMODE);
- g_label(false_label);
- ap2 = g_expr(vnode->v.p[1], flagx);
- norm+=vcg_done();
- if (norm>alt1 && norm>alt2) {
- if (alt2<alt1) swap_nodes(vnode);
- ap1 = g_expr(vnode->v.p[1], flagx);
- (alt2>=alt1?falsejp:truejp)
- (node->v.p[0], end_label);
- freeop(ap1);
- ap2 = g_expr(vnode->v.p[0], flagx);
- if (alt2<alt1) swap_nodes(vnode); // we absolutely need this!!!
- goto done; // (hardcore TI-Chess+VTILog debug)
- }
- }
- #endif
- #if defined(ALTERNATE_HOOK) || defined(OPTIMIZED_HOOK)
- int c1=complexity(vnode->v.p[0]),c2=complexity(vnode->v.p[1]);
- if (c1>=0 || c2>=0) {
- if ((unsigned)c1<(unsigned)c2)
- swap_nodes(vnode);
- ap1 = g_expr(vnode->v.p[1], flagx);
- ((unsigned)c1<(unsigned)c2?truejp:falsejp)
- (node->v.p[0], end_label);
- freeop(ap1);
- ap2 = g_expr(vnode->v.p[0], flagx);
- if ((unsigned)c1<(unsigned)c2)
- swap_nodes(vnode);
- } else {
- #endif
- classic_fashion:
- false_label = nxtlabel();
- falsejp(node->v.p[0], false_label);
- /* all scratch registers are void */
- ap1 = g_expr(vnode->v.p[0], flagx);
- freeop(ap1);
- /* all scratch registers are void */
- g_code(op_bra, 0, mk_label(end_label), NIL_AMODE);
- g_label(false_label);
- ap2 = g_expr(vnode->v.p[1], flagx);
- #if defined(ALTERNATE_HOOK) || defined(OPTIMIZED_HOOK)
- }
- #endif
- done:
- if (!result_is_void && !equal_address(ap1,ap2))
- ierr(G_HOOK,1);
- } else {
- ap1 = g_expr(node->v.p[0], flagx);
- /* all scratch registers are void */
- g_code(op_tst, (int)node->v.p[0]->esize, ap1, NIL_AMODE);
- freeop(ap1);
- g_code(op_bne, 0, mk_label(end_label), NIL_AMODE);
- ap2 = g_expr(vnode->v.p[1], flagx);
- if (!result_is_void && !equal_address(ap1,ap2))
- ierr(G_HOOK,2);
- }
- g_label(end_label);
- #ifdef VCG
- if (best_flagx>=0)
- #endif
- return mk_legal(ap2, flags, size);
- #ifdef VCG
- if (best_flagx<0) {
- cost1=cost2;
- cost2=vcg_done();
- if (!(flags&F_AREG) || size==1 || flagx==(F_AREG|F_VOL))
- best_flagx = cost1<cost2?(F_DREG|F_VOL):flagx;
- else flagx=F_AREG|F_VOL;
- }
- }
- #endif
- }
- struct amode *g_asadd(struct enode *node, int flags, enum(e_op) op) {
- /*
- * generate a plus equal or a minus equal node.
- */
- int f;
- struct amode *ap1, *ap2;
- switch (node->etype) {
- case bt_char:
- case bt_uchar:
- case bt_short:
- case bt_ushort:
- case bt_long:
- case bt_ulong:
- case bt_pointer:
- if (flags & F_NOVALUE)
- f = F_ALL;
- else
- f = F_ALL | F_USES;
- ap1 = g_expr(node->v.p[0], f);
- if (ap1->mode==am_dreg || ap1->mode==am_areg)
- f = F_ALL | F_SRCOP;
- else f = F_DREG | F_IMMED;
- ap2 = g_expr(node->v.p[1], f);
- validate(ap1);
- g_code(op, (int) node->esize, ap2, ap1);
- freeop(ap2);
- return mk_legal(ap1, flags, node->esize);
- #ifndef NOFLOAT
- case bt_float:
- #ifdef DOUBLE
- case bt_double:
- #endif
- if (op == op_add)
- return as_fcall(node, flags, str(ffpadd));
- else
- return as_fcall(node, flags, str(ffpsub));
- #endif
- }
- ierr(G_ASADD,1);
- /* NOTREACHED */
- return 0; // make the compiler happy
- }
- readonly xstatic int bits_for_size[4]={7,15,0,31};
- void g_bitmancode(enum(e_op) op,int size,struct amode *ap1,struct amode *ap2) {
- struct amode *ap3=0;
- if (ap2->mode!=am_dreg && size && size!=1) {
- int bits_to_skip;
- if (ap1->mode!=am_immed || ap1->offset->nodetype!=en_icon)
- uerrc("illegal address mode");
- bits_to_skip=bits_for_size[size-1]-ap1->offset->v.i;
- while (bits_to_skip>=8) {
- if (!ap3) ap3=copy_addr(ap2),ap3->offset=copynode(ap3->offset);
- if (ap3->mode==am_ind)
- ap3->mode=am_indx,ap3->offset=mk_icon(0);
- if (ap3->offset->nodetype==en_icon)
- ap3->offset->v.i++;
- else ap3->offset=mk_node(en_add,ap3->offset,mk_icon(1)),opt4(&ap3->offset);
- bits_to_skip-=8;
- }
- ap1=mk_immed(7-bits_to_skip);
- }
- if (!ap3) ap3=ap2;
- g_code(op,ap2->mode==am_dreg?4:1,ap1,ap3);
- }
- #ifdef BITWISE_REDUCE
- /* the latter relies on the big-endianness of the 68k */
- int bitwise_reduction(unsigned long x,int *size) {
- if (!x) return; // anyway the constant folder will already have taken care :)
- int offs=0,end_offs=0;
- unsigned long v=0xFF<<((*size-1)*8);
- while (!(x&v)) offs++,x<<=8;
- if (!(x&(v>>8))) {
- if (!(x&(v>>16)) && !(x&(v>>24)))
- *size=4;
- else *size=2;
- } else *size=1;
- if (*size==1) {
- if (offs==1 && v!=0xFF) /* avoid such a case... (unless *size _was_ already 1) */
- offs=0,*size=2;
- } else if (offs&1) /* too bad... we can do nothing */
- offs=0,*size=4;
- return offs;
- }
- readonly int deflt_types[5]={0,bt_uchar,bt_ushort,0,bt_ulong};
- void bitwise_optimize(struct enode *ep,long mode) {
- long *ref=0;
- /* we may not call swap_nodes here! VCG needs to preserve the order */
- if (ep->v.p[0]->nodetype==en_icon && ep->v.p[1]->nodetype==en_ref)
- ref=&ep->v.p[0]->v.i;
- else if (ep->v.p[1]->nodetype==en_icon && ep->v.p[0]->nodetype==en_ref)
- ref=&ep->v.p[1]->v.i;
- if (ref) {
- int offs=bitwise_reduction((*ref)^mode,&ep->esize);
- ep->etype=deflt_types[ep->esize];
- ep->v.p[0]->etype=
- #endif
- struct amode *g_asxor(struct enode *node, int flags) {
- /*
- * generate an ^= node
- */
- int f;
- struct amode *ap1, *ap2;
- switch (node->etype) {
- case bt_char:
- case bt_uchar:
- case bt_short:
- case bt_ushort:
- case bt_long:
- case bt_ulong:
- case bt_pointer:
- if (flags & F_NOVALUE)
- f = F_ALL;
- else
- f = F_ALL | F_USES;
- ap1 = g_expr(node->v.p[0], f);
- if (ap1->mode==am_dreg || ap1->mode==am_areg)
- f = F_ALL | F_SRCOP;
- else f = F_DREG | F_IMMED;
- ap2 = g_expr(node->v.p[1], f);
- validate(ap1);
- if (ap2->mode==am_immed && ap1->mode!=am_dreg && ap1->mode!=am_areg) {
- int i,n=0,j=0; long z=ap2->offset->v.i;
- for (i=0;i<8*node->esize;i++)
- if (z&(1<<i)) { n++; j=i; }
- if (n==1) {
- g_bitmancode(op_bchg, (int) node->esize, mk_immed(j), ap1);
- } else g_code(op_eor, (int) node->esize, ap2, ap1);
- } else g_code(op_eor, (int) node->esize, ap2, ap1);
- freeop(ap2);
- return mk_legal(ap1, flags, node->esize);
- }
- ierr(G_ASXOR,1);
- /* NOTREACHED */
- return 0; // make the compiler happy
- }
- struct amode *g_aslogic(struct enode *node, int flags, enum(e_op) op) {
- /*
- * generate a&= or a|=
- */
- int f;
- struct amode *ap1, *ap2, *ap3;
- if (flags & F_NOVALUE)
- f = F_ALL;
- else
- f = F_ALL | F_USES;
- ap1 = g_expr(node->v.p[0], f);
- if (ap1->mode==am_dreg || ap1->mode==am_areg)
- f = (F_ALL & ~F_AREG) | F_SRCOP;
- else f = F_DREG | F_IMMED;
- ap2 = g_expr(node->v.p[1], f);
- validate(ap1);
- if (ap1->mode != am_areg) {
- if (/*(op==op_and || op==op_or || op==op_eor) && */ap2->mode==am_immed
- && ap1->mode!=am_dreg && ap1->mode!=am_areg
- && (node->esize==1/* || (ap1->mode!=am_ainc && ap1->mode!=am_adec)*/)) {
- int i,n=-1,j=0,and=(op==op_and); long z=ap2->offset->v.i;
- for (i=0;i<8*node->esize;i++)
- if ((!!(z&(1<<i)))^and) { n++; j=i; }
- if (!n) {
- ap3 = ap1;
- /* if (node->esize!=1) {
- ap3 = copy_addr(ap1);
- switch (ap1->mode) {
- case am_ind:
- ap3->mode=am_indx;
- ap3->offset=mk_immed(
- }*/
- g_bitmancode(and?op_bclr:(op==op_or?op_bset:op_bchg),
- 0/* ALWAYS .B !!! */, mk_immed(j), ap3);
- goto asdone;
- }
- }
- g_code(op, (int) node->esize, ap2, ap1);
- } else {
- ap3 = temp_data();
- g_code(op_move, 4, ap1, ap3);
- g_code(op, (int) node->esize, ap2, ap3);
- g_code(op_move, (int) node->esize, ap3, ap1);
- freeop(ap3);
- }
- asdone:
- freeop(ap2);
- return mk_legal(ap1, flags, node->esize);
- }
- struct amode *g_asshift(struct enode *node, int flags, enum(e_op) op) {
- /*
- * generate shift equals operators.
- */
- int f;
- struct amode *ap1, *ap2, *ap3;
- switch (node->etype) {
- case bt_uchar:
- case bt_char:
- case bt_ushort:
- case bt_short:
- case bt_ulong:
- case bt_long:
- case bt_pointer:
- if (flags & F_NOVALUE)
- f = F_ALL;
- else
- f = F_ALL | F_USES;
- ap1 = g_expr(node->v.p[0], f);
- if (ap1->mode != am_dreg) {
- ap3 = temp_data();
- g_code(op_move, (int) node->esize, ap1, ap3);
- } else
- ap3 = ap1;
- ap2 = g_expr(node->v.p[1], F_DREG | F_IMMED);
- /* add if const=1 and op is << */
- if (op==op_lsl && ap2->mode == am_immed && ap2->offset->nodetype == en_icon
- && ap2->offset->v.i == 1) {
- op=op_add; ap2=ap3;
- }
- /* quick constant if 2<=const<=8 */
- if (ap2->mode == am_immed && ap2->offset->nodetype == en_icon
- && (ap2->offset->v.i > 8 || ap2->offset->v.i < 1)) {
- /*if (ap2->offset->v.i <= 0)
- uwarn("negative shift constant");*/
- ap2 = mk_legal(ap2, F_DREG, 1l);
- }
- validate(ap3);
- g_code(op, (int) node->esize, ap2, ap3);
- if (ap2 != ap3)
- freeop(ap2);
- if (ap3 != ap1) {
- g_code(op_move, (int) node->esize, ap3, ap1);
- freeop(ap3);
- }
- return mk_legal(ap1, flags, node->esize);
- }
- ierr(G_ASSHIFT,1);
- /* NOTREACHED */
- return 0; // make the compiler happy
- }
- struct amode *g_asmul(struct enode *node, int flags) {
- /*
- * generate a *= node.
- */
- struct amode *ap1, *ap2, *ap3;
- enum(e_op) op = op_mulu;
- switch (node->etype) {
- case bt_char:
- ap1 = g_expr(node->v.p[0], F_ALL | F_USES);
- if (ap1->mode != am_dreg) {
- ap2 = temp_data();
- g_code(op_move, 1, ap1, ap2);
- } else
- ap2 = ap1;
- g_code(op_ext, 2, ap2, NIL_AMODE);
- ap3 = g_expr(node->v.p[1], F_DREG | F_IMMED);
- if (ap3->mode == am_dreg)
- g_code(op_ext, 2, ap3, NIL_AMODE);
- validate(ap2);
- g_code(op_muls, 0, ap3, ap2);
- freeop(ap3);
- if (ap2 != ap1) {
- validate(ap1);
- g_code(op_move, 1, ap2, ap1);
- freeop(ap2);
- }
- return mk_legal(ap1, flags, node->esize);
- case bt_uchar:
- ap1 = g_expr(node->v.p[0], F_ALL | F_USES);
- if (ap1->mode != am_dreg) {
- ap2 = temp_data();
- g_code(op_move, 1, ap1, ap2);
- } else
- ap2 = ap1;
- g_code(op_and, 2, mk_immed(255l), ap2);
- ap3 = g_expr(node->v.p[1], F_DREG | F_IMMED);
- if (ap3->mode == am_dreg)
- g_code(op_and, 2, mk_immed(255l), ap3);
- validate(ap2);
- g_code(op_mulu, 0, ap3, ap2);
- freeop(ap3);
- if (ap2 != ap1) {
- validate(ap1);
- g_code(op_move, 1, ap2, ap1);
- freeop(ap2);
- }
- return mk_legal(ap1, flags, node->esize);
- case bt_short:
- op = op_muls;
- case bt_ushort:
- ap1 = g_expr(node->v.p[0], F_ALL | F_USES);
- ap2 = g_expr(node->v.p[1], F_ALL);
- validate(ap1);
- if (ap1->mode != am_dreg) {
- ap3 = temp_data();
- g_code(op_move, 2, ap1, ap3);
- g_code(op, 0, ap2, ap3);
- freeop(ap2);
- freeop(ap3);
- g_code(op_move, 2, ap3, ap1);
- } else {
- g_code(op_muls, 0, ap2, ap1);
- freeop(ap2);
- }
- return mk_legal(ap1, flags, node->esize);
- case bt_long:
- case bt_ulong:
- case bt_pointer:
- return as_fcall(node, flags, "__mulsi3");
- #ifndef NOFLOAT
- case bt_float:
- #ifdef DOUBLE
- case bt_double:
- #endif
- return as_fcall(node, flags, str(ffpmul));
- #endif
- }
- ierr(G_ASMUL,1);
- /* NOTREACHED */
- return 0; // make the compiler happy
- }
- struct amode *g_asdiv(struct enode *node, int flags) {
- /*
- * generate /= and %= nodes.
- */
- struct amode *ap1, *ap2, *ap3;
- switch (node->etype) {
- case bt_char:
- ap1 = g_expr(node->v.p[0], F_ALL | F_USES);
- if (ap1->mode != am_dreg) {
- ap2 = temp_data();
- g_code(op_move, 1, ap1, ap2);
- } else
- ap2 = ap1;
- g_code(op_ext, 2, ap2, NIL_AMODE);
- g_code(op_ext, 4, ap2, NIL_AMODE);
- ap3 = g_expr(node->v.p[1], F_DREG | F_IMMED);
- if (ap3->mode == am_dreg)
- g_code(op_ext, 2, ap3, NIL_AMODE);
- validate(ap2);
- g_code(op_divs, 0, ap3, ap2);
- freeop(ap3);
- if (ap2 != ap1) {
- validate(ap1);
- g_code(op_move, 1, ap2, ap1);
- freeop(ap2);
- }
- return mk_legal(ap1, flags, node->esize);
- case bt_uchar:
- ap1 = g_expr(node->v.p[0], F_ALL | F_USES);
- if (ap1->mode != am_dreg) {
- ap2 = temp_data();
- g_code(op_move, 1, ap1, ap2);
- } else
- ap2 = ap1;
- g_code(op_and, 4, mk_immed(255l), ap2);
- ap3 = g_expr(node->v.p[1], F_DREG | F_IMMED);
- if (ap3->mode == am_dreg)
- g_code(op_and, 2, mk_immed(255l), ap3);
- validate(ap2);
- g_code(op_divu, 0, ap3, ap2);
- freeop(ap3);
- if (ap2 != ap1) {
- validate(ap1);
- g_code(op_move, 1, ap2, ap1);
- freeop(ap2);
- }
- return mk_legal(ap1, flags, node->esize);
- case bt_short:
- case bt_ushort:
- ap1 = temp_data();
- ap2 = g_expr(node->v.p[0], F_ALL | F_USES);
- validate(ap1);
- g_code(op_move, 2, ap2, ap1);
- ap3 = g_expr(node->v.p[1], F_ALL & ~F_AREG);
- validate(ap2);
- validate(ap1);
- if (node->etype == bt_short) {
- g_code(op_ext, 4, ap1, NIL_AMODE);
- g_code(op_divs, 0, ap3, ap1);
- } else {
- g_code(op_and, 4, mk_immed(65535l), ap1);
- g_code(op_divu, 0, ap3, ap1);
- }
- freeop(ap3);
- g_code(op_move, 2, ap1, ap2);
- freeop(ap2);
- return mk_legal(ap1, flags, 2l);
- case bt_long:
- return as_fcall(node, flags, "__divsi3");
- case bt_ulong:
- case bt_pointer:
- return as_fcall(node, flags, "__udivsi3");
- #ifndef NOFLOAT
- #ifdef DOUBLE
- case bt_double:
- #endif
- case bt_float:
- return as_fcall(node, flags, str(ffpdiv));
- #endif
- }
- ierr(G_ASDIV,1);
- /* NOTREACHED */
- return 0; // make the compiler happy
- }
- struct amode *g_asmod(struct enode *node, int flags) {
- /*
- * generate /= and %= nodes.
- */
- struct amode *ap1, *ap2, *ap3;
- switch (node->etype) {
- case bt_short:
- case bt_ushort:
- ap1 = temp_data();
- ap2 = g_expr(node->v.p[0], F_ALL | F_USES);
- validate(ap1);
- g_code(op_move, 2, ap2, ap1);
- ap3 = g_expr(node->v.p[1], F_ALL & ~F_AREG);
- validate(ap2);
- validate(ap1);
- if (node->etype == bt_short) {
- g_code(op_ext, 4, ap1, NIL_AMODE);
- g_code(op_divs, 0, ap3, ap1);
- } else {
- g_code(op_and, 4, mk_immed(65535l), ap1);
- g_code(op_divu, 0, ap3, ap1);
- }
- g_code(op_swap, 0, ap1, NIL_AMODE);
- freeop(ap3);
- g_code(op_move, 2, ap1, ap2);
- freeop(ap2);
- return mk_legal(ap1, flags, 2l);
- case bt_long:
- return as_fcall(node, flags, ".lrem");
- case bt_ulong:
- case bt_pointer:
- return as_fcall(node, flags, ".ulrem");
- }
- ierr(G_ASMOD,1);
- /* NOTREACHED */
- return 0; // make the compiler happy
- }
- void structassign(struct amode *ap1, struct amode *ap2, long size, int mode) {
- /*
- * assign structure from ap1 to ap2
- * ap1, ap2 are scratch address registers
- */
- #ifdef BIGMEM
- long loop_c;
- #else
- int loop_c;
- #endif
- int rest;
- struct amode *ap3;
- unsigned int label;
- ap1 = copy_addr(ap1);
- ap2 = copy_addr(ap2);
- ap1->mode = mode;
- ap2->mode = mode;
- loop_c = size >> 2;
- rest = (int) (size & 3);
- if (loop_c <= 5) /* loop-unrolling */
- while (loop_c--)
- g_code(op_move, 4, ap1, ap2);
- else {
- loop_c--; /* for dbra */
- ap3 = temp_data();
- freeop(ap3);
- label = nxtlabel();
- #ifdef BIGMEM
- if (loop_c <= 65535) { // single loop
- #endif
- g_code(op_move, 2, mk_immed(loop_c), ap3);
- g_label(label);
- g_code(op_move, 4, ap1, ap2);
- g_code(op_dbra, 0, ap3, mk_label(label));
- #ifdef BIGMEM
- } else { // extended loop
- g_code(op_move, 4, mk_immed(loop), ap3);
- g_label(label);
- g_code(op_move, 4, ap1, ap2);
- g_code(op_dbra, 0, ap3, mk_label(label));
- g_code(op_sub, 4, mk_immed(65536l), ap3);
- g_code(op_bhs, 0, mk_label(label), NIL_AMODE);
- }
- #endif
- }
- #if AL_DEFAULT!=2
- if (rest >= 2) {
- rest -= 2;
- g_code(op_move, 2, ap1, ap2);
- }
- /* This cannot happen if the size of structures is always even */
- if (rest)
- g_code(op_move, 1, ap1, ap2);
- #ifdef SHORT_STRUCT_PASSING
- #error "Much of the short struct stuff assumes that structs whose size is under 4 \
- really are short structs (while they aren't, since to do an assignment of a \
- 3-byte struct, you have to do 2 moves, if not 3...)"
- #error "So let AL_DEFAULT be 2."
- #endif
- #else
- if (rest)
- g_code(op_move, 2, ap1, ap2);
- #endif
- }
- struct amode *g_assign(struct enode *node, int flags) {
- /*
- * generate code for an assignment node.
- */
- int f;
- struct amode *ap1, *ap2, *ap3;
- struct enode *ep;
- long size = node->esize;
- if (flags & F_NOVALUE)
- f = F_ALL;
- else
- f = F_ALL | F_USES;
- if (bt_aggregate(node->etype)) {
- #ifdef SHORT_STRUCT_PASSING
- if (node->esize<=4) {
- ap1 = g_expr(node->v.p[1], F_AREG);
- ap2 = g_expr(node->v.p[0], F_AREG);
- validate(ap1);
- structassign(ap1, ap2, (long)node->esize, am_ind);
- freeop(ap2);
- return mk_legal(ap1, flags, 4l);
- }
- #endif
- /*
- * Other parts of this module return a pointer to a struct in a register,
- * not the struct itself
- */
- ap1 = g_expr(node->v.p[1], F_AREG | F_VOL);
- ap2 = g_expr(node->v.p[0], F_AREG | F_VOL);
- validate(ap1);
- /* hacky: save ap1 if needed later, structassign destroys it */
- if (!(flags & F_NOVALUE)) {
- ap3 = temp_addr();
- /* BTW, this code gets eliminated with MAX_ADDR = 1 */
- g_code(op_move, 4, ap1, ap3);
- structassign(ap3, ap2, (long)size, am_ainc);
- freeop(ap3);
- freeop(ap2);
- validate(ap1);
- return mk_legal(ap1, flags, 4l);
- } else { /* no need to save any registers */
- structassign(ap1, ap2, (long)node->esize, am_ainc);
- freeop(ap2);
- /* mk_legal is a no-op here */
- return mk_legal(ap1, flags, 4l);
- }
- }
- if (node->v.p[0]->nodetype == en_fieldref) {
- long mask;
- int i;
- /*
- * Field assignment
- */
- #ifdef OLD_FIELD_ASSIGN
- /* get the value */
- ap1 = g_expr(node->v.p[1], F_DREG | F_VOL);
- i = node->v.p[0]->bit_width;
- mask = 0;
- while (i--)
- mask = mask + mask + 1;
- g_code(op_and, (int) size, mk_immed(mask), ap1);
- i = (node->v.p[0]->esize<<3)-node->v.p[0]->bit_offset-node->v.p[0]->bit_width;
- mask <<= i;
- if (!(flags & F_NOVALUE)) {
- /*
- * result value needed
- */
- ap3 = temp_data();
- g_code(op_move, 4, ap1, ap3);
- } else
- ap3 = ap1;
- if (i > 0) {
- if (i == 1) {
- /* add dn,dn */
- g_code(op_add, (int) node->esize, ap3, ap3);
- } else if (i <= 8) {
- g_code(op_lsl, (int) size,
- mk_immed(i), ap3);
- } else {
- ap2 = temp_data();
- g_code(op_moveq, 0,
- mk_immed(i), ap2);
- g_code(op_lsl, (int) size, ap2, ap3);
- freeop(ap2);
- }
- }
- ep = mk_node(en_ref, node->v.p[0]->v.p[0], NIL_ENODE);
- ep->esize = 1;
- ap2 = g_expr(ep, F_MEM);
- validate(ap3);
- g_code(op_and, (int) size, mk_immed(~mask), ap2);
- g_code(op_or, (int) size, ap3, ap2);
- freeop(ap2);
- if (!(flags & F_NOVALUE)) {
- freeop(ap3);
- validate(ap1);
- }
- #else
- {
- ep = mk_node(en_ref, node->v.p[0]->v.p[0], NIL_ENODE);
- ep->esize = node->v.p[1]->esize;
- ep->etype = node->v.p[1]->etype;
- ap2 = g_expr(ep, F_MEM);
- ep=node->v.p[1];
- /* get the value */
- i = node->v.p[0]->bit_width;
- mask = 0;
- while (i--)
- mask = mask + mask + 1;
- ep = mk_node(en_and, ep, mk_icon(mask));
- ep->esize=ep->v.p[0]->esize;
- ep->etype=ep->v.p[0]->etype;
- ep->v.p[1]->esize=ep->esize;
- ep->v.p[1]->etype=ep->etype;
- i = (node->v.p[0]->esize<<3)-node->v.p[0]->bit_offset-node->v.p[0]->bit_width;
- mask <<= i;
- ep = mk_node(en_lsh, ep, mk_icon(i));
- ep->esize=ep->v.p[0]->esize;
- ep->etype=ep->v.p[0]->etype;
- ep->v.p[1]->esize=1;
- ep->v.p[1]->etype=bt_char;
- opt0(&ep);
- ap1 = g_expr(ep, F_DREG | F_IMMED);
- validate(ap2);
- if (ap1->mode==am_immed && node->v.p[0]->bit_width==1) {
- // note that thus, we need not free/validate anything...
- if (!((~ap1->offset->v.i)&mask)) {
- ap1->offset->v.i = i;
- g_bitmancode(op_bset, (int)size, ap1, ap2);
- freeop(ap2);
- if (!(flags & F_NOVALUE))
- return mk_legal(mk_immed(1L),flags,node->esize);
- return NIL_AMODE;
- } else if (!(ap1->offset->v.i&mask)) {
- ap1->offset->v.i = i;
- g_bitmancode(op_bclr, (int)size, ap1, ap2);
- freeop(ap2);
- if (!(flags & F_NOVALUE))
- return mk_legal(mk_immed(0L),flags,node->esize);
- return NIL_AMODE;
- }
- } else {
- g_code(op_and, (int) size, mk_immed(~mask), ap2);
- g_code(op_or, (int) size, ap1, ap2);
- freeop(ap1);
- if (!(flags & F_NOVALUE))
- return g_fderef(node->v.p[0], ap2, flags);
- freeop(ap2);
- return NIL_AMODE;
- }
- }
- #endif
- return mk_legal(ap1, flags, size);
- }
- /*
- * (uns.) char, (uns.) short, (uns.) long, float
- *
- * we want to pass the right hand side as the expression value. This can't
- * be done if the left side is a register variable on which the right
- * hand side addressing mode depends. But if the left side IS a register
- * variable, it is desirable to pass the left side, so no problem.
- */
- if (node->v.p[0]->nodetype == en_tempref) {
- /* pass the left side as expr. value */
- ap1 = g_expr(node->v.p[0], f);
- ap2 = g_expr(node->v.p[1], F_ALL | F_SRCOP);
- validate(ap1);
- g_code(op_move, (int) size, ap2, ap1);
- freeop(ap2);
- return mk_legal(ap1, flags, size);
- } else {
- /* pass the right side as expr. value */
- /* normally, this is more efficient */
- ap1 = g_expr(node->v.p[1], f | F_SRCOP);
- ap2 = g_expr(node->v.p[0], F_ALL);
- validate(ap1);
- g_code(op_move, (int) size, ap1, ap2);
- freeop(ap2);
- return mk_legal(ap1, flags, size);
- }
- }
- struct amode *g_aincdec(struct enode *node, int flags, enum(e_op) op) {
- /*
- * generate an auto increment or decrement node. op should be either op_add
- * (for increment) or op_sub (for decrement).
- */
- struct amode *ap1, *ap2;
- switch (node->etype) {
- case bt_uchar:
- case bt_char:
- case bt_short:
- case bt_ushort:
- case bt_long:
- case bt_ulong:
- case bt_pointer:
- if (flags & F_NOVALUE) {/* dont need result */
- ap1 = g_expr(node->v.p[0], F_ALL);
- g_code(op, (int) node->esize, mk_immed((long) node->v.p[1]->v.i),
- ap1);
- return mk_legal(ap1, flags, node->esize);
- }
- if (flags & F_DREG)
- ap1 = temp_data();
- else
- ap1 = temp_addr();
- ap2 = g_expr(node->v.p[0], F_ALL | F_USES);
- validate(ap1);
- g_code(op_move, (int) node->esize, ap2, ap1);
- g_code(op, (int) node->esize, mk_immed((long) node->v.p[1]->v.i), ap2);
- freeop(ap2);
- return mk_legal(ap1, flags, node->esize);
- }
- ierr(G_AINCDEC,1);
- /* NOTREACHED */
- return 0; // make the compiler happy
- }
- long push_param(struct enode *ep) {
- /*
- * push the operand expression onto the stack. return the number of bytes
- * pushed
- */
- struct amode *ap;
- #ifdef OLD_STRUCT_PUSH
- struct amode *ap1;
- #endif
- long size = ep->esize;
- int old_pushed;
- /* pushing of aggregates: (short) structures and unions, as well as BCD floats */
- if (bt_aggregate(ep->etype)) {
- if (ep->nodetype==en_ref)
- ep = ep->v.p[0];
- /* all other cases return a pointer to the struct anyway */
- #ifdef OLD_STRUCT_PUSH
- /* allocate stack space */
- g_code(op_sub, 4, mk_immed(size), mk_reg(STACKPTR));
- /*
- * F_VOL was missing in the following line --
- * it took a hard-core debugging session to find this error
- */
- ap = g_expr(ep, F_AREG | F_VOL);
- ap1 = temp_addr();
- validate(ap);
- g_code(op_move, 4, mk_reg(STACKPTR), ap1);
- /* now, copy it on stack - the same as structassign */
- structassign(ap, ap1, size, am_ainc);
- freeop(ap1);
- freeop(ap);
- #else
- if ((size&1)) size++; /* otherwise there will be a bunch of problems */
- {
- struct enode *ep2=mk_icon(size);
- ep2->etype=bt_long; ep2->esize=4;
- ep = mk_node(en_add,ep,ep2);
- ep->etype=bt_pointer; ep->esize=4;
- opt0(&ep);
- ap = g_expr(ep, F_AREG | F_VOL);
- /* now, copy it on stack - the same as structassign */
- structassign(ap, mk_reg(STACKPTR), size, am_adec);
- freeop(ap);
- }
- #endif
- return size;
- }
- old_pushed = pushed;
- pushed = 0;
- ap = g_expr(ep, F_ALL | F_DEREF);
- /*
- * This is a hook for the peephole optimizer, which will convert lea
- * <ea>,An + pea (An) ==> pea <ea>
- */
- #ifdef POP_OPT
- if (old_pushed && pushed)
- g_code(_op_adj, 0, NIL_AMODE, NIL_AMODE);
- #endif
- pushed = 1;
- if ((ap->mode == am_areg || ap->mode == am_immed)
- && size == 4 && ap->preg <= MAX_ADDR) {
- ap = copy_addr(ap);
- am_doderef(ap->mode);
- g_code(op_pea, 0, ap, NIL_AMODE);
- } else
- g_code(op_move, (int) size, ap, push_am);
- freeop(ap);
- return size+(size&1);
- }
- int req_all_aregs(struct enode *plist,int rp_dn,int rp_an) {
- /* requires all regs if and only if (num_params>=regs_num || num_pointers>=aregs_num) */
- rp_dn+=rp_an;
- while (plist) {
- if (!--rp_dn) return 1;
- if (plist->v.p[0]->etype==bt_pointer && !--rp_an) return 1;
- plist=plist->v.p[1];
- }
- return 0;
- }
- long g_parms(struct enode *plist
- #ifdef REGPARM
- , int rp_dn, int rp_an, struct amode **a1ap
- #endif
- ) {
- /*
- * push a list of parameters onto the stack and return the number of
- * parameters pushed.
- */
- #ifdef BIGSTACK
- long i=0;
- #else
- int i=0;
- #endif
- pushed = 0;
- #ifdef REGPARM
- #ifdef PC
- if (rp_dn IS_INVALID || rp_an IS_INVALID)
- ierr(G_PARMS,1);
- #endif
- if (rp_dn || rp_an) {
- int nr=rp_dn+rp_an,np=0,n;
- struct enode *ep=plist,**p,**dp,**ap,*allocbase[16],*list[16];
- struct amode deep[CONVENTION_MAX_DATA+1+CONVENTION_MAX_ADDR+1],*deepp;
- while (ep) np++, ep=ep->v.p[1];
- /* first, push stack params while all the temp registers are free */
- while (np>nr) {
- i += push_param(plist->v.p[0]);
- plist = plist->v.p[1];
- np--;
- }
- /* store the last params so we can examinate them in the correct order */
- n=np; while (n--) list[n]=plist->v.p[0], plist=plist->v.p[1];
- /* now, fill in 'allocbase' */
- p=list; dp=&allocbase[0]; ap=&allocbase[8];
- n=np; while (n--) {
- ep=*p++;
- if ((ep->etype==bt_pointer && rp_an) || !rp_dn)
- *ap++=ep, rp_an--;
- else *dp++=ep, rp_dn--;
- }
- *ap=NULL; *dp=NULL;
- /* finally, load all the parameters into the correct registers */
- dp=&allocbase[0]; ap=&allocbase[8];
- deepp=deep;
- n=8; while (n--) { /* push d0/a0/d1/a1/... */
- if (*dp) {
- //#ifdef PC
- struct amode *amp=
- //#endif
- g_expr(*dp++,F_DREG|F_VOL);
- #ifdef INFINITE_REGISTERS
- struct amode *ap2 = (struct amode *) xalloc((int) sizeof(struct amode), 0);
- ap2->mode = am_dreg;
- ap2->preg = TDREGBASE+dp-allocbase-1;
- g_code(op_move, dp[-1]->esize, amp, ap2);
- freeop(amp);
- amp=ap2;
- #endif
- #ifdef PC
- if (amp->mode!=am_dreg || amp->preg!=TDREGBASE+dp-allocbase-1)
- ierr(REGPARM,1);
- #endif
- *deepp++=*amp;
- }
- if (*ap) {
- //#ifdef PC
- struct amode *amp=
- //#endif
- *a1ap = g_expr(*ap++,F_AREG|F_VOL);
- #ifdef INFINITE_REGISTERS
- struct amode *ap2 = (struct amode *) xalloc((int) sizeof(struct amode), 0);
- ap2->mode = am_areg;
- ap2->preg = TDREGBASE+ap-allocbase-1-8;
- g_code(op_move, ap[-1]->esize, amp, ap2);
- freeop(amp);
- amp=ap2;
- #endif
- #ifdef PC
- if (amp->mode!=am_areg || amp->preg!=TDREGBASE+ap-allocbase-1-8)
- ierr(REGPARM,2);
- #endif
- *deepp++=*amp;
- }
- }
- while (deepp>deep)
- validate(--deepp);
- } else {
- #endif
- while (plist != 0) {
- i += push_param(plist->v.p[0]);
- plist = plist->v.p[1];
- }
- #ifdef REGPARM
- }
- #endif
- return i;
- }
- struct amode *func_result(int flags, long bytes) {
- /*
- * saves a function call result in D0 it is assumed that flags contain
- * either F_DREG or F_AREG return value is the addressing mode of the
- * result bytes is the number of bytes to pop off the stack
- *
- * This routine does not use mk_legal and takes care of the stuff itself.
- */
- struct amode *ap;
- if (bytes != 0)
- /* adjust stack pointer */
- g_code(op_add, 4, mk_immed(bytes), mk_reg(STACKPTR));
- if (flags & F_NOVALUE)
- return 0;
- if (flags & F_DREG) {
- ap = temp_data();
- g_code(op_move, 4, mk_reg(RESULT), ap);
- } else if (flags & F_AREG) {
- ap = temp_addr();
- g_code(op_move, 4, mk_reg(RESULT), ap);
- #ifdef PC
- } else {
- ierr(FUNC_RESULT,1);
- return 0; // make the compiler happy
- #endif
- }
- return ap;
- }
- struct amode *func_result2(int flags, long bytes, int reg) {
- /*
- * Saves a function call result in REG. It is assumed that flags contain
- * either F_DREG or F_AREG. Return value is the addressing mode of the
- * result; bytes is the number of bytes to pop off the stack
- *
- * This routine does not use mk_legal and takes care of the stuff itself.
- */
- struct amode *ap;
- if (bytes != 0) /* adjust stack pointer */
- g_code(op_add, 4, mk_immed(bytes), mk_reg(STACKPTR));
- if (flags & F_NOVALUE)
- return 0;
- if ((flags & F_DREG) && reg==RESULT) { // permet d'éviter move.l a0,d0 /
- ap = temp_data(); // move.l d0,rn #roll#
- g_code(op_move, 4, mk_reg(reg), ap);
- } else if (flags & F_AREG) {
- ap = temp_addr();
- g_code(op_move, 4, mk_reg(reg), ap);
- } else {
- #ifdef PC
- if (flags & F_DREG) {
- #endif
- ap = temp_data();
- g_code(op_move, 4, mk_reg(reg), ap);
- #ifdef PC
- } else {
- ierr(FUNC_RESULT,2);
- return 0; // make the compiler happy
- }
- #endif
- }
- return ap;
- }
- struct amode *as_fcall(struct enode *node, int flags, char *libname) {
- /* assignment operations with library calls */
- long i;
- struct amode *ap1;
- long size;
- size = node->esize;
- temp_inv();
- i = push_param(node->v.p[1]);
- if (node->v.p[0]->nodetype == en_tempref) {
- /* ap1 cannot be destroyed, no problem */
- ap1 = g_expr(node->v.p[0], F_DREG | F_AREG);
- g_code(op_move, (int) size, ap1, push_am);
- i += size;
- call_library(libname);
- /* ap1 is always valid and not equal to RESULT */
- g_code(op_move, (int) size, mk_reg(RESULT), ap1);
- } else {
- uwarn("possible flaw in lib call");
- ap1 = g_expr(node->v.p[0], F_DREG | F_AREG);
- g_code(op_move, (int) size, ap1, push_am);
- i += size;
- call_library(libname);
- /* ap1 is always valid and not equal to RESULT */
- g_code(op_move, (int) size, mk_reg(RESULT), ap1);
- }
- g_code(op_add, 4, mk_immed((long) i), mk_reg(STACKPTR));
- if (!(flags & F_NOVALUE)) {
- if (flags & F_AREG)
- ap1 = temp_addr();
- else
- ap1 = temp_data();
- g_code(op_move, 4, mk_reg(RESULT), ap1);
- return mk_legal(ap1, flags, size);
- } else
- return 0;
- }
- #ifndef __HAVE_REGS_IMAGE
- #define __HAVE_REGS_IMAGE
- typedef struct _regsimg {
- #ifndef INFINITE_REGISTERS
- int reg_alloc_ptr,reg_stack_ptr;
- int next_data,next_addr;
- #endif
- } REGS_IMAGE;
- #endif
- readonly struct amode am_a1={am_areg,0,1,0,0,0};
- readonly struct amode am_a2={am_areg,0,2,0,0,0};
- readonly struct amode am_a2ind={am_ind,0,2,0,0,0};
- extern int hexatoi(char *s);
- struct amode *g_fcall(struct enode *node, int flags) {
- /*
- * generate a function call node and return the address mode of the result.
- */
- struct amode *ap; enum(e_node) nt;
- long i;
- #ifdef SHORT_STRUCT_PASSING
- int short_struct_return=0;
- #endif
- #ifdef PC
- // avoid a compiler warning...
- struct amode *struct_ap = 0;
- #else
- struct amode *struct_ap = struct_ap;
- #endif
- #ifdef REGPARM
- // struct amode *regap[(MAX_DATA+1+MAX_ADDR+1)+1],**rapp;
- struct amode *a1ap; struct enode *dep;
- REGS_IMAGE regs_img;
- int allaregs_patch=0;
- #endif
- /* push any used addr&data temps */
- dep = node->v.p[0];
- while (dep->nodetype==en_cast && dep->esize==4) dep=dep->v.p[0];
- nt = dep->nodetype;
- // nt = node->v.p[0]->nodetype;
- /* if (nt==en_nacon && !strcmp(node->v.p[0]->v.ensp,"rand"))
- printf("jdfio");*/
- temp_inv();
- #ifdef REGPARM
- useregs(®s_img);
- #ifndef INFINITE_REGISTERS
- if (node->rp_an>MAX_ADDR && !(nt==en_nacon || nt==en_labcon
- || (nt==en_tempref && node->v.p[0]->v.i>=AREGBASE))
- && req_all_aregs(node->v.p[1],node->rp_dn,node->rp_an))
- allaregs_patch=1;
- #endif
- i = g_parms(node->v.p[1],node->rp_dn,
- node->rp_an/*-allaregs_patch*/,&a1ap); /* generate parameters */
- if (allaregs_patch) freeop(a1ap);
- #else
- i = g_parms(node->v.p[1]); /* generate parameters */
- #endif
- /*
- * for functions returning a structure or a union, push a pointer to the
- * return value as additional argument The scratch space will be
- * allocated in the stack frame of the calling function.
- */
- if (bt_aggregate(node->etype)) {
- struct_ap = mk_scratch(node->esize);
- #ifdef SHORT_STRUCT_PASSING
- if (node->esize>4)
- #endif
- g_code(op_pea, 0, struct_ap, NIL_AMODE), i += 4l;
- #ifdef SHORT_STRUCT_PASSING
- else short_struct_return=1;
- #endif
- // freeop(ap); it is useless, as scratch amode's need not be freed
- }
- /* call the function */
- if (nt == en_nacon || nt == en_labcon) {
- /*if (!strcmp(node->v.p[0]->v.ensp,"rand"))
- printf("jdfio");*/
- #ifdef FLINE_RC
- if (fline_rc && nt==en_nacon && dep->v.ensp && !strncmp(dep->v.ensp,"_ROM_CALL_",10))
- g_code(op_dc, 2, mk_offset(mk_icon(0xF800+hexatoi(dep->v.ensp+10))), NIL_AMODE);
- else
- #endif
- g_code(op_jsr, 0, mk_offset(dep), NIL_AMODE);
- // g_code(op_jsr, 0, mk_offset(node->v.p[0]), NIL_AMODE);
- } else {
- #ifdef REGPARM
- if (allaregs_patch) {
- g_code(op_move, 4, (struct amode *)&am_a2, push_am);
- g_code(op_move, 4, (struct amode *)&am_a1, (struct amode *)&am_a2);
- }
- #endif
- ap = g_expr(node->v.p[0], F_AREG);
- ap = copy_addr(ap);
- ap->mode = am_ind;
- freeop(ap);
- #ifdef REGPARM
- if (allaregs_patch) {
- #ifdef PC
- if (ap->preg!=1)
- ierr(REGPARM,3);
- #endif
- /* struct amode *ap2 =
- (struct amode *) xalloc((int) sizeof(struct amode), AMODE);*/
- g_code(op_exg, 4, (struct amode *)&am_a1, (struct amode *)&am_a2);
- ap=(struct amode *)&am_a2ind;
- /* ap2->mode = am_areg;
- ap2->preg = node->rp_an-1;
- g_code(op_move, 4, pop_am, ap2); // always long since it's 'bt_pointer'
- i-=4;*/
- }
- #endif
- g_code(op_jsr, 0, ap, NIL_AMODE);
- #ifdef REGPARM
- if (allaregs_patch)
- g_code(op_move, 4, pop_am, (struct amode *)&am_a2);
- #endif
- }
- #ifdef REGPARM
- /* free register params */
- /* rapp=regap;
- while (*rapp)
- freeop(*rapp++);*/
- freeregs(®s_img);
- #endif
- #ifdef SHORT_STRUCT_PASSING
- if (short_struct_return) {
- if (flags & F_NOVALUE)
- return func_result2(F_NOVALUE,i,0);
- g_code(op_lea,0,struct_ap,mk_reg(PRESULT)); /* note : this *is* commutative with
- * popping args off as we use a virtual
- * a6-like register for struct_ap...
- * But we had better postpone this lea
- * as late as possible to take advantage
- * of peephole optimizations.
- */
- ap = mk_reg(PRESULT); ap->mode=am_ind;
- g_code(op_move,node->esize,mk_reg(RESULT),ap);
- }
- #endif
- return func_result2(flags, i,
- (node->etype>=bt_pointer&&node->etype<=bt_union)?PRESULT:RESULT);
- }
- struct amode *g_alloca(struct enode *node) {
- struct enode *ep=mk_node(en_add,node->v.p[0],mk_icon(1));
- struct amode *ap1, *ap2;
- ep->etype=node->v.p[0]->etype;
- ep->esize=node->v.p[0]->esize;
- ep->v.p[1]->etype=ep->etype;
- ep->v.p[1]->esize=ep->esize;
- ep=mk_node(en_and,mk_icon(-2),ep);
- ep->etype=ep->v.p[1]->etype;
- ep->esize=ep->v.p[1]->esize;
- ep->v.p[0]->etype=ep->etype;
- ep->v.p[0]->esize=ep->esize;
- ap1 = mk_reg(STACKPTR);
- opt0(&ep);
- ap2 = g_expr(ep, F_DREG | F_IMMED);
- g_code(op_sub, 2, ap2, ap1);
- freeop(ap2);
- return ap1;
- }
- #define F_GCAST 0
- //#define F_GCAST F_USES => seems completely useless...
- #ifdef G_CAST2
- struct amode *g_cast2(struct enode *ep, enum(e_bt) typ2, int flags) {
- /*
- * generates code for a en_cast node
- *
- */
- struct amode *ap;
- enum(e_bt) typ1=ep->etype;
- if (typ1==bt_long && typ2==bt_short) { /* useful when using short mul's */
- if (ep->nodetype==en_cast && ep->v.p[0]->etype==bt_short)
- return g_expr(ep->v.p[0], flags);
- }
- ap=g_expr(ep, F_ALL | F_SRCOP | F_GCAST);
- return g_cast(ap, typ1, typ2, flags);
- }
- #endif
- struct amode *g_cast(struct amode *ap, enum(e_bt) typ1, enum(e_bt) typ2, int flags) {
- /*
- * generates code for an en_cast node
- *
- */
- struct amode *ap1;
- int f;
- if (flags & F_NOVALUE) {
- freeop(ap);
- return 0;
- }
- /* the following code from now on is meaningless :
- * 'useless' casts are sometimes generated to keep track of
- * the previous TYP structure */
- #if 0
- if (typ1 == typ2)
- /*
- * this can happen in with the g_xmul stuff, where a cast from
- * (u)short to long now casts from (u)short to (u)short for an 68000
- * mulu or muls instruction.
- * It is safe to cut things short then.
- * It should not happen with types other than (u)short, but
- * it does not harm either.
- */
- if (typ1 == bt_short || typ1 == bt_ushort)
- return mk_legal(ap, flags, 2l);
- //else
- // msg("DEBUG: g_cast: typ1 == typ2\n");
- #endif
- switch (typ2) {
- /* switch: type to cast to */
- case bt_char:
- case bt_uchar:
- switch (typ1) {
- case bt_uchar:
- case bt_char:
- return mk_legal(ap, flags, 1l);
- case bt_ushort:
- case bt_short:
- if ((ap1 = g_offset(ap, 1)) == 0)
- ap1 = mk_legal(ap, F_DREG, 2l);
- return mk_legal(ap1, flags, 1l);
- case bt_ulong:
- case bt_long:
- case bt_pointer:
- if ((ap1 = g_offset(ap, 3)) == 0)
- ap1 = mk_legal(ap, F_DREG, 4l);
- return mk_legal(ap1, flags, 1l);
- case bt_float:
- #ifdef DOUBLE
- case bt_double:
- #endif
- return g_cast(g_cast(ap, bt_double, bt_long, F_DREG),
- bt_long, typ2, F_DREG);
- }
- break;
- case bt_ushort:
- case bt_short:
- switch (typ1) {
- case bt_uchar:
- ap = mk_legal(ap, F_DREG | F_VOL, 1l);
- g_code(op_and, 2, mk_immed(255l), ap);
- return mk_legal(ap, flags, 2l);
- case bt_char:
- ap = mk_legal(ap, F_DREG | F_VOL, 1l); // F_VOL is important here!
- g_code(op_ext, 2, ap, NIL_AMODE); // (otherwise (short)(char)my_short fails...)
- return mk_legal(ap, flags, 2l);
- case bt_short:
- case bt_ushort:
- return mk_legal(ap, flags, 2l);
- case bt_long:
- case bt_ulong:
- case bt_pointer:
- if ((ap1 = g_offset(ap, 2)) == 0)
- ap1 = mk_legal(ap, F_DREG, 4l);
- return mk_legal(ap1, flags, 2l);
- case bt_float:
- #ifdef DOUBLE
- case bt_double:
- #endif
- return g_cast(g_cast(ap, bt_double, bt_long, F_DREG),
- bt_long, typ2, F_DREG);
- }
- break;
- case bt_long:
- case bt_ulong:
- case bt_pointer:
- switch (typ1) {
- case bt_uchar:
- ap = mk_legal(ap, F_DREG | F_VOL, 1l);
- g_code(op_and, 4, mk_immed(255l), ap);
- return mk_legal(ap, flags, 4l);
- case bt_char:
- ap = mk_legal(ap, F_DREG | F_VOL, 1l); // F_VOL is important here!
- g_code(op_ext, 2, ap, NIL_AMODE); // (otherwise (short)(char)my_short fails...)
- g_code(op_ext, 4, ap, NIL_AMODE);
- return mk_legal(ap, flags, 4l);
- case bt_ushort:
- ap = mk_legal(ap, F_DREG | F_VOL, 2l);
- g_code(op_and, 4, mk_immed(65535l), ap);
- return mk_legal(ap, flags, 4l);
- case bt_short:
- f = flags & (F_DREG | F_AREG);
- if (f == 0) f = F_DREG | F_AREG;
- ap = mk_legal(ap, f | F_VOL, 2l); // F_VOL is important here!
- if (ap->mode == am_dreg) // (otherwise (short)(char)my_short fails...)
- g_code(op_ext, 4, ap, NIL_AMODE);
- return mk_legal(ap, flags, 4l);
- case bt_long:
- case bt_ulong:
- case bt_pointer:
- return mk_legal(ap, flags, 4l);
- #ifndef NOFLOAT
- case bt_float:
- #ifdef DOUBLE
- case bt_double:
- #endif
- /* library call */
- #ifndef BCDFLT
- freeop(ap);
- temp_inv();
- g_code(op_move, 4, ap, push_am);
- if (typ2 == bt_long)
- call_library(str(ffpftol));
- else
- call_library(str(ffpftou));
- return func_result(flags, 4l);
- #else
- fatal(
- "__floatsibf"); // !!!STUDY ME!!!
- #endif
- #endif
- }
- break;
- #ifndef NOFLOAT
- case bt_float:
- #ifdef DOUBLE
- case bt_double:
- #endif
- switch (typ1) {
- case bt_char:
- case bt_uchar:
- case bt_short:
- case bt_ushort:
- ap = g_cast(ap, typ1, bt_long, F_ALL);
- case bt_long:
- case bt_ulong:
- case bt_pointer:
- /* library call */
- #ifndef BCDFLT
- freeop(ap);
- temp_inv();
- g_code(op_move, 4, ap, push_am);
- if (typ1 == bt_ulong || typ1 == bt_pointer)
- call_library(str(ffputof));
- else
- call_library(str(ffpltof));
- return func_result(flags, 4l);
- #else
- fatal(
- "__fixbfsi"); // !!!STUDY ME!!!
- #endif
- case bt_float:
- #ifdef DOUBLE
- case bt_double:
- #endif
- return mk_legal(ap, flags, (long)float_size);
- }
- #endif
- break;
- }
- ierr(G_CAST,1);
- /* NOTREACHED */
- return 0; // make the compiler happy
- }
- struct amode *g_offset(struct amode *ap, int off) {
- /*
- * return true, if ap can be switched to address a location with a short
- * offset. typical application: cast long -> short: 8(a6) --> 10(a6) offset
- * is a small number (1,2 or 3)
- */
- switch (ap->mode) {
- case am_ind:
- ap = copy_addr(ap);
- ap->mode = am_indx;
- ap->offset = mk_icon((long) off);
- return ap;
- case am_indx:
- if (ap->offset->nodetype == en_icon &&
- off + ap->offset->v.i <= 32767) {
- ap = copy_addr(ap);
- ap->offset->v.i += off;
- return ap;
- }
- break;
- case am_indx2:
- case am_indx3:
- if (ap->offset->nodetype == en_icon &&
- off + ap->offset->v.i <= 127) {
- ap = copy_addr(ap);
- ap->offset->v.i += off;
- return ap;
- }
- break;
- case am_direct:
- ap = copy_addr(ap);
- ap->offset = mk_node(en_add, ap->offset,
- mk_icon((long) off));
- return ap;
- }
- /* special value indicating that it must be done by hand */
- return 0;
- }
- struct amode *g_xmul(struct enode *node, int flags, enum(e_op) op) {
- /*
- * performs a mixed-mode multiplication
- */
- struct amode *ap1, *ap2;
- /* if (lineid==139)
- bkpt();*/
- ap1 = g_expr(node->v.p[1], F_DREG | F_VOL);
- ap2 = g_expr(node->v.p[0], F_ALL & ~F_AREG);
- validate(ap1);
- g_code(op, 0, ap2, ap1);
- freeop(ap2);
- return mk_legal(ap1, flags, node->esize);
- }
- #ifndef __HAVE_STACK_IMAGE
- #define __HAVE_STACK_IMAGE
- typedef struct _stackimg {
- int next_data,next_addr;
- #ifndef INFINITE_REGISTERS
- int reg_alloc_ptr,reg_stack_ptr;
- char dreg_in_use[MAX_DATA+1];
- char areg_in_use[MAX_ADDR+1];
- struct reg_struct reg_stack[MAX_REG_STACK+1],reg_alloc[MAX_REG_STACK+1];
- int act_scratch;
- #endif
- } STACK_IMAGE;
- #endif
- struct amode *g_compound(struct snode *st, int flags) {
- STACK_IMAGE img;
- struct amode *ap1,*ap2;
- int old=need_res;
- need_res=(~flags)&F_NOVALUE;
- temp_inv(); /* we are forced to do so :'( */
- usestack(&img);
- genstmt(st);
- need_res=old;
- if (!(ap1=lastexpr_am)) {
- if (!(flags&F_NOVALUE))
- err_force_line=st->line, uerrc("no value returned in compound expression");
- }
- if (flags&F_NOVALUE) {
- freeop(lastexpr_am);
- return NIL_AMODE;
- }
- freestack(&img);
- /* always one of F_DREG or F_AREG is set */
- if ((flags&(F_AREG|F_DEREF))==(F_AREG|F_DEREF) || !(flags&F_DREG))
- ap2=temp_addr();
- else ap2=temp_data();
- g_code(op_move, 4, ap1, ap2);
- return ap2; /* we needn't call mk_legal :) */
- }
- struct amode *g_expr(struct enode *node, int flags) {
- /*
- * general expression evaluation. returns the addressing mode of the result.
- *
- * notice how most of the code actually lies in other functions: this is to
- * reduce the stack footprint, which is necessary because calls to g_expr may
- * be deeply nested
- */
- struct amode *ap1, *ap2;
- unsigned int lab0
- #ifndef ALTERNATE_HOOK
- , lab1
- #endif
- ;
- long size;
- enum(e_bt) type;
- if (node == 0)
- ierr(G_EXPR,1);
- /* if (node==0x7e1b50)
- bkpt();*/
- if (tst_const(node)) {
- #ifndef NOBCDFLT
- if (node->nodetype==en_fcon) {
- extern int glblabel;
- int lab = nxtglabel();
- int i;
- dseg();
- put_align(2);
- put_label(lab);
- genfloat(node->v.f);
- //char s[2+BCDLEN];
- //int i;
- //s[0] = (node->v.f.exponent>>8)&255;
- //s[1] = (node->v.f.exponent>>0)&255;
- //for (i=0;i<BCDLEN;i++)
- // s[i+2] = node->v.f.mantissa[i];
- //lab = stringlit(s,sizeof(s)-1);
- node = mk_node(en_labcon, NIL_ENODE, NIL_ENODE);
- node->v.enlab = lab;
- node->etype = bt_pointer;
- node->esize = 4;
- }
- #endif
- ap1 = (struct amode *) xalloc((int) sizeof(struct amode), AMODE+G_EXPR);
- ap1->mode = am_immed;
- ap1->offset = node;
- return mk_legal(ap1, flags, node->esize);
- }
- type = node->etype;
- size = node->esize;
- switch (node->nodetype) {
- case en_autocon:
- ap1 = temp_addr();
- #ifdef BIGSTACK
- if (node->v.i >= -32768 && node->v.i <= 32767) {
- #endif
- ap2 = (struct amode *) xalloc((int) sizeof(struct amode),
- AMODE+G_EXPR);
- ap2->mode = am_indx;
- ap2->preg = FRAMEPTR - AREGBASE; /* frame pointer */
- ap2->offset = node; /* use as constant node */
- g_code(op_lea, 0, ap2, ap1);
- #ifdef BIGSTACK
- } else {
- g_code(op_move, 4, mk_immed((long) node->v.p[0]->v.i), ap1);
- g_code(op_add, 4, mk_reg(FRAMEPTR), ap1);
- ap1 = copy_addr(ap1);
- ap1->mode = am_ind;
- }
- #endif
- return mk_legal(ap1, flags, size);
- case en_ref:
- /*
- * g_deref uses flags and size only to test F_USES
- */
- ap1 = g_deref(node->v.p[0], type, flags, node->esize);
- if (bt_aggregate(type))
- return mk_legal(ap1, flags, 4l);
- else
- return mk_legal(ap1, flags, size);
- case en_fieldref:
- return g_fderef(node, NULL, flags);
- case en_tempref:
- ap1 = (struct amode *) xalloc((int) sizeof(struct amode), AMODE+G_EXPR);
- if (node->v.i < AREGBASE) {
- ap1->mode = am_dreg;
- ap1->preg = (reg_t)node->v.i;
- } else {
- ap1->mode = am_areg;
- ap1->preg = (reg_t)(node->v.i - AREGBASE);
- }
- return mk_legal(ap1, flags, size);
- case en_uminus:
- return g_unary(node, flags, op_neg);
- case en_compl:
- return g_unary(node, flags, op_not);
- case en_add:
- #ifdef VCG
- return g_commute(g_addsub, node, flags, op_add, symmetric);
- #else
- return g_addsub(node, flags, op_add);
- #endif
- case en_sub:
- //#ifdef VCG
- // return g_commute(g_addsub, node, flags, op_sub, antisymmetric);
- //#else
- return g_addsub(node, flags, op_sub);
- //#endif
- case en_and:
- #ifdef BITWISE_REDUCE
- bitwise_optimize(node, -1L);
- #endif
- #ifdef VCG
- return g_commute(g_ybin, node, flags, op_and, symmetric);
- #else
- return g_ybin(node, flags, op_and);
- #endif
- case en_or:
- #ifdef BITWISE_REDUCE
- bitwise_optimize(node, 0L);
- #endif
- #ifdef VCG
- return g_commute(g_ybin, node, flags, op_or, symmetric);
- #else
- return g_ybin(node, flags, op_or);
- #endif
- case en_xor:
- #ifdef BITWISE_REDUCE
- bitwise_optimize(node, 0L);
- #endif
- #ifdef VCG
- return g_commute(g_xbin, node, flags, op_eor, symmetric);
- #else
- return g_xbin(node, flags, op_eor);
- #endif
- case en_mul:
- /*
- * special optimization possible if there are patterns matching the
- * 68000 mulu, muls instructions. ugly, but it gives a big
- * performance increase
- */
- if (type == bt_long || type == bt_ulong || type == bt_pointer) {
- /* TODO : (char/uchar) * (icon both short & ushort) would be more
- * efficient with muls instead of mulu (ext.w instead of and.w
- * #255)
- */
- if (tst_ushort(node->v.p[0]) && tst_ushort(node->v.p[1])) {
- /*if (node->v.p[0]->esize>2) {*/
- node->v.p[0]->etype = bt_ushort;
- node->v.p[0]->esize = 2;
- /*}
- if (node->v.p[1]->esize>2) {*/
- node->v.p[1]->etype = bt_ushort;
- node->v.p[1]->esize = 2;
- /*}*/
- return g_xmul(node, flags, op_mulu);
- } else if (tst_short(node->v.p[0]) && tst_short(node->v.p[1])) {
- /*if (node->v.p[0]->esize>2) {*/
- node->v.p[0]->etype = bt_short;
- node->v.p[0]->esize = 2;
- /*}
- if (node->v.p[1]->esize>2) {*/
- node->v.p[1]->etype = bt_short;
- node->v.p[1]->esize = 2;
- /*}*/
- return g_xmul(node, flags, op_muls);
- }
- }
- return g_mul(node, flags);
- case en_div:
- return g_div(node, flags);
- case en_mod:
- return g_mod(node, flags);
- case en_lsh:
- return g_shift(node, flags, op_lsl);
- case en_rsh:
- if (type==bt_ulong || type==bt_ushort || type==bt_uchar)
- return g_shift(node, flags, op_lsr);
- else
- return g_shift(node, flags, op_asr);
- case en_asadd:
- return g_asadd(node, flags, op_add);
- case en_assub:
- return g_asadd(node, flags, op_sub);
- case en_asand:
- return g_aslogic(node, flags, op_and);
- case en_asor:
- return g_aslogic(node, flags, op_or);
- case en_aslsh:
- return g_asshift(node, flags, op_lsl);
- case en_asrsh:
- if (type==bt_ulong || type==bt_ushort || type==bt_uchar)
- return g_asshift(node, flags, op_lsr);
- else
- return g_asshift(node, flags, op_asr);
- case en_asmul:
- return g_asmul(node, flags);
- case en_asdiv:
- return g_asdiv(node, flags);
- case en_asmod:
- return g_asmod(node, flags);
- case en_asxor:
- return g_asxor(node, flags);
- case en_assign:
- return g_assign(node, flags);
- case en_ainc:
- return g_aincdec(node, flags, op_add);
- case en_adec:
- return g_aincdec(node, flags, op_sub);
- case en_land:
- case en_lor:
- case en_eq:
- case en_ne:
- case en_lt:
- case en_le:
- case en_gt:
- case en_ge:
- case en_not:
- #ifndef ALTERNATE_HOOK
- lab0 = nxtlabel();
- lab1 = nxtlabel();
- falsejp(node, lab0);
- ap1 = temp_data();
- g_code(op_moveq, 0, mk_immed(1l), ap1);
- g_code(op_bra, 0, mk_label(lab1), NIL_AMODE);
- g_label(lab0);
- g_code(op_moveq, 0, mk_immed(0l), ap1);
- g_label(lab1);
- #else
- lab0 = nxtlabel();
- ap1 = temp_data();
- g_code(op_moveq, 0, mk_immed(0l), ap1);
- falsejp(node, lab0);
- g_code(op_moveq, 0, mk_immed(1l), ap1);
- g_label(lab0);
- #endif
- return mk_legal(ap1, flags, size);
- case en_cond:
- return g_hook(node, flags);
- case en_void:
- freeop(g_expr(node->v.p[0], F_ALL | F_SRCOP | F_NOVALUE));
- return g_expr(node->v.p[1], flags);
- case en_fcall:
- return g_fcall(node, flags);
- case en_alloca:
- return mk_legal(g_alloca(node), flags, 4);
- case en_cast:
- /*
- * On the 68000, suppress all casts between any of
- * long, unsigned long, pointer
- */
- if (type == bt_pointer || type == bt_long || type == bt_ulong) {
- type = node->v.p[0]->etype;
- if (type == bt_pointer || type == bt_long || type == bt_ulong)
- return g_expr(node->v.p[0], flags);
- }
- /*
- * The cast really results in some work
- */
- #ifdef G_CAST2
- return g_cast2(node->v.p[0], node->etype, flags);
- #else
- return g_cast(g_expr(node->v.p[0], F_ALL | F_SRCOP | F_GCAST),
- node->v.p[0]->etype,
- node->etype, flags);
- #endif
- case en_deref:
- /*
- * The cases where this node occurs are handled automatically:
- * g_assign and g_fcall return a pointer to a structure rather than a
- * structure.
- */
- return g_expr(node->v.p[0], flags);
- case en_compound:
- return g_compound(node->v.st, flags);
- default:
- uerr(ERR_OTH,"debug: node=$%lx, nodetype=%d, etype=%d, esize=%d",node,node->nodetype,node->etype,node->esize);
- ierr(G_EXPR,2);
- /* NOTREACHED */
- return 0; // make the compiler happy
- }
- }
- extern struct enode *regexp[REGEXP_SIZE];
- int tst_ushort(struct enode *node) {
- /*
- * tests if node is a integer constant falling in the range of uns. short or
- * if node is cast from uns. short, uns. char or char.
- */
- enum(e_bt) type;
- if (node->nodetype == en_icon && 0 <= node->v.i && node->v.i <= 65535)
- return 1;
- if (node->nodetype == en_tempref) /* because it could be something
- like a constant in a register */
- return tst_ushort(regexp[reg_t_to_regexp(node->v.i)]);
- if (node->nodetype == en_cast) {
- type = node->v.p[0]->etype;
- if (type == bt_ushort || type == bt_uchar || type == bt_char)
- return 1;
- }
- return 0;
- }
- int tst_short(struct enode *node) {
- /*
- * tests if node is a integer constant falling in the range of short or if
- * node is cast from signed or unsigned short.
- */
- enum(e_bt) type;
- if (node->nodetype == en_icon && -32768 <= node->v.i && node->v.i <= 32767)
- return 1;
- if (node->nodetype == en_tempref) /* because it could be something
- like a constant in a register */
- return tst_short(regexp[reg_t_to_regexp(node->v.i)]);
- if (node->nodetype == en_cast) {
- type = node->v.p[0]->etype;
- if (type == bt_short || type == bt_ushort
- || type == bt_char || type == bt_uchar)
- return 1;
- }
- return 0;
- }
- int tst_const(struct enode *node) {
- /*
- * tests if it is a constant node, that means either en_icon, en_nacon or
- * en_labcon, or sums or differences of such nodes
- */
- enum(e_node) typ1 = node->nodetype;
- enum(e_node) typ2;
- if (typ1 == en_icon || typ1 == en_nacon || typ1 == en_labcon
- || typ1 == en_fcon)
- return 1;
- if (typ1 == en_add || typ1 == en_sub) {
- typ1 = node->v.p[0]->nodetype;
- typ2 = node->v.p[1]->nodetype;
- if (((typ1 == en_nacon || typ1 == en_labcon) && typ2 == en_icon) ||
- ((typ2 == en_nacon || typ2 == en_labcon) && typ1 == en_icon))
- return 1;
- }
- return 0;
- }
- static int g_compare(struct enode *node) {
- /*
- * generate code to do a comparison of the two operands of node. returns 1 if
- * it was an unsigned comparison
- */
- struct amode *ap1, *ap2, *ap3;
- #ifndef NOFLOAT
- long i;
- #endif
- switch (node->v.p[0]->etype) {
- case bt_uchar:
- case bt_char:
- case bt_ushort:
- case bt_short:
- case bt_pointer:
- case bt_long:
- case bt_ulong:
- ap2 = g_expr(node->v.p[1], F_ALL | F_SRCOP);
- /* We want to handle the special case 'tst.w pcrel_variable' smoothly,
- * which is why we set F_SRCOP in the latter
- * We will unset it later on. */
- if (ap2->mode == am_immed)
- ap1 = g_expr(node->v.p[0], (F_ALL & ~F_IMMED) | F_SRCOP);
- else
- ap1 = g_expr(node->v.p[0], F_AREG | F_DREG);
- validate(ap2);
- /*if (ap1->mode == am_direct
- && (ap->offset->nodetype == en_nacon
- || ap->offset->nodetype == en_labcon)
- #ifdef AS
- && !external(ap->offset->v.enlab)
- #else
- #ifdef PC
- && ((long)ap->offset->v.ensp>0x1000 ? internal(ap->offset->v.ensp) : 1)
- #endif
- #endif
- )
- t*/
- /*
- * sorry, no tst.l An on the 68000, but we can move to a data
- * register if one is free
- * As there is no tst.l myval(pc), we can do it this way for am_direct's too.
- */
- if ((ap1->mode == am_areg || ap1->mode==am_direct)
- && node->v.p[1]->nodetype == en_icon
- && node->v.p[1]->v.i == 0 && free_data()) {
- ap3 = temp_data();
- g_code(op_move, node->v.p[0]->esize, ap1, ap3);
- /* tst.l ap3 not needed */
- freeop(ap3);
- } else {
- /* the only case where the following != nop is when ap2->mode==am_immed and ap1->mode==am_direct */
- ap1=mk_legal(ap1, F_ALL, node->v.p[0]->esize);
- g_code(op_cmp, (int) node->v.p[0]->esize, ap2, ap1);
- }
- freeop(ap1);
- freeop(ap2);
- if (node->v.p[0]->etype == bt_char ||
- node->v.p[0]->etype == bt_short ||
- node->v.p[0]->etype == bt_long)
- return 0;
- return 1;
- case bt_struct:
- ap1 = g_expr(node->v.p[1], F_AREG | F_VOL);
- ap2 = g_expr(node->v.p[0], F_AREG | F_VOL);
- validate(ap1); {
- int lab=nxtlabel();
- ap1 = copy_addr(ap1);
- ap2 = copy_addr(ap2);
- ap2->mode=ap1->mode=am_ainc;
- ap3 = temp_data();
- freeop(ap3);
- g_code(op_move,2,mk_immed((node->esize-1)>>1),ap3);
- g_label(lab);
- g_code(op_cmp,2,ap1,ap2);
- g_code(op_dbne,0,ap3,mk_label(lab));
- }
- freeop(ap2);
- freeop(ap1);
- return 1;
- #ifndef NOFLOAT
- case bt_float:
- #ifdef DOUBLE
- case bt_double:
- #endif
- #ifndef BCDFLT
- if (node->v.p[1]->nodetype == en_fcon && node->v.p[1]->v.f==0) {
- node->etype = bt_long; /* no conversion func call (raw cast) */
- node=mk_node(en_cast,node,NIL_ENODE);
- node->etype = bt_char;
- node->esize = 1;
- ap1 = g_expr(node, F_DALT);
- g_code(op_tst, (int) node->esize, ap1, NIL_AMODE);
- freeop(ap1);
- } else {
- #endif
- temp_inv();
- i = push_param(node->v.p[1]);
- i += push_param(node->v.p[0]);
- #ifndef BCDFLT
- call_library(str(ffpcmp));
- #else
- call_library("__cmpbf2");
- #endif
- g_code(op_add, 4, mk_immed((long) i), mk_reg(STACKPTR));
- return 0;
- #ifndef BCDFLT
- }
- #endif
- #endif
- }
- ierr(G_COMPARE,1);
- /* NOTREACHED */
- return 0; // make the compiler happy
- }
- #ifndef NOBCDFLT
- readonly struct enode __bcd_zero__value={
- en_labcon,
- #ifdef DOUBLE
- bt_double,
- #else
- bt_float,
- #endif
- 10
- };
- #ifdef AS
- #define bcd_zero (pchsearch("__bcd_zero",PCHS_ADD), \
- __bcd_zero__value.v.enlab=label("__bcd_zero"), \
- &__bcd_zero__value)
- #else
- #define bcd_zero (__bcd_zero__value.v.ensp="__bcd_zero", &__bcd_zero__value)
- #endif
- #endif
- void truejp(struct enode *node, unsigned int lab) {
- /*
- * generate a jump to lab if the node passed evaluates to a true condition.
- */
- struct amode *ap;
- unsigned int lab0;
- if (node == 0)
- ierr(TRUEJP,1);
- if (node->nodetype == en_icon) {
- if (node->v.i)
- g_code(op_bra, 0, mk_label(lab), NIL_AMODE);
- return;
- }
- opt_compare(node);
- switch (node->nodetype) {
- case en_eq:
- (void) g_compare(node);
- g_code(op_beq, 0, mk_label(lab), NIL_AMODE);
- break;
- case en_ne:
- (void) g_compare(node);
- g_code(op_bne, 0, mk_label(lab), NIL_AMODE);
- break;
- case en_lt:
- case en_le:
- case en_gt:
- case en_ge:
- {
- int n=(en_ge-node->nodetype)*2+op_bhs;
- g_code(g_compare(node)?n:++n, 0, mk_label(lab), NIL_AMODE);
- break;
- }
- case en_fieldref:
- {
- struct enode *ep,*ep2;
- ep=mk_node(en_ref, node->v.p[0], (struct enode *) NIL_AMODE);
- ep->esize=node->esize;
- ep->etype=node->etype;
- ep2=mk_icon(((1<<node->bit_width)-1) <<
- ((node->esize<<3)-node->bit_offset-node->bit_width));
- ep2->esize=node->esize;
- ep2->etype=node->etype;
- ep=mk_node(en_and,ep,ep2);
- ep->esize=node->esize;
- ep->etype=node->etype;
- truejp(ep, lab);
- break;
- }
- /* case en_lt:
- g_compare(node) ?
- g_code(op_blo, 0, mk_label(lab), NIL_AMODE) :
- g_code(op_blt, 0, mk_label(lab), NIL_AMODE);
- break;
- case en_le:
- g_compare(node) ?
- g_code(op_bls, 0, mk_label(lab), NIL_AMODE) :
- g_code(op_ble, 0, mk_label(lab), NIL_AMODE);
- break;
- case en_gt:
- g_compare(node) ?
- g_code(op_bhi, 0, mk_label(lab), NIL_AMODE) :
- g_code(op_bgt, 0, mk_label(lab), NIL_AMODE);
- break;
- case en_ge:
- g_compare(node) ?
- g_code(op_bhs, 0, mk_label(lab), NIL_AMODE) :
- g_code(op_bge, 0, mk_label(lab), NIL_AMODE);
- break;*/
- case en_land:
- lab0 = nxtlabel();
- falsejp(node->v.p[0], lab0);
- truejp(node->v.p[1], lab);
- g_label(lab0);
- break;
- case en_lor:
- truejp(node->v.p[0], lab);
- truejp(node->v.p[1], lab);
- break;
- case en_not:
- falsejp(node->v.p[0], lab);
- break;
- #ifdef OPTIMIZED_AINCDEC_TEST
- case en_adec:
- // struct amode *lblap = mk_label(lab);
- ap = g_expr(node->v.p[0], F_ALL);
- /* if (ap->mode==am_dreg)
- freeop(ap),
- g_code(op_dbra, 0, ap, lblap);
- else {*/
- g_code(op_sub, (int) node->esize, mk_immed(1), ap);
- freeop(ap);
- g_code(op_bhs, 0, /*lblap*/mk_label(lab), NIL_AMODE);
- /* }*/
- break;
- #endif
- case en_and:
- /*#ifdef PC*/
- #define is_powerof2(x) (((x)<<1)==((x)^((x)-1))+1)
- /*#else
- #define is_powerof2(x) ({int __x=x;((__x)<<1)==((__x)^((__x)-1))+1;})
- #endif*/
- if (node->v.p[1]->nodetype==en_icon) {
- unsigned long v=node->v.p[1]->v.i;
- if (v>=128/*otherwise moveq is cool enough and faster for dregs*/
- && is_powerof2(v)) {
- ap=g_expr(node->v.p[0],F_DREG|F_MEM);
- g_bitmancode(op_btst,node->v.p[0]->esize,mk_immed(pwrof2(v)),ap);
- freeop(ap);
- g_code(op_bne, 0, mk_label(lab), NIL_AMODE);
- break;
- }
- }
- /* FALL THROUGH */
- default:
- #ifndef NOFLOAT
- if (node->etype == bt_float || node->etype == bt_double) {
- #ifdef DOUBLE
- long i;
- temp_inv();
- i = push_param(node);
- call_library(".fptst"); // obsolete
- /* The pop-off does not change the condition codes */
- g_code(op_add, 4, mk_immed((long) i), mk_reg(STACKPTR));
- } else {
- #else
- #ifndef BCDFLT
- node->etype = bt_long; /* no conversion func call (raw cast) */
- node=mk_node(en_cast,node,NIL_ENODE);
- node->etype = bt_char;
- node->esize = 1;
- }
- {
- #else
- g_compare(mk_node(en_void,node,bcd_zero));
- } else {
- #endif
- #endif
- #else
- {
- #endif
- ap = g_expr(node, F_DALT|F_SRCOP);
- if (ap->mode==am_direct && free_data()) {
- struct amode *ap2 = temp_data();
- g_code(op_move, (int) node->esize, ap, ap2);
- g_code(op_tst, (int) node->esize, ap2, NIL_AMODE);
- freeop(ap2);
- } else
- g_code(op_tst, (int) node->esize, ap, NIL_AMODE);
- freeop(ap);
- }
- g_code(op_bne, 0, mk_label(lab), NIL_AMODE);
- break;
- }
- }
- void falsejp(struct enode *node, unsigned int lab) {
- /*
- * generate code to execute a jump to lab if the expression passed is
- * false.
- */
- struct amode *ap;
- unsigned int lab0;
- if (node == 0)
- ierr(FALSEJP,1);
- if (node->nodetype == en_icon) {
- if (!node->v.i)
- g_code(op_bra, 0, mk_label(lab), NIL_AMODE);
- return;
- }
- opt_compare(node);
- switch (node->nodetype) {
- case en_eq:
- (void) g_compare(node);
- g_code(op_bne, 0, mk_label(lab), NIL_AMODE);
- break;
- case en_ne:
- (void) g_compare(node);
- g_code(op_beq, 0, mk_label(lab), NIL_AMODE);
- break;
- case en_lt:
- case en_le:
- case en_gt:
- case en_ge:
- {
- int n=(node->nodetype-en_lt)*2+op_bhs;
- g_code(g_compare(node)?n:++n, 0, mk_label(lab), NIL_AMODE);
- break;
- }
- case en_fieldref:
- {
- struct enode *ep,*ep2;
- ep=mk_node(en_ref, node->v.p[0], (struct enode *) NIL_AMODE);
- ep->esize=node->esize;
- ep->etype=node->etype;
- ep2=mk_icon(((1<<node->bit_width)-1) <<
- ((node->esize<<3)-node->bit_offset-node->bit_width));
- ep2->esize=node->esize;
- ep2->etype=node->etype;
- ep=mk_node(en_and,ep,ep2);
- ep->esize=node->esize;
- ep->etype=node->etype;
- falsejp(ep, lab);
- break;
- }
- /* case en_lt:
- g_compare(node) ?
- g_code(op_bhs, 0, mk_label(lab), NIL_AMODE) :
- g_code(op_bge, 0, mk_label(lab), NIL_AMODE);
- break;
- case en_le:
- g_compare(node) ?
- g_code(op_bhi, 0, mk_label(lab), NIL_AMODE) :
- g_code(op_bgt, 0, mk_label(lab), NIL_AMODE);
- break;
- case en_gt:
- g_compare(node) ?
- g_code(op_bls, 0, mk_label(lab), NIL_AMODE) :
- g_code(op_ble, 0, mk_label(lab), NIL_AMODE);
- break;
- case en_ge:
- g_compare(node) ?
- g_code(op_blo, 0, mk_label(lab), NIL_AMODE) :
- g_code(op_blt, 0, mk_label(lab), NIL_AMODE);
- break;*/
- case en_land:
- falsejp(node->v.p[0], lab);
- falsejp(node->v.p[1], lab);
- break;
- case en_lor:
- lab0 = nxtlabel();
- truejp(node->v.p[0], lab0);
- falsejp(node->v.p[1], lab);
- g_label(lab0);
- break;
- case en_not:
- truejp(node->v.p[0], lab);
- break;
- #ifdef OPTIMIZED_AINCDEC_TEST
- case en_adec:
- ap = g_expr(node->v.p[0], F_ALL);
- g_code(op_sub, (int) node->esize, mk_immed(1), ap);
- freeop(ap);
- g_code(op_blo, 0, mk_label(lab), NIL_AMODE);
- break;
- #endif
- case en_and:
- if (node->v.p[1]->nodetype==en_icon) {
- unsigned long v=node->v.p[1]->v.i;
- if (v>=128/*otherwise moveq is cool enough and faster for dregs*/
- && is_powerof2(v)) {
- ap=g_expr(node->v.p[0],F_DREG|F_MEM);
- g_bitmancode(op_btst,node->v.p[0]->esize,mk_immed(pwrof2(v)),ap);
- freeop(ap);
- g_code(op_beq, 0, mk_label(lab), NIL_AMODE);
- break;
- }
- }
- /* FALL THROUGH */
- default:
- #ifndef NOFLOAT
- if (node->etype == bt_float || node->etype == bt_double) {
- #ifdef DOUBLE
- long i;
- temp_inv();
- i = push_param(node);
- call_library(".fptst"); // obsolete
- /* The pop-off does not change the condition codes */
- g_code(op_add, 4, mk_immed((long) i), mk_reg(STACKPTR));
- } else {
- #else
- #ifndef BCDFLT
- node->etype = bt_long; /* no conversion func call (raw cast) */
- node=mk_node(en_cast,node,NIL_ENODE);
- node->etype = bt_char;
- node->esize = 1;
- }
- {
- #else
- g_compare(mk_node(en_void,node,bcd_zero));
- } else {
- #endif
- #endif
- #else
- {
- #endif
- ap = g_expr(node, F_DALT|F_SRCOP);
- if (ap->mode==am_direct && free_data()) {
- struct amode *ap2 = temp_data();
- g_code(op_move, (int) node->esize, ap, ap2);
- g_code(op_tst, (int) node->esize, ap2, NIL_AMODE);
- freeop(ap2);
- } else
- g_code(op_tst, (int) node->esize, ap, NIL_AMODE);
- freeop(ap);
- }
- g_code(op_beq, 0, mk_label(lab), NIL_AMODE);
- break;
- }
- }
- void opt_compare(struct enode *node) {
- /* temprefs should be the second operand to a cmp instruction */
- enum(e_node) t = node->nodetype;
- if ((t == en_eq || t == en_ne || t == en_le || t == en_ge
- || t == en_lt || t == en_gt)
- && (node->v.p[1]->nodetype == en_tempref ||
- node->v.p[0]->nodetype == en_icon)) {
- swap_nodes(node);
- /* if you change the operands, change the comparison operator */
- switch (t) {
- case en_le:
- node->nodetype = en_ge;
- break;
- case en_ge:
- node->nodetype = en_le;
- break;
- case en_lt:
- node->nodetype = en_gt;
- break;
- case en_gt:
- node->nodetype = en_lt;
- break;
- }
- }
- }
- #endif /* MC680X0 */
- // vim:ts=4:sw=4
|