#include "gc.h"

void
noretval(int n)
{

       if(n & 1) {
               gins(ANOP, Z, Z);
               p->to.type = D_REG;
               p->to.reg = REGRET;
       }
       if(n & 2) {
               gins(ANOP, Z, Z);
               p->to.type = D_FREG;
               p->to.reg = FREGRET;
       }
}

/*
*      calculate addressability as follows
*              CONST ==> 20            $value
*              NAME ==> 10             name
*              REGISTER ==> 11         register
*              INDREG ==> 12           *[(reg)+offset]
*              &10 ==> 2               $name
*              ADD(2, 20) ==> 2        $name+offset
*              ADD(3, 20) ==> 3        $(reg)+offset
*              &12 ==> 3               $(reg)+offset
*              *11 ==> 11              ??
*              *2 ==> 10               name
*              *3 ==> 12               *(reg)+offset
*      calculate complexity (number of registers)
*/
void
xcom(Node *n)
{
       Node *l, *r;
       int t;

       if(n == Z)
               return;
       l = n->left;
       r = n->right;
       n->addable = 0;
       n->complex = 0;
       switch(n->op) {
       case OCONST:
               n->addable = 20;
               return;

       case OREGISTER:
               n->addable = 11;
               return;

       case OINDREG:
               n->addable = 12;
               return;

       case ONAME:
               n->addable = 10;
               return;

       case OADDR:
               xcom(l);
               if(l->addable == 10)
                       n->addable = 2;
               if(l->addable == 12)
                       n->addable = 3;
               break;

       case OIND:
               xcom(l);
               if(l->addable == 11)
                       n->addable = 12;
               if(l->addable == 3)
                       n->addable = 12;
               if(l->addable == 2)
                       n->addable = 10;
               break;

       case OADD:
               xcom(l);
               xcom(r);
               if(l->addable == 20) {
                       if(r->addable == 2)
                               n->addable = 2;
                       if(r->addable == 3)
                               n->addable = 3;
               }
               if(r->addable == 20) {
                       if(l->addable == 2)
                               n->addable = 2;
                       if(l->addable == 3)
                               n->addable = 3;
               }
               break;

       case OASLMUL:
       case OASMUL:
               xcom(l);
               xcom(r);
               t = vlog(r);
               if(t >= 0) {
                       n->op = OASASHL;
                       r->vconst = t;
                       r->type = types[TINT];
               }
               break;

       case OMUL:
       case OLMUL:
               if(typev[n->type->etype]){
                       /* try to lift 32->64 bit cast */
                       if(typev[l->type->etype] && l->op == OCAST && typeil[l->left->type->etype]
                       && typeu[n->type->etype] == typeu[l->left->type->etype])
                               l = l->left;
                       if(typev[r->type->etype] && r->op == OCAST && typeil[r->left->type->etype]
                       && typeu[n->type->etype] == typeu[r->left->type->etype])
                               r = r->left;

                       if(typeil[l->type->etype] && typeil[r->type->etype]){
                               n->left = l;
                               n->right = r;
                               xcom(l);
                               xcom(r);
                               break;
                       }
                       l = n->left;
                       r = n->right;
               }
               xcom(l);
               xcom(r);
               t = vlog(r);
               if(t >= 0) {
                       n->op = OASHL;
                       r->vconst = t;
                       r->type = types[TINT];
               }
               t = vlog(l);
               if(t >= 0) {
                       n->op = OASHL;
                       n->left = r;
                       n->right = l;
                       r = l;
                       r->vconst = t;
                       r->type = types[TINT];
               }
               break;

       case OASLDIV:
               xcom(l);
               xcom(r);
               t = vlog(r);
               if(t >= 0) {
                       n->op = OASLSHR;
                       r->vconst = t;
                       r->type = types[TINT];
               }
               break;

       case OLDIV:
               xcom(l);
               xcom(r);
               t = vlog(r);
               if(t >= 0) {
                       n->op = OLSHR;
                       r->vconst = t;
                       r->type = types[TINT];
               }
               break;

       case OASLMOD:
               xcom(l);
               xcom(r);
               t = vlog(r);
               if(t >= 0) {
                       n->op = OASAND;
                       r->vconst--;
               }
               break;

       case OLMOD:
               xcom(l);
               xcom(r);
               t = vlog(r);
               if(t >= 0) {
                       n->op = OAND;
                       r->vconst--;
               }
               break;

       case OOR:
               xcom(l);
               xcom(r);
               if(typeil[n->type->etype])
                       rolor(n);
               break;

       default:
               if(l != Z)
                       xcom(l);
               if(r != Z)
                       xcom(r);
               break;
       }
       if(n->addable >= 10)
               return;
       l = n->left;
       r = n->right;
       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 OXOR:
       case OAND:
       case OOR:
       case OEQ:
       case ONE:
               /*
                * immediate operators, make const on right
                */
               if(l->op == OCONST) {
                       n->left = r;
                       n->right = l;
               }
               break;
       }
}