2008-06-04 15:37:38 -06:00
|
|
|
// 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.
|
|
|
|
|
2011-08-25 14:25:10 -06:00
|
|
|
#include <u.h>
|
|
|
|
#include <libc.h>
|
2008-06-04 15:37:38 -06:00
|
|
|
#include "go.h"
|
|
|
|
#define TUP(x,y) (((x)<<16)|(y))
|
|
|
|
|
2010-02-18 18:55:11 -07:00
|
|
|
static Val tocplx(Val);
|
|
|
|
static Val toflt(Val);
|
|
|
|
static Val tostr(Val);
|
|
|
|
static Val copyval(Val);
|
2010-02-19 21:42:50 -07:00
|
|
|
static void cmplxmpy(Mpcplx*, Mpcplx*);
|
|
|
|
static void cmplxdiv(Mpcplx*, Mpcplx*);
|
2009-03-12 20:04:38 -06:00
|
|
|
|
|
|
|
/*
|
|
|
|
* truncate float literal fv to 32-bit or 64-bit precision
|
2009-05-27 11:16:13 -06:00
|
|
|
* according to type; return truncated value.
|
2009-03-12 20:04:38 -06:00
|
|
|
*/
|
2009-05-27 11:16:13 -06:00
|
|
|
Mpflt*
|
|
|
|
truncfltlit(Mpflt *oldv, Type *t)
|
2008-12-02 18:03:47 -07:00
|
|
|
{
|
|
|
|
double d;
|
|
|
|
float f;
|
2009-05-27 11:16:13 -06:00
|
|
|
Mpflt *fv;
|
2008-12-02 18:03:47 -07:00
|
|
|
|
|
|
|
if(t == T)
|
2009-05-27 11:16:13 -06:00
|
|
|
return oldv;
|
|
|
|
|
|
|
|
fv = mal(sizeof *fv);
|
|
|
|
*fv = *oldv;
|
2008-12-02 18:03:47 -07:00
|
|
|
|
|
|
|
// 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;
|
|
|
|
}
|
2009-05-27 11:16:13 -06:00
|
|
|
return fv;
|
2008-12-02 18:03:47 -07:00
|
|
|
}
|
|
|
|
|
2009-03-12 20:04:38 -06:00
|
|
|
/*
|
|
|
|
* convert n, if literal, to type t.
|
|
|
|
* implicit conversion.
|
|
|
|
*/
|
2008-06-04 15:37:38 -06:00
|
|
|
void
|
2009-07-17 14:38:16 -06:00
|
|
|
convlit(Node **np, Type *t)
|
2009-03-12 20:04:38 -06:00
|
|
|
{
|
2009-11-20 12:42:28 -07:00
|
|
|
convlit1(np, t, 0);
|
2009-03-12 20:04:38 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* convert n, if literal, to type t.
|
2009-07-17 14:38:16 -06:00
|
|
|
* return a new node if necessary
|
|
|
|
* (if n is a named constant, can't edit n->type directly).
|
2009-03-12 20:04:38 -06:00
|
|
|
*/
|
|
|
|
void
|
2009-07-17 14:38:16 -06:00
|
|
|
convlit1(Node **np, Type *t, int explicit)
|
2008-06-04 15:37:38 -06:00
|
|
|
{
|
2009-08-27 12:16:34 -06:00
|
|
|
int ct, et;
|
2009-07-17 14:38:16 -06:00
|
|
|
Node *n, *nn;
|
2008-06-04 15:37:38 -06:00
|
|
|
|
2009-07-17 14:38:16 -06:00
|
|
|
n = *np;
|
2009-09-21 16:45:55 -06:00
|
|
|
if(n == N || t == T || n->type == T || isideal(t) || n->type == t)
|
2009-03-12 20:04:38 -06:00
|
|
|
return;
|
2009-08-27 12:16:34 -06:00
|
|
|
if(!explicit && !isideal(n->type))
|
2009-08-24 14:41:47 -06:00
|
|
|
return;
|
2009-07-17 14:38:16 -06:00
|
|
|
|
|
|
|
if(n->op == OLITERAL) {
|
|
|
|
nn = nod(OXXX, N, N);
|
|
|
|
*nn = *n;
|
|
|
|
n = nn;
|
|
|
|
*np = n;
|
|
|
|
}
|
2008-10-29 21:25:34 -06:00
|
|
|
|
2008-08-29 14:24:53 -06:00
|
|
|
switch(n->op) {
|
|
|
|
default:
|
2012-02-21 22:29:37 -07:00
|
|
|
if(n->type == idealbool)
|
|
|
|
n->type = types[TBOOL];
|
2009-07-30 17:53:08 -06:00
|
|
|
if(n->type->etype == TIDEAL) {
|
|
|
|
convlit(&n->left, t);
|
|
|
|
convlit(&n->right, t);
|
|
|
|
n->type = t;
|
|
|
|
}
|
2008-08-29 14:24:53 -06:00
|
|
|
return;
|
|
|
|
case OLITERAL:
|
2010-02-02 00:05:15 -07:00
|
|
|
// target is invalid type for a constant? leave alone.
|
2010-06-08 19:50:02 -06:00
|
|
|
if(!okforconst[t->etype] && n->type->etype != TNIL) {
|
|
|
|
defaultlit(&n, T);
|
|
|
|
*np = n;
|
2010-02-02 00:05:15 -07:00
|
|
|
return;
|
2010-06-08 19:50:02 -06:00
|
|
|
}
|
2008-08-29 14:24:53 -06:00
|
|
|
break;
|
|
|
|
case OLSH:
|
|
|
|
case ORSH:
|
2010-12-13 11:42:51 -07:00
|
|
|
convlit1(&n->left, t, explicit && isideal(n->left->type));
|
2009-08-23 19:09:44 -06:00
|
|
|
t = n->left->type;
|
2011-05-31 13:05:40 -06:00
|
|
|
if(t != T && t->etype == TIDEAL && n->val.ctype != CTINT)
|
|
|
|
n->val = toint(n->val);
|
2009-08-23 19:09:44 -06:00
|
|
|
if(t != T && !isint[t->etype]) {
|
2011-10-31 11:09:40 -06:00
|
|
|
yyerror("invalid operation: %N (shift of type %T)", n, t);
|
2009-08-23 19:09:44 -06:00
|
|
|
t = T;
|
|
|
|
}
|
|
|
|
n->type = t;
|
2008-08-29 14:24:53 -06:00
|
|
|
return;
|
|
|
|
}
|
2010-02-02 00:05:15 -07:00
|
|
|
|
2009-03-12 20:04:38 -06:00
|
|
|
// avoided repeated calculations, errors
|
2010-06-08 19:50:02 -06:00
|
|
|
if(eqtype(n->type, t))
|
2009-03-12 20:04:38 -06:00
|
|
|
return;
|
|
|
|
|
|
|
|
ct = consttype(n);
|
|
|
|
if(ct < 0)
|
|
|
|
goto bad;
|
2008-10-16 16:59:31 -06:00
|
|
|
|
2009-08-27 12:16:34 -06:00
|
|
|
et = t->etype;
|
2009-03-12 20:04:38 -06:00
|
|
|
if(et == TINTER) {
|
2009-07-06 22:37:29 -06:00
|
|
|
if(ct == CTNIL && n->type == types[TNIL]) {
|
2009-03-12 20:04:38 -06:00
|
|
|
n->type = t;
|
|
|
|
return;
|
|
|
|
}
|
2009-07-17 14:38:16 -06:00
|
|
|
defaultlit(np, T);
|
2009-03-12 20:04:38 -06:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch(ct) {
|
2008-06-17 19:01:05 -06:00
|
|
|
default:
|
2009-03-12 20:04:38 -06:00
|
|
|
goto bad;
|
2008-06-17 19:01:05 -06:00
|
|
|
|
2009-03-12 20:04:38 -06:00
|
|
|
case CTNIL:
|
2008-12-18 22:33:45 -07:00
|
|
|
switch(et) {
|
|
|
|
default:
|
2009-09-09 02:21:20 -06:00
|
|
|
n->type = T;
|
2009-03-12 20:04:38 -06:00
|
|
|
goto bad;
|
2008-12-18 22:33:45 -07:00
|
|
|
|
2009-05-29 14:44:30 -06:00
|
|
|
case TSTRING:
|
|
|
|
// let normal conversion code handle it
|
|
|
|
return;
|
|
|
|
|
2009-07-27 18:24:07 -06:00
|
|
|
case TARRAY:
|
|
|
|
if(!isslice(t))
|
|
|
|
goto bad;
|
|
|
|
break;
|
|
|
|
|
2008-12-18 22:33:45 -07:00
|
|
|
case TPTR32:
|
|
|
|
case TPTR64:
|
|
|
|
case TINTER:
|
2009-01-09 12:13:39 -07:00
|
|
|
case TMAP:
|
|
|
|
case TCHAN:
|
2009-01-30 15:39:42 -07:00
|
|
|
case TFUNC:
|
2011-03-07 13:10:01 -07:00
|
|
|
case TUNSAFEPTR:
|
2008-10-15 18:08:10 -06:00
|
|
|
break;
|
2008-12-18 22:33:45 -07:00
|
|
|
}
|
|
|
|
break;
|
2008-06-17 23:33:32 -06:00
|
|
|
|
2009-03-12 20:04:38 -06:00
|
|
|
case CTSTR:
|
|
|
|
case CTBOOL:
|
|
|
|
if(et != n->type->etype)
|
|
|
|
goto bad;
|
|
|
|
break;
|
2008-06-04 15:37:38 -06:00
|
|
|
|
2009-03-12 20:04:38 -06:00
|
|
|
case CTINT:
|
2011-12-08 20:07:43 -07:00
|
|
|
case CTRUNE:
|
2009-03-12 20:04:38 -06:00
|
|
|
case CTFLT:
|
2010-02-17 23:08:30 -07:00
|
|
|
case CTCPLX:
|
2009-03-12 20:04:38 -06:00
|
|
|
ct = n->val.ctype;
|
2008-06-04 15:37:38 -06:00
|
|
|
if(isint[et]) {
|
2010-02-17 23:08:30 -07:00
|
|
|
switch(ct) {
|
|
|
|
default:
|
2010-02-21 12:18:09 -07:00
|
|
|
goto bad;
|
2010-02-17 23:08:30 -07:00
|
|
|
case CTCPLX:
|
|
|
|
case CTFLT:
|
2011-12-08 20:07:43 -07:00
|
|
|
case CTRUNE:
|
2009-03-12 20:04:38 -06:00
|
|
|
n->val = toint(n->val);
|
2010-02-17 23:08:30 -07:00
|
|
|
// flowthrough
|
|
|
|
case CTINT:
|
|
|
|
overflow(n->val, t);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else
|
|
|
|
if(isfloat[et]) {
|
|
|
|
switch(ct) {
|
|
|
|
default:
|
2010-02-21 12:18:09 -07:00
|
|
|
goto bad;
|
2010-02-17 23:08:30 -07:00
|
|
|
case CTCPLX:
|
|
|
|
case CTINT:
|
2011-12-08 20:07:43 -07:00
|
|
|
case CTRUNE:
|
2009-03-12 20:04:38 -06:00
|
|
|
n->val = toflt(n->val);
|
2010-02-17 23:08:30 -07:00
|
|
|
// flowthrough
|
|
|
|
case CTFLT:
|
|
|
|
overflow(n->val, t);
|
|
|
|
n->val.u.fval = truncfltlit(n->val.u.fval, t);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else
|
|
|
|
if(iscomplex[et]) {
|
|
|
|
switch(ct) {
|
|
|
|
default:
|
2009-03-12 20:04:38 -06:00
|
|
|
goto bad;
|
2010-02-17 23:08:30 -07:00
|
|
|
case CTFLT:
|
|
|
|
case CTINT:
|
2011-12-08 20:07:43 -07:00
|
|
|
case CTRUNE:
|
2010-02-17 23:08:30 -07:00
|
|
|
n->val = tocplx(n->val);
|
|
|
|
break;
|
|
|
|
case CTCPLX:
|
|
|
|
overflow(n->val, t);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else
|
2011-12-08 20:07:43 -07:00
|
|
|
if(et == TSTRING && (ct == CTINT || ct == CTRUNE) && explicit)
|
2009-03-12 20:04:38 -06:00
|
|
|
n->val = tostr(n->val);
|
|
|
|
else
|
|
|
|
goto bad;
|
2010-02-17 23:08:30 -07:00
|
|
|
break;
|
2008-06-04 15:37:38 -06:00
|
|
|
}
|
2008-06-15 21:24:30 -06:00
|
|
|
n->type = t;
|
2008-06-04 15:37:38 -06:00
|
|
|
return;
|
|
|
|
|
2009-03-12 20:04:38 -06:00
|
|
|
bad:
|
2010-01-08 01:01:03 -07:00
|
|
|
if(!n->diag) {
|
2011-10-31 11:09:40 -06:00
|
|
|
yyerror("cannot convert %N to type %T", n, t);
|
2010-01-08 01:01:03 -07:00
|
|
|
n->diag = 1;
|
|
|
|
}
|
2009-08-27 12:16:34 -06:00
|
|
|
if(isideal(n->type)) {
|
2009-07-17 14:38:16 -06:00
|
|
|
defaultlit(&n, T);
|
|
|
|
*np = n;
|
|
|
|
}
|
2008-06-04 15:37:38 -06:00
|
|
|
return;
|
2009-03-12 20:04:38 -06:00
|
|
|
}
|
2008-06-04 15:37:38 -06:00
|
|
|
|
2009-03-12 20:04:38 -06:00
|
|
|
static Val
|
|
|
|
copyval(Val v)
|
|
|
|
{
|
|
|
|
Mpint *i;
|
|
|
|
Mpflt *f;
|
2010-02-17 23:08:30 -07:00
|
|
|
Mpcplx *c;
|
2008-10-16 16:59:31 -06:00
|
|
|
|
2009-03-12 20:04:38 -06:00
|
|
|
switch(v.ctype) {
|
|
|
|
case CTINT:
|
2011-12-08 20:07:43 -07:00
|
|
|
case CTRUNE:
|
2009-03-12 20:04:38 -06:00
|
|
|
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;
|
2010-02-17 23:08:30 -07:00
|
|
|
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:
|
2011-12-08 20:07:43 -07:00
|
|
|
case CTRUNE:
|
2010-02-17 23:08:30 -07:00
|
|
|
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;
|
2009-03-12 20:04:38 -06:00
|
|
|
}
|
|
|
|
return v;
|
2008-06-04 15:37:38 -06:00
|
|
|
}
|
|
|
|
|
2009-03-12 20:04:38 -06:00
|
|
|
static Val
|
|
|
|
toflt(Val v)
|
2008-12-12 14:10:36 -07:00
|
|
|
{
|
2009-03-12 20:04:38 -06:00
|
|
|
Mpflt *f;
|
|
|
|
|
2010-02-17 23:08:30 -07:00
|
|
|
switch(v.ctype) {
|
|
|
|
case CTINT:
|
2011-12-08 20:07:43 -07:00
|
|
|
case CTRUNE:
|
2009-03-12 20:04:38 -06:00
|
|
|
f = mal(sizeof(*f));
|
|
|
|
mpmovefixflt(f, v.u.xval);
|
|
|
|
v.ctype = CTFLT;
|
|
|
|
v.u.fval = f;
|
2010-02-17 23:08:30 -07:00
|
|
|
break;
|
|
|
|
case CTCPLX:
|
|
|
|
f = mal(sizeof(*f));
|
|
|
|
mpmovefltflt(f, &v.u.cval->real);
|
|
|
|
if(mpcmpfltc(&v.u.cval->imag, 0) != 0)
|
2010-12-13 13:34:45 -07:00
|
|
|
yyerror("constant %#F%+#Fi truncated to real", &v.u.cval->real, &v.u.cval->imag);
|
2010-02-17 23:08:30 -07:00
|
|
|
v.ctype = CTFLT;
|
|
|
|
v.u.fval = f;
|
|
|
|
break;
|
2009-03-12 20:04:38 -06:00
|
|
|
}
|
|
|
|
return v;
|
|
|
|
}
|
|
|
|
|
2010-02-12 14:59:02 -07:00
|
|
|
Val
|
2009-03-12 20:04:38 -06:00
|
|
|
toint(Val v)
|
|
|
|
{
|
|
|
|
Mpint *i;
|
|
|
|
|
2010-02-17 23:08:30 -07:00
|
|
|
switch(v.ctype) {
|
2011-12-08 20:07:43 -07:00
|
|
|
case CTRUNE:
|
|
|
|
v.ctype = CTINT;
|
|
|
|
break;
|
2010-02-17 23:08:30 -07:00
|
|
|
case CTFLT:
|
2009-03-12 20:04:38 -06:00
|
|
|
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;
|
2010-02-17 23:08:30 -07:00
|
|
|
break;
|
|
|
|
case CTCPLX:
|
|
|
|
i = mal(sizeof(*i));
|
|
|
|
if(mpmovefltfix(i, &v.u.cval->real) < 0)
|
2010-12-13 13:34:45 -07:00
|
|
|
yyerror("constant %#F%+#Fi truncated to integer", &v.u.cval->real, &v.u.cval->imag);
|
2010-02-17 23:08:30 -07:00
|
|
|
if(mpcmpfltc(&v.u.cval->imag, 0) != 0)
|
2010-12-13 13:34:45 -07:00
|
|
|
yyerror("constant %#F%+#Fi truncated to real", &v.u.cval->real, &v.u.cval->imag);
|
2010-02-17 23:08:30 -07:00
|
|
|
v.ctype = CTINT;
|
|
|
|
v.u.xval = i;
|
|
|
|
break;
|
2009-03-12 20:04:38 -06:00
|
|
|
}
|
|
|
|
return v;
|
|
|
|
}
|
|
|
|
|
2012-10-21 11:22:51 -06:00
|
|
|
int
|
|
|
|
doesoverflow(Val v, Type *t)
|
2009-03-12 20:04:38 -06:00
|
|
|
{
|
|
|
|
switch(v.ctype) {
|
|
|
|
case CTINT:
|
2011-12-08 20:07:43 -07:00
|
|
|
case CTRUNE:
|
2009-07-30 17:53:08 -06:00
|
|
|
if(!isint[t->etype])
|
|
|
|
fatal("overflow: %T integer constant", t);
|
2010-02-17 23:08:30 -07:00
|
|
|
if(mpcmpfixfix(v.u.xval, minintval[t->etype]) < 0 ||
|
|
|
|
mpcmpfixfix(v.u.xval, maxintval[t->etype]) > 0)
|
2012-10-21 11:22:51 -06:00
|
|
|
return 1;
|
2009-03-12 20:04:38 -06:00
|
|
|
break;
|
|
|
|
case CTFLT:
|
2009-07-30 17:53:08 -06:00
|
|
|
if(!isfloat[t->etype])
|
|
|
|
fatal("overflow: %T floating-point constant", t);
|
2010-02-17 23:08:30 -07:00
|
|
|
if(mpcmpfltflt(v.u.fval, minfltval[t->etype]) <= 0 ||
|
|
|
|
mpcmpfltflt(v.u.fval, maxfltval[t->etype]) >= 0)
|
2012-10-21 11:22:51 -06:00
|
|
|
return 1;
|
2010-02-17 23:08:30 -07:00
|
|
|
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)
|
2012-10-21 11:22:51 -06:00
|
|
|
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);
|
2009-03-12 20:04:38 -06:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static Val
|
|
|
|
tostr(Val v)
|
|
|
|
{
|
|
|
|
Rune rune;
|
|
|
|
int l;
|
2009-04-09 19:16:21 -06:00
|
|
|
Strlit *s;
|
2009-03-12 20:04:38 -06:00
|
|
|
|
|
|
|
switch(v.ctype) {
|
|
|
|
case CTINT:
|
2011-12-08 20:07:43 -07:00
|
|
|
case CTRUNE:
|
2010-02-17 23:08:30 -07:00
|
|
|
if(mpcmpfixfix(v.u.xval, minintval[TINT]) < 0 ||
|
|
|
|
mpcmpfixfix(v.u.xval, maxintval[TINT]) > 0)
|
2009-03-12 20:04:38 -06:00
|
|
|
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);
|
2009-09-21 16:45:55 -06:00
|
|
|
memset(&v, 0, sizeof v);
|
2009-03-12 20:04:38 -06:00
|
|
|
v.ctype = CTSTR;
|
|
|
|
v.u.sval = s;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CTFLT:
|
|
|
|
yyerror("no float -> string");
|
2009-10-20 09:27:14 -06:00
|
|
|
|
2009-09-21 16:45:55 -06:00
|
|
|
case CTNIL:
|
|
|
|
memset(&v, 0, sizeof v);
|
|
|
|
v.ctype = CTSTR;
|
|
|
|
v.u.sval = mal(sizeof *s);
|
|
|
|
break;
|
2009-03-12 20:04:38 -06:00
|
|
|
}
|
|
|
|
return v;
|
2008-12-12 14:10:36 -07:00
|
|
|
}
|
|
|
|
|
2009-03-12 20:04:38 -06:00
|
|
|
int
|
|
|
|
consttype(Node *n)
|
|
|
|
{
|
|
|
|
if(n == N || n->op != OLITERAL)
|
|
|
|
return -1;
|
|
|
|
return n->val.ctype;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
isconst(Node *n, int ct)
|
|
|
|
{
|
2011-12-08 20:07:43 -07:00
|
|
|
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);
|
2009-03-12 20:04:38 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* if n is constant, rewrite as OLITERAL node.
|
|
|
|
*/
|
2008-06-04 15:37:38 -06:00
|
|
|
void
|
|
|
|
evconst(Node *n)
|
|
|
|
{
|
2011-11-28 10:22:15 -07:00
|
|
|
Node *nl, *nr, *norig;
|
2008-08-03 18:25:15 -06:00
|
|
|
int32 len;
|
2009-04-09 19:16:21 -06:00
|
|
|
Strlit *str;
|
2009-03-24 17:40:38 -06:00
|
|
|
int wl, wr, lno, et;
|
2010-01-24 23:42:18 -07:00
|
|
|
Val v, rv;
|
2009-03-24 17:40:38 -06:00
|
|
|
Mpint b;
|
2008-10-06 14:52:23 -06:00
|
|
|
|
2009-11-16 18:40:47 -07:00
|
|
|
// pick off just the opcodes that can be
|
|
|
|
// constant evaluated.
|
2009-07-30 17:53:08 -06:00
|
|
|
switch(n->op) {
|
2009-11-16 18:40:47 -07:00
|
|
|
default:
|
2009-07-30 17:53:08 -06:00
|
|
|
return;
|
2009-11-16 18:40:47 -07:00
|
|
|
case OADD:
|
|
|
|
case OADDSTR:
|
|
|
|
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;
|
2010-02-02 00:05:15 -07:00
|
|
|
case OCONV:
|
|
|
|
if(n->type == T)
|
|
|
|
return;
|
|
|
|
if(!okforconst[n->type->etype] && n->type->etype != TNIL)
|
|
|
|
return;
|
|
|
|
break;
|
2009-07-30 17:53:08 -06:00
|
|
|
}
|
|
|
|
|
2008-06-04 15:37:38 -06:00
|
|
|
nl = n->left;
|
2009-03-12 20:04:38 -06:00
|
|
|
if(nl == N || nl->type == T)
|
2008-06-04 15:37:38 -06:00
|
|
|
return;
|
2009-03-12 20:04:38 -06:00
|
|
|
if(consttype(nl) < 0)
|
2008-06-04 15:37:38 -06:00
|
|
|
return;
|
2009-03-12 20:04:38 -06:00
|
|
|
wl = nl->type->etype;
|
2010-02-17 23:08:30 -07:00
|
|
|
if(isint[wl] || isfloat[wl] || iscomplex[wl])
|
2009-03-12 20:04:38 -06:00
|
|
|
wl = TIDEAL;
|
2008-06-04 15:37:38 -06:00
|
|
|
|
|
|
|
nr = n->right;
|
|
|
|
if(nr == N)
|
|
|
|
goto unary;
|
2009-03-12 20:04:38 -06:00
|
|
|
if(nr->type == T)
|
2008-06-04 15:37:38 -06:00
|
|
|
return;
|
2009-03-12 20:04:38 -06:00
|
|
|
if(consttype(nr) < 0)
|
|
|
|
return;
|
|
|
|
wr = nr->type->etype;
|
2010-02-17 23:08:30 -07:00
|
|
|
if(isint[wr] || isfloat[wr] || iscomplex[wr])
|
2009-03-12 20:04:38 -06:00
|
|
|
wr = TIDEAL;
|
|
|
|
|
|
|
|
// check for compatible general types (numeric, string, etc)
|
|
|
|
if(wl != wr)
|
|
|
|
goto illegal;
|
2008-06-04 15:37:38 -06:00
|
|
|
|
2009-03-12 20:04:38 -06:00
|
|
|
// check for compatible types.
|
|
|
|
switch(n->op) {
|
|
|
|
default:
|
|
|
|
// ideal const mixes with anything but otherwise must match.
|
2009-07-17 14:38:16 -06:00
|
|
|
if(nl->type->etype != TIDEAL) {
|
|
|
|
defaultlit(&nr, nl->type);
|
|
|
|
n->right = nr;
|
|
|
|
}
|
|
|
|
if(nr->type->etype != TIDEAL) {
|
|
|
|
defaultlit(&nl, nr->type);
|
|
|
|
n->left = nl;
|
|
|
|
}
|
2009-03-12 20:04:38 -06:00
|
|
|
if(nl->type->etype != nr->type->etype)
|
|
|
|
goto illegal;
|
2008-06-04 15:37:38 -06:00
|
|
|
break;
|
2008-06-15 21:24:30 -06:00
|
|
|
|
2009-03-12 20:04:38 -06:00
|
|
|
case OLSH:
|
|
|
|
case ORSH:
|
|
|
|
// right must be unsigned.
|
|
|
|
// left can be ideal.
|
2009-07-17 14:38:16 -06:00
|
|
|
defaultlit(&nr, types[TUINT]);
|
|
|
|
n->right = nr;
|
2009-07-07 00:33:17 -06:00
|
|
|
if(nr->type && (issigned[nr->type->etype] || !isint[nr->type->etype]))
|
|
|
|
goto illegal;
|
2011-12-08 20:07:43 -07:00
|
|
|
if(nl->val.ctype != CTRUNE)
|
|
|
|
nl->val = toint(nl->val);
|
2011-05-31 13:05:40 -06:00
|
|
|
nr->val = toint(nr->val);
|
2009-03-12 20:04:38 -06:00
|
|
|
break;
|
2008-06-04 15:37:38 -06:00
|
|
|
}
|
|
|
|
|
2009-03-12 20:04:38 -06:00
|
|
|
// 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);
|
|
|
|
|
2010-01-24 23:42:18 -07:00
|
|
|
rv = nr->val;
|
|
|
|
|
2010-02-17 23:08:30 -07:00
|
|
|
// convert to common ideal
|
|
|
|
if(v.ctype == CTCPLX || rv.ctype == CTCPLX) {
|
|
|
|
v = tocplx(v);
|
|
|
|
rv = tocplx(rv);
|
|
|
|
}
|
|
|
|
if(v.ctype == CTFLT || rv.ctype == CTFLT) {
|
2009-03-12 20:04:38 -06:00
|
|
|
v = toflt(v);
|
2010-01-24 23:42:18 -07:00
|
|
|
rv = toflt(rv);
|
2008-08-08 18:13:31 -06:00
|
|
|
}
|
2011-12-08 20:07:43 -07:00
|
|
|
|
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
|
2010-07-26 18:34:17 -06:00
|
|
|
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);
|
|
|
|
}
|
2008-08-08 18:13:31 -06:00
|
|
|
|
2009-03-12 20:04:38 -06:00
|
|
|
// run op
|
|
|
|
switch(TUP(n->op, v.ctype)) {
|
2008-06-04 15:37:38 -06:00
|
|
|
default:
|
2009-03-12 20:04:38 -06:00
|
|
|
illegal:
|
2009-07-07 00:33:17 -06:00
|
|
|
if(!n->diag) {
|
|
|
|
yyerror("illegal constant expression: %T %O %T",
|
|
|
|
nl->type, n->op, nr->type);
|
|
|
|
n->diag = 1;
|
|
|
|
}
|
2008-06-04 15:37:38 -06:00
|
|
|
return;
|
2012-02-21 20:54:07 -07:00
|
|
|
|
2009-03-12 20:04:38 -06:00
|
|
|
case TUP(OADD, CTINT):
|
2011-12-08 20:07:43 -07:00
|
|
|
case TUP(OADD, CTRUNE):
|
2012-02-10 22:50:56 -07:00
|
|
|
mpaddfixfix(v.u.xval, rv.u.xval, 0);
|
2008-06-04 15:37:38 -06:00
|
|
|
break;
|
2009-03-12 20:04:38 -06:00
|
|
|
case TUP(OSUB, CTINT):
|
2011-12-08 20:07:43 -07:00
|
|
|
case TUP(OSUB, CTRUNE):
|
2010-01-24 23:42:18 -07:00
|
|
|
mpsubfixfix(v.u.xval, rv.u.xval);
|
2008-06-04 15:37:38 -06:00
|
|
|
break;
|
2009-03-12 20:04:38 -06:00
|
|
|
case TUP(OMUL, CTINT):
|
2011-12-08 20:07:43 -07:00
|
|
|
case TUP(OMUL, CTRUNE):
|
2010-01-24 23:42:18 -07:00
|
|
|
mpmulfixfix(v.u.xval, rv.u.xval);
|
2008-06-04 15:37:38 -06:00
|
|
|
break;
|
2009-03-12 20:04:38 -06:00
|
|
|
case TUP(ODIV, CTINT):
|
2011-12-08 20:07:43 -07:00
|
|
|
case TUP(ODIV, CTRUNE):
|
2010-01-24 23:42:18 -07:00
|
|
|
if(mpcmpfixc(rv.u.xval, 0) == 0) {
|
2009-03-12 20:04:38 -06:00
|
|
|
yyerror("division by zero");
|
|
|
|
mpmovecfix(v.u.xval, 1);
|
|
|
|
break;
|
|
|
|
}
|
2010-01-24 23:42:18 -07:00
|
|
|
mpdivfixfix(v.u.xval, rv.u.xval);
|
2008-06-04 15:37:38 -06:00
|
|
|
break;
|
2009-03-12 20:04:38 -06:00
|
|
|
case TUP(OMOD, CTINT):
|
2011-12-08 20:07:43 -07:00
|
|
|
case TUP(OMOD, CTRUNE):
|
2010-01-24 23:42:18 -07:00
|
|
|
if(mpcmpfixc(rv.u.xval, 0) == 0) {
|
2009-03-12 20:04:38 -06:00
|
|
|
yyerror("division by zero");
|
|
|
|
mpmovecfix(v.u.xval, 1);
|
|
|
|
break;
|
|
|
|
}
|
2010-01-24 23:42:18 -07:00
|
|
|
mpmodfixfix(v.u.xval, rv.u.xval);
|
2008-06-04 15:37:38 -06:00
|
|
|
break;
|
2008-08-08 18:13:31 -06:00
|
|
|
|
2009-03-12 20:04:38 -06:00
|
|
|
case TUP(OLSH, CTINT):
|
2011-12-08 20:07:43 -07:00
|
|
|
case TUP(OLSH, CTRUNE):
|
2010-01-24 23:42:18 -07:00
|
|
|
mplshfixfix(v.u.xval, rv.u.xval);
|
2008-06-04 15:37:38 -06:00
|
|
|
break;
|
2009-03-12 20:04:38 -06:00
|
|
|
case TUP(ORSH, CTINT):
|
2011-12-08 20:07:43 -07:00
|
|
|
case TUP(ORSH, CTRUNE):
|
2010-01-24 23:42:18 -07:00
|
|
|
mprshfixfix(v.u.xval, rv.u.xval);
|
2008-06-04 15:37:38 -06:00
|
|
|
break;
|
2009-03-12 20:04:38 -06:00
|
|
|
case TUP(OOR, CTINT):
|
2011-12-08 20:07:43 -07:00
|
|
|
case TUP(OOR, CTRUNE):
|
2010-01-24 23:42:18 -07:00
|
|
|
mporfixfix(v.u.xval, rv.u.xval);
|
2008-06-04 15:37:38 -06:00
|
|
|
break;
|
2009-03-12 20:04:38 -06:00
|
|
|
case TUP(OAND, CTINT):
|
2011-12-08 20:07:43 -07:00
|
|
|
case TUP(OAND, CTRUNE):
|
2010-01-24 23:42:18 -07:00
|
|
|
mpandfixfix(v.u.xval, rv.u.xval);
|
2008-06-04 15:37:38 -06:00
|
|
|
break;
|
2009-03-12 20:04:38 -06:00
|
|
|
case TUP(OANDNOT, CTINT):
|
2011-12-08 20:07:43 -07:00
|
|
|
case TUP(OANDNOT, CTRUNE):
|
2010-01-24 23:42:18 -07:00
|
|
|
mpandnotfixfix(v.u.xval, rv.u.xval);
|
2009-03-11 20:59:35 -06:00
|
|
|
break;
|
2009-03-12 20:04:38 -06:00
|
|
|
case TUP(OXOR, CTINT):
|
2011-12-08 20:07:43 -07:00
|
|
|
case TUP(OXOR, CTRUNE):
|
2010-01-24 23:42:18 -07:00
|
|
|
mpxorfixfix(v.u.xval, rv.u.xval);
|
2008-07-27 14:09:15 -06:00
|
|
|
break;
|
2010-02-19 21:42:50 -07:00
|
|
|
|
2009-03-12 20:04:38 -06:00
|
|
|
case TUP(OADD, CTFLT):
|
2010-01-24 23:42:18 -07:00
|
|
|
mpaddfltflt(v.u.fval, rv.u.fval);
|
2008-06-04 15:37:38 -06:00
|
|
|
break;
|
2009-03-12 20:04:38 -06:00
|
|
|
case TUP(OSUB, CTFLT):
|
2010-01-24 23:42:18 -07:00
|
|
|
mpsubfltflt(v.u.fval, rv.u.fval);
|
2008-06-04 15:37:38 -06:00
|
|
|
break;
|
2009-03-12 20:04:38 -06:00
|
|
|
case TUP(OMUL, CTFLT):
|
2010-01-24 23:42:18 -07:00
|
|
|
mpmulfltflt(v.u.fval, rv.u.fval);
|
2008-06-04 15:37:38 -06:00
|
|
|
break;
|
2009-03-12 20:04:38 -06:00
|
|
|
case TUP(ODIV, CTFLT):
|
2010-01-24 23:42:18 -07:00
|
|
|
if(mpcmpfltc(rv.u.fval, 0) == 0) {
|
2009-03-12 20:04:38 -06:00
|
|
|
yyerror("division by zero");
|
|
|
|
mpmovecflt(v.u.fval, 1.0);
|
|
|
|
break;
|
|
|
|
}
|
2010-01-24 23:42:18 -07:00
|
|
|
mpdivfltflt(v.u.fval, rv.u.fval);
|
2008-06-04 15:37:38 -06:00
|
|
|
break;
|
2012-02-18 22:12:31 -07:00
|
|
|
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;
|
2012-02-21 20:54:07 -07:00
|
|
|
|
2010-02-17 23:08:30 -07:00
|
|
|
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):
|
2010-02-18 18:55:11 -07:00
|
|
|
cmplxmpy(v.u.cval, rv.u.cval);
|
|
|
|
break;
|
2010-02-17 23:08:30 -07:00
|
|
|
case TUP(ODIV, CTCPLX):
|
2010-02-19 21:42:50 -07:00
|
|
|
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;
|
|
|
|
}
|
2010-02-18 18:55:11 -07:00
|
|
|
cmplxdiv(v.u.cval, rv.u.cval);
|
2010-02-17 23:08:30 -07:00
|
|
|
break;
|
|
|
|
|
2009-03-12 20:04:38 -06:00
|
|
|
case TUP(OEQ, CTNIL):
|
2008-12-09 18:52:41 -07:00
|
|
|
goto settrue;
|
2009-03-12 20:04:38 -06:00
|
|
|
case TUP(ONE, CTNIL):
|
2008-12-09 18:52:41 -07:00
|
|
|
goto setfalse;
|
|
|
|
|
2009-03-12 20:04:38 -06:00
|
|
|
case TUP(OEQ, CTINT):
|
2011-12-08 20:07:43 -07:00
|
|
|
case TUP(OEQ, CTRUNE):
|
2010-01-24 23:42:18 -07:00
|
|
|
if(mpcmpfixfix(v.u.xval, rv.u.xval) == 0)
|
2008-06-04 15:37:38 -06:00
|
|
|
goto settrue;
|
|
|
|
goto setfalse;
|
2009-03-12 20:04:38 -06:00
|
|
|
case TUP(ONE, CTINT):
|
2011-12-08 20:07:43 -07:00
|
|
|
case TUP(ONE, CTRUNE):
|
2010-01-24 23:42:18 -07:00
|
|
|
if(mpcmpfixfix(v.u.xval, rv.u.xval) != 0)
|
2008-06-04 15:37:38 -06:00
|
|
|
goto settrue;
|
|
|
|
goto setfalse;
|
2009-03-12 20:04:38 -06:00
|
|
|
case TUP(OLT, CTINT):
|
2011-12-08 20:07:43 -07:00
|
|
|
case TUP(OLT, CTRUNE):
|
2010-01-24 23:42:18 -07:00
|
|
|
if(mpcmpfixfix(v.u.xval, rv.u.xval) < 0)
|
2008-06-04 15:37:38 -06:00
|
|
|
goto settrue;
|
|
|
|
goto setfalse;
|
2009-03-12 20:04:38 -06:00
|
|
|
case TUP(OLE, CTINT):
|
2011-12-08 20:07:43 -07:00
|
|
|
case TUP(OLE, CTRUNE):
|
2010-01-24 23:42:18 -07:00
|
|
|
if(mpcmpfixfix(v.u.xval, rv.u.xval) <= 0)
|
2008-06-04 15:37:38 -06:00
|
|
|
goto settrue;
|
|
|
|
goto setfalse;
|
2009-03-12 20:04:38 -06:00
|
|
|
case TUP(OGE, CTINT):
|
2011-12-08 20:07:43 -07:00
|
|
|
case TUP(OGE, CTRUNE):
|
2010-01-24 23:42:18 -07:00
|
|
|
if(mpcmpfixfix(v.u.xval, rv.u.xval) >= 0)
|
2008-06-04 15:37:38 -06:00
|
|
|
goto settrue;
|
|
|
|
goto setfalse;
|
2009-03-12 20:04:38 -06:00
|
|
|
case TUP(OGT, CTINT):
|
2011-12-08 20:07:43 -07:00
|
|
|
case TUP(OGT, CTRUNE):
|
2010-01-24 23:42:18 -07:00
|
|
|
if(mpcmpfixfix(v.u.xval, rv.u.xval) > 0)
|
2008-06-04 15:37:38 -06:00
|
|
|
goto settrue;
|
|
|
|
goto setfalse;
|
|
|
|
|
2009-03-12 20:04:38 -06:00
|
|
|
case TUP(OEQ, CTFLT):
|
2010-01-24 23:42:18 -07:00
|
|
|
if(mpcmpfltflt(v.u.fval, rv.u.fval) == 0)
|
2008-06-04 15:37:38 -06:00
|
|
|
goto settrue;
|
|
|
|
goto setfalse;
|
2009-03-12 20:04:38 -06:00
|
|
|
case TUP(ONE, CTFLT):
|
2010-01-24 23:42:18 -07:00
|
|
|
if(mpcmpfltflt(v.u.fval, rv.u.fval) != 0)
|
2008-06-04 15:37:38 -06:00
|
|
|
goto settrue;
|
|
|
|
goto setfalse;
|
2009-03-12 20:04:38 -06:00
|
|
|
case TUP(OLT, CTFLT):
|
2010-01-24 23:42:18 -07:00
|
|
|
if(mpcmpfltflt(v.u.fval, rv.u.fval) < 0)
|
2008-06-04 15:37:38 -06:00
|
|
|
goto settrue;
|
|
|
|
goto setfalse;
|
2009-03-12 20:04:38 -06:00
|
|
|
case TUP(OLE, CTFLT):
|
2010-01-24 23:42:18 -07:00
|
|
|
if(mpcmpfltflt(v.u.fval, rv.u.fval) <= 0)
|
2008-06-04 15:37:38 -06:00
|
|
|
goto settrue;
|
|
|
|
goto setfalse;
|
2009-03-12 20:04:38 -06:00
|
|
|
case TUP(OGE, CTFLT):
|
2010-01-24 23:42:18 -07:00
|
|
|
if(mpcmpfltflt(v.u.fval, rv.u.fval) >= 0)
|
2008-06-04 15:37:38 -06:00
|
|
|
goto settrue;
|
|
|
|
goto setfalse;
|
2009-03-12 20:04:38 -06:00
|
|
|
case TUP(OGT, CTFLT):
|
2010-01-24 23:42:18 -07:00
|
|
|
if(mpcmpfltflt(v.u.fval, rv.u.fval) > 0)
|
2008-06-04 15:37:38 -06:00
|
|
|
goto settrue;
|
|
|
|
goto setfalse;
|
|
|
|
|
2010-02-19 21:42:50 -07:00
|
|
|
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;
|
|
|
|
|
2009-03-12 20:04:38 -06:00
|
|
|
case TUP(OEQ, CTSTR):
|
2008-06-04 15:37:38 -06:00
|
|
|
if(cmpslit(nl, nr) == 0)
|
|
|
|
goto settrue;
|
|
|
|
goto setfalse;
|
2009-03-12 20:04:38 -06:00
|
|
|
case TUP(ONE, CTSTR):
|
2008-06-04 15:37:38 -06:00
|
|
|
if(cmpslit(nl, nr) != 0)
|
|
|
|
goto settrue;
|
|
|
|
goto setfalse;
|
2009-03-12 20:04:38 -06:00
|
|
|
case TUP(OLT, CTSTR):
|
2008-06-04 15:37:38 -06:00
|
|
|
if(cmpslit(nl, nr) < 0)
|
|
|
|
goto settrue;
|
|
|
|
goto setfalse;
|
2009-03-12 20:04:38 -06:00
|
|
|
case TUP(OLE, CTSTR):
|
2008-06-04 15:37:38 -06:00
|
|
|
if(cmpslit(nl, nr) <= 0)
|
|
|
|
goto settrue;
|
|
|
|
goto setfalse;
|
2009-03-12 20:04:38 -06:00
|
|
|
case TUP(OGE, CTSTR):
|
2008-06-04 15:37:38 -06:00
|
|
|
if(cmpslit(nl, nr) >= 0l)
|
|
|
|
goto settrue;
|
|
|
|
goto setfalse;
|
2009-03-12 20:04:38 -06:00
|
|
|
case TUP(OGT, CTSTR):
|
2008-06-04 15:37:38 -06:00
|
|
|
if(cmpslit(nl, nr) > 0)
|
|
|
|
goto settrue;
|
|
|
|
goto setfalse;
|
2009-08-03 12:58:52 -06:00
|
|
|
case TUP(OADDSTR, CTSTR):
|
2010-01-24 23:42:18 -07:00
|
|
|
len = v.u.sval->len + rv.u.sval->len;
|
2008-06-04 15:37:38 -06:00
|
|
|
str = mal(sizeof(*str) + len);
|
|
|
|
str->len = len;
|
2009-03-12 20:04:38 -06:00
|
|
|
memcpy(str->s, v.u.sval->s, v.u.sval->len);
|
2010-01-24 23:42:18 -07:00
|
|
|
memcpy(str->s+v.u.sval->len, rv.u.sval->s, rv.u.sval->len);
|
2008-06-04 15:37:38 -06:00
|
|
|
str->len = len;
|
2009-03-12 20:04:38 -06:00
|
|
|
v.u.sval = str;
|
2008-06-04 15:37:38 -06:00
|
|
|
break;
|
|
|
|
|
2009-03-12 20:04:38 -06:00
|
|
|
case TUP(OOROR, CTBOOL):
|
2010-01-24 23:42:18 -07:00
|
|
|
if(v.u.bval || rv.u.bval)
|
2008-06-04 15:37:38 -06:00
|
|
|
goto settrue;
|
|
|
|
goto setfalse;
|
2009-03-12 20:04:38 -06:00
|
|
|
case TUP(OANDAND, CTBOOL):
|
2010-01-24 23:42:18 -07:00
|
|
|
if(v.u.bval && rv.u.bval)
|
2009-03-12 20:04:38 -06:00
|
|
|
goto settrue;
|
|
|
|
goto setfalse;
|
|
|
|
case TUP(OEQ, CTBOOL):
|
2010-01-24 23:42:18 -07:00
|
|
|
if(v.u.bval == rv.u.bval)
|
2009-03-12 20:04:38 -06:00
|
|
|
goto settrue;
|
|
|
|
goto setfalse;
|
|
|
|
case TUP(ONE, CTBOOL):
|
2010-01-24 23:42:18 -07:00
|
|
|
if(v.u.bval != rv.u.bval)
|
2008-06-04 15:37:38 -06:00
|
|
|
goto settrue;
|
|
|
|
goto setfalse;
|
|
|
|
}
|
2008-08-09 18:29:26 -06:00
|
|
|
goto ret;
|
2008-06-04 15:37:38 -06:00
|
|
|
|
|
|
|
unary:
|
2009-03-12 20:04:38 -06:00
|
|
|
// 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);
|
2008-08-09 18:29:26 -06:00
|
|
|
|
2009-03-12 20:04:38 -06:00
|
|
|
switch(TUP(n->op, v.ctype)) {
|
2008-06-04 15:37:38 -06:00
|
|
|
default:
|
2009-07-07 00:33:17 -06:00
|
|
|
if(!n->diag) {
|
|
|
|
yyerror("illegal constant expression %O %T", n->op, nl->type);
|
|
|
|
n->diag = 1;
|
|
|
|
}
|
2008-06-04 15:37:38 -06:00
|
|
|
return;
|
|
|
|
|
2009-09-21 16:45:55 -06:00
|
|
|
case TUP(OCONV, CTNIL):
|
|
|
|
case TUP(OARRAYBYTESTR, CTNIL):
|
|
|
|
if(n->type->etype == TSTRING) {
|
|
|
|
v = tostr(v);
|
|
|
|
nl->type = n->type;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
// fall through
|
2009-07-29 13:47:51 -06:00
|
|
|
case TUP(OCONV, CTINT):
|
2011-12-08 20:07:43 -07:00
|
|
|
case TUP(OCONV, CTRUNE):
|
2009-07-29 13:47:51 -06:00
|
|
|
case TUP(OCONV, CTFLT):
|
|
|
|
case TUP(OCONV, CTSTR):
|
|
|
|
convlit1(&nl, n->type, 1);
|
|
|
|
break;
|
|
|
|
|
2009-03-12 20:04:38 -06:00
|
|
|
case TUP(OPLUS, CTINT):
|
2011-12-08 20:07:43 -07:00
|
|
|
case TUP(OPLUS, CTRUNE):
|
2008-06-04 15:37:38 -06:00
|
|
|
break;
|
2009-03-12 20:04:38 -06:00
|
|
|
case TUP(OMINUS, CTINT):
|
2011-12-08 20:07:43 -07:00
|
|
|
case TUP(OMINUS, CTRUNE):
|
2009-03-12 20:04:38 -06:00
|
|
|
mpnegfix(v.u.xval);
|
2008-06-04 15:37:38 -06:00
|
|
|
break;
|
2009-03-12 20:04:38 -06:00
|
|
|
case TUP(OCOM, CTINT):
|
2011-12-08 20:07:43 -07:00
|
|
|
case TUP(OCOM, CTRUNE):
|
2009-03-24 17:40:38 -06:00
|
|
|
et = Txxx;
|
|
|
|
if(nl->type != T)
|
|
|
|
et = nl->type->etype;
|
|
|
|
|
|
|
|
// calculate the mask in b
|
|
|
|
// result will be (a ^ mask)
|
|
|
|
switch(et) {
|
|
|
|
default:
|
2009-05-29 16:34:47 -06:00
|
|
|
// signed guys change sign
|
2009-03-24 17:40:38 -06:00
|
|
|
mpmovecfix(&b, -1);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case TUINT8:
|
|
|
|
case TUINT16:
|
|
|
|
case TUINT32:
|
|
|
|
case TUINT64:
|
|
|
|
case TUINT:
|
|
|
|
case TUINTPTR:
|
2009-05-29 16:34:47 -06:00
|
|
|
// unsigned guys invert their bits
|
2009-03-24 17:40:38 -06:00
|
|
|
mpmovefixfix(&b, maxintval[et]);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
mpxorfixfix(v.u.xval, &b);
|
2008-06-04 15:37:38 -06:00
|
|
|
break;
|
|
|
|
|
2009-03-12 20:04:38 -06:00
|
|
|
case TUP(OPLUS, CTFLT):
|
2008-06-04 15:37:38 -06:00
|
|
|
break;
|
2009-03-12 20:04:38 -06:00
|
|
|
case TUP(OMINUS, CTFLT):
|
|
|
|
mpnegflt(v.u.fval);
|
2008-06-04 15:37:38 -06:00
|
|
|
break;
|
|
|
|
|
2010-02-18 18:55:11 -07:00
|
|
|
case TUP(OPLUS, CTCPLX):
|
|
|
|
break;
|
|
|
|
case TUP(OMINUS, CTCPLX):
|
|
|
|
mpnegflt(&v.u.cval->real);
|
|
|
|
mpnegflt(&v.u.cval->imag);
|
|
|
|
break;
|
|
|
|
|
2009-03-12 20:04:38 -06:00
|
|
|
case TUP(ONOT, CTBOOL):
|
|
|
|
if(!v.u.bval)
|
2008-06-04 15:37:38 -06:00
|
|
|
goto settrue;
|
|
|
|
goto setfalse;
|
|
|
|
}
|
2008-08-09 18:29:26 -06:00
|
|
|
|
|
|
|
ret:
|
2011-12-07 14:18:50 -07:00
|
|
|
if(n == n->orig) {
|
|
|
|
// duplicate node for n->orig.
|
|
|
|
norig = nod(OLITERAL, N, N);
|
|
|
|
*norig = *n;
|
|
|
|
} else
|
|
|
|
norig = n->orig;
|
2008-06-04 15:37:38 -06:00
|
|
|
*n = *nl;
|
2011-11-28 10:22:15 -07:00
|
|
|
// restore value of n->orig.
|
|
|
|
n->orig = norig;
|
2009-03-12 20:04:38 -06:00
|
|
|
n->val = v;
|
|
|
|
|
|
|
|
// check range.
|
2009-06-25 17:32:33 -06:00
|
|
|
lno = setlineno(n);
|
2009-03-12 20:04:38 -06:00
|
|
|
overflow(v, n->type);
|
|
|
|
lineno = lno;
|
|
|
|
|
|
|
|
// truncate precision for non-ideal float.
|
|
|
|
if(v.ctype == CTFLT && n->type->etype != TIDEAL)
|
2009-05-27 11:16:13 -06:00
|
|
|
n->val.u.fval = truncfltlit(v.u.fval, n->type);
|
2009-03-12 20:04:38 -06:00
|
|
|
return;
|
|
|
|
|
|
|
|
settrue:
|
|
|
|
*n = *nodbool(1);
|
|
|
|
return;
|
|
|
|
|
|
|
|
setfalse:
|
|
|
|
*n = *nodbool(0);
|
|
|
|
return;
|
|
|
|
}
|
2008-08-09 18:29:26 -06:00
|
|
|
|
2009-03-12 20:04:38 -06:00
|
|
|
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:
|
2009-09-21 16:45:55 -06:00
|
|
|
n->type = idealstring;
|
2009-03-12 20:04:38 -06:00
|
|
|
break;
|
|
|
|
case CTBOOL:
|
2012-02-21 20:54:07 -07:00
|
|
|
n->type = idealbool;
|
2009-03-12 20:04:38 -06:00
|
|
|
break;
|
|
|
|
case CTINT:
|
2011-12-08 20:07:43 -07:00
|
|
|
case CTRUNE:
|
2009-03-12 20:04:38 -06:00
|
|
|
case CTFLT:
|
2010-02-17 23:08:30 -07:00
|
|
|
case CTCPLX:
|
2009-03-12 20:04:38 -06:00
|
|
|
n->type = types[TIDEAL];
|
|
|
|
break;
|
|
|
|
case CTNIL:
|
|
|
|
n->type = types[TNIL];
|
|
|
|
break;
|
2008-08-09 18:29:26 -06:00
|
|
|
}
|
2009-03-12 20:04:38 -06:00
|
|
|
return n;
|
2008-06-04 15:37:38 -06:00
|
|
|
}
|
|
|
|
|
2010-02-18 15:46:28 -07:00
|
|
|
Node*
|
|
|
|
nodcplxlit(Val r, Val i)
|
|
|
|
{
|
|
|
|
Node *n;
|
|
|
|
Mpcplx *c;
|
|
|
|
|
2010-03-08 16:44:18 -07:00
|
|
|
r = toflt(r);
|
|
|
|
i = toflt(i);
|
|
|
|
|
2010-02-18 15:46:28 -07:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2009-08-04 11:26:29 -06:00
|
|
|
// TODO(rsc): combine with convlit
|
2008-06-04 15:37:38 -06:00
|
|
|
void
|
2009-07-17 14:38:16 -06:00
|
|
|
defaultlit(Node **np, Type *t)
|
2008-06-04 15:37:38 -06:00
|
|
|
{
|
2009-03-12 20:04:38 -06:00
|
|
|
int lno;
|
2009-07-17 14:38:16 -06:00
|
|
|
Node *n, *nn;
|
2009-03-12 20:04:38 -06:00
|
|
|
|
2009-07-17 14:38:16 -06:00
|
|
|
n = *np;
|
2009-08-27 12:16:34 -06:00
|
|
|
if(n == N || !isideal(n->type))
|
2008-06-04 15:37:38 -06:00
|
|
|
return;
|
2009-03-12 20:04:38 -06:00
|
|
|
|
|
|
|
switch(n->op) {
|
|
|
|
case OLITERAL:
|
2009-07-17 14:38:16 -06:00
|
|
|
nn = nod(OXXX, N, N);
|
|
|
|
*nn = *n;
|
|
|
|
n = nn;
|
|
|
|
*np = n;
|
2009-03-12 20:04:38 -06:00
|
|
|
break;
|
|
|
|
case OLSH:
|
|
|
|
case ORSH:
|
2009-07-17 14:38:16 -06:00
|
|
|
defaultlit(&n->left, t);
|
2009-08-23 19:09:44 -06:00
|
|
|
t = n->left->type;
|
|
|
|
if(t != T && !isint[t->etype]) {
|
2011-10-31 11:09:40 -06:00
|
|
|
yyerror("invalid operation: %N (shift of type %T)", n, t);
|
2009-08-23 19:09:44 -06:00
|
|
|
t = T;
|
|
|
|
}
|
|
|
|
n->type = t;
|
2008-06-04 15:37:38 -06:00
|
|
|
return;
|
2012-07-01 19:33:22 -06:00
|
|
|
case OCOM:
|
2012-02-21 22:29:37 -07:00
|
|
|
case ONOT:
|
|
|
|
defaultlit(&n->left, t);
|
|
|
|
n->type = n->left->type;
|
|
|
|
return;
|
2009-07-30 17:53:08 -06:00
|
|
|
default:
|
2012-07-01 19:33:22 -06:00
|
|
|
if(n->left == N || n->right == N) {
|
2009-09-09 02:01:39 -06:00
|
|
|
dump("defaultlit", n);
|
|
|
|
fatal("defaultlit");
|
|
|
|
}
|
2011-07-28 11:03:30 -06:00
|
|
|
// n is ideal, so left and right must both be ideal.
|
|
|
|
// n has not been computed as a constant value,
|
|
|
|
// so either left or right must not be constant.
|
|
|
|
// The only 'ideal' non-constant expressions are shifts. Ugh.
|
|
|
|
// If one of these is a shift and the other is not, use that type.
|
|
|
|
// When compiling x := 1<<i + 3.14, this means we try to push
|
|
|
|
// the float64 down into the 1<<i, producing the correct error
|
|
|
|
// (cannot shift float64).
|
|
|
|
if(t == T && (n->right->op == OLSH || n->right->op == ORSH)) {
|
|
|
|
defaultlit(&n->left, T);
|
|
|
|
defaultlit(&n->right, n->left->type);
|
|
|
|
} else if(t == T && (n->left->op == OLSH || n->left->op == ORSH)) {
|
|
|
|
defaultlit(&n->right, T);
|
|
|
|
defaultlit(&n->left, n->right->type);
|
2012-02-21 22:29:37 -07:00
|
|
|
} else if(iscmp[n->op]) {
|
|
|
|
defaultlit2(&n->left, &n->right, 1);
|
2011-07-28 11:03:30 -06:00
|
|
|
} else {
|
|
|
|
defaultlit(&n->left, t);
|
|
|
|
defaultlit(&n->right, t);
|
|
|
|
}
|
2012-02-21 22:29:37 -07:00
|
|
|
if(n->type == idealbool || n->type == idealstring) {
|
|
|
|
if(t != T && t->etype == n->type->etype)
|
|
|
|
n->type = t;
|
|
|
|
else
|
|
|
|
n->type = types[n->type->etype];
|
|
|
|
} else
|
2009-09-21 16:45:55 -06:00
|
|
|
n->type = n->left->type;
|
2009-07-30 17:53:08 -06:00
|
|
|
return;
|
2009-03-12 20:04:38 -06:00
|
|
|
}
|
2008-06-04 15:37:38 -06:00
|
|
|
|
2009-08-27 12:16:34 -06:00
|
|
|
lno = setlineno(n);
|
2008-06-04 15:37:38 -06:00
|
|
|
switch(n->val.ctype) {
|
|
|
|
default:
|
2009-08-04 11:26:29 -06:00
|
|
|
if(t != T) {
|
|
|
|
convlit(np, t);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if(n->val.ctype == CTNIL) {
|
|
|
|
lineno = lno;
|
|
|
|
yyerror("use of untyped nil");
|
|
|
|
n->type = T;
|
|
|
|
break;
|
|
|
|
}
|
2009-08-27 12:16:34 -06:00
|
|
|
if(n->val.ctype == CTSTR) {
|
|
|
|
n->type = types[TSTRING];
|
|
|
|
break;
|
|
|
|
}
|
2011-10-31 11:09:40 -06:00
|
|
|
yyerror("defaultlit: unknown literal: %N", n);
|
2008-06-04 15:37:38 -06:00
|
|
|
break;
|
2009-09-21 16:45:55 -06:00
|
|
|
case CTBOOL:
|
|
|
|
n->type = types[TBOOL];
|
2010-06-08 19:50:02 -06:00
|
|
|
if(t != T && t->etype == TBOOL)
|
|
|
|
n->type = t;
|
2009-09-21 16:45:55 -06:00
|
|
|
break;
|
2008-06-04 15:37:38 -06:00
|
|
|
case CTINT:
|
2008-10-29 13:46:44 -06:00
|
|
|
n->type = types[TINT];
|
2010-02-21 12:18:09 -07:00
|
|
|
goto num;
|
2011-12-08 20:07:43 -07:00
|
|
|
case CTRUNE:
|
|
|
|
n->type = runetype;
|
|
|
|
goto num;
|
2008-06-04 15:37:38 -06:00
|
|
|
case CTFLT:
|
2011-01-19 21:08:11 -07:00
|
|
|
n->type = types[TFLOAT64];
|
2010-02-21 12:18:09 -07:00
|
|
|
goto num;
|
|
|
|
case CTCPLX:
|
2011-01-19 21:08:11 -07:00
|
|
|
n->type = types[TCOMPLEX128];
|
2010-02-21 12:18:09 -07:00
|
|
|
goto num;
|
|
|
|
num:
|
2009-03-12 20:04:38 -06:00
|
|
|
if(t != T) {
|
2010-02-17 23:08:30 -07:00
|
|
|
if(isint[t->etype]) {
|
|
|
|
n->type = t;
|
|
|
|
n->val = toint(n->val);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
if(isfloat[t->etype]) {
|
|
|
|
n->type = t;
|
|
|
|
n->val = toflt(n->val);
|
2010-02-21 12:18:09 -07:00
|
|
|
}
|
|
|
|
else
|
|
|
|
if(iscomplex[t->etype]) {
|
2009-03-12 20:04:38 -06:00
|
|
|
n->type = t;
|
2010-02-21 12:18:09 -07:00
|
|
|
n->val = tocplx(n->val);
|
2009-03-12 20:04:38 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
overflow(n->val, n->type);
|
2008-06-04 15:37:38 -06:00
|
|
|
break;
|
|
|
|
}
|
2009-03-12 20:04:38 -06:00
|
|
|
lineno = lno;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* defaultlit on both nodes simultaneously;
|
|
|
|
* if they're both ideal going in they better
|
|
|
|
* get the same type going out.
|
2010-02-21 12:18:09 -07:00
|
|
|
* force means must assign concrete (non-ideal) type.
|
2009-03-12 20:04:38 -06:00
|
|
|
*/
|
|
|
|
void
|
2009-07-30 17:53:08 -06:00
|
|
|
defaultlit2(Node **lp, Node **rp, int force)
|
2009-03-12 20:04:38 -06:00
|
|
|
{
|
2009-07-17 14:38:16 -06:00
|
|
|
Node *l, *r;
|
|
|
|
|
|
|
|
l = *lp;
|
|
|
|
r = *rp;
|
2009-03-12 20:04:38 -06:00
|
|
|
if(l->type == T || r->type == T)
|
|
|
|
return;
|
2009-09-21 16:45:55 -06:00
|
|
|
if(!isideal(l->type)) {
|
2009-07-17 14:38:16 -06:00
|
|
|
convlit(rp, l->type);
|
2009-03-12 20:04:38 -06:00
|
|
|
return;
|
|
|
|
}
|
2009-09-21 16:45:55 -06:00
|
|
|
if(!isideal(r->type)) {
|
2009-07-17 14:38:16 -06:00
|
|
|
convlit(lp, r->type);
|
2009-03-12 20:04:38 -06:00
|
|
|
return;
|
|
|
|
}
|
2009-07-30 17:53:08 -06:00
|
|
|
if(!force)
|
|
|
|
return;
|
2012-02-21 22:29:37 -07:00
|
|
|
if(l->type->etype == TBOOL) {
|
|
|
|
convlit(lp, types[TBOOL]);
|
|
|
|
convlit(rp, types[TBOOL]);
|
|
|
|
}
|
2010-02-17 23:08:30 -07:00
|
|
|
if(isconst(l, CTCPLX) || isconst(r, CTCPLX)) {
|
2011-01-19 21:08:11 -07:00
|
|
|
convlit(lp, types[TCOMPLEX128]);
|
|
|
|
convlit(rp, types[TCOMPLEX128]);
|
2010-02-17 23:08:30 -07:00
|
|
|
return;
|
|
|
|
}
|
2009-03-12 20:04:38 -06:00
|
|
|
if(isconst(l, CTFLT) || isconst(r, CTFLT)) {
|
2011-01-19 21:08:11 -07:00
|
|
|
convlit(lp, types[TFLOAT64]);
|
|
|
|
convlit(rp, types[TFLOAT64]);
|
2009-03-12 20:04:38 -06:00
|
|
|
return;
|
|
|
|
}
|
2011-12-08 20:07:43 -07:00
|
|
|
|
|
|
|
if(isconst(l, CTRUNE) || isconst(r, CTRUNE)) {
|
|
|
|
convlit(lp, runetype);
|
|
|
|
convlit(rp, runetype);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-07-17 14:38:16 -06:00
|
|
|
convlit(lp, types[TINT]);
|
|
|
|
convlit(rp, types[TINT]);
|
2008-06-04 15:37:38 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
cmpslit(Node *l, Node *r)
|
|
|
|
{
|
2008-08-03 18:25:15 -06:00
|
|
|
int32 l1, l2, i, m;
|
2011-02-16 15:57:15 -07:00
|
|
|
uchar *s1, *s2;
|
2008-06-04 15:37:38 -06:00
|
|
|
|
2008-08-08 18:13:31 -06:00
|
|
|
l1 = l->val.u.sval->len;
|
|
|
|
l2 = r->val.u.sval->len;
|
2011-02-16 15:57:15 -07:00
|
|
|
s1 = (uchar*)l->val.u.sval->s;
|
|
|
|
s2 = (uchar*)r->val.u.sval->s;
|
2008-06-04 15:37:38 -06:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
2008-12-14 19:45:00 -07:00
|
|
|
|
|
|
|
int
|
|
|
|
smallintconst(Node *n)
|
|
|
|
{
|
2011-12-08 20:07:43 -07:00
|
|
|
if(n->op == OLITERAL && isconst(n, CTINT) && n->type != T)
|
2008-12-14 19:45:00 -07:00
|
|
|
switch(simtype[n->type->etype]) {
|
|
|
|
case TINT8:
|
|
|
|
case TUINT8:
|
|
|
|
case TINT16:
|
|
|
|
case TUINT16:
|
|
|
|
case TINT32:
|
|
|
|
case TUINT32:
|
|
|
|
case TBOOL:
|
|
|
|
case TPTR32:
|
|
|
|
return 1;
|
2011-08-31 05:37:14 -06:00
|
|
|
case TIDEAL:
|
2010-08-03 01:26:02 -06:00
|
|
|
case TINT64:
|
|
|
|
case TUINT64:
|
cmd/gc: recognize small TPTR64 values as small integer constants.
Given the following Go program:
func sum(s []int) int {
ret := 0
for _, x := range s {
ret += x
}
return ret
}
6g would previously generate:
--- prog list "sum" ---
0000 (main.go:3) TEXT sum+0(SB),$0-24
0001 (main.go:5) MOVQ s+0(FP),CX
0002 (main.go:5) MOVL s+8(FP),DI
0003 (main.go:5) MOVL s+12(FP),BX
0004 (main.go:4) MOVL $0,SI
0005 (main.go:5) MOVL $0,AX
0006 (main.go:5) JMP ,8
0007 (main.go:5) INCL ,AX
0008 (main.go:5) CMPL AX,DI
0009 (main.go:5) JGE $0,16
0010 (main.go:5) MOVL (CX),DX
0011 (main.go:5) MOVQ $4,BX
0012 (main.go:5) ADDQ CX,BX
0013 (main.go:5) MOVQ BX,CX
0014 (main.go:6) ADDL DX,SI
0015 (main.go:5) JMP ,7
0016 (main.go:8) MOVL SI,.noname+16(FP)
0017 (main.go:8) RET ,
and now generates:
--- prog list "sum" ---
0000 (main.go:3) TEXT sum+0(SB),$0-24
0001 (main.go:5) MOVQ s+0(FP),CX
0002 (main.go:5) MOVL s+8(FP),DI
0003 (main.go:5) MOVL s+12(FP),BX
0004 (main.go:4) MOVL $0,SI
0005 (main.go:5) MOVL $0,AX
0006 (main.go:5) JMP ,8
0007 (main.go:5) INCL ,AX
0008 (main.go:5) CMPL AX,DI
0009 (main.go:5) JGE $0,14
0010 (main.go:5) MOVL (CX),BP
0011 (main.go:5) ADDQ $4,CX
0012 (main.go:6) ADDL BP,SI
0013 (main.go:5) JMP ,7
0014 (main.go:8) MOVL SI,.noname+16(FP)
0015 (main.go:8) RET ,
The key difference is that
0011 (main.go:5) MOVQ $4,BX
0012 (main.go:5) ADDQ CX,BX
0013 (main.go:5) MOVQ BX,CX
has changed to
0011 (main.go:5) ADDQ $4,CX
R=rsc, dave, remyoudompheng
CC=golang-dev
https://golang.org/cl/6506089
2012-09-11 03:45:28 -06:00
|
|
|
case TPTR64:
|
2010-08-03 01:26:02 -06:00
|
|
|
if(mpcmpfixfix(n->val.u.xval, minintval[TINT32]) < 0
|
|
|
|
|| mpcmpfixfix(n->val.u.xval, maxintval[TINT32]) > 0)
|
|
|
|
break;
|
|
|
|
return 1;
|
2008-12-14 19:45:00 -07:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
2009-05-21 14:46:07 -06:00
|
|
|
|
|
|
|
long
|
|
|
|
nonnegconst(Node *n)
|
|
|
|
{
|
2009-08-21 18:54:07 -06:00
|
|
|
if(n->op == OLITERAL && n->type != T)
|
2009-05-21 14:46:07 -06:00
|
|
|
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;
|
|
|
|
}
|
2009-05-28 00:55:14 -06:00
|
|
|
|
|
|
|
/*
|
|
|
|
* convert x to type et and back to int64
|
|
|
|
* for sign extension and truncation.
|
|
|
|
*/
|
2010-06-14 12:24:51 -06:00
|
|
|
static int64
|
2009-05-28 00:55:14 -06:00
|
|
|
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:
|
2009-05-28 16:48:47 -06:00
|
|
|
fatal("convconst ctype=%d %lT", val->ctype, t);
|
2009-05-28 00:55:14 -06:00
|
|
|
case CTINT:
|
2011-12-08 20:07:43 -07:00
|
|
|
case CTRUNE:
|
2009-05-28 00:55:14 -06:00
|
|
|
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]) {
|
2010-02-17 23:08:30 -07:00
|
|
|
con->val = toflt(con->val);
|
2010-02-21 12:18:09 -07:00
|
|
|
if(con->val.ctype != CTFLT)
|
|
|
|
fatal("convconst ctype=%d %T", con->val.ctype, t);
|
2009-05-28 00:55:14 -06:00
|
|
|
if(tt == TFLOAT32)
|
|
|
|
con->val.u.fval = truncfltlit(con->val.u.fval, t);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2010-02-17 23:08:30 -07:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2009-05-28 00:55:14 -06:00
|
|
|
fatal("convconst %lT constant", t);
|
|
|
|
|
|
|
|
}
|
2010-02-18 18:55:11 -07:00
|
|
|
|
|
|
|
// 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)
|
|
|
|
}
|