Add compiler source to new directory structure

SVN=121164
This commit is contained in:
Rob Pike 2008-06-04 14:37:38 -07:00
parent 896c8f4ecc
commit 0cafb9ea3d
65 changed files with 46104 additions and 0 deletions

206
src/cmd/6a/a.h Normal file
View file

@ -0,0 +1,206 @@
// Inferno utils/6a/a.h
// http://code.google.com/p/inferno-os/source/browse/utils/6a/a.h
//
// 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.
#include <u.h>
#include <libc.h>
#include <bio.h>
#include "../6l/6.out.h"
#include "compat.h"
#ifndef EXTERN
#define EXTERN extern
#endif
typedef struct Sym Sym;
typedef struct Ref Ref;
typedef struct Gen Gen;
typedef struct Io Io;
typedef struct Hist Hist;
typedef struct Gen2 Gen2;
#define MAXALIGN 7
#define FPCHIP 1
#define NSYMB 500
#define BUFSIZ 8192
#define HISTSZ 20
#define NINCLUDE 10
#define NHUNK 10000
#define EOF (-1)
#define IGN (-2)
#define GETC() ((--fi.c < 0)? filbuf(): *fi.p++ & 0xff)
#define NHASH 503
#define STRINGSZ 200
#define NMACRO 10
struct Sym
{
Sym* link;
Ref* ref;
char* macro;
vlong value;
ushort type;
char *name;
char sym;
};
#define S ((Sym*)0)
struct Ref
{
int class;
};
EXTERN struct
{
char* p;
int c;
} fi;
struct Io
{
Io* link;
char b[BUFSIZ];
char* p;
short c;
short f;
};
#define I ((Io*)0)
EXTERN struct
{
Sym* sym;
short type;
} h[NSYM];
struct Gen
{
double dval;
char sval[8];
vlong offset;
Sym* sym;
short type;
short index;
short scale;
};
struct Gen2
{
Gen from;
Gen to;
};
struct Hist
{
Hist* link;
char* name;
long line;
vlong offset;
};
#define H ((Hist*)0)
enum
{
CLAST,
CMACARG,
CMACRO,
CPREPROC,
};
EXTERN char debug[256];
EXTERN Sym* hash[NHASH];
EXTERN char* Dlist[30];
EXTERN int nDlist;
EXTERN Hist* ehist;
EXTERN int newflag;
EXTERN Hist* hist;
EXTERN char* hunk;
EXTERN char* include[NINCLUDE];
EXTERN Io* iofree;
EXTERN Io* ionext;
EXTERN Io* iostack;
EXTERN long lineno;
EXTERN int nerrors;
EXTERN long nhunk;
EXTERN int ninclude;
EXTERN Gen nullgen;
EXTERN char* outfile;
EXTERN int pass;
EXTERN char* pathname;
EXTERN long pc;
EXTERN int peekc;
EXTERN int sym;
EXTERN char symb[NSYMB];
EXTERN int thechar;
EXTERN char* thestring;
EXTERN long thunk;
EXTERN Biobuf obuf;
void* allocn(void*, long, long);
void errorexit(void);
void pushio(void);
void newio(void);
void newfile(char*, int);
Sym* slookup(char*);
Sym* lookup(void);
void syminit(Sym*);
long yylex(void);
int getc(void);
int getnsc(void);
void unget(int);
int escchar(int);
void cinit(void);
void checkscale(int);
void pinit(char*);
void cclean(void);
int isreg(Gen*);
void outcode(int, Gen2*);
void outhist(void);
void zaddr(Gen*, int);
void zname(char*, int, int);
void ieeedtod(Ieee*, double);
int filbuf(void);
Sym* getsym(void);
void domacro(void);
void macund(void);
void macdef(void);
void macexpand(Sym*, char*);
void macinc(void);
void macprag(void);
void maclin(void);
void macif(int);
void macend(void);
void dodefine(char*);
void prfile(long);
void linehist(char*, int);
void gethunk(void);
void yyerror(char*, ...);
int yyparse(void);
void setinclude(char*);
int assemble(char*);

592
src/cmd/6a/a.y Normal file
View file

@ -0,0 +1,592 @@
// Inferno utils/6a/a.y
// http://code.google.com/p/inferno-os/source/browse/utils/6a/a.y
//
// 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.
%{
#include "a.h"
%}
%union {
Sym *sym;
vlong lval;
double dval;
char sval[8];
Gen gen;
Gen2 gen2;
}
%left '|'
%left '^'
%left '&'
%left '<' '>'
%left '+' '-'
%left '*' '/' '%'
%token <lval> LTYPE0 LTYPE1 LTYPE2 LTYPE3 LTYPE4
%token <lval> LTYPEC LTYPED LTYPEN LTYPER LTYPET LTYPES LTYPEM LTYPEI LTYPEXC LTYPEX LTYPERT
%token <lval> LCONST LFP LPC LSB
%token <lval> LBREG LLREG LSREG LFREG LMREG LXREG
%token <dval> LFCONST
%token <sval> LSCONST LSP
%token <sym> LNAME LLAB LVAR
%type <lval> con expr pointer offset
%type <gen> mem imm reg nam rel rem rim rom omem nmem
%type <gen2> nonnon nonrel nonrem rimnon rimrem remrim spec10
%type <gen2> spec1 spec2 spec3 spec4 spec5 spec6 spec7 spec8 spec9
%%
prog:
| prog line
line:
LLAB ':'
{
if($1->value != pc)
yyerror("redeclaration of %s", $1->name);
$1->value = pc;
}
line
| LNAME ':'
{
$1->type = LLAB;
$1->value = pc;
}
line
| ';'
| inst ';'
| error ';'
inst:
LNAME '=' expr
{
$1->type = LVAR;
$1->value = $3;
}
| LVAR '=' expr
{
if($1->value != $3)
yyerror("redeclaration of %s", $1->name);
$1->value = $3;
}
| LTYPE0 nonnon { outcode($1, &$2); }
| LTYPE1 nonrem { outcode($1, &$2); }
| LTYPE2 rimnon { outcode($1, &$2); }
| LTYPE3 rimrem { outcode($1, &$2); }
| LTYPE4 remrim { outcode($1, &$2); }
| LTYPER nonrel { outcode($1, &$2); }
| LTYPED spec1 { outcode($1, &$2); }
| LTYPET spec2 { outcode($1, &$2); }
| LTYPEC spec3 { outcode($1, &$2); }
| LTYPEN spec4 { outcode($1, &$2); }
| LTYPES spec5 { outcode($1, &$2); }
| LTYPEM spec6 { outcode($1, &$2); }
| LTYPEI spec7 { outcode($1, &$2); }
| LTYPEXC spec8 { outcode($1, &$2); }
| LTYPEX spec9 { outcode($1, &$2); }
| LTYPERT spec10 { outcode($1, &$2); }
nonnon:
{
$$.from = nullgen;
$$.to = nullgen;
}
| ','
{
$$.from = nullgen;
$$.to = nullgen;
}
rimrem:
rim ',' rem
{
$$.from = $1;
$$.to = $3;
}
remrim:
rem ',' rim
{
$$.from = $1;
$$.to = $3;
}
rimnon:
rim ','
{
$$.from = $1;
$$.to = nullgen;
}
| rim
{
$$.from = $1;
$$.to = nullgen;
}
nonrem:
',' rem
{
$$.from = nullgen;
$$.to = $2;
}
| rem
{
$$.from = nullgen;
$$.to = $1;
}
nonrel:
',' rel
{
$$.from = nullgen;
$$.to = $2;
}
| rel
{
$$.from = nullgen;
$$.to = $1;
}
spec1: /* DATA */
nam '/' con ',' imm
{
$$.from = $1;
$$.from.scale = $3;
$$.to = $5;
}
spec2: /* TEXT */
mem ',' imm
{
$$.from = $1;
$$.to = $3;
}
| mem ',' con ',' imm
{
$$.from = $1;
$$.from.scale = $3;
$$.to = $5;
}
spec3: /* JMP/CALL */
',' rom
{
$$.from = nullgen;
$$.to = $2;
}
| rom
{
$$.from = nullgen;
$$.to = $1;
}
spec4: /* NOP */
nonnon
| nonrem
spec5: /* SHL/SHR */
rim ',' rem
{
$$.from = $1;
$$.to = $3;
}
| rim ',' rem ':' LLREG
{
$$.from = $1;
$$.to = $3;
if($$.from.index != D_NONE)
yyerror("dp shift with lhs index");
$$.from.index = $5;
}
spec6: /* MOVW/MOVL */
rim ',' rem
{
$$.from = $1;
$$.to = $3;
}
| rim ',' rem ':' LSREG
{
$$.from = $1;
$$.to = $3;
if($$.to.index != D_NONE)
yyerror("dp move with lhs index");
$$.to.index = $5;
}
spec7:
rim ','
{
$$.from = $1;
$$.to = nullgen;
}
| rim
{
$$.from = $1;
$$.to = nullgen;
}
| rim ',' rem
{
$$.from = $1;
$$.to = $3;
}
spec8: /* CMPPS/CMPPD */
reg ',' rem ',' con
{
$$.from = $1;
$$.to = $3;
$$.from.offset = $5;
}
spec9: /* shufl */
imm ',' rem ',' reg
{
$$.from = $3;
$$.to = $5;
if($1.type != D_CONST)
yyerror("illegal constant");
$$.to.offset = $1.offset;
}
spec10: /* RET/RETF */
{
$$.from = nullgen;
$$.to = nullgen;
}
| imm
{
$$.from = $1;
$$.to = nullgen;
}
rem:
reg
| mem
rom:
rel
| nmem
| '*' reg
{
$$ = $2;
}
| '*' omem
{
$$ = $2;
}
| reg
| omem
rim:
rem
| imm
rel:
con '(' LPC ')'
{
$$ = nullgen;
$$.type = D_BRANCH;
$$.offset = $1 + pc;
}
| LNAME offset
{
$$ = nullgen;
if(pass == 2)
yyerror("undefined label: %s", $1->name);
$$.type = D_BRANCH;
$$.sym = $1;
$$.offset = $2;
}
| LLAB offset
{
$$ = nullgen;
$$.type = D_BRANCH;
$$.sym = $1;
$$.offset = $1->value + $2;
}
reg:
LBREG
{
$$ = nullgen;
$$.type = $1;
}
| LFREG
{
$$ = nullgen;
$$.type = $1;
}
| LLREG
{
$$ = nullgen;
$$.type = $1;
}
| LMREG
{
$$ = nullgen;
$$.type = $1;
}
| LSP
{
$$ = nullgen;
$$.type = D_SP;
}
| LSREG
{
$$ = nullgen;
$$.type = $1;
}
| LXREG
{
$$ = nullgen;
$$.type = $1;
}
imm:
'$' con
{
$$ = nullgen;
$$.type = D_CONST;
$$.offset = $2;
}
| '$' nam
{
$$ = $2;
$$.index = $2.type;
$$.type = D_ADDR;
/*
if($2.type == D_AUTO || $2.type == D_PARAM)
yyerror("constant cannot be automatic: %s",
$2.sym->name);
*/
}
| '$' LSCONST
{
$$ = nullgen;
$$.type = D_SCONST;
memcpy($$.sval, $2, sizeof($$.sval));
}
| '$' LFCONST
{
$$ = nullgen;
$$.type = D_FCONST;
$$.dval = $2;
}
| '$' '(' LFCONST ')'
{
$$ = nullgen;
$$.type = D_FCONST;
$$.dval = $3;
}
| '$' '-' LFCONST
{
$$ = nullgen;
$$.type = D_FCONST;
$$.dval = -$3;
}
mem:
omem
| nmem
omem:
con
{
$$ = nullgen;
$$.type = D_INDIR+D_NONE;
$$.offset = $1;
}
| con '(' LLREG ')'
{
$$ = nullgen;
$$.type = D_INDIR+$3;
$$.offset = $1;
}
| con '(' LSP ')'
{
$$ = nullgen;
$$.type = D_INDIR+D_SP;
$$.offset = $1;
}
| con '(' LLREG '*' con ')'
{
$$ = nullgen;
$$.type = D_INDIR+D_NONE;
$$.offset = $1;
$$.index = $3;
$$.scale = $5;
checkscale($$.scale);
}
| con '(' LLREG ')' '(' LLREG '*' con ')'
{
$$ = nullgen;
$$.type = D_INDIR+$3;
$$.offset = $1;
$$.index = $6;
$$.scale = $8;
checkscale($$.scale);
}
| '(' LLREG ')'
{
$$ = nullgen;
$$.type = D_INDIR+$2;
}
| '(' LSP ')'
{
$$ = nullgen;
$$.type = D_INDIR+D_SP;
}
| '(' LLREG '*' con ')'
{
$$ = nullgen;
$$.type = D_INDIR+D_NONE;
$$.index = $2;
$$.scale = $4;
checkscale($$.scale);
}
| '(' LLREG ')' '(' LLREG '*' con ')'
{
$$ = nullgen;
$$.type = D_INDIR+$2;
$$.index = $5;
$$.scale = $7;
checkscale($$.scale);
}
nmem:
nam
{
$$ = $1;
}
| nam '(' LLREG '*' con ')'
{
$$ = $1;
$$.index = $3;
$$.scale = $5;
checkscale($$.scale);
}
nam:
LNAME offset '(' pointer ')'
{
$$ = nullgen;
$$.type = $4;
$$.sym = $1;
$$.offset = $2;
}
| LNAME '<' '>' offset '(' LSB ')'
{
$$ = nullgen;
$$.type = D_STATIC;
$$.sym = $1;
$$.offset = $4;
}
offset:
{
$$ = 0;
}
| '+' con
{
$$ = $2;
}
| '-' con
{
$$ = -$2;
}
pointer:
LSB
| LSP
{
$$ = D_AUTO;
}
| LFP
con:
LCONST
| LVAR
{
$$ = $1->value;
}
| '-' con
{
$$ = -$2;
}
| '+' con
{
$$ = $2;
}
| '~' con
{
$$ = ~$2;
}
| '(' expr ')'
{
$$ = $2;
}
expr:
con
| expr '+' expr
{
$$ = $1 + $3;
}
| expr '-' expr
{
$$ = $1 - $3;
}
| expr '*' expr
{
$$ = $1 * $3;
}
| expr '/' expr
{
$$ = $1 / $3;
}
| expr '%' expr
{
$$ = $1 % $3;
}
| expr '<' '<' expr
{
$$ = $1 << $4;
}
| expr '>' '>' expr
{
$$ = $1 >> $4;
}
| expr '&' expr
{
$$ = $1 & $3;
}
| expr '^' expr
{
$$ = $1 ^ $3;
}
| expr '|' expr
{
$$ = $1 | $3;
}

1337
src/cmd/6a/lex.c Normal file

File diff suppressed because it is too large Load diff

1971
src/cmd/6c/cgen.c Normal file

File diff suppressed because it is too large Load diff

236
src/cmd/6c/div.c Normal file
View file

@ -0,0 +1,236 @@
// Inferno utils/6c/div.c
// http://code.google.com/p/inferno-os/source/browse/utils/6c/div.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.
#include "gc.h"
/*
* Based on: Granlund, T.; Montgomery, P.L.
* "Division by Invariant Integers using Multiplication".
* SIGPLAN Notices, Vol. 29, June 1994, page 61.
*/
#define TN(n) ((uvlong)1 << (n))
#define T31 TN(31)
#define T32 TN(32)
int
multiplier(ulong d, int p, uvlong *mp)
{
int l;
uvlong mlo, mhi, tlo, thi;
l = topbit(d - 1) + 1;
mlo = (((TN(l) - d) << 32) / d) + T32;
if(l + p == 64)
mhi = (((TN(l) + 1 - d) << 32) / d) + T32;
else
mhi = (TN(32 + l) + TN(32 + l - p)) / d;
/*assert(mlo < mhi);*/
while(l > 0) {
tlo = mlo >> 1;
thi = mhi >> 1;
if(tlo == thi)
break;
mlo = tlo;
mhi = thi;
l--;
}
*mp = mhi;
return l;
}
int
sdiv(ulong d, ulong *mp, int *sp)
{
int s;
uvlong m;
s = multiplier(d, 32 - 1, &m);
*mp = m;
*sp = s;
if(m >= T31)
return 1;
else
return 0;
}
int
udiv(ulong d, ulong *mp, int *sp, int *pp)
{
int p, s;
uvlong m;
s = multiplier(d, 32, &m);
p = 0;
if(m >= T32) {
while((d & 1) == 0) {
d >>= 1;
p++;
}
s = multiplier(d, 32 - p, &m);
}
*mp = m;
*pp = p;
if(m >= T32) {
/*assert(p == 0);*/
*sp = s - 1;
return 1;
}
else {
*sp = s;
return 0;
}
}
void
sdivgen(Node *l, Node *r, Node *ax, Node *dx)
{
int a, s;
ulong m;
vlong c;
c = r->vconst;
if(c < 0)
c = -c;
a = sdiv(c, &m, &s);
//print("a=%d i=%ld s=%d m=%lux\n", a, (long)r->vconst, s, m);
gins(AMOVL, nodconst(m), ax);
gins(AIMULL, l, Z);
gins(AMOVL, l, ax);
if(a)
gins(AADDL, ax, dx);
gins(ASHRL, nodconst(31), ax);
gins(ASARL, nodconst(s), dx);
gins(AADDL, ax, dx);
if(r->vconst < 0)
gins(ANEGL, Z, dx);
}
void
udivgen(Node *l, Node *r, Node *ax, Node *dx)
{
int a, s, t;
ulong m;
Node nod;
a = udiv(r->vconst, &m, &s, &t);
//print("a=%ud i=%ld p=%d s=%d m=%lux\n", a, (long)r->vconst, t, s, m);
if(t != 0) {
gins(AMOVL, l, ax);
gins(ASHRL, nodconst(t), ax);
gins(AMOVL, nodconst(m), dx);
gins(AMULL, dx, Z);
}
else if(a) {
if(l->op != OREGISTER) {
regalloc(&nod, l, Z);
gins(AMOVL, l, &nod);
l = &nod;
}
gins(AMOVL, nodconst(m), ax);
gins(AMULL, l, Z);
gins(AADDL, l, dx);
gins(ARCRL, nodconst(1), dx);
if(l == &nod)
regfree(l);
}
else {
gins(AMOVL, nodconst(m), ax);
gins(AMULL, l, Z);
}
if(s != 0)
gins(ASHRL, nodconst(s), dx);
}
void
sext(Node *d, Node *s, Node *l)
{
if(s->reg == D_AX && !nodreg(d, Z, D_DX)) {
reg[D_DX]++;
gins(ACDQ, Z, Z);
}
else {
regalloc(d, l, Z);
gins(AMOVL, s, d);
gins(ASARL, nodconst(31), d);
}
}
void
sdiv2(long c, int v, Node *l, Node *n)
{
Node nod;
if(v > 0) {
if(v > 1) {
sext(&nod, n, l);
gins(AANDL, nodconst((1 << v) - 1), &nod);
gins(AADDL, &nod, n);
regfree(&nod);
}
else {
gins(ACMPL, n, nodconst(0x80000000));
gins(ASBBL, nodconst(-1), n);
}
gins(ASARL, nodconst(v), n);
}
if(c < 0)
gins(ANEGL, Z, n);
}
void
smod2(long c, int v, Node *l, Node *n)
{
Node nod;
if(c == 1) {
zeroregm(n);
return;
}
sext(&nod, n, l);
if(v == 0) {
zeroregm(n);
gins(AXORL, &nod, n);
gins(ASUBL, &nod, n);
}
else if(v > 1) {
gins(AANDL, nodconst((1 << v) - 1), &nod);
gins(AADDL, &nod, n);
gins(AANDL, nodconst((1 << v) - 1), n);
gins(ASUBL, &nod, n);
}
else {
gins(AANDL, nodconst(1), n);
gins(AXORL, &nod, n);
gins(ASUBL, &nod, n);
}
regfree(&nod);
}

411
src/cmd/6c/gc.h Normal file
View file

@ -0,0 +1,411 @@
// Inferno utils/6c/gc.h
// http://code.google.com/p/inferno-os/source/browse/utils/6c/gc.h
//
// 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.
#include "../cc/cc.h"
#include "../6l/6.out.h"
/*
* 6c/amd64
* Intel 386 with AMD64 extensions
*/
#define SZ_CHAR 1
#define SZ_SHORT 2
#define SZ_INT 4
#define SZ_LONG 4
#define SZ_IND 8
#define SZ_FLOAT 4
#define SZ_VLONG 8
#define SZ_DOUBLE 8
#define FNX 100
typedef struct Adr Adr;
typedef struct Prog Prog;
typedef struct Case Case;
typedef struct C1 C1;
typedef struct Var Var;
typedef struct Reg Reg;
typedef struct Rgn Rgn;
typedef struct Renv Renv;
EXTERN struct
{
Node* regtree;
Node* basetree;
short scale;
short reg;
short ptr;
} idx;
struct Adr
{
vlong offset;
double dval;
char sval[NSNAME];
Sym* sym;
uchar type;
uchar index;
uchar etype;
uchar scale; /* doubles as width in DATA op */
};
#define A ((Adr*)0)
#define INDEXED 9
struct Prog
{
Adr from;
Adr to;
Prog* link;
long lineno;
short as;
};
#define P ((Prog*)0)
struct Case
{
Case* link;
vlong val;
long label;
char def;
char isv;
};
#define C ((Case*)0)
struct C1
{
vlong val;
long label;
};
struct Var
{
vlong offset;
Sym* sym;
char name;
char etype;
};
struct Reg
{
long pc;
long rpo; /* reverse post ordering */
Bits set;
Bits use1;
Bits use2;
Bits refbehind;
Bits refahead;
Bits calbehind;
Bits calahead;
Bits regdiff;
Bits act;
long regu;
long loop; /* could be shorter */
Reg* log5;
long active;
Reg* p1;
Reg* p2;
Reg* p2link;
Reg* s1;
Reg* s2;
Reg* link;
Prog* prog;
};
#define R ((Reg*)0)
struct Renv
{
int safe;
Node base;
Node* saved;
Node* scope;
};
#define NRGN 600
struct Rgn
{
Reg* enter;
short cost;
short varno;
short regno;
};
EXTERN long breakpc;
EXTERN long nbreak;
EXTERN Case* cases;
EXTERN Node constnode;
EXTERN Node fconstnode;
EXTERN Node vconstnode;
EXTERN long continpc;
EXTERN long curarg;
EXTERN long cursafe;
EXTERN Prog* firstp;
EXTERN Prog* lastp;
EXTERN long maxargsafe;
EXTERN int mnstring;
EXTERN Node* nodrat;
EXTERN Node* nodret;
EXTERN Node* nodsafe;
EXTERN long nrathole;
EXTERN long nstring;
EXTERN Prog* p;
EXTERN long pc;
EXTERN Node lregnode;
EXTERN Node qregnode;
EXTERN char string[NSNAME];
EXTERN Sym* symrathole;
EXTERN Node znode;
EXTERN Prog zprog;
EXTERN int reg[D_NONE];
EXTERN long exregoffset;
EXTERN long exfregoffset;
EXTERN uchar typechlpv[NTYPE];
#define BLOAD(r) band(bnot(r->refbehind), r->refahead)
#define BSTORE(r) band(bnot(r->calbehind), r->calahead)
#define LOAD(r) (~r->refbehind.b[z] & r->refahead.b[z])
#define STORE(r) (~r->calbehind.b[z] & r->calahead.b[z])
#define bset(a,n) ((a).b[(n)/32]&(1L<<(n)%32))
#define CLOAD 5
#define CREF 5
#define CINF 1000
#define LOOP 3
EXTERN Rgn region[NRGN];
EXTERN Rgn* rgp;
EXTERN int nregion;
EXTERN int nvar;
EXTERN Bits externs;
EXTERN Bits params;
EXTERN Bits consts;
EXTERN Bits addrs;
EXTERN long regbits;
EXTERN long exregbits;
EXTERN int change;
EXTERN int suppress;
EXTERN Reg* firstr;
EXTERN Reg* lastr;
EXTERN Reg zreg;
EXTERN Reg* freer;
EXTERN Var var[NVAR];
EXTERN long* idom;
EXTERN Reg** rpo2r;
EXTERN long maxnr;
extern char* anames[];
/*
* sgen.c
*/
void codgen(Node*, Node*);
void gen(Node*);
void noretval(int);
void usedset(Node*, int);
void xcom(Node*);
void indx(Node*);
int bcomplex(Node*, Node*);
/*
* cgen.c
*/
void zeroregm(Node*);
void cgen(Node*, Node*);
void reglcgen(Node*, Node*, Node*);
void lcgen(Node*, Node*);
void bcgen(Node*, int);
void boolgen(Node*, int, Node*);
void sugen(Node*, Node*, long);
int needreg(Node*, int);
int hardconst(Node*);
int immconst(Node*);
/*
* cgen64.c
*/
int vaddr(Node*, int);
void loadpair(Node*, Node*);
int cgen64(Node*, Node*);
void testv(Node*, int);
/*
* txt.c
*/
void ginit(void);
void gclean(void);
void nextpc(void);
void gargs(Node*, Node*, Node*);
void garg1(Node*, Node*, Node*, int, Node**);
Node* nodconst(long);
Node* nodfconst(double);
Node* nodgconst(vlong, Type*);
int nodreg(Node*, Node*, int);
int isreg(Node*, int);
void regret(Node*, Node*);
void regalloc(Node*, Node*, Node*);
void regfree(Node*);
void regialloc(Node*, Node*, Node*);
void regsalloc(Node*, Node*);
void regaalloc1(Node*, Node*);
void regaalloc(Node*, Node*);
void regind(Node*, Node*);
void gprep(Node*, Node*);
void naddr(Node*, Adr*);
void gcmp(int, Node*, vlong);
void gmove(Node*, Node*);
void gins(int a, Node*, Node*);
void gopcode(int, Type*, Node*, Node*);
int samaddr(Node*, Node*);
void gbranch(int);
void patch(Prog*, long);
int sconst(Node*);
void gpseudo(int, Sym*, Node*);
/*
* swt.c
*/
int swcmp(const void*, const void*);
void doswit(Node*);
void swit1(C1*, int, long, Node*);
void cas(void);
void bitload(Node*, Node*, Node*, Node*, Node*);
void bitstore(Node*, Node*, Node*, Node*, Node*);
long outstring(char*, long);
void nullwarn(Node*, Node*);
void sextern(Sym*, Node*, long, long);
void gextern(Sym*, Node*, long, long);
void outcode(void);
void ieeedtod(Ieee*, double);
/*
* list
*/
void listinit(void);
int Pconv(Fmt*);
int Aconv(Fmt*);
int Dconv(Fmt*);
int Sconv(Fmt*);
int Rconv(Fmt*);
int Xconv(Fmt*);
int Bconv(Fmt*);
/*
* reg.c
*/
Reg* rega(void);
int rcmp(const void*, const void*);
void regopt(Prog*);
void addmove(Reg*, int, int, int);
Bits mkvar(Reg*, Adr*);
void prop(Reg*, Bits, Bits);
void loopit(Reg*, long);
void synch(Reg*, Bits);
ulong allreg(ulong, Rgn*);
void paint1(Reg*, int);
ulong paint2(Reg*, int);
void paint3(Reg*, int, long, int);
void addreg(Adr*, int);
/*
* peep.c
*/
void peep(void);
void excise(Reg*);
Reg* uniqp(Reg*);
Reg* uniqs(Reg*);
int regtyp(Adr*);
int anyvar(Adr*);
int subprop(Reg*);
int copyprop(Reg*);
int copy1(Adr*, Adr*, Reg*, int);
int copyu(Prog*, Adr*, Adr*);
int copyas(Adr*, Adr*);
int copyau(Adr*, Adr*);
int copysub(Adr*, Adr*, Adr*, int);
int copysub1(Prog*, Adr*, Adr*, int);
long RtoB(int);
long FtoB(int);
int BtoR(long);
int BtoF(long);
#define D_HI D_NONE
#define D_LO D_NONE
#define isregtype(t) ((t)>= D_AX && (t)<=D_R15)
/*
* bound
*/
void comtarg(void);
/*
* com64
*/
int cond(int);
int com64(Node*);
void com64init(void);
void bool64(Node*);
long lo64v(Node*);
long hi64v(Node*);
Node* lo64(Node*);
Node* hi64(Node*);
/*
* div/mul
*/
void sdivgen(Node*, Node*, Node*, Node*);
void udivgen(Node*, Node*, Node*, Node*);
void sdiv2(long, int, Node*, Node*);
void smod2(long, int, Node*, Node*);
void mulgen(Type*, Node*, Node*);
void genmuladd(Node*, Node*, int, Node*);
void shiftit(Type*, Node*, Node*);
#pragma varargck type "A" int
#pragma varargck type "B" Bits
#pragma varargck type "D" Adr*
#pragma varargck type "P" Prog*
#pragma varargck type "R" int
#pragma varargck type "S" char*
#define D_X7 (D_X0+7)
void fgopcode(int, Node*, Node*, int, int);

372
src/cmd/6c/list.c Normal file
View file

@ -0,0 +1,372 @@
// Inferno utils/6c/list.c
// http://code.google.com/p/inferno-os/source/browse/utils/6c/list.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.
#define EXTERN
#include "gc.h"
void
listinit(void)
{
fmtinstall('A', Aconv);
fmtinstall('B', Bconv);
fmtinstall('P', Pconv);
fmtinstall('S', Sconv);
fmtinstall('D', Dconv);
fmtinstall('R', Rconv);
}
int
Bconv(Fmt *fp)
{
char str[STRINGSZ], ss[STRINGSZ], *s;
Bits bits;
int i;
str[0] = 0;
bits = va_arg(fp->args, Bits);
while(bany(&bits)) {
i = bnum(bits);
if(str[0])
strcat(str, " ");
if(var[i].sym == S) {
sprint(ss, "$%lld", var[i].offset);
s = ss;
} else
s = var[i].sym->name;
if(strlen(str) + strlen(s) + 1 >= STRINGSZ)
break;
strcat(str, s);
bits.b[i/32] &= ~(1L << (i%32));
}
return fmtstrcpy(fp, str);
}
int
Pconv(Fmt *fp)
{
char str[STRINGSZ];
Prog *p;
p = va_arg(fp->args, Prog*);
if(p->as == ADATA)
sprint(str, " %A %D/%d,%D",
p->as, &p->from, p->from.scale, &p->to);
else if(p->as == ATEXT)
sprint(str, " %A %D,%d,%D",
p->as, &p->from, p->from.scale, &p->to);
else
sprint(str, " %A %D,%D",
p->as, &p->from, &p->to);
return fmtstrcpy(fp, str);
}
int
Aconv(Fmt *fp)
{
int i;
i = va_arg(fp->args, int);
return fmtstrcpy(fp, anames[i]);
}
int
Dconv(Fmt *fp)
{
char str[40], s[20];
Adr *a;
int i;
a = va_arg(fp->args, Adr*);
i = a->type;
if(i >= D_INDIR) {
if(a->offset)
sprint(str, "%lld(%R)", a->offset, i-D_INDIR);
else
sprint(str, "(%R)", i-D_INDIR);
goto brk;
}
switch(i) {
default:
if(a->offset)
sprint(str, "$%lld,%R", a->offset, i);
else
sprint(str, "%R", i);
break;
case D_NONE:
str[0] = 0;
break;
case D_BRANCH:
sprint(str, "%lld(PC)", a->offset-pc);
break;
case D_EXTERN:
sprint(str, "%s+%lld(SB)", a->sym->name, a->offset);
break;
case D_STATIC:
sprint(str, "%s<>+%lld(SB)", a->sym->name,
a->offset);
break;
case D_AUTO:
if(a->sym) {
sprint(str, "%s+%lld(SP)", a->sym->name, a->offset);
break;
}
sprint(str, "%lld(SP)", a->offset);
break;
case D_PARAM:
if(a->sym) {
sprint(str, "%s+%lld(FP)", a->sym->name, a->offset);
break;
}
sprint(str, "%lld(FP)", a->offset);
break;
case D_CONST:
sprint(str, "$%lld", a->offset);
break;
case D_FCONST:
sprint(str, "$(%.17e)", a->dval);
break;
case D_SCONST:
sprint(str, "$\"%S\"", a->sval);
break;
case D_ADDR:
a->type = a->index;
a->index = D_NONE;
sprint(str, "$%D", a);
a->index = a->type;
a->type = D_ADDR;
goto conv;
}
brk:
if(a->index != D_NONE) {
sprint(s, "(%R*%d)", (int)a->index, (int)a->scale);
strcat(str, s);
}
conv:
return fmtstrcpy(fp, str);
}
char* regstr[] =
{
"AL", /* [D_AL] */
"CL",
"DL",
"BL",
"SPB",
"BPB",
"SIB",
"DIB",
"R8B",
"R9B",
"R10B",
"R11B",
"R12B",
"R13B",
"R14B",
"R15B",
"AX", /* [D_AX] */
"CX",
"DX",
"BX",
"SP",
"BP",
"SI",
"DI",
"R8",
"R9",
"R10",
"R11",
"R12",
"R13",
"R14",
"R15",
"AH",
"CH",
"DH",
"BH",
"F0", /* [D_F0] */
"F1",
"F2",
"F3",
"F4",
"F5",
"F6",
"F7",
"M0",
"M1",
"M2",
"M3",
"M4",
"M5",
"M6",
"M7",
"X0",
"X1",
"X2",
"X3",
"X4",
"X5",
"X6",
"X7",
"X8",
"X9",
"X10",
"X11",
"X12",
"X13",
"X14",
"X15",
"CS", /* [D_CS] */
"SS",
"DS",
"ES",
"FS",
"GS",
"GDTR", /* [D_GDTR] */
"IDTR", /* [D_IDTR] */
"LDTR", /* [D_LDTR] */
"MSW", /* [D_MSW] */
"TASK", /* [D_TASK] */
"CR0", /* [D_CR] */
"CR1",
"CR2",
"CR3",
"CR4",
"CR5",
"CR6",
"CR7",
"CR8",
"CR9",
"CR10",
"CR11",
"CR12",
"CR13",
"CR14",
"CR15",
"DR0", /* [D_DR] */
"DR1",
"DR2",
"DR3",
"DR4",
"DR5",
"DR6",
"DR7",
"TR0", /* [D_TR] */
"TR1",
"TR2",
"TR3",
"TR4",
"TR5",
"TR6",
"TR7",
"NONE", /* [D_NONE] */
};
int
Rconv(Fmt *fp)
{
char str[20];
int r;
r = va_arg(fp->args, int);
if(r >= D_AL && r <= D_NONE)
sprint(str, "%s", regstr[r-D_AL]);
else
sprint(str, "gok(%d)", r);
return fmtstrcpy(fp, str);
}
int
Sconv(Fmt *fp)
{
int i, c;
char str[30], *p, *a;
a = va_arg(fp->args, char*);
p = str;
for(i=0; i<sizeof(double); i++) {
c = a[i] & 0xff;
if(c >= 'a' && c <= 'z' ||
c >= 'A' && c <= 'Z' ||
c >= '0' && c <= '9') {
*p++ = c;
continue;
}
*p++ = '\\';
switch(c) {
default:
if(c < 040 || c >= 0177)
break; /* not portable */
p[-1] = c;
continue;
case 0:
*p++ = 'z';
continue;
case '\\':
case '"':
*p++ = c;
continue;
case '\n':
*p++ = 'n';
continue;
case '\t':
*p++ = 't';
continue;
}
*p++ = (c>>6) + '0';
*p++ = ((c>>3) & 7) + '0';
*p++ = (c & 7) + '0';
}
*p = 0;
return fmtstrcpy(fp, str);
}

108
src/cmd/6c/machcap.c Normal file
View file

@ -0,0 +1,108 @@
// Inferno utils/6c/machcap.c
// http://code.google.com/p/inferno-os/source/browse/utils/6c/machcap.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.
#include "gc.h"
int
machcap(Node *n)
{
if(n == Z)
return 1; /* test */
switch(n->op) {
case OMUL:
case OLMUL:
case OASMUL:
case OASLMUL:
if(typechl[n->type->etype])
return 1;
if(typev[n->type->etype]) {
return 1;
}
break;
case OCOM:
case ONEG:
case OADD:
case OAND:
case OOR:
case OSUB:
case OXOR:
case OASHL:
case OLSHR:
case OASHR:
if(typechlv[n->left->type->etype])
return 1;
break;
case OCAST:
return 1;
case OCOND:
case OCOMMA:
case OLIST:
case OANDAND:
case OOROR:
case ONOT:
return 1;
case OASADD:
case OASSUB:
case OASAND:
case OASOR:
case OASXOR:
return 1;
case OASASHL:
case OASASHR:
case OASLSHR:
return 1;
case OPOSTINC:
case OPOSTDEC:
case OPREINC:
case OPREDEC:
return 1;
case OEQ:
case ONE:
case OLE:
case OGT:
case OLT:
case OGE:
case OHI:
case OHS:
case OLO:
case OLS:
return 1;
}
return 0;
}

458
src/cmd/6c/mul.c Normal file
View file

@ -0,0 +1,458 @@
// Inferno utils/6c/mul.c
// http://code.google.com/p/inferno-os/source/browse/utils/6c/mul.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.
#include "gc.h"
typedef struct Malg Malg;
typedef struct Mparam Mparam;
struct Malg
{
char vals[10];
};
struct Mparam
{
ulong value;
char alg;
char neg;
char shift;
char arg;
char off;
};
static Mparam multab[32];
static int mulptr;
static Malg malgs[] =
{
{0, 100},
{-1, 1, 100},
{-9, -5, -3, 3, 5, 9, 100},
{6, 10, 12, 18, 20, 24, 36, 40, 72, 100},
{-8, -4, -2, 2, 4, 8, 100},
};
/*
* return position of lowest 1
*/
int
lowbit(ulong v)
{
int s, i;
ulong m;
s = 0;
m = 0xFFFFFFFFUL;
for(i = 16; i > 0; i >>= 1) {
m >>= i;
if((v & m) == 0) {
v >>= i;
s += i;
}
}
return s;
}
void
genmuladd(Node *d, Node *s, int m, Node *a)
{
Node nod;
nod.op = OINDEX;
nod.left = a;
nod.right = s;
nod.scale = m;
nod.type = types[TIND];
nod.xoffset = 0;
xcom(&nod);
gopcode(OADDR, d->type, &nod, d);
}
void
mulparam(ulong m, Mparam *mp)
{
int c, i, j, n, o, q, s;
int bc, bi, bn, bo, bq, bs, bt;
char *p;
long u;
ulong t;
bc = bq = 10;
bi = bn = bo = bs = bt = 0;
for(i = 0; i < nelem(malgs); i++) {
for(p = malgs[i].vals, j = 0; (o = p[j]) < 100; j++)
for(s = 0; s < 2; s++) {
c = 10;
q = 10;
u = m - o;
if(u == 0)
continue;
if(s) {
o = -o;
if(o > 0)
continue;
u = -u;
}
n = lowbit(u);
t = (ulong)u >> n;
switch(i) {
case 0:
if(t == 1) {
c = s + 1;
q = 0;
break;
}
switch(t) {
case 3:
case 5:
case 9:
c = s + 1;
if(n)
c++;
q = 0;
break;
}
if(s)
break;
switch(t) {
case 15:
case 25:
case 27:
case 45:
case 81:
c = 2;
if(n)
c++;
q = 1;
break;
}
break;
case 1:
if(t == 1) {
c = 3;
q = 3;
break;
}
switch(t) {
case 3:
case 5:
case 9:
c = 3;
q = 2;
break;
}
break;
case 2:
if(t == 1) {
c = 3;
q = 2;
break;
}
break;
case 3:
if(s)
break;
if(t == 1) {
c = 3;
q = 1;
break;
}
break;
case 4:
if(t == 1) {
c = 3;
q = 0;
break;
}
break;
}
if(c < bc || (c == bc && q > bq)) {
bc = c;
bi = i;
bn = n;
bo = o;
bq = q;
bs = s;
bt = t;
}
}
}
mp->value = m;
if(bc <= 3) {
mp->alg = bi;
mp->shift = bn;
mp->off = bo;
mp->neg = bs;
mp->arg = bt;
}
else
mp->alg = -1;
}
int
m0(int a)
{
switch(a) {
case -2:
case 2:
return 2;
case -3:
case 3:
return 2;
case -4:
case 4:
return 4;
case -5:
case 5:
return 4;
case 6:
return 2;
case -8:
case 8:
return 8;
case -9:
case 9:
return 8;
case 10:
return 4;
case 12:
return 2;
case 15:
return 2;
case 18:
return 8;
case 20:
return 4;
case 24:
return 2;
case 25:
return 4;
case 27:
return 2;
case 36:
return 8;
case 40:
return 4;
case 45:
return 4;
case 72:
return 8;
case 81:
return 8;
}
diag(Z, "bad m0");
return 0;
}
int
m1(int a)
{
switch(a) {
case 15:
return 4;
case 25:
return 4;
case 27:
return 8;
case 45:
return 8;
case 81:
return 8;
}
diag(Z, "bad m1");
return 0;
}
int
m2(int a)
{
switch(a) {
case 6:
return 2;
case 10:
return 2;
case 12:
return 4;
case 18:
return 2;
case 20:
return 4;
case 24:
return 8;
case 36:
return 4;
case 40:
return 8;
case 72:
return 8;
}
diag(Z, "bad m2");
return 0;
}
void
shiftit(Type *t, Node *s, Node *d)
{
long c;
c = (long)s->vconst & 31;
switch(c) {
case 0:
break;
case 1:
gopcode(OADD, t, d, d);
break;
default:
gopcode(OASHL, t, s, d);
}
}
static int
mulgen1(ulong v, Node *n)
{
int i, o;
Mparam *p;
Node nod, nods;
for(i = 0; i < nelem(multab); i++) {
p = &multab[i];
if(p->value == v)
goto found;
}
p = &multab[mulptr];
if(++mulptr == nelem(multab))
mulptr = 0;
mulparam(v, p);
found:
// print("v=%.lx a=%d n=%d s=%d g=%d o=%d \n", p->value, p->alg, p->neg, p->shift, p->arg, p->off);
if(p->alg < 0)
return 0;
nods = *nodconst(p->shift);
o = OADD;
if(p->alg > 0) {
regalloc(&nod, n, Z);
if(p->off < 0)
o = OSUB;
}
switch(p->alg) {
case 0:
switch(p->arg) {
case 1:
shiftit(n->type, &nods, n);
break;
case 15:
case 25:
case 27:
case 45:
case 81:
genmuladd(n, n, m1(p->arg), n);
/* fall thru */
case 3:
case 5:
case 9:
genmuladd(n, n, m0(p->arg), n);
shiftit(n->type, &nods, n);
break;
default:
goto bad;
}
if(p->neg == 1)
gins(ANEGL, Z, n);
break;
case 1:
switch(p->arg) {
case 1:
gmove(n, &nod);
shiftit(n->type, &nods, &nod);
break;
case 3:
case 5:
case 9:
genmuladd(&nod, n, m0(p->arg), n);
shiftit(n->type, &nods, &nod);
break;
default:
goto bad;
}
if(p->neg)
gopcode(o, n->type, &nod, n);
else {
gopcode(o, n->type, n, &nod);
gmove(&nod, n);
}
break;
case 2:
genmuladd(&nod, n, m0(p->off), n);
shiftit(n->type, &nods, n);
goto comop;
case 3:
genmuladd(&nod, n, m0(p->off), n);
shiftit(n->type, &nods, n);
genmuladd(n, &nod, m2(p->off), n);
break;
case 4:
genmuladd(&nod, n, m0(p->off), nodconst(0));
shiftit(n->type, &nods, n);
goto comop;
default:
diag(Z, "bad mul alg");
break;
comop:
if(p->neg) {
gopcode(o, n->type, n, &nod);
gmove(&nod, n);
}
else
gopcode(o, n->type, &nod, n);
}
if(p->alg > 0)
regfree(&nod);
return 1;
bad:
diag(Z, "mulgen botch");
return 1;
}
void
mulgen(Type *t, Node *r, Node *n)
{
if(!mulgen1(r->vconst, n))
gopcode(OMUL, t, r, n);
}

876
src/cmd/6c/peep.c Normal file
View file

@ -0,0 +1,876 @@
// Inferno utils/6c/peep.c
// http://code.google.com/p/inferno-os/source/browse/utils/6c/peep.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.
#include "gc.h"
static int
needc(Prog *p)
{
while(p != P) {
switch(p->as) {
case AADCL:
case AADCQ:
case ASBBL:
case ASBBQ:
case ARCRL:
case ARCRQ:
return 1;
case AADDL:
case AADDQ:
case ASUBL:
case ASUBQ:
case AJMP:
case ARET:
case ACALL:
return 0;
default:
if(p->to.type == D_BRANCH)
return 0;
}
p = p->link;
}
return 0;
}
static Reg*
rnops(Reg *r)
{
Prog *p;
Reg *r1;
if(r != R)
for(;;){
p = r->prog;
if(p->as != ANOP || p->from.type != D_NONE || p->to.type != D_NONE)
break;
r1 = uniqs(r);
if(r1 == R)
break;
r = r1;
}
return r;
}
void
peep(void)
{
Reg *r, *r1, *r2;
Prog *p, *p1;
int t;
/*
* complete R structure
*/
t = 0;
for(r=firstr; r!=R; r=r1) {
r1 = r->link;
if(r1 == R)
break;
p = r->prog->link;
while(p != r1->prog)
switch(p->as) {
default:
r2 = rega();
r->link = r2;
r2->link = r1;
r2->prog = p;
r2->p1 = r;
r->s1 = r2;
r2->s1 = r1;
r1->p1 = r2;
r = r2;
t++;
case ADATA:
case AGLOBL:
case ANAME:
case ASIGNAME:
p = p->link;
}
}
pc = 0; /* speculating it won't kill */
loop1:
t = 0;
for(r=firstr; r!=R; r=r->link) {
p = r->prog;
switch(p->as) {
case AMOVL:
case AMOVQ:
case AMOVSS:
case AMOVSD:
if(regtyp(&p->to))
if(regtyp(&p->from)) {
if(copyprop(r)) {
excise(r);
t++;
} else
if(subprop(r) && copyprop(r)) {
excise(r);
t++;
}
}
break;
case AMOVBLZX:
case AMOVWLZX:
case AMOVBLSX:
case AMOVWLSX:
if(regtyp(&p->to)) {
r1 = rnops(uniqs(r));
if(r1 != R) {
p1 = r1->prog;
if(p->as == p1->as && p->to.type == p1->from.type){
p1->as = AMOVL;
t++;
}
}
}
break;
case AMOVBQSX:
case AMOVBQZX:
case AMOVWQSX:
case AMOVWQZX:
case AMOVLQSX:
case AMOVLQZX:
if(regtyp(&p->to)) {
r1 = rnops(uniqs(r));
if(r1 != R) {
p1 = r1->prog;
if(p->as == p1->as && p->to.type == p1->from.type){
p1->as = AMOVQ;
t++;
}
}
}
break;
case AADDL:
case AADDQ:
case AADDW:
if(p->from.type != D_CONST || needc(p->link))
break;
if(p->from.offset == -1){
if(p->as == AADDQ)
p->as = ADECQ;
else if(p->as == AADDL)
p->as = ADECL;
else
p->as = ADECW;
p->from = zprog.from;
}
else if(p->from.offset == 1){
if(p->as == AADDQ)
p->as = AINCQ;
else if(p->as == AADDL)
p->as = AINCL;
else
p->as = AINCW;
p->from = zprog.from;
}
break;
case ASUBL:
case ASUBQ:
case ASUBW:
if(p->from.type != D_CONST || needc(p->link))
break;
if(p->from.offset == -1) {
if(p->as == ASUBQ)
p->as = AINCQ;
else if(p->as == ASUBL)
p->as = AINCL;
else
p->as = AINCW;
p->from = zprog.from;
}
else if(p->from.offset == 1){
if(p->as == ASUBQ)
p->as = ADECQ;
else if(p->as == ASUBL)
p->as = ADECL;
else
p->as = ADECW;
p->from = zprog.from;
}
break;
}
}
if(t)
goto loop1;
}
void
excise(Reg *r)
{
Prog *p;
p = r->prog;
p->as = ANOP;
p->from = zprog.from;
p->to = zprog.to;
}
Reg*
uniqp(Reg *r)
{
Reg *r1;
r1 = r->p1;
if(r1 == R) {
r1 = r->p2;
if(r1 == R || r1->p2link != R)
return R;
} else
if(r->p2 != R)
return R;
return r1;
}
Reg*
uniqs(Reg *r)
{
Reg *r1;
r1 = r->s1;
if(r1 == R) {
r1 = r->s2;
if(r1 == R)
return R;
} else
if(r->s2 != R)
return R;
return r1;
}
int
regtyp(Adr *a)
{
int t;
t = a->type;
if(t >= D_AX && t <= D_R15)
return 1;
if(t >= D_X0 && t <= D_X0+15)
return 1;
return 0;
}
/*
* the idea is to substitute
* one register for another
* from one MOV to another
* MOV a, R0
* ADD b, R0 / no use of R1
* MOV R0, R1
* would be converted to
* MOV a, R1
* ADD b, R1
* MOV R1, R0
* hopefully, then the former or latter MOV
* will be eliminated by copy propagation.
*/
int
subprop(Reg *r0)
{
Prog *p;
Adr *v1, *v2;
Reg *r;
int t;
p = r0->prog;
v1 = &p->from;
if(!regtyp(v1))
return 0;
v2 = &p->to;
if(!regtyp(v2))
return 0;
for(r=uniqp(r0); r!=R; r=uniqp(r)) {
if(uniqs(r) == R)
break;
p = r->prog;
switch(p->as) {
case ACALL:
return 0;
case AIMULL:
case AIMULQ:
case AIMULW:
if(p->to.type != D_NONE)
break;
case ADIVB:
case ADIVL:
case ADIVQ:
case ADIVW:
case AIDIVB:
case AIDIVL:
case AIDIVQ:
case AIDIVW:
case AIMULB:
case AMULB:
case AMULL:
case AMULQ:
case AMULW:
case AROLB:
case AROLL:
case AROLQ:
case AROLW:
case ARORB:
case ARORL:
case ARORQ:
case ARORW:
case ASALB:
case ASALL:
case ASALQ:
case ASALW:
case ASARB:
case ASARL:
case ASARQ:
case ASARW:
case ASHLB:
case ASHLL:
case ASHLQ:
case ASHLW:
case ASHRB:
case ASHRL:
case ASHRQ:
case ASHRW:
case AREP:
case AREPN:
case ACWD:
case ACDQ:
case ACQO:
case AMOVSL:
case AMOVSQ:
return 0;
case AMOVL:
case AMOVQ:
if(p->to.type == v1->type)
goto gotit;
break;
}
if(copyau(&p->from, v2) ||
copyau(&p->to, v2))
break;
if(copysub(&p->from, v1, v2, 0) ||
copysub(&p->to, v1, v2, 0))
break;
}
return 0;
gotit:
copysub(&p->to, v1, v2, 1);
if(debug['P']) {
print("gotit: %D->%D\n%P", v1, v2, r->prog);
if(p->from.type == v2->type)
print(" excise");
print("\n");
}
for(r=uniqs(r); r!=r0; r=uniqs(r)) {
p = r->prog;
copysub(&p->from, v1, v2, 1);
copysub(&p->to, v1, v2, 1);
if(debug['P'])
print("%P\n", r->prog);
}
t = v1->type;
v1->type = v2->type;
v2->type = t;
if(debug['P'])
print("%P last\n", r->prog);
return 1;
}
/*
* The idea is to remove redundant copies.
* v1->v2 F=0
* (use v2 s/v2/v1/)*
* set v1 F=1
* use v2 return fail
* -----------------
* v1->v2 F=0
* (use v2 s/v2/v1/)*
* set v1 F=1
* set v2 return success
*/
int
copyprop(Reg *r0)
{
Prog *p;
Adr *v1, *v2;
Reg *r;
p = r0->prog;
v1 = &p->from;
v2 = &p->to;
if(copyas(v1, v2))
return 1;
for(r=firstr; r!=R; r=r->link)
r->active = 0;
return copy1(v1, v2, r0->s1, 0);
}
int
copy1(Adr *v1, Adr *v2, Reg *r, int f)
{
int t;
Prog *p;
if(r->active) {
if(debug['P'])
print("act set; return 1\n");
return 1;
}
r->active = 1;
if(debug['P'])
print("copy %D->%D f=%d\n", v1, v2, f);
for(; r != R; r = r->s1) {
p = r->prog;
if(debug['P'])
print("%P", p);
if(!f && uniqp(r) == R) {
f = 1;
if(debug['P'])
print("; merge; f=%d", f);
}
t = copyu(p, v2, A);
switch(t) {
case 2: /* rar, cant split */
if(debug['P'])
print("; %D rar; return 0\n", v2);
return 0;
case 3: /* set */
if(debug['P'])
print("; %D set; return 1\n", v2);
return 1;
case 1: /* used, substitute */
case 4: /* use and set */
if(f) {
if(!debug['P'])
return 0;
if(t == 4)
print("; %D used+set and f=%d; return 0\n", v2, f);
else
print("; %D used and f=%d; return 0\n", v2, f);
return 0;
}
if(copyu(p, v2, v1)) {
if(debug['P'])
print("; sub fail; return 0\n");
return 0;
}
if(debug['P'])
print("; sub %D/%D", v2, v1);
if(t == 4) {
if(debug['P'])
print("; %D used+set; return 1\n", v2);
return 1;
}
break;
}
if(!f) {
t = copyu(p, v1, A);
if(!f && (t == 2 || t == 3 || t == 4)) {
f = 1;
if(debug['P'])
print("; %D set and !f; f=%d", v1, f);
}
}
if(debug['P'])
print("\n");
if(r->s2)
if(!copy1(v1, v2, r->s2, f))
return 0;
}
return 1;
}
/*
* return
* 1 if v only used (and substitute),
* 2 if read-alter-rewrite
* 3 if set
* 4 if set and used
* 0 otherwise (not touched)
*/
int
copyu(Prog *p, Adr *v, Adr *s)
{
switch(p->as) {
default:
if(debug['P'])
print("unknown op %A\n", p->as);
/* SBBL; ADCL; FLD1; SAHF */
return 2;
case ANEGB:
case ANEGW:
case ANEGL:
case ANEGQ:
case ANOTB:
case ANOTW:
case ANOTL:
case ANOTQ:
if(copyas(&p->to, v))
return 2;
break;
case ALEAL: /* lhs addr, rhs store */
case ALEAQ:
if(copyas(&p->from, v))
return 2;
case ANOP: /* rhs store */
case AMOVL:
case AMOVQ:
case AMOVBLSX:
case AMOVBLZX:
case AMOVBQSX:
case AMOVBQZX:
case AMOVLQSX:
case AMOVLQZX:
case AMOVWLSX:
case AMOVWLZX:
case AMOVWQSX:
case AMOVWQZX:
case AMOVSS:
case AMOVSD:
case ACVTSD2SL:
case ACVTSD2SQ:
case ACVTSD2SS:
case ACVTSL2SD:
case ACVTSL2SS:
case ACVTSQ2SD:
case ACVTSQ2SS:
case ACVTSS2SD:
case ACVTSS2SL:
case ACVTSS2SQ:
case ACVTTSD2SL:
case ACVTTSD2SQ:
case ACVTTSS2SL:
case ACVTTSS2SQ:
if(copyas(&p->to, v)) {
if(s != A)
return copysub(&p->from, v, s, 1);
if(copyau(&p->from, v))
return 4;
return 3;
}
goto caseread;
case AROLB:
case AROLL:
case AROLQ:
case AROLW:
case ARORB:
case ARORL:
case ARORQ:
case ARORW:
case ASALB:
case ASALL:
case ASALQ:
case ASALW:
case ASARB:
case ASARL:
case ASARQ:
case ASARW:
case ASHLB:
case ASHLL:
case ASHLQ:
case ASHLW:
case ASHRB:
case ASHRL:
case ASHRQ:
case ASHRW:
if(copyas(&p->to, v))
return 2;
if(copyas(&p->from, v))
if(p->from.type == D_CX)
return 2;
goto caseread;
case AADDB: /* rhs rar */
case AADDL:
case AADDQ:
case AADDW:
case AANDB:
case AANDL:
case AANDQ:
case AANDW:
case ADECL:
case ADECQ:
case ADECW:
case AINCL:
case AINCQ:
case AINCW:
case ASUBB:
case ASUBL:
case ASUBQ:
case ASUBW:
case AORB:
case AORL:
case AORQ:
case AORW:
case AXORB:
case AXORL:
case AXORQ:
case AXORW:
case AMOVB:
case AMOVW:
case AADDSD:
case AADDSS:
case ACMPSD:
case ACMPSS:
case ADIVSD:
case ADIVSS:
case AMAXSD:
case AMAXSS:
case AMINSD:
case AMINSS:
case AMULSD:
case AMULSS:
case ARCPSS:
case ARSQRTSS:
case ASQRTSD:
case ASQRTSS:
case ASUBSD:
case ASUBSS:
case AXORPD:
if(copyas(&p->to, v))
return 2;
goto caseread;
case ACMPL: /* read only */
case ACMPW:
case ACMPB:
case ACMPQ:
case ACOMISD:
case ACOMISS:
case AUCOMISD:
case AUCOMISS:
caseread:
if(s != A) {
if(copysub(&p->from, v, s, 1))
return 1;
return copysub(&p->to, v, s, 1);
}
if(copyau(&p->from, v))
return 1;
if(copyau(&p->to, v))
return 1;
break;
case AJGE: /* no reference */
case AJNE:
case AJLE:
case AJEQ:
case AJHI:
case AJLS:
case AJMI:
case AJPL:
case AJGT:
case AJLT:
case AJCC:
case AJCS:
case AADJSP:
case AWAIT:
case ACLD:
break;
case AIMULL:
case AIMULQ:
case AIMULW:
if(p->to.type != D_NONE) {
if(copyas(&p->to, v))
return 2;
goto caseread;
}
case ADIVB:
case ADIVL:
case ADIVQ:
case ADIVW:
case AIDIVB:
case AIDIVL:
case AIDIVQ:
case AIDIVW:
case AIMULB:
case AMULB:
case AMULL:
case AMULQ:
case AMULW:
case ACWD:
case ACDQ:
case ACQO:
if(v->type == D_AX || v->type == D_DX)
return 2;
goto caseread;
case AMOVSL:
case AMOVSQ:
case AREP:
case AREPN:
if(v->type == D_CX || v->type == D_DI || v->type == D_SI)
return 2;
goto caseread;
case AJMP: /* funny */
if(s != A) {
if(copysub(&p->to, v, s, 1))
return 1;
return 0;
}
if(copyau(&p->to, v))
return 1;
return 0;
case ARET: /* funny */
if(v->type == REGRET || v->type == FREGRET)
return 2;
if(s != A)
return 1;
return 3;
case ACALL: /* funny */
if(REGEXT && v->type <= REGEXT && v->type > exregoffset)
return 2;
if(REGARG && v->type == REGARG)
return 2;
if(s != A) {
if(copysub(&p->to, v, s, 1))
return 1;
return 0;
}
if(copyau(&p->to, v))
return 4;
return 3;
case ATEXT: /* funny */
if(REGARG && v->type == REGARG)
return 3;
return 0;
}
return 0;
}
/*
* direct reference,
* could be set/use depending on
* semantics
*/
int
copyas(Adr *a, Adr *v)
{
if(a->type != v->type)
return 0;
if(regtyp(v))
return 1;
if(v->type == D_AUTO || v->type == D_PARAM)
if(v->offset == a->offset)
return 1;
return 0;
}
/*
* either direct or indirect
*/
int
copyau(Adr *a, Adr *v)
{
if(copyas(a, v))
return 1;
if(regtyp(v)) {
if(a->type-D_INDIR == v->type)
return 1;
if(a->index == v->type)
return 1;
}
return 0;
}
/*
* substitute s for v in a
* return failure to substitute
*/
int
copysub(Adr *a, Adr *v, Adr *s, int f)
{
int t;
if(copyas(a, v)) {
t = s->type;
if(t >= D_AX && t <= D_R15 || t >= D_X0 && t <= D_X0+15) {
if(f)
a->type = t;
}
return 0;
}
if(regtyp(v)) {
t = v->type;
if(a->type == t+D_INDIR) {
if((s->type == D_BP || s->type == D_R13) && a->index != D_NONE)
return 1; /* can't use BP-base with index */
if(f)
a->type = s->type+D_INDIR;
// return 0;
}
if(a->index == t) {
if(f)
a->index = s->type;
return 0;
}
return 0;
}
return 0;
}

550
src/cmd/6c/pgen.c Normal file
View file

@ -0,0 +1,550 @@
// Inferno utils/6c/sgen.c
// http://code.google.com/p/inferno-os/source/browse/utils/6c/sgen.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.
#include "gc.h"
void
codgen(Node *n, Node *nn)
{
Prog *sp;
Node *n1, nod, nod1;
cursafe = 0;
curarg = 0;
maxargsafe = 0;
/*
* isolate name
*/
for(n1 = nn;; n1 = n1->left) {
if(n1 == Z) {
diag(nn, "cant find function name");
return;
}
if(n1->op == ONAME)
break;
}
nearln = nn->lineno;
gpseudo(ATEXT, n1->sym, nodconst(stkoff));
sp = p;
/*
* isolate first argument
*/
if(REGARG) {
if(typecmplx[thisfn->link->etype]) {
nod1 = *nodret->left;
nodreg(&nod, &nod1, REGARG);
gmove(&nod, &nod1);
} else
if(firstarg && typeword[firstargtype->etype]) {
nod1 = *nodret->left;
nod1.sym = firstarg;
nod1.type = firstargtype;
nod1.xoffset = align(0, firstargtype, Aarg1);
nod1.etype = firstargtype->etype;
nodreg(&nod, &nod1, REGARG);
gmove(&nod, &nod1);
}
}
canreach = 1;
warnreach = 1;
gen(n);
if(canreach && thisfn->link->etype != TVOID)
warn(Z, "no return at end of function: %s", n1->sym->name);
noretval(3);
gbranch(ORETURN);
if(!debug['N'] || debug['R'] || debug['P'])
regopt(sp);
if(thechar=='6' || thechar=='7') /* [sic] */
maxargsafe = xround(maxargsafe, 8);
sp->to.offset += maxargsafe;
}
void
supgen(Node *n)
{
int owarn;
long spc;
Prog *sp;
if(n == Z)
return;
suppress++;
owarn = warnreach;
warnreach = 0;
spc = pc;
sp = lastp;
gen(n);
lastp = sp;
pc = spc;
sp->link = nil;
suppress--;
warnreach = owarn;
}
void
gen(Node *n)
{
Node *l, nod;
Prog *sp, *spc, *spb;
Case *cn;
long sbc, scc;
int snbreak, sncontin;
int f, o, oldreach;
loop:
if(n == Z)
return;
nearln = n->lineno;
o = n->op;
if(debug['G'])
if(o != OLIST)
print("%L %O\n", nearln, o);
if(!canreach) {
switch(o) {
case OLABEL:
case OCASE:
case OLIST:
case OBREAK:
case OFOR:
case OWHILE:
case ODWHILE:
/* all handled specially - see switch body below */
break;
default:
if(warnreach) {
warn(n, "unreachable code %O", o);
warnreach = 0;
}
}
}
switch(o) {
default:
complex(n);
cgen(n, Z);
break;
case OLIST:
gen(n->left);
rloop:
n = n->right;
goto loop;
case ORETURN:
canreach = 0;
warnreach = !suppress;
complex(n);
if(n->type == T)
break;
l = n->left;
if(l == Z) {
noretval(3);
gbranch(ORETURN);
break;
}
if(typecmplx[n->type->etype]) {
sugen(l, nodret, n->type->width);
noretval(3);
gbranch(ORETURN);
break;
}
regret(&nod, n);
cgen(l, &nod);
regfree(&nod);
if(typefd[n->type->etype])
noretval(1);
else
noretval(2);
gbranch(ORETURN);
break;
case OLABEL:
canreach = 1;
l = n->left;
if(l) {
l->pc = pc;
if(l->label)
patch(l->label, pc);
}
gbranch(OGOTO); /* prevent self reference in reg */
patch(p, pc);
goto rloop;
case OGOTO:
canreach = 0;
warnreach = !suppress;
n = n->left;
if(n == Z)
return;
if(n->complex == 0) {
diag(Z, "label undefined: %s", n->sym->name);
return;
}
if(suppress)
return;
gbranch(OGOTO);
if(n->pc) {
patch(p, n->pc);
return;
}
if(n->label)
patch(n->label, pc-1);
n->label = p;
return;
case OCASE:
canreach = 1;
l = n->left;
if(cases == C)
diag(n, "case/default outside a switch");
if(l == Z) {
cas();
cases->val = 0;
cases->def = 1;
cases->label = pc;
cases->isv = 0;
goto rloop;
}
complex(l);
if(l->type == T)
goto rloop;
if(l->op == OCONST)
if(typeword[l->type->etype] && l->type->etype != TIND) {
cas();
cases->val = l->vconst;
cases->def = 0;
cases->label = pc;
cases->isv = typev[l->type->etype];
goto rloop;
}
diag(n, "case expression must be integer constant");
goto rloop;
case OSWITCH:
l = n->left;
complex(l);
if(l->type == T)
break;
if(!typeword[l->type->etype] || l->type->etype == TIND) {
diag(n, "switch expression must be integer");
break;
}
gbranch(OGOTO); /* entry */
sp = p;
cn = cases;
cases = C;
cas();
sbc = breakpc;
breakpc = pc;
snbreak = nbreak;
nbreak = 0;
gbranch(OGOTO);
spb = p;
gen(n->right); /* body */
if(canreach){
gbranch(OGOTO);
patch(p, breakpc);
nbreak++;
}
patch(sp, pc);
regalloc(&nod, l, Z);
/* always signed */
if(typev[l->type->etype])
nod.type = types[TVLONG];
else
nod.type = types[TLONG];
cgen(l, &nod);
doswit(&nod);
regfree(&nod);
patch(spb, pc);
cases = cn;
breakpc = sbc;
canreach = nbreak!=0;
if(canreach == 0)
warnreach = !suppress;
nbreak = snbreak;
break;
case OWHILE:
case ODWHILE:
l = n->left;
gbranch(OGOTO); /* entry */
sp = p;
scc = continpc;
continpc = pc;
gbranch(OGOTO);
spc = p;
sbc = breakpc;
breakpc = pc;
snbreak = nbreak;
nbreak = 0;
gbranch(OGOTO);
spb = p;
patch(spc, pc);
if(n->op == OWHILE)
patch(sp, pc);
bcomplex(l, Z); /* test */
patch(p, breakpc);
if(l->op != OCONST || vconst(l) == 0)
nbreak++;
if(n->op == ODWHILE)
patch(sp, pc);
gen(n->right); /* body */
gbranch(OGOTO);
patch(p, continpc);
patch(spb, pc);
continpc = scc;
breakpc = sbc;
canreach = nbreak!=0;
if(canreach == 0)
warnreach = !suppress;
nbreak = snbreak;
break;
case OFOR:
l = n->left;
if(!canreach && l->right->left && warnreach) {
warn(n, "unreachable code FOR");
warnreach = 0;
}
gen(l->right->left); /* init */
gbranch(OGOTO); /* entry */
sp = p;
/*
* if there are no incoming labels in the
* body and the top's not reachable, warn
*/
if(!canreach && warnreach && deadheads(n)) {
warn(n, "unreachable code %O", o);
warnreach = 0;
}
scc = continpc;
continpc = pc;
gbranch(OGOTO);
spc = p;
sbc = breakpc;
breakpc = pc;
snbreak = nbreak;
nbreak = 0;
sncontin = ncontin;
ncontin = 0;
gbranch(OGOTO);
spb = p;
patch(spc, pc);
gen(l->right->right); /* inc */
patch(sp, pc);
if(l->left != Z) { /* test */
bcomplex(l->left, Z);
patch(p, breakpc);
if(l->left->op != OCONST || vconst(l->left) == 0)
nbreak++;
}
canreach = 1;
gen(n->right); /* body */
if(canreach){
gbranch(OGOTO);
patch(p, continpc);
ncontin++;
}
if(!ncontin && l->right->right && warnreach) {
warn(l->right->right, "unreachable FOR inc");
warnreach = 0;
}
patch(spb, pc);
continpc = scc;
breakpc = sbc;
canreach = nbreak!=0;
if(canreach == 0)
warnreach = !suppress;
nbreak = snbreak;
ncontin = sncontin;
break;
case OCONTINUE:
if(continpc < 0) {
diag(n, "continue not in a loop");
break;
}
gbranch(OGOTO);
patch(p, continpc);
ncontin++;
canreach = 0;
warnreach = !suppress;
break;
case OBREAK:
if(breakpc < 0) {
diag(n, "break not in a loop");
break;
}
/*
* Don't complain about unreachable break statements.
* There are breaks hidden in yacc's output and some people
* write return; break; in their switch statements out of habit.
* However, don't confuse the analysis by inserting an
* unreachable reference to breakpc either.
*/
if(!canreach)
break;
gbranch(OGOTO);
patch(p, breakpc);
nbreak++;
canreach = 0;
warnreach = !suppress;
break;
case OIF:
l = n->left;
if(bcomplex(l, n->right)) {
if(typefd[l->type->etype])
f = !l->fconst;
else
f = !l->vconst;
if(debug['c'])
print("%L const if %s\n", nearln, f ? "false" : "true");
if(f) {
canreach = 1;
supgen(n->right->left);
oldreach = canreach;
canreach = 1;
gen(n->right->right);
/*
* treat constant ifs as regular ifs for
* reachability warnings.
*/
if(!canreach && oldreach && debug['w'] < 2)
warnreach = 0;
}
else {
canreach = 1;
gen(n->right->left);
oldreach = canreach;
canreach = 1;
supgen(n->right->right);
/*
* treat constant ifs as regular ifs for
* reachability warnings.
*/
if(!oldreach && canreach && debug['w'] < 2)
warnreach = 0;
canreach = oldreach;
}
}
else {
sp = p;
canreach = 1;
if(n->right->left != Z)
gen(n->right->left);
oldreach = canreach;
canreach = 1;
if(n->right->right != Z) {
gbranch(OGOTO);
patch(sp, pc);
sp = p;
gen(n->right->right);
}
patch(sp, pc);
canreach = canreach || oldreach;
if(canreach == 0)
warnreach = !suppress;
}
break;
case OSET:
case OUSED:
usedset(n->left, o);
break;
}
}
void
usedset(Node *n, int o)
{
if(n->op == OLIST) {
usedset(n->left, o);
usedset(n->right, o);
return;
}
complex(n);
switch(n->op) {
case OADDR: /* volatile */
gins(ANOP, n, Z);
break;
case ONAME:
if(o == OSET)
gins(ANOP, Z, n);
else
gins(ANOP, n, Z);
break;
}
}
int
bcomplex(Node *n, Node *c)
{
complex(n);
if(n->type != T)
if(tcompat(n, T, n->type, tnot))
n->type = T;
if(n->type == T) {
gbranch(OGOTO);
return 0;
}
if(c != Z && n->op == OCONST && deadheads(c))
return 1;
bool64(n);
boolgen(n, 1, Z);
return 0;
}

168
src/cmd/6c/pswt.c Normal file
View file

@ -0,0 +1,168 @@
// Inferno utils/6c/swt.c
// http://code.google.com/p/inferno-os/source/browse/utils/6c/swt.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.
#include "gc.h"
int
swcmp(const void *a1, const void *a2)
{
C1 *p1, *p2;
p1 = (C1*)a1;
p2 = (C1*)a2;
if(p1->val < p2->val)
return -1;
return p1->val > p2->val;
}
void
doswit(Node *n)
{
Case *c;
C1 *q, *iq;
long def, nc, i, isv;
def = 0;
nc = 0;
isv = 0;
for(c = cases; c->link != C; c = c->link) {
if(c->def) {
if(def)
diag(n, "more than one default in switch");
def = c->label;
continue;
}
isv |= c->isv;
nc++;
}
if(isv && !typev[n->type->etype])
warn(n, "32-bit switch expression with 64-bit case constant");
iq = alloc(nc*sizeof(C1));
q = iq;
for(c = cases; c->link != C; c = c->link) {
if(c->def)
continue;
q->label = c->label;
if(isv)
q->val = c->val;
else
q->val = (long)c->val; /* cast ensures correct value for 32-bit switch on 64-bit architecture */
q++;
}
qsort(iq, nc, sizeof(C1), swcmp);
if(debug['W'])
for(i=0; i<nc; i++)
print("case %2ld: = %.8llux\n", i, (vlong)iq[i].val);
for(i=0; i<nc-1; i++)
if(iq[i].val == iq[i+1].val)
diag(n, "duplicate cases in switch %lld", (vlong)iq[i].val);
if(def == 0) {
def = breakpc;
nbreak++;
}
swit1(iq, nc, def, n);
}
void
cas(void)
{
Case *c;
c = alloc(sizeof(*c));
c->link = cases;
cases = c;
}
long
outlstring(ushort *s, long n)
{
char buf[2];
int c;
long r;
if(suppress)
return nstring;
while(nstring & 1)
outstring("", 1);
r = nstring;
while(n > 0) {
c = *s++;
if(align(0, types[TCHAR], Aarg1)) {
buf[0] = c>>8;
buf[1] = c;
} else {
buf[0] = c;
buf[1] = c>>8;
}
outstring(buf, 2);
n -= sizeof(ushort);
}
return r;
}
void
nullwarn(Node *l, Node *r)
{
warn(Z, "result of operation not used");
if(l != Z)
cgen(l, Z);
if(r != Z)
cgen(r, Z);
}
void
ieeedtod(Ieee *ieee, double native)
{
double fr, ho, f;
int exp;
if(native < 0) {
ieeedtod(ieee, -native);
ieee->h |= 0x80000000L;
return;
}
if(native == 0) {
ieee->l = 0;
ieee->h = 0;
return;
}
fr = frexp(native, &exp);
f = 2097152L; /* shouldnt use fp constants here */
fr = modf(fr*f, &ho);
ieee->h = ho;
ieee->h &= 0xfffffL;
ieee->h |= (exp+1022L) << 20;
f = 65536L;
fr = modf(fr*f, &ho);
ieee->l = ho;
ieee->l <<= 16;
ieee->l |= (long)(fr*f);
}

1386
src/cmd/6c/reg.c Normal file

File diff suppressed because it is too large Load diff

465
src/cmd/6c/sgen.c Normal file
View file

@ -0,0 +1,465 @@
// Inferno utils/6c/sgen.c
// http://code.google.com/p/inferno-os/source/browse/utils/6c/sgen.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.
#include "gc.h"
void
noretval(int n)
{
if(n & 1) {
gins(ANOP, Z, Z);
p->to.type = REGRET;
}
if(n & 2) {
gins(ANOP, Z, Z);
p->to.type = FREGRET;
}
}
/* welcome to commute */
static void
commute(Node *n)
{
Node *l, *r;
l = n->left;
r = n->right;
if(r->complex > l->complex) {
n->left = r;
n->right = l;
}
}
void
indexshift(Node *n)
{
int g;
if(!typechlpv[n->type->etype])
return;
simplifyshift(n);
if(n->op == OASHL && n->right->op == OCONST){
g = vconst(n->right);
if(g >= 0 && g <= 3)
n->addable = 7;
}
}
/*
* calculate addressability as follows
* NAME ==> 10/11 name+value(SB/SP)
* REGISTER ==> 12 register
* CONST ==> 20 $value
* *(20) ==> 21 value
* &(10) ==> 13 $name+value(SB)
* &(11) ==> 1 $name+value(SP)
* (13) + (20) ==> 13 fold constants
* (1) + (20) ==> 1 fold constants
* *(13) ==> 10 back to name
* *(1) ==> 11 back to name
*
* (20) * (X) ==> 7 multiplier in indexing
* (X,7) + (13,1) ==> 8 adder in indexing (addresses)
* (8) ==> &9(OINDEX) index, almost addressable
*
* calculate complexity (number of registers)
*/
void
xcom(Node *n)
{
Node *l, *r;
int g;
if(n == Z)
return;
l = n->left;
r = n->right;
n->complex = 0;
n->addable = 0;
switch(n->op) {
case OCONST:
n->addable = 20;
break;
case ONAME:
n->addable = 10;
if(n->class == CPARAM || n->class == CAUTO)
n->addable = 11;
break;
case OREGISTER:
n->addable = 12;
break;
case OINDREG:
n->addable = 12;
break;
case OADDR:
xcom(l);
if(l->addable == 10)
n->addable = 13;
else
if(l->addable == 11)
n->addable = 1;
break;
case OADD:
xcom(l);
xcom(r);
if(n->type->etype != TIND)
break;
switch(r->addable) {
case 20:
switch(l->addable) {
case 1:
case 13:
commadd:
l->type = n->type;
*n = *l;
l = new(0, Z, Z);
*l = *(n->left);
l->xoffset += r->vconst;
n->left = l;
r = n->right;
goto brk;
}
break;
case 1:
case 13:
case 10:
case 11:
/* l is the base, r is the index */
if(l->addable != 20)
n->addable = 8;
break;
}
switch(l->addable) {
case 20:
switch(r->addable) {
case 13:
case 1:
r = n->left;
l = n->right;
n->left = l;
n->right = r;
goto commadd;
}
break;
case 13:
case 1:
case 10:
case 11:
/* r is the base, l is the index */
if(r->addable != 20)
n->addable = 8;
break;
}
if(n->addable == 8 && !side(n)) {
indx(n);
l = new1(OINDEX, idx.basetree, idx.regtree);
l->scale = idx.scale;
l->addable = 9;
l->complex = l->right->complex;
l->type = l->left->type;
n->op = OADDR;
n->left = l;
n->right = Z;
n->addable = 8;
break;
}
break;
case OINDEX:
xcom(l);
xcom(r);
n->addable = 9;
break;
case OIND:
xcom(l);
if(l->op == OADDR) {
l = l->left;
l->type = n->type;
*n = *l;
return;
}
switch(l->addable) {
case 20:
n->addable = 21;
break;
case 1:
n->addable = 11;
break;
case 13:
n->addable = 10;
break;
}
break;
case OASHL:
xcom(l);
xcom(r);
indexshift(n);
break;
case OMUL:
case OLMUL:
xcom(l);
xcom(r);
g = vlog(l);
if(g >= 0) {
n->left = r;
n->right = l;
l = r;
r = n->right;
}
g = vlog(r);
if(g >= 0) {
n->op = OASHL;
r->vconst = g;
r->type = types[TINT];
indexshift(n);
break;
}
commute(n);
break;
case OASLDIV:
xcom(l);
xcom(r);
g = vlog(r);
if(g >= 0) {
n->op = OASLSHR;
r->vconst = g;
r->type = types[TINT];
}
break;
case OLDIV:
xcom(l);
xcom(r);
g = vlog(r);
if(g >= 0) {
n->op = OLSHR;
r->vconst = g;
r->type = types[TINT];
indexshift(n);
break;
}
break;
case OASLMOD:
xcom(l);
xcom(r);
g = vlog(r);
if(g >= 0) {
n->op = OASAND;
r->vconst--;
}
break;
case OLMOD:
xcom(l);
xcom(r);
g = vlog(r);
if(g >= 0) {
n->op = OAND;
r->vconst--;
}
break;
case OASMUL:
case OASLMUL:
xcom(l);
xcom(r);
g = vlog(r);
if(g >= 0) {
n->op = OASASHL;
r->vconst = g;
}
break;
case OLSHR:
case OASHR:
xcom(l);
xcom(r);
indexshift(n);
break;
default:
if(l != Z)
xcom(l);
if(r != Z)
xcom(r);
break;
}
brk:
if(n->addable >= 10)
return;
if(l != Z)
n->complex = l->complex;
if(r != Z) {
if(r->complex == n->complex)
n->complex = r->complex+1;
else
if(r->complex > n->complex)
n->complex = r->complex;
}
if(n->complex == 0)
n->complex++;
switch(n->op) {
case OFUNC:
n->complex = FNX;
break;
case OCAST:
if(l->type->etype == TUVLONG && typefd[n->type->etype])
n->complex += 2;
break;
case OLMOD:
case OMOD:
case OLMUL:
case OLDIV:
case OMUL:
case ODIV:
case OASLMUL:
case OASLDIV:
case OASLMOD:
case OASMUL:
case OASDIV:
case OASMOD:
if(r->complex >= l->complex) {
n->complex = l->complex + 3;
if(r->complex > n->complex)
n->complex = r->complex;
} else {
n->complex = r->complex + 3;
if(l->complex > n->complex)
n->complex = l->complex;
}
break;
case OLSHR:
case OASHL:
case OASHR:
case OASLSHR:
case OASASHL:
case OASASHR:
if(r->complex >= l->complex) {
n->complex = l->complex + 2;
if(r->complex > n->complex)
n->complex = r->complex;
} else {
n->complex = r->complex + 2;
if(l->complex > n->complex)
n->complex = l->complex;
}
break;
case OADD:
case OXOR:
case OAND:
case OOR:
/*
* immediate operators, make const on right
*/
if(l->op == OCONST) {
n->left = r;
n->right = l;
}
break;
case OEQ:
case ONE:
case OLE:
case OLT:
case OGE:
case OGT:
case OHI:
case OHS:
case OLO:
case OLS:
/*
* compare operators, make const on left
*/
if(r->op == OCONST) {
n->left = r;
n->right = l;
n->op = invrel[relindex(n->op)];
}
break;
}
}
void
indx(Node *n)
{
Node *l, *r;
if(debug['x'])
prtree(n, "indx");
l = n->left;
r = n->right;
if(l->addable == 1 || l->addable == 13 || r->complex > l->complex) {
n->right = l;
n->left = r;
l = r;
r = n->right;
}
if(l->addable != 7) {
idx.regtree = l;
idx.scale = 1;
} else
if(l->right->addable == 20) {
idx.regtree = l->left;
idx.scale = 1 << l->right->vconst;
} else
if(l->left->addable == 20) {
idx.regtree = l->right;
idx.scale = 1 << l->left->vconst;
} else
diag(n, "bad index");
idx.basetree = r;
if(debug['x']) {
print("scale = %d\n", idx.scale);
prtree(idx.regtree, "index");
prtree(idx.basetree, "base");
}
}

566
src/cmd/6c/swt.c Normal file
View file

@ -0,0 +1,566 @@
// Inferno utils/6c/swt.c
// http://code.google.com/p/inferno-os/source/browse/utils/6c/swt.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.
#include "gc.h"
void
swit1(C1 *q, int nc, long def, Node *n)
{
C1 *r;
int i;
Prog *sp;
if(nc < 5) {
for(i=0; i<nc; i++) {
if(debug['W'])
print("case = %.8llux\n", q->val);
gcmp(OEQ, n, q->val);
patch(p, q->label);
q++;
}
gbranch(OGOTO);
patch(p, def);
return;
}
i = nc / 2;
r = q+i;
if(debug['W'])
print("case > %.8llux\n", r->val);
gcmp(OGT, n, r->val);
sp = p;
gbranch(OGOTO);
p->as = AJEQ;
patch(p, r->label);
swit1(q, i, def, n);
if(debug['W'])
print("case < %.8llux\n", r->val);
patch(sp, pc);
swit1(r+1, nc-i-1, def, n);
}
void
bitload(Node *b, Node *n1, Node *n2, Node *n3, Node *nn)
{
int sh;
long v;
Node *l;
/*
* n1 gets adjusted/masked value
* n2 gets address of cell
* n3 gets contents of cell
*/
l = b->left;
if(n2 != Z) {
regalloc(n1, l, nn);
reglcgen(n2, l, Z);
regalloc(n3, l, Z);
gmove(n2, n3);
gmove(n3, n1);
} else {
regalloc(n1, l, nn);
cgen(l, n1);
}
if(b->type->shift == 0 && typeu[b->type->etype]) {
v = ~0 + (1L << b->type->nbits);
gopcode(OAND, tfield, nodconst(v), n1);
} else {
sh = 32 - b->type->shift - b->type->nbits;
if(sh > 0)
gopcode(OASHL, tfield, nodconst(sh), n1);
sh += b->type->shift;
if(sh > 0)
if(typeu[b->type->etype])
gopcode(OLSHR, tfield, nodconst(sh), n1);
else
gopcode(OASHR, tfield, nodconst(sh), n1);
}
}
void
bitstore(Node *b, Node *n1, Node *n2, Node *n3, Node *nn)
{
long v;
Node nod;
int sh;
regalloc(&nod, b->left, Z);
v = ~0 + (1L << b->type->nbits);
gopcode(OAND, types[TLONG], nodconst(v), n1);
gmove(n1, &nod);
if(nn != Z)
gmove(n1, nn);
sh = b->type->shift;
if(sh > 0)
gopcode(OASHL, types[TLONG], nodconst(sh), &nod);
v <<= sh;
gopcode(OAND, types[TLONG], nodconst(~v), n3);
gopcode(OOR, types[TLONG], n3, &nod);
gmove(&nod, n2);
regfree(&nod);
regfree(n1);
regfree(n2);
regfree(n3);
}
long
outstring(char *s, long n)
{
long r;
if(suppress)
return nstring;
r = nstring;
while(n) {
string[mnstring] = *s++;
mnstring++;
nstring++;
if(mnstring >= NSNAME) {
gpseudo(ADATA, symstring, nodconst(0L));
p->from.offset += nstring - NSNAME;
p->from.scale = NSNAME;
p->to.type = D_SCONST;
memmove(p->to.sval, string, NSNAME);
mnstring = 0;
}
n--;
}
return r;
}
void
sextern(Sym *s, Node *a, long o, long w)
{
long e, lw;
for(e=0; e<w; e+=NSNAME) {
lw = NSNAME;
if(w-e < lw)
lw = w-e;
gpseudo(ADATA, s, nodconst(0L));
p->from.offset += o+e;
p->from.scale = lw;
p->to.type = D_SCONST;
memmove(p->to.sval, a->cstring+e, lw);
}
}
void
gextern(Sym *s, Node *a, long o, long w)
{
if(0 && a->op == OCONST && typev[a->type->etype]) {
gpseudo(ADATA, s, lo64(a));
p->from.offset += o;
p->from.scale = 4;
gpseudo(ADATA, s, hi64(a));
p->from.offset += o + 4;
p->from.scale = 4;
return;
}
gpseudo(ADATA, s, a);
p->from.offset += o;
p->from.scale = w;
switch(p->to.type) {
default:
p->to.index = p->to.type;
p->to.type = D_ADDR;
case D_CONST:
case D_FCONST:
case D_ADDR:
break;
}
}
void zname(Biobuf*, Sym*, int);
void zaddr(Biobuf*, Adr*, int);
void outhist(Biobuf*);
void
outcode(void)
{
struct { Sym *sym; short type; } h[NSYM];
Prog *p;
Sym *s;
int f, sf, st, t, sym;
Biobuf b;
if(debug['S']) {
for(p = firstp; p != P; p = p->link)
if(p->as != ADATA && p->as != AGLOBL)
pc--;
for(p = firstp; p != P; p = p->link) {
print("%P\n", p);
if(p->as != ADATA && p->as != AGLOBL)
pc++;
}
}
f = open(outfile, OWRITE);
if(f < 0) {
diag(Z, "cannot open %s", outfile);
return;
}
Binit(&b, f, OWRITE);
Bprint(&b, "x86-64\n");
Bprint(&b, "!\n");
outhist(&b);
for(sym=0; sym<NSYM; sym++) {
h[sym].sym = S;
h[sym].type = 0;
}
sym = 1;
for(p = firstp; p != P; p = p->link) {
jackpot:
sf = 0;
s = p->from.sym;
while(s != S) {
sf = s->sym;
if(sf < 0 || sf >= NSYM)
sf = 0;
t = p->from.type;
if(t == D_ADDR)
t = p->from.index;
if(h[sf].type == t)
if(h[sf].sym == s)
break;
s->sym = sym;
zname(&b, s, t);
h[sym].sym = s;
h[sym].type = t;
sf = sym;
sym++;
if(sym >= NSYM)
sym = 1;
break;
}
st = 0;
s = p->to.sym;
while(s != S) {
st = s->sym;
if(st < 0 || st >= NSYM)
st = 0;
t = p->to.type;
if(t == D_ADDR)
t = p->to.index;
if(h[st].type == t)
if(h[st].sym == s)
break;
s->sym = sym;
zname(&b, s, t);
h[sym].sym = s;
h[sym].type = t;
st = sym;
sym++;
if(sym >= NSYM)
sym = 1;
if(st == sf)
goto jackpot;
break;
}
Bputc(&b, p->as);
Bputc(&b, p->as>>8);
Bputc(&b, p->lineno);
Bputc(&b, p->lineno>>8);
Bputc(&b, p->lineno>>16);
Bputc(&b, p->lineno>>24);
zaddr(&b, &p->from, sf);
zaddr(&b, &p->to, st);
}
Bflush(&b);
close(f);
firstp = P;
lastp = P;
}
void
outhist(Biobuf *b)
{
Hist *h;
char *p, *q, *op, c;
Prog pg;
int n;
pg = zprog;
pg.as = AHISTORY;
c = pathchar();
for(h = hist; h != H; h = h->link) {
p = h->name;
op = 0;
/* on windows skip drive specifier in pathname */
if(systemtype(Windows) && p && p[1] == ':'){
p += 2;
c = *p;
}
if(p && p[0] != c && h->offset == 0 && pathname){
/* on windows skip drive specifier in pathname */
if(systemtype(Windows) && pathname[1] == ':') {
op = p;
p = pathname+2;
c = *p;
} else if(pathname[0] == c){
op = p;
p = pathname;
}
}
while(p) {
q = utfrune(p, c);
if(q) {
n = q-p;
if(n == 0){
n = 1; /* leading "/" */
*p = '/'; /* don't emit "\" on windows */
}
q++;
} else {
n = strlen(p);
q = 0;
}
if(n) {
Bputc(b, ANAME);
Bputc(b, ANAME>>8);
Bputc(b, D_FILE);
Bputc(b, 1);
Bputc(b, '<');
Bwrite(b, p, n);
Bputc(b, 0);
}
p = q;
if(p == 0 && op) {
p = op;
op = 0;
}
}
pg.lineno = h->line;
pg.to.type = zprog.to.type;
pg.to.offset = h->offset;
if(h->offset)
pg.to.type = D_CONST;
Bputc(b, pg.as);
Bputc(b, pg.as>>8);
Bputc(b, pg.lineno);
Bputc(b, pg.lineno>>8);
Bputc(b, pg.lineno>>16);
Bputc(b, pg.lineno>>24);
zaddr(b, &pg.from, 0);
zaddr(b, &pg.to, 0);
}
}
void
zname(Biobuf *b, Sym *s, int t)
{
char *n;
ulong sig;
if(debug['T'] && t == D_EXTERN && s->sig != SIGDONE && s->type != types[TENUM] && s != symrathole){
sig = sign(s);
Bputc(b, ASIGNAME);
Bputc(b, ASIGNAME>>8);
Bputc(b, sig);
Bputc(b, sig>>8);
Bputc(b, sig>>16);
Bputc(b, sig>>24);
s->sig = SIGDONE;
}
else{
Bputc(b, ANAME); /* as */
Bputc(b, ANAME>>8); /* as */
}
Bputc(b, t); /* type */
Bputc(b, s->sym); /* sym */
n = s->name;
while(*n) {
Bputc(b, *n);
n++;
}
Bputc(b, 0);
}
void
zaddr(Biobuf *b, Adr *a, int s)
{
long l;
int i, t;
char *n;
Ieee e;
t = 0;
if(a->index != D_NONE || a->scale != 0)
t |= T_INDEX;
if(s != 0)
t |= T_SYM;
switch(a->type) {
default:
t |= T_TYPE;
case D_NONE:
if(a->offset != 0) {
t |= T_OFFSET;
l = a->offset;
if((vlong)l != a->offset)
t |= T_64;
}
break;
case D_FCONST:
t |= T_FCONST;
break;
case D_SCONST:
t |= T_SCONST;
break;
}
Bputc(b, t);
if(t & T_INDEX) { /* implies index, scale */
Bputc(b, a->index);
Bputc(b, a->scale);
}
if(t & T_OFFSET) { /* implies offset */
l = a->offset;
Bputc(b, l);
Bputc(b, l>>8);
Bputc(b, l>>16);
Bputc(b, l>>24);
if(t & T_64) {
l = a->offset>>32;
Bputc(b, l);
Bputc(b, l>>8);
Bputc(b, l>>16);
Bputc(b, l>>24);
}
}
if(t & T_SYM) /* implies sym */
Bputc(b, s);
if(t & T_FCONST) {
ieeedtod(&e, a->dval);
l = e.l;
Bputc(b, l);
Bputc(b, l>>8);
Bputc(b, l>>16);
Bputc(b, l>>24);
l = e.h;
Bputc(b, l);
Bputc(b, l>>8);
Bputc(b, l>>16);
Bputc(b, l>>24);
return;
}
if(t & T_SCONST) {
n = a->sval;
for(i=0; i<NSNAME; i++) {
Bputc(b, *n);
n++;
}
return;
}
if(t & T_TYPE)
Bputc(b, a->type);
}
long
align(long i, Type *t, int op)
{
long o;
Type *v;
int w;
o = i;
w = 1;
switch(op) {
default:
diag(Z, "unknown align opcode %d", op);
break;
case Asu2: /* padding at end of a struct */
w = SZ_VLONG;
if(packflg)
w = packflg;
break;
case Ael1: /* initial align of struct element */
for(v=t; v->etype==TARRAY; v=v->link)
;
w = ewidth[v->etype];
if(w <= 0 || w >= SZ_VLONG)
w = SZ_VLONG;
if(packflg)
w = packflg;
break;
case Ael2: /* width of a struct element */
o += t->width;
break;
case Aarg0: /* initial passbyptr argument in arg list */
if(typesu[t->etype]) {
o = align(o, types[TIND], Aarg1);
o = align(o, types[TIND], Aarg2);
}
break;
case Aarg1: /* initial align of parameter */
w = ewidth[t->etype];
if(w <= 0 || w >= SZ_VLONG) {
w = SZ_VLONG;
break;
}
w = 1; /* little endian no adjustment */
break;
case Aarg2: /* width of a parameter */
o += t->width;
w = t->width;
if(w > SZ_VLONG)
w = SZ_VLONG;
break;
case Aaut3: /* total allign of automatic */
o = align(o, t, Ael1);
o = align(o, t, Ael2);
break;
}
o = xround(o, w);
if(debug['A'])
print("align %s %ld %T = %ld\n", bnames[op], i, t, o);
return o;
}
long
maxround(long max, long v)
{
v += SZ_VLONG-1;
if(v > max)
max = xround(v, SZ_VLONG);
return max;
}

1546
src/cmd/6c/txt.c Normal file

File diff suppressed because it is too large Load diff

210
src/cmd/6g/align.c Normal file
View file

@ -0,0 +1,210 @@
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
#include "gg.h"
/*
* machine size and rounding
* alignment is dictated around
* the size of a pointer.
* the size of the generic types
* are pulled from the typedef table.
*/
static int wptr = 8; // width of a pointer
static int wmax = 8; // max rounding
static char*
typedefs[] =
{
"short", "int16", // shorts
"ushort", "uint16",
"int", "int32", // ints
"uint", "uint32",
"rune", "uint32",
"long", "int64", // longs
"ulong", "uint64",
"vlong", "int64", // vlongs
"uvlong", "uint64",
"float", "float32", // floats
"double", "float64",
};
ulong
rnd(ulong o, ulong r)
{
if(r > wmax)
r = wmax;
if(r != 0)
while(o%r != 0)
o++;
return o;
}
void
offmod(Type *t)
{
Type *f;
long o;
o = 0;
for(f=t->type; f!=T; f=f->down) {
if(f->etype != TFIELD)
fatal("widstruct: not TFIELD: %lT", f);
if(f->type->etype != TFUNC)
continue;
f->width = o;
o += wptr;
}
}
ulong
widstruct(Type *t, ulong o, int flag)
{
Type *f;
long w;
for(f=t->type; f!=T; f=f->down) {
if(f->etype != TFIELD)
fatal("widstruct: not TFIELD: %lT", f);
dowidth(f->type);
w = f->type->width;
o = rnd(o, w);
f->width = o; // really offset for TFIELD
o += w;
}
// final width is rounded
if(flag)
o = rnd(o, maxround);
t->width = o;
return o;
}
void
dowidth(Type *t)
{
ulong w;
w = 0;
if(t == T)
return;
switch(t->etype) {
default:
fatal("dowidth: unknown type: %E", t->etype);
break;
case TINT8:
case TUINT8:
case TBOOL: // bool is int8
w = 1;
break;
case TINT16:
case TUINT16:
w = 2;
break;
case TINT32:
case TUINT32:
case TFLOAT32:
case TPTR32:
w = 4;
break;
case TINT64:
case TUINT64:
case TFLOAT64:
case TPTR64:
w = 8;
break;
case TFLOAT80:
w = 10;
break;
case TINTER: // implemented as 2 pointers
offmod(t);
w = 2*wptr;
break;
case TCHAN: // implemented as pointer
dowidth(t->type);
dowidth(t->down);
w = wptr;
break;
case TMAP: // implemented as pointer
dowidth(t->type);
w = wptr;
break;
case TFORW: // implemented as pointer
w = wptr;
break;
case TANY: // implemented as pointer
w = wptr;
break;
case TSTRING: // implemented as pointer
w = wptr;
break;
case TARRAY:
case TDARRAY:
if(t->type == T)
break;
dowidth(t->type);
w = t->bound * t->type->width;
break;
case TSTRUCT:
w = widstruct(t, 0, 1);
offmod(t);
break;
case TFUNC:
// function is 3 cated structures
w = widstruct(*getthis(t), 0, 0);
w = widstruct(*getinarg(t), w, 0);
w = widstruct(*getoutarg(t), w, 1);
w = 0;
break;
}
t->width = w;
}
void
besetptr(void)
{
maxround = wmax;
widthptr = wptr;
types[TPTR32] = typ(TPTR32);
dowidth(types[TPTR32]);
types[TPTR64] = typ(TPTR64);
dowidth(types[TPTR64]);
tptr = TPTR32;
if(wptr == 8)
tptr = TPTR64;
}
void
belexinit(int lextype)
{
int i;
Sym *s0, *s1;
for(i=0; i<nelem(typedefs); i+=2) {
s1 = lookup(typedefs[i+1]);
if(s1->lexical != lextype)
yyerror("need %s to define %s",
typedefs[i+1], typedefs[i+0]);
s0 = lookup(typedefs[i+0]);
s0->lexical = s1->lexical;
s0->otype = s1->otype;
}
symstringo = lookup(".stringo"); // strings
listinit();
buildtxt();
}

638
src/cmd/6g/cgen.c Normal file
View file

@ -0,0 +1,638 @@
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
#include "gg.h"
void
cgen(Node *n, Node *res)
{
long lno;
Node *nl, *nr, *r;
Node n1, tmp;
int a;
Prog *p1, *p2, *p3;
if(debug['g']) {
dump("\ncgen-l", res);
dump("cgen-r", n);
}
if(n == N || n->type == T)
return;
if(res == N || res->type == T)
fatal("cgen: res nil");
lno = dynlineno;
if(n->op != ONAME)
dynlineno = n->lineno; // for diagnostics
if(isfat(n->type)) {
sgen(n, res, n->type->width);
goto ret;
}
if(!res->addable) {
igen(res, &n1, N);
cgen(n, &n1);
regfree(&n1);
goto ret;
}
if(n->addable) {
gmove(n, res);
goto ret;
}
nl = n->left;
nr = n->right;
if(nl != N && nl->ullman >= UINF)
if(nr != N && nr->ullman >= UINF) {
fatal("cgen: both sides functions");
goto ret;
}
switch(n->op) {
default:
dump("cgen", n);
fatal("cgen: unknown op %N", n);
break;
// these call bgen to get a bool value
case OOROR:
case OANDAND:
case OEQ:
case ONE:
case OLT:
case OLE:
case OGE:
case OGT:
case ONOT:
p1 = gbranch(AJMP, T);
p2 = pc;
gmove(booltrue, res);
p3 = gbranch(AJMP, T);
patch(p1, pc);
bgen(n, 1, p2);
gmove(boolfalse, res);
patch(p3, pc);
goto ret;
case OPLUS:
cgen(nl, res);
goto ret;
// unary
case OMINUS:
case OCOM:
a = optoas(n->op, nl->type);
goto uop;
// symmetric binary
case OAND:
case OOR:
case OXOR:
case OADD:
case OMUL:
a = optoas(n->op, nl->type);
goto sbop;
// asymmetric binary
case OMOD:
case OSUB:
case ODIV:
case OLSH:
case ORSH:
a = optoas(n->op, nl->type);
goto abop;
case OCONV:
if(eqtype(n->type, nl->type, 0)) {
cgen(nl, res);
break;
}
regalloc(&n1, nl->type, res);
cgen(nl, &n1);
gmove(&n1, res);
regfree(&n1);
break;
// case OINDEXPTRSTR:
// nl = n->left;
// nr = n->right;
// if(nl->addable) {
// cgen(nr);
// cgen(nl);
// gopcode(P_LOADI, T_ADDR, N);
// gopcodet(P_INDEXZ, nr->type, N);
// break;
// }
// break;
// case OINDEXSTR:
// nl = n->left;
// nr = n->right;
// if(nl->addable) {
// cgen(nr);
// gopcodet(P_INDEXZ, nr->type, nl);
// break;
// }
// cgen(nl);
// r = tempname(nl->type);
// gopcodet(P_STORE, nl->type, r);
// cgen(nr);
// gopcodet(P_INDEXZ, nr->type, r);
// break;
// case OSLICESTR:
// case OSLICEPTRSTR:
// nl = n->left; // name
// nr = n->right;
//
// r = nr->right; // index2
// if(!r->addable) {
// cgen(r);
// r = tempname(r->type);
// gopcodet(P_STORE, r->type, r);
// }
//
// // string into T_ADDR
// if(!nl->addable) {
// cgen(nl);
// gconv(T_ADDR, nl->type->etype);
// } else
// gopcode(P_LOAD, T_ADDR, nl);
//
// if(n->op == OSLICEPTRSTR)
// gopcode(P_LOADI, T_ADDR, N);
//
// // offset in int reg
// cgen(nr->left);
//
// // index 2 addressed
// gopcodet(P_SLICE, r->type, r);
// break;
case OS2I:
case OI2I:
case OI2S:
case OINDEXPTR:
case OINDEX:
case ODOT:
case ODOTPTR:
case OIND:
igen(n, &n1, res);
gmove(&n1, res);
regfree(&n1);
break;
case OLEN:
if(isptrto(nl->type, TSTRING)) {
regalloc(&n1, types[tptr], res);
cgen(nl, res);
n1.op = OINDREG;
n1.type = types[TINT32];
gmove(&n1, res);
regfree(&n1);
break;
}
fatal("cgen: OLEN: unknown type %lT", nl->type);
break;
// case ODOTMETH:
// case ODOTINTER:
// cgen(n->left);
// break;
case OADDR:
agen(nl, res);
break;
case OCALLMETH:
cgen_callmeth(n);
cgen_callret(n, res);
break;
case OCALLINTER:
cgen_callinter(n, res);
cgen_callret(n, res);
break;
case OCALL:
cgen_call(n);
cgen_callret(n, res);
break;
}
goto ret;
sbop: // symmetric binary
if(nl->ullman < nr->ullman) {
r = nl;
nl = nr;
nr = r;
}
abop: // asymmetric binary
if(nr->addable) {
regalloc(&n1, nl->type, res);
cgen(nl, &n1);
gins(a, nr, &n1);
gmove(&n1, res);
regfree(&n1);
goto ret;
}
tempname(&tmp, nr->type);
regalloc(&n1, nr->type, res);
cgen(nr, &n1);
gmove(&n1, &tmp);
regfree(&n1);
regalloc(&n1, nl->type, res);
cgen(nl, &n1);
gins(a, &tmp, &n1);
gmove(&n1, res);
regfree(&n1);
goto ret;
uop: // unary
regalloc(&n1, nl->type, res);
cgen(nl, &n1);
gins(a, N, &n1);
gmove(&n1, res);
regfree(&n1);
goto ret;
ret:
dynlineno = lno;
}
void
agen(Node *n, Node *res)
{
Node *nl, *nr;
Node n1, n2, n3, tmp;
ulong w;
Type *t;
if(n == N || n->type == T)
return;
if(!isptr[res->type->etype])
fatal("agen: not tptr: %T", res->type);
if(n->addable) {
regalloc(&n1, types[tptr], res);
gins(ALEAQ, n, &n1);
gmove(&n1, res);
regfree(&n1);
return;
}
switch(n->op) {
default:
fatal("agen: unknown op %N", n);
break;
// case ONAME:
// regalloc(&n1, types[tptr], res);
// gins(optoas(OADDR, types[tptr]), n, &n1);
// gmove(&n1, res);
// regfree(&n1);
// break;
case OINDEXPTR:
nl = n->left;
nr = n->right;
w = n->type->width;
if(nr->addable)
goto iprad;
if(nl->addable) {
regalloc(&n1, nr->type, N);
cgen(nr, &n1);
cgen(nl, res);
goto index;
}
cgen(nr, res);
tempname(&tmp, nr->type);
gmove(res, &tmp);
iprad:
cgen(nl, res);
regalloc(&n1, nr->type, N);
cgen(nr, &n1);
goto index;
case OS2I:
case OI2I:
case OI2S:
agen_inter(n, res);
break;
// case OINDREG:
case OINDEX:
nl = n->left;
nr = n->right;
w = n->type->width;
if(nr->addable)
goto irad;
if(nl->addable) {
regalloc(&n1, nr->type, N);
cgen(nr, &n1);
agen(nl, res);
goto index;
}
cgen(nr, res);
tempname(&tmp, nr->type);
gmove(res, &tmp);
irad:
agen(nl, res);
regalloc(&n1, nr->type, N);
cgen(nr, &n1);
goto index;
index:
// &a is in res
// i is in &n1
// w is width
if(issigned[n1.type->etype]) {
nodconst(&n3, types[TINT64], w); // w/tint64
regalloc(&n2, types[TINT64], &n1); // i/int64
gmove(&n1, &n2);
gins(optoas(OMUL, types[TINT64]), &n3, &n2);
gins(optoas(OADD, types[tptr]), &n2, res);
regfree(&n1);
regfree(&n2);
break;
}
// unsigned multiply is a pain in the ass
fatal("agen: unsigned index");
break;
// case OIND:
// nl = n->left;
// if(nl->addable) {
// gopcode(P_LOAD, T_ADDR, nl);
// break;
// }
// cgen(nl);
// gconv(T_ADDR, nl->type->etype);
// break;
case ODOT:
nl = n->left;
t = nl->type;
agen(nl, res);
if(n->xoffset != 0) {
nodconst(&n1, types[TINT64], n->xoffset);
gins(optoas(OADD, types[tptr]), &n1, res);
}
break;
case ODOTPTR:
nl = n->left;
t = nl->type;
if(!isptr[t->etype])
fatal("agen: not ptr %N", n);
cgen(nl, res);
if(n->xoffset != 0) {
nodconst(&n1, types[TINT64], n->xoffset);
gins(optoas(OADD, types[tptr]), &n1, res);
}
break;
}
}
vlong
fieldoffset(Type *t, Node *n)
{
if(t->etype != TSTRUCT)
fatal("fieldoffset: not struct %lT", t);
if(n->op != ONAME)
fatal("fieldoffset: not field name %N", n);
return 0;
}
void
igen(Node *n, Node *a, Node *res)
{
regalloc(a, types[tptr], res);
agen(n, a);
a->op = OINDREG;
a->type = n->type;
}
void
bgen(Node *n, int true, Prog *to)
{
long lno;
int et, a, b;
Node *nl, *nr, *r;
Node n1, n2, tmp;
Prog *p1, *p2;
if(n == N)
n = booltrue;
lno = dynlineno;
if(n->op != ONAME)
dynlineno = n->lineno; // for diagnostics
if(n->type == T) {
convlit(n, types[TBOOL]);
if(n->type == T)
goto ret;
}
et = n->type->etype;
if(et != TBOOL) {
yyerror("cgen: bad type %T for %O", n->type, n->op);
patch(gins(AEND, N, N), to);
goto ret;
}
nl = N;
nr = N;
switch(n->op) {
default:
regalloc(&n1, n->type, N);
cgen(n, &n1);
nodconst(&n2, n->type, 0);
gins(optoas(OCMP, n->type), &n1, &n2);
a = AJNE;
if(!true)
a = AJEQ;
patch(gbranch(a, n->type), to);
regfree(&n1);
goto ret;
case OLITERAL:
if(!true == !n->val.vval)
patch(gbranch(AJMP, T), to);
goto ret;
case ONAME:
nodconst(&n1, n->type, 0);
gins(optoas(OCMP, n->type), n, &n1);
a = AJNE;
if(!true)
a = AJEQ;
patch(gbranch(a, n->type), to);
goto ret;
case OANDAND:
if(!true)
goto caseor;
caseand:
p1 = gbranch(AJMP, T);
p2 = gbranch(AJMP, T);
patch(p1, pc);
bgen(n->left, !true, p2);
bgen(n->right, !true, p2);
p1 = gbranch(AJMP, T);
patch(p1, to);
patch(p2, pc);
goto ret;
case OOROR:
if(!true)
goto caseand;
caseor:
bgen(n->left, true, to);
bgen(n->right, true, to);
goto ret;
case OEQ:
case ONE:
case OLT:
case OGT:
case OLE:
case OGE:
nr = n->right;
if(nr == N || nr->type == T)
goto ret;
case ONOT: // unary
nl = n->left;
if(nl == N || nl->type == T)
goto ret;
}
switch(n->op) {
case ONOT:
bgen(nl, !true, to);
goto ret;
case OEQ:
case ONE:
case OLT:
case OGT:
case OLE:
case OGE:
a = n->op;
if(!true)
a = brcom(a);
// make simplest on right
if(nl->ullman < nr->ullman) {
a = brrev(a);
r = nl;
nl = nr;
nr = r;
}
a = optoas(a, nr->type);
if(nr->addable) {
regalloc(&n1, nl->type, N);
cgen(nl, &n1);
b = optoas(OCMP, nr->type);
switch(b) {
case ACMPQ:
if(nr->op == OLITERAL)
if(nr->val.vval >= (1LL<<32))
goto dolit;
case AUCOMISS:
if(nr->op == OLITERAL)
goto dolit;
if(nr->op == ONAME)
goto dolit;
}
gins(b, &n1, nr);
patch(gbranch(a, nr->type), to);
regfree(&n1);
break;
dolit:
regalloc(&n2, nr->type, N);
cgen(nr, &n2);
gins(b, &n1, &n2);
patch(gbranch(a, nr->type), to);
regfree(&n2);
regfree(&n1);
break;
}
tempname(&tmp, nr->type);
cgen(nr, &tmp);
regalloc(&n1, nl->type, N);
cgen(nl, &n1);
gins(optoas(OCMP, nr->type), &n1, &tmp);
patch(gbranch(a, nr->type), to);
regfree(&n1);
break;
}
goto ret;
ret:
dynlineno = lno;
}
void
sgen(Node *n, Node *ns, ulong w)
{
Node nodl, nodr;
long c;
if(w == 0)
return;
if(n->ullman >= UINF && ns->ullman >= UINF) {
fatal("sgen UINF");
}
nodreg(&nodl, types[tptr], D_DI);
nodreg(&nodr, types[tptr], D_SI);
if(n->ullman >= ns->ullman) {
agen(n, &nodr);
agen(ns, &nodl);
} else {
agen(ns, &nodl);
agen(n, &nodr);
}
gins(ACLD, N, N); // clear direction flag
c = w / 8;
if(c > 0) {
gconreg(AMOVQ, c, D_CX);
gins(AREP, N, N); // repeat
gins(AMOVSQ, N, N); // MOVQ *(SI)+,*(DI)+
}
c = w % 8;
if(c > 0) {
gconreg(AMOVQ, c, D_CX);
gins(AREP, N, N); // repeat
gins(AMOVSB, N, N); // MOVB *(SI)+,*(DI)+
}
}

820
src/cmd/6g/gen.c Normal file
View file

@ -0,0 +1,820 @@
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
#undef EXTERN
#define EXTERN
#include "gg.h"
enum
{
// random unused opcode
AJMPX = AADDPD,
};
static Node* curfn;
void
compile(Node *fn)
{
Plist *pl;
Node nod1;
Prog *ptxt;
if(fn->nbody == N)
return;
curfn = fn;
dowidth(curfn->type);
if(nerrors != 0) {
walk(curfn);
return;
}
if(debug['w'])
dump("--- pre walk ---", curfn->nbody);
maxarg = 0;
stksize = 0;
walk(curfn);
if(nerrors != 0)
return;
if(debug['w'])
dump("--- post walk ---", curfn->nbody);
allocparams();
continpc = P;
breakpc = P;
pl = newplist();
pl->name = curfn->nname;
pl->locals = autodcl;
nodconst(&nod1, types[TINT32], 0);
ptxt = gins(ATEXT, curfn->nname, &nod1);
// inarggen();
ginit();
gen(curfn->nbody);
gclean();
// if(curfn->type->outtuple != 0)
// gins(AGOK, N, N);
pc->as = ARET; // overwrite AEND
// fill in final stack size
ptxt->to.offset = rnd(stksize+maxarg, maxround);
if(debug['f'])
frame(0);
}
void
allocparams(void)
{
Dcl *d;
Iter list;
Type *t;
Node *n;
ulong w;
/*
* allocate (set xoffset) the stack
* slots for this, inargs, outargs
* these are allocated positavely
* from 0 up.
* note that this uses the 'width'
* field, which, in the OFIELD of the
* parameters, is the offset in the
* parameter list.
*/
d = autodcl;
t = funcfirst(&list, curfn->type);
while(t != T) {
if(d == D)
fatal("allocparams: this nil");
if(d->op != ONAME) {
d = d->forw;
continue;
}
n = d->dnode;
if(n->class != PPARAM)
fatal("allocparams: this class");
n->xoffset = t->width;
d = d->forw;
t = funcnext(&list);
}
/*
* allocate (set xoffset) the stack
* slots for all automatics.
* allocated starting at -w down.
*/
for(d=autodcl; d!=D; d=d->forw) {
if(d->op != ONAME)
continue;
n = d->dnode;
if(n->class != PAUTO)
continue;
dowidth(n->type);
w = n->type->width;
stksize += w;
stksize = rnd(stksize, w);
n->xoffset = -stksize;
}
}
/*
* compile statements
*/
void
gen(Node *n)
{
long lno;
Prog *scontin, *sbreak;
Prog *p1, *p2, *p3;
Sym *s;
lno = dynlineno;
loop:
if(n == N)
goto ret;
dynlineno = n->lineno; // for diagnostics
switch(n->op) {
default:
fatal("gen: unknown op %N", n);
break;
case OLIST:
gen(n->left);
n = n->right;
goto loop;
case OPANIC:
genpanic();
break;
case OCASE:
case OFALL:
case OXCASE:
case OXFALL:
case OEMPTY:
break;
case OLABEL:
// before declaration, s->label points at
// a link list of PXGOTO instructions.
// after declaration, s->label points
// at a AJMP to .+1
s = n->left->sym;
p1 = (Prog*)s->label;
if(p1 != P) {
if(p1->as == AJMP) {
yyerror("label redeclared: %S", s);
break;
}
while(p1 != P) {
if(p1->as != AJMPX)
fatal("bad label pointer: %S", s);
p1->as = AJMP;
p2 = p1->to.branch;
patch(p1, pc);
p1 = p2;
}
}
s->label = pc;
p1 = gbranch(AJMP, T);
patch(p1, pc);
break;
case OGOTO:
s = n->left->sym;
p1 = (Prog*)s->label;
if(p1 != P && p1->as == AJMP) {
// already declared
p2 = gbranch(AJMP, T);
patch(p2, p1->to.branch);
break;
}
// link thru to.branch
p2 = gbranch(AJMPX, T);
p2->to.branch = p1;
s->label = p2;
break;
case OBREAK:
if(breakpc == P) {
yyerror("gen: break is not in a loop");
break;
}
patch(gbranch(AJMP, T), breakpc);
break;
case OCONTINUE:
if(continpc == P) {
yyerror("gen: continue is not in a loop");
break;
}
patch(gbranch(AJMP, T), continpc);
break;
case OFOR:
gen(n->ninit); // init
p1 = gbranch(AJMP, T); // goto test
sbreak = breakpc;
breakpc = gbranch(AJMP, T); // break: goto done
scontin = continpc;
continpc = pc;
gen(n->nincr); // contin: incr
patch(p1, pc); // test:
bgen(n->ntest, 0, breakpc); // if(!test) goto break
gen(n->nbody); // body
patch(gbranch(AJMP, T), continpc); // goto contin
patch(breakpc, pc); // done:
continpc = scontin;
breakpc = sbreak;
break;
case OIF:
gen(n->ninit); // init
p1 = gbranch(AJMP, T); // goto test
p2 = gbranch(AJMP, T); // p2: goto else
patch(p1, pc); // test:
bgen(n->ntest, 0, p2); // if(!test) goto p2
gen(n->nbody); // then
p3 = gbranch(AJMP, T); // goto done
patch(p2, pc); // else:
gen(n->nelse); // else
patch(p3, pc); // done:
break;
case OSWITCH:
gen(n->ninit); // init
p1 = gbranch(AJMP, T); // goto test
sbreak = breakpc;
breakpc = gbranch(AJMP, T); // break: goto done
patch(p1, pc); // test:
swgen(n); // switch(test) body
patch(breakpc, pc); // done:
breakpc = sbreak;
break;
case OASOP:
cgen_asop(n->left, n->right, n->etype);
break;
case OAS:
cgen_as(n->left, n->right, n->op);
break;
case OCALLMETH:
cgen_callmeth(n);
break;
case OCALLINTER:
cgen_callinter(n, N);
break;
case OCALL:
cgen_call(n);
break;
case ORETURN:
cgen_ret(n);
break;
}
ret:
dynlineno = lno;
}
void
agen_inter(Node *n, Node *res)
{
Node nodo, nodr, nodt;
Sym *s;
char *e;
long o;
// stack offset
memset(&nodo, 0, sizeof(nodo));
nodo.op = OINDREG;
nodo.val.vval = D_SP;
nodo.addable = 1;
nodo.type = types[tptr];
// pointer register
regalloc(&nodr, types[tptr], res);
switch(n->op) {
default:
fatal("agen_inter %O\n", n->op);
case OS2I:
// ifaces2i(*sigi, *sigs, i.map, i.s)
// i.s is input
// (i.map, i.s) is output
cgen(n->left, &nodr);
nodo.xoffset = 3*widthptr;
cgen_as(&nodo, &nodr, 0);
nodtypesig(&nodt, n->type);
agen(&nodt, &nodr);
nodo.xoffset = 0*widthptr;
cgen_as(&nodo, &nodr, 0);
nodtypesig(&nodt, n->left->type);
agen(&nodt, &nodr);
nodo.xoffset = 1*widthptr;
cgen_as(&nodo, &nodr, 0);
e = "ifaces2i";
if(maxarg < 4*widthptr)
maxarg = 4*widthptr;
o = 2*widthptr;
break;
case OI2I:
// ifacei2i(*sigi, i.map, i.s)
// (i.map, i.s) is input
// (i.map, i.s) is output
nodo.xoffset = 1*widthptr;
if(!n->left->addable) {
agen(n->left, &nodr);
gmove(&nodr, &nodo);
fatal("agen_inter i2i");
} else {
cgen(n->left, &nodo);
}
nodtypesig(&nodt, n->type);
agen(&nodt, &nodr);
nodo.xoffset = 0*widthptr;
cgen_as(&nodo, &nodr, 0);
e = "ifacei2i";
if(maxarg < 3*widthptr)
maxarg = 3*widthptr;
o = 1*widthptr;
break;
case OI2S:
// ifacei2s(*sigs, i.map, i.s)
// (i.map, i.s) is input
// i.s is output
nodo.xoffset = 1*widthptr;
if(!n->left->addable) {
agen(n->left, &nodr);
gmove(&nodr, &nodo);
fatal("agen_inter i2s");
} else
gmove(n->left, &nodo);
nodtypesig(&nodt, n->type);
agen(&nodt, &nodr);
nodo.xoffset = 0*widthptr;
cgen_as(&nodo, &nodr, 0);
e = "ifacei2s";
if(maxarg < 3*widthptr)
maxarg = 3*widthptr;
o = 2*widthptr;
break;
}
s = pkglookup(e, "sys");
if(s->oname == N) {
s->oname = newname(s);
s->oname->class = PEXTERN;
}
gins(ACALL, N, s->oname);
nodo.xoffset = o;
gins(ALEAQ, &nodo, res);
regfree(&nodr);
}
void
swgen(Node *n)
{
Node *c1, *c2;
Node n1, tmp;
Case *s0, *se, *s;
Prog *p1, *dflt;
long lno;
int any;
Iter save1, save2;
// botch - put most of this code in
// walk. gen binary search for
// sequence of constant cases
lno = dynlineno;
p1 = gbranch(AJMP, T);
s0 = C;
se = C;
// walk thru the body placing breaks
// and labels into the case statements
any = 0;
dflt = P;
c1 = listfirst(&save1, &n->nbody);
while(c1 != N) {
dynlineno = c1->lineno; // for diagnostics
if(c1->op != OCASE) {
if(s0 == C)
yyerror("unreachable statements in a switch");
gen(c1);
any = 1;
if(c1->op == OFALL)
any = 0;
c1 = listnext(&save1);
continue;
}
// put in the break between cases
if(any) {
patch(gbranch(AJMP, T), breakpc);
any = 0;
}
// over case expressions
c2 = listfirst(&save2, &c1->left);
if(c2 == N)
dflt = pc;
while(c2 != N) {
s = mal(sizeof(*s));
if(s0 == C)
s0 = s;
else
se->slink = s;
se = s;
s->scase = c2; // case expression
s->sprog = pc; // where to go
c2 = listnext(&save2);
}
c1 = listnext(&save1);
}
if(any)
patch(gbranch(AJMP, T), breakpc);
patch(p1, pc);
tempname(&tmp, n->ntest->type);
cgen(n->ntest, &tmp);
for(s=s0; s!=C; s=s->slink) {
memset(&n1, 0, sizeof(n1));
n1.op = OEQ;
n1.left = &tmp;
n1.right = s->scase;
walktype(&n1, 0);
bgen(&n1, 1, s->sprog);
}
if(dflt != P) {
patch(gbranch(AJMP, T), dflt);
goto ret;
}
patch(gbranch(AJMP, T), breakpc);
ret:
dynlineno = lno;
}
void
inarggen(void)
{
fatal("inarggen");
}
void
genpanic(void)
{
Node n1, n2;
Prog *p;
nodconst(&n1, types[TINT64], 0xf0);
nodreg(&n2, types[TINT64], D_AX);
gins(AMOVL, &n1, &n2);
p = pc;
gins(AMOVQ, &n2, N);
p->to.type = D_INDIR+D_AX;
}
void
cgen_callinter(Node *n, Node *res)
{
Node *i, *f;
Node tmpi, nodo, nodr, nodsp;
i = n->left;
if(i->op != ODOTINTER)
fatal("cgen_callinter: not ODOTINTER %O", i->op);
f = i->right; // field
if(f->op != ONAME)
fatal("cgen_callinter: not ONAME %O", f->op);
i = i->left; // interface
if(!i->addable) {
tempname(&tmpi, i->type);
cgen(i, &tmpi);
i = &tmpi;
}
gen(n->right); // args
regalloc(&nodr, types[tptr], res);
regalloc(&nodo, types[tptr], &nodr);
nodo.op = OINDREG;
agen(i, &nodr); // REG = &inter
nodindreg(&nodsp, types[tptr], D_SP);
nodo.xoffset += widthptr;
cgen(&nodo, &nodsp); // 0(SP) = 8(REG) -- i.s
nodo.xoffset -= widthptr;
cgen(&nodo, &nodr); // REG = 0(REG) -- i.m
//print("field = %N\n", f);
//print("offset = %ld\n", n->left->xoffset);
nodo.xoffset = n->left->xoffset + 4*widthptr;
cgen(&nodo, &nodr); // REG = 32+offset(REG) -- i.m->fun[f]
gins(ACALL, N, &nodr);
regfree(&nodr);
regfree(&nodr);
setmaxarg(n->left->type);
}
void
cgen_callmeth(Node *n)
{
Node *l;
// generate a rewrite for method call
// (p.f)(...) goes to (f)(p,...)
l = n->left;
n->op = OCALL;
n->left = n->left->right;
n->left->type = l->type;
if(n->left->op == ONAME)
n->left->class = PEXTERN;
cgen_call(n);
}
void
cgen_call(Node *n)
{
Type *t;
Node nod, afun;
if(n == N)
return;
if(n->left->ullman >= UINF) {
// if name involves a fn call
// precompute the address of the fn
tempname(&afun, types[tptr]);
if(isptr[n->left->type->etype])
cgen(n->left, &afun);
else
agen(n->left, &afun);
}
gen(n->right); // assign the args
t = n->left->type;
if(isptr[t->etype])
t = t->type;
setmaxarg(t);
// call tempname pointer
if(n->left->ullman >= UINF) {
regalloc(&nod, types[tptr], N);
cgen_as(&nod, &afun, 0);
gins(ACALL, N, &nod);
regfree(&nod);
return;
}
// call pointer
if(isptr[n->left->type->etype]) {
regalloc(&nod, types[tptr], N);
cgen_as(&nod, n->left, 0);
gins(ACALL, N, &nod);
regfree(&nod);
return;
}
// call direct
gins(ACALL, N, n->left);
}
void
cgen_callret(Node *n, Node *res)
{
Node nod;
Type *fp, *t;
Iter flist;
t = n->left->type;
if(t->etype == TPTR32 || t->etype == TPTR64)
t = t->type;
fp = structfirst(&flist, getoutarg(t));
if(fp == T)
fatal("cgen_callret: nil");
memset(&nod, 0, sizeof(nod));
nod.op = OINDREG;
nod.val.vval = D_SP;
nod.addable = 1;
nod.xoffset = fp->width;
nod.type = fp->type;
cgen_as(res, &nod, 0);
}
void
cgen_ret(Node *n)
{
gen(n->left); // copy out args
gins(ARET, N, N);
}
void
cgen_asop(Node *nl, Node *nr, int op)
{
Node n1, n2;
int a;
// botch compare ullman numbers
// and use temp for functions
a = optoas(op, nl->type);
regalloc(&n1, nl->type, N);
if(nl->addable) {
cgen(nr, &n1);
gins(a, nl, &n1);
gmove(&n1, nl);
regfree(&n1);
return;
}
igen(nl, &n2, N);
cgen(nr, &n1);
gins(a, &n2, &n1);
gmove(&n1, &n2);
regfree(&n1);
regfree(&n2);
}
void
cgen_as(Node *nl, Node *nr, int op)
{
Node nc, n1;
Type *tl;
ulong w, c;
if(nl == N)
return;
tl = nl->type;
if(tl == T)
return;
if(nr == N) {
if(isfat(tl)) {
/* clear a fat object */
if(debug['g'])
dump("\nclearfat", nl);
w = nl->type->width;
if(w > 0)
gconreg(AMOVQ, 0, D_AX);
if(w > 0) {
nodreg(&n1, types[tptr], D_DI);
agen(nl, &n1);
gins(ACLD, N, N); // clear direction flag
}
c = w / 8;
if(c > 0) {
gconreg(AMOVQ, c, D_CX);
gins(AREP, N, N); // repeat
gins(ASTOSQ, N, N); // STOQ AL,*(DI)+
}
c = w % 8;
if(c > 0) {
gconreg(AMOVQ, c, D_CX);
gins(AREP, N, N); // repeat
gins(ASTOSB, N, N); // STOB AL,*(DI)+
}
return;
}
/* invent a "zero" for the rhs */
nr = &nc;
memset(nr, 0, sizeof(*nr));
switch(tl->etype) {
default:
fatal("cgen_as: tl %T", tl);
break;
case TINT8:
case TUINT8:
case TINT16:
case TUINT16:
case TINT32:
case TUINT32:
case TINT64:
case TUINT64:
nr->val.ctype = CTINT;
nr->val.vval = 0;
break;
case TFLOAT32:
case TFLOAT64:
case TFLOAT80:
nr->val.ctype = CTFLT;
nr->val.dval = 0.0;
break;
case TBOOL:
nr->val.ctype = CTBOOL;
nr->val.vval = 0;
break;
case TPTR32:
case TPTR64:
if(isptrto(nl->type, TSTRING)) {
nr->val.ctype = CTSTR;
nr->val.sval = &emptystring;
break;
}
nr->val.ctype = CTNIL;
nr->val.vval = 0;
break;
// case TINTER:
// nodreg(&n1, types[tptr], D_DI);
// agen(nl, &n1);
// n1.op = OINDREG;
//
// nodreg(&nc, types[tptr], D_AX);
// gconreg(AMOVQ, 0, D_AX);
//
// gins(AMOVQ, &nc, &n1);
// n1.xoffset += widthptr;
// gins(AMOVQ, &nc, &n1);
// return;
}
nr->op = OLITERAL;
nr->type = tl;
nr->addable = 1;
ullmancalc(nr);
}
cgen(nr, nl);
}

203
src/cmd/6g/gg.h Normal file
View file

@ -0,0 +1,203 @@
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
#include <u.h>
#include <libc.h>
#include "../gc/go.h"
#include "../6l/6.out.h"
#ifndef EXTERN
#define EXTERN extern
#endif
typedef struct Prog Prog;
typedef struct Addr Addr;
struct Addr
{
vlong offset;
double dval;
Prog* branch;
char sval[NSNAME];
Sym* sym;
uchar type;
uchar index;
uchar etype;
uchar scale; /* doubles as width in DATA op */
};
#define A ((Addr*)0)
struct Prog
{
short as; // opcode
ulong loc; // pc offset in this func
ulong lineno; // source line that generated this
Addr from; // src address
Addr to; // dst address
Prog* link; // next instruction in this func
};
#define P ((Prog*)0)
typedef struct Plist Plist;
struct Plist
{
Node* name;
Dcl* locals;
Prog* firstpc;
int recur;
Plist* link;
};
typedef struct Sig Sig;
struct Sig
{
char* name;
Sym* sym;
ulong hash;
long offset;
Sig* link;
};
typedef struct Case Case;
struct Case
{
Prog* sprog;
Node* scase;
Case* slink;
};
#define C ((Case*)0)
typedef struct Pool Pool;
struct Pool
{
String* sval;
Pool* link;
};
EXTERN Prog* continpc;
EXTERN Prog* breakpc;
EXTERN Prog* pc;
EXTERN Prog* firstpc;
EXTERN Plist* plist;
EXTERN Plist* plast;
EXTERN Pool* poolist;
EXTERN Pool* poolast;
EXTERN Biobuf* bout;
EXTERN long dynloc;
EXTERN uchar reg[D_NONE];
EXTERN ushort txt[NTYPE*NTYPE];
EXTERN long maxround;
EXTERN long widthptr;
EXTERN long maxarg;
EXTERN long stksize;
EXTERN Sym* symstringo; // string objects
EXTERN long stringo; // size of string objects
EXTERN long pcloc; // instruction counter
EXTERN String emptystring;
extern char* anames[];
/*
* gen.c
*/
void compile(Node*);
void proglist(void);
void gen(Node*);
void swgen(Node*);
Node* lookdot(Node*, Node*, int);
void inarggen(void);
void agen_inter(Node*, Node*);
void cgen_as(Node*, Node*, int);
void cgen_asop(Node*, Node*, int);
void cgen_ret(Node*);
void cgen_call(Node*);
void cgen_callmeth(Node*);
void cgen_callinter(Node*, Node*);
void cgen_callret(Node*, Node*);
void genpanic(void);
int needconvert(Type*, Type*);
void genconv(Type*, Type*);
void allocparams(void);
/*
* cgen
*/
void cgen(Node*, Node*);
void agen(Node*, Node*);
void igen(Node*, Node*, Node*);
vlong fieldoffset(Type*, Node*);
void bgen(Node*, int, Prog*);
void sgen(Node*, Node*, ulong);
void gmove(Node*, Node*);
Prog* gins(int, Node*, Node*);
int samaddr(Node*, Node*);
void naddr(Node*, Addr*);
/*
* gsubr.c
*/
void clearp(Prog*);
void proglist(void);
Prog* gbranch(int, Type*);
void patch(Prog*, Prog*);
Prog* prog(int);
void gaddoffset(Node*);
void gconv(int, int);
int conv2pt(Type*);
void belexinit(int);
vlong convvtox(vlong, int);
int brcom(int);
int brrev(int);
void fnparam(Type*, int, int);
Sig* lsort(Sig*, int(*)(Sig*, Sig*));
Prog* gop(int, Node*, Node*, Node*);
void setconst(Addr*, vlong);
void setaddr(Addr*, Node*);
int optoas(int, Type*);
void ginit(void);
void gclean(void);
void regalloc(Node*, Type*, Node*);
void regfree(Node*);
void regsalloc(Node*, Type*); // replace w tmpvar
void regret(Node*, Type*);
Node* nodarg(Type*, int);
void nodreg(Node*, Type*, int);
void nodindreg(Node*, Type*, int);
void nodconst(Node*, Type*, vlong);
Sym* signame(Type*);
void nodtypesig(Node*, Type*);
void gconreg(int, vlong, int);
void buildtxt(void);
void stringpool(Node*);
void tempname(Node*, Type*);
Plist* newplist(void);
int isfat(Type*);
void setmaxarg(Type*);
/*
* list.c
*/
int Aconv(Fmt*);
int Dconv(Fmt*);
int Pconv(Fmt*);
int Rconv(Fmt*);
int Yconv(Fmt*);
void listinit(void);
/*
* obj
*/
void zname(Biobuf*, Sym*, int);
void zaddr(Biobuf*, Addr*, int);
void ieeedtod(Ieee*, double);
void dumpstrings(void);
void dumpsignatures(void);
/*
* align
*/
void dowidth(Type*);
ulong rnd(ulong, ulong);

1649
src/cmd/6g/gsubr.c Normal file

File diff suppressed because it is too large Load diff

336
src/cmd/6g/list.c Normal file
View file

@ -0,0 +1,336 @@
// Derived from Inferno utils/6c/list.c
// http://code.google.com/p/inferno-os/source/browse/utils/6c/list.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.
#include "gg.h"
static int sconsize;
void
listinit(void)
{
fmtinstall('A', Aconv); // as
fmtinstall('P', Pconv); // Prog*
fmtinstall('D', Dconv); // Addr*
fmtinstall('R', Rconv); // reg
fmtinstall('Y', Yconv); // sconst
}
int
Pconv(Fmt *fp)
{
char str[STRINGSZ];
Prog *p;
p = va_arg(fp->args, Prog*);
sconsize = 8;
if(p->as == ADATA) {
sconsize = p->from.scale;
snprint(str, sizeof(str), "%.4ld %-7A %D/%d,%D",
p->loc, p->as, &p->from, sconsize, &p->to);
return fmtstrcpy(fp, str);
}
snprint(str, sizeof(str), "%.4ld %-7A %D,%D",
p->loc, p->as, &p->from, &p->to);
return fmtstrcpy(fp, str);
}
int
Dconv(Fmt *fp)
{
char str[40], s[20];
Addr *a;
int i;
a = va_arg(fp->args, Addr*);
i = a->type;
if(i >= D_INDIR) {
if(a->offset)
sprint(str, "%lld(%R)", a->offset, i-D_INDIR);
else
sprint(str, "(%R)", i-D_INDIR);
goto brk;
}
switch(i) {
default:
if(a->offset)
sprint(str, "$%lld,%R", a->offset, i);
else
sprint(str, "%R", i);
break;
case D_NONE:
str[0] = 0;
break;
case D_BRANCH:
snprint(str, sizeof(str), "%ld", a->branch->loc);
break;
case D_EXTERN:
sprint(str, "%S+%lld(SB)", a->sym, a->offset);
break;
case D_STATIC:
sprint(str, "%S<>+%lld(SB)", a->sym, a->offset);
break;
case D_AUTO:
sprint(str, "%S+%lld(SP)", a->sym, a->offset);
break;
case D_PARAM:
sprint(str, "%S+%lld(FP)", a->sym, a->offset);
break;
case D_CONST:
sprint(str, "$%lld", a->offset);
break;
case D_FCONST:
sprint(str, "$(%.17e)", a->dval);
break;
case D_SCONST:
sprint(str, "$\"%Y\"", a->sval);
break;
case D_ADDR:
a->type = a->index;
a->index = D_NONE;
sprint(str, "$%D", a);
a->index = a->type;
a->type = D_ADDR;
goto conv;
}
brk:
if(a->index != D_NONE) {
sprint(s, "(%R*%d)", (int)a->index, (int)a->scale);
strcat(str, s);
}
conv:
return fmtstrcpy(fp, str);
}
static char* regstr[] =
{
"AL", /* [D_AL] */
"CL",
"DL",
"BL",
"SPB",
"BPB",
"SIB",
"DIB",
"R8B",
"R9B",
"R10B",
"R11B",
"R12B",
"R13B",
"R14B",
"R15B",
"AX", /* [D_AX] */
"CX",
"DX",
"BX",
"SP",
"BP",
"SI",
"DI",
"R8",
"R9",
"R10",
"R11",
"R12",
"R13",
"R14",
"R15",
"AH",
"CH",
"DH",
"BH",
"F0", /* [D_F0] */
"F1",
"F2",
"F3",
"F4",
"F5",
"F6",
"F7",
"M0",
"M1",
"M2",
"M3",
"M4",
"M5",
"M6",
"M7",
"X0",
"X1",
"X2",
"X3",
"X4",
"X5",
"X6",
"X7",
"X8",
"X9",
"X10",
"X11",
"X12",
"X13",
"X14",
"X15",
"CS", /* [D_CS] */
"SS",
"DS",
"ES",
"FS",
"GS",
"GDTR", /* [D_GDTR] */
"IDTR", /* [D_IDTR] */
"LDTR", /* [D_LDTR] */
"MSW", /* [D_MSW] */
"TASK", /* [D_TASK] */
"CR0", /* [D_CR] */
"CR1",
"CR2",
"CR3",
"CR4",
"CR5",
"CR6",
"CR7",
"CR8",
"CR9",
"CR10",
"CR11",
"CR12",
"CR13",
"CR14",
"CR15",
"DR0", /* [D_DR] */
"DR1",
"DR2",
"DR3",
"DR4",
"DR5",
"DR6",
"DR7",
"TR0", /* [D_TR] */
"TR1",
"TR2",
"TR3",
"TR4",
"TR5",
"TR6",
"TR7",
"NONE", /* [D_NONE] */
};
int
Rconv(Fmt *fp)
{
char str[STRINGSZ];
int r;
r = va_arg(fp->args, int);
if(r < 0 || r >= nelem(regstr) || regstr[r] == nil) {
snprint(str, sizeof(str), "BAD_R(%d)", r);
return fmtstrcpy(fp, str);
}
return fmtstrcpy(fp, regstr[r]);
}
int
Aconv(Fmt *fp)
{
int i;
i = va_arg(fp->args, int);
return fmtstrcpy(fp, anames[i]);
}
int
Yconv(Fmt *fp)
{
int i, c;
char str[30], *p, *a;
a = va_arg(fp->args, char*);
p = str;
for(i=0; i<sconsize; i++) {
c = a[i] & 0xff;
if(c >= 'a' && c <= 'z' ||
c >= 'A' && c <= 'Z' ||
c >= '0' && c <= '9') {
*p++ = c;
continue;
}
*p++ = '\\';
switch(c) {
default:
if(c < 040 || c >= 0177)
break; /* not portable */
p[-1] = c;
continue;
case 0:
*p++ = 'z';
continue;
case '\\':
case '"':
*p++ = c;
continue;
case '\n':
*p++ = 'n';
continue;
case '\t':
*p++ = 't';
continue;
}
*p++ = (c>>6) + '0';
*p++ = ((c>>3) & 7) + '0';
*p++ = (c & 7) + '0';
}
*p = 0;
return fmtstrcpy(fp, str);
}

604
src/cmd/6g/obj.c Normal file
View file

@ -0,0 +1,604 @@
// Derived from Inferno utils/6c/swt.c
// http://code.google.com/p/inferno-os/source/browse/utils/6c/swt.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.
#include "gg.h"
void
dumpobj(void)
{
Plist *pl;
Prog *p;
Dcl *d;
Sym *s;
Node *n;
struct { Sym *sym; short type; } h[NSYM];
int sf, st, t, sym;
Node n1;
// add nil plist w AEND
newplist();
bout = Bopen(outfile, OWRITE);
if(bout == nil)
fatal("cant open %s", outfile);
Bprint(bout, "x86-64\n");
Bprint(bout, " exports automatically generated from\n");
Bprint(bout, " %s in package \"%s\"\n", curio.infile, package);
dumpexport();
Bprint(bout, "\n!\n");
// add globals
nodconst(&n1, types[TINT32], 0);
for(d=externdcl; d!=D; d=d->forw) {
if(d->op != ONAME)
continue;
s = d->dsym;
if(s == S)
fatal("external nil");
n = d->dnode;
if(n == N || n->type == T)
fatal("external %S nil\n", s);
if(n->type->etype == TFUNC)
continue;
dowidth(n->type);
n1.val.vval = n->type->width;
p = pc;
gins(AGLOBL, s->oname, &n1);
p->lineno = s->oname->lineno;
}
dumpstrings();
dumpsignatures();
for(sym=0; sym<NSYM; sym++) {
h[sym].sym = S;
h[sym].type = 0;
}
sym = 1;
// put out functions
for(pl=plist; pl!=nil; pl=pl->link) {
if(debug['S']) {
s = S;
if(pl->name != N)
s = pl->name->sym;
print("\n--- prog list \"%S\" ---\n", s);
for(p=pl->firstpc; p!=P; p=p->link)
print("%P\n", p);
}
for(p=pl->firstpc; p!=P; p=p->link) {
jackpot:
sf = 0;
s = p->from.sym;
while(s != S) {
sf = s->sym;
if(sf < 0 || sf >= NSYM)
sf = 0;
t = p->from.type;
if(t == D_ADDR)
t = p->from.index;
if(h[sf].type == t)
if(h[sf].sym == s)
break;
s->sym = sym;
zname(bout, s, t);
h[sym].sym = s;
h[sym].type = t;
sf = sym;
sym++;
if(sym >= NSYM)
sym = 1;
break;
}
st = 0;
s = p->to.sym;
while(s != S) {
st = s->sym;
if(st < 0 || st >= NSYM)
st = 0;
t = p->to.type;
if(t == D_ADDR)
t = p->to.index;
if(h[st].type == t)
if(h[st].sym == s)
break;
s->sym = sym;
zname(bout, s, t);
h[sym].sym = s;
h[sym].type = t;
st = sym;
sym++;
if(sym >= NSYM)
sym = 1;
if(st == sf)
goto jackpot;
break;
}
Bputc(bout, p->as);
Bputc(bout, p->as>>8);
Bputc(bout, p->lineno);
Bputc(bout, p->lineno>>8);
Bputc(bout, p->lineno>>16);
Bputc(bout, p->lineno>>24);
zaddr(bout, &p->from, sf);
zaddr(bout, &p->to, st);
}
}
}
void
zname(Biobuf *b, Sym *s, int t)
{
char *n;
Bputc(b, ANAME); /* as */
Bputc(b, ANAME>>8); /* as */
Bputc(b, t); /* type */
Bputc(b, s->sym); /* sym */
for(n=s->opackage; *n; n++)
Bputc(b, *n);
Bputc(b, '_');
for(n=s->name; *n; n++)
Bputc(b, *n);
Bputc(b, 0);
}
void
zaddr(Biobuf *b, Addr *a, int s)
{
long l;
int i, t;
char *n;
Ieee e;
t = 0;
if(a->index != D_NONE || a->scale != 0)
t |= T_INDEX;
if(s != 0)
t |= T_SYM;
switch(a->type) {
default:
t |= T_TYPE;
case D_NONE:
if(a->offset != 0) {
t |= T_OFFSET;
l = a->offset;
if((vlong)l != a->offset)
t |= T_64;
}
break;
case D_FCONST:
t |= T_FCONST;
break;
case D_SCONST:
t |= T_SCONST;
break;
}
Bputc(b, t);
if(t & T_INDEX) { /* implies index, scale */
Bputc(b, a->index);
Bputc(b, a->scale);
}
if(t & T_OFFSET) { /* implies offset */
l = a->offset;
Bputc(b, l);
Bputc(b, l>>8);
Bputc(b, l>>16);
Bputc(b, l>>24);
if(t & T_64) {
l = a->offset>>32;
Bputc(b, l);
Bputc(b, l>>8);
Bputc(b, l>>16);
Bputc(b, l>>24);
}
}
if(t & T_SYM) /* implies sym */
Bputc(b, s);
if(t & T_FCONST) {
ieeedtod(&e, a->dval);
l = e.l;
Bputc(b, l);
Bputc(b, l>>8);
Bputc(b, l>>16);
Bputc(b, l>>24);
l = e.h;
Bputc(b, l);
Bputc(b, l>>8);
Bputc(b, l>>16);
Bputc(b, l>>24);
return;
}
if(t & T_SCONST) {
n = a->sval;
for(i=0; i<NSNAME; i++) {
Bputc(b, *n);
n++;
}
return;
}
if(t & T_TYPE)
Bputc(b, a->type);
}
void
ieeedtod(Ieee *ieee, double native)
{
double fr, ho, f;
int exp;
if(native < 0) {
ieeedtod(ieee, -native);
ieee->h |= 0x80000000L;
return;
}
if(native == 0) {
ieee->l = 0;
ieee->h = 0;
return;
}
fr = frexp(native, &exp);
f = 2097152L; /* shouldnt use fp constants here */
fr = modf(fr*f, &ho);
ieee->h = ho;
ieee->h &= 0xfffffL;
ieee->h |= (exp+1022L) << 20;
f = 65536L;
fr = modf(fr*f, &ho);
ieee->l = ho;
ieee->l <<= 16;
ieee->l |= (long)(fr*f);
}
void
datastring(char *s, int len)
{
int w;
Prog *p;
Addr ac, ao;
// string
memset(&ao, 0, sizeof(ao));
ao.type = D_STATIC;
ao.index = D_NONE;
ao.etype = TINT32;
ao.sym = symstringo;
ao.offset = 0; // fill in
// constant
memset(&ac, 0, sizeof(ac));
ac.type = D_CONST;
ac.index = D_NONE;
ac.offset = 0; // fill in
for(w=0; w<len; w+=8) {
p = pc;
gins(ADATA, N, N);
// .stringo<>+oo, [NSNAME], $"xxx"
p->from = ao;
p->from.offset = stringo;
p->from.scale = NSNAME;
if(w+8 > len)
p->from.scale = len-w;
p->to = ac;
p->to.type = D_SCONST;
p->to.offset = len;
memmove(p->to.sval, s+w, p->from.scale);
stringo += p->from.scale;
}
}
void
dumpstrings(void)
{
Pool *l;
Prog *p;
Addr ac, ao;
long wi;
if(poolist == nil)
return;
memset(&ac, 0, sizeof(ac));
memset(&ao, 0, sizeof(ao));
// constant
ac.type = D_CONST;
ac.index = D_NONE;
ac.offset = 0; // fill in
// string len+ptr
ao.type = D_STATIC;
ao.index = D_NONE;
ao.etype = TINT32;
ao.sym = symstringo;
ao.offset = 0; // fill in
wi = types[TINT32]->width;
// lay out (count+string)
for(l=poolist; l!=nil; l=l->link) {
p = pc;
gins(ADATA, N, N);
// .stringo<>+xx, wi, $len
stringo = rnd(stringo, wi);
p->from = ao;
p->from.offset = stringo;
p->from.scale = wi;
p->to = ac;
p->to.offset = l->sval->len;
stringo += wi;
datastring(l->sval->s, l->sval->len);
}
}
static int
sigcmp(Sig *a, Sig *b)
{
return strcmp(a->name, b->name);
}
void
dumpsignatures(void)
{
Dcl *d;
Type *t, *f;
Sym *s1, *s;
int et, o, wi, ot;
Sig *a, *b;
Addr at, ao, ac, ad;
Prog *p;
char *sp;
/*
* put all the names into a linked
* list so that it may be generated in sorted order.
* the runtime will be linear rather than quadradic
*/
memset(&at, 0, sizeof(at));
memset(&ao, 0, sizeof(ao));
memset(&ac, 0, sizeof(ac));
memset(&ad, 0, sizeof(ad));
// sig structure
at.type = D_EXTERN;
at.index = D_NONE;
at.sym = S; // fill in
at.offset = 0; // fill in
// $string
ao.type = D_ADDR;
ao.index = D_STATIC;
ao.etype = TINT32;
ao.sym = symstringo;
ao.offset = 0; // fill in
// constant
ac.type = D_CONST;
ac.index = D_NONE;
ac.offset = 0; // fill in
// $method
ad.type = D_ADDR;
ad.index = D_EXTERN;
ad.sym = S; // fill in
ad.offset = 0;
wi = types[TINT32]->width;
for(d=externdcl; d!=D; d=d->forw) {
if(d->op != OTYPE)
continue;
t = d->dtype;
et = t->etype;
if(et != TSTRUCT && et != TINTER)
continue;
s = d->dsym;
if(s == S)
continue;
if(s->name[0] == '_')
continue;
if(strcmp(s->opackage, package) != 0)
continue;
at.sym = signame(t);
a = nil;
o = 0;
for(f=t->type; f!=T; f=f->down) {
if(f->type->etype != TFUNC)
continue;
if(f->etype != TFIELD)
fatal("dumpsignatures: not field");
s1 = f->sym;
if(s1 == nil)
continue;
if(s1->name[0] == '_')
continue;
b = mal(sizeof(*b));
b->link = a;
a = b;
a->name = s1->name;
sp = strchr(s1->name, '_');
if(sp != nil)
a->name = sp+1;
a->hash = PRIME8*stringhash(a->name) + PRIME9*typehash(f->type, 0);
a->sym = f->sym;
a->offset = o;
o++;
}
a = lsort(a, sigcmp);
ot = 0;
if(et == TINTER) {
o = 0;
for(b=a; b!=nil; b=b->link)
o++;
// sigi[0].name = ""
ot = rnd(ot, maxround);
p = pc;
gins(ADATA, N, N);
p->from = at;
p->from.offset = ot;
p->from.scale = widthptr;
p->to = ao;
p->to.offset = stringo;
ot += widthptr;
// sigi[0].hash = 0
ot = rnd(ot, wi);
p = pc;
gins(ADATA, N, N);
p->from = at;
p->from.offset = ot;
p->from.scale = wi;
p->to = ac;
p->to.offset = 0;
ot += wi;
// sigi[0].offset = count
ot = rnd(ot, wi);
p = pc;
gins(ADATA, N, N);
p->from = at;
p->from.offset = ot;
p->from.scale = wi;
p->to = ac;
p->to.offset = o;
ot += wi;
datastring("", 1);
}
for(b=a; b!=nil; b=b->link) {
// sigx[++].name = "fieldname"
ot = rnd(ot, maxround);
p = pc;
gins(ADATA, N, N);
p->from = at;
p->from.offset = ot;
p->from.scale = widthptr;
p->to = ao;
p->to.offset = stringo;
ot += widthptr;
// sigx[++].hash = hashcode
ot = rnd(ot, wi);
p = pc;
gins(ADATA, N, N);
p->from = at;
p->from.offset = ot;
p->from.scale = wi;
p->to = ac;
p->to.offset = b->hash;
ot += wi;
if(et == TINTER) {
// sigi[++].offset = offset of method
ot = rnd(ot, wi);
p = pc;
gins(ADATA, N, N);
p->from = at;
p->from.offset = ot;
p->from.scale = wi;
p->to = ac;
p->to.offset = b->offset;
ot += wi;
} else {
// sigs[++].fun = &method
ot = rnd(ot, widthptr);
p = pc;
gins(ADATA, N, N);
p->from = at;
p->from.offset = ot;
p->from.scale = widthptr;
p->to = ad;
p->to.sym = b->sym;
ot += widthptr;
}
datastring(b->name, strlen(b->name)+1);
}
// nil field name at end
ot = rnd(ot, maxround);
p = pc;
gins(ADATA, N, N);
p->from = at;
p->from.offset = ot;
p->from.scale = widthptr;
p->to = ac;
p->to.offset = 0;
ot += widthptr;
p = pc;
gins(AGLOBL, N, N);
p->from = at;
p->to = ac;
p->to.offset = ot;
}
if(stringo > 0) {
p = pc;
gins(AGLOBL, N, N);
p->from = ao;
p->to = ac;
p->to.offset = stringo;
}
}

595
src/cmd/6g/runtime.c Normal file
View file

@ -0,0 +1,595 @@
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
#include "runtime.h"
int32 debug = 0;
void
sys_printbool(bool v)
{
if(v) {
sys_write(1, (byte*)"true", 4);
return;
}
sys_write(1, (byte*)"false", 5);
}
void
sys_printfloat(float64 v)
{
sys_write(1, "printfloat", 10);
}
void
sys_printint(int64 v)
{
byte buf[100];
int32 i, s;
s = 0;
if(v < 0) {
v = -v;
s = 1;
if(v < 0) {
sys_write(1, (byte*)"-oo", 3);
return;
}
}
for(i=nelem(buf)-1; i>0; i--) {
buf[i] = v%10 + '0';
if(v < 10)
break;
v = v/10;
}
if(s) {
i--;
buf[i] = '-';
}
sys_write(1, buf+i, nelem(buf)-i);
}
void
sys_printpointer(void *p)
{
uint64 v;
byte buf[100];
int32 i;
v = (int64)p;
for(i=nelem(buf)-1; i>0; i--) {
buf[i] = v%16 + '0';
if(buf[i] > '9')
buf[i] += 'a'-'0'-10;
if(v < 16)
break;
v = v/16;
}
sys_write(1, buf+i, nelem(buf)-i);
}
void
sys_panicl(int32 lno)
{
prints("\npanic on line ");
sys_printint(lno);
prints("\n");
*(int32*)0 = 0;
}
void
sys_printstring(string v)
{
sys_write(1, v->str, v->len);
}
int32
strlen(int8 *s)
{
int32 l;
for(l=0; s[l]!=0; l++)
;
return l;
}
void
prints(int8 *s)
{
sys_write(1, s, strlen(s));
}
dump(byte *p, int32 n)
{
uint32 v;
int32 i;
for(i=0; i<n; i++) {
sys_printpointer((byte*)(p[i]>>4));
sys_printpointer((byte*)(p[i]&0xf));
if((i&15) == 15)
prints("\n");
else
prints(" ");
}
if(n & 15)
prints("\n");
}
static uint8* hunk;
static uint32 nhunk;
static uint64 nmmap;
static uint64 nmal;
enum
{
NHUNK = 20<<20,
PROT_NONE = 0x00,
PROT_READ = 0x01,
PROT_WRITE = 0x02,
PROT_EXEC = 0x04,
MAP_FILE = 0x0000,
MAP_SHARED = 0x0001,
MAP_PRIVATE = 0x0002,
MAP_FIXED = 0x0010,
MAP_ANON = 0x1000,
};
static void
throw(int8 *s)
{
prints("throw: ");
prints(s);
prints("\n");
sys_exit(1);
}
static void
mcpy(byte *t, byte *f, uint32 n)
{
while(n > 0) {
*t = *f;
t++;
f++;
n--;
}
}
static byte*
brk(uint32 n)
{
byte* v;
v = sys_mmap(nil, NHUNK, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, 0, 0);
sys_memclr(v, n);
nmmap += n;
return v;
}
static void*
mal(uint32 n)
{
byte* v;
// round to keep everything 64-bit alligned
while(n & 7)
n++;
nmal += n;
// do we have enough in contiguous hunk
if(n > nhunk) {
// if it is big allocate it separately
if(n > NHUNK)
return brk(n);
// allocate a new contiguous hunk
hunk = brk(NHUNK);
nhunk = NHUNK;
}
// allocate from the contiguous hunk
v = hunk;
hunk += n;
nhunk -= n;
return v;
}
void
sys_mal(uint32 n, uint8 *ret)
{
ret = mal(n);
FLUSH(&ret);
}
void
sys_catstring(string s1, string s2, string s3)
{
uint32 l;
if(s1->len == 0) {
s3 = s2;
goto out;
}
if(s2->len == 0) {
s3 = s1;
goto out;
}
l = s1->len + s2->len;
s3 = mal(sizeof(s3->len)+l);
s3->len = l;
mcpy(s3->str, s1->str, s1->len);
mcpy(s3->str+s1->len, s2->str, s2->len);
out:
FLUSH(&s3);
}
void
sys_cmpstring(string s1, string s2, int32 v)
{
uint32 i, l;
byte c1, c2;
l = s1->len;
if(s2->len < l)
l = s2->len;
for(i=0; i<l; i++) {
c1 = s1->str[i];
c2 = s2->str[i];
if(c1 < c2) {
v = -1;
goto out;
}
if(c1 > c2) {
v = +1;
goto out;
}
}
if(s1->len < s2->len) {
v = -1;
goto out;
}
if(s1->len > s2->len) {
v = +1;
goto out;
}
v = 0;
out:
FLUSH(&v);
}
static int32
strcmp(byte *s1, byte *s2)
{
uint32 i;
byte c1, c2;
for(i=0;; i++) {
c1 = s1[i];
c2 = s2[i];
if(c1 < c2)
return -1;
if(c1 > c2)
return +1;
if(c1 == 0)
return 0;
}
}
static void
prbounds(int8* s, int32 a, int32 b, int32 c)
{
int32 i;
prints(s);
prints(" ");
sys_printint(a);
prints("<");
sys_printint(b);
prints(">");
sys_printint(c);
prints("\n");
throw("bounds");
}
void
sys_slicestring(string si, int32 lindex, int32 hindex, string so)
{
string s, str;
int32 l;
if(lindex < 0 || lindex > si->len ||
hindex < lindex || hindex > si->len)
prbounds("slice", lindex, si->len, hindex);
l = hindex-lindex;
so = mal(sizeof(so->len)+l);
so->len = l;
mcpy(so->str, si->str+lindex, l);
FLUSH(&so);
}
void
sys_indexstring(string s, int32 i, byte b)
{
if(i < 0 || i >= s->len)
prbounds("index", 0, i, s->len);
b = s->str[i];
FLUSH(&b);
}
/*
* this is the plan9 runetochar
* extended for 36 bits in 7 bytes
* note that it truncates to 32 bits
* through the argument passing.
*/
static int32
runetochar(byte *str, uint32 c)
{
int32 i, n;
uint32 mask, mark;
/*
* one character in 7 bits
*/
if(c <= 0x07FUL) {
str[0] = c;
return 1;
}
/*
* every new character picks up 5 bits
* one less in the first byte and
* six more in an extension byte
*/
mask = 0x7ffUL;
mark = 0xC0UL;
for(n=1;; n++) {
if(c <= mask)
break;
mask = (mask<<5) | 0x1fUL;
mark = (mark>>1) | 0x80UL;
}
/*
* lay down the bytes backwards
* n is the number of extension bytes
* mask is the max codepoint
* mark is the zeroth byte indicator
*/
for(i=n; i>0; i--) {
str[i] = 0x80UL | (c&0x3fUL);
c >>= 6;
}
str[0] = mark|c;
return n+1;
}
void
sys_intstring(int64 v, string s)
{
int32 l;
s = mal(sizeof(s->len)+8);
s->len = runetochar(s->str, v);
FLUSH(&s);
}
void
sys_byteastring(byte *a, int32 l, string s)
{
s = mal(sizeof(s->len)+l);
s->len = l;
mcpy(s->str, a, l);
FLUSH(&s);
}
static Map* hash[1009];
static Map*
hashmap(Sigi *si, Sigs *ss)
{
int32 ns, ni;
uint32 ihash, h;
byte *sname, *iname;
Map *m;
h = ((uint32)si + (uint32)ss) % nelem(hash);
for(m=hash[h]; m!=nil; m=m->link) {
if(m->si == si && m->ss == ss) {
if(m->bad) {
throw("bad hashmap");
m = nil;
}
// prints("old hashmap\n");
return m;
}
}
ni = si[0].offset; // first word has size
m = mal(sizeof(*m) + ni*sizeof(m->fun[0]));
m->si = si;
m->ss = ss;
ni = 1; // skip first word
ns = 0;
loop1:
// pick up next name from
// interface signature
iname = si[ni].name;
if(iname == nil) {
m->link = hash[h];
hash[h] = m;
// prints("new hashmap\n");
return m;
}
ihash = si[ni].hash;
loop2:
// pick up and comapre next name
// from structure signature
sname = ss[ns].name;
if(sname == nil) {
prints((int8*)iname);
prints(": ");
throw("hashmap: failed to find method");
m->bad = 1;
m->link = hash[h];
hash[h] = m;
return nil;
}
if(ihash != ss[ns].hash ||
strcmp(sname, iname) != 0) {
ns++;
goto loop2;
}
m->fun[si[ni].offset] = ss[ns].fun;
ni++;
goto loop1;
}
void
sys_ifaces2i(Sigi *si, Sigs *ss, Map *m, void *s)
{
if(debug) {
prints("s2i sigi=");
sys_printpointer(si);
prints(" sigs=");
sys_printpointer(ss);
prints(" s=");
sys_printpointer(s);
}
if(s == nil) {
throw("ifaces2i: nil pointer");
m = nil;
FLUSH(&m);
return;
}
m = hashmap(si, ss);
if(debug) {
prints(" returning m=");
sys_printpointer(m);
prints(" s=");
sys_printpointer(s);
prints("\n");
dump((byte*)m, 64);
}
FLUSH(&m);
}
void
sys_ifacei2i(Sigi *si, Map *m, void *s)
{
if(debug) {
prints("i2i sigi=");
sys_printpointer(si);
prints(" m=");
sys_printpointer(m);
prints(" s=");
sys_printpointer(s);
}
if(m == nil) {
throw("ifacei2i: nil map");
s = nil;
FLUSH(&s);
return;
}
if(m->si == nil) {
throw("ifacei2i: nil pointer");
return;
}
if(m->si != si) {
m = hashmap(si, m->ss);
FLUSH(&m);
}
if(debug) {
prints(" returning m=");
sys_printpointer(m);
prints(" s=");
sys_printpointer(s);
prints("\n");
dump((byte*)m, 64);
}
}
void
sys_ifacei2s(Sigs *ss, Map *m, void *s)
{
if(debug) {
prints("i2s m=");
sys_printpointer(m);
prints(" s=");
sys_printpointer(s);
prints("\n");
}
if(m == nil) {
throw("ifacei2s: nil map");
s = nil;
FLUSH(&s);
return;
}
if(m->ss != ss) {
dump((byte*)m, 64);
throw("ifacei2s: wrong pointer");
s = nil;
FLUSH(&s);
return;
}
}
void
check(void)
{
int8 a;
uint8 b;
int16 c;
uint16 d;
int32 e;
uint32 f;
int64 g;
uint64 h;
float32 i;
float64 j;
void* k;
uint16* l;
if(sizeof(a) != 1) throw("bad a");
if(sizeof(b) != 1) throw("bad b");
if(sizeof(c) != 2) throw("bad c");
if(sizeof(d) != 2) throw("bad d");
if(sizeof(e) != 4) throw("bad e");
if(sizeof(f) != 4) throw("bad f");
if(sizeof(g) != 8) throw("bad g");
if(sizeof(h) != 8) throw("bad h");
if(sizeof(i) != 4) throw("bad i");
if(sizeof(j) != 8) throw("bad j");
if(sizeof(k) != 8) throw("bad k");
if(sizeof(l) != 8) throw("bad l");
// prints(1"check ok\n");
}

107
src/cmd/6g/runtime.h Normal file
View file

@ -0,0 +1,107 @@
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
/*
* basic types
*/
typedef signed char int8;
typedef unsigned char uint8;
typedef signed short int16;
typedef unsigned short uint16;
typedef signed int int32;
typedef unsigned int uint32;
typedef signed long long int int64;
typedef unsigned long long int uint64;
typedef float float32;
typedef double float64;
/*
* get rid of C types
*/
#define unsigned XXunsigned
#define signed XXsigned
#define char XXchar
#define short XXshort
#define int XXint
#define long XXlong
#define float XXfloat
#define double XXdouble
/*
* defined types
*/
typedef uint8 bool;
typedef uint8 byte;
typedef struct
{
int32 len;
byte str[1];
} *string;
typedef struct
{
byte* name;
uint32 hash;
void (*fun)(void);
} Sigs;
typedef struct
{
byte* name;
uint32 hash;
uint32 offset;
} Sigi;
typedef struct Map Map;
struct Map
{
Sigi* si;
Sigs* ss;
Map* link;
int32 bad;
int32 unused;
void (*fun[])(void);
};
/*
* defined constants
*/
enum
{
true = 1,
false = 0,
};
/*
* defined macros
* you need super-goru privilege
* to add this list.
*/
#define nelem(x) (sizeof(x)/sizeof((x)[0]))
#define nil ((void*)0)
/*
* very low level
*/
void FLUSH(void*);
void prints(int8*);
void sys_exit(int32);
void sys_write(int32, void*, int32);
void sys_breakpoint(void);
uint8* sys_mmap(byte*, uint32, int32, int32, int32, uint32);
void sys_memclr(byte*, uint32);
/*
* runtime
*/
void sys_printbool(bool);
void sys_printfloat(float64);
void sys_printint(int64);
void sys_printstring(string);
void sys_catstring(string, string, string);
void sys_cmpstring(string, string, int32);
void sys_slicestring(string, int32, int32, string);
void sys_indexstring(string, int32, byte);
void sys_intstring(int64, string);
void sys_ifaces2i(Sigi*, Sigs*, Map*, void*);
void sys_ifacei2i(Sigi*, Map*, void*);
void sys_ifacei2s(Sigs*, Map*, void*);

857
src/cmd/6l/6.out.h Normal file
View file

@ -0,0 +1,857 @@
// Inferno utils/6c/6.out.h
// http://code.google.com/p/inferno-os/source/browse/utils/6c/6.out.h
//
// 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.
#define NSYM 50
#define NSNAME 8
#define NOPROF (1<<0)
#define DUPOK (1<<1)
/*
* amd64
*/
enum as
{
AXXX,
AAAA,
AAAD,
AAAM,
AAAS,
AADCB,
AADCL,
AADCW,
AADDB,
AADDL,
AADDW,
AADJSP,
AANDB,
AANDL,
AANDW,
AARPL,
ABOUNDL,
ABOUNDW,
ABSFL,
ABSFW,
ABSRL,
ABSRW,
ABTL,
ABTW,
ABTCL,
ABTCW,
ABTRL,
ABTRW,
ABTSL,
ABTSW,
ABYTE,
ACALL,
ACLC,
ACLD,
ACLI,
ACLTS,
ACMC,
ACMPB,
ACMPL,
ACMPW,
ACMPSB,
ACMPSL,
ACMPSW,
ADAA,
ADAS,
ADATA,
ADECB,
ADECL,
ADECQ,
ADECW,
ADIVB,
ADIVL,
ADIVW,
AENTER,
AGLOBL,
AGOK,
AHISTORY,
AHLT,
AIDIVB,
AIDIVL,
AIDIVW,
AIMULB,
AIMULL,
AIMULW,
AINB,
AINL,
AINW,
AINCB,
AINCL,
AINCQ,
AINCW,
AINSB,
AINSL,
AINSW,
AINT,
AINTO,
AIRETL,
AIRETW,
AJCC,
AJCS,
AJCXZ,
AJEQ,
AJGE,
AJGT,
AJHI,
AJLE,
AJLS,
AJLT,
AJMI,
AJMP,
AJNE,
AJOC,
AJOS,
AJPC,
AJPL,
AJPS,
ALAHF,
ALARL,
ALARW,
ALEAL,
ALEAW,
ALEAVEL,
ALEAVEW,
ALOCK,
ALODSB,
ALODSL,
ALODSW,
ALONG,
ALOOP,
ALOOPEQ,
ALOOPNE,
ALSLL,
ALSLW,
AMOVB,
AMOVL,
AMOVW,
AMOVBLSX,
AMOVBLZX,
AMOVBQSX,
AMOVBQZX,
AMOVBWSX,
AMOVBWZX,
AMOVWLSX,
AMOVWLZX,
AMOVWQSX,
AMOVWQZX,
AMOVSB,
AMOVSL,
AMOVSW,
AMULB,
AMULL,
AMULW,
ANAME,
ANEGB,
ANEGL,
ANEGW,
ANOP,
ANOTB,
ANOTL,
ANOTW,
AORB,
AORL,
AORW,
AOUTB,
AOUTL,
AOUTW,
AOUTSB,
AOUTSL,
AOUTSW,
APOPAL,
APOPAW,
APOPFL,
APOPFW,
APOPL,
APOPW,
APUSHAL,
APUSHAW,
APUSHFL,
APUSHFW,
APUSHL,
APUSHW,
ARCLB,
ARCLL,
ARCLW,
ARCRB,
ARCRL,
ARCRW,
AREP,
AREPN,
ARET,
AROLB,
AROLL,
AROLW,
ARORB,
ARORL,
ARORW,
ASAHF,
ASALB,
ASALL,
ASALW,
ASARB,
ASARL,
ASARW,
ASBBB,
ASBBL,
ASBBW,
ASCASB,
ASCASL,
ASCASW,
ASETCC,
ASETCS,
ASETEQ,
ASETGE,
ASETGT,
ASETHI,
ASETLE,
ASETLS,
ASETLT,
ASETMI,
ASETNE,
ASETOC,
ASETOS,
ASETPC,
ASETPL,
ASETPS,
ACDQ,
ACWD,
ASHLB,
ASHLL,
ASHLW,
ASHRB,
ASHRL,
ASHRW,
ASTC,
ASTD,
ASTI,
ASTOSB,
ASTOSL,
ASTOSW,
ASUBB,
ASUBL,
ASUBW,
ASYSCALL,
ATESTB,
ATESTL,
ATESTW,
ATEXT,
AVERR,
AVERW,
AWAIT,
AWORD,
AXCHGB,
AXCHGL,
AXCHGW,
AXLAT,
AXORB,
AXORL,
AXORW,
AFMOVB,
AFMOVBP,
AFMOVD,
AFMOVDP,
AFMOVF,
AFMOVFP,
AFMOVL,
AFMOVLP,
AFMOVV,
AFMOVVP,
AFMOVW,
AFMOVWP,
AFMOVX,
AFMOVXP,
AFCOMB,
AFCOMBP,
AFCOMD,
AFCOMDP,
AFCOMDPP,
AFCOMF,
AFCOMFP,
AFCOML,
AFCOMLP,
AFCOMW,
AFCOMWP,
AFUCOM,
AFUCOMP,
AFUCOMPP,
AFADDDP,
AFADDW,
AFADDL,
AFADDF,
AFADDD,
AFMULDP,
AFMULW,
AFMULL,
AFMULF,
AFMULD,
AFSUBDP,
AFSUBW,
AFSUBL,
AFSUBF,
AFSUBD,
AFSUBRDP,
AFSUBRW,
AFSUBRL,
AFSUBRF,
AFSUBRD,
AFDIVDP,
AFDIVW,
AFDIVL,
AFDIVF,
AFDIVD,
AFDIVRDP,
AFDIVRW,
AFDIVRL,
AFDIVRF,
AFDIVRD,
AFXCHD,
AFFREE,
AFLDCW,
AFLDENV,
AFRSTOR,
AFSAVE,
AFSTCW,
AFSTENV,
AFSTSW,
AF2XM1,
AFABS,
AFCHS,
AFCLEX,
AFCOS,
AFDECSTP,
AFINCSTP,
AFINIT,
AFLD1,
AFLDL2E,
AFLDL2T,
AFLDLG2,
AFLDLN2,
AFLDPI,
AFLDZ,
AFNOP,
AFPATAN,
AFPREM,
AFPREM1,
AFPTAN,
AFRNDINT,
AFSCALE,
AFSIN,
AFSINCOS,
AFSQRT,
AFTST,
AFXAM,
AFXTRACT,
AFYL2X,
AFYL2XP1,
AEND,
ADYNT,
AINIT,
ASIGNAME,
/* extra 32-bit operations */
ACMPXCHGB,
ACMPXCHGL,
ACMPXCHGW,
ACMPXCHG8B,
ACPUID,
AINVD,
AINVLPG,
ALFENCE,
AMFENCE,
AMOVNTIL,
ARDMSR,
ARDPMC,
ARDTSC,
ARSM,
ASFENCE,
ASYSRET,
AWBINVD,
AWRMSR,
AXADDB,
AXADDL,
AXADDW,
/* conditional move */
ACMOVLCC,
ACMOVLCS,
ACMOVLEQ,
ACMOVLGE,
ACMOVLGT,
ACMOVLHI,
ACMOVLLE,
ACMOVLLS,
ACMOVLLT,
ACMOVLMI,
ACMOVLNE,
ACMOVLOC,
ACMOVLOS,
ACMOVLPC,
ACMOVLPL,
ACMOVLPS,
ACMOVQCC,
ACMOVQCS,
ACMOVQEQ,
ACMOVQGE,
ACMOVQGT,
ACMOVQHI,
ACMOVQLE,
ACMOVQLS,
ACMOVQLT,
ACMOVQMI,
ACMOVQNE,
ACMOVQOC,
ACMOVQOS,
ACMOVQPC,
ACMOVQPL,
ACMOVQPS,
ACMOVWCC,
ACMOVWCS,
ACMOVWEQ,
ACMOVWGE,
ACMOVWGT,
ACMOVWHI,
ACMOVWLE,
ACMOVWLS,
ACMOVWLT,
ACMOVWMI,
ACMOVWNE,
ACMOVWOC,
ACMOVWOS,
ACMOVWPC,
ACMOVWPL,
ACMOVWPS,
/* 64-bit */
AADCQ,
AADDQ,
AANDQ,
ABSFQ,
ABSRQ,
ABTCQ,
ABTQ,
ABTRQ,
ABTSQ,
ACMPQ,
ACMPSQ,
ACMPXCHGQ,
ACQO,
ADIVQ,
AIDIVQ,
AIMULQ,
AIRETQ,
ALEAQ,
ALEAVEQ,
ALODSQ,
AMOVQ,
AMOVLQSX,
AMOVLQZX,
AMOVNTIQ,
AMOVSQ,
AMULQ,
ANEGQ,
ANOTQ,
AORQ,
APOPFQ,
APOPQ,
APUSHFQ,
APUSHQ,
ARCLQ,
ARCRQ,
AROLQ,
ARORQ,
AQUAD,
ASALQ,
ASARQ,
ASBBQ,
ASCASQ,
ASHLQ,
ASHRQ,
ASTOSQ,
ASUBQ,
ATESTQ,
AXADDQ,
AXCHGQ,
AXORQ,
/* media */
AADDPD,
AADDPS,
AADDSD,
AADDSS,
AANDNPD,
AANDNPS,
AANDPD,
AANDPS,
ACMPPD,
ACMPPS,
ACMPSD,
ACMPSS,
ACOMISD,
ACOMISS,
ACVTPD2PL,
ACVTPD2PS,
ACVTPL2PD,
ACVTPL2PS,
ACVTPS2PD,
ACVTPS2PL,
ACVTSD2SL,
ACVTSD2SQ,
ACVTSD2SS,
ACVTSL2SD,
ACVTSL2SS,
ACVTSQ2SD,
ACVTSQ2SS,
ACVTSS2SD,
ACVTSS2SL,
ACVTSS2SQ,
ACVTTPD2PL,
ACVTTPS2PL,
ACVTTSD2SL,
ACVTTSD2SQ,
ACVTTSS2SL,
ACVTTSS2SQ,
ADIVPD,
ADIVPS,
ADIVSD,
ADIVSS,
AEMMS,
AFXRSTOR,
AFXRSTOR64,
AFXSAVE,
AFXSAVE64,
ALDMXCSR,
AMASKMOVOU,
AMASKMOVQ,
AMAXPD,
AMAXPS,
AMAXSD,
AMAXSS,
AMINPD,
AMINPS,
AMINSD,
AMINSS,
AMOVAPD,
AMOVAPS,
AMOVOU,
AMOVHLPS,
AMOVHPD,
AMOVHPS,
AMOVLHPS,
AMOVLPD,
AMOVLPS,
AMOVMSKPD,
AMOVMSKPS,
AMOVNTO,
AMOVNTPD,
AMOVNTPS,
AMOVNTQ,
AMOVO,
AMOVQOZX,
AMOVSD,
AMOVSS,
AMOVUPD,
AMOVUPS,
AMULPD,
AMULPS,
AMULSD,
AMULSS,
AORPD,
AORPS,
APACKSSLW,
APACKSSWB,
APACKUSWB,
APADDB,
APADDL,
APADDQ,
APADDSB,
APADDSW,
APADDUSB,
APADDUSW,
APADDW,
APANDB,
APANDL,
APANDSB,
APANDSW,
APANDUSB,
APANDUSW,
APANDW,
APAND,
APANDN,
APAVGB,
APAVGW,
APCMPEQB,
APCMPEQL,
APCMPEQW,
APCMPGTB,
APCMPGTL,
APCMPGTW,
APEXTRW,
APFACC,
APFADD,
APFCMPEQ,
APFCMPGE,
APFCMPGT,
APFMAX,
APFMIN,
APFMUL,
APFNACC,
APFPNACC,
APFRCP,
APFRCPIT1,
APFRCPI2T,
APFRSQIT1,
APFRSQRT,
APFSUB,
APFSUBR,
APINSRW,
APMADDWL,
APMAXSW,
APMAXUB,
APMINSW,
APMINUB,
APMOVMSKB,
APMULHRW,
APMULHUW,
APMULHW,
APMULLW,
APMULULQ,
APOR,
APSADBW,
APSHUFHW,
APSHUFL,
APSHUFLW,
APSHUFW,
APSLLO,
APSLLL,
APSLLQ,
APSLLW,
APSRAL,
APSRAW,
APSRLO,
APSRLL,
APSRLQ,
APSRLW,
APSUBB,
APSUBL,
APSUBQ,
APSUBSB,
APSUBSW,
APSUBUSB,
APSUBUSW,
APSUBW,
APSWAPL,
APUNPCKHBW,
APUNPCKHLQ,
APUNPCKHQDQ,
APUNPCKHWL,
APUNPCKLBW,
APUNPCKLLQ,
APUNPCKLQDQ,
APUNPCKLWL,
APXOR,
ARCPPS,
ARCPSS,
ARSQRTPS,
ARSQRTSS,
ASHUFPD,
ASHUFPS,
ASQRTPD,
ASQRTPS,
ASQRTSD,
ASQRTSS,
ASTMXCSR,
ASUBPD,
ASUBPS,
ASUBSD,
ASUBSS,
AUCOMISD,
AUCOMISS,
AUNPCKHPD,
AUNPCKHPS,
AUNPCKLPD,
AUNPCKLPS,
AXORPD,
AXORPS,
APF2IW,
APF2IL,
API2FW,
API2FL,
ARETFW,
ARETFL,
ARETFQ,
ASWAPGS,
AMODE,
ALAST
};
enum
{
D_AL = 0,
D_CL,
D_DL,
D_BL,
D_SPB,
D_BPB,
D_SIB,
D_DIB,
D_R8B,
D_R9B,
D_R10B,
D_R11B,
D_R12B,
D_R13B,
D_R14B,
D_R15B,
D_AX = 16,
D_CX,
D_DX,
D_BX,
D_SP,
D_BP,
D_SI,
D_DI,
D_R8,
D_R9,
D_R10,
D_R11,
D_R12,
D_R13,
D_R14,
D_R15,
D_AH = 32,
D_CH,
D_DH,
D_BH,
D_F0 = 36,
D_M0 = 44,
D_X0 = 52,
D_X1,
D_X2,
D_X3,
D_X4,
D_X5,
D_X6,
D_X7,
D_CS = 68,
D_SS,
D_DS,
D_ES,
D_FS,
D_GS,
D_GDTR, /* global descriptor table register */
D_IDTR, /* interrupt descriptor table register */
D_LDTR, /* local descriptor table register */
D_MSW, /* machine status word */
D_TASK, /* task register */
D_CR = 79,
D_DR = 95,
D_TR = 103,
D_NONE = 111,
D_BRANCH = 112,
D_EXTERN = 113,
D_STATIC = 114,
D_AUTO = 115,
D_PARAM = 116,
D_CONST = 117,
D_FCONST = 118,
D_SCONST = 119,
D_ADDR = 120,
D_FILE,
D_FILE1,
D_INDIR, /* additive */
T_TYPE = 1<<0,
T_INDEX = 1<<1,
T_OFFSET = 1<<2,
T_FCONST = 1<<3,
T_SYM = 1<<4,
T_SCONST = 1<<5,
T_64 = 1<<6,
REGARG = 0,
REGRET = D_AX,
FREGRET = D_X0,
REGSP = D_SP,
REGTMP = D_DI,
REGEXT = D_R15, /* compiler allocates external registers R15 down */
FREGMIN = D_X0+5, /* first register variable */
FREGEXT = D_X0+7 /* first external register */
};
/*
* this is the ranlib header
*/
#define SYMDEF "__.SYMDEF"
/*
* this is the simulated IEEE floating point
*/
typedef struct ieee Ieee;
struct ieee
{
long l; /* contains ls-man 0xffffffff */
long h; /* contains sign 0x80000000
exp 0x7ff00000
ms-man 0x000fffff */
};

617
src/cmd/6l/asm.c Normal file
View file

@ -0,0 +1,617 @@
// Inferno utils/6l/asm.c
// http://code.google.com/p/inferno-os/source/browse/utils/6l/asm.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.
#include "l.h"
#define Dbufslop 100
#define PADDR(a) ((ulong)(a) & ~0x80000000)
vlong
entryvalue(void)
{
char *a;
Sym *s;
a = INITENTRY;
if(*a >= '0' && *a <= '9')
return atolwhex(a);
s = lookup(a, 0);
if(s->type == 0)
return INITTEXT;
switch(s->type) {
case STEXT:
break;
case SDATA:
if(dlm)
return s->value+INITDAT;
default:
diag("entry not text: %s", s->name);
}
return s->value;
}
void
wputl(ushort w)
{
cput(w);
cput(w>>8);
}
void
wput(ushort w)
{
cput(w>>8);
cput(w);
}
void
lput(long l)
{
cput(l>>24);
cput(l>>16);
cput(l>>8);
cput(l);
}
void
llput(vlong v)
{
lput(v>>32);
lput(v);
}
void
lputl(long l)
{
cput(l);
cput(l>>8);
cput(l>>16);
cput(l>>24);
}
void
strnput(char *s, int n)
{
int i;
for(i=0; i<n; i++) {
cput(*s);
if(*s != 0)
s++;
}
}
void
asmb(void)
{
Prog *p;
long v, magic, w;
int a;
uchar *op1;
vlong vl, va;
if(debug['v'])
Bprint(&bso, "%5.2f asmb\n", cputime());
Bflush(&bso);
seek(cout, HEADR, 0);
pc = INITTEXT;
curp = firstp;
for(p = firstp; p != P; p = p->link) {
if(p->as == ATEXT)
curtext = p;
if(p->pc != pc) {
if(!debug['a'])
print("%P\n", curp);
diag("phase error %llux sb %llux in %s", p->pc, pc, TNAME);
pc = p->pc;
}
curp = p;
asmins(p);
a = (andptr - and);
if(cbc < a)
cflush();
if(debug['a']) {
Bprint(&bso, pcstr, pc);
for(op1 = and; op1 < andptr; op1++)
Bprint(&bso, "%.2ux", *op1);
for(; op1 < and+Maxand; op1++)
Bprint(&bso, " ");
Bprint(&bso, "%P\n", curp);
}
if(dlm) {
if(p->as == ATEXT)
reloca = nil;
else if(reloca != nil)
diag("reloc failure: %P", curp);
}
memmove(cbp, and, a);
cbp += a;
pc += a;
cbc -= a;
}
cflush();
switch(HEADTYPE) {
default:
diag("unknown header type %ld", HEADTYPE);
case 2:
case 5:
seek(cout, HEADR+textsize, 0);
break;
case 6:
v = HEADR+textsize;
myseek(cout, v);
v = rnd(v, 4096) - v;
while(v > 0) {
cput(0);
v--;
}
cflush();
break;
}
if(debug['v'])
Bprint(&bso, "%5.2f datblk\n", cputime());
Bflush(&bso);
if(dlm){
char buf[8];
write(cout, buf, INITDAT-textsize);
textsize = INITDAT;
}
for(v = 0; v < datsize; v += sizeof(buf)-Dbufslop) {
if(datsize-v > sizeof(buf)-Dbufslop)
datblk(v, sizeof(buf)-Dbufslop);
else
datblk(v, datsize-v);
}
symsize = 0;
spsize = 0;
lcsize = 0;
if(!debug['s']) {
if(debug['v'])
Bprint(&bso, "%5.2f sym\n", cputime());
Bflush(&bso);
switch(HEADTYPE) {
default:
case 2:
case 5:
seek(cout, HEADR+textsize+datsize, 0);
break;
case 6:
debug['s'] = 1;
break;
}
if(!debug['s'])
asmsym();
if(debug['v'])
Bprint(&bso, "%5.2f sp\n", cputime());
Bflush(&bso);
if(debug['v'])
Bprint(&bso, "%5.2f pc\n", cputime());
Bflush(&bso);
if(!debug['s'])
asmlc();
if(dlm)
asmdyn();
cflush();
}
else if(dlm){
seek(cout, HEADR+textsize+datsize, 0);
asmdyn();
cflush();
}
if(debug['v'])
Bprint(&bso, "%5.2f headr\n", cputime());
Bflush(&bso);
seek(cout, 0L, 0);
switch(HEADTYPE) {
default:
case 2: /* plan9 */
magic = 4*26*26+7;
magic |= 0x00008000; /* fat header */
if(dlm)
magic |= 0x80000000; /* dlm */
lput(magic); /* magic */
lput(textsize); /* sizes */
lput(datsize);
lput(bsssize);
lput(symsize); /* nsyms */
vl = entryvalue();
lput(PADDR(vl)); /* va of entry */
lput(spsize); /* sp offsets */
lput(lcsize); /* line offsets */
llput(vl); /* va of entry */
break;
case 3: /* plan9 */
magic = 4*26*26+7;
if(dlm)
magic |= 0x80000000;
lput(magic); /* magic */
lput(textsize); /* sizes */
lput(datsize);
lput(bsssize);
lput(symsize); /* nsyms */
lput(entryvalue()); /* va of entry */
lput(spsize); /* sp offsets */
lput(lcsize); /* line offsets */
break;
case 5:
strnput("\177ELF", 4); /* e_ident */
cput(1); /* class = 32 bit */
cput(1); /* data = LSB */
cput(1); /* version = CURRENT */
strnput("", 9);
wputl(2); /* type = EXEC */
wputl(62); /* machine = AMD64 */
lputl(1L); /* version = CURRENT */
lputl(PADDR(entryvalue())); /* entry vaddr */
lputl(52L); /* offset to first phdr */
lputl(0L); /* offset to first shdr */
lputl(0L); /* processor specific flags */
wputl(52); /* Ehdr size */
wputl(32); /* Phdr size */
wputl(3); /* # of Phdrs */
wputl(0); /* Shdr size */
wputl(0); /* # of Shdrs */
wputl(0); /* Shdr string size */
lputl(1L); /* text - type = PT_LOAD */
lputl(HEADR); /* file offset */
lputl(INITTEXT); /* vaddr */
lputl(PADDR(INITTEXT)); /* paddr */
lputl(textsize); /* file size */
lputl(textsize); /* memory size */
lputl(0x05L); /* protections = RX */
lputl(INITRND); /* alignment */
lputl(1L); /* data - type = PT_LOAD */
lputl(HEADR+textsize); /* file offset */
lputl(INITDAT); /* vaddr */
lputl(PADDR(INITDAT)); /* paddr */
lputl(datsize); /* file size */
lputl(datsize+bsssize); /* memory size */
lputl(0x06L); /* protections = RW */
lputl(INITRND); /* alignment */
lputl(0L); /* data - type = PT_NULL */
lputl(HEADR+textsize+datsize); /* file offset */
lputl(0L);
lputl(0L);
lputl(symsize); /* symbol table size */
lputl(lcsize); /* line number size */
lputl(0x04L); /* protections = R */
lputl(0x04L); /* alignment */
break;
case 6:
/* apple MACH */
va = 4096;
lputl(0xfeedfacf); /* 64-bit */
lputl((1<<24)|7); /* cputype - x86/ABI64 */
lputl(3); /* subtype - x86 */
lputl(2); /* file type - mach executable */
lputl(4); /* number of loads */
lputl(machheadr()-32); /* size of loads */
lputl(1); /* flags - no undefines */
lputl(0); /* reserved */
machseg("__PAGEZERO",
0,va, /* vaddr vsize */
0,0, /* fileoffset filesize */
0,0, /* protects */
0,0); /* sections flags */
v = rnd(HEADR+textsize, INITRND);
machseg("__TEXT",
va, /* vaddr */
v, /* vsize */
0,v, /* fileoffset filesize */
7,5, /* protects */
1,0); /* sections flags */
machsect("__text", "__TEXT",
va+HEADR,v-HEADR, /* addr size */
HEADR,0,0,0, /* offset align reloc nreloc */
0|0x400); /* flag - some instructions */
w = datsize+bsssize;
machseg("__DATA",
va+v, /* vaddr */
w, /* vsize */
v,datsize, /* fileoffset filesize */
7,3, /* protects */
2,0); /* sections flags */
machsect("__data", "__DATA",
va+v,datsize, /* addr size */
v,0,0,0, /* offset align reloc nreloc */
0); /* flag */
machsect("__bss", "__DATA",
va+v+datsize,bsssize, /* addr size */
0,0,0,0, /* offset align reloc nreloc */
1); /* flag - zero fill */
machstack(va+HEADR);
break;
}
cflush();
}
void
cflush(void)
{
int n;
n = sizeof(buf.cbuf) - cbc;
if(n)
write(cout, buf.cbuf, n);
cbp = buf.cbuf;
cbc = sizeof(buf.cbuf);
}
void
outa(int n, uchar *cast, uchar *map, vlong l)
{
int i, j;
Bprint(&bso, pcstr, l);
for(i=0; i<n; i++) {
j = i;
if(map != nil)
j = map[j];
Bprint(&bso, "%.2ux", cast[j]);
}
for(; i<Maxand; i++)
Bprint(&bso, " ");
Bprint(&bso, "%P\n", curp);
}
void
datblk(long s, long n)
{
Prog *p;
uchar *cast;
long l, fl, j;
vlong o;
int i, c;
memset(buf.dbuf, 0, n+Dbufslop);
for(p = datap; p != P; p = p->link) {
curp = p;
l = p->from.sym->value + p->from.offset - s;
c = p->from.scale;
i = 0;
if(l < 0) {
if(l+c <= 0)
continue;
while(l < 0) {
l++;
i++;
}
}
if(l >= n)
continue;
if(p->as != AINIT && p->as != ADYNT) {
for(j=l+(c-i)-1; j>=l; j--)
if(buf.dbuf[j]) {
print("%P\n", p);
diag("multiple initialization");
break;
}
}
switch(p->to.type) {
case D_FCONST:
switch(c) {
default:
case 4:
fl = ieeedtof(&p->to.ieee);
cast = (uchar*)&fl;
if(debug['a'] && i == 0)
outa(c, cast, fnuxi4, l+s+INITDAT);
for(; i<c; i++) {
buf.dbuf[l] = cast[fnuxi4[i]];
l++;
}
break;
case 8:
cast = (uchar*)&p->to.ieee;
if(debug['a'] && i == 0)
outa(c, cast, fnuxi8, l+s+INITDAT);
for(; i<c; i++) {
buf.dbuf[l] = cast[fnuxi8[i]];
l++;
}
break;
}
break;
case D_SCONST:
if(debug['a'] && i == 0)
outa(c, (uchar*)p->to.scon, nil, l+s+INITDAT);
for(; i<c; i++) {
buf.dbuf[l] = p->to.scon[i];
l++;
}
break;
default:
o = p->to.offset;
if(p->to.type == D_ADDR) {
if(p->to.index != D_STATIC && p->to.index != D_EXTERN)
diag("DADDR type%P", p);
if(p->to.sym) {
if(p->to.sym->type == SUNDEF)
ckoff(p->to.sym, o);
o += p->to.sym->value;
if(p->to.sym->type != STEXT && p->to.sym->type != SUNDEF)
o += INITDAT;
if(dlm)
dynreloc(p->to.sym, l+s+INITDAT, 1);
}
}
fl = o;
cast = (uchar*)&fl;
switch(c) {
default:
diag("bad nuxi %d %d\n%P", c, i, curp);
break;
case 1:
if(debug['a'] && i == 0)
outa(c, cast, inuxi1, l+s+INITDAT);
for(; i<c; i++) {
buf.dbuf[l] = cast[inuxi1[i]];
l++;
}
break;
case 2:
if(debug['a'] && i == 0)
outa(c, cast, inuxi2, l+s+INITDAT);
for(; i<c; i++) {
buf.dbuf[l] = cast[inuxi2[i]];
l++;
}
break;
case 4:
if(debug['a'] && i == 0)
outa(c, cast, inuxi4, l+s+INITDAT);
for(; i<c; i++) {
buf.dbuf[l] = cast[inuxi4[i]];
l++;
}
break;
case 8:
cast = (uchar*)&o;
if(debug['a'] && i == 0)
outa(c, cast, inuxi8, l+s+INITDAT);
for(; i<c; i++) {
buf.dbuf[l] = cast[inuxi8[i]];
l++;
}
break;
}
break;
}
}
write(cout, buf.dbuf, n);
}
vlong
rnd(vlong v, vlong r)
{
vlong c;
if(r <= 0)
return v;
v += r - 1;
c = v % r;
if(c < 0)
c += r;
v -= c;
return v;
}
void
vputl(vlong v)
{
lputl(v);
lputl(v>>32);
}
void
machseg(char *name, vlong vaddr, vlong vsize, vlong foff, vlong fsize,
ulong prot1, ulong prot2, ulong nsect, ulong flag)
{
lputl(25); // section
lputl(72 + 80*nsect);
strnput(name, 16);
vputl(vaddr);
vputl(vsize);
vputl(foff);
vputl(fsize);
lputl(prot1);
lputl(prot2);
lputl(nsect);
lputl(flag);
}
void
machsect(char *name, char *seg, vlong addr, vlong size, ulong off,
ulong align, ulong reloc, ulong nreloc, ulong flag)
{
strnput(name, 16);
strnput(seg, 16);
vputl(addr);
vputl(size);
lputl(off);
lputl(align);
lputl(reloc);
lputl(nreloc);
lputl(flag);
lputl(0); /* reserved */
lputl(0); /* reserved */
lputl(0); /* reserved */
}
void
machstack(vlong e)
{
int i;
lputl(5); /* unix thread */
lputl((42+4)*4); /* total byte count */
lputl(4); /* thread type */
lputl(42); /* word count */
for(i=0; i<32; i++)
lputl(0);
vputl(e);
for(i=0; i<8; i++)
lputl(0);
}
ulong
machheadr(void)
{
ulong a;
a = 8; /* a.out header */
a += 18; /* page zero seg */
a += 18; /* text seg */
a += 20; /* text sect */
a += 18; /* data seg */
a += 20; /* data sect */
a += 20; /* bss sect */
a += 46; /* stack sect */
return a*4;
}

430
src/cmd/6l/l.h Normal file
View file

@ -0,0 +1,430 @@
// Inferno utils/6l/l.h
// http://code.google.com/p/inferno-os/source/browse/utils/6l/l.h
//
// 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.
#include <u.h>
#include <libc.h>
#include <bio.h>
#include "../6l/6.out.h"
#include "compat.h"
#ifndef EXTERN
#define EXTERN extern
#endif
#define P ((Prog*)0)
#define S ((Sym*)0)
#define TNAME (curtext?curtext->from.sym->name:noname)
#define cput(c)\
{ *cbp++ = c;\
if(--cbc <= 0)\
cflush(); }
typedef struct Adr Adr;
typedef struct Prog Prog;
typedef struct Sym Sym;
typedef struct Auto Auto;
typedef struct Optab Optab;
typedef struct Movtab Movtab;
struct Adr
{
union
{
vlong u0offset;
char u0scon[8];
Prog *u0cond; /* not used, but should be D_BRANCH */
Ieee u0ieee;
} u0;
union
{
Auto* u1autom;
Sym* u1sym;
} u1;
short type;
char index;
char scale;
};
#define offset u0.u0offset
#define scon u0.u0scon
#define cond u0.u0cond
#define ieee u0.u0ieee
#define autom u1.u1autom
#define sym u1.u1sym
struct Prog
{
Adr from;
Adr to;
Prog *forwd;
Prog* link;
Prog* pcond; /* work on this */
vlong pc;
long line;
uchar mark; /* work on these */
uchar back;
short as;
char width; /* fake for DATA */
char mode; /* 16, 32, or 64 */
};
struct Auto
{
Sym* asym;
Auto* link;
long aoffset;
short type;
};
struct Sym
{
char *name;
short type;
short version;
short become;
short frame;
uchar subtype;
ushort file;
vlong value;
long sig;
Sym* link;
};
struct Optab
{
short as;
uchar* ytab;
uchar prefix;
uchar op[20];
};
struct Movtab
{
short as;
uchar ft;
uchar tt;
uchar code;
uchar op[4];
};
enum
{
STEXT = 1,
SDATA,
SBSS,
SDATA1,
SXREF,
SFILE,
SCONST,
SUNDEF,
SIMPORT,
SEXPORT,
NHASH = 10007,
NHUNK = 100000,
MINSIZ = 8,
STRINGSZ = 200,
MINLC = 1,
MAXIO = 8192,
MAXHIST = 20, /* limit of path elements for history symbols */
Yxxx = 0,
Ynone,
Yi0,
Yi1,
Yi8,
Ys32,
Yi32,
Yi64,
Yiauto,
Yal,
Ycl,
Yax,
Ycx,
Yrb,
Yrl,
Yrf,
Yf0,
Yrx,
Ymb,
Yml,
Ym,
Ybr,
Ycol,
Ycs, Yss, Yds, Yes, Yfs, Ygs,
Ygdtr, Yidtr, Yldtr, Ymsw, Ytask,
Ycr0, Ycr1, Ycr2, Ycr3, Ycr4, Ycr5, Ycr6, Ycr7, Ycr8,
Ydr0, Ydr1, Ydr2, Ydr3, Ydr4, Ydr5, Ydr6, Ydr7,
Ytr0, Ytr1, Ytr2, Ytr3, Ytr4, Ytr5, Ytr6, Ytr7, Yrl32, Yrl64,
Ymr, Ymm,
Yxr, Yxm,
Ymax,
Zxxx = 0,
Zlit,
Z_rp,
Zbr,
Zcall,
Zib_,
Zib_rp,
Zibo_m,
Zibo_m_xm,
Zil_,
Zil_rp,
Ziq_rp,
Zilo_m,
Ziqo_m,
Zjmp,
Zloop,
Zo_iw,
Zm_o,
Zm_r,
Zm_r_xm,
Zm_r_i_xm,
Zm_r_3d,
Zm_r_xm_nr,
Zr_m_xm_nr,
Zibm_r, /* mmx1,mmx2/mem64,imm8 */
Zmb_r,
Zaut_r,
Zo_m,
Zo_m64,
Zpseudo,
Zr_m,
Zr_m_xm,
Zr_m_i_xm,
Zrp_,
Z_ib,
Z_il,
Zm_ibo,
Zm_ilo,
Zib_rr,
Zil_rr,
Zclr,
Zbyte,
Zmax,
Px = 0,
P32 = 0x32, /* 32-bit only */
Pe = 0x66, /* operand escape */
Pm = 0x0f, /* 2byte opcode escape */
Pq = 0xff, /* both escape */
Pb = 0xfe, /* byte operands */
Pf2 = 0xf2, /* xmm escape 1 */
Pf3 = 0xf3, /* xmm escape 2 */
Pw = 0x48, /* Rex.w */
Py = 0x80, /* defaults to 64-bit mode */
Rxf = 1<<9, /* internal flag for Rxr on from */
Rxt = 1<<8, /* internal flag for Rxr on to */
Rxw = 1<<3, /* =1, 64-bit operand size */
Rxr = 1<<2, /* extend modrm reg */
Rxx = 1<<1, /* extend sib index */
Rxb = 1<<0, /* extend modrm r/m, sib base, or opcode reg */
Roffset = 22, /* no. bits for offset in relocation address */
Rindex = 10, /* no. bits for index in relocation address */
Maxand = 10, /* in -a output width of the byte codes */
};
EXTERN union
{
struct
{
char obuf[MAXIO]; /* output buffer */
uchar ibuf[MAXIO]; /* input buffer */
} u;
char dbuf[1];
} buf;
#define cbuf u.obuf
#define xbuf u.ibuf
#pragma varargck type "A" uint
#pragma varargck type "D" Adr*
#pragma varargck type "P" Prog*
#pragma varargck type "R" int
#pragma varargck type "S" char*
EXTERN long HEADR;
EXTERN long HEADTYPE;
EXTERN vlong INITDAT;
EXTERN long INITRND;
EXTERN vlong INITTEXT;
EXTERN char* INITENTRY; /* entry point */
EXTERN Biobuf bso;
EXTERN long bsssize;
EXTERN int cbc;
EXTERN char* cbp;
EXTERN char* pcstr;
EXTERN int cout;
EXTERN Auto* curauto;
EXTERN Auto* curhist;
EXTERN Prog* curp;
EXTERN Prog* curtext;
EXTERN Prog* datap;
EXTERN Prog* edatap;
EXTERN vlong datsize;
EXTERN char debug[128];
EXTERN char literal[32];
EXTERN Prog* etextp;
EXTERN Prog* firstp;
EXTERN uchar fnuxi8[8];
EXTERN uchar fnuxi4[4];
EXTERN Sym* hash[NHASH];
EXTERN Sym* histfrog[MAXHIST];
EXTERN int histfrogp;
EXTERN int histgen;
EXTERN char* library[50];
EXTERN char* libraryobj[50];
EXTERN int libraryp;
EXTERN int xrefresolv;
EXTERN char* hunk;
EXTERN uchar inuxi1[1];
EXTERN uchar inuxi2[2];
EXTERN uchar inuxi4[4];
EXTERN uchar inuxi8[8];
EXTERN char ycover[Ymax*Ymax];
EXTERN uchar* andptr;
EXTERN uchar* rexptr;
EXTERN uchar and[30];
EXTERN int reg[D_NONE];
EXTERN int regrex[D_NONE+1];
EXTERN Prog* lastp;
EXTERN long lcsize;
EXTERN int nerrors;
EXTERN long nhunk;
EXTERN long nsymbol;
EXTERN char* noname;
EXTERN char* outfile;
EXTERN vlong pc;
EXTERN long spsize;
EXTERN Sym* symlist;
EXTERN long symsize;
EXTERN Prog* textp;
EXTERN vlong textsize;
EXTERN long thunk;
EXTERN int version;
EXTERN Prog zprg;
EXTERN int dtype;
EXTERN char* paramspace;
EXTERN Adr* reloca;
EXTERN int doexp, dlm;
EXTERN int imports, nimports;
EXTERN int exports, nexports;
EXTERN char* EXPTAB;
EXTERN Prog undefp;
#define UP (&undefp)
extern Optab optab[];
extern Optab* opindex[];
extern char* anames[];
int Aconv(Fmt*);
int Dconv(Fmt*);
int Pconv(Fmt*);
int Rconv(Fmt*);
int Sconv(Fmt*);
void addhist(long, int);
Prog* appendp(Prog*);
void asmb(void);
void asmdyn(void);
void asmins(Prog*);
void asmlc(void);
void asmsp(void);
void asmsym(void);
vlong atolwhex(char*);
Prog* brchain(Prog*);
Prog* brloop(Prog*);
void buildop(void);
void cflush(void);
void ckoff(Sym*, long);
Prog* copyp(Prog*);
double cputime(void);
void datblk(long, long);
void diag(char*, ...);
void dodata(void);
void doinit(void);
void doprof1(void);
void doprof2(void);
void dostkoff(void);
void dynreloc(Sym*, ulong, int);
vlong entryvalue(void);
void errorexit(void);
void export(void);
int find1(long, int);
int find2(long, int);
void follow(void);
void gethunk(void);
void histtoauto(void);
double ieeedtod(Ieee*);
long ieeedtof(Ieee*);
void import(void);
void ldobj(int, long, char*);
void loadlib(void);
void listinit(void);
Sym* lookup(char*, int);
void lput(long);
void lputl(long);
void main(int, char*[]);
void mkfwd(void);
void* mysbrk(ulong);
void nuxiinit(void);
void objfile(char*);
int opsize(Prog*);
void patch(void);
Prog* prg(void);
void readundefs(char*, int);
int relinv(int);
long reuse(Prog*, Sym*);
vlong rnd(vlong, vlong);
void span(void);
void undef(void);
void undefsym(Sym*);
vlong vaddr(Adr*);
void wput(ushort);
void xdefine(char*, int, vlong);
void xfol(Prog*);
int zaddr(uchar*, Adr*, Sym*[]);
void zerosig(char*);
void machseg(char*, vlong, vlong, vlong, vlong, ulong, ulong, ulong, ulong);
void machsect(char*, char*, vlong, vlong, ulong, ulong, ulong, ulong, ulong);
void machstack(vlong);
ulong machheadr(void);
#pragma varargck type "D" Adr*
#pragma varargck type "P" Prog*
#pragma varargck type "R" int
#pragma varargck type "A" int
#pragma varargck argpos diag 1

397
src/cmd/6l/list.c Normal file
View file

@ -0,0 +1,397 @@
// Inferno utils/6l/list.c
// http://code.google.com/p/inferno-os/source/browse/utils/6l/list.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.
#include "l.h"
static Prog* bigP;
void
listinit(void)
{
fmtinstall('R', Rconv);
fmtinstall('A', Aconv);
fmtinstall('D', Dconv);
fmtinstall('S', Sconv);
fmtinstall('P', Pconv);
}
int
Pconv(Fmt *fp)
{
char str[STRINGSZ], str1[STRINGSZ];
Prog *p;
p = va_arg(fp->args, Prog*);
bigP = p;
sprint(str1, "(%ld)", p->line);
switch(p->as) {
case ATEXT:
if(p->from.scale) {
sprint(str, "%-7s %-7A %D,%d,%D",
str1, p->as, &p->from, p->from.scale, &p->to);
break;
}
default:
sprint(str, "%-7s %-7A %D,%D",
str1, p->as, &p->from, &p->to);
break;
case ADATA:
case AINIT:
case ADYNT:
sprint(str, "%-7s %-7A %D/%d,%D",
str1, p->as, &p->from, p->from.scale, &p->to);
break;
}
bigP = P;
return fmtstrcpy(fp, str);
}
int
Aconv(Fmt *fp)
{
int i;
i = va_arg(fp->args, int);
return fmtstrcpy(fp, anames[i]);
}
int
Dconv(Fmt *fp)
{
char str[40], s[20];
Adr *a;
int i;
a = va_arg(fp->args, Adr*);
i = a->type;
if(i >= D_INDIR) {
if(a->offset)
sprint(str, "%lld(%R)", a->offset, i-D_INDIR);
else
sprint(str, "(%R)", i-D_INDIR);
goto brk;
}
switch(i) {
default:
if(a->offset)
sprint(str, "$%lld,%R", a->offset, i);
else
sprint(str, "%R", i);
break;
case D_NONE:
str[0] = 0;
break;
case D_BRANCH:
if(bigP != P && bigP->pcond != P)
if(a->sym != S)
sprint(str, "%llux+%s", bigP->pcond->pc,
a->sym->name);
else
sprint(str, "%llux", bigP->pcond->pc);
else
sprint(str, "%lld(PC)", a->offset);
break;
case D_EXTERN:
if(a->sym) {
sprint(str, "%s+%lld(SB)", a->sym->name, a->offset);
break;
}
sprint(str, "!!noname!!+%lld(SB)", a->offset);
break;
case D_STATIC:
if(a->sym) {
sprint(str, "%s<%d>+%lld(SB)", a->sym->name,
a->sym->version, a->offset);
break;
}
sprint(str, "!!noname!!<999>+%lld(SB)", a->offset);
break;
case D_AUTO:
if(a->sym) {
sprint(str, "%s+%lld(SP)", a->sym->name, a->offset);
break;
}
sprint(str, "!!noname!!+%lld(SP)", a->offset);
break;
case D_PARAM:
if(a->sym) {
sprint(str, "%s+%lld(%s)", a->sym->name, a->offset, paramspace);
break;
}
sprint(str, "!!noname!!+%lld(%s)", a->offset, paramspace);
break;
case D_CONST:
sprint(str, "$%lld", a->offset);
break;
case D_FCONST:
sprint(str, "$(%.8lux,%.8lux)", a->ieee.h, a->ieee.l);
break;
case D_SCONST:
sprint(str, "$\"%S\"", a->scon);
break;
case D_ADDR:
a->type = a->index;
a->index = D_NONE;
sprint(str, "$%D", a);
a->index = a->type;
a->type = D_ADDR;
goto conv;
}
brk:
if(a->index != D_NONE) {
sprint(s, "(%R*%d)", a->index, a->scale);
strcat(str, s);
}
conv:
return fmtstrcpy(fp, str);
}
char* regstr[] =
{
"AL", /* [D_AL] */
"CL",
"DL",
"BL",
"SPB",
"BPB",
"SIB",
"DIB",
"R8B",
"R9B",
"R10B",
"R11B",
"R12B",
"R13B",
"R14B",
"R15B",
"AX", /* [D_AX] */
"CX",
"DX",
"BX",
"SP",
"BP",
"SI",
"DI",
"R8",
"R9",
"R10",
"R11",
"R12",
"R13",
"R14",
"R15",
"AH",
"CH",
"DH",
"BH",
"F0", /* [D_F0] */
"F1",
"F2",
"F3",
"F4",
"F5",
"F6",
"F7",
"M0",
"M1",
"M2",
"M3",
"M4",
"M5",
"M6",
"M7",
"X0",
"X1",
"X2",
"X3",
"X4",
"X5",
"X6",
"X7",
"X8",
"X9",
"X10",
"X11",
"X12",
"X13",
"X14",
"X15",
"CS", /* [D_CS] */
"SS",
"DS",
"ES",
"FS",
"GS",
"GDTR", /* [D_GDTR] */
"IDTR", /* [D_IDTR] */
"LDTR", /* [D_LDTR] */
"MSW", /* [D_MSW] */
"TASK", /* [D_TASK] */
"CR0", /* [D_CR] */
"CR1",
"CR2",
"CR3",
"CR4",
"CR5",
"CR6",
"CR7",
"CR8",
"CR9",
"CR10",
"CR11",
"CR12",
"CR13",
"CR14",
"CR15",
"DR0", /* [D_DR] */
"DR1",
"DR2",
"DR3",
"DR4",
"DR5",
"DR6",
"DR7",
"TR0", /* [D_TR] */
"TR1",
"TR2",
"TR3",
"TR4",
"TR5",
"TR6",
"TR7",
"NONE", /* [D_NONE] */
};
int
Rconv(Fmt *fp)
{
char str[20];
int r;
r = va_arg(fp->args, int);
if(r >= D_AL && r <= D_NONE)
sprint(str, "%s", regstr[r-D_AL]);
else
sprint(str, "gok(%d)", r);
return fmtstrcpy(fp, str);
}
int
Sconv(Fmt *fp)
{
int i, c;
char str[30], *p, *a;
a = va_arg(fp->args, char*);
p = str;
for(i=0; i<sizeof(double); i++) {
c = a[i] & 0xff;
if(c >= 'a' && c <= 'z' ||
c >= 'A' && c <= 'Z' ||
c >= '0' && c <= '9') {
*p++ = c;
continue;
}
*p++ = '\\';
switch(c) {
default:
if(c < 040 || c >= 0177)
break; /* not portable */
p[-1] = c;
continue;
case 0:
*p++ = 'z';
continue;
case '\\':
case '"':
*p++ = c;
continue;
case '\n':
*p++ = 'n';
continue;
case '\t':
*p++ = 't';
continue;
}
*p++ = (c>>6) + '0';
*p++ = ((c>>3) & 7) + '0';
*p++ = (c & 7) + '0';
}
*p = 0;
return fmtstrcpy(fp, str);
}
void
diag(char *fmt, ...)
{
char buf[STRINGSZ], *tn;
va_list arg;
tn = "??none??";
if(curtext != P && curtext->from.sym != S)
tn = curtext->from.sym->name;
va_start(arg, fmt);
vseprint(buf, buf+sizeof(buf), fmt, arg);
va_end(arg);
print("%s: %s\n", tn, buf);
nerrors++;
if(nerrors > 20) {
print("too many errors\n");
errorexit();
}
}

45
src/cmd/6l/mkenam Normal file
View file

@ -0,0 +1,45 @@
# Inferno utils/6c/mkenam
# http://code.google.com/p/inferno-os/source/browse/utils/6c/mkenam
#
# 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.
ed - ../6l/6.out.h <<'!'
v/^ A/d
,s/^ A/ "/
g/ .*$/s///
,s/,*$/",/
1i
char* anames[] =
{
.
$a
};
.
w enam.c
Q
!

1595
src/cmd/6l/obj.c Normal file

File diff suppressed because it is too large Load diff

1213
src/cmd/6l/optab.c Normal file

File diff suppressed because it is too large Load diff

820
src/cmd/6l/pass.c Normal file
View file

@ -0,0 +1,820 @@
// Inferno utils/6l/pass.c
// http://code.google.com/p/inferno-os/source/browse/utils/6l/pass.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.
#include "l.h"
void
dodata(void)
{
int i;
Sym *s;
Prog *p;
long t, u;
if(debug['v'])
Bprint(&bso, "%5.2f dodata\n", cputime());
Bflush(&bso);
for(p = datap; p != P; p = p->link) {
s = p->from.sym;
if(p->as == ADYNT || p->as == AINIT)
s->value = dtype;
if(s->type == SBSS)
s->type = SDATA;
if(s->type != SDATA)
diag("initialize non-data (%d): %s\n%P",
s->type, s->name, p);
t = p->from.offset + p->width;
if(t > s->value)
diag("initialize bounds (%lld): %s\n%P",
s->value, s->name, p);
}
/* allocate small guys */
datsize = 0;
for(i=0; i<NHASH; i++)
for(s = hash[i]; s != S; s = s->link) {
if(s->type != SDATA)
if(s->type != SBSS)
continue;
t = s->value;
if(t == 0) {
diag("%s: no size", s->name);
t = 1;
}
t = rnd(t, 4);
s->value = t;
if(t > MINSIZ)
continue;
if(t >= 8)
datsize = rnd(datsize, 8);
s->value = datsize;
datsize += t;
s->type = SDATA1;
}
/* allocate the rest of the data */
for(i=0; i<NHASH; i++)
for(s = hash[i]; s != S; s = s->link) {
if(s->type != SDATA) {
if(s->type == SDATA1)
s->type = SDATA;
continue;
}
t = s->value;
if(t >= 8)
datsize = rnd(datsize, 8);
s->value = datsize;
datsize += t;
}
if(datsize)
datsize = rnd(datsize, 8);
if(debug['j']) {
/*
* pad data with bss that fits up to next
* 8k boundary, then push data to 8k
*/
u = rnd(datsize, 8192);
u -= datsize;
for(i=0; i<NHASH; i++)
for(s = hash[i]; s != S; s = s->link) {
if(s->type != SBSS)
continue;
t = s->value;
if(t > u)
continue;
u -= t;
s->value = datsize;
s->type = SDATA;
datsize += t;
}
datsize += u;
}
/* now the bss */
bsssize = 0;
for(i=0; i<NHASH; i++)
for(s = hash[i]; s != S; s = s->link) {
if(s->type != SBSS)
continue;
t = s->value;
if(t >= 8)
bsssize = rnd(bsssize, 8);
s->value = bsssize + datsize;
bsssize += t;
}
xdefine("edata", SBSS, datsize);
xdefine("end", SBSS, bsssize + datsize);
}
Prog*
brchain(Prog *p)
{
int i;
for(i=0; i<20; i++) {
if(p == P || p->as != AJMP)
return p;
p = p->pcond;
}
return P;
}
void
follow(void)
{
if(debug['v'])
Bprint(&bso, "%5.2f follow\n", cputime());
Bflush(&bso);
firstp = prg();
lastp = firstp;
xfol(textp);
lastp->link = P;
firstp = firstp->link;
}
void
xfol(Prog *p)
{
Prog *q;
int i;
enum as a;
loop:
if(p == P)
return;
if(p->as == ATEXT)
curtext = p;
if(p->as == AJMP)
if((q = p->pcond) != P) {
p->mark = 1;
p = q;
if(p->mark == 0)
goto loop;
}
if(p->mark) {
/* copy up to 4 instructions to avoid branch */
for(i=0,q=p; i<4; i++,q=q->link) {
if(q == P)
break;
if(q == lastp)
break;
a = q->as;
if(a == ANOP) {
i--;
continue;
}
switch(a) {
case AJMP:
case ARET:
case AIRETL:
case AIRETQ:
case AIRETW:
case ARETFL:
case ARETFQ:
case ARETFW:
case APUSHL:
case APUSHFL:
case APUSHQ:
case APUSHFQ:
case APUSHW:
case APUSHFW:
case APOPL:
case APOPFL:
case APOPQ:
case APOPFQ:
case APOPW:
case APOPFW:
goto brk;
}
if(q->pcond == P || q->pcond->mark)
continue;
if(a == ACALL || a == ALOOP)
continue;
for(;;) {
if(p->as == ANOP) {
p = p->link;
continue;
}
q = copyp(p);
p = p->link;
q->mark = 1;
lastp->link = q;
lastp = q;
if(q->as != a || q->pcond == P || q->pcond->mark)
continue;
q->as = relinv(q->as);
p = q->pcond;
q->pcond = q->link;
q->link = p;
xfol(q->link);
p = q->link;
if(p->mark)
return;
goto loop;
}
} /* */
brk:;
q = prg();
q->as = AJMP;
q->line = p->line;
q->to.type = D_BRANCH;
q->to.offset = p->pc;
q->pcond = p;
p = q;
}
p->mark = 1;
lastp->link = p;
lastp = p;
a = p->as;
if(a == AJMP || a == ARET || a == AIRETL || a == AIRETQ || a == AIRETW ||
a == ARETFL || a == ARETFQ || a == ARETFW)
return;
if(p->pcond != P)
if(a != ACALL) {
q = brchain(p->link);
if(q != P && q->mark)
if(a != ALOOP) {
p->as = relinv(a);
p->link = p->pcond;
p->pcond = q;
}
xfol(p->link);
q = brchain(p->pcond);
if(q->mark) {
p->pcond = q;
return;
}
p = q;
goto loop;
}
p = p->link;
goto loop;
}
int
relinv(int a)
{
switch(a) {
case AJEQ: return AJNE;
case AJNE: return AJEQ;
case AJLE: return AJGT;
case AJLS: return AJHI;
case AJLT: return AJGE;
case AJMI: return AJPL;
case AJGE: return AJLT;
case AJPL: return AJMI;
case AJGT: return AJLE;
case AJHI: return AJLS;
case AJCS: return AJCC;
case AJCC: return AJCS;
case AJPS: return AJPC;
case AJPC: return AJPS;
case AJOS: return AJOC;
case AJOC: return AJOS;
}
diag("unknown relation: %s in %s", anames[a], TNAME);
return a;
}
void
doinit(void)
{
Sym *s;
Prog *p;
int x;
for(p = datap; p != P; p = p->link) {
x = p->to.type;
if(x != D_EXTERN && x != D_STATIC)
continue;
s = p->to.sym;
if(s->type == 0 || s->type == SXREF)
diag("undefined %s initializer of %s",
s->name, p->from.sym->name);
p->to.offset += s->value;
p->to.type = D_CONST;
if(s->type == SDATA || s->type == SBSS)
p->to.offset += INITDAT;
}
}
void
patch(void)
{
long c;
Prog *p, *q;
Sym *s;
long vexit;
if(debug['v'])
Bprint(&bso, "%5.2f mkfwd\n", cputime());
Bflush(&bso);
mkfwd();
if(debug['v'])
Bprint(&bso, "%5.2f patch\n", cputime());
Bflush(&bso);
s = lookup("exit", 0);
vexit = s->value;
for(p = firstp; p != P; p = p->link) {
if(p->as == ATEXT)
curtext = p;
if(p->as == ACALL || p->as == ARET) {
s = p->to.sym;
if(s) {
if(debug['c'])
Bprint(&bso, "%s calls %s\n", TNAME, s->name);
switch(s->type) {
default:
diag("undefined: %s in %s", s->name, TNAME);
s->type = STEXT;
s->value = vexit;
break; /* or fall through to set offset? */
case STEXT:
p->to.offset = s->value;
break;
case SUNDEF:
p->pcond = UP;
p->to.offset = 0;
break;
}
p->to.type = D_BRANCH;
}
}
if(p->to.type != D_BRANCH || p->pcond == UP)
continue;
c = p->to.offset;
for(q = firstp; q != P;) {
if(q->forwd != P)
if(c >= q->forwd->pc) {
q = q->forwd;
continue;
}
if(c == q->pc)
break;
q = q->link;
}
if(q == P) {
diag("branch out of range in %s\n%P", TNAME, p);
p->to.type = D_NONE;
}
p->pcond = q;
}
for(p = firstp; p != P; p = p->link) {
if(p->as == ATEXT)
curtext = p;
p->mark = 0; /* initialization for follow */
if(p->pcond != P && p->pcond != UP) {
p->pcond = brloop(p->pcond);
if(p->pcond != P)
if(p->to.type == D_BRANCH)
p->to.offset = p->pcond->pc;
}
}
}
#define LOG 5
void
mkfwd(void)
{
Prog *p;
int i;
long dwn[LOG], cnt[LOG];
Prog *lst[LOG];
for(i=0; i<LOG; i++) {
if(i == 0)
cnt[i] = 1; else
cnt[i] = LOG * cnt[i-1];
dwn[i] = 1;
lst[i] = P;
}
i = 0;
for(p = firstp; p != P; p = p->link) {
if(p->as == ATEXT)
curtext = p;
i--;
if(i < 0)
i = LOG-1;
p->forwd = P;
dwn[i]--;
if(dwn[i] <= 0) {
dwn[i] = cnt[i];
if(lst[i] != P)
lst[i]->forwd = p;
lst[i] = p;
}
}
}
Prog*
brloop(Prog *p)
{
int c;
Prog *q;
c = 0;
for(q = p; q != P; q = q->pcond) {
if(q->as != AJMP)
break;
c++;
if(c >= 5000)
return P;
}
return q;
}
void
dostkoff(void)
{
Prog *p, *q;
long autoffset, deltasp;
int a, f, curframe, curbecome, maxbecome, pcsize;
curframe = 0;
curbecome = 0;
maxbecome = 0;
curtext = 0;
for(p = firstp; p != P; p = p->link) {
/* find out how much arg space is used in this TEXT */
if(p->to.type == (D_INDIR+D_SP))
if(p->to.offset > curframe)
curframe = p->to.offset;
switch(p->as) {
case ATEXT:
if(curtext && curtext->from.sym) {
curtext->from.sym->frame = curframe;
curtext->from.sym->become = curbecome;
if(curbecome > maxbecome)
maxbecome = curbecome;
}
curframe = 0;
curbecome = 0;
curtext = p;
break;
case ARET:
/* special form of RET is BECOME */
if(p->from.type == D_CONST)
if(p->from.offset > curbecome)
curbecome = p->from.offset;
break;
}
}
if(curtext && curtext->from.sym) {
curtext->from.sym->frame = curframe;
curtext->from.sym->become = curbecome;
if(curbecome > maxbecome)
maxbecome = curbecome;
}
if(debug['b'])
print("max become = %d\n", maxbecome);
xdefine("ALEFbecome", STEXT, maxbecome);
curtext = 0;
for(p = firstp; p != P; p = p->link) {
switch(p->as) {
case ATEXT:
curtext = p;
break;
case ACALL:
if(curtext != P && curtext->from.sym != S && curtext->to.offset >= 0) {
f = maxbecome - curtext->from.sym->frame;
if(f <= 0)
break;
/* calling a become or calling a variable */
if(p->to.sym == S || p->to.sym->become) {
curtext->to.offset += f;
if(debug['b']) {
curp = p;
print("%D calling %D increase %d\n",
&curtext->from, &p->to, f);
}
}
}
break;
}
}
autoffset = 0;
deltasp = 0;
for(p = firstp; p != P; p = p->link) {
if(p->as == ATEXT) {
curtext = p;
autoffset = p->to.offset;
if(autoffset < 0)
autoffset = 0;
if(autoffset) {
p = appendp(p);
p->as = AADJSP;
p->from.type = D_CONST;
p->from.offset = autoffset;
}
deltasp = autoffset;
}
pcsize = p->mode/8;
a = p->from.type;
if(a == D_AUTO)
p->from.offset += deltasp;
if(a == D_PARAM)
p->from.offset += deltasp + pcsize;
a = p->to.type;
if(a == D_AUTO)
p->to.offset += deltasp;
if(a == D_PARAM)
p->to.offset += deltasp + pcsize;
switch(p->as) {
default:
continue;
case APUSHL:
case APUSHFL:
deltasp += 4;
continue;
case APUSHQ:
case APUSHFQ:
deltasp += 8;
continue;
case APUSHW:
case APUSHFW:
deltasp += 2;
continue;
case APOPL:
case APOPFL:
deltasp -= 4;
continue;
case APOPQ:
case APOPFQ:
deltasp -= 8;
continue;
case APOPW:
case APOPFW:
deltasp -= 2;
continue;
case ARET:
break;
}
if(autoffset != deltasp)
diag("unbalanced PUSH/POP");
if(p->from.type == D_CONST)
goto become;
if(autoffset) {
q = p;
p = appendp(p);
p->as = ARET;
q->as = AADJSP;
q->from.type = D_CONST;
q->from.offset = -autoffset;
}
continue;
become:
q = p;
p = appendp(p);
p->as = AJMP;
p->to = q->to;
p->pcond = q->pcond;
q->as = AADJSP;
q->from = zprg.from;
q->from.type = D_CONST;
q->from.offset = -autoffset;
q->to = zprg.to;
continue;
}
}
vlong
atolwhex(char *s)
{
vlong n;
int f;
n = 0;
f = 0;
while(*s == ' ' || *s == '\t')
s++;
if(*s == '-' || *s == '+') {
if(*s++ == '-')
f = 1;
while(*s == ' ' || *s == '\t')
s++;
}
if(s[0]=='0' && s[1]){
if(s[1]=='x' || s[1]=='X'){
s += 2;
for(;;){
if(*s >= '0' && *s <= '9')
n = n*16 + *s++ - '0';
else if(*s >= 'a' && *s <= 'f')
n = n*16 + *s++ - 'a' + 10;
else if(*s >= 'A' && *s <= 'F')
n = n*16 + *s++ - 'A' + 10;
else
break;
}
} else
while(*s >= '0' && *s <= '7')
n = n*8 + *s++ - '0';
} else
while(*s >= '0' && *s <= '9')
n = n*10 + *s++ - '0';
if(f)
n = -n;
return n;
}
void
undef(void)
{
int i;
Sym *s;
for(i=0; i<NHASH; i++)
for(s = hash[i]; s != S; s = s->link)
if(s->type == SXREF)
diag("%s: not defined", s->name);
}
void
import(void)
{
int i;
Sym *s;
for(i = 0; i < NHASH; i++)
for(s = hash[i]; s != S; s = s->link)
if(s->sig != 0 && s->type == SXREF && (nimports == 0 || s->subtype == SIMPORT)){
if(s->value != 0)
diag("value != 0 on SXREF");
undefsym(s);
Bprint(&bso, "IMPORT: %s sig=%lux v=%lld\n", s->name, s->sig, s->value);
if(debug['S'])
s->sig = 0;
}
}
void
ckoff(Sym *s, long v)
{
if(v < 0 || v >= 1<<Roffset)
diag("relocation offset %ld for %s out of range", v, s->name);
}
static Prog*
newdata(Sym *s, int o, int w, int t)
{
Prog *p;
p = prg();
if(edatap == P)
datap = p;
else
edatap->link = p;
edatap = p;
p->as = ADATA;
p->width = w;
p->from.scale = w;
p->from.type = t;
p->from.sym = s;
p->from.offset = o;
p->to.type = D_CONST;
return p;
}
void
export(void)
{
int i, j, n, off, nb, sv, ne;
Sym *s, *et, *str, **esyms;
Prog *p;
char buf[NSNAME], *t;
n = 0;
for(i = 0; i < NHASH; i++)
for(s = hash[i]; s != S; s = s->link)
if(s->sig != 0 && s->type != SXREF && s->type != SUNDEF && (nexports == 0 || s->subtype == SEXPORT))
n++;
esyms = malloc(n*sizeof(Sym*));
ne = n;
n = 0;
for(i = 0; i < NHASH; i++)
for(s = hash[i]; s != S; s = s->link)
if(s->sig != 0 && s->type != SXREF && s->type != SUNDEF && (nexports == 0 || s->subtype == SEXPORT))
esyms[n++] = s;
for(i = 0; i < ne-1; i++)
for(j = i+1; j < ne; j++)
if(strcmp(esyms[i]->name, esyms[j]->name) > 0){
s = esyms[i];
esyms[i] = esyms[j];
esyms[j] = s;
}
nb = 0;
off = 0;
et = lookup(EXPTAB, 0);
if(et->type != 0 && et->type != SXREF)
diag("%s already defined", EXPTAB);
et->type = SDATA;
str = lookup(".string", 0);
if(str->type == 0)
str->type = SDATA;
sv = str->value;
for(i = 0; i < ne; i++){
s = esyms[i];
if(debug['S'])
s->sig = 0;
/* Bprint(&bso, "EXPORT: %s sig=%lux t=%d\n", s->name, s->sig, s->type); */
/* signature */
p = newdata(et, off, sizeof(long), D_EXTERN);
off += sizeof(long);
p->to.offset = s->sig;
/* address */
p = newdata(et, off, sizeof(long), D_EXTERN);
off += sizeof(long);
p->to.type = D_ADDR;
p->to.index = D_EXTERN;
p->to.sym = s;
/* string */
t = s->name;
n = strlen(t)+1;
for(;;){
buf[nb++] = *t;
sv++;
if(nb >= NSNAME){
p = newdata(str, sv-NSNAME, NSNAME, D_STATIC);
p->to.type = D_SCONST;
memmove(p->to.scon, buf, NSNAME);
nb = 0;
}
if(*t++ == 0)
break;
}
/* name */
p = newdata(et, off, sizeof(long), D_EXTERN);
off += sizeof(long);
p->to.type = D_ADDR;
p->to.index = D_STATIC;
p->to.sym = str;
p->to.offset = sv-n;
}
if(nb > 0){
p = newdata(str, sv-nb, nb, D_STATIC);
p->to.type = D_SCONST;
memmove(p->to.scon, buf, nb);
}
for(i = 0; i < 3; i++){
newdata(et, off, sizeof(long), D_EXTERN);
off += sizeof(long);
}
et->value = off;
if(sv == 0)
sv = 1;
str->value = sv;
exports = ne;
free(esyms);
}

1776
src/cmd/6l/span.c Normal file

File diff suppressed because it is too large Load diff

331
src/cmd/cc/acid.c Normal file
View file

@ -0,0 +1,331 @@
// Inferno utils/cc/acid.c
// http://code.google.com/p/inferno-os/source/browse/utils/cc/acid.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.
#include "cc.h"
static char *kwd[] =
{
"$adt", "$aggr", "$append", "$complex", "$defn",
"$delete", "$do", "$else", "$eval", "$head", "$if",
"$local", "$loop", "$return", "$tail", "$then",
"$union", "$whatis", "$while",
};
char*
amap(char *s)
{
int i, bot, top, new;
bot = 0;
top = bot + nelem(kwd) - 1;
while(bot <= top){
new = bot + (top - bot)/2;
i = strcmp(kwd[new]+1, s);
if(i == 0)
return kwd[new];
if(i < 0)
bot = new + 1;
else
top = new - 1;
}
return s;
}
Sym*
acidsue(Type *t)
{
int h;
Sym *s;
if(t != T)
for(h=0; h<nelem(hash); h++)
for(s = hash[h]; s != S; s = s->link)
if(s->suetag && s->suetag->link == t)
return s;
return 0;
}
Sym*
acidfun(Type *t)
{
int h;
Sym *s;
for(h=0; h<nelem(hash); h++)
for(s = hash[h]; s != S; s = s->link)
if(s->type == t)
return s;
return 0;
}
char acidchar[NTYPE];
Init acidcinit[] =
{
TCHAR, 'C', 0,
TUCHAR, 'b', 0,
TSHORT, 'd', 0,
TUSHORT, 'u', 0,
TLONG, 'D', 0,
TULONG, 'U', 0,
TVLONG, 'V', 0,
TUVLONG, 'W', 0,
TFLOAT, 'f', 0,
TDOUBLE, 'F', 0,
TARRAY, 'a', 0,
TIND, 'X', 0,
-1, 0, 0,
};
static void
acidinit(void)
{
Init *p;
for(p=acidcinit; p->code >= 0; p++)
acidchar[p->code] = p->value;
acidchar[TINT] = acidchar[TLONG];
acidchar[TUINT] = acidchar[TULONG];
if(types[TINT]->width != types[TLONG]->width) {
acidchar[TINT] = acidchar[TSHORT];
acidchar[TUINT] = acidchar[TUSHORT];
if(types[TINT]->width != types[TSHORT]->width)
warn(Z, "acidmember int not long or short");
}
}
void
acidmember(Type *t, long off, int flag)
{
Sym *s, *s1;
Type *l;
static int acidcharinit = 0;
if(acidcharinit == 0) {
acidinit();
acidcharinit = 1;
}
s = t->sym;
switch(t->etype) {
default:
Bprint(&outbuf, " T%d\n", t->etype);
break;
case TIND:
if(s == S)
break;
if(flag) {
for(l=t; l->etype==TIND; l=l->link)
;
if(typesu[l->etype]) {
s1 = acidsue(l->link);
if(s1 != S) {
Bprint(&outbuf, " 'A' %s %ld %s;\n",
amap(s1->name),
t->offset+off, amap(s->name));
break;
}
}
} else {
Bprint(&outbuf,
"\tprint(\"\t%s\t\", addr.%s\\X, \"\\n\");\n",
amap(s->name), amap(s->name));
break;
}
case TINT:
case TUINT:
case TCHAR:
case TUCHAR:
case TSHORT:
case TUSHORT:
case TLONG:
case TULONG:
case TVLONG:
case TUVLONG:
case TFLOAT:
case TDOUBLE:
case TARRAY:
if(s == S)
break;
if(flag) {
Bprint(&outbuf, " '%c' %ld %s;\n",
acidchar[t->etype], t->offset+off, amap(s->name));
} else {
Bprint(&outbuf, "\tprint(\"\t%s\t\", addr.%s, \"\\n\");\n",
amap(s->name), amap(s->name));
}
break;
case TSTRUCT:
case TUNION:
s1 = acidsue(t->link);
if(s1 == S)
break;
if(flag) {
if(s == S) {
Bprint(&outbuf, " {\n");
for(l = t->link; l != T; l = l->down)
acidmember(l, t->offset+off, flag);
Bprint(&outbuf, " };\n");
} else {
Bprint(&outbuf, " %s %ld %s;\n",
amap(s1->name),
t->offset+off, amap(s->name));
}
} else {
if(s != S) {
Bprint(&outbuf, "\tprint(\"%s %s {\\n\");\n",
amap(s1->name), amap(s->name));
Bprint(&outbuf, "\t%s(addr.%s);\n",
amap(s1->name), amap(s->name));
Bprint(&outbuf, "\tprint(\"}\\n\");\n");
} else {
Bprint(&outbuf, "\tprint(\"%s {\\n\");\n",
amap(s1->name));
Bprint(&outbuf, "\t\t%s(addr+%ld);\n",
amap(s1->name), t->offset+off);
Bprint(&outbuf, "\tprint(\"}\\n\");\n");
}
}
break;
}
}
void
acidtype(Type *t)
{
Sym *s;
Type *l;
Io *i;
int n;
char *an;
if(!debug['a'])
return;
if(debug['a'] > 1) {
n = 0;
for(i=iostack; i; i=i->link)
n++;
if(n > 1)
return;
}
s = acidsue(t->link);
if(s == S)
return;
switch(t->etype) {
default:
Bprint(&outbuf, "T%d\n", t->etype);
return;
case TUNION:
case TSTRUCT:
if(debug['s'])
goto asmstr;
an = amap(s->name);
Bprint(&outbuf, "sizeof%s = %ld;\n", an, t->width);
Bprint(&outbuf, "aggr %s\n{\n", an);
for(l = t->link; l != T; l = l->down)
acidmember(l, 0, 1);
Bprint(&outbuf, "};\n\n");
Bprint(&outbuf, "defn\n%s(addr) {\n\tcomplex %s addr;\n", an, an);
for(l = t->link; l != T; l = l->down)
acidmember(l, 0, 0);
Bprint(&outbuf, "};\n\n");
break;
asmstr:
if(s == S)
break;
for(l = t->link; l != T; l = l->down)
if(l->sym != S)
Bprint(&outbuf, "#define\t%s.%s\t%ld\n",
s->name,
l->sym->name,
l->offset);
break;
}
}
void
acidvar(Sym *s)
{
int n;
Io *i;
Type *t;
Sym *s1, *s2;
if(!debug['a'] || debug['s'])
return;
if(debug['a'] > 1) {
n = 0;
for(i=iostack; i; i=i->link)
n++;
if(n > 1)
return;
}
t = s->type;
while(t && t->etype == TIND)
t = t->link;
if(t == T)
return;
if(t->etype == TENUM) {
Bprint(&outbuf, "%s = ", amap(s->name));
if(!typefd[t->etype])
Bprint(&outbuf, "%lld;\n", s->vconst);
else
Bprint(&outbuf, "%f\n;", s->fconst);
return;
}
if(!typesu[t->etype])
return;
s1 = acidsue(t->link);
if(s1 == S)
return;
switch(s->class) {
case CAUTO:
case CPARAM:
s2 = acidfun(thisfn);
if(s2)
Bprint(&outbuf, "complex %s %s:%s;\n",
amap(s1->name), amap(s2->name), amap(s->name));
break;
case CSTATIC:
case CEXTERN:
case CGLOBL:
case CLOCAL:
Bprint(&outbuf, "complex %s %s;\n",
amap(s1->name), amap(s->name));
break;
}
}

119
src/cmd/cc/bits.c Normal file
View file

@ -0,0 +1,119 @@
// Inferno utils/cc/bits.c
// http://code.google.com/p/inferno-os/source/browse/utils/cc/bits.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.
#include "cc.h"
Bits
bor(Bits a, Bits b)
{
Bits c;
int i;
for(i=0; i<BITS; i++)
c.b[i] = a.b[i] | b.b[i];
return c;
}
Bits
band(Bits a, Bits b)
{
Bits c;
int i;
for(i=0; i<BITS; i++)
c.b[i] = a.b[i] & b.b[i];
return c;
}
/*
Bits
bnot(Bits a)
{
Bits c;
int i;
for(i=0; i<BITS; i++)
c.b[i] = ~a.b[i];
return c;
}
*/
int
bany(Bits *a)
{
int i;
for(i=0; i<BITS; i++)
if(a->b[i])
return 1;
return 0;
}
int
beq(Bits a, Bits b)
{
int i;
for(i=0; i<BITS; i++)
if(a.b[i] != b.b[i])
return 0;
return 1;
}
int
bnum(Bits a)
{
int i;
long b;
for(i=0; i<BITS; i++)
if(b = a.b[i])
return 32*i + bitno(b);
diag(Z, "bad in bnum");
return 0;
}
Bits
blsh(uint n)
{
Bits c;
c = zbits;
c.b[n/32] = 1L << (n%32);
return c;
}
int
bset(Bits a, uint n)
{
if(a.b[n/32] & (1L << (n%32)))
return 1;
return 0;
}

795
src/cmd/cc/cc.h Normal file
View file

@ -0,0 +1,795 @@
// Inferno utils/cc/cc.h
// http://code.google.com/p/inferno-os/source/browse/utils/cc/cc.h
//
// 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.
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <ctype.h>
#include "compat.h"
#pragma lib "../cc/cc.a$O"
#ifndef EXTERN
#define EXTERN extern
#endif
typedef struct Node Node;
typedef struct Sym Sym;
typedef struct Type Type;
typedef struct Funct Funct;
typedef struct Decl Decl;
typedef struct Io Io;
typedef struct Hist Hist;
typedef struct Term Term;
typedef struct Init Init;
typedef struct Bits Bits;
#define NHUNK 50000L
#define BUFSIZ 8192
#define NSYMB 500
#define NHASH 1024
#define STRINGSZ 200
#define HISTSZ 20
#define YYMAXDEPTH 500
#define NTERM 10
#define MAXALIGN 7
#define SIGN(n) ((vlong)1<<(n-1))
#define MASK(n) (SIGN(n)|(SIGN(n)-1))
#define BITS 5
#define NVAR (BITS*sizeof(ulong)*8)
struct Bits
{
ulong b[BITS];
};
struct Node
{
Node* left;
Node* right;
void* label;
long pc;
int reg;
long xoffset;
double fconst; /* fp constant */
vlong vconst; /* non fp const */
char* cstring; /* character string */
ushort* rstring; /* rune string */
Sym* sym;
Type* type;
long lineno;
uchar op;
uchar oldop;
uchar xcast;
uchar class;
uchar etype;
uchar complex;
uchar addable;
uchar scale;
uchar garb;
};
#define Z ((Node*)0)
struct Sym
{
Sym* link;
Type* type;
Type* suetag;
Type* tenum;
char* macro;
long varlineno;
long offset;
vlong vconst;
double fconst;
Node* label;
ushort lexical;
char *name;
ushort block;
ushort sueblock;
uchar class;
uchar sym;
uchar aused;
uchar sig;
};
#define S ((Sym*)0)
enum{
SIGNONE = 0,
SIGDONE = 1,
SIGINTERN = 2,
SIGNINTERN = 1729*325*1729,
};
struct Decl
{
Decl* link;
Sym* sym;
Type* type;
long varlineno;
long offset;
short val;
ushort block;
uchar class;
uchar aused;
};
#define D ((Decl*)0)
struct Type
{
Sym* sym;
Sym* tag;
Funct* funct;
Type* link;
Type* down;
long width;
long offset;
long lineno;
uchar shift;
uchar nbits;
uchar etype;
uchar garb;
};
#define T ((Type*)0)
#define NODECL ((void(*)(int, Type*, Sym*))0)
struct Init /* general purpose initialization */
{
int code;
ulong value;
char* s;
};
EXTERN struct
{
char* p;
int c;
} fi;
struct Io
{
Io* link;
char* p;
char b[BUFSIZ];
short c;
short f;
};
#define I ((Io*)0)
struct Hist
{
Hist* link;
char* name;
long line;
long offset;
};
#define H ((Hist*)0)
EXTERN Hist* hist;
struct Term
{
vlong mult;
Node *node;
};
enum
{
Axxx,
Ael1,
Ael2,
Asu2,
Aarg0,
Aarg1,
Aarg2,
Aaut3,
NALIGN,
};
enum
{
DMARK,
DAUTO,
DSUE,
DLABEL,
};
enum
{
OXXX,
OADD,
OADDR,
OAND,
OANDAND,
OARRAY,
OAS,
OASI,
OASADD,
OASAND,
OASASHL,
OASASHR,
OASDIV,
OASHL,
OASHR,
OASLDIV,
OASLMOD,
OASLMUL,
OASLSHR,
OASMOD,
OASMUL,
OASOR,
OASSUB,
OASXOR,
OBIT,
OBREAK,
OCASE,
OCAST,
OCOMMA,
OCOND,
OCONST,
OCONTINUE,
ODIV,
ODOT,
ODOTDOT,
ODWHILE,
OENUM,
OEQ,
OFOR,
OFUNC,
OGE,
OGOTO,
OGT,
OHI,
OHS,
OIF,
OIND,
OINDREG,
OINIT,
OLABEL,
OLDIV,
OLE,
OLIST,
OLMOD,
OLMUL,
OLO,
OLS,
OLSHR,
OLT,
OMOD,
OMUL,
ONAME,
ONE,
ONOT,
OOR,
OOROR,
OPOSTDEC,
OPOSTINC,
OPREDEC,
OPREINC,
OPROTO,
OREGISTER,
ORETURN,
OSET,
OSIGN,
OSIZE,
OSTRING,
OLSTRING,
OSTRUCT,
OSUB,
OSWITCH,
OUNION,
OUSED,
OWHILE,
OXOR,
ONEG,
OCOM,
OPOS,
OELEM,
OTST, /* used in some compilers */
OINDEX,
OFAS,
OREGPAIR,
OEND
};
enum
{
TXXX,
TCHAR,
TUCHAR,
TSHORT,
TUSHORT,
TINT,
TUINT,
TLONG,
TULONG,
TVLONG,
TUVLONG,
TFLOAT,
TDOUBLE,
TIND,
TFUNC,
TARRAY,
TVOID,
TSTRUCT,
TUNION,
TENUM,
NTYPE,
TAUTO = NTYPE,
TEXTERN,
TSTATIC,
TTYPEDEF,
TTYPESTR,
TREGISTER,
TCONSTNT,
TVOLATILE,
TUNSIGNED,
TSIGNED,
TDOT,
TFILE,
TOLD,
NALLTYPES,
};
enum
{
CXXX,
CAUTO,
CEXTERN,
CGLOBL,
CSTATIC,
CLOCAL,
CTYPEDEF,
CTYPESTR,
CPARAM,
CSELEM,
CLABEL,
CEXREG,
NCTYPES,
};
enum
{
GXXX = 0,
GCONSTNT = 1<<0,
GVOLATILE = 1<<1,
NGTYPES = 1<<2,
GINCOMPLETE = 1<<2,
};
enum
{
BCHAR = 1L<<TCHAR,
BUCHAR = 1L<<TUCHAR,
BSHORT = 1L<<TSHORT,
BUSHORT = 1L<<TUSHORT,
BINT = 1L<<TINT,
BUINT = 1L<<TUINT,
BLONG = 1L<<TLONG,
BULONG = 1L<<TULONG,
BVLONG = 1L<<TVLONG,
BUVLONG = 1L<<TUVLONG,
BFLOAT = 1L<<TFLOAT,
BDOUBLE = 1L<<TDOUBLE,
BIND = 1L<<TIND,
BFUNC = 1L<<TFUNC,
BARRAY = 1L<<TARRAY,
BVOID = 1L<<TVOID,
BSTRUCT = 1L<<TSTRUCT,
BUNION = 1L<<TUNION,
BENUM = 1L<<TENUM,
BFILE = 1L<<TFILE,
BDOT = 1L<<TDOT,
BCONSTNT = 1L<<TCONSTNT,
BVOLATILE = 1L<<TVOLATILE,
BUNSIGNED = 1L<<TUNSIGNED,
BSIGNED = 1L<<TSIGNED,
BAUTO = 1L<<TAUTO,
BEXTERN = 1L<<TEXTERN,
BSTATIC = 1L<<TSTATIC,
BTYPEDEF = 1L<<TTYPEDEF,
BTYPESTR = 1L<<TTYPESTR,
BREGISTER = 1L<<TREGISTER,
BINTEGER = BCHAR|BUCHAR|BSHORT|BUSHORT|BINT|BUINT|
BLONG|BULONG|BVLONG|BUVLONG,
BNUMBER = BINTEGER|BFLOAT|BDOUBLE,
/* these can be overloaded with complex types */
BCLASS = BAUTO|BEXTERN|BSTATIC|BTYPEDEF|BTYPESTR|BREGISTER,
BGARB = BCONSTNT|BVOLATILE,
};
struct Funct
{
Sym* sym[OEND];
Sym* castto[NTYPE];
Sym* castfr[NTYPE];
};
EXTERN struct
{
Type* tenum; /* type of entire enum */
Type* cenum; /* type of current enum run */
vlong lastenum; /* value of current enum */
double floatenum; /* value of current enum */
} en;
EXTERN int autobn;
EXTERN long autoffset;
EXTERN int blockno;
EXTERN Decl* dclstack;
EXTERN char debug[256];
EXTERN Hist* ehist;
EXTERN long firstbit;
EXTERN Sym* firstarg;
EXTERN Type* firstargtype;
EXTERN Decl* firstdcl;
EXTERN int fperror;
EXTERN Sym* hash[NHASH];
EXTERN char* hunk;
EXTERN char* include[20];
EXTERN Io* iofree;
EXTERN Io* ionext;
EXTERN Io* iostack;
EXTERN long lastbit;
EXTERN char lastclass;
EXTERN Type* lastdcl;
EXTERN long lastfield;
EXTERN Type* lasttype;
EXTERN long lineno;
EXTERN long nearln;
EXTERN int nerrors;
EXTERN int newflag;
EXTERN long nhunk;
EXTERN int ninclude;
EXTERN Node* nodproto;
EXTERN Node* nodcast;
EXTERN Biobuf outbuf;
EXTERN Biobuf diagbuf;
EXTERN char* outfile;
EXTERN char* pathname;
EXTERN int peekc;
EXTERN long stkoff;
EXTERN Type* strf;
EXTERN Type* strl;
EXTERN char symb[NSYMB];
EXTERN Sym* symstring;
EXTERN int taggen;
EXTERN Type* tfield;
EXTERN Type* tufield;
EXTERN int thechar;
EXTERN char* thestring;
EXTERN Type* thisfn;
EXTERN long thunk;
EXTERN Type* types[NTYPE];
EXTERN Type* fntypes[NTYPE];
EXTERN Node* initlist;
EXTERN Term term[NTERM];
EXTERN int nterm;
EXTERN int packflg;
EXTERN int fproundflg;
EXTERN int profileflg;
EXTERN int ncontin;
EXTERN int canreach;
EXTERN int warnreach;
EXTERN Bits zbits;
extern char *onames[], *tnames[], *gnames[];
extern char *cnames[], *qnames[], *bnames[];
extern uchar tab[NTYPE][NTYPE];
extern uchar comrel[], invrel[], logrel[];
extern long ncast[], tadd[], tand[];
extern long targ[], tasadd[], tasign[], tcast[];
extern long tdot[], tfunct[], tindir[], tmul[];
extern long tnot[], trel[], tsub[];
extern uchar typeaf[];
extern uchar typefd[];
extern uchar typei[];
extern uchar typesu[];
extern uchar typesuv[];
extern uchar typeu[];
extern uchar typev[];
extern uchar typec[];
extern uchar typeh[];
extern uchar typeil[];
extern uchar typeilp[];
extern uchar typechl[];
extern uchar typechlv[];
extern uchar typechlvp[];
extern uchar typechlp[];
extern uchar typechlpfd[];
EXTERN uchar* typeword;
EXTERN uchar* typecmplx;
extern ulong thash1;
extern ulong thash2;
extern ulong thash3;
extern ulong thash[];
/*
* compat.c/unix.c/windows.c
*/
int mywait(int*);
int mycreat(char*, int);
int systemtype(int);
int pathchar(void);
int myaccess(char*);
char* mygetwd(char*, int);
int myexec(char*, char*[]);
int mydup(int, int);
int myfork(void);
int mypipe(int*);
void* mysbrk(ulong);
/*
* parser
*/
int yyparse(void);
int mpatov(char*, vlong*);
/*
* lex.c
*/
void* allocn(void*, long, long);
void* alloc(long);
void cinit(void);
int compile(char*, char**, int);
void errorexit(void);
int filbuf(void);
int getc(void);
long getr(void);
int getnsc(void);
Sym* lookup(void);
void main(int, char*[]);
void newfile(char*, int);
void newio(void);
void pushio(void);
long escchar(long, int, int);
Sym* slookup(char*);
void syminit(Sym*);
void unget(int);
long yylex(void);
int Lconv(Fmt*);
int Tconv(Fmt*);
int FNconv(Fmt*);
int Oconv(Fmt*);
int Qconv(Fmt*);
int VBconv(Fmt*);
void setinclude(char*);
/*
* mac.c
*/
void dodefine(char*);
void domacro(void);
Sym* getsym(void);
long getnsn(void);
void linehist(char*, int);
void macdef(void);
void macprag(void);
void macend(void);
void macexpand(Sym*, char*);
void macif(int);
void macinc(void);
void maclin(void);
void macund(void);
/*
* dcl.c
*/
Node* doinit(Sym*, Type*, long, Node*);
Type* tcopy(Type*);
Node* init1(Sym*, Type*, long, int);
Node* newlist(Node*, Node*);
void adecl(int, Type*, Sym*);
int anyproto(Node*);
void argmark(Node*, int);
void dbgdecl(Sym*);
Node* dcllabel(Sym*, int);
Node* dodecl(void(*)(int, Type*, Sym*), int, Type*, Node*);
Sym* mkstatic(Sym*);
void doenum(Sym*, Node*);
void snap(Type*);
Type* dotag(Sym*, int, int);
void edecl(int, Type*, Sym*);
Type* fnproto(Node*);
Type* fnproto1(Node*);
void markdcl(void);
Type* paramconv(Type*, int);
void pdecl(int, Type*, Sym*);
Decl* push(void);
Decl* push1(Sym*);
Node* revertdcl(void);
long xround(long, int);
int rsametype(Type*, Type*, int, int);
int sametype(Type*, Type*);
ulong sign(Sym*);
ulong signature(Type*);
void suallign(Type*);
void tmerge(Type*, Sym*);
void walkparam(Node*, int);
void xdecl(int, Type*, Sym*);
Node* contig(Sym*, Node*, long);
/*
* com.c
*/
void ccom(Node*);
void complex(Node*);
int tcom(Node*);
int tcoma(Node*, Node*, Type*, int);
int tcomd(Node*);
int tcomo(Node*, int);
int tcomx(Node*);
int tlvalue(Node*);
void constas(Node*, Type*, Type*);
/*
* con.c
*/
void acom(Node*);
void acom1(vlong, Node*);
void acom2(Node*, Type*);
int acomcmp1(const void*, const void*);
int acomcmp2(const void*, const void*);
int addo(Node*);
void evconst(Node*);
/*
* funct.c
*/
int isfunct(Node*);
void dclfunct(Type*, Sym*);
/*
* sub.c
*/
void arith(Node*, int);
int deadheads(Node*);
Type* dotsearch(Sym*, Type*, Node*, long*);
long dotoffset(Type*, Type*, Node*);
void gethunk(void);
Node* invert(Node*);
int bitno(long);
void makedot(Node*, Type*, long);
int mixedasop(Type*, Type*);
Node* new(int, Node*, Node*);
Node* new1(int, Node*, Node*);
int nilcast(Type*, Type*);
int nocast(Type*, Type*);
void prtree(Node*, char*);
void prtree1(Node*, int, int);
void relcon(Node*, Node*);
int relindex(int);
int simpleg(long);
Type* garbt(Type*, long);
int simplec(long);
Type* simplet(long);
int stcompat(Node*, Type*, Type*, long[]);
int tcompat(Node*, Type*, Type*, long[]);
void tinit(void);
Type* typ(int, Type*);
Type* copytyp(Type*);
void typeext(Type*, Node*);
void typeext1(Type*, Node*);
int side(Node*);
int vconst(Node*);
int xlog2(uvlong);
int vlog(Node*);
int topbit(ulong);
void simplifyshift(Node*);
long typebitor(long, long);
void diag(Node*, char*, ...);
void warn(Node*, char*, ...);
void yyerror(char*, ...);
void fatal(Node*, char*, ...);
/*
* acid.c
*/
void acidtype(Type*);
void acidvar(Sym*);
/*
* pickle.c
*/
void pickletype(Type*);
/*
* bits.c
*/
Bits bor(Bits, Bits);
Bits band(Bits, Bits);
Bits bnot(Bits);
int bany(Bits*);
int bnum(Bits);
Bits blsh(uint);
int beq(Bits, Bits);
int bset(Bits, uint);
/*
* dpchk.c
*/
void dpcheck(Node*);
void arginit(void);
void pragvararg(void);
void pragpack(void);
void pragfpround(void);
void pragprofile(void);
void pragincomplete(void);
/*
* calls to machine depend part
*/
void codgen(Node*, Node*);
void gclean(void);
void gextern(Sym*, Node*, long, long);
void ginit(void);
long outstring(char*, long);
long outlstring(ushort*, long);
void sextern(Sym*, Node*, long, long);
void xcom(Node*);
long exreg(Type*);
long align(long, Type*, int);
long maxround(long, long);
extern schar ewidth[];
/*
* com64
*/
int com64(Node*);
void com64init(void);
void bool64(Node*);
double convvtof(vlong);
vlong convftov(double);
double convftox(double, int);
vlong convvtox(vlong, int);
/*
* machcap
*/
int machcap(Node*);
#pragma varargck argpos warn 2
#pragma varargck argpos diag 2
#pragma varargck argpos yyerror 1
#pragma varargck type "F" Node*
#pragma varargck type "L" long
#pragma varargck type "Q" long
#pragma varargck type "O" int
#pragma varargck type "T" Type*
#pragma varargck type "|" int

1205
src/cmd/cc/cc.y Normal file

File diff suppressed because it is too large Load diff

1378
src/cmd/cc/com.c Normal file

File diff suppressed because it is too large Load diff

643
src/cmd/cc/com64.c Normal file
View file

@ -0,0 +1,643 @@
// Inferno utils/cc/com64.c
// http://code.google.com/p/inferno-os/source/browse/utils/cc/com64.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.
#include "cc.h"
/*
* this is machine depend, but it is totally
* common on all of the 64-bit symulating machines.
*/
#define FNX 100 /* botch -- redefinition */
Node* nodaddv;
Node* nodsubv;
Node* nodmulv;
Node* noddivv;
Node* noddivvu;
Node* nodmodv;
Node* nodmodvu;
Node* nodlshv;
Node* nodrshav;
Node* nodrshlv;
Node* nodandv;
Node* nodorv;
Node* nodxorv;
Node* nodnegv;
Node* nodcomv;
Node* nodtestv;
Node* nodeqv;
Node* nodnev;
Node* nodlev;
Node* nodltv;
Node* nodgev;
Node* nodgtv;
Node* nodhiv;
Node* nodhsv;
Node* nodlov;
Node* nodlsv;
Node* nodf2v;
Node* nodd2v;
Node* nodp2v;
Node* nodsi2v;
Node* nodui2v;
Node* nodsl2v;
Node* nodul2v;
Node* nodsh2v;
Node* noduh2v;
Node* nodsc2v;
Node* noduc2v;
Node* nodv2f;
Node* nodv2d;
Node* nodv2ui;
Node* nodv2si;
Node* nodv2ul;
Node* nodv2sl;
Node* nodv2uh;
Node* nodv2sh;
Node* nodv2uc;
Node* nodv2sc;
Node* nodvpp;
Node* nodppv;
Node* nodvmm;
Node* nodmmv;
Node* nodvasop;
char etconv[NTYPE]; /* for _vasop */
Init initetconv[] =
{
TCHAR, 1, 0,
TUCHAR, 2, 0,
TSHORT, 3, 0,
TUSHORT, 4, 0,
TLONG, 5, 0,
TULONG, 6, 0,
TVLONG, 7, 0,
TUVLONG, 8, 0,
TINT, 9, 0,
TUINT, 10, 0,
-1, 0, 0,
};
Node*
fvn(char *name, int type)
{
Node *n;
n = new(ONAME, Z, Z);
n->sym = slookup(name);
n->sym->sig = SIGINTERN;
if(fntypes[type] == 0)
fntypes[type] = typ(TFUNC, types[type]);
n->type = fntypes[type];
n->etype = type;
n->class = CGLOBL;
n->addable = 10;
n->complex = 0;
return n;
}
void
com64init(void)
{
Init *p;
nodaddv = fvn("_addv", TVLONG);
nodsubv = fvn("_subv", TVLONG);
nodmulv = fvn("_mulv", TVLONG);
noddivv = fvn("_divv", TVLONG);
noddivvu = fvn("_divvu", TVLONG);
nodmodv = fvn("_modv", TVLONG);
nodmodvu = fvn("_modvu", TVLONG);
nodlshv = fvn("_lshv", TVLONG);
nodrshav = fvn("_rshav", TVLONG);
nodrshlv = fvn("_rshlv", TVLONG);
nodandv = fvn("_andv", TVLONG);
nodorv = fvn("_orv", TVLONG);
nodxorv = fvn("_xorv", TVLONG);
nodnegv = fvn("_negv", TVLONG);
nodcomv = fvn("_comv", TVLONG);
nodtestv = fvn("_testv", TLONG);
nodeqv = fvn("_eqv", TLONG);
nodnev = fvn("_nev", TLONG);
nodlev = fvn("_lev", TLONG);
nodltv = fvn("_ltv", TLONG);
nodgev = fvn("_gev", TLONG);
nodgtv = fvn("_gtv", TLONG);
nodhiv = fvn("_hiv", TLONG);
nodhsv = fvn("_hsv", TLONG);
nodlov = fvn("_lov", TLONG);
nodlsv = fvn("_lsv", TLONG);
nodf2v = fvn("_f2v", TVLONG);
nodd2v = fvn("_d2v", TVLONG);
nodp2v = fvn("_p2v", TVLONG);
nodsi2v = fvn("_si2v", TVLONG);
nodui2v = fvn("_ui2v", TVLONG);
nodsl2v = fvn("_sl2v", TVLONG);
nodul2v = fvn("_ul2v", TVLONG);
nodsh2v = fvn("_sh2v", TVLONG);
noduh2v = fvn("_uh2v", TVLONG);
nodsc2v = fvn("_sc2v", TVLONG);
noduc2v = fvn("_uc2v", TVLONG);
nodv2f = fvn("_v2f", TFLOAT);
nodv2d = fvn("_v2d", TDOUBLE);
nodv2sl = fvn("_v2sl", TLONG);
nodv2ul = fvn("_v2ul", TULONG);
nodv2si = fvn("_v2si", TINT);
nodv2ui = fvn("_v2ui", TUINT);
nodv2sh = fvn("_v2sh", TSHORT);
nodv2uh = fvn("_v2ul", TUSHORT);
nodv2sc = fvn("_v2sc", TCHAR);
nodv2uc = fvn("_v2uc", TUCHAR);
nodvpp = fvn("_vpp", TVLONG);
nodppv = fvn("_ppv", TVLONG);
nodvmm = fvn("_vmm", TVLONG);
nodmmv = fvn("_mmv", TVLONG);
nodvasop = fvn("_vasop", TVLONG);
for(p = initetconv; p->code >= 0; p++)
etconv[p->code] = p->value;
}
int
com64(Node *n)
{
Node *l, *r, *a, *t;
int lv, rv;
if(n->type == 0)
return 0;
l = n->left;
r = n->right;
lv = 0;
if(l && l->type && typev[l->type->etype])
lv = 1;
rv = 0;
if(r && r->type && typev[r->type->etype])
rv = 1;
if(lv) {
switch(n->op) {
case OEQ:
a = nodeqv;
goto setbool;
case ONE:
a = nodnev;
goto setbool;
case OLE:
a = nodlev;
goto setbool;
case OLT:
a = nodltv;
goto setbool;
case OGE:
a = nodgev;
goto setbool;
case OGT:
a = nodgtv;
goto setbool;
case OHI:
a = nodhiv;
goto setbool;
case OHS:
a = nodhsv;
goto setbool;
case OLO:
a = nodlov;
goto setbool;
case OLS:
a = nodlsv;
goto setbool;
case OANDAND:
case OOROR:
if(machcap(n))
return 1;
if(rv) {
r = new(OFUNC, nodtestv, r);
n->right = r;
r->complex = FNX;
r->op = OFUNC;
r->type = types[TLONG];
}
case OCOND:
case ONOT:
if(machcap(n))
return 1;
l = new(OFUNC, nodtestv, l);
n->left = l;
l->complex = FNX;
l->op = OFUNC;
l->type = types[TLONG];
n->complex = FNX;
return 1;
}
}
if(rv) {
if(machcap(n))
return 1;
switch(n->op) {
case OANDAND:
case OOROR:
r = new(OFUNC, nodtestv, r);
n->right = r;
r->complex = FNX;
r->op = OFUNC;
r->type = types[TLONG];
return 1;
}
}
if(typev[n->type->etype]) {
if(machcap(n))
return 1;
switch(n->op) {
default:
diag(n, "unknown vlong %O", n->op);
case OFUNC:
n->complex = FNX;
case ORETURN:
case OAS:
case OIND:
return 1;
case OADD:
a = nodaddv;
goto setbop;
case OSUB:
a = nodsubv;
goto setbop;
case OMUL:
case OLMUL:
a = nodmulv;
goto setbop;
case ODIV:
a = noddivv;
goto setbop;
case OLDIV:
a = noddivvu;
goto setbop;
case OMOD:
a = nodmodv;
goto setbop;
case OLMOD:
a = nodmodvu;
goto setbop;
case OASHL:
a = nodlshv;
goto setbop;
case OASHR:
a = nodrshav;
goto setbop;
case OLSHR:
a = nodrshlv;
goto setbop;
case OAND:
a = nodandv;
goto setbop;
case OOR:
a = nodorv;
goto setbop;
case OXOR:
a = nodxorv;
goto setbop;
case OPOSTINC:
a = nodvpp;
goto setvinc;
case OPOSTDEC:
a = nodvmm;
goto setvinc;
case OPREINC:
a = nodppv;
goto setvinc;
case OPREDEC:
a = nodmmv;
goto setvinc;
case ONEG:
a = nodnegv;
goto setfnx;
case OCOM:
a = nodcomv;
goto setfnx;
case OCAST:
switch(l->type->etype) {
case TCHAR:
a = nodsc2v;
goto setfnxl;
case TUCHAR:
a = noduc2v;
goto setfnxl;
case TSHORT:
a = nodsh2v;
goto setfnxl;
case TUSHORT:
a = noduh2v;
goto setfnxl;
case TINT:
a = nodsi2v;
goto setfnx;
case TUINT:
a = nodui2v;
goto setfnx;
case TLONG:
a = nodsl2v;
goto setfnx;
case TULONG:
a = nodul2v;
goto setfnx;
case TFLOAT:
a = nodf2v;
goto setfnx;
case TDOUBLE:
a = nodd2v;
goto setfnx;
case TIND:
a = nodp2v;
goto setfnx;
}
diag(n, "unknown %T->vlong cast", l->type);
return 1;
case OASADD:
a = nodaddv;
goto setasop;
case OASSUB:
a = nodsubv;
goto setasop;
case OASMUL:
case OASLMUL:
a = nodmulv;
goto setasop;
case OASDIV:
a = noddivv;
goto setasop;
case OASLDIV:
a = noddivvu;
goto setasop;
case OASMOD:
a = nodmodv;
goto setasop;
case OASLMOD:
a = nodmodvu;
goto setasop;
case OASASHL:
a = nodlshv;
goto setasop;
case OASASHR:
a = nodrshav;
goto setasop;
case OASLSHR:
a = nodrshlv;
goto setasop;
case OASAND:
a = nodandv;
goto setasop;
case OASOR:
a = nodorv;
goto setasop;
case OASXOR:
a = nodxorv;
goto setasop;
}
}
if(typefd[n->type->etype] && l && l->op == OFUNC) {
switch(n->op) {
case OASADD:
case OASSUB:
case OASMUL:
case OASLMUL:
case OASDIV:
case OASLDIV:
case OASMOD:
case OASLMOD:
case OASASHL:
case OASASHR:
case OASLSHR:
case OASAND:
case OASOR:
case OASXOR:
if(l->right && typev[l->right->etype]) {
diag(n, "sorry float <asop> vlong not implemented\n");
}
}
}
if(n->op == OCAST) {
if(l->type && typev[l->type->etype]) {
if(machcap(n))
return 1;
switch(n->type->etype) {
case TDOUBLE:
a = nodv2d;
goto setfnx;
case TFLOAT:
a = nodv2f;
goto setfnx;
case TLONG:
a = nodv2sl;
goto setfnx;
case TULONG:
a = nodv2ul;
goto setfnx;
case TINT:
a = nodv2si;
goto setfnx;
case TUINT:
a = nodv2ui;
goto setfnx;
case TSHORT:
a = nodv2sh;
goto setfnx;
case TUSHORT:
a = nodv2uh;
goto setfnx;
case TCHAR:
a = nodv2sc;
goto setfnx;
case TUCHAR:
a = nodv2uc;
goto setfnx;
case TIND: // small pun here
a = nodv2ul;
goto setfnx;
}
diag(n, "unknown vlong->%T cast", n->type);
return 1;
}
}
return 0;
setbop:
n->left = a;
n->right = new(OLIST, l, r);
n->complex = FNX;
n->op = OFUNC;
return 1;
setfnxl:
l = new(OCAST, l, 0);
l->type = types[TLONG];
l->complex = l->left->complex;
setfnx:
n->left = a;
n->right = l;
n->complex = FNX;
n->op = OFUNC;
return 1;
setvinc:
n->left = a;
l = new(OADDR, l, Z);
l->type = typ(TIND, l->left->type);
n->right = new(OLIST, l, r);
n->complex = FNX;
n->op = OFUNC;
return 1;
setbool:
if(machcap(n))
return 1;
n->left = a;
n->right = new(OLIST, l, r);
n->complex = FNX;
n->op = OFUNC;
n->type = types[TLONG];
return 1;
setasop:
if(l->op == OFUNC) {
l = l->right;
goto setasop;
}
t = new(OCONST, 0, 0);
t->vconst = etconv[l->type->etype];
t->type = types[TLONG];
t->addable = 20;
r = new(OLIST, t, r);
t = new(OADDR, a, 0);
t->type = typ(TIND, a->type);
r = new(OLIST, t, r);
t = new(OADDR, l, 0);
t->type = typ(TIND, l->type);
r = new(OLIST, t, r);
n->left = nodvasop;
n->right = r;
n->complex = FNX;
n->op = OFUNC;
return 1;
}
void
bool64(Node *n)
{
Node *n1;
if(machcap(Z))
return;
if(typev[n->type->etype]) {
n1 = new(OXXX, 0, 0);
*n1 = *n;
n->right = n1;
n->left = nodtestv;
n->complex = FNX;
n->addable = 0;
n->op = OFUNC;
n->type = types[TLONG];
}
}
/*
* more machine depend stuff.
* this is common for 8,16,32,64 bit machines.
* this is common for ieee machines.
*/
double
convvtof(vlong v)
{
double d;
d = v; /* BOTCH */
return d;
}
vlong
convftov(double d)
{
vlong v;
v = d; /* BOTCH */
return v;
}
double
convftox(double d, int et)
{
if(!typefd[et])
diag(Z, "bad type in castftox %s", tnames[et]);
return d;
}
vlong
convvtox(vlong c, int et)
{
int n;
n = 8 * ewidth[et];
c &= MASK(n);
if(!typeu[et])
if(c & SIGN(n))
c |= ~MASK(n);
return c;
}

1664
src/cmd/cc/dcl.c Normal file

File diff suppressed because it is too large Load diff

524
src/cmd/cc/dpchk.c Normal file
View file

@ -0,0 +1,524 @@
// Inferno utils/cc/dpchk.c
// http://code.google.com/p/inferno-os/source/browse/utils/cc/dpchk.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.
#include "cc.h"
#include "y.tab.h"
enum
{
Fnone = 0,
Fl,
Fvl,
Fignor,
Fstar,
Fadj,
Fverb = 10,
};
typedef struct Tprot Tprot;
struct Tprot
{
Type* type;
Bits flag;
Tprot* link;
};
typedef struct Tname Tname;
struct Tname
{
char* name;
int param;
Tname* link;
};
static Type* indchar;
static uchar flagbits[512];
static char fmtbuf[100];
static int lastadj;
static int lastverb;
static int nstar;
static Tprot* tprot;
static Tname* tname;
void
argflag(int c, int v)
{
switch(v) {
case Fignor:
case Fstar:
case Fl:
case Fvl:
flagbits[c] = v;
break;
case Fverb:
flagbits[c] = lastverb;
/*print("flag-v %c %d\n", c, lastadj);*/
lastverb++;
break;
case Fadj:
flagbits[c] = lastadj;
/*print("flag-l %c %d\n", c, lastadj);*/
lastadj++;
break;
}
}
Bits
getflag(char *s)
{
Bits flag;
int f;
char *fmt;
Rune c;
fmt = fmtbuf;
flag = zbits;
nstar = 0;
for(;;) {
s += chartorune(&c, s);
if(c == 0 || c >= nelem(flagbits))
break;
fmt += runetochar(fmt, &c);
f = flagbits[c];
switch(f) {
case Fnone:
argflag(c, Fverb);
f = flagbits[c];
break;
case Fstar:
nstar++;
case Fignor:
continue;
case Fl:
if(bset(flag, Fl))
flag = bor(flag, blsh(Fvl));
}
flag = bor(flag, blsh(f));
if(f >= Fverb)
break;
}
*fmt = 0;
return flag;
}
void
newprot(Sym *m, Type *t, char *s)
{
Bits flag;
Tprot *l;
if(t == T) {
warn(Z, "%s: newprot: type not defined", m->name);
return;
}
flag = getflag(s);
for(l=tprot; l; l=l->link)
if(beq(flag, l->flag) && sametype(t, l->type))
return;
l = alloc(sizeof(*l));
l->type = t;
l->flag = flag;
l->link = tprot;
tprot = l;
}
void
newname(char *s, int p)
{
Tname *l;
for(l=tname; l; l=l->link)
if(strcmp(l->name, s) == 0) {
if(l->param != p)
yyerror("vargck %s already defined\n", s);
return;
}
l = alloc(sizeof(*l));
l->name = s;
l->param = p;
l->link = tname;
tname = l;
}
void
arginit(void)
{
int i;
/* debug['F'] = 1;*/
/* debug['w'] = 1;*/
lastadj = Fadj;
lastverb = Fverb;
indchar = typ(TIND, types[TCHAR]);
memset(flagbits, Fnone, sizeof(flagbits));
for(i='0'; i<='9'; i++)
argflag(i, Fignor);
argflag('.', Fignor);
argflag('#', Fignor);
argflag('u', Fignor);
argflag('h', Fignor);
argflag('+', Fignor);
argflag('-', Fignor);
argflag('*', Fstar);
argflag('l', Fl);
argflag('o', Fverb);
flagbits['x'] = flagbits['o'];
flagbits['X'] = flagbits['o'];
}
void
pragvararg(void)
{
Sym *s;
int n, c;
char *t;
Rune r;
Type *ty;
if(!debug['F'])
goto out;
s = getsym();
if(s && strcmp(s->name, "argpos") == 0)
goto ckpos;
if(s && strcmp(s->name, "type") == 0)
goto cktype;
if(s && strcmp(s->name, "flag") == 0)
goto ckflag;
yyerror("syntax in #pragma varargck");
goto out;
ckpos:
/*#pragma varargck argpos warn 2*/
s = getsym();
if(s == S)
goto bad;
n = getnsn();
if(n < 0)
goto bad;
newname(s->name, n);
goto out;
ckflag:
/*#pragma varargck flag 'c'*/
c = getnsc();
if(c != '\'')
goto bad;
c = getr();
if(c == '\\')
c = getr();
else if(c == '\'')
goto bad;
if(c == '\n')
goto bad;
if(getc() != '\'')
goto bad;
argflag(c, Fignor);
goto out;
cktype:
/*#pragma varargck type O int*/
c = getnsc();
if(c != '"')
goto bad;
t = fmtbuf;
for(;;) {
r = getr();
if(r == ' ' || r == '\n')
goto bad;
if(r == '"')
break;
t += runetochar(t, &r);
}
*t = 0;
t = strdup(fmtbuf);
s = getsym();
if(s == S)
goto bad;
ty = s->type;
while((c = getnsc()) == '*')
ty = typ(TIND, ty);
unget(c);
newprot(s, ty, t);
goto out;
bad:
yyerror("syntax in #pragma varargck");
out:
while(getnsc() != '\n')
;
}
Node*
nextarg(Node *n, Node **a)
{
if(n == Z) {
*a = Z;
return Z;
}
if(n->op == OLIST) {
*a = n->left;
return n->right;
}
*a = n;
return Z;
}
void
checkargs(Node *nn, char *s, int pos)
{
Node *a, *n;
Bits flag;
Tprot *l;
if(!debug['F'])
return;
n = nn;
for(;;) {
s = strchr(s, '%');
if(s == 0) {
nextarg(n, &a);
if(a != Z)
warn(nn, "more arguments than format %T",
a->type);
return;
}
s++;
flag = getflag(s);
while(nstar > 0) {
n = nextarg(n, &a);
pos++;
nstar--;
if(a == Z) {
warn(nn, "more format than arguments %s",
fmtbuf);
return;
}
if(a->type == T)
continue;
if(!sametype(types[TINT], a->type) &&
!sametype(types[TUINT], a->type))
warn(nn, "format mismatch '*' in %s %T, arg %d",
fmtbuf, a->type, pos);
}
for(l=tprot; l; l=l->link)
if(sametype(types[TVOID], l->type)) {
if(beq(flag, l->flag)) {
s++;
goto loop;
}
}
n = nextarg(n, &a);
pos++;
if(a == Z) {
warn(nn, "more format than arguments %s",
fmtbuf);
return;
}
if(a->type == 0)
continue;
for(l=tprot; l; l=l->link)
if(sametype(a->type, l->type)) {
/*print("checking %T/%ulx %T/%ulx\n", a->type, flag.b[0], l->type, l->flag.b[0]);*/
if(beq(flag, l->flag))
goto loop;
}
warn(nn, "format mismatch %s %T, arg %d", fmtbuf, a->type, pos);
loop:;
}
}
void
dpcheck(Node *n)
{
char *s;
Node *a, *b;
Tname *l;
int i;
if(n == Z)
return;
b = n->left;
if(b == Z || b->op != ONAME)
return;
s = b->sym->name;
for(l=tname; l; l=l->link)
if(strcmp(s, l->name) == 0)
break;
if(l == 0)
return;
i = l->param;
b = n->right;
while(i > 0) {
b = nextarg(b, &a);
i--;
}
if(a == Z) {
warn(n, "cant find format arg");
return;
}
if(!sametype(indchar, a->type)) {
warn(n, "format arg type %T", a->type);
return;
}
if(a->op != OADDR || a->left->op != ONAME || a->left->sym != symstring) {
/* warn(n, "format arg not constant string");*/
return;
}
s = a->left->cstring;
checkargs(b, s, l->param);
}
void
pragpack(void)
{
Sym *s;
packflg = 0;
s = getsym();
if(s) {
packflg = atoi(s->name+1);
if(strcmp(s->name, "on") == 0 ||
strcmp(s->name, "yes") == 0)
packflg = 1;
}
while(getnsc() != '\n')
;
if(debug['f'])
if(packflg)
print("%4ld: pack %d\n", lineno, packflg);
else
print("%4ld: pack off\n", lineno);
}
void
pragfpround(void)
{
Sym *s;
fproundflg = 0;
s = getsym();
if(s) {
fproundflg = atoi(s->name+1);
if(strcmp(s->name, "on") == 0 ||
strcmp(s->name, "yes") == 0)
fproundflg = 1;
}
while(getnsc() != '\n')
;
if(debug['f'])
if(fproundflg)
print("%4ld: fproundflg %d\n", lineno, fproundflg);
else
print("%4ld: fproundflg off\n", lineno);
}
void
pragprofile(void)
{
Sym *s;
profileflg = 0;
s = getsym();
if(s) {
profileflg = atoi(s->name+1);
if(strcmp(s->name, "on") == 0 ||
strcmp(s->name, "yes") == 0)
profileflg = 1;
}
while(getnsc() != '\n')
;
if(debug['f'])
if(profileflg)
print("%4ld: profileflg %d\n", lineno, profileflg);
else
print("%4ld: profileflg off\n", lineno);
}
void
pragincomplete(void)
{
Sym *s;
Type *t;
int istag, w, et;
istag = 0;
s = getsym();
if(s == nil)
goto out;
et = 0;
w = s->lexical;
if(w == LSTRUCT)
et = TSTRUCT;
else if(w == LUNION)
et = TUNION;
if(et != 0){
s = getsym();
if(s == nil){
yyerror("missing struct/union tag in pragma incomplete");
goto out;
}
if(s->lexical != LNAME && s->lexical != LTYPE){
yyerror("invalid struct/union tag: %s", s->name);
goto out;
}
dotag(s, et, 0);
istag = 1;
}else if(strcmp(s->name, "_off_") == 0){
debug['T'] = 0;
goto out;
}else if(strcmp(s->name, "_on_") == 0){
debug['T'] = 1;
goto out;
}
t = s->type;
if(istag)
t = s->suetag;
if(t == T)
yyerror("unknown type %s in pragma incomplete", s->name);
else if(!typesu[t->etype])
yyerror("not struct/union type in pragma incomplete: %s", s->name);
else
t->garb |= GINCOMPLETE;
out:
while(getnsc() != '\n')
;
if(debug['f'])
print("%s incomplete\n", s->name);
}

430
src/cmd/cc/funct.c Normal file
View file

@ -0,0 +1,430 @@
// Inferno utils/cc/funct.c
// http://code.google.com/p/inferno-os/source/browse/utils/cc/funct.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.
#include "cc.h"
typedef struct Ftab Ftab;
struct Ftab
{
char op;
char* name;
char typ;
};
typedef struct Gtab Gtab;
struct Gtab
{
char etype;
char* name;
};
Ftab ftabinit[OEND];
Gtab gtabinit[NTYPE];
int
isfunct(Node *n)
{
Type *t, *t1;
Funct *f;
Node *l;
Sym *s;
int o;
o = n->op;
if(n->left == Z)
goto no;
t = n->left->type;
if(t == T)
goto no;
f = t->funct;
switch(o) {
case OAS: // put cast on rhs
case OASI:
case OASADD:
case OASAND:
case OASASHL:
case OASASHR:
case OASDIV:
case OASLDIV:
case OASLMOD:
case OASLMUL:
case OASLSHR:
case OASMOD:
case OASMUL:
case OASOR:
case OASSUB:
case OASXOR:
if(n->right == Z)
goto no;
t1 = n->right->type;
if(t1 == T)
goto no;
if(t1->funct == f)
break;
l = new(OXXX, Z, Z);
*l = *n->right;
n->right->left = l;
n->right->right = Z;
n->right->type = t;
n->right->op = OCAST;
if(!isfunct(n->right))
prtree(n, "isfunc !");
break;
case OCAST: // t f(T) or T f(t)
t1 = n->type;
if(t1 == T)
goto no;
if(f != nil) {
s = f->castfr[t1->etype];
if(s == S)
goto no;
n->right = n->left;
goto build;
}
f = t1->funct;
if(f != nil) {
s = f->castto[t->etype];
if(s == S)
goto no;
n->right = n->left;
goto build;
}
goto no;
}
if(f == nil)
goto no;
s = f->sym[o];
if(s == S)
goto no;
/*
* the answer is yes,
* now we rewrite the node
* and give diagnostics
*/
switch(o) {
default:
diag(n, "isfunct op missing %O\n", o);
goto bad;
case OADD: // T f(T, T)
case OAND:
case OASHL:
case OASHR:
case ODIV:
case OLDIV:
case OLMOD:
case OLMUL:
case OLSHR:
case OMOD:
case OMUL:
case OOR:
case OSUB:
case OXOR:
case OEQ: // int f(T, T)
case OGE:
case OGT:
case OHI:
case OHS:
case OLE:
case OLO:
case OLS:
case OLT:
case ONE:
if(n->right == Z)
goto bad;
t1 = n->right->type;
if(t1 == T)
goto bad;
if(t1->funct != f)
goto bad;
n->right = new(OLIST, n->left, n->right);
break;
case OAS: // structure copies done by the compiler
case OASI:
goto no;
case OASADD: // T f(T*, T)
case OASAND:
case OASASHL:
case OASASHR:
case OASDIV:
case OASLDIV:
case OASLMOD:
case OASLMUL:
case OASLSHR:
case OASMOD:
case OASMUL:
case OASOR:
case OASSUB:
case OASXOR:
if(n->right == Z)
goto bad;
t1 = n->right->type;
if(t1 == T)
goto bad;
if(t1->funct != f)
goto bad;
n->right = new(OLIST, new(OADDR, n->left, Z), n->right);
break;
case OPOS: // T f(T)
case ONEG:
case ONOT:
case OCOM:
n->right = n->left;
break;
}
build:
l = new(ONAME, Z, Z);
l->sym = s;
l->type = s->type;
l->etype = s->type->etype;
l->xoffset = s->offset;
l->class = s->class;
tcomo(l, 0);
n->op = OFUNC;
n->left = l;
n->type = l->type->link;
if(tcompat(n, T, l->type, tfunct))
goto bad;
if(tcoma(n->left, n->right, l->type->down, 1))
goto bad;
return 1;
no:
return 0;
bad:
diag(n, "cant rewrite typestr for op %O\n", o);
prtree(n, "isfunct");
n->type = T;
return 1;
}
void
dclfunct(Type *t, Sym *s)
{
Funct *f;
Node *n;
Type *f1, *f2, *f3, *f4;
int o, i, c;
char str[100];
if(t->funct)
return;
// recognize generated tag of dorm _%d_
if(t->tag == S)
goto bad;
for(i=0; c = t->tag->name[i]; i++) {
if(c == '_') {
if(i == 0 || t->tag->name[i+1] == 0)
continue;
break;
}
if(c < '0' || c > '9')
break;
}
if(c == 0)
goto bad;
f = alloc(sizeof(*f));
for(o=0; o<sizeof(f->sym); o++)
f->sym[o] = S;
t->funct = f;
f1 = typ(TFUNC, t);
f1->down = copytyp(t);
f1->down->down = t;
f2 = typ(TFUNC, types[TINT]);
f2->down = copytyp(t);
f2->down->down = t;
f3 = typ(TFUNC, t);
f3->down = typ(TIND, t);
f3->down->down = t;
f4 = typ(TFUNC, t);
f4->down = t;
for(i=0;; i++) {
o = ftabinit[i].op;
if(o == OXXX)
break;
sprint(str, "%s_%s_", t->tag->name, ftabinit[i].name);
n = new(ONAME, Z, Z);
n->sym = slookup(str);
f->sym[o] = n->sym;
switch(ftabinit[i].typ) {
default:
diag(Z, "dclfunct op missing %d\n", ftabinit[i].typ);
break;
case 1: // T f(T,T) +
dodecl(xdecl, CEXTERN, f1, n);
break;
case 2: // int f(T,T) ==
dodecl(xdecl, CEXTERN, f2, n);
break;
case 3: // void f(T*,T) +=
dodecl(xdecl, CEXTERN, f3, n);
break;
case 4: // T f(T) ~
dodecl(xdecl, CEXTERN, f4, n);
break;
}
}
for(i=0;; i++) {
o = gtabinit[i].etype;
if(o == TXXX)
break;
/*
* OCAST types T1 _T2_T1_(T2)
*/
sprint(str, "_%s%s_", gtabinit[i].name, t->tag->name);
n = new(ONAME, Z, Z);
n->sym = slookup(str);
f->castto[o] = n->sym;
f1 = typ(TFUNC, t);
f1->down = types[o];
dodecl(xdecl, CEXTERN, f1, n);
sprint(str, "%s_%s_", t->tag->name, gtabinit[i].name);
n = new(ONAME, Z, Z);
n->sym = slookup(str);
f->castfr[o] = n->sym;
f1 = typ(TFUNC, types[o]);
f1->down = t;
dodecl(xdecl, CEXTERN, f1, n);
}
return;
bad:
diag(Z, "dclfunct bad %T %s\n", t, s->name);
}
Gtab gtabinit[NTYPE] =
{
TCHAR, "c",
TUCHAR, "uc",
TSHORT, "h",
TUSHORT, "uh",
TINT, "i",
TUINT, "ui",
TLONG, "l",
TULONG, "ul",
TVLONG, "v",
TUVLONG, "uv",
TFLOAT, "f",
TDOUBLE, "d",
TXXX
};
Ftab ftabinit[OEND] =
{
OADD, "add", 1,
OAND, "and", 1,
OASHL, "ashl", 1,
OASHR, "ashr", 1,
ODIV, "div", 1,
OLDIV, "ldiv", 1,
OLMOD, "lmod", 1,
OLMUL, "lmul", 1,
OLSHR, "lshr", 1,
OMOD, "mod", 1,
OMUL, "mul", 1,
OOR, "or", 1,
OSUB, "sub", 1,
OXOR, "xor", 1,
OEQ, "eq", 2,
OGE, "ge", 2,
OGT, "gt", 2,
OHI, "hi", 2,
OHS, "hs", 2,
OLE, "le", 2,
OLO, "lo", 2,
OLS, "ls", 2,
OLT, "lt", 2,
ONE, "ne", 2,
OASADD, "asadd", 3,
OASAND, "asand", 3,
OASASHL, "asashl", 3,
OASASHR, "asashr", 3,
OASDIV, "asdiv", 3,
OASLDIV, "asldiv", 3,
OASLMOD, "aslmod", 3,
OASLMUL, "aslmul", 3,
OASLSHR, "aslshr", 3,
OASMOD, "asmod", 3,
OASMUL, "asmul", 3,
OASOR, "asor", 3,
OASSUB, "assub", 3,
OASXOR, "asxor", 3,
OPOS, "pos", 4,
ONEG, "neg", 4,
OCOM, "com", 4,
ONOT, "not", 4,
// OPOSTDEC,
// OPOSTINC,
// OPREDEC,
// OPREINC,
OXXX,
};
// Node* nodtestv;
// Node* nodvpp;
// Node* nodppv;
// Node* nodvmm;
// Node* nodmmv;

1542
src/cmd/cc/lex.c Normal file

File diff suppressed because it is too large Load diff

723
src/cmd/cc/lexbody Normal file
View file

@ -0,0 +1,723 @@
// Inferno utils/cc/lexbody
// http://code.google.com/p/inferno-os/source/browse/utils/cc/lexbody
//
// 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.
/*
* common code for all the assemblers
*/
void
pragpack(void)
{
while(getnsc() != '\n')
;
}
void
pragvararg(void)
{
while(getnsc() != '\n')
;
}
void
pragfpround(void)
{
while(getnsc() != '\n')
;
}
void
pragprofile(void)
{
while(getnsc() != '\n')
;
}
void
pragincomplete(void)
{
while(getnsc() != '\n')
;
}
void
gethunk(void)
{
hunk = malloc(NHUNK);
memset(hunk, 0, NHUNK);
nhunk = NHUNK;
}
void*
alloc(long n)
{
void *p;
while((uintptr)hunk & MAXALIGN) {
hunk++;
nhunk--;
}
while(nhunk < n)
gethunk();
p = hunk;
nhunk -= n;
hunk += n;
return p;
}
void*
allocn(void *p, long on, long n)
{
void *q;
q = (uchar*)p + on;
if(q != hunk || nhunk < n) {
while(nhunk < on+n)
gethunk();
memmove(hunk, p, on);
p = hunk;
hunk += on;
nhunk -= on;
}
hunk += n;
nhunk -= n;
return p;
}
void
setinclude(char *p)
{
int i;
if(p == 0)
return;
for(i=1; i < ninclude; i++)
if(strcmp(p, include[i]) == 0)
return;
if(ninclude >= nelem(include)) {
yyerror("ninclude too small %d", nelem(include));
exits("ninclude");
}
include[ninclude++] = p;
}
void
errorexit(void)
{
if(outfile)
remove(outfile);
exits("error");
}
void
pushio(void)
{
Io *i;
i = iostack;
if(i == I) {
yyerror("botch in pushio");
errorexit();
}
i->p = fi.p;
i->c = fi.c;
}
void
newio(void)
{
Io *i;
static int pushdepth = 0;
i = iofree;
if(i == I) {
pushdepth++;
if(pushdepth > 1000) {
yyerror("macro/io expansion too deep");
errorexit();
}
i = alloc(sizeof(*i));
} else
iofree = i->link;
i->c = 0;
i->f = -1;
ionext = i;
}
void
newfile(char *s, int f)
{
Io *i;
i = ionext;
i->link = iostack;
iostack = i;
i->f = f;
if(f < 0)
i->f = open(s, 0);
if(i->f < 0) {
yyerror("%ca: %r: %s", thechar, s);
errorexit();
}
fi.c = 0;
linehist(s, 0);
}
Sym*
slookup(char *s)
{
strcpy(symb, s);
return lookup();
}
Sym*
lookup(void)
{
Sym *s;
long h;
char *p;
int c, l;
h = 0;
for(p=symb; c = *p; p++)
h = h+h+h + c;
l = (p - symb) + 1;
if(h < 0)
h = ~h;
h %= NHASH;
c = symb[0];
for(s = hash[h]; s != S; s = s->link) {
if(s->name[0] != c)
continue;
if(memcmp(s->name, symb, l) == 0)
return s;
}
s = alloc(sizeof(*s));
s->name = alloc(l);
memmove(s->name, symb, l);
s->link = hash[h];
hash[h] = s;
syminit(s);
return s;
}
long
yylex(void)
{
int c, c1;
char *cp;
Sym *s;
c = peekc;
if(c != IGN) {
peekc = IGN;
goto l1;
}
l0:
c = GETC();
l1:
if(c == EOF) {
peekc = EOF;
return -1;
}
if(isspace(c)) {
if(c == '\n') {
lineno++;
return ';';
}
goto l0;
}
if(isalpha(c))
goto talph;
if(isdigit(c))
goto tnum;
switch(c)
{
case '\n':
lineno++;
return ';';
case '#':
domacro();
goto l0;
case '.':
c = GETC();
if(isalpha(c)) {
cp = symb;
*cp++ = '.';
goto aloop;
}
if(isdigit(c)) {
cp = symb;
*cp++ = '.';
goto casedot;
}
peekc = c;
return '.';
talph:
case '_':
case '@':
cp = symb;
aloop:
*cp++ = c;
c = GETC();
if(isalpha(c) || isdigit(c) || c == '_' || c == '$')
goto aloop;
*cp = 0;
peekc = c;
s = lookup();
if(s->macro) {
newio();
cp = ionext->b;
macexpand(s, cp);
pushio();
ionext->link = iostack;
iostack = ionext;
fi.p = cp;
fi.c = strlen(cp);
if(peekc != IGN) {
cp[fi.c++] = peekc;
cp[fi.c] = 0;
peekc = IGN;
}
goto l0;
}
if(s->type == 0)
s->type = LNAME;
if(s->type == LNAME ||
s->type == LVAR ||
s->type == LLAB) {
yylval.sym = s;
return s->type;
}
yylval.lval = s->value;
return s->type;
tnum:
cp = symb;
if(c != '0')
goto dc;
*cp++ = c;
c = GETC();
c1 = 3;
if(c == 'x' || c == 'X') {
c1 = 4;
c = GETC();
} else
if(c < '0' || c > '7')
goto dc;
yylval.lval = 0;
for(;;) {
if(c >= '0' && c <= '9') {
if(c > '7' && c1 == 3)
break;
yylval.lval <<= c1;
yylval.lval += c - '0';
c = GETC();
continue;
}
if(c1 == 3)
break;
if(c >= 'A' && c <= 'F')
c += 'a' - 'A';
if(c >= 'a' && c <= 'f') {
yylval.lval <<= c1;
yylval.lval += c - 'a' + 10;
c = GETC();
continue;
}
break;
}
goto ncu;
dc:
for(;;) {
if(!isdigit(c))
break;
*cp++ = c;
c = GETC();
}
if(c == '.')
goto casedot;
if(c == 'e' || c == 'E')
goto casee;
*cp = 0;
if(sizeof(yylval.lval) == sizeof(vlong))
yylval.lval = strtoll(symb, nil, 10);
else
yylval.lval = strtol(symb, nil, 10);
ncu:
while(c == 'U' || c == 'u' || c == 'l' || c == 'L')
c = GETC();
peekc = c;
return LCONST;
casedot:
for(;;) {
*cp++ = c;
c = GETC();
if(!isdigit(c))
break;
}
if(c == 'e' || c == 'E')
goto casee;
goto caseout;
casee:
*cp++ = 'e';
c = GETC();
if(c == '+' || c == '-') {
*cp++ = c;
c = GETC();
}
while(isdigit(c)) {
*cp++ = c;
c = GETC();
}
caseout:
*cp = 0;
peekc = c;
if(FPCHIP) {
yylval.dval = atof(symb);
return LFCONST;
}
yyerror("assembler cannot interpret fp constants");
yylval.lval = 1L;
return LCONST;
case '"':
memcpy(yylval.sval, nullgen.sval, sizeof(yylval.sval));
cp = yylval.sval;
c1 = 0;
for(;;) {
c = escchar('"');
if(c == EOF)
break;
if(c1 < sizeof(yylval.sval))
*cp++ = c;
c1++;
}
if(c1 > sizeof(yylval.sval))
yyerror("string constant too long");
return LSCONST;
case '\'':
c = escchar('\'');
if(c == EOF)
c = '\'';
if(escchar('\'') != EOF)
yyerror("missing '");
yylval.lval = c;
return LCONST;
case '/':
c1 = GETC();
if(c1 == '/') {
for(;;) {
c = GETC();
if(c == '\n') {
lineno++;
goto l1;
}
if(c == EOF) {
yyerror("eof in comment");
errorexit();
}
}
}
if(c1 == '*') {
for(;;) {
c = GETC();
while(c == '*') {
c = GETC();
if(c == '/')
goto l0;
}
if(c == EOF) {
yyerror("eof in comment");
errorexit();
}
if(c == '\n')
lineno++;
}
}
break;
default:
return c;
}
peekc = c1;
return c;
}
int
getc(void)
{
int c;
c = peekc;
if(c != IGN) {
peekc = IGN;
return c;
}
c = GETC();
if(c == '\n')
lineno++;
if(c == EOF) {
yyerror("End of file");
errorexit();
}
return c;
}
int
getnsc(void)
{
int c;
for(;;) {
c = getc();
if(!isspace(c) || c == '\n')
return c;
}
}
void
unget(int c)
{
peekc = c;
if(c == '\n')
lineno--;
}
int
escchar(int e)
{
int c, l;
loop:
c = getc();
if(c == '\n') {
yyerror("newline in string");
return EOF;
}
if(c != '\\') {
if(c == e)
return EOF;
return c;
}
c = getc();
if(c >= '0' && c <= '7') {
l = c - '0';
c = getc();
if(c >= '0' && c <= '7') {
l = l*8 + c-'0';
c = getc();
if(c >= '0' && c <= '7') {
l = l*8 + c-'0';
return l;
}
}
peekc = c;
return l;
}
switch(c)
{
case '\n': goto loop;
case 'n': return '\n';
case 't': return '\t';
case 'b': return '\b';
case 'r': return '\r';
case 'f': return '\f';
case 'a': return 0x07;
case 'v': return 0x0b;
case 'z': return 0x00;
}
return c;
}
void
pinit(char *f)
{
int i;
Sym *s;
lineno = 1;
newio();
newfile(f, -1);
pc = 0;
peekc = IGN;
sym = 1;
for(i=0; i<NSYM; i++) {
h[i].type = 0;
h[i].sym = S;
}
for(i=0; i<NHASH; i++)
for(s = hash[i]; s != S; s = s->link)
s->macro = 0;
}
int
filbuf(void)
{
Io *i;
loop:
i = iostack;
if(i == I)
return EOF;
if(i->f < 0)
goto pop;
fi.c = read(i->f, i->b, BUFSIZ) - 1;
if(fi.c < 0) {
close(i->f);
linehist(0, 0);
goto pop;
}
fi.p = i->b + 1;
return i->b[0];
pop:
iostack = i->link;
i->link = iofree;
iofree = i;
i = iostack;
if(i == I)
return EOF;
fi.p = i->p;
fi.c = i->c;
if(--fi.c < 0)
goto loop;
return *fi.p++;
}
void
yyerror(char *a, ...)
{
char buf[200];
va_list arg;
/*
* hack to intercept message from yaccpar
*/
if(strcmp(a, "syntax error") == 0) {
yyerror("syntax error, last name: %s", symb);
return;
}
prfile(lineno);
va_start(arg, a);
vseprint(buf, buf+sizeof(buf), a, arg);
va_end(arg);
print("%s\n", buf);
nerrors++;
if(nerrors > 10) {
print("too many errors\n");
errorexit();
}
}
void
prfile(long l)
{
int i, n;
Hist a[HISTSZ], *h;
long d;
n = 0;
for(h = hist; h != H; h = h->link) {
if(l < h->line)
break;
if(h->name) {
if(h->offset == 0) {
if(n >= 0 && n < HISTSZ)
a[n] = *h;
n++;
continue;
}
if(n > 0 && n < HISTSZ)
if(a[n-1].offset == 0) {
a[n] = *h;
n++;
} else
a[n-1] = *h;
continue;
}
n--;
if(n >= 0 && n < HISTSZ) {
d = h->line - a[n].line;
for(i=0; i<n; i++)
a[i].line += d;
}
}
if(n > HISTSZ)
n = HISTSZ;
for(i=0; i<n; i++)
print("%s:%ld ", a[i].name, (long)(l-a[i].line+a[i].offset+1));
}
void
ieeedtod(Ieee *ieee, double native)
{
double fr, ho, f;
int exp;
if(native < 0) {
ieeedtod(ieee, -native);
ieee->h |= 0x80000000L;
return;
}
if(native == 0) {
ieee->l = 0;
ieee->h = 0;
return;
}
fr = frexp(native, &exp);
f = 2097152L; /* shouldnt use fp constants here */
fr = modf(fr*f, &ho);
ieee->h = ho;
ieee->h &= 0xfffffL;
ieee->h |= (exp+1022L) << 20;
f = 65536L;
fr = modf(fr*f, &ho);
ieee->l = ho;
ieee->l <<= 16;
ieee->l |= (long)(fr*f);
}

33
src/cmd/cc/mac.c Normal file
View file

@ -0,0 +1,33 @@
// Inferno utils/cc/mac.c
// http://code.google.com/p/inferno-os/source/browse/utils/cc/mac.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.
#include "cc.h"
#include "macbody"

842
src/cmd/cc/macbody Normal file
View file

@ -0,0 +1,842 @@
// Inferno utils/cc/macbody
// http://code.google.com/p/inferno-os/source/browse/utils/cc/macbody
//
// 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.
#define VARMAC 0x80
long
getnsn(void)
{
long n;
int c;
c = getnsc();
if(c < '0' || c > '9')
return -1;
n = 0;
while(c >= '0' && c <= '9') {
n = n*10 + c-'0';
c = getc();
}
unget(c);
return n;
}
Sym*
getsym(void)
{
int c;
char *cp;
c = getnsc();
if(!isalpha(c) && c != '_') {
unget(c);
return S;
}
for(cp = symb;;) {
if(cp <= symb+NSYMB-4)
*cp++ = c;
c = getc();
if(isalnum(c) || c == '_')
continue;
unget(c);
break;
}
*cp = 0;
if(cp > symb+NSYMB-4)
yyerror("symbol too large: %s", symb);
return lookup();
}
Sym*
getsymdots(int *dots)
{
int c;
Sym *s;
s = getsym();
if(s != S)
return s;
c = getnsc();
if(c != '.'){
unget(c);
return S;
}
if(getc() != '.' || getc() != '.')
yyerror("bad dots in macro");
*dots = 1;
return slookup("__VA_ARGS__");
}
int
getcom(void)
{
int c;
for(;;) {
c = getnsc();
if(c != '/')
break;
c = getc();
if(c == '/') {
while(c != '\n')
c = getc();
break;
}
if(c != '*')
break;
c = getc();
for(;;) {
if(c == '*') {
c = getc();
if(c != '/')
continue;
c = getc();
break;
}
if(c == '\n') {
yyerror("comment across newline");
break;
}
c = getc();
}
if(c == '\n')
break;
}
return c;
}
void
dodefine(char *cp)
{
Sym *s;
char *p;
long l;
strcpy(symb, cp);
p = strchr(symb, '=');
if(p) {
*p++ = 0;
s = lookup();
l = strlen(p) + 2; /* +1 null, +1 nargs */
s->macro = alloc(l);
strcpy(s->macro+1, p);
} else {
s = lookup();
s->macro = "\0001"; /* \000 is nargs */
}
if(debug['m'])
print("#define (-D) %s %s\n", s->name, s->macro+1);
}
struct
{
char *macname;
void (*macf)(void);
} mactab[] =
{
"ifdef", 0, /* macif(0) */
"ifndef", 0, /* macif(1) */
"else", 0, /* macif(2) */
"line", maclin,
"define", macdef,
"include", macinc,
"undef", macund,
"pragma", macprag,
"endif", macend,
0
};
void
domacro(void)
{
int i;
Sym *s;
s = getsym();
if(s == S)
s = slookup("endif");
for(i=0; mactab[i].macname; i++)
if(strcmp(s->name, mactab[i].macname) == 0) {
if(mactab[i].macf)
(*mactab[i].macf)();
else
macif(i);
return;
}
yyerror("unknown #: %s", s->name);
macend();
}
void
macund(void)
{
Sym *s;
s = getsym();
macend();
if(s == S) {
yyerror("syntax in #undef");
return;
}
s->macro = 0;
}
#define NARG 25
void
macdef(void)
{
Sym *s, *a;
char *args[NARG], *np, *base;
int n, i, c, len, dots;
int ischr;
s = getsym();
if(s == S)
goto bad;
if(s->macro)
yyerror("macro redefined: %s", s->name);
c = getc();
n = -1;
dots = 0;
if(c == '(') {
n++;
c = getnsc();
if(c != ')') {
unget(c);
for(;;) {
a = getsymdots(&dots);
if(a == S)
goto bad;
if(n >= NARG) {
yyerror("too many arguments in #define: %s", s->name);
goto bad;
}
args[n++] = a->name;
c = getnsc();
if(c == ')')
break;
if(c != ',' || dots)
goto bad;
}
}
c = getc();
}
if(isspace(c))
if(c != '\n')
c = getnsc();
base = hunk;
len = 1;
ischr = 0;
for(;;) {
if(isalpha(c) || c == '_') {
np = symb;
*np++ = c;
c = getc();
while(isalnum(c) || c == '_') {
*np++ = c;
c = getc();
}
*np = 0;
for(i=0; i<n; i++)
if(strcmp(symb, args[i]) == 0)
break;
if(i >= n) {
i = strlen(symb);
base = allocn(base, len, i);
memcpy(base+len, symb, i);
len += i;
continue;
}
base = allocn(base, len, 2);
base[len++] = '#';
base[len++] = 'a' + i;
continue;
}
if(ischr){
if(c == '\\'){
base = allocn(base, len, 1);
base[len++] = c;
c = getc();
}else if(c == ischr)
ischr = 0;
}else{
if(c == '"' || c == '\''){
base = allocn(base, len, 1);
base[len++] = c;
ischr = c;
c = getc();
continue;
}
if(c == '/') {
c = getc();
if(c == '/'){
c = getc();
for(;;) {
if(c == '\n')
break;
c = getc();
}
continue;
}
if(c == '*'){
c = getc();
for(;;) {
if(c == '*') {
c = getc();
if(c != '/')
continue;
c = getc();
break;
}
if(c == '\n') {
yyerror("comment and newline in define: %s", s->name);
break;
}
c = getc();
}
continue;
}
base = allocn(base, len, 1);
base[len++] = '/';
continue;
}
}
if(c == '\\') {
c = getc();
if(c == '\n') {
c = getc();
continue;
}
else if(c == '\r') {
c = getc();
if(c == '\n') {
c = getc();
continue;
}
}
base = allocn(base, len, 1);
base[len++] = '\\';
continue;
}
if(c == '\n')
break;
if(c == '#')
if(n > 0) {
base = allocn(base, len, 1);
base[len++] = c;
}
base = allocn(base, len, 1);
base[len++] = c;
c = ((--fi.c < 0)? filbuf(): (*fi.p++ & 0xff));
if(c == '\n')
lineno++;
if(c == -1) {
yyerror("eof in a macro: %s", s->name);
break;
}
}
do {
base = allocn(base, len, 1);
base[len++] = 0;
} while(len & 3);
*base = n+1;
if(dots)
*base |= VARMAC;
s->macro = base;
if(debug['m'])
print("#define %s %s\n", s->name, s->macro+1);
return;
bad:
if(s == S)
yyerror("syntax in #define");
else
yyerror("syntax in #define: %s", s->name);
macend();
}
void
macexpand(Sym *s, char *b)
{
char buf[2000];
int n, l, c, nargs;
char *arg[NARG], *cp, *ob, *ecp, dots;
ob = b;
if(*s->macro == 0) {
strcpy(b, s->macro+1);
if(debug['m'])
print("#expand %s %s\n", s->name, ob);
return;
}
nargs = (char)(*s->macro & ~VARMAC) - 1;
dots = *s->macro & VARMAC;
c = getnsc();
if(c != '(')
goto bad;
n = 0;
c = getc();
if(c != ')') {
unget(c);
l = 0;
cp = buf;
ecp = cp + sizeof(buf)-4;
arg[n++] = cp;
for(;;) {
if(cp >= ecp)
goto toobig;
c = getc();
if(c == '"')
for(;;) {
if(cp >= ecp)
goto toobig;
*cp++ = c;
c = getc();
if(c == '\\') {
*cp++ = c;
c = getc();
continue;
}
if(c == '\n')
goto bad;
if(c == '"')
break;
}
if(c == '\'')
for(;;) {
if(cp >= ecp)
goto toobig;
*cp++ = c;
c = getc();
if(c == '\\') {
*cp++ = c;
c = getc();
continue;
}
if(c == '\n')
goto bad;
if(c == '\'')
break;
}
if(c == '/') {
c = getc();
switch(c) {
case '*':
for(;;) {
c = getc();
if(c == '*') {
c = getc();
if(c == '/')
break;
}
}
*cp++ = ' ';
continue;
case '/':
while((c = getc()) != '\n')
;
break;
default:
unget(c);
c = '/';
}
}
if(l == 0) {
if(c == ',') {
if(n == nargs && dots) {
*cp++ = ',';
continue;
}
*cp++ = 0;
arg[n++] = cp;
if(n > nargs)
break;
continue;
}
if(c == ')')
break;
}
if(c == '\n')
c = ' ';
*cp++ = c;
if(c == '(')
l++;
if(c == ')')
l--;
}
*cp = 0;
}
if(n != nargs) {
yyerror("argument mismatch expanding: %s", s->name);
*b = 0;
return;
}
cp = s->macro+1;
for(;;) {
c = *cp++;
if(c == '\n')
c = ' ';
if(c != '#') {
*b++ = c;
if(c == 0)
break;
continue;
}
c = *cp++;
if(c == 0)
goto bad;
if(c == '#') {
*b++ = c;
continue;
}
c -= 'a';
if(c < 0 || c >= n)
continue;
strcpy(b, arg[c]);
b += strlen(arg[c]);
}
*b = 0;
if(debug['m'])
print("#expand %s %s\n", s->name, ob);
return;
bad:
yyerror("syntax in macro expansion: %s", s->name);
*b = 0;
return;
toobig:
yyerror("too much text in macro expansion: %s", s->name);
*b = 0;
}
void
macinc(void)
{
int c0, c, i, f;
char str[STRINGSZ], *hp;
c0 = getnsc();
if(c0 != '"') {
c = c0;
if(c0 != '<')
goto bad;
c0 = '>';
}
for(hp = str;;) {
c = getc();
if(c == c0)
break;
if(c == '\n')
goto bad;
*hp++ = c;
}
*hp = 0;
c = getcom();
if(c != '\n')
goto bad;
f = -1;
for(i=0; i<ninclude; i++) {
if(i == 0 && c0 == '>')
continue;
strcpy(symb, include[i]);
strcat(symb, "/");
if(strcmp(symb, "./") == 0)
symb[0] = 0;
strcat(symb, str);
f = myopen(symb);
if(f >= 0)
break;
}
if(f < 0)
strcpy(symb, str);
c = strlen(symb) + 1;
hp = alloc(c);
memcpy(hp, symb, c);
newio();
pushio();
newfile(hp, f);
return;
bad:
unget(c);
yyerror("syntax in #include");
macend();
}
void
maclin(void)
{
char *cp;
int c;
long n;
n = getnsn();
c = getc();
if(n < 0)
goto bad;
for(;;) {
if(c == ' ' || c == '\t') {
c = getc();
continue;
}
if(c == '"')
break;
if(c == '\n') {
strcpy(symb, "<noname>");
goto nn;
}
goto bad;
}
cp = symb;
for(;;) {
c = getc();
if(c == '"')
break;
*cp++ = c;
}
*cp = 0;
c = getcom();
if(c != '\n')
goto bad;
nn:
c = strlen(symb) + 1;
cp = alloc(c);
memcpy(cp, symb, c);
linehist(cp, n);
return;
bad:
unget(c);
yyerror("syntax in #line");
macend();
}
void
macif(int f)
{
int c, l, bol;
Sym *s;
if(f == 2)
goto skip;
s = getsym();
if(s == S)
goto bad;
if(getcom() != '\n')
goto bad;
if((s->macro != 0) ^ f)
return;
skip:
bol = 1;
l = 0;
for(;;) {
c = getc();
if(c != '#') {
if(!isspace(c))
bol = 0;
if(c == '\n')
bol = 1;
continue;
}
if(!bol)
continue;
s = getsym();
if(s == S)
continue;
if(strcmp(s->name, "endif") == 0) {
if(l) {
l--;
continue;
}
macend();
return;
}
if(strcmp(s->name, "ifdef") == 0 || strcmp(s->name, "ifndef") == 0) {
l++;
continue;
}
if(l == 0 && f != 2 && strcmp(s->name, "else") == 0) {
macend();
return;
}
}
bad:
yyerror("syntax in #if(n)def");
macend();
}
void
macprag(void)
{
Sym *s;
int c0, c;
char *hp;
Hist *h;
s = getsym();
if(s && strcmp(s->name, "lib") == 0)
goto praglib;
if(s && strcmp(s->name, "pack") == 0) {
pragpack();
return;
}
if(s && strcmp(s->name, "fpround") == 0) {
pragfpround();
return;
}
if(s && strcmp(s->name, "profile") == 0) {
pragprofile();
return;
}
if(s && strcmp(s->name, "varargck") == 0) {
pragvararg();
return;
}
if(s && strcmp(s->name, "incomplete") == 0) {
pragincomplete();
return;
}
while(getnsc() != '\n')
;
return;
praglib:
c0 = getnsc();
if(c0 != '"') {
c = c0;
if(c0 != '<')
goto bad;
c0 = '>';
}
for(hp = symb;;) {
c = getc();
if(c == c0)
break;
if(c == '\n')
goto bad;
*hp++ = c;
}
*hp = 0;
c = getcom();
if(c != '\n')
goto bad;
/*
* put pragma-line in as a funny history
*/
c = strlen(symb) + 1;
hp = alloc(c);
memcpy(hp, symb, c);
h = alloc(sizeof(Hist));
h->name = hp;
h->line = lineno;
h->offset = -1;
h->link = H;
if(ehist == H) {
hist = h;
ehist = h;
return;
}
ehist->link = h;
ehist = h;
return;
bad:
unget(c);
yyerror("syntax in #pragma lib");
macend();
}
void
macend(void)
{
int c;
for(;;) {
c = getnsc();
if(c < 0 || c == '\n')
return;
}
}
void
linehist(char *f, int offset)
{
Hist *h;
/*
* overwrite the last #line directive if
* no alloc has happened since the last one
*/
if(newflag == 0 && ehist != H && offset != 0 && ehist->offset != 0)
if(f && ehist->name && strcmp(f, ehist->name) == 0) {
ehist->line = lineno;
ehist->offset = offset;
return;
}
if(debug['f'])
if(f) {
if(offset)
print("%4ld: %s (#line %d)\n", lineno, f, offset);
else
print("%4ld: %s\n", lineno, f);
} else
print("%4ld: <pop>\n", lineno);
newflag = 0;
h = alloc(sizeof(Hist));
h->name = f;
h->line = lineno;
h->offset = offset;
h->link = H;
if(ehist == H) {
hist = h;
ehist = h;
return;
}
ehist->link = h;
ehist = h;
}

38
src/cmd/cc/omachcap.c Normal file
View file

@ -0,0 +1,38 @@
// Inferno utils/cc/machcap.c
// http://code.google.com/p/inferno-os/source/browse/utils/cc/machcap.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.
#include "cc.h"
/* default, like old cc */
int
machcap(Node *n)
{
return 0;
}

550
src/cmd/cc/pgen.c Normal file
View file

@ -0,0 +1,550 @@
// Inferno utils/6c/sgen.c
// http://code.google.com/p/inferno-os/source/browse/utils/6c/sgen.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.
#include "gc.h"
void
codgen(Node *n, Node *nn)
{
Prog *sp;
Node *n1, nod, nod1;
cursafe = 0;
curarg = 0;
maxargsafe = 0;
/*
* isolate name
*/
for(n1 = nn;; n1 = n1->left) {
if(n1 == Z) {
diag(nn, "cant find function name");
return;
}
if(n1->op == ONAME)
break;
}
nearln = nn->lineno;
gpseudo(ATEXT, n1->sym, nodconst(stkoff));
sp = p;
/*
* isolate first argument
*/
if(REGARG) {
if(typecmplx[thisfn->link->etype]) {
nod1 = *nodret->left;
nodreg(&nod, &nod1, REGARG);
gmove(&nod, &nod1);
} else
if(firstarg && typeword[firstargtype->etype]) {
nod1 = *nodret->left;
nod1.sym = firstarg;
nod1.type = firstargtype;
nod1.xoffset = align(0, firstargtype, Aarg1);
nod1.etype = firstargtype->etype;
nodreg(&nod, &nod1, REGARG);
gmove(&nod, &nod1);
}
}
canreach = 1;
warnreach = 1;
gen(n);
if(canreach && thisfn->link->etype != TVOID)
warn(Z, "no return at end of function: %s", n1->sym->name);
noretval(3);
gbranch(ORETURN);
if(!debug['N'] || debug['R'] || debug['P'])
regopt(sp);
if(thechar=='6' || thechar=='7') /* [sic] */
maxargsafe = xround(maxargsafe, 8);
sp->to.offset += maxargsafe;
}
void
supgen(Node *n)
{
int owarn;
long spc;
Prog *sp;
if(n == Z)
return;
suppress++;
owarn = warnreach;
warnreach = 0;
spc = pc;
sp = lastp;
gen(n);
lastp = sp;
pc = spc;
sp->link = nil;
suppress--;
warnreach = owarn;
}
void
gen(Node *n)
{
Node *l, nod;
Prog *sp, *spc, *spb;
Case *cn;
long sbc, scc;
int snbreak, sncontin;
int f, o, oldreach;
loop:
if(n == Z)
return;
nearln = n->lineno;
o = n->op;
if(debug['G'])
if(o != OLIST)
print("%L %O\n", nearln, o);
if(!canreach) {
switch(o) {
case OLABEL:
case OCASE:
case OLIST:
case OBREAK:
case OFOR:
case OWHILE:
case ODWHILE:
/* all handled specially - see switch body below */
break;
default:
if(warnreach) {
warn(n, "unreachable code %O", o);
warnreach = 0;
}
}
}
switch(o) {
default:
complex(n);
cgen(n, Z);
break;
case OLIST:
gen(n->left);
rloop:
n = n->right;
goto loop;
case ORETURN:
canreach = 0;
warnreach = !suppress;
complex(n);
if(n->type == T)
break;
l = n->left;
if(l == Z) {
noretval(3);
gbranch(ORETURN);
break;
}
if(typecmplx[n->type->etype]) {
sugen(l, nodret, n->type->width);
noretval(3);
gbranch(ORETURN);
break;
}
regret(&nod, n);
cgen(l, &nod);
regfree(&nod);
if(typefd[n->type->etype])
noretval(1);
else
noretval(2);
gbranch(ORETURN);
break;
case OLABEL:
canreach = 1;
l = n->left;
if(l) {
l->pc = pc;
if(l->label)
patch(l->label, pc);
}
gbranch(OGOTO); /* prevent self reference in reg */
patch(p, pc);
goto rloop;
case OGOTO:
canreach = 0;
warnreach = !suppress;
n = n->left;
if(n == Z)
return;
if(n->complex == 0) {
diag(Z, "label undefined: %s", n->sym->name);
return;
}
if(suppress)
return;
gbranch(OGOTO);
if(n->pc) {
patch(p, n->pc);
return;
}
if(n->label)
patch(n->label, pc-1);
n->label = p;
return;
case OCASE:
canreach = 1;
l = n->left;
if(cases == C)
diag(n, "case/default outside a switch");
if(l == Z) {
cas();
cases->val = 0;
cases->def = 1;
cases->label = pc;
cases->isv = 0;
goto rloop;
}
complex(l);
if(l->type == T)
goto rloop;
if(l->op == OCONST)
if(typeword[l->type->etype] && l->type->etype != TIND) {
cas();
cases->val = l->vconst;
cases->def = 0;
cases->label = pc;
cases->isv = typev[l->type->etype];
goto rloop;
}
diag(n, "case expression must be integer constant");
goto rloop;
case OSWITCH:
l = n->left;
complex(l);
if(l->type == T)
break;
if(!typeword[l->type->etype] || l->type->etype == TIND) {
diag(n, "switch expression must be integer");
break;
}
gbranch(OGOTO); /* entry */
sp = p;
cn = cases;
cases = C;
cas();
sbc = breakpc;
breakpc = pc;
snbreak = nbreak;
nbreak = 0;
gbranch(OGOTO);
spb = p;
gen(n->right); /* body */
if(canreach){
gbranch(OGOTO);
patch(p, breakpc);
nbreak++;
}
patch(sp, pc);
regalloc(&nod, l, Z);
/* always signed */
if(typev[l->type->etype])
nod.type = types[TVLONG];
else
nod.type = types[TLONG];
cgen(l, &nod);
doswit(&nod);
regfree(&nod);
patch(spb, pc);
cases = cn;
breakpc = sbc;
canreach = nbreak!=0;
if(canreach == 0)
warnreach = !suppress;
nbreak = snbreak;
break;
case OWHILE:
case ODWHILE:
l = n->left;
gbranch(OGOTO); /* entry */
sp = p;
scc = continpc;
continpc = pc;
gbranch(OGOTO);
spc = p;
sbc = breakpc;
breakpc = pc;
snbreak = nbreak;
nbreak = 0;
gbranch(OGOTO);
spb = p;
patch(spc, pc);
if(n->op == OWHILE)
patch(sp, pc);
bcomplex(l, Z); /* test */
patch(p, breakpc);
if(l->op != OCONST || vconst(l) == 0)
nbreak++;
if(n->op == ODWHILE)
patch(sp, pc);
gen(n->right); /* body */
gbranch(OGOTO);
patch(p, continpc);
patch(spb, pc);
continpc = scc;
breakpc = sbc;
canreach = nbreak!=0;
if(canreach == 0)
warnreach = !suppress;
nbreak = snbreak;
break;
case OFOR:
l = n->left;
if(!canreach && l->right->left && warnreach) {
warn(n, "unreachable code FOR");
warnreach = 0;
}
gen(l->right->left); /* init */
gbranch(OGOTO); /* entry */
sp = p;
/*
* if there are no incoming labels in the
* body and the top's not reachable, warn
*/
if(!canreach && warnreach && deadheads(n)) {
warn(n, "unreachable code %O", o);
warnreach = 0;
}
scc = continpc;
continpc = pc;
gbranch(OGOTO);
spc = p;
sbc = breakpc;
breakpc = pc;
snbreak = nbreak;
nbreak = 0;
sncontin = ncontin;
ncontin = 0;
gbranch(OGOTO);
spb = p;
patch(spc, pc);
gen(l->right->right); /* inc */
patch(sp, pc);
if(l->left != Z) { /* test */
bcomplex(l->left, Z);
patch(p, breakpc);
if(l->left->op != OCONST || vconst(l->left) == 0)
nbreak++;
}
canreach = 1;
gen(n->right); /* body */
if(canreach){
gbranch(OGOTO);
patch(p, continpc);
ncontin++;
}
if(!ncontin && l->right->right && warnreach) {
warn(l->right->right, "unreachable FOR inc");
warnreach = 0;
}
patch(spb, pc);
continpc = scc;
breakpc = sbc;
canreach = nbreak!=0;
if(canreach == 0)
warnreach = !suppress;
nbreak = snbreak;
ncontin = sncontin;
break;
case OCONTINUE:
if(continpc < 0) {
diag(n, "continue not in a loop");
break;
}
gbranch(OGOTO);
patch(p, continpc);
ncontin++;
canreach = 0;
warnreach = !suppress;
break;
case OBREAK:
if(breakpc < 0) {
diag(n, "break not in a loop");
break;
}
/*
* Don't complain about unreachable break statements.
* There are breaks hidden in yacc's output and some people
* write return; break; in their switch statements out of habit.
* However, don't confuse the analysis by inserting an
* unreachable reference to breakpc either.
*/
if(!canreach)
break;
gbranch(OGOTO);
patch(p, breakpc);
nbreak++;
canreach = 0;
warnreach = !suppress;
break;
case OIF:
l = n->left;
if(bcomplex(l, n->right)) {
if(typefd[l->type->etype])
f = !l->fconst;
else
f = !l->vconst;
if(debug['c'])
print("%L const if %s\n", nearln, f ? "false" : "true");
if(f) {
canreach = 1;
supgen(n->right->left);
oldreach = canreach;
canreach = 1;
gen(n->right->right);
/*
* treat constant ifs as regular ifs for
* reachability warnings.
*/
if(!canreach && oldreach && debug['w'] < 2)
warnreach = 0;
}
else {
canreach = 1;
gen(n->right->left);
oldreach = canreach;
canreach = 1;
supgen(n->right->right);
/*
* treat constant ifs as regular ifs for
* reachability warnings.
*/
if(!oldreach && canreach && debug['w'] < 2)
warnreach = 0;
canreach = oldreach;
}
}
else {
sp = p;
canreach = 1;
if(n->right->left != Z)
gen(n->right->left);
oldreach = canreach;
canreach = 1;
if(n->right->right != Z) {
gbranch(OGOTO);
patch(sp, pc);
sp = p;
gen(n->right->right);
}
patch(sp, pc);
canreach = canreach || oldreach;
if(canreach == 0)
warnreach = !suppress;
}
break;
case OSET:
case OUSED:
usedset(n->left, o);
break;
}
}
void
usedset(Node *n, int o)
{
if(n->op == OLIST) {
usedset(n->left, o);
usedset(n->right, o);
return;
}
complex(n);
switch(n->op) {
case OADDR: /* volatile */
gins(ANOP, n, Z);
break;
case ONAME:
if(o == OSET)
gins(ANOP, Z, n);
else
gins(ANOP, n, Z);
break;
}
}
int
bcomplex(Node *n, Node *c)
{
complex(n);
if(n->type != T)
if(tcompat(n, T, n->type, tnot))
n->type = T;
if(n->type == T) {
gbranch(OGOTO);
return 0;
}
if(c != Z && n->op == OCONST && deadheads(c))
return 1;
bool64(n);
boolgen(n, 1, Z);
return 0;
}

298
src/cmd/cc/pickle.c Normal file
View file

@ -0,0 +1,298 @@
// Inferno utils/cc/pickle.c
// http://code.google.com/p/inferno-os/source/browse/utils/cc/pickle.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.
#include "cc.h"
static char *kwd[] =
{
"$adt", "$aggr", "$append", "$complex", "$defn",
"$delete", "$do", "$else", "$eval", "$head", "$if",
"$local", "$loop", "$return", "$tail", "$then",
"$union", "$whatis", "$while",
};
static char picklestr[] = "\tbp = pickle(bp, ep, un, ";
static char*
pmap(char *s)
{
int i, bot, top, new;
bot = 0;
top = bot + nelem(kwd) - 1;
while(bot <= top){
new = bot + (top - bot)/2;
i = strcmp(kwd[new]+1, s);
if(i == 0)
return kwd[new];
if(i < 0)
bot = new + 1;
else
top = new - 1;
}
return s;
}
Sym*
picklesue(Type *t)
{
int h;
Sym *s;
if(t != T)
for(h=0; h<nelem(hash); h++)
for(s = hash[h]; s != S; s = s->link)
if(s->suetag && s->suetag->link == t)
return s;
return 0;
}
Sym*
picklefun(Type *t)
{
int h;
Sym *s;
for(h=0; h<nelem(hash); h++)
for(s = hash[h]; s != S; s = s->link)
if(s->type == t)
return s;
return 0;
}
char picklechar[NTYPE];
Init picklecinit[] =
{
TCHAR, 'C', 0,
TUCHAR, 'b', 0,
TSHORT, 'd', 0,
TUSHORT, 'u', 0,
TLONG, 'D', 0,
TULONG, 'U', 0,
TVLONG, 'V', 0,
TUVLONG, 'W', 0,
TFLOAT, 'f', 0,
TDOUBLE, 'F', 0,
TARRAY, 'a', 0,
TIND, 'X', 0,
-1, 0, 0,
};
static void
pickleinit(void)
{
Init *p;
for(p=picklecinit; p->code >= 0; p++)
picklechar[p->code] = p->value;
picklechar[TINT] = picklechar[TLONG];
picklechar[TUINT] = picklechar[TULONG];
if(types[TINT]->width != types[TLONG]->width) {
picklechar[TINT] = picklechar[TSHORT];
picklechar[TUINT] = picklechar[TUSHORT];
if(types[TINT]->width != types[TSHORT]->width)
warn(Z, "picklemember int not long or short");
}
}
void
picklemember(Type *t, long off)
{
Sym *s, *s1;
static int picklecharinit = 0;
if(picklecharinit == 0) {
pickleinit();
picklecharinit = 1;
}
s = t->sym;
switch(t->etype) {
default:
Bprint(&outbuf, " T%d\n", t->etype);
break;
case TIND:
if(s == S)
Bprint(&outbuf,
"%s\"p\", (char*)addr+%ld+_i*%ld);\n",
picklestr, t->offset+off, t->width);
else
Bprint(&outbuf,
"%s\"p\", &addr->%s);\n",
picklestr, pmap(s->name));
break;
case TINT:
case TUINT:
case TCHAR:
case TUCHAR:
case TSHORT:
case TUSHORT:
case TLONG:
case TULONG:
case TVLONG:
case TUVLONG:
case TFLOAT:
case TDOUBLE:
if(s == S)
Bprint(&outbuf, "%s\"%c\", (char*)addr+%ld+_i*%ld);\n",
picklestr, picklechar[t->etype], t->offset+off, t->width);
else
Bprint(&outbuf, "%s\"%c\", &addr->%s);\n",
picklestr, picklechar[t->etype], pmap(s->name));
break;
case TARRAY:
Bprint(&outbuf, "\tfor(_i = 0; _i < %ld; _i++) {\n\t",
t->width/t->link->width);
picklemember(t->link, t->offset+off);
Bprint(&outbuf, "\t}\n\t_i = 0;\n\tUSED(_i);\n");
break;
case TSTRUCT:
case TUNION:
s1 = picklesue(t->link);
if(s1 == S)
break;
if(s == S) {
Bprint(&outbuf, "\tbp = pickle_%s(bp, ep, un, (%s*)((char*)addr+%ld+_i*%ld));\n",
pmap(s1->name), pmap(s1->name), t->offset+off, t->width);
} else {
Bprint(&outbuf, "\tbp = pickle_%s(bp, ep, un, &addr->%s);\n",
pmap(s1->name), pmap(s->name));
}
break;
}
}
void
pickletype(Type *t)
{
Sym *s;
Type *l;
Io *i;
int n;
char *an;
if(!debug['P'])
return;
if(debug['P'] > 1) {
n = 0;
for(i=iostack; i; i=i->link)
n++;
if(n > 1)
return;
}
s = picklesue(t->link);
if(s == S)
return;
switch(t->etype) {
default:
Bprint(&outbuf, "T%d\n", t->etype);
return;
case TUNION:
case TSTRUCT:
if(debug['s'])
goto asmstr;
an = pmap(s->name);
Bprint(&outbuf, "char *\npickle_%s(char *bp, char *ep, int un, %s *addr)\n{\n\tint _i = 0;\n\n\tUSED(_i);\n", an, an);
for(l = t->link; l != T; l = l->down)
picklemember(l, 0);
Bprint(&outbuf, "\treturn bp;\n}\n\n");
break;
asmstr:
if(s == S)
break;
for(l = t->link; l != T; l = l->down)
if(l->sym != S)
Bprint(&outbuf, "#define\t%s.%s\t%ld\n",
s->name,
l->sym->name,
l->offset);
break;
}
}
void
picklevar(Sym *s)
{
int n;
Io *i;
Type *t;
Sym *s1, *s2;
if(!debug['P'] || debug['s'])
return;
if(debug['P'] > 1) {
n = 0;
for(i=iostack; i; i=i->link)
n++;
if(n > 1)
return;
}
t = s->type;
while(t && t->etype == TIND)
t = t->link;
if(t == T)
return;
if(t->etype == TENUM) {
Bprint(&outbuf, "%s = ", pmap(s->name));
if(!typefd[t->etype])
Bprint(&outbuf, "%lld;\n", s->vconst);
else
Bprint(&outbuf, "%f\n;", s->fconst);
return;
}
if(!typesu[t->etype])
return;
s1 = picklesue(t->link);
if(s1 == S)
return;
switch(s->class) {
case CAUTO:
case CPARAM:
s2 = picklefun(thisfn);
if(s2)
Bprint(&outbuf, "complex %s %s:%s;\n",
pmap(s1->name), pmap(s2->name), pmap(s->name));
break;
case CSTATIC:
case CEXTERN:
case CGLOBL:
case CLOCAL:
Bprint(&outbuf, "complex %s %s;\n",
pmap(s1->name), pmap(s->name));
break;
}
}

168
src/cmd/cc/pswt.c Normal file
View file

@ -0,0 +1,168 @@
// Inferno utils/6c/swt.c
// http://code.google.com/p/inferno-os/source/browse/utils/6c/swt.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.
#include "gc.h"
int
swcmp(const void *a1, const void *a2)
{
C1 *p1, *p2;
p1 = (C1*)a1;
p2 = (C1*)a2;
if(p1->val < p2->val)
return -1;
return p1->val > p2->val;
}
void
doswit(Node *n)
{
Case *c;
C1 *q, *iq;
long def, nc, i, isv;
def = 0;
nc = 0;
isv = 0;
for(c = cases; c->link != C; c = c->link) {
if(c->def) {
if(def)
diag(n, "more than one default in switch");
def = c->label;
continue;
}
isv |= c->isv;
nc++;
}
if(isv && !typev[n->type->etype])
warn(n, "32-bit switch expression with 64-bit case constant");
iq = alloc(nc*sizeof(C1));
q = iq;
for(c = cases; c->link != C; c = c->link) {
if(c->def)
continue;
q->label = c->label;
if(isv)
q->val = c->val;
else
q->val = (long)c->val; /* cast ensures correct value for 32-bit switch on 64-bit architecture */
q++;
}
qsort(iq, nc, sizeof(C1), swcmp);
if(debug['W'])
for(i=0; i<nc; i++)
print("case %2ld: = %.8llux\n", i, (vlong)iq[i].val);
for(i=0; i<nc-1; i++)
if(iq[i].val == iq[i+1].val)
diag(n, "duplicate cases in switch %lld", (vlong)iq[i].val);
if(def == 0) {
def = breakpc;
nbreak++;
}
swit1(iq, nc, def, n);
}
void
cas(void)
{
Case *c;
c = alloc(sizeof(*c));
c->link = cases;
cases = c;
}
long
outlstring(ushort *s, long n)
{
char buf[2];
int c;
long r;
if(suppress)
return nstring;
while(nstring & 1)
outstring("", 1);
r = nstring;
while(n > 0) {
c = *s++;
if(align(0, types[TCHAR], Aarg1)) {
buf[0] = c>>8;
buf[1] = c;
} else {
buf[0] = c;
buf[1] = c>>8;
}
outstring(buf, 2);
n -= sizeof(ushort);
}
return r;
}
void
nullwarn(Node *l, Node *r)
{
warn(Z, "result of operation not used");
if(l != Z)
cgen(l, Z);
if(r != Z)
cgen(r, Z);
}
void
ieeedtod(Ieee *ieee, double native)
{
double fr, ho, f;
int exp;
if(native < 0) {
ieeedtod(ieee, -native);
ieee->h |= 0x80000000L;
return;
}
if(native == 0) {
ieee->l = 0;
ieee->h = 0;
return;
}
fr = frexp(native, &exp);
f = 2097152L; /* shouldnt use fp constants here */
fr = modf(fr*f, &ho);
ieee->h = ho;
ieee->h &= 0xfffffL;
ieee->h |= (exp+1022L) << 20;
f = 65536L;
fr = modf(fr*f, &ho);
ieee->l = ho;
ieee->l <<= 16;
ieee->l |= (long)(fr*f);
}

636
src/cmd/cc/scon.c Normal file
View file

@ -0,0 +1,636 @@
// Inferno utils/cc/scon.c
// http://code.google.com/p/inferno-os/source/browse/utils/cc/scon.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.
#include "cc.h"
static Node*
acast(Type *t, Node *n)
{
if(n->type->etype != t->etype || n->op == OBIT) {
n = new1(OCAST, n, Z);
if(nocast(n->left->type, t))
*n = *n->left;
n->type = t;
}
return n;
}
void
evconst(Node *n)
{
Node *l, *r;
int et, isf;
vlong v;
double d;
if(n == Z || n->type == T)
return;
et = n->type->etype;
isf = typefd[et];
l = n->left;
r = n->right;
d = 0;
v = 0;
switch(n->op) {
default:
return;
case ONEG:
if(isf)
d = -l->fconst;
else
v = -l->vconst;
break;
case OCOM:
v = ~l->vconst;
break;
case OCAST:
if(et == TVOID)
return;
et = l->type->etype;
if(isf) {
if(typefd[et])
d = l->fconst;
else
d = l->vconst;
} else {
if(typefd[et])
v = l->fconst;
else
v = convvtox(l->vconst, n->type->etype);
}
break;
case OCONST:
break;
case OADD:
if(isf)
d = l->fconst + r->fconst;
else {
v = l->vconst + r->vconst;
}
break;
case OSUB:
if(isf)
d = l->fconst - r->fconst;
else
v = l->vconst - r->vconst;
break;
case OMUL:
if(isf)
d = l->fconst * r->fconst;
else {
v = l->vconst * r->vconst;
}
break;
case OLMUL:
v = (uvlong)l->vconst * (uvlong)r->vconst;
break;
case ODIV:
if(vconst(r) == 0) {
warn(n, "divide by zero");
return;
}
if(isf)
d = l->fconst / r->fconst;
else
v = l->vconst / r->vconst;
break;
case OLDIV:
if(vconst(r) == 0) {
warn(n, "divide by zero");
return;
}
v = (uvlong)l->vconst / (uvlong)r->vconst;
break;
case OMOD:
if(vconst(r) == 0) {
warn(n, "modulo by zero");
return;
}
v = l->vconst % r->vconst;
break;
case OLMOD:
if(vconst(r) == 0) {
warn(n, "modulo by zero");
return;
}
v = (uvlong)l->vconst % (uvlong)r->vconst;
break;
case OAND:
v = l->vconst & r->vconst;
break;
case OOR:
v = l->vconst | r->vconst;
break;
case OXOR:
v = l->vconst ^ r->vconst;
break;
case OLSHR:
v = (uvlong)l->vconst >> r->vconst;
break;
case OASHR:
v = l->vconst >> r->vconst;
break;
case OASHL:
v = l->vconst << r->vconst;
break;
case OLO:
v = (uvlong)l->vconst < (uvlong)r->vconst;
break;
case OLT:
if(typefd[l->type->etype])
v = l->fconst < r->fconst;
else
v = l->vconst < r->vconst;
break;
case OHI:
v = (uvlong)l->vconst > (uvlong)r->vconst;
break;
case OGT:
if(typefd[l->type->etype])
v = l->fconst > r->fconst;
else
v = l->vconst > r->vconst;
break;
case OLS:
v = (uvlong)l->vconst <= (uvlong)r->vconst;
break;
case OLE:
if(typefd[l->type->etype])
v = l->fconst <= r->fconst;
else
v = l->vconst <= r->vconst;
break;
case OHS:
v = (uvlong)l->vconst >= (uvlong)r->vconst;
break;
case OGE:
if(typefd[l->type->etype])
v = l->fconst >= r->fconst;
else
v = l->vconst >= r->vconst;
break;
case OEQ:
if(typefd[l->type->etype])
v = l->fconst == r->fconst;
else
v = l->vconst == r->vconst;
break;
case ONE:
if(typefd[l->type->etype])
v = l->fconst != r->fconst;
else
v = l->vconst != r->vconst;
break;
case ONOT:
if(typefd[l->type->etype])
v = !l->fconst;
else
v = !l->vconst;
break;
case OANDAND:
if(typefd[l->type->etype])
v = l->fconst && r->fconst;
else
v = l->vconst && r->vconst;
break;
case OOROR:
if(typefd[l->type->etype])
v = l->fconst || r->fconst;
else
v = l->vconst || r->vconst;
break;
}
if(isf) {
n->fconst = d;
} else {
n->vconst = convvtox(v, n->type->etype);
}
n->oldop = n->op;
n->op = OCONST;
}
void
acom(Node *n)
{
Type *t;
Node *l, *r;
int i;
switch(n->op)
{
case ONAME:
case OCONST:
case OSTRING:
case OINDREG:
case OREGISTER:
return;
case ONEG:
l = n->left;
if(addo(n) && addo(l))
break;
acom(l);
return;
case OADD:
case OSUB:
case OMUL:
l = n->left;
r = n->right;
if(addo(n)) {
if(addo(r))
break;
if(addo(l))
break;
}
acom(l);
acom(r);
return;
default:
l = n->left;
r = n->right;
if(l != Z)
acom(l);
if(r != Z)
acom(r);
return;
}
/* bust terms out */
t = n->type;
term[0].mult = 0;
term[0].node = Z;
nterm = 1;
acom1(1, n);
if(debug['m'])
for(i=0; i<nterm; i++) {
print("%d %3lld ", i, term[i].mult);
prtree1(term[i].node, 1, 0);
}
if(nterm < NTERM)
acom2(n, t);
n->type = t;
}
int
acomcmp1(const void *a1, const void *a2)
{
vlong c1, c2;
Term *t1, *t2;
t1 = (Term*)a1;
t2 = (Term*)a2;
c1 = t1->mult;
if(c1 < 0)
c1 = -c1;
c2 = t2->mult;
if(c2 < 0)
c2 = -c2;
if(c1 > c2)
return 1;
if(c1 < c2)
return -1;
c1 = 1;
if(t1->mult < 0)
c1 = 0;
c2 = 1;
if(t2->mult < 0)
c2 = 0;
if(c2 -= c1)
return c2;
if(t2 > t1)
return 1;
return -1;
}
int
acomcmp2(const void *a1, const void *a2)
{
vlong c1, c2;
Term *t1, *t2;
t1 = (Term*)a1;
t2 = (Term*)a2;
c1 = t1->mult;
c2 = t2->mult;
if(c1 > c2)
return 1;
if(c1 < c2)
return -1;
if(t2 > t1)
return 1;
return -1;
}
void
acom2(Node *n, Type *t)
{
Node *l, *r;
Term trm[NTERM];
int et, nt, i, j;
vlong c1, c2;
/*
* copy into automatic
*/
c2 = 0;
nt = nterm;
for(i=0; i<nt; i++)
trm[i] = term[i];
/*
* recur on subtrees
*/
j = 0;
for(i=1; i<nt; i++) {
c1 = trm[i].mult;
if(c1 == 0)
continue;
l = trm[i].node;
if(l != Z) {
j = 1;
acom(l);
}
}
c1 = trm[0].mult;
if(j == 0) {
n->oldop = n->op;
n->op = OCONST;
n->vconst = c1;
return;
}
et = t->etype;
/*
* prepare constant term,
* combine it with an addressing term
*/
if(c1 != 0) {
l = new1(OCONST, Z, Z);
l->type = t;
l->vconst = c1;
trm[0].mult = 1;
for(i=1; i<nt; i++) {
if(trm[i].mult != 1)
continue;
r = trm[i].node;
if(r->op != OADDR)
continue;
r->type = t;
l = new1(OADD, r, l);
l->type = t;
trm[i].mult = 0;
break;
}
trm[0].node = l;
}
/*
* look for factorable terms
* c1*i + c1*c2*j -> c1*(i + c2*j)
*/
qsort(trm+1, nt-1, sizeof(trm[0]), acomcmp1);
for(i=nt-1; i>=0; i--) {
c1 = trm[i].mult;
if(c1 < 0)
c1 = -c1;
if(c1 <= 1)
continue;
for(j=i+1; j<nt; j++) {
c2 = trm[j].mult;
if(c2 < 0)
c2 = -c2;
if(c2 <= 1)
continue;
if(c2 % c1)
continue;
r = trm[j].node;
if(r->type->etype != et)
r = acast(t, r);
c2 = trm[j].mult/trm[i].mult;
if(c2 != 1 && c2 != -1) {
r = new1(OMUL, r, new(OCONST, Z, Z));
r->type = t;
r->right->type = t;
r->right->vconst = c2;
}
l = trm[i].node;
if(l->type->etype != et)
l = acast(t, l);
r = new1(OADD, l, r);
r->type = t;
if(c2 == -1)
r->op = OSUB;
trm[i].node = r;
trm[j].mult = 0;
}
}
if(debug['m']) {
print("\n");
for(i=0; i<nt; i++) {
print("%d %3lld ", i, trm[i].mult);
prtree1(trm[i].node, 1, 0);
}
}
/*
* put it all back together
*/
qsort(trm+1, nt-1, sizeof(trm[0]), acomcmp2);
l = Z;
for(i=nt-1; i>=0; i--) {
c1 = trm[i].mult;
if(c1 == 0)
continue;
r = trm[i].node;
if(r->type->etype != et || r->op == OBIT)
r = acast(t, r);
if(c1 != 1 && c1 != -1) {
r = new1(OMUL, r, new(OCONST, Z, Z));
r->type = t;
r->right->type = t;
if(c1 < 0) {
r->right->vconst = -c1;
c1 = -1;
} else {
r->right->vconst = c1;
c1 = 1;
}
}
if(l == Z) {
l = r;
c2 = c1;
continue;
}
if(c1 < 0)
if(c2 < 0)
l = new1(OADD, l, r);
else
l = new1(OSUB, l, r);
else
if(c2 < 0) {
l = new1(OSUB, r, l);
c2 = 1;
} else
l = new1(OADD, l, r);
l->type = t;
}
if(c2 < 0) {
r = new1(OCONST, 0, 0);
r->vconst = 0;
r->type = t;
l = new1(OSUB, r, l);
l->type = t;
}
*n = *l;
}
void
acom1(vlong v, Node *n)
{
Node *l, *r;
if(v == 0 || nterm >= NTERM)
return;
if(!addo(n)) {
if(n->op == OCONST)
if(!typefd[n->type->etype]) {
term[0].mult += v*n->vconst;
return;
}
term[nterm].mult = v;
term[nterm].node = n;
nterm++;
return;
}
switch(n->op) {
case OCAST:
acom1(v, n->left);
break;
case ONEG:
acom1(-v, n->left);
break;
case OADD:
acom1(v, n->left);
acom1(v, n->right);
break;
case OSUB:
acom1(v, n->left);
acom1(-v, n->right);
break;
case OMUL:
l = n->left;
r = n->right;
if(l->op == OCONST)
if(!typefd[n->type->etype]) {
acom1(v*l->vconst, r);
break;
}
if(r->op == OCONST)
if(!typefd[n->type->etype]) {
acom1(v*r->vconst, l);
break;
}
break;
default:
diag(n, "not addo");
}
}
int
addo(Node *n)
{
if(n != Z)
if(!typefd[n->type->etype])
if(!typev[n->type->etype] || ewidth[TVLONG] == ewidth[TIND])
switch(n->op) {
case OCAST:
if(nilcast(n->left->type, n->type))
return 1;
break;
case ONEG:
case OADD:
case OSUB:
return 1;
case OMUL:
if(n->left->op == OCONST)
return 1;
if(n->right->op == OCONST)
return 1;
}
return 0;
}

2054
src/cmd/cc/sub.c Normal file

File diff suppressed because it is too large Load diff

370
src/cmd/gc/const.c Normal file
View file

@ -0,0 +1,370 @@
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
#include "go.h"
#define TUP(x,y) (((x)<<16)|(y))
void
convlit(Node *n, Type *t)
{
int et;
if(n->op != OLITERAL)
return;
if(t == T)
return;
n->type = t;
et = t->etype;
switch(whatis(n)) {
case Wlitint:
if(isptrto(t, TSTRING)) {
Rune rune;
int l;
String *s;
rune = n->val.vval;
l = runelen(rune);
s = mal(sizeof(*s)+l);
s->len = l;
runetochar((char*)(s->s), &rune);
n->val.sval = s;
n->val.ctype = CTSTR;
break;
}
if(isint[et]) {
if(n->val.vval < minintval[et])
goto bad2;
if(n->val.vval > maxintval[et])
goto bad2;
break;
}
if(isfloat[et]) {
if(n->val.vval < minfloatval[et])
goto bad2;
if(n->val.vval > maxfloatval[et])
goto bad2;
n->val.dval = n->val.vval;
n->val.ctype = CTFLT;
break;
}
goto bad1;
case Wlitfloat:
if(isint[et]) {
if(n->val.dval < minintval[et])
goto bad2;
if(n->val.dval > maxintval[et])
goto bad2;
n->val.vval = n->val.dval;
n->val.ctype = CTINT;
break;
}
if(isfloat[et]) {
if(n->val.dval < minfloatval[et])
goto bad2;
if(n->val.dval > maxfloatval[et])
goto bad2;
break;
}
goto bad1;
}
return;
bad1:
yyerror("illegal conversion of constant to %T", t);
return;
bad2:
yyerror("overflow converting constant to %T", t);
return;
}
void
evconst(Node *n)
{
Node *nl, *nr;
long len;
String *str;
int wl, wr;
nl = n->left;
if(nl == N)
return;
wl = whatis(nl);
switch(wl) {
default:
return;
case Wlitint:
case Wlitfloat:
case Wlitbool:
case Wlitstr:
break;
}
nr = n->right;
if(nr == N)
goto unary;
wr = whatis(nr);
switch(wr) {
default:
return;
case Wlitint:
case Wlitfloat:
case Wlitbool:
case Wlitstr:
break;
}
if(wl != wr) {
yyerror("illegal combination of literals %d %d", nl->etype, nr->etype);
return;
}
switch(TUP(n->op, wl)) {
default:
yyerror("illegal combination of literals %O %d", n->op, wl);
return;
case TUP(OADD, Wlitint):
nl->val.vval += nr->val.vval;
break;
case TUP(OSUB, Wlitint):
nl->val.vval -= nr->val.vval;
break;
case TUP(OMUL, Wlitint):
nl->val.vval *= nr->val.vval;
break;
case TUP(ODIV, Wlitint):
nl->val.vval /= nr->val.vval;
break;
case TUP(OMOD, Wlitint):
nl->val.vval %= nr->val.vval;
break;
case TUP(OLSH, Wlitint):
nl->val.vval <<= nr->val.vval;
break;
case TUP(ORSH, Wlitint):
nl->val.vval >>= nr->val.vval;
break;
case TUP(OOR, Wlitint):
nl->val.vval |= nr->val.vval;
break;
case TUP(OAND, Wlitint):
nl->val.vval &= nr->val.vval;
break;
case TUP(OADD, Wlitfloat):
nl->val.dval += nr->val.dval;
break;
case TUP(OSUB, Wlitfloat):
nl->val.dval -= nr->val.dval;
break;
case TUP(OMUL, Wlitfloat):
nl->val.dval *= nr->val.dval;
break;
case TUP(ODIV, Wlitfloat):
nl->val.dval /= nr->val.dval;
break;
case TUP(OEQ, Wlitint):
if(nl->val.vval == nr->val.vval)
goto settrue;
goto setfalse;
case TUP(ONE, Wlitint):
if(nl->val.vval != nr->val.vval)
goto settrue;
goto setfalse;
case TUP(OLT, Wlitint):
if(nl->val.vval < nr->val.vval)
goto settrue;
goto setfalse;
case TUP(OLE, Wlitint):
if(nl->val.vval <= nr->val.vval)
goto settrue;
goto setfalse;
case TUP(OGE, Wlitint):
if(nl->val.vval >= nr->val.vval)
goto settrue;
goto setfalse;
case TUP(OGT, Wlitint):
if(nl->val.vval > nr->val.vval)
goto settrue;
goto setfalse;
case TUP(OEQ, Wlitfloat):
if(nl->val.dval == nr->val.dval)
goto settrue;
goto setfalse;
case TUP(ONE, Wlitfloat):
if(nl->val.dval != nr->val.dval)
goto settrue;
goto setfalse;
case TUP(OLT, Wlitfloat):
if(nl->val.dval < nr->val.dval)
goto settrue;
goto setfalse;
case TUP(OLE, Wlitfloat):
if(nl->val.dval <= nr->val.dval)
goto settrue;
goto setfalse;
case TUP(OGE, Wlitfloat):
if(nl->val.dval >= nr->val.dval)
goto settrue;
goto setfalse;
case TUP(OGT, Wlitfloat):
if(nl->val.dval > nr->val.dval)
goto settrue;
goto setfalse;
case TUP(OEQ, Wlitstr):
if(cmpslit(nl, nr) == 0)
goto settrue;
goto setfalse;
case TUP(ONE, Wlitstr):
if(cmpslit(nl, nr) != 0)
goto settrue;
goto setfalse;
case TUP(OLT, Wlitstr):
if(cmpslit(nl, nr) < 0)
goto settrue;
goto setfalse;
case TUP(OLE, Wlitstr):
if(cmpslit(nl, nr) <= 0)
goto settrue;
goto setfalse;
case TUP(OGE, Wlitstr):
if(cmpslit(nl, nr) >= 0l)
goto settrue;
goto setfalse;
case TUP(OGT, Wlitstr):
if(cmpslit(nl, nr) > 0)
goto settrue;
goto setfalse;
case TUP(OADD, Wlitstr):
len = nl->val.sval->len + nr->val.sval->len;
str = mal(sizeof(*str) + len);
str->len = len;
memcpy(str->s, nl->val.sval->s, nl->val.sval->len);
memcpy(str->s+nl->val.sval->len, nr->val.sval->s, nr->val.sval->len);
str->len = len;
nl->val.sval = str;
break;
case TUP(OOROR, Wlitbool):
if(nl->val.vval || nr->val.vval)
goto settrue;
goto setfalse;
case TUP(OANDAND, Wlitbool):
if(nl->val.vval && nr->val.vval)
goto settrue;
goto setfalse;
}
*n = *nl;
return;
settrue:
*n = *booltrue;
return;
setfalse:
*n = *boolfalse;
return;
unary:
switch(TUP(n->op, wl)) {
default:
yyerror("illegal combination of literals %O %d", n->op, wl);
return;
case TUP(OPLUS, Wlitint):
nl->val.vval = +nl->val.vval;
break;
case TUP(OMINUS, Wlitint):
nl->val.vval = -nl->val.vval;
break;
case TUP(OCOM, Wlitint):
nl->val.vval = ~nl->val.vval;
break;
case TUP(OPLUS, Wlitfloat):
nl->val.dval = +nl->val.dval;
break;
case TUP(OMINUS, Wlitfloat):
nl->val.dval = -nl->val.dval;
break;
case TUP(ONOT, Wlitbool):
if(nl->val.vval)
goto settrue;
goto setfalse;
}
*n = *nl;
}
void
defaultlit(Node *n)
{
if(n == N)
return;
if(n->type != T)
return;
if(n->op != OLITERAL)
return;
switch(n->val.ctype) {
default:
yyerror("defaultlit: unknown literal: %N", n);
break;
case CTINT:
case CTSINT:
case CTUINT:
n->type = types[TINT32];
break;
case CTFLT:
n->type = types[TFLOAT64];
break;
case CTBOOL:
n->type = types[TBOOL];
break;
case CTSTR:
n->type = types[TSTRING];
break;
}
}
int
cmpslit(Node *l, Node *r)
{
long l1, l2, i, m;
char *s1, *s2;
l1 = l->val.sval->len;
l2 = r->val.sval->len;
s1 = l->val.sval->s;
s2 = r->val.sval->s;
m = l1;
if(l2 < m)
m = l2;
for(i=0; i<m; i++) {
if(s1[i] == s2[i])
continue;
if(s1[i] > s2[i])
return +1;
return -1;
}
if(l1 == l2)
return 0;
if(l1 > l2)
return +1;
return -1;
}

814
src/cmd/gc/dcl.c Normal file
View file

@ -0,0 +1,814 @@
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
#include "go.h"
#include "y.tab.h"
void
dodclvar(Node *n, Type *t)
{
loop:
if(n == N)
return;
if(n->op == OLIST) {
dodclvar(n->left, t);
n = n->right;
goto loop;
}
addvar(n, t, dclcontext);
}
void
dodcltype(Type *n, Type *t)
{
if(n == T)
return;
addtyp(n, t, dclcontext);
}
void
dodclconst(Node *n, Node *e)
{
Sym *s;
Dcl *r, *d;
loop:
if(n == N)
return;
if(n->op == OLIST) {
dodclconst(n->left, e);
n = n->right;
goto loop;
}
if(n->op != ONAME)
fatal("dodclconst: not a name");
if(e->op != OLITERAL) {
yyerror("expression must be a constant");
goto loop;
}
s = n->sym;
s->oconst = e;
s->lexical = LACONST;
r = autodcl;
if(dclcontext == PEXTERN)
r = externdcl;
d = dcl();
d->dsym = s;
d->dnode = e;
d->op = OCONST;
r->back->forw = d;
r->back = d;
if(debug['d'])
print("const-dcl %S %N\n", n->sym, n->sym->oconst);
}
/*
* return nelem of list
*/
int
listcount(Node *n)
{
int v;
v = 0;
while(n != N) {
v++;
if(n->op != OLIST)
break;
n = n->right;
}
return v;
}
/*
* turn a parsed function declaration
* into a type
*/
Type*
functype(Node *this, Node *in, Node *out)
{
Type *t;
t = typ(TFUNC);
t->type = dostruct(this, TSTRUCT);
t->type->down = dostruct(out, TSTRUCT);
t->type->down->down = dostruct(in, TSTRUCT);
t->thistuple = listcount(this);
t->outtuple = listcount(out);
t->intuple = listcount(in);
dowidth(t);
return t;
}
void
funcnam(Type *t, char *nam)
{
Node *n;
Sym *s;
char buf[100];
if(nam == nil) {
vargen++;
snprint(buf, sizeof(buf), "_f%.3ld", vargen);
nam = buf;
}
if(t->etype != TFUNC)
fatal("funcnam: not func %T\n", t);
if(t->thistuple > 0) {
vargen++;
snprint(namebuf, sizeof(namebuf), "_t%.3ld", vargen);
s = lookup(namebuf);
addtyp(newtype(s), t->type, PEXTERN);
n = newname(s);
n->vargen = vargen;
t->type->nname = n;
}
if(t->outtuple > 0) {
vargen++;
snprint(namebuf, sizeof(namebuf), "_o%.3ld", vargen);
s = lookup(namebuf);
addtyp(newtype(s), t->type->down, PEXTERN);
n = newname(s);
n->vargen = vargen;
t->type->down->nname = n;
}
if(t->intuple > 0) {
vargen++;
snprint(namebuf, sizeof(namebuf), "_i%.3ld", vargen);
s = lookup(namebuf);
addtyp(newtype(s), t->type->down->down, PEXTERN);
n = newname(s);
n->vargen = vargen;
t->type->down->down->nname = n;
}
}
int
methcmp(Type *t1, Type *t2)
{
if(t1->etype != TFUNC)
return 0;
if(t2->etype != TFUNC)
return 0;
t1 = t1->type->down; // skip this arg
t2 = t2->type->down; // skip this arg
for(;;) {
if(t1 == t2)
break;
if(t1 == T || t2 == T)
return 0;
if(t1->etype != TSTRUCT || t2->etype != TSTRUCT)
return 0;
if(!eqtype(t1->type, t2->type, 0))
return 0;
t1 = t1->down;
t2 = t2->down;
}
return 1;
}
Node*
methodname(Node *n, Type *t)
{
if(isptr[t->etype])
t = t->type;
if(t->etype != TSTRUCT)
goto bad;
if(t->sym == S)
goto bad;
snprint(namebuf, sizeof(namebuf), "%s_%s", t->sym->name, n->sym->name);
return newname(lookup(namebuf));
bad:
yyerror("illegal <this> pointer");
return n;
}
/*
* add a method, declared as a function,
* into the structure
*/
void
addmethod(Node *n, Type *pa, Type *t)
{
Type *f, *d, *p;
Sym *s;
if(n->op != ONAME)
goto bad;
s = n->sym;
if(s == S)
goto bad;
if(pa == T)
goto bad;
if(!isptr[pa->etype])
goto bad;
p = pa->type;
if(p == T)
goto bad;
if(p->etype != TSTRUCT)
goto bad;
if(p->sym == S)
goto bad;
if(p->type == T) {
n = nod(ODCLFIELD, newname(s), N);
n->type = t;
stotype(n, &p->type);
return;
}
d = T; // last found
for(f=p->type; f!=T; f=f->down) {
if(f->etype != TFIELD)
fatal("addmethod: not TFIELD: %N", f);
if(strcmp(s->name, f->sym->name) != 0) {
d = f;
continue;
}
// if a field matches a non-this function
// then delete it and let it be redeclared
if(methcmp(t, f->type)) {
if(d == T) {
p->type = f->down;
continue;
}
d->down = f->down;
continue;
}
if(!eqtype(t, f->type, 0))
yyerror("field redeclared as method: %S", s);
return;
}
n = nod(ODCLFIELD, newname(s), N);
n->type = t;
if(d == T)
stotype(n, &p->type);
else
stotype(n, &d->down);
return;
bad:
yyerror("unknown method pointer: %T", pa);
}
/*
* declare the function proper.
* and declare the arguments
* called in extern-declaration context
* returns in auto-declaration context.
*/
void
funchdr(Node *n)
{
Node *on;
Sym *s;
s = n->nname->sym;
on = s->oname;
// check for same types
if(on != N) {
if(eqtype(n->type, on->type, 0)) {
if(!eqargs(n->type, on->type))
yyerror("foreward declarations not the same: %S", s);
} else {
yyerror("redeclare of function: %S", s);
on = N;
}
}
// check for foreward declaration
if(on == N) {
// initial declaration or redeclaration
// declare fun name, argument types and argument names
funcnam(n->type, s->name);
n->nname->type = n->type;
if(n->type->thistuple == 0)
addvar(n->nname, n->type, PEXTERN);
else
n->nname->class = PEXTERN;
} else {
// identical redeclaration
// steal previous names
n->nname = on;
n->type = on->type;
n->class = on->class;
n->sym = s;
if(debug['d'])
print("forew var-dcl %S %T\n", n->sym, n->type);
}
// change the declaration context from extern to auto
autodcl = dcl();
autodcl->back = autodcl;
if(dclcontext != PEXTERN)
fatal("funchdr: dclcontext");
dclcontext = PAUTO;
markdcl("func");
funcargs(n->type);
if(n->type->thistuple > 0) {
Type *t;
t = *getthis(n->type);
addmethod(n->nname, t->type->type, n->type);
}
}
void
funcargs(Type *t)
{
Type *n1;
Iter save;
// declare the this argument
n1 = funcfirst(&save, t);
while(n1 != T) {
if(n1->nname != N)
addvar(n1->nname, n1->type, PPARAM);
n1 = funcnext(&save);
}
// declare the outgoing arguments
// n1 = structfirst(&save, getoutarg(t));
// while(n1 != T) {
// n1->left = newname(n1->sym);
// if(n1->nname != N)
// addvar(n1->nname, n1->type, PPARAM);
// n1 = structnext(&save);
// }
}
/*
* compile the function.
* called in auto-declaration context.
* returns in extern-declaration context.
*/
void
funcbody(Node *n)
{
compile(n);
// change the declaration context from auto to extern
if(dclcontext != PAUTO)
fatal("funcbody: dclcontext");
popdcl("func");
dclcontext = PEXTERN;
}
/*
* turn a parsed struct into a type
*/
Type**
stotype(Node *n, Type **t)
{
Type *f;
Iter save;
n = listfirst(&save, &n);
loop:
if(n == N) {
*t = T;
return t;
}
if(n->op == OLIST) {
// recursive because it can be lists of lists
t = stotype(n, t);
goto next;
}
if(n->op != ODCLFIELD || n->type == T)
fatal("stotype: oops %N\n", n);
if(n->type->etype == TDARRAY)
yyerror("type of a structure field cannot be an open array");
f = typ(TFIELD);
f->type = n->type;
if(n->left != N && n->left->op == ONAME) {
f->nname = n->left;
} else {
vargen++;
snprint(namebuf, sizeof(namebuf), "_e%.3ld", vargen);
f->nname = newname(lookup(namebuf));
}
f->sym = f->nname->sym;
*t = f;
t = &f->down;
next:
n = listnext(&save);
goto loop;
}
Type*
dostruct(Node *n, int et)
{
Type *t;
/*
* convert a parsed id/type list into
* a type for struct/interface/arglist
*/
t = typ(et);
stotype(n, &t->type);
dowidth(t);
return t;
}
Type*
sortinter(Type *t)
{
return t;
}
void
dcopy(Sym *a, Sym *b)
{
a->name = b->name;
a->oname = b->oname;
a->otype = b->otype;
a->oconst = b->oconst;
a->package = b->package;
a->opackage = b->opackage;
a->forwtype = b->forwtype;
a->lexical = b->lexical;
a->undef = b->undef;
a->vargen = b->vargen;
}
Sym*
push(void)
{
Sym *d;
d = mal(sizeof(*d));
d->link = dclstack;
dclstack = d;
return d;
}
Sym*
pushdcl(Sym *s)
{
Sym *d;
d = push();
dcopy(d, s);
return d;
}
void
popdcl(char *why)
{
Sym *d, *s;
// if(debug['d'])
// print("revert\n");
for(d=dclstack; d!=S; d=d->link) {
if(d->name == nil)
break;
s = pkglookup(d->name, d->package);
dcopy(s, d);
if(debug['d'])
print("\t%ld pop %S\n", curio.lineno, s);
}
if(d == S)
fatal("popdcl: no mark");
if(strcmp(why, d->package) != 0)
fatal("popdcl: pushed as %s poped as %s", d->package, why);
dclstack = d->link;
}
void
poptodcl(void)
{
Sym *d, *s;
for(d=dclstack; d!=S; d=d->link) {
if(d->name == nil)
break;
s = pkglookup(d->name, d->package);
dcopy(s, d);
if(debug['d'])
print("\t%ld pop %S\n", curio.lineno, s);
}
if(d == S)
fatal("poptodcl: no mark");
}
void
markdcl(char *why)
{
Sym *d;
d = push();
d->name = nil; // used as a mark in fifo
d->package = why; // diagnostic for unmatched
// if(debug['d'])
// print("markdcl\n");
}
void
markdclstack(void)
{
Sym *d, *s;
markdcl("fnlit");
// copy the entire pop of the stack
// all the way back to block0.
// after this the symbol table is at
// block0 and popdcl will restore it.
for(d=dclstack; d!=S; d=d->link) {
if(d == b0stack)
break;
if(d->name != nil) {
s = pkglookup(d->name, d->package);
pushdcl(s);
dcopy(s, d);
}
}
}
void
testdclstack(void)
{
Sym *d;
for(d=dclstack; d!=S; d=d->link) {
if(d->name == nil) {
yyerror("mark left on the stack");
continue;
}
}
}
void
addvar(Node *n, Type *t, int ctxt)
{
Dcl *r, *d;
Sym *s;
Type *ot;
Node *on;
int gen;
if(n==N || n->sym == S || n->op != ONAME || t == T)
fatal("addvar: n=%N t=%T nil", n, t);
ot = t;
if(isptr[ot->etype])
ot = ot->type;
if(ot->etype == TSTRUCT && ot->vargen == 0) {
vargen++;
snprint(namebuf, sizeof(namebuf), "_s%.3ld", vargen);
s = lookup(namebuf);
addtyp(newtype(s), ot, PEXTERN);
}
s = n->sym;
vargen++;
gen = vargen;
r = autodcl;
if(ctxt == PEXTERN) {
on = s->oname;
if(on != N) {
if(eqtype(t, on->type, 0)) {
warn("%S redeclared", s);
return;
}
yyerror("%S redeclared (%T %T)", s,
on->type, t);
}
r = externdcl;
gen = 0;
}
if(ctxt != PEXTERN)
pushdcl(s);
s->vargen = gen;
s->oname = n;
s->offset = 0;
n->type = t;
n->vargen = gen;
n->class = ctxt;
d = dcl();
d->dsym = s;
d->dnode = n;
d->op = ONAME;
r->back->forw = d;
r->back = d;
if(debug['d']) {
if(ctxt == PEXTERN)
print("extern var-dcl %S G%ld %T\n", s, s->vargen, t);
else
print("auto var-dcl %S G%ld %T\n", s, s->vargen, t);
}
}
void
addtyp(Type *n, Type *t, int ctxt)
{
Dcl *r, *d;
Sym *s;
Type *f, *ot;
if(n==T || n->sym == S || t == T)
fatal("addtyp: n=%T t=%T nil", n, t);
s = n->sym;
r = autodcl;
if(ctxt == PEXTERN) {
ot = s->otype;
if(ot != T) {
// allow nil interface to be
// redeclared as an interface
if(ot->etype == TINTER && ot->type == T && t->etype == TINTER) {
if(debug['d'])
print("forew typ-dcl %S G%ld %T\n", s, s->vargen, t);
s->otype = t;
return;
}
if(eqtype(t, ot, 0)) {
warn("%S redeclared", s);
return;
}
yyerror("%S redeclared (%T %T)", s,
ot, t);
}
r = externdcl;
}
if(ctxt != PEXTERN)
pushdcl(s);
if(t->sym != S)
warn("addtyp: renaming %S/%lT to %S/%lT", t->sym, t->sym->otype, s, n);
vargen++;
s->vargen = vargen;
s->otype = t;
s->lexical = LATYPE;
t->sym = s;
t->vargen = vargen;
for(f=s->forwtype; f!=T; f=f->nforw) {
if(!isptr[f->etype])
fatal("addtyp: foreward");
f->type = t;
}
s->forwtype = T;
d = dcl();
d->dsym = s;
d->dtype = t;
d->op = OTYPE;
r->back->forw = d;
r->back = d;
if(debug['d']) {
if(ctxt == PEXTERN)
print("extern typ-dcl %S G%ld %T\n", s, s->vargen, t);
else
print("auto typ-dcl %S G%ld %T\n", s, s->vargen, t);
}
}
Node*
fakethis(void)
{
Node *n;
Type *t;
n = nod(ODCLFIELD, N, N);
t = dostruct(N, TSTRUCT);
t = ptrto(t);
n->type = t;
return n;
}
/*
* this generates a new name that is
* pushed down on the declaration list.
* no diagnostics are produced as this
* name will soon be declared.
*/
Node*
newname(Sym *s)
{
Node *n;
n = nod(ONAME, N, N);
n->sym = s;
n->type = T;
n->addable = 1;
n->ullman = 0;
return n;
}
/*
* this will return an old name
* that has already been pushed on the
* declaration list. a diagnostic is
* generated if no name has been defined.
*/
Node*
oldname(Sym *s)
{
Node *n;
n = s->oname;
if(n == N) {
yyerror("%S undefined", s);
n = newname(s);
dodclvar(n, types[TINT32]);
}
return n;
}
/*
* same for types
*/
Type*
newtype(Sym *s)
{
Type *t;
t = typ(TFORW);
t->sym = s;
t->type = T;
return t;
}
Type*
oldtype(Sym *s)
{
Type *t;
t = s->otype;
if(t == T)
fatal("%S not a type", s); // cant happen
return t;
}
Type*
forwdcl(Sym *s)
{
Type *t;
// this type has no meaning and
// will cause an error if referenced.
// it will be patched when/if the
// type is ever assigned.
t = typ(TFORW);
t = ptrto(t);
t->nforw = s->forwtype;
s->forwtype = t;
return t;
}

578
src/cmd/gc/export.c Normal file
View file

@ -0,0 +1,578 @@
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
#include "go.h"
#include "y.tab.h"
void
markexport(Node *n)
{
Sym *s;
Dcl *d, *r;
loop:
if(n == N)
return;
if(n->op == OLIST) {
markexport(n->left);
n = n->right;
goto loop;
}
if(n->op != OEXPORT)
fatal("markexport: op no OEXPORT: %O", n->op);
s = n->sym;
if(n->psym != S)
s = pkglookup(n->sym->name, n->psym->name);
if(s->export != 0)
return;
s->export = 1;
d = mal(sizeof(*d));
d->dsym = s;
d->dnode = N;
d->lineno = curio.lineno;
r = exportlist;
d->back = r->back;
r->back->forw = d;
r->back = d;
}
void
reexport(Type *t)
{
Sym *s;
if(t == T)
fatal("reexport: type nil\n");
s = t->sym;
if(s == S/* || s->name[0] == '_'*/) {
exportgen++;
snprint(namebuf, sizeof(namebuf), "_e%.3ld", exportgen);
s = lookup(namebuf);
s->lexical = LATYPE;
s->otype = t;
t->sym = s;
}
dumpexporttype(s);
}
void
dumpexportconst(Sym *s)
{
Node *n;
Type *t;
if(s->exported != 0)
return;
s->exported = 1;
n = s->oconst;
if(n == N || n->op != OLITERAL)
fatal("dumpexportconst: oconst nil: %S\n", s);
t = n->type; // may or may not be specified
if(t != T)
reexport(t);
Bprint(bout, "\tconst ");
if(s->export != 0)
Bprint(bout, "!");
Bprint(bout, "%lS ", s);
if(t != T)
Bprint(bout, "%lS ", t->sym);
switch(n->val.ctype) {
default:
fatal("dumpexportconst: unknown ctype: %S\n", s);
case CTINT:
case CTSINT:
case CTUINT:
case CTBOOL:
Bprint(bout, "0x%llux\n", n->val.vval);
break;
case CTFLT:
Bprint(bout, "%.17e\n", n->val.dval);
break;
case CTSTR:
Bprint(bout, "\"%Z\"\n", n->val.sval);
break;
}
}
void
dumpexportvar(Sym *s)
{
Node *n;
Type *t;
if(s->exported != 0)
return;
s->exported = 1;
n = s->oname;
if(n == N || n->type == T)
fatal("dumpexportvar: oname nil: %S\n", s);
t = n->type;
reexport(t);
Bprint(bout, "\tvar ");
if(s->export != 0)
Bprint(bout, "!");
Bprint(bout, "%lS %lS\n", s, t->sym);
}
void
dumpexporttype(Sym *s)
{
Type *t, *f;
Sym *ts;
int et;
if(s->exported != 0)
return;
s->exported = 1;
t = s->otype;
if(t == T)
fatal("dumpexporttype: otype nil: %S\n", s);
if(t->sym != s)
fatal("dumpexporttype: cross reference: %S\n", s);
et = t->etype;
switch(et) {
default:
if(et < 0 || et >= nelem(types) || types[et] == T)
fatal("dumpexporttype: basic type: %S %E\n", s, et);
/* type 5 */
Bprint(bout, "\ttype %lS %d\n", s, et);
break;
case TARRAY:
reexport(t->type);
/* type 2 */
Bprint(bout, "\ttype ");
if(s->export != 0)
Bprint(bout, "!");
Bprint(bout, "%lS [%lud] %lS\n", s, t->bound, t->type->sym);
break;
case TPTR32:
case TPTR64:
reexport(t->type);
/* type 6 */
Bprint(bout, "\ttype ");
if(s->export != 0)
Bprint(bout, "!");
Bprint(bout, "%lS *%lS\n", s, t->type->sym);
break;
case TFUNC:
for(f=t->type; f!=T; f=f->down) {
if(f->etype != TSTRUCT)
fatal("dumpexporttype: funct not field: %T\n", f);
reexport(f);
}
/* type 3 */
Bprint(bout, "\ttype ");
if(s->export != 0)
Bprint(bout, "!");
Bprint(bout, "%lS (", s);
for(f=t->type; f!=T; f=f->down) {
if(f != t->type)
Bprint(bout, " ");
Bprint(bout, "%lS", f->sym);
}
Bprint(bout, ")\n");
break;
case TSTRUCT:
case TINTER:
for(f=t->type; f!=T; f=f->down) {
if(f->etype != TFIELD)
fatal("dumpexporttype: funct not field: %lT\n", f);
reexport(f->type);
}
/* type 4 */
Bprint(bout, "\ttype ");
if(s->export)
Bprint(bout, "!");
Bprint(bout, "%lS %c", s, (et==TSTRUCT)? '{': '<');
for(f=t->type; f!=T; f=f->down) {
ts = f->type->sym;
if(f != t->type)
Bprint(bout, " ");
Bprint(bout, "%s %lS", f->sym->name, ts);
}
Bprint(bout, "%c\n", (et==TSTRUCT)? '}': '>');
break;
}
}
void
dumpe(Sym *s)
{
switch(s->lexical) {
default:
yyerror("unknown export symbol: %S\n", s, s->lexical);
break;
case LPACK:
yyerror("package export symbol: %S\n", s);
break;
case LATYPE:
case LBASETYPE:
dumpexporttype(s);
break;
case LNAME:
dumpexportvar(s);
break;
case LACONST:
dumpexportconst(s);
break;
}
}
void
dumpexport(void)
{
Dcl *d;
long lno;
lno = dynlineno;
Bprint(bout, " import\n");
Bprint(bout, " ((\n");
// print it depth first
for(d=exportlist->forw; d!=D; d=d->forw) {
dynlineno = d->lineno;
dumpe(d->dsym);
}
Bprint(bout, " ))\n");
dynlineno = lno;
}
/*
* ******* import *******
*/
Type*
importlooktype(Node *n)
{
Sym *s;
if(n->op != OIMPORT)
fatal("importlooktype: oops1 %N\n", n);
s = pkglookup(n->sym->name, n->psym->name);
if(s->otype == T)
fatal("importlooktype: oops2 %S\n", s);
return s->otype;
}
Type**
importstotype(Node *fl, Type **t, Type *uber)
{
Type *f;
Iter save;
Node *n;
n = listfirst(&save, &fl);
loop:
if(n == N) {
*t = T;
return t;
}
f = typ(TFIELD);
f->type = importlooktype(n);
if(n->fsym != S) {
f->nname = newname(n->fsym);
} else {
vargen++;
snprint(namebuf, sizeof(namebuf), "_m%.3ld", vargen);
f->nname = newname(lookup(namebuf));
}
f->sym = f->nname->sym;
*t = f;
t = &f->down;
n = listnext(&save);
goto loop;
}
int
importcount(Type *t)
{
int i;
Type *f;
if(t == T || t->etype != TSTRUCT)
fatal("importcount: not a struct: %N", t);
i = 0;
for(f=t->type; f!=T; f=f->down)
i = i+1;
return i;
}
void
importfuncnam(Type *t)
{
Node *n;
Type *t1;
if(t->etype != TFUNC)
fatal("importfuncnam: not func %T\n", t);
if(t->thistuple > 0) {
t1 = t->type;
if(t1->sym == S)
fatal("importfuncnam: no this");
n = newname(t1->sym);
vargen++;
n->vargen = vargen;
t1->nname = n;
}
if(t->outtuple > 0) {
t1 = t->type->down;
if(t1->sym == S)
fatal("importfuncnam: no output");
n = newname(t1->sym);
vargen++;
n->vargen = vargen;
t1->nname = n;
}
if(t->intuple > 0) {
t1 = t->type->down->down;
if(t1->sym == S)
fatal("importfuncnam: no input");
n = newname(t1->sym);
vargen++;
n->vargen = vargen;
t1->nname = n;
}
}
Sym*
getimportsym(Node *ss)
{
char *pkg;
Sym *s;
pkg = ss->psym->name;
if(pkgmyname != S)
pkg = pkgmyname->name;
s = pkglookup(ss->sym->name, pkg);
/* botch - need some diagnostic checking for the following assignment */
s->opackage = ss->osym->name;
return s;
}
void
importaddtyp(Node *ss, Type *t)
{
Sym *s;
s = getimportsym(ss);
if(s->otype == T || !eqtype(t, s->otype, 0)) {
addtyp(newtype(s), t, PEXTERN);
}
}
/*
* LCONST importsym LITERAL
* untyped constant
*/
void
doimportc1(Node *ss, Val *v)
{
Node *n;
Sym *s;
n = nod(OLITERAL, N, N);
n->val = *v;
s = getimportsym(ss);
if(s->oconst == N) {
// botch sould ask if already declared the same
dodclconst(newname(s), n);
}
}
/*
* LCONST importsym importsym LITERAL
* typed constant
*/
void
doimportc2(Node *ss, Node *st, Val *v)
{
Node *n;
Type *t;
Sym *s;
n = nod(OLITERAL, N, N);
n->val = *v;
t = importlooktype(st);
n->type = t;
s = getimportsym(ss);
if(s->oconst == N) {
// botch sould ask if already declared the same
dodclconst(newname(s), n);
}
}
/*
* LVAR importsym importsym
* variable
*/
void
doimportv1(Node *ss, Node *st)
{
Type *t;
Sym *s;
t = importlooktype(st);
s = getimportsym(ss);
if(s->oname == N || !eqtype(t, s->oname->type, 0)) {
addvar(newname(s), t, dclcontext);
}
}
/*
* LTYPE importsym [ importsym ] importsym
* array type
*/
void
doimport1(Node *ss, Node *ss1, Node *s)
{
fatal("doimport1");
}
/*
* LTYPE importsym [ LLITERAL ] importsym
* array type
*/
void
doimport2(Node *ss, Val *b, Node *st)
{
Type *t;
Sym *s;
t = typ(TARRAY);
t->bound = b->vval;
s = pkglookup(st->sym->name, st->psym->name);
t->type = s->otype;
importaddtyp(ss, t);
}
/*
* LTYPE importsym '(' importsym_list ')'
* function/method type
*/
void
doimport3(Node *ss, Node *n)
{
Type *t;
t = typ(TFUNC);
t->type = importlooktype(n->left);
t->type->down = importlooktype(n->right->left);
t->type->down->down = importlooktype(n->right->right);
t->thistuple = importcount(t->type);
t->outtuple = importcount(t->type->down);
t->intuple = importcount(t->type->down->down);
importfuncnam(t);
importaddtyp(ss, t);
}
/*
* LTYPE importsym '{' importsym_list '}'
* structure type
*/
void
doimport4(Node *ss, Node *n)
{
Type *t;
t = typ(TSTRUCT);
importstotype(n, &t->type, t);
importaddtyp(ss, t);
}
/*
* LTYPE importsym LLITERAL
* basic type
*/
void
doimport5(Node *ss, Val *v)
{
int et;
Type *t;
et = v->vval;
if(et <= 0 || et >= nelem(types) || types[et] == T)
fatal("doimport5: bad type index: %E\n", et);
t = typ(et);
t->sym = S;
importaddtyp(ss, t);
}
/*
* LTYPE importsym * importsym
* pointer type
*/
void
doimport6(Node *ss, Node *st)
{
Type *t;
Sym *s;
s = pkglookup(st->sym->name, st->psym->name);
t = s->otype;
if(t == T)
t = forwdcl(s);
else
t = ptrto(t);
importaddtyp(ss, t);
}
/*
* LTYPE importsym '<' importsym '>'
* interface type
*/
void
doimport7(Node *ss, Node *n)
{
Type *t;
t = typ(TINTER);
importstotype(n, &t->type, t);
importaddtyp(ss, t);
}

553
src/cmd/gc/go.h Normal file
View file

@ -0,0 +1,553 @@
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
/*
todo:
1. dyn arrays
2. multi
3. block 0
tothinkabout:
2. argument in import
*/
#include <u.h>
#include <libc.h>
#include <bio.h>
#ifndef EXTERN
#define EXTERN extern
#endif
enum
{
NHUNK = 50000,
BUFSIZ = 8192,
NSYMB = 500,
NHASH = 1024,
STRINGSZ = 200,
YYMAXDEPTH = 500,
MAXALIGN = 7,
UINF = 100,
PRIME1 = 3,
PRIME2 = 10007,
PRIME3 = 10009,
PRIME4 = 10037,
PRIME5 = 10039,
PRIME6 = 10061,
PRIME7 = 10067,
PRIME8 = 10079,
PRIME9 = 10091,
};
/*
* note this is the representation
* of the compilers string literals,
* it happens to also be the runtime
* representation, ignoring sizes and
* alignment, but that may change.
*/
typedef struct String String;
struct String
{
long len;
char s[3]; // variable
};
typedef struct Val Val;
struct Val
{
int ctype;
double dval;
vlong vval;
String* sval;
};
typedef struct Sym Sym;
typedef struct Node Node;
typedef struct Type Type;
struct Type
{
int etype;
int chan;
uchar recur; // to detect loops
uchar trecur; // to detect loops
Sym* sym;
long vargen; // unique name for OTYPE/ONAME
// most nodes
Type* type;
vlong width; // offset in TFIELD, width in all others
// TFIELD
Type* down; // also used in TMAP
// TPTR
Type* nforw;
// TFUNCT
Type* this;
Type* argout;
Type* argin;
Node* nname;
uchar thistuple;
uchar outtuple;
uchar intuple;
// TARRAY
long bound;
};
#define T ((Type*)0)
struct Node
{
int op;
// most nodes
Node* left;
Node* right;
Type* type;
// for-body
Node* ninit;
Node* ntest;
Node* nincr;
Node* nbody;
// if-body
Node* nelse;
// cases
Node* ncase;
// func
Node* nname;
// OLITERAL
Val val;
Sym* osym; // import
Sym* fsym; // import
Sym* psym; // import
Sym* sym; // various
uchar ullman; // sethi/ullman number
uchar addable; // type of addressability - 0 is not addressable
uchar trecur; // to detect loops
uchar etype; // op for OASOP, etype for OTYPE, exclam for export
uchar class; // PPARAM, PAUTO, PEXTERN, PSTATIC
long vargen; // unique name for OTYPE/ONAME
ulong lineno;
vlong xoffset;
};
#define N ((Node*)0)
struct Sym
{
char* opackage; // original package name
char* package; // package name
char* name; // variable name
Node* oname; // ONAME node if a var
Type* otype; // TYPE node if a type
Node* oconst; // OLITERAL node if a const
Type* forwtype; // TPTR iff foreward declared
void* label; // pointer to Prog* of label
vlong offset; // stack location if automatic
long lexical;
long vargen; // unique variable number
uchar undef; // a diagnostic has been generated
uchar export; // marked as export
uchar exported; // has been exported
uchar sym; // huffman encoding in object file
Sym* link;
};
#define S ((Sym*)0)
typedef struct Dcl Dcl;
struct Dcl
{
int op;
Sym* dsym; // for printing only
Node* dnode; // oname
Type* dtype; // otype
long lineno;
Dcl* forw;
Dcl* back; // sentinel has pointer to last
};
#define D ((Dcl*)0)
typedef struct Iter Iter;
struct Iter
{
int done;
Type* tfunc;
Type* t;
Node** an;
Node* n;
};
enum
{
OXXX,
OTYPE, OCONST, OVAR, OEXPORT, OIMPORT,
ONAME,
ODOT, ODOTPTR, ODOTMETH, ODOTINTER,
ODCLFUNC, ODCLFIELD, ODCLARG,
OLIST, OCMP,
OPTR, OARRAY,
ORETURN, OFOR, OIF, OSWITCH, OI2S, OS2I, OI2I,
OAS, OASOP, OCASE, OXCASE, OFALL, OXFALL,
OGOTO, OPROC, ONEW, OPANIC, OPRINT, OEMPTY,
OOROR,
OANDAND,
OEQ, ONE, OLT, OLE, OGE, OGT,
OADD, OSUB, OOR, OXOR,
OMUL, ODIV, OMOD, OLSH, ORSH, OAND,
ODEC, OINC,
OLEN,
OFUNC,
OLABEL,
OBREAK,
OCONTINUE,
OADDR,
OIND,
OCALL, OCALLMETH, OCALLINTER,
OINDEX, OINDEXPTR, OSLICE,
ONOT, OCOM, OPLUS, OMINUS, OSEND, ORECV,
OLITERAL, OREGISTER, OINDREG,
OCONV,
OBAD,
OEND,
};
enum
{
Txxx, // 0
TINT8, TUINT8, // 1
TINT16, TUINT16,
TINT32, TUINT32,
TINT64, TUINT64,
TFLOAT32, // 9
TFLOAT64,
TFLOAT80,
TBOOL, // 12
TPTR32, TPTR64, // 13
TFUNC,
TARRAY,
TDARRAY,
TSTRUCT,
TCHAN,
TMAP,
TINTER,
TFORW,
TFIELD,
TANY,
TSTRING,
NTYPE, // 26
};
enum
{
CTxxx,
CTINT,
CTSINT,
CTUINT,
CTFLT,
CTSTR,
CTBOOL,
CTNIL,
};
enum
{
/* indications for whatis() */
Wnil = 0,
Wtnil,
Wtfloat,
Wtint,
Wtbool,
Wtstr,
Wlitfloat,
Wlitint,
Wlitbool,
Wlitstr,
Wtunkn,
};
enum
{
/* types of channel */
Cxxx,
Cboth,
Crecv,
Csend,
};
enum
{
Pxxx,
PEXTERN, // declaration context
PAUTO,
PPARAM,
PSTATIC,
};
typedef struct Io Io;
struct Io
{
char* infile;
Biobuf* bin;
long lineno;
int peekc;
char* cp; // used for content when bin==nil
};
EXTERN Io curio;
EXTERN Io pushedio;
EXTERN char* outfile;
EXTERN char* package;
EXTERN Biobuf* bout;
EXTERN int nerrors;
EXTERN char namebuf[NSYMB];
EXTERN char debug[256];
EXTERN long dynlineno;
EXTERN Sym* hash[NHASH];
EXTERN Sym* dclstack;
EXTERN Sym* b0stack;
EXTERN Sym* pkgmyname; // my name for package
EXTERN int tptr; // either TPTR32 or TPTR64
extern char* sysimport;
EXTERN Type* types[NTYPE];
EXTERN uchar isptr[NTYPE];
EXTERN uchar isint[NTYPE];
EXTERN uchar isfloat[NTYPE];
EXTERN uchar issigned[NTYPE];
EXTERN uchar okforeq[NTYPE];
EXTERN uchar okforadd[NTYPE];
EXTERN uchar okforand[NTYPE];
EXTERN double minfloatval[NTYPE];
EXTERN double maxfloatval[NTYPE];
EXTERN vlong minintval[NTYPE];
EXTERN vlong maxintval[NTYPE];
EXTERN Dcl* autodcl;
EXTERN Dcl* externdcl;
EXTERN Dcl* exportlist;
EXTERN int dclcontext; // PEXTERN/PAUTO
EXTERN int importflag;
EXTERN Node* booltrue;
EXTERN Node* boolfalse;
EXTERN ulong iota;
EXTERN long vargen;
EXTERN long exportgen;
EXTERN Node* retnil;
EXTERN Node* fskel;
EXTERN char* context;
EXTERN int thechar;
EXTERN char* thestring;
EXTERN char* hunk;
EXTERN long nhunk;
EXTERN long thunk;
/*
* y.tab.c
*/
int yyparse(void);
/*
* lex.c
*/
int main(int, char*[]);
void importfile(Val*);
void cannedimports(void);
void unimportfile();
long yylex(void);
void lexinit(void);
char* lexname(int);
long getr(void);
int getnsc(void);
long escchar(long, int*);
int getc(void);
void ungetc(int);
void mkpackage(char*);
/*
* mpatof.c
*/
int mpatof(char*, double*);
int mpatov(char*, vlong*);
/*
* subr.c
*/
void myexit(int);
void* mal(long);
void* remal(void*, long, long);
void errorexit(void);
ulong stringhash(char*);
Sym* lookup(char*);
Sym* pkglookup(char*, char*);
void yyerror(char*, ...);
void warn(char*, ...);
void fatal(char*, ...);
Node* nod(int, Node*, Node*);
Type* typ(int);
Dcl* dcl(void);
Node* rev(Node*);
Node* unrev(Node*);
void dodump(Node*, int);
void dump(char*, Node*);
Type* aindex(Node*, Type*);
int isnil(Node*);
int isptrto(Type*, int);
int isinter(Type*);
int isbytearray(Type*);
int eqtype(Type*, Type*, int);
int eqargs(Type*, Type*);
ulong typehash(Type*, int);
void frame(int);
Node* literal(long);
Node* dobad(void);
Node* nodintconst(long);
void ullmancalc(Node*);
void badtype(int, Type*, Type*);
Type* ptrto(Type*);
Node* cleanidlist(Node*);
Type** getthis(Type*);
Type** getoutarg(Type*);
Type** getinarg(Type*);
Type* getthisx(Type*);
Type* getoutargx(Type*);
Type* getinargx(Type*);
Node* listfirst(Iter*, Node**);
Node* listnext(Iter*);
Type* structfirst(Iter*, Type**);
Type* structnext(Iter*);
Type* funcfirst(Iter*, Type*);
Type* funcnext(Iter*);
int Econv(Fmt*);
int Jconv(Fmt*);
int Oconv(Fmt*);
int Sconv(Fmt*);
int Tconv(Fmt*);
int Nconv(Fmt*);
int Zconv(Fmt*);
/*
* dcl.c
*/
void dodclvar(Node*, Type*);
void dodcltype(Type*, Type*);
void dodclconst(Node*, Node*);
void defaultlit(Node*);
int listcount(Node*);
Node* methodname(Node*, Type*);
Type* functype(Node*, Node*, Node*);
char* thistypenam(Node*);
void funcnam(Type*, char*);
void funchdr(Node*);
void funcargs(Type*);
void funcbody(Node*);
Type* dostruct(Node*, int);
Type** stotype(Node*, Type**);
Type* sortinter(Type*);
void markdcl(char*);
void popdcl(char*);
void poptodcl(void);
void markdclstack(void);
void testdclstack(void);
Sym* pushdcl(Sym*);
void addvar(Node*, Type*, int);
void addtyp(Type*, Type*, int);
Node* fakethis(void);
Node* newname(Sym*);
Node* oldname(Sym*);
Type* newtype(Sym*);
Type* oldtype(Sym*);
Type* forwdcl(Sym*);
/*
* export.c
*/
void markexport(Node*);
void dumpe(Sym*);
void dumpexport(void);
void dumpexporttype(Sym*);
void dumpexportvar(Sym*);
void dumpexportconst(Sym*);
void doimportv1(Node*, Node*);
void doimportc1(Node*, Val*);
void doimportc2(Node*, Node*, Val*);
void doimport1(Node*, Node*, Node*);
void doimport2(Node*, Val*, Node*);
void doimport3(Node*, Node*);
void doimport4(Node*, Node*);
void doimport5(Node*, Val*);
void doimport6(Node*, Node*);
void doimport7(Node*, Node*);
/*
* walk.c
*/
void walk(Node*);
void walktype(Node*, int);
Type* walkswitch(Node*, Node*, Type*(*)(Node*, Type*));
int casebody(Node*);
int whatis(Node*);
void walkdot(Node*);
Node* ascompatee(int, Node**, Node**);
Node* ascompatet(int, Node**, Type**, int);
Node* ascompatte(int, Type**, Node**, int);
int ascompat(Type*, Type*);
Node* prcompat(Node*);
Node* nodpanic(long);
Node* newcompat(Node*);
Node* stringop(Node*);
Node* convas(Node*);
Node* reorder(Node*);
/*
* const.c
*/
void convlit(Node*, Type*);
void evconst(Node*);
int cmpslit(Node *l, Node *r);
/*
* gen.c/gsubr.c/obj.c
*/
void belexinit(int);
void besetptr(void);
vlong convvtox(vlong, int);
void compile(Node*);
void proglist(void);
int optopop(int);
void dumpobj(void);
void dowidth(Type*);
void argspace(long);
Node* nodarg(Type*, int);

1292
src/cmd/gc/go.y Normal file

File diff suppressed because it is too large Load diff

1088
src/cmd/gc/lex.c Normal file

File diff suppressed because it is too large Load diff

19
src/cmd/gc/mksys.bash Normal file
View file

@ -0,0 +1,19 @@
# Copyright 2009 The Go Authors. All rights reserved.
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
6g sys.go
echo '1,/((/d
/))/+1,$d
1,$s/foop/sys/g
1,$s/^[ ]*/ "/g
1,$s/$/\\n"/g
1i
char* sysimport =
.
$a
;
.
w sysimport.c
q' | ed foop.6

342
src/cmd/gc/mpatof.c Normal file
View file

@ -0,0 +1,342 @@
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
#include <u.h>
#include <libc.h>
int mpatof(char*, double*);
int mpatov(char *s, vlong *v);
enum
{
Mpscale = 29, /* safely smaller than bits in a long */
Mpprec = 36, /* Mpscale*Mpprec sb > largest fp exp */
Mpbase = 1L<<Mpscale,
};
typedef
struct
{
long a[Mpprec];
char ovf;
} Mp;
static void mpint(Mp*, int);
static void mppow(Mp*, int, int);
static void mpmul(Mp*, int);
static void mpadd(Mp*, Mp*);
static int mptof(Mp*, double*);
/*
* convert a string, s, to floating in *d
* return conversion overflow.
* required syntax is [+-]d*[.]d*[e[+-]d*]
*/
int
mpatof(char *s, double *d)
{
Mp a, b;
int dp, c, f, ef, ex, zer;
double d1, d2;
dp = 0; /* digits after decimal point */
f = 0; /* sign */
ex = 0; /* exponent */
zer = 1; /* zero */
memset(&a, 0, sizeof(a));
for(;;) {
switch(c = *s++) {
default:
goto bad;
case '-':
f = 1;
case ' ':
case '\t':
case '+':
continue;
case '.':
dp = 1;
continue;
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
zer = 0;
case '0':
mpint(&b, c-'0');
mpmul(&a, 10);
mpadd(&a, &b);
if(dp)
dp++;
continue;
case 'E':
case 'e':
ex = 0;
ef = 0;
for(;;) {
c = *s++;
if(c == '+' || c == ' ' || c == '\t')
continue;
if(c == '-') {
ef = 1;
continue;
}
if(c >= '0' && c <= '9') {
ex = ex*10 + (c-'0');
continue;
}
break;
}
if(ef)
ex = -ex;
case 0:
break;
}
break;
}
if(a.ovf)
goto bad;
if(zer) {
*d = 0;
return 0;
}
if(dp)
dp--;
dp -= ex;
if(dp > 0) {
/*
* must divide by 10**dp
*/
if(mptof(&a, &d1))
goto bad;
/*
* trial exponent of 8**dp
* 8 (being between 5 and 10)
* should pick up all underflows
* in the division of 5**dp.
*/
d2 = frexp(d1, &ex);
d2 = ldexp(d2, ex-3*dp);
if(d2 == 0)
goto bad;
/*
* decompose each 10 into 5*2.
* create 5**dp in fixed point
* and then play with the exponent
* for the remaining 2**dp.
* note that 5**dp will overflow
* with as few as 134 input digits.
*/
mpint(&a, 1);
mppow(&a, 5, dp);
if(mptof(&a, &d2))
goto bad;
d1 = frexp(d1/d2, &ex);
d1 = ldexp(d1, ex-dp);
if(d1 == 0)
goto bad;
} else {
/*
* must multiply by 10**|dp| --
* just do it in fixed point.
*/
mppow(&a, 10, -dp);
if(mptof(&a, &d1))
goto bad;
}
if(f)
d1 = -d1;
*d = d1;
return 0;
bad:
return 1;
}
/*
* convert a to floating in *d
* return conversion overflow
*/
static int
mptof(Mp *a, double *d)
{
double f, g;
long x, *a1;
int i;
if(a->ovf)
return 1;
a1 = a->a;
f = ldexp(*a1++, 0);
for(i=Mpscale; i<Mpprec*Mpscale; i+=Mpscale)
if(x = *a1++) {
g = ldexp(x, i);
/*
* NOTE: the test (g==0) is plan9
* specific. ansi compliant overflow
* is signaled by HUGE and errno==ERANGE.
* change this for your particular ldexp.
*/
if(g == 0)
return 1;
f += g; /* this could bomb! */
}
*d = f;
return 0;
}
/*
* return a += b
*/
static void
mpadd(Mp *a, Mp *b)
{
int i, c;
long x, *a1, *b1;
if(b->ovf)
a->ovf = 1;
if(a->ovf)
return;
c = 0;
a1 = a->a;
b1 = b->a;
for(i=0; i<Mpprec; i++) {
x = *a1 + *b1++ + c;
c = 0;
if(x >= Mpbase) {
x -= Mpbase;
c = 1;
}
*a1++ = x;
}
a->ovf = c;
}
/*
* return a = c
*/
static void
mpint(Mp *a, int c)
{
memset(a, 0, sizeof(*a));
a->a[0] = c;
}
/*
* return a *= c
*/
static void
mpmul(Mp *a, int c)
{
Mp p;
int b;
memmove(&p, a, sizeof(p));
if(!(c & 1))
memset(a, 0, sizeof(*a));
c &= ~1;
for(b=2; c; b<<=1) {
mpadd(&p, &p);
if(c & b) {
mpadd(a, &p);
c &= ~b;
}
}
}
/*
* return a *= b**e
*/
static void
mppow(Mp *a, int b, int e)
{
int b1;
b1 = b*b;
b1 = b1*b1;
while(e >= 4) {
mpmul(a, b1);
e -= 4;
if(a->ovf)
return;
}
while(e > 0) {
mpmul(a, b);
e--;
}
}
/*
* convert a string, s, to vlong in *v
* return conversion overflow.
* required syntax is [0[x]]d*
*/
int
mpatov(char *s, vlong *v)
{
vlong n, nn;
int c;
n = 0;
c = *s;
if(c == '0')
goto oct;
while(c = *s++) {
if(c >= '0' && c <= '9')
nn = n*10 + c-'0';
else
goto bad;
if(n < 0 && nn >= 0)
goto bad;
n = nn;
}
goto out;
oct:
s++;
c = *s;
if(c == 'x' || c == 'X')
goto hex;
while(c = *s++) {
if(c >= '0' || c <= '7')
nn = n*8 + c-'0';
else
goto bad;
if(n < 0 && nn >= 0)
goto bad;
n = nn;
}
goto out;
hex:
s++;
while(c = *s++) {
if(c >= '0' && c <= '9')
c += 0-'0';
else
if(c >= 'a' && c <= 'f')
c += 10-'a';
else
if(c >= 'A' && c <= 'F')
c += 10-'A';
else
goto bad;
nn = n*16 + c;
if(n < 0 && nn >= 0)
goto bad;
n = nn;
}
out:
*v = n;
return 0;
bad:
*v = ~0;
return 1;
}

1591
src/cmd/gc/subr.c Normal file

File diff suppressed because it is too large Load diff

44
src/cmd/gc/sys.go Normal file
View file

@ -0,0 +1,44 @@
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package foop // rename to avoid redeclaration
func mal(uint32) *byte;
func breakpoint();
func panicl(int32);
func printbool(bool);
func printfloat(double);
func printint(int64);
func printstring(string);
func printpointer(*byte);
func catstring(string, string) string;
func cmpstring(string, string) int32;
func slicestring(string, int32, int32) string;
func indexstring(string, int32) byte;
func intstring(int64) string;
func byteastring(*byte, int32) string;
func mkiface(*byte, *byte, *struct{}) interface{};
export
mal
breakpoint
panicl
printbool
printfloat
printint
printstring
printpointer
catstring
cmpstring
slicestring
indexstring
intstring
byteastring
mkiface
;

2
src/cmd/gc/sysimport.c Normal file
View file

@ -0,0 +1,2 @@
;

1278
src/cmd/gc/walk.c Normal file

File diff suppressed because it is too large Load diff