diff options
author | Russ Cox <rsc@golang.org> | 2009-05-27 23:55:14 -0700 |
---|---|---|
committer | Russ Cox <rsc@golang.org> | 2009-05-27 23:55:14 -0700 |
commit | f6f70933698bcfaa2f7fbed24dcc75784d80d5bb (patch) | |
tree | 7ec702ad1c80def016cbfd23ccaebc0fdbdf134a /src | |
parent | 7d3403fdf5d248c36b407fe33fd5408105d89e2b (diff) | |
download | golang-f6f70933698bcfaa2f7fbed24dcc75784d80d5bb.tar.gz |
clean up gmove:
* conversions all in one place.
* no separate load, store phases;
direct memory addressing when possible
(this is the x86 after all!).
avoids extra registers, extra MOVQs.
* fixes int32 -> uint64 bug
(was zero-extending)
R=ken
OCL=29482
CL=29484
Diffstat (limited to 'src')
-rw-r--r-- | src/cmd/6g/cgen.c | 8 | ||||
-rw-r--r-- | src/cmd/6g/ggen.c | 4 | ||||
-rw-r--r-- | src/cmd/6g/gsubr.c | 815 | ||||
-rw-r--r-- | src/cmd/gc/const.c | 92 | ||||
-rw-r--r-- | src/cmd/gc/dcl.c | 2 | ||||
-rw-r--r-- | src/cmd/gc/go.h | 8 | ||||
-rw-r--r-- | src/cmd/gc/subr.c | 27 |
7 files changed, 459 insertions, 497 deletions
diff --git a/src/cmd/6g/cgen.c b/src/cmd/6g/cgen.c index 1027f9076..5ac8b0f9c 100644 --- a/src/cmd/6g/cgen.c +++ b/src/cmd/6g/cgen.c @@ -201,8 +201,14 @@ cgen(Node *n, Node *res) break; } regalloc(&n1, nl->type, res); + regalloc(&n2, n->type, &n1); cgen(nl, &n1); - gmove(&n1, res); + // if we do the conversion n1 -> n2 here + // reusing the register, then gmove won't + // have to allocate its own register. + gmove(&n1, &n2); + gmove(&n2, res); + regfree(&n2); regfree(&n1); break; diff --git a/src/cmd/6g/ggen.c b/src/cmd/6g/ggen.c index 6da512da1..06b0f8003 100644 --- a/src/cmd/6g/ggen.c +++ b/src/cmd/6g/ggen.c @@ -491,8 +491,10 @@ dodiv(int op, Node *nl, Node *nr, Node *res, Node *ax, Node *dx) t = types[TUINT32]; } a = optoas(op, t); + ax->type = t; + dx->type = t; - regalloc(&n3, nr->type, N); + regalloc(&n3, t, N); if(nl->ullman >= nr->ullman) { cgen(nl, ax); if(!issigned[t->etype]) { diff --git a/src/cmd/6g/gsubr.c b/src/cmd/6g/gsubr.c index 0d9034f2c..d8bd0767f 100644 --- a/src/cmd/6g/gsubr.c +++ b/src/cmd/6g/gsubr.c @@ -411,575 +411,397 @@ gconreg(int as, vlong c, int reg) #define CASE(a,b) (((a)<<16)|((b)<<0)) /* - * generate move: - * t = f + * Is this node a memory operand? */ -void -gmove(Node *f, Node *t) +int +ismem(Node *n) { - int ft, tt, t64, a; - Node nod, nod1, nod2, nod3, nodc; - Prog *p1, *p2; - - ft = simtype[f->type->etype]; - tt = simtype[t->type->etype]; - - t64 = 0; - if(tt == TINT64 || tt == TUINT64 || tt == TPTR64) - t64 = 1; - - if(debug['M']) - print("gop: %O %O[%E],%O[%E]\n", OAS, - f->op, ft, t->op, tt); - if(isfloat[ft] && f->op == OCONST) { - /* TO DO: pick up special constants, possibly preloaded */ - if(mpgetflt(f->val.u.fval) == 0.0) { - regalloc(&nod, t->type, t); - gins(AXORPD, &nod, &nod); - gmove(&nod, t); - regfree(&nod); - return; - } + switch(n->op) { + case OINDREG: + case ONAME: + case OPARAM: + return 1; } + return 0; +} + /* - * load + * set up nodes representing 2^63 */ - if(f->op == ONAME || f->op == OINDREG || - f->op == OIND || f->op == OINDEX) - switch(ft) { - case TINT8: - a = AMOVBLSX; - if(t64) - a = AMOVBQSX; - goto ld; - case TBOOL: - case TUINT8: - a = AMOVBLZX; - if(t64) - a = AMOVBQZX; - goto ld; - case TINT16: - a = AMOVWLSX; - if(t64) - a = AMOVWQSX; - goto ld; - case TUINT16: - a = AMOVWLZX; - if(t64) - a = AMOVWQZX; - goto ld; - case TINT32: - if(isfloat[tt]) { - regalloc(&nod, t->type, t); - if(tt == TFLOAT64) - a = ACVTSL2SD; - else - a = ACVTSL2SS; - gins(a, f, &nod); - gmove(&nod, t); - regfree(&nod); - return; - } - a = AMOVL; - if(t64) - a = AMOVLQSX; - goto ld; - case TUINT32: - case TPTR32: - a = AMOVL; - if(t64) - a = AMOVLQZX; - goto ld; - case TINT64: - if(isfloat[tt]) { - regalloc(&nod, t->type, t); - if(tt == TFLOAT64) - a = ACVTSQ2SD; - else - a = ACVTSQ2SS; - gins(a, f, &nod); - gmove(&nod, t); - regfree(&nod); - return; - } - case TUINT64: - case TPTR64: - a = AMOVQ; +Node bigi; +Node bigf; - ld: - regalloc(&nod, f->type, t); - nod.type = t64? types[TINT64]: types[TINT32]; - gins(a, f, &nod); - gmove(&nod, t); - regfree(&nod); - return; +void +bignodes(void) +{ + static int did; - case TFLOAT32: - a = AMOVSS; - goto fld; - case TFLOAT64: - a = AMOVSD; - fld: - regalloc(&nod, f->type, t); - if(tt != TFLOAT64 && tt != TFLOAT32){ /* TO DO: why is this here */ - dump("odd tree", f); - nod.type = t64? types[TINT64]: types[TINT32]; - } - gins(a, f, &nod); - gmove(&nod, t); - regfree(&nod); + if(did) return; - } + did = 1; -/* - * store - */ - if(t->op == ONAME || t->op == OINDREG || - t->op == OIND || t->op == OINDEX) - switch(tt) { - case TBOOL: - case TINT8: - case TUINT8: - a = AMOVB; - goto st; - case TINT16: - case TUINT16: - a = AMOVW; - goto st; - case TINT32: - case TUINT32: - a = AMOVL; - goto st; - case TINT64: - case TUINT64: - a = AMOVQ; - goto st; + nodconst(&bigi, types[TUINT64], 1); + mpshiftfix(bigi.val.u.xval, 63); - case TPTR32: - case TPTR64: - /* - * store to pointer. - */ - if(tt == TPTR32) - a = AMOVL; - else - a = AMOVQ; - switch(t->op) { - default: - dump("gmove to", t); - fatal("gmove t %O", t->op); + bigf = bigi; + bigf.type = types[TFLOAT64]; + bigf.val.ctype = CTFLT; + bigf.val.u.fval = mal(sizeof *bigf.val.u.fval); + mpmovefixflt(bigf.val.u.fval, bigi.val.u.xval); +} - case OINDREG: - if(t->val.u.reg != D_SP) - goto refcount; - break; +/* + * generate move: + * t = f + * hard part is conversions. + */ +void +gmove(Node *f, Node *t) +{ + int a, ft, tt; + Type *cvt; + Node r1, r2, r3, r4, zero, one, con; + Prog *p1, *p2; - case ONAME: - switch(t->class) { - default: - dump("gmove", t); - fatal("gmove t %O class %d reg %R", t->op, t->class, t->val.u.reg); - case PEXTERN: - goto refcount; - break; - case PAUTO: - case PPARAM: - case PPARAMOUT: - break; + if(debug['M']) + print("gmove %N -> %N\n", f, t); + + ft = simsimtype(f->type); + tt = simsimtype(t->type); + cvt = t->type; + + // cannot have two memory operands + if(ismem(f) && ismem(t)) + goto hard; + + // convert constant to desired type + if(f->op == OLITERAL) { + convconst(&con, t->type, &f->val); + f = &con; + ft = tt; // so big switch will choose a simple mov + + // some constants can't move directly to memory. + if(ismem(t)) { + // float constants come from memory. + if(isfloat[tt]) + goto hard; + // 64-bit immediates are really 32-bit sign-extended + // unless moving into a register. + if(isint[tt]) { + if(mpcmpfixfix(con.val.u.xval, minintval[TINT32]) < 0) + goto hard; + if(mpcmpfixfix(con.val.u.xval, maxintval[TINT32]) > 0) + goto hard; } - break; - } - goto st; - - st: - // 64-bit immediates only allowed for move into registers. - // this is not a move into a register. - if(f->op == OCONST || (f->op == OLITERAL && !t64)) { - gins(a, f, t); - return; } - fst: - regalloc(&nod, t->type, f); - gmove(f, &nod); - gins(a, &nod, t); - regfree(&nod); - return; - - refcount: - if(!debug['r']) - goto st; - // for now, mark ref count updates with AXCHGQ. - // using a temporary on the left, so no semantic - // changes. code is likely slower, but still correct. - if(t64) - a = AXCHGQ; - else - a = AXCHGL; - regalloc(&nod, t->type, f); - gmove(f, &nod); - gins(a, &nod, t); - regfree(&nod); - return; - - case TFLOAT32: - a = AMOVSS; - goto fst; - case TFLOAT64: - a = AMOVSD; - goto fst; } -/* - * convert - */ + // value -> value copy, only one memory operand. + // figure out the instruction to use. + // break out of switch for one-instruction gins. + // goto rdst for "destination must be register". + // goto hard for "convert to cvt type first". + // otherwise handle and return. + switch(CASE(ft, tt)) { default: -/* - * integer to integer - ******** - * a = AGOK; break; - - * case CASE(TBOOL, TBOOL): - * case CASE(TINT8, TBOOL): - * case CASE(TUINT8, TBOOL): - * case CASE(TINT16, TBOOL): - * case CASE(TUINT16, TBOOL): - * case CASE(TINT32, TBOOL): - * case CASE(TUINT32, TBOOL): - * case CASE(TPTR64, TBOOL): - - * case CASE(TBOOL, TINT8): - * case CASE(TINT8, TINT8): - * case CASE(TUINT8, TINT8): - * case CASE(TINT16, TINT8): - * case CASE(TUINT16, TINT8): - * case CASE(TINT32, TINT8): - * case CASE(TUINT32, TINT8): - * case CASE(TPTR64, TINT8): - - * case CASE(TBOOL, TUINT8): - * case CASE(TINT8, TUINT8): - * case CASE(TUINT8, TUINT8): - * case CASE(TINT16, TUINT8): - * case CASE(TUINT16, TUINT8): - * case CASE(TINT32, TUINT8): - * case CASE(TUINT32, TUINT8): - * case CASE(TPTR64, TUINT8): - - * case CASE(TINT16, TINT16): - * case CASE(TUINT16, TINT16): - * case CASE(TINT32, TINT16): - * case CASE(TUINT32, TINT16): - * case CASE(TPTR64, TINT16): - - * case CASE(TINT16, TUINT16): - * case CASE(TUINT16, TUINT16): - * case CASE(TINT32, TUINT16): - * case CASE(TUINT32, TUINT16): - * case CASE(TPTR64, TUINT16): - - * case CASE(TINT64, TUINT): - * case CASE(TINT64, TUINT32): - * case CASE(TUINT64, TUINT32): - *****/ - a = AMOVL; - break; - + fatal("gmove %T -> %T", f, t); + + /* + * integer copy and truncate + */ + case CASE(TINT8, TINT8): // same size + case CASE(TINT8, TUINT8): + case CASE(TUINT8, TINT8): + case CASE(TUINT8, TUINT8): + case CASE(TINT16, TINT8): // truncate + case CASE(TUINT16, TINT8): + case CASE(TINT32, TINT8): + case CASE(TUINT32, TINT8): case CASE(TINT64, TINT8): - case CASE(TINT64, TINT16): - case CASE(TINT64, TINT32): case CASE(TUINT64, TINT8): - case CASE(TUINT64, TINT16): - case CASE(TUINT64, TINT32): - a = AMOVLQSX; // this looks bad + case CASE(TINT16, TUINT8): + case CASE(TUINT16, TUINT8): + case CASE(TINT32, TUINT8): + case CASE(TUINT32, TUINT8): + case CASE(TINT64, TUINT8): + case CASE(TUINT64, TUINT8): + a = AMOVB; break; - case CASE(TINT32, TINT64): - case CASE(TINT32, TPTR64): - a = AMOVLQSX; + case CASE(TINT16, TINT16): // same size + case CASE(TINT16, TUINT16): + case CASE(TUINT16, TINT16): + case CASE(TUINT16, TUINT16): + case CASE(TINT32, TINT16): // truncate + case CASE(TUINT32, TINT16): + case CASE(TINT64, TINT16): + case CASE(TUINT64, TINT16): + case CASE(TINT32, TUINT16): + case CASE(TUINT32, TUINT16): + case CASE(TINT64, TUINT16): + case CASE(TUINT64, TUINT16): + a = AMOVW; break; - case CASE(TUINT32, TINT64): - case CASE(TUINT32, TUINT64): - case CASE(TUINT32, TPTR64): - case CASE(TPTR32, TINT64): - case CASE(TPTR32, TUINT64): - case CASE(TPTR32, TPTR64): - a = AMOVLQZX; + case CASE(TINT32, TINT32): // same size + case CASE(TINT32, TUINT32): + case CASE(TUINT32, TINT32): + case CASE(TUINT32, TUINT32): + case CASE(TINT64, TINT32): // truncate + case CASE(TUINT64, TINT32): + case CASE(TINT64, TUINT32): + case CASE(TUINT64, TUINT32): + a = AMOVL; break; - case CASE(TPTR64, TINT64): - case CASE(TINT64, TINT64): - case CASE(TUINT64, TINT64): + case CASE(TINT64, TINT64): // same size case CASE(TINT64, TUINT64): + case CASE(TUINT64, TINT64): case CASE(TUINT64, TUINT64): - case CASE(TPTR64, TUINT64): - case CASE(TINT64, TPTR64): - case CASE(TUINT64, TPTR64): - case CASE(TPTR64, TPTR64): a = AMOVQ; break; - case CASE(TINT16, TINT32): - case CASE(TINT16, TUINT32): - a = AMOVWLSX; -// if(f->op == OCONST) { -// f->val.vval &= 0xffff; -// if(f->val.vval & 0x8000) -// f->val.vval |= 0xffff0000; -// a = AMOVL; -// } - break; - - case CASE(TINT16, TINT64): - case CASE(TINT16, TUINT64): - case CASE(TINT16, TPTR64): - a = AMOVWQSX; -// if(f->op == OCONST) { -// f->val.vval &= 0xffff; -// if(f->val.vval & 0x8000){ -// f->val.vval |= 0xffff0000; -// f->val.vval |= (vlong)~0 << 32; -// } -// a = AMOVL; -// } - break; - - case CASE(TUINT16, TINT32): - case CASE(TUINT16, TUINT32): - a = AMOVWLZX; -// if(f->op == OCONST) { -// f->val.vval &= 0xffff; -// a = AMOVL; -// } - break; - - case CASE(TUINT16, TINT64): - case CASE(TUINT16, TUINT64): - case CASE(TUINT16, TPTR64): - a = AMOVWQZX; -// if(f->op == OCONST) { -// f->val.vval &= 0xffff; -// a = AMOVL; /* MOVL also zero-extends to 64 bits */ -// } - break; - - case CASE(TINT8, TINT16): + /* + * integer up-conversions + */ + case CASE(TINT8, TINT16): // sign extend int8 case CASE(TINT8, TUINT16): + a = AMOVBWSX; + goto rdst; case CASE(TINT8, TINT32): case CASE(TINT8, TUINT32): a = AMOVBLSX; -// if(f->op == OCONST) { -// f->val.vval &= 0xff; -// if(f->val.vval & 0x80) -// f->val.vval |= 0xffffff00; -// a = AMOVL; -// } - break; - + goto rdst; case CASE(TINT8, TINT64): case CASE(TINT8, TUINT64): - case CASE(TINT8, TPTR64): a = AMOVBQSX; -// if(f->op == OCONST) { -// f->val.vval &= 0xff; -// if(f->val.vval & 0x80){ -// f->val.vval |= 0xffffff00; -// f->val.vval |= (vlong)~0 << 32; -// } -// a = AMOVQ; -// } - break; + goto rdst; - case CASE(TBOOL, TINT16): - case CASE(TBOOL, TUINT16): - case CASE(TBOOL, TINT32): - case CASE(TBOOL, TUINT32): - case CASE(TUINT8, TINT16): + case CASE(TUINT8, TINT16): // zero extend uint8 case CASE(TUINT8, TUINT16): + a = AMOVBWZX; + goto rdst; case CASE(TUINT8, TINT32): case CASE(TUINT8, TUINT32): a = AMOVBLZX; -// if(f->op == OCONST) { -// f->val.vval &= 0xff; -// a = AMOVL; -// } - break; - - case CASE(TBOOL, TINT64): - case CASE(TBOOL, TUINT64): - case CASE(TBOOL, TPTR64): + goto rdst; case CASE(TUINT8, TINT64): case CASE(TUINT8, TUINT64): - case CASE(TUINT8, TPTR64): a = AMOVBQZX; -// if(f->op == OCONST) { -// f->val.vval &= 0xff; -// a = AMOVL; /* zero-extends to 64-bits */ -// } - break; + goto rdst; -/* - * float to fix - */ - case CASE(TFLOAT32, TINT8): - case CASE(TFLOAT32, TINT16): + case CASE(TINT16, TINT32): // sign extend int16 + case CASE(TINT16, TUINT32): + a = AMOVWLSX; + goto rdst; + case CASE(TINT16, TINT64): + case CASE(TINT16, TUINT64): + a = AMOVWQSX; + goto rdst; + + case CASE(TUINT16, TINT32): // zero extend uint16 + case CASE(TUINT16, TUINT32): + a = AMOVWLZX; + goto rdst; + case CASE(TUINT16, TINT64): + case CASE(TUINT16, TUINT64): + a = AMOVWQZX; + goto rdst; + + case CASE(TINT32, TINT64): // sign extend int32 + case CASE(TINT32, TUINT64): + a = AMOVLQSX; + goto rdst; + + case CASE(TUINT32, TINT64): // zero extend uint32 + case CASE(TUINT32, TUINT64): + // AMOVL into a register zeros the top of the register, + // so this is not always necessary, but if we rely on AMOVL + // the optimizer is almost certain to screw with us. + a = AMOVLQZX; + goto rdst; + + /* + * float to integer + */ case CASE(TFLOAT32, TINT32): - regalloc(&nod, t->type, N); - gins(ACVTTSS2SL, f, &nod); - gmove(&nod, t); - regfree(&nod); - return; + a = ACVTTSS2SL; + goto rdst; + + case CASE(TFLOAT64, TINT32): + a = ACVTTSD2SL; + goto rdst; - case CASE(TFLOAT32, TBOOL): - case CASE(TFLOAT32, TUINT8): - case CASE(TFLOAT32, TUINT16): - case CASE(TFLOAT32, TUINT32): case CASE(TFLOAT32, TINT64): - case CASE(TFLOAT32, TUINT64): - case CASE(TFLOAT32, TPTR64): - regalloc(&nod, t->type, N); - gins(ACVTTSS2SQ, f, &nod); - gmove(&nod, t); - regfree(&nod); - return; + a = ACVTTSS2SQ; + goto rdst; - case CASE(TFLOAT64, TINT8): - case CASE(TFLOAT64, TINT16): - case CASE(TFLOAT64, TINT32): - regalloc(&nod, t->type, N); - gins(ACVTTSD2SL, f, &nod); - gmove(&nod, t); - regfree(&nod); - return; + case CASE(TFLOAT64, TINT64): + a = ACVTTSD2SQ; + goto rdst; - case CASE(TFLOAT64, TBOOL): - case CASE(TFLOAT64, TUINT8): + case CASE(TFLOAT32, TINT16): + case CASE(TFLOAT32, TINT8): + case CASE(TFLOAT32, TUINT16): + case CASE(TFLOAT32, TUINT8): + case CASE(TFLOAT64, TINT16): + case CASE(TFLOAT64, TINT8): case CASE(TFLOAT64, TUINT16): + case CASE(TFLOAT64, TUINT8): + // convert via int32. + cvt = types[TINT32]; + goto hard; + + case CASE(TFLOAT32, TUINT32): case CASE(TFLOAT64, TUINT32): - case CASE(TFLOAT64, TINT64): - case CASE(TFLOAT64, TUINT64): - case CASE(TFLOAT64, TPTR64): - regalloc(&nod, t->type, N); - gins(ACVTTSD2SQ, f, &nod); - gmove(&nod, t); - regfree(&nod); - return; + // convert via int64. + cvt = types[TINT64]; + goto hard; -/* - * uvlong to float - */ - case CASE(TUINT64, TFLOAT64): - case CASE(TUINT64, TFLOAT32): - a = ACVTSQ2SS; - if(tt == TFLOAT64) - a = ACVTSQ2SD; - regalloc(&nod, f->type, f); - gmove(f, &nod); - regalloc(&nod1, t->type, t); - nodconst(&nodc, types[TUINT64], 0); - gins(ACMPQ, &nod, &nodc); - p1 = gbranch(AJLT, T); - gins(a, &nod, &nod1); + case CASE(TFLOAT32, TUINT64): + case CASE(TFLOAT64, TUINT64): + // algorithm is: + // if small enough, use native float64 -> int64 conversion. + // otherwise, subtract 2^63, convert, and add it back. + a = ACVTSS2SQ; + if(ft == TFLOAT64) + a = ACVTSD2SQ; + bignodes(); + regalloc(&r1, types[ft], N); + regalloc(&r2, types[tt], t); + regalloc(&r3, types[ft], N); + regalloc(&r4, types[tt], N); + gins(optoas(OAS, f->type), f, &r1); + gins(optoas(OCMP, f->type), &bigf, &r1); + p1 = gbranch(optoas(OLE, f->type), T); + gins(a, &r1, &r2); p2 = gbranch(AJMP, T); patch(p1, pc); - regalloc(&nod2, f->type, N); - regalloc(&nod3, f->type, N); - gmove(&nod, &nod2); - nodconst(&nodc, types[TUINT64], 1); - gins(ASHRQ, &nodc, &nod2); - gmove(&nod, &nod3); - gins(AANDL, &nodc, &nod3); - gins(AORQ, &nod3, &nod2); - gins(a, &nod2, &nod1); - gins(tt == TFLOAT64? AADDSD: AADDSS, &nod1, &nod1); - regfree(&nod2); - regfree(&nod3); + gins(optoas(OAS, f->type), &bigf, &r3); + gins(optoas(OSUB, f->type), &r3, &r1); + gins(a, &r1, &r2); + gins(AMOVQ, &bigi, &r4); + gins(AXORQ, &r4, &r2); patch(p2, pc); - regfree(&nod); - regfree(&nod1); + gmove(&r2, t); + regfree(&r4); + regfree(&r3); + regfree(&r2); + regfree(&r1); return; - case CASE(TUINT32, TFLOAT64): - case CASE(TUINT32, TFLOAT32): - a = ACVTSQ2SS; - if(tt == TFLOAT64) - a = ACVTSQ2SD; - regalloc(&nod, f->type, f); - gins(AMOVLQZX, f, &nod); - regalloc(&nod1, t->type, t); - gins(a, &nod, &nod1); - gmove(&nod1, t); - regfree(&nod); - regfree(&nod1); - return; + /* + * integer to float + */ + case CASE(TINT32, TFLOAT32): + a = ACVTSL2SS; + goto rdst; + + + case CASE(TINT32, TFLOAT64): + a = ACVTSL2SD; + goto rdst; -/* - * fix to float - */ case CASE(TINT64, TFLOAT32): - case CASE(TPTR64, TFLOAT32): - regalloc(&nod, t->type, t); - gins(ACVTSQ2SS, f, &nod); - gmove(&nod, t); - regfree(&nod); - return; + a = ACVTSQ2SS; + goto rdst; case CASE(TINT64, TFLOAT64): - case CASE(TPTR64, TFLOAT64): - regalloc(&nod, t->type, t); - gins(ACVTSQ2SD, f, &nod); - gmove(&nod, t); - regfree(&nod); - return; + a = ACVTSQ2SD; + goto rdst; - case CASE(TBOOL, TFLOAT32): - case CASE(TINT8, TFLOAT32): - case CASE(TUINT8, TFLOAT32): case CASE(TINT16, TFLOAT32): - case CASE(TUINT16, TFLOAT32): - case CASE(TINT32, TFLOAT32): - regalloc(&nod, t->type, t); - gins(ACVTSL2SS, f, &nod); - gmove(&nod, t); - regfree(&nod); - return; - - case CASE(TBOOL, TFLOAT64): - case CASE(TINT8, TFLOAT64): - case CASE(TUINT8, TFLOAT64): case CASE(TINT16, TFLOAT64): + case CASE(TINT8, TFLOAT32): + case CASE(TINT8, TFLOAT64): + case CASE(TUINT16, TFLOAT32): case CASE(TUINT16, TFLOAT64): - case CASE(TINT32, TFLOAT64): - regalloc(&nod, t->type, t); - gins(ACVTSL2SD, f, &nod); - gmove(&nod, t); - regfree(&nod); + case CASE(TUINT8, TFLOAT32): + case CASE(TUINT8, TFLOAT64): + // convert via int32 + cvt = types[TINT32]; + goto hard; + + case CASE(TUINT32, TFLOAT32): + case CASE(TUINT32, TFLOAT64): + // convert via int64. + cvt = types[TINT64]; + goto hard; + + case CASE(TUINT64, TFLOAT32): + case CASE(TUINT64, TFLOAT64): + // algorithm is: + // if small enough, use native int64 -> uint64 conversion. + // otherwise, halve (rounding to odd?), convert, and double. + a = ACVTSQ2SS; + if(tt == TFLOAT64) + a = ACVTSQ2SD; + nodconst(&zero, types[TUINT64], 0); + nodconst(&one, types[TUINT64], 1); + regalloc(&r1, f->type, f); + regalloc(&r2, t->type, t); + regalloc(&r3, f->type, N); + regalloc(&r4, f->type, N); + gmove(f, &r1); + gins(ACMPQ, &r1, &zero); + p1 = gbranch(AJLT, T); + gins(a, &r1, &r2); + p2 = gbranch(AJMP, T); + patch(p1, pc); + gmove(&r1, &r3); + gins(ASHRQ, &one, &r3); + gmove(&r1, &r4); + gins(AANDL, &one, &r4); + gins(AORQ, &r4, &r3); + gins(a, &r3, &r2); + gins(optoas(OADD, t->type), &r2, &r2); + patch(p2, pc); + gmove(&r2, t); + regfree(&r4); + regfree(&r3); + regfree(&r2); + regfree(&r1); return; -/* - * float to float - */ + /* + * float to float + */ case CASE(TFLOAT32, TFLOAT32): a = AMOVSS; break; - case CASE(TFLOAT64, TFLOAT32): - a = ACVTSD2SS; - break; - case CASE(TFLOAT32, TFLOAT64): - a = ACVTSS2SD; - break; + case CASE(TFLOAT64, TFLOAT64): a = AMOVSD; break; + + case CASE(TFLOAT32, TFLOAT64): + a = ACVTSS2SD; + goto rdst; + + case CASE(TFLOAT64, TFLOAT32): + a = ACVTSD2SS; + goto rdst; } - if(a == AMOVQ || - a == AMOVSD || - a == AMOVSS || - (a == AMOVL && f->type->width == t->type->width)) /* TO DO: check AMOVL */ - if(samaddr(f, t)) - return; + gins(a, f, t); + return; + +rdst: + // requires register destination + regalloc(&r1, t->type, t); + gins(a, f, &r1); + gmove(&r1, t); + regfree(&r1); + return; + +hard: + // requires register intermediate + regalloc(&r1, cvt, t); + gmove(f, &r1); + gmove(&r1, t); + regfree(&r1); + return; } int @@ -1026,6 +848,17 @@ gins(int as, Node *f, Node *t) // regfree(&nod); // } + switch(as) { + case AMOVB: + case AMOVW: + case AMOVL: + case AMOVQ: + case AMOVSS: + case AMOVSD: + if(f != N && t != N && samaddr(f, t)) + return nil; + } + p = prog(as); if(f != N) naddr(f, &p->from); diff --git a/src/cmd/gc/const.c b/src/cmd/gc/const.c index 33acec6fc..72cf684ad 100644 --- a/src/cmd/gc/const.c +++ b/src/cmd/gc/const.c @@ -801,3 +801,95 @@ nonnegconst(Node *n) } return -1; } + +/* + * convert x to type et and back to int64 + * for sign extension and truncation. + */ +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->type); + case CTINT: + 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]) { + if(con->val.ctype == CTINT) { + con->val.ctype = CTFLT; + con->val.u.fval = mal(sizeof *con->val.u.fval); + mpmovefixflt(con->val.u.fval, val->u.xval); + } + if(con->val.ctype != CTFLT) + fatal("convconst ctype=%d %T", con->val.ctype, t); + if(!isfloat[tt]) { + // easy to handle, but can it happen? + fatal("convconst CTINT %T", t); + } + if(tt == TFLOAT32) + con->val.u.fval = truncfltlit(con->val.u.fval, t); + return; + } + + fatal("convconst %lT constant", t); + +} diff --git a/src/cmd/gc/dcl.c b/src/cmd/gc/dcl.c index e4d1a0455..6068651b8 100644 --- a/src/cmd/gc/dcl.c +++ b/src/cmd/gc/dcl.c @@ -1061,7 +1061,7 @@ addconst(Node *n, Node *e, int ctxt) d = dcl(); d->dsym = s; d->dnode = e; - d->op = OCONST; + d->op = OLITERAL; d->back = r->back; r->back->forw = d; r->back = d; diff --git a/src/cmd/gc/go.h b/src/cmd/gc/go.h index eb253d778..5abdfcce0 100644 --- a/src/cmd/gc/go.h +++ b/src/cmd/gc/go.h @@ -298,7 +298,7 @@ enum { OXXX, - OTYPE, OCONST, OVAR, OIMPORT, + OTYPE, OVAR, OIMPORT, ONAME, ONONAME, ODCL, ODOT, ODOTPTR, ODOTMETH, ODOTINTER, @@ -315,7 +315,7 @@ enum OEQ, ONE, OLT, OLE, OGE, OGT, OADD, OSUB, OOR, OXOR, OMUL, ODIV, OMOD, OLSH, ORSH, OAND, OANDNOT, - OINC, ODEC, // placeholders - not used + OINC, ODEC, OFUNC, OLABEL, OBREAK, @@ -795,6 +795,8 @@ Node* adddot(Node*); void expandmeth(Sym*, Type*); void genwrapper(Type*, Type*, Sym*); +int simsimtype(Type*); + /* * dcl.c */ @@ -949,6 +951,8 @@ int smallintconst(Node*); long nonnegconst(Node*); int consttype(Node*); int isconst(Node*, int); +Mpflt* truncfltlit(Mpflt*, Type*); +void convconst(Node*, Type*, Val*); /* * align.c diff --git a/src/cmd/gc/subr.c b/src/cmd/gc/subr.c index de32c8e6d..dcaa11a00 100644 --- a/src/cmd/gc/subr.c +++ b/src/cmd/gc/subr.c @@ -671,7 +671,6 @@ opnames[] = [OCOMPOS] = "COMPOS", [OCOMPSLICE] = "COMPSLICE", [OCOM] = "COM", - [OCONST] = "CONST", [OCONTINUE] = "CONTINUE", [OCONV] = "CONV", [ODCLARG] = "DCLARG", @@ -3015,3 +3014,29 @@ runifacechecks(void) } lineno = lno; } + +/* + * even simpler simtype; get rid of ptr, bool. + * assuming that the front end has rejected + * all the invalid conversions (like ptr -> bool) + */ +int +simsimtype(Type *t) +{ + int et; + + et = simtype[t->etype]; + switch(et) { + case TPTR32: + et = TUINT32; + break; + case TPTR64: + et = TUINT64; + break; + case TBOOL: + et = TUINT8; + break; + } + return et; +} + |