2009-05-01 14:21:53 -06:00
|
|
|
// Derived from Inferno utils/5c/txt.c
|
|
|
|
// http://code.google.com/p/inferno-os/source/browse/utils/5c/txt.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.
|
|
|
|
|
2011-08-25 14:25:10 -06:00
|
|
|
#include <u.h>
|
|
|
|
#include <libc.h>
|
2009-05-01 14:21:53 -06:00
|
|
|
#include "gg.h"
|
|
|
|
|
2009-10-26 22:49:32 -06:00
|
|
|
// TODO(kaib): Can make this bigger if we move
|
|
|
|
// the text segment up higher in 5l for all GOOS.
|
|
|
|
long unmappedzero = 4096;
|
|
|
|
|
2009-05-01 14:21:53 -06:00
|
|
|
void
|
|
|
|
clearp(Prog *p)
|
|
|
|
{
|
|
|
|
p->as = AEND;
|
2009-06-26 05:08:20 -06:00
|
|
|
p->reg = NREG;
|
|
|
|
p->scond = C_SCOND_NONE;
|
2009-05-01 14:21:53 -06:00
|
|
|
p->from.type = D_NONE;
|
agen, sgen, cgen_callret, cgen_asop, D_ADDR handling, gmove
8bit and 16bit, some optoas, replaced Addr.index with
Addr.name
empty function compiles, mutex compiles
R=rsc
APPROVED=rsc
DELTA=908 (83 added, 41 deleted, 784 changed)
OCL=31127
CL=31188
2009-07-06 07:42:37 -06:00
|
|
|
p->from.name = D_NONE;
|
2009-06-26 05:08:20 -06:00
|
|
|
p->from.reg = NREG;
|
2009-05-01 14:21:53 -06:00
|
|
|
p->to.type = D_NONE;
|
agen, sgen, cgen_callret, cgen_asop, D_ADDR handling, gmove
8bit and 16bit, some optoas, replaced Addr.index with
Addr.name
empty function compiles, mutex compiles
R=rsc
APPROVED=rsc
DELTA=908 (83 added, 41 deleted, 784 changed)
OCL=31127
CL=31188
2009-07-06 07:42:37 -06:00
|
|
|
p->to.name = D_NONE;
|
2009-06-26 05:08:20 -06:00
|
|
|
p->to.reg = NREG;
|
2009-05-01 14:21:53 -06:00
|
|
|
p->loc = pcloc;
|
|
|
|
pcloc++;
|
|
|
|
}
|
|
|
|
|
2011-08-31 05:37:14 -06:00
|
|
|
static int ddumped;
|
|
|
|
static Prog *dfirst;
|
|
|
|
static Prog *dpc;
|
|
|
|
|
2009-05-01 14:21:53 -06:00
|
|
|
/*
|
|
|
|
* generate and return proc with p->as = as,
|
|
|
|
* linked into program. pc is next instruction.
|
|
|
|
*/
|
|
|
|
Prog*
|
|
|
|
prog(int as)
|
|
|
|
{
|
|
|
|
Prog *p;
|
|
|
|
|
2011-08-31 05:37:14 -06:00
|
|
|
if(as == ADATA || as == AGLOBL) {
|
|
|
|
if(ddumped)
|
|
|
|
fatal("already dumped data");
|
|
|
|
if(dpc == nil) {
|
|
|
|
dpc = mal(sizeof(*dpc));
|
|
|
|
dfirst = dpc;
|
|
|
|
}
|
|
|
|
p = dpc;
|
|
|
|
dpc = mal(sizeof(*dpc));
|
|
|
|
p->link = dpc;
|
2012-02-22 14:29:14 -07:00
|
|
|
p->reg = 0; // used for flags
|
2011-08-31 05:37:14 -06:00
|
|
|
} else {
|
|
|
|
p = pc;
|
|
|
|
pc = mal(sizeof(*pc));
|
|
|
|
clearp(pc);
|
|
|
|
p->link = pc;
|
|
|
|
}
|
2009-05-01 14:21:53 -06:00
|
|
|
|
|
|
|
if(lineno == 0) {
|
|
|
|
if(debug['K'])
|
|
|
|
warn("prog: line 0");
|
|
|
|
}
|
|
|
|
|
|
|
|
p->as = as;
|
|
|
|
p->lineno = lineno;
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
2011-08-31 05:37:14 -06:00
|
|
|
void
|
|
|
|
dumpdata(void)
|
|
|
|
{
|
|
|
|
ddumped = 1;
|
|
|
|
if(dfirst == nil)
|
|
|
|
return;
|
|
|
|
newplist();
|
|
|
|
*pc = *dfirst;
|
|
|
|
pc = dpc;
|
|
|
|
clearp(pc);
|
|
|
|
}
|
|
|
|
|
2009-05-01 14:21:53 -06:00
|
|
|
/*
|
|
|
|
* generate a branch.
|
|
|
|
* t is ignored.
|
2012-05-30 16:07:39 -06:00
|
|
|
* likely values are for branch prediction:
|
|
|
|
* -1 unlikely
|
|
|
|
* 0 no opinion
|
|
|
|
* +1 likely
|
2009-05-01 14:21:53 -06:00
|
|
|
*/
|
|
|
|
Prog*
|
2012-05-30 16:07:39 -06:00
|
|
|
gbranch(int as, Type *t, int likely)
|
2009-05-01 14:21:53 -06:00
|
|
|
{
|
|
|
|
Prog *p;
|
|
|
|
|
2011-08-25 14:29:56 -06:00
|
|
|
USED(t);
|
2012-05-30 16:07:39 -06:00
|
|
|
USED(likely); // TODO: record this for linker
|
2011-08-25 14:29:56 -06:00
|
|
|
|
2009-05-01 14:21:53 -06:00
|
|
|
p = prog(as);
|
|
|
|
p->to.type = D_BRANCH;
|
2012-12-13 12:20:24 -07:00
|
|
|
p->to.u.branch = P;
|
2009-05-01 14:21:53 -06:00
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* patch previous branch to jump to to.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
patch(Prog *p, Prog *to)
|
|
|
|
{
|
|
|
|
if(p->to.type != D_BRANCH)
|
|
|
|
fatal("patch: not a branch");
|
2012-12-13 12:20:24 -07:00
|
|
|
p->to.u.branch = to;
|
2009-05-01 14:21:53 -06:00
|
|
|
p->to.offset = to->loc;
|
|
|
|
}
|
|
|
|
|
2011-06-17 13:25:05 -06:00
|
|
|
Prog*
|
|
|
|
unpatch(Prog *p)
|
|
|
|
{
|
|
|
|
Prog *q;
|
|
|
|
|
|
|
|
if(p->to.type != D_BRANCH)
|
|
|
|
fatal("unpatch: not a branch");
|
2012-12-13 12:20:24 -07:00
|
|
|
q = p->to.u.branch;
|
|
|
|
p->to.u.branch = P;
|
2011-06-17 13:25:05 -06:00
|
|
|
p->to.offset = 0;
|
|
|
|
return q;
|
|
|
|
}
|
|
|
|
|
2009-05-01 14:21:53 -06:00
|
|
|
/*
|
|
|
|
* start a new Prog list.
|
|
|
|
*/
|
|
|
|
Plist*
|
|
|
|
newplist(void)
|
|
|
|
{
|
|
|
|
Plist *pl;
|
|
|
|
|
|
|
|
pl = mal(sizeof(*pl));
|
|
|
|
if(plist == nil)
|
|
|
|
plist = pl;
|
|
|
|
else
|
|
|
|
plast->link = pl;
|
|
|
|
plast = pl;
|
|
|
|
|
|
|
|
pc = mal(sizeof(*pc));
|
|
|
|
clearp(pc);
|
|
|
|
pl->firstpc = pc;
|
|
|
|
|
|
|
|
return pl;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gused(Node *n)
|
|
|
|
{
|
|
|
|
gins(ANOP, n, N); // used
|
|
|
|
}
|
|
|
|
|
|
|
|
Prog*
|
|
|
|
gjmp(Prog *to)
|
|
|
|
{
|
|
|
|
Prog *p;
|
|
|
|
|
2012-05-30 16:07:39 -06:00
|
|
|
p = gbranch(AB, T, 0);
|
2009-05-01 14:21:53 -06:00
|
|
|
if(to != P)
|
|
|
|
patch(p, to);
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ggloblnod(Node *nam, int32 width)
|
|
|
|
{
|
|
|
|
Prog *p;
|
|
|
|
|
|
|
|
p = gins(AGLOBL, nam, N);
|
|
|
|
p->lineno = nam->lineno;
|
|
|
|
p->to.sym = S;
|
|
|
|
p->to.type = D_CONST;
|
|
|
|
p->to.offset = width;
|
2012-02-19 01:19:52 -07:00
|
|
|
if(nam->readonly)
|
2012-02-21 20:08:42 -07:00
|
|
|
p->reg = RODATA;
|
2012-02-19 01:19:52 -07:00
|
|
|
if(nam->type != T && !haspointers(nam->type))
|
2012-02-21 20:08:42 -07:00
|
|
|
p->reg |= NOPTR;
|
2009-05-01 14:21:53 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2012-07-02 17:09:05 -06:00
|
|
|
ggloblsym(Sym *s, int32 width, int dupok, int rodata)
|
2009-05-01 14:21:53 -06:00
|
|
|
{
|
|
|
|
Prog *p;
|
|
|
|
|
|
|
|
p = gins(AGLOBL, N, N);
|
agen, sgen, cgen_callret, cgen_asop, D_ADDR handling, gmove
8bit and 16bit, some optoas, replaced Addr.index with
Addr.name
empty function compiles, mutex compiles
R=rsc
APPROVED=rsc
DELTA=908 (83 added, 41 deleted, 784 changed)
OCL=31127
CL=31188
2009-07-06 07:42:37 -06:00
|
|
|
p->from.type = D_OREG;
|
|
|
|
p->from.name = D_EXTERN;
|
2009-05-01 14:21:53 -06:00
|
|
|
p->from.sym = s;
|
|
|
|
p->to.type = D_CONST;
|
agen, sgen, cgen_callret, cgen_asop, D_ADDR handling, gmove
8bit and 16bit, some optoas, replaced Addr.index with
Addr.name
empty function compiles, mutex compiles
R=rsc
APPROVED=rsc
DELTA=908 (83 added, 41 deleted, 784 changed)
OCL=31127
CL=31188
2009-07-06 07:42:37 -06:00
|
|
|
p->to.name = D_NONE;
|
2009-05-01 14:21:53 -06:00
|
|
|
p->to.offset = width;
|
|
|
|
if(dupok)
|
2012-07-02 17:09:05 -06:00
|
|
|
p->reg |= DUPOK;
|
|
|
|
if(rodata)
|
|
|
|
p->reg |= RODATA;
|
2009-05-01 14:21:53 -06:00
|
|
|
}
|
|
|
|
|
cmd/gc, cmd/ld: struct field tracking
This is an experiment in static analysis of Go programs
to understand which struct fields a program might use.
It is not part of the Go language specification, it must
be enabled explicitly when building the toolchain,
and it may be removed at any time.
After building the toolchain with GOEXPERIMENT=fieldtrack,
a specific field can be marked for tracking by including
`go:"track"` in the field tag:
package pkg
type T struct {
F int `go:"track"`
G int // untracked
}
To simplify usage, only named struct types can have
tracked fields, and only exported fields can be tracked.
The implementation works by making each function begin
with a sequence of no-op USEFIELD instructions declaring
which tracked fields are accessed by a specific function.
After the linker's dead code elimination removes unused
functions, the fields referred to by the remaining
USEFIELD instructions are the ones reported as used by
the binary.
The -k option to the linker specifies the fully qualified
symbol name (such as my/pkg.list) of a string variable that
should be initialized with the field tracking information
for the program. The field tracking string is a sequence
of lines, each terminated by a \n and describing a single
tracked field referred to by the program. Each line is made
up of one or more tab-separated fields. The first field is
the name of the tracked field, fully qualified, as in
"my/pkg.T.F". Subsequent fields give a shortest path of
reverse references from that field to a global variable or
function, corresponding to one way in which the program
might reach that field.
A common source of false positives in field tracking is
types with large method sets, because a reference to the
type descriptor carries with it references to all methods.
To address this problem, the CL also introduces a comment
annotation
//go:nointerface
that marks an upcoming method declaration as unavailable
for use in satisfying interfaces, both statically and
dynamically. Such a method is also invisible to package
reflect.
Again, all of this is disabled by default. It only turns on
if you have GOEXPERIMENT=fieldtrack set during make.bash.
R=iant, ken
CC=golang-dev
https://golang.org/cl/6749064
2012-11-01 22:17:21 -06:00
|
|
|
void
|
|
|
|
gtrack(Sym *s)
|
|
|
|
{
|
|
|
|
Prog *p;
|
|
|
|
|
|
|
|
p = gins(AUSEFIELD, N, N);
|
|
|
|
p->from.type = D_OREG;
|
|
|
|
p->from.name = D_EXTERN;
|
|
|
|
p->from.sym = s;
|
|
|
|
}
|
|
|
|
|
2009-05-01 14:21:53 -06:00
|
|
|
int
|
|
|
|
isfat(Type *t)
|
|
|
|
{
|
|
|
|
if(t != T)
|
|
|
|
switch(t->etype) {
|
|
|
|
case TSTRUCT:
|
|
|
|
case TARRAY:
|
|
|
|
case TSTRING:
|
|
|
|
case TINTER: // maybe remove later
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* naddr of func generates code for address of func.
|
|
|
|
* if using opcode that can take address implicitly,
|
|
|
|
* call afunclit to fix up the argument.
|
2009-09-22 14:13:23 -06:00
|
|
|
* also fix up direct register references to be D_OREG.
|
2009-05-01 14:21:53 -06:00
|
|
|
*/
|
|
|
|
void
|
|
|
|
afunclit(Addr *a)
|
|
|
|
{
|
2009-10-19 13:44:08 -06:00
|
|
|
if(a->type == D_CONST && a->name == D_EXTERN || a->type == D_REG) {
|
agen, sgen, cgen_callret, cgen_asop, D_ADDR handling, gmove
8bit and 16bit, some optoas, replaced Addr.index with
Addr.name
empty function compiles, mutex compiles
R=rsc
APPROVED=rsc
DELTA=908 (83 added, 41 deleted, 784 changed)
OCL=31127
CL=31188
2009-07-06 07:42:37 -06:00
|
|
|
a->type = D_OREG;
|
2009-05-01 14:21:53 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-09-11 22:06:45 -06:00
|
|
|
static int resvd[] =
|
|
|
|
{
|
2012-10-28 13:11:21 -06:00
|
|
|
9, // reserved for m
|
|
|
|
10, // reserved for g
|
|
|
|
REGSP, // reserved for SP
|
2010-09-11 22:06:45 -06:00
|
|
|
};
|
|
|
|
|
|
|
|
void
|
|
|
|
ginit(void)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for(i=0; i<nelem(reg); i++)
|
|
|
|
reg[i] = 0;
|
|
|
|
for(i=0; i<nelem(resvd); i++)
|
|
|
|
reg[resvd[i]]++;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gclean(void)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for(i=0; i<nelem(resvd); i++)
|
|
|
|
reg[resvd[i]]--;
|
|
|
|
|
|
|
|
for(i=0; i<nelem(reg); i++)
|
|
|
|
if(reg[i])
|
|
|
|
yyerror("reg %R left allocated\n", i);
|
|
|
|
}
|
|
|
|
|
2010-05-20 18:31:28 -06:00
|
|
|
int32
|
|
|
|
anyregalloc(void)
|
|
|
|
{
|
2010-09-11 22:06:45 -06:00
|
|
|
int i, j;
|
|
|
|
|
|
|
|
for(i=0; i<nelem(reg); i++) {
|
|
|
|
if(reg[i] == 0)
|
|
|
|
goto ok;
|
|
|
|
for(j=0; j<nelem(resvd); j++)
|
|
|
|
if(resvd[j] == i)
|
|
|
|
goto ok;
|
|
|
|
return 1;
|
|
|
|
ok:;
|
|
|
|
}
|
2010-05-20 18:31:28 -06:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-02-13 23:13:14 -07:00
|
|
|
uintptr regpc[REGALLOC_FMAX+1];
|
2012-02-10 22:19:24 -07:00
|
|
|
|
2009-06-25 12:01:17 -06:00
|
|
|
/*
|
|
|
|
* allocate register of type t, leave in n.
|
|
|
|
* if o != N, o is desired fixed register.
|
|
|
|
* caller must regfree(n).
|
|
|
|
*/
|
2009-05-01 14:21:53 -06:00
|
|
|
void
|
2009-06-25 12:01:17 -06:00
|
|
|
regalloc(Node *n, Type *t, Node *o)
|
2009-05-01 14:21:53 -06:00
|
|
|
{
|
2009-10-06 10:47:46 -06:00
|
|
|
int i, et, fixfree, floatfree;
|
|
|
|
|
2011-10-18 12:55:28 -06:00
|
|
|
if(0 && debug['r']) {
|
2009-10-06 10:47:46 -06:00
|
|
|
fixfree = 0;
|
|
|
|
for(i=REGALLOC_R0; i<=REGALLOC_RMAX; i++)
|
|
|
|
if(reg[i] == 0)
|
|
|
|
fixfree++;
|
|
|
|
floatfree = 0;
|
|
|
|
for(i=REGALLOC_F0; i<=REGALLOC_FMAX; i++)
|
|
|
|
if(reg[i] == 0)
|
|
|
|
floatfree++;
|
|
|
|
print("regalloc fix %d float %d\n", fixfree, floatfree);
|
|
|
|
}
|
2009-06-25 12:01:17 -06:00
|
|
|
|
|
|
|
if(t == T)
|
|
|
|
fatal("regalloc: t nil");
|
|
|
|
et = simtype[t->etype];
|
2009-08-21 17:29:19 -06:00
|
|
|
if(is64(t))
|
|
|
|
fatal("regalloc: 64 bit type %T");
|
2009-06-25 12:01:17 -06:00
|
|
|
|
|
|
|
switch(et) {
|
|
|
|
case TINT8:
|
|
|
|
case TUINT8:
|
|
|
|
case TINT16:
|
|
|
|
case TUINT16:
|
|
|
|
case TINT32:
|
|
|
|
case TUINT32:
|
|
|
|
case TPTR32:
|
|
|
|
case TBOOL:
|
|
|
|
if(o != N && o->op == OREGISTER) {
|
|
|
|
i = o->val.u.reg;
|
|
|
|
if(i >= REGALLOC_R0 && i <= REGALLOC_RMAX)
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
for(i=REGALLOC_R0; i<=REGALLOC_RMAX; i++)
|
2012-02-10 22:19:24 -07:00
|
|
|
if(reg[i] == 0) {
|
|
|
|
regpc[i] = (uintptr)getcallerpc(&n);
|
2009-06-25 12:01:17 -06:00
|
|
|
goto out;
|
2012-02-10 22:19:24 -07:00
|
|
|
}
|
2012-11-12 15:56:11 -07:00
|
|
|
print("registers allocated at\n");
|
2012-02-10 22:19:24 -07:00
|
|
|
for(i=REGALLOC_R0; i<=REGALLOC_RMAX; i++)
|
|
|
|
print("%d %p\n", i, regpc[i]);
|
2009-06-25 12:01:17 -06:00
|
|
|
yyerror("out of fixed registers");
|
|
|
|
goto err;
|
2009-05-28 15:25:54 -06:00
|
|
|
|
2009-06-25 12:01:17 -06:00
|
|
|
case TFLOAT32:
|
|
|
|
case TFLOAT64:
|
|
|
|
if(o != N && o->op == OREGISTER) {
|
|
|
|
i = o->val.u.reg;
|
|
|
|
if(i >= REGALLOC_F0 && i <= REGALLOC_FMAX)
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
for(i=REGALLOC_F0; i<=REGALLOC_FMAX; i++)
|
|
|
|
if(reg[i] == 0)
|
|
|
|
goto out;
|
2009-10-01 14:52:55 -06:00
|
|
|
yyerror("out of floating point registers");
|
2009-06-25 12:01:17 -06:00
|
|
|
goto err;
|
2010-10-25 17:26:33 -06:00
|
|
|
|
|
|
|
case TCOMPLEX64:
|
|
|
|
case TCOMPLEX128:
|
|
|
|
tempname(n, t);
|
|
|
|
return;
|
2009-06-25 12:01:17 -06:00
|
|
|
}
|
|
|
|
yyerror("regalloc: unknown type %T", t);
|
|
|
|
|
|
|
|
err:
|
|
|
|
nodreg(n, t, 0);
|
|
|
|
return;
|
|
|
|
|
|
|
|
out:
|
|
|
|
reg[i]++;
|
|
|
|
nodreg(n, t, i);
|
2009-05-01 14:21:53 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2009-06-25 12:01:17 -06:00
|
|
|
regfree(Node *n)
|
2009-05-01 14:21:53 -06:00
|
|
|
{
|
2009-10-06 10:47:46 -06:00
|
|
|
int i, fixfree, floatfree;
|
|
|
|
|
2011-10-18 12:55:28 -06:00
|
|
|
if(0 && debug['r']) {
|
2009-10-06 10:47:46 -06:00
|
|
|
fixfree = 0;
|
|
|
|
for(i=REGALLOC_R0; i<=REGALLOC_RMAX; i++)
|
|
|
|
if(reg[i] == 0)
|
|
|
|
fixfree++;
|
|
|
|
floatfree = 0;
|
|
|
|
for(i=REGALLOC_F0; i<=REGALLOC_FMAX; i++)
|
|
|
|
if(reg[i] == 0)
|
|
|
|
floatfree++;
|
|
|
|
print("regalloc fix %d float %d\n", fixfree, floatfree);
|
|
|
|
}
|
2009-06-25 12:01:17 -06:00
|
|
|
|
2012-10-28 13:11:21 -06:00
|
|
|
if(n->op == ONAME)
|
2010-10-25 17:26:33 -06:00
|
|
|
return;
|
2009-06-25 12:01:17 -06:00
|
|
|
if(n->op != OREGISTER && n->op != OINDREG)
|
|
|
|
fatal("regfree: not a register");
|
|
|
|
i = n->val.u.reg;
|
2012-10-28 13:11:21 -06:00
|
|
|
if(i == REGSP)
|
|
|
|
return;
|
2012-02-13 23:13:14 -07:00
|
|
|
if(i < 0 || i >= nelem(reg) || i >= nelem(regpc))
|
2009-06-25 12:01:17 -06:00
|
|
|
fatal("regfree: reg out of range");
|
|
|
|
if(reg[i] <= 0)
|
2012-10-28 13:11:21 -06:00
|
|
|
fatal("regfree: reg %R not allocated", i);
|
2009-06-25 12:01:17 -06:00
|
|
|
reg[i]--;
|
2012-02-10 22:19:24 -07:00
|
|
|
if(reg[i] == 0)
|
|
|
|
regpc[i] = 0;
|
2009-05-01 14:21:53 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* initialize n to be register r of type t.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
nodreg(Node *n, Type *t, int r)
|
|
|
|
{
|
|
|
|
if(t == T)
|
|
|
|
fatal("nodreg: t nil");
|
|
|
|
|
|
|
|
memset(n, 0, sizeof(*n));
|
|
|
|
n->op = OREGISTER;
|
|
|
|
n->addable = 1;
|
|
|
|
ullmancalc(n);
|
|
|
|
n->val.u.reg = r;
|
|
|
|
n->type = t;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* initialize n to be indirect of register r; n is type t.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
nodindreg(Node *n, Type *t, int r)
|
|
|
|
{
|
|
|
|
nodreg(n, t, r);
|
|
|
|
n->op = OINDREG;
|
|
|
|
}
|
|
|
|
|
|
|
|
Node*
|
|
|
|
nodarg(Type *t, int fp)
|
|
|
|
{
|
2009-05-28 15:25:54 -06:00
|
|
|
Node *n;
|
|
|
|
Type *first;
|
|
|
|
Iter savet;
|
|
|
|
|
|
|
|
// entire argument struct, not just one arg
|
|
|
|
if(t->etype == TSTRUCT && t->funarg) {
|
|
|
|
n = nod(ONAME, N, N);
|
|
|
|
n->sym = lookup(".args");
|
|
|
|
n->type = t;
|
|
|
|
first = structfirst(&savet, &t);
|
|
|
|
if(first == nil)
|
|
|
|
fatal("nodarg: bad struct");
|
|
|
|
if(first->width == BADWIDTH)
|
|
|
|
fatal("nodarg: offset not computed for %T", t);
|
2009-09-29 08:27:49 -06:00
|
|
|
n->xoffset = first->width;
|
2009-05-28 15:25:54 -06:00
|
|
|
n->addable = 1;
|
|
|
|
goto fp;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(t->etype != TFIELD)
|
|
|
|
fatal("nodarg: not field %T", t);
|
|
|
|
|
|
|
|
n = nod(ONAME, N, N);
|
|
|
|
n->type = t->type;
|
|
|
|
n->sym = t->sym;
|
|
|
|
if(t->width == BADWIDTH)
|
|
|
|
fatal("nodarg: offset not computed for %T", t);
|
2009-09-29 08:27:49 -06:00
|
|
|
n->xoffset = t->width;
|
2009-05-28 15:25:54 -06:00
|
|
|
n->addable = 1;
|
2011-10-03 15:46:36 -06:00
|
|
|
n->orig = t->nname;
|
2009-05-28 15:25:54 -06:00
|
|
|
|
|
|
|
fp:
|
2011-12-09 09:59:21 -07:00
|
|
|
// Rewrite argument named _ to __,
|
|
|
|
// or else the assignment to _ will be
|
|
|
|
// discarded during code generation.
|
|
|
|
if(isblank(n))
|
|
|
|
n->sym = lookup("__");
|
|
|
|
|
2009-05-28 15:25:54 -06:00
|
|
|
switch(fp) {
|
2009-07-12 23:12:33 -06:00
|
|
|
default:
|
|
|
|
fatal("nodarg %T %d", t, fp);
|
|
|
|
|
2009-09-29 08:27:49 -06:00
|
|
|
case 0: // output arg for calling another function
|
2009-05-28 15:25:54 -06:00
|
|
|
n->op = OINDREG;
|
2009-07-12 23:12:33 -06:00
|
|
|
n->val.u.reg = REGSP;
|
2009-09-29 08:27:49 -06:00
|
|
|
n->xoffset += 4;
|
2009-05-28 15:25:54 -06:00
|
|
|
break;
|
|
|
|
|
2009-09-29 08:27:49 -06:00
|
|
|
case 1: // input arg to current function
|
2009-05-28 15:25:54 -06:00
|
|
|
n->class = PPARAM;
|
|
|
|
break;
|
|
|
|
}
|
2011-07-28 16:22:12 -06:00
|
|
|
n->typecheck = 1;
|
2009-05-28 15:25:54 -06:00
|
|
|
return n;
|
2009-05-01 14:21:53 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2009-08-21 17:29:19 -06:00
|
|
|
* return constant i node.
|
|
|
|
* overwritten by next call, but useful in calls to gins.
|
2009-05-01 14:21:53 -06:00
|
|
|
*/
|
2009-08-21 17:29:19 -06:00
|
|
|
Node*
|
|
|
|
ncon(uint32 i)
|
2009-05-01 14:21:53 -06:00
|
|
|
{
|
2009-08-21 17:29:19 -06:00
|
|
|
static Node n;
|
2009-05-01 14:21:53 -06:00
|
|
|
|
2009-08-21 17:29:19 -06:00
|
|
|
if(n.type == T)
|
|
|
|
nodconst(&n, types[TUINT32], 0);
|
|
|
|
mpmovecfix(n.val.u.xval, i);
|
|
|
|
return &n;
|
2009-05-01 14:21:53 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2009-06-25 12:01:17 -06:00
|
|
|
* Is this node a memory operand?
|
2009-05-01 14:21:53 -06:00
|
|
|
*/
|
2009-06-25 12:01:17 -06:00
|
|
|
int
|
|
|
|
ismem(Node *n)
|
2009-05-01 14:21:53 -06:00
|
|
|
{
|
2009-06-25 12:01:17 -06:00
|
|
|
switch(n->op) {
|
|
|
|
case OINDREG:
|
|
|
|
case ONAME:
|
|
|
|
case OPARAM:
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
2009-05-01 14:21:53 -06:00
|
|
|
|
2009-08-21 17:29:19 -06:00
|
|
|
Node sclean[10];
|
|
|
|
int nsclean;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* n is a 64-bit value. fill in lo and hi to refer to its 32-bit halves.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
split64(Node *n, Node *lo, Node *hi)
|
|
|
|
{
|
|
|
|
Node n1;
|
|
|
|
int64 i;
|
|
|
|
|
|
|
|
if(!is64(n->type))
|
|
|
|
fatal("split64 %T", n->type);
|
|
|
|
|
|
|
|
if(nsclean >= nelem(sclean))
|
|
|
|
fatal("split64 clean");
|
2013-02-08 00:19:47 -07:00
|
|
|
sclean[nsclean].op = OEMPTY;
|
2009-08-21 17:29:19 -06:00
|
|
|
nsclean++;
|
|
|
|
switch(n->op) {
|
|
|
|
default:
|
|
|
|
if(!dotaddable(n, &n1)) {
|
|
|
|
igen(n, &n1, N);
|
|
|
|
sclean[nsclean-1] = n1;
|
|
|
|
}
|
|
|
|
n = &n1;
|
|
|
|
goto common;
|
|
|
|
case ONAME:
|
|
|
|
if(n->class == PPARAMREF) {
|
|
|
|
cgen(n->heapaddr, &n1);
|
|
|
|
sclean[nsclean-1] = n1;
|
|
|
|
// fall through.
|
|
|
|
n = &n1;
|
|
|
|
}
|
|
|
|
goto common;
|
|
|
|
case OINDREG:
|
|
|
|
common:
|
|
|
|
*lo = *n;
|
|
|
|
*hi = *n;
|
|
|
|
lo->type = types[TUINT32];
|
|
|
|
if(n->type->etype == TINT64)
|
|
|
|
hi->type = types[TINT32];
|
|
|
|
else
|
|
|
|
hi->type = types[TUINT32];
|
|
|
|
hi->xoffset += 4;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OLITERAL:
|
|
|
|
convconst(&n1, n->type, &n->val);
|
|
|
|
i = mpgetfix(n1.val.u.xval);
|
|
|
|
nodconst(lo, types[TUINT32], (uint32)i);
|
|
|
|
i >>= 32;
|
|
|
|
if(n->type->etype == TINT64)
|
|
|
|
nodconst(hi, types[TINT32], (int32)i);
|
|
|
|
else
|
|
|
|
nodconst(hi, types[TUINT32], (uint32)i);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
splitclean(void)
|
|
|
|
{
|
|
|
|
if(nsclean <= 0)
|
|
|
|
fatal("splitclean");
|
|
|
|
nsclean--;
|
|
|
|
if(sclean[nsclean].op != OEMPTY)
|
|
|
|
regfree(&sclean[nsclean]);
|
|
|
|
}
|
|
|
|
|
2009-06-25 12:01:17 -06:00
|
|
|
#define CASE(a,b) (((a)<<16)|((b)<<0))
|
2009-05-01 14:21:53 -06:00
|
|
|
|
2009-06-25 12:01:17 -06:00
|
|
|
void
|
|
|
|
gmove(Node *f, Node *t)
|
|
|
|
{
|
2009-10-11 21:01:11 -06:00
|
|
|
int a, ft, tt, fa, ta;
|
2009-06-25 12:01:17 -06:00
|
|
|
Type *cvt;
|
2009-08-21 17:29:19 -06:00
|
|
|
Node r1, r2, flo, fhi, tlo, thi, con;
|
|
|
|
Prog *p1;
|
2009-05-28 15:25:54 -06:00
|
|
|
|
|
|
|
if(debug['M'])
|
2009-06-25 12:01:17 -06:00
|
|
|
print("gmove %N -> %N\n", f, t);
|
|
|
|
|
|
|
|
ft = simsimtype(f->type);
|
|
|
|
tt = simsimtype(t->type);
|
|
|
|
cvt = t->type;
|
|
|
|
|
2010-10-20 22:56:20 -06:00
|
|
|
if(iscomplex[ft] || iscomplex[tt]) {
|
|
|
|
complexmove(f, t);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-10-11 21:01:11 -06:00
|
|
|
// cannot have two memory operands;
|
2009-06-25 12:01:17 -06:00
|
|
|
// except 64-bit, which always copies via registers anyway.
|
2009-10-11 21:01:11 -06:00
|
|
|
if(!is64(f->type) && !is64(t->type) && ismem(f) && ismem(t))
|
2009-08-21 17:29:19 -06:00
|
|
|
goto hard;
|
2009-06-25 12:01:17 -06:00
|
|
|
|
|
|
|
// convert constant to desired type
|
|
|
|
if(f->op == OLITERAL) {
|
agen, sgen, cgen_callret, cgen_asop, D_ADDR handling, gmove
8bit and 16bit, some optoas, replaced Addr.index with
Addr.name
empty function compiles, mutex compiles
R=rsc
APPROVED=rsc
DELTA=908 (83 added, 41 deleted, 784 changed)
OCL=31127
CL=31188
2009-07-06 07:42:37 -06:00
|
|
|
switch(tt) {
|
|
|
|
default:
|
2009-06-25 12:01:17 -06:00
|
|
|
convconst(&con, t->type, &f->val);
|
agen, sgen, cgen_callret, cgen_asop, D_ADDR handling, gmove
8bit and 16bit, some optoas, replaced Addr.index with
Addr.name
empty function compiles, mutex compiles
R=rsc
APPROVED=rsc
DELTA=908 (83 added, 41 deleted, 784 changed)
OCL=31127
CL=31188
2009-07-06 07:42:37 -06:00
|
|
|
break;
|
|
|
|
|
|
|
|
case TINT16:
|
|
|
|
case TINT8:
|
|
|
|
convconst(&con, types[TINT32], &f->val);
|
|
|
|
regalloc(&r1, con.type, t);
|
|
|
|
gins(AMOVW, &con, &r1);
|
|
|
|
gmove(&r1, t);
|
|
|
|
regfree(&r1);
|
|
|
|
return;
|
|
|
|
|
|
|
|
case TUINT16:
|
|
|
|
case TUINT8:
|
|
|
|
convconst(&con, types[TUINT32], &f->val);
|
|
|
|
regalloc(&r1, con.type, t);
|
|
|
|
gins(AMOVW, &con, &r1);
|
|
|
|
gmove(&r1, t);
|
|
|
|
regfree(&r1);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-06-25 12:01:17 -06:00
|
|
|
f = &con;
|
|
|
|
ft = simsimtype(con.type);
|
|
|
|
|
agen, sgen, cgen_callret, cgen_asop, D_ADDR handling, gmove
8bit and 16bit, some optoas, replaced Addr.index with
Addr.name
empty function compiles, mutex compiles
R=rsc
APPROVED=rsc
DELTA=908 (83 added, 41 deleted, 784 changed)
OCL=31127
CL=31188
2009-07-06 07:42:37 -06:00
|
|
|
// constants can't move directly to memory
|
2009-08-21 17:29:19 -06:00
|
|
|
if(ismem(t) && !is64(t->type)) goto hard;
|
2009-06-25 12:01:17 -06:00
|
|
|
}
|
2009-05-28 15:25:54 -06:00
|
|
|
|
2009-06-25 12:01:17 -06:00
|
|
|
// value -> value copy, only one memory operand.
|
|
|
|
// figure out the instruction to use.
|
|
|
|
// break out of switch for one-instruction gins.
|
|
|
|
// goto rdst for "destination must be register".
|
|
|
|
// goto hard for "convert to cvt type first".
|
|
|
|
// otherwise handle and return.
|
2009-05-28 15:25:54 -06:00
|
|
|
|
2009-06-25 12:01:17 -06:00
|
|
|
switch(CASE(ft, tt)) {
|
|
|
|
default:
|
|
|
|
goto fatal;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* integer copy and truncate
|
|
|
|
*/
|
|
|
|
case CASE(TINT8, TINT8): // same size
|
|
|
|
case CASE(TUINT8, TINT8):
|
|
|
|
case CASE(TINT16, TINT8): // truncate
|
|
|
|
case CASE(TUINT16, TINT8):
|
|
|
|
case CASE(TINT32, TINT8):
|
|
|
|
case CASE(TUINT32, TINT8):
|
2009-08-19 21:17:09 -06:00
|
|
|
a = AMOVB;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CASE(TINT8, TUINT8):
|
|
|
|
case CASE(TUINT8, TUINT8):
|
2009-06-25 12:01:17 -06:00
|
|
|
case CASE(TINT16, TUINT8):
|
|
|
|
case CASE(TUINT16, TUINT8):
|
|
|
|
case CASE(TINT32, TUINT8):
|
|
|
|
case CASE(TUINT32, TUINT8):
|
2009-08-19 21:17:09 -06:00
|
|
|
a = AMOVBU;
|
2009-06-25 12:01:17 -06:00
|
|
|
break;
|
2009-05-28 15:25:54 -06:00
|
|
|
|
2009-06-25 12:01:17 -06:00
|
|
|
case CASE(TINT64, TINT8): // truncate low word
|
|
|
|
case CASE(TUINT64, TINT8):
|
2009-08-21 17:29:19 -06:00
|
|
|
a = AMOVB;
|
|
|
|
goto trunc64;
|
|
|
|
|
2009-06-25 12:01:17 -06:00
|
|
|
case CASE(TINT64, TUINT8):
|
|
|
|
case CASE(TUINT64, TUINT8):
|
2009-08-21 17:29:19 -06:00
|
|
|
a = AMOVBU;
|
|
|
|
goto trunc64;
|
2009-05-28 15:25:54 -06:00
|
|
|
|
2009-06-25 12:01:17 -06:00
|
|
|
case CASE(TINT16, TINT16): // same size
|
|
|
|
case CASE(TUINT16, TINT16):
|
|
|
|
case CASE(TINT32, TINT16): // truncate
|
|
|
|
case CASE(TUINT32, TINT16):
|
2009-08-19 21:17:09 -06:00
|
|
|
a = AMOVH;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CASE(TINT16, TUINT16):
|
|
|
|
case CASE(TUINT16, TUINT16):
|
2009-06-25 12:01:17 -06:00
|
|
|
case CASE(TINT32, TUINT16):
|
|
|
|
case CASE(TUINT32, TUINT16):
|
2009-08-19 21:17:09 -06:00
|
|
|
a = AMOVHU;
|
2009-05-28 15:25:54 -06:00
|
|
|
break;
|
|
|
|
|
2009-06-25 12:01:17 -06:00
|
|
|
case CASE(TINT64, TINT16): // truncate low word
|
|
|
|
case CASE(TUINT64, TINT16):
|
2009-08-21 17:29:19 -06:00
|
|
|
a = AMOVH;
|
|
|
|
goto trunc64;
|
|
|
|
|
2009-06-25 12:01:17 -06:00
|
|
|
case CASE(TINT64, TUINT16):
|
|
|
|
case CASE(TUINT64, TUINT16):
|
2009-08-21 17:29:19 -06:00
|
|
|
a = AMOVHU;
|
|
|
|
goto trunc64;
|
2009-05-28 15:25:54 -06:00
|
|
|
|
2009-06-25 12:01:17 -06:00
|
|
|
case CASE(TINT32, TINT32): // same size
|
|
|
|
case CASE(TINT32, TUINT32):
|
|
|
|
case CASE(TUINT32, TINT32):
|
|
|
|
case CASE(TUINT32, TUINT32):
|
|
|
|
a = AMOVW;
|
|
|
|
break;
|
2009-05-28 15:25:54 -06:00
|
|
|
|
2009-06-25 12:01:17 -06:00
|
|
|
case CASE(TINT64, TINT32): // truncate
|
|
|
|
case CASE(TUINT64, TINT32):
|
|
|
|
case CASE(TINT64, TUINT32):
|
|
|
|
case CASE(TUINT64, TUINT32):
|
2009-08-21 17:29:19 -06:00
|
|
|
split64(f, &flo, &fhi);
|
|
|
|
regalloc(&r1, t->type, N);
|
|
|
|
gins(AMOVW, &flo, &r1);
|
|
|
|
gins(AMOVW, &r1, t);
|
|
|
|
regfree(&r1);
|
|
|
|
splitclean();
|
2009-05-28 15:25:54 -06:00
|
|
|
return;
|
|
|
|
|
2009-06-25 12:01:17 -06:00
|
|
|
case CASE(TINT64, TINT64): // same size
|
|
|
|
case CASE(TINT64, TUINT64):
|
|
|
|
case CASE(TUINT64, TINT64):
|
|
|
|
case CASE(TUINT64, TUINT64):
|
2009-08-21 17:29:19 -06:00
|
|
|
split64(f, &flo, &fhi);
|
|
|
|
split64(t, &tlo, &thi);
|
2009-09-15 17:12:47 -06:00
|
|
|
regalloc(&r1, flo.type, N);
|
|
|
|
regalloc(&r2, fhi.type, N);
|
|
|
|
gins(AMOVW, &flo, &r1);
|
|
|
|
gins(AMOVW, &fhi, &r2);
|
|
|
|
gins(AMOVW, &r1, &tlo);
|
|
|
|
gins(AMOVW, &r2, &thi);
|
|
|
|
regfree(&r1);
|
|
|
|
regfree(&r2);
|
2009-08-21 17:29:19 -06:00
|
|
|
splitclean();
|
|
|
|
splitclean();
|
2009-05-28 15:25:54 -06:00
|
|
|
return;
|
|
|
|
|
2009-06-25 12:01:17 -06:00
|
|
|
/*
|
|
|
|
* integer up-conversions
|
|
|
|
*/
|
2009-08-19 21:17:09 -06:00
|
|
|
case CASE(TINT8, TINT16): // sign extend int8
|
|
|
|
case CASE(TINT8, TUINT16):
|
|
|
|
case CASE(TINT8, TINT32):
|
|
|
|
case CASE(TINT8, TUINT32):
|
|
|
|
a = AMOVB;
|
|
|
|
goto rdst;
|
2009-08-21 17:29:19 -06:00
|
|
|
case CASE(TINT8, TINT64): // convert via int32
|
|
|
|
case CASE(TINT8, TUINT64):
|
|
|
|
cvt = types[TINT32];
|
|
|
|
goto hard;
|
agen, sgen, cgen_callret, cgen_asop, D_ADDR handling, gmove
8bit and 16bit, some optoas, replaced Addr.index with
Addr.name
empty function compiles, mutex compiles
R=rsc
APPROVED=rsc
DELTA=908 (83 added, 41 deleted, 784 changed)
OCL=31127
CL=31188
2009-07-06 07:42:37 -06:00
|
|
|
|
2009-08-19 21:17:09 -06:00
|
|
|
case CASE(TUINT8, TINT16): // zero extend uint8
|
|
|
|
case CASE(TUINT8, TUINT16):
|
|
|
|
case CASE(TUINT8, TINT32):
|
|
|
|
case CASE(TUINT8, TUINT32):
|
|
|
|
a = AMOVBU;
|
|
|
|
goto rdst;
|
2009-08-21 17:29:19 -06:00
|
|
|
case CASE(TUINT8, TINT64): // convert via uint32
|
|
|
|
case CASE(TUINT8, TUINT64):
|
|
|
|
cvt = types[TUINT32];
|
|
|
|
goto hard;
|
agen, sgen, cgen_callret, cgen_asop, D_ADDR handling, gmove
8bit and 16bit, some optoas, replaced Addr.index with
Addr.name
empty function compiles, mutex compiles
R=rsc
APPROVED=rsc
DELTA=908 (83 added, 41 deleted, 784 changed)
OCL=31127
CL=31188
2009-07-06 07:42:37 -06:00
|
|
|
|
2009-08-19 21:17:09 -06:00
|
|
|
case CASE(TINT16, TINT32): // sign extend int16
|
|
|
|
case CASE(TINT16, TUINT32):
|
|
|
|
a = AMOVH;
|
|
|
|
goto rdst;
|
2009-08-21 17:29:19 -06:00
|
|
|
case CASE(TINT16, TINT64): // convert via int32
|
|
|
|
case CASE(TINT16, TUINT64):
|
|
|
|
cvt = types[TINT32];
|
|
|
|
goto hard;
|
agen, sgen, cgen_callret, cgen_asop, D_ADDR handling, gmove
8bit and 16bit, some optoas, replaced Addr.index with
Addr.name
empty function compiles, mutex compiles
R=rsc
APPROVED=rsc
DELTA=908 (83 added, 41 deleted, 784 changed)
OCL=31127
CL=31188
2009-07-06 07:42:37 -06:00
|
|
|
|
2009-08-19 21:17:09 -06:00
|
|
|
case CASE(TUINT16, TINT32): // zero extend uint16
|
|
|
|
case CASE(TUINT16, TUINT32):
|
|
|
|
a = AMOVHU;
|
|
|
|
goto rdst;
|
2009-08-21 17:29:19 -06:00
|
|
|
case CASE(TUINT16, TINT64): // convert via uint32
|
|
|
|
case CASE(TUINT16, TUINT64):
|
|
|
|
cvt = types[TUINT32];
|
|
|
|
goto hard;
|
agen, sgen, cgen_callret, cgen_asop, D_ADDR handling, gmove
8bit and 16bit, some optoas, replaced Addr.index with
Addr.name
empty function compiles, mutex compiles
R=rsc
APPROVED=rsc
DELTA=908 (83 added, 41 deleted, 784 changed)
OCL=31127
CL=31188
2009-07-06 07:42:37 -06:00
|
|
|
|
2009-08-18 20:20:33 -06:00
|
|
|
case CASE(TINT32, TINT64): // sign extend int32
|
|
|
|
case CASE(TINT32, TUINT64):
|
2009-08-21 17:29:19 -06:00
|
|
|
split64(t, &tlo, &thi);
|
|
|
|
regalloc(&r1, tlo.type, N);
|
|
|
|
regalloc(&r2, thi.type, N);
|
|
|
|
gmove(f, &r1);
|
|
|
|
p1 = gins(AMOVW, &r1, &r2);
|
|
|
|
p1->from.type = D_SHIFT;
|
|
|
|
p1->from.offset = 2 << 5 | 31 << 7 | r1.val.u.reg; // r1->31
|
|
|
|
p1->from.reg = NREG;
|
|
|
|
//print("gmove: %P\n", p1);
|
|
|
|
gins(AMOVW, &r1, &tlo);
|
|
|
|
gins(AMOVW, &r2, &thi);
|
|
|
|
regfree(&r1);
|
|
|
|
regfree(&r2);
|
|
|
|
splitclean();
|
2009-08-18 20:20:33 -06:00
|
|
|
return;
|
|
|
|
|
|
|
|
case CASE(TUINT32, TINT64): // zero extend uint32
|
|
|
|
case CASE(TUINT32, TUINT64):
|
2009-08-21 17:29:19 -06:00
|
|
|
split64(t, &tlo, &thi);
|
|
|
|
gmove(f, &tlo);
|
2009-10-02 10:06:51 -06:00
|
|
|
regalloc(&r1, thi.type, N);
|
|
|
|
gins(AMOVW, ncon(0), &r1);
|
|
|
|
gins(AMOVW, &r1, &thi);
|
|
|
|
regfree(&r1);
|
2009-08-21 17:29:19 -06:00
|
|
|
splitclean();
|
2009-08-18 20:20:33 -06:00
|
|
|
return;
|
agen, sgen, cgen_callret, cgen_asop, D_ADDR handling, gmove
8bit and 16bit, some optoas, replaced Addr.index with
Addr.name
empty function compiles, mutex compiles
R=rsc
APPROVED=rsc
DELTA=908 (83 added, 41 deleted, 784 changed)
OCL=31127
CL=31188
2009-07-06 07:42:37 -06:00
|
|
|
|
2009-08-18 20:20:33 -06:00
|
|
|
/*
|
|
|
|
* float to integer
|
|
|
|
*/
|
|
|
|
case CASE(TFLOAT32, TINT8):
|
|
|
|
case CASE(TFLOAT32, TUINT8):
|
2010-07-28 06:58:35 -06:00
|
|
|
case CASE(TFLOAT32, TINT16):
|
2009-08-18 20:20:33 -06:00
|
|
|
case CASE(TFLOAT32, TUINT16):
|
2010-07-28 06:58:35 -06:00
|
|
|
case CASE(TFLOAT32, TINT32):
|
2009-08-18 20:20:33 -06:00
|
|
|
case CASE(TFLOAT32, TUINT32):
|
2010-11-11 20:54:35 -07:00
|
|
|
// case CASE(TFLOAT32, TUINT64):
|
agen, sgen, cgen_callret, cgen_asop, D_ADDR handling, gmove
8bit and 16bit, some optoas, replaced Addr.index with
Addr.name
empty function compiles, mutex compiles
R=rsc
APPROVED=rsc
DELTA=908 (83 added, 41 deleted, 784 changed)
OCL=31127
CL=31188
2009-07-06 07:42:37 -06:00
|
|
|
|
2009-08-18 20:20:33 -06:00
|
|
|
case CASE(TFLOAT64, TINT8):
|
|
|
|
case CASE(TFLOAT64, TUINT8):
|
2010-07-28 06:58:35 -06:00
|
|
|
case CASE(TFLOAT64, TINT16):
|
2009-08-18 20:20:33 -06:00
|
|
|
case CASE(TFLOAT64, TUINT16):
|
2010-07-28 06:58:35 -06:00
|
|
|
case CASE(TFLOAT64, TINT32):
|
2009-08-18 20:20:33 -06:00
|
|
|
case CASE(TFLOAT64, TUINT32):
|
2010-11-11 20:54:35 -07:00
|
|
|
// case CASE(TFLOAT64, TUINT64):
|
|
|
|
fa = AMOVF;
|
|
|
|
a = AMOVFW;
|
|
|
|
if(ft == TFLOAT64) {
|
|
|
|
fa = AMOVD;
|
|
|
|
a = AMOVDW;
|
|
|
|
}
|
2009-10-11 21:01:11 -06:00
|
|
|
ta = AMOVW;
|
2010-11-11 20:54:35 -07:00
|
|
|
switch(tt) {
|
|
|
|
case TINT8:
|
|
|
|
ta = AMOVB;
|
|
|
|
break;
|
|
|
|
case TUINT8:
|
|
|
|
ta = AMOVBU;
|
|
|
|
break;
|
|
|
|
case TINT16:
|
|
|
|
ta = AMOVH;
|
|
|
|
break;
|
|
|
|
case TUINT16:
|
|
|
|
ta = AMOVHU;
|
|
|
|
break;
|
|
|
|
}
|
agen, sgen, cgen_callret, cgen_asop, D_ADDR handling, gmove
8bit and 16bit, some optoas, replaced Addr.index with
Addr.name
empty function compiles, mutex compiles
R=rsc
APPROVED=rsc
DELTA=908 (83 added, 41 deleted, 784 changed)
OCL=31127
CL=31188
2009-07-06 07:42:37 -06:00
|
|
|
|
2010-11-11 20:54:35 -07:00
|
|
|
regalloc(&r1, types[ft], f);
|
|
|
|
regalloc(&r2, types[tt], t);
|
|
|
|
gins(fa, f, &r1); // load to fpu
|
|
|
|
p1 = gins(a, &r1, &r1); // convert to w
|
|
|
|
switch(tt) {
|
|
|
|
case TUINT8:
|
|
|
|
case TUINT16:
|
|
|
|
case TUINT32:
|
|
|
|
p1->scond |= C_UBIT;
|
|
|
|
}
|
|
|
|
gins(AMOVW, &r1, &r2); // copy to cpu
|
|
|
|
gins(ta, &r2, t); // store
|
|
|
|
regfree(&r1);
|
|
|
|
regfree(&r2);
|
2009-08-18 20:20:33 -06:00
|
|
|
return;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* integer to float
|
|
|
|
*/
|
|
|
|
case CASE(TINT8, TFLOAT32):
|
|
|
|
case CASE(TUINT8, TFLOAT32):
|
2010-07-28 06:58:35 -06:00
|
|
|
case CASE(TINT16, TFLOAT32):
|
2009-08-18 20:20:33 -06:00
|
|
|
case CASE(TUINT16, TFLOAT32):
|
2010-07-28 06:58:35 -06:00
|
|
|
case CASE(TINT32, TFLOAT32):
|
2009-08-18 20:20:33 -06:00
|
|
|
case CASE(TUINT32, TFLOAT32):
|
|
|
|
case CASE(TINT8, TFLOAT64):
|
|
|
|
case CASE(TUINT8, TFLOAT64):
|
2010-07-28 06:58:35 -06:00
|
|
|
case CASE(TINT16, TFLOAT64):
|
2009-08-18 20:20:33 -06:00
|
|
|
case CASE(TUINT16, TFLOAT64):
|
2010-07-28 06:58:35 -06:00
|
|
|
case CASE(TINT32, TFLOAT64):
|
2009-08-18 20:20:33 -06:00
|
|
|
case CASE(TUINT32, TFLOAT64):
|
2009-10-11 21:01:11 -06:00
|
|
|
fa = AMOVW;
|
2010-11-11 20:54:35 -07:00
|
|
|
switch(ft) {
|
|
|
|
case TINT8:
|
|
|
|
fa = AMOVB;
|
|
|
|
break;
|
|
|
|
case TUINT8:
|
|
|
|
fa = AMOVBU;
|
|
|
|
break;
|
|
|
|
case TINT16:
|
|
|
|
fa = AMOVH;
|
|
|
|
break;
|
|
|
|
case TUINT16:
|
|
|
|
fa = AMOVHU;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
a = AMOVWF;
|
|
|
|
ta = AMOVF;
|
|
|
|
if(tt == TFLOAT64) {
|
|
|
|
a = AMOVWD;
|
|
|
|
ta = AMOVD;
|
|
|
|
}
|
|
|
|
regalloc(&r1, types[ft], f);
|
|
|
|
regalloc(&r2, types[tt], t);
|
|
|
|
gins(fa, f, &r1); // load to cpu
|
|
|
|
gins(AMOVW, &r1, &r2); // copy to fpu
|
|
|
|
p1 = gins(a, &r2, &r2); // convert
|
|
|
|
switch(ft) {
|
|
|
|
case TUINT8:
|
|
|
|
case TUINT16:
|
|
|
|
case TUINT32:
|
|
|
|
p1->scond |= C_UBIT;
|
|
|
|
}
|
|
|
|
gins(ta, &r2, t); // store
|
|
|
|
regfree(&r1);
|
|
|
|
regfree(&r2);
|
|
|
|
return;
|
2009-08-18 20:20:33 -06:00
|
|
|
|
|
|
|
case CASE(TUINT64, TFLOAT32):
|
|
|
|
case CASE(TUINT64, TFLOAT64):
|
2009-10-11 21:01:11 -06:00
|
|
|
fatal("gmove UINT64, TFLOAT not implemented");
|
2009-08-18 20:20:33 -06:00
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* float to float
|
|
|
|
*/
|
|
|
|
case CASE(TFLOAT32, TFLOAT32):
|
|
|
|
a = AMOVF;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CASE(TFLOAT64, TFLOAT64):
|
|
|
|
a = AMOVD;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CASE(TFLOAT32, TFLOAT64):
|
2009-10-11 21:01:11 -06:00
|
|
|
regalloc(&r1, types[TFLOAT64], t);
|
|
|
|
gins(AMOVF, f, &r1);
|
|
|
|
gins(AMOVFD, &r1, &r1);
|
|
|
|
gins(AMOVD, &r1, t);
|
|
|
|
regfree(&r1);
|
|
|
|
return;
|
2009-08-18 20:20:33 -06:00
|
|
|
|
|
|
|
case CASE(TFLOAT64, TFLOAT32):
|
2009-10-11 21:01:11 -06:00
|
|
|
regalloc(&r1, types[TFLOAT64], t);
|
|
|
|
gins(AMOVD, f, &r1);
|
|
|
|
gins(AMOVDF, &r1, &r1);
|
|
|
|
gins(AMOVF, &r1, t);
|
|
|
|
regfree(&r1);
|
|
|
|
return;
|
2009-05-28 15:25:54 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
gins(a, f, t);
|
2009-06-25 12:01:17 -06:00
|
|
|
return;
|
|
|
|
|
2009-08-19 21:17:09 -06:00
|
|
|
rdst:
|
|
|
|
// TODO(kaib): we almost always require a register dest anyway, this can probably be
|
|
|
|
// removed.
|
2009-06-25 12:01:17 -06:00
|
|
|
// requires register destination
|
|
|
|
regalloc(&r1, t->type, t);
|
|
|
|
gins(a, f, &r1);
|
|
|
|
gmove(&r1, t);
|
|
|
|
regfree(&r1);
|
|
|
|
return;
|
|
|
|
|
|
|
|
hard:
|
|
|
|
// requires register intermediate
|
2009-10-11 21:01:11 -06:00
|
|
|
regalloc(&r1, cvt, t);
|
2009-06-25 12:01:17 -06:00
|
|
|
gmove(f, &r1);
|
|
|
|
gmove(&r1, t);
|
|
|
|
regfree(&r1);
|
|
|
|
return;
|
|
|
|
|
2009-08-21 17:29:19 -06:00
|
|
|
trunc64:
|
|
|
|
// truncate 64 bit integer
|
|
|
|
split64(f, &flo, &fhi);
|
|
|
|
regalloc(&r1, t->type, N);
|
|
|
|
gins(a, &flo, &r1);
|
|
|
|
gins(a, &r1, t);
|
|
|
|
regfree(&r1);
|
|
|
|
splitclean();
|
2009-06-25 12:01:17 -06:00
|
|
|
return;
|
|
|
|
|
|
|
|
fatal:
|
|
|
|
// should not happen
|
|
|
|
fatal("gmove %N -> %N", f, t);
|
2009-05-01 14:21:53 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
samaddr(Node *f, Node *t)
|
|
|
|
{
|
|
|
|
|
|
|
|
if(f->op != t->op)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
switch(f->op) {
|
|
|
|
case OREGISTER:
|
|
|
|
if(f->val.u.reg != t->val.u.reg)
|
|
|
|
break;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* generate one instruction:
|
|
|
|
* as f, t
|
|
|
|
*/
|
|
|
|
Prog*
|
|
|
|
gins(int as, Node *f, Node *t)
|
|
|
|
{
|
2009-08-18 08:16:10 -06:00
|
|
|
// Node nod;
|
|
|
|
// int32 v;
|
2009-05-01 14:21:53 -06:00
|
|
|
Prog *p;
|
2009-10-26 22:49:32 -06:00
|
|
|
Addr af, at;
|
2009-05-01 14:21:53 -06:00
|
|
|
|
agen, sgen, cgen_callret, cgen_asop, D_ADDR handling, gmove
8bit and 16bit, some optoas, replaced Addr.index with
Addr.name
empty function compiles, mutex compiles
R=rsc
APPROVED=rsc
DELTA=908 (83 added, 41 deleted, 784 changed)
OCL=31127
CL=31188
2009-07-06 07:42:37 -06:00
|
|
|
if(f != N && f->op == OINDEX) {
|
|
|
|
fatal("gins OINDEX not implemented");
|
2009-05-01 14:21:53 -06:00
|
|
|
// regalloc(&nod, ®node, Z);
|
|
|
|
// v = constnode.vconst;
|
|
|
|
// cgen(f->right, &nod);
|
|
|
|
// constnode.vconst = v;
|
|
|
|
// idx.reg = nod.reg;
|
|
|
|
// regfree(&nod);
|
agen, sgen, cgen_callret, cgen_asop, D_ADDR handling, gmove
8bit and 16bit, some optoas, replaced Addr.index with
Addr.name
empty function compiles, mutex compiles
R=rsc
APPROVED=rsc
DELTA=908 (83 added, 41 deleted, 784 changed)
OCL=31127
CL=31188
2009-07-06 07:42:37 -06:00
|
|
|
}
|
|
|
|
if(t != N && t->op == OINDEX) {
|
|
|
|
fatal("gins OINDEX not implemented");
|
2009-05-01 14:21:53 -06:00
|
|
|
// regalloc(&nod, ®node, Z);
|
|
|
|
// v = constnode.vconst;
|
|
|
|
// cgen(t->right, &nod);
|
|
|
|
// constnode.vconst = v;
|
|
|
|
// idx.reg = nod.reg;
|
|
|
|
// regfree(&nod);
|
agen, sgen, cgen_callret, cgen_asop, D_ADDR handling, gmove
8bit and 16bit, some optoas, replaced Addr.index with
Addr.name
empty function compiles, mutex compiles
R=rsc
APPROVED=rsc
DELTA=908 (83 added, 41 deleted, 784 changed)
OCL=31127
CL=31188
2009-07-06 07:42:37 -06:00
|
|
|
}
|
2009-05-01 14:21:53 -06:00
|
|
|
|
2009-10-26 22:49:32 -06:00
|
|
|
memset(&af, 0, sizeof af);
|
|
|
|
memset(&at, 0, sizeof at);
|
2009-05-01 14:21:53 -06:00
|
|
|
if(f != N)
|
2009-10-26 22:49:32 -06:00
|
|
|
naddr(f, &af, 1);
|
2009-05-01 14:21:53 -06:00
|
|
|
if(t != N)
|
2012-02-22 14:29:14 -07:00
|
|
|
naddr(t, &at, 1);
|
|
|
|
p = prog(as);
|
2009-10-26 22:49:32 -06:00
|
|
|
if(f != N)
|
|
|
|
p->from = af;
|
|
|
|
if(t != N)
|
|
|
|
p->to = at;
|
2009-05-01 14:21:53 -06:00
|
|
|
if(debug['g'])
|
|
|
|
print("%P\n", p);
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
2009-06-26 23:04:30 -06:00
|
|
|
/*
|
|
|
|
* insert n into reg slot of p
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
raddr(Node *n, Prog *p)
|
|
|
|
{
|
|
|
|
Addr a;
|
|
|
|
|
2009-10-26 22:49:32 -06:00
|
|
|
naddr(n, &a, 1);
|
2009-06-26 23:04:30 -06:00
|
|
|
if(a.type != D_REG && a.type != D_FREG) {
|
|
|
|
if(n)
|
|
|
|
fatal("bad in raddr: %O", n->op);
|
|
|
|
else
|
|
|
|
fatal("bad in raddr: <null>");
|
|
|
|
p->reg = NREG;
|
|
|
|
} else
|
|
|
|
p->reg = a.reg;
|
|
|
|
}
|
|
|
|
|
2009-09-28 16:40:13 -06:00
|
|
|
/* generate a comparison
|
2009-10-27 23:38:45 -06:00
|
|
|
TODO(kaib): one of the args can actually be a small constant. relax the constraint and fix call sites.
|
2009-09-28 16:40:13 -06:00
|
|
|
*/
|
|
|
|
Prog*
|
|
|
|
gcmp(int as, Node *lhs, Node *rhs)
|
|
|
|
{
|
|
|
|
Prog *p;
|
|
|
|
|
cmd/5g: avoid temporary in slice bounds check
before
func addr(s[]int) *int {
return &s[2]
10c1c: e28d0008 add r0, sp, #8
10c20: e5901004 ldr r1, [r0, #4]
10c24: e3a02002 mov r2, #2
10c28: e1510002 cmp r1, r2
10c2c: 8a000000 bhi 10c34 <main.addr+0x34>
10c30: eb0035e6 bl 1e3d0 <runtime.panicindex>
10c34: e5900000 ldr r0, [r0]
10c38: e2800008 add r0, r0, #8
10c3c: e58d0014 str r0, [sp, #20]
10c40: e49df004 pop {pc} ; (ldr pc, [sp], #4)
after
func addr(s[]int) *int {
return &s[2]
10c1c: e28d0008 add r0, sp, #8
10c20: e5901004 ldr r1, [r0, #4]
10c24: e3510002 cmp r1, #2
10c28: 8a000000 bhi 10c30 <main.addr+0x30>
10c2c: eb0035e6 bl 1e3cc <runtime.panicindex>
10c30: e5900000 ldr r0, [r0]
10c34: e2800008 add r0, r0, #8
10c38: e58d0014 str r0, [sp, #20]
10c3c: e49df004 pop {pc} ; (ldr pc, [sp], #4)
Also, relax gcmp restriction that 2nd operand must be a register. A followup
CL will address the remaining TODO items.
R=rsc, remyoudompheng, minux.ma
CC=golang-dev
https://golang.org/cl/6620064
2012-10-06 18:37:14 -06:00
|
|
|
if(lhs->op != OREGISTER)
|
2009-09-28 16:40:13 -06:00
|
|
|
fatal("bad operands to gcmp: %O %O", lhs->op, rhs->op);
|
|
|
|
|
|
|
|
p = gins(as, rhs, N);
|
|
|
|
raddr(lhs, p);
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
2009-10-12 14:35:28 -06:00
|
|
|
/* generate a constant shift
|
2009-10-15 20:41:51 -06:00
|
|
|
* arm encodes a shift by 32 as 0, thus asking for 0 shift is illegal.
|
2009-10-12 14:35:28 -06:00
|
|
|
*/
|
|
|
|
Prog*
|
|
|
|
gshift(int as, Node *lhs, int32 stype, int32 sval, Node *rhs)
|
|
|
|
{
|
|
|
|
Prog *p;
|
|
|
|
|
2010-07-30 01:37:51 -06:00
|
|
|
if(sval <= 0 || sval > 32)
|
2009-10-12 14:35:28 -06:00
|
|
|
fatal("bad shift value: %d", sval);
|
|
|
|
|
2009-10-15 20:41:51 -06:00
|
|
|
sval = sval&0x1f;
|
|
|
|
|
2009-10-12 14:35:28 -06:00
|
|
|
p = gins(as, N, rhs);
|
|
|
|
p->from.type = D_SHIFT;
|
|
|
|
p->from.offset = stype | sval<<7 | lhs->val.u.reg;
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* generate a register shift
|
|
|
|
*/
|
|
|
|
Prog *
|
|
|
|
gregshift(int as, Node *lhs, int32 stype, Node *reg, Node *rhs)
|
|
|
|
{
|
|
|
|
Prog *p;
|
|
|
|
p = gins(as, N, rhs);
|
|
|
|
p->from.type = D_SHIFT;
|
|
|
|
p->from.offset = stype | reg->val.u.reg << 8 | 1<<4 | lhs->val.u.reg;
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
2012-06-02 20:50:57 -06:00
|
|
|
// Generate an instruction referencing *n
|
|
|
|
// to force segv on nil pointer dereference.
|
2012-06-02 21:57:38 -06:00
|
|
|
void
|
2012-06-02 20:50:57 -06:00
|
|
|
checkref(Node *n)
|
|
|
|
{
|
|
|
|
Node m1, m2;
|
|
|
|
|
|
|
|
if(n->type->type->width < unmappedzero)
|
|
|
|
return;
|
|
|
|
|
|
|
|
regalloc(&m1, types[TUINTPTR], n);
|
|
|
|
regalloc(&m2, types[TUINT8], n);
|
|
|
|
cgen(n, &m1);
|
|
|
|
m1.xoffset = 0;
|
|
|
|
m1.op = OINDREG;
|
|
|
|
m1.type = types[TUINT8];
|
|
|
|
gins(AMOVBU, &m1, &m2);
|
|
|
|
regfree(&m2);
|
|
|
|
regfree(&m1);
|
|
|
|
}
|
|
|
|
|
2009-10-26 22:49:32 -06:00
|
|
|
static void
|
|
|
|
checkoffset(Addr *a, int canemitcode)
|
|
|
|
{
|
|
|
|
Prog *p;
|
|
|
|
Node n1;
|
|
|
|
|
|
|
|
if(a->offset < unmappedzero)
|
|
|
|
return;
|
|
|
|
if(!canemitcode)
|
2010-12-12 12:40:19 -07:00
|
|
|
fatal("checkoffset %#x, cannot emit code", a->offset);
|
2009-10-26 22:49:32 -06:00
|
|
|
|
|
|
|
// cannot rely on unmapped nil page at 0 to catch
|
|
|
|
// reference with large offset. instead, emit explicit
|
|
|
|
// test of 0(reg).
|
|
|
|
regalloc(&n1, types[TUINTPTR], N);
|
2012-12-05 22:52:16 -07:00
|
|
|
p = gins(AMOVB, N, &n1);
|
2009-10-26 22:49:32 -06:00
|
|
|
p->from = *a;
|
|
|
|
p->from.offset = 0;
|
|
|
|
regfree(&n1);
|
|
|
|
}
|
2009-09-28 16:40:13 -06:00
|
|
|
|
2009-05-01 14:21:53 -06:00
|
|
|
/*
|
|
|
|
* generate code to compute n;
|
|
|
|
* make a refer to result.
|
|
|
|
*/
|
|
|
|
void
|
2009-10-26 22:49:32 -06:00
|
|
|
naddr(Node *n, Addr *a, int canemitcode)
|
2009-05-01 14:21:53 -06:00
|
|
|
{
|
|
|
|
a->type = D_NONE;
|
agen, sgen, cgen_callret, cgen_asop, D_ADDR handling, gmove
8bit and 16bit, some optoas, replaced Addr.index with
Addr.name
empty function compiles, mutex compiles
R=rsc
APPROVED=rsc
DELTA=908 (83 added, 41 deleted, 784 changed)
OCL=31127
CL=31188
2009-07-06 07:42:37 -06:00
|
|
|
a->name = D_NONE;
|
|
|
|
a->reg = NREG;
|
2011-06-09 16:02:34 -06:00
|
|
|
a->node = N;
|
2011-07-28 16:22:12 -06:00
|
|
|
a->etype = 0;
|
2009-05-01 14:21:53 -06:00
|
|
|
if(n == N)
|
|
|
|
return;
|
|
|
|
|
2012-09-22 08:01:35 -06:00
|
|
|
if(n->type != T && n->type->etype != TIDEAL) {
|
|
|
|
dowidth(n->type);
|
|
|
|
a->width = n->type->width;
|
|
|
|
}
|
|
|
|
|
2009-05-01 14:21:53 -06:00
|
|
|
switch(n->op) {
|
|
|
|
default:
|
|
|
|
fatal("naddr: bad %O %D", n->op, a);
|
|
|
|
break;
|
|
|
|
|
2009-06-25 12:01:17 -06:00
|
|
|
case OREGISTER:
|
2010-07-30 01:37:51 -06:00
|
|
|
if(n->val.u.reg <= REGALLOC_RMAX) {
|
2009-10-01 14:52:55 -06:00
|
|
|
a->type = D_REG;
|
2009-06-25 12:01:17 -06:00
|
|
|
a->reg = n->val.u.reg;
|
2009-10-01 14:52:55 -06:00
|
|
|
} else {
|
|
|
|
a->type = D_FREG;
|
2009-06-25 12:01:17 -06:00
|
|
|
a->reg = n->val.u.reg - REGALLOC_F0;
|
2009-10-01 14:52:55 -06:00
|
|
|
}
|
2009-06-25 12:01:17 -06:00
|
|
|
a->sym = S;
|
|
|
|
break;
|
2009-05-01 14:21:53 -06:00
|
|
|
|
2009-06-25 12:01:17 -06:00
|
|
|
case OINDEX:
|
|
|
|
case OIND:
|
agen, sgen, cgen_callret, cgen_asop, D_ADDR handling, gmove
8bit and 16bit, some optoas, replaced Addr.index with
Addr.name
empty function compiles, mutex compiles
R=rsc
APPROVED=rsc
DELTA=908 (83 added, 41 deleted, 784 changed)
OCL=31127
CL=31188
2009-07-06 07:42:37 -06:00
|
|
|
fatal("naddr: OINDEX");
|
2009-05-01 14:21:53 -06:00
|
|
|
// naddr(n->left, a);
|
|
|
|
// if(a->type >= D_AX && a->type <= D_DI)
|
|
|
|
// a->type += D_INDIR;
|
|
|
|
// else
|
|
|
|
// if(a->type == D_CONST)
|
|
|
|
// a->type = D_NONE+D_INDIR;
|
|
|
|
// else
|
|
|
|
// if(a->type == D_ADDR) {
|
|
|
|
// a->type = a->index;
|
|
|
|
// a->index = D_NONE;
|
|
|
|
// } else
|
|
|
|
// goto bad;
|
|
|
|
// if(n->op == OINDEX) {
|
|
|
|
// a->index = idx.reg;
|
|
|
|
// a->scale = n->scale;
|
|
|
|
// }
|
|
|
|
// break;
|
|
|
|
|
agen, sgen, cgen_callret, cgen_asop, D_ADDR handling, gmove
8bit and 16bit, some optoas, replaced Addr.index with
Addr.name
empty function compiles, mutex compiles
R=rsc
APPROVED=rsc
DELTA=908 (83 added, 41 deleted, 784 changed)
OCL=31127
CL=31188
2009-07-06 07:42:37 -06:00
|
|
|
case OINDREG:
|
|
|
|
a->type = D_OREG;
|
|
|
|
a->reg = n->val.u.reg;
|
|
|
|
a->sym = n->sym;
|
|
|
|
a->offset = n->xoffset;
|
2009-10-26 22:49:32 -06:00
|
|
|
checkoffset(a, canemitcode);
|
agen, sgen, cgen_callret, cgen_asop, D_ADDR handling, gmove
8bit and 16bit, some optoas, replaced Addr.index with
Addr.name
empty function compiles, mutex compiles
R=rsc
APPROVED=rsc
DELTA=908 (83 added, 41 deleted, 784 changed)
OCL=31127
CL=31188
2009-07-06 07:42:37 -06:00
|
|
|
break;
|
2009-05-01 14:21:53 -06:00
|
|
|
|
2009-09-18 00:07:52 -06:00
|
|
|
case OPARAM:
|
|
|
|
// n->left is PHEAP ONAME for stack parameter.
|
|
|
|
// compute address of actual parameter on stack.
|
|
|
|
a->etype = simtype[n->left->type->etype];
|
|
|
|
a->width = n->left->type->width;
|
|
|
|
a->offset = n->xoffset;
|
|
|
|
a->sym = n->left->sym;
|
|
|
|
a->type = D_OREG;
|
|
|
|
a->name = D_PARAM;
|
2011-10-03 15:46:36 -06:00
|
|
|
a->node = n->left->orig;
|
2009-09-18 00:07:52 -06:00
|
|
|
break;
|
2009-05-01 14:21:53 -06:00
|
|
|
|
|
|
|
case ONAME:
|
|
|
|
a->etype = 0;
|
2009-05-28 15:25:54 -06:00
|
|
|
a->width = 0;
|
agen, sgen, cgen_callret, cgen_asop, D_ADDR handling, gmove
8bit and 16bit, some optoas, replaced Addr.index with
Addr.name
empty function compiles, mutex compiles
R=rsc
APPROVED=rsc
DELTA=908 (83 added, 41 deleted, 784 changed)
OCL=31127
CL=31188
2009-07-06 07:42:37 -06:00
|
|
|
a->reg = NREG;
|
2009-05-28 15:25:54 -06:00
|
|
|
if(n->type != T) {
|
2009-05-01 14:21:53 -06:00
|
|
|
a->etype = simtype[n->type->etype];
|
2009-05-28 15:25:54 -06:00
|
|
|
a->width = n->type->width;
|
|
|
|
}
|
2009-05-01 14:21:53 -06:00
|
|
|
a->offset = n->xoffset;
|
|
|
|
a->sym = n->sym;
|
2011-10-03 15:46:36 -06:00
|
|
|
a->node = n->orig;
|
|
|
|
//if(a->node >= (Node*)&n)
|
|
|
|
// fatal("stack node");
|
2009-05-01 14:21:53 -06:00
|
|
|
if(a->sym == S)
|
|
|
|
a->sym = lookup(".noname");
|
|
|
|
if(n->method) {
|
|
|
|
if(n->type != T)
|
|
|
|
if(n->type->sym != S)
|
2010-01-22 18:06:20 -07:00
|
|
|
if(n->type->sym->pkg != nil)
|
|
|
|
a->sym = pkglookup(a->sym->name, n->type->sym->pkg);
|
2009-05-01 14:21:53 -06:00
|
|
|
}
|
|
|
|
|
agen, sgen, cgen_callret, cgen_asop, D_ADDR handling, gmove
8bit and 16bit, some optoas, replaced Addr.index with
Addr.name
empty function compiles, mutex compiles
R=rsc
APPROVED=rsc
DELTA=908 (83 added, 41 deleted, 784 changed)
OCL=31127
CL=31188
2009-07-06 07:42:37 -06:00
|
|
|
a->type = D_OREG;
|
2009-05-01 14:21:53 -06:00
|
|
|
switch(n->class) {
|
|
|
|
default:
|
|
|
|
fatal("naddr: ONAME class %S %d\n", n->sym, n->class);
|
|
|
|
case PEXTERN:
|
agen, sgen, cgen_callret, cgen_asop, D_ADDR handling, gmove
8bit and 16bit, some optoas, replaced Addr.index with
Addr.name
empty function compiles, mutex compiles
R=rsc
APPROVED=rsc
DELTA=908 (83 added, 41 deleted, 784 changed)
OCL=31127
CL=31188
2009-07-06 07:42:37 -06:00
|
|
|
a->name = D_EXTERN;
|
2009-05-01 14:21:53 -06:00
|
|
|
break;
|
|
|
|
case PAUTO:
|
agen, sgen, cgen_callret, cgen_asop, D_ADDR handling, gmove
8bit and 16bit, some optoas, replaced Addr.index with
Addr.name
empty function compiles, mutex compiles
R=rsc
APPROVED=rsc
DELTA=908 (83 added, 41 deleted, 784 changed)
OCL=31127
CL=31188
2009-07-06 07:42:37 -06:00
|
|
|
a->name = D_AUTO;
|
2009-05-01 14:21:53 -06:00
|
|
|
break;
|
|
|
|
case PPARAM:
|
|
|
|
case PPARAMOUT:
|
agen, sgen, cgen_callret, cgen_asop, D_ADDR handling, gmove
8bit and 16bit, some optoas, replaced Addr.index with
Addr.name
empty function compiles, mutex compiles
R=rsc
APPROVED=rsc
DELTA=908 (83 added, 41 deleted, 784 changed)
OCL=31127
CL=31188
2009-07-06 07:42:37 -06:00
|
|
|
a->name = D_PARAM;
|
2009-05-01 14:21:53 -06:00
|
|
|
break;
|
|
|
|
case PFUNC:
|
agen, sgen, cgen_callret, cgen_asop, D_ADDR handling, gmove
8bit and 16bit, some optoas, replaced Addr.index with
Addr.name
empty function compiles, mutex compiles
R=rsc
APPROVED=rsc
DELTA=908 (83 added, 41 deleted, 784 changed)
OCL=31127
CL=31188
2009-07-06 07:42:37 -06:00
|
|
|
a->name = D_EXTERN;
|
2009-10-19 13:44:08 -06:00
|
|
|
a->type = D_CONST;
|
2009-05-01 14:21:53 -06:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OLITERAL:
|
|
|
|
switch(n->val.ctype) {
|
|
|
|
default:
|
|
|
|
fatal("naddr: const %lT", n->type);
|
|
|
|
break;
|
|
|
|
case CTFLT:
|
|
|
|
a->type = D_FCONST;
|
2012-12-13 12:20:24 -07:00
|
|
|
a->u.dval = mpgetflt(n->val.u.fval);
|
2009-05-01 14:21:53 -06:00
|
|
|
break;
|
|
|
|
case CTINT:
|
2011-12-08 20:07:43 -07:00
|
|
|
case CTRUNE:
|
2009-05-01 14:21:53 -06:00
|
|
|
a->sym = S;
|
|
|
|
a->type = D_CONST;
|
|
|
|
a->offset = mpgetfix(n->val.u.xval);
|
|
|
|
break;
|
|
|
|
case CTSTR:
|
2009-05-28 15:25:54 -06:00
|
|
|
datagostring(n->val.u.sval, a);
|
2009-05-01 14:21:53 -06:00
|
|
|
break;
|
|
|
|
case CTBOOL:
|
|
|
|
a->sym = S;
|
|
|
|
a->type = D_CONST;
|
|
|
|
a->offset = n->val.u.bval;
|
|
|
|
break;
|
|
|
|
case CTNIL:
|
|
|
|
a->sym = S;
|
|
|
|
a->type = D_CONST;
|
|
|
|
a->offset = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2012-02-10 22:19:24 -07:00
|
|
|
case OITAB:
|
|
|
|
// itable of interface value
|
|
|
|
naddr(n->left, a, canemitcode);
|
|
|
|
a->etype = TINT32;
|
|
|
|
if(a->type == D_CONST && a->offset == 0)
|
|
|
|
break; // len(nil)
|
|
|
|
if(a->offset >= unmappedzero && a->offset-Array_nel < unmappedzero)
|
|
|
|
checkoffset(a, canemitcode);
|
|
|
|
break;
|
|
|
|
|
2009-07-27 16:55:27 -06:00
|
|
|
case OLEN:
|
|
|
|
// len of string or slice
|
2009-10-26 22:49:32 -06:00
|
|
|
naddr(n->left, a, canemitcode);
|
2011-07-28 16:22:12 -06:00
|
|
|
a->etype = TINT32;
|
2010-06-29 13:48:24 -06:00
|
|
|
if(a->type == D_CONST && a->offset == 0)
|
|
|
|
break; // len(nil)
|
2009-07-27 16:55:27 -06:00
|
|
|
a->offset += Array_nel;
|
2009-10-26 22:49:32 -06:00
|
|
|
if(a->offset >= unmappedzero && a->offset-Array_nel < unmappedzero)
|
|
|
|
checkoffset(a, canemitcode);
|
2009-07-27 16:55:27 -06:00
|
|
|
break;
|
|
|
|
|
|
|
|
case OCAP:
|
|
|
|
// cap of string or slice
|
2009-10-26 22:49:32 -06:00
|
|
|
naddr(n->left, a, canemitcode);
|
2011-07-28 16:22:12 -06:00
|
|
|
a->etype = TINT32;
|
2010-06-29 13:48:24 -06:00
|
|
|
if(a->type == D_CONST && a->offset == 0)
|
|
|
|
break; // cap(nil)
|
2009-07-27 16:55:27 -06:00
|
|
|
a->offset += Array_cap;
|
2009-10-26 22:49:32 -06:00
|
|
|
if(a->offset >= unmappedzero && a->offset-Array_cap < unmappedzero)
|
|
|
|
checkoffset(a, canemitcode);
|
2009-07-27 16:55:27 -06:00
|
|
|
break;
|
|
|
|
|
agen, sgen, cgen_callret, cgen_asop, D_ADDR handling, gmove
8bit and 16bit, some optoas, replaced Addr.index with
Addr.name
empty function compiles, mutex compiles
R=rsc
APPROVED=rsc
DELTA=908 (83 added, 41 deleted, 784 changed)
OCL=31127
CL=31188
2009-07-06 07:42:37 -06:00
|
|
|
case OADDR:
|
2009-10-26 22:49:32 -06:00
|
|
|
naddr(n->left, a, canemitcode);
|
2011-07-28 16:22:12 -06:00
|
|
|
a->etype = tptr;
|
2009-10-19 13:44:08 -06:00
|
|
|
switch(a->type) {
|
|
|
|
case D_OREG:
|
agen, sgen, cgen_callret, cgen_asop, D_ADDR handling, gmove
8bit and 16bit, some optoas, replaced Addr.index with
Addr.name
empty function compiles, mutex compiles
R=rsc
APPROVED=rsc
DELTA=908 (83 added, 41 deleted, 784 changed)
OCL=31127
CL=31188
2009-07-06 07:42:37 -06:00
|
|
|
a->type = D_CONST;
|
|
|
|
break;
|
2009-10-19 13:44:08 -06:00
|
|
|
|
|
|
|
case D_REG:
|
|
|
|
case D_CONST:
|
2009-08-18 20:20:33 -06:00
|
|
|
break;
|
2009-10-19 13:44:08 -06:00
|
|
|
|
|
|
|
default:
|
|
|
|
fatal("naddr: OADDR %d\n", a->type);
|
agen, sgen, cgen_callret, cgen_asop, D_ADDR handling, gmove
8bit and 16bit, some optoas, replaced Addr.index with
Addr.name
empty function compiles, mutex compiles
R=rsc
APPROVED=rsc
DELTA=908 (83 added, 41 deleted, 784 changed)
OCL=31127
CL=31188
2009-07-06 07:42:37 -06:00
|
|
|
}
|
2009-05-01 14:21:53 -06:00
|
|
|
}
|
2012-09-22 08:01:35 -06:00
|
|
|
|
|
|
|
if(a->width < 0)
|
|
|
|
fatal("naddr: bad width for %N -> %D", n, a);
|
2009-05-01 14:21:53 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* return Axxx for Oxxx on type t.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
optoas(int op, Type *t)
|
|
|
|
{
|
2009-05-28 15:25:54 -06:00
|
|
|
int a;
|
|
|
|
|
|
|
|
if(t == T)
|
|
|
|
fatal("optoas: t is nil");
|
|
|
|
|
|
|
|
a = AGOK;
|
|
|
|
switch(CASE(op, simtype[t->etype])) {
|
|
|
|
default:
|
2009-10-06 10:47:46 -06:00
|
|
|
fatal("optoas: no entry %O-%T etype %T simtype %T", op, t, types[t->etype], types[simtype[t->etype]]);
|
2009-05-28 15:25:54 -06:00
|
|
|
break;
|
|
|
|
|
|
|
|
/* case CASE(OADDR, TPTR32):
|
|
|
|
a = ALEAL;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CASE(OADDR, TPTR64):
|
|
|
|
a = ALEAQ;
|
|
|
|
break;
|
|
|
|
*/
|
2009-09-28 16:40:13 -06:00
|
|
|
// TODO(kaib): make sure the conditional branches work on all edge cases
|
2009-05-28 15:25:54 -06:00
|
|
|
case CASE(OEQ, TBOOL):
|
|
|
|
case CASE(OEQ, TINT8):
|
|
|
|
case CASE(OEQ, TUINT8):
|
|
|
|
case CASE(OEQ, TINT16):
|
|
|
|
case CASE(OEQ, TUINT16):
|
|
|
|
case CASE(OEQ, TINT32):
|
|
|
|
case CASE(OEQ, TUINT32):
|
|
|
|
case CASE(OEQ, TINT64):
|
|
|
|
case CASE(OEQ, TUINT64):
|
|
|
|
case CASE(OEQ, TPTR32):
|
|
|
|
case CASE(OEQ, TPTR64):
|
|
|
|
case CASE(OEQ, TFLOAT32):
|
|
|
|
case CASE(OEQ, TFLOAT64):
|
|
|
|
a = ABEQ;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CASE(ONE, TBOOL):
|
|
|
|
case CASE(ONE, TINT8):
|
|
|
|
case CASE(ONE, TUINT8):
|
|
|
|
case CASE(ONE, TINT16):
|
|
|
|
case CASE(ONE, TUINT16):
|
|
|
|
case CASE(ONE, TINT32):
|
|
|
|
case CASE(ONE, TUINT32):
|
|
|
|
case CASE(ONE, TINT64):
|
|
|
|
case CASE(ONE, TUINT64):
|
|
|
|
case CASE(ONE, TPTR32):
|
|
|
|
case CASE(ONE, TPTR64):
|
|
|
|
case CASE(ONE, TFLOAT32):
|
|
|
|
case CASE(ONE, TFLOAT64):
|
|
|
|
a = ABNE;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CASE(OLT, TINT8):
|
|
|
|
case CASE(OLT, TINT16):
|
|
|
|
case CASE(OLT, TINT32):
|
|
|
|
case CASE(OLT, TINT64):
|
2009-10-24 23:47:25 -06:00
|
|
|
case CASE(OLT, TFLOAT32):
|
|
|
|
case CASE(OLT, TFLOAT64):
|
|
|
|
a = ABLT;
|
|
|
|
break;
|
|
|
|
|
2009-05-28 15:25:54 -06:00
|
|
|
case CASE(OLT, TUINT8):
|
|
|
|
case CASE(OLT, TUINT16):
|
|
|
|
case CASE(OLT, TUINT32):
|
|
|
|
case CASE(OLT, TUINT64):
|
2009-10-24 23:47:25 -06:00
|
|
|
a = ABLO;
|
2009-05-28 15:25:54 -06:00
|
|
|
break;
|
|
|
|
|
|
|
|
case CASE(OLE, TINT8):
|
|
|
|
case CASE(OLE, TINT16):
|
|
|
|
case CASE(OLE, TINT32):
|
|
|
|
case CASE(OLE, TINT64):
|
2009-10-24 23:47:25 -06:00
|
|
|
case CASE(OLE, TFLOAT32):
|
|
|
|
case CASE(OLE, TFLOAT64):
|
|
|
|
a = ABLE;
|
|
|
|
break;
|
|
|
|
|
2009-05-28 15:25:54 -06:00
|
|
|
case CASE(OLE, TUINT8):
|
|
|
|
case CASE(OLE, TUINT16):
|
|
|
|
case CASE(OLE, TUINT32):
|
|
|
|
case CASE(OLE, TUINT64):
|
2009-10-24 23:47:25 -06:00
|
|
|
a = ABLS;
|
2009-05-28 15:25:54 -06:00
|
|
|
break;
|
|
|
|
|
|
|
|
case CASE(OGT, TINT8):
|
|
|
|
case CASE(OGT, TINT16):
|
|
|
|
case CASE(OGT, TINT32):
|
|
|
|
case CASE(OGT, TINT64):
|
2009-10-24 23:47:25 -06:00
|
|
|
case CASE(OGT, TFLOAT32):
|
|
|
|
case CASE(OGT, TFLOAT64):
|
|
|
|
a = ABGT;
|
|
|
|
break;
|
|
|
|
|
2009-05-28 15:25:54 -06:00
|
|
|
case CASE(OGT, TUINT8):
|
|
|
|
case CASE(OGT, TUINT16):
|
|
|
|
case CASE(OGT, TUINT32):
|
|
|
|
case CASE(OGT, TUINT64):
|
2009-10-24 23:47:25 -06:00
|
|
|
a = ABHI;
|
2009-05-28 15:25:54 -06:00
|
|
|
break;
|
|
|
|
|
|
|
|
case CASE(OGE, TINT8):
|
|
|
|
case CASE(OGE, TINT16):
|
|
|
|
case CASE(OGE, TINT32):
|
|
|
|
case CASE(OGE, TINT64):
|
2009-10-24 23:47:25 -06:00
|
|
|
case CASE(OGE, TFLOAT32):
|
|
|
|
case CASE(OGE, TFLOAT64):
|
|
|
|
a = ABGE;
|
|
|
|
break;
|
|
|
|
|
2009-05-28 15:25:54 -06:00
|
|
|
case CASE(OGE, TUINT8):
|
|
|
|
case CASE(OGE, TUINT16):
|
|
|
|
case CASE(OGE, TUINT32):
|
|
|
|
case CASE(OGE, TUINT64):
|
2009-10-24 23:47:25 -06:00
|
|
|
a = ABHS;
|
2009-05-28 15:25:54 -06:00
|
|
|
break;
|
|
|
|
|
|
|
|
case CASE(OCMP, TBOOL):
|
|
|
|
case CASE(OCMP, TINT8):
|
|
|
|
case CASE(OCMP, TUINT8):
|
2009-08-21 17:29:19 -06:00
|
|
|
case CASE(OCMP, TINT16):
|
|
|
|
case CASE(OCMP, TUINT16):
|
agen, sgen, cgen_callret, cgen_asop, D_ADDR handling, gmove
8bit and 16bit, some optoas, replaced Addr.index with
Addr.name
empty function compiles, mutex compiles
R=rsc
APPROVED=rsc
DELTA=908 (83 added, 41 deleted, 784 changed)
OCL=31127
CL=31188
2009-07-06 07:42:37 -06:00
|
|
|
case CASE(OCMP, TINT32):
|
|
|
|
case CASE(OCMP, TUINT32):
|
|
|
|
case CASE(OCMP, TPTR32):
|
|
|
|
a = ACMP;
|
|
|
|
break;
|
2009-05-28 15:25:54 -06:00
|
|
|
|
2009-08-18 20:20:33 -06:00
|
|
|
case CASE(OCMP, TFLOAT32):
|
|
|
|
a = ACMPF;
|
|
|
|
break;
|
2009-05-28 15:25:54 -06:00
|
|
|
|
2009-08-18 20:20:33 -06:00
|
|
|
case CASE(OCMP, TFLOAT64):
|
|
|
|
a = ACMPD;
|
|
|
|
break;
|
2009-05-28 15:25:54 -06:00
|
|
|
|
agen, sgen, cgen_callret, cgen_asop, D_ADDR handling, gmove
8bit and 16bit, some optoas, replaced Addr.index with
Addr.name
empty function compiles, mutex compiles
R=rsc
APPROVED=rsc
DELTA=908 (83 added, 41 deleted, 784 changed)
OCL=31127
CL=31188
2009-07-06 07:42:37 -06:00
|
|
|
case CASE(OAS, TBOOL):
|
|
|
|
case CASE(OAS, TINT8):
|
|
|
|
a = AMOVB;
|
|
|
|
break;
|
2009-05-28 15:25:54 -06:00
|
|
|
|
2010-09-28 19:12:46 -06:00
|
|
|
case CASE(OAS, TUINT8):
|
|
|
|
a = AMOVBU;
|
|
|
|
break;
|
|
|
|
|
agen, sgen, cgen_callret, cgen_asop, D_ADDR handling, gmove
8bit and 16bit, some optoas, replaced Addr.index with
Addr.name
empty function compiles, mutex compiles
R=rsc
APPROVED=rsc
DELTA=908 (83 added, 41 deleted, 784 changed)
OCL=31127
CL=31188
2009-07-06 07:42:37 -06:00
|
|
|
case CASE(OAS, TINT16):
|
|
|
|
a = AMOVH;
|
|
|
|
break;
|
2009-05-28 15:25:54 -06:00
|
|
|
|
2010-09-28 19:12:46 -06:00
|
|
|
case CASE(OAS, TUINT16):
|
|
|
|
a = AMOVHU;
|
|
|
|
break;
|
|
|
|
|
agen, sgen, cgen_callret, cgen_asop, D_ADDR handling, gmove
8bit and 16bit, some optoas, replaced Addr.index with
Addr.name
empty function compiles, mutex compiles
R=rsc
APPROVED=rsc
DELTA=908 (83 added, 41 deleted, 784 changed)
OCL=31127
CL=31188
2009-07-06 07:42:37 -06:00
|
|
|
case CASE(OAS, TINT32):
|
|
|
|
case CASE(OAS, TUINT32):
|
|
|
|
case CASE(OAS, TPTR32):
|
|
|
|
a = AMOVW;
|
|
|
|
break;
|
2009-05-28 15:25:54 -06:00
|
|
|
|
2009-08-18 20:20:33 -06:00
|
|
|
case CASE(OAS, TFLOAT32):
|
|
|
|
a = AMOVF;
|
|
|
|
break;
|
2009-05-28 15:25:54 -06:00
|
|
|
|
2009-08-18 20:20:33 -06:00
|
|
|
case CASE(OAS, TFLOAT64):
|
|
|
|
a = AMOVD;
|
|
|
|
break;
|
2009-05-28 15:25:54 -06:00
|
|
|
|
2009-06-25 12:01:17 -06:00
|
|
|
case CASE(OADD, TINT8):
|
|
|
|
case CASE(OADD, TUINT8):
|
|
|
|
case CASE(OADD, TINT16):
|
|
|
|
case CASE(OADD, TUINT16):
|
|
|
|
case CASE(OADD, TINT32):
|
|
|
|
case CASE(OADD, TUINT32):
|
|
|
|
case CASE(OADD, TPTR32):
|
|
|
|
a = AADD;
|
|
|
|
break;
|
2009-05-28 15:25:54 -06:00
|
|
|
|
2009-08-18 20:20:33 -06:00
|
|
|
case CASE(OADD, TFLOAT32):
|
|
|
|
a = AADDF;
|
|
|
|
break;
|
2009-05-28 15:25:54 -06:00
|
|
|
|
2009-08-18 20:20:33 -06:00
|
|
|
case CASE(OADD, TFLOAT64):
|
|
|
|
a = AADDD;
|
|
|
|
break;
|
2009-05-28 15:25:54 -06:00
|
|
|
|
2009-08-18 20:20:33 -06:00
|
|
|
case CASE(OSUB, TINT8):
|
|
|
|
case CASE(OSUB, TUINT8):
|
|
|
|
case CASE(OSUB, TINT16):
|
|
|
|
case CASE(OSUB, TUINT16):
|
|
|
|
case CASE(OSUB, TINT32):
|
|
|
|
case CASE(OSUB, TUINT32):
|
|
|
|
case CASE(OSUB, TPTR32):
|
|
|
|
a = ASUB;
|
|
|
|
break;
|
2009-05-28 15:25:54 -06:00
|
|
|
|
2009-08-18 20:20:33 -06:00
|
|
|
case CASE(OSUB, TFLOAT32):
|
|
|
|
a = ASUBF;
|
|
|
|
break;
|
2009-05-28 15:25:54 -06:00
|
|
|
|
2009-08-18 20:20:33 -06:00
|
|
|
case CASE(OSUB, TFLOAT64):
|
|
|
|
a = ASUBD;
|
|
|
|
break;
|
2009-05-28 15:25:54 -06:00
|
|
|
|
2012-12-12 01:25:22 -07:00
|
|
|
case CASE(OMINUS, TINT8):
|
|
|
|
case CASE(OMINUS, TUINT8):
|
|
|
|
case CASE(OMINUS, TINT16):
|
|
|
|
case CASE(OMINUS, TUINT16):
|
|
|
|
case CASE(OMINUS, TINT32):
|
|
|
|
case CASE(OMINUS, TUINT32):
|
|
|
|
case CASE(OMINUS, TPTR32):
|
|
|
|
a = ARSB;
|
|
|
|
break;
|
|
|
|
|
2009-08-19 21:17:09 -06:00
|
|
|
case CASE(OAND, TINT8):
|
|
|
|
case CASE(OAND, TUINT8):
|
|
|
|
case CASE(OAND, TINT16):
|
|
|
|
case CASE(OAND, TUINT16):
|
|
|
|
case CASE(OAND, TINT32):
|
|
|
|
case CASE(OAND, TUINT32):
|
|
|
|
case CASE(OAND, TPTR32):
|
|
|
|
a = AAND;
|
|
|
|
break;
|
2009-05-28 15:25:54 -06:00
|
|
|
|
2009-08-19 21:17:09 -06:00
|
|
|
case CASE(OOR, TINT8):
|
|
|
|
case CASE(OOR, TUINT8):
|
|
|
|
case CASE(OOR, TINT16):
|
|
|
|
case CASE(OOR, TUINT16):
|
|
|
|
case CASE(OOR, TINT32):
|
|
|
|
case CASE(OOR, TUINT32):
|
|
|
|
case CASE(OOR, TPTR32):
|
|
|
|
a = AORR;
|
|
|
|
break;
|
2009-05-28 15:25:54 -06:00
|
|
|
|
2009-08-19 21:17:09 -06:00
|
|
|
case CASE(OXOR, TINT8):
|
|
|
|
case CASE(OXOR, TUINT8):
|
|
|
|
case CASE(OXOR, TINT16):
|
|
|
|
case CASE(OXOR, TUINT16):
|
|
|
|
case CASE(OXOR, TINT32):
|
|
|
|
case CASE(OXOR, TUINT32):
|
|
|
|
case CASE(OXOR, TPTR32):
|
|
|
|
a = AEOR;
|
|
|
|
break;
|
2009-05-28 15:25:54 -06:00
|
|
|
|
2009-08-19 21:17:09 -06:00
|
|
|
case CASE(OLSH, TINT8):
|
|
|
|
case CASE(OLSH, TUINT8):
|
|
|
|
case CASE(OLSH, TINT16):
|
|
|
|
case CASE(OLSH, TUINT16):
|
|
|
|
case CASE(OLSH, TINT32):
|
|
|
|
case CASE(OLSH, TUINT32):
|
|
|
|
case CASE(OLSH, TPTR32):
|
|
|
|
a = ASLL;
|
|
|
|
break;
|
2009-05-28 15:25:54 -06:00
|
|
|
|
2009-08-19 21:17:09 -06:00
|
|
|
case CASE(ORSH, TUINT8):
|
|
|
|
case CASE(ORSH, TUINT16):
|
|
|
|
case CASE(ORSH, TUINT32):
|
|
|
|
case CASE(ORSH, TPTR32):
|
|
|
|
a = ASRL;
|
|
|
|
break;
|
2009-05-28 15:25:54 -06:00
|
|
|
|
2009-08-19 21:17:09 -06:00
|
|
|
case CASE(ORSH, TINT8):
|
|
|
|
case CASE(ORSH, TINT16):
|
|
|
|
case CASE(ORSH, TINT32):
|
|
|
|
a = ASRA;
|
|
|
|
break;
|
2009-05-28 15:25:54 -06:00
|
|
|
|
2009-08-18 20:20:33 -06:00
|
|
|
case CASE(OMUL, TUINT8):
|
|
|
|
case CASE(OMUL, TUINT16):
|
|
|
|
case CASE(OMUL, TUINT32):
|
|
|
|
case CASE(OMUL, TPTR32):
|
2009-08-19 21:17:09 -06:00
|
|
|
a = AMULU;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CASE(OMUL, TINT8):
|
|
|
|
case CASE(OMUL, TINT16):
|
|
|
|
case CASE(OMUL, TINT32):
|
2009-08-18 20:20:33 -06:00
|
|
|
a = AMUL;
|
|
|
|
break;
|
2009-05-28 15:25:54 -06:00
|
|
|
|
2009-08-19 21:17:09 -06:00
|
|
|
case CASE(OMUL, TFLOAT32):
|
|
|
|
a = AMULF;
|
|
|
|
break;
|
2009-05-28 15:25:54 -06:00
|
|
|
|
2009-08-19 21:17:09 -06:00
|
|
|
case CASE(OMUL, TFLOAT64):
|
|
|
|
a = AMULD;
|
|
|
|
break;
|
2009-05-28 15:25:54 -06:00
|
|
|
|
2009-08-18 20:20:33 -06:00
|
|
|
case CASE(ODIV, TUINT8):
|
|
|
|
case CASE(ODIV, TUINT16):
|
|
|
|
case CASE(ODIV, TUINT32):
|
|
|
|
case CASE(ODIV, TPTR32):
|
2009-08-19 21:17:09 -06:00
|
|
|
a = ADIVU;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CASE(ODIV, TINT8):
|
|
|
|
case CASE(ODIV, TINT16):
|
|
|
|
case CASE(ODIV, TINT32):
|
2009-08-18 20:20:33 -06:00
|
|
|
a = ADIV;
|
|
|
|
break;
|
2009-05-28 15:25:54 -06:00
|
|
|
|
2009-08-18 20:20:33 -06:00
|
|
|
case CASE(OMOD, TUINT8):
|
|
|
|
case CASE(OMOD, TUINT16):
|
|
|
|
case CASE(OMOD, TUINT32):
|
|
|
|
case CASE(OMOD, TPTR32):
|
2009-08-19 21:17:09 -06:00
|
|
|
a = AMODU;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CASE(OMOD, TINT8):
|
|
|
|
case CASE(OMOD, TINT16):
|
|
|
|
case CASE(OMOD, TINT32):
|
2009-08-18 20:20:33 -06:00
|
|
|
a = AMOD;
|
|
|
|
break;
|
2009-05-28 15:25:54 -06:00
|
|
|
|
|
|
|
// case CASE(OEXTEND, TINT16):
|
|
|
|
// a = ACWD;
|
|
|
|
// break;
|
|
|
|
|
|
|
|
// case CASE(OEXTEND, TINT32):
|
|
|
|
// a = ACDQ;
|
|
|
|
// break;
|
|
|
|
|
|
|
|
// case CASE(OEXTEND, TINT64):
|
|
|
|
// a = ACQO;
|
|
|
|
// break;
|
|
|
|
|
2009-08-19 21:17:09 -06:00
|
|
|
case CASE(ODIV, TFLOAT32):
|
|
|
|
a = ADIVF;
|
|
|
|
break;
|
2009-05-28 15:25:54 -06:00
|
|
|
|
2009-08-19 21:17:09 -06:00
|
|
|
case CASE(ODIV, TFLOAT64):
|
|
|
|
a = ADIVD;
|
|
|
|
break;
|
2009-05-28 15:25:54 -06:00
|
|
|
|
|
|
|
}
|
|
|
|
return a;
|
2009-05-01 14:21:53 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
enum
|
|
|
|
{
|
|
|
|
ODynam = 1<<0,
|
|
|
|
OPtrto = 1<<1,
|
|
|
|
};
|
|
|
|
|
|
|
|
static Node clean[20];
|
|
|
|
static int cleani = 0;
|
|
|
|
|
|
|
|
void
|
|
|
|
sudoclean(void)
|
|
|
|
{
|
|
|
|
if(clean[cleani-1].op != OEMPTY)
|
|
|
|
regfree(&clean[cleani-1]);
|
|
|
|
if(clean[cleani-2].op != OEMPTY)
|
|
|
|
regfree(&clean[cleani-2]);
|
|
|
|
cleani -= 2;
|
|
|
|
}
|
|
|
|
|
2009-08-21 17:29:19 -06:00
|
|
|
int
|
|
|
|
dotaddable(Node *n, Node *n1)
|
|
|
|
{
|
|
|
|
int o, oary[10];
|
|
|
|
Node *nn;
|
|
|
|
|
|
|
|
if(n->op != ODOT)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
o = dotoffset(n, oary, &nn);
|
|
|
|
if(nn != N && nn->addable && o == 1 && oary[0] >= 0) {
|
|
|
|
*n1 = *nn;
|
|
|
|
n1->type = n->type;
|
|
|
|
n1->xoffset += oary[0];
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-05-01 14:21:53 -06:00
|
|
|
/*
|
|
|
|
* generate code to compute address of n,
|
|
|
|
* a reference to a (perhaps nested) field inside
|
|
|
|
* an array or struct.
|
|
|
|
* return 0 on failure, 1 on success.
|
|
|
|
* on success, leaves usable address in a.
|
|
|
|
*
|
|
|
|
* caller is responsible for calling sudoclean
|
|
|
|
* after successful sudoaddable,
|
|
|
|
* to release the register used for a.
|
|
|
|
*/
|
|
|
|
int
|
2009-08-18 20:20:33 -06:00
|
|
|
sudoaddable(int as, Node *n, Addr *a, int *w)
|
2009-05-01 14:21:53 -06:00
|
|
|
{
|
2009-08-18 20:20:33 -06:00
|
|
|
int o, i;
|
2009-05-01 14:21:53 -06:00
|
|
|
int oary[10];
|
2009-05-28 15:25:54 -06:00
|
|
|
int64 v;
|
2009-09-22 14:13:23 -06:00
|
|
|
Node n1, n2, n3, n4, *nn, *l, *r;
|
2009-05-01 14:21:53 -06:00
|
|
|
Node *reg, *reg1;
|
2010-07-30 01:37:51 -06:00
|
|
|
Prog *p1, *p2;
|
2009-05-01 14:21:53 -06:00
|
|
|
Type *t;
|
|
|
|
|
|
|
|
if(n->type == T)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
switch(n->op) {
|
2009-05-28 15:25:54 -06:00
|
|
|
case OLITERAL:
|
2011-12-08 20:07:43 -07:00
|
|
|
if(!isconst(n, CTINT))
|
2009-05-28 15:25:54 -06:00
|
|
|
break;
|
|
|
|
v = mpgetfix(n->val.u.xval);
|
|
|
|
if(v >= 32000 || v <= -32000)
|
|
|
|
break;
|
|
|
|
goto lit;
|
2009-05-01 14:21:53 -06:00
|
|
|
|
|
|
|
case ODOT:
|
|
|
|
case ODOTPTR:
|
|
|
|
cleani += 2;
|
|
|
|
reg = &clean[cleani-1];
|
|
|
|
reg1 = &clean[cleani-2];
|
|
|
|
reg->op = OEMPTY;
|
|
|
|
reg1->op = OEMPTY;
|
|
|
|
goto odot;
|
|
|
|
|
|
|
|
case OINDEX:
|
2012-11-02 00:50:59 -06:00
|
|
|
return 0;
|
|
|
|
// disabled: OINDEX case is now covered by agenr
|
|
|
|
// for a more suitable register allocation pattern.
|
2010-10-26 22:11:17 -06:00
|
|
|
if(n->left->type->etype == TSTRING)
|
|
|
|
return 0;
|
2009-05-01 14:21:53 -06:00
|
|
|
cleani += 2;
|
|
|
|
reg = &clean[cleani-1];
|
|
|
|
reg1 = &clean[cleani-2];
|
|
|
|
reg->op = OEMPTY;
|
|
|
|
reg1->op = OEMPTY;
|
|
|
|
goto oindex;
|
|
|
|
}
|
2009-05-28 15:25:54 -06:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
lit:
|
2009-08-18 20:20:33 -06:00
|
|
|
switch(as) {
|
|
|
|
default:
|
|
|
|
return 0;
|
|
|
|
case AADD: case ASUB: case AAND: case AORR: case AEOR:
|
|
|
|
case AMOVB: case AMOVBU: case AMOVH: case AMOVHU:
|
|
|
|
case AMOVW:
|
|
|
|
break;
|
|
|
|
}
|
2009-05-28 15:25:54 -06:00
|
|
|
|
2009-08-18 08:16:10 -06:00
|
|
|
cleani += 2;
|
|
|
|
reg = &clean[cleani-1];
|
|
|
|
reg1 = &clean[cleani-2];
|
|
|
|
reg->op = OEMPTY;
|
|
|
|
reg1->op = OEMPTY;
|
2009-10-26 22:49:32 -06:00
|
|
|
naddr(n, a, 1);
|
2009-08-18 08:16:10 -06:00
|
|
|
goto yes;
|
2009-05-01 14:21:53 -06:00
|
|
|
|
|
|
|
odot:
|
|
|
|
o = dotoffset(n, oary, &nn);
|
|
|
|
if(nn == N)
|
|
|
|
goto no;
|
|
|
|
|
2009-05-28 15:25:54 -06:00
|
|
|
if(nn->addable && o == 1 && oary[0] >= 0) {
|
|
|
|
// directly addressable set of DOTs
|
|
|
|
n1 = *nn;
|
|
|
|
n1.type = n->type;
|
|
|
|
n1.xoffset += oary[0];
|
2009-10-26 22:49:32 -06:00
|
|
|
naddr(&n1, a, 1);
|
2009-05-28 15:25:54 -06:00
|
|
|
goto yes;
|
|
|
|
}
|
|
|
|
|
2009-05-01 14:21:53 -06:00
|
|
|
regalloc(reg, types[tptr], N);
|
|
|
|
n1 = *reg;
|
|
|
|
n1.op = OINDREG;
|
|
|
|
if(oary[0] >= 0) {
|
|
|
|
agen(nn, reg);
|
|
|
|
n1.xoffset = oary[0];
|
|
|
|
} else {
|
|
|
|
cgen(nn, reg);
|
|
|
|
n1.xoffset = -(oary[0]+1);
|
|
|
|
}
|
|
|
|
|
2009-07-06 10:23:41 -06:00
|
|
|
for(i=1; i<o; i++) {
|
|
|
|
if(oary[i] >= 0)
|
|
|
|
fatal("cant happen");
|
|
|
|
gins(AMOVW, &n1, reg);
|
|
|
|
n1.xoffset = -(oary[i]+1);
|
|
|
|
}
|
2009-05-01 14:21:53 -06:00
|
|
|
|
|
|
|
a->type = D_NONE;
|
agen, sgen, cgen_callret, cgen_asop, D_ADDR handling, gmove
8bit and 16bit, some optoas, replaced Addr.index with
Addr.name
empty function compiles, mutex compiles
R=rsc
APPROVED=rsc
DELTA=908 (83 added, 41 deleted, 784 changed)
OCL=31127
CL=31188
2009-07-06 07:42:37 -06:00
|
|
|
a->name = D_NONE;
|
2011-07-28 16:22:12 -06:00
|
|
|
n1.type = n->type;
|
2009-10-26 22:49:32 -06:00
|
|
|
naddr(&n1, a, 1);
|
2009-05-01 14:21:53 -06:00
|
|
|
goto yes;
|
|
|
|
|
|
|
|
oindex:
|
|
|
|
l = n->left;
|
|
|
|
r = n->right;
|
|
|
|
if(l->ullman >= UINF && r->ullman >= UINF)
|
|
|
|
goto no;
|
|
|
|
|
|
|
|
// set o to type of array
|
|
|
|
o = 0;
|
|
|
|
if(isptr[l->type->etype]) {
|
|
|
|
o += OPtrto;
|
|
|
|
if(l->type->type->etype != TARRAY)
|
|
|
|
fatal("not ptr ary");
|
|
|
|
if(l->type->type->bound < 0)
|
|
|
|
o += ODynam;
|
|
|
|
} else {
|
|
|
|
if(l->type->etype != TARRAY)
|
|
|
|
fatal("not ary");
|
|
|
|
if(l->type->bound < 0)
|
|
|
|
o += ODynam;
|
|
|
|
}
|
|
|
|
|
2009-08-18 20:20:33 -06:00
|
|
|
*w = n->type->width;
|
2009-05-01 14:21:53 -06:00
|
|
|
if(isconst(r, CTINT))
|
|
|
|
goto oindex_const;
|
|
|
|
|
2009-08-18 20:20:33 -06:00
|
|
|
switch(*w) {
|
2009-05-01 14:21:53 -06:00
|
|
|
default:
|
|
|
|
goto no;
|
|
|
|
case 1:
|
|
|
|
case 2:
|
|
|
|
case 4:
|
|
|
|
case 8:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// load the array (reg)
|
|
|
|
if(l->ullman > r->ullman) {
|
|
|
|
regalloc(reg, types[tptr], N);
|
|
|
|
if(o & OPtrto)
|
|
|
|
cgen(l, reg);
|
|
|
|
else
|
|
|
|
agen(l, reg);
|
|
|
|
}
|
|
|
|
|
|
|
|
// load the index (reg1)
|
2009-08-18 20:20:33 -06:00
|
|
|
t = types[TUINT32];
|
2009-05-01 14:21:53 -06:00
|
|
|
if(issigned[r->type->etype])
|
2009-08-18 20:20:33 -06:00
|
|
|
t = types[TINT32];
|
2009-05-01 14:21:53 -06:00
|
|
|
regalloc(reg1, t, N);
|
2010-07-30 01:37:51 -06:00
|
|
|
regalloc(&n3, types[TINT32], reg1);
|
2012-11-27 13:37:38 -07:00
|
|
|
p2 = cgenindex(r, &n3, debug['B'] || n->bounded);
|
2009-05-28 15:25:54 -06:00
|
|
|
gmove(&n3, reg1);
|
|
|
|
regfree(&n3);
|
2009-05-01 14:21:53 -06:00
|
|
|
|
|
|
|
// load the array (reg)
|
|
|
|
if(l->ullman <= r->ullman) {
|
|
|
|
regalloc(reg, types[tptr], N);
|
|
|
|
if(o & OPtrto)
|
|
|
|
cgen(l, reg);
|
|
|
|
else
|
|
|
|
agen(l, reg);
|
|
|
|
}
|
|
|
|
|
|
|
|
// check bounds
|
|
|
|
if(!debug['B']) {
|
|
|
|
if(o & ODynam) {
|
|
|
|
n2 = *reg;
|
|
|
|
n2.op = OINDREG;
|
|
|
|
n2.type = types[tptr];
|
|
|
|
n2.xoffset = Array_nel;
|
|
|
|
} else {
|
2009-10-26 22:49:32 -06:00
|
|
|
if(l->type->width >= unmappedzero && l->op == OIND) {
|
|
|
|
// cannot rely on page protections to
|
|
|
|
// catch array ptr == 0, so dereference.
|
|
|
|
n2 = *reg;
|
|
|
|
n2.op = OINDREG;
|
|
|
|
n2.type = types[TUINTPTR];
|
|
|
|
n2.xoffset = 0;
|
|
|
|
regalloc(&n3, n2.type, N);
|
|
|
|
gins(AMOVW, &n2, &n3);
|
|
|
|
regfree(&n3);
|
|
|
|
}
|
2009-08-19 21:17:09 -06:00
|
|
|
nodconst(&n2, types[TUINT32], l->type->bound);
|
2009-05-01 14:21:53 -06:00
|
|
|
if(o & OPtrto)
|
2009-08-19 21:17:09 -06:00
|
|
|
nodconst(&n2, types[TUINT32], l->type->type->bound);
|
2009-05-01 14:21:53 -06:00
|
|
|
}
|
2009-09-18 00:07:52 -06:00
|
|
|
regalloc(&n3, n2.type, N);
|
|
|
|
cgen(&n2, &n3);
|
2009-09-28 16:40:13 -06:00
|
|
|
gcmp(optoas(OCMP, types[TUINT32]), reg1, &n3);
|
2009-09-18 00:07:52 -06:00
|
|
|
regfree(&n3);
|
2012-05-30 16:07:39 -06:00
|
|
|
p1 = gbranch(optoas(OLT, types[TUINT32]), T, +1);
|
2010-07-30 01:37:51 -06:00
|
|
|
if(p2)
|
|
|
|
patch(p2, pc);
|
2010-04-01 23:31:27 -06:00
|
|
|
ginscall(panicindex, 0);
|
2009-05-01 14:21:53 -06:00
|
|
|
patch(p1, pc);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(o & ODynam) {
|
|
|
|
n2 = *reg;
|
|
|
|
n2.op = OINDREG;
|
|
|
|
n2.type = types[tptr];
|
|
|
|
n2.xoffset = Array_array;
|
|
|
|
gmove(&n2, reg);
|
|
|
|
}
|
|
|
|
|
2010-10-20 14:18:00 -06:00
|
|
|
switch(*w) {
|
|
|
|
case 1:
|
2009-10-15 23:16:31 -06:00
|
|
|
gins(AADD, reg1, reg);
|
2010-10-20 14:18:00 -06:00
|
|
|
break;
|
|
|
|
case 2:
|
2009-10-15 23:16:31 -06:00
|
|
|
gshift(AADD, reg1, SHIFT_LL, 1, reg);
|
2010-10-20 14:18:00 -06:00
|
|
|
break;
|
|
|
|
case 4:
|
2009-10-15 23:16:31 -06:00
|
|
|
gshift(AADD, reg1, SHIFT_LL, 2, reg);
|
2010-10-20 14:18:00 -06:00
|
|
|
break;
|
|
|
|
case 8:
|
2009-10-15 23:16:31 -06:00
|
|
|
gshift(AADD, reg1, SHIFT_LL, 3, reg);
|
2010-10-20 14:18:00 -06:00
|
|
|
break;
|
|
|
|
}
|
2009-10-15 23:16:31 -06:00
|
|
|
|
2009-10-26 22:49:32 -06:00
|
|
|
naddr(reg1, a, 1);
|
2009-08-18 20:20:33 -06:00
|
|
|
a->type = D_OREG;
|
|
|
|
a->reg = reg->val.u.reg;
|
2009-10-15 23:16:31 -06:00
|
|
|
a->offset = 0;
|
2009-05-01 14:21:53 -06:00
|
|
|
goto yes;
|
|
|
|
|
|
|
|
oindex_const:
|
|
|
|
// index is constant
|
|
|
|
// can check statically and
|
|
|
|
// can multiply by width statically
|
|
|
|
|
|
|
|
regalloc(reg, types[tptr], N);
|
|
|
|
if(o & OPtrto)
|
|
|
|
cgen(l, reg);
|
|
|
|
else
|
|
|
|
agen(l, reg);
|
|
|
|
|
|
|
|
v = mpgetfix(r->val.u.xval);
|
|
|
|
if(o & ODynam) {
|
|
|
|
|
2012-05-24 15:20:07 -06:00
|
|
|
if(!debug['B'] && !n->bounded) {
|
2009-05-01 14:21:53 -06:00
|
|
|
n1 = *reg;
|
|
|
|
n1.op = OINDREG;
|
|
|
|
n1.type = types[tptr];
|
|
|
|
n1.xoffset = Array_nel;
|
2009-08-19 21:17:09 -06:00
|
|
|
nodconst(&n2, types[TUINT32], v);
|
2009-09-18 00:07:52 -06:00
|
|
|
regalloc(&n3, types[TUINT32], N);
|
|
|
|
cgen(&n2, &n3);
|
2009-09-22 14:13:23 -06:00
|
|
|
regalloc(&n4, n1.type, N);
|
|
|
|
cgen(&n1, &n4);
|
2009-09-28 16:40:13 -06:00
|
|
|
gcmp(optoas(OCMP, types[TUINT32]), &n4, &n3);
|
2009-09-22 14:13:23 -06:00
|
|
|
regfree(&n4);
|
2009-09-18 00:07:52 -06:00
|
|
|
regfree(&n3);
|
2012-05-30 16:07:39 -06:00
|
|
|
p1 = gbranch(optoas(OGT, types[TUINT32]), T, +1);
|
2010-04-01 23:31:27 -06:00
|
|
|
ginscall(panicindex, 0);
|
2009-05-01 14:21:53 -06:00
|
|
|
patch(p1, pc);
|
|
|
|
}
|
|
|
|
|
|
|
|
n1 = *reg;
|
|
|
|
n1.op = OINDREG;
|
|
|
|
n1.type = types[tptr];
|
|
|
|
n1.xoffset = Array_array;
|
|
|
|
gmove(&n1, reg);
|
|
|
|
}
|
|
|
|
|
|
|
|
n2 = *reg;
|
|
|
|
n2.op = OINDREG;
|
2009-08-18 20:20:33 -06:00
|
|
|
n2.xoffset = v * (*w);
|
2009-05-01 14:21:53 -06:00
|
|
|
a->type = D_NONE;
|
agen, sgen, cgen_callret, cgen_asop, D_ADDR handling, gmove
8bit and 16bit, some optoas, replaced Addr.index with
Addr.name
empty function compiles, mutex compiles
R=rsc
APPROVED=rsc
DELTA=908 (83 added, 41 deleted, 784 changed)
OCL=31127
CL=31188
2009-07-06 07:42:37 -06:00
|
|
|
a->name = D_NONE;
|
2009-10-26 22:49:32 -06:00
|
|
|
naddr(&n2, a, 1);
|
2009-05-01 14:21:53 -06:00
|
|
|
goto yes;
|
|
|
|
|
|
|
|
yes:
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
no:
|
|
|
|
sudoclean();
|
|
|
|
return 0;
|
|
|
|
}
|