int constant(LVALUE *lval) { constype=CINT; conssign=dosigned; lval->is_const = 1 ; /* assume constant will be found */ if ( fnumber(&lval->const_val) ) { lval->val_type=DOUBLE; if ( doublestrings ) { immedlit(litlab); outdec(lval->const_val); nl(); callrts("__atof2"); WriteDefined("math_atof",1); } else { immedlit(dublab); outdec(lval->const_val); nl(); callrts("dload"); } lval->is_const = 0 ; /* floating point not constant */ lval->flags=0; return(1); } else if ( number(&lval->const_val) || pstr(&lval->const_val) ) { /* Insert long stuff/long pointer here? */ if ( (unsigned long )lval->const_val >= 65536LU ) constype = LONG; lval->val_type = constype ; lval->flags = (lval->flags&MKSIGN)|conssign; if (constype == LONG) vlongconst(lval->const_val); else vconst(lval->const_val); return(1); } else if ( tstr(&lval->const_val) ) { lval->is_const = 0 ; /* string address not constant */ lval->ptr_type=CCHAR; /* djm 9/3/99 */ lval->val_type=CINT; lval->flags=0; immedlit(litlab); } else { lval->is_const = 0 ; return(0); } outdec(lval->const_val); nl(); return(1); }
void gen(Node *n) { Node *l, nod; Prog *sp, *spc, *spb; Case *cn; long sbc, scc; int snbreak, sncontin; int f, o, oldreach; loop: if(n == Z) return; nearln = n->lineno; o = n->op; if(debug['G']) if(o != OLIST) print("%L %O\n", nearln, o); if(!canreach) { switch(o) { case OLABEL: case OCASE: case OLIST: case OBREAK: case OFOR: case OWHILE: case ODWHILE: /* all handled specially - see switch body below */ break; default: if(warnreach) { warn(n, "unreachable code %O", o); warnreach = 0; } } } switch(o) { default: complex(n); cgen(n, Z); break; case OLIST: gen(n->left); rloop: n = n->right; goto loop; case ORETURN: canreach = 0; warnreach = !suppress; complex(n); if(n->type == T) break; l = n->left; if(l == Z) { noretval(3); gbranch(ORETURN); break; } if(typecmplx[n->type->etype]) { sugen(l, nodret, n->type->width); noretval(3); gbranch(ORETURN); break; } regret(&nod, n); cgen(l, &nod); regfree(&nod); if(typefd[n->type->etype]) noretval(1); else noretval(2); gbranch(ORETURN); break; case OLABEL: canreach = 1; l = n->left; if(l) { l->pc = pc; if(l->label) patch(l->label, pc); } gbranch(OGOTO); /* prevent self reference in reg */ patch(p, pc); goto rloop; case OGOTO: canreach = 0; warnreach = !suppress; n = n->left; if(n == Z) return; if(n->complex == 0) { diag(Z, "label undefined: %s", n->sym->name); return; } if(suppress) return; gbranch(OGOTO); if(n->pc) { patch(p, n->pc); return; } if(n->label) patch(n->label, pc-1); n->label = p; return; case OCASE: canreach = 1; l = n->left; if(cases == C) diag(n, "case/default outside a switch"); if(l == Z) { newcase(); cases->val = 0; cases->def = 1; cases->label = pc; cases->isv = 0; goto rloop; } complex(l); if(l->type == T) goto rloop; if(l->op == OCONST) if(typeword[l->type->etype] && l->type->etype != TIND) { newcase(); cases->val = l->vconst; cases->def = 0; cases->label = pc; cases->isv = typev[l->type->etype]; goto rloop; } diag(n, "case expression must be integer constant"); goto rloop; case OSWITCH: l = n->left; complex(l); if(l->type == T) break; if(!typechlvp[l->type->etype] || l->type->etype == TIND) { diag(n, "switch expression must be integer"); break; } gbranch(OGOTO); /* entry */ sp = p; cn = cases; cases = C; newcase(); sbc = breakpc; breakpc = pc; snbreak = nbreak; nbreak = 0; gbranch(OGOTO); spb = p; gen(n->right); /* body */ if(canreach){ gbranch(OGOTO); patch(p, breakpc); nbreak++; } patch(sp, pc); doswit(l); patch(spb, pc); cases = cn; breakpc = sbc; canreach = nbreak!=0; if(canreach == 0) warnreach = !suppress; nbreak = snbreak; break; case OWHILE: case ODWHILE: l = n->left; gbranch(OGOTO); /* entry */ sp = p; scc = continpc; continpc = pc; gbranch(OGOTO); spc = p; sbc = breakpc; breakpc = pc; snbreak = nbreak; nbreak = 0; gbranch(OGOTO); spb = p; patch(spc, pc); if(n->op == OWHILE) patch(sp, pc); bcomplex(l, Z); /* test */ patch(p, breakpc); if(l->op != OCONST || vconst(l) == 0) nbreak++; if(n->op == ODWHILE) patch(sp, pc); gen(n->right); /* body */ gbranch(OGOTO); patch(p, continpc); patch(spb, pc); continpc = scc; breakpc = sbc; canreach = nbreak!=0; if(canreach == 0) warnreach = !suppress; nbreak = snbreak; break; case OFOR: l = n->left; if(!canreach && l->right->left && warnreach) { warn(n, "unreachable code FOR"); warnreach = 0; } gen(l->right->left); /* init */ gbranch(OGOTO); /* entry */ sp = p; /* * if there are no incoming labels in the * body and the top's not reachable, warn */ if(!canreach && warnreach && deadheads(n)) { warn(n, "unreachable code %O", o); warnreach = 0; } scc = continpc; continpc = pc; gbranch(OGOTO); spc = p; sbc = breakpc; breakpc = pc; snbreak = nbreak; nbreak = 0; sncontin = ncontin; ncontin = 0; gbranch(OGOTO); spb = p; patch(spc, pc); gen(l->right->right); /* inc */ patch(sp, pc); if(l->left != Z) { /* test */ bcomplex(l->left, Z); patch(p, breakpc); if(l->left->op != OCONST || vconst(l->left) == 0) nbreak++; } canreach = 1; gen(n->right); /* body */ if(canreach){ gbranch(OGOTO); patch(p, continpc); ncontin++; } if(!ncontin && l->right->right && warnreach) { warn(l->right->right, "unreachable FOR inc"); warnreach = 0; } patch(spb, pc); continpc = scc; breakpc = sbc; canreach = nbreak!=0; if(canreach == 0) warnreach = !suppress; nbreak = snbreak; ncontin = sncontin; break; case OCONTINUE: if(continpc < 0) { diag(n, "continue not in a loop"); break; } gbranch(OGOTO); patch(p, continpc); ncontin++; canreach = 0; warnreach = !suppress; break; case OBREAK: if(breakpc < 0) { diag(n, "break not in a loop"); break; } /* * Don't complain about unreachable break statements. * There are breaks hidden in yacc's output and some people * write return; break; in their switch statements out of habit. * However, don't confuse the analysis by inserting an * unreachable reference to breakpc either. */ if(!canreach) break; gbranch(OGOTO); patch(p, breakpc); nbreak++; canreach = 0; warnreach = !suppress; break; case OIF: l = n->left; if(bcomplex(l, n->right)) { if(typefd[l->type->etype]) f = !l->fconst; else f = !l->vconst; if(debug['c']) print("%L const if %s\n", nearln, f ? "false" : "true"); if(f) { canreach = 1; supgen(n->right->left); oldreach = canreach; canreach = 1; gen(n->right->right); /* * treat constant ifs as regular ifs for * reachability warnings. */ if(!canreach && oldreach && debug['w'] < 2) warnreach = 0; } else { canreach = 1; gen(n->right->left); oldreach = canreach; canreach = 1; supgen(n->right->right); /* * treat constant ifs as regular ifs for * reachability warnings. */ if(!oldreach && canreach && debug['w'] < 2) warnreach = 0; canreach = oldreach; } } else { sp = p; canreach = 1; if(n->right->left != Z) gen(n->right->left); oldreach = canreach; canreach = 1; if(n->right->right != Z) { gbranch(OGOTO); patch(sp, pc); sp = p; gen(n->right->right); } patch(sp, pc); canreach = canreach || oldreach; if(canreach == 0) warnreach = !suppress; } break; case OSET: case OUSED: case OPREFETCH: usedset(n->left, o); break; } }
/* * calculate addressability as follows * REGISTER ==> 12 register * NAME ==> 11 name+value(SB/SP) * note that 10 is no longer generated * CONST ==> 20 $value * *(20) ==> 21 value * &(10) ==> 12 $name+value(SB) * &(11) ==> 1 $name+value(SP) * (12) + (20) ==> 12 fold constants * (1) + (20) ==> 1 fold constants * *(12) ==> 10 back to name * *(1) ==> 11 back to name * * (2,10,11) + (20) ==> 2 indirect w offset * (2) ==> &13 * *(10,11) ==> 13 indirect, no index * * (20) * (X) ==> 7 multiplier in indexing * (X,7) + (12,1) ==> 8 adder in indexing (addresses) * (X,7) + (10,11,2) ==> 8 adder in indexing (names) * (8) ==> &9 index, almost addressable * * (X)++ ==> X fake addressability * * calculate complexity (number of registers) */ void xcom(Node *n) { Node *l, *r; int g; if(n == Z) return; l = n->left; r = n->right; n->complex = 0; n->addable = 0; switch(n->op) { case OCONST: n->addable = 20; break; case ONAME: n->addable = 11; /* difference to make relocatable */ break; case OREGISTER: n->addable = 12; break; case OADDR: xcom(l); if(l->addable == 10) n->addable = 12; else if(l->addable == 11) n->addable = 1; break; case OADD: xcom(l); xcom(r); if(n->type->etype != TIND) break; if(l->addable == 20) switch(r->addable) { case 12: case 1: n->addable = r->addable; goto brk; } if(r->addable == 20) switch(l->addable) { case 12: case 1: n->addable = l->addable; goto brk; } break; case OIND: xcom(l); if(l->op == OADDR) { l = l->left; l->type = n->type; *n = *l; return; } switch(l->addable) { case 20: n->addable = 21; break; case 1: n->addable = 11; break; case 12: n->addable = 10; break; } break; case OASHL: xcom(l); xcom(r); if(typev[n->type->etype]) break; g = vconst(r); if(g >= 0 && g < 4) n->addable = 7; break; case OMUL: case OLMUL: xcom(l); xcom(r); if(typev[n->type->etype]) break; g = vlog(r); if(g >= 0) { n->op = OASHL; r->vconst = g; if(g < 4) n->addable = 7; break; } g = vlog(l); if(g >= 0) { n->left = r; n->right = l; l = r; r = n->right; n->op = OASHL; r->vconst = g; if(g < 4) n->addable = 7; break; } break; case ODIV: case OLDIV: xcom(l); xcom(r); if(typev[n->type->etype]) break; g = vlog(r); if(g >= 0) { if(n->op == ODIV) n->op = OASHR; else n->op = OLSHR; r->vconst = g; } break; case OSUB: xcom(l); xcom(r); if(typev[n->type->etype]) break; if(vconst(l) == 0) { n->op = ONEG; n->left = r; n->right = Z; } break; case OXOR: xcom(l); xcom(r); if(typev[n->type->etype]) break; if(vconst(l) == -1) { n->op = OCOM; n->left = r; n->right = Z; } break; case OASMUL: case OASLMUL: xcom(l); xcom(r); if(typev[n->type->etype]) break; g = vlog(r); if(g >= 0) { n->op = OASASHL; r->vconst = g; } goto aseae; case OASDIV: case OASLDIV: xcom(l); xcom(r); if(typev[n->type->etype]) break; g = vlog(r); if(g >= 0) { if(n->op == OASDIV) n->op = OASASHR; else n->op = OASLSHR; r->vconst = g; } goto aseae; case OASLMOD: case OASMOD: xcom(l); xcom(r); if(typev[n->type->etype]) break; aseae: /* hack that there are no byte/short mul/div operators */ if(n->type->etype == TCHAR || n->type->etype == TSHORT) { n->right = new1(OCAST, n->right, Z); n->right->type = types[TLONG]; n->type = types[TLONG]; } if(n->type->etype == TUCHAR || n->type->etype == TUSHORT) { n->right = new1(OCAST, n->right, Z); n->right->type = types[TULONG]; n->type = types[TULONG]; } goto asop; case OASXOR: case OASOR: case OASADD: case OASSUB: case OASLSHR: case OASASHR: case OASASHL: case OASAND: case OAS: xcom(l); xcom(r); if(typev[n->type->etype]) break; asop: if(l->addable > INDEXED && l->complex < FNX && r && r->complex < FNX) n->addable = l->addable; break; case OPOSTINC: case OPREINC: case OPOSTDEC: case OPREDEC: xcom(l); if(typev[n->type->etype]) break; if(l->addable > INDEXED && l->complex < FNX) n->addable = l->addable; break; default: if(l != Z) xcom(l); if(r != Z) xcom(r); break; } brk: n->complex = 0; if(n->addable >= 10) return; if(l != Z) n->complex = l->complex; if(r != Z) { if(r->complex == n->complex) n->complex = r->complex+1; else if(r->complex > n->complex) n->complex = r->complex; } if(n->complex == 0) n->complex++; if(com64(n)) return; switch(n->op) { case OFUNC: n->complex = FNX; break; case OADD: case OMUL: case OLMUL: case OXOR: case OAND: case OOR: /* * symmetric operators, make right side simple * if same, put constant on left to get movq */ if(r->complex > l->complex || (r->complex == l->complex && r->addable == 20)) { n->left = r; n->right = l; } break; case OLE: case OLT: case OGE: case OGT: case OEQ: case ONE: /* * relational operators, make right side simple * if same, put constant on left to get movq */ if(r->complex > l->complex || r->addable == 20) { n->left = r; n->right = l; n->op = invrel[relindex(n->op)]; } break; } }
void gen(Node *n) { Node *l; Prog *sp, *spc, *spb; Case *cn; long sbc, scc; int snbreak; int g, o; loop: if(n == Z) return; nearln = n->lineno; o = n->op; if(debug['G']) if(o != OLIST) print("%L %O\n", nearln, o); retok = 0; switch(o) { default: complex(n); doinc(n, PRE); cgen(n, D_NONE, n); doinc(n, POST); break; case OLIST: gen(n->left); rloop: n = n->right; goto loop; case ORETURN: retok = 1; complex(n); if(n->type == T) break; l = n->left; if(l == Z) { noretval(3); gbranch(ORETURN); break; } doinc(l, PRE); if(typesuv[n->type->etype]) { sugen(l, D_TREE, nodret, n->type->width); doinc(l, POST); noretval(3); gbranch(ORETURN); break; } g = regalloc(n->type, regret(n->type)); cgen(l, g, n); doinc(l, POST); if(typefd[n->type->etype]) noretval(1); else noretval(2); gbranch(ORETURN); regfree(g); break; case OLABEL: l = n->left; if(l) { l->xoffset = pc; if(l->label) patch(l->label, pc); } gbranch(OGOTO); /* prevent self reference in reg */ patch(p, pc); goto rloop; case OGOTO: retok = 1; n = n->left; if(n == Z) return; if(n->complex == 0) { diag(Z, "label undefined: %s", n->sym->name); return; } gbranch(OGOTO); if(n->xoffset) { patch(p, n->xoffset); return; } if(n->label) patch(n->label, pc-1); n->label = p; return; case OCASE: l = n->left; if(cases == C) diag(n, "case/default outside a switch"); if(l == Z) { casf(); cases->val = 0; cases->def = 1; cases->label = pc; setsp();; goto rloop; } complex(l); if(l->type == T) goto rloop; if(l->op == OCONST) if(typechl[l->type->etype]) { casf(); cases->val = l->vconst; cases->def = 0; cases->label = pc; setsp(); goto rloop; } diag(n, "case expression must be integer constant"); goto rloop; case OSWITCH: l = n->left; complex(l); doinc(l, PRE); if(l->type == T) break; if(!typechl[l->type->etype]) { diag(n, "switch expression must be integer"); break; } g = regalloc(types[TLONG], D_NONE); n->type = types[TLONG]; cgen(l, g, n); regfree(g); doinc(l, POST); setsp(); gbranch(OGOTO); /* entry */ sp = p; cn = cases; cases = C; casf(); sbc = breakpc; breakpc = pc; snbreak = nbreak; nbreak = 0; gbranch(OGOTO); spb = p; gen(n->right); gbranch(OGOTO); patch(p, breakpc); nbreak++; patch(sp, pc); doswit(g, l); patch(spb, pc); cases = cn; breakpc = sbc; nbreak = snbreak; setsp(); break; case OWHILE: case ODWHILE: l = n->left; gbranch(OGOTO); /* entry */ sp = p; scc = continpc; continpc = pc; gbranch(OGOTO); spc = p; sbc = breakpc; breakpc = pc; snbreak = nbreak; nbreak = 0; gbranch(OGOTO); spb = p; patch(spc, pc); if(n->op == OWHILE) patch(sp, pc); bcomplex(l); /* test */ patch(p, breakpc); if(l->op != OCONST || vconst(l) == 0) nbreak++; if(n->op == ODWHILE) patch(sp, pc); gen(n->right); /* body */ gbranch(OGOTO); patch(p, continpc); patch(spb, pc); continpc = scc; breakpc = sbc; if(nbreak == 0) retok = 1; nbreak = snbreak; break; case OFOR: l = n->left; gen(l->right->left); /* init */ gbranch(OGOTO); /* entry */ sp = p; scc = continpc; continpc = pc; gbranch(OGOTO); spc = p; sbc = breakpc; breakpc = pc; snbreak = nbreak; nbreak = 0; gbranch(OGOTO); spb = p; patch(spc, pc); gen(l->right->right); /* inc */ patch(sp, pc); if(l->left != Z) { /* test */ bcomplex(l->left); patch(p, breakpc); if(l->left->op != OCONST || vconst(l->left) == 0) nbreak++; } gen(n->right); /* body */ gbranch(OGOTO); patch(p, continpc); patch(spb, pc); continpc = scc; breakpc = sbc; if(nbreak == 0) retok = 1; nbreak = snbreak; break; case OCONTINUE: if(continpc < 0) { diag(n, "continue not in a loop"); break; } gbranch(OGOTO); patch(p, continpc); break; case OBREAK: if(breakpc < 0) { diag(n, "break not in a loop"); break; } gbranch(OGOTO); patch(p, breakpc); nbreak++; break; case OIF: l = n->left; bcomplex(l); sp = p; if(n->right->left != Z) gen(n->right->left); if(n->right->right != Z) { gbranch(OGOTO); patch(sp, pc); sp = p; gen(n->right->right); } patch(sp, pc); break; case OSET: case OUSED: usedset(n->left, o); break; } }
void Ceval(Node *tp) { unsigned int i1, i2; Node * tp0; if(tp->Cone || tp->Czero) return; switch(tp->code) { case 0: return; case ELIST: if(tp->t1 != 0) Ceval(tp->t1); if(tp->t2 != 0) Ceval(tp->t2); tp->Czero = tp->Cone = 0; return; case ASSIGN: Ceval(tp->t2); tp->Czero = tp->t2->Czero; tp->Cone = tp->t2->Cone; return; case DONTCARE: Ceval(tp->t2); tp->Czero = tp->t2->Czero; tp->Cone = tp->t2->Cone; return; case AND: Ceval(tp->t2); Ceval(tp->t1); tp->Czero = tp->t2->Czero | tp->t1->Czero; tp->Cone = tp->t2->Cone & tp->t1->Cone; return; case OR: Ceval(tp->t2); Ceval(tp->t1); tp->Czero = tp->t2->Czero & tp->t1->Czero; tp->Cone = tp->t2->Cone | tp->t1->Cone; return; case LAND: Ceval(tp->t2); Ceval(tp->t1); tp->Czero = (~0 << 1) | ((tp->t2->Czero == ~0) || (tp->t1->Czero == ~0)); tp->Cone = (tp->t1->Cone) && (tp->t2->Cone); return; case LOR: Ceval(tp->t2); Ceval(tp->t1); tp->Czero = (~0 << 1) | ((tp->t2->Czero == ~0) && (tp->t1->Czero == ~0)); tp->Cone = (tp->t1->Cone) ||(tp->t2->Cone); return; case NEG: Ceval(tp->t1); tp->Cone = tp->Czero = 0; if(ISCONST(tp->t1)) tp->Czero = ~(tp->Cone = -tp->t1->Cone); return; case XOR: Ceval(tp->t2); Ceval(tp->t1); tp->Czero = (tp->t2->Czero & tp->t1->Czero) | (tp->t2->Cone & tp->t1->Cone); tp->Cone = (tp->t2->Czero & tp->t1->Cone) | (tp->t2->Cone & tp->t1->Czero); return; case FLONE: if(!vconst(tp->t1)) { fprintf(stderr, "Restrick hasn't done find left one for variable\n"); exits("error");; } tp->Cone = eval(tp->t1); tp->Czero = ~tp->Cone; return; case FRONE: if(!vconst(tp->t1)) { fprintf(stderr, "Restrick hasn't done find right one for variable\n"); exits("error");; } tp->Cone = eval(tp->t1); tp->Czero = ~tp->Cone; return; case GREY: if(!vconst(tp->t1)) { fprintf(stderr, "Restrick hasn't done grey code for variable\n"); exits("error");; } tp->Cone = eval(tp->t1); tp->Czero = ~tp->Cone; return; case NOT: Ceval(tp->t1); tp->Cone = (tp->t1->Czero == ~0); tp->Czero = (tp->t1->Cone) ? ~0 : (~0 << 1); return; case COM: Ceval(tp->t1); tp->Cone = (tp->t1->Czero); tp->Czero = (tp->t1->Cone); return; case ADD: Ceval(tp->t2); Ceval(tp->t1); i1 = tp->t1->Cone | tp->t1->Czero; i1 = i1 & ~(i1 + 1); i2 = tp->t2->Cone | tp->t2->Czero; i2 = i2 & ~(i2 + 1); tp->Cone = i1 & i2 & (tp->t1->Cone + tp->t2->Cone); tp->Czero = i1 & i2 & ~tp->Cone; for(i1 = 0; ; i1 = i1<<1 | 1) if(((tp->t1->Czero | i1) == ~0) && ((tp->t2->Czero | i1) == ~0)) break; tp->Czero |= ~(i1<<1 | 1); return; case SUB: Ceval(tp->t2); Ceval(tp->t1); i1 = tp->t1->Cone | tp->t1->Czero; i1 = i1 & ~(i1 + 1); i2 = tp->t2->Cone | tp->t2->Czero; i2 = i2 & ~(i2 + 1); tp->Cone = i1 & i2 & (tp->t1->Cone + tp->t2->Cone); tp->Czero = i1 & i2 & ~tp->Cone; for(i1 = 0; ; i1 = i1<<1 | 1) if(((tp->t1->Czero | i1) == ~0) && ((tp->t2->Czero | i1) == ~0)) break; i2 = i1 ^ i1>>1; if((tp->t1->Cone & i2) && (tp->t2->Czero & i2)) tp->Czero |= ~(i1<<1 | 1); else if((tp->t1->Czero & i2) && (tp->t2->Cone & i2)) tp->Cone |= ~(i1<<1 | 1); return; case MUL: if(!vconst(tp->t1)) { fprintf(stderr, "Restrick hasn't done mult for variable\n"); exits("error");; } if(!vconst(tp->t2)) { fprintf(stderr, "Restrick hasn't done mult for variable\n"); exits("error");; } tp->Cone = eval(tp->t1) * eval(tp->t2); tp->Czero = ~tp->Cone; return; case DIV: if(!vconst(tp->t1)) { fprintf(stderr, "Restrick hasn't done div for variable\n"); exits("error");; } if(!vconst(tp->t2)) { fprintf(stderr, "Restrick hasn't done div for variable\n"); exits("error");; } tp->Cone = eval(tp->t1) / eval(tp->t2); tp->Czero = ~tp->Cone; return; case MOD: if(!vconst(tp->t1)) { fprintf(stderr, "Restrick hasn't done mod for variable\n"); exits("error");; } if(!vconst(tp->t2)) { fprintf(stderr, "Restrick hasn't done mod for variable\n"); exits("error");; } tp->Cone = eval(tp->t1) % eval(tp->t2); tp->Czero = ~tp->Cone; return; case GT: case LT: case GE: case LE: Ceval(tp->t2); Ceval(tp->t1); for(i1 = 0; ; i1 = i1<<1 | 1) if(((tp->t1->Czero | tp->t1->Cone | i1) == ~0) && ((tp->t2->Czero | tp->t2->Cone | i1) == ~0)) break; i1 = ~i1; switch(tp->code) { case LT: case LE: tp->Cone = (tp->t1->Cone & i1) < (tp->t2->Cone & i1); tp->Czero = (tp->t1->Cone & i1) > (tp->t2->Cone & i1); break; case GT: case GE: tp->Cone = (tp->t1->Cone & i1) > (tp->t2->Cone & i1); tp->Czero = (tp->t1->Cone & i1) < (tp->t2->Cone & i1); } return; case EQ: Ceval(tp->t2); Ceval(tp->t1); if(ISCONST(tp->t1) && ISCONST(tp->t2)) { tp->Cone = (tp->t1->Cone == tp->t2->Cone) ? 1 : 0; tp->Czero = ~tp->Cone; } else { i1 = (tp->t1->Cone | tp->t1->Czero) & (tp->t2->Cone | tp->t2->Czero); tp->Czero = (i1 & (tp->t1->Cone ^ tp->t2->Cone)) ? ~0 : ~1; tp->Cone = 0; } return; case NE: Ceval(tp->t2); Ceval(tp->t1); if(ISCONST(tp->t1) && ISCONST(tp->t2)) { tp->Cone = (tp->t1->Cone != tp->t2->Cone) ? 1 : 0; tp->Czero = ~tp->Cone; } else { tp->Czero = ~1; i1 = (tp->t1->Cone | tp->t1->Czero) & (tp->t2->Cone | tp->t2->Czero); tp->Cone = (i1 & (tp->t1->Cone ^ tp->t2->Cone)) ? 1 : 0; } return; case LS: Ceval(tp->t2); Ceval(tp->t1); if(ISCONST(tp->t2)) { tp->Cone = tp->t1->Cone << tp->t2->Cone; tp->Czero = tp->t1->Czero << tp->t2->Cone; i1 = ~0 << tp->t2->Cone; tp->Czero |= ~i1; return; } tp->Cone = tp->Czero = 0; return; case RS: Ceval(tp->t2); Ceval(tp->t1); if(ISCONST(tp->t2)) { tp->Cone = tp->t1->Cone >> tp->t2->Cone; tp->Czero = tp->t1->Czero >> tp->t2->Cone; i1 = ~0 >> tp->t2->Cone; tp->Czero |= ~i1; return; } tp->Cone = tp->Czero = 0; return; case CND: Ceval(tp->t1); Ceval(tp->t2->t1); Ceval(tp->t2->t2); if(ISCONST(tp->t1)) { if (tp->t1->Cone) { tp->Cone = tp->t2->t1->Cone; tp->Czero = tp->t2->t1->Czero; return; } tp->Cone = tp->t2->t2->Cone; tp->Czero = tp->t2->t2->Czero; return; } tp->Cone = tp->t2->t1->Cone & tp->t2->t2->Cone; tp->Czero = tp->t2->t1->Czero & tp->t2->t2->Czero; return; case SWITCH: { int o, z; if(vconst(tp)) { tp->Cone = eval(tp); tp->Czero = ~tp->Cone; return; } Ceval(tp->t1); tp0 = tp; o = z = ~0; for(tp = tp->t2; tp; tp = tp->t2) { if(tp->code == ALT) { if(tp->t1) { Ceval(tp->t1); continue; } tp = tp->t2; if(tp == 0) break; if(tp->code != CASE) break; Ceval(tp->t1); o &= tp->t1->Cone; z &= tp->t1->Czero; continue; } if(tp->code != CASE) break; Ceval(tp->t1); o &= tp->t1->Cone; z &= tp->t1->Czero; } tp0->Cone = o; tp0->Czero = z; return; } case EQN: tp0 = ((Hshtab *) (tp->t1))->assign; Ceval(tp0); tp->Cone = tp0->Cone; tp->Czero = tp0->Czero; return; case BOTH: case INPUT: tp->Czero = ~1; tp->Cone = 0; return; case FIELD: i1 = HI((Hshtab *) tp->t1) - LO((Hshtab *) tp->t1); tp->Cone = 0; tp->Czero = (i1 > 31) ? 0 : ( ~0 << i1); return; case NUMBER: tp->Cone = (int) tp->t1; tp->Czero = ~tp->Cone; return; default: fprintf(stderr,"unknown Ceval op %d\n", tp->code); exits("error");; }
//execute context l_thread::type_return l_thread::execute(l_call_context& context) { //lock context context.lock(); //save context register3(R_CONTEXT) = l_variable( &context ); //pc... unsigned int pc = 0; l_function& function = m_vm->function(context.get_fun_id()); l_list_command& commands = function.m_commands; //macro #define raise(str)\ {\ push_error(str, pc, (unsigned int)commands[pc].m_line);\ return T_RETURN_ERROR;\ } #define vconst(c) function.m_costants[c] #define top_size (m_top+1) //for all commands for (pc = 0; pc < commands.size(); ++pc) { //current command l_command& cmp = commands[pc]; //opcodes switch (cmp.m_op_code) { case L_JMP: pc = cmp.m_arg - 1; break; case L_RETURN: //push return if(cmp.m_arg) { //get value register3(2) = pop(); //return... return T_RETURN_VALUE; } else { //came back return T_RETURN_VOID; } //.. break; case L_IF: if(top().is_true()) { pc = cmp.m_arg - 1; } pop(); break; case L_IF0: if(top().is_false()) { pc = cmp.m_arg - 1; } pop(); break; case L_IF_OR_POP: if(top().is_true()) { pc = cmp.m_arg - 1; } else { pop(); } break; case L_IF0_OR_POP: if(top().is_false()) { pc = cmp.m_arg - 1; } else { pop(); } break; case L_PUSH: push( stack(cmp.m_arg) ); break; case L_PUSH_NULL: push( l_variable() ); break; case L_PUSH_TRUE: push( l_variable(true) ); break; case L_PUSH_FALSE: push( l_variable(false) ); break; case L_PUSHK: push( vconst(cmp.m_arg) ); break; case L_CLOSER: { //get value l_variable& call_fun = vconst(cmp.m_arg); //... if(call_fun.is_function()) { //new context register3(0) = l_closer::gc_new(get_gc()); //init context register3(0).to<l_closer>()->init(call_fun.m_value.m_fid, this, l_variable(&context)); //push context push(register3(0)); } } break; //////////////////////////////////////////////////////////// case L_ADD: if(!stack(1).add(stack(0),stack(1))) raise("not valid operation"); pop(); break; case L_MUL: if(!stack(1).mul(stack(0),stack(1))) raise("not valid operation"); pop(); break; case L_SUB: if(!stack(1).sub(stack(0),stack(1))) raise("not valid operation"); pop(); break; case L_DIV: if(!stack(1).div(stack(0),stack(1))) raise("not valid operation"); pop(); break; case L_MOD: if(!stack(1).mod(stack(0),stack(1))) raise("not valid operation"); pop(); break; case L_UNM: if(!stack(0).unm(stack(0))) raise("not valid operation"); break; //////////////////////////////////////////////////////////// case L_EQ: if(!stack(1).equal(stack(0),stack(1))) raise("not valid operation"); pop(); break; case L_NEQ: if(!stack(1).not_equal(stack(0),stack(1))) raise("not valid operation"); pop(); break; case L_RT: if(!stack(1).rt(stack(0),stack(1))) raise("not valid operation"); pop(); break; case L_RE: if(!stack(1).re(stack(0),stack(1))) raise("not valid operation"); pop(); break; case L_LT: if(!stack(1).lt(stack(0),stack(1))) raise("not valid operation"); pop(); break; case L_LE: if(!stack(1).le(stack(0),stack(1))) raise("not valid operation"); pop(); break; //////////////////////////////////////////////////////////// case L_NOT: if(!stack(0).not_value(stack(0))) raise("not valid operation"); break; case L_OR: if(!stack(1).or_value(stack(0),stack(1))) raise("not valid operation"); pop(); break; case L_AND: if(!stack(1).and_value(stack(0),stack(1))) raise("not valid operation"); pop(); break; //////////////////////////////////////////////////////////// case L_GET_GLOBAL: push( global(context,cmp.m_arg) ); break; case L_SET_GLOBAL: global(context,cmp.m_arg) = pop(); break; //////////////////////////////////////////////////////////// case L_GET_LOCAL: push( strick_local(context,cmp.m_arg) ); break; case L_SET_LOCAL: strick_local(context,cmp.m_arg) = pop(); break; //////////////////////////////////////////////////////////// case L_SET_UP_VALUE: local(context,cmp.m_arg) = pop(); break; case L_GET_UP_VALUE: push( local(context,cmp.m_arg) ); break; //////////////////////////////////////////////////////////// case L_GET_THIS: push(context.this_field()); break; case L_SET_THIS: context.this_field() = pop(); break; case L_SET_THIS_NPOP: context.this_field() = stack(cmp.m_arg); break; //////////////////////////////////////////////////////////// case L_NEW_ARRAY: { register3(0) = l_array::gc_new(get_gc()); //init ? if( cmp.m_arg > 0 ) { //types l_array* vector = register3(0).array(); //put stack into vector for(int i = cmp.m_arg-1; i >= 0; --i) { vector->operator[](i) = pop(); } } //push array (n.b. gc run...) push( register3(0) ); } break; //alloc tablet case L_NEW_TABLE: { register3(0) = l_table::gc_new(get_gc()); //init ? if( cmp.m_arg > 0 ) { //types l_table* table = register3(0).table(); //assert assert(!(cmp.m_arg % 2)); //put stack into vector for(int i = (cmp.m_arg)-1; i >= 0; i-=2) { //push key and value table->operator[](stack(1)) = stack(0); //pop value pop(); //pop key pop(); } } //push table (n.b. gc run...) push( register3(0) ); } break; case L_GET_AT_VAL: { l_variable& r_b = stack(1); const l_variable& r_c = stack(0); //try if ( r_b.is_object() ) { //is a vector if(r_b.is_array()) { //types l_array* vector = r_b.array(); //to size int size_t index = 0; //cast if( r_c.is_int() ) index= (size_t)r_c.m_value.m_i; else if( r_c.is_float() )index= (size_t)r_c.m_value.m_f; else raise( "value isn't a valid key" ); //save last get_this() = stack(1); //get stack(1) = vector->operator[](index) ; } else if(r_b.is_table()) { //types l_table* table = r_b.table(); //is a string? if(!r_c.is_string()) raise( "value isn't a valid key" ); //save last get_this() = stack(1); //get and pop value stack(1) = table->operator[](r_c); } else { raise( "value isn't a vector/table, field not available" ); } } else { raise( "value isn't a vector/table/object, field not avaliable" ); } //pop index pop(); } break; case L_SET_AT_VAL: { //get table/array l_variable& r_a = stack(2); //get index const l_variable& r_b = stack(1); //try if ( r_a.is_object() ) { //is a vector if(r_a.is_array()) { //types l_array* vector = r_a.array(); //to size int size_t index = 0; //cast if( r_b.is_int() ) index= (size_t)r_b.m_value.m_i; else if( r_b.is_float() ) index= (size_t)r_b.m_value.m_f; else raise( "value isn't a valid key" ); //get and pop value vector->operator[](index) = pop(); } else if(r_a.is_table()) { //types l_table* table = r_a.table(); //is a string? if(!r_b.is_string()) raise( "value isn't a valid key" ); //get and pop value table->operator[](r_b) = pop(); } else { raise( "value isn't a vector/table, field not available" ); } } else { //pop value pop(); } //pop index pop(); //pop array/tablet pop(); } break; //for in case L_IT: { //get index l_variable& r_a = top(); //.. //try if ( r_a.is_object() ) { //get object l_obj* this_obj = (l_obj*)r_a.m_value.m_pobj; //is a vector if(r_a.is_array()) { //types l_array* vector = r_a.array(); //pop value pop(); //push it push( vector->get_it() ); } else if (r_a.is_table()) { //types l_table* table = r_a.table(); //pop value pop(); //push it push( table->get_it() ); } else if (r_a.to<l_xrange>()) { //types l_xrange* xrange = static_cast< l_xrange* > ( this_obj ); //pop value pop(); //push it push( xrange->get_it() ); } else { raise( "this value not have a iterator" ); } } else { //pop value pop(); //.. raise( "value isn't a table/array/object, iterator not supported" ); } } break; //for of case L_FOR_IN: case L_FOR_OF: { //get index l_variable& r_it = top(); //try if ( r_it.is_iterator() ) { //types l_iterator* l_it = r_it.iterator(); //is array it if(l_it) { //else assert assert(l_it); //push it if(l_it->valid()) { if(cmp.m_op_code == L_FOR_OF) { //get next push( l_it->get() ); } else //L_FOR_IN { //get next push( l_it->get_id() ); } //next l_it->self_next(); } else { //pop iterator pop(); //and jump pc = cmp.m_arg - 1; } } else { raise( "value isn't a valid iterator" ); } } else { //pop it pop(); //and jump pc = cmp.m_arg - 1; //... raise( "value isn't an iterator" ); } } break; case L_THIS_CALL: case L_CALL: { //get index register3(0) = pop(); //get args if( register3(0).is_cfunction() ) { //return size int n_return = register3(0).m_value.m_pcfun(this,cmp.m_arg); //assert (1 return) assert(n_return <= 1); //error if(n_return<0) { raise( "native call exception" ); } else if(n_return>1) { raise( "native call can't return more than a value" ); } //pop args for(int i=0; i < cmp.m_arg; ++i) { pop(); } //if return if(n_return) push(get_return()); } else if( register3(0).is_closer() ) { //get context l_closer* closer = register3(0).to<l_closer>(); //else assert if(!closer){ assert(0); }; //new function l_function& call_fun = m_vm->function(closer->get_fun_id()); //save last context l_variable last_ctx = register3(R_CONTEXT); //new context register3(1) = l_call_context::gc_new(get_gc()); l_call_context* new_ctx = register3(1).to<l_call_context>(); //this? if(cmp.m_op_code == L_THIS_CALL) { new_ctx->this_field() = get_this(); } //init new_ctx->init(*closer); //lock context new_ctx->lock(); //n args unsigned int n_fun_args = call_fun.m_args_size; //alloc array args..? if (call_fun.m_have_args_list) { //alloc array register3(3) = l_array::gc_new(get_gc()); } //put arguments for(unsigned int arg = 0; arg != cmp.m_arg; ++arg) { if (arg < n_fun_args) { new_ctx->variable( call_fun.constant(arg) ) = pop(); } else if (call_fun.m_have_args_list) { register3(3).array()->push(pop()); } else { pop(); } } //add var list if (call_fun.m_have_args_list) { //push array new_ctx->variable( call_fun.constant(n_fun_args) ) = register3(3); //to null register3(3) = l_variable(); } //save stack long stack_top_bf_call = m_top; //execute call type_return n_return = execute(*new_ctx); //error? if(n_return==T_RETURN_ERROR) { raise( "call exception" ); } //unlock context new_ctx->unlock(); //reset last context register3(R_CONTEXT) = last_ctx; //restore stack m_top = stack_top_bf_call; //return? if(n_return == T_RETURN_VALUE) { push(register3(2)); } } else { raise( "value isn't an function" ); } //dealloc if(cmp.m_op_code == L_THIS_CALL) { get_this() = l_variable(); } } break; default: break; } } return T_RETURN_VOID; }
void cgen(Node *n, int result, Node *nn) { Node *l, *r, nod; int lg, rg, xg, yg, g, o; long v; Prog *p1; if(n == Z || n->type == T) return; if(typesuv[n->type->etype]) { sugen(n, result, nn, n->type->width); return; } if(debug['g']) { if(result == D_TREE) prtree(nn, "result"); else print("result = %R\n", result); prtree(n, "cgen"); } l = n->left; r = n->right; o = n->op; if(n->addable >= INDEXED) { if(result == D_NONE) { if(nn == Z) switch(o) { default: nullwarn(Z, Z); break; case OINDEX: nullwarn(l, r); break; } return; } gmove(n->type, nn->type, D_TREE, n, result, nn); return; } v = 0; /* set */ switch(o) { default: diag(n, "unknown op in cgen: %O", o); break; case OAS: if(l->op == OBIT) goto bitas; /* * recursive use of result */ if(result == D_NONE) if(l->addable > INDEXED) if(l->complex < FNX) { cgen(r, D_TREE, l); break; } /* * function calls on both sides */ if(l->complex >= FNX && r->complex >= FNX) { cgen(r, D_TOS, r); v = argoff; lg = regaddr(result); lcgen(l, lg, Z); lg |= I_INDIR; adjsp(v - argoff); gmove(r->type, l->type, D_TOS, r, lg, l); if(result != D_NONE) gmove(l->type, nn->type, lg, l, result, nn); regfree(lg); break; } rg = D_TREE; lg = D_TREE; if(r->complex >= l->complex) { /* * right side before left */ if(result != D_NONE) { rg = regalloc(n->type, result); cgen(r, rg, n); } else if(r->complex >= FNX || r->addable < INDEXED) { rg = regalloc(r->type, result); cgen(r, rg, r); } if(l->addable < INDEXED) { lg = regaddr(lg); lcgen(l, lg, Z); lg |= I_INDIR; } } else { /* * left before right */ if(l->complex >= FNX || l->addable < INDEXED) { lg = regaddr(lg); lcgen(l, lg, Z); lg |= I_INDIR; } if(result != D_NONE) { rg = regalloc(n->type, result); cgen(r, rg, n); } else if(r->addable < INDEXED) { rg = regalloc(r->type, result); cgen(r, rg, r); } } if(result != D_NONE) { gmove(n->type, l->type, rg, r, lg, l); gmove(n->type, nn->type, rg, r, result, nn); } else gmove(r->type, l->type, rg, r, lg, l); regfree(lg); regfree(rg); break; bitas: n = l->left; rg = regalloc(tfield, result); if(l->complex >= r->complex) { lg = regaddr(D_NONE); lcgen(n, lg, Z); lg |= I_INDIR; cgen(r, rg, r); } else { cgen(r, rg, r); lg = regaddr(D_NONE); lcgen(n, lg, Z); lg |= I_INDIR; } g = regalloc(n->type, D_NONE); gmove(l->type, l->type, lg, l, g, l); bitstore(l, rg, lg, g, result, nn); break; case OBIT: if(result == D_NONE) { nullwarn(l, Z); break; } g = bitload(n, D_NONE, D_NONE, result, nn); gopcode(OAS, nn->type, g, n, result, nn); regfree(g); break; case ODOT: sugen(l, D_TREE, nodrat, l->type->width); if(result != D_NONE) { warn(n, "non-interruptable temporary"); nod = *nodrat; if(!r || r->op != OCONST) { diag(n, "DOT and no offset"); break; } nod.xoffset += r->vconst; nod.type = n->type; cgen(&nod, result, nn); } break; case OASLDIV: case OASLMOD: case OASDIV: case OASMOD: if(l->op == OBIT) goto asbitop; if(typefd[n->type->etype]) goto asbinop; rg = D_TREE; if(l->complex >= FNX || r->complex >= FNX) { rg = D_TOS; cgen(r, rg, r); v = argoff; } else if(r->addable < INDEXED) { rg = regalloc(n->type, D_NONE); cgen(r, rg, r); } lg = D_TREE; if(!simplv(l)) { lg = regaddr(D_NONE); lcgen(l, lg, Z); /* destroys register optimization */ lg |= I_INDIR; } g = regpair(result); gmove(l->type, n->type, lg, l, g, n); if(rg == D_TOS) adjsp(v - argoff); gopcode(o, n->type, rg, r, g, n); if(o == OASLMOD || o == OASMOD) gmove(n->type, l->type, g+1, n, lg, l); else gmove(n->type, l->type, g, n, lg, l); if(result != D_NONE) if(o == OASLMOD || o == OASMOD) gmove(n->type, nn->type, g+1, n, result, nn); else gmove(n->type, nn->type, g, n, result, nn); regfree(g); regfree(g+1); regfree(lg); regfree(rg); break; case OASXOR: case OASAND: case OASOR: if(l->op == OBIT) goto asbitop; if(l->complex >= FNX || l->addable < INDEXED || result != D_NONE || typefd[n->type->etype]) goto asbinop; rg = D_TREE; if(r->op != OCONST) { rg = regalloc(n->type, D_NONE); cgen(r, rg, r); } gopcode(o, l->type, rg, r, D_TREE, l); regfree(rg); break; case OASADD: case OASSUB: if(l->op == OBIT || l->complex >= FNX || l->addable < INDEXED || result != D_NONE || typefd[n->type->etype]) goto asbinop; v = vconst(r); if(v > 0 && v <= 8) { gopcode(o, n->type, D_TREE, r, D_TREE, l); break; } rg = regalloc(n->type, D_NONE); cgen(r, rg, r); gopcode(o, n->type, rg, r, D_TREE, l); regfree(rg); break; case OASLSHR: case OASASHR: case OASASHL: if(l->op == OBIT || l->complex >= FNX || l->addable < INDEXED || result != D_NONE || typefd[n->type->etype]) goto asbinop; rg = D_TREE; v = vconst(r); if(v <= 0 || v > 8) { rg = regalloc(n->type, D_NONE); cgen(r, rg, r); } lg = regalloc(n->type, D_NONE); cgen(l, lg, l); gopcode(o, n->type, rg, r, lg, l); gmove(n->type, n->type, lg, l, D_TREE, l); regfree(lg); regfree(rg); break; case OASLMUL: case OASMUL: asbinop: if(l->op == OBIT) goto asbitop; rg = D_TREE; if(l->complex >= FNX || r->complex >= FNX) { rg = D_TOS; cgen(r, rg, r); v = argoff; } else if(r->addable < INDEXED) { rg = regalloc(n->type, D_NONE); cgen(r, rg, r); } else { if(o == OASLSHR || o == OASASHR || o == OASASHL) { v = vconst(r); if(v <= 0 || v > 8) { rg = regalloc(n->type, D_NONE); cgen(r, rg, r); } } } lg = D_TREE; if(!simplv(l)) { lg = regaddr(D_NONE); lcgen(l, lg, Z); /* destroys register optimization */ lg |= I_INDIR; } g = regalloc(n->type, result); gmove(l->type, n->type, lg, l, g, n); if(rg == D_TOS) adjsp(v - argoff); if(o == OASXOR) if(rg == D_TREE) { rg = regalloc(n->type, D_NONE); cgen(r, rg, r); } if(o == OASXOR || o == OASLSHR || o == OASASHR || o == OASASHL) if(rg == D_TOS) { rg = regalloc(n->type, D_NONE); gmove(n->type, n->type, D_TOS, n, rg, n); } gopcode(o, n->type, rg, r, g, n); gmove(n->type, l->type, g, n, lg, l); if(result != D_NONE) gmove(n->type, nn->type, g, n, result, nn); regfree(g); regfree(lg); regfree(rg); break; asbitop: rg = regaddr(D_NONE); lg = regalloc(tfield, D_NONE); if(l->complex >= r->complex) { g = bitload(l, lg, rg, result, nn); xg = regalloc(r->type, D_NONE); cgen(r, xg, nn); } else { xg = regalloc(r->type, D_NONE); cgen(r, xg, nn); g = bitload(l, lg, rg, result, nn); } if(!typefd[n->type->etype]) { if(o == OASLDIV || o == OASDIV) { yg = regpair(result); gmove(tfield, n->type, g, l, yg, n); gopcode(o, n->type, xg, r, yg, n); gmove(n->type, tfield, yg, n, g, l); regfree(yg); regfree(yg+1); regfree(xg); bitstore(l, g, rg, lg, D_NONE, nn); break; } if(o == OASLMOD || o == OASMOD) { yg = regpair(result); gmove(tfield, n->type, g, l, yg, n); gopcode(o, n->type, xg, r, yg, n); gmove(n->type, tfield, yg+1, n, g, l); regfree(yg); regfree(yg+1); regfree(xg); bitstore(l, g, rg, lg, D_NONE, nn); break; } } yg = regalloc(n->type, result); gmove(tfield, n->type, g, l, yg, n); gopcode(o, n->type, xg, r, yg, n); gmove(n->type, tfield, yg, n, g, l); regfree(yg); regfree(xg); bitstore(l, g, rg, lg, D_NONE, nn); break; case OCAST: if(result == D_NONE) { nullwarn(l, Z); break; } lg = result; if(l->complex >= FNX) lg = regret(l->type); lg = eval(l, lg); if(nocast(l->type, n->type)) { gmove(n->type, nn->type, lg, l, result, nn); regfree(lg); break; } if(nocast(n->type, nn->type)) { gmove(l->type, n->type, lg, l, result, nn); regfree(lg); break; } rg = regalloc(n->type, result); gmove(l->type, n->type, lg, l, rg, n); gmove(n->type, nn->type, rg, n, result, nn); regfree(rg); regfree(lg); break; case OCOND: doinc(l, PRE); boolgen(l, 1, D_NONE, Z, l); p1 = p; inargs++; doinc(r->left, PRE); cgen(r->left, result, nn); doinc(r->left, POST); gbranch(OGOTO); patch(p1, pc); p1 = p; doinc(r->right, PRE); cgen(r->right, result, nn); doinc(r->right, POST); patch(p1, pc); inargs--; break; case OIND: if(result == D_NONE) { nullwarn(l, Z); break; } lg = nodalloc(types[TIND], result, &nod); nod.lineno = n->lineno; if(l->op == OADD) { if(l->left->op == OCONST) { nod.xoffset += l->left->vconst; l = l->right; } else if(l->right->op == OCONST) { nod.xoffset += l->right->vconst; l = l->left; } } cgen(l, lg, l); gmove(n->type, nn->type, D_TREE, &nod, result, nn); regfree(lg); break; case OFUNC: v = argoff; inargs++; gargs(r); lg = D_TREE; if(l->addable < INDEXED) { lg = regaddr(result); lcgen(l, lg, Z); lg |= I_INDIR; } inargs--; doinc(r, POST); doinc(l, POST); gopcode(OFUNC, types[TCHAR], D_NONE, Z, lg, l); regfree(lg); if(inargs) adjsp(v - argoff); if(result != D_NONE) { lg = regret(n->type); gmove(n->type, nn->type, lg, n, result, nn); } break; case OLDIV: case OLMOD: case ODIV: case OMOD: if(result == D_NONE) { nullwarn(l, r); break; } if(typefd[n->type->etype]) goto binop; if(r->addable >= INDEXED && r->complex < FNX) { lg = regpair(result); cgen(l, lg, l); rg = D_TREE; } else { cgen(r, D_TOS, r); v = argoff; lg = regpair(result); cgen(l, lg, l); adjsp(v - argoff); rg = D_TOS; } gopcode(o, n->type, rg, r, lg, l); if(o == OMOD || o == OLMOD) gmove(l->type, nn->type, lg+1, l, result, nn); else gmove(l->type, nn->type, lg, l, result, nn); regfree(lg); regfree(lg+1); break; case OMUL: case OLMUL: if(l->op == OCONST) if(mulcon(r, l, result, nn)) break; if(r->op == OCONST) if(mulcon(l, r, result, nn)) break; if(debug['M']) print("%L multiply\n", n->lineno); goto binop; case OAND: if(r->op == OCONST) if(typeil[n->type->etype]) if(l->op == OCAST) { if(typec[l->left->type->etype]) if(!(r->vconst & ~0xff)) { l = l->left; goto binop; } if(typeh[l->left->type->etype]) if(!(r->vconst & ~0xffff)) { l = l->left; goto binop; } } goto binop; case OADD: if(result == D_TOS) if(r->addable >= INDEXED) if(l->op == OCONST) if(typeil[l->type->etype]) { v = l->vconst; if(v > -32768 && v < 32768) { rg = regaddr(D_NONE); gmove(r->type, r->type, D_TREE, r, rg, r); gopcode(OADDR, types[TSHORT], D_NONE, Z, rg, r); p->to.offset = v; p->to.type |= I_INDIR; regfree(rg); break; } } case OSUB: if(result == D_TOS) if(l->addable >= INDEXED) if(r->op == OCONST) if(typeil[r->type->etype]) { v = r->vconst; if(v > -32768 && v < 32768) { if(n->op == OSUB) v = -v; lg = regaddr(D_NONE); gmove(l->type, l->type, D_TREE, l, lg, l); gopcode(OADDR, types[TSHORT], D_NONE, Z, lg, l); p->to.offset = v; p->to.type |= I_INDIR; regfree(lg); break; } } goto binop; case OOR: case OXOR: binop: if(result == D_NONE) { nullwarn(l, r); break; } if(l->complex >= FNX && r->complex >= FNX) { cgen(r, D_TOS, r); v = argoff; lg = regalloc(l->type, result); cgen(l, lg, l); adjsp(v - argoff); if(o == OXOR) { rg = regalloc(r->type, D_NONE); gmove(r->type, r->type, D_TOS, r, rg, r); gopcode(o, n->type, rg, r, lg, l); regfree(rg); } else gopcode(o, n->type, D_TOS, r, lg, l); gmove(n->type, nn->type, lg, l, result, nn); regfree(lg); break; } if(l->complex >= r->complex) { if(l->op == OADDR && (o == OADD || o == OSUB)) lg = regaddr(result); else lg = regalloc(l->type, result); cgen(l, lg, l); rg = eval(r, D_NONE); } else { rg = regalloc(r->type, D_NONE); cgen(r, rg, r); lg = regalloc(l->type, result); cgen(l, lg, l); } if(o == OXOR) { if(rg == D_TREE) { rg = regalloc(r->type, D_NONE); cgen(r, rg, r); } if(rg == D_TOS) { rg = regalloc(r->type, D_NONE); gmove(r->type, r->type, D_TOS, r, rg, r); } } gopcode(o, n->type, rg, r, lg, l); gmove(n->type, nn->type, lg, l, result, nn); regfree(lg); regfree(rg); break; case OASHL: if(r->op == OCONST) if(shlcon(l, r, result, nn)) break; case OLSHR: case OASHR: if(result == D_NONE) { nullwarn(l, r); break; } if(l->complex >= FNX && r->complex >= FNX) { cgen(r, D_TOS, r); v = argoff; lg = regalloc(l->type, result); cgen(l, lg, l); adjsp(v - argoff); rg = regalloc(r->type, D_NONE); gopcode(OAS, r->type, D_TOS, r, rg, r); gopcode(n->op, n->type, rg, r, lg, l); gmove(n->type, nn->type, lg, l, result, nn); regfree(lg); regfree(rg); break; } if(l->complex >= r->complex) { lg = regalloc(l->type, result); cgen(l, lg, l); v = vconst(r); if(v <= 0 || v > 8) { rg = regalloc(r->type, D_NONE); cgen(r, rg, r); } else rg = eval(r, D_NONE); } else { rg = regalloc(r->type, D_NONE); cgen(r, rg, r); lg = regalloc(l->type, result); cgen(l, lg, l); } gopcode(o, n->type, rg, r, lg, l); gmove(n->type, nn->type, lg, l, result, nn); regfree(lg); regfree(rg); break; case ONEG: case OCOM: if(result == D_NONE) { nullwarn(l, Z); break; } lg = regalloc(l->type, result); cgen(l, lg, l); gopcode(o, l->type, D_NONE, Z, lg, l); gmove(n->type, nn->type, lg, l, result, nn); regfree(lg); break; case OADDR: if(result == D_NONE) { nullwarn(l, Z); break; } lcgen(l, result, nn); break; case OEQ: case ONE: case OLE: case OLT: case OGE: case OGT: case OLO: case OLS: case OHI: case OHS: if(result == D_NONE) { nullwarn(l, r); break; } boolgen(n, 1, result, nn, Z); break; case OANDAND: case OOROR: boolgen(n, 1, result, nn, Z); if(result == D_NONE) patch(p, pc); break; case OCOMMA: cgen(l, D_NONE, l); doinc(l, POST); doinc(r, PRE); cgen(r, result, nn); break; case ONOT: if(result == D_NONE) { nullwarn(l, Z); break; } boolgen(n, 1, result, nn, Z); break; case OPOSTINC: case OPOSTDEC: v = 1; if(l->type->etype == TIND) v = l->type->link->width; if(o == OPOSTDEC) v = -v; if(l->op == OBIT) goto bitinc; if(nn == Z) goto pre; lg = D_TREE; if(l->addable < INDEXED) { lg = regaddr(D_NONE); lcgen(l, lg, Z); lg |= I_INDIR; } if(result != D_NONE) gmove(l->type, nn->type, lg, l, result, nn); if(typefd[n->type->etype]) { rg = regalloc(n->type, D_NONE); gmove(l->type, l->type, lg, l, rg, l); gopcode(o, n->type, D_CONST, nodconst(1), rg, l); gmove(l->type, l->type, rg, l, lg, l); regfree(rg); } else { if(v < 0) gopcode(o, n->type, D_CONST, nodconst(-v), lg, l); else gopcode(o, n->type, D_CONST, nodconst(v), lg, l); } regfree(lg); break; case OPREINC: case OPREDEC: v = 1; if(l->type->etype == TIND) v = l->type->link->width; if(o == OPREDEC) v = -v; if(l->op == OBIT) goto bitinc; pre: lg = D_TREE; if(l->addable < INDEXED) { lg = regaddr(D_NONE); lcgen(l, lg, Z); lg |= I_INDIR; } if(typefd[n->type->etype]) { rg = regalloc(n->type, D_NONE); gmove(l->type, l->type, lg, l, rg, l); gopcode(o, n->type, D_CONST, nodconst(1), rg, l); gmove(l->type, l->type, rg, l, lg, l); regfree(rg); } else { if(v < 0) gopcode(o, n->type, D_CONST, nodconst(-v), lg, l); else gopcode(o, n->type, D_CONST, nodconst(v), lg, l); } if(result != D_NONE) gmove(l->type, nn->type, lg, l, result, nn); regfree(lg); break; bitinc: rg = regaddr(D_NONE); lg = regalloc(tfield, D_NONE); if(result != D_NONE && (o == OPOSTINC || o == OPOSTDEC)) { g = bitload(l, lg, rg, D_NONE, nn); if(nn != Z) gmove(l->type, nn->type, g, l, result, nn); if(v < 0) gopcode(o, n->type, D_CONST, nodconst(-v), g, n); else gopcode(o, n->type, D_CONST, nodconst(v), g, n); bitstore(l, g, rg, lg, D_NONE, nn); break; } g = bitload(l, lg, rg, result, nn); if(v < 0) gopcode(o, n->type, D_CONST, nodconst(-v), g, n); else gopcode(o, n->type, D_CONST, nodconst(v), g, n); if(result != D_NONE) gmove(l->type, nn->type, g, l, result, nn); bitstore(l, g, rg, lg, D_NONE, nn); break; } }