#include #include #include #include "ansi.h" #include "host.h" #include "files.h" #include "hash.h" #include "il.h" #include "allocate.h" #include "config.h" #undef NULL #define NULL 0 extern file_pos_t yypos; static node_t *free_list; typedef enum { _Binary, _Unary, _Pointer, _Other } node_class_t; #define is_const_int(x) ((x)->node_kind == _Int_Number) #define is_const_fp(x) ((x)->node_kind == _FP_Number) #define is_constant(x) (is_const_int(x) || is_const_fp(x)) void free_node(n) node_t *n; { assert(n->node_kind != _Ident); n->node_kind = 0; n->node.unary = free_list; free_list = n; } static node_t* alloc_node(kind) node_kind_t kind; { node_t *n; int i; n = free_list; if (n == NULL) { n = (node_t*) allocate(sizeof(node_t)*64); for (i = 1; i<63; i++) { n[i].node.unary = &n[i+1]; } free_list = &n[1]; } else { free_list = n->node.unary; memset(n, 0, sizeof(node_t)); } n->node_def = yypos; n->node_kind = kind; return n; } node_class_t node_classof(kind) node_kind_t kind; { if (kind >= _List && kind <= _Shr) { return _Binary; } if (kind >= _Sizeof && kind <= _Indirect) { return _Unary; } switch (kind) { case _Ident: return _Pointer; default: break; } return _Other; } node_t* new_node(node_kind_t kind, ...) { va_list ap; node_t *n; va_start(ap, kind); n = alloc_node(kind); switch (node_classof(kind)) { case _Binary: n->node.binary.l = va_arg(ap, node_t*); n->node.binary.r = va_arg(ap, node_t*); break; case _Unary: n->node.unary = va_arg(ap, node_t*); break; case _Pointer: n->node.id.name = va_arg(ap, char*); break; case _Other: switch (kind) { case _Elipsis: break; case _String: n->node.str.form = va_arg(ap, char*); n->node.str.len = va_arg(ap, int); break; case _Sym: n->node.sym = va_arg(ap, symbol_t*); break; case _Type: n->node.typ = va_arg(ap, typeinfo_t*); break; case _Cond: n->node.cond.bool = va_arg(ap, node_t*); n->node.cond.tru = va_arg(ap, node_t*); n->node.cond.fals = va_arg(ap, node_t*); break; case _FP_Number: n->node.fval = va_arg(ap, host_float_t); break; case _Int_Number: n->node.ival = va_arg(ap, host_int_t); break; default: fatal(__FILE__,__LINE__,"Unandled noded - (%d)", kind); break; } break; default: assert(0); break; } va_end(ap); return n; } static void promote(n) node_t *n; { node_t *l, *r; host_float_t fv; assert(n != NULL); l = n->node.binary.l; r = n->node.binary.r; assert(l != NULL); assert(r != NULL); if (is_const_int(l) && is_const_fp(r)) { fv = (host_float_t) l->node.ival; l->node_kind = _FP_Number; l->node.fval = fv; } else if (is_const_fp(l) && is_const_int(r)) { fv = (host_float_t) r->node.ival; r->node_kind = _FP_Number; r->node.fval = fv; } } static void reduce_binary(); /* Force constants to RHS */ static void distributive(n) node_t *n; { node_t *l, *r, *dr; assert(n != NULL); l = n->node.binary.l; assert(l != NULL); r = n->node.binary.r; assert(r != NULL); if (is_constant(l) && !is_constant(r)) { n->node.binary.l = r; n->node.binary.r = l; } if (is_constant(r) && l->node_kind == n->node_kind) { dr = l->node.binary.r; if (is_constant(dr)) { /* Transformation * * (n) (n) * / \ / \ * (l) (C) (?) (l) * / \ / \ * (?) (C) (C) (C) */ n->node.binary.l = l->node.binary.l; n->node.binary.r = l; l->node.binary.l = dr; l->node.binary.r = r; reduce_binary(l); } } } static void reduce_binary(n) node_t *n; { node_t *l, *r; if (n == NULL) return; switch (n->node_kind) { case _Add: distributive(n); promote(n); l = n->node.binary.l; assert(l != NULL); r = n->node.binary.r; assert(r != NULL); if (is_constant(l)) { assert(is_constant(r)); /* because distributive() */ if (is_const_int(l)) { n->node_kind = _Int_Number; n->node.ival = l->node.ival + r->node.ival; } else { n->node_kind = _FP_Number; n->node.fval = l->node.fval + r->node.fval; } free_node(l); free_node(r); } break; case _Sub: promote(n); l = n->node.binary.l; assert(l != NULL); r = n->node.binary.r; assert(r != NULL); if (is_constant(l) && is_constant(r)) { if (is_const_int(l)) { n->node_kind = _Int_Number; n->node.ival = l->node.ival - r->node.ival; } else { n->node_kind = _FP_Number; n->node.fval = l->node.fval - r->node.fval; } free_node(l); free_node(r); } break; case _Mul: distributive(n); promote(n); l = n->node.binary.l; assert(l != NULL); r = n->node.binary.r; assert(r != NULL); if (is_constant(l)) { assert(is_constant(r)); /* because distributive() */ if (is_const_int(l)) { n->node_kind = _Int_Number; n->node.ival = l->node.ival * r->node.ival; } else { n->node_kind = _FP_Number; n->node.fval = l->node.fval * r->node.fval; } free_node(l); free_node(r); } break; case _Div: promote(n); l = n->node.binary.l; assert(l != NULL); r = n->node.binary.r; assert(r != NULL); if (is_constant(l) && is_constant(r)) { if (is_const_int(l)) { if (r->node.ival != 0) { n->node_kind = _Int_Number; n->node.ival = l->node.ival / r->node.ival; free_node(l); free_node(r); } } else { if (r->node.fval != 0.0) { n->node_kind = _FP_Number; n->node.fval = l->node.fval / r->node.fval; free_node(l); free_node(r); } } } break; case _Rem: l = n->node.binary.l; assert(l != NULL); r = n->node.binary.r; assert(r != NULL); if (is_const_int(l) && is_const_int(r)) { if (r->node.ival != 0) { n->node_kind = _Int_Number; n->node.ival = l->node.ival % r->node.ival; free_node(l); free_node(r); } } break; case _Shl: l = n->node.binary.l; assert(l != NULL); r = n->node.binary.r; assert(r != NULL); if (is_const_int(l) && is_const_int(r)) { n->node_kind = _Int_Number; n->node.ival = l->node.ival << r->node.ival; free_node(l); free_node(r); } break; case _Shr: l = n->node.binary.l; assert(l != NULL); r = n->node.binary.r; assert(r != NULL); if (is_const_int(l) && is_const_int(r)) { n->node_kind = _Int_Number; n->node.ival = l->node.ival >> r->node.ival; free_node(l); free_node(r); } break; case _Bor: distributive(n); l = n->node.binary.l; assert(l != NULL); r = n->node.binary.r; assert(r != NULL); if (is_const_int(l) && is_const_int(r)) { n->node_kind = _Int_Number; n->node.ival = l->node.ival | r->node.ival; free_node(l); free_node(r); } break; case _Band: distributive(n); l = n->node.binary.l; assert(l != NULL); r = n->node.binary.r; assert(r != NULL); if (is_const_int(l) && is_const_int(r)) { n->node_kind = _Int_Number; n->node.ival = l->node.ival & r->node.ival; free_node(l); free_node(r); } break; case _Xor: distributive(n); l = n->node.binary.l; assert(l != NULL); r = n->node.binary.r; assert(r != NULL); if (is_const_int(l) && is_const_int(r)) { n->node_kind = _Int_Number; n->node.ival = l->node.ival ^ r->node.ival; free_node(l); free_node(r); } break; } } static void reduce_unary(n) node_t *n; { node_t *l; typeinfo_t *typ; symbol_t *sym; host_int_t iv; assert(n != NULL); l = n->node.unary; if (l == NULL) return; switch (n->node_kind) { case _Sizeof: switch (l->node_kind) { case _Type: typ = l->node.typ; break; case _Sym: sym = l->node.sym; if (sym == NULL) return; typ = sym->sym_type; break; default: return; } if (typ == NULL) return; iv = type_sizeof(typ); free_node(l); n->node_kind = _Int_Number; n->node.ival = iv; break; case _Unary_Plus: switch (l->node_kind) { case _Int_Number: n->node_kind = _Int_Number; n->node.ival = l->node.ival; free_node(l); break; case _FP_Number: n->node_kind = _FP_Number; n->node.fval = l->node.fval; free_node(l); break; } break; case _Unary_Minus: switch (l->node_kind) { case _Int_Number: n->node_kind = _Int_Number; n->node.ival = -l->node.ival; free_node(l); break; case _FP_Number: n->node_kind = _FP_Number; n->node.fval = -l->node.fval; free_node(l); break; } break; case _Ones_Complement: if (l->node_kind == _Int_Number) { n->node_kind = _Int_Number; n->node.ival = ~l->node.ival; free_node(l); } break; case _Not: if (l->node_kind == _Int_Number) { n->node_kind = _Int_Number; n->node.ival = !l->node.ival; free_node(l); } break; case _Pre_Inc: case _Pre_Dec: case _Post_Inc: case _Post_Dec: case _Addrof: case _Aggregate: case _Indirect: break; } } void reduce_node(n) node_t *n; { if (n == NULL) return; switch (node_classof(n->node_kind)) { case _Binary: reduce_node(n->node.binary.l); reduce_node(n->node.binary.r); reduce_binary(n); break; case _Unary: reduce_node(n->node.unary); reduce_unary(n); break; default: return; } } node_t* access_to(ptr, decl) node_t *ptr, *decl; { node_t *n; assert(ptr != NULL); assert(decl != NULL); assert(ptr->node_kind == _Indirect); for (n = ptr; n; ) { switch (n->node_kind) { case _Indirect: if (n->node.unary == NULL) { n->node.unary = decl; return ptr; } n = n->node.unary; break; default: fatal(__FILE__,__LINE__,"Unhandled node (%d)", n->node_kind); break; } } assert(0); return ptr; } node_t* id_from_typedef(typ) typeinfo_t *typ; { symbol_t *basetype; assert(typ != NULL); basetype = typ->type_base; assert(basetype != NULL); assert(basetype->sym_ident != NULL); assert(basetype->sym_ident->node_kind == _Ident); assert(basetype->sym_ident->node.id.name != NULL); return new_node(_Ident, basetype->sym_ident->node.id.name); }