extern Prog zprog; // zeroed Prog
+// Prog.as opcodes.
+// These are the portable opcodes, common to all architectures.
+// Each architecture defines many more arch-specific opcodes,
+// with values starting at A_ARCHSPECIFIC.
+enum {
+ AXXX = 0,
+
+ ACALL,
+ ACHECKNIL,
+ ADATA,
+ ADUFFCOPY,
+ ADUFFZERO,
+ AEND,
+ AFUNCDATA,
+ AGLOBL,
+ AJMP,
+ ANOP,
+ APCDATA,
+ ARET,
+ ATEXT,
+ ATYPE,
+ AUNDEF,
+ AUSEFIELD,
+ AVARDEF,
+ AVARKILL,
+
+ A_ARCHSPECIFIC, // first architecture-specific opcode value
+};
+
// prevent incompatible type signatures between liblink and 8l on Plan 9
#pragma incomplete struct Section
void (*preprocess)(Link*, LSym*);
void (*assemble)(Link*, LSym*);
void (*follow)(Link*, LSym*);
- int (*iscall)(Prog*);
- int (*isdata)(Prog*);
void (*progedit)(Link*, Prog*);
int minlc;
int ptrsize;
int regsize;
-
- int ACALL;
- int ADATA;
- int AEND;
- int AFUNCDATA;
- int AGLOBL;
- int AJMP;
- int ANOP;
- int APCDATA;
- int ARET;
- int ATEXT;
- int ATYPE;
- int AUSEFIELD;
};
/* executable header types */
arch.thestring = thestring;
arch.thelinkarch = thelinkarch;
arch.typedefs = typedefs;
- arch.ACALL = ABL;
- arch.ACHECKNIL = ACHECKNIL;
- arch.ADATA = ADATA;
- arch.AFUNCDATA = AFUNCDATA;
- arch.AGLOBL = AGLOBL;
- arch.AJMP = AB;
- arch.ANAME = ANAME;
- arch.ANOP = ANOP;
- arch.APCDATA = APCDATA;
- arch.ARET = ARET;
- arch.ASIGNAME = ASIGNAME;
- arch.ATEXT = ATEXT;
- arch.ATYPE = ATYPE;
- arch.AUNDEF = AUNDEF;
- arch.AVARDEF = AVARDEF;
- arch.AVARKILL = AVARKILL;
arch.MAXWIDTH = MAXWIDTH;
arch.afunclit = afunclit;
arch.anyregalloc = anyregalloc;
* prog.c
*/
void proginfo(ProgInfo*, Prog*);
-
-// To allow use of AJMP and ACALL in ../gc/popt.c.
-enum
-{
- AJMP = AB,
- ACALL = ABL,
-};
case AXXX:
case ADATA:
case AGLOBL:
- case AHISTORY:
- case ANAME:
- case ASIGNAME:
case ATEXT:
case AWORD:
case ABCASE:
enum
{
- AXXX,
-
- AAND,
+ AAND = A_ARCHSPECIFIC,
AEOR,
ASUB,
ARSB,
AMVN,
- AB,
- ABL,
-
/*
* Do not reorder or fragment the conditional branch
* opcodes, or the predication code will break
ASWPBU,
ASWPW,
- ANOP,
ARFE,
ASWI,
AMULA,
- ADATA,
- AGLOBL,
- AHISTORY,
- ANAME,
- ARET,
- ATEXT,
AWORD,
- ADYNT_,
- AINIT_,
ABCASE,
ACASE,
- AEND,
AMULL,
AMULAL,
ABXRET,
ADWORD,
- ASIGNAME,
ALDREX,
ASTREX,
APLD,
- AUNDEF,
ACLZ,
AMULAWT,
AMULAWB,
- AUSEFIELD,
- ATYPE,
- AFUNCDATA,
- APCDATA,
- ACHECKNIL,
- AVARDEF,
- AVARKILL,
- ADUFFCOPY,
- ADUFFZERO,
ADATABUNDLE,
ADATABUNDLEEND,
AMRC, // MRC/MCR
ALAST,
+
+ // aliases
+ AB = AJMP,
+ ABL = ACALL,
};
/* scond byte */
arch.thestring = thestring;
arch.thelinkarch = thelinkarch;
arch.typedefs = typedefs;
- arch.ACALL = ACALL;
- arch.ACHECKNIL = ACHECKNIL;
- arch.ADATA = ADATA;
- arch.AFUNCDATA = AFUNCDATA;
- arch.AGLOBL = AGLOBL;
- arch.AJMP = AJMP;
- arch.ANAME = ANAME;
- arch.ANOP = ANOP;
- arch.APCDATA = APCDATA;
- arch.ARET = ARET;
- arch.ASIGNAME = ASIGNAME;
- arch.ATEXT = ATEXT;
- arch.ATYPE = ATYPE;
- arch.AUNDEF = AUNDEF;
- arch.AVARDEF = AVARDEF;
- arch.AVARKILL = AVARKILL;
arch.MAXWIDTH = MAXWIDTH;
arch.afunclit = afunclit;
arch.anyregalloc = anyregalloc;
enum
{
- AXXX,
- AAAA,
+ AAAA = A_ARCHSPECIFIC,
AAAD,
AAAM,
AAAS,
ABTSL,
ABTSW,
ABYTE,
- ACALL,
ACLC,
ACLD,
ACLI,
ACMPSW,
ADAA,
ADAS,
- ADATA,
ADECB,
ADECL,
ADECQ,
ADIVL,
ADIVW,
AENTER,
- AGLOBL,
- AHISTORY,
AHLT,
AIDIVB,
AIDIVL,
AJLS,
AJLT,
AJMI,
- AJMP,
AJNE,
AJOC,
AJOS,
AMULB,
AMULL,
AMULW,
- ANAME,
ANEGB,
ANEGL,
ANEGW,
- ANOP,
ANOTB,
ANOTL,
ANOTW,
ARCRW,
AREP,
AREPN,
- ARET,
AROLB,
AROLL,
AROLW,
ATESTB,
ATESTL,
ATESTW,
- ATEXT,
AVERR,
AVERW,
AWAIT,
AFYL2X,
AFYL2XP1,
- AEND,
- ADYNT_,
- AINIT_,
- ASIGNAME,
/* extra 32-bit operations */
ACMPXCHGB,
ABSWAPL,
ABSWAPQ,
- AUNDEF,
AAESENC,
AAESENCLAST,
APSHUFD,
APCLMULQDQ,
- AUSEFIELD,
- ATYPE,
- AFUNCDATA,
- APCDATA,
- ACHECKNIL,
- AVARDEF,
- AVARKILL,
- ADUFFCOPY,
- ADUFFZERO,
ALAST
};
arch.thestring = thestring;
arch.thelinkarch = thelinkarch;
arch.typedefs = typedefs;
- arch.ACALL = ACALL;
- arch.ACHECKNIL = ACHECKNIL;
- arch.ADATA = ADATA;
- arch.AFUNCDATA = AFUNCDATA;
- arch.AGLOBL = AGLOBL;
- arch.AJMP = AJMP;
- arch.ANAME = ANAME;
- arch.ANOP = ANOP;
- arch.APCDATA = APCDATA;
- arch.ARET = ARET;
- arch.ASIGNAME = ASIGNAME;
- arch.ATEXT = ATEXT;
- arch.ATYPE = ATYPE;
- arch.AUNDEF = AUNDEF;
- arch.AVARDEF = AVARDEF;
- arch.AVARKILL = AVARKILL;
arch.MAXWIDTH = MAXWIDTH;
arch.afunclit = afunclit;
arch.anyregalloc = anyregalloc;
enum
{
- AXXX,
- AAAA,
+ AAAA = A_ARCHSPECIFIC,
AAAD,
AAAM,
AAAS,
ABTSL,
ABTSW,
ABYTE,
- ACALL,
ACLC,
ACLD,
ACLI,
ACMPSW,
ADAA,
ADAS,
- ADATA,
ADECB,
ADECL,
ADECW,
ADIVL,
ADIVW,
AENTER,
- AGLOBL,
- AHISTORY,
AHLT,
AIDIVB,
AIDIVL,
AJLS,
AJLT,
AJMI,
- AJMP,
AJNE,
AJOC,
AJOS,
AMULB,
AMULL,
AMULW,
- ANAME,
ANEGB,
ANEGL,
ANEGW,
- ANOP,
ANOTB,
ANOTL,
ANOTW,
ARCRW,
AREP,
AREPN,
- ARET,
AROLB,
AROLL,
AROLW,
ATESTB,
ATESTL,
ATESTW,
- ATEXT,
AVERR,
AVERW,
AWAIT,
AFYL2X,
AFYL2XP1,
- AEND,
- ADYNT_,
- AINIT_,
- ASIGNAME,
ACMPXCHGB,
ACMPXCHGL,
ABSWAPL,
- AUNDEF,
// SSE2
AADDPD,
APINSRD,
APSHUFB,
- AUSEFIELD,
- ATYPE,
- AFUNCDATA,
- APCDATA,
- ACHECKNIL,
- AVARDEF,
- AVARKILL,
- ADUFFCOPY,
- ADUFFZERO,
ALAST
};
arch.thestring = thestring;
arch.thelinkarch = thelinkarch;
arch.typedefs = typedefs;
- arch.ACALL = ABL;
- arch.ACHECKNIL = ACHECKNIL;
- arch.ADATA = ADATA;
- arch.AFUNCDATA = AFUNCDATA;
- arch.AGLOBL = AGLOBL;
- arch.AJMP = ABR;
- arch.ANAME = ANAME;
- arch.ANOP = ANOP;
- arch.APCDATA = APCDATA;
- arch.ARET = ARETURN;
- arch.ASIGNAME = ASIGNAME;
- arch.ATEXT = ATEXT;
- arch.ATYPE = ATYPE;
- arch.AUNDEF = AUNDEF;
- arch.AVARDEF = AVARDEF;
- arch.AVARKILL = AVARKILL;
arch.MAXWIDTH = MAXWIDTH;
arch.afunclit = afunclit;
arch.anyregalloc = anyregalloc;
int as2variant(int);
int variant2as(int, int);
-
-// To allow use of AJMP, ACALL, ARET in ../gc/popt.c.
-enum
-{
- AJMP = ABR,
- ACALL = ABL,
- ARET = ARETURN,
-};
enum
{
- AXXX,
- AADD,
+ AADD = A_ARCHSPECIFIC,
AADDCC,
AADDV,
AADDVCC,
ABEQ,
ABGE,
ABGT,
- ABL,
ABLE,
ABLT,
ABNE,
- ABR,
ABVC,
ABVS,
ACMP,
ATW,
ASYSCALL,
- ADATA,
- AGLOBL,
- AHISTORY,
- ANAME,
- ANOP,
- ARETURN,
- ATEXT,
AWORD,
- AEND,
- ADYNT,
- AINIT,
- ASIGNAME,
ARFCI,
/* more 64-bit operations */
AHRFID,
- AUNDEF,
- AUSEFIELD,
- ATYPE,
- AFUNCDATA,
- APCDATA,
- ACHECKNIL,
- AVARDEF,
- AVARKILL,
- ADUFFCOPY,
- ADUFFZERO,
-
- ALAST
+ ALAST,
+
+ // aliases
+ ABR = AJMP,
+ ABL = ACALL,
+ ARETURN = ARET,
};
/*
func mkanames(dir, file string) {
ch := file[len(file)-3]
targ := pathf("%s/../cmd/%cl/%c.out.h", dir, ch, ch)
- in := readfile(targ)
+ in := readfile(pathf("%s/../../include/link.h", dir)) + readfile(targ)
lines := splitlines(in)
// Include link.h so that the extern declaration there is
fmt.Fprintf(&out, "char* anames%c[] = {\n", ch)
for _, line := range lines {
- if strings.HasPrefix(line, "\tA") {
+ // Use all A names found in the headers,
+ // except don't use A_ARCHSPECIFIC (left to arch to define),
+ // and don't use any aliases (= A...),
+ // except do use the arch-defined alias for A_ARCHSPECIFIC.
+ if strings.Contains(line, ";") {
+ continue
+ }
+ if strings.HasPrefix(line, "\tA") && !strings.Contains(line, "\tA_") && (!strings.Contains(line, "= A") || strings.Contains(line, "= A_ARCHSPECIFIC")) {
if i := strings.Index(line, ","); i >= 0 {
line = line[:i]
}
+ if i := strings.Index(line, "="); i >= 0 {
+ line = line[:i]
+ }
if i := strings.Index(line, "\n"); i >= 0 {
line = line[:i]
}
char *thestring;
LinkArch *thelinkarch;
Typedef *typedefs;
-
- int ACALL;
- int ACHECKNIL;
- int ADATA;
- int AFUNCDATA;
- int AGLOBL;
- int AJMP;
- int ANAME;
- int ANOP;
- int APCDATA;
- int ARET;
- int ASIGNAME;
- int ATEXT;
- int ATYPE;
- int AUNDEF;
- int AVARDEF;
- int AVARKILL;
+
vlong MAXWIDTH;
void (*afunclit)(Addr*, Node*);
pnod = newname(sym);
pnod->class = PEXTERN;
nodconst(&nod, types[TINT32], funcdatakind);
- arch.gins(arch.AFUNCDATA, &nod, pnod);
+ arch.gins(AFUNCDATA, &nod, pnod);
return sym;
}
void
gvardef(Node *n)
{
- gvardefx(n, arch.AVARDEF);
+ gvardefx(n, AVARDEF);
}
void
gvarkill(Node *n)
{
- gvardefx(n, arch.AVARKILL);
+ gvardefx(n, AVARKILL);
}
static void
Prog *p;
for(p = firstp; p != P; p = p->link) {
- while(p->link != P && (p->link->as == arch.AVARDEF || p->link->as == arch.AVARKILL))
+ while(p->link != P && (p->link->as == AVARDEF || p->link->as == AVARKILL))
p->link = p->link->link;
if(p->to.type == TYPE_BRANCH)
- while(p->to.u.branch != P && (p->to.u.branch->as == arch.AVARDEF || p->to.u.branch->as == arch.AVARKILL))
+ while(p->to.u.branch != P && (p->to.u.branch->as == AVARDEF || p->to.u.branch->as == AVARKILL))
p->to.u.branch = p->to.u.branch->link;
}
}
setlineno(curfn);
nodconst(&nod1, types[TINT32], 0);
- ptxt = arch.gins(arch.ATEXT, isblank(curfn->nname) ? N : curfn->nname, &nod1);
+ ptxt = arch.gins(ATEXT, isblank(curfn->nname) ? N : curfn->nname, &nod1);
if(fn->dupok)
ptxt->from3.offset |= DUPOK;
if(fn->wrapper)
case PPARAM:
case PPARAMOUT:
nodconst(&nod1, types[TUINTPTR], l->n->type->width);
- p = arch.gins(arch.ATYPE, l->n, &nod1);
+ p = arch.gins(ATYPE, l->n, &nod1);
p->from.gotype = linksym(ngotype(l->n));
break;
}
if(nerrors != 0)
goto ret;
- pc->as = arch.ARET; // overwrite AEND
+ pc->as = ARET; // overwrite AEND
pc->lineno = lineno;
fixjmp(ptxt);
if(((arch.thechar == '5' || arch.thechar == '9') && n->op != OREGISTER) || !n->addable || n->op == OLITERAL) {
arch.regalloc(®, types[tptr], n);
arch.cgen(n, ®);
- arch.gins(arch.ACHECKNIL, ®, N);
+ arch.gins(ACHECKNIL, ®, N);
arch.regfree(®);
return;
}
- arch.gins(arch.ACHECKNIL, n, N);
+ arch.gins(ACHECKNIL, n, N);
}
fatal("iscall: prog is nil");
if(name == nil)
fatal("iscall: function name is nil");
- if(prog->as != arch.ACALL)
+ if(prog->as != ACALL)
return 0;
return name == prog->to.sym;
}
p->to.u.branch->opt = newblock(p->to.u.branch);
arrayadd(cfg, &p->to.u.branch->opt);
}
- if(p->as != arch.AJMP && p->link != nil && p->link->opt == nil) {
+ if(p->as != AJMP && p->link != nil && p->link->opt == nil) {
p->link->opt = newblock(p->link);
arrayadd(cfg, &p->link->opt);
}
// Stop before an unreachable RET, to avoid creating
// unreachable control flow nodes.
- if(p->link != nil && p->link->as == arch.ARET && p->link->mode == 1)
+ if(p->link != nil && p->link->as == ARET && p->link->mode == 1)
break;
// Collect basic blocks with selectgo calls.
if(bb->last->link != nil) {
// Add a fall-through when the instruction is
// not an unconditional control transfer.
- if(bb->last->as != arch.AJMP && bb->last->as != arch.ARET && bb->last->as != arch.AUNDEF)
+ if(bb->last->as != AJMP && bb->last->as != ARET && bb->last->as != AUNDEF)
addedge(bb, bb->last->link->opt);
}
}
bvresetall(avarinit);
arch.proginfo(&info, prog);
- if(prog->as == arch.ARET) {
+ if(prog->as == ARET) {
// Return instructions implicitly read all the arguments. For
// the sake of correctness, out arguments must be read. For the
// sake of backtrace quality, we read in arguments as well.
}
return;
}
- if(prog->as == arch.ATEXT) {
+ if(prog->as == ATEXT) {
// A text instruction marks the entry point to a function and
// the definition point of all in arguments.
for(i = 0; i < arraylength(vars); i++) {
if(pos >= arraylength(vars) || *(Node**)arrayget(vars, pos) != to->node)
fatal("bad bookkeeping in liveness %N %d", to->node, pos);
if(((Node*)(to->node))->addrtaken) {
- if(prog->as != arch.AVARKILL)
+ if(prog->as != AVARKILL)
bvset(avarinit, pos);
- if(prog->as == arch.AVARDEF || prog->as == arch.AVARKILL)
+ if(prog->as == AVARDEF || prog->as == AVARKILL)
bvset(varkill, pos);
} else {
// RightRead is a read, obviously.
if((info.flags & RightRead) || (info.flags & (RightAddr|RightWrite)) == RightAddr)
bvset(uevar, pos);
if(info.flags & RightWrite)
- if(to->node != nil && (!arch.isfat(((Node*)(to->node))->type) || prog->as == arch.AVARDEF))
+ if(to->node != nil && (!arch.isfat(((Node*)(to->node))->type) || prog->as == AVARDEF))
bvset(varkill, pos);
}
}
print("\tprog:\n");
for(prog = bb->first;; prog = prog->link) {
print("\t\t%P", prog);
- if(prog->as == arch.APCDATA && prog->from.offset == PCDATA_StackMapIndex) {
+ if(prog->as == APCDATA && prog->from.offset == PCDATA_StackMapIndex) {
pos = prog->to.offset;
live = *(Bvec**)arrayget(lv->livepointers, pos);
print(" ");
for(p = firstp; p != P; p = p->link) {
if(0)
print("analyzing '%P'\n", p);
- if(p->as != arch.ADATA && p->as != arch.AGLOBL && p->as != arch.ANAME && p->as != arch.ASIGNAME && p->as != arch.ATYPE)
+ if(p->as != ADATA && p->as != AGLOBL && p->as != ATYPE)
checkprog(fn, p);
}
}
nodconst(&from, types[TINT32], PCDATA_StackMapIndex);
nodconst(&to, types[TINT32], index);
- pcdata = unlinkedprog(arch.APCDATA);
+ pcdata = unlinkedprog(APCDATA);
pcdata->lineno = prog->lineno;
arch.naddr(&from, &pcdata->from, 0);
arch.naddr(&to, &pcdata->to, 0);
static int
issafepoint(Prog *prog)
{
- return prog->as == arch.ATEXT || prog->as == arch.ACALL;
+ return prog->as == ATEXT || prog->as == ACALL;
}
// Initializes the sets for solving the live variables. Visits all the
// walk backward, emit pcdata and populate the maps
pos = bb->lastbitmapindex;
if(pos < 0) {
- // the first block we encounter should have the arch.ATEXT so
+ // the first block we encounter should have the ATEXT so
// at no point should pos ever be less than zero.
fatal("livenessepilogue");
}
// Useful sanity check: on entry to the function,
// the only things that can possibly be live are the
// input parameters.
- if(p->as == arch.ATEXT) {
+ if(p->as == ATEXT) {
for(j = 0; j < liveout->n; j++) {
if(!bvget(liveout, j))
continue;
// Ambiguously live variables are zeroed immediately after
// function entry. Mark them live for all the non-entry bitmaps
// so that GODEBUG=gcdead=1 mode does not poison them.
- if(p->as == arch.ACALL)
+ if(p->as == ACALL)
bvor(locals, locals, ambig);
// Show live pointer bitmaps.
if(msg != nil) {
fmtstrinit(&fmt);
fmtprint(&fmt, "%L: live at ", p->lineno);
- if(p->as == arch.ACALL && p->to.node)
+ if(p->as == ACALL && p->to.node)
fmtprint(&fmt, "call to %s:", ((Node*)(p->to.node))->sym->name);
- else if(p->as == arch.ACALL)
+ else if(p->as == ACALL)
fmtprint(&fmt, "indirect call:");
else
fmtprint(&fmt, "entry to %s:", ((Node*)(p->from.node))->sym->name);
// Only CALL instructions need a PCDATA annotation.
// The TEXT instruction annotation is implicit.
- if(p->as == arch.ACALL) {
+ if(p->as == ACALL) {
if(isdeferreturn(p)) {
// runtime.deferreturn modifies its return address to return
// back to the CALL, not to the subsequent instruction.
// Rewrite PCDATA instructions to use new numbering.
for(p=lv->ptxt; p != P; p=p->link) {
- if(p->as == arch.APCDATA && p->from.offset == PCDATA_StackMapIndex) {
+ if(p->as == APCDATA && p->from.offset == PCDATA_StackMapIndex) {
i = p->to.offset;
if(i >= 0)
p->to.offset = remap[i];
// program listing, with individual effects listed
for(p = bb->first;; p = p->link) {
print("%P\n", p);
- if(p->as == arch.APCDATA && p->from.offset == PCDATA_StackMapIndex)
+ if(p->as == APCDATA && p->from.offset == PCDATA_StackMapIndex)
pcdata = p->to.offset;
progeffects(p, lv->vars, uevar, varkill, avarinit);
printed = 0;
int n;
n = 0;
- while(p != P && p->as == arch.AJMP && p->to.type == TYPE_BRANCH) {
+ while(p != P && p->as == AJMP && p->to.type == TYPE_BRANCH) {
if(++n > 10) {
*jmploop = 1;
break;
if(p->opt != dead)
break;
p->opt = alive;
- if(p->as != arch.ACALL && p->to.type == TYPE_BRANCH && p->to.u.branch)
+ if(p->as != ACALL && p->to.type == TYPE_BRANCH && p->to.u.branch)
mark(p->to.u.branch);
- if(p->as == arch.AJMP || p->as == arch.ARET || p->as == arch.AUNDEF)
+ if(p->as == AJMP || p->as == ARET || p->as == AUNDEF)
break;
}
}
for(p=firstp; p; p=p->link) {
if(debug['R'] && debug['v'])
print("%P\n", p);
- if(p->as != arch.ACALL && p->to.type == TYPE_BRANCH && p->to.u.branch && p->to.u.branch->as == arch.AJMP) {
+ if(p->as != ACALL && p->to.type == TYPE_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);
last = nil;
for(p=firstp; p; p=p->link) {
if(p->opt == dead) {
- if(p->link == P && p->as == arch.ARET && last && last->as != arch.ARET) {
- // This is the final arch.ARET, and the code so far doesn't have one.
+ 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. The register allocator assumes that all live code in
// the function can be traversed by starting at all the RET instructions
// and following predecessor links. If we remove the final RET,
if(!jmploop) {
last = nil;
for(p=firstp; p; p=p->link) {
- if(p->as == arch.AJMP && p->to.type == TYPE_BRANCH && p->to.u.branch == p->link) {
+ if(p->as == AJMP && p->to.type == TYPE_BRANCH && p->to.u.branch == p->link) {
if(debug['R'] && debug['v'])
print("del %P\n", p);
continue;
p = r->f.prog;
arch.proginfo(&info, p);
if(p->to.node == v->node && (info.flags & RightWrite) && !(info.flags & RightRead)) {
- p->as = arch.ANOP;
+ p->as = ANOP;
p->to = zprog.to;
v->removed = 1;
if(Debug)
v->end = p->pc;
if(v->start > p->pc)
v->start = p->pc;
- if(p->as == arch.ARET || (p->as == arch.AVARKILL && p->to.node == v->node))
+ if(p->as == ARET || (p->as == AVARKILL && p->to.node == v->node))
break;
}
nkill = 0;
for(r = (NilFlow*)g->start; r != nil; r = (NilFlow*)r->f.link) {
p = r->f.prog;
- if(p->as != arch.ACHECKNIL || !arch.regtyp(&p->from))
+ if(p->as != ACHECKNIL || !arch.regtyp(&p->from))
continue;
ncheck++;
if(arch.stackaddr(&p->from)) {
// without first finding the check, so this one is unchecked.
return;
}
- if(r != rcheck && p->as == arch.ACHECKNIL && arch.sameaddr(&p->from, &rcheck->f.prog->from)) {
+ if(r != rcheck && p->as == ACHECKNIL && arch.sameaddr(&p->from, &rcheck->f.prog->from)) {
rcheck->kill = 1;
return;
}
// If same check, stop this loop but still check
// alternate predecessors up to this point.
- if(r1 != rcheck && p->as == arch.ACHECKNIL && arch.sameaddr(&p->from, &rcheck->f.prog->from))
+ if(r1 != rcheck && p->as == ACHECKNIL && arch.sameaddr(&p->from, &rcheck->f.prog->from))
break;
arch.proginfo(&info, p);
}
// Stop if another nil check happens.
- if(p->as == arch.ACHECKNIL)
+ if(p->as == ACHECKNIL)
return;
// Stop if value is lost.
if((info.flags & RightWrite) && arch.sameaddr(&p->to, &rcheck->f.prog->from))
o1 = oprrr(ctxt, p->as, p->scond);
o1 |= ((p->from.reg&15)<<0);
o1 |= ((FREGTMP&15)<<12);
- o2 = oprrr(ctxt, AMOVFW+AEND, p->scond);
+ o2 = oprrr(ctxt, AMOVFW+ALAST, p->scond);
o2 |= ((FREGTMP&15)<<16);
o2 |= ((p->to.reg&15)<<12);
break;
case 87: /* movwf reg,freg - fix-to-float */
// macro for movw reg,FTMP; movwf FTMP,freg
- o1 = oprrr(ctxt, AMOVWF+AEND, p->scond);
+ o1 = oprrr(ctxt, AMOVWF+ALAST, p->scond);
o1 |= ((p->from.reg&15)<<12);
o1 |= ((FREGTMP&15)<<16);
o2 = oprrr(ctxt, p->as, p->scond);
o2 |= ((p->to.reg&15)<<12);
break;
case 88: /* movw reg,freg */
- o1 = oprrr(ctxt, AMOVWF+AEND, p->scond);
+ o1 = oprrr(ctxt, AMOVWF+ALAST, p->scond);
o1 |= ((p->from.reg&15)<<12);
o1 |= ((p->to.reg&15)<<16);
break;
case 89: /* movw freg,reg */
- o1 = oprrr(ctxt, AMOVFW+AEND, p->scond);
+ o1 = oprrr(ctxt, AMOVFW+ALAST, p->scond);
o1 |= ((p->from.reg&15)<<16);
o1 |= ((p->to.reg&15)<<12);
break;
case 90: /* tst reg */
- o1 = oprrr(ctxt, ACMP+AEND, p->scond);
+ o1 = oprrr(ctxt, ACMP+ALAST, p->scond);
o1 |= (p->from.reg&15)<<16;
break;
case 91: /* ldrexd oreg,reg */
return o | (0xe<<24) | (0xb<<20) | (8<<16) | (0xa<<8) | (4<<4) |
(1<<18) | (1<<8) | (1<<7); // toint, double, trunc
- case AMOVWF+AEND: // copy WtoF
+ case AMOVWF+ALAST: // copy WtoF
return o | (0xe<<24) | (0x0<<20) | (0xb<<8) | (1<<4);
- case AMOVFW+AEND: // copy FtoW
+ case AMOVFW+ALAST: // copy FtoW
return o | (0xe<<24) | (0x1<<20) | (0xb<<8) | (1<<4);
- case ACMP+AEND: // cmp imm
+ case ACMP+ALAST: // cmp imm
return o | (0x3<<24) | (0x5<<20);
case ACLZ:
{ AFXRSTOR64, ysvrs, Pw, {0x0f,0xae,(01),0x0f,0xae,(01)} },
{ AFXSAVE64, ysvrs, Pw, {0x0f,0xae,(00),0x0f,0xae,(00)} },
{ AGLOBL },
- { AHISTORY },
{ AHLT, ynone, Px, {0xf4} },
{ AIDIVB, ydivb, Pb, {0xf6,(07)} },
{ AIDIVL, ydivl, Px, {0xf7,(07)} },
{ AMULSD, yxm, Pf2, {0x59} },
{ AMULSS, yxm, Pf3, {0x59} },
{ AMULW, ydivl, Pe, {0xf7,(04)} },
- { ANAME },
{ ANEGB, yscond, Pb, {0xf6,(03)} },
{ ANEGL, yscond, Px, {0xf7,(03)} },
{ ANEGQ, yscond, Pw, {0xf7,(03)} },
uchar op[13];
};
+static Optab* opindex[ALAST+1];
+
enum
{
Yxxx = 0,
{ ADIVW, ydivl, Pe, {0xf7,(06)} },
{ AENTER }, /* botch */
{ AGLOBL },
- { AHISTORY },
{ AHLT, ynone, Px, {0xf4} },
{ AIDIVB, ydivb, Pb, {0xf6,(07)} },
{ AIDIVL, ydivl, Px, {0xf7,(07)} },
{ AMULB, ydivb, Pb, {0xf6,(04)} },
{ AMULL, ydivl, Px, {0xf7,(04)} },
{ AMULW, ydivl, Pe, {0xf7,(04)} },
- { ANAME },
{ ANEGB, yscond, Px, {0xf6,(03)} },
{ ANEGL, yscond, Px, {0xf7,(03)} }, // TODO(rsc): yscond is wrong here.
{ ANEGW, yscond, Pe, {0xf7,(03)} }, // TODO(rsc): yscond is wrong here.
{ AFYL2X, ynone, Px, {0xd9, 0xf1} },
{ AFYL2XP1, ynone, Px, {0xd9, 0xf9} },
{ AEND },
- { ADYNT_ },
- { AINIT_ },
- { ASIGNAME },
{ ACMPXCHGB, yrb_mb, Pm, {0xb0} },
{ ACMPXCHGL, yrl_ml, Pm, {0xb1} },
{ ACMPXCHGW, yrl_ml, Pm, {0xb1} },
static void
instinit(void)
{
- int i;
+ int i, c;
- for(i=1; optab[i].as; i++)
- if(i != optab[i].as)
- sysfatal("phase error in optab: at %A found %A", i, optab[i].as);
+ for(i=1; optab[i].as; i++) {
+ c = optab[i].as;
+ if(opindex[c] != nil)
+ sysfatal("phase error in optab: %d (%A)", i, c);
+ opindex[c] = &optab[i];
+ }
for(i=0; i<Ymax; i++)
ycover[i*Ymax + i] = 1;
ft = p->ft * Ymax;
tt = p->tt * Ymax;
- o = &optab[p->as];
+ o = opindex[p->as];
t = o->ytab;
if(t == 0) {
ctxt->diag("asmins: noproto %P", p);
r = p->to.reg;
if(p->as == AADD && (!r0iszero && p->reg == 0 || r0iszero && p->to.reg == 0))
ctxt->diag("literal operation on R0\n%P", p);
- o1 = AOP_IRR(opirr(ctxt, p->as+AEND), p->to.reg, r, v>>16);
+ o1 = AOP_IRR(opirr(ctxt, p->as+ALAST), p->to.reg, r, v>>16);
break;
case 22: /* add $lcon,r1,r2 ==> cau+or+add */ /* could do add/sub more efficiently */
r = p->reg;
if(r == 0)
r = p->to.reg;
- o1 = LOP_IRR(opirr(ctxt, p->as+AEND), p->to.reg, r, v>>16); /* oris, xoris, andis */
+ o1 = LOP_IRR(opirr(ctxt, p->as+ALAST), p->to.reg, r, v>>16); /* oris, xoris, andis */
break;
case 60: /* tw to,a,b */
case AADD: return OPVCC(14,0,0,0);
case AADDC: return OPVCC(12,0,0,0);
case AADDCCC: return OPVCC(13,0,0,0);
- case AADD+AEND: return OPVCC(15,0,0,0); /* ADDIS/CAU */
+ case AADD+ALAST: return OPVCC(15,0,0,0); /* ADDIS/CAU */
case AANDCC: return OPVCC(28,0,0,0);
- case AANDCC+AEND: return OPVCC(29,0,0,0); /* ANDIS./ANDIU. */
+ case AANDCC+ALAST: return OPVCC(29,0,0,0); /* ANDIS./ANDIU. */
case ABR: return OPVCC(18,0,0,0);
case ABL: return OPVCC(18,0,0,0) | 1;
case AMULLW: return OPVCC(7,0,0,0);
case AOR: return OPVCC(24,0,0,0);
- case AOR+AEND: return OPVCC(25,0,0,0); /* ORIS/ORIU */
+ case AOR+ALAST: return OPVCC(25,0,0,0); /* ORIS/ORIU */
case ARLWMI: return OPVCC(20,0,0,0); /* rlwimi */
case ARLWMICC: return OPVCC(20,0,0,1);
case ATD: return OPVCC(2,0,0,0);
case AXOR: return OPVCC(26,0,0,0); /* XORIL */
- case AXOR+AEND: return OPVCC(27,0,0,0); /* XORIU */
+ case AXOR+ALAST: return OPVCC(27,0,0,0); /* XORIU */
}
ctxt->diag("bad opcode i/r %A", a);
return 0;
a = p->as;
str[0] = 0;
- if(a == ADATA || a == AINIT || a == ADYNT)
+ if(a == ADATA)
sprint(str, "%.5lld (%L) %A %D/%lld,%D", p->pc, p->lineno, a, &p->from, p->from3.offset, &p->to);
else if(a == ATEXT || a == AGLOBL) {
if(p->from3.offset != 0)
#include "../cmd/5l/5.out.h"
#include "../runtime/stack.h"
-static int
-isdata(Prog *p)
-{
- return p->as == ADATA || p->as == AGLOBL;
-}
-
-static int
-iscall(Prog *p)
-{
- return p->as == ABL;
-}
-
static void
progedit(Link *ctxt, Prog *p)
{
.preprocess = preprocess,
.assemble = span5,
.follow = follow,
- .iscall = iscall,
- .isdata = isdata,
.progedit = progedit,
.minlc = 4,
.ptrsize = 4,
.regsize = 4,
-
- .ACALL = ABL,
- .ADATA = ADATA,
- .AEND = AEND,
- .AFUNCDATA = AFUNCDATA,
- .AGLOBL = AGLOBL,
- .AJMP = AB,
- .ANOP = ANOP,
- .APCDATA = APCDATA,
- .ARET = ARET,
- .ATEXT = ATEXT,
- .ATYPE = ATYPE,
- .AUSEFIELD = AUSEFIELD,
};
p->to.name = 0;
}
-static int
-isdata(Prog *p)
-{
- return p->as == ADATA || p->as == AGLOBL;
-}
-
-static int
-iscall(Prog *p)
-{
- return p->as == ACALL;
-}
-
static void nacladdr(Link*, Prog*, Addr*);
static int
.preprocess = preprocess,
.assemble = span6,
.follow = follow,
- .iscall = iscall,
- .isdata = isdata,
.progedit = progedit,
.minlc = 1,
.ptrsize = 8,
.regsize = 8,
-
- .ACALL = ACALL,
- .ADATA = ADATA,
- .AEND = AEND,
- .AFUNCDATA = AFUNCDATA,
- .AGLOBL = AGLOBL,
- .AJMP = AJMP,
- .ANOP = ANOP,
- .APCDATA = APCDATA,
- .ARET = ARET,
- .ATEXT = ATEXT,
- .ATYPE = ATYPE,
- .AUSEFIELD = AUSEFIELD,
};
LinkArch linkamd64p32 = {
.preprocess = preprocess,
.assemble = span6,
.follow = follow,
- .iscall = iscall,
- .isdata = isdata,
.progedit = progedit,
.minlc = 1,
.ptrsize = 4,
.regsize = 8,
-
- .ACALL = ACALL,
- .ADATA = ADATA,
- .AEND = AEND,
- .AFUNCDATA = AFUNCDATA,
- .AGLOBL = AGLOBL,
- .AJMP = AJMP,
- .ANOP = ANOP,
- .APCDATA = APCDATA,
- .ARET = ARET,
- .ATEXT = ATEXT,
- .ATYPE = ATYPE,
- .AUSEFIELD = AUSEFIELD,
};
#include "../cmd/8l/8.out.h"
#include "../runtime/stack.h"
-static int
-isdata(Prog *p)
-{
- return p->as == ADATA || p->as == AGLOBL;
-}
-
-static int
-iscall(Prog *p)
-{
- return p->as == ACALL;
-}
-
static int
canuselocaltls(Link *ctxt)
{
.preprocess = preprocess,
.assemble = span8,
.follow = follow,
- .iscall = iscall,
- .isdata = isdata,
.progedit = progedit,
.minlc = 1,
.ptrsize = 4,
.regsize = 4,
-
- .ACALL = ACALL,
- .ADATA = ADATA,
- .AEND = AEND,
- .AFUNCDATA = AFUNCDATA,
- .AGLOBL = AGLOBL,
- .AJMP = AJMP,
- .ANOP = ANOP,
- .APCDATA = APCDATA,
- .ARET = ARET,
- .ATEXT = ATEXT,
- .ATYPE = ATYPE,
- .AUSEFIELD = AUSEFIELD,
};
#include "../runtime/stack.h"
#include "../runtime/funcdata.h"
-static int
-isdata(Prog *p)
-{
- return p->as == ADATA || p->as == AGLOBL;
-}
-
-static int
-iscall(Prog *p)
-{
- return p->as == ABL;
-}
-
static void
progedit(Link *ctxt, Prog *p)
{
.preprocess = preprocess,
.assemble = span9,
.follow = follow,
- .iscall = iscall,
- .isdata = isdata,
.progedit = progedit,
.minlc = 4,
.ptrsize = 8,
.regsize = 8,
-
- .ACALL = ABL,
- .ADATA = ADATA,
- .AEND = AEND,
- .AFUNCDATA = AFUNCDATA,
- .AGLOBL = AGLOBL,
- .AJMP = ABR,
- .ANOP = ANOP,
- .APCDATA = APCDATA,
- .ARET = ARETURN,
- .ATEXT = ATEXT,
- .ATYPE = ATYPE,
- .AUSEFIELD = AUSEFIELD,
};
LinkArch linkppc64le = {
.preprocess = preprocess,
.assemble = span9,
.follow = follow,
- .iscall = iscall,
- .isdata = isdata,
.progedit = progedit,
.minlc = 4,
.ptrsize = 8,
.regsize = 8,
-
- .ACALL = ABL,
- .ADATA = ADATA,
- .AEND = AEND,
- .AFUNCDATA = AFUNCDATA,
- .AGLOBL = AGLOBL,
- .AJMP = ABR,
- .ANOP = ANOP,
- .APCDATA = APCDATA,
- .ARET = ARETURN,
- .ATEXT = ATEXT,
- .ATYPE = ATYPE,
- .AUSEFIELD = AUSEFIELD,
};
plink = p->link;
p->link = nil;
- if(p->as == ctxt->arch->AEND)
+ if(p->as == AEND)
continue;
- if(p->as == ctxt->arch->ATYPE) {
+ if(p->as == ATYPE) {
// Assume each TYPE instruction describes
// a different local variable or parameter,
// so no dedup.
continue;
}
- if(p->as == ctxt->arch->AGLOBL) {
+ if(p->as == AGLOBL) {
s = p->from.sym;
if(s->seenglobl++)
print("duplicate %P\n", p);
continue;
}
- if(p->as == ctxt->arch->ADATA) {
+ if(p->as == ADATA) {
savedata(ctxt, p->from.sym, p, "<input>");
continue;
}
- if(p->as == ctxt->arch->ATEXT) {
+ if(p->as == ATEXT) {
s = p->from.sym;
if(s == nil) {
// func _() { }
continue;
}
- if(p->as == ctxt->arch->AFUNCDATA) {
+ if(p->as == AFUNCDATA) {
// Rewrite reference to go_args_stackmap(SB) to the Go-provided declaration information.
if(curtext == nil) // func _() {}
continue;
continue;
found = 0;
for(p = s->text; p != nil; p = p->link) {
- if(p->as == ctxt->arch->AFUNCDATA && p->from.type == TYPE_CONST && p->from.offset == FUNCDATA_ArgsPointerMaps) {
+ if(p->as == AFUNCDATA && p->from.type == TYPE_CONST && p->from.offset == FUNCDATA_ArgsPointerMaps) {
found = 1;
break;
}
}
if(!found) {
p = appendp(ctxt, s->text);
- p->as = ctxt->arch->AFUNCDATA;
+ p->as = AFUNCDATA;
p->from.type = TYPE_CONST;
p->from.offset = FUNCDATA_ArgsPointerMaps;
p->to.type = TYPE_MEM;
{
int i;
+ USED(ctxt);
for(i=0; i<20; i++) {
- if(p == nil || p->as != ctxt->arch->AJMP || p->pcond == nil)
+ if(p == nil || p->as != AJMP || p->pcond == nil)
return p;
p = p->pcond;
}
int c;
Prog *q;
+ USED(ctxt);
c = 0;
for(q = p; q != nil; q = q->pcond) {
- if(q->as != ctxt->arch->AJMP || q->pcond == nil)
+ if(q->as != AJMP || q->pcond == nil)
break;
c++;
if(c >= 5000)
USED(sym);
- if(p->as == ctxt->arch->ATEXT || p->as == ctxt->arch->ANOP || p->as == ctxt->arch->AUSEFIELD || p->lineno == 0 || phase == 1)
+ if(p->as == ATEXT || p->as == ANOP || p->as == AUSEFIELD || p->lineno == 0 || phase == 1)
return oldval;
linkgetline(ctxt, p->lineno, &f, &l);
if(f == nil) {
{
USED(sym);
- if(phase == 0 || p->as != ctxt->arch->APCDATA || p->from.offset != (uintptr)arg)
+ if(phase == 0 || p->as != APCDATA || p->from.offset != (uintptr)arg)
return oldval;
if((int32)p->to.offset != p->to.offset) {
ctxt->diag("overflow in PCDATA instruction: %P", p);
npcdata = 0;
nfuncdata = 0;
for(p = cursym->text; p != nil; p = p->link) {
- if(p->as == ctxt->arch->APCDATA && p->from.offset >= npcdata)
+ if(p->as == APCDATA && p->from.offset >= npcdata)
npcdata = p->from.offset+1;
- if(p->as == ctxt->arch->AFUNCDATA && p->from.offset >= nfuncdata)
+ if(p->as == AFUNCDATA && p->from.offset >= nfuncdata)
nfuncdata = p->from.offset+1;
}
havepc = emallocz(n);
havefunc = havepc + (npcdata+31)/32;
for(p = cursym->text; p != nil; p = p->link) {
- if(p->as == ctxt->arch->AFUNCDATA) {
+ if(p->as == AFUNCDATA) {
if((havefunc[p->from.offset/32]>>(p->from.offset%32))&1)
ctxt->diag("multiple definitions for FUNCDATA $%d", p->from.offset);
havefunc[p->from.offset/32] |= 1<<(p->from.offset%32);
}
- if(p->as == ctxt->arch->APCDATA)
+ if(p->as == APCDATA)
havepc[p->from.offset/32] |= 1<<(p->from.offset%32);
}
// pcdata.
// funcdata
if(nfuncdata > 0) {
for(p = cursym->text; p != nil; p = p->link) {
- if(p->as == ctxt->arch->AFUNCDATA) {
+ if(p->as == AFUNCDATA) {
i = p->from.offset;
pcln->funcdataoff[i] = p->to.offset;
if(p->to.type != TYPE_CONST) {