aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/gc/const.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/gc/const.c')
-rw-r--r--src/cmd/gc/const.c1678
1 files changed, 0 insertions, 1678 deletions
diff --git a/src/cmd/gc/const.c b/src/cmd/gc/const.c
deleted file mode 100644
index 50accb93a3..0000000000
--- a/src/cmd/gc/const.c
+++ /dev/null
@@ -1,1678 +0,0 @@
-// 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 <u.h>
-#include <libc.h>
-#include "go.h"
-#define TUP(x,y) (((x)<<16)|(y))
-/*c2go int TUP(int, int); */
-
-static Val tocplx(Val);
-static Val toflt(Val);
-static Val tostr(Val);
-static Val copyval(Val);
-static void cmplxmpy(Mpcplx*, Mpcplx*);
-static void cmplxdiv(Mpcplx*, Mpcplx*);
-
-/*
- * truncate float literal fv to 32-bit or 64-bit precision
- * according to type; return truncated value.
- */
-Mpflt*
-truncfltlit(Mpflt *oldv, Type *t)
-{
- double d;
- Mpflt *fv;
- Val v;
-
- if(t == T)
- return oldv;
-
- memset(&v, 0, sizeof v);
- v.ctype = CTFLT;
- v.u.fval = oldv;
- overflow(v, t);
-
- fv = mal(sizeof *fv);
- *fv = *oldv;
-
- // convert large precision literal floating
- // into limited precision (float64 or float32)
- switch(t->etype) {
- case TFLOAT64:
- d = mpgetflt(fv);
- mpmovecflt(fv, d);
- break;
-
- case TFLOAT32:
- d = mpgetflt32(fv);
- mpmovecflt(fv, d);
-
- break;
- }
- return fv;
-}
-
-/*
- * convert n, if literal, to type t.
- * implicit conversion.
- */
-void
-convlit(Node **np, Type *t)
-{
- convlit1(np, t, 0);
-}
-
-/*
- * convert n, if literal, to type t.
- * return a new node if necessary
- * (if n is a named constant, can't edit n->type directly).
- */
-void
-convlit1(Node **np, Type *t, int explicit)
-{
- int ct, et;
- Node *n, *nn;
-
- n = *np;
- if(n == N || t == T || n->type == T || isideal(t) || n->type == t)
- return;
- if(!explicit && !isideal(n->type))
- return;
-
- if(n->op == OLITERAL) {
- nn = nod(OXXX, N, N);
- *nn = *n;
- n = nn;
- *np = n;
- }
-
- switch(n->op) {
- default:
- if(n->type == idealbool) {
- if(t->etype == TBOOL)
- n->type = t;
- else
- n->type = types[TBOOL];
- }
- if(n->type->etype == TIDEAL) {
- convlit(&n->left, t);
- convlit(&n->right, t);
- n->type = t;
- }
- return;
- case OLITERAL:
- // target is invalid type for a constant? leave alone.
- if(!okforconst[t->etype] && n->type->etype != TNIL) {
- defaultlit(&n, T);
- *np = n;
- return;
- }
- break;
- case OLSH:
- case ORSH:
- convlit1(&n->left, t, explicit && isideal(n->left->type));
- t = n->left->type;
- if(t != T && t->etype == TIDEAL && n->val.ctype != CTINT)
- n->val = toint(n->val);
- if(t != T && !isint[t->etype]) {
- yyerror("invalid operation: %N (shift of type %T)", n, t);
- t = T;
- }
- n->type = t;
- return;
- case OCOMPLEX:
- if(n->type->etype == TIDEAL) {
- switch(t->etype) {
- default:
- // If trying to convert to non-complex type,
- // leave as complex128 and let typechecker complain.
- t = types[TCOMPLEX128];
- //fallthrough
- case TCOMPLEX128:
- n->type = t;
- convlit(&n->left, types[TFLOAT64]);
- convlit(&n->right, types[TFLOAT64]);
- break;
- case TCOMPLEX64:
- n->type = t;
- convlit(&n->left, types[TFLOAT32]);
- convlit(&n->right, types[TFLOAT32]);
- break;
- }
- }
- return;
- }
-
- // avoided repeated calculations, errors
- if(eqtype(n->type, t))
- return;
-
- ct = consttype(n);
- if(ct < 0)
- goto bad;
-
- et = t->etype;
- if(et == TINTER) {
- if(ct == CTNIL && n->type == types[TNIL]) {
- n->type = t;
- return;
- }
- defaultlit(np, T);
- return;
- }
-
- switch(ct) {
- default:
- goto bad;
-
- case CTNIL:
- switch(et) {
- default:
- n->type = T;
- goto bad;
-
- case TSTRING:
- // let normal conversion code handle it
- return;
-
- case TARRAY:
- if(!isslice(t))
- goto bad;
- break;
-
- case TPTR32:
- case TPTR64:
- case TINTER:
- case TMAP:
- case TCHAN:
- case TFUNC:
- case TUNSAFEPTR:
- break;
-
- case TUINTPTR:
- // A nil literal may be converted to uintptr
- // if it is an unsafe.Pointer
- if(n->type->etype == TUNSAFEPTR) {
- n->val.u.xval = mal(sizeof(*n->val.u.xval));
- mpmovecfix(n->val.u.xval, 0);
- n->val.ctype = CTINT;
- } else
- goto bad;
- }
- break;
-
- case CTSTR:
- case CTBOOL:
- if(et != n->type->etype)
- goto bad;
- break;
-
- case CTINT:
- case CTRUNE:
- case CTFLT:
- case CTCPLX:
- ct = n->val.ctype;
- if(isint[et]) {
- switch(ct) {
- default:
- goto bad;
- case CTCPLX:
- case CTFLT:
- case CTRUNE:
- n->val = toint(n->val);
- // flowthrough
- case CTINT:
- overflow(n->val, t);
- break;
- }
- } else
- if(isfloat[et]) {
- switch(ct) {
- default:
- goto bad;
- case CTCPLX:
- case CTINT:
- case CTRUNE:
- n->val = toflt(n->val);
- // flowthrough
- case CTFLT:
- n->val.u.fval = truncfltlit(n->val.u.fval, t);
- break;
- }
- } else
- if(iscomplex[et]) {
- switch(ct) {
- default:
- goto bad;
- case CTFLT:
- case CTINT:
- case CTRUNE:
- n->val = tocplx(n->val);
- break;
- case CTCPLX:
- overflow(n->val, t);
- break;
- }
- } else
- if(et == TSTRING && (ct == CTINT || ct == CTRUNE) && explicit)
- n->val = tostr(n->val);
- else
- goto bad;
- break;
- }
- n->type = t;
- return;
-
-bad:
- if(!n->diag) {
- if(!t->broke)
- yyerror("cannot convert %N to type %T", n, t);
- n->diag = 1;
- }
- if(isideal(n->type)) {
- defaultlit(&n, T);
- *np = n;
- }
- return;
-}
-
-static Val
-copyval(Val v)
-{
- Mpint *i;
- Mpflt *f;
- Mpcplx *c;
-
- switch(v.ctype) {
- case CTINT:
- case CTRUNE:
- 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;
- case CTCPLX:
- c = mal(sizeof(*c));
- mpmovefltflt(&c->real, &v.u.cval->real);
- mpmovefltflt(&c->imag, &v.u.cval->imag);
- v.u.cval = c;
- break;
- }
- return v;
-}
-
-static Val
-tocplx(Val v)
-{
- Mpcplx *c;
-
- switch(v.ctype) {
- case CTINT:
- case CTRUNE:
- c = mal(sizeof(*c));
- mpmovefixflt(&c->real, v.u.xval);
- mpmovecflt(&c->imag, 0.0);
- v.ctype = CTCPLX;
- v.u.cval = c;
- break;
- case CTFLT:
- c = mal(sizeof(*c));
- mpmovefltflt(&c->real, v.u.fval);
- mpmovecflt(&c->imag, 0.0);
- v.ctype = CTCPLX;
- v.u.cval = c;
- break;
- }
- return v;
-}
-
-static Val
-toflt(Val v)
-{
- Mpflt *f;
-
- switch(v.ctype) {
- case CTINT:
- case CTRUNE:
- f = mal(sizeof(*f));
- mpmovefixflt(f, v.u.xval);
- v.ctype = CTFLT;
- v.u.fval = f;
- break;
- case CTCPLX:
- f = mal(sizeof(*f));
- mpmovefltflt(f, &v.u.cval->real);
- if(mpcmpfltc(&v.u.cval->imag, 0) != 0)
- yyerror("constant %#F%+#Fi truncated to real", &v.u.cval->real, &v.u.cval->imag);
- v.ctype = CTFLT;
- v.u.fval = f;
- break;
- }
- return v;
-}
-
-Val
-toint(Val v)
-{
- Mpint *i;
-
- switch(v.ctype) {
- case CTRUNE:
- v.ctype = CTINT;
- break;
- case 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;
- break;
- case CTCPLX:
- i = mal(sizeof(*i));
- if(mpmovefltfix(i, &v.u.cval->real) < 0)
- yyerror("constant %#F%+#Fi truncated to integer", &v.u.cval->real, &v.u.cval->imag);
- if(mpcmpfltc(&v.u.cval->imag, 0) != 0)
- yyerror("constant %#F%+#Fi truncated to real", &v.u.cval->real, &v.u.cval->imag);
- v.ctype = CTINT;
- v.u.xval = i;
- break;
- }
- return v;
-}
-
-int
-doesoverflow(Val v, Type *t)
-{
- switch(v.ctype) {
- case CTINT:
- case CTRUNE:
- if(!isint[t->etype])
- fatal("overflow: %T integer constant", t);
- if(mpcmpfixfix(v.u.xval, minintval[t->etype]) < 0 ||
- mpcmpfixfix(v.u.xval, maxintval[t->etype]) > 0)
- return 1;
- break;
- case CTFLT:
- if(!isfloat[t->etype])
- fatal("overflow: %T floating-point constant", t);
- if(mpcmpfltflt(v.u.fval, minfltval[t->etype]) <= 0 ||
- mpcmpfltflt(v.u.fval, maxfltval[t->etype]) >= 0)
- return 1;
- break;
- case CTCPLX:
- if(!iscomplex[t->etype])
- fatal("overflow: %T complex constant", t);
- if(mpcmpfltflt(&v.u.cval->real, minfltval[t->etype]) <= 0 ||
- mpcmpfltflt(&v.u.cval->real, maxfltval[t->etype]) >= 0 ||
- mpcmpfltflt(&v.u.cval->imag, minfltval[t->etype]) <= 0 ||
- mpcmpfltflt(&v.u.cval->imag, maxfltval[t->etype]) >= 0)
- return 1;
- break;
- }
- return 0;
-}
-
-void
-overflow(Val v, Type *t)
-{
- // v has already been converted
- // to appropriate form for t.
- if(t == T || t->etype == TIDEAL)
- return;
-
- if(!doesoverflow(v, t))
- return;
-
- switch(v.ctype) {
- case CTINT:
- case CTRUNE:
- yyerror("constant %B overflows %T", v.u.xval, t);
- break;
- case CTFLT:
- yyerror("constant %#F overflows %T", v.u.fval, t);
- break;
- case CTCPLX:
- 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:
- case CTRUNE:
- 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);
- memset(&v, 0, sizeof v);
- v.ctype = CTSTR;
- v.u.sval = s;
- break;
-
- case CTFLT:
- yyerror("no float -> string");
-
- case CTNIL:
- memset(&v, 0, sizeof v);
- v.ctype = CTSTR;
- v.u.sval = mal(sizeof *s);
- break;
- }
- return v;
-}
-
-int
-consttype(Node *n)
-{
- if(n == N || n->op != OLITERAL)
- return -1;
- return n->val.ctype;
-}
-
-int
-isconst(Node *n, int ct)
-{
- int t;
-
- t = consttype(n);
- // If the caller is asking for CTINT, allow CTRUNE too.
- // Makes life easier for back ends.
- return t == ct || (ct == CTINT && t == CTRUNE);
-}
-
-static Node*
-saveorig(Node *n)
-{
- Node *n1;
-
- if(n == n->orig) {
- // duplicate node for n->orig.
- n1 = nod(OLITERAL, N, N);
- n->orig = n1;
- *n1 = *n;
- }
- return n->orig;
-}
-
-/*
- * if n is constant, rewrite as OLITERAL node.
- */
-void
-evconst(Node *n)
-{
- Node *nl, *nr, *norig;
- int32 len;
- Strlit *str;
- int wl, wr, lno, et;
- Val v, rv;
- Mpint b;
- NodeList *l1, *l2;
-
- // pick off just the opcodes that can be
- // constant evaluated.
- switch(n->op) {
- default:
- return;
- case OADD:
- case OAND:
- case OANDAND:
- case OANDNOT:
- case OARRAYBYTESTR:
- case OCOM:
- case ODIV:
- case OEQ:
- case OGE:
- case OGT:
- case OLE:
- case OLSH:
- case OLT:
- case OMINUS:
- case OMOD:
- case OMUL:
- case ONE:
- case ONOT:
- case OOR:
- case OOROR:
- case OPLUS:
- case ORSH:
- case OSUB:
- case OXOR:
- break;
- case OCONV:
- if(n->type == T)
- return;
- if(!okforconst[n->type->etype] && n->type->etype != TNIL)
- return;
- break;
-
- case OADDSTR:
- // merge adjacent constants in the argument list.
- for(l1=n->list; l1 != nil; l1= l1->next) {
- if(isconst(l1->n, CTSTR) && l1->next != nil && isconst(l1->next->n, CTSTR)) {
- l2 = l1;
- len = 0;
- while(l2 != nil && isconst(l2->n, CTSTR)) {
- nr = l2->n;
- len += nr->val.u.sval->len;
- l2 = l2->next;
- }
- // merge from l1 up to but not including l2
- str = mal(sizeof(*str) + len);
- str->len = len;
- len = 0;
- l2 = l1;
- while(l2 != nil && isconst(l2->n, CTSTR)) {
- nr = l2->n;
- memmove(str->s+len, nr->val.u.sval->s, nr->val.u.sval->len);
- len += nr->val.u.sval->len;
- l2 = l2->next;
- }
- nl = nod(OXXX, N, N);
- *nl = *l1->n;
- nl->orig = nl;
- nl->val.ctype = CTSTR;
- nl->val.u.sval = str;
- l1->n = nl;
- l1->next = l2;
- }
- }
- // fix list end pointer.
- for(l2=n->list; l2 != nil; l2=l2->next)
- n->list->end = l2;
- // collapse single-constant list to single constant.
- if(count(n->list) == 1 && isconst(n->list->n, CTSTR)) {
- n->op = OLITERAL;
- n->val = n->list->n->val;
- }
- return;
- }
-
- nl = n->left;
- if(nl == N || nl->type == T)
- return;
- if(consttype(nl) < 0)
- return;
- wl = nl->type->etype;
- if(isint[wl] || isfloat[wl] || iscomplex[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] || iscomplex[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);
- n->right = nr;
- }
- if(nr->type->etype != TIDEAL) {
- defaultlit(&nl, nr->type);
- n->left = nl;
- }
- 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]);
- n->right = nr;
- if(nr->type && (issigned[nr->type->etype] || !isint[nr->type->etype]))
- goto illegal;
- if(nl->val.ctype != CTRUNE)
- nl->val = toint(nl->val);
- nr->val = toint(nr->val);
- 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);
-
- rv = nr->val;
-
- // convert to common ideal
- if(v.ctype == CTCPLX || rv.ctype == CTCPLX) {
- v = tocplx(v);
- rv = tocplx(rv);
- }
- if(v.ctype == CTFLT || rv.ctype == CTFLT) {
- v = toflt(v);
- rv = toflt(rv);
- }
-
- // Rune and int turns into rune.
- if(v.ctype == CTRUNE && rv.ctype == CTINT)
- rv.ctype = CTRUNE;
- if(v.ctype == CTINT && rv.ctype == CTRUNE) {
- if(n->op == OLSH || n->op == ORSH)
- rv.ctype = CTINT;
- else
- v.ctype = CTRUNE;
- }
-
- if(v.ctype != rv.ctype) {
- // Use of undefined name as constant?
- if((v.ctype == 0 || rv.ctype == 0) && nerrors > 0)
- return;
- fatal("constant type mismatch %T(%d) %T(%d)", nl->type, v.ctype, nr->type, rv.ctype);
- }
-
- // run op
- switch(TUP(n->op, v.ctype)) {
- default:
- goto illegal;
- case TUP(OADD, CTINT):
- case TUP(OADD, CTRUNE):
- mpaddfixfix(v.u.xval, rv.u.xval, 0);
- break;
- case TUP(OSUB, CTINT):
- case TUP(OSUB, CTRUNE):
- mpsubfixfix(v.u.xval, rv.u.xval);
- break;
- case TUP(OMUL, CTINT):
- case TUP(OMUL, CTRUNE):
- mpmulfixfix(v.u.xval, rv.u.xval);
- break;
- case TUP(ODIV, CTINT):
- case TUP(ODIV, CTRUNE):
- if(mpcmpfixc(rv.u.xval, 0) == 0) {
- yyerror("division by zero");
- mpmovecfix(v.u.xval, 1);
- break;
- }
- mpdivfixfix(v.u.xval, rv.u.xval);
- break;
- case TUP(OMOD, CTINT):
- case TUP(OMOD, CTRUNE):
- if(mpcmpfixc(rv.u.xval, 0) == 0) {
- yyerror("division by zero");
- mpmovecfix(v.u.xval, 1);
- break;
- }
- mpmodfixfix(v.u.xval, rv.u.xval);
- break;
-
- case TUP(OLSH, CTINT):
- case TUP(OLSH, CTRUNE):
- mplshfixfix(v.u.xval, rv.u.xval);
- break;
- case TUP(ORSH, CTINT):
- case TUP(ORSH, CTRUNE):
- mprshfixfix(v.u.xval, rv.u.xval);
- break;
- case TUP(OOR, CTINT):
- case TUP(OOR, CTRUNE):
- mporfixfix(v.u.xval, rv.u.xval);
- break;
- case TUP(OAND, CTINT):
- case TUP(OAND, CTRUNE):
- mpandfixfix(v.u.xval, rv.u.xval);
- break;
- case TUP(OANDNOT, CTINT):
- case TUP(OANDNOT, CTRUNE):
- mpandnotfixfix(v.u.xval, rv.u.xval);
- break;
- case TUP(OXOR, CTINT):
- case TUP(OXOR, CTRUNE):
- mpxorfixfix(v.u.xval, rv.u.xval);
- break;
-
- case TUP(OADD, CTFLT):
- mpaddfltflt(v.u.fval, rv.u.fval);
- break;
- case TUP(OSUB, CTFLT):
- mpsubfltflt(v.u.fval, rv.u.fval);
- break;
- case TUP(OMUL, CTFLT):
- mpmulfltflt(v.u.fval, rv.u.fval);
- break;
- case TUP(ODIV, CTFLT):
- if(mpcmpfltc(rv.u.fval, 0) == 0) {
- yyerror("division by zero");
- mpmovecflt(v.u.fval, 1.0);
- break;
- }
- mpdivfltflt(v.u.fval, rv.u.fval);
- break;
- case TUP(OMOD, CTFLT):
- // The default case above would print 'ideal % ideal',
- // which is not quite an ideal error.
- if(!n->diag) {
- yyerror("illegal constant expression: floating-point %% operation");
- n->diag = 1;
- }
- return;
-
- case TUP(OADD, CTCPLX):
- mpaddfltflt(&v.u.cval->real, &rv.u.cval->real);
- mpaddfltflt(&v.u.cval->imag, &rv.u.cval->imag);
- break;
- case TUP(OSUB, CTCPLX):
- mpsubfltflt(&v.u.cval->real, &rv.u.cval->real);
- mpsubfltflt(&v.u.cval->imag, &rv.u.cval->imag);
- break;
- case TUP(OMUL, CTCPLX):
- cmplxmpy(v.u.cval, rv.u.cval);
- break;
- case TUP(ODIV, CTCPLX):
- if(mpcmpfltc(&rv.u.cval->real, 0) == 0 &&
- mpcmpfltc(&rv.u.cval->imag, 0) == 0) {
- yyerror("complex division by zero");
- mpmovecflt(&rv.u.cval->real, 1.0);
- mpmovecflt(&rv.u.cval->imag, 0.0);
- break;
- }
- cmplxdiv(v.u.cval, rv.u.cval);
- break;
-
- case TUP(OEQ, CTNIL):
- goto settrue;
- case TUP(ONE, CTNIL):
- goto setfalse;
-
- case TUP(OEQ, CTINT):
- case TUP(OEQ, CTRUNE):
- if(mpcmpfixfix(v.u.xval, rv.u.xval) == 0)
- goto settrue;
- goto setfalse;
- case TUP(ONE, CTINT):
- case TUP(ONE, CTRUNE):
- if(mpcmpfixfix(v.u.xval, rv.u.xval) != 0)
- goto settrue;
- goto setfalse;
- case TUP(OLT, CTINT):
- case TUP(OLT, CTRUNE):
- if(mpcmpfixfix(v.u.xval, rv.u.xval) < 0)
- goto settrue;
- goto setfalse;
- case TUP(OLE, CTINT):
- case TUP(OLE, CTRUNE):
- if(mpcmpfixfix(v.u.xval, rv.u.xval) <= 0)
- goto settrue;
- goto setfalse;
- case TUP(OGE, CTINT):
- case TUP(OGE, CTRUNE):
- if(mpcmpfixfix(v.u.xval, rv.u.xval) >= 0)
- goto settrue;
- goto setfalse;
- case TUP(OGT, CTINT):
- case TUP(OGT, CTRUNE):
- if(mpcmpfixfix(v.u.xval, rv.u.xval) > 0)
- goto settrue;
- goto setfalse;
-
- case TUP(OEQ, CTFLT):
- if(mpcmpfltflt(v.u.fval, rv.u.fval) == 0)
- goto settrue;
- goto setfalse;
- case TUP(ONE, CTFLT):
- if(mpcmpfltflt(v.u.fval, rv.u.fval) != 0)
- goto settrue;
- goto setfalse;
- case TUP(OLT, CTFLT):
- if(mpcmpfltflt(v.u.fval, rv.u.fval) < 0)
- goto settrue;
- goto setfalse;
- case TUP(OLE, CTFLT):
- if(mpcmpfltflt(v.u.fval, rv.u.fval) <= 0)
- goto settrue;
- goto setfalse;
- case TUP(OGE, CTFLT):
- if(mpcmpfltflt(v.u.fval, rv.u.fval) >= 0)
- goto settrue;
- goto setfalse;
- case TUP(OGT, CTFLT):
- if(mpcmpfltflt(v.u.fval, rv.u.fval) > 0)
- goto settrue;
- goto setfalse;
-
- case TUP(OEQ, CTCPLX):
- if(mpcmpfltflt(&v.u.cval->real, &rv.u.cval->real) == 0 &&
- mpcmpfltflt(&v.u.cval->imag, &rv.u.cval->imag) == 0)
- goto settrue;
- goto setfalse;
- case TUP(ONE, CTCPLX):
- if(mpcmpfltflt(&v.u.cval->real, &rv.u.cval->real) != 0 ||
- mpcmpfltflt(&v.u.cval->imag, &rv.u.cval->imag) != 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(OOROR, CTBOOL):
- if(v.u.bval || rv.u.bval)
- goto settrue;
- goto setfalse;
- case TUP(OANDAND, CTBOOL):
- if(v.u.bval && rv.u.bval)
- goto settrue;
- goto setfalse;
- case TUP(OEQ, CTBOOL):
- if(v.u.bval == rv.u.bval)
- goto settrue;
- goto setfalse;
- case TUP(ONE, CTBOOL):
- if(v.u.bval != rv.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:
- if(!n->diag) {
- yyerror("illegal constant expression %O %T", n->op, nl->type);
- n->diag = 1;
- }
- return;
-
- case TUP(OCONV, CTNIL):
- case TUP(OARRAYBYTESTR, CTNIL):
- if(n->type->etype == TSTRING) {
- v = tostr(v);
- nl->type = n->type;
- break;
- }
- // fall through
- case TUP(OCONV, CTINT):
- case TUP(OCONV, CTRUNE):
- case TUP(OCONV, CTFLT):
- case TUP(OCONV, CTSTR):
- convlit1(&nl, n->type, 1);
- v = nl->val;
- break;
-
- case TUP(OPLUS, CTINT):
- case TUP(OPLUS, CTRUNE):
- break;
- case TUP(OMINUS, CTINT):
- case TUP(OMINUS, CTRUNE):
- mpnegfix(v.u.xval);
- break;
- case TUP(OCOM, CTINT):
- case TUP(OCOM, CTRUNE):
- et = Txxx;
- if(nl->type != T)
- et = nl->type->etype;
-
- // calculate the mask in b
- // result will be (a ^ mask)
- switch(et) {
- default:
- // signed guys change sign
- mpmovecfix(&b, -1);
- break;
-
- case TUINT8:
- case TUINT16:
- case TUINT32:
- case TUINT64:
- case TUINT:
- case TUINTPTR:
- // unsigned guys invert their bits
- 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(OPLUS, CTCPLX):
- break;
- case TUP(OMINUS, CTCPLX):
- mpnegflt(&v.u.cval->real);
- mpnegflt(&v.u.cval->imag);
- break;
-
- case TUP(ONOT, CTBOOL):
- if(!v.u.bval)
- goto settrue;
- goto setfalse;
- }
-
-ret:
- norig = saveorig(n);
- *n = *nl;
- // restore value of n->orig.
- n->orig = norig;
- n->val = v;
-
- // check range.
- lno = setlineno(n);
- overflow(v, n->type);
- lineno = lno;
-
- // truncate precision for non-ideal float.
- if(v.ctype == CTFLT && n->type->etype != TIDEAL)
- n->val.u.fval = truncfltlit(v.u.fval, n->type);
- return;
-
-settrue:
- norig = saveorig(n);
- *n = *nodbool(1);
- n->orig = norig;
- return;
-
-setfalse:
- norig = saveorig(n);
- *n = *nodbool(0);
- n->orig = norig;
- return;
-
-illegal:
- if(!n->diag) {
- yyerror("illegal constant expression: %T %O %T",
- nl->type, n->op, nr->type);
- n->diag = 1;
- }
- 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 = idealstring;
- break;
- case CTBOOL:
- n->type = idealbool;
- break;
- case CTINT:
- case CTRUNE:
- case CTFLT:
- case CTCPLX:
- n->type = types[TIDEAL];
- break;
- case CTNIL:
- n->type = types[TNIL];
- break;
- }
- return n;
-}
-
-Node*
-nodcplxlit(Val r, Val i)
-{
- Node *n;
- Mpcplx *c;
-
- r = toflt(r);
- i = toflt(i);
-
- c = mal(sizeof(*c));
- n = nod(OLITERAL, N, N);
- n->type = types[TIDEAL];
- n->val.u.cval = c;
- n->val.ctype = CTCPLX;
-
- if(r.ctype != CTFLT || i.ctype != CTFLT)
- fatal("nodcplxlit ctype %d/%d", r.ctype, i.ctype);
-
- mpmovefltflt(&c->real, r.u.fval);
- mpmovefltflt(&c->imag, i.u.fval);
- return n;
-}
-
-// idealkind returns a constant kind like consttype
-// but for an arbitrary "ideal" (untyped constant) expression.
-static int
-idealkind(Node *n)
-{
- int k1, k2;
-
- if(n == N || !isideal(n->type))
- return CTxxx;
-
- switch(n->op) {
- default:
- return CTxxx;
- case OLITERAL:
- return n->val.ctype;
- case OADD:
- case OAND:
- case OANDNOT:
- case OCOM:
- case ODIV:
- case OMINUS:
- case OMOD:
- case OMUL:
- case OSUB:
- case OXOR:
- case OOR:
- case OPLUS:
- // numeric kinds.
- k1 = idealkind(n->left);
- k2 = idealkind(n->right);
- if(k1 > k2)
- return k1;
- else
- return k2;
- case OREAL:
- case OIMAG:
- return CTFLT;
- case OCOMPLEX:
- return CTCPLX;
- case OADDSTR:
- return CTSTR;
- case OANDAND:
- case OEQ:
- case OGE:
- case OGT:
- case OLE:
- case OLT:
- case ONE:
- case ONOT:
- case OOROR:
- case OCMPSTR:
- case OCMPIFACE:
- return CTBOOL;
- case OLSH:
- case ORSH:
- // shifts (beware!).
- return idealkind(n->left);
- }
-}
-
-void
-defaultlit(Node **np, Type *t)
-{
- int lno;
- int ctype;
- Node *n, *nn;
- Type *t1;
-
- n = *np;
- if(n == N || !isideal(n->type))
- return;
-
- if(n->op == OLITERAL) {
- nn = nod(OXXX, N, N);
- *nn = *n;
- n = nn;
- *np = n;
- }
-
- lno = setlineno(n);
- ctype = idealkind(n);
- switch(ctype) {
- default:
- if(t != T) {
- convlit(np, t);
- return;
- }
- if(n->val.ctype == CTNIL) {
- lineno = lno;
- if(!n->diag) {
- yyerror("use of untyped nil");
- n->diag = 1;
- }
- n->type = T;
- break;
- }
- if(n->val.ctype == CTSTR) {
- t1 = types[TSTRING];
- convlit(np, t1);
- break;
- }
- yyerror("defaultlit: unknown literal: %N", n);
- break;
- case CTxxx:
- fatal("defaultlit: idealkind is CTxxx: %+N", n);
- break;
- case CTBOOL:
- t1 = types[TBOOL];
- if(t != T && t->etype == TBOOL)
- t1 = t;
- convlit(np, t1);
- break;
- case CTINT:
- t1 = types[TINT];
- goto num;
- case CTRUNE:
- t1 = runetype;
- goto num;
- case CTFLT:
- t1 = types[TFLOAT64];
- goto num;
- case CTCPLX:
- t1 = types[TCOMPLEX128];
- goto num;
- }
- lineno = lno;
- return;
-
-num:
- if(t != T) {
- if(isint[t->etype]) {
- t1 = t;
- n->val = toint(n->val);
- }
- else
- if(isfloat[t->etype]) {
- t1 = t;
- n->val = toflt(n->val);
- }
- else
- if(iscomplex[t->etype]) {
- t1 = t;
- n->val = tocplx(n->val);
- }
- }
- overflow(n->val, t1);
- convlit(np, t1);
- lineno = lno;
- return;
-}
-
-/*
- * defaultlit on both nodes simultaneously;
- * if they're both ideal going in they better
- * get the same type going out.
- * force means must assign concrete (non-ideal) type.
- */
-void
-defaultlit2(Node **lp, Node **rp, int force)
-{
- Node *l, *r;
- int lkind, rkind;
-
- l = *lp;
- r = *rp;
- if(l->type == T || r->type == T)
- return;
- if(!isideal(l->type)) {
- convlit(rp, l->type);
- return;
- }
- if(!isideal(r->type)) {
- convlit(lp, r->type);
- return;
- }
- if(!force)
- return;
- if(l->type->etype == TBOOL) {
- convlit(lp, types[TBOOL]);
- convlit(rp, types[TBOOL]);
- }
- lkind = idealkind(l);
- rkind = idealkind(r);
- if(lkind == CTCPLX || rkind == CTCPLX) {
- convlit(lp, types[TCOMPLEX128]);
- convlit(rp, types[TCOMPLEX128]);
- return;
- }
- if(lkind == CTFLT || rkind == CTFLT) {
- convlit(lp, types[TFLOAT64]);
- convlit(rp, types[TFLOAT64]);
- return;
- }
-
- if(lkind == CTRUNE || rkind == CTRUNE) {
- convlit(lp, runetype);
- convlit(rp, runetype);
- return;
- }
-
- convlit(lp, types[TINT]);
- convlit(rp, types[TINT]);
-}
-
-int
-cmpslit(Node *l, Node *r)
-{
- int32 l1, l2, i, m;
- uchar *s1, *s2;
-
- l1 = l->val.u.sval->len;
- l2 = r->val.u.sval->len;
- s1 = (uchar*)l->val.u.sval->s;
- s2 = (uchar*)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 && isconst(n, CTINT) && n->type != T)
- switch(simtype[n->type->etype]) {
- case TINT8:
- case TUINT8:
- case TINT16:
- case TUINT16:
- case TINT32:
- case TUINT32:
- case TBOOL:
- case TPTR32:
- return 1;
- case TIDEAL:
- case TINT64:
- case TUINT64:
- case TPTR64:
- if(mpcmpfixfix(n->val.u.xval, minintval[TINT32]) < 0
- || mpcmpfixfix(n->val.u.xval, maxintval[TINT32]) > 0)
- break;
- return 1;
- }
- return 0;
-}
-
-long
-nonnegconst(Node *n)
-{
- if(n->op == OLITERAL && n->type != T)
- switch(simtype[n->type->etype]) {
- case TINT8:
- case TUINT8:
- case TINT16:
- case TUINT16:
- case TINT32:
- case TUINT32:
- case TINT64:
- case TUINT64:
- case TIDEAL:
- // check negative and 2^31
- if(mpcmpfixfix(n->val.u.xval, minintval[TUINT32]) < 0
- || mpcmpfixfix(n->val.u.xval, maxintval[TINT32]) > 0)
- break;
- return mpgetfix(n->val.u.xval);
- }
- return -1;
-}
-
-/*
- * convert x to type et and back to int64
- * for sign extension and truncation.
- */
-static int64
-iconv(int64 x, int et)
-{
- switch(et) {
- case TINT8:
- x = (int8)x;
- break;
- case TUINT8:
- x = (uint8)x;
- break;
- case TINT16:
- x = (int16)x;
- break;
- case TUINT16:
- x = (uint64)x;
- break;
- case TINT32:
- x = (int32)x;
- break;
- case TUINT32:
- x = (uint32)x;
- break;
- case TINT64:
- case TUINT64:
- break;
- }
- return x;
-}
-
-/*
- * convert constant val to type t; leave in con.
- * for back end.
- */
-void
-convconst(Node *con, Type *t, Val *val)
-{
- int64 i;
- int tt;
-
- tt = simsimtype(t);
-
- // copy the constant for conversion
- nodconst(con, types[TINT8], 0);
- con->type = t;
- con->val = *val;
-
- if(isint[tt]) {
- con->val.ctype = CTINT;
- con->val.u.xval = mal(sizeof *con->val.u.xval);
- switch(val->ctype) {
- default:
- fatal("convconst ctype=%d %lT", val->ctype, t);
- case CTINT:
- case CTRUNE:
- i = mpgetfix(val->u.xval);
- break;
- case CTBOOL:
- i = val->u.bval;
- break;
- case CTNIL:
- i = 0;
- break;
- }
- i = iconv(i, tt);
- mpmovecfix(con->val.u.xval, i);
- return;
- }
-
- if(isfloat[tt]) {
- con->val = toflt(con->val);
- if(con->val.ctype != CTFLT)
- fatal("convconst ctype=%d %T", con->val.ctype, t);
- if(tt == TFLOAT32)
- con->val.u.fval = truncfltlit(con->val.u.fval, t);
- return;
- }
-
- if(iscomplex[tt]) {
- con->val = tocplx(con->val);
- if(tt == TCOMPLEX64) {
- con->val.u.cval->real = *truncfltlit(&con->val.u.cval->real, types[TFLOAT32]);
- con->val.u.cval->imag = *truncfltlit(&con->val.u.cval->imag, types[TFLOAT32]);
- }
- return;
- }
-
- fatal("convconst %lT constant", t);
-
-}
-
-// complex multiply v *= rv
-// (a, b) * (c, d) = (a*c - b*d, b*c + a*d)
-static void
-cmplxmpy(Mpcplx *v, Mpcplx *rv)
-{
- Mpflt ac, bd, bc, ad;
-
- mpmovefltflt(&ac, &v->real);
- mpmulfltflt(&ac, &rv->real); // ac
-
- mpmovefltflt(&bd, &v->imag);
- mpmulfltflt(&bd, &rv->imag); // bd
-
- mpmovefltflt(&bc, &v->imag);
- mpmulfltflt(&bc, &rv->real); // bc
-
- mpmovefltflt(&ad, &v->real);
- mpmulfltflt(&ad, &rv->imag); // ad
-
- mpmovefltflt(&v->real, &ac);
- mpsubfltflt(&v->real, &bd); // ac-bd
-
- mpmovefltflt(&v->imag, &bc);
- mpaddfltflt(&v->imag, &ad); // bc+ad
-}
-
-// complex divide v /= rv
-// (a, b) / (c, d) = ((a*c + b*d), (b*c - a*d))/(c*c + d*d)
-static void
-cmplxdiv(Mpcplx *v, Mpcplx *rv)
-{
- Mpflt ac, bd, bc, ad, cc_plus_dd;
-
- mpmovefltflt(&cc_plus_dd, &rv->real);
- mpmulfltflt(&cc_plus_dd, &rv->real); // cc
-
- mpmovefltflt(&ac, &rv->imag);
- mpmulfltflt(&ac, &rv->imag); // dd
-
- mpaddfltflt(&cc_plus_dd, &ac); // cc+dd
-
- mpmovefltflt(&ac, &v->real);
- mpmulfltflt(&ac, &rv->real); // ac
-
- mpmovefltflt(&bd, &v->imag);
- mpmulfltflt(&bd, &rv->imag); // bd
-
- mpmovefltflt(&bc, &v->imag);
- mpmulfltflt(&bc, &rv->real); // bc
-
- mpmovefltflt(&ad, &v->real);
- mpmulfltflt(&ad, &rv->imag); // ad
-
- mpmovefltflt(&v->real, &ac);
- mpaddfltflt(&v->real, &bd); // ac+bd
- mpdivfltflt(&v->real, &cc_plus_dd); // (ac+bd)/(cc+dd)
-
- mpmovefltflt(&v->imag, &bc);
- mpsubfltflt(&v->imag, &ad); // bc-ad
- mpdivfltflt(&v->imag, &cc_plus_dd); // (bc+ad)/(cc+dd)
-}
-
-static int hascallchan(Node*);
-
-// Is n a Go language constant (as opposed to a compile-time constant)?
-// Expressions derived from nil, like string([]byte(nil)), while they
-// may be known at compile time, are not Go language constants.
-// Only called for expressions known to evaluated to compile-time
-// constants.
-int
-isgoconst(Node *n)
-{
- Node *l;
- Type *t;
-
- if(n->orig != N)
- n = n->orig;
-
- switch(n->op) {
- case OADD:
- case OADDSTR:
- case OAND:
- case OANDAND:
- case OANDNOT:
- case OCOM:
- case ODIV:
- case OEQ:
- case OGE:
- case OGT:
- case OLE:
- case OLSH:
- case OLT:
- case OMINUS:
- case OMOD:
- case OMUL:
- case ONE:
- case ONOT:
- case OOR:
- case OOROR:
- case OPLUS:
- case ORSH:
- case OSUB:
- case OXOR:
- case OIOTA:
- case OCOMPLEX:
- case OREAL:
- case OIMAG:
- if(isgoconst(n->left) && (n->right == N || isgoconst(n->right)))
- return 1;
- break;
-
- case OCONV:
- if(okforconst[n->type->etype] && isgoconst(n->left))
- return 1;
- break;
-
- case OLEN:
- case OCAP:
- l = n->left;
- if(isgoconst(l))
- return 1;
- // Special case: len/cap is constant when applied to array or
- // pointer to array when the expression does not contain
- // function calls or channel receive operations.
- t = l->type;
- if(t != T && isptr[t->etype])
- t = t->type;
- if(isfixedarray(t) && !hascallchan(l))
- return 1;
- break;
-
- case OLITERAL:
- if(n->val.ctype != CTNIL)
- return 1;
- break;
-
- case ONAME:
- l = n->sym->def;
- if(l && l->op == OLITERAL && n->val.ctype != CTNIL)
- return 1;
- break;
-
- case ONONAME:
- if(n->sym->def != N && n->sym->def->op == OIOTA)
- return 1;
- break;
-
- case OCALL:
- // Only constant calls are unsafe.Alignof, Offsetof, and Sizeof.
- l = n->left;
- while(l->op == OPAREN)
- l = l->left;
- if(l->op != ONAME || l->sym->pkg != unsafepkg)
- break;
- if(strcmp(l->sym->name, "Alignof") == 0 ||
- strcmp(l->sym->name, "Offsetof") == 0 ||
- strcmp(l->sym->name, "Sizeof") == 0)
- return 1;
- break;
- }
-
- //dump("nonconst", n);
- return 0;
-}
-
-static int
-hascallchan(Node *n)
-{
- NodeList *l;
-
- if(n == N)
- return 0;
- switch(n->op) {
- case OAPPEND:
- case OCALL:
- case OCALLFUNC:
- case OCALLINTER:
- case OCALLMETH:
- case OCAP:
- case OCLOSE:
- case OCOMPLEX:
- case OCOPY:
- case ODELETE:
- case OIMAG:
- case OLEN:
- case OMAKE:
- case ONEW:
- case OPANIC:
- case OPRINT:
- case OPRINTN:
- case OREAL:
- case ORECOVER:
- case ORECV:
- return 1;
- }
-
- if(hascallchan(n->left) ||
- hascallchan(n->right))
- return 1;
-
- for(l=n->list; l; l=l->next)
- if(hascallchan(l->n))
- return 1;
- for(l=n->rlist; l; l=l->next)
- if(hascallchan(l->n))
- return 1;
-
- return 0;
-}