summaryrefslogtreecommitdiff
path: root/src/cmd
diff options
context:
space:
mode:
authorRuss Cox <rsc@golang.org>2014-11-24 12:07:11 -0500
committerRuss Cox <rsc@golang.org>2014-11-24 12:07:11 -0500
commite5fc9ffb729e31c4eb0a6518e819e9fc70f14818 (patch)
tree5f67f9fb6c209085505b8fa6a01a245942ea45c3 /src/cmd
parentdf7d4576f312e1b646af4f5f1a32412a4221b785 (diff)
parentdb6a11ff558add790779fdef118b5ad899f77137 (diff)
downloadgo-e5fc9ffb729e31c4eb0a6518e819e9fc70f14818.tar.gz
[dev.garbage] all: merge dev.cc (493ad916c3b1) into dev.garbage
TBR=austin CC=golang-codereviews https://codereview.appspot.com/179290043
Diffstat (limited to 'src/cmd')
-rw-r--r--src/cmd/5g/opt.h30
-rw-r--r--src/cmd/5g/reg.c47
-rw-r--r--src/cmd/5l/5.out.h2
-rw-r--r--src/cmd/6g/opt.h32
-rw-r--r--src/cmd/6g/reg.c43
-rw-r--r--src/cmd/6l/6.out.h2
-rw-r--r--src/cmd/8g/opt.h32
-rw-r--r--src/cmd/8g/reg.c53
-rw-r--r--src/cmd/8l/8.out.h2
-rw-r--r--src/cmd/9a/lex.c3
-rw-r--r--src/cmd/9c/Makefile5
-rw-r--r--src/cmd/9c/Notes14
-rw-r--r--src/cmd/9c/cgen.c1147
-rw-r--r--src/cmd/9c/doc.go17
-rw-r--r--src/cmd/9c/gc.h350
-rw-r--r--src/cmd/9c/list.c37
-rw-r--r--src/cmd/9c/machcap.c105
-rw-r--r--src/cmd/9c/mul.c638
-rw-r--r--src/cmd/9c/peep.c1076
-rw-r--r--src/cmd/9c/reg.c1163
-rw-r--r--src/cmd/9c/sgen.c291
-rw-r--r--src/cmd/9c/swt.c407
-rw-r--r--src/cmd/9c/txt.c1537
-rw-r--r--src/cmd/9g/prog.c9
-rw-r--r--src/cmd/9g/reg.c7
-rw-r--r--src/cmd/9l/9.out.h2
-rw-r--r--src/cmd/cgo/doc.go2
-rw-r--r--src/cmd/dist/build.c7
-rw-r--r--src/cmd/dist/buildgc.c87
-rw-r--r--src/cmd/dist/buildruntime.c60
-rw-r--r--src/cmd/gc/walk.c1
-rw-r--r--src/cmd/go/tool.go12
-rw-r--r--src/cmd/internal/goobj/read.go666
-rw-r--r--src/cmd/internal/goobj/read_test.go28
-rw-r--r--src/cmd/internal/objfile/goobj.go2
-rw-r--r--src/cmd/link/auto.go2
-rw-r--r--src/cmd/link/auto_test.go2
-rw-r--r--src/cmd/link/dead.go2
-rw-r--r--src/cmd/link/dead_test.go2
-rw-r--r--src/cmd/link/layout.go2
-rw-r--r--src/cmd/link/link_test.go2
-rw-r--r--src/cmd/link/pclntab.go2
-rw-r--r--src/cmd/link/pclntab_test.go2
-rw-r--r--src/cmd/link/prog.go2
-rw-r--r--src/cmd/link/runtime.go2
-rw-r--r--src/cmd/link/scan.go4
-rw-r--r--src/cmd/pprof/internal/report/source.go6
47 files changed, 985 insertions, 6961 deletions
diff --git a/src/cmd/5g/opt.h b/src/cmd/5g/opt.h
index 5016d1cc8..a606f1d31 100644
--- a/src/cmd/5g/opt.h
+++ b/src/cmd/5g/opt.h
@@ -75,12 +75,18 @@ 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;
@@ -93,6 +99,16 @@ struct Reg
#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;
@@ -144,7 +160,7 @@ void prop(Reg*, Bits, Bits);
void synch(Reg*, Bits);
uint32 allreg(uint32, Rgn*);
void paint1(Reg*, int);
-uint32 paint2(Reg*, int);
+uint32 paint2(Reg*, int, int);
void paint3(Reg*, int, uint32, int);
void addreg(Adr*, int);
void dumpit(char *str, Flow *r0, int);
@@ -187,16 +203,16 @@ 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,
diff --git a/src/cmd/5g/reg.c b/src/cmd/5g/reg.c
index 441792873..611310f12 100644
--- a/src/cmd/5g/reg.c
+++ b/src/cmd/5g/reg.c
@@ -230,7 +230,7 @@ regopt(Prog *firstp)
/* the mod/div runtime routines smash R12 */
if(p->as == ADIV || p->as == ADIVU || p->as == AMOD || p->as == AMODU)
- r->set.b[z] |= RtoB(12);
+ r->set.b[0] |= RtoB(12);
}
if(firstr == R)
return;
@@ -454,9 +454,13 @@ brk:
* replace code (paint3)
*/
rgp = region;
+ if(debug['R'] && debug['v'])
+ print("\nregisterizing\n");
for(i=0; i<nregion; i++) {
+ if(debug['R'] && debug['v'])
+ print("region %d: cost %d varno %d enter %d\n", i, rgp->cost, rgp->varno, rgp->enter->f.prog->pc);
bit = blsh(rgp->varno);
- vreg = paint2(rgp->enter, rgp->varno);
+ vreg = paint2(rgp->enter, rgp->varno, 0);
vreg = allreg(vreg, rgp);
if(debug['R']) {
if(rgp->regno >= NREG)
@@ -477,9 +481,6 @@ brk:
rgp++;
}
- if(debug['R'] && debug['v'])
- dumpit("pass6", &firstr->f, 1);
-
/*
* free aux structures. peep allocates new ones.
*/
@@ -488,6 +489,15 @@ brk:
flowend(g);
firstr = R;
+ if(debug['R'] && debug['v']) {
+ // Rebuild flow graph, since we inserted instructions
+ g = flowstart(firstp, sizeof(Reg));
+ firstr = (Reg*)g->start;
+ dumpit("pass6", &firstr->f, 1);
+ flowend(g);
+ firstr = R;
+ }
+
/*
* pass 7
* peep-hole on basic block
@@ -1189,7 +1199,7 @@ paint1(Reg *r, int bn)
}
uint32
-paint2(Reg *r, int bn)
+paint2(Reg *r, int bn, int depth)
{
Reg *r1;
int z;
@@ -1213,6 +1223,9 @@ paint2(Reg *r, int bn)
r = r1;
}
for(;;) {
+ if(debug['R'] && debug['v'])
+ print(" paint2 %d %P\n", depth, r->f.prog);
+
r->act.b[z] &= ~bb;
vreg |= r->regu;
@@ -1220,14 +1233,14 @@ paint2(Reg *r, int bn)
if(r->refbehind.b[z] & bb)
for(r1 = (Reg*)r->f.p2; r1 != R; r1 = (Reg*)r1->f.p2link)
if(r1->refahead.b[z] & bb)
- vreg |= paint2(r1, bn);
+ vreg |= paint2(r1, bn, depth+1);
if(!(r->refahead.b[z] & bb))
break;
r1 = (Reg*)r->f.s2;
if(r1 != R)
if(r1->refbehind.b[z] & bb)
- vreg |= paint2(r1, bn);
+ vreg |= paint2(r1, bn, depth+1);
r = (Reg*)r->f.s1;
if(r == R)
break;
@@ -1344,6 +1357,8 @@ RtoB(int r)
int
BtoR(uint32 b)
{
+ // TODO Allow R0 and R1, but be careful with a 0 return
+ // TODO Allow R9. Only R10 is reserved now (just g, not m).
b &= 0x11fcL; // excluded R9 and R10 for m and g, but not R12
if(b == 0)
return 0;
@@ -1442,12 +1457,14 @@ dumpit(char *str, Flow *r0, int isreg)
print(" (only)");
print("\n");
}
-// r1 = r->s1;
-// if(r1 != nil) {
-// print(" succ:");
-// for(; r1 != R; r1 = r1->s1)
-// print(" %.4ud", (int)r1->prog->pc);
-// print("\n");
-// }
+ // Print successors if it's not just the next one
+ if(r->s1 != r->link || r->s2 != nil) {
+ print(" succ:");
+ if(r->s1 != nil)
+ print(" %.4ud", (int)r->s1->prog->pc);
+ if(r->s2 != nil)
+ print(" %.4ud", (int)r->s2->prog->pc);
+ print("\n");
+ }
}
}
diff --git a/src/cmd/5l/5.out.h b/src/cmd/5l/5.out.h
index 7b16ac446..38a33db64 100644
--- a/src/cmd/5l/5.out.h
+++ b/src/cmd/5l/5.out.h
@@ -338,6 +338,8 @@ enum
D_STATIC = (D_NONE+4),
D_AUTO = (D_NONE+5),
D_PARAM = (D_NONE+6),
+
+ D_LAST = (D_NONE+26),
};
/*
diff --git a/src/cmd/6g/opt.h b/src/cmd/6g/opt.h
index 4c9bb89fc..493171ef8 100644
--- a/src/cmd/6g/opt.h
+++ b/src/cmd/6g/opt.h
@@ -75,12 +75,18 @@ 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;
@@ -93,6 +99,16 @@ struct Reg
#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;
@@ -140,7 +156,7 @@ void prop(Reg*, Bits, Bits);
void synch(Reg*, Bits);
uint32 allreg(uint32, Rgn*);
void paint1(Reg*, int);
-uint32 paint2(Reg*, int);
+uint32 paint2(Reg*, int, int);
void paint3(Reg*, int, uint32, int);
void addreg(Adr*, int);
void dumpone(Flow*, int);
@@ -165,8 +181,8 @@ typedef struct ProgInfo ProgInfo;
struct ProgInfo
{
uint32 flags; // the bits below
- uint32 reguse; // required registers used by this instruction
- uint32 regset; // required registers set by this instruction
+ uint32 reguse; // registers implicitly used by this instruction
+ uint32 regset; // registers implicitly set by this instruction
uint32 regindex; // registers used by addressing mode
};
@@ -187,12 +203,12 @@ 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,
- // Right side: address taken, read, write.
+ // Right side (Prog.to): address taken, read, write.
RightAddr = 1<<12,
RightRead = 1<<13,
RightWrite = 1<<14,
diff --git a/src/cmd/6g/reg.c b/src/cmd/6g/reg.c
index 4ce2f4db0..75f9573b2 100644
--- a/src/cmd/6g/reg.c
+++ b/src/cmd/6g/reg.c
@@ -389,9 +389,13 @@ brk:
* replace code (paint3)
*/
rgp = region;
+ if(debug['R'] && debug['v'])
+ print("\nregisterizing\n");
for(i=0; i<nregion; i++) {
+ if(debug['R'] && debug['v'])
+ print("region %d: cost %d varno %d enter %d\n", i, rgp->cost, rgp->varno, rgp->enter->f.prog->pc);
bit = blsh(rgp->varno);
- vreg = paint2(rgp->enter, rgp->varno);
+ vreg = paint2(rgp->enter, rgp->varno, 0);
vreg = allreg(vreg, rgp);
if(rgp->regno != 0) {
if(debug['R'] && debug['v']) {
@@ -406,9 +410,6 @@ brk:
rgp++;
}
- if(debug['R'] && debug['v'])
- dumpit("pass6", &firstr->f, 1);
-
/*
* free aux structures. peep allocates new ones.
*/
@@ -417,6 +418,15 @@ brk:
flowend(g);
firstr = R;
+ if(debug['R'] && debug['v']) {
+ // Rebuild flow graph, since we inserted instructions
+ g = flowstart(firstp, sizeof(Reg));
+ firstr = (Reg*)g->start;
+ dumpit("pass6", &firstr->f, 1);
+ flowend(g);
+ firstr = R;
+ }
+
/*
* pass 7
* peep-hole on basic block
@@ -1020,7 +1030,7 @@ paint1(Reg *r, int bn)
}
uint32
-paint2(Reg *r, int bn)
+paint2(Reg *r, int bn, int depth)
{
Reg *r1;
int z;
@@ -1044,6 +1054,9 @@ paint2(Reg *r, int bn)
r = r1;
}
for(;;) {
+ if(debug['R'] && debug['v'])
+ print(" paint2 %d %P\n", depth, r->f.prog);
+
r->act.b[z] &= ~bb;
vreg |= r->regu;
@@ -1051,14 +1064,14 @@ paint2(Reg *r, int bn)
if(r->refbehind.b[z] & bb)
for(r1 = (Reg*)r->f.p2; r1 != R; r1 = (Reg*)r1->f.p2link)
if(r1->refahead.b[z] & bb)
- vreg |= paint2(r1, bn);
+ vreg |= paint2(r1, bn, depth+1);
if(!(r->refahead.b[z] & bb))
break;
r1 = (Reg*)r->f.s2;
if(r1 != R)
if(r1->refbehind.b[z] & bb)
- vreg |= paint2(r1, bn);
+ vreg |= paint2(r1, bn, depth+1);
r = (Reg*)r->f.s1;
if(r == R)
break;
@@ -1259,12 +1272,14 @@ dumpit(char *str, Flow *r0, int isreg)
print(" %.4ud", (int)r1->prog->pc);
print("\n");
}
-// r1 = r->s1;
-// if(r1 != R) {
-// print(" succ:");
-// for(; r1 != R; r1 = r1->s1)
-// print(" %.4ud", (int)r1->prog->pc);
-// print("\n");
-// }
+ // Print successors if it's not just the next one
+ if(r->s1 != r->link || r->s2 != nil) {
+ print(" succ:");
+ if(r->s1 != nil)
+ print(" %.4ud", (int)r->s1->prog->pc);
+ if(r->s2 != nil)
+ print(" %.4ud", (int)r->s2->prog->pc);
+ print("\n");
+ }
}
}
diff --git a/src/cmd/6l/6.out.h b/src/cmd/6l/6.out.h
index af72784e8..c09ac2824 100644
--- a/src/cmd/6l/6.out.h
+++ b/src/cmd/6l/6.out.h
@@ -865,6 +865,8 @@ enum
D_INDIR, /* additive */
+ D_LAST,
+
T_TYPE = 1<<0,
T_INDEX = 1<<1,
T_OFFSET = 1<<2,
diff --git a/src/cmd/8g/opt.h b/src/cmd/8g/opt.h
index 0e2d165b1..5445f9127 100644
--- a/src/cmd/8g/opt.h
+++ b/src/cmd/8g/opt.h
@@ -75,12 +75,18 @@ 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;
@@ -106,6 +112,16 @@ struct Reg
#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;
@@ -158,7 +174,7 @@ void loopit(Reg*, int32);
void synch(Reg*, Bits);
uint32 allreg(uint32, Rgn*);
void paint1(Reg*, int);
-uint32 paint2(Reg*, int);
+uint32 paint2(Reg*, int, int);
void paint3(Reg*, int, uint32, int);
void addreg(Adr*, int);
void dumpone(Flow*, int);
@@ -183,8 +199,8 @@ typedef struct ProgInfo ProgInfo;
struct ProgInfo
{
uint32 flags; // the bits below
- uint32 reguse; // required registers used by this instruction
- uint32 regset; // required registers set by this instruction
+ uint32 reguse; // registers implicitly used by this instruction
+ uint32 regset; // registers implicitly set by this instruction
uint32 regindex; // registers used by addressing mode
};
@@ -205,12 +221,12 @@ 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,
- // Right side: address taken, read, write.
+ // Right side (Prog.to): address taken, read, write.
RightAddr = 1<<12,
RightRead = 1<<13,
RightWrite = 1<<14,
diff --git a/src/cmd/8g/reg.c b/src/cmd/8g/reg.c
index 79d60bed5..d7394a16d 100644
--- a/src/cmd/8g/reg.c
+++ b/src/cmd/8g/reg.c
@@ -358,18 +358,19 @@ brk:
* replace code (paint3)
*/
rgp = region;
+ if(debug['R'] && debug['v'])
+ print("\nregisterizing\n");
for(i=0; i<nregion; i++) {
+ if(debug['R'] && debug['v'])
+ print("region %d: cost %d varno %d enter %lld\n", i, rgp->cost, rgp->varno, rgp->enter->f.prog->pc);
bit = blsh(rgp->varno);
- vreg = paint2(rgp->enter, rgp->varno);
+ vreg = paint2(rgp->enter, rgp->varno, 0);
vreg = allreg(vreg, rgp);
if(rgp->regno != 0)
paint3(rgp->enter, rgp->varno, vreg, rgp->regno);
rgp++;
}
- if(debug['R'] && debug['v'])
- dumpit("pass6", &firstr->f, 1);
-
/*
* free aux structures. peep allocates new ones.
*/
@@ -378,6 +379,15 @@ brk:
flowend(g);
firstr = R;
+ if(debug['R'] && debug['v']) {
+ // Rebuild flow graph, since we inserted instructions
+ g = flowstart(firstp, sizeof(Reg));
+ firstr = (Reg*)g->start;
+ dumpit("pass6", &firstr->f, 1);
+ flowend(g);
+ firstr = R;
+ }
+
/*
* pass 7
* peep-hole on basic block
@@ -926,7 +936,7 @@ paint1(Reg *r, int bn)
Reg *r1;
Prog *p;
int z;
- uint64 bb;
+ uint64 bb, rbz;
z = bn/64;
bb = 1LL<<(bn%64);
@@ -945,7 +955,8 @@ paint1(Reg *r, int bn)
r = r1;
}
- if(LOAD(r) & ~(r->set.b[z]&~(r->use1.b[z]|r->use2.b[z])) & bb) {
+ rbz = ~(r->set.b[z]&~(r->use1.b[z]|r->use2.b[z]));
+ if(LOAD(r) & rbz & bb) {
change -= CLOAD * r->f.loop;
}
for(;;) {
@@ -996,7 +1007,7 @@ paint1(Reg *r, int bn)
}
uint32
-paint2(Reg *r, int bn)
+paint2(Reg *r, int bn, int depth)
{
Reg *r1;
int z;
@@ -1020,6 +1031,9 @@ paint2(Reg *r, int bn)
r = r1;
}
for(;;) {
+ if(debug['R'] && debug['v'])
+ print(" paint2 %d %P\n", depth, r->f.prog);
+
r->act.b[z] &= ~bb;
vreg |= r->regu;
@@ -1027,14 +1041,14 @@ paint2(Reg *r, int bn)
if(r->refbehind.b[z] & bb)
for(r1 = (Reg*)r->f.p2; r1 != R; r1 = (Reg*)r1->f.p2link)
if(r1->refahead.b[z] & bb)
- vreg |= paint2(r1, bn);
+ vreg |= paint2(r1, bn, depth+1);
if(!(r->refahead.b[z] & bb))
break;
r1 = (Reg*)r->f.s2;
if(r1 != R)
if(r1->refbehind.b[z] & bb)
- vreg |= paint2(r1, bn);
+ vreg |= paint2(r1, bn, depth+1);
r = (Reg*)r->f.s1;
if(r == R)
break;
@@ -1053,7 +1067,7 @@ paint3(Reg *r, int bn, uint32 rb, int rn)
Reg *r1;
Prog *p;
int z;
- uint64 bb;
+ uint64 bb, rbz;
z = bn/64;
bb = 1LL << (bn%64);
@@ -1072,7 +1086,8 @@ paint3(Reg *r, int bn, uint32 rb, int rn)
r = r1;
}
- if(LOAD(r) & ~(r->set.b[z] & ~(r->use1.b[z]|r->use2.b[z])) & bb)
+ rbz = ~(r->set.b[z] & ~(r->use1.b[z]|r->use2.b[z]));
+ if(LOAD(r) & rbz & bb)
addmove(r, bn, rn, 0);
for(;;) {
r->act.b[z] |= bb;
@@ -1227,12 +1242,14 @@ dumpit(char *str, Flow *r0, int isreg)
print(" %.4ud", (int)r1->prog->pc);
print("\n");
}
-// r1 = r->s1;
-// if(r1 != nil) {
-// print(" succ:");
-// for(; r1 != R; r1 = r1->s1)
-// print(" %.4ud", (int)r1->prog->pc);
-// print("\n");
-// }
+ // Print successors if it's not just the next one
+ if(r->s1 != r->link || r->s2 != nil) {
+ print(" succ:");
+ if(r->s1 != nil)
+ print(" %.4ud", (int)r->s1->prog->pc);
+ if(r->s2 != nil)
+ print(" %.4ud", (int)r->s2->prog->pc);
+ print("\n");
+ }
}
}
diff --git a/src/cmd/8l/8.out.h b/src/cmd/8l/8.out.h
index ed54f6744..596c5f61a 100644
--- a/src/cmd/8l/8.out.h
+++ b/src/cmd/8l/8.out.h
@@ -654,6 +654,8 @@ enum
D_CONST2 = D_INDIR+D_INDIR,
+ D_LAST,
+
T_TYPE = 1<<0,
T_INDEX = 1<<1,
T_OFFSET = 1<<2,
diff --git a/src/cmd/9a/lex.c b/src/cmd/9a/lex.c
index 26f21f743..e2945ef89 100644
--- a/src/cmd/9a/lex.c
+++ b/src/cmd/9a/lex.c
@@ -250,7 +250,7 @@ struct
"R27", LREG, 27,
"R28", LREG, 28,
"R29", LREG, 29,
- "R30", LREG, 30,
+ "g", LREG, 30, // avoid unintentionally clobbering g using R30
"R31", LREG, 31,
"F", LF, 0,
@@ -488,6 +488,7 @@ struct
"SYSCALL", LNOP, ASYSCALL,
"UNDEF", LNOP, AUNDEF,
+ "RET", LRETRN, ARETURN,
"RETURN", LRETRN, ARETURN,
"RFI", LRETRN, ARFI,
"RFCI", LRETRN, ARFCI,
diff --git a/src/cmd/9c/Makefile b/src/cmd/9c/Makefile
deleted file mode 100644
index 3f528d751..000000000
--- a/src/cmd/9c/Makefile
+++ /dev/null
@@ -1,5 +0,0 @@
-# Copyright 2012 The Go Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style
-# license that can be found in the LICENSE file.
-
-include ../../Make.dist
diff --git a/src/cmd/9c/Notes b/src/cmd/9c/Notes
deleted file mode 100644
index 92dd9deb3..000000000
--- a/src/cmd/9c/Notes
+++ /dev/null
@@ -1,14 +0,0 @@
-- effect of register expansion on 32-bit shifts and masks etc
-9c
-- multab
-- floating-point conversions
-- conversions of constants
-- nodtype for loads
-- sign-extension instruction (32-64) when in register?
-- double indexing
-- SLW (eg, in cat)
-- scheduling
-
-9l
-- D_QCONST, DWORD
-- maskgen
diff --git a/src/cmd/9c/cgen.c b/src/cmd/9c/cgen.c
deleted file mode 100644
index bd1f7b28f..000000000
--- a/src/cmd/9c/cgen.c
+++ /dev/null
@@ -1,1147 +0,0 @@
-// cmd/9c/cgen.c from Vita Nuova.
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2008 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-// Revisions Copyright © 2000-2008 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-#include "gc.h"
-#include "../../runtime/funcdata.h"
-
-void
-cgen(Node *n, Node *nn)
-{
- Node *l, *r;
- Prog *p1;
- Node nod, nod1, nod2, nod3, nod4;
- int o;
- int32 v, curs;
-
- if(debug['g']) {
- prtree(nn, "cgen lhs");
- prtree(n, "cgen");
- }
- if(n == Z || n->type == T)
- return;
- if(typesu[n->type->etype] && (n->op != OFUNC || nn != Z)) {
- sugen(n, nn, n->type->width);
- return;
- }
- l = n->left;
- r = n->right;
- o = n->op;
- if(n->addable >= INDEXED) {
- if(nn == Z) {
- switch(o) {
- default:
- nullwarn(Z, Z);
- break;
- case OINDEX:
- nullwarn(l, r);
- break;
- }
- return;
- }
- gmove(n, nn);
- return;
- }
- curs = cursafe;
-
- if(n->complex >= FNX)
- if(l->complex >= FNX)
- if(r != Z && r->complex >= FNX)
- switch(o) {
- default:
- regret(&nod, r, 0, 0);
- cgen(r, &nod);
-
- regsalloc(&nod1, r);
- gopcode(OAS, &nod, Z, &nod1);
-
- regfree(&nod);
- nod = *n;
- nod.right = &nod1;
- cgen(&nod, nn);
- return;
-
- case OFUNC:
- case OCOMMA:
- case OANDAND:
- case OOROR:
- case OCOND:
- case ODOT:
- break;
- }
-
- switch(o) {
- default:
- diag(n, "unknown op in cgen: %O", o);
- break;
-
- case OAS:
- if(l->op == OBIT)
- goto bitas;
- if(l->addable >= INDEXED) {
- if(nn != Z || r->addable < INDEXED) {
- regalloc(&nod, r, nn);
- cgen(r, &nod);
- gmove(&nod, l);
- regfree(&nod);
- } else
- gmove(r, l);
- break;
- }
- if(l->complex >= r->complex) {
- reglcgen(&nod1, l, Z);
- if(r->addable >= INDEXED) {
- gmove(r, &nod1);
- if(nn != Z)
- gmove(r, nn);
- regfree(&nod1);
- break;
- }
- regalloc(&nod, r, nn);
- cgen(r, &nod);
- } else {
- regalloc(&nod, r, nn);
- cgen(r, &nod);
- reglcgen(&nod1, l, Z);
- }
- gmove(&nod, &nod1);
- regfree(&nod);
- regfree(&nod1);
- break;
-
- bitas:
- n = l->left;
- regalloc(&nod, r, nn);
- if(l->complex >= r->complex) {
- reglcgen(&nod1, n, Z);
- cgen(r, &nod);
- } else {
- cgen(r, &nod);
- reglcgen(&nod1, n, Z);
- }
- regalloc(&nod2, n, Z);
- gopcode(OAS, &nod1, Z, &nod2);
- bitstore(l, &nod, &nod1, &nod2, nn);
- break;
-
- case OBIT:
- if(nn == Z) {
- nullwarn(l, Z);
- break;
- }
- bitload(n, &nod, Z, Z, nn);
- gopcode(OAS, &nod, Z, nn);
- regfree(&nod);
- break;
-
- case OXOR:
- if(nn != Z)
- if(r->op == OCONST && r->vconst == -1){
- cgen(l, nn);
- gopcode(OCOM, nn, Z, nn);
- break;
- }
-
- case OADD:
- case OSUB:
- case OAND:
- case OOR:
- case OLSHR:
- case OASHL:
- case OASHR:
- /*
- * immediate operands
- */
- if(nn != Z &&
- r->op == OCONST &&
- !typefd[n->type->etype] &&
- immconst(r)) {
- cgen(l, nn);
- if(r->vconst == 0)
- if(o != OAND)
- break;
- if(nn != Z)
- gopcode(o, r, Z, nn);
- break;
- }
-
- case OMUL:
- case OLMUL:
- case OLDIV:
- case OLMOD:
- case ODIV:
- case OMOD:
- if(nn == Z) {
- nullwarn(l, r);
- break;
- }
- if(o == OMUL || o == OLMUL) {
- if(mulcon(n, nn))
- break;
- if(debug['M'])
- print("%L multiply\n", n->lineno);
- }
- if(l->complex >= r->complex) {
- regalloc(&nod, l, nn);
- cgen(l, &nod);
- regalloc(&nod1, l, Z); /* note: l used for type, so shifts work! */
- cgen(r, &nod1);
- gopcode(o, &nod1, Z, &nod);
- } else {
- regalloc(&nod, l, nn); /* note: l used for type, so shifts work! */
- cgen(r, &nod);
- regalloc(&nod1, l, Z);
- cgen(l, &nod1);
- gopcode(o, &nod, &nod1, &nod);
- }
- gopcode(OAS, &nod, Z, nn);
- regfree(&nod);
- regfree(&nod1);
- break;
-
- case OASLSHR:
- case OASASHL:
- case OASASHR:
- case OASAND:
- case OASADD:
- case OASSUB:
- case OASXOR:
- case OASOR:
- if(l->op == OBIT)
- goto asbitop;
- if(r->op == OCONST &&
- !typefd[n->type->etype] &&
- immconst(r)) {
- if(l->addable < INDEXED)
- reglcgen(&nod2, l, Z);
- else
- nod2 = *l;
- regalloc(&nod, l, nn); /* note: l used for type, so shifts work! */
- gopcode(OAS, &nod2, Z, &nod);
- gopcode(o, r, Z, &nod);
- gopcode(OAS, &nod, Z, &nod2);
-
- regfree(&nod);
- if(l->addable < INDEXED)
- regfree(&nod2);
- break;
- }
-
- case OASLMUL:
- case OASLDIV:
- case OASLMOD:
- case OASMUL:
- case OASDIV:
- case OASMOD:
- if(l->op == OBIT)
- goto asbitop;
- if(l->complex >= r->complex) {
- if(l->addable < INDEXED)
- reglcgen(&nod2, l, Z);
- else
- nod2 = *l;
- regalloc(&nod, n, nn);
- cgen(r, &nod);
- } else {
- regalloc(&nod, n, nn);
- cgen(r, &nod);
- if(l->addable < INDEXED)
- reglcgen(&nod2, l, Z);
- else
- nod2 = *l;
- }
- regalloc(&nod1, n, Z);
- gopcode(OAS, &nod2, Z, &nod1);
- if(nod1.type->etype != nod.type->etype){
- regalloc(&nod3, &nod, Z);
- gmove(&nod1, &nod3);
- regfree(&nod1);
- nod1 = nod3;
- }
- gopcode(o, &nod, &nod1, &nod);
- gmove(&nod, &nod2);
- if(nn != Z)
- gmove(&nod, nn);
- regfree(&nod);
- regfree(&nod1);
- if(l->addable < INDEXED)
- regfree(&nod2);
- break;
-
- asbitop:
- regalloc(&nod4, n, nn);
- regalloc(&nod3, r, Z);
- if(l->complex >= r->complex) {
- bitload(l, &nod, &nod1, &nod2, &nod4);
- cgen(r, &nod3);
- } else {
- cgen(r, &nod3);
- bitload(l, &nod, &nod1, &nod2, &nod4);
- }
- gmove(&nod, &nod4);
- gopcode(n->op, &nod3, Z, &nod4);
- regfree(&nod3);
- gmove(&nod4, &nod);
- regfree(&nod4);
- bitstore(l, &nod, &nod1, &nod2, nn);
- break;
-
- case OADDR:
- if(nn == Z) {
- nullwarn(l, Z);
- break;
- }
- lcgen(l, nn);
- break;
-
- case OFUNC:
- if(l->complex >= FNX) {
- if(l->op != OIND)
- diag(n, "bad function call");
-
- regret(&nod, l->left, 0, 0);
- cgen(l->left, &nod);
- regsalloc(&nod1, l->left);
- gopcode(OAS, &nod, Z, &nod1);
- regfree(&nod);
-
- nod = *n;
- nod.left = &nod2;
- nod2 = *l;
- nod2.left = &nod1;
- nod2.complex = 1;
- cgen(&nod, nn);
-
- return;
- }
- if(REGARG >= 0)
- o = reg[REGARG];
- gargs(r, &nod, &nod1);
- if(l->addable < INDEXED) {
- reglcgen(&nod, l, Z);
- gopcode(OFUNC, Z, Z, &nod);
- regfree(&nod);
- } else
- gopcode(OFUNC, Z, Z, l);
- if(REGARG>=0)
- if(o != reg[REGARG])
- reg[REGARG]--;
- regret(&nod, n, l->type, 1); // update maxarg if nothing else
- if(nn != Z)
- gopcode(OAS, &nod, Z, nn);
- if(nod.op == OREGISTER)
- regfree(&nod);
- break;
-
- case OIND:
- if(nn == Z) {
- cgen(l, nn);
- break;
- }
- regialloc(&nod, n, nn);
- r = l;
- while(r->op == OADD)
- r = r->right;
- if(sconst(r)) {
- v = r->vconst;
- r->vconst = 0;
- cgen(l, &nod);
- nod.xoffset += v;
- r->vconst = v;
- } else
- cgen(l, &nod);
- regind(&nod, n);
- gopcode(OAS, &nod, Z, nn);
- regfree(&nod);
- break;
-
- case OEQ:
- case ONE:
- case OLE:
- case OLT:
- case OGE:
- case OGT:
- case OLO:
- case OLS:
- case OHI:
- case OHS:
- if(nn == Z) {
- nullwarn(l, r);
- break;
- }
- boolgen(n, 1, nn);
- break;
-
- case OANDAND:
- case OOROR:
- boolgen(n, 1, nn);
- if(nn == Z)
- patch(p, pc);
- break;
-
- case ONOT:
- if(nn == Z) {
- nullwarn(l, Z);
- break;
- }
- boolgen(n, 1, nn);
- break;
-
- case OCOMMA:
- cgen(l, Z);
- cgen(r, nn);
- break;
-
- case OCAST:
- if(nn == Z) {
- nullwarn(l, Z);
- break;
- }
- /*
- * convert from types l->n->nn
- */
- if(nocast(l->type, n->type) && nocast(n->type, nn->type)) {
- /* both null, gen l->nn */
- cgen(l, nn);
- break;
- }
- regalloc(&nod, l, nn);
- cgen(l, &nod);
- regalloc(&nod1, n, &nod);
- gopcode(OAS, &nod, Z, &nod1);
- gopcode(OAS, &nod1, Z, nn);
- regfree(&nod1);
- regfree(&nod);
- break;
-
- case ODOT:
- sugen(l, nodrat, l->type->width);
- if(nn != Z) {
- warn(n, "non-interruptable temporary");
- nod = *nodrat;
- if(!r || r->op != OCONST) {
- diag(n, "DOT and no offset");
- break;
- }
- nod.xoffset += (int32)r->vconst;
- nod.type = n->type;
- cgen(&nod, nn);
- }
- break;
-
- case OCOND:
- bcgen(l, 1);
- p1 = p;
- cgen(r->left, nn);
- gbranch(OGOTO);
- patch(p1, pc);
- p1 = p;
- cgen(r->right, nn);
- patch(p1, pc);
- break;
-
- case OPOSTINC:
- case OPOSTDEC:
- v = 1;
- if(l->type->etype == TIND)
- v = l->type->link->width;
- if(o == OPOSTDEC)
- v = -v;
- if(l->op == OBIT)
- goto bitinc;
- if(nn == Z)
- goto pre;
-
- if(l->addable < INDEXED)
- reglcgen(&nod2, l, Z);
- else
- nod2 = *l;
-
- regalloc(&nod, l, nn);
- gopcode(OAS, &nod2, Z, &nod);
- regalloc(&nod1, l, Z);
- if(typefd[l->type->etype]) {
- regalloc(&nod3, l, Z);
- if(v < 0) {
- gopcode(OAS, nodfconst(-v), Z, &nod3);
- gopcode(OSUB, &nod3, &nod, &nod1);
- } else {
- gopcode(OAS, nodfconst(v), Z, &nod3);
- gopcode(OADD, &nod3, &nod, &nod1);
- }
- regfree(&nod3);
- } else
- gopcode(OADD, nodconst(v), &nod, &nod1);
- gopcode(OAS, &nod1, Z, &nod2);
-
- regfree(&nod);
- regfree(&nod1);
- if(l->addable < INDEXED)
- regfree(&nod2);
- break;
-
- case OPREINC:
- case OPREDEC:
- v = 1;
- if(l->type->etype == TIND)
- v = l->type->link->width;
- if(o == OPREDEC)
- v = -v;
- if(l->op == OBIT)
- goto bitinc;
-
- pre:
- if(l->addable < INDEXED)
- reglcgen(&nod2, l, Z);
- else
- nod2 = *l;
-
- regalloc(&nod, l, nn);
- gopcode(OAS, &nod2, Z, &nod);
- if(typefd[l->type->etype]) {
- regalloc(&nod3, l, Z);
- if(v < 0) {
- gopcode(OAS, nodfconst(-v), Z, &nod3);
- gopcode(OSUB, &nod3, Z, &nod);
- } else {
- gopcode(OAS, nodfconst(v), Z, &nod3);
- gopcode(OADD, &nod3, Z, &nod);
- }
- regfree(&nod3);
- } else
- gopcode(OADD, nodconst(v), Z, &nod);
- gopcode(OAS, &nod, Z, &nod2);
- if(nn && l->op == ONAME) /* in x=++i, emit USED(i) */
- gins(ANOP, l, Z);
-
- regfree(&nod);
- if(l->addable < INDEXED)
- regfree(&nod2);
- break;
-
- bitinc:
- if(nn != Z && (o == OPOSTINC || o == OPOSTDEC)) {
- bitload(l, &nod, &nod1, &nod2, Z);
- gopcode(OAS, &nod, Z, nn);
- gopcode(OADD, nodconst(v), Z, &nod);
- bitstore(l, &nod, &nod1, &nod2, Z);
- break;
- }
- bitload(l, &nod, &nod1, &nod2, nn);
- gopcode(OADD, nodconst(v), Z, &nod);
- bitstore(l, &nod, &nod1, &nod2, nn);
- break;
- }
- cursafe = curs;
-}
-
-void
-reglcgen(Node *t, Node *n, Node *nn)
-{
- Node *r;
- int32 v;
-
- regialloc(t, n, nn);
- if(n->op == OIND) {
- r = n->left;
- while(r->op == OADD)
- r = r->right;
- if(sconst(r)) {
- v = r->vconst;
- r->vconst = 0;
- lcgen(n, t);
- t->xoffset += v;
- r->vconst = v;
- regind(t, n);
- return;
- }
- }
- lcgen(n, t);
- regind(t, n);
-}
-
-void
-lcgen(Node *n, Node *nn)
-{
- Prog *p1;
- Node nod;
-
- if(debug['g']) {
- prtree(nn, "lcgen lhs");
- prtree(n, "lcgen");
- }
- if(n == Z || n->type == T)
- return;
- if(nn == Z) {
- nn = &nod;
- regalloc(&nod, n, Z);
- }
- switch(n->op) {
- default:
- if(n->addable < INDEXED) {
- diag(n, "unknown op in lcgen: %O", n->op);
- break;
- }
- nod = *n;
- nod.op = OADDR;
- nod.left = n;
- nod.right = Z;
- nod.type = types[TIND];
- gopcode(OAS, &nod, Z, nn);
- break;
-
- case OCOMMA:
- cgen(n->left, n->left);
- lcgen(n->right, nn);
- break;
-
- case OIND:
- cgen(n->left, nn);
- break;
-
- case OCOND:
- bcgen(n->left, 1);
- p1 = p;
- lcgen(n->right->left, nn);
- gbranch(OGOTO);
- patch(p1, pc);
- p1 = p;
- lcgen(n->right->right, nn);
- patch(p1, pc);
- break;
- }
-}
-
-void
-bcgen(Node *n, int true)
-{
-
- if(n->type == T)
- gbranch(OGOTO);
- else
- boolgen(n, true, Z);
-}
-
-void
-boolgen(Node *n, int true, Node *nn)
-{
- int o;
- Prog *p1, *p2;
- Node *l, *r, nod, nod1;
- int32 curs;
-
- if(debug['g']) {
- prtree(nn, "boolgen lhs");
- prtree(n, "boolgen");
- }
- curs = cursafe;
- l = n->left;
- r = n->right;
- switch(n->op) {
-
- default:
- if(n->op == OCONST) {
- o = vconst(n);
- if(!true)
- o = !o;
- gbranch(OGOTO);
- if(o) {
- p1 = p;
- gbranch(OGOTO);
- patch(p1, pc);
- }
- goto com;
- }
- regalloc(&nod, n, nn);
- cgen(n, &nod);
- o = ONE;
- if(true)
- o = comrel[relindex(o)];
- if(typefd[n->type->etype]) {
- nodreg(&nod1, n, NREG+FREGZERO);
- gopcode(o, &nod, Z, &nod1);
- } else
- gopcode(o, &nod, Z, nodconst(0));
- regfree(&nod);
- goto com;
-
- case OCOMMA:
- cgen(l, Z);
- boolgen(r, true, nn);
- break;
-
- case ONOT:
- boolgen(l, !true, nn);
- break;
-
- case OCOND:
- bcgen(l, 1);
- p1 = p;
- bcgen(r->left, true);
- p2 = p;
- gbranch(OGOTO);
- patch(p1, pc);
- p1 = p;
- bcgen(r->right, !true);
- patch(p2, pc);
- p2 = p;
- gbranch(OGOTO);
- patch(p1, pc);
- patch(p2, pc);
- goto com;
-
- case OANDAND:
- if(!true)
- goto caseor;
-
- caseand:
- bcgen(l, true);
- p1 = p;
- bcgen(r, !true);
- p2 = p;
- patch(p1, pc);
- gbranch(OGOTO);
- patch(p2, pc);
- goto com;
-
- case OOROR:
- if(!true)
- goto caseand;
-
- caseor:
- bcgen(l, !true);
- p1 = p;
- bcgen(r, !true);
- p2 = p;
- gbranch(OGOTO);
- patch(p1, pc);
- patch(p2, pc);
- goto com;
-
- case OEQ:
- case ONE:
- case OLE:
- case OLT:
- case OGE:
- case OGT:
- case OHI:
- case OHS:
- case OLO:
- case OLS:
- o = n->op;
- if(true)
- o = comrel[relindex(o)];
- if(l->complex >= FNX && r->complex >= FNX) {
- regret(&nod, r, 0, 0);
- cgen(r, &nod);
- regsalloc(&nod1, r);
- gopcode(OAS, &nod, Z, &nod1);
- regfree(&nod);
- nod = *n;
- nod.right = &nod1;
- boolgen(&nod, true, nn);
- break;
- }
- if(sconst(r)) {
- regalloc(&nod, l, nn);
- cgen(l, &nod);
- gopcode(o, &nod, Z, r);
- regfree(&nod);
- goto com;
- }
- if(l->complex >= r->complex) {
- regalloc(&nod1, l, nn);
- cgen(l, &nod1);
- regalloc(&nod, r, Z);
- cgen(r, &nod);
- } else {
- regalloc(&nod, r, nn);
- cgen(r, &nod);
- regalloc(&nod1, l, Z);
- cgen(l, &nod1);
- }
- gopcode(o, &nod1, Z, &nod);
- regfree(&nod);
- regfree(&nod1);
-
- com:
- if(nn != Z) {
- p1 = p;
- gopcode(OAS, nodconst(1L), Z, nn);
- gbranch(OGOTO);
- p2 = p;
- patch(p1, pc);
- gopcode(OAS, nodconst(0L), Z, nn);
- patch(p2, pc);
- }
- break;
- }
- cursafe = curs;
-}
-
-void
-sugen(Node *n, Node *nn, int32 w)
-{
- Prog *p1;
- Node nod0, nod1, nod2, nod3, nod4, *l, *r;
- Type *t;
- int32 pc1;
- int i, m, c;
-
- if(n == Z || n->type == T)
- return;
- if(debug['g']) {
- prtree(nn, "sugen lhs");
- prtree(n, "sugen");
- }
- if(nn == nodrat)
- if(w > nrathole)
- nrathole = w;
- switch(n->op) {
- case OIND:
- if(nn == Z) {
- nullwarn(n->left, Z);
- break;
- }
-
- default:
- goto copy;
-
- case OCONST:
- if(n->type && typev[n->type->etype]) {
- if(nn == Z) {
- nullwarn(n->left, Z);
- break;
- }
-
- t = nn->type;
- nn->type = types[TLONG];
- reglcgen(&nod1, nn, Z);
- nn->type = t;
-
- if(align(0, types[TCHAR], Aarg1, nil)) /* isbigendian */
- gopcode(OAS, nod32const(n->vconst>>32), Z, &nod1);
- else
- gopcode(OAS, nod32const(n->vconst), Z, &nod1);
- nod1.xoffset += SZ_LONG;
- if(align(0, types[TCHAR], Aarg1, nil)) /* isbigendian */
- gopcode(OAS, nod32const(n->vconst), Z, &nod1);
- else
- gopcode(OAS, nod32const(n->vconst>>32), Z, &nod1);
-
- regfree(&nod1);
- break;
- }
- goto copy;
-
- case ODOT:
- l = n->left;
- sugen(l, nodrat, l->type->width);
- if(nn != Z) {
- warn(n, "non-interruptable temporary");
- nod1 = *nodrat;
- r = n->right;
- if(!r || r->op != OCONST) {
- diag(n, "DOT and no offset");
- break;
- }
- nod1.xoffset += (int32)r->vconst;
- nod1.type = n->type;
- sugen(&nod1, nn, w);
- }
- break;
-
- case OSTRUCT:
- /*
- * rewrite so lhs has no side effects
- */
- if(nn != Z && side(nn)) {
- nod1 = *n;
- nod1.type = typ(TIND, n->type);
- regalloc(&nod2, &nod1, Z);
- lcgen(nn, &nod2);
- regsalloc(&nod0, &nod1);
- gopcode(OAS, &nod2, Z, &nod0);
- regfree(&nod2);
-
- nod1 = *n;
- nod1.op = OIND;
- nod1.left = &nod0;
- nod1.right = Z;
- nod1.complex = 1;
-
- sugen(n, &nod1, w);
- return;
- }
-
- r = n->left;
- for(t = n->type->link; t != T; t = t->down) {
- l = r;
- if(r->op == OLIST) {
- l = r->left;
- r = r->right;
- }
- if(nn == Z) {
- cgen(l, nn);
- continue;
- }
- /*
- * hand craft *(&nn + o) = l
- */
- nod0 = znode;
- nod0.op = OAS;
- nod0.type = t;
- nod0.left = &nod1;
- nod0.right = l;
-
- nod1 = znode;
- nod1.op = OIND;
- nod1.type = t;
- nod1.left = &nod2;
-
- nod2 = znode;
- nod2.op = OADD;
- nod2.type = typ(TIND, t);
- nod2.left = &nod3;
- nod2.right = &nod4;
-
- nod3 = znode;
- nod3.op = OADDR;
- nod3.type = nod2.type;
- nod3.left = nn;
-
- nod4 = znode;
- nod4.op = OCONST;
- nod4.type = nod2.type;
- nod4.vconst = t->offset;
-
- ccom(&nod0);
- acom(&nod0);
- xcom(&nod0);
- nod0.addable = 0;
-
- /* prtree(&nod0, "hand craft"); /* */
- cgen(&nod0, Z);
- }
- break;
-
- case OAS:
- if(nn == Z) {
- if(n->addable < INDEXED)
- sugen(n->right, n->left, w);
- break;
- }
- /* BOTCH -- functions can clobber rathole */
- sugen(n->right, nodrat, w);
- warn(n, "non-interruptable temporary");
- sugen(nodrat, n->left, w);
- sugen(nodrat, nn, w);
- break;
-
- case OFUNC:
- if(!hasdotdotdot(n->left->type)) {
- cgen(n, Z);
- if(nn != Z) {
- curarg -= n->type->width;
- regret(&nod1, n, n->left->type, 1);
- if(nn->complex >= FNX) {
- regsalloc(&nod2, n);
- cgen(&nod1, &nod2);
- nod1 = nod2;
- }
- cgen(&nod1, nn);
- }
- break;
- }
- if(nn == Z) {
- sugen(n, nodrat, w);
- break;
- }
- if(nn->op != OIND) {
- nn = new1(OADDR, nn, Z);
- nn->type = types[TIND];
- nn->addable = 0;
- } else
- nn = nn->left;
- n = new(OFUNC, n->left, new(OLIST, nn, n->right));
- n->type = types[TVOID];
- n->left->type = types[TVOID];
- cgen(n, Z);
- break;
-
- case OCOND:
- bcgen(n->left, 1);
- p1 = p;
- sugen(n->right->left, nn, w);
- gbranch(OGOTO);
- patch(p1, pc);
- p1 = p;
- sugen(n->right->right, nn, w);
- patch(p1, pc);
- break;
-
- case OCOMMA:
- cgen(n->left, Z);
- sugen(n->right, nn, w);
- break;
- }
- return;
-
-copy:
- if(nn == Z)
- return;
- if(n->complex >= FNX && nn->complex >= FNX) {
- t = nn->type;
- nn->type = types[TLONG];
- regialloc(&nod1, nn, Z);
- lcgen(nn, &nod1);
- regsalloc(&nod2, nn);
- nn->type = t;
-
- gopcode(OAS, &nod1, Z, &nod2);
- regfree(&nod1);
-
- nod2.type = typ(TIND, t);
-
- nod1 = nod2;
- nod1.op = OIND;
- nod1.left = &nod2;
- nod1.right = Z;
- nod1.complex = 1;
- nod1.type = t;
-
- sugen(n, &nod1, w);
- return;
- }
-
- if(n->complex > nn->complex) {
- t = n->type;
- n->type = types[TLONG];
- reglcgen(&nod1, n, Z);
- n->type = t;
-
- t = nn->type;
- nn->type = types[TLONG];
- reglcgen(&nod2, nn, Z);
- nn->type = t;
- } else {
- t = nn->type;
- nn->type = types[TLONG];
- reglcgen(&nod2, nn, Z);
- nn->type = t;
-
- t = n->type;
- n->type = types[TLONG];
- reglcgen(&nod1, n, Z);
- n->type = t;
- }
-
- w /= SZ_LONG;
- if(w <= 5) {
- layout(&nod1, &nod2, w, 0, Z);
- goto out;
- }
-
- /*
- * minimize space for unrolling loop
- * 3,4,5 times. (6 or more is never minimum)
- * if small structure, try 2 also.
- */
- c = 0; /* set */
- m = 100;
- i = 3;
- if(w <= 15)
- i = 2;
- for(; i<=5; i++)
- if(i + w%i <= m) {
- c = i;
- m = c + w%c;
- }
-
- regalloc(&nod3, &regnode, Z);
- layout(&nod1, &nod2, w%c, w/c, &nod3);
-
- pc1 = pc;
- layout(&nod1, &nod2, c, 0, Z);
-
- gopcode(OSUB, nodconst(1L), Z, &nod3);
- nod1.op = OREGISTER;
- gopcode(OADD, nodconst(c*SZ_LONG), Z, &nod1);
- nod2.op = OREGISTER;
- gopcode(OADD, nodconst(c*SZ_LONG), Z, &nod2);
-
- gopcode(OGT, &nod3, Z, nodconst(0));
- patch(p, pc1);
-
- regfree(&nod3);
-out:
- regfree(&nod1);
- regfree(&nod2);
-}
-
-void
-layout(Node *f, Node *t, int c, int cv, Node *cn)
-{
- Node t1, t2;
-
- while(c > 3) {
- layout(f, t, 2, 0, Z);
- c -= 2;
- }
-
- regalloc(&t1, &regnode, Z);
- regalloc(&t2, &regnode, Z);
- if(c > 0) {
- gopcode(OAS, f, Z, &t1);
- f->xoffset += SZ_LONG;
- }
- if(cn != Z)
- gopcode(OAS, nodconst(cv), Z, cn);
- if(c > 1) {
- gopcode(OAS, f, Z, &t2);
- f->xoffset += SZ_LONG;
- }
- if(c > 0) {
- gopcode(OAS, &t1, Z, t);
- t->xoffset += SZ_LONG;
- }
- if(c > 2) {
- gopcode(OAS, f, Z, &t1);
- f->xoffset += SZ_LONG;
- }
- if(c > 1) {
- gopcode(OAS, &t2, Z, t);
- t->xoffset += SZ_LONG;
- }
- if(c > 2) {
- gopcode(OAS, &t1, Z, t);
- t->xoffset += SZ_LONG;
- }
- regfree(&t1);
- regfree(&t2);
-}
diff --git a/src/cmd/9c/doc.go b/src/cmd/9c/doc.go
deleted file mode 100644
index 6c9b4762d..000000000
--- a/src/cmd/9c/doc.go
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build ignore
-
-/*
-
-9c is a version of the Plan 9 C compiler. The original is documented at
-
- http://plan9.bell-labs.com/magic/man2html/1/8c
-
-Its target architecture is the Power64, referred to by these tools as
-power64 (big endian) or power64le (little endian).
-
-*/
-package main
diff --git a/src/cmd/9c/gc.h b/src/cmd/9c/gc.h
deleted file mode 100644
index fbe5099fe..000000000
--- a/src/cmd/9c/gc.h
+++ /dev/null
@@ -1,350 +0,0 @@
-// cmd/9c/gc.h from Vita Nuova.
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2008 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-// Revisions Copyright © 2000-2008 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-#include <u.h>
-#include "../cc/cc.h"
-#include "../9l/9.out.h"
-
-/*
- * 9c/powerpc64
- */
-#define SZ_CHAR 1
-#define SZ_SHORT 2
-#define SZ_INT 4
-#define SZ_LONG 4
-#define SZ_IND 8
-#define SZ_FLOAT 4
-#define SZ_VLONG 8
-#define SZ_DOUBLE 8
-#define FNX 100
-
-typedef struct Case Case;
-typedef struct C1 C1;
-typedef struct Multab Multab;
-typedef struct Hintab Hintab;
-typedef struct Reg Reg;
-typedef struct Rgn Rgn;
-
-#define A ((Adr*)0)
-
-#define INDEXED 9
-#define P ((Prog*)0)
-
-struct Case
-{
- Case* link;
- vlong val;
- int32 label;
- char def;
- char isv;
-};
-#define C ((Case*)0)
-
-struct C1
-{
- vlong val;
- int32 label;
-};
-
-struct Multab
-{
- int32 val;
- char code[20];
-};
-
-struct Hintab
-{
- ushort val;
- char hint[10];
-};
-
-struct Reg
-{
- int32 pc;
- int32 rpo; /* reverse post ordering */
-
- Bits set;
- Bits use1;
- Bits use2;
-
- Bits refbehind;
- Bits refahead;
- Bits calbehind;
- Bits calahead;
- Bits regdiff;
- Bits act;
-
- int32 regu;
- int32 loop; /* could be shorter */
-
- union
- {
- Reg* log5;
- int32 active;
- };
- Reg* p1;
- Reg* p2;
- Reg* p2link;
- Reg* s1;
- Reg* s2;
- Reg* link;
- Prog* prog;
-};
-#define R ((Reg*)0)
-
-#define NRGN 600
-struct Rgn
-{
- Reg* enter;
- short cost;
- short varno;
- short regno;
-};
-
-EXTERN int32 breakpc;
-EXTERN int32 nbreak;
-EXTERN Case* cases;
-EXTERN Node constnode;
-EXTERN Node fconstnode;
-EXTERN Node vconstnode;
-EXTERN int32 continpc;
-EXTERN int32 curarg;
-EXTERN int32 cursafe;
-EXTERN Prog* lastp;
-extern int hintabsize;
-EXTERN int32 maxargsafe;
-EXTERN Multab multab[20];
-EXTERN int mnstring;
-EXTERN Node* nodrat;
-EXTERN Node* nodret;
-EXTERN Node* nodsafe;
-EXTERN int32 nrathole;
-EXTERN int32 nstring;
-EXTERN Prog* p;
-EXTERN int32 pc;
-EXTERN Node regnode;
-EXTERN Node qregnode;
-EXTERN char string[NSNAME];
-EXTERN Sym* symrathole;
-EXTERN Node znode;
-EXTERN Prog zprog;
-EXTERN int reg[NREG+NREG];
-EXTERN int32 exregoffset;
-EXTERN int32 exfregoffset;
-EXTERN uchar typechlpv[NTYPE];
-
-#define BLOAD(r) band(bnot(r->refbehind), r->refahead)
-#define BSTORE(r) band(bnot(r->calbehind), r->calahead)
-#define LOAD(r) (~r->refbehind.b[z] & r->refahead.b[z])
-#define STORE(r) (~r->calbehind.b[z] & r->calahead.b[z])
-
-#define bset(a,n) ((a).b[(n)/32]&(1L<<(n)%32))
-
-#define CLOAD 5
-#define CREF 5
-#define CINF 1000
-#define LOOP 3
-
-EXTERN Rgn region[NRGN];
-EXTERN Rgn* rgp;
-EXTERN int nregion;
-EXTERN int nvar;
-
-EXTERN Bits externs;
-EXTERN Bits params;
-EXTERN Bits consts;
-EXTERN Bits addrs;
-
-EXTERN int32 regbits;
-EXTERN int32 exregbits;
-
-EXTERN int change;
-EXTERN int suppress;
-
-EXTERN Reg* firstr;
-EXTERN Reg* lastr;
-EXTERN Reg zreg;
-EXTERN Reg* freer;
-EXTERN Var var[NVAR];
-EXTERN int32* idom;
-EXTERN Reg** rpo2r;
-EXTERN int32 maxnr;
-
-#define R0ISZERO (debug['0']==0)
-
-extern char* anames[];
-extern Hintab hintab[];
-
-/*
- * sgen.c
- */
-void codgen(Node*, Node*);
-void gen(Node*);
-void usedset(Node*, int);
-void noretval(int);
-void xcom(Node*);
-int bcomplex(Node*, Node*);
-Prog* gtext(Sym*, int32);
-vlong argsize(int);
-
-/*
- * cgen.c
- */
-void cgen(Node*, Node*);
-void reglcgen(Node*, Node*, Node*);
-void lcgen(Node*, Node*);
-void bcgen(Node*, int);
-void boolgen(Node*, int, Node*);
-void sugen(Node*, Node*, int32);
-void layout(Node*, Node*, int, int, Node*);
-
-/*
- * txt.c
- */
-void ginit(void);
-void gclean(void);
-void nextpc(void);
-void gargs(Node*, Node*, Node*);
-void garg1(Node*, Node*, Node*, int, Node**);
-Node* nodconst(int32);
-Node* nod32const(vlong);
-Node* nodfconst(double);
-Node* nodgconst(vlong v, Type *t);
-void nodreg(Node*, Node*, int);
-void regret(Node*, Node*, Type*, int);
-void regalloc(Node*, Node*, Node*);
-void regfree(Node*);
-void regialloc(Node*, Node*, Node*);
-void regsalloc(Node*, Node*);
-void regaalloc1(Node*, Node*);
-void regaalloc(Node*, Node*);
-void regind(Node*, Node*);
-void gprep(Node*, Node*);
-void raddr(Node*, Prog*);
-void naddr(Node*, Addr*);
-void gmove(Node*, Node*);
-void gins(int a, Node*, Node*);
-void gopcode(int, Node*, Node*, Node*);
-int samaddr(Node*, Node*);
-void gbranch(int);
-int immconst(Node*);
-void patch(Prog*, int32);
-int sconst(Node*);
-int sval(int32);
-int uconst(Node*);
-void gpseudo(int, Sym*, Node*);
-void gprefetch(Node*);
-void gpcdata(int, int);
-
-/*
- * swt.c
- */
-int swcmp(const void*, const void*);
-void doswit(Node*);
-void swit1(C1*, int, int32, Node*);
-void swit2(C1*, int, int32, Node*, Node*);
-void newcase(void);
-void bitload(Node*, Node*, Node*, Node*, Node*);
-void bitstore(Node*, Node*, Node*, Node*, Node*);
-int32 outstring(char*, int32);
-int mulcon(Node*, Node*);
-Multab* mulcon0(Node*, int32);
-int mulcon1(Node*, int32, Node*);
-void nullwarn(Node*, Node*);
-void sextern(Sym*, Node*, int32, int32);
-void gextern(Sym*, Node*, int32, int32);
-void outcode(void);
-
-/*
- * list
- */
-void listinit(void);
-int Pconv(Fmt*);
-int Aconv(Fmt*);
-int Dconv(Fmt*);
-int Sconv(Fmt*);
-int Nconv(Fmt*);
-int Bconv(Fmt*);
-
-/*
- * reg.c
- */
-Reg* rega(void);
-int rcmp(const void*, const void*);
-void regopt(Prog*);
-void addmove(Reg*, int, int, int);
-Bits mkvar(Addr*, int);
-void prop(Reg*, Bits, Bits);
-void loopit(Reg*, int32);
-void synch(Reg*, Bits);
-uint32 allreg(uint32, Rgn*);
-void paint1(Reg*, int);
-uint32 paint2(Reg*, int);
-void paint3(Reg*, int, int32, int);
-void addreg(Addr*, int);
-
-/*
- * peep.c
- */
-void peep(void);
-void excise(Reg*);
-Reg* uniqp(Reg*);
-Reg* uniqs(Reg*);
-int regtyp(Addr*);
-int regzer(Addr*);
-int anyvar(Addr*);
-int subprop(Reg*);
-int copyprop(Reg*);
-int copy1(Addr*, Addr*, Reg*, int);
-int copyu(Prog*, Addr*, Addr*);
-
-int copyas(Addr*, Addr*);
-int copyau(Addr*, Addr*);
-int copyau1(Prog*, Addr*);
-int copysub(Addr*, Addr*, Addr*, int);
-int copysub1(Prog*, Addr*, Addr*, int);
-
-int32 RtoB(int);
-int32 FtoB(int);
-int BtoR(int32);
-int BtoF(int32);
-
-/*
- * com64.c
- */
-int com64(Node*);
-void com64init(void);
-void bool64(Node*);
-
-#pragma varargck type "A" int
-#pragma varargck type "B" Bits
-#pragma varargck type "D" Addr*
-#pragma varargck type "N" Addr*
-#pragma varargck type "P" Prog*
-#pragma varargck type "S" char*
diff --git a/src/cmd/9c/list.c b/src/cmd/9c/list.c
deleted file mode 100644
index 5cfc442cb..000000000
--- a/src/cmd/9c/list.c
+++ /dev/null
@@ -1,37 +0,0 @@
-// cmd/9c/list.c from Vita Nuova.
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2008 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-// Revisions Copyright © 2000-2008 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-#define EXTERN
-#include "gc.h"
-
-void
-listinit(void)
-{
- listinit9();
-}
diff --git a/src/cmd/9c/machcap.c b/src/cmd/9c/machcap.c
deleted file mode 100644
index af44bc820..000000000
--- a/src/cmd/9c/machcap.c
+++ /dev/null
@@ -1,105 +0,0 @@
-// cmd/9c/machcap.c from Vita Nuova.
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2008 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-// Revisions Copyright © 2000-2008 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-#include "gc.h"
-
-int
-machcap(Node *n)
-{
-
- if(n == Z)
- return 1; /* test */
-
- switch(n->op) {
- case OMUL:
- case OLMUL:
- case OASMUL:
- case OASLMUL:
- if(typechlv[n->type->etype])
- return 1;
- break;
-
- case OADD:
- case OAND:
- case OOR:
- case OSUB:
- case OXOR:
- case OASHL:
- case OLSHR:
- case OASHR:
- if(typechlv[n->left->type->etype])
- return 1;
- break;
-
- case OCAST:
- return 1;
-
- case OCOND:
- case OCOMMA:
- case OLIST:
- case OANDAND:
- case OOROR:
- case ONOT:
- return 1;
-
- case OASADD:
- case OASSUB:
- case OASAND:
- case OASOR:
- case OASXOR:
- return 1;
-
- case OASASHL:
- case OASASHR:
- case OASLSHR:
- return 1;
-
- case OPOSTINC:
- case OPOSTDEC:
- case OPREINC:
- case OPREDEC:
- return 1;
-
- case OEQ:
- case ONE:
- case OLE:
- case OGT:
- case OLT:
- case OGE:
- case OHI:
- case OHS:
- case OLO:
- case OLS:
- return 1;
- case ONEG:
- case OCOM:
- break;
- }
- return 0;
-}
diff --git a/src/cmd/9c/mul.c b/src/cmd/9c/mul.c
deleted file mode 100644
index 353376f15..000000000
--- a/src/cmd/9c/mul.c
+++ /dev/null
@@ -1,638 +0,0 @@
-// cmd/9c/mul.c from Vita Nuova.
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2008 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-// Revisions Copyright © 2000-2008 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-#include "gc.h"
-
-/*
- * code sequences for multiply by constant.
- * [a-l][0-3]
- * lsl $(A-'a'),r0,r1
- * [+][0-7]
- * add r0,r1,r2
- * [-][0-7]
- * sub r0,r1,r2
- */
-
-static int multabp;
-static int32 mulval;
-static char* mulcp;
-static int32 valmax;
-static int shmax;
-
-static int docode(char *hp, char *cp, int r0, int r1);
-static int gen1(int len);
-static int gen2(int len, int32 r1);
-static int gen3(int len, int32 r0, int32 r1, int flag);
-enum
-{
- SR1 = 1<<0, /* r1 has been shifted */
- SR0 = 1<<1, /* r0 has been shifted */
- UR1 = 1<<2, /* r1 has not been used */
- UR0 = 1<<3, /* r0 has not been used */
-};
-
-Multab*
-mulcon0(Node *n, int32 v)
-{
- int a1, a2, g;
- Multab *m, *m1;
- char hint[10];
-
- if(v < 0)
- v = -v;
-
- /*
- * look in cache
- */
- m = multab;
- for(g=0; g<nelem(multab); g++) {
- if(m->val == v) {
- if(m->code[0] == 0)
- return 0;
- return m;
- }
- m++;
- }
-
- /*
- * select a spot in cache to overwrite
- */
- multabp++;
- if(multabp < 0 || multabp >= nelem(multab))
- multabp = 0;
- m = multab+multabp;
- m->val = v;
- mulval = v;
-
- /*
- * look in execption hint table
- */
- a1 = 0;
- a2 = hintabsize;
- for(;;) {
- if(a1 >= a2)
- goto no;
- g = (a2 + a1)/2;
- if(v < hintab[g].val) {
- a2 = g;
- continue;
- }
- if(v > hintab[g].val) {
- a1 = g+1;
- continue;
- }
- break;
- }
-
- if(docode(hintab[g].hint, m->code, 1, 0))
- return m;
- print("%L: multiply table failure %ld\n", n->lineno, v);
- m->code[0] = 0;
- return 0;
-
-no:
- /*
- * try to search
- */
- hint[0] = 0;
- for(g=1; g<=6; g++) {
- if(g >= 6 && v >= 65535)
- break;
- mulcp = hint+g;
- *mulcp = 0;
- if(gen1(g)) {
- if(docode(hint, m->code, 1, 0))
- return m;
- print("%L: multiply table failure (g=%d h=%s) %ld\n",
- n->lineno, g, hint, v);
- break;
- }
- }
-
- /*
- * try a recur followed by a shift
- */
- g = 0;
- while(!(v & 1)) {
- g++;
- v >>= 1;
- }
- if(g) {
- m1 = mulcon0(n, v);
- if(m1) {
- strcpy(m->code, m1->code);
- sprint(strchr(m->code, 0), "%c0", g+'a');
- return m;
- }
- }
- m->code[0] = 0;
- return 0;
-}
-
-static int
-docode(char *hp, char *cp, int r0, int r1)
-{
- int c, i;
-
- c = *hp++;
- *cp = c;
- cp += 2;
- switch(c) {
- default:
- c -= 'a';
- if(c < 1 || c >= 30)
- break;
- for(i=0; i<4; i++) {
- switch(i) {
- case 0:
- if(docode(hp, cp, r0<<c, r1))
- goto out;
- break;
- case 1:
- if(docode(hp, cp, r1<<c, r1))
- goto out;
- break;
- case 2:
- if(docode(hp, cp, r0, r0<<c))
- goto out;
- break;
- case 3:
- if(docode(hp, cp, r0, r1<<c))
- goto out;
- break;
- }
- }
- break;
-
- case '+':
- for(i=0; i<8; i++) {
- cp[-1] = i+'0';
- switch(i) {
- case 1:
- if(docode(hp, cp, r0+r1, r1))
- goto out;
- break;
- case 5:
- if(docode(hp, cp, r0, r0+r1))
- goto out;
- break;
- }
- }
- break;
-
- case '-':
- for(i=0; i<8; i++) {
- cp[-1] = i+'0';
- switch(i) {
- case 1:
- if(docode(hp, cp, r0-r1, r1))
- goto out;
- break;
- case 2:
- if(docode(hp, cp, r1-r0, r1))
- goto out;
- break;
- case 5:
- if(docode(hp, cp, r0, r0-r1))
- goto out;
- break;
- case 6:
- if(docode(hp, cp, r0, r1-r0))
- goto out;
- break;
- }
- }
- break;
-
- case 0:
- if(r0 == mulval)
- return 1;
- }
- return 0;
-
-out:
- cp[-1] = i+'0';
- return 1;
-}
-
-static int
-gen1(int len)
-{
- int i;
-
- for(shmax=1; shmax<30; shmax++) {
- valmax = 1<<shmax;
- if(valmax >= mulval)
- break;
- }
- if(mulval == 1)
- return 1;
-
- len--;
- for(i=1; i<=shmax; i++)
- if(gen2(len, 1<<i)) {
- *--mulcp = 'a'+i;
- return 1;
- }
- return 0;
-}
-
-static int
-gen2(int len, int32 r1)
-{
- int i;
-
- if(len <= 0) {
- if(r1 == mulval)
- return 1;
- return 0;
- }
-
- len--;
- if(len == 0)
- goto calcr0;
-
- if(gen3(len, r1, r1+1, UR1)) {
- i = '+';
- goto out;
- }
- if(gen3(len, r1-1, r1, UR0)) {
- i = '-';
- goto out;
- }
- if(gen3(len, 1, r1+1, UR1)) {
- i = '+';
- goto out;
- }
- if(gen3(len, 1, r1-1, UR1)) {
- i = '-';
- goto out;
- }
-
- return 0;
-
-calcr0:
- if(mulval == r1+1) {
- i = '+';
- goto out;
- }
- if(mulval == r1-1) {
- i = '-';
- goto out;
- }
- return 0;
-
-out:
- *--mulcp = i;
- return 1;
-}
-
-static int
-gen3(int len, int32 r0, int32 r1, int flag)
-{
- int i, f1, f2;
- int32 x;
-
- if(r0 <= 0 ||
- r0 >= r1 ||
- r1 > valmax)
- return 0;
-
- len--;
- if(len == 0)
- goto calcr0;
-
- if(!(flag & UR1)) {
- f1 = UR1|SR1;
- for(i=1; i<=shmax; i++) {
- x = r0<<i;
- if(x > valmax)
- break;
- if(gen3(len, r0, x, f1)) {
- i += 'a';
- goto out;
- }
- }
- }
-
- if(!(flag & UR0)) {
- f1 = UR1|SR1;
- for(i=1; i<=shmax; i++) {
- x = r1<<i;
- if(x > valmax)
- break;
- if(gen3(len, r1, x, f1)) {
- i += 'a';
- goto out;
- }
- }
- }
-
- if(!(flag & SR1)) {
- f1 = UR1|SR1|(flag&UR0);
- for(i=1; i<=shmax; i++) {
- x = r1<<i;
- if(x > valmax)
- break;
- if(gen3(len, r0, x, f1)) {
- i += 'a';
- goto out;
- }
- }
- }
-
- if(!(flag & SR0)) {
- f1 = UR0|SR0|(flag&(SR1|UR1));
-
- f2 = UR1|SR1;
- if(flag & UR1)
- f2 |= UR0;
- if(flag & SR1)
- f2 |= SR0;
-
- for(i=1; i<=shmax; i++) {
- x = r0<<i;
- if(x > valmax)
- break;
- if(x > r1) {
- if(gen3(len, r1, x, f2)) {
- i += 'a';
- goto out;
- }
- } else
- if(gen3(len, x, r1, f1)) {
- i += 'a';
- goto out;
- }
- }
- }
-
- x = r1+r0;
- if(gen3(len, r0, x, UR1)) {
- i = '+';
- goto out;
- }
-
- if(gen3(len, r1, x, UR1)) {
- i = '+';
- goto out;
- }
-
- x = r1-r0;
- if(gen3(len, x, r1, UR0)) {
- i = '-';
- goto out;
- }
-
- if(x > r0) {
- if(gen3(len, r0, x, UR1)) {
- i = '-';
- goto out;
- }
- } else
- if(gen3(len, x, r0, UR0)) {
- i = '-';
- goto out;
- }
-
- return 0;
-
-calcr0:
- f1 = flag & (UR0|UR1);
- if(f1 == UR1) {
- for(i=1; i<=shmax; i++) {
- x = r1<<i;
- if(x >= mulval) {
- if(x == mulval) {
- i += 'a';
- goto out;
- }
- break;
- }
- }
- }
-
- if(mulval == r1+r0) {
- i = '+';
- goto out;
- }
- if(mulval == r1-r0) {
- i = '-';
- goto out;
- }
-
- return 0;
-
-out:
- *--mulcp = i;
- return 1;
-}
-
-/*
- * hint table has numbers that
- * the search algorithm fails on.
- * <1000:
- * all numbers
- * <5000:
- * ÷ by 5
- * <10000:
- * ÷ by 50
- * <65536:
- * ÷ by 250
- */
-Hintab hintab[] =
-{
- 683, "b++d+e+",
- 687, "b+e++e-",
- 691, "b++d+e+",
- 731, "b++d+e+",
- 811, "b++d+i+",
- 821, "b++e+e+",
- 843, "b+d++e+",
- 851, "b+f-+e-",
- 853, "b++e+e+",
- 877, "c++++g-",
- 933, "b+c++g-",
- 981, "c-+e-d+",
- 1375, "b+c+b+h-",
- 1675, "d+b++h+",
- 2425, "c++f-e+",
- 2675, "c+d++f-",
- 2750, "b+d-b+h-",
- 2775, "c-+g-e-",
- 3125, "b++e+g+",
- 3275, "b+c+g+e+",
- 3350, "c++++i+",
- 3475, "c-+e-f-",
- 3525, "c-+d+g-",
- 3625, "c-+e-j+",
- 3675, "b+d+d+e+",
- 3725, "b+d-+h+",
- 3925, "b+d+f-d-",
- 4275, "b+g++e+",
- 4325, "b+h-+d+",
- 4425, "b+b+g-j-",
- 4525, "b+d-d+f+",
- 4675, "c++d-g+",
- 4775, "b+d+b+g-",
- 4825, "c+c-+i-",
- 4850, "c++++i-",
- 4925, "b++e-g-",
- 4975, "c+f++e-",
- 5500, "b+g-c+d+",
- 6700, "d+b++i+",
- 9700, "d++++j-",
- 11000, "b+f-c-h-",
- 11750, "b+d+g+j-",
- 12500, "b+c+e-k+",
- 13250, "b+d+e-f+",
- 13750, "b+h-c-d+",
- 14250, "b+g-c+e-",
- 14500, "c+f+j-d-",
- 14750, "d-g--f+",
- 16750, "b+e-d-n+",
- 17750, "c+h-b+e+",
- 18250, "d+b+h-d+",
- 18750, "b+g-++f+",
- 19250, "b+e+b+h+",
- 19750, "b++h--f-",
- 20250, "b+e-l-c+",
- 20750, "c++bi+e-",
- 21250, "b+i+l+c+",
- 22000, "b+e+d-g-",
- 22250, "b+d-h+k-",
- 22750, "b+d-e-g+",
- 23250, "b+c+h+e-",
- 23500, "b+g-c-g-",
- 23750, "b+g-b+h-",
- 24250, "c++g+m-",
- 24750, "b+e+e+j-",
- 25000, "b++dh+g+",
- 25250, "b+e+d-g-",
- 25750, "b+e+b+j+",
- 26250, "b+h+c+e+",
- 26500, "b+h+c+g+",
- 26750, "b+d+e+g-",
- 27250, "b+e+e+f+",
- 27500, "c-i-c-d+",
- 27750, "b+bd++j+",
- 28250, "d-d-++i-",
- 28500, "c+c-h-e-",
- 29000, "b+g-d-f+",
- 29500, "c+h+++e-",
- 29750, "b+g+f-c+",
- 30250, "b+f-g-c+",
- 33500, "c-f-d-n+",
- 33750, "b+d-b+j-",
- 34250, "c+e+++i+",
- 35250, "e+b+d+k+",
- 35500, "c+e+d-g-",
- 35750, "c+i-++e+",
- 36250, "b+bh-d+e+",
- 36500, "c+c-h-e-",
- 36750, "d+e--i+",
- 37250, "b+g+g+b+",
- 37500, "b+h-b+f+",
- 37750, "c+be++j-",
- 38500, "b+e+b+i+",
- 38750, "d+i-b+d+",
- 39250, "b+g-l-+d+",
- 39500, "b+g-c+g-",
- 39750, "b+bh-c+f-",
- 40250, "b+bf+d+g-",
- 40500, "b+g-c+g+",
- 40750, "c+b+i-e+",
- 41250, "d++bf+h+",
- 41500, "b+j+c+d-",
- 41750, "c+f+b+h-",
- 42500, "c+h++g+",
- 42750, "b+g+d-f-",
- 43250, "b+l-e+d-",
- 43750, "c+bd+h+f-",
- 44000, "b+f+g-d-",
- 44250, "b+d-g--f+",
- 44500, "c+e+c+h+",
- 44750, "b+e+d-h-",
- 45250, "b++g+j-g+",
- 45500, "c+d+e-g+",
- 45750, "b+d-h-e-",
- 46250, "c+bd++j+",
- 46500, "b+d-c-j-",
- 46750, "e-e-b+g-",
- 47000, "b+c+d-j-",
- 47250, "b+e+e-g-",
- 47500, "b+g-c-h-",
- 47750, "b+f-c+h-",
- 48250, "d--h+n-",
- 48500, "b+c-g+m-",
- 48750, "b+e+e-g+",
- 49500, "c-f+e+j-",
- 49750, "c+c+g++f-",
- 50000, "b+e+e+k+",
- 50250, "b++i++g+",
- 50500, "c+g+f-i+",
- 50750, "b+e+d+k-",
- 51500, "b+i+c-f+",
- 51750, "b+bd+g-e-",
- 52250, "b+d+g-j+",
- 52500, "c+c+f+g+",
- 52750, "b+c+e+i+",
- 53000, "b+i+c+g+",
- 53500, "c+g+g-n+",
- 53750, "b+j+d-c+",
- 54250, "b+d-g-j-",
- 54500, "c-f+e+f+",
- 54750, "b+f-+c+g+",
- 55000, "b+g-d-g-",
- 55250, "b+e+e+g+",
- 55500, "b+cd++j+",
- 55750, "b+bh-d-f-",
- 56250, "c+d-b+j-",
- 56500, "c+d+c+i+",
- 56750, "b+e+d++h-",
- 57000, "b+d+g-f+",
- 57250, "b+f-m+d-",
- 57750, "b+i+c+e-",
- 58000, "b+e+d+h+",
- 58250, "c+b+g+g+",
- 58750, "d-e-j--e+",
- 59000, "d-i-+e+",
- 59250, "e--h-m+",
- 59500, "c+c-h+f-",
- 59750, "b+bh-e+i-",
- 60250, "b+bh-e-e-",
- 60500, "c+c-g-g-",
- 60750, "b+e-l-e-",
- 61250, "b+g-g-c+",
- 61750, "b+g-c+g+",
- 62250, "f--+c-i-",
- 62750, "e+f--+g+",
- 64750, "b+f+d+p-",
-};
-int hintabsize = nelem(hintab);
diff --git a/src/cmd/9c/peep.c b/src/cmd/9c/peep.c
deleted file mode 100644
index 2e8e2adcc..000000000
--- a/src/cmd/9c/peep.c
+++ /dev/null
@@ -1,1076 +0,0 @@
-// cmd/9c/peep.c from Vita Nuova.
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2008 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-// Revisions Copyright © 2000-2008 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-#include "gc.h"
-
-/*
-static Reg*
-rnops(Reg *r)
-{
- Prog *p;
- Reg *r1;
-
- if(r != R)
- for(;;){
- p = r->prog;
- if(p->as != ANOP || p->from.type != D_NONE || p->to.type != D_NONE)
- break;
- r1 = uniqs(r);
- if(r1 == R)
- break;
- r = r1;
- }
- return r;
-}
-*/
-
-void
-peep(void)
-{
- Reg *r, *r1, *r2;
- Prog *p, *p1;
- int t;
-/*
- * complete R structure
- */
- t = 0;
- for(r=firstr; r!=R; r=r1) {
- r1 = r->link;
- if(r1 == R)
- break;
- p = r->prog->link;
- while(p != r1->prog)
- switch(p->as) {
- default:
- r2 = rega();
- r->link = r2;
- r2->link = r1;
-
- r2->prog = p;
- r2->p1 = r;
- r->s1 = r2;
- r2->s1 = r1;
- r1->p1 = r2;
-
- r = r2;
- t++;
-
- case ADATA:
- case AGLOBL:
- case ANAME:
- case ASIGNAME:
- p = p->link;
- }
- }
-
-loop1:
- t = 0;
- for(r=firstr; r!=R; r=r->link) {
- p = r->prog;
- if(p->as == AMOVW || p->as == AMOVD || p->as == AFMOVS || p->as == AFMOVD)
- if(regtyp(&p->to)) {
- if(regtyp(&p->from))
- if(p->from.type == p->to.type) {
- if(copyprop(r)) {
- excise(r);
- t++;
- } else
- if(subprop(r) && copyprop(r)) {
- excise(r);
- t++;
- }
- }
- if(regzer(&p->from))
- if(p->to.type == D_REG) {
- p->from.type = D_REG;
- p->from.reg = REGZERO;
- if(copyprop(r)) {
- excise(r);
- t++;
- } else
- if(subprop(r) && copyprop(r)) {
- excise(r);
- t++;
- }
- }
- }
- }
- if(t)
- goto loop1;
- /*
- * look for MOVB x,R; MOVB R,R
- */
- for(r=firstr; r!=R; r=r->link) {
- p = r->prog;
- switch(p->as) {
- default:
- continue;
- case AMOVH:
- case AMOVHZ:
- case AMOVB:
- case AMOVBZ:
- case AMOVW:
- case AMOVWZ:
- if(p->to.type != D_REG)
- continue;
- break;
- }
- r1 = r->link;
- if(r1 == R)
- continue;
- p1 = r1->prog;
- if(p1->as != p->as)
- continue;
- if(p1->from.type != D_REG || p1->from.reg != p->to.reg)
- continue;
- if(p1->to.type != D_REG || p1->to.reg != p->to.reg)
- continue;
- excise(r1);
- }
-
- if(debug['D'] > 1)
- return; /* allow following code improvement to be suppressed */
-
- /*
- * look for OP x,y,R; CMP R, $0 -> OPCC x,y,R
- * when OP can set condition codes correctly
- */
- for(r=firstr; r!=R; r=r->link) {
- p = r->prog;
- switch(p->as) {
- case ACMP:
- case ACMPW: /* always safe? */
- if(!regzer(&p->to))
- continue;
- r1 = r->s1;
- if(r1 == R)
- continue;
- switch(r1->prog->as) {
- default:
- continue;
- case ABCL:
- case ABC:
- /* the conditions can be complex and these are currently little used */
- continue;
- case ABEQ:
- case ABGE:
- case ABGT:
- case ABLE:
- case ABLT:
- case ABNE:
- case ABVC:
- case ABVS:
- break;
- }
- r1 = r;
- do
- r1 = uniqp(r1);
- while (r1 != R && r1->prog->as == ANOP);
- if(r1 == R)
- continue;
- p1 = r1->prog;
- if(p1->to.type != D_REG || p1->to.reg != p->from.reg)
- continue;
- switch(p1->as) {
- case ASUB:
- case AADD:
- case AXOR:
- case AOR:
- /* irregular instructions */
- if(p1->from.type == D_CONST)
- continue;
- break;
- }
- switch(p1->as) {
- default:
- continue;
- case AMOVW:
- case AMOVD:
- if(p1->from.type != D_REG)
- continue;
- continue;
- case AANDCC:
- case AANDNCC:
- case AORCC:
- case AORNCC:
- case AXORCC:
- case ASUBCC:
- case ASUBECC:
- case ASUBMECC:
- case ASUBZECC:
- case AADDCC:
- case AADDCCC:
- case AADDECC:
- case AADDMECC:
- case AADDZECC:
- case ARLWMICC:
- case ARLWNMCC:
- t = p1->as;
- break;
- /* don't deal with floating point instructions for now */
-/*
- case AFABS: t = AFABSCC; break;
- case AFADD: t = AFADDCC; break;
- case AFADDS: t = AFADDSCC; break;
- case AFCTIW: t = AFCTIWCC; break;
- case AFCTIWZ: t = AFCTIWZCC; break;
- case AFDIV: t = AFDIVCC; break;
- case AFDIVS: t = AFDIVSCC; break;
- case AFMADD: t = AFMADDCC; break;
- case AFMADDS: t = AFMADDSCC; break;
- case AFMOVD: t = AFMOVDCC; break;
- case AFMSUB: t = AFMSUBCC; break;
- case AFMSUBS: t = AFMSUBSCC; break;
- case AFMUL: t = AFMULCC; break;
- case AFMULS: t = AFMULSCC; break;
- case AFNABS: t = AFNABSCC; break;
- case AFNEG: t = AFNEGCC; break;
- case AFNMADD: t = AFNMADDCC; break;
- case AFNMADDS: t = AFNMADDSCC; break;
- case AFNMSUB: t = AFNMSUBCC; break;
- case AFNMSUBS: t = AFNMSUBSCC; break;
- case AFRSP: t = AFRSPCC; break;
- case AFSUB: t = AFSUBCC; break;
- case AFSUBS: t = AFSUBSCC; break;
- case ACNTLZW: t = ACNTLZWCC; break;
- case AMTFSB0: t = AMTFSB0CC; break;
- case AMTFSB1: t = AMTFSB1CC; break;
-*/
- case AADD: t = AADDCC; break;
- case AADDV: t = AADDVCC; break;
- case AADDC: t = AADDCCC; break;
- case AADDCV: t = AADDCVCC; break;
- case AADDME: t = AADDMECC; break;
- case AADDMEV: t = AADDMEVCC; break;
- case AADDE: t = AADDECC; break;
- case AADDEV: t = AADDEVCC; break;
- case AADDZE: t = AADDZECC; break;
- case AADDZEV: t = AADDZEVCC; break;
- case AAND: t = AANDCC; break;
- case AANDN: t = AANDNCC; break;
- case ADIVW: t = ADIVWCC; break;
- case ADIVWV: t = ADIVWVCC; break;
- case ADIVWU: t = ADIVWUCC; break;
- case ADIVWUV: t = ADIVWUVCC; break;
- case ADIVD: t = ADIVDCC; break;
- case ADIVDV: t = ADIVDVCC; break;
- case ADIVDU: t = ADIVDUCC; break;
- case ADIVDUV: t = ADIVDUVCC; break;
- case AEQV: t = AEQVCC; break;
- case AEXTSB: t = AEXTSBCC; break;
- case AEXTSH: t = AEXTSHCC; break;
- case AEXTSW: t = AEXTSWCC; break;
- case AMULHW: t = AMULHWCC; break;
- case AMULHWU: t = AMULHWUCC; break;
- case AMULLW: t = AMULLWCC; break;
- case AMULLWV: t = AMULLWVCC; break;
- case AMULHD: t = AMULHDCC; break;
- case AMULHDU: t = AMULHDUCC; break;
- case AMULLD: t = AMULLDCC; break;
- case AMULLDV: t = AMULLDVCC; break;
- case ANAND: t = ANANDCC; break;
- case ANEG: t = ANEGCC; break;
- case ANEGV: t = ANEGVCC; break;
- case ANOR: t = ANORCC; break;
- case AOR: t = AORCC; break;
- case AORN: t = AORNCC; break;
- case AREM: t = AREMCC; break;
- case AREMV: t = AREMVCC; break;
- case AREMU: t = AREMUCC; break;
- case AREMUV: t = AREMUVCC; break;
- case AREMD: t = AREMDCC; break;
- case AREMDV: t = AREMDVCC; break;
- case AREMDU: t = AREMDUCC; break;
- case AREMDUV: t = AREMDUVCC; break;
- case ARLWMI: t = ARLWMICC; break;
- case ARLWNM: t = ARLWNMCC; break;
- case ASLW: t = ASLWCC; break;
- case ASRAW: t = ASRAWCC; break;
- case ASRW: t = ASRWCC; break;
- case ASLD: t = ASLDCC; break;
- case ASRAD: t = ASRADCC; break;
- case ASRD: t = ASRDCC; break;
- case ASUB: t = ASUBCC; break;
- case ASUBV: t = ASUBVCC; break;
- case ASUBC: t = ASUBCCC; break;
- case ASUBCV: t = ASUBCVCC; break;
- case ASUBME: t = ASUBMECC; break;
- case ASUBMEV: t = ASUBMEVCC; break;
- case ASUBE: t = ASUBECC; break;
- case ASUBEV: t = ASUBEVCC; break;
- case ASUBZE: t = ASUBZECC; break;
- case ASUBZEV: t = ASUBZEVCC; break;
- case AXOR: t = AXORCC; break;
- break;
- }
- if(debug['D'])
- print("cmp %P; %P -> ", p1, p);
- p1->as = t;
- if(debug['D'])
- print("%P\n", p1);
- excise(r);
- continue;
- }
- }
-}
-
-void
-excise(Reg *r)
-{
- Prog *p;
-
- p = r->prog;
- p->as = ANOP;
- p->from = zprog.from;
- p->from3 = zprog.from3;
- p->to = zprog.to;
- p->reg = zprog.reg; /**/
-}
-
-Reg*
-uniqp(Reg *r)
-{
- Reg *r1;
-
- r1 = r->p1;
- if(r1 == R) {
- r1 = r->p2;
- if(r1 == R || r1->p2link != R)
- return R;
- } else
- if(r->p2 != R)
- return R;
- return r1;
-}
-
-Reg*
-uniqs(Reg *r)
-{
- Reg *r1;
-
- r1 = r->s1;
- if(r1 == R) {
- r1 = r->s2;
- if(r1 == R)
- return R;
- } else
- if(r->s2 != R)
- return R;
- return r1;
-}
-
-/*
- * if the system forces R0 to be zero,
- * convert references to $0 to references to R0.
- */
-int
-regzer(Addr *a)
-{
- if(R0ISZERO) {
- if(a->type == D_CONST)
- if(a->sym == nil)
- if(a->offset == 0)
- return 1;
- if(a->type == D_REG)
- if(a->reg == REGZERO)
- return 1;
- }
- return 0;
-}
-
-int
-regtyp(Addr *a)
-{
-
- if(a->type == D_REG) {
- if(!R0ISZERO || a->reg != REGZERO)
- return 1;
- return 0;
- }
- if(a->type == D_FREG)
- return 1;
- return 0;
-}
-
-/*
- * the idea is to substitute
- * one register for another
- * from one MOV to another
- * MOV a, R0
- * ADD b, R0 / no use of R1
- * MOV R0, R1
- * would be converted to
- * MOV a, R1
- * ADD b, R1
- * MOV R1, R0
- * hopefully, then the former or latter MOV
- * will be eliminated by copy propagation.
- */
-int
-subprop(Reg *r0)
-{
- Prog *p;
- Addr *v1, *v2;
- Reg *r;
- int t;
-
- p = r0->prog;
- v1 = &p->from;
- if(!regtyp(v1))
- return 0;
- v2 = &p->to;
- if(!regtyp(v2))
- return 0;
- for(r=uniqp(r0); r!=R; r=uniqp(r)) {
- if(uniqs(r) == R)
- break;
- p = r->prog;
- switch(p->as) {
- case ABL:
- return 0;
-
- case AADD:
- case AADDC:
- case AADDCC:
- case AADDE:
- case AADDECC:
- case ASUB:
- case ASUBCC:
- case ASUBC:
- case ASUBCCC:
- case ASUBE:
- case ASUBECC:
- case ASLW:
- case ASRW:
- case ASRWCC:
- case ASRAW:
- case ASRAWCC:
- case ASLD:
- case ASRD:
- case ASRAD:
- case AOR:
- case AORCC:
- case AORN:
- case AORNCC:
- case AAND:
- case AANDCC:
- case AANDN:
- case AANDNCC:
- case ANAND:
- case ANANDCC:
- case ANOR:
- case ANORCC:
- case AXOR:
- case AXORCC:
- case AMULHW:
- case AMULHWU:
- case AMULLW:
- case AMULLD:
- case ADIVW:
- case ADIVWU:
- case ADIVD:
- case ADIVDU:
- case AREM:
- case AREMU:
- case AREMD:
- case AREMDU:
- case ARLWNM:
- case ARLWNMCC:
-
- case AFADD:
- case AFADDS:
- case AFSUB:
- case AFSUBS:
- case AFMUL:
- case AFMULS:
- case AFDIV:
- case AFDIVS:
- if(p->to.type == v1->type)
- if(p->to.reg == v1->reg) {
- if(p->reg == NREG)
- p->reg = p->to.reg;
- goto gotit;
- }
- break;
-
- case AADDME:
- case AADDMECC:
- case AADDZE:
- case AADDZECC:
- case ASUBME:
- case ASUBMECC:
- case ASUBZE:
- case ASUBZECC:
- case ANEG:
- case ANEGCC:
- case AFNEG:
- case AFNEGCC:
- case AFMOVS:
- case AFMOVD:
- case AMOVW:
- case AMOVD:
- if(p->to.type == v1->type)
- if(p->to.reg == v1->reg)
- goto gotit;
- break;
- }
- if(copyau(&p->from, v2) ||
- copyau1(p, v2) ||
- copyau(&p->to, v2))
- break;
- if(copysub(&p->from, v1, v2, 0) ||
- copysub1(p, v1, v2, 0) ||
- copysub(&p->to, v1, v2, 0))
- break;
- }
- return 0;
-
-gotit:
- copysub(&p->to, v1, v2, 1);
- if(debug['P']) {
- print("gotit: %D->%D\n%P", v1, v2, r->prog);
- if(p->from.type == v2->type)
- print(" excise");
- print("\n");
- }
- for(r=uniqs(r); r!=r0; r=uniqs(r)) {
- p = r->prog;
- copysub(&p->from, v1, v2, 1);
- copysub1(p, v1, v2, 1);
- copysub(&p->to, v1, v2, 1);
- if(debug['P'])
- print("%P\n", r->prog);
- }
- t = v1->reg;
- v1->reg = v2->reg;
- v2->reg = t;
- if(debug['P'])
- print("%P last\n", r->prog);
- return 1;
-}
-
-/*
- * The idea is to remove redundant copies.
- * v1->v2 F=0
- * (use v2 s/v2/v1/)*
- * set v1 F=1
- * use v2 return fail
- * -----------------
- * v1->v2 F=0
- * (use v2 s/v2/v1/)*
- * set v1 F=1
- * set v2 return success
- */
-int
-copyprop(Reg *r0)
-{
- Prog *p;
- Addr *v1, *v2;
- Reg *r;
-
- p = r0->prog;
- v1 = &p->from;
- v2 = &p->to;
- if(copyas(v1, v2))
- return 1;
- for(r=firstr; r!=R; r=r->link)
- r->active = 0;
- return copy1(v1, v2, r0->s1, 0);
-}
-
-int
-copy1(Addr *v1, Addr *v2, Reg *r, int f)
-{
- int t;
- Prog *p;
-
- if(r->active) {
- if(debug['P'])
- print("act set; return 1\n");
- return 1;
- }
- r->active = 1;
- if(debug['P'])
- print("copy %D->%D f=%d\n", v1, v2, f);
- for(; r != R; r = r->s1) {
- p = r->prog;
- if(debug['P'])
- print("%P", p);
- if(!f && uniqp(r) == R) {
- f = 1;
- if(debug['P'])
- print("; merge; f=%d", f);
- }
- t = copyu(p, v2, nil);
- switch(t) {
- case 2: /* rar, cant split */
- if(debug['P'])
- print("; %Drar; return 0\n", v2);
- return 0;
-
- case 3: /* set */
- if(debug['P'])
- print("; %Dset; return 1\n", v2);
- return 1;
-
- case 1: /* used, substitute */
- case 4: /* use and set */
- if(f) {
- if(!debug['P'])
- return 0;
- if(t == 4)
- print("; %Dused+set and f=%d; return 0\n", v2, f);
- else
- print("; %Dused and f=%d; return 0\n", v2, f);
- return 0;
- }
- if(copyu(p, v2, v1)) {
- if(debug['P'])
- print("; sub fail; return 0\n");
- return 0;
- }
- if(debug['P'])
- print("; sub%D/%D", v2, v1);
- if(t == 4) {
- if(debug['P'])
- print("; %Dused+set; return 1\n", v2);
- return 1;
- }
- break;
- }
- if(!f) {
- t = copyu(p, v1, nil);
- if(!f && (t == 2 || t == 3 || t == 4)) {
- f = 1;
- if(debug['P'])
- print("; %Dset and !f; f=%d", v1, f);
- }
- }
- if(debug['P'])
- print("\n");
- if(r->s2)
- if(!copy1(v1, v2, r->s2, f))
- return 0;
- }
- return 1;
-}
-
-/*
- * return
- * 1 if v only used (and substitute),
- * 2 if read-alter-rewrite
- * 3 if set
- * 4 if set and used
- * 0 otherwise (not touched)
- */
-int
-copyu(Prog *p, Addr *v, Addr *s)
-{
-
- switch(p->as) {
-
- default:
- if(debug['P'])
- print(" (\?\?\?)");
- return 2;
-
-
- case ANOP: /* read, write */
- case AMOVH:
- case AMOVHZ:
- case AMOVB:
- case AMOVBZ:
- case AMOVW:
- case AMOVWZ:
- case AMOVD:
-
- case ANEG:
- case ANEGCC:
- case AADDME:
- case AADDMECC:
- case AADDZE:
- case AADDZECC:
- case ASUBME:
- case ASUBMECC:
- case ASUBZE:
- case ASUBZECC:
-
- case AFCTIW:
- case AFCTIWZ:
- case AFMOVS:
- case AFMOVD:
- case AFRSP:
- case AFNEG:
- case AFNEGCC:
- if(s != nil) {
- if(copysub(&p->from, v, s, 1))
- return 1;
- if(!copyas(&p->to, v))
- if(copysub(&p->to, v, s, 1))
- return 1;
- return 0;
- }
- if(copyas(&p->to, v)) {
- if(copyau(&p->from, v))
- return 4;
- return 3;
- }
- if(copyau(&p->from, v))
- return 1;
- if(copyau(&p->to, v))
- return 1;
- return 0;
-
- case ARLWMI: /* read read rar */
- case ARLWMICC:
- if(copyas(&p->to, v))
- return 2;
- /* fall through */
-
- case AADD: /* read read write */
- case AADDC:
- case AADDE:
- case ASUB:
- case ASLW:
- case ASRW:
- case ASRAW:
- case ASLD:
- case ASRD:
- case ASRAD:
- case AOR:
- case AORCC:
- case AORN:
- case AORNCC:
- case AAND:
- case AANDCC:
- case AANDN:
- case AANDNCC:
- case ANAND:
- case ANANDCC:
- case ANOR:
- case ANORCC:
- case AXOR:
- case AMULHW:
- case AMULHWU:
- case AMULLW:
- case AMULLD:
- case ADIVW:
- case ADIVD:
- case ADIVWU:
- case ADIVDU:
- case AREM:
- case AREMU:
- case AREMD:
- case AREMDU:
- case ARLWNM:
- case ARLWNMCC:
-
- case AFADDS:
- case AFADD:
- case AFSUBS:
- case AFSUB:
- case AFMULS:
- case AFMUL:
- case AFDIVS:
- case AFDIV:
- if(s != nil) {
- if(copysub(&p->from, v, s, 1))
- return 1;
- if(copysub1(p, v, s, 1))
- return 1;
- if(!copyas(&p->to, v))
- if(copysub(&p->to, v, s, 1))
- return 1;
- return 0;
- }
- if(copyas(&p->to, v)) {
- if(p->reg == NREG)
- p->reg = p->to.reg;
- if(copyau(&p->from, v))
- return 4;
- if(copyau1(p, v))
- return 4;
- return 3;
- }
- if(copyau(&p->from, v))
- return 1;
- if(copyau1(p, v))
- return 1;
- if(copyau(&p->to, v))
- return 1;
- return 0;
-
- case ABEQ:
- case ABGT:
- case ABGE:
- case ABLT:
- case ABLE:
- case ABNE:
- case ABVC:
- case ABVS:
- break;
-
- case ACMP: /* read read */
- case ACMPU:
- case ACMPW:
- case ACMPWU:
- case AFCMPO:
- case AFCMPU:
- if(s != nil) {
- if(copysub(&p->from, v, s, 1))
- return 1;
- return copysub(&p->to, v, s, 1);
- }
- if(copyau(&p->from, v))
- return 1;
- if(copyau(&p->to, v))
- return 1;
- break;
-
- case ABR: /* funny */
- if(s != nil) {
- if(copysub(&p->to, v, s, 1))
- return 1;
- return 0;
- }
- if(copyau(&p->to, v))
- return 1;
- return 0;
-
- case ARETURN: /* funny */
- if(v->type == D_REG)
- if(v->reg == REGRET)
- return 2;
- if(v->type == D_FREG)
- if(v->reg == FREGRET)
- return 2;
-
- case ABL: /* funny */
- if(v->type == D_REG) {
- if(v->reg <= REGEXT && v->reg > exregoffset)
- return 2;
- if(v->reg == REGARG)
- return 2;
- }
- if(v->type == D_FREG) {
- if(v->reg <= FREGEXT && v->reg > exfregoffset)
- return 2;
- }
-
- if(s != nil) {
- if(copysub(&p->to, v, s, 1))
- return 1;
- return 0;
- }
- if(copyau(&p->to, v))
- return 4;
- return 3;
-
- case ATEXT: /* funny */
- if(v->type == D_REG)
- if(v->reg == REGARG)
- return 3;
- return 0;
- }
- return 0;
-}
-
-int
-a2type(Prog *p)
-{
-
- switch(p->as) {
- case AADD:
- case AADDC:
- case AADDCC:
- case AADDCCC:
- case AADDE:
- case AADDECC:
- case AADDME:
- case AADDMECC:
- case AADDZE:
- case AADDZECC:
- case ASUB:
- case ASUBC:
- case ASUBCC:
- case ASUBCCC:
- case ASUBE:
- case ASUBECC:
- case ASUBME:
- case ASUBMECC:
- case ASUBZE:
- case ASUBZECC:
- case ASLW:
- case ASLWCC:
- case ASRW:
- case ASRWCC:
- case ASRAW:
- case ASRAWCC:
- case ASLD:
- case ASLDCC:
- case ASRD:
- case ASRDCC:
- case ASRAD:
- case ASRADCC:
- case AOR:
- case AORCC:
- case AORN:
- case AORNCC:
- case AAND:
- case AANDCC:
- case AANDN:
- case AANDNCC:
- case AXOR:
- case AXORCC:
- case ANEG:
- case ANEGCC:
- case AMULHW:
- case AMULHWU:
- case AMULLW:
- case AMULLWCC:
- case ADIVW:
- case ADIVWCC:
- case ADIVWU:
- case ADIVWUCC:
- case AREM:
- case AREMCC:
- case AREMU:
- case AREMUCC:
- case AMULLD:
- case AMULLDCC:
- case ADIVD:
- case ADIVDCC:
- case ADIVDU:
- case ADIVDUCC:
- case AREMD:
- case AREMDCC:
- case AREMDU:
- case AREMDUCC:
- case ANAND:
- case ANANDCC:
- case ANOR:
- case ANORCC:
- case ARLWMI:
- case ARLWMICC:
- case ARLWNM:
- case ARLWNMCC:
- return D_REG;
-
- case AFADDS:
- case AFADDSCC:
- case AFADD:
- case AFADDCC:
- case AFSUBS:
- case AFSUBSCC:
- case AFSUB:
- case AFSUBCC:
- case AFMULS:
- case AFMULSCC:
- case AFMUL:
- case AFMULCC:
- case AFDIVS:
- case AFDIVSCC:
- case AFDIV:
- case AFDIVCC:
- case AFNEG:
- case AFNEGCC:
- return D_FREG;
- }
- return D_NONE;
-}
-
-/*
- * direct reference,
- * could be set/use depending on
- * semantics
- */
-int
-copyas(Addr *a, Addr *v)
-{
-
- if(regtyp(v))
- if(a->type == v->type)
- if(a->reg == v->reg)
- return 1;
- return 0;
-}
-
-/*
- * either direct or indirect
- */
-int
-copyau(Addr *a, Addr *v)
-{
-
- if(copyas(a, v))
- return 1;
- if(v->type == D_REG)
- if(a->type == D_OREG)
- if(v->reg == a->reg)
- return 1;
- return 0;
-}
-
-int
-copyau1(Prog *p, Addr *v)
-{
-
- if(regtyp(v))
- if(p->from.type == v->type || p->to.type == v->type)
- if(p->reg == v->reg) {
- if(a2type(p) != v->type)
- print("botch a2type %P\n", p);
- return 1;
- }
- return 0;
-}
-
-/*
- * substitute s for v in a
- * return failure to substitute
- */
-int
-copysub(Addr *a, Addr *v, Addr *s, int f)
-{
-
- if(f)
- if(copyau(a, v))
- a->reg = s->reg;
- return 0;
-}
-
-int
-copysub1(Prog *p1, Addr *v, Addr *s, int f)
-{
-
- if(f)
- if(copyau1(p1, v))
- p1->reg = s->reg;
- return 0;
-}
diff --git a/src/cmd/9c/reg.c b/src/cmd/9c/reg.c
deleted file mode 100644
index 81a7c7fe4..000000000
--- a/src/cmd/9c/reg.c
+++ /dev/null
@@ -1,1163 +0,0 @@
-// cmd/9c/reg.c from Vita Nuova.
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2008 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-// Revisions Copyright © 2000-2008 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-#include "gc.h"
-
-Reg*
-rega(void)
-{
- Reg *r;
-
- r = freer;
- if(r == R) {
- r = alloc(sizeof(*r));
- } else
- freer = r->link;
-
- *r = zreg;
- return r;
-}
-
-int
-rcmp(const void *a1, const void *a2)
-{
- const Rgn *p1, *p2;
- int c1, c2;
-
- p1 = a1;
- p2 = a2;
- c1 = p2->cost;
- c2 = p1->cost;
- if(c1 -= c2)
- return c1;
- return p2->varno - p1->varno;
-}
-
-void
-regopt(Prog *p)
-{
- Reg *r, *r1, *r2;
- Prog *p1;
- int i, z;
- int32 initpc, val, npc;
- uint32 vreg;
- Bits bit;
- struct
- {
- int32 m;
- int32 c;
- Reg* p;
- } log5[6], *lp;
-
- firstr = R;
- lastr = R;
- nvar = 0;
- regbits = 0;
- for(z=0; z<BITS; z++) {
- externs.b[z] = 0;
- params.b[z] = 0;
- consts.b[z] = 0;
- addrs.b[z] = 0;
- }
-
- /*
- * pass 1
- * build aux data structure
- * allocate pcs
- * find use and set of variables
- */
- val = 5L * 5L * 5L * 5L * 5L;
- lp = log5;
- for(i=0; i<5; i++) {
- lp->m = val;
- lp->c = 0;
- lp->p = R;
- val /= 5L;
- lp++;
- }
- val = 0;
- for(; p != P; p = p->link) {
- switch(p->as) {
- case ADATA:
- case AGLOBL:
- case ANAME:
- case ASIGNAME:
- case AFUNCDATA:
- continue;
- }
- r = rega();
- if(firstr == R) {
- firstr = r;
- lastr = r;
- } else {
- lastr->link = r;
- r->p1 = lastr;
- lastr->s1 = r;
- lastr = r;
- }
- r->prog = p;
- r->pc = val;
- val++;
-
- lp = log5;
- for(i=0; i<5; i++) {
- lp->c--;
- if(lp->c <= 0) {
- lp->c = lp->m;
- if(lp->p != R)
- lp->p->log5 = r;
- lp->p = r;
- (lp+1)->c = 0;
- break;
- }
- lp++;
- }
-
- r1 = r->p1;
- if(r1 != R)
- switch(r1->prog->as) {
- case ARETURN:
- case ABR:
- case ARFI:
- case ARFCI:
- case ARFID:
- r->p1 = R;
- r1->s1 = R;
- }
-
- /*
- * left side always read
- */
- bit = mkvar(&p->from, p->as==AMOVW || p->as == AMOVWZ || p->as == AMOVD);
- for(z=0; z<BITS; z++)
- r->use1.b[z] |= bit.b[z];
-
- /*
- * right side depends on opcode
- */
- bit = mkvar(&p->to, 0);
- if(bany(&bit))
- switch(p->as) {
- default:
- diag(Z, "reg: unknown asop: %A", p->as);
- break;
-
- /*
- * right side write
- */
- case ANOP:
- case AMOVB:
- case AMOVBU:
- case AMOVBZ:
- case AMOVBZU:
- case AMOVH:
- case AMOVHBR:
- case AMOVWBR:
- case AMOVHU:
- case AMOVHZ:
- case AMOVHZU:
- case AMOVW:
- case AMOVWU:
- case AMOVWZ:
- case AMOVWZU:
- case AMOVD:
- case AMOVDU:
- case AFMOVD:
- case AFMOVDCC:
- case AFMOVDU:
- case AFMOVS:
- case AFMOVSU:
- case AFRSP:
- for(z=0; z<BITS; z++)
- r->set.b[z] |= bit.b[z];
- break;
-
- /*
- * funny
- */
- case ABL:
- for(z=0; z<BITS; z++)
- addrs.b[z] |= bit.b[z];
- break;
- }
- }
- if(firstr == R)
- return;
- initpc = pc - val;
- npc = val;
-
- /*
- * pass 2
- * turn branch references to pointers
- * build back pointers
- */
- for(r = firstr; r != R; r = r->link) {
- p = r->prog;
- if(p->to.type == D_BRANCH) {
- val = p->to.offset - initpc;
- r1 = firstr;
- while(r1 != R) {
- r2 = r1->log5;
- if(r2 != R && val >= r2->pc) {
- r1 = r2;
- continue;
- }
- if(r1->pc == val)
- break;
- r1 = r1->link;
- }
- if(r1 == R) {
- nearln = p->lineno;
- diag(Z, "ref not found\n%P", p);
- continue;
- }
- if(r1 == r) {
- nearln = p->lineno;
- diag(Z, "ref to self\n%P", p);
- continue;
- }
- r->s2 = r1;
- r->p2link = r1->p2;
- r1->p2 = r;
- }
- }
- if(debug['R']) {
- p = firstr->prog;
- print("\n%L %D\n", p->lineno, &p->from);
- }
-
- /*
- * pass 2.5
- * find looping structure
- */
- for(r = firstr; r != R; r = r->link)
- r->active = 0;
- change = 0;
- loopit(firstr, npc);
- if(debug['R'] && debug['v']) {
- print("\nlooping structure:\n");
- for(r = firstr; r != R; r = r->link) {
- print("%ld:%P", r->loop, r->prog);
- for(z=0; z<BITS; z++)
- bit.b[z] = r->use1.b[z] |
- r->use2.b[z] | r->set.b[z];
- if(bany(&bit)) {
- print("\t");
- if(bany(&r->use1))
- print(" u1=%B", r->use1);
- if(bany(&r->use2))
- print(" u2=%B", r->use2);
- if(bany(&r->set))
- print(" st=%B", r->set);
- }
- print("\n");
- }
- }
-
- /*
- * pass 3
- * iterate propagating usage
- * back until flow graph is complete
- */
-loop1:
- change = 0;
- for(r = firstr; r != R; r = r->link)
- r->active = 0;
- for(r = firstr; r != R; r = r->link)
- if(r->prog->as == ARETURN)
- prop(r, zbits, zbits);
-loop11:
- /* pick up unreachable code */
- i = 0;
- for(r = firstr; r != R; r = r1) {
- r1 = r->link;
- if(r1 && r1->active && !r->active) {
- prop(r, zbits, zbits);
- i = 1;
- }
- }
- if(i)
- goto loop11;
- if(change)
- goto loop1;
-
-
- /*
- * pass 4
- * iterate propagating register/variable synchrony
- * forward until graph is complete
- */
-loop2:
- change = 0;
- for(r = firstr; r != R; r = r->link)
- r->active = 0;
- synch(firstr, zbits);
- if(change)
- goto loop2;
-
-
- /*
- * pass 5
- * isolate regions
- * calculate costs (paint1)
- */
- r = firstr;
- if(r) {
- 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)) {
- nearln = r->prog->lineno;
- warn(Z, "used and not set: %B", bit);
- if(debug['R'] && !debug['w'])
- print("used and not set: %B\n", bit);
- }
- }
- if(debug['R'] && debug['v'])
- print("\nprop structure:\n");
- for(r = firstr; r != R; r = r->link)
- r->act = zbits;
- rgp = region;
- nregion = 0;
- for(r = firstr; r != R; r = r->link) {
- if(debug['R'] && debug['v'])
- print("%P\n set = %B; rah = %B; cal = %B\n",
- r->prog, r->set, r->refahead, r->calahead);
- for(z=0; z<BITS; z++)
- bit.b[z] = r->set.b[z] &
- ~(r->refahead.b[z] | r->calahead.b[z] | addrs.b[z]);
- if(bany(&bit)) {
- nearln = r->prog->lineno;
- warn(Z, "set and not used: %B", bit);
- if(debug['R'])
- print("set an not used: %B\n", bit);
- excise(r);
- }
- for(z=0; z<BITS; z++)
- bit.b[z] = LOAD(r) & ~(r->act.b[z] | addrs.b[z]);
- while(bany(&bit)) {
- i = bnum(bit);
- rgp->enter = r;
- rgp->varno = i;
- change = 0;
- if(debug['R'] && debug['v'])
- print("\n");
- paint1(r, i);
- bit.b[i/32] &= ~(1L<<(i%32));
- if(change <= 0) {
- if(debug['R'])
- print("%L$%d: %B\n",
- r->prog->lineno, change, blsh(i));
- continue;
- }
- rgp->cost = change;
- nregion++;
- if(nregion >= NRGN)
- fatal(Z, "too many regions");
- rgp++;
- }
- }
- qsort(region, nregion, sizeof(region[0]), rcmp);
-
- /*
- * pass 6
- * determine used registers (paint2)
- * replace code (paint3)
- */
- rgp = region;
- for(i=0; i<nregion; i++) {
- bit = blsh(rgp->varno);
- vreg = paint2(rgp->enter, rgp->varno);
- vreg = allreg(vreg, rgp);
- if(debug['R']) {
- if(rgp->regno >= NREG)
- print("%L$%d F%d: %B\n",
- rgp->enter->prog->lineno,
- rgp->cost,
- rgp->regno-NREG,
- bit);
- else
- print("%L$%d R%d: %B\n",
- rgp->enter->prog->lineno,
- rgp->cost,
- rgp->regno,
- bit);
- }
- if(rgp->regno != 0)
- paint3(rgp->enter, rgp->varno, vreg, rgp->regno);
- rgp++;
- }
- /*
- * pass 7
- * peep-hole on basic block
- */
- if(!debug['R'] || debug['P'])
- peep();
-
- /*
- * pass 8
- * recalculate pc
- */
- val = initpc;
- for(r = firstr; r != R; r = r1) {
- r->pc = val;
- p = r->prog;
- p1 = P;
- r1 = r->link;
- if(r1 != R)
- p1 = r1->prog;
- for(; p != p1; p = p->link) {
- switch(p->as) {
- default:
- val++;
- break;
-
- case ANOP:
- case ADATA:
- case AGLOBL:
- case ANAME:
- case ASIGNAME:
- case AFUNCDATA:
- break;
- }
- }
- }
- pc = val;
-
- /*
- * fix up branches
- */
- if(debug['R'])
- if(bany(&addrs))
- print("addrs: %B\n", addrs);
-
- r1 = 0; /* set */
- for(r = firstr; r != R; r = r->link) {
- p = r->prog;
- if(p->to.type == D_BRANCH) {
- p->to.offset = r->s2->pc;
- p->to.u.branch = r->s2->prog;
- }
- r1 = r;
- }
-
- /*
- * last pass
- * eliminate nops
- * free aux structures
- */
- for(p = firstr->prog; p != P; p = p->link){
- while(p->link && p->link->as == ANOP)
- p->link = p->link->link;
- }
- if(r1 != R) {
- r1->link = freer;
- freer = firstr;
- }
-}
-
-/*
- * add mov b,rn
- * just after r
- */
-void
-addmove(Reg *r, int bn, int rn, int f)
-{
- Prog *p, *p1;
- Addr *a;
- Var *v;
-
- p1 = alloc(sizeof(*p1));
- *p1 = zprog;
- p = r->prog;
-
- p1->link = p->link;
- p->link = p1;
- p1->lineno = p->lineno;
-
- v = var + bn;
-
- a = &p1->to;
- a->sym = v->sym;
- a->name = v->name;
- a->offset = v->offset;
- a->etype = v->etype;
- a->type = D_OREG;
- if(a->etype == TARRAY || a->sym == nil)
- a->type = D_CONST;
-
- p1->as = AMOVW;
- if(v->etype == TCHAR || v->etype == TUCHAR)
- p1->as = AMOVB;
- if(v->etype == TSHORT || v->etype == TUSHORT)
- p1->as = AMOVH;
- if(v->etype == TVLONG || v->etype == TUVLONG || v->etype == TIND)
- p1->as = AMOVD;
- if(v->etype == TFLOAT)
- p1->as = AFMOVS;
- if(v->etype == TDOUBLE)
- p1->as = AFMOVD;
-
- p1->from.type = D_REG;
- p1->from.reg = rn;
- if(rn >= NREG) {
- p1->from.type = D_FREG;
- p1->from.reg = rn-NREG;
- }
- if(!f) {
- p1->from = *a;
- *a = zprog.from;
- a->type = D_REG;
- a->reg = rn;
- if(rn >= NREG) {
- a->type = D_FREG;
- a->reg = rn-NREG;
- }
- if(v->etype == TUCHAR)
- p1->as = AMOVBZ;
- if(v->etype == TUSHORT)
- p1->as = AMOVHZ;
- if(v->etype == TUINT || v->etype == TULONG)
- p1->as = AMOVWZ;
- }
- if(debug['R'])
- print("%P\t.a%P\n", p, p1);
-}
-
-Bits
-mkvar(Addr *a, int docon)
-{
- Var *v;
- int i, t, n, et, z;
- int64 o;
- Bits bit;
- LSym *s;
-
- t = a->type;
- if(t == D_REG && a->reg != NREG)
- regbits |= RtoB(a->reg);
- if(t == D_FREG && a->reg != NREG)
- regbits |= FtoB(a->reg);
- s = a->sym;
- o = a->offset;
- et = a->etype;
- if(s == nil) {
- if(t != D_CONST || !docon || a->reg != NREG)
- goto none;
- et = TLONG;
- }
- if(t == D_CONST) {
- if(s == nil && sval(o))
- goto none;
- }
- n = a->name;
- v = var;
- for(i=0; i<nvar; i++) {
- if(s == v->sym)
- if(n == v->name)
- if(o == v->offset)
- goto out;
- v++;
- }
- if(s)
- if(s->name[0] == '.')
- goto none;
- if(nvar >= NVAR)
- fatal(Z, "variable not optimized: %s", s->name);
- i = nvar;
- nvar++;
- v = &var[i];
- v->sym = s;
- v->offset = o;
- v->etype = et;
- v->name = n;
- if(debug['R'])
- print("bit=%2d et=%2d %D\n", i, et, a);
-out:
- bit = blsh(i);
- if(n == D_EXTERN || n == D_STATIC)
- for(z=0; z<BITS; z++)
- externs.b[z] |= bit.b[z];
- if(n == D_PARAM)
- for(z=0; z<BITS; z++)
- params.b[z] |= bit.b[z];
- if(v->etype != et || !(typechlpfd[et] || typev[et])) /* funny punning */
- for(z=0; z<BITS; z++)
- addrs.b[z] |= bit.b[z];
- if(t == D_CONST) {
- if((int32)o != o)
- v->etype = TVLONG;
- if(s == nil) {
- for(z=0; z<BITS; z++)
- consts.b[z] |= bit.b[z];
- return bit;
- }
- if(et != TARRAY)
- for(z=0; z<BITS; z++)
- addrs.b[z] |= bit.b[z];
- for(z=0; z<BITS; z++)
- params.b[z] |= bit.b[z];
- return bit;
- }
- if(t == D_OREG)
- return bit;
-
-none:
- return zbits;
-}
-
-void
-prop(Reg *r, Bits ref, Bits cal)
-{
- Reg *r1, *r2;
- int z;
-
- for(r1 = r; r1 != R; r1 = r1->p1) {
- for(z=0; z<BITS; z++) {
- ref.b[z] |= r1->refahead.b[z];
- if(ref.b[z] != r1->refahead.b[z]) {
- r1->refahead.b[z] = ref.b[z];
- change++;
- }
- cal.b[z] |= r1->calahead.b[z];
- if(cal.b[z] != r1->calahead.b[z]) {
- r1->calahead.b[z] = cal.b[z];
- change++;
- }
- }
- switch(r1->prog->as) {
- case ABL:
- for(z=0; z<BITS; z++) {
- cal.b[z] |= ref.b[z] | externs.b[z];
- ref.b[z] = 0;
- }
- break;
-
- case ATEXT:
- for(z=0; z<BITS; z++) {
- cal.b[z] = 0;
- ref.b[z] = 0;
- }
- break;
-
- case ARETURN:
- for(z=0; z<BITS; z++) {
- cal.b[z] = externs.b[z];
- ref.b[z] = 0;
- }
- }
- for(z=0; z<BITS; z++) {
- ref.b[z] = (ref.b[z] & ~r1->set.b[z]) |
- r1->use1.b[z] | r1->use2.b[z];
- cal.b[z] &= ~(r1->set.b[z] | r1->use1.b[z] | r1->use2.b[z]);
- r1->refbehind.b[z] = ref.b[z];
- r1->calbehind.b[z] = cal.b[z];
- }
- if(r1->active)
- break;
- r1->active = 1;
- }
- for(; r != r1; r = r->p1)
- for(r2 = r->p2; r2 != R; r2 = r2->p2link)
- prop(r2, r->refbehind, r->calbehind);
-}
-
-/*
- * find looping structure
- *
- * 1) find reverse postordering
- * 2) find approximate dominators,
- * the actual dominators if the flow graph is reducible
- * otherwise, dominators plus some other non-dominators.
- * See Matthew S. Hecht and Jeffrey D. Ullman,
- * "Analysis of a Simple Algorithm for Global Data Flow Problems",
- * Conf. Record of ACM Symp. on Principles of Prog. Langs, Boston, Massachusetts,
- * Oct. 1-3, 1973, pp. 207-217.
- * 3) find all nodes with a predecessor dominated by the current node.
- * such a node is a loop head.
- * recursively, all preds with a greater rpo number are in the loop
- */
-int32
-postorder(Reg *r, Reg **rpo2r, int32 n)
-{
- Reg *r1;
-
- r->rpo = 1;
- r1 = r->s1;
- if(r1 && !r1->rpo)
- n = postorder(r1, rpo2r, n);
- r1 = r->s2;
- if(r1 && !r1->rpo)
- n = postorder(r1, rpo2r, n);
- rpo2r[n] = r;
- n++;
- return n;
-}
-
-int32
-rpolca(int32 *idom, int32 rpo1, int32 rpo2)
-{
- int32 t;
-
- if(rpo1 == -1)
- return rpo2;
- while(rpo1 != rpo2){
- if(rpo1 > rpo2){
- t = rpo2;
- rpo2 = rpo1;
- rpo1 = t;
- }
- while(rpo1 < rpo2){
- t = idom[rpo2];
- if(t >= rpo2)
- fatal(Z, "bad idom");
- rpo2 = t;
- }
- }
- return rpo1;
-}
-
-int
-doms(int32 *idom, int32 r, int32 s)
-{
- while(s > r)
- s = idom[s];
- return s == r;
-}
-
-int
-loophead(int32 *idom, Reg *r)
-{
- int32 src;
-
- src = r->rpo;
- if(r->p1 != R && doms(idom, src, r->p1->rpo))
- return 1;
- for(r = r->p2; r != R; r = r->p2link)
- if(doms(idom, src, r->rpo))
- return 1;
- return 0;
-}
-
-void
-loopmark(Reg **rpo2r, int32 head, Reg *r)
-{
- if(r->rpo < head || r->active == head)
- return;
- r->active = head;
- r->loop += LOOP;
- if(r->p1 != R)
- loopmark(rpo2r, head, r->p1);
- for(r = r->p2; r != R; r = r->p2link)
- loopmark(rpo2r, head, r);
-}
-
-void
-loopit(Reg *r, int32 nr)
-{
- Reg *r1;
- int32 i, d, me;
-
- if(nr > maxnr) {
- rpo2r = alloc(nr * sizeof(Reg*));
- idom = alloc(nr * sizeof(int32));
- maxnr = nr;
- }
-
- d = postorder(r, rpo2r, 0);
- if(d > nr)
- fatal(Z, "too many reg nodes");
- nr = d;
- for(i = 0; i < nr / 2; i++){
- r1 = rpo2r[i];
- rpo2r[i] = rpo2r[nr - 1 - i];
- rpo2r[nr - 1 - i] = r1;
- }
- for(i = 0; i < nr; i++)
- rpo2r[i]->rpo = i;
-
- idom[0] = 0;
- for(i = 0; i < nr; i++){
- r1 = rpo2r[i];
- me = r1->rpo;
- d = -1;
- if(r1->p1 != R && r1->p1->rpo < me)
- d = r1->p1->rpo;
- for(r1 = r1->p2; r1 != nil; r1 = r1->p2link)
- if(r1->rpo < me)
- d = rpolca(idom, d, r1->rpo);
- idom[i] = d;
- }
-
- for(i = 0; i < nr; i++){
- r1 = rpo2r[i];
- r1->loop++;
- if(r1->p2 != R && loophead(idom, r1))
- loopmark(rpo2r, i, r1);
- }
-}
-
-void
-synch(Reg *r, Bits dif)
-{
- Reg *r1;
- int z;
-
- for(r1 = r; r1 != R; r1 = r1->s1) {
- for(z=0; z<BITS; z++) {
- dif.b[z] = (dif.b[z] &
- ~(~r1->refbehind.b[z] & r1->refahead.b[z])) |
- r1->set.b[z] | r1->regdiff.b[z];
- if(dif.b[z] != r1->regdiff.b[z]) {
- r1->regdiff.b[z] = dif.b[z];
- change++;
- }
- }
- if(r1->active)
- break;
- r1->active = 1;
- for(z=0; z<BITS; z++)
- dif.b[z] &= ~(~r1->calbehind.b[z] & r1->calahead.b[z]);
- if(r1->s2 != R)
- synch(r1->s2, dif);
- }
-}
-
-uint32
-allreg(uint32 b, Rgn *r)
-{
- Var *v;
- int i;
-
- v = var + r->varno;
- r->regno = 0;
- switch(v->etype) {
-
- default:
- diag(Z, "unknown etype %d/%d", bitno(b), v->etype);
- break;
-
- case TCHAR:
- case TUCHAR:
- case TSHORT:
- case TUSHORT:
- case TINT:
- case TUINT:
- case TLONG:
- case TULONG:
- case TIND:
- case TVLONG:
- case TUVLONG:
- case TARRAY:
- i = BtoR(~b);
- if(i && r->cost > 0) {
- r->regno = i;
- return RtoB(i);
- }
- break;
-
- case TDOUBLE:
- case TFLOAT:
- i = BtoF(~b);
- if(i && r->cost > 0) {
- r->regno = i+NREG;
- return FtoB(i);
- }
- break;
- }
- return 0;
-}
-
-void
-paint1(Reg *r, int bn)
-{
- Reg *r1;
- Prog *p;
- int z;
- uint32 bb;
-
- z = bn/32;
- bb = 1L<<(bn%32);
- if(r->act.b[z] & bb)
- return;
- for(;;) {
- if(!(r->refbehind.b[z] & bb))
- break;
- r1 = r->p1;
- if(r1 == R)
- break;
- if(!(r1->refahead.b[z] & bb))
- break;
- if(r1->act.b[z] & bb)
- break;
- r = r1;
- }
-
- if(LOAD(r) & ~(r->set.b[z]&~(r->use1.b[z]|r->use2.b[z])) & bb) {
- change -= CLOAD * r->loop;
- if(debug['R'] && debug['v'])
- print("%ld%P\tld %B $%d\n", r->loop,
- r->prog, blsh(bn), change);
- }
- for(;;) {
- r->act.b[z] |= bb;
- p = r->prog;
-
- if(r->use1.b[z] & bb) {
- change += CREF * r->loop;
- if(p->to.type == D_FREG && (p->as == AMOVW || p->as == AMOVD))
- change = -CINF; /* cant go Rreg to Freg */
- if(debug['R'] && debug['v'])
- print("%ld%P\tu1 %B $%d\n", r->loop,
- p, blsh(bn), change);
- }
-
- if((r->use2.b[z]|r->set.b[z]) & bb) {
- change += CREF * r->loop;
- if(p->from.type == D_FREG && (p->as == AMOVW || p->as == AMOVD))
- change = -CINF; /* cant go Rreg to Freg */
- if(debug['R'] && debug['v'])
- print("%ld%P\tu2 %B $%d\n", r->loop,
- p, blsh(bn), change);
- }
-
- if(STORE(r) & r->regdiff.b[z] & bb) {
- change -= CLOAD * r->loop;
- if(debug['R'] && debug['v'])
- print("%ld%P\tst %B $%d\n", r->loop,
- p, blsh(bn), change);
- }
-
- if(r->refbehind.b[z] & bb)
- for(r1 = r->p2; r1 != R; r1 = r1->p2link)
- if(r1->refahead.b[z] & bb)
- paint1(r1, bn);
-
- if(!(r->refahead.b[z] & bb))
- break;
- r1 = r->s2;
- if(r1 != R)
- if(r1->refbehind.b[z] & bb)
- paint1(r1, bn);
- r = r->s1;
- if(r == R)
- break;
- if(r->act.b[z] & bb)
- break;
- if(!(r->refbehind.b[z] & bb))
- break;
- }
-}
-
-uint32
-paint2(Reg *r, int bn)
-{
- Reg *r1;
- int z;
- uint32 bb, vreg;
-
- z = bn/32;
- bb = 1L << (bn%32);
- vreg = regbits;
- if(!(r->act.b[z] & bb))
- return vreg;
- for(;;) {
- if(!(r->refbehind.b[z] & bb))
- break;
- r1 = r->p1;
- if(r1 == R)
- break;
- if(!(r1->refahead.b[z] & bb))
- break;
- if(!(r1->act.b[z] & bb))
- break;
- r = r1;
- }
- for(;;) {
- r->act.b[z] &= ~bb;
-
- vreg |= r->regu;
-
- if(r->refbehind.b[z] & bb)
- for(r1 = r->p2; r1 != R; r1 = r1->p2link)
- if(r1->refahead.b[z] & bb)
- vreg |= paint2(r1, bn);
-
- if(!(r->refahead.b[z] & bb))
- break;
- r1 = r->s2;
- if(r1 != R)
- if(r1->refbehind.b[z] & bb)
- vreg |= paint2(r1, bn);
- r = r->s1;
- if(r == R)
- break;
- if(!(r->act.b[z] & bb))
- break;
- if(!(r->refbehind.b[z] & bb))
- break;
- }
- return vreg;
-}
-
-void
-paint3(Reg *r, int bn, int32 rb, int rn)
-{
- Reg *r1;
- Prog *p;
- int z;
- uint32 bb;
-
- z = bn/32;
- bb = 1L << (bn%32);
- if(r->act.b[z] & bb)
- return;
- for(;;) {
- if(!(r->refbehind.b[z] & bb))
- break;
- r1 = r->p1;
- if(r1 == R)
- break;
- if(!(r1->refahead.b[z] & bb))
- break;
- if(r1->act.b[z] & bb)
- break;
- r = r1;
- }
-
- if(LOAD(r) & ~(r->set.b[z] & ~(r->use1.b[z]|r->use2.b[z])) & bb)
- addmove(r, bn, rn, 0);
- for(;;) {
- r->act.b[z] |= bb;
- p = r->prog;
-
- if(r->use1.b[z] & bb) {
- if(debug['R'])
- print("%P", p);
- addreg(&p->from, rn);
- if(debug['R'])
- print("\t.c%P\n", p);
- }
- if((r->use2.b[z]|r->set.b[z]) & bb) {
- if(debug['R'])
- print("%P", p);
- addreg(&p->to, rn);
- if(debug['R'])
- print("\t.c%P\n", p);
- }
-
- if(STORE(r) & r->regdiff.b[z] & bb)
- addmove(r, bn, rn, 1);
- r->regu |= rb;
-
- if(r->refbehind.b[z] & bb)
- for(r1 = r->p2; r1 != R; r1 = r1->p2link)
- if(r1->refahead.b[z] & bb)
- paint3(r1, bn, rb, rn);
-
- if(!(r->refahead.b[z] & bb))
- break;
- r1 = r->s2;
- if(r1 != R)
- if(r1->refbehind.b[z] & bb)
- paint3(r1, bn, rb, rn);
- r = r->s1;
- if(r == R)
- break;
- if(r->act.b[z] & bb)
- break;
- if(!(r->refbehind.b[z] & bb))
- break;
- }
-}
-
-void
-addreg(Addr *a, int rn)
-{
-
- a->sym = 0;
- a->name = D_NONE;
- a->type = D_REG;
- a->reg = rn;
- if(rn >= NREG) {
- a->type = D_FREG;
- a->reg = rn-NREG;
- }
-}
-
-/*
- * track register variables including external registers:
- * bit reg
- * 0 R7
- * 1 R8
- * ... ...
- * 21 R28
- */
-int32
-RtoB(int r)
-{
-
- if(r >= REGMIN && r <= REGMAX)
- return 1L << (r-REGMIN);
- return 0;
-}
-
-int
-BtoR(int32 b)
-{
- b &= 0x001fffffL;
- if(b == 0)
- return 0;
- return bitno(b) + REGMIN;
-}
-
-/*
- * bit reg
- * 22 F17
- * 23 F18
- * ... ...
- * 31 F26
- */
-int32
-FtoB(int f)
-{
- if(f < FREGMIN || f > FREGEXT)
- return 0;
- return 1L << (f - FREGMIN + 22);
-}
-
-int
-BtoF(int32 b)
-{
-
- b &= 0xffc00000L;
- if(b == 0)
- return 0;
- return bitno(b) - 22 + FREGMIN;
-}
diff --git a/src/cmd/9c/sgen.c b/src/cmd/9c/sgen.c
deleted file mode 100644
index b03c17267..000000000
--- a/src/cmd/9c/sgen.c
+++ /dev/null
@@ -1,291 +0,0 @@
-// cmd/9c/sgen.c from Vita Nuova.
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2008 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-// Revisions Copyright © 2000-2008 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-#include "gc.h"
-
-Prog*
-gtext(Sym *s, int32 stkoff)
-{
- vlong v;
-
- v = ((uvlong)argsize(1) << 32) | (stkoff & 0xffffffff);
- if((textflag & NOSPLIT) && stkoff >= 128)
- yyerror("stack frame too large for NOSPLIT function");
-
- gpseudo(ATEXT, s, nodgconst(v, types[TVLONG]));
- return p;
-}
-
-
-void
-noretval(int n)
-{
-
- if(n & 1) {
- gins(ANOP, Z, Z);
- p->to.type = D_REG;
- p->to.reg = REGRET;
- }
- if(n & 2) {
- gins(ANOP, Z, Z);
- p->to.type = D_FREG;
- p->to.reg = FREGRET;
- }
-}
-
-/*
- * calculate addressability as follows
- * CONST ==> 20 $value
- * NAME ==> 10 name
- * REGISTER ==> 11 register
- * INDREG ==> 12 *[(reg)+offset]
- * &10 ==> 2 $name
- * ADD(2, 20) ==> 2 $name+offset
- * ADD(3, 20) ==> 3 $(reg)+offset
- * &12 ==> 3 $(reg)+offset
- * *11 ==> 11 ??
- * *2 ==> 10 name
- * *3 ==> 12 *(reg)+offset
- * calculate complexity (number of registers)
- */
-void
-xcom(Node *n)
-{
- Node *l, *r;
- int v;
-
- if(n == Z)
- return;
- l = n->left;
- r = n->right;
- n->addable = 0;
- n->complex = 0;
- switch(n->op) {
- case OCONST:
- n->addable = 20;
- return;
-
- case OREGISTER:
- n->addable = 11;
- return;
-
- case OINDREG:
- n->addable = 12;
- return;
-
- case ONAME:
- n->addable = 10;
- return;
-
- case OADDR:
- xcom(l);
- if(l->addable == 10)
- n->addable = 2;
- if(l->addable == 12)
- n->addable = 3;
- break;
-
- case OIND:
- xcom(l);
- if(l->addable == 11)
- n->addable = 12;
- if(l->addable == 3)
- n->addable = 12;
- if(l->addable == 2)
- n->addable = 10;
- break;
-
- case OADD:
- xcom(l);
- xcom(r);
- if(l->addable == 20) {
- if(r->addable == 2)
- n->addable = 2;
- if(r->addable == 3)
- n->addable = 3;
- }
- if(r->addable == 20) {
- if(l->addable == 2)
- n->addable = 2;
- if(l->addable == 3)
- n->addable = 3;
- }
- break;
-
- case OASMUL:
- case OASLMUL:
- xcom(l);
- xcom(r);
- v = vlog(r);
- if(v >= 0) {
- n->op = OASASHL;
- r->vconst = v;
- r->type = types[TINT];
- }
- break;
-
- case OMUL:
- case OLMUL:
- xcom(l);
- xcom(r);
- v = vlog(r);
- if(v >= 0) {
- n->op = OASHL;
- r->vconst = v;
- r->type = types[TINT];
- }
- v = vlog(l);
- if(v >= 0) {
- n->op = OASHL;
- n->left = r;
- n->right = l;
- r = l;
- l = n->left;
- r->vconst = v;
- r->type = types[TINT];
- simplifyshift(n);
- }
- break;
-
- case OASLDIV:
- xcom(l);
- xcom(r);
- v = vlog(r);
- if(v >= 0) {
- n->op = OASLSHR;
- r->vconst = v;
- r->type = types[TINT];
- }
- break;
-
- case OLDIV:
- xcom(l);
- xcom(r);
- v = vlog(r);
- if(v >= 0) {
- n->op = OLSHR;
- r->vconst = v;
- r->type = types[TINT];
- simplifyshift(n);
- }
- break;
-
- case OASLMOD:
- xcom(l);
- xcom(r);
- v = vlog(r);
- if(v >= 0) {
- n->op = OASAND;
- r->vconst--;
- }
- break;
-
- case OLMOD:
- xcom(l);
- xcom(r);
- v = vlog(r);
- if(v >= 0) {
- n->op = OAND;
- r->vconst--;
- }
- break;
-
- case OLSHR:
- case OASHL:
- case OASHR:
- xcom(l);
- xcom(r);
- simplifyshift(n);
- break;
-
- default:
- if(l != Z)
- xcom(l);
- if(r != Z)
- xcom(r);
- break;
- }
- if(n->addable >= 10)
- return;
- if(l != Z)
- n->complex = l->complex;
- if(r != Z) {
- if(r->complex == n->complex)
- n->complex = r->complex+1;
- else
- if(r->complex > n->complex)
- n->complex = r->complex;
- }
- if(n->complex == 0)
- n->complex++;
-
-// if(com64(n))
-// return;
-
- switch(n->op) {
-
- case OFUNC:
- n->complex = FNX;
- break;
-
- case OEQ:
- case ONE:
- case OLE:
- case OLT:
- case OGE:
- case OGT:
- case OHI:
- case OHS:
- case OLO:
- case OLS:
- /*
- * immediate operators, make const on right
- */
- if(l->op == OCONST) {
- n->left = r;
- n->right = l;
- n->op = invrel[relindex(n->op)];
- }
- break;
-
- case OADD:
- case OXOR:
- case OAND:
- case OOR:
- /*
- * immediate operators, make const on right
- */
- if(l->op == OCONST) {
- n->left = r;
- n->right = l;
- }
- break;
- }
-}
-
diff --git a/src/cmd/9c/swt.c b/src/cmd/9c/swt.c
deleted file mode 100644
index a63db60b2..000000000
--- a/src/cmd/9c/swt.c
+++ /dev/null
@@ -1,407 +0,0 @@
-// cmd/9c/swt.c from Vita Nuova.
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2008 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-// Revisions Copyright © 2000-2008 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-#include "gc.h"
-
-void
-swit1(C1 *q, int nc, int32 def, Node *n)
-{
- Node tn, nod;
-
- regalloc(&nod, n, Z);
- /* always signed */
- if(typev[n->type->etype])
- nod.type = types[TVLONG];
- else
- nod.type = types[TLONG];
- cgen(n, &nod);
- regalloc(&tn, &regnode, Z);
- swit2(q, nc, def, &nod, &tn);
- regfree(&tn);
- regfree(&nod);
-}
-
-void
-swit2(C1 *q, int nc, int32 def, Node *n, Node *tn)
-{
- C1 *r;
- int i;
- Prog *sp;
-
- if(nc < 5) {
- for(i=0; i<nc; i++) {
- if(sval(q->val)) {
- gopcode(OEQ, n, Z, nodconst(q->val));
- } else {
- gopcode(OSUB, nodconst(q->val), n, tn);
- gopcode(OEQ, tn, Z, nodconst(0));
- }
- patch(p, q->label);
- q++;
- }
- gbranch(OGOTO);
- patch(p, def);
- return;
- }
- i = nc / 2;
- r = q+i;
- if(sval(r->val)) {
- gopcode(OGT, n, Z, nodconst(r->val));
- sp = p;
- } else {
- gopcode(OSUB, nodconst(r->val), n, tn);
- gopcode(OGT, tn, Z, nodconst(0));
- sp = p;
- }
- gbranch(OGOTO);
- p->as = ABEQ;
- patch(p, r->label);
- swit2(q, i, def, n, tn);
-
- patch(sp, pc);
- swit2(r+1, nc-i-1, def, n, tn);
-}
-
-void
-bitload(Node *b, Node *n1, Node *n2, Node *n3, Node *nn)
-{
- int sh;
- int32 v;
- Node *l;
-
- /*
- * n1 gets adjusted/masked value
- * n2 gets address of cell
- * n3 gets contents of cell
- */
- l = b->left;
- if(n2 != Z) {
- regalloc(n1, l, nn);
- reglcgen(n2, l, Z);
- regalloc(n3, l, Z);
- gopcode(OAS, n2, Z, n3);
- gopcode(OAS, n3, Z, n1);
- } else {
- regalloc(n1, l, nn);
- cgen(l, n1);
- }
- if(b->type->shift == 0 && typeu[b->type->etype]) {
- v = ~0 + (1L << b->type->nbits);
- gopcode(OAND, nodconst(v), Z, n1);
- } else {
- sh = 32 - b->type->shift - b->type->nbits;
- if(sh > 0)
- gopcode(OASHL, nodconst(sh), Z, n1);
- sh += b->type->shift;
- if(sh > 0)
- if(typeu[b->type->etype])
- gopcode(OLSHR, nodconst(sh), Z, n1);
- else
- gopcode(OASHR, nodconst(sh), Z, n1);
- }
-}
-
-void
-bitstore(Node *b, Node *n1, Node *n2, Node *n3, Node *nn)
-{
- int32 v;
- Node nod, *l;
- int sh;
-
- /*
- * n1 has adjusted/masked value
- * n2 has address of cell
- * n3 has contents of cell
- */
- l = b->left;
- regalloc(&nod, l, Z);
- v = ~0 + (1L << b->type->nbits);
- gopcode(OAND, nodconst(v), Z, n1);
- gopcode(OAS, n1, Z, &nod);
- if(nn != Z)
- gopcode(OAS, n1, Z, nn);
- sh = b->type->shift;
- if(sh > 0)
- gopcode(OASHL, nodconst(sh), Z, &nod);
- v <<= sh;
- gopcode(OAND, nodconst(~v), Z, n3);
- gopcode(OOR, n3, Z, &nod);
- gopcode(OAS, &nod, Z, n2);
-
- regfree(&nod);
- regfree(n1);
- regfree(n2);
- regfree(n3);
-}
-
-int32
-outstring(char *s, int32 n)
-{
- int32 r;
-
- if(suppress)
- return nstring;
- r = nstring;
- while(n) {
- string[mnstring] = *s++;
- mnstring++;
- nstring++;
- if(mnstring >= NSNAME) {
- gpseudo(ADATA, symstring, nodconst(0L));
- p->from.offset += nstring - NSNAME;
- p->reg = NSNAME;
- p->to.type = D_SCONST;
- memmove(p->to.u.sval, string, NSNAME);
- mnstring = 0;
- }
- n--;
- }
- return r;
-}
-
-int
-mulcon(Node *n, Node *nn)
-{
- Node *l, *r, nod1, nod2;
- Multab *m;
- int32 v;
- int o;
- char code[sizeof(m->code)+2], *p;
-
- if(typefd[n->type->etype])
- return 0;
- l = n->left;
- r = n->right;
- if(l->op == OCONST) {
- l = r;
- r = n->left;
- }
- if(r->op != OCONST)
- return 0;
- v = convvtox(r->vconst, n->type->etype);
- if(v != r->vconst) {
- if(debug['M'])
- print("%L multiply conv: %lld\n", n->lineno, r->vconst);
- return 0;
- }
- m = mulcon0(n, v);
- if(!m) {
- if(debug['M'])
- print("%L multiply table: %lld\n", n->lineno, r->vconst);
- return 0;
- }
-
- memmove(code, m->code, sizeof(m->code));
- code[sizeof(m->code)] = 0;
-
- p = code;
- if(p[1] == 'i')
- p += 2;
- regalloc(&nod1, n, nn);
- cgen(l, &nod1);
- if(v < 0)
- gopcode(ONEG, &nod1, Z, &nod1);
- regalloc(&nod2, n, Z);
-
-loop:
- switch(*p) {
- case 0:
- regfree(&nod2);
- gopcode(OAS, &nod1, Z, nn);
- regfree(&nod1);
- return 1;
- case '+':
- o = OADD;
- goto addsub;
- case '-':
- o = OSUB;
- addsub: /* number is r,n,l */
- v = p[1] - '0';
- r = &nod1;
- if(v&4)
- r = &nod2;
- n = &nod1;
- if(v&2)
- n = &nod2;
- l = &nod1;
- if(v&1)
- l = &nod2;
- gopcode(o, l, n, r);
- break;
- default: /* op is shiftcount, number is r,l */
- v = p[1] - '0';
- r = &nod1;
- if(v&2)
- r = &nod2;
- l = &nod1;
- if(v&1)
- l = &nod2;
- v = *p - 'a';
- if(v < 0 || v >= 32) {
- diag(n, "mulcon unknown op: %c%c", p[0], p[1]);
- break;
- }
- gopcode(OASHL, nodconst(v), l, r);
- break;
- }
- p += 2;
- goto loop;
-}
-
-void
-sextern(Sym *s, Node *a, int32 o, int32 w)
-{
- int32 e, lw;
-
- for(e=0; e<w; e+=NSNAME) {
- lw = NSNAME;
- if(w-e < lw)
- lw = w-e;
- gpseudo(ADATA, s, nodconst(0));
- p->from.offset += o+e;
- p->reg = lw;
- p->to.type = D_SCONST;
- memmove(p->to.u.sval, a->cstring+e, lw);
- }
-}
-
-void
-gextern(Sym *s, Node *a, int32 o, int32 w)
-{
- gpseudo(ADATA, s, a);
- p->from.offset += o;
- p->reg = w;
- if(p->to.type == D_OREG)
- p->to.type = D_CONST;
-}
-
-void
-outcode(void)
-{
- Bprint(&outbuf, "go object %s %s %s\n", getgoos(), getgoarch(), getgoversion());
- if(pragcgobuf.to > pragcgobuf.start) {
- Bprint(&outbuf, "\n");
- Bprint(&outbuf, "$$ // exports\n\n");
- Bprint(&outbuf, "$$ // local types\n\n");
- Bprint(&outbuf, "$$ // cgo\n");
- Bprint(&outbuf, "%s", fmtstrflush(&pragcgobuf));
- Bprint(&outbuf, "\n$$\n\n");
- }
- Bprint(&outbuf, "!\n");
-
- writeobj(ctxt, &outbuf);
- lastp = nil;
-}
-
-int32
-align(int32 i, Type *t, int op, int32 *maxalign)
-{
- int32 o;
- Type *v;
- int w, packw;
-
- o = i;
- w = 1;
- packw = 0;
- switch(op) {
- default:
- diag(Z, "unknown align opcode %d", op);
- break;
-
- case Asu2: /* padding at end of a struct */
- w = *maxalign;
- if(w < 1)
- w = 1;
- if(packflg)
- packw = packflg;
- break;
-
- case Ael1: /* initial allign of struct element */
- for(v=t; v->etype==TARRAY; v=v->link)
- ;
- if(v->etype == TSTRUCT || v->etype == TUNION)
- w = v->align;
- else
- w = ewidth[v->etype];
- if(w < 1 || w > SZ_VLONG)
- fatal(Z, "align");
- if(packflg)
- packw = packflg;
- break;
-
- case Ael2: /* width of a struct element */
- o += t->width;
- break;
-
- case Aarg0: /* initial passbyptr argument in arg list */
- if(typesu[t->etype]) {
- o = align(o, types[TIND], Aarg1, nil);
- o = align(o, types[TIND], Aarg2, nil);
- }
- break;
-
- case Aarg1: /* initial align of parameter */
- w = ewidth[t->etype];
- if(w <= 0 || w >= SZ_VLONG) {
- w = SZ_VLONG;
- break;
- }
- w = 1;
- break;
-
- case Aarg2: /* width of a parameter */
- o += t->width;
- w = t->width;
- if(w > SZ_VLONG)
- w = SZ_VLONG;
- break;
-
- case Aaut3: /* total align of automatic */
- o = align(o, t, Ael1, nil);
- o = align(o, t, Ael2, nil);
- break;
- }
- if(packw != 0 && xround(o, w) != xround(o, packw))
- diag(Z, "#pragma pack changes offset of %T", t);
- o = xround(o, w);
- if(maxalign && *maxalign < w)
- *maxalign = w;
- if(debug['A'])
- print("align %s %ld %T = %ld\n", bnames[op], i, t, o);
- return o;
-}
-
-int32
-maxround(int32 max, int32 v)
-{
- v = xround(v, SZ_VLONG);
- if(v > max)
- return v;
- return max;
-}
diff --git a/src/cmd/9c/txt.c b/src/cmd/9c/txt.c
deleted file mode 100644
index e46aba84e..000000000
--- a/src/cmd/9c/txt.c
+++ /dev/null
@@ -1,1537 +0,0 @@
-// cmd/9c/txt.c from Vita Nuova.
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2008 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-// Revisions Copyright © 2000-2008 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-#include "gc.h"
-
-static int resvreg[nelem(reg)];
-
-#define isv(et) ((et) == TVLONG || (et) == TUVLONG || (et) == TIND)
-
-int thechar = '9';
-char *thestring = "power64";
-
-LinkArch *thelinkarch;
-
-void
-linkarchinit(void)
-{
- thestring = getgoarch();
- if(strcmp(thestring, "power64le") == 0)
- thelinkarch = &linkpower64le;
- else
- thelinkarch = &linkpower64;
-}
-
-
-void
-ginit(void)
-{
- Type *t;
-
- dodefine("_64BITREG");
- dodefine("_64BIT");
- exregoffset = REGEXT;
- exfregoffset = FREGEXT;
- listinit();
- nstring = 0;
- mnstring = 0;
- nrathole = 0;
- pc = 0;
- breakpc = -1;
- continpc = -1;
- cases = C;
- lastp = P;
- tfield = types[TLONG];
-
- typeword = typechlvp;
- typecmplx = typesu;
- /* TO DO */
- memmove(typechlpv, typechlp, sizeof(typechlpv));
- typechlpv[TVLONG] = 1;
- typechlpv[TUVLONG] = 1;
-
- zprog.link = P;
- zprog.as = AGOK;
- zprog.reg = NREG;
- zprog.from.type = D_NONE;
- zprog.from.name = D_NONE;
- zprog.from.reg = NREG;
- zprog.from3 = zprog.from;
- zprog.to = zprog.from;
-
- regnode.op = OREGISTER;
- regnode.class = CEXREG;
- regnode.reg = 0;
- regnode.complex = 0;
- regnode.addable = 11;
- regnode.type = types[TLONG];
-
- qregnode = regnode;
- qregnode.type = types[TVLONG];
-
- constnode.op = OCONST;
- constnode.class = CXXX;
- constnode.complex = 0;
- constnode.addable = 20;
- constnode.type = types[TLONG];
-
- vconstnode = constnode;
- vconstnode.type = types[TVLONG];
-
- fconstnode.op = OCONST;
- fconstnode.class = CXXX;
- fconstnode.complex = 0;
- fconstnode.addable = 20;
- fconstnode.type = types[TDOUBLE];
-
- nodsafe = new(ONAME, Z, Z);
- nodsafe->sym = slookup(".safe");
- nodsafe->type = types[TINT];
- nodsafe->etype = types[TINT]->etype;
- nodsafe->class = CAUTO;
- complex(nodsafe);
-
- t = typ(TARRAY, types[TCHAR]);
- symrathole = slookup(".rathole");
- symrathole->class = CGLOBL;
- symrathole->type = t;
-
- nodrat = new(ONAME, Z, Z);
- nodrat->sym = symrathole;
- nodrat->type = types[TIND];
- nodrat->etype = TVOID;
- nodrat->class = CGLOBL;
- complex(nodrat);
- nodrat->type = t;
-
- nodret = new(ONAME, Z, Z);
- nodret->sym = slookup(".ret");
- nodret->type = types[TIND];
- nodret->etype = TIND;
- nodret->class = CPARAM;
- nodret = new(OIND, nodret, Z);
- complex(nodret);
-
- com64init();
-
- memset(reg, 0, sizeof(reg));
- reg[REGZERO] = 1; /* don't use */
- reg[REGTMP] = 1;
- reg[FREGCVI+NREG] = 1;
- reg[FREGZERO+NREG] = 1;
- reg[FREGHALF+NREG] = 1;
- reg[FREGONE+NREG] = 1;
- reg[FREGTWO+NREG] = 1;
- memmove(resvreg, reg, sizeof(reg));
-}
-
-void
-gclean(void)
-{
- int i;
- Sym *s;
-
- for(i=0; i<NREG; i++)
- if(reg[i] && !resvreg[i])
- diag(Z, "reg %d left allocated", i);
- for(i=NREG; i<NREG+NREG; i++)
- if(reg[i] && !resvreg[i])
- diag(Z, "freg %d left allocated", i-NREG);
- while(mnstring)
- outstring("", 1L);
- symstring->type->width = nstring;
- symrathole->type->width = nrathole;
- for(i=0; i<NHASH; i++)
- for(s = hash[i]; s != S; s = s->link) {
- if(s->type == T)
- continue;
- if(s->type->width == 0)
- continue;
- if(s->class != CGLOBL && s->class != CSTATIC)
- continue;
- if(s->type == types[TENUM])
- continue;
- gpseudo(AGLOBL, s, nodconst(s->type->width));
- }
- nextpc();
- p->as = AEND;
- outcode();
-}
-
-void
-nextpc(void)
-{
- Plist *pl;
-
- p = alloc(sizeof(*p));
- *p = zprog;
- p->lineno = nearln;
- p->pc = pc;
- pc++;
- if(lastp == P) {
- pl = linknewplist(ctxt);
- pl->firstpc = p;
- } else
- lastp->link = p;
- lastp = p;
-}
-
-void
-gargs(Node *n, Node *tn1, Node *tn2)
-{
- int32 regs;
- Node fnxargs[20], *fnxp;
-
- regs = cursafe;
-
- fnxp = fnxargs;
- garg1(n, tn1, tn2, 0, &fnxp); /* compile fns to temps */
-
- curarg = 0;
- fnxp = fnxargs;
- garg1(n, tn1, tn2, 1, &fnxp); /* compile normal args and temps */
-
- cursafe = regs;
-}
-
-void
-garg1(Node *n, Node *tn1, Node *tn2, int f, Node **fnxp)
-{
- Node nod;
-
- if(n == Z)
- return;
- if(n->op == OLIST) {
- garg1(n->left, tn1, tn2, f, fnxp);
- garg1(n->right, tn1, tn2, f, fnxp);
- return;
- }
- if(f == 0) {
- if(n->complex >= FNX) {
- regsalloc(*fnxp, n);
- nod = znode;
- nod.op = OAS;
- nod.left = *fnxp;
- nod.right = n;
- nod.type = n->type;
- cgen(&nod, Z);
- (*fnxp)++;
- }
- return;
- }
- if(typesu[n->type->etype]) {
- regaalloc(tn2, n);
- if(n->complex >= FNX) {
- sugen(*fnxp, tn2, n->type->width);
- (*fnxp)++;
- } else
- sugen(n, tn2, n->type->width);
- return;
- }
- if(REGARG>=0 && curarg == 0 && typechlpv[n->type->etype]) {
- regaalloc1(tn1, n);
- if(n->complex >= FNX) {
- cgen(*fnxp, tn1);
- (*fnxp)++;
- } else
- cgen(n, tn1);
- return;
- }
- if(vconst(n) == 0) {
- regaalloc(tn2, n);
- gopcode(OAS, n, Z, tn2);
- return;
- }
- regalloc(tn1, n, Z);
- if(n->complex >= FNX) {
- cgen(*fnxp, tn1);
- (*fnxp)++;
- } else
- cgen(n, tn1);
- regaalloc(tn2, n);
- gopcode(OAS, tn1, Z, tn2);
- regfree(tn1);
-}
-
-Node*
-nod32const(vlong v)
-{
- constnode.vconst = v & MASK(32);
- return &constnode;
-}
-
-Node*
-nodgconst(vlong v, Type *t)
-{
- if(!typev[t->etype])
- return nodconst((int32)v);
- vconstnode.vconst = v;
- return &vconstnode;
-}
-
-Node*
-nodconst(int32 v)
-{
- constnode.vconst = v;
- return &constnode;
-}
-
-Node*
-nodfconst(double d)
-{
- fconstnode.fconst = d;
- return &fconstnode;
-}
-
-void
-nodreg(Node *n, Node *nn, int reg)
-{
- *n = qregnode;
- n->reg = reg;
- n->type = nn->type;
- n->lineno = nn->lineno;
-}
-
-void
-regret(Node *n, Node *nn, Type *t, int mode)
-{
- int r;
-
- if(mode == 0 || hasdotdotdot(t) || nn->type->width == 0) {
- r = REGRET;
- if(typefd[nn->type->etype])
- r = FREGRET+NREG;
- nodreg(n, nn, r);
- reg[r]++;
- return;
- }
-
- if(mode == 1) {
- // fetch returned value after call.
- // already called gargs, so curarg is set.
- curarg = (curarg+7) & ~7;
- regaalloc(n, nn);
- return;
- }
-
- if(mode == 2) {
- // store value to be returned.
- // must compute arg offset.
- if(t->etype != TFUNC)
- fatal(Z, "bad regret func %T", t);
- *n = *nn;
- n->op = ONAME;
- n->class = CPARAM;
- n->sym = slookup(".ret");
- n->complex = nodret->complex;
- n->addable = 20;
- n->xoffset = argsize(0);
- return;
- }
-
- fatal(Z, "bad regret");
-}
-
-void
-regalloc(Node *n, Node *tn, Node *o)
-{
- int i, j;
- static int lasti;
-
- switch(tn->type->etype) {
- case TCHAR:
- case TUCHAR:
- case TSHORT:
- case TUSHORT:
- case TINT:
- case TUINT:
- case TLONG:
- case TULONG:
- case TVLONG:
- case TUVLONG:
- case TIND:
- if(o != Z && o->op == OREGISTER) {
- i = o->reg;
- if(i > 0 && i < NREG)
- goto out;
- }
- j = lasti + REGRET+1;
- for(i=REGRET+1; i<NREG; i++) {
- if(j >= NREG)
- j = REGRET+1;
- if(reg[j] == 0) {
- i = j;
- goto out;
- }
- j++;
- }
- diag(tn, "out of fixed registers");
- goto err;
-
- case TFLOAT:
- case TDOUBLE:
- if(o != Z && o->op == OREGISTER) {
- i = o->reg;
- if(i >= NREG && i < NREG+NREG)
- goto out;
- }
- j = lasti + NREG;
- for(i=NREG; i<NREG+NREG; i++) {
- if(j >= NREG+NREG)
- j = NREG;
- if(reg[j] == 0) {
- i = j;
- goto out;
- }
- j++;
- }
- diag(tn, "out of float registers");
- goto err;
- }
- diag(tn, "unknown type in regalloc: %T", tn->type);
-err:
- i = 0;
-out:
- if(i)
- reg[i]++;
- lasti++;
- if(lasti >= 5)
- lasti = 0;
- nodreg(n, tn, i);
-}
-
-void
-regialloc(Node *n, Node *tn, Node *o)
-{
- Node nod;
-
- nod = *tn;
- nod.type = types[TIND];
- regalloc(n, &nod, o);
-}
-
-void
-regfree(Node *n)
-{
- int i;
-
- i = 0;
- if(n->op != OREGISTER && n->op != OINDREG)
- goto err;
- i = n->reg;
- if(i < 0 || i >= sizeof(reg))
- goto err;
- if(reg[i] <= 0)
- goto err;
- reg[i]--;
- return;
-err:
- diag(n, "error in regfree: %d", i);
-}
-
-void
-regsalloc(Node *n, Node *nn)
-{
- cursafe = align(cursafe, nn->type, Aaut3, nil);
- maxargsafe = maxround(maxargsafe, cursafe+curarg);
- *n = *nodsafe;
- n->xoffset = -(stkoff + cursafe);
- n->type = nn->type;
- n->etype = nn->type->etype;
- n->lineno = nn->lineno;
-}
-
-void
-regaalloc1(Node *n, Node *nn)
-{
- if(REGARG < 0)
- return;
- nodreg(n, nn, REGARG);
- reg[REGARG]++;
- curarg = align(curarg, nn->type, Aarg1, nil);
- curarg = align(curarg, nn->type, Aarg2, nil);
- maxargsafe = maxround(maxargsafe, cursafe+curarg);
-}
-
-void
-regaalloc(Node *n, Node *nn)
-{
- curarg = align(curarg, nn->type, Aarg1, nil);
- *n = *nn;
- n->op = OINDREG;
- n->reg = REGSP;
- n->xoffset = curarg + SZ_VLONG;
- n->complex = 0;
- n->addable = 20;
- curarg = align(curarg, nn->type, Aarg2, nil);
- maxargsafe = maxround(maxargsafe, cursafe+curarg);
-}
-
-void
-regind(Node *n, Node *nn)
-{
-
- if(n->op != OREGISTER) {
- diag(n, "regind not OREGISTER");
- return;
- }
- n->op = OINDREG;
- n->type = nn->type;
-}
-
-void
-raddr(Node *n, Prog *p)
-{
- Addr a;
-
- naddr(n, &a);
- if(R0ISZERO && a.type == D_CONST && a.offset == 0) {
- a.type = D_REG;
- a.reg = REGZERO;
- }
- if(a.type != D_REG && a.type != D_FREG) {
- if(n)
- diag(n, "bad in raddr: %O", n->op);
- else
- diag(n, "bad in raddr: <null>");
- p->reg = NREG;
- } else
- p->reg = a.reg;
-}
-
-void
-naddr(Node *n, Addr *a)
-{
- int32 v;
-
- a->type = D_NONE;
- if(n == Z)
- return;
- switch(n->op) {
- default:
- bad:
- prtree(n, "naddr");
- diag(n, "%L: !bad in naddr: %O", n->lineno, n->op);
- break;
-
- case OREGISTER:
- a->type = D_REG;
- a->sym = nil;
- a->reg = n->reg;
- if(a->reg >= NREG) {
- a->type = D_FREG;
- a->reg -= NREG;
- }
- break;
-
- case OIND:
- naddr(n->left, a);
- if(a->type == D_REG) {
- a->type = D_OREG;
- break;
- }
- if(a->type == D_CONST) {
- a->type = D_OREG;
- break;
- }
- goto bad;
-
- case OINDREG:
- a->type = D_OREG;
- a->sym = nil;
- a->offset = n->xoffset;
- a->reg = n->reg;
- break;
-
- case ONAME:
- a->etype = n->etype;
- a->type = D_OREG;
- a->name = D_STATIC;
- a->sym = linksym(n->sym);
- a->offset = n->xoffset;
- if(n->class == CSTATIC)
- break;
- if(n->class == CEXTERN || n->class == CGLOBL) {
- a->name = D_EXTERN;
- break;
- }
- if(n->class == CAUTO) {
- a->name = D_AUTO;
- break;
- }
- if(n->class == CPARAM) {
- a->name = D_PARAM;
- break;
- }
- goto bad;
-
- case OCONST:
- a->sym = nil;
- a->reg = NREG;
- if(typefd[n->type->etype]) {
- a->type = D_FCONST;
- a->u.dval = n->fconst;
- } else {
- a->type = D_CONST;
- a->offset = n->vconst;
- }
- break;
-
- case OADDR:
- naddr(n->left, a);
- if(a->type == D_OREG) {
- a->type = D_CONST;
- break;
- }
- goto bad;
-
- case OADD:
- if(n->left->op == OCONST) {
- naddr(n->left, a);
- v = a->offset;
- naddr(n->right, a);
- } else {
- naddr(n->right, a);
- v = a->offset;
- naddr(n->left, a);
- }
- a->offset += v;
- break;
-
- }
-}
-
-void
-fop(int as, int f1, int f2, Node *t)
-{
- Node nod1, nod2, nod3;
-
- nodreg(&nod1, t, NREG+f1);
- nodreg(&nod2, t, NREG+f2);
- regalloc(&nod3, t, t);
- gopcode(as, &nod1, &nod2, &nod3);
- gmove(&nod3, t);
- regfree(&nod3);
-}
-
-void
-gmove(Node *f, Node *t)
-{
- int ft, tt, a;
- Node nod, fxc0, fxc1, fxc2, fxrat;
- Prog *p1;
- double d;
-
- ft = f->type->etype;
- tt = t->type->etype;
-
- if(ft == TDOUBLE && f->op == OCONST) {
- d = f->fconst;
- if(d == 0.0) {
- a = FREGZERO;
- goto ffreg;
- }
- if(d == 0.5) {
- a = FREGHALF;
- goto ffreg;
- }
- if(d == 1.0) {
- a = FREGONE;
- goto ffreg;
- }
- if(d == 2.0) {
- a = FREGTWO;
- goto ffreg;
- }
- if(d == -.5) {
- fop(OSUB, FREGHALF, FREGZERO, t);
- return;
- }
- if(d == -1.0) {
- fop(OSUB, FREGONE, FREGZERO, t);
- return;
- }
- if(d == -2.0) {
- fop(OSUB, FREGTWO, FREGZERO, t);
- return;
- }
- if(d == 1.5) {
- fop(OADD, FREGONE, FREGHALF, t);
- return;
- }
- if(d == 2.5) {
- fop(OADD, FREGTWO, FREGHALF, t);
- return;
- }
- if(d == 3.0) {
- fop(OADD, FREGTWO, FREGONE, t);
- return;
- }
- }
- if(ft == TFLOAT && f->op == OCONST) {
- d = f->fconst;
- if(d == 0) {
- a = FREGZERO;
- ffreg:
- nodreg(&nod, f, NREG+a);
- gmove(&nod, t);
- return;
- }
- }
- /*
- * a load --
- * put it into a register then
- * worry what to do with it.
- */
- if(f->op == ONAME || f->op == OINDREG || f->op == OIND) {
- switch(ft) {
- default:
- if(ewidth[ft] == 4){
- if(typeu[ft])
- a = AMOVWZ;
- else
- a = AMOVW;
- }else
- a = AMOVD;
- break;
- case TINT:
- a = AMOVW;
- break;
- case TUINT:
- a = AMOVWZ;
- break;
- case TFLOAT:
- a = AFMOVS;
- break;
- case TDOUBLE:
- a = AFMOVD;
- break;
- case TCHAR:
- a = AMOVB;
- break;
- case TUCHAR:
- a = AMOVBZ;
- break;
- case TSHORT:
- a = AMOVH;
- break;
- case TUSHORT:
- a = AMOVHZ;
- break;
- }
- regalloc(&nod, f, t);
- gins(a, f, &nod);
- gmove(&nod, t);
- regfree(&nod);
- return;
- }
-
- /*
- * a store --
- * put it into a register then
- * store it.
- */
- if(t->op == ONAME || t->op == OINDREG || t->op == OIND) {
- switch(tt) {
- default:
- if(ewidth[tt] == 4)
- a = AMOVW;
- else
- a = AMOVD;
- break;
- case TINT:
- a = AMOVW;
- break;
- case TUINT:
- a = AMOVWZ;
- break;
- case TUCHAR:
- a = AMOVBZ;
- break;
- case TCHAR:
- a = AMOVB;
- break;
- case TUSHORT:
- a = AMOVHZ;
- break;
- case TSHORT:
- a = AMOVH;
- break;
- case TFLOAT:
- a = AFMOVS;
- break;
- case TDOUBLE:
- a = AFMOVD;
- break;
- }
- if(!typefd[ft] && vconst(f) == 0) {
- gins(a, f, t);
- return;
- }
- if(ft == tt)
- regalloc(&nod, t, f);
- else
- regalloc(&nod, t, Z);
- gmove(f, &nod);
- gins(a, &nod, t);
- regfree(&nod);
- return;
- }
-
- /*
- * type x type cross table
- */
- a = AGOK;
- switch(ft) {
- case TDOUBLE:
- case TFLOAT:
- switch(tt) {
- case TDOUBLE:
- a = AFMOVD;
- if(ft == TFLOAT)
- a = AFMOVS; /* AFMOVSD */
- break;
- case TFLOAT:
- a = AFRSP;
- if(ft == TFLOAT)
- a = AFMOVS;
- break;
- case TINT:
- case TUINT:
- case TLONG:
- case TULONG:
- case TIND:
- case TSHORT:
- case TUSHORT:
- case TCHAR:
- case TUCHAR:
- /* BUG: not right for unsigned int32 */
- regalloc(&nod, f, Z); /* should be type float */
- regsalloc(&fxrat, f);
- gins(AFCTIWZ, f, &nod);
- gins(AFMOVD, &nod, &fxrat);
- regfree(&nod);
- fxrat.type = nodrat->type;
- fxrat.etype = nodrat->etype;
- fxrat.xoffset += 4;
- gins(AMOVW, &fxrat, t); /* TO DO */
- gmove(t, t);
- return;
- case TVLONG:
- case TUVLONG:
- /* BUG: not right for unsigned int32 */
- regalloc(&nod, f, Z); /* should be type float */
- regsalloc(&fxrat, f);
- gins(AFCTIDZ, f, &nod);
- gins(AFMOVD, &nod, &fxrat);
- regfree(&nod);
- fxrat.type = nodrat->type;
- fxrat.etype = nodrat->etype;
- gins(AMOVD, &fxrat, t);
- gmove(t, t);
- return;
- }
- break;
- case TINT:
- case TUINT:
- case TLONG:
- case TULONG:
- switch(tt) {
- case TDOUBLE:
- case TFLOAT:
- goto fxtofl;
- case TINT:
- case TUINT:
- case TLONG:
- case TULONG:
- case TSHORT:
- case TUSHORT:
- case TCHAR:
- case TUCHAR:
- if(typeu[tt])
- a = AMOVWZ;
- else
- a = AMOVW;
- break;
- case TVLONG:
- case TUVLONG:
- case TIND:
- a = AMOVD;
- break;
- }
- break;
- case TVLONG:
- case TUVLONG:
- case TIND:
- switch(tt) {
- case TDOUBLE:
- case TFLOAT:
- goto fxtofl;
- case TINT:
- case TUINT:
- case TLONG:
- case TULONG:
- case TVLONG:
- case TUVLONG:
- case TIND:
- case TSHORT:
- case TUSHORT:
- case TCHAR:
- case TUCHAR:
- a = AMOVD; /* TO DO: conversion done? */
- break;
- }
- break;
- case TSHORT:
- switch(tt) {
- case TDOUBLE:
- case TFLOAT:
- goto fxtofl;
- case TINT:
- case TUINT:
- case TLONG:
- case TULONG:
- case TVLONG:
- case TUVLONG:
- case TIND:
- a = AMOVH;
- break;
- case TSHORT:
- case TUSHORT:
- case TCHAR:
- case TUCHAR:
- a = AMOVD;
- break;
- }
- break;
- case TUSHORT:
- switch(tt) {
- case TDOUBLE:
- case TFLOAT:
- goto fxtofl;
- case TINT:
- case TUINT:
- case TLONG:
- case TULONG:
- case TVLONG:
- case TUVLONG:
- case TIND:
- a = AMOVHZ;
- break;
- case TSHORT:
- case TUSHORT:
- case TCHAR:
- case TUCHAR:
- a = AMOVD;
- break;
- }
- break;
- case TCHAR:
- switch(tt) {
- case TDOUBLE:
- case TFLOAT:
- goto fxtofl;
- case TINT:
- case TUINT:
- case TLONG:
- case TULONG:
- case TVLONG:
- case TUVLONG:
- case TIND:
- case TSHORT:
- case TUSHORT:
- a = AMOVB;
- break;
- case TCHAR:
- case TUCHAR:
- a = AMOVD;
- break;
- }
- break;
- case TUCHAR:
- switch(tt) {
- case TDOUBLE:
- case TFLOAT:
- fxtofl:
- /*
- * rat[0] = 0x43300000; rat[1] = f^0x80000000;
- * t = *(double*)rat - FREGCVI;
- * is-unsigned(t) => if(t<0) t += 2^32;
- * could be streamlined for int-to-float
- */
- regalloc(&fxc0, f, Z);
- regalloc(&fxc2, f, Z);
- regsalloc(&fxrat, t); /* should be type float */
- gins(AMOVW, nodconst(0x43300000L), &fxc0);
- gins(AMOVW, f, &fxc2);
- gins(AXOR, nodconst(0x80000000L), &fxc2);
- if(ctxt->arch->endian == BigEndian) {
- gins(AMOVW, &fxc0, &fxrat);
- fxc1 = fxrat;
- fxc1.type = nodrat->type;
- fxc1.etype = nodrat->etype;
- fxc1.xoffset += SZ_LONG;
- gins(AMOVW, &fxc2, &fxc1);
- } else {
- gins(AMOVW, &fxc2, &fxrat);
- fxc1 = fxrat;
- fxc1.type = nodrat->type;
- fxc1.etype = nodrat->etype;
- fxc1.xoffset += SZ_LONG;
- gins(AMOVW, &fxc0, &fxc1);
- }
- regfree(&fxc2);
- regfree(&fxc0);
- regalloc(&nod, t, t); /* should be type float */
- gins(AFMOVD, &fxrat, &nod);
- nodreg(&fxc1, t, NREG+FREGCVI);
- gins(AFSUB, &fxc1, &nod);
- a = AFMOVD;
- if(tt == TFLOAT)
- a = AFRSP;
- gins(a, &nod, t);
- regfree(&nod);
- if(ft == TULONG) {
- regalloc(&nod, t, Z);
- if(tt == TFLOAT) {
- gins(AFCMPU, t, Z);
- p->to.type = D_FREG;
- p->to.reg = FREGZERO;
- gins(ABGE, Z, Z);
- p1 = p;
- gins(AFMOVS, nodfconst(4294967296.), &nod);
- gins(AFADDS, &nod, t);
- } else {
- gins(AFCMPU, t, Z);
- p->to.type = D_FREG;
- p->to.reg = FREGZERO;
- gins(ABGE, Z, Z);
- p1 = p;
- gins(AFMOVD, nodfconst(4294967296.), &nod);
- gins(AFADD, &nod, t);
- }
- patch(p1, pc);
- regfree(&nod);
- }
- return;
- case TINT:
- case TUINT:
- case TLONG:
- case TULONG:
- case TVLONG:
- case TUVLONG:
- case TIND:
- case TSHORT:
- case TUSHORT:
- a = AMOVBZ;
- break;
- case TCHAR:
- case TUCHAR:
- a = AMOVD;
- break;
- }
- break;
- }
- if(a == AGOK)
- diag(Z, "bad opcode in gmove %T -> %T", f->type, t->type);
- if(a == AMOVD || (a == AMOVW || a == AMOVWZ) && ewidth[ft] == ewidth[tt] || a == AFMOVS || a == AFMOVD)
- if(samaddr(f, t))
- return;
- gins(a, f, t);
-}
-
-void
-gins(int a, Node *f, Node *t)
-{
-
- nextpc();
- p->as = a;
- if(f != Z)
- naddr(f, &p->from);
- if(t != Z)
- naddr(t, &p->to);
- if(debug['g'])
- print("%P\n", p);
-}
-
-void
-gopcode(int o, Node *f1, Node *f2, Node *t)
-{
- int a, et;
- Addr ta;
- int uns;
-
- uns = 0;
- et = TLONG;
- if(f1 != Z && f1->type != T) {
- if(f1->op == OCONST && t != Z && t->type != T)
- et = t->type->etype;
- else
- et = f1->type->etype;
- }
- a = AGOK;
- switch(o) {
- case OAS:
- gmove(f1, t);
- return;
-
- case OASADD:
- case OADD:
- a = AADD;
- if(et == TFLOAT)
- a = AFADDS;
- else
- if(et == TDOUBLE)
- a = AFADD;
- break;
-
- case OASSUB:
- case OSUB:
- a = ASUB;
- if(et == TFLOAT)
- a = AFSUBS;
- else
- if(et == TDOUBLE)
- a = AFSUB;
- break;
-
- case OASOR:
- case OOR:
- a = AOR;
- break;
-
- case OASAND:
- case OAND:
- a = AAND;
- if(f1->op == OCONST)
- a = AANDCC;
- break;
-
- case OASXOR:
- case OXOR:
- a = AXOR;
- break;
-
- case OASLSHR:
- case OLSHR:
- a = ASRW;
- if(isv(et))
- a = ASRD;
- break;
-
- case OASASHR:
- case OASHR:
- a = ASRAW;
- if(isv(et))
- a = ASRAD;
- break;
-
- case OASASHL:
- case OASHL:
- a = ASLW;
- if(isv(et))
- a = ASLD;
- break;
-
- case OFUNC:
- a = ABL;
- break;
-
- case OASLMUL:
- case OLMUL:
- case OASMUL:
- case OMUL:
- if(et == TFLOAT) {
- a = AFMULS;
- break;
- } else
- if(et == TDOUBLE) {
- a = AFMUL;
- break;
- }
- a = AMULLW;
- if(isv(et))
- a = AMULLD;
- break;
-
- case OASDIV:
- case ODIV:
- if(et == TFLOAT) {
- a = AFDIVS;
- break;
- } else
- if(et == TDOUBLE) {
- a = AFDIV;
- break;
- } else
- a = ADIVW;
- if(isv(et))
- a = ADIVD;
- break;
-
- case OASMOD:
- case OMOD:
- a = AREM;
- if(isv(et))
- a = AREMD;
- break;
-
- case OASLMOD:
- case OLMOD:
- a = AREMU;
- if(isv(et))
- a = AREMDU;
- break;
-
- case OASLDIV:
- case OLDIV:
- a = ADIVWU;
- if(isv(et))
- a = ADIVDU;
- break;
-
- case OCOM:
- a = ANOR;
- break;
-
- case ONEG:
- a = ANEG;
- if(et == TFLOAT || et == TDOUBLE)
- a = AFNEG;
- break;
-
- case OEQ:
- a = ABEQ;
- goto cmp;
-
- case ONE:
- a = ABNE;
- goto cmp;
-
- case OLT:
- a = ABLT;
- goto cmp;
-
- case OLE:
- a = ABLE;
- goto cmp;
-
- case OGE:
- a = ABGE;
- goto cmp;
-
- case OGT:
- a = ABGT;
- goto cmp;
-
- case OLO:
- a = ABLT;
- goto cmpu;
-
- case OLS:
- a = ABLE;
- goto cmpu;
-
- case OHS:
- a = ABGE;
- goto cmpu;
-
- case OHI:
- a = ABGT;
- goto cmpu;
-
- cmpu:
- uns = 1;
- cmp:
- nextpc();
- switch(et){
- case TINT:
- case TLONG:
- p->as = ACMPW;
- break;
- case TUINT:
- case TULONG:
- p->as = ACMPWU;
- break;
- case TFLOAT:
- case TDOUBLE:
- p->as = AFCMPU;
- break;
- default:
- p->as = uns? ACMPU: ACMP;
- break;
- }
- if(f1 != Z)
- naddr(f1, &p->from);
- if(t != Z)
- naddr(t, &p->to);
- if(f1 == Z || t == Z || f2 != Z)
- diag(Z, "bad cmp in gopcode %O", o);
- if(debug['g'])
- print("%P\n", p);
- f1 = Z;
- f2 = Z;
- t = Z;
- break;
- }
- if(a == AGOK)
- diag(Z, "bad in gopcode %O", o);
- nextpc();
- p->as = a;
- if(f1 != Z)
- naddr(f1, &p->from);
- if(f2 != Z) {
- naddr(f2, &ta);
- p->reg = ta.reg;
- if(ta.type == D_CONST && ta.offset == 0) {
- if(R0ISZERO)
- p->reg = REGZERO;
- else
- diag(Z, "REGZERO in gopcode %O", o);
- }
- }
- if(t != Z)
- naddr(t, &p->to);
- if(debug['g'])
- print("%P\n", p);
-}
-
-int
-samaddr(Node *f, Node *t)
-{
- return f->op == OREGISTER && t->op == OREGISTER && f->reg == t->reg;
-}
-
-void
-gbranch(int o)
-{
- int a;
-
- a = AGOK;
- switch(o) {
- case ORETURN:
- a = ARETURN;
- break;
- case OGOTO:
- a = ABR;
- break;
- }
- nextpc();
- if(a == AGOK) {
- diag(Z, "bad in gbranch %O", o);
- nextpc();
- }
- p->as = a;
-}
-
-void
-patch(Prog *op, int32 pc)
-{
-
- op->to.offset = pc;
- op->to.type = D_BRANCH;
-}
-
-void
-gpseudo(int a, Sym *s, Node *n)
-{
-
- nextpc();
- p->as = a;
- p->from.type = D_OREG;
- p->from.sym = linksym(s);
-
- switch(a) {
- case ATEXT:
- p->reg = textflag;
- textflag = 0;
- break;
- case AGLOBL:
- p->reg = s->dataflag;
- break;
- }
-
- p->from.name = D_EXTERN;
- if(s->class == CSTATIC)
- p->from.name = D_STATIC;
- naddr(n, &p->to);
- if(a == ADATA || a == AGLOBL)
- pc--;
-}
-
-int
-sval(int32 v)
-{
-
- if(v >= -(1<<15) && v < (1<<15))
- return 1;
- return 0;
-}
-
-void
-gpcdata(int index, int value)
-{
- Node n1;
-
- n1 = *nodconst(index);
- gins(APCDATA, &n1, nodconst(value));
-}
-
-void
-gprefetch(Node *n)
-{
- // TODO(minux)
- USED(n);
- /*
- Node n1;
-
- regalloc(&n1, n, Z);
- gmove(n, &n1);
- n1.op = OINDREG;
- gins(ADCBT, &n1, Z);
- regfree(&n1);
- */
-}
-
-
-int
-sconst(Node *n)
-{
- vlong vv;
-
- if(n->op == OCONST) {
- if(!typefd[n->type->etype]) {
- vv = n->vconst;
- if(vv >= -(((vlong)1)<<15) && vv < (((vlong)1)<<15))
- return 1;
- }
- }
- return 0;
-}
-
-int
-uconst(Node *n)
-{
- vlong vv;
-
- if(n->op == OCONST) {
- if(!typefd[n->type->etype]) {
- vv = n->vconst;
- if(vv >= 0 && vv < (((vlong)1)<<16))
- return 1;
- }
- }
- return 0;
-}
-
-int
-immconst(Node *n)
-{
- vlong v;
-
- if(n->op != OCONST || typefd[n->type->etype])
- return 0;
- v = n->vconst;
- if((v & 0xFFFF) == 0)
- v >>= 16;
- if(v >= 0 && v < ((vlong)1<<16))
- return 1;
- if(v >= -((vlong)1<<15) && v <= ((vlong)1<<15))
- return 1;
- return 0;
-}
-
-int32
-exreg(Type *t)
-{
- int32 o;
-
- if(typechlpv[t->etype]) {
- if(exregoffset <= 3)
- return 0;
- o = exregoffset;
- exregoffset--;
- return o;
- }
- if(typefd[t->etype]) {
- if(exfregoffset <= 16)
- return 0;
- o = exfregoffset + NREG;
- exfregoffset--;
- return o;
- }
- return 0;
-}
-
-schar ewidth[NTYPE] =
-{
- -1, /* [TXXX] */
- SZ_CHAR, /* [TCHAR] */
- SZ_CHAR, /* [TUCHAR] */
- SZ_SHORT, /* [TSHORT] */
- SZ_SHORT, /* [TUSHORT] */
- SZ_INT, /* [TINT] */
- SZ_INT, /* [TUINT] */
- SZ_LONG, /* [TLONG] */
- SZ_LONG, /* [TULONG] */
- SZ_VLONG, /* [TVLONG] */
- SZ_VLONG, /* [TUVLONG] */
- SZ_FLOAT, /* [TFLOAT] */
- SZ_DOUBLE, /* [TDOUBLE] */
- SZ_IND, /* [TIND] */
- 0, /* [TFUNC] */
- -1, /* [TARRAY] */
- 0, /* [TVOID] */
- -1, /* [TSTRUCT] */
- -1, /* [TUNION] */
- SZ_INT, /* [TENUM] */
-};
-int32 ncast[NTYPE] =
-{
- 0, /* [TXXX] */
- BCHAR|BUCHAR, /* [TCHAR] */
- BCHAR|BUCHAR, /* [TUCHAR] */
- BSHORT|BUSHORT, /* [TSHORT] */
- BSHORT|BUSHORT, /* [TUSHORT] */
- BINT|BUINT|BLONG|BULONG, /* [TINT] */
- BINT|BUINT|BLONG|BULONG, /* [TUINT] */
- BINT|BUINT|BLONG|BULONG, /* [TLONG] */
- BINT|BUINT|BLONG|BULONG, /* [TULONG] */
- BVLONG|BUVLONG|BIND, /* [TVLONG] */
- BVLONG|BUVLONG|BIND, /* [TUVLONG] */
- BFLOAT, /* [TFLOAT] */
- BDOUBLE, /* [TDOUBLE] */
- BVLONG|BUVLONG|BIND, /* [TIND] */
- 0, /* [TFUNC] */
- 0, /* [TARRAY] */
- 0, /* [TVOID] */
- BSTRUCT, /* [TSTRUCT] */
- BUNION, /* [TUNION] */
- 0, /* [TENUM] */
-};
diff --git a/src/cmd/9g/prog.c b/src/cmd/9g/prog.c
index e3e50f28a..51c132d18 100644
--- a/src/cmd/9g/prog.c
+++ b/src/cmd/9g/prog.c
@@ -134,11 +134,12 @@ proginfo(ProgInfo *info, Prog *p)
}
if(p->as == ADUFFZERO) {
- info->reguse |= RtoB(0) | RtoB(2);
- info->regset |= RtoB(2);
+ info->reguse |= (1<<D_R0) | RtoB(3);
+ info->regset |= RtoB(3);
}
if(p->as == ADUFFCOPY) {
- info->reguse |= RtoB(0) | RtoB(2) | RtoB(3);
- info->regset |= RtoB(2) | RtoB(3);
+ // TODO(austin) Revisit when duffcopy is implemented
+ info->reguse |= RtoB(3) | RtoB(4) | RtoB(5);
+ info->regset |= RtoB(3) | RtoB(4);
}
}
diff --git a/src/cmd/9g/reg.c b/src/cmd/9g/reg.c
index b911a2399..2e546a95b 100644
--- a/src/cmd/9g/reg.c
+++ b/src/cmd/9g/reg.c
@@ -1322,7 +1322,6 @@ void
dumpit(char *str, Flow *r0, int isreg)
{
Flow *r, *r1;
- int s1v, s2v;
print("\n%s\n", str);
for(r = r0; r != nil; r = r->link) {
@@ -1334,10 +1333,8 @@ dumpit(char *str, Flow *r0, int isreg)
print(" %.4ud", (int)r1->prog->pc);
print("\n");
}
- // If at least one successor is "interesting", print both
- s1v = (r->s1 != nil) && (r->s1->prog != r->prog->link);
- s2v = (r->s2 != nil) && (r->s2->prog != r->prog->link);
- if(s1v || s2v) {
+ // Print successors if it's not just the next one
+ if(r->s1 != r->link || r->s2 != nil) {
print(" succ:");
if(r->s1 != nil)
print(" %.4ud", (int)r->s1->prog->pc);
diff --git a/src/cmd/9l/9.out.h b/src/cmd/9l/9.out.h
index 08a339318..87917f88a 100644
--- a/src/cmd/9l/9.out.h
+++ b/src/cmd/9l/9.out.h
@@ -497,6 +497,8 @@ enum
D_DCONST,
D_ADDR, // not used, use D_CONST with non-empty sym.
+ D_LAST,
+
/* reg names for 9g OREGISTER */
D_R0 = 0, // type is D_REG
D_F0 = D_R0+NREG, // type is D_FREG
diff --git a/src/cmd/cgo/doc.go b/src/cmd/cgo/doc.go
index 69c7ce893..6179c7afd 100644
--- a/src/cmd/cgo/doc.go
+++ b/src/cmd/cgo/doc.go
@@ -152,7 +152,7 @@ In C, a function argument written as a fixed size array
actually requires a pointer to the first element of the array.
C compilers are aware of this calling convention and adjust
the call accordingly, but Go cannot. In Go, you must pass
-the pointer to the first element explicitly: C.f(&x[0]).
+the pointer to the first element explicitly: C.f(&C.x[0]).
A few special functions convert between Go and C types
by making copies of the data. In pseudo-Go definitions:
diff --git a/src/cmd/dist/build.c b/src/cmd/dist/build.c
index e4f307bee..bfb3d15b8 100644
--- a/src/cmd/dist/build.c
+++ b/src/cmd/dist/build.c
@@ -615,8 +615,6 @@ static struct {
{"anames9.c", mkanames},
{"zdefaultcc.go", mkzdefaultcc},
{"zsys_", mkzsys},
- {"zgoarch_", mkzgoarch},
- {"zgoos_", mkzgoos},
{"zversion.go", mkzversion},
{"zaexperiment.h", mkzexperiment},
@@ -1419,12 +1417,13 @@ clean(void)
xremove(bpathf(&b, "%s/%s", bstr(&path), cleantab[i]+4));
}
- // remove src/runtime/z* unconditionally
+ // remove src/runtime/z* unconditionally,
+ // except leave zgoos and zgoarch, now maintained with go generate.
vreset(&dir);
bpathf(&path, "%s/src/runtime", goroot);
xreaddir(&dir, bstr(&path));
for(j=0; j<dir.len; j++) {
- if(hasprefix(dir.p[j], "z"))
+ if(hasprefix(dir.p[j], "z") && !hasprefix(dir.p[j], "zg"))
xremove(bpathf(&b, "%s/%s", bstr(&path), dir.p[j]));
}
diff --git a/src/cmd/dist/buildgc.c b/src/cmd/dist/buildgc.c
index 1c3329758..64434d51e 100644
--- a/src/cmd/dist/buildgc.c
+++ b/src/cmd/dist/buildgc.c
@@ -63,22 +63,36 @@ gcopnames(char *dir, char *file)
vfree(&fields);
}
+static int
+xatoi(char *s, char **end)
+{
+ int val = 0;
+ for(; *s && *s >= '0' && *s <= '9'; ++s)
+ val = val * 10 + (*s - '0');
+ *end = s;
+ return val;
+}
+
// mkanames reads [5689].out.h and writes anames[5689].c
// The format is much the same as the Go opcodes above.
-// it also writes out cnames array for C_* constants.
+// It also writes out cnames array for C_* constants and the dnames
+// array for D_* constants.
void
mkanames(char *dir, char *file)
{
- int i, j, ch;
+ int i, j, ch, n, unknown;
Buf in, b, out, out2;
Vec lines;
- char *p;
+ char *p, *p2;
+ Vec dnames[128];
binit(&b);
binit(&in);
binit(&out);
binit(&out2);
vinit(&lines);
+ for(i=0; i<nelem(dnames); i++)
+ vinit(&dnames[i]);
ch = file[xstrlen(file)-3];
bprintf(&b, "%s/../cmd/%cl/%c.out.h", dir, ch, ch);
@@ -87,10 +101,12 @@ mkanames(char *dir, char *file)
// Include link.h so that the extern declaration there is
// checked against the non-extern declaration we are generating.
+ bwritestr(&out, bprintf(&b, "// auto generated by go tool dist\n"));
bwritestr(&out, bprintf(&b, "#include <u.h>\n"));
bwritestr(&out, bprintf(&b, "#include <libc.h>\n"));
bwritestr(&out, bprintf(&b, "#include <bio.h>\n"));
bwritestr(&out, bprintf(&b, "#include <link.h>\n"));
+ bwritestr(&out, bprintf(&b, "#include \"../cmd/%cl/%c.out.h\"\n", ch, ch));
bwritestr(&out, bprintf(&b, "\n"));
bwritestr(&out, bprintf(&b, "char* anames%c[] = {\n", ch));
@@ -127,6 +143,69 @@ mkanames(char *dir, char *file)
if(j>0)
bwriteb(&out, &out2);
+ j=unknown=0;
+ n=-1;
+ for(i=0; i<lines.len; i++) {
+ if(hasprefix(lines.p[i], "\tD_")) {
+ p = xstrstr(lines.p[i], ",");
+ if(p)
+ *p = '\0';
+ p = xstrstr(lines.p[i], "\n");
+ if(p)
+ *p = '\0';
+
+ // Parse explicit value, if any
+ p = xstrstr(lines.p[i], "=");
+ if(p) {
+ // Skip space after '='
+ p2 = p + 1;
+ while(*p2 == ' ' || *p2 == '\t')
+ p2++;
+ n = xatoi(p2, &p2);
+ // We can't do anything about
+ // non-numeric values or anything that
+ // follows
+ while(*p2 == ' ' || *p2 == '\t')
+ p2++;
+ if(*p2 != 0) {
+ unknown = 1;
+ continue;
+ }
+ // Truncate space before '='
+ while(*(p-1) == ' ' || *(p-1) == '\t')
+ p--;
+ *p = '\0';
+ unknown = 0;
+ } else {
+ n++;
+ }
+
+ if(unknown || n >= nelem(dnames))
+ continue;
+
+ p = lines.p[i] + 3;
+ if(xstrcmp(p, "LAST") == 0)
+ continue;
+ vadd(&dnames[n], p);
+ j++;
+ }
+ }
+ if(j>0){
+ bwritestr(&out, bprintf(&b, "char* dnames%c[D_LAST] = {\n", ch));
+ for(i=0; i<nelem(dnames); i++) {
+ if(dnames[i].len == 0)
+ continue;
+ bwritestr(&out, bprintf(&b, "\t[D_%s] = \"", dnames[i].p[0]));
+ for(j=0; j<dnames[i].len; j++) {
+ if(j != 0)
+ bwritestr(&out, "/");
+ bwritestr(&out, dnames[i].p[j]);
+ }
+ bwritestr(&out, "\",\n");
+ }
+ bwritestr(&out, "};\n");
+ }
+
writefile(&out, file, 0);
bfree(&b);
@@ -134,4 +213,6 @@ mkanames(char *dir, char *file)
bfree(&out);
bfree(&out2);
vfree(&lines);
+ for(i=0; i<nelem(dnames); i++)
+ vfree(&dnames[i]);
}
diff --git a/src/cmd/dist/buildruntime.c b/src/cmd/dist/buildruntime.c
index e561937fb..38e99e116 100644
--- a/src/cmd/dist/buildruntime.c
+++ b/src/cmd/dist/buildruntime.c
@@ -67,66 +67,6 @@ mkzexperiment(char *dir, char *file)
bfree(&exp);
}
-// mkzgoarch writes zgoarch_$GOARCH.go:
-//
-// package runtime
-// const theGoarch = <goarch>
-//
-void
-mkzgoarch(char *dir, char *file)
-{
- Buf b, out;
-
- USED(dir);
-
- binit(&b);
- binit(&out);
-
- bwritestr(&out, bprintf(&b,
- "// auto generated by go tool dist\n"
- "\n"
- "package runtime\n"
- "\n"
- "const theGoarch = `%s`\n", goarch));
-
- writefile(&out, file, 0);
-
- bfree(&b);
- bfree(&out);
-}
-
-// mkzgoos writes zgoos_$GOOS.go:
-//
-// package runtime
-// const theGoos = <goos>
-//
-void
-mkzgoos(char *dir, char *file)
-{
- Buf b, out;
-
- USED(dir);
-
- binit(&b);
- binit(&out);
-
- bwritestr(&out, "// auto generated by go tool dist\n\n");
-
- if(streq(goos, "linux")) {
- bwritestr(&out, "// +build !android\n\n");
- }
-
- bwritestr(&out, bprintf(&b,
- "package runtime\n"
- "\n"
- "const theGoos = `%s`\n", goos));
-
- writefile(&out, file, 0);
-
- bfree(&b);
- bfree(&out);
-}
-
#define MAXWINCB 2000 /* maximum number of windows callbacks allowed */
// mkzsys writes zsys_$GOOS_$GOARCH.s,
diff --git a/src/cmd/gc/walk.c b/src/cmd/gc/walk.c
index 37bd62dea..061089349 100644
--- a/src/cmd/gc/walk.c
+++ b/src/cmd/gc/walk.c
@@ -1776,7 +1776,6 @@ walkprint(Node *nn, NodeList **init)
int notfirst, et, op;
NodeList *calls;
- on = nil;
op = nn->op;
all = nn->list;
calls = nil;
diff --git a/src/cmd/go/tool.go b/src/cmd/go/tool.go
index c96161e0f..3f11c3e3d 100644
--- a/src/cmd/go/tool.go
+++ b/src/cmd/go/tool.go
@@ -47,7 +47,7 @@ const toolWindowsExtension = ".exe"
func tool(toolName string) string {
toolPath := filepath.Join(toolDir, toolName)
- if toolIsWindows && toolName != "pprof" {
+ if toolIsWindows {
toolPath += toolWindowsExtension
}
// Give a nice message if there is no tool with that name.
@@ -91,16 +91,6 @@ func runTool(cmd *Command, args []string) {
if toolPath == "" {
return
}
- if toolIsWindows && toolName == "pprof" {
- args = append([]string{"perl", toolPath}, args[1:]...)
- var err error
- toolPath, err = exec.LookPath("perl")
- if err != nil {
- fmt.Fprintf(os.Stderr, "go tool: perl not found\n")
- setExitStatus(3)
- return
- }
- }
if toolN {
fmt.Printf("%s %s\n", toolPath, strings.Join(args[1:], " "))
return
diff --git a/src/cmd/internal/goobj/read.go b/src/cmd/internal/goobj/read.go
new file mode 100644
index 000000000..79a83e59a
--- /dev/null
+++ b/src/cmd/internal/goobj/read.go
@@ -0,0 +1,666 @@
+// Copyright 2013 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.
+
+// Package goobj implements reading of Go object files and archives.
+//
+// TODO(rsc): Decide where this package should live. (golang.org/issue/6932)
+// TODO(rsc): Decide the appropriate integer types for various fields.
+// TODO(rsc): Write tests. (File format still up in the air a little.)
+package goobj
+
+import (
+ "bufio"
+ "bytes"
+ "errors"
+ "fmt"
+ "io"
+ "strconv"
+ "strings"
+)
+
+// A SymKind describes the kind of memory represented by a symbol.
+type SymKind int
+
+// This list is taken from include/link.h.
+
+// Defined SymKind values.
+// TODO(rsc): Give idiomatic Go names.
+// TODO(rsc): Reduce the number of symbol types in the object files.
+const (
+ _ SymKind = iota
+
+ // readonly, executable
+ STEXT
+ SELFRXSECT
+
+ // readonly, non-executable
+ STYPE
+ SSTRING
+ SGOSTRING
+ SGOFUNC
+ SRODATA
+ SFUNCTAB
+ STYPELINK
+ SSYMTAB // TODO: move to unmapped section
+ SPCLNTAB
+ SELFROSECT
+
+ // writable, non-executable
+ SMACHOPLT
+ SELFSECT
+ SMACHO // Mach-O __nl_symbol_ptr
+ SMACHOGOT
+ SNOPTRDATA
+ SINITARR
+ SDATA
+ SWINDOWS
+ SBSS
+ SNOPTRBSS
+ STLSBSS
+
+ // not mapped
+ SXREF
+ SMACHOSYMSTR
+ SMACHOSYMTAB
+ SMACHOINDIRECTPLT
+ SMACHOINDIRECTGOT
+ SFILE
+ SFILEPATH
+ SCONST
+ SDYNIMPORT
+ SHOSTOBJ
+)
+
+var symKindStrings = []string{
+ SBSS: "SBSS",
+ SCONST: "SCONST",
+ SDATA: "SDATA",
+ SDYNIMPORT: "SDYNIMPORT",
+ SELFROSECT: "SELFROSECT",
+ SELFRXSECT: "SELFRXSECT",
+ SELFSECT: "SELFSECT",
+ SFILE: "SFILE",
+ SFILEPATH: "SFILEPATH",
+ SFUNCTAB: "SFUNCTAB",
+ SGOFUNC: "SGOFUNC",
+ SGOSTRING: "SGOSTRING",
+ SHOSTOBJ: "SHOSTOBJ",
+ SINITARR: "SINITARR",
+ SMACHO: "SMACHO",
+ SMACHOGOT: "SMACHOGOT",
+ SMACHOINDIRECTGOT: "SMACHOINDIRECTGOT",
+ SMACHOINDIRECTPLT: "SMACHOINDIRECTPLT",
+ SMACHOPLT: "SMACHOPLT",
+ SMACHOSYMSTR: "SMACHOSYMSTR",
+ SMACHOSYMTAB: "SMACHOSYMTAB",
+ SNOPTRBSS: "SNOPTRBSS",
+ SNOPTRDATA: "SNOPTRDATA",
+ SPCLNTAB: "SPCLNTAB",
+ SRODATA: "SRODATA",
+ SSTRING: "SSTRING",
+ SSYMTAB: "SSYMTAB",
+ STEXT: "STEXT",
+ STLSBSS: "STLSBSS",
+ STYPE: "STYPE",
+ STYPELINK: "STYPELINK",
+ SWINDOWS: "SWINDOWS",
+ SXREF: "SXREF",
+}
+
+func (k SymKind) String() string {
+ if k < 0 || int(k) >= len(symKindStrings) {
+ return fmt.Sprintf("SymKind(%d)", k)
+ }
+ return symKindStrings[k]
+}
+
+// A Sym is a named symbol in an object file.
+type Sym struct {
+ SymID // symbol identifier (name and version)
+ Kind SymKind // kind of symbol
+ DupOK bool // are duplicate definitions okay?
+ Size int // size of corresponding data
+ Type SymID // symbol for Go type information
+ Data Data // memory image of symbol
+ Reloc []Reloc // relocations to apply to Data
+ Func *Func // additional data for functions
+}
+
+// A SymID - the combination of Name and Version - uniquely identifies
+// a symbol within a package.
+type SymID struct {
+ // Name is the name of a symbol.
+ Name string
+
+ // Version is zero for symbols with global visibility.
+ // Symbols with only file visibility (such as file-level static
+ // declarations in C) have a non-zero version distinguishing
+ // a symbol in one file from a symbol of the same name
+ // in another file
+ Version int
+}
+
+func (s SymID) String() string {
+ if s.Version == 0 {
+ return s.Name
+ }
+ return fmt.Sprintf("%s<%d>", s.Name, s.Version)
+}
+
+// A Data is a reference to data stored in an object file.
+// It records the offset and size of the data, so that a client can
+// read the data only if necessary.
+type Data struct {
+ Offset int64
+ Size int64
+}
+
+// A Reloc describes a relocation applied to a memory image to refer
+// to an address within a particular symbol.
+type Reloc struct {
+ // The bytes at [Offset, Offset+Size) within the memory image
+ // should be updated to refer to the address Add bytes after the start
+ // of the symbol Sym.
+ Offset int
+ Size int
+ Sym SymID
+ Add int
+
+ // The Type records the form of address expected in the bytes
+ // described by the previous fields: absolute, PC-relative, and so on.
+ // TODO(rsc): The interpretation of Type is not exposed by this package.
+ Type int
+}
+
+// A Var describes a variable in a function stack frame: a declared
+// local variable, an input argument, or an output result.
+type Var struct {
+ // The combination of Name, Kind, and Offset uniquely
+ // identifies a variable in a function stack frame.
+ // Using fewer of these - in particular, using only Name - does not.
+ Name string // Name of variable.
+ Kind int // TODO(rsc): Define meaning.
+ Offset int // Frame offset. TODO(rsc): Define meaning.
+
+ Type SymID // Go type for variable.
+}
+
+// Func contains additional per-symbol information specific to functions.
+type Func struct {
+ Args int // size in bytes of argument frame: inputs and outputs
+ Frame int // size in bytes of local variable frame
+ Leaf bool // function omits save of link register (ARM)
+ NoSplit bool // function omits stack split prologue
+ Var []Var // detail about local variables
+ PCSP Data // PC → SP offset map
+ PCFile Data // PC → file number map (index into File)
+ PCLine Data // PC → line number map
+ PCData []Data // PC → runtime support data map
+ FuncData []FuncData // non-PC-specific runtime support data
+ File []string // paths indexed by PCFile
+}
+
+// TODO: Add PCData []byte and PCDataIter (similar to liblink).
+
+// A FuncData is a single function-specific data value.
+type FuncData struct {
+ Sym SymID // symbol holding data
+ Offset int64 // offset into symbol for funcdata pointer
+}
+
+// A Package is a parsed Go object file or archive defining a Go package.
+type Package struct {
+ ImportPath string // import path denoting this package
+ Imports []string // packages imported by this package
+ Syms []*Sym // symbols defined by this package
+ MaxVersion int // maximum Version in any SymID in Syms
+}
+
+var (
+ archiveHeader = []byte("!<arch>\n")
+ archiveMagic = []byte("`\n")
+ goobjHeader = []byte("go objec") // truncated to size of archiveHeader
+
+ errCorruptArchive = errors.New("corrupt archive")
+ errTruncatedArchive = errors.New("truncated archive")
+ errNotArchive = errors.New("unrecognized archive format")
+
+ errCorruptObject = errors.New("corrupt object file")
+ errTruncatedObject = errors.New("truncated object file")
+ errNotObject = errors.New("unrecognized object file format")
+)
+
+// An objReader is an object file reader.
+type objReader struct {
+ p *Package
+ b *bufio.Reader
+ f io.ReadSeeker
+ err error
+ offset int64
+ limit int64
+ tmp [256]byte
+ pkg string
+ pkgprefix string
+}
+
+// importPathToPrefix returns the prefix that will be used in the
+// final symbol table for the given import path.
+// We escape '%', '"', all control characters and non-ASCII bytes,
+// and any '.' after the final slash.
+//
+// See ../../../cmd/ld/lib.c:/^pathtoprefix and
+// ../../../cmd/gc/subr.c:/^pathtoprefix.
+func importPathToPrefix(s string) string {
+ // find index of last slash, if any, or else -1.
+ // used for determining whether an index is after the last slash.
+ slash := strings.LastIndex(s, "/")
+
+ // check for chars that need escaping
+ n := 0
+ for r := 0; r < len(s); r++ {
+ if c := s[r]; c <= ' ' || (c == '.' && r > slash) || c == '%' || c == '"' || c >= 0x7F {
+ n++
+ }
+ }
+
+ // quick exit
+ if n == 0 {
+ return s
+ }
+
+ // escape
+ const hex = "0123456789abcdef"
+ p := make([]byte, 0, len(s)+2*n)
+ for r := 0; r < len(s); r++ {
+ if c := s[r]; c <= ' ' || (c == '.' && r > slash) || c == '%' || c == '"' || c >= 0x7F {
+ p = append(p, '%', hex[c>>4], hex[c&0xF])
+ } else {
+ p = append(p, c)
+ }
+ }
+
+ return string(p)
+}
+
+// init initializes r to read package p from f.
+func (r *objReader) init(f io.ReadSeeker, p *Package) {
+ r.f = f
+ r.p = p
+ r.offset, _ = f.Seek(0, 1)
+ r.limit, _ = f.Seek(0, 2)
+ f.Seek(r.offset, 0)
+ r.b = bufio.NewReader(f)
+ r.pkgprefix = importPathToPrefix(p.ImportPath) + "."
+}
+
+// error records that an error occurred.
+// It returns only the first error, so that an error
+// caused by an earlier error does not discard information
+// about the earlier error.
+func (r *objReader) error(err error) error {
+ if r.err == nil {
+ if err == io.EOF {
+ err = io.ErrUnexpectedEOF
+ }
+ r.err = err
+ }
+ // panic("corrupt") // useful for debugging
+ return r.err
+}
+
+// readByte reads and returns a byte from the input file.
+// On I/O error or EOF, it records the error but returns byte 0.
+// A sequence of 0 bytes will eventually terminate any
+// parsing state in the object file. In particular, it ends the
+// reading of a varint.
+func (r *objReader) readByte() byte {
+ if r.err != nil {
+ return 0
+ }
+ if r.offset >= r.limit {
+ r.error(io.ErrUnexpectedEOF)
+ return 0
+ }
+ b, err := r.b.ReadByte()
+ if err != nil {
+ if err == io.EOF {
+ err = io.ErrUnexpectedEOF
+ }
+ r.error(err)
+ b = 0
+ } else {
+ r.offset++
+ }
+ return b
+}
+
+// read reads exactly len(b) bytes from the input file.
+// If an error occurs, read returns the error but also
+// records it, so it is safe for callers to ignore the result
+// as long as delaying the report is not a problem.
+func (r *objReader) readFull(b []byte) error {
+ if r.err != nil {
+ return r.err
+ }
+ if r.offset+int64(len(b)) > r.limit {
+ return r.error(io.ErrUnexpectedEOF)
+ }
+ n, err := io.ReadFull(r.b, b)
+ r.offset += int64(n)
+ if err != nil {
+ return r.error(err)
+ }
+ return nil
+}
+
+// readInt reads a zigzag varint from the input file.
+func (r *objReader) readInt() int {
+ var u uint64
+
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ r.error(errCorruptObject)
+ return 0
+ }
+ c := r.readByte()
+ u |= uint64(c&0x7F) << shift
+ if c&0x80 == 0 {
+ break
+ }
+ }
+
+ v := int64(u>>1) ^ (int64(u) << 63 >> 63)
+ if int64(int(v)) != v {
+ r.error(errCorruptObject) // TODO
+ return 0
+ }
+ return int(v)
+}
+
+// readString reads a length-delimited string from the input file.
+func (r *objReader) readString() string {
+ n := r.readInt()
+ buf := make([]byte, n)
+ r.readFull(buf)
+ return string(buf)
+}
+
+// readSymID reads a SymID from the input file.
+func (r *objReader) readSymID() SymID {
+ name, vers := r.readString(), r.readInt()
+
+ // In a symbol name in an object file, "". denotes the
+ // prefix for the package in which the object file has been found.
+ // Expand it.
+ name = strings.Replace(name, `"".`, r.pkgprefix, -1)
+
+ // An individual object file only records version 0 (extern) or 1 (static).
+ // To make static symbols unique across all files being read, we
+ // replace version 1 with the version corresponding to the current
+ // file number. The number is incremented on each call to parseObject.
+ if vers != 0 {
+ vers = r.p.MaxVersion
+ }
+
+ return SymID{name, vers}
+}
+
+// readData reads a data reference from the input file.
+func (r *objReader) readData() Data {
+ n := r.readInt()
+ d := Data{Offset: r.offset, Size: int64(n)}
+ r.skip(int64(n))
+ return d
+}
+
+// skip skips n bytes in the input.
+func (r *objReader) skip(n int64) {
+ if n < 0 {
+ r.error(fmt.Errorf("debug/goobj: internal error: misuse of skip"))
+ }
+ if n < int64(len(r.tmp)) {
+ // Since the data is so small, a just reading from the buffered
+ // reader is better than flushing the buffer and seeking.
+ r.readFull(r.tmp[:n])
+ } else if n <= int64(r.b.Buffered()) {
+ // Even though the data is not small, it has already been read.
+ // Advance the buffer instead of seeking.
+ for n > int64(len(r.tmp)) {
+ r.readFull(r.tmp[:])
+ n -= int64(len(r.tmp))
+ }
+ r.readFull(r.tmp[:n])
+ } else {
+ // Seek, giving up buffered data.
+ _, err := r.f.Seek(r.offset+n, 0)
+ if err != nil {
+ r.error(err)
+ }
+ r.offset += n
+ r.b.Reset(r.f)
+ }
+}
+
+// Parse parses an object file or archive from r,
+// assuming that its import path is pkgpath.
+func Parse(r io.ReadSeeker, pkgpath string) (*Package, error) {
+ if pkgpath == "" {
+ pkgpath = `""`
+ }
+ p := new(Package)
+ p.ImportPath = pkgpath
+
+ var rd objReader
+ rd.init(r, p)
+ err := rd.readFull(rd.tmp[:8])
+ if err != nil {
+ if err == io.EOF {
+ err = io.ErrUnexpectedEOF
+ }
+ return nil, err
+ }
+
+ switch {
+ default:
+ return nil, errNotObject
+
+ case bytes.Equal(rd.tmp[:8], archiveHeader):
+ if err := rd.parseArchive(); err != nil {
+ return nil, err
+ }
+ case bytes.Equal(rd.tmp[:8], goobjHeader):
+ if err := rd.parseObject(goobjHeader); err != nil {
+ return nil, err
+ }
+ }
+
+ return p, nil
+}
+
+// trimSpace removes trailing spaces from b and returns the corresponding string.
+// This effectively parses the form used in archive headers.
+func trimSpace(b []byte) string {
+ return string(bytes.TrimRight(b, " "))
+}
+
+// parseArchive parses a Unix archive of Go object files.
+// TODO(rsc): Need to skip non-Go object files.
+// TODO(rsc): Maybe record table of contents in r.p so that
+// linker can avoid having code to parse archives too.
+func (r *objReader) parseArchive() error {
+ for r.offset < r.limit {
+ if err := r.readFull(r.tmp[:60]); err != nil {
+ return err
+ }
+ data := r.tmp[:60]
+
+ // Each file is preceded by this text header (slice indices in first column):
+ // 0:16 name
+ // 16:28 date
+ // 28:34 uid
+ // 34:40 gid
+ // 40:48 mode
+ // 48:58 size
+ // 58:60 magic - `\n
+ // We only care about name, size, and magic.
+ // The fields are space-padded on the right.
+ // The size is in decimal.
+ // The file data - size bytes - follows the header.
+ // Headers are 2-byte aligned, so if size is odd, an extra padding
+ // byte sits between the file data and the next header.
+ // The file data that follows is padded to an even number of bytes:
+ // if size is odd, an extra padding byte is inserted betw the next header.
+ if len(data) < 60 {
+ return errTruncatedArchive
+ }
+ if !bytes.Equal(data[58:60], archiveMagic) {
+ return errCorruptArchive
+ }
+ name := trimSpace(data[0:16])
+ size, err := strconv.ParseInt(trimSpace(data[48:58]), 10, 64)
+ if err != nil {
+ return errCorruptArchive
+ }
+ data = data[60:]
+ fsize := size + size&1
+ if fsize < 0 || fsize < size {
+ return errCorruptArchive
+ }
+ switch name {
+ case "__.SYMDEF", "__.GOSYMDEF", "__.PKGDEF":
+ r.skip(size)
+ default:
+ oldLimit := r.limit
+ r.limit = r.offset + size
+ if err := r.parseObject(nil); err != nil {
+ return fmt.Errorf("parsing archive member %q: %v", name, err)
+ }
+ r.skip(r.limit - r.offset)
+ r.limit = oldLimit
+ }
+ if size&1 != 0 {
+ r.skip(1)
+ }
+ }
+ return nil
+}
+
+// parseObject parses a single Go object file.
+// The prefix is the bytes already read from the file,
+// typically in order to detect that this is an object file.
+// The object file consists of a textual header ending in "\n!\n"
+// and then the part we want to parse begins.
+// The format of that part is defined in a comment at the top
+// of src/liblink/objfile.c.
+func (r *objReader) parseObject(prefix []byte) error {
+ // TODO(rsc): Maybe use prefix and the initial input to
+ // record the header line from the file, which would
+ // give the architecture and other version information.
+
+ r.p.MaxVersion++
+ var c1, c2, c3 byte
+ for {
+ c1, c2, c3 = c2, c3, r.readByte()
+ if c3 == 0 { // NUL or EOF, either is bad
+ return errCorruptObject
+ }
+ if c1 == '\n' && c2 == '!' && c3 == '\n' {
+ break
+ }
+ }
+
+ r.readFull(r.tmp[:8])
+ if !bytes.Equal(r.tmp[:8], []byte("\x00\x00go13ld")) {
+ return r.error(errCorruptObject)
+ }
+
+ b := r.readByte()
+ if b != 1 {
+ return r.error(errCorruptObject)
+ }
+
+ // Direct package dependencies.
+ for {
+ s := r.readString()
+ if s == "" {
+ break
+ }
+ r.p.Imports = append(r.p.Imports, s)
+ }
+
+ // Symbols.
+ for {
+ if b := r.readByte(); b != 0xfe {
+ if b != 0xff {
+ return r.error(errCorruptObject)
+ }
+ break
+ }
+
+ typ := r.readInt()
+ s := &Sym{SymID: r.readSymID()}
+ r.p.Syms = append(r.p.Syms, s)
+ s.Kind = SymKind(typ)
+ flags := r.readInt()
+ s.DupOK = flags&1 != 0
+ s.Size = r.readInt()
+ s.Type = r.readSymID()
+ s.Data = r.readData()
+ s.Reloc = make([]Reloc, r.readInt())
+ for i := range s.Reloc {
+ rel := &s.Reloc[i]
+ rel.Offset = r.readInt()
+ rel.Size = r.readInt()
+ rel.Type = r.readInt()
+ rel.Add = r.readInt()
+ r.readInt() // Xadd - ignored
+ rel.Sym = r.readSymID()
+ r.readSymID() // Xsym - ignored
+ }
+
+ if s.Kind == STEXT {
+ f := new(Func)
+ s.Func = f
+ f.Args = r.readInt()
+ f.Frame = r.readInt()
+ flags := r.readInt()
+ f.Leaf = flags&1 != 0
+ f.NoSplit = r.readInt() != 0
+ f.Var = make([]Var, r.readInt())
+ for i := range f.Var {
+ v := &f.Var[i]
+ v.Name = r.readSymID().Name
+ v.Offset = r.readInt()
+ v.Kind = r.readInt()
+ v.Type = r.readSymID()
+ }
+
+ f.PCSP = r.readData()
+ f.PCFile = r.readData()
+ f.PCLine = r.readData()
+ f.PCData = make([]Data, r.readInt())
+ for i := range f.PCData {
+ f.PCData[i] = r.readData()
+ }
+ f.FuncData = make([]FuncData, r.readInt())
+ for i := range f.FuncData {
+ f.FuncData[i].Sym = r.readSymID()
+ }
+ for i := range f.FuncData {
+ f.FuncData[i].Offset = int64(r.readInt()) // TODO
+ }
+ f.File = make([]string, r.readInt())
+ for i := range f.File {
+ f.File[i] = r.readSymID().Name
+ }
+ }
+ }
+
+ r.readFull(r.tmp[:7])
+ if !bytes.Equal(r.tmp[:7], []byte("\xffgo13ld")) {
+ return r.error(errCorruptObject)
+ }
+
+ return nil
+}
diff --git a/src/cmd/internal/goobj/read_test.go b/src/cmd/internal/goobj/read_test.go
new file mode 100644
index 000000000..cc991e5d9
--- /dev/null
+++ b/src/cmd/internal/goobj/read_test.go
@@ -0,0 +1,28 @@
+// Copyright 2013 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.
+
+package goobj
+
+import "testing"
+
+var importPathToPrefixTests = []struct {
+ in string
+ out string
+}{
+ {"runtime", "runtime"},
+ {"sync/atomic", "sync/atomic"},
+ {"golang.org/x/tools/godoc", "golang.org/x/tools/godoc"},
+ {"foo.bar/baz.quux", "foo.bar/baz%2equux"},
+ {"", ""},
+ {"%foo%bar", "%25foo%25bar"},
+ {"\x01\x00\x7F☺", "%01%00%7f%e2%98%ba"},
+}
+
+func TestImportPathToPrefix(t *testing.T) {
+ for _, tt := range importPathToPrefixTests {
+ if out := importPathToPrefix(tt.in); out != tt.out {
+ t.Errorf("importPathToPrefix(%q) = %q, want %q", tt.in, out, tt.out)
+ }
+ }
+}
diff --git a/src/cmd/internal/objfile/goobj.go b/src/cmd/internal/objfile/goobj.go
index a1d773023..6b1607a17 100644
--- a/src/cmd/internal/objfile/goobj.go
+++ b/src/cmd/internal/objfile/goobj.go
@@ -7,7 +7,7 @@
package objfile
import (
- "debug/goobj"
+ "cmd/internal/goobj"
"fmt"
"os"
)
diff --git a/src/cmd/link/auto.go b/src/cmd/link/auto.go
index f9228e8ca..21f6d6082 100644
--- a/src/cmd/link/auto.go
+++ b/src/cmd/link/auto.go
@@ -10,7 +10,7 @@
package main
import (
- "debug/goobj"
+ "cmd/internal/goobj"
"strconv"
"strings"
)
diff --git a/src/cmd/link/auto_test.go b/src/cmd/link/auto_test.go
index 27f8e2b96..f99e097a9 100644
--- a/src/cmd/link/auto_test.go
+++ b/src/cmd/link/auto_test.go
@@ -13,7 +13,7 @@ package main
import (
"bytes"
- "debug/goobj"
+ "cmd/internal/goobj"
"testing"
)
diff --git a/src/cmd/link/dead.go b/src/cmd/link/dead.go
index e1e775eb3..ee23a61f8 100644
--- a/src/cmd/link/dead.go
+++ b/src/cmd/link/dead.go
@@ -6,7 +6,7 @@
package main
-import "debug/goobj"
+import "cmd/internal/goobj"
// dead removes unreachable code and data from the program.
// It is basically a mark-sweep garbage collection: traverse all the
diff --git a/src/cmd/link/dead_test.go b/src/cmd/link/dead_test.go
index 2e179b453..eb34d0580 100644
--- a/src/cmd/link/dead_test.go
+++ b/src/cmd/link/dead_test.go
@@ -5,7 +5,7 @@
package main
import (
- "debug/goobj"
+ "cmd/internal/goobj"
"reflect"
"strings"
"testing"
diff --git a/src/cmd/link/layout.go b/src/cmd/link/layout.go
index 149ebced0..d5c291e25 100644
--- a/src/cmd/link/layout.go
+++ b/src/cmd/link/layout.go
@@ -7,7 +7,7 @@
package main
import (
- "debug/goobj"
+ "cmd/internal/goobj"
)
// A layoutSection describes a single section to add to the
diff --git a/src/cmd/link/link_test.go b/src/cmd/link/link_test.go
index 984796784..b5ae15fc7 100644
--- a/src/cmd/link/link_test.go
+++ b/src/cmd/link/link_test.go
@@ -6,7 +6,7 @@ package main
import (
"bytes"
- "debug/goobj"
+ "cmd/internal/goobj"
"io/ioutil"
"testing"
)
diff --git a/src/cmd/link/pclntab.go b/src/cmd/link/pclntab.go
index 232d586bf..2d131781f 100644
--- a/src/cmd/link/pclntab.go
+++ b/src/cmd/link/pclntab.go
@@ -7,7 +7,7 @@
package main
import (
- "debug/goobj"
+ "cmd/internal/goobj"
"encoding/binary"
"os"
"sort"
diff --git a/src/cmd/link/pclntab_test.go b/src/cmd/link/pclntab_test.go
index 19953f579..ea8080674 100644
--- a/src/cmd/link/pclntab_test.go
+++ b/src/cmd/link/pclntab_test.go
@@ -6,7 +6,7 @@ package main
import (
"bytes"
- "debug/goobj"
+ "cmd/internal/goobj"
"fmt"
"math/rand"
"sort"
diff --git a/src/cmd/link/prog.go b/src/cmd/link/prog.go
index a52b5ff9b..77fb1ece5 100644
--- a/src/cmd/link/prog.go
+++ b/src/cmd/link/prog.go
@@ -5,7 +5,7 @@
package main
import (
- "debug/goobj"
+ "cmd/internal/goobj"
"encoding/binary"
"fmt"
"go/build"
diff --git a/src/cmd/link/runtime.go b/src/cmd/link/runtime.go
index b0c1ac98a..acda2d24d 100644
--- a/src/cmd/link/runtime.go
+++ b/src/cmd/link/runtime.go
@@ -7,7 +7,7 @@
package main
-import "debug/goobj"
+import "cmd/internal/goobj"
func (p *Prog) runtime() {
p.pclntab()
diff --git a/src/cmd/link/scan.go b/src/cmd/link/scan.go
index 0720e039b..7feb0d890 100644
--- a/src/cmd/link/scan.go
+++ b/src/cmd/link/scan.go
@@ -11,7 +11,7 @@
package main
import (
- "debug/goobj"
+ "cmd/internal/goobj"
"os"
"sort"
"strings"
@@ -69,7 +69,7 @@ func (p *Prog) scanFile(pkgpath string, file string) {
return
}
- // TODO(rsc): Change debug/goobj to record package name as gp.Name.
+ // TODO(rsc): Change cmd/internal/goobj to record package name as gp.Name.
// TODO(rsc): If pkgpath == "main", check that gp.Name == "main".
pkg.Package = gp
diff --git a/src/cmd/pprof/internal/report/source.go b/src/cmd/pprof/internal/report/source.go
index 57300dd91..73ae1b4ea 100644
--- a/src/cmd/pprof/internal/report/source.go
+++ b/src/cmd/pprof/internal/report/source.go
@@ -358,9 +358,13 @@ func getFunctionSource(fun, file string, fns nodes, start, end int) (nodes, stri
for {
line, err := buf.ReadString('\n')
if err != nil {
- if line == "" || err != io.EOF {
+ if err != io.EOF {
return nil, file, err
}
+ if line == "" {
+ // end was at or past EOF; that's okay
+ break
+ }
}
if lineno >= start {
flat, cum := sumNodes(lineNodes[lineno])