#include "chibicc.h"
#define TYPE_C "type.c"


Type *ty_void = &(Type){TY_VOID, 1, 1};
Type *ty_bool = &(Type){TY_BOOL, 1, 1, true};

Type *ty_char = &(Type){TY_CHAR, 1, 1};
Type *ty_short = &(Type){TY_SHORT, 2, 2};
Type *ty_int = &(Type){TY_INT, 4, 4};
Type *ty_long = &(Type){TY_LONG, 8, 8};

Type *ty_uchar = &(Type){TY_CHAR, 1, 1, true};
Type *ty_ushort = &(Type){TY_SHORT, 2, 2, true};
Type *ty_uint = &(Type){TY_INT, 4, 4, true};
Type *ty_ulong = &(Type){TY_LONG, 8, 8, true};

Type *ty_llong = &(Type){TY_LLONG, 8, 8};
Type *ty_ullong = &(Type){TY_LLONG, 8, 8, true};

Type *ty_float = &(Type){TY_FLOAT, 4, 4};
Type *ty_double = &(Type){TY_DOUBLE, 8, 8};
Type *ty_ldouble = &(Type){TY_LDOUBLE, 16, 16};
Type *ty_void_ptr = &(Type){TY_PTR, 8, 8, true};

Type *ty_int128 = &(Type){TY_INT128, 16, 16}; 
Type *ty_uint128 = &(Type){TY_INT128, 16, 16, true}; 


static Type *new_type(TypeKind kind, int64_t size, int align)
{
  Type *ty = calloc(1, sizeof(Type));
  if (ty == NULL)
    error("%s: %s:%d: error: in new_type ty is null!", TYPE_C, __FILE__, __LINE__);
  ty->kind = kind;
  ty->size = size;
  ty->align = align;
  if (ty->kind == TY_INT128)
    ty->is_aligned = true;
  return ty;
}

Type *new_qualified_type(Type *ty) {
  if (ty->origin)
    ty = ty->origin;

  Type *ret = calloc(1, sizeof(Type));
  *ret = *ty;
  ret->origin = ty;

  if (ty->size < 0) {
    ret->decl_next = ty->decl_next;
    ty->decl_next = ret;
  }
  return ret;
}

bool is_integer(Type *ty)
{
  TypeKind k = ty->kind;
  return k == TY_BOOL || k == TY_CHAR || k == TY_SHORT || k == TY_INT128 ||
         k == TY_INT || k == TY_LONG ||  k == TY_LLONG || k == TY_ENUM;
}

bool is_flonum(Type *ty)
{
  return ty->kind == TY_FLOAT || ty->kind == TY_DOUBLE ||
         ty->kind == TY_LDOUBLE;
}


bool is_array(Type *ty) {
  return ty && (ty->kind == TY_ARRAY || ty->kind == TY_VLA);
}

bool is_bitfield(Node *node) {
  return node->kind == ND_MEMBER && node->member->is_bitfield;
}

static bool is_bitfield2(Node *node, int *width) {
  switch (node->kind) {
  case ND_ASSIGN:
    return is_bitfield2(node->lhs, width);
  case ND_COMMA:
    return is_bitfield2(node->rhs, width);
  case ND_STMT_EXPR: {
    Node *stmt = node->body;
    while (stmt->next)
      stmt = stmt->next;
    if (stmt->kind == ND_EXPR_STMT)
      return is_bitfield2(stmt->lhs, width);
  }
  case ND_MEMBER:
    if (!node->member->is_bitfield)
      return false;
    *width = node->member->bit_width;
    return true;
  }
  return false;
}


int int_rank(Type *t) {
  switch (t->kind) {
    case TY_ENUM:
    case TY_BOOL:
    case TY_CHAR:
    case TY_SHORT:
      return 0;
    case TY_INT:
      return 1;
    case TY_LONG:
      return 2;
    case TY_LLONG:
      return 3;
  }
  printf("======%d\n", t->kind);
  unreachable();
}

static void int_promotion(Node **node) {
  Type *ty = (*node)->ty;
  int bit_width;

  if (is_bitfield2(*node, &bit_width)) {
    int int_width = ty_int->size * 8;
    //int bit_width = (*node)->member->bit_width;

    if (bit_width == int_width && ty->is_unsigned) {
      *node = new_cast(*node, ty_uint);
    } else if (bit_width <= int_width) {
      *node = new_cast(*node, ty_int);
    } else {
      *node = new_cast(*node, ty);
    }
    return;
  }

  if (ty->size < ty_int->size) {
    *node = new_cast(*node, ty_int);
    return;
  }

  if (ty->size == ty_int->size && int_rank(ty) < int_rank(ty_int)) {
    if (ty->is_unsigned)
      *node = new_cast(*node, ty_uint);
    else
      *node = new_cast(*node, ty_int);
    return;
  }

}


bool is_numeric(Type *ty)
{
  return is_integer(ty) || is_flonum(ty);
}

bool is_compatible(Type *t1, Type *t2)
{
  if (t1 == t2)
    return true;

  if (t1->origin)
    return is_compatible(t1->origin, t2);

  if (t2->origin)
    return is_compatible(t1, t2->origin);

  if (t1->kind != t2->kind)
    return false;

  if ((t1->kind == TY_VLA && t2->kind == TY_VLA) ||
    (t1->kind == TY_VLA && t2->kind == TY_ARRAY) ||
    (t1->kind == TY_ARRAY && t2->kind == TY_VLA))
    return is_compatible(t1->base, t2->base);
  if(is_vector(t1) && is_vector(t2))
    return is_compatible(t1->base, t2->base);

  switch (t1->kind)
  {
  case TY_CHAR:
  case TY_SHORT:
  case TY_INT:
  case TY_LONG:
  case TY_LLONG:
    return t1->is_unsigned == t2->is_unsigned;
  case TY_FLOAT:
  case TY_DOUBLE:
  case TY_LDOUBLE:
    return true;
  case TY_INT128: 
    return t1->is_unsigned == t2->is_unsigned;     
  case TY_PTR:
    return is_compatible(t1->base, t2->base);
  case TY_FUNC:
  {
    if (!is_compatible(t1->return_ty, t2->return_ty))
      return false;
    if (t1->is_variadic != t2->is_variadic)
      return false;

    Type *p1 = t1->params;
    Type *p2 = t2->params;
    for (; p1 && p2; p1 = p1->next, p2 = p2->next)
      if (!is_compatible(p1, p2))
        return false;
    return p1 == NULL && p2 == NULL;
  }
  case TY_ARRAY:
    if (!is_compatible(t1->base, t2->base))
      return false;
    return t1->array_len < 0 && t2->array_len < 0 &&
           t1->array_len == t2->array_len;
  case TY_VECTOR:
    if (!is_compatible(t1->base, t2->base))
      return false;
    return t1->array_len < 0 && t2->array_len < 0 &&
           t1->array_len == t2->array_len;           
  }
  return false;
}

Type *copy_type(Type *ty)
{
  Type *ret = calloc(1, sizeof(Type));
  if (ret == NULL)
    error("%s: %s:%d: error: in copy_type ret is null!", TYPE_C, __FILE__, __LINE__);
  *ret = *ty;
  ret->origin = ty;
  return ret;
}

Type *pointer_to(Type *base)
{
  Type *ty = new_type(TY_PTR, 8, 8);
  ty->base = base;
  ty->is_pointer = true;
  ty->pointertype = base;
  ty->is_unsigned = true;
  ty->is_vector = base->is_vector;
  return ty;
}

Type *func_type(Type *return_ty)
{
  // The C spec disallows sizeof(<function type>), but
  // GCC allows that and the expression is evaluated to 1.
  Type *ty = new_type(TY_FUNC, 1, 1);
  ty->return_ty = return_ty;
  ty->is_constructor = false;
  ty->is_destructor = false;
  ty->destructor_priority = 0;
  ty->constructor_priority = 0;  
  return ty;
}

Type *array_of(Type *base, int64_t len)
{
  if (!base)
  error("%s %d: in array_of : base is null", TYPE_C, __LINE__); 
  Type *ty = new_type(TY_ARRAY, base->size * len, base->align);
  ty->base = base;
  ty->array_len = len;  
  ty->has_vla = base->has_vla; 
  return ty;
}


Type *vector_of(Type *base, int64_t len)
{
  if (!base)
    error("%s %d: in vector_of : base is null", TYPE_C, __LINE__); 
  Type *ty = new_type(TY_VECTOR, base->size * len, base->align);
  int total_size = base->size * len;
  ty->size = total_size;
  ty->base = base;
  ty->array_len = len;  
  ty->has_vla = base->has_vla; 
  ty->is_vector = true;
  return ty;
}


Type *vla_of(Type *base, Node *len)
{

  Type *ty = new_type(TY_VLA, 8, 8);
  ty->base = base;
  ty->vla_len = len;
  ty->has_vla = true;
  return ty;

}




Type *enum_type(void)
{
  return new_type(TY_ENUM, 4, 4);
}

Type *struct_type(void)
{
  return new_type(TY_STRUCT, 0, 1);
}

Type *array_to_pointer(Type *ty) {
  if (ty->base && ty->kind != TY_PTR)
    return pointer_to(ty->base);
  return ty;
}

bool is_nullptr(Node *n) {
    return n->kind == ND_NUM && n->val == 0;
}


static Type *get_common_type(Node **lhs, Node **rhs)
{
  Type *ty1 = (*lhs)->ty;
  Type *ty2 = (*rhs)->ty;
  //======ISS-158 trying to fix issue with "parse.c: in struct_ref : not a struct nor a union" when in a macro definition we have (size_t)-1 ? NULL : (n) - 1
  //assuming that if one is void it returns the second type that could be void also or different type.
  if (!ty2) {
    return ty1;
  }

  if (ty1->base) {
    if (ty1->base->kind == TY_VOID)
      if (ty2->base)
        return pointer_to(ty2->base);  
    return pointer_to(ty1->base);
  }

  if (ty1->base && is_nullptr(*rhs))
    return array_to_pointer(ty1);
  if (ty2->base && is_nullptr(*lhs))
    return array_to_pointer(ty2);

  if (ty1->kind == TY_FUNC)
    return pointer_to(ty1);
  if (ty2->kind == TY_FUNC)
    return pointer_to(ty2);

  if (ty1->kind == TY_LDOUBLE || ty2->kind == TY_LDOUBLE)
    return ty_ldouble;
  if (ty1->kind == TY_DOUBLE || ty2->kind == TY_DOUBLE)
    return ty_double;
  if (ty1->kind == TY_FLOAT || ty2->kind == TY_FLOAT)
    return ty_float;

  if (ty1->kind == TY_INT128 || ty2->kind == TY_INT128) {
    if( ty1->is_unsigned || ty2->is_unsigned) 
      return ty_uint128;
    else
      return ty_int128;
  }

  if (ty1->kind == TY_STRUCT || ty1->kind == TY_UNION) {
    if (is_compatible(ty1, ty2))
        return ty1;  
  }

  if (ty2->kind == TY_STRUCT || ty2->kind == TY_UNION) {
    if (is_compatible(ty1, ty2))
        return ty2;
  }


  if (ty1->kind == TY_PTR)
      return ty1;
  if (ty2->kind == TY_PTR)
      return ty2;


  int_promotion(lhs);
  int_promotion(rhs);
  ty1 = (*lhs)->ty;
  ty2 = (*rhs)->ty;

  if (ty1->size != ty2->size)
    return (ty1->size < ty2->size) ? ty2 : ty1;

  Type *ranked_ty = int_rank(ty1) > int_rank(ty2) ? ty1 : ty2;

  if (ty1->is_unsigned == ty2->is_unsigned)
    return ranked_ty;

  // If same size but different sign, the common type is unsigned
  // variant of the highest-ranked type between the two.
  switch (ranked_ty->kind) {
    case TY_INT:
      return ty_uint;
    case TY_LONG:
      return ty_ulong;
    case TY_LLONG:
      return ty_ullong;
  }
  unreachable();

}

// For many binary operators, we implicitly promote operands so that
// both operands have the same type. Any integral type smaller than
// int is always promoted to int. If the type of one operand is larger
// than the other's (e.g. "long" vs. "int"), the smaller operand will
// be promoted to match with the other.
//
// This operation is called the "usual arithmetic conversion".
static void usual_arith_conv(Node **lhs, Node **rhs)
{
  Type *ty = get_common_type(lhs, rhs);
  *lhs = new_cast(*lhs, ty);
  *rhs = new_cast(*rhs, ty);
  
}


bool is_vector(Type *ty) {
  return ty && ty->kind == TY_VECTOR;
}

bool is_int128(Type *ty) {
  return ty && ty->kind == TY_INT128;
}

bool is_pointer(Type *ty) {
  return ty && ty->kind == TY_PTR;
}

void add_type(Node *node)
{
  if (!node || node->ty)
    return;

  add_type(node->lhs);
  add_type(node->rhs);
  add_type(node->cond);
  add_type(node->then);
  add_type(node->els);
  add_type(node->init);
  add_type(node->inc);

  for (Node *n = node->body; n; n = n->next)
    add_type(n);
  for (Node *n = node->args; n; n = n->next)
    add_type(n);

  switch (node->kind)
  {
  case ND_NUM:  
    node->ty = ty_int;
    return;
  case ND_ADD:
  case ND_SUB:
  case ND_MUL:
  case ND_DIV:
  case ND_MOD:
  case ND_BITAND:
  case ND_BITOR:
  case ND_BITXOR:    
    if (is_vector(node->lhs->ty) && is_vector(node->rhs->ty)) {
          node->ty = node->lhs->ty;
    } else {

        usual_arith_conv(&node->lhs, &node->rhs);
        node->ty = node->lhs->ty;
    }
    return;
  case ND_POS:
  case ND_NEG:
    if (!is_numeric(node->lhs->ty) && !is_vector(node->lhs->ty))
      error_tok(node->lhs->tok, "%s %d: in add_type: invalid operand", TYPE_C, __LINE__);
    if (is_integer(node->lhs->ty))
      int_promotion(&node->lhs);
    node->ty = node->lhs->ty;
    return;  
  case ND_ASSIGN:
    if (node->lhs->ty->kind == TY_ARRAY)
      error_tok(node->lhs->tok, "%s %d: not an lvalue", TYPE_C, __LINE__);
    if (node->lhs->ty->kind != TY_STRUCT && node->lhs->ty->kind != TY_UNION)
      node->rhs = new_cast(node->rhs, node->lhs->ty);
    node->ty = node->lhs->ty;
    return;
  case ND_EQ:
  case ND_NE:
  case ND_LT:
  case ND_LE:
    usual_arith_conv(&node->lhs, &node->rhs);
    node->ty = ty_int;
    return;
  case ND_ALLOC:
    add_type(node->lhs);  
  case ND_FUNCALL:
    node->ty = node->func_ty->return_ty;
    return;
  case ND_NOT:
  case ND_LOGOR:
  case ND_LOGAND:
    node->ty = ty_int;
    return;
  case ND_BITNOT:
  case ND_SHL:
  case ND_SHR:
    //node->ty = node->lhs->ty;  
    if (!is_integer(node->lhs->ty) && !is_vector(node->lhs->ty))
      error_tok(node->tok, "%s %d %d invalid operand ", TYPE_C, __LINE__, node->kind);
    if (is_integer(node->lhs->ty))
      int_promotion(&node->lhs);
    node->ty = node->lhs->ty;       
    return;
  case ND_VAR:
      if (!node->var) {
        error_tok(node->tok, "%s %d %d variable undefined ", TYPE_C, __LINE__, node->kind);
      }
  case ND_VLA_PTR:
    node->ty = node->var->ty;
    return;
  case ND_COND: {

    Type *lt = node->then->ty;
    Type *rt = node->els->ty;
    if (lt->kind == TY_VOID && rt->kind == TY_VOID)
    {
      node->ty = ty_void;
    }
    else if (!is_numeric(node->then->ty) && is_compatible(node->then->ty, node->els->ty)) {
      node->ty = array_to_pointer(node->then->ty);
    }
    else
    {
      usual_arith_conv(&node->then, &node->els);
      node->ty = node->then->ty;
    }
    return;
  }
  case ND_COMMA:
    node->ty = node->rhs->ty;
    return;
  case ND_MEMBER:
    node->ty = node->member->ty;
    return;
  case ND_ADDR: {
    Type *ty = node->lhs->ty;
  //from @fuhsnn add_type():Remove overaggressive array decaying
    node->ty = pointer_to(ty);
    return;
  }
  case ND_DEREF:
    if (!node->lhs->ty->base) {
      //ISS-163 trying to fix issue with pointer dereference
      if (node->lhs->ty)
        node->lhs->ty->base = node->lhs->ty;
      else
        error_tok(node->tok, "%s %d: invalid pointer dereference", TYPE_C, __LINE__);
    }
    //======ISS-154 trying to fix deferencing pointer issue when we have a macro that can return a pointer or null  (self) ? NULL      
    //printf("======%d %d %s\n", node->lhs->ty->base->kind, node->lhs->ty->kind, node->lhs->tok->loc);
    if (node->lhs->ty->base->kind == TY_VOID && node->lhs->ty->kind == TY_VOID)
      error_tok(node->tok, "%s %d : dereferencing a void pointer", TYPE_C, __LINE__);
    if (node->lhs->ty->base->kind == TY_VOID)
      node->lhs->ty->base = node->lhs->ty;
    node->ty = node->lhs->ty->base;
    return;
  case ND_STMT_EXPR:
    if (node->body) {
      Node *stmt = node->body;
      while (stmt->next) {
        stmt = stmt->next;
        add_type(stmt);
      }
      while (stmt->kind == ND_LABEL) {
        stmt = stmt->lhs;
        add_type(stmt);
      }
      if (stmt->kind == ND_EXPR_STMT)
      {
        node->ty = stmt->lhs->ty;
        return;
      }
    }
    //trying to fix =====ISS-144 compiling util-linux failed with expression returning void is not supported
    //error_tok(node->tok, "%s statement expression returning void is not supported", TYPE_C);
    return;
  case ND_LABEL_VAL:
    node->ty = pointer_to(ty_void);
    return;
  case ND_CAS:  
    add_type(node->cas_addr);
    add_type(node->cas_old);
    add_type(node->cas_new);
    node->ty = ty_bool;
    return;
  case ND_CAS_N:
    node->ty = ty_bool;
    return;
  case ND_BUILTIN_MEMSET:    
  case ND_BUILTIN_MEMCPY:
    node->ty = ty_void_ptr;
    return;
  case ND_PSADBW:
  case ND_PMULUDQ:
    node->ty = vector_of(ty_ulong, 1);
    return;
  case ND_PMULUDQ128:
    node->ty = vector_of(ty_ulong, 2);
    return;
  case ND_PXOR:
  case ND_POR:
  case ND_PAND:
  case ND_PANDN:
  case ND_PSRLQ:
  case ND_PSRLQI:
  case ND_PSLLQI:
  case ND_PSLLQ:
  case ND_PSUBQ:
  case ND_PADDQ:
  case ND_MOVQ128:
    node->ty = vector_of(ty_long, 1);
    return;
  case ND_PCMPGTD:
  case ND_PCMPEQD:
  case ND_PSRADI:
  case ND_PSRAD:
  case ND_PSLLDI:
  case ND_PSLLD:
  case ND_PSUBD:
  case ND_PADDD:
  case ND_PUNPCKLDQ:
  case ND_PUNPCKHDQ:
  case ND_VECINITV2SI:  
  case ND_CVTPS2PI:  
  case ND_CVTTPS2PI:
  case ND_CVTPD2PI:
  case ND_CVTTPD2PI:
    node->ty = vector_of(ty_int, 2);
    return;   
  case ND_LDDQU:
    node->ty = vector_of(ty_int, 16); 
    return;
  case ND_CVTPD2DQ:
  case ND_CVTTPD2DQ:
  case ND_CVTPS2DQ:
  case ND_CVTTPS2DQ:
  case ND_PSIGND128:
  case ND_PABSD128:
  case ND_PMINSD128:
  case ND_PMAXSD128:
  case ND_PMINUD128:
  case ND_PMAXUD128:
    node->ty = vector_of(ty_int, 4);
    return;   
  case ND_CMPUNORDPS:
  case ND_CMPORDPS:
  case ND_CMPNGEPS:
  case ND_CMPNGTPS:
  case ND_CMPNLEPS:
  case ND_CMPNLTPS:
  case ND_CMPNEQPS:
  case ND_CMPGEPS:
  case ND_CMPGTPS:
  case ND_CMPLEPS:
  case ND_CMPLTPS:
  case ND_CMPEQPS:
  case ND_CMPUNORDSS:
  case ND_CMPORDSS:
  case ND_CMPNLESS:
  case ND_CMPNLTSS:
  case ND_CMPNEQSS:
  case ND_MOVSS:
  case ND_CMPLESS:
  case ND_CMPLTSS:
  case ND_CMPEQSS:
  case ND_XORPS:
  case ND_ORPS:
  case ND_ANDNPS:
  case ND_ANDPS:
  case ND_MAXPS:
  case ND_MINPS:
  case ND_RSQRTPS:
  case ND_RCPPS:
  case ND_SQRTPS:   
  case ND_MAXSS:
  case ND_MINSS:
  case ND_RSQRTSS:
  case ND_RCPSS:
  case ND_SQRTSS: 
  case ND_DIVSS:
  case ND_MULSS:
  case ND_SUBSS:
  case ND_ADDSS:
  case ND_CVTPI2PS:
  case ND_CVTSI2SS:
  case ND_CVTSI642SS:
  case ND_MOVLHPS:
  case ND_MOVHLPS:
  case ND_UNPCKHPS:
  case ND_UNPCKLPS:
  case ND_LOADHPS:
  case ND_LOADLPS:
  case ND_SHUFPS:
  case ND_SHUFFLE:
  case ND_PMAXSW:
  case ND_PMINSW:
  case ND_SHUFPD:
  case ND_CVTDQ2PS:
  case ND_CVTPD2PS:
  case ND_CVTSD2SS:
  case ND_ADDSUBPS:
  case ND_HADDPS:
  case ND_HSUBPS:
  case ND_MOVSHDUP:
  case ND_MOVSLDUP:
  case ND_BLENDVPS:
    node->ty = vector_of(ty_float, 4);
    return;  
  case ND_EXPECT:
    add_type(node->rhs);
    add_type(node->lhs);
    node->ty = node->lhs->ty;
    return;
  case ND_ABORT:
    return;
  case ND_STORELPS:
  case ND_STOREHPS:    
  case ND_LDMXCSR:
  case ND_STMXCSR:
  case ND_MASKMOVQ:
  case ND_MOVNTQ:
  case ND_MOVNTPS:
  case ND_MASKMOVDQU:
  case ND_MOVNTI:
  case ND_MOVNTI64:
  case ND_MOVNTDQ:
  case ND_SLWPCB:
    node->ty = ty_void_ptr;
    return;
  case ND_CLFLUSH:
  case ND_BUILTIN_FRAME_ADDRESS:
  case ND_RETURN_ADDR:
    add_type(node->lhs);
    node->ty = ty_void_ptr;
    return;
  case ND_BUILTIN_SUB_OVERFLOW:
  case ND_BUILTIN_MUL_OVERFLOW:
  case ND_BUILTIN_ADD_OVERFLOW:
  case ND_UMULLL_OVERFLOW:
  case ND_UMULL_OVERFLOW:
  case ND_UMUL_OVERFLOW:  
  case ND_UADDLL_OVERFLOW:
  case ND_UADDL_OVERFLOW:
  case ND_UADD_OVERFLOW:
    add_type(node->lhs);
    add_type(node->rhs);
    add_type(node->builtin_dest);
    if (node->builtin_dest->kind == ND_NUM && node->builtin_dest->val == 0) {
        node->builtin_dest->ty = pointer_to(ty_void);
    }
    node->ty = ty_bool;
    return;
  case ND_BUILTIN_ISNAN:
    add_type(node->builtin_val);
    node->ty = ty_int;
    return;
  case ND_BUILTIN_CTZ:
  case ND_BUILTIN_CTZL:
  case ND_BUILTIN_CTZLL:
  case ND_BUILTIN_CLZ:
  case ND_BUILTIN_CLZL:
  case ND_BUILTIN_CLZLL:
  case ND_POPCOUNT:
    add_type(node->builtin_val);
    node->ty = ty_int;
    return;
  case ND_BUILTIN_BSWAP32:
    add_type(node->builtin_val);
    node->ty = ty_uint;
    return;
  case ND_POPCOUNTL:
    add_type(node->builtin_val);
    node->ty = ty_int;
    return;
  case ND_POPCOUNTLL:
    add_type(node->builtin_val);
    node->ty = ty_int;
    return;
  case ND_BUILTIN_BSWAP16:
    add_type(node->builtin_val);
    node->ty = ty_ushort;
    return;   
  case ND_BUILTIN_BSWAP64:
    add_type(node->builtin_val);
    node->ty = ty_ulong;
    return;       
  case ND_CMPEXCH:
  case ND_CMPEXCH_N:
    node->ty = ty_bool;
    return;
  case ND_SIGNBIT:
  case ND_SIGNBITF:
  case ND_SIGNBITL:
  case ND_ISUNORDERED:
    node->ty = ty_int;
    return;    
  case ND_EXCH_N:
  case ND_ADDFETCH:
  case ND_FETCHADD:
  case ND_FETCHSUB:
  case ND_FETCHXOR:
  case ND_FETCHAND:
  case ND_FETCHOR:  
  case ND_ORFETCH:
  case ND_ANDFETCH:
  case ND_XORFETCH:
  case ND_NANDFETCH:
  case ND_FETCHNAND:
  case ND_SUBFETCH:
    if (node->lhs->ty->kind != TY_PTR)
      error_tok(node->lhs->tok, "%s %d:  in add_type: pointer expected", TYPE_C, __LINE__);
    node->rhs = new_cast(node->rhs, node->lhs->ty->base);
    node->ty = node->lhs->ty->base;
    return;
  case ND_SYNC:
  case ND_MEMBARRIER:
    node->ty = ty_void;
    return;
  case ND_MWAIT:
  case ND_MONITOR:
  case ND_EMMS:
  case ND_SFENCE:
  case ND_LFENCE:
  case ND_MFENCE:
  case ND_PAUSE:
  case ND_PREFETCH:
  case ND_SETSSBSY:
  case ND_SAVEPREVSSP:
  case ND_XEND:
  case ND_SERIALIZE:
  case ND_XSUSLDTRK:
  case ND_XRESLDTRK:
  case ND_CLUI:
  case ND_STUI:
  case ND_WBNOINVD:
  case ND_WBINVD:
  case ND_VZEROALL:
  case ND_VZEROUPPER:
  case ND_FEMMS:
  case ND_WRITEEFLAGS_U64:
  case ND_INCSSPQ:
  case ND_RSTORSSP:
  case ND_WRSSD:
  case ND_WRSSQ:
  case ND_WRUSSD:
  case ND_WRUSSQ:
  case ND_CLRSSBSY:
  case ND_UNREACHABLE:
    node->ty = ty_void;
    return;
  case ND_EXCH:
    if (node->lhs->ty->kind != TY_PTR)
      error_tok(node->cas_addr->tok, "%s %d: pointer expected", TYPE_C, __LINE__);
    node->ty = node->lhs->ty->base;
    return;
  case ND_BUILTIN_NANF:  
  case ND_BUILTIN_INFF:
  case ND_BUILTIN_HUGE_VALF:
    node->ty = ty_float;
    return;
  case ND_BUILTIN_NAN:    
  case ND_BUILTIN_INF:
  case ND_BUILTIN_HUGE_VAL:
    node->ty = ty_double;
    return;    
  case ND_BUILTIN_NANL:  
  case ND_BUILTIN_HUGE_VALL:
    node->ty = ty_ldouble;
    return;
  case ND_CVTTSS2SI: 
  case ND_CVTTSD2SI:     
  case ND_VECEXTV2SI:
  case ND_VECEXTV4SI:
    node->ty = ty_int;
    return;
  case ND_CVTTSD2SI64:
  case ND_CVTSD2SI64:
  case ND_CVTSS2SI64:
  case ND_CVTTSS2SI64:
    node->ty = ty_long;
    return;
  case ND_VECINITV4HI:
  case ND_PCMPGTW:
  case ND_PCMPEQW:
  case ND_PSRLDI:
  case ND_PSRLD:       
  case ND_PSRLWI:
  case ND_PSRLW:
  case ND_PSRAWI:
  case ND_PSRAW: 
  case ND_PSLLWI:
  case ND_PSLLW:
  case ND_PMULLW:
  case ND_PMULHW:
  case ND_PMADDWD:
  case ND_PSUBSW:
  case ND_PSUBW:
  case ND_PADDW:
  case ND_PADDSW:
  case ND_PADDUSW:
  case ND_PUNPCKLWD:
  case ND_PUNPCKHWD:    
  case ND_PACKSSDW:
  case ND_PAVGW:
  case ND_PACKSSDW128:
  case ND_PHADDW:
  case ND_PHADDSW:
  case ND_PMADDUBSW:
  case ND_PMULHRSW:
  case ND_PSIGNW:
  case ND_PABSW:
    node->ty = vector_of(ty_short, 4);
    return;
  case ND_PCMPEQB:
  case ND_PSUBUSB:
  case ND_PACKUSWB:
  case ND_PADDUSB:
  case ND_PMAXUB:
  case ND_PMINUB:
  case ND_PAVGB:  
    node->ty = vector_of(ty_uchar, 8);
    return;  
  case ND_VECINITV8QI:    
  case ND_PCMPGTB:
  case ND_PSUBSB:
  case ND_PSUBB:
  case ND_PADDB:
  case ND_PADDSB:
  case ND_PUNPCKLBW:
  case ND_PUNPCKHBW:
  case ND_PACKSSWB:
  case ND_PSHUFB:
  case ND_PSIGNB:
  case ND_PABSB:
    node->ty = vector_of(ty_char, 8);
    return;
  case ND_PSUBUSW:
  case ND_PMULHUW:
  case ND_PHSUBW:
  case ND_PHSUBSW:
    node->ty = vector_of(ty_ushort, 4);
    return;
  case ND_PSUBUSW128:
  case ND_PMULHUW128:
  case ND_PAVGW128:
  case ND_PMAXUW128:
  case ND_PMINUW128:
  case ND_PHMINPOSUW128:
    node->ty = vector_of(ty_ushort, 8);
    return;
  case ND_PUNPCKHWD128:
  case ND_PUNPCKLWD128:
  case ND_PADDSW128:
  case ND_PADDUSW128:
  case ND_PSUBSW128:
  case ND_PSLLWI128:
  case ND_PSRAWI128:
  case ND_PSRLWI128:
  case ND_PSLLW128:
  case ND_PSRAW128:
  case ND_PSRLW128:
  case ND_PHADDW128:
  case ND_PMAXSW128:
  case ND_PMINSW128:
  case ND_PHADDSW128:
  case ND_PHSUBW128:
  case ND_PHSUBSW128:
  case ND_PMADDUBSW128:
  case ND_PMULHRSW128:
  case ND_PSIGNW128:
  case ND_PABSW128:  
  case ND_PMOVSXBW128:
  case ND_PMOVZXBW128:  
  case ND_PACKUSDW128:
    node->ty = vector_of(ty_short, 8);
    return;
  case ND_PUNPCKHDQ128:
  case ND_PUNPCKHQDQ128:
  case ND_PUNPCKLDQ128:
  case ND_PMADDWD128:
  case ND_PMULHW128:
  case ND_PSLLDI128:
  case ND_PSRADI128:
  case ND_PSRLDI128:
  case ND_PSLLD128:
  case ND_PSRAD128:
  case ND_PSRLD128:
  case ND_PANDN128:
  case ND_PHADDD128:
  case ND_PHSUBD128:
  case ND_PMOVSXBD128:
  case ND_PMOVSXWD128:
  case ND_PMOVZXBD128:
  case ND_PMOVZXWD128:
  case ND_PSHUFD:
    node->ty = vector_of(ty_int, 4);
    return;
  case ND_PUNPCKLQDQ128:
  case ND_PSLLQI128:
  case ND_PSRLQI128:
  case ND_PSLLQ128:
  case ND_PSRLQ128:
  case ND_PSADBW128:
  case ND_PMOVSXBQ128:  
    node->ty = vector_of(ty_long, 2);
    return;    
  case ND_ADDSD:
  case ND_SUBSD:
  case ND_MULSD:
  case ND_DIVSD:
  case ND_SQRTPD:
  case ND_MOVSD:
  case ND_SQRTSD:
  case ND_MINPD:
  case ND_MINSD:
  case ND_MAXPD:
  case ND_MAXSD:
  case ND_ANDPD:
  case ND_ANDNPD:
  case ND_ORPD:
  case ND_XORPD:
  case ND_CMPEQPD:
  case ND_CMPLTPD:
  case ND_CMPLEPD:
  case ND_CMPGTPD:
  case ND_CMPGEPD:
  case ND_CMPNEQPD:
  case ND_CMPNLTPD:
  case ND_CMPNLEPD:
  case ND_CMPNGTPD:
  case ND_CMPNGEPD:
  case ND_CMPORDPD:
  case ND_CMPUNORDPD:
  case ND_CMPEQSD:
  case ND_CMPLTSD:
  case ND_CMPLESD:
  case ND_CMPNEQSD:
  case ND_CMPNLTSD:
  case ND_CMPNLESD:
  case ND_CMPORDSD:
  case ND_CMPUNORDSD:
  case ND_CVTDQ2PD:
  case ND_CVTPI2PD:
  case ND_CVTPS2PD:
  case ND_CVTSI2SD:
  case ND_CVTSI642SD:
  case ND_CVTSS2SD:
  case ND_UNPCKHPD:
  case ND_UNPCKLPD:
  case ND_LOADHPD:
  case ND_LOADLPD:
  case ND_MOVMSKPD:
  case ND_MOVNTPD:
  case ND_ADDSUBPD:
  case ND_HADDPD:
  case ND_HSUBPD:
  case ND_BLENDVPD:
    node->ty = vector_of(ty_double, 2);
    return;
  case ND_PACKUSWB128:
  case ND_PUNPCKHBW128:
  case ND_PUNPCKLBW128:
  case ND_PADDUSB128:
  case ND_PSUBUSB128:
  case ND_PMAXUB128:
  case ND_PMINUB128:
  case ND_PAVGB128:
  case ND_PMINSB128:
  case ND_PMAXSB128:
    node->ty = vector_of(ty_uchar, 16);
    return;
  case ND_PACKSSWB128:
  case ND_PADDSB128:
  case ND_PSUBSB128:
  case ND_PSHUFB128:
  case ND_PSIGNB128:
  case ND_PABSB128:
  case ND_PBLENDVB128:
    node->ty = vector_of(ty_char, 16);
    return;
  case ND_CVTSS2SI:
  case ND_UCOMINEQ:
  case ND_UCOMIGE:
  case ND_UCOMIGT:
  case ND_UCOMILE:
  case ND_UCOMILT:
  case ND_UCOMIEQ:    
  case ND_COMINEQ:
  case ND_COMIGE:
  case ND_COMIGT:
  case ND_COMILE:
  case ND_COMILT:
  case ND_COMIEQ:
  case ND_MOVMSKPS:
  case ND_PMOVMSKB:
  case ND_COMISDEQ:
  case ND_COMISDLT:
  case ND_COMISDLE:
  case ND_COMISDGT:
  case ND_COMISDGE:
  case ND_COMISDNEQ:
  case ND_UCOMISDEQ:
  case ND_UCOMISDLT:
  case ND_UCOMISDLE:
  case ND_UCOMISDGT:
  case ND_UCOMISDGE:
  case ND_UCOMISDNEQ:  
  case ND_CVTSD2SI:
  case ND_PMOVMSKB128:
  case ND_PARITYL:
  case ND_PARITYLL:
  case ND_PARITY:
  case ND_PTESTZ128:
  case ND_PTESTC128:
  case ND_PTESTNZC128:
  case ND_RDPKRU:
  case ND_CRC32QI:
  case ND_CRC32HI:
  case ND_XTEST:
  case ND_BSRSI:
  case ND_CRC32SI:
    node->ty = ty_int;
    return;
  case ND_XBEGIN:
  case ND_RDPID:
  case ND_RDFSBASE32:
  case ND_RDGSBASE32:
  case ND_RDTSCP:
  case ND_RDPMC:
  case ND_SBB_U32:
  case ND_BEXTR_U32:
    node->ty = ty_uint;
    return;    
  case ND_BSRDI:
  case ND_CRC32DI:
    node->ty = ty_long;
    return;
  case ND_PHADDD:
  case ND_PHSUBD:
  case ND_PSIGND:
  case ND_PABSD:
    node->ty = vector_of(ty_int, 2);
    return;
  case ND_PMULDQ128:
  case ND_PMOVSXWQ128:
  case ND_PMOVSXDQ128:
  case ND_PMOVZXBQ128:
  case ND_PMOVZXDQ128:
  case ND_PMOVZXWQ128:
  case ND_MOVNTDQA:
    node->ty = vector_of(ty_llong, 2);
    return;
  case ND_READEFLAGS_U64:
  case ND_RDSSPQ:  
  case ND_RDFSBASE64:
  case ND_RDGSBASE64:
  case ND_RDTSC:
    node->ty = ty_ullong;
    return;
  case ND_ROLQI:
  case ND_RORQI:
  case ND_TESTUI:
  case ND_ADDCARRYX_U32:
  case ND_SBB_U64:
    node->ty = ty_uchar;
    return;
  case ND_RORHI:
  case ND_ROLHI:
  case ND_TZCNT_U16:
    node->ty = ty_ushort;
    return;
  default:
    node->ty = ty_void_ptr;
  }
}