// Copyright 2009 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. #include "go.h" #define TUP(x,y) (((x)<<16)|(y)) static Val toflt(Val); static Val toint(Val); static Val tostr(Val); static void overflow(Val, Type*); static Val copyval(Val); /* * truncate float literal fv to 32-bit or 64-bit precision * according to type. */ void truncfltlit(Mpflt *fv, Type *t) { double d; float f; if(t == T) return; // convert large precision literal floating // into limited precision (float64 or float32) // botch -- this assumes that compiler fp // has same precision as runtime fp switch(t->etype) { case TFLOAT64: d = mpgetflt(fv); mpmovecflt(fv, d); break; case TFLOAT32: d = mpgetflt(fv); f = d; d = f; mpmovecflt(fv, d); break; } } /* * convert n, if literal, to type t. * implicit conversion. */ void convlit(Node *n, Type *t) { convlit1(n, t, 0); } /* * convert n, if literal, to type t. */ void convlit1(Node *n, Type *t, int explicit) { int et, ct; if(n == N || t == T || n->type == T) return; et = t->etype; if(et == TIDEAL || et == TNIL) return; switch(n->op) { default: return; case OLITERAL: break; case OLSH: case ORSH: convlit(n->left, t); n->type = n->left->type; return; } // avoided repeated calculations, errors if(cvttype(n->type, t)) { n->type = t; return; } ct = consttype(n); if(ct < 0) goto bad; if(et == TINTER) { if(ct == CTNIL) { n->type = t; return; } defaultlit(n, T); return; } // if already has non-ideal type, cannot change implicitly if(!explicit) { switch(n->type->etype) { case TIDEAL: case TNIL: break; case TSTRING: if(n->type == idealstring) break; // fall through default: goto bad; } } switch(ct) { default: goto bad; case CTNIL: switch(et) { default: goto bad; case TPTR32: case TPTR64: case TINTER: case TARRAY: case TMAP: case TCHAN: case TFUNC: break; } break; case CTSTR: case CTBOOL: if(et != n->type->etype) goto bad; break; case CTINT: case CTFLT: ct = n->val.ctype; if(isint[et]) { if(ct == CTFLT) n->val = toint(n->val); else if(ct != CTINT) goto bad; overflow(n->val, t); } else if(isfloat[et]) { if(ct == CTINT) n->val = toflt(n->val); else if(ct != CTFLT) goto bad; overflow(n->val, t); truncfltlit(n->val.u.fval, t); } else if(et == TSTRING && ct == CTINT && explicit) n->val = tostr(n->val); else goto bad; } n->type = t; return; bad: if(n->type->etype == TIDEAL) defaultlit(n, T); yyerror("cannot convert %T constant to %T", n->type, t); n->diag = 1; return; } static Val copyval(Val v) { Mpint *i; Mpflt *f; switch(v.ctype) { case CTINT: i = mal(sizeof(*i)); mpmovefixfix(i, v.u.xval); v.u.xval = i; break; case CTFLT: f = mal(sizeof(*f)); mpmovefltflt(f, v.u.fval); v.u.fval = f; break; } return v; } static Val toflt(Val v) { Mpflt *f; if(v.ctype == CTINT) { f = mal(sizeof(*f)); mpmovefixflt(f, v.u.xval); v.ctype = CTFLT; v.u.fval = f; } return v; } static Val toint(Val v) { Mpint *i; if(v.ctype == CTFLT) { i = mal(sizeof(*i)); if(mpmovefltfix(i, v.u.fval) < 0) yyerror("constant %#F truncated to integer", v.u.fval); v.ctype = CTINT; v.u.xval = i; } return v; } static void overflow(Val v, Type *t) { // v has already been converted // to appropriate form for t. if(t == T || t->etype == TIDEAL) return; switch(v.ctype) { case CTINT: if(mpcmpfixfix(v.u.xval, minintval[t->etype]) < 0 || mpcmpfixfix(v.u.xval, maxintval[t->etype]) > 0) yyerror("constant %B overflows %T", v.u.xval, t); break; case CTFLT: if(mpcmpfltflt(v.u.fval, minfltval[t->etype]) < 0 || mpcmpfltflt(v.u.fval, maxfltval[t->etype]) > 0) yyerror("constant %#F overflows %T", v.u.fval, t); break; } } static Val tostr(Val v) { Rune rune; int l; Strlit *s; switch(v.ctype) { case CTINT: if(mpcmpfixfix(v.u.xval, minintval[TINT]) < 0 || mpcmpfixfix(v.u.xval, maxintval[TINT]) > 0) yyerror("overflow in int -> string"); rune = mpgetfix(v.u.xval); l = runelen(rune); s = mal(sizeof(*s)+l); s->len = l; runetochar((char*)s->s, &rune); v.ctype = CTSTR; v.u.sval = s; break; case CTFLT: yyerror("no float -> string"); } return v; } int consttype(Node *n) { if(n == N || n->op != OLITERAL) return -1; return n->val.ctype; } int isconst(Node *n, int ct) { return consttype(n) == ct; } /* * if n is constant, rewrite as OLITERAL node. */ void evconst(Node *n) { Node *nl, *nr; int32 len; Strlit *str; int wl, wr, lno, et; Val v; Mpint b; nl = n->left; if(nl == N || nl->type == T) return; if(consttype(nl) < 0) return; wl = nl->type->etype; if(isint[wl] || isfloat[wl]) wl = TIDEAL; nr = n->right; if(nr == N) goto unary; if(nr->type == T) return; if(consttype(nr) < 0) return; wr = nr->type->etype; if(isint[wr] || isfloat[wr]) wr = TIDEAL; // check for compatible general types (numeric, string, etc) if(wl != wr) goto illegal; // check for compatible types. switch(n->op) { default: // ideal const mixes with anything but otherwise must match. if(nl->type->etype != TIDEAL) defaultlit(nr, nl->type); if(nr->type->etype != TIDEAL) defaultlit(nl, nr->type); if(nl->type->etype != nr->type->etype) goto illegal; break; case OLSH: case ORSH: // right must be unsigned. // left can be ideal. defaultlit(nr, types[TUINT]); break; } // copy numeric value to avoid modifying // n->left, in case someone still refers to it (e.g. iota). v = nl->val; if(wl == TIDEAL) v = copyval(v); // since wl == wr, // the only way v.ctype != nr->val.ctype // is when one is CTINT and the other CTFLT. // make both CTFLT. if(v.ctype != nr->val.ctype) { v = toflt(v); nr->val = toflt(nr->val); } // run op switch(TUP(n->op, v.ctype)) { default: illegal: yyerror("illegal constant expression %T %O %T", nl->type, n->op, nr->type); n->diag = 1; return; case TUP(OADD, CTINT): mpaddfixfix(v.u.xval, nr->val.u.xval); break; case TUP(OSUB, CTINT): mpsubfixfix(v.u.xval, nr->val.u.xval); break; case TUP(OMUL, CTINT): mpmulfixfix(v.u.xval, nr->val.u.xval); break; case TUP(ODIV, CTINT): if(mpcmpfixc(nr->val.u.xval, 0) == 0) { yyerror("division by zero"); mpmovecfix(v.u.xval, 1); break; } mpdivfixfix(v.u.xval, nr->val.u.xval); break; case TUP(OMOD, CTINT): if(mpcmpfixc(nr->val.u.xval, 0) == 0) { yyerror("division by zero"); mpmovecfix(v.u.xval, 1); break; } mpmodfixfix(v.u.xval, nr->val.u.xval); break; case TUP(OLSH, CTINT): mplshfixfix(v.u.xval, nr->val.u.xval); break; case TUP(ORSH, CTINT): mprshfixfix(v.u.xval, nr->val.u.xval); break; case TUP(OOR, CTINT): mporfixfix(v.u.xval, nr->val.u.xval); break; case TUP(OAND, CTINT): mpandfixfix(v.u.xval, nr->val.u.xval); break; case TUP(OANDNOT, CTINT): mpandnotfixfix(v.u.xval, nr->val.u.xval); break; case TUP(OXOR, CTINT): mpxorfixfix(v.u.xval, nr->val.u.xval); break; case TUP(OADD, CTFLT): mpaddfltflt(v.u.fval, nr->val.u.fval); break; case TUP(OSUB, CTFLT): mpsubfltflt(v.u.fval, nr->val.u.fval); break; case TUP(OMUL, CTFLT): mpmulfltflt(v.u.fval, nr->val.u.fval); break; case TUP(ODIV, CTFLT): if(mpcmpfltc(nr->val.u.fval, 0) == 0) { yyerror("division by zero"); mpmovecflt(v.u.fval, 1.0); break; } mpdivfltflt(v.u.fval, nr->val.u.fval); break; case TUP(OEQ, CTNIL): goto settrue; case TUP(ONE, CTNIL): goto setfalse; case TUP(OEQ, CTINT): if(mpcmpfixfix(v.u.xval, nr->val.u.xval) == 0) goto settrue; goto setfalse; case TUP(ONE, CTINT): if(mpcmpfixfix(v.u.xval, nr->val.u.xval) != 0) goto settrue; goto setfalse; case TUP(OLT, CTINT): if(mpcmpfixfix(v.u.xval, nr->val.u.xval) < 0) goto settrue; goto setfalse; case TUP(OLE, CTINT): if(mpcmpfixfix(v.u.xval, nr->val.u.xval) <= 0) goto settrue; goto setfalse; case TUP(OGE, CTINT): if(mpcmpfixfix(v.u.xval, nr->val.u.xval) >= 0) goto settrue; goto setfalse; case TUP(OGT, CTINT): if(mpcmpfixfix(v.u.xval, nr->val.u.xval) > 0) goto settrue; goto setfalse; case TUP(OEQ, CTFLT): if(mpcmpfltflt(v.u.fval, nr->val.u.fval) == 0) goto settrue; goto setfalse; case TUP(ONE, CTFLT): if(mpcmpfltflt(v.u.fval, nr->val.u.fval) != 0) goto settrue; goto setfalse; case TUP(OLT, CTFLT): if(mpcmpfltflt(v.u.fval, nr->val.u.fval) < 0) goto settrue; goto setfalse; case TUP(OLE, CTFLT): if(mpcmpfltflt(v.u.fval, nr->val.u.fval) <= 0) goto settrue; goto setfalse; case TUP(OGE, CTFLT): if(mpcmpfltflt(v.u.fval, nr->val.u.fval) >= 0) goto settrue; goto setfalse; case TUP(OGT, CTFLT): if(mpcmpfltflt(v.u.fval, nr->val.u.fval) > 0) goto settrue; goto setfalse; case TUP(OEQ, CTSTR): if(cmpslit(nl, nr) == 0) goto settrue; goto setfalse; case TUP(ONE, CTSTR): if(cmpslit(nl, nr) != 0) goto settrue; goto setfalse; case TUP(OLT, CTSTR): if(cmpslit(nl, nr) < 0) goto settrue; goto setfalse; case TUP(OLE, CTSTR): if(cmpslit(nl, nr) <= 0) goto settrue; goto setfalse; case TUP(OGE, CTSTR): if(cmpslit(nl, nr) >= 0l) goto settrue; goto setfalse; case TUP(OGT, CTSTR): if(cmpslit(nl, nr) > 0) goto settrue; goto setfalse; case TUP(OADD, CTSTR): len = v.u.sval->len + nr->val.u.sval->len; str = mal(sizeof(*str) + len); str->len = len; memcpy(str->s, v.u.sval->s, v.u.sval->len); memcpy(str->s+v.u.sval->len, nr->val.u.sval->s, nr->val.u.sval->len); str->len = len; v.u.sval = str; break; case TUP(OOROR, CTBOOL): if(v.u.bval || nr->val.u.bval) goto settrue; goto setfalse; case TUP(OANDAND, CTBOOL): if(v.u.bval && nr->val.u.bval) goto settrue; goto setfalse; case TUP(OEQ, CTBOOL): if(v.u.bval == nr->val.u.bval) goto settrue; goto setfalse; case TUP(ONE, CTBOOL): if(v.u.bval != nr->val.u.bval) goto settrue; goto setfalse; } goto ret; unary: // copy numeric value to avoid modifying // nl, in case someone still refers to it (e.g. iota). v = nl->val; if(wl == TIDEAL) v = copyval(v); switch(TUP(n->op, v.ctype)) { default: yyerror("illegal constant expression %O %T", n->op, nl->type); return; case TUP(OPLUS, CTINT): break; case TUP(OMINUS, CTINT): mpnegfix(v.u.xval); break; case TUP(OCOM, CTINT): et = Txxx; if(nl->type != T) et = nl->type->etype; // calculate the mask in b // result will be (a ^ mask) switch(et) { default: mpmovecfix(&b, -1); break; case TINT8: case TINT16: case TINT32: case TINT64: case TINT: et++; // convert to unsigned // fallthrough case TUINT8: case TUINT16: case TUINT32: case TUINT64: case TUINT: case TUINTPTR: mpmovefixfix(&b, maxintval[et]); break; } mpxorfixfix(v.u.xval, &b); break; case TUP(OPLUS, CTFLT): break; case TUP(OMINUS, CTFLT): mpnegflt(v.u.fval); break; case TUP(ONOT, CTBOOL): if(!v.u.bval) goto settrue; goto setfalse; } ret: // rewrite n in place. *n = *nl; n->val = v; // check range. lno = lineno; lineno = n->lineno; overflow(v, n->type); lineno = lno; // truncate precision for non-ideal float. if(v.ctype == CTFLT && n->type->etype != TIDEAL) truncfltlit(v.u.fval, n->type); return; settrue: *n = *nodbool(1); return; setfalse: *n = *nodbool(0); return; } Node* nodlit(Val v) { Node *n; n = nod(OLITERAL, N, N); n->val = v; switch(v.ctype) { default: fatal("nodlit ctype %d", v.ctype); case CTSTR: n->type = types[TSTRING]; break; case CTBOOL: n->type = types[TBOOL]; break; case CTINT: case CTFLT: n->type = types[TIDEAL]; break; case CTNIL: n->type = types[TNIL]; break; } return n; } void defaultlit(Node *n, Type *t) { int lno; if(n == N) return; if(n->type == T || n->type->etype != TIDEAL) return; switch(n->op) { case OLITERAL: break; case OLSH: case ORSH: defaultlit(n->left, t); n->type = n->left->type; return; } lno = lineno; lineno = n->lineno; switch(n->val.ctype) { default: yyerror("defaultlit: unknown literal: %N", n); break; case CTINT: n->type = types[TINT]; if(t != T) { if(isint[t->etype]) n->type = t; else if(isfloat[t->etype]) { n->type = t; n->val = toflt(n->val); } } overflow(n->val, n->type); break; case CTFLT: n->type = types[TFLOAT]; if(t != T) { if(isfloat[t->etype]) n->type = t; else if(isint[t->etype]) { n->type = t; n->val = toint(n->val); } } overflow(n->val, n->type); break; } lineno = lno; } /* * defaultlit on both nodes simultaneously; * if they're both ideal going in they better * get the same type going out. */ void defaultlit2(Node *l, Node *r) { if(l->type == T || r->type == T) return; if(l->type->etype != TIDEAL && l->type->etype != TNIL) { convlit(r, l->type); return; } if(r->type->etype != TIDEAL && r->type->etype != TNIL) { convlit(l, r->type); return; } if(isconst(l, CTFLT) || isconst(r, CTFLT)) { convlit(l, types[TFLOAT]); convlit(r, types[TFLOAT]); return; } convlit(l, types[TINT]); convlit(r, types[TINT]); } int cmpslit(Node *l, Node *r) { int32 l1, l2, i, m; char *s1, *s2; l1 = l->val.u.sval->len; l2 = r->val.u.sval->len; s1 = l->val.u.sval->s; s2 = r->val.u.sval->s; m = l1; if(l2 < m) m = l2; for(i=0; i s2[i]) return +1; return -1; } if(l1 == l2) return 0; if(l1 > l2) return +1; return -1; } int smallintconst(Node *n) { if(n->op == OLITERAL) switch(simtype[n->type->etype]) { case TINT8: case TUINT8: case TINT16: case TUINT16: case TINT32: case TUINT32: case TBOOL: case TPTR32: return 1; } return 0; }