12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439 |
- #include "gc.h"
- int xtramodes(Reg*, Adr*);
- void
- peep(void)
- {
- Reg *r, *r1, *r2;
- Prog *p, *p1;
- int t;
- /*
- * complete R structure
- */
- t = 0;
- for(r=firstr; r!=R; r=r1) {
- r1 = r->link;
- if(r1 == R)
- break;
- p = r->prog->link;
- while(p != r1->prog)
- switch(p->as) {
- default:
- r2 = rega();
- r->link = r2;
- r2->link = r1;
- r2->prog = p;
- r2->p1 = r;
- r->s1 = r2;
- r2->s1 = r1;
- r1->p1 = r2;
- r = r2;
- t++;
- case ADATA:
- case AGLOBL:
- case ANAME:
- case ASIGNAME:
- p = p->link;
- }
- }
- loop1:
- t = 0;
- for(r=firstr; r!=R; r=r->link) {
- p = r->prog;
- if(p->as == ASLL || p->as == ASRL || p->as == ASRA) {
- /*
- * elide shift into D_SHIFT operand of subsequent instruction
- */
- if(shiftprop(r)) {
- excise(r);
- t++;
- }
- }
- if(p->as == AMOVW || p->as == AMOVF || p->as == AMOVD)
- if(regtyp(&p->to)) {
- if(p->from.type == D_CONST)
- constprop(&p->from, &p->to, r->s1);
- else if(regtyp(&p->from))
- if(p->from.type == p->to.type) {
- if(copyprop(r)) {
- excise(r);
- t++;
- } else
- if(subprop(r) && copyprop(r)) {
- excise(r);
- t++;
- }
- }
- }
- }
- if(t)
- goto loop1;
- /*
- * look for MOVB x,R; MOVB R,R
- */
- for(r=firstr; r!=R; r=r->link) {
- p = r->prog;
- switch(p->as) {
- default:
- continue;
- case AEOR:
- /*
- * EOR -1,x,y => MVN x,y
- */
- if(p->from.type == D_CONST && p->from.offset == -1) {
- p->as = AMVN;
- p->from.type = D_REG;
- if(p->reg != NREG)
- p->from.reg = p->reg;
- else
- p->from.reg = p->to.reg;
- p->reg = NREG;
- }
- continue;
- case AMOVH:
- case AMOVHU:
- case AMOVB:
- case AMOVBU:
- if(p->to.type != D_REG)
- continue;
- break;
- }
- r1 = r->link;
- if(r1 == R)
- continue;
- p1 = r1->prog;
- if(p1->as != p->as)
- continue;
- if(p1->from.type != D_REG || p1->from.reg != p->to.reg)
- continue;
- if(p1->to.type != D_REG || p1->to.reg != p->to.reg)
- continue;
- excise(r1);
- }
- for(r=firstr; r!=R; r=r->link) {
- p = r->prog;
- switch(p->as) {
- case AMOVW:
- case AMOVB:
- case AMOVBU:
- if(p->from.type == D_OREG && p->from.offset == 0)
- xtramodes(r, &p->from);
- else if(p->to.type == D_OREG && p->to.offset == 0)
- xtramodes(r, &p->to);
- else
- continue;
- break;
- case ACMP:
- /*
- * elide CMP $0,x if calculation of x can set condition codes
- */
- if(p->from.type != D_CONST || p->from.offset != 0)
- continue;
- r2 = r->s1;
- if(r2 == R)
- continue;
- t = r2->prog->as;
- switch(t) {
- default:
- continue;
- case ABEQ:
- case ABNE:
- case ABMI:
- case ABPL:
- break;
- case ABGE:
- t = ABPL;
- break;
- case ABLT:
- t = ABMI;
- break;
- case ABHI:
- t = ABNE;
- break;
- case ABLS:
- t = ABEQ;
- break;
- }
- r1 = r;
- do
- r1 = uniqp(r1);
- while (r1 != R && r1->prog->as == ANOP);
- if(r1 == R)
- continue;
- p1 = r1->prog;
- if(p1->to.type != D_REG)
- continue;
- if(p1->to.reg != p->reg)
- if(!(p1->as == AMOVW && p1->from.type == D_REG && p1->from.reg == p->reg))
- continue;
- switch(p1->as) {
- default:
- continue;
- case AMOVW:
- if(p1->from.type != D_REG)
- continue;
- case AAND:
- case AEOR:
- case AORR:
- case ABIC:
- case AMVN:
- case ASUB:
- case ARSB:
- case AADD:
- case AADC:
- case ASBC:
- case ARSC:
- break;
- }
- p1->scond |= C_SBIT;
- r2->prog->as = t;
- excise(r);
- continue;
- }
- }
- predicate();
- }
- void
- excise(Reg *r)
- {
- Prog *p;
- p = r->prog;
- p->as = ANOP;
- p->scond = zprog.scond;
- p->from = zprog.from;
- p->to = zprog.to;
- p->reg = zprog.reg; /**/
- }
- Reg*
- uniqp(Reg *r)
- {
- Reg *r1;
- r1 = r->p1;
- if(r1 == R) {
- r1 = r->p2;
- if(r1 == R || r1->p2link != R)
- return R;
- } else
- if(r->p2 != R)
- return R;
- return r1;
- }
- Reg*
- uniqs(Reg *r)
- {
- Reg *r1;
- r1 = r->s1;
- if(r1 == R) {
- r1 = r->s2;
- if(r1 == R)
- return R;
- } else
- if(r->s2 != R)
- return R;
- return r1;
- }
- int
- regtyp(Adr *a)
- {
- if(a->type == D_REG)
- return 1;
- if(a->type == D_FREG)
- return 1;
- return 0;
- }
- /*
- * the idea is to substitute
- * one register for another
- * from one MOV to another
- * MOV a, R0
- * ADD b, R0 / no use of R1
- * MOV R0, R1
- * would be converted to
- * MOV a, R1
- * ADD b, R1
- * MOV R1, R0
- * hopefully, then the former or latter MOV
- * will be eliminated by copy propagation.
- */
- int
- subprop(Reg *r0)
- {
- Prog *p;
- Adr *v1, *v2;
- Reg *r;
- int t;
- p = r0->prog;
- v1 = &p->from;
- if(!regtyp(v1))
- return 0;
- v2 = &p->to;
- if(!regtyp(v2))
- return 0;
- for(r=uniqp(r0); r!=R; r=uniqp(r)) {
- if(uniqs(r) == R)
- break;
- p = r->prog;
- switch(p->as) {
- case ABL:
- return 0;
- case ACMP:
- case ACMN:
- case AADD:
- case ASUB:
- case ARSB:
- case ASLL:
- case ASRL:
- case ASRA:
- case AORR:
- case AAND:
- case AEOR:
- case AMUL:
- case ADIV:
- case ADIVU:
- case ACMPF:
- case ACMPD:
- case AADDD:
- case AADDF:
- case ASUBD:
- case ASUBF:
- case AMULD:
- case AMULF:
- case ADIVD:
- case ADIVF:
- if(p->to.type == v1->type)
- if(p->to.reg == v1->reg) {
- if(p->reg == NREG)
- p->reg = p->to.reg;
- goto gotit;
- }
- break;
- case AMOVF:
- case AMOVD:
- case AMOVW:
- if(p->to.type == v1->type)
- if(p->to.reg == v1->reg)
- goto gotit;
- break;
- case AMOVM:
- t = 1<<v2->reg;
- if((p->from.type == D_CONST && (p->from.offset&t)) ||
- (p->to.type == D_CONST && (p->to.offset&t)))
- return 0;
- break;
- }
- if(copyau(&p->from, v2) ||
- copyau1(p, v2) ||
- copyau(&p->to, v2))
- break;
- if(copysub(&p->from, v1, v2, 0) ||
- copysub1(p, v1, v2, 0) ||
- copysub(&p->to, v1, v2, 0))
- break;
- }
- return 0;
- gotit:
- copysub(&p->to, v1, v2, 1);
- if(debug['P']) {
- print("gotit: %D->%D\n%P", v1, v2, r->prog);
- if(p->from.type == v2->type)
- print(" excise");
- print("\n");
- }
- for(r=uniqs(r); r!=r0; r=uniqs(r)) {
- p = r->prog;
- copysub(&p->from, v1, v2, 1);
- copysub1(p, v1, v2, 1);
- copysub(&p->to, v1, v2, 1);
- if(debug['P'])
- print("%P\n", r->prog);
- }
- t = v1->reg;
- v1->reg = v2->reg;
- v2->reg = t;
- if(debug['P'])
- print("%P last\n", r->prog);
- return 1;
- }
- /*
- * The idea is to remove redundant copies.
- * v1->v2 F=0
- * (use v2 s/v2/v1/)*
- * set v1 F=1
- * use v2 return fail
- * -----------------
- * v1->v2 F=0
- * (use v2 s/v2/v1/)*
- * set v1 F=1
- * set v2 return success
- */
- int
- copyprop(Reg *r0)
- {
- Prog *p;
- Adr *v1, *v2;
- Reg *r;
- p = r0->prog;
- v1 = &p->from;
- v2 = &p->to;
- if(copyas(v1, v2))
- return 1;
- for(r=firstr; r!=R; r=r->link)
- r->active = 0;
- return copy1(v1, v2, r0->s1, 0);
- }
- int
- copy1(Adr *v1, Adr *v2, Reg *r, int f)
- {
- int t;
- Prog *p;
- if(r->active) {
- if(debug['P'])
- print("act set; return 1\n");
- return 1;
- }
- r->active = 1;
- if(debug['P'])
- print("copy %D->%D f=%d\n", v1, v2, f);
- for(; r != R; r = r->s1) {
- p = r->prog;
- if(debug['P'])
- print("%P", p);
- if(!f && uniqp(r) == R) {
- f = 1;
- if(debug['P'])
- print("; merge; f=%d", f);
- }
- t = copyu(p, v2, A);
- switch(t) {
- case 2: /* rar, cant split */
- if(debug['P'])
- print("; %Drar; return 0\n", v2);
- return 0;
- case 3: /* set */
- if(debug['P'])
- print("; %Dset; return 1\n", v2);
- return 1;
- case 1: /* used, substitute */
- case 4: /* use and set */
- if(f) {
- if(!debug['P'])
- return 0;
- if(t == 4)
- print("; %Dused+set and f=%d; return 0\n", v2, f);
- else
- print("; %Dused and f=%d; return 0\n", v2, f);
- return 0;
- }
- if(copyu(p, v2, v1)) {
- if(debug['P'])
- print("; sub fail; return 0\n");
- return 0;
- }
- if(debug['P'])
- print("; sub%D/%D", v2, v1);
- if(t == 4) {
- if(debug['P'])
- print("; %Dused+set; return 1\n", v2);
- return 1;
- }
- break;
- }
- if(!f) {
- t = copyu(p, v1, A);
- if(!f && (t == 2 || t == 3 || t == 4)) {
- f = 1;
- if(debug['P'])
- print("; %Dset and !f; f=%d", v1, f);
- }
- }
- if(debug['P'])
- print("\n");
- if(r->s2)
- if(!copy1(v1, v2, r->s2, f))
- return 0;
- }
- return 1;
- }
- /*
- * The idea is to remove redundant constants.
- * $c1->v1
- * ($c1->v2 s/$c1/v1)*
- * set v1 return
- * The v1->v2 should be eliminated by copy propagation.
- */
- void
- constprop(Adr *c1, Adr *v1, Reg *r)
- {
- Prog *p;
- if(debug['C'])
- print("constprop %D->%D\n", c1, v1);
- for(; r != R; r = r->s1) {
- p = r->prog;
- if(debug['C'])
- print("%P", p);
- if(uniqp(r) == R) {
- if(debug['C'])
- print("; merge; return\n");
- return;
- }
- if(p->as == AMOVW && copyas(&p->from, c1)) {
- if(debug['C'])
- print("; sub%D/%D", &p->from, v1);
- p->from = *v1;
- } else if(copyu(p, v1, A) > 1) {
- if(debug['C'])
- print("; %Dset; return\n", v1);
- return;
- }
- if(debug['C'])
- print("\n");
- if(r->s2)
- constprop(c1, v1, r->s2);
- }
- }
- /*
- * ASLL x,y,w
- * .. (not use w, not set x y w)
- * AXXX w,a,b (a != w)
- * .. (not use w)
- * (set w)
- * ----------- changed to
- * ..
- * AXXX (x<<y),a,b
- * ..
- */
- #define FAIL(msg) { if(debug['H']) print("\t%s; FAILURE\n", msg); return 0; }
- int
- shiftprop(Reg *r)
- {
- Reg *r1;
- Prog *p, *p1, *p2;
- int n, o;
- Adr a;
- p = r->prog;
- if(p->to.type != D_REG)
- FAIL("BOTCH: result not reg");
- n = p->to.reg;
- a = zprog.from;
- if(p->reg != NREG && p->reg != p->to.reg) {
- a.type = D_REG;
- a.reg = p->reg;
- }
- if(debug['H'])
- print("shiftprop\n%P", p);
- r1 = r;
- for(;;) {
- /* find first use of shift result; abort if shift operands or result are changed */
- r1 = uniqs(r1);
- if(r1 == R)
- FAIL("branch");
- if(uniqp(r1) == R)
- FAIL("merge");
- p1 = r1->prog;
- if(debug['H'])
- print("\n%P", p1);
- switch(copyu(p1, &p->to, A)) {
- case 0: /* not used or set */
- if((p->from.type == D_REG && copyu(p1, &p->from, A) > 1) ||
- (a.type == D_REG && copyu(p1, &a, A) > 1))
- FAIL("args modified");
- continue;
- case 3: /* set, not used */
- FAIL("BOTCH: noref");
- }
- break;
- }
- /* check whether substitution can be done */
- switch(p1->as) {
- default:
- FAIL("non-dpi");
- case AAND:
- case AEOR:
- case AADD:
- case AADC:
- case AORR:
- case ASUB:
- case ARSB:
- case ASBC:
- case ARSC:
- if(p1->reg == n || (p1->reg == NREG && p1->to.type == D_REG && p1->to.reg == n)) {
- if(p1->from.type != D_REG)
- FAIL("can't swap");
- p1->reg = p1->from.reg;
- p1->from.reg = n;
- switch(p1->as) {
- case ASUB:
- p1->as = ARSB;
- break;
- case ARSB:
- p1->as = ASUB;
- break;
- case ASBC:
- p1->as = ARSC;
- break;
- case ARSC:
- p1->as = ASBC;
- break;
- }
- if(debug['H'])
- print("\t=>%P", p1);
- }
- case ABIC:
- case ACMP:
- case ACMN:
- if(p1->reg == n)
- FAIL("can't swap");
- if(p1->reg == NREG && p1->to.reg == n)
- FAIL("shift result used twice");
- case AMVN:
- if(p1->from.type == D_SHIFT)
- FAIL("shift result used in shift");
- if(p1->from.type != D_REG || p1->from.reg != n)
- FAIL("BOTCH: where is it used?");
- break;
- }
- /* check whether shift result is used subsequently */
- p2 = p1;
- if(p1->to.reg != n)
- for (;;) {
- r1 = uniqs(r1);
- if(r1 == R)
- FAIL("inconclusive");
- p1 = r1->prog;
- if(debug['H'])
- print("\n%P", p1);
- switch(copyu(p1, &p->to, A)) {
- case 0: /* not used or set */
- continue;
- case 3: /* set, not used */
- break;
- default:/* used */
- FAIL("reused");
- }
- break;
- }
- /* make the substitution */
- p2->from.type = D_SHIFT;
- p2->from.reg = NREG;
- o = p->reg;
- if(o == NREG)
- o = p->to.reg;
- switch(p->from.type){
- case D_CONST:
- o |= (p->from.offset&0x1f)<<7;
- break;
- case D_REG:
- o |= (1<<4) | (p->from.reg<<8);
- break;
- }
- switch(p->as){
- case ASLL:
- o |= 0<<5;
- break;
- case ASRL:
- o |= 1<<5;
- break;
- case ASRA:
- o |= 2<<5;
- break;
- }
- p2->from.offset = o;
- if(debug['H'])
- print("\t=>%P\tSUCCEED\n", p2);
- return 1;
- }
- Reg*
- findpre(Reg *r, Adr *v)
- {
- Reg *r1;
- for(r1=uniqp(r); r1!=R; r=r1,r1=uniqp(r)) {
- if(uniqs(r1) != r)
- return R;
- switch(copyu(r1->prog, v, A)) {
- case 1: /* used */
- case 2: /* read-alter-rewrite */
- return R;
- case 3: /* set */
- case 4: /* set and used */
- return r1;
- }
- }
- return R;
- }
- Reg*
- findinc(Reg *r, Reg *r2, Adr *v)
- {
- Reg *r1;
- Prog *p;
- for(r1=uniqs(r); r1!=R && r1!=r2; r=r1,r1=uniqs(r)) {
- if(uniqp(r1) != r)
- return R;
- switch(copyu(r1->prog, v, A)) {
- case 0: /* not touched */
- continue;
- case 4: /* set and used */
- p = r1->prog;
- if(p->as == AADD)
- if(p->from.type == D_CONST)
- if(p->from.offset > -4096 && p->from.offset < 4096)
- return r1;
- default:
- return R;
- }
- }
- return R;
- }
- int
- nochange(Reg *r, Reg *r2, Prog *p)
- {
- Adr a[3];
- int i, n;
- if(r == r2)
- return 1;
- n = 0;
- if(p->reg != NREG && p->reg != p->to.reg) {
- a[n].type = D_REG;
- a[n++].reg = p->reg;
- }
- switch(p->from.type) {
- case D_SHIFT:
- a[n].type = D_REG;
- a[n++].reg = p->from.offset&0xf;
- case D_REG:
- a[n].type = D_REG;
- a[n++].reg = p->from.reg;
- }
- if(n == 0)
- return 1;
- for(; r!=R && r!=r2; r=uniqs(r)) {
- p = r->prog;
- for(i=0; i<n; i++)
- if(copyu(p, &a[i], A) > 1)
- return 0;
- }
- return 1;
- }
- int
- findu1(Reg *r, Adr *v)
- {
- for(; r != R; r = r->s1) {
- if(r->active)
- return 0;
- r->active = 1;
- switch(copyu(r->prog, v, A)) {
- case 1: /* used */
- case 2: /* read-alter-rewrite */
- case 4: /* set and used */
- return 1;
- case 3: /* set */
- return 0;
- }
- if(r->s2)
- if (findu1(r->s2, v))
- return 1;
- }
- return 0;
- }
- int
- finduse(Reg *r, Adr *v)
- {
- Reg *r1;
- for(r1=firstr; r1!=R; r1=r1->link)
- r1->active = 0;
- return findu1(r, v);
- }
- int
- xtramodes(Reg *r, Adr *a)
- {
- Reg *r1, *r2, *r3;
- Prog *p, *p1;
- Adr v;
- p = r->prog;
- if(debug['h'] && p->as == AMOVB && p->from.type == D_OREG) /* byte load */
- return 0;
- v = *a;
- v.type = D_REG;
- r1 = findpre(r, &v);
- if(r1 != R) {
- p1 = r1->prog;
- if(p1->to.type == D_REG && p1->to.reg == v.reg)
- switch(p1->as) {
- case AADD:
- if(p1->from.type == D_REG ||
- (p1->from.type == D_SHIFT && (p1->from.offset&(1<<4)) == 0 &&
- (p->as != AMOVB || (a == &p->from && (p1->from.offset&~0xf) == 0))) ||
- (p1->from.type == D_CONST &&
- p1->from.offset > -4096 && p1->from.offset < 4096))
- if(nochange(uniqs(r1), r, p1)) {
- if(a != &p->from || v.reg != p->to.reg)
- if (finduse(r->s1, &v)) {
- if(p1->reg == NREG || p1->reg == v.reg)
- /* pre-indexing */
- p->scond |= C_WBIT;
- else return 0;
- }
- switch (p1->from.type) {
- case D_REG:
- /* register offset */
- a->type = D_SHIFT;
- a->offset = p1->from.reg;
- break;
- case D_SHIFT:
- /* scaled register offset */
- a->type = D_SHIFT;
- case D_CONST:
- /* immediate offset */
- a->offset = p1->from.offset;
- break;
- }
- if(p1->reg != NREG)
- a->reg = p1->reg;
- excise(r1);
- return 1;
- }
- break;
- case AMOVW:
- if(p1->from.type == D_REG)
- if((r2 = findinc(r1, r, &p1->from)) != R) {
- for(r3=uniqs(r2); r3->prog->as==ANOP; r3=uniqs(r3))
- ;
- if(r3 == r) {
- /* post-indexing */
- p1 = r2->prog;
- a->reg = p1->to.reg;
- a->offset = p1->from.offset;
- p->scond |= C_PBIT;
- if(!finduse(r, &r1->prog->to))
- excise(r1);
- excise(r2);
- return 1;
- }
- }
- break;
- }
- }
- if(a != &p->from || a->reg != p->to.reg)
- if((r1 = findinc(r, R, &v)) != R) {
- /* post-indexing */
- p1 = r1->prog;
- a->offset = p1->from.offset;
- p->scond |= C_PBIT;
- excise(r1);
- return 1;
- }
- return 0;
- }
- /*
- * return
- * 1 if v only used (and substitute),
- * 2 if read-alter-rewrite
- * 3 if set
- * 4 if set and used
- * 0 otherwise (not touched)
- */
- int
- copyu(Prog *p, Adr *v, Adr *s)
- {
- switch(p->as) {
- default:
- if(debug['P'])
- print(" (???)");
- return 2;
- case AMOVM:
- if(v->type != D_REG)
- return 0;
- if(p->from.type == D_CONST) { /* read reglist, read/rar */
- if(s != A) {
- if(p->from.offset&(1<<v->reg))
- return 1;
- if(copysub(&p->to, v, s, 1))
- return 1;
- return 0;
- }
- if(copyau(&p->to, v)) {
- if(p->scond&C_WBIT)
- return 2;
- return 1;
- }
- if(p->from.offset&(1<<v->reg))
- return 1;
- } else { /* read/rar, write reglist */
- if(s != A) {
- if(p->to.offset&(1<<v->reg))
- return 1;
- if(copysub(&p->from, v, s, 1))
- return 1;
- return 0;
- }
- if(copyau(&p->from, v)) {
- if(p->scond&C_WBIT)
- return 2;
- if(p->to.offset&(1<<v->reg))
- return 4;
- return 1;
- }
- if(p->to.offset&(1<<v->reg))
- return 3;
- }
- return 0;
-
- case ANOP: /* read, write */
- case AMOVW:
- case AMOVF:
- case AMOVD:
- case AMOVH:
- case AMOVHU:
- case AMOVB:
- case AMOVBU:
- case AMOVDW:
- case AMOVWD:
- case AMOVFD:
- case AMOVDF:
- if(p->scond&(C_WBIT|C_PBIT))
- if(v->type == D_REG) {
- if(p->from.type == D_OREG || p->from.type == D_SHIFT) {
- if(p->from.reg == v->reg)
- return 2;
- } else {
- if(p->to.reg == v->reg)
- return 2;
- }
- }
- if(s != A) {
- if(copysub(&p->from, v, s, 1))
- return 1;
- if(!copyas(&p->to, v))
- if(copysub(&p->to, v, s, 1))
- return 1;
- return 0;
- }
- if(copyas(&p->to, v)) {
- if(copyau(&p->from, v))
- return 4;
- return 3;
- }
- if(copyau(&p->from, v))
- return 1;
- if(copyau(&p->to, v))
- return 1;
- return 0;
- case AADD: /* read, read, write */
- case ASUB:
- case ARSB:
- case ASLL:
- case ASRL:
- case ASRA:
- case AORR:
- case AAND:
- case AEOR:
- case AMUL:
- case ADIV:
- case ADIVU:
- case AADDF:
- case AADDD:
- case ASUBF:
- case ASUBD:
- case AMULF:
- case AMULD:
- case ADIVF:
- case ADIVD:
- case ACMPF:
- case ACMPD:
- case ACMP:
- case ACMN:
- case ACASE:
- if(s != A) {
- if(copysub(&p->from, v, s, 1))
- return 1;
- if(copysub1(p, v, s, 1))
- return 1;
- if(!copyas(&p->to, v))
- if(copysub(&p->to, v, s, 1))
- return 1;
- return 0;
- }
- if(copyas(&p->to, v)) {
- if(p->reg == NREG)
- p->reg = p->to.reg;
- if(copyau(&p->from, v))
- return 4;
- if(copyau1(p, v))
- return 4;
- return 3;
- }
- if(copyau(&p->from, v))
- return 1;
- if(copyau1(p, v))
- return 1;
- if(copyau(&p->to, v))
- return 1;
- return 0;
- case ABEQ: /* read, read */
- case ABNE:
- case ABCS:
- case ABHS:
- case ABCC:
- case ABLO:
- case ABMI:
- case ABPL:
- case ABVS:
- case ABVC:
- case ABHI:
- case ABLS:
- case ABGE:
- case ABLT:
- case ABGT:
- case ABLE:
- if(s != A) {
- if(copysub(&p->from, v, s, 1))
- return 1;
- return copysub1(p, v, s, 1);
- }
- if(copyau(&p->from, v))
- return 1;
- if(copyau1(p, v))
- return 1;
- return 0;
- case AB: /* funny */
- if(s != A) {
- if(copysub(&p->to, v, s, 1))
- return 1;
- return 0;
- }
- if(copyau(&p->to, v))
- return 1;
- return 0;
- case ARET: /* funny */
- if(v->type == D_REG)
- if(v->reg == REGRET)
- return 2;
- if(v->type == D_FREG)
- if(v->reg == FREGRET)
- return 2;
- case ABL: /* funny */
- if(v->type == D_REG) {
- if(v->reg <= REGEXT && v->reg > exregoffset)
- return 2;
- if(v->reg == REGARG)
- return 2;
- }
- if(v->type == D_FREG)
- if(v->reg <= FREGEXT && v->reg > exfregoffset)
- return 2;
- if(s != A) {
- if(copysub(&p->to, v, s, 1))
- return 1;
- return 0;
- }
- if(copyau(&p->to, v))
- return 4;
- return 3;
- case ATEXT: /* funny */
- if(v->type == D_REG)
- if(v->reg == REGARG)
- return 3;
- return 0;
- }
- }
- int
- a2type(Prog *p)
- {
- switch(p->as) {
- case ACMP:
- case ACMN:
- case AADD:
- case ASUB:
- case ARSB:
- case ASLL:
- case ASRL:
- case ASRA:
- case AORR:
- case AAND:
- case AEOR:
- case AMUL:
- case ADIV:
- case ADIVU:
- return D_REG;
- case ACMPF:
- case ACMPD:
- case AADDF:
- case AADDD:
- case ASUBF:
- case ASUBD:
- case AMULF:
- case AMULD:
- case ADIVF:
- case ADIVD:
- return D_FREG;
- }
- return D_NONE;
- }
- /*
- * direct reference,
- * could be set/use depending on
- * semantics
- */
- int
- copyas(Adr *a, Adr *v)
- {
- if(regtyp(v)) {
- if(a->type == v->type)
- if(a->reg == v->reg)
- return 1;
- } else if(v->type == D_CONST) { /* for constprop */
- if(a->type == v->type)
- if(a->name == v->name)
- if(a->sym == v->sym)
- if(a->reg == v->reg)
- if(a->offset == v->offset)
- return 1;
- }
- return 0;
- }
- /*
- * either direct or indirect
- */
- int
- copyau(Adr *a, Adr *v)
- {
- if(copyas(a, v))
- return 1;
- if(v->type == D_REG) {
- if(a->type == D_OREG) {
- if(v->reg == a->reg)
- return 1;
- } else if(a->type == D_SHIFT) {
- if((a->offset&0xf) == v->reg)
- return 1;
- if((a->offset&(1<<4)) && (a->offset>>8) == v->reg)
- return 1;
- }
- }
- return 0;
- }
- int
- copyau1(Prog *p, Adr *v)
- {
- if(regtyp(v)) {
- if(a2type(p) == v->type)
- if(p->reg == v->reg) {
- if(a2type(p) != v->type)
- print("botch a2type %P\n", p);
- return 1;
- }
- }
- return 0;
- }
- /*
- * substitute s for v in a
- * return failure to substitute
- */
- int
- copysub(Adr *a, Adr *v, Adr *s, int f)
- {
- if(f)
- if(copyau(a, v)) {
- if(a->type == D_SHIFT) {
- if((a->offset&0xf) == v->reg)
- a->offset = (a->offset&~0xf)|s->reg;
- if((a->offset&(1<<4)) && (a->offset>>8) == v->reg)
- a->offset = (a->offset&~(0xf<<8))|(s->reg<<8);
- } else
- a->reg = s->reg;
- }
- return 0;
- }
- int
- copysub1(Prog *p1, Adr *v, Adr *s, int f)
- {
- if(f)
- if(copyau1(p1, v))
- p1->reg = s->reg;
- return 0;
- }
- struct {
- int opcode;
- int notopcode;
- int scond;
- int notscond;
- } predinfo[] = {
- { ABEQ, ABNE, 0x0, 0x1, },
- { ABNE, ABEQ, 0x1, 0x0, },
- { ABCS, ABCC, 0x2, 0x3, },
- { ABHS, ABLO, 0x2, 0x3, },
- { ABCC, ABCS, 0x3, 0x2, },
- { ABLO, ABHS, 0x3, 0x2, },
- { ABMI, ABPL, 0x4, 0x5, },
- { ABPL, ABMI, 0x5, 0x4, },
- { ABVS, ABVC, 0x6, 0x7, },
- { ABVC, ABVS, 0x7, 0x6, },
- { ABHI, ABLS, 0x8, 0x9, },
- { ABLS, ABHI, 0x9, 0x8, },
- { ABGE, ABLT, 0xA, 0xB, },
- { ABLT, ABGE, 0xB, 0xA, },
- { ABGT, ABLE, 0xC, 0xD, },
- { ABLE, ABGT, 0xD, 0xC, },
- };
- typedef struct {
- Reg *start;
- Reg *last;
- Reg *end;
- int len;
- } Joininfo;
- enum {
- Join,
- Split,
- End,
- Branch,
- Setcond,
- Toolong
- };
-
- enum {
- Falsecond,
- Truecond,
- Delbranch,
- Keepbranch
- };
- int
- isbranch(Prog *p)
- {
- return (ABEQ <= p->as) && (p->as <= ABLE);
- }
- int
- predicable(Prog *p)
- {
- if (isbranch(p)
- || p->as == ANOP
- || p->as == AXXX
- || p->as == ADATA
- || p->as == AGLOBL
- || p->as == AGOK
- || p->as == AHISTORY
- || p->as == ANAME
- || p->as == ASIGNAME
- || p->as == ATEXT
- || p->as == AWORD
- || p->as == ADYNT
- || p->as == AINIT
- || p->as == ABCASE
- || p->as == ACASE)
- return 0;
- return 1;
- }
- /*
- * Depends on an analysis of the encodings performed by 5l.
- * These seem to be all of the opcodes that lead to the "S" bit
- * being set in the instruction encodings.
- *
- * C_SBIT may also have been set explicitly in p->scond.
- */
- int
- modifiescpsr(Prog *p)
- {
- return (p->scond&C_SBIT)
- || p->as == ATST
- || p->as == ATEQ
- || p->as == ACMN
- || p->as == ACMP
- || p->as == AMULU
- || p->as == ADIVU
- || p->as == AMUL
- || p->as == ADIV
- || p->as == AMOD
- || p->as == AMODU
- || p->as == ABL;
- }
- /*
- * Find the maximal chain of instructions starting with r which could
- * be executed conditionally
- */
- int
- joinsplit(Reg *r, Joininfo *j)
- {
- j->start = r;
- j->last = r;
- j->len = 0;
- do {
- if (r->p2 && (r->p1 || r->p2->p2link)) {
- j->end = r;
- return Join;
- }
- if (r->s1 && r->s2) {
- j->end = r;
- return Split;
- }
- j->last = r;
- if (r->prog->as != ANOP)
- j->len++;
- if (!r->s1 && !r->s2) {
- j->end = r->link;
- return End;
- }
- if (r->s2) {
- j->end = r->s2;
- return Branch;
- }
- if (modifiescpsr(r->prog)) {
- j->end = r->s1;
- return Setcond;
- }
- r = r->s1;
- } while (j->len < 4);
- j->end = r;
- return Toolong;
- }
- Reg *
- successor(Reg *r)
- {
- if (r->s1)
- return r->s1;
- else
- return r->s2;
- }
- void
- applypred(Reg *rstart, Joininfo *j, int cond, int branch)
- {
- int pred;
- Reg *r;
- if(j->len == 0)
- return;
- if (cond == Truecond)
- pred = predinfo[rstart->prog->as - ABEQ].scond;
- else
- pred = predinfo[rstart->prog->as - ABEQ].notscond;
-
- for (r = j->start; ; r = successor(r)) {
- if (r->prog->as == AB) {
- if (r != j->last || branch == Delbranch)
- excise(r);
- else {
- if (cond == Truecond)
- r->prog->as = predinfo[rstart->prog->as - ABEQ].opcode;
- else
- r->prog->as = predinfo[rstart->prog->as - ABEQ].notopcode;
- }
- }
- else if (predicable(r->prog))
- r->prog->scond = (r->prog->scond&~C_SCOND)|pred;
- if (r->s1 != r->link) {
- r->s1 = r->link;
- r->link->p1 = r;
- }
- if (r == j->last)
- break;
- }
- }
- void
- predicate(void)
- {
- Reg *r;
- int t1, t2;
- Joininfo j1, j2;
- for(r=firstr; r!=R; r=r->link) {
- if (isbranch(r->prog)) {
- t1 = joinsplit(r->s1, &j1);
- t2 = joinsplit(r->s2, &j2);
- if(j1.last->link != j2.start)
- continue;
- if(j1.end == j2.end)
- if((t1 == Branch && (t2 == Join || t2 == Setcond)) ||
- (t2 == Join && (t1 == Join || t1 == Setcond))) {
- applypred(r, &j1, Falsecond, Delbranch);
- applypred(r, &j2, Truecond, Delbranch);
- excise(r);
- continue;
- }
- if(t1 == End || t1 == Branch) {
- applypred(r, &j1, Falsecond, Keepbranch);
- excise(r);
- continue;
- }
- }
- }
- }
|