uint32 loc; // pc offset in this func
uint32 lineno; // source line that generated this
Prog* link; // next instruction in this func
- void* regp; // points to enclosing Reg struct
+ void* opt; // for optimizer passes
short as; // opcode
uchar reg; // doubles as width in DATA op
uchar scond;
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
+#include "../gc/popt.h"
+
#define Z N
#define Adr Addr
// A Reg is a wrapper around a single Prog (one instruction) that holds
// register optimization information while the optimizer runs.
// r->prog is the instruction.
-// r->prog->regp points back to r.
+// r->prog->opt points back to r.
struct Reg
{
void paint3(Reg*, int, int32, int);
void addreg(Adr*, int);
void dumpit(char *str, Reg *r0);
-int noreturn(Prog *p);
/*
* peep.c
};
void proginfo(ProgInfo*, Prog*);
+
+// To allow use of AJMP and ACALL in ../gc/popt.c.
+enum
+{
+ AJMP = AB,
+ ACALL = ABL,
+};
r2->link = r1;
r2->prog = p;
- p->regp = r2;
+ p->opt = r2;
r2->p1 = r;
r->s1 = r2;
[ATEXT]= {Pseudo},
[AFUNCDATA]= {Pseudo},
[APCDATA]= {Pseudo},
+ [AUNDEF]= {OK},
+ [AUSEFIELD]= {OK},
// NOP is an internal no-op that also stands
// for USED and SET annotations, not the Intel opcode.
#define NREGVAR 32
#define REGBITS ((uint32)0xffffffff)
-#define P2R(p) (Reg*)(p->reg)
void addsplits(void);
- int noreturn(Prog *p);
static int first = 0;
-static void fixjmp(Prog*);
-
Reg*
rega(void)
lastr = r;
}
r->prog = p;
- p->regp = r;
+ p->opt = r;
r1 = r->p1;
if(r1 != R) {
if(p->to.type == D_BRANCH) {
if(p->to.u.branch == P)
fatal("pnil %P", p);
- r1 = p->to.u.branch->regp;
+ r1 = p->to.u.branch->opt;
if(r1 == R)
fatal("rnil %P", p);
if(r1 == r) {
return bitno(b) - 16;
}
-static Sym* symlist[10];
-
-int
-noreturn(Prog *p)
-{
- Sym *s;
- int i;
-
- if(symlist[0] == S) {
- symlist[0] = pkglookup("panicindex", runtimepkg);
- symlist[1] = pkglookup("panicslice", runtimepkg);
- symlist[2] = pkglookup("throwinit", runtimepkg);
- symlist[3] = pkglookup("panic", runtimepkg);
- symlist[4] = pkglookup("panicwrap", runtimepkg);
- }
-
- s = p->to.sym;
- if(s == S)
- return 0;
- for(i=0; symlist[i]!=S; i++)
- if(s == symlist[i])
- return 1;
- return 0;
-}
-
void
dumpone(Reg *r)
{
// }
}
}
-
-/*
- * the code generator depends on being able to write out JMP (B)
- * instructions that it can jump to now but fill in later.
- * the linker will resolve them nicely, but they make the code
- * longer and more difficult to follow during debugging.
- * remove them.
- */
-
-/* what instruction does a JMP to p eventually land on? */
-static Prog*
-chasejmp(Prog *p, int *jmploop)
-{
- int n;
-
- n = 0;
- while(p != P && p->as == AB && p->to.type == D_BRANCH) {
- if(++n > 10) {
- *jmploop = 1;
- break;
- }
- p = p->to.u.branch;
- }
- return p;
-}
-
-/*
- * reuse reg pointer for mark/sweep state.
- * leave reg==nil at end because alive==nil.
- */
-#define alive ((void*)0)
-#define dead ((void*)1)
-
-/* mark all code reachable from firstp as alive */
-static void
-mark(Prog *firstp)
-{
- Prog *p;
-
- for(p=firstp; p; p=p->link) {
- if(p->regp != dead)
- break;
- p->regp = alive;
- if(p->as != ABL && p->to.type == D_BRANCH && p->to.u.branch)
- mark(p->to.u.branch);
- if(p->as == AB || p->as == ARET || (p->as == ABL && noreturn(p)))
- break;
- }
-}
-
-static void
-fixjmp(Prog *firstp)
-{
- int jmploop;
- Prog *p, *last;
-
- if(debug['R'] && debug['v'])
- print("\nfixjmp\n");
-
- // pass 1: resolve jump to B, mark all code as dead.
- jmploop = 0;
- for(p=firstp; p; p=p->link) {
- if(debug['R'] && debug['v'])
- print("%P\n", p);
- if(p->as != ABL && p->to.type == D_BRANCH && p->to.u.branch && p->to.u.branch->as == AB) {
- p->to.u.branch = chasejmp(p->to.u.branch, &jmploop);
- if(debug['R'] && debug['v'])
- print("->%P\n", p);
- }
- p->regp = dead;
- }
- if(debug['R'] && debug['v'])
- print("\n");
-
- // pass 2: mark all reachable code alive
- mark(firstp);
-
- // pass 3: delete dead code (mostly JMPs).
- last = nil;
- for(p=firstp; p; p=p->link) {
- if(p->regp == dead) {
- if(p->link == P && p->as == ARET && last && last->as != ARET) {
- // This is the final ARET, and the code so far doesn't have one.
- // Let it stay.
- } else {
- if(debug['R'] && debug['v'])
- print("del %P\n", p);
- continue;
- }
- }
- if(last)
- last->link = p;
- last = p;
- }
- last->link = P;
-
- // pass 4: elide JMP to next instruction.
- // only safe if there are no jumps to JMPs anymore.
- if(!jmploop) {
- last = nil;
- for(p=firstp; p; p=p->link) {
- if(p->as == AB && p->to.type == D_BRANCH && p->to.u.branch == p->link) {
- if(debug['R'] && debug['v'])
- print("del %P\n", p);
- continue;
- }
- if(last)
- last->link = p;
- last = p;
- }
- last->link = P;
- }
-
- if(debug['R'] && debug['v']) {
- print("\n");
- for(p=firstp; p; p=p->link)
- print("%P\n", p);
- print("\n");
- }
-}
Addr from; // src address
Addr to; // dst address
Prog* link; // next instruction in this func
- void* reg; // pointer to containing Reg struct
+ void* opt; // for optimizer passes
};
#define TEXTFLAG from.scale
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
+#include "../gc/popt.h"
+
#define Z N
#define Adr Addr
// A Reg is a wrapper around a single Prog (one instruction) that holds
// register optimization information while the optimizer runs.
// r->prog is the instruction.
-// r->prog->regp points back to r.
+// r->prog->opt points back to r.
struct Reg
{
void addreg(Adr*, int);
void dumpone(Reg*);
void dumpit(char*, Reg*);
-int noreturn(Prog *p);
/*
* peep.c
r2->link = r1;
r2->prog = p;
- p->reg = r2;
+ p->opt = r2;
r2->p1 = r;
r->s1 = r2;
[ATEXT]= {Pseudo},
[AFUNCDATA]= {Pseudo},
[APCDATA]= {Pseudo},
+ [AUNDEF]= {OK},
+ [AUSEFIELD]= {OK},
// NOP is an internal no-op that also stands
// for USED and SET annotations, not the Intel opcode.
[ANOP]= {LeftRead | RightWrite},
-
[AADCL]= {SizeL | LeftRead | RightRdwr | SetCarry | UseCarry},
[AADCQ]= {SizeQ | LeftRead | RightRdwr | SetCarry | UseCarry},
[AADCW]= {SizeW | LeftRead | RightRdwr | SetCarry | UseCarry},
[AUCOMISD]= {SizeD | LeftRead | RightRead},
[AUCOMISS]= {SizeF | LeftRead | RightRead},
- [AUNDEF]= {OK},
-
- [AUSEFIELD]= {OK},
-
[AXCHGB]= {SizeB | LeftRdwr | RightRdwr},
[AXCHGL]= {SizeL | LeftRdwr | RightRdwr},
[AXCHGQ]= {SizeQ | LeftRdwr | RightRdwr},
#define NREGVAR 32 /* 16 general + 16 floating */
#define REGBITS ((uint32)0xffffffff)
-#define P2R(p) (Reg*)(p->reg)
static int first = 1;
static Node* regnodes[NREGVAR];
-static void fixjmp(Prog*);
-
void
regopt(Prog *firstp)
{
lastr = r;
}
r->prog = p;
- p->reg = r;
+ p->opt = r;
r1 = r->p1;
if(r1 != R) {
if(p->to.type == D_BRANCH) {
if(p->to.u.branch == P)
fatal("pnil %P", p);
- r1 = p->to.u.branch->reg;
+ r1 = p->to.u.branch->opt;
if(r1 == R)
fatal("rnil %P", p);
if(r1 == r) {
// }
}
}
-
-static Sym* symlist[10];
-
-int
-noreturn(Prog *p)
-{
- Sym *s;
- int i;
-
- if(symlist[0] == S) {
- symlist[0] = pkglookup("panicindex", runtimepkg);
- symlist[1] = pkglookup("panicslice", runtimepkg);
- symlist[2] = pkglookup("throwinit", runtimepkg);
- symlist[3] = pkglookup("panic", runtimepkg);
- symlist[4] = pkglookup("panicwrap", runtimepkg);
- }
-
- s = p->to.sym;
- if(s == S)
- return 0;
- for(i=0; symlist[i]!=S; i++)
- if(s == symlist[i])
- return 1;
- return 0;
-}
-
-/*
- * the code generator depends on being able to write out JMP
- * instructions that it can jump to now but fill in later.
- * the linker will resolve them nicely, but they make the code
- * longer and more difficult to follow during debugging.
- * remove them.
- */
-
-/* what instruction does a JMP to p eventually land on? */
-static Prog*
-chasejmp(Prog *p, int *jmploop)
-{
- int n;
-
- n = 0;
- while(p != P && p->as == AJMP && p->to.type == D_BRANCH) {
- if(++n > 10) {
- *jmploop = 1;
- break;
- }
- p = p->to.u.branch;
- }
- return p;
-}
-
-/*
- * reuse reg pointer for mark/sweep state.
- * leave reg==nil at end because alive==nil.
- */
-#define alive ((void*)0)
-#define dead ((void*)1)
-
-/* mark all code reachable from firstp as alive */
-static void
-mark(Prog *firstp)
-{
- Prog *p;
-
- for(p=firstp; p; p=p->link) {
- if(p->reg != dead)
- break;
- p->reg = alive;
- if(p->as != ACALL && p->to.type == D_BRANCH && p->to.u.branch)
- mark(p->to.u.branch);
- if(p->as == AJMP || p->as == ARET || p->as == AUNDEF)
- break;
- }
-}
-
-static void
-fixjmp(Prog *firstp)
-{
- int jmploop;
- Prog *p, *last;
-
- if(debug['R'] && debug['v'])
- print("\nfixjmp\n");
-
- // pass 1: resolve jump to AJMP, mark all code as dead.
- jmploop = 0;
- for(p=firstp; p; p=p->link) {
- if(debug['R'] && debug['v'])
- print("%P\n", p);
- if(p->as != ACALL && p->to.type == D_BRANCH && p->to.u.branch && p->to.u.branch->as == AJMP) {
- p->to.u.branch = chasejmp(p->to.u.branch, &jmploop);
- if(debug['R'] && debug['v'])
- print("->%P\n", p);
- }
- p->reg = dead;
- }
- if(debug['R'] && debug['v'])
- print("\n");
-
- // pass 2: mark all reachable code alive
- mark(firstp);
-
- // pass 3: delete dead code (mostly JMPs).
- last = nil;
- for(p=firstp; p; p=p->link) {
- if(p->reg == dead) {
- if(p->link == P && p->as == ARET && last && last->as != ARET) {
- // This is the final ARET, and the code so far doesn't have one.
- // Let it stay.
- } else {
- if(debug['R'] && debug['v'])
- print("del %P\n", p);
- continue;
- }
- }
- if(last)
- last->link = p;
- last = p;
- }
- last->link = P;
-
- // pass 4: elide JMP to next instruction.
- // only safe if there are no jumps to JMPs anymore.
- if(!jmploop) {
- last = nil;
- for(p=firstp; p; p=p->link) {
- if(p->as == AJMP && p->to.type == D_BRANCH && p->to.u.branch == p->link) {
- if(debug['R'] && debug['v'])
- print("del %P\n", p);
- continue;
- }
- if(last)
- last->link = p;
- last = p;
- }
- last->link = P;
- }
-
- if(debug['R'] && debug['v']) {
- print("\n");
- for(p=firstp; p; p=p->link)
- print("%P\n", p);
- print("\n");
- }
-}
Addr from; // src address
Addr to; // dst address
Prog* link; // next instruction in this func
- void* reg; // pointer to containing Reg struct
+ void* opt; // for optimizer passes
};
#define TEXTFLAG from.scale
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
+#include "../gc/popt.h"
+
#define Z N
#define Adr Addr
// A Reg is a wrapper around a single Prog (one instruction) that holds
// register optimization information while the optimizer runs.
// r->prog is the instruction.
-// r->prog->regp points back to r.
+// r->prog->opt points back to r.
struct Reg
{
void addreg(Adr*, int);
void dumpone(Reg*);
void dumpit(char*, Reg*);
-int noreturn(Prog *p);
/*
* peep.c
r2->link = r1;
r2->prog = p;
- p->reg = r2;
+ p->opt = r2;
r2->p1 = r;
r->s1 = r2;
[ATEXT]= {Pseudo},
[AFUNCDATA]= {Pseudo},
[APCDATA]= {Pseudo},
+ [AUNDEF]= {OK},
+ [AUSEFIELD]= {OK},
// NOP is an internal no-op that also stands
// for USED and SET annotations, not the Intel opcode.
[AUCOMISD]= {SizeD | LeftRead | RightRead},
[AUCOMISS]= {SizeF | LeftRead | RightRead},
- [AUNDEF]= {OK},
-
- [AUSEFIELD]= {OK},
-
[AXCHGB]= {SizeB | LeftRdwr | RightRdwr},
[AXCHGL]= {SizeL | LeftRdwr | RightRdwr},
[AXCHGW]= {SizeW | LeftRdwr | RightRdwr},
#define NREGVAR 16 /* 8 integer + 8 floating */
#define REGBITS ((uint32)0xffff)
-#define P2R(p) (Reg*)(p->reg)
static int first = 1;
-static void fixjmp(Prog*);
static void fixtemp(Prog*);
Reg*
lastr = r;
}
r->prog = p;
- p->reg = r;
+ p->opt = r;
r1 = r->p1;
if(r1 != R) {
if(p->to.type == D_BRANCH) {
if(p->to.u.branch == P)
fatal("pnil %P", p);
- r1 = p->to.u.branch->reg;
+ r1 = p->to.u.branch->opt;
if(r1 == R)
fatal("rnil %P", p);
if(r1 == r) {
}
}
-static Sym* symlist[10];
-
-int
-noreturn(Prog *p)
-{
- Sym *s;
- int i;
-
- if(symlist[0] == S) {
- symlist[0] = pkglookup("panicindex", runtimepkg);
- symlist[1] = pkglookup("panicslice", runtimepkg);
- symlist[2] = pkglookup("throwinit", runtimepkg);
- symlist[3] = pkglookup("panic", runtimepkg);
- symlist[4] = pkglookup("panicwrap", runtimepkg);
- }
-
- s = p->to.sym;
- if(s == S)
- return 0;
- for(i=0; symlist[i]!=S; i++)
- if(s == symlist[i])
- return 1;
- return 0;
-}
-
-/*
- * the code generator depends on being able to write out JMP
- * instructions that it can jump to now but fill in later.
- * the linker will resolve them nicely, but they make the code
- * longer and more difficult to follow during debugging.
- * remove them.
- */
-
-/* what instruction does a JMP to p eventually land on? */
-static Prog*
-chasejmp(Prog *p, int *jmploop)
-{
- int n;
-
- n = 0;
- while(p != P && p->as == AJMP && p->to.type == D_BRANCH) {
- if(++n > 10) {
- *jmploop = 1;
- break;
- }
- p = p->to.u.branch;
- }
- return p;
-}
-
-/*
- * reuse reg pointer for mark/sweep state.
- * leave reg==nil at end because alive==nil.
- */
-#define alive ((void*)0)
-#define dead ((void*)1)
-
-/* mark all code reachable from firstp as alive */
-static void
-mark(Prog *firstp)
-{
- Prog *p;
-
- for(p=firstp; p; p=p->link) {
- if(p->reg != dead)
- break;
- p->reg = alive;
- if(p->as != ACALL && p->to.type == D_BRANCH && p->to.u.branch)
- mark(p->to.u.branch);
- if(p->as == AJMP || p->as == ARET || p->as == AUNDEF)
- break;
- }
-}
-
-static void
-fixjmp(Prog *firstp)
-{
- int jmploop;
- Prog *p, *last;
-
- if(debug['R'] && debug['v'])
- print("\nfixjmp\n");
-
- // pass 1: resolve jump to AJMP, mark all code as dead.
- jmploop = 0;
- for(p=firstp; p; p=p->link) {
- if(debug['R'] && debug['v'])
- print("%P\n", p);
- if(p->as != ACALL && p->to.type == D_BRANCH && p->to.u.branch && p->to.u.branch->as == AJMP) {
- p->to.u.branch = chasejmp(p->to.u.branch, &jmploop);
- if(debug['R'] && debug['v'])
- print("->%P\n", p);
- }
- p->reg = dead;
- }
- if(debug['R'] && debug['v'])
- print("\n");
-
- // pass 2: mark all reachable code alive
- mark(firstp);
-
- // pass 3: delete dead code (mostly JMPs).
- last = nil;
- for(p=firstp; p; p=p->link) {
- if(p->reg == dead) {
- if(p->link == P && p->as == ARET && last && last->as != ARET) {
- // This is the final ARET, and the code so far doesn't have one.
- // Let it stay.
- } else {
- if(debug['R'] && debug['v'])
- print("del %P\n", p);
- continue;
- }
- }
- if(last)
- last->link = p;
- last = p;
- }
- last->link = P;
-
- // pass 4: elide JMP to next instruction.
- // only safe if there are no jumps to JMPs anymore.
- if(!jmploop) {
- last = nil;
- for(p=firstp; p; p=p->link) {
- if(p->as == AJMP && p->to.type == D_BRANCH && p->to.u.branch == p->link) {
- if(debug['R'] && debug['v'])
- print("del %P\n", p);
- continue;
- }
- if(last)
- last->link = p;
- last = p;
- }
- last->link = P;
- }
-
- if(debug['R'] && debug['v']) {
- print("\n");
- for(p=firstp; p; p=p->link)
- print("%P\n", p);
- print("\n");
- }
-}
-
static uint32
fnv1(Sym *sym)
{
{"cmd/gc", {
"-cplx.c",
"-pgen.c",
+ "-popt.c",
"-y1.tab.c", // makefile dreg
"opnames.h",
}},
{"cmd/5g", {
"../gc/cplx.c",
"../gc/pgen.c",
+ "../gc/popt.c",
+ "../gc/popt.h",
"../5l/enam.c",
"$GOROOT/pkg/obj/$GOOS_$GOARCH/libgc.a",
}},
{"cmd/6g", {
"../gc/cplx.c",
"../gc/pgen.c",
+ "../gc/popt.c",
+ "../gc/popt.h",
"../6l/enam.c",
"$GOROOT/pkg/obj/$GOOS_$GOARCH/libgc.a",
}},
{"cmd/8g", {
"../gc/cplx.c",
"../gc/pgen.c",
+ "../gc/popt.c",
+ "../gc/popt.h",
"../8l/enam.c",
"$GOROOT/pkg/obj/$GOOS_$GOARCH/libgc.a",
}},
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// "Portable" code generation.
+// Compiled separately for 5g, 6g, and 8g, so allowed to use gg.h, opt.h.
+// Must code to the intersection of the three back ends.
+
#include <u.h>
#include <libc.h>
#include "gg.h"
--- /dev/null
+// Derived from Inferno utils/6c/reg.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6c/reg.c
+//
+// 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-2007 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-2007 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.
+
+// "Portable" optimizations.
+// Compiled separately for 5g, 6g, and 8g, so allowed to use gg.h, opt.h.
+// Must code to the intersection of the three back ends.
+
+#include <u.h>
+#include <libc.h>
+#include "gg.h"
+#include "opt.h"
+
+// p is a call instruction. Does the call fail to return?
+int
+noreturn(Prog *p)
+{
+ Sym *s;
+ int i;
+ static Sym* symlist[10];
+
+ if(symlist[0] == S) {
+ symlist[0] = pkglookup("panicindex", runtimepkg);
+ symlist[1] = pkglookup("panicslice", runtimepkg);
+ symlist[2] = pkglookup("throwinit", runtimepkg);
+ symlist[3] = pkglookup("panic", runtimepkg);
+ symlist[4] = pkglookup("panicwrap", runtimepkg);
+ }
+
+ s = p->to.sym;
+ if(s == S)
+ return 0;
+ for(i=0; symlist[i]!=S; i++)
+ if(s == symlist[i])
+ return 1;
+ return 0;
+}
+
+// JMP chasing and removal.
+//
+// The code generator depends on being able to write out jump
+// instructions that it can jump to now but fill in later.
+// the linker will resolve them nicely, but they make the code
+// longer and more difficult to follow during debugging.
+// Remove them.
+
+/* what instruction does a JMP to p eventually land on? */
+static Prog*
+chasejmp(Prog *p, int *jmploop)
+{
+ int n;
+
+ n = 0;
+ while(p != P && p->as == AJMP && p->to.type == D_BRANCH) {
+ if(++n > 10) {
+ *jmploop = 1;
+ break;
+ }
+ p = p->to.u.branch;
+ }
+ return p;
+}
+
+/*
+ * reuse reg pointer for mark/sweep state.
+ * leave reg==nil at end because alive==nil.
+ */
+#define alive ((void*)0)
+#define dead ((void*)1)
+
+/* mark all code reachable from firstp as alive */
+static void
+mark(Prog *firstp)
+{
+ Prog *p;
+
+ for(p=firstp; p; p=p->link) {
+ if(p->opt != dead)
+ break;
+ p->opt = alive;
+ if(p->as != ACALL && p->to.type == D_BRANCH && p->to.u.branch)
+ mark(p->to.u.branch);
+ if(p->as == AJMP || p->as == ARET || p->as == AUNDEF)
+ break;
+ }
+}
+
+void
+fixjmp(Prog *firstp)
+{
+ int jmploop;
+ Prog *p, *last;
+
+ if(debug['R'] && debug['v'])
+ print("\nfixjmp\n");
+
+ // pass 1: resolve jump to jump, mark all code as dead.
+ jmploop = 0;
+ for(p=firstp; p; p=p->link) {
+ if(debug['R'] && debug['v'])
+ print("%P\n", p);
+ if(p->as != ACALL && p->to.type == D_BRANCH && p->to.u.branch && p->to.u.branch->as == AJMP) {
+ p->to.u.branch = chasejmp(p->to.u.branch, &jmploop);
+ if(debug['R'] && debug['v'])
+ print("->%P\n", p);
+ }
+ p->opt = dead;
+ }
+ if(debug['R'] && debug['v'])
+ print("\n");
+
+ // pass 2: mark all reachable code alive
+ mark(firstp);
+
+ // pass 3: delete dead code (mostly JMPs).
+ last = nil;
+ for(p=firstp; p; p=p->link) {
+ if(p->opt == dead) {
+ if(p->link == P && p->as == ARET && last && last->as != ARET) {
+ // This is the final ARET, and the code so far doesn't have one.
+ // Let it stay.
+ } else {
+ if(debug['R'] && debug['v'])
+ print("del %P\n", p);
+ continue;
+ }
+ }
+ if(last)
+ last->link = p;
+ last = p;
+ }
+ last->link = P;
+
+ // pass 4: elide JMP to next instruction.
+ // only safe if there are no jumps to JMPs anymore.
+ if(!jmploop) {
+ last = nil;
+ for(p=firstp; p; p=p->link) {
+ if(p->as == AJMP && p->to.type == D_BRANCH && p->to.u.branch == p->link) {
+ if(debug['R'] && debug['v'])
+ print("del %P\n", p);
+ continue;
+ }
+ if(last)
+ last->link = p;
+ last = p;
+ }
+ last->link = P;
+ }
+
+ if(debug['R'] && debug['v']) {
+ print("\n");
+ for(p=firstp; p; p=p->link)
+ print("%P\n", p);
+ print("\n");
+ }
+}
--- /dev/null
+// 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.
+
+void fixjmp(Prog*);
+int noreturn(Prog*);