| // 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(eqtype(n->type, t, 0)) { | |
| 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(n->type->etype != TIDEAL && n->type->etype != TNIL && !explicit) | |
| 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->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 %d", n->op, nl->type, v.ctype); | |
| 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; | |
| // lose type name if any: | |
| // type T int | |
| // const A T = 1; | |
| // A+0 has type int, not T. | |
| n->type = types[n->type->etype]; | |
| // 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<m; i++) { | |
| if(s1[i] == s2[i]) | |
| continue; | |
| if(s1[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; | |
| } |