[dev.garbage] all: merge dev.power64 (7667e41f3ced) into dev.garbage

Now the only difference between dev.cc and dev.garbage
is the runtime conversion on the one side and the
garbage collection on the other. They both have the
same set of changes from default and dev.power64.

LGTM=austin
R=austin
CC=golang-codereviews
https://golang.org/cl/172570043
This commit is contained in:
Russ Cox 2014-11-14 12:09:42 -05:00
commit 9ef4e56108
33 changed files with 1545 additions and 313 deletions

View file

@ -54,7 +54,7 @@ struct Addr
{
char sval[8];
float64 dval;
Prog* branch; // for 5g, 6g, 8g
Prog* branch; // for 5g, 6g, 8g, 9g
} u;
LSym* sym;
@ -89,10 +89,13 @@ struct Prog
int32 lineno;
Prog* link;
short as;
uchar reg; // arm, power64 only
uchar scond; // arm only
// operands
Addr from;
Addr from3; // power64 only, fma and rlwm
uchar reg; // arm, power64 only (e.g., ADD from, reg, to);
// also used for ADATA width on arm, power64
Addr from3; // power64 only (e.g., RLWM/FMADD from, reg, from3, to)
Addr to;
// for 5g, 6g, 8g internal use

View file

@ -86,7 +86,7 @@ datagostring(Strlit *sval, Addr *a)
sym = stringsym(sval->s, sval->len);
a->type = D_OREG;
a->name = D_EXTERN;
a->etype = TINT32;
a->etype = TSTRING;
a->offset = 0; // header
a->reg = NREG;
a->sym = linksym(sym);

View file

@ -1353,9 +1353,10 @@ naddr(Node *n, Addr *a, int canemitcode)
case OITAB:
// itable of interface value
naddr(n->left, a, canemitcode);
a->etype = TINT32;
a->etype = simtype[tptr];
if(a->type == D_CONST && a->offset == 0)
break; // len(nil)
a->width = widthptr;
break;
case OSPTR:

View file

@ -63,8 +63,8 @@ enum
uint32 BLOAD(Reg*);
uint32 BSTORE(Reg*);
uint32 LOAD(Reg*);
uint32 STORE(Reg*);
uint64 LOAD(Reg*);
uint64 STORE(Reg*);
*/
// A Reg is a wrapper around a single Prog (one instruction) that holds
@ -145,7 +145,7 @@ void synch(Reg*, Bits);
uint32 allreg(uint32, Rgn*);
void paint1(Reg*, int);
uint32 paint2(Reg*, int);
void paint3(Reg*, int, int32, int);
void paint3(Reg*, int, uint32, int);
void addreg(Adr*, int);
void dumpit(char *str, Flow *r0, int);
@ -156,10 +156,10 @@ void peep(Prog*);
void excise(Flow*);
int copyu(Prog*, Adr*, Adr*);
int32 RtoB(int);
int32 FtoB(int);
int BtoR(int32);
int BtoF(int32);
uint32 RtoB(int);
uint32 FtoB(int);
int BtoR(uint32);
int BtoF(uint32);
/*
* prog.c

View file

@ -35,7 +35,7 @@
#include "opt.h"
#define NREGVAR 32
#define REGBITS ((uint32)0xffffffff)
#define REGBITS ((uint64)0xffffffffull)
/*c2go enum {
NREGVAR = 32,
REGBITS = 0xffffffff,
@ -86,7 +86,7 @@ setaddrs(Bits bit)
i = bnum(bit);
node = var[i].node;
n = var[i].name;
bit.b[i/32] &= ~(1L<<(i%32));
biclr(&bit, i);
// disable all pieces of that variable
for(i=0; i<nvar; i++) {
@ -393,7 +393,7 @@ loop2:
for(z=0; z<BITS; z++)
bit.b[z] = (r->refahead.b[z] | r->calahead.b[z]) &
~(externs.b[z] | params.b[z] | addrs.b[z] | consts.b[z]);
if(bany(&bit) & !r->f.refset) {
if(bany(&bit) && !r->f.refset) {
// should never happen - all variables are preset
if(debug['w'])
print("%L: used and not set: %Q\n", r->f.prog->lineno, bit);
@ -425,7 +425,7 @@ loop2:
if(debug['R'] > 1)
print("\n");
paint1(r, i);
bit.b[i/32] &= ~(1L<<(i%32));
biclr(&bit, i);
if(change <= 0) {
if(debug['R'])
print("%L $%d: %Q\n",
@ -570,7 +570,7 @@ walkvardef(Node *n, Reg *r, int active)
break;
for(v=n->opt; v!=nil; v=v->nextinnode) {
bn = v - var;
r1->act.b[bn/32] |= 1L << (bn%32);
biset(&r1->act, bn);
}
if(r1->f.prog->as == ABL)
break;
@ -606,7 +606,7 @@ addsplits(void)
~(r->calahead.b[z] & addrs.b[z]);
while(bany(&bit)) {
i = bnum(bit);
bit.b[i/32] &= ~(1L << (i%32));
biclr(&bit, i);
}
}
}
@ -972,10 +972,10 @@ prop(Reg *r, Bits ref, Bits cal)
for(z=0; z<BITS; z++) {
if(cal.b[z] == 0)
continue;
for(i=0; i<32; i++) {
if(z*32+i >= nvar || ((cal.b[z]>>i)&1) == 0)
for(i=0; i<64; i++) {
if(z*64+i >= nvar || ((cal.b[z]>>i)&1) == 0)
continue;
v = var+z*32+i;
v = var+z*64+i;
if(v->node->opt == nil) // v represents fixed register, not Go variable
continue;
@ -991,10 +991,10 @@ prop(Reg *r, Bits ref, Bits cal)
// This will set the bits at most twice, keeping the overall loop linear.
v1 = v->node->opt;
j = v1 - var;
if(v == v1 || ((cal.b[j/32]>>(j&31))&1) == 0) {
if(v == v1 || !btest(&cal, j)) {
for(; v1 != nil; v1 = v1->nextinnode) {
j = v1 - var;
cal.b[j/32] |= 1<<(j&31);
biset(&cal, j);
}
}
}
@ -1115,10 +1115,10 @@ paint1(Reg *r, int bn)
Reg *r1;
Prog *p;
int z;
uint32 bb;
uint64 bb;
z = bn/32;
bb = 1L<<(bn%32);
z = bn/64;
bb = 1LL<<(bn%64);
if(r->act.b[z] & bb)
return;
for(;;) {
@ -1193,10 +1193,10 @@ paint2(Reg *r, int bn)
{
Reg *r1;
int z;
uint32 bb, vreg;
uint64 bb, vreg;
z = bn/32;
bb = 1L << (bn%32);
z = bn/64;
bb = 1LL << (bn%64);
vreg = regbits;
if(!(r->act.b[z] & bb))
return vreg;
@ -1240,15 +1240,15 @@ paint2(Reg *r, int bn)
}
void
paint3(Reg *r, int bn, int32 rb, int rn)
paint3(Reg *r, int bn, uint32 rb, int rn)
{
Reg *r1;
Prog *p;
int z;
uint32 bb;
uint64 bb;
z = bn/32;
bb = 1L << (bn%32);
z = bn/64;
bb = 1LL << (bn%64);
if(r->act.b[z] & bb)
return;
for(;;) {
@ -1333,7 +1333,7 @@ addreg(Adr *a, int rn)
* 10 R10
* 12 R12
*/
int32
uint32
RtoB(int r)
{
if(r >= REGTMP-2 && r != 12) // excluded R9 and R10 for m and g, but not R12
@ -1342,7 +1342,7 @@ RtoB(int r)
}
int
BtoR(int32 b)
BtoR(uint32 b)
{
b &= 0x11fcL; // excluded R9 and R10 for m and g, but not R12
if(b == 0)
@ -1357,7 +1357,7 @@ BtoR(int32 b)
* ... ...
* 31 F15
*/
int32
uint32
FtoB(int f)
{
@ -1367,7 +1367,7 @@ FtoB(int f)
}
int
BtoF(int32 b)
BtoF(uint32 b)
{
b &= 0xfffc0000L;

View file

@ -81,7 +81,7 @@ datagostring(Strlit *sval, Addr *a)
a->sym = linksym(sym);
a->node = sym->def;
a->offset = 0; // header
a->etype = TINT32;
a->etype = TSTRING;
}
void

View file

@ -63,8 +63,8 @@ enum
uint32 BLOAD(Reg*);
uint32 BSTORE(Reg*);
uint32 LOAD(Reg*);
uint32 STORE(Reg*);
uint64 LOAD(Reg*);
uint64 STORE(Reg*);
*/
// A Reg is a wrapper around a single Prog (one instruction) that holds
@ -141,7 +141,7 @@ void synch(Reg*, Bits);
uint32 allreg(uint32, Rgn*);
void paint1(Reg*, int);
uint32 paint2(Reg*, int);
void paint3(Reg*, int, int32, int);
void paint3(Reg*, int, uint32, int);
void addreg(Adr*, int);
void dumpone(Flow*, int);
void dumpit(char*, Flow*, int);
@ -153,10 +153,10 @@ void peep(Prog*);
void excise(Flow*);
int copyu(Prog*, Adr*, Adr*);
int32 RtoB(int);
int32 FtoB(int);
int BtoR(int32);
int BtoF(int32);
uint32 RtoB(int);
uint32 FtoB(int);
int BtoR(uint32);
int BtoF(uint32);
/*
* prog.c

View file

@ -34,7 +34,7 @@
#include "opt.h"
#define NREGVAR 32 /* 16 general + 16 floating */
#define REGBITS ((uint32)0xffffffff)
#define REGBITS ((uint64)0xffffffffull)
/*c2go enum {
NREGVAR = 32,
REGBITS = 0xffffffff,
@ -71,7 +71,7 @@ setaddrs(Bits bit)
i = bnum(bit);
node = var[i].node;
n = var[i].name;
bit.b[i/32] &= ~(1L<<(i%32));
biclr(&bit, i);
// disable all pieces of that variable
for(i=0; i<nvar; i++) {
@ -364,7 +364,7 @@ loop2:
rgp->varno = i;
change = 0;
paint1(r, i);
bit.b[i/32] &= ~(1L<<(i%32));
biclr(&bit, i);
if(change <= 0)
continue;
rgp->cost = change;
@ -477,7 +477,7 @@ walkvardef(Node *n, Reg *r, int active)
break;
for(v=n->opt; v!=nil; v=v->nextinnode) {
bn = v - var;
r1->act.b[bn/32] |= 1L << (bn%32);
biset(&r1->act, bn);
}
if(r1->f.prog->as == ACALL)
break;
@ -621,6 +621,9 @@ mkvar(Reg *r, Adr *a)
if(r != R)
r->use1.b[0] |= doregbits(a->index);
if(t >= D_INDIR && t < 2*D_INDIR)
goto none;
switch(t) {
default:
regu = doregbits(t);
@ -822,10 +825,10 @@ prop(Reg *r, Bits ref, Bits cal)
for(z=0; z<BITS; z++) {
if(cal.b[z] == 0)
continue;
for(i=0; i<32; i++) {
if(z*32+i >= nvar || ((cal.b[z]>>i)&1) == 0)
for(i=0; i<64; i++) {
if(z*64+i >= nvar || ((cal.b[z]>>i)&1) == 0)
continue;
v = var+z*32+i;
v = var+z*64+i;
if(v->node->opt == nil) // v represents fixed register, not Go variable
continue;
@ -841,10 +844,10 @@ prop(Reg *r, Bits ref, Bits cal)
// This will set the bits at most twice, keeping the overall loop linear.
v1 = v->node->opt;
j = v1 - var;
if(v == v1 || ((cal.b[j/32]>>(j&31))&1) == 0) {
if(v == v1 || !btest(&cal, j)) {
for(; v1 != nil; v1 = v1->nextinnode) {
j = v1 - var;
cal.b[j/32] |= 1UL<<(j&31);
biset(&cal, j);
}
}
}
@ -959,10 +962,10 @@ paint1(Reg *r, int bn)
{
Reg *r1;
int z;
uint32 bb;
uint64 bb;
z = bn/32;
bb = 1L<<(bn%32);
z = bn/64;
bb = 1LL<<(bn%64);
if(r->act.b[z] & bb)
return;
for(;;) {
@ -1016,55 +1019,15 @@ paint1(Reg *r, int bn)
}
}
uint32
regset(Reg *r, uint32 bb)
{
uint32 b, set;
Adr v;
int c;
set = 0;
v = zprog.from;
while(b = bb & ~(bb-1)) {
v.type = b & 0xFFFF? BtoR(b): BtoF(b);
if(v.type == 0)
fatal("zero v.type for %#ux", b);
c = copyu(r->f.prog, &v, nil);
if(c == 3)
set |= b;
bb &= ~b;
}
return set;
}
uint32
reguse(Reg *r, uint32 bb)
{
uint32 b, set;
Adr v;
int c;
set = 0;
v = zprog.from;
while(b = bb & ~(bb-1)) {
v.type = b & 0xFFFF? BtoR(b): BtoF(b);
c = copyu(r->f.prog, &v, nil);
if(c == 1 || c == 2 || c == 4)
set |= b;
bb &= ~b;
}
return set;
}
uint32
paint2(Reg *r, int bn)
{
Reg *r1;
int z;
uint32 bb, vreg, x;
uint64 bb, vreg;
z = bn/32;
bb = 1L << (bn%32);
z = bn/64;
bb = 1LL << (bn%64);
vreg = regbits;
if(!(r->act.b[z] & bb))
return vreg;
@ -1105,27 +1068,19 @@ paint2(Reg *r, int bn)
break;
}
bb = vreg;
for(; r; r=(Reg*)r->f.s1) {
x = r->regu & ~bb;
if(x) {
vreg |= reguse(r, x);
bb |= regset(r, x);
}
}
return vreg;
}
void
paint3(Reg *r, int bn, int32 rb, int rn)
paint3(Reg *r, int bn, uint32 rb, int rn)
{
Reg *r1;
Prog *p;
int z;
uint32 bb;
uint64 bb;
z = bn/32;
bb = 1L << (bn%32);
z = bn/64;
bb = 1LL << (bn%64);
if(r->act.b[z] & bb)
return;
for(;;) {
@ -1198,7 +1153,7 @@ addreg(Adr *a, int rn)
ostats.ncvtreg++;
}
int32
uint32
RtoB(int r)
{
@ -1208,7 +1163,7 @@ RtoB(int r)
}
int
BtoR(int32 b)
BtoR(uint32 b)
{
b &= 0xffffL;
if(nacl)
@ -1224,7 +1179,7 @@ BtoR(int32 b)
* ...
* 31 X15
*/
int32
uint32
FtoB(int f)
{
if(f < D_X0 || f > D_X15)
@ -1233,7 +1188,7 @@ FtoB(int f)
}
int
BtoF(int32 b)
BtoF(uint32 b)
{
b &= 0xFFFF0000L;

View file

@ -81,7 +81,7 @@ datagostring(Strlit *sval, Addr *a)
a->sym = linksym(sym);
a->node = sym->def;
a->offset = 0; // header
a->etype = TINT32;
a->etype = TSTRING;
}
void

View file

@ -63,8 +63,8 @@ enum
uint32 BLOAD(Reg*);
uint32 BSTORE(Reg*);
uint32 LOAD(Reg*);
uint32 STORE(Reg*);
uint64 LOAD(Reg*);
uint64 STORE(Reg*);
*/
// A Reg is a wrapper around a single Prog (one instruction) that holds
@ -159,7 +159,7 @@ void synch(Reg*, Bits);
uint32 allreg(uint32, Rgn*);
void paint1(Reg*, int);
uint32 paint2(Reg*, int);
void paint3(Reg*, int, int32, int);
void paint3(Reg*, int, uint32, int);
void addreg(Adr*, int);
void dumpone(Flow*, int);
void dumpit(char*, Flow*, int);
@ -171,10 +171,10 @@ void peep(Prog*);
void excise(Flow*);
int copyu(Prog*, Adr*, Adr*);
int32 RtoB(int);
int32 FtoB(int);
int BtoR(int32);
int BtoF(int32);
uint32 RtoB(int);
uint32 FtoB(int);
int BtoR(uint32);
int BtoF(uint32);
/*
* prog.c

View file

@ -34,7 +34,7 @@
#include "opt.h"
#define NREGVAR 16 /* 8 integer + 8 floating */
#define REGBITS ((uint32)0xffff)
#define REGBITS ((uint64)0xffffull)
/*c2go enum {
NREGVAR = 16,
REGBITS = (1<<NREGVAR) - 1,
@ -71,7 +71,7 @@ setaddrs(Bits bit)
i = bnum(bit);
node = var[i].node;
n = var[i].name;
bit.b[i/32] &= ~(1L<<(i%32));
biclr(&bit, i);
// disable all pieces of that variable
for(i=0; i<nvar; i++) {
@ -336,7 +336,7 @@ loop2:
rgp->varno = i;
change = 0;
paint1(r, i);
bit.b[i/32] &= ~(1L<<(i%32));
biclr(&bit, i);
if(change <= 0)
continue;
rgp->cost = change;
@ -446,7 +446,7 @@ walkvardef(Node *n, Reg *r, int active)
break;
for(v=n->opt; v!=nil; v=v->nextinnode) {
bn = v - var;
r1->act.b[bn/32] |= 1L << (bn%32);
biset(&r1->act, bn);
}
if(r1->f.prog->as == ACALL)
break;
@ -788,10 +788,10 @@ prop(Reg *r, Bits ref, Bits cal)
for(z=0; z<BITS; z++) {
if(cal.b[z] == 0)
continue;
for(i=0; i<32; i++) {
if(z*32+i >= nvar || ((cal.b[z]>>i)&1) == 0)
for(i=0; i<64; i++) {
if(z*64+i >= nvar || ((cal.b[z]>>i)&1) == 0)
continue;
v = var+z*32+i;
v = var+z*64+i;
if(v->node->opt == nil) // v represents fixed register, not Go variable
continue;
@ -807,10 +807,10 @@ prop(Reg *r, Bits ref, Bits cal)
// This will set the bits at most twice, keeping the overall loop linear.
v1 = v->node->opt;
j = v1 - var;
if(v == v1 || ((cal.b[j/32]>>(j&31))&1) == 0) {
if(v == v1 || !btest(&cal, j)) {
for(; v1 != nil; v1 = v1->nextinnode) {
j = v1 - var;
cal.b[j/32] |= 1<<(j&31);
biset(&cal, j);
}
}
}
@ -926,10 +926,10 @@ paint1(Reg *r, int bn)
Reg *r1;
Prog *p;
int z;
uint32 bb;
uint64 bb;
z = bn/32;
bb = 1L<<(bn%32);
z = bn/64;
bb = 1LL<<(bn%64);
if(r->act.b[z] & bb)
return;
for(;;) {
@ -995,53 +995,15 @@ paint1(Reg *r, int bn)
}
}
uint32
regset(Reg *r, uint32 bb)
{
uint32 b, set;
Adr v;
int c;
set = 0;
v = zprog.from;
while(b = bb & ~(bb-1)) {
v.type = b & 0xFF ? BtoR(b): BtoF(b);
c = copyu(r->f.prog, &v, nil);
if(c == 3)
set |= b;
bb &= ~b;
}
return set;
}
uint32
reguse(Reg *r, uint32 bb)
{
uint32 b, set;
Adr v;
int c;
set = 0;
v = zprog.from;
while(b = bb & ~(bb-1)) {
v.type = b & 0xFF ? BtoR(b): BtoF(b);
c = copyu(r->f.prog, &v, nil);
if(c == 1 || c == 2 || c == 4)
set |= b;
bb &= ~b;
}
return set;
}
uint32
paint2(Reg *r, int bn)
{
Reg *r1;
int z;
uint32 bb, vreg, x;
uint64 bb, vreg;
z = bn/32;
bb = 1L << (bn%32);
z = bn/64;
bb = 1LL << (bn%64);
vreg = regbits;
if(!(r->act.b[z] & bb))
return vreg;
@ -1082,27 +1044,19 @@ paint2(Reg *r, int bn)
break;
}
bb = vreg;
for(; r; r=(Reg*)r->f.s1) {
x = r->regu & ~bb;
if(x) {
vreg |= reguse(r, x);
bb |= regset(r, x);
}
}
return vreg;
}
void
paint3(Reg *r, int bn, int32 rb, int rn)
paint3(Reg *r, int bn, uint32 rb, int rn)
{
Reg *r1;
Prog *p;
int z;
uint32 bb;
uint64 bb;
z = bn/32;
bb = 1L << (bn%32);
z = bn/64;
bb = 1LL << (bn%64);
if(r->act.b[z] & bb)
return;
for(;;) {
@ -1175,7 +1129,7 @@ addreg(Adr *a, int rn)
ostats.ncvtreg++;
}
int32
uint32
RtoB(int r)
{
@ -1185,7 +1139,7 @@ RtoB(int r)
}
int
BtoR(int32 b)
BtoR(uint32 b)
{
b &= 0xffL;
@ -1194,7 +1148,7 @@ BtoR(int32 b)
return bitno(b) + D_AX;
}
int32
uint32
FtoB(int f)
{
if(f < D_X0 || f > D_X7)
@ -1203,7 +1157,7 @@ FtoB(int f)
}
int
BtoF(int32 b)
BtoF(uint32 b)
{
b &= 0xFF00L;
if(b == 0)

View file

@ -900,7 +900,7 @@ ret:
void
clearfat(Node *nl)
{
uint64 w, c, q, t;
uint64 w, c, q, t, boff;
Node dst, end, r0, *f;
Prog *p, *pl;
@ -944,6 +944,8 @@ clearfat(Node *nl)
patch(gbranch(ABNE, T, 0), pl);
regfree(&end);
// The loop leaves R3 on the last zeroed dword
boff = 8;
} else if(q >= 4) {
p = gins(ASUB, N, &dst);
p->from.type = D_CONST;
@ -953,17 +955,21 @@ clearfat(Node *nl)
afunclit(&p->to, f);
// 4 and 128 = magic constants: see ../../runtime/asm_power64x.s
p->to.offset = 4*(128-q);
} else
for(t = 0; t < q; t++) {
p = gins(AMOVD, &r0, &dst);
p->to.type = D_OREG;
p->to.offset = 8*t;
// duffzero leaves R3 on the last zeroed dword
boff = 8;
} else {
for(t = 0; t < q; t++) {
p = gins(AMOVD, &r0, &dst);
p->to.type = D_OREG;
p->to.offset = 8*t;
}
boff = 8*q;
}
for(t = 0; t < c; t++) {
p = gins(AMOVB, &r0, &dst);
p->to.type = D_OREG;
p->to.offset = t;
p->to.offset = t+boff;
}
reg[REGRT1]--;
}

View file

@ -89,7 +89,7 @@ datagostring(Strlit *sval, Addr *a)
a->reg = NREG;
a->node = sym->def;
a->offset = 0; // header
a->etype = TINT32;
a->etype = TSTRING;
}
void

View file

@ -1001,10 +1001,13 @@ hard:
Prog*
gins(int as, Node *f, Node *t)
{
//int32 w;
int32 w;
Prog *p;
Addr af, at;
// TODO(austin): Add self-move test like in 6g (but be careful
// of truncation moves)
memset(&af, 0, sizeof af);
memset(&at, 0, sizeof at);
if(f != N)
@ -1021,9 +1024,6 @@ gins(int as, Node *f, Node *t)
if(debug['g'])
print("%P\n", p);
// TODO(minux): enable these.
// right now it fails on MOVD $type."".TypeAssertionError(SB) [width=1], R7 [width=8]
/*
w = 0;
switch(as) {
case AMOVB:
@ -1046,15 +1046,16 @@ gins(int as, Node *f, Node *t)
break;
case AMOVD:
case AMOVDU:
if(af.type == D_CONST)
break;
w = 8;
break;
}
if(w != 0 && ((f != N && af.width < w) || (t != N && at.width > w))) {
if(w != 0 && ((f != N && af.width < w) || (t != N && at.type != D_REG && at.width > w))) {
dump("f", f);
dump("t", t);
fatal("bad width: %P (%d, %d)\n", p, af.width, at.width);
}
*/
return p;
}
@ -1116,12 +1117,9 @@ naddr(Node *n, Addr *a, int canemitcode)
case ONAME:
a->etype = 0;
a->width = 0;
a->reg = NREG;
if(n->type != T) {
if(n->type != T)
a->etype = simtype[n->type->etype];
a->width = n->type->width;
}
a->offset = n->xoffset;
s = n->sym;
a->node = n->orig;
@ -1242,15 +1240,16 @@ naddr(Node *n, Addr *a, int canemitcode)
naddr(n->left, a, canemitcode);
a->etype = simtype[tptr];
if(a->type == D_CONST && a->offset == 0)
break; // len(nil)
break; // itab(nil)
a->width = widthptr;
break;
case OSPTR:
// pointer in a string or slice
naddr(n->left, a, canemitcode);
a->etype = simtype[tptr];
if(a->type == D_CONST && a->offset == 0)
break; // ptr(nil)
a->etype = simtype[tptr];
a->offset += Array_array;
a->width = widthptr;
break;
@ -1262,6 +1261,7 @@ naddr(Node *n, Addr *a, int canemitcode)
if(a->type == D_CONST && a->offset == 0)
break; // len(nil)
a->offset += Array_nel;
a->width = widthint;
break;
case OCAP:
@ -1271,6 +1271,7 @@ naddr(Node *n, Addr *a, int canemitcode)
if(a->type == D_CONST && a->offset == 0)
break; // cap(nil)
a->offset += Array_cap;
a->width = widthint;
break;
case OADDR:
@ -1288,6 +1289,7 @@ naddr(Node *n, Addr *a, int canemitcode)
default:
fatal("naddr: OADDR %d\n", a->type);
}
break;
}
}

View file

@ -70,24 +70,40 @@ struct Reg
{
Flow f;
Bits set; // variables written by this instruction.
Bits use1; // variables read by prog->from.
Bits use2; // variables read by prog->to.
Bits set; // regopt variables written by this instruction.
Bits use1; // regopt variables read by prog->from.
Bits use2; // regopt variables read by prog->to.
// refahead/refbehind are the regopt variables whose current
// value may be used in the following/preceding instructions
// up to a CALL (or the value is clobbered).
Bits refbehind;
Bits refahead;
// calahead/calbehind are similar, but for variables in
// instructions that are reachable after hitting at least one
// CALL.
Bits calbehind;
Bits calahead;
Bits regdiff;
Bits act;
int32 regu; // register used bitmap
uint64 regu; // register used bitmap
};
#define R ((Reg*)0)
/*c2go extern Reg *R; */
#define NRGN 600
/*c2go enum { NRGN = 600 }; */
// A Rgn represents a single regopt variable over a region of code
// where a register could potentially be dedicated to that variable.
// The code encompassed by a Rgn is defined by the flow graph,
// starting at enter, flood-filling forward while varno is refahead
// and backward while varno is refbehind, and following branches. A
// single variable may be represented by multiple disjoint Rgns and
// each Rgn may choose a different register for that variable.
// Registers are allocated to regions greedily in order of descending
// cost.
struct Rgn
{
Reg* enter;
@ -104,7 +120,7 @@ EXTERN Rgn* rgp;
EXTERN int nregion;
EXTERN int nvar;
EXTERN int32 regbits;
EXTERN int32 exregbits;
EXTERN int32 exregbits; // TODO(austin) not used; remove
EXTERN Bits externs;
EXTERN Bits params;
EXTERN Bits consts;
@ -118,10 +134,8 @@ EXTERN struct
{
int32 ncvtreg;
int32 nspill;
int32 nreload;
int32 ndelmov;
int32 nvar;
int32 naddr;
} ostats;
/*
@ -133,10 +147,10 @@ void addmove(Reg*, int, int, int);
Bits mkvar(Reg*, Adr*);
void prop(Reg*, Bits, Bits);
void synch(Reg*, Bits);
uint32 allreg(uint32, Rgn*);
uint64 allreg(uint64, Rgn*);
void paint1(Reg*, int);
uint32 paint2(Reg*, int);
void paint3(Reg*, int, int32, int);
uint64 paint2(Reg*, int, int);
void paint3(Reg*, int, uint64, int);
void addreg(Adr*, int);
void dumpone(Flow*, int);
void dumpit(char*, Flow*, int);
@ -160,8 +174,8 @@ typedef struct ProgInfo ProgInfo;
struct ProgInfo
{
uint32 flags; // the bits below
uint64 reguse; // required registers used by this instruction
uint64 regset; // required registers set by this instruction
uint64 reguse; // registers implicitly used by this instruction
uint64 regset; // registers implicitly set by this instruction
uint64 regindex; // registers used by addressing mode
};
@ -182,20 +196,21 @@ enum
SizeF = 1<<7, // float aka float32
SizeD = 1<<8, // double aka float64
// Left side: address taken, read, write.
// Left side (Prog.from): address taken, read, write.
LeftAddr = 1<<9,
LeftRead = 1<<10,
LeftWrite = 1<<11,
// Register in middle; never written.
// Register in middle (Prog.reg); only ever read.
RegRead = 1<<12,
CanRegRead = 1<<13,
// Right side: address taken, read, write.
// Right side (Prog.to): address taken, read, write.
RightAddr = 1<<14,
RightRead = 1<<15,
RightWrite = 1<<16,
// Instruction updates whichever of from/to is type D_OREG
PostInc = 1<<17,
// Instruction kinds

View file

@ -44,13 +44,15 @@ peep(Prog *p)
void
excise(Flow *r)
{
Prog *p;
Prog *p, *l;
p = r->prog;
if(debug['P'] && debug['v'])
print("%P ===delete===\n", p);
l = p->link;
*p = zprog;
p->as = ANOP;
p->link = l;
ostats.ndelmov++;
}

View file

@ -96,11 +96,8 @@ static ProgInfo progtable[ALAST] = {
[ABGT]= {Cjmp},
[ABLE]= {Cjmp},
[ARETURN]= {Break},
// In addtion, duffzero reads R0,R2 and writes R2. This fact must be
// encoded in peep.c (TODO)
[ADUFFZERO]= {Call},
// In addtion, duffcopy reads R0,R2,R3 and writes R2,R3. This fact must be
// encoded in peep.c (TODO)
[ADUFFCOPY]= {Call},
};
@ -118,14 +115,14 @@ proginfo(ProgInfo *info, Prog *p)
info->flags |= /*CanRegRead |*/ RightRead;
}
if(p->from.type == D_OREG && p->from.reg != NREG) {
info->reguse |= RtoB(p->from.reg);
if((p->from.type == D_OREG || p->from.type == D_CONST) && p->from.reg != NREG) {
info->regindex |= RtoB(p->from.reg);
if(info->flags & PostInc) {
info->regset |= RtoB(p->from.reg);
}
}
if(p->to.type == D_OREG && p->to.reg != NREG) {
info->reguse |= RtoB(p->to.reg);
if((p->to.type == D_OREG || p->to.type == D_CONST) && p->to.reg != NREG) {
info->regindex |= RtoB(p->to.reg);
if(info->flags & PostInc) {
info->regset |= RtoB(p->to.reg);
}
@ -135,4 +132,13 @@ proginfo(ProgInfo *info, Prog *p)
info->flags &= ~LeftRead;
info->flags |= LeftAddr;
}
if(p->as == ADUFFZERO) {
info->reguse |= RtoB(0) | RtoB(2);
info->regset |= RtoB(2);
}
if(p->as == ADUFFCOPY) {
info->reguse |= RtoB(0) | RtoB(2) | RtoB(3);
info->regset |= RtoB(2) | RtoB(3);
}
}

File diff suppressed because it is too large Load diff

View file

@ -131,7 +131,7 @@ enum
C_NCLASS, /* must be the last */
};
enum as
enum
{
AXXX,
AADD,
@ -501,7 +501,7 @@ enum
D_R0 = 0, // type is D_REG
D_F0 = D_R0+NREG, // type is D_FREG
/* reg names iff type is D_SPR */
/* reg names in offset field iff type is D_SPR */
D_XER = 1,
D_LR = 8,
D_CTR = 9

View file

@ -95,11 +95,11 @@ int
bnum(Bits a)
{
int i;
int32 b;
uint64 b;
for(i=0; i<BITS; i++)
if(b = a.b[i])
return 32*i + bitno(b);
return 64*i + bitno(b);
fatal("bad in bnum");
return 0;
}
@ -110,27 +110,35 @@ blsh(uint n)
Bits c;
c = zbits;
c.b[n/32] = 1L << (n%32);
c.b[n/64] = 1LL << (n%64);
return c;
}
/*
int
bset(Bits a, uint n)
btest(Bits *a, uint n)
{
if(a.b[n/32] & (1L << (n%32)))
return 1;
return 0;
return (a->b[n/64] & (1LL << (n%64))) != 0;
}
void
biset(Bits *a, uint n)
{
a->b[n/64] |= 1LL << (n%64);
}
void
biclr(Bits *a, uint n)
{
a->b[n/64] &= ~(1LL << (n%64));
}
*/
int
bitno(int32 b)
bitno(uint64 b)
{
int i;
for(i=0; i<32; i++)
if(b & (1L<<i))
for(i=0; i<64; i++)
if(b & (1LL<<i))
return i;
fatal("bad in bitno");
return 0;
@ -157,7 +165,7 @@ Qconv(Fmt *fp)
if(var[i].offset != 0)
fmtprint(fp, "%+lld", (vlong)var[i].offset);
}
bits.b[i/32] &= ~(1L << (i%32));
biclr(&bits, i);
}
return 0;
}

View file

@ -704,13 +704,13 @@ enum
Ecomplit = 1<<11, // type in composite literal
};
#define BITS 5
#define NVAR (BITS*sizeof(uint32)*8)
#define BITS 3
#define NVAR (BITS*sizeof(uint64)*8)
typedef struct Bits Bits;
struct Bits
{
uint32 b[BITS];
uint64 b[BITS];
};
EXTERN Bits zbits;
@ -1027,12 +1027,14 @@ int Qconv(Fmt *fp);
Bits band(Bits a, Bits b);
int bany(Bits *a);
int beq(Bits a, Bits b);
int bitno(int32 b);
int bitno(uint64 b);
Bits blsh(uint n);
Bits bnot(Bits a);
int bnum(Bits a);
Bits bor(Bits a, Bits b);
int bset(Bits a, uint n);
int btest(Bits *a, uint n);
void biset(Bits *a, uint n);
void biclr(Bits *a, uint n);
/*
* bv.c

View file

@ -101,6 +101,10 @@ func testDisasm(t *testing.T, flags ...string) {
}
func TestDisasm(t *testing.T) {
switch runtime.GOARCH {
case "power64", "power64le":
t.Skipf("skipping on %s, issue 9039", runtime.GOARCH)
}
testDisasm(t)
}
@ -109,5 +113,9 @@ func TestDisasmExtld(t *testing.T) {
case "plan9", "windows":
t.Skipf("skipping on %s", runtime.GOOS)
}
switch runtime.GOARCH {
case "power64", "power64le":
t.Skipf("skipping on %s, no support for external linking, issue 9038", runtime.GOARCH)
}
testDisasm(t, "-ldflags=-linkmode=external")
}

View file

@ -259,11 +259,12 @@ Dconv(Fmt *fp)
sprint(str, "%s+%.5lux(BRANCH)", a->sym->name, v);
else
sprint(str, "%.5lux(BRANCH)", v);
} else
if(a->sym != nil)
sprint(str, "%s+%lld(APC)", a->sym->name, a->offset);
else
sprint(str, "%lld(APC)", a->offset);
} else if(a->u.branch != nil)
sprint(str, "%lld", a->u.branch->pc);
else if(a->sym != nil)
sprint(str, "%s+%lld(APC)", a->sym->name, a->offset);
else
sprint(str, "%lld(APC)", a->offset);
break;
case D_FCONST:

View file

@ -5,12 +5,14 @@
// +build power64 power64le
#include "textflag.h"
#include "funcdata.h"
// makeFuncStub is the code half of the function returned by MakeFunc.
// See the comment on the declaration of makeFuncStub in makefunc.go
// for more details.
// No argsize here, gc generates argsize info at call site.
// No arg size here, runtime pulls arg map out of the func value.
TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$16
NO_LOCAL_POINTERS
MOVD R11, 8(R1)
MOVD $argframe+0(FP), R3
MOVD R3, 16(R1)
@ -20,8 +22,9 @@ TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$16
// methodValueCall is the code half of the function returned by makeMethodValue.
// See the comment on the declaration of methodValueCall in makefunc.go
// for more details.
// No argsize here, gc generates argsize info at call site.
// No arg size here; runtime pulls arg map out of the func value.
TEXT ·methodValueCall(SB),(NOSPLIT|WRAPPER),$16
NO_LOCAL_POINTERS
MOVD R11, 8(R1)
MOVD $argframe+0(FP), R3
MOVD R3, 16(R1)

View file

@ -86,7 +86,7 @@ TEXT runtime·reginit(SB),NOSPLIT,$-8-0
// void gosave(Gobuf*)
// save state in Gobuf; setjmp
TEXT runtime·gosave(SB), NOSPLIT, $-8-8
MOVD gobuf+0(FP), R3
MOVD buf+0(FP), R3
MOVD R1, gobuf_sp(R3)
MOVD LR, R31
MOVD R31, gobuf_pc(R3)
@ -99,7 +99,7 @@ TEXT runtime·gosave(SB), NOSPLIT, $-8-8
// void gogo(Gobuf*)
// restore state from Gobuf; longjmp
TEXT runtime·gogo(SB), NOSPLIT, $-8-8
MOVD gobuf+0(FP), R5
MOVD buf+0(FP), R5
MOVD gobuf_g(R5), g // make sure g is not nil
MOVD 0(g), R4
MOVD gobuf_sp(R5), R1
@ -299,7 +299,7 @@ TEXT runtime·morestack_noctxt(SB),NOSPLIT,$-8-0
// Note: can't just "BR NAME(SB)" - bad inlining results.
TEXT ·reflectcall(SB), NOSPLIT, $-8-24
MOVW argsize+16(FP), R3
MOVWZ n+16(FP), R3
DISPATCH(runtime·call16, 16)
DISPATCH(runtime·call32, 32)
DISPATCH(runtime·call64, 64)
@ -335,8 +335,8 @@ TEXT ·reflectcall(SB), NOSPLIT, $-8-24
TEXT NAME(SB), WRAPPER, $MAXSIZE-24; \
NO_LOCAL_POINTERS; \
/* copy arguments to stack */ \
MOVD argptr+8(FP), R3; \
MOVW argsize+16(FP), R4; \
MOVD arg+8(FP), R3; \
MOVWZ n+16(FP), R4; \
MOVD R1, R5; \
ADD $(8-1), R5; \
SUB $1, R3; \
@ -353,9 +353,9 @@ TEXT NAME(SB), WRAPPER, $MAXSIZE-24; \
PCDATA $PCDATA_StackMapIndex, $0; \
BL (CTR); \
/* copy return values back */ \
MOVD argptr+8(FP), R3; \
MOVW argsize+16(FP), R4; \
MOVW retoffset+20(FP), R6; \
MOVD arg+8(FP), R3; \
MOVWZ n+16(FP), R4; \
MOVWZ retoffset+20(FP), R6; \
MOVD R1, R5; \
ADD R6, R5; \
ADD R6, R3; \
@ -398,7 +398,7 @@ CALLFN(·call268435456, 268435456)
CALLFN(·call536870912, 536870912)
CALLFN(·call1073741824, 1073741824)
// bool cas(int32 *val, int32 old, int32 new)
// bool cas(uint32 *ptr, uint32 old, uint32 new)
// Atomically:
// if(*val == old){
// *val = new;
@ -406,9 +406,9 @@ CALLFN(·call1073741824, 1073741824)
// } else
// return 0;
TEXT runtime·cas(SB), NOSPLIT, $0-17
MOVD p+0(FP), R3
MOVW old+8(FP), R4
MOVW new+12(FP), R5
MOVD ptr+0(FP), R3
MOVWZ old+8(FP), R4
MOVWZ new+12(FP), R5
cas_again:
SYNC
LWAR (R3), R6
@ -425,7 +425,7 @@ cas_fail:
MOVD $0, R3
BR -5(PC)
// bool runtime·cas64(uint64 *val, uint64 old, uint64 new)
// bool runtime·cas64(uint64 *ptr, uint64 old, uint64 new)
// Atomically:
// if(*val == *old){
// *val = new;
@ -434,7 +434,7 @@ cas_fail:
// return 0;
// }
TEXT runtime·cas64(SB), NOSPLIT, $0-25
MOVD p+0(FP), R3
MOVD ptr+0(FP), R3
MOVD old+8(FP), R4
MOVD new+16(FP), R5
cas64_again:
@ -475,12 +475,12 @@ TEXT runtime·atomicstoreuintptr(SB), NOSPLIT, $0-16
TEXT runtime·casp1(SB), NOSPLIT, $0-25
BR runtime·cas64(SB)
// uint32 xadd(uint32 volatile *val, int32 delta)
// uint32 xadd(uint32 volatile *ptr, int32 delta)
// Atomically:
// *val += delta;
// return *val;
TEXT runtime·xadd(SB), NOSPLIT, $0-20
MOVD p+0(FP), R4
MOVD ptr+0(FP), R4
MOVW delta+8(FP), R5
SYNC
LWAR (R4), R3
@ -493,7 +493,7 @@ TEXT runtime·xadd(SB), NOSPLIT, $0-20
RETURN
TEXT runtime·xadd64(SB), NOSPLIT, $0-24
MOVD p+0(FP), R4
MOVD ptr+0(FP), R4
MOVD delta+8(FP), R5
SYNC
LDAR (R4), R3
@ -506,7 +506,7 @@ TEXT runtime·xadd64(SB), NOSPLIT, $0-24
RETURN
TEXT runtime·xchg(SB), NOSPLIT, $0-20
MOVD p+0(FP), R4
MOVD ptr+0(FP), R4
MOVW new+8(FP), R5
SYNC
LWAR (R4), R3
@ -518,7 +518,7 @@ TEXT runtime·xchg(SB), NOSPLIT, $0-20
RETURN
TEXT runtime·xchg64(SB), NOSPLIT, $0-24
MOVD p+0(FP), R4
MOVD ptr+0(FP), R4
MOVD new+8(FP), R5
SYNC
LDAR (R4), R3
@ -651,7 +651,7 @@ TEXT runtime·setcallerpc(SB),NOSPLIT,$-8-16
RETURN
TEXT runtime·getcallersp(SB),NOSPLIT,$0-16
MOVD sp+0(FP), R3
MOVD argp+0(FP), R3
SUB $8, R3
MOVD R3, ret+8(FP)
RETURN
@ -695,16 +695,17 @@ TEXT runtime·aeshashstr(SB),NOSPLIT,$-8-0
TEXT runtime·memeq(SB),NOSPLIT,$-8-25
MOVD a+0(FP), R3
MOVD b+8(FP), R4
MOVD count+16(FP), R5
MOVD size+16(FP), R5
SUB $1, R3
SUB $1, R4
ADD R3, R5, R8
loop:
CMP R3, R8
BNE 4(PC)
BNE test
MOVD $1, R3
MOVB R3, ret+24(FP)
RETURN
test:
MOVBZU 1(R3), R6
MOVBZU 1(R4), R7
CMP R6, R7
@ -828,7 +829,7 @@ notfound:
// in ../../cmd/9g/ggen.c:/^clearfat.
// R0: always zero
// R3 (aka REGRT1): ptr to memory to be zeroed - 8
// R3 is updated as a side effect.
// On return, R3 points to the last zeroed dword.
TEXT runtime·duffzero(SB), NOSPLIT, $-8-0
MOVDU R0, 8(R3)
MOVDU R0, 8(R3)
@ -964,7 +965,7 @@ TEXT runtime·fastrand1(SB), NOSPLIT, $0-4
MOVD g_m(g), R4
MOVWZ m_fastrand(R4), R3
ADD R3, R3
CMP R3, $0
CMPW R3, $0
BGE 2(PC)
XOR $0x88888eef, R3
MOVW R3, m_fastrand(R4)
@ -979,3 +980,9 @@ TEXT runtime·return0(SB), NOSPLIT, $0
// Must obey the gcc calling convention.
TEXT _cgo_topofstack(SB),NOSPLIT,$0
MOVD R0, 26(R0)
// The top-most function running on a goroutine
// returns to goexit+PCQuantum.
TEXT runtime·goexit(SB),NOSPLIT,$-8-0
MOVD R0, R0 // NOP
BL runtime·goexit1(SB) // does not return

View file

@ -137,7 +137,7 @@ func infoBigStruct() []byte {
BitsScalar, BitsScalar, BitsScalar, BitsScalar, // t int; y uint16; u uint64
BitsPointer, BitsDead, // i string
}
case "amd64":
case "amd64", "power64", "power64le":
return []byte{
BitsPointer, // q *int
BitsScalar, BitsScalar, BitsScalar, // w byte; e [17]byte
@ -153,12 +153,6 @@ func infoBigStruct() []byte {
BitsScalar, BitsScalar, BitsDead, BitsScalar, BitsScalar, // t int; y uint16; u uint64
BitsPointer, BitsDead, // i string
}
case "power64", "power64le":
return []byte{
BitsPointer, BitsScalar, BitsScalar, BitsScalar,
BitsMultiWord, BitsSlice, BitsScalar, BitsScalar,
BitsScalar, BitsScalar, BitsMultiWord, BitsString,
}
default:
panic("unknown arch")
}

View file

@ -122,6 +122,7 @@
enum {
Debug = 0,
DebugPtrs = 0, // if 1, print trace of every pointer load during GC
ConcurrentSweep = 1,
FinBlockSize = 4*1024,

View file

@ -69,7 +69,7 @@ runtime·recovery_m(G *gp)
// each call to deferproc.
// (The pc we're returning to does pop pop
// before it tests the return value.)
// On the arm there are 2 saved LRs mixed in too.
// On the arm and power there are 2 saved LRs mixed in too.
if(thechar == '5' || thechar == '9')
gp->sched.sp = (uintptr)argp - 4*sizeof(uintptr);
else

View file

@ -226,6 +226,12 @@ runtime·check(void)
if(z != 4)
runtime·throw("cas4");
z = 0xffffffff;
if(!runtime·cas(&z, 0xffffffff, 0xfffffffe))
runtime·throw("cas5");
if(z != 0xfffffffe)
runtime·throw("cas6");
k = (byte*)0xfedcb123;
if(sizeof(void*) == 8)
k = (byte*)((uintptr)k<<10);

View file

@ -124,7 +124,7 @@ runtime·sighandler(int32 sig, Siginfo *info, void *ctxt, G *gp)
if(runtime·gotraceback(&crash)){
runtime·goroutineheader(gp);
runtime·traceback(SIG_PC(info, ctxt), SIG_SP(info, ctxt), SIG_LINK(info, ctxt), gp);
runtime·tracebacktrap(SIG_PC(info, ctxt), SIG_SP(info, ctxt), SIG_LINK(info, ctxt), gp);
runtime·tracebackothers(gp);
runtime·printf("\n");
runtime·dumpregs(info, ctxt);

68
test/clearfat.go Normal file
View file

@ -0,0 +1,68 @@
// runoutput
// Copyright 2014 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.
// Check that {5,6,8,9}g/ggen.c:clearfat is zeroing the entire object.
package main
import (
"bytes"
"fmt"
"strconv"
"strings"
)
const ntest = 1100
func main() {
var decls, calls bytes.Buffer
for i := 1; i <= ntest; i++ {
s := strconv.Itoa(i)
decls.WriteString(strings.Replace(decl, "$", s, -1))
calls.WriteString(strings.Replace("poison$()\n\tclearfat$()\n\t", "$", s, -1))
}
program = strings.Replace(program, "$DECLS", decls.String(), 1)
program = strings.Replace(program, "$CALLS", calls.String(), 1)
fmt.Print(program)
}
var program = `package main
var count int
$DECLS
func main() {
$CALLS
if count != 0 {
println("failed", count, "case(s)")
}
}
`
const decl = `
func poison$() {
// Grow and poison the stack space that will be used by clearfat$
var t [2*$]byte
for i := range t {
t[i] = 0xff
}
}
func clearfat$() {
var t [$]byte
for _, x := range t {
if x != 0 {
// println("clearfat$: index", i, "expected 0, got", x)
count++
break
}
}
}
`

View file

@ -634,8 +634,8 @@ func newT40() *T40 {
func bad40() {
t := newT40()
printnl()
_ = t
printnl()
}
func good40() {

View file

@ -1,4 +1,6 @@
// errorcheck -0 -d=nil
// Fails on power64x because of incomplete optimization. See issue 9058.
// +build !power64,!power64le
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style