URL
https://opencores.org/ocsvn/eco32/eco32/trunk
Subversion Repositories eco32
Compare Revisions
- This comparison shows the changes necessary to convert path
/eco32/tags/eco32-0.23/lcc/src
- from Rev 4 to Rev 157
- ↔ Reverse comparison
Rev 4 → Rev 157
/bytecode.c
0,0 → 1,282
#include "c.h" |
#define I(f) b_##f |
|
static char rcsid[] = "$Id: bytecode.c,v 1.1 2002/08/28 23:12:41 drh Exp $"; |
|
static void I(segment)(int n) { |
static int cseg; |
|
if (cseg != n) |
switch (cseg = n) { |
case CODE: print("code\n"); return; |
case DATA: print("data\n"); return; |
case BSS: print("bss\n"); return; |
case LIT: print("lit\n"); return; |
default: assert(0); |
} |
} |
|
static void I(address)(Symbol q, Symbol p, long n) { |
q->x.name = stringf("%s%s%D", p->x.name, n > 0 ? "+" : "", n); |
} |
|
static void I(defaddress)(Symbol p) { |
print("address %s\n", p->x.name); |
} |
|
static void I(defconst)(int suffix, int size, Value v) { |
switch (suffix) { |
case I: |
if (size > sizeof (int)) |
print("byte %d %D\n", size, v.i); |
else |
print("byte %d %d\n", size, v.i); |
return; |
case U: |
if (size > sizeof (unsigned)) |
print("byte %d %U\n", size, v.u); |
else |
print("byte %d %u\n", size, v.u); |
return; |
case P: print("byte %d %U\n", size, (unsigned long)v.p); return; |
case F: |
if (size == 4) { |
float f = v.d; |
print("byte 4 %u\n", *(unsigned *)&f); |
} else { |
double d = v.d; |
unsigned *p = (unsigned *)&d; |
print("byte 4 %u\n", p[swap]); |
print("byte 4 %u\n", p[1 - swap]); |
} |
return; |
} |
assert(0); |
} |
|
static void I(defstring)(int len, char *str) { |
char *s; |
|
for (s = str; s < str + len; s++) |
print("byte 1 %d\n", (*s)&0377); |
} |
|
static void I(defsymbol)(Symbol p) { |
if (p->scope == CONSTANTS) |
switch (optype(ttob(p->type))) { |
case I: p->x.name = stringf("%D", p->u.c.v.i); break; |
case U: p->x.name = stringf("%U", p->u.c.v.u); break; |
case P: p->x.name = stringf("%U", p->u.c.v.p); break; |
default: assert(0); |
} |
else if (p->scope >= LOCAL && p->sclass == STATIC) |
p->x.name = stringf("$%d", genlabel(1)); |
else if (p->scope == LABELS || p->generated) |
p->x.name = stringf("$%s", p->name); |
else |
p->x.name = p->name; |
} |
|
static void dumptree(Node p) { |
switch (specific(p->op)) { |
case ASGN+B: |
assert(p->kids[0]); |
assert(p->kids[1]); |
assert(p->syms[0]); |
dumptree(p->kids[0]); |
dumptree(p->kids[1]); |
print("%s %d\n", opname(p->op), p->syms[0]->u.c.v.u); |
return; |
case RET+V: |
assert(!p->kids[0]); |
assert(!p->kids[1]); |
print("%s\n", opname(p->op)); |
return; |
} |
switch (generic(p->op)) { |
case CNST: case ADDRG: case ADDRF: case ADDRL: case LABEL: |
assert(!p->kids[0]); |
assert(!p->kids[1]); |
assert(p->syms[0] && p->syms[0]->x.name); |
print("%s %s\n", opname(p->op), p->syms[0]->x.name); |
return; |
case CVF: case CVI: case CVP: case CVU: |
assert(p->kids[0]); |
assert(!p->kids[1]); |
assert(p->syms[0]); |
dumptree(p->kids[0]); |
print("%s %d\n", opname(p->op), p->syms[0]->u.c.v.i); |
return; |
case ARG: case BCOM: case NEG: case INDIR: case JUMP: case RET: |
assert(p->kids[0]); |
assert(!p->kids[1]); |
dumptree(p->kids[0]); |
print("%s\n", opname(p->op)); |
return; |
case CALL: |
assert(p->kids[0]); |
assert(!p->kids[1]); |
assert(optype(p->op) != B); |
dumptree(p->kids[0]); |
print("%s\n", opname(p->op)); |
return; |
case ASGN: case BOR: case BAND: case BXOR: case RSH: case LSH: |
case ADD: case SUB: case DIV: case MUL: case MOD: |
assert(p->kids[0]); |
assert(p->kids[1]); |
dumptree(p->kids[0]); |
dumptree(p->kids[1]); |
print("%s\n", opname(p->op)); |
return; |
case EQ: case NE: case GT: case GE: case LE: case LT: |
assert(p->kids[0]); |
assert(p->kids[1]); |
assert(p->syms[0]); |
assert(p->syms[0]->x.name); |
dumptree(p->kids[0]); |
dumptree(p->kids[1]); |
print("%s %s\n", opname(p->op), p->syms[0]->x.name); |
return; |
} |
assert(0); |
} |
|
static void I(emit)(Node p) { |
for (; p; p = p->link) |
dumptree(p); |
} |
|
static void I(export)(Symbol p) { |
print("export %s\n", p->x.name); |
} |
|
static void I(function)(Symbol f, Symbol caller[], Symbol callee[], int ncalls) { |
int i; |
|
(*IR->segment)(CODE); |
offset = 0; |
for (i = 0; caller[i] && callee[i]; i++) { |
offset = roundup(offset, caller[i]->type->align); |
caller[i]->x.name = callee[i]->x.name = stringf("%d", offset); |
caller[i]->x.offset = callee[i]->x.offset = offset; |
offset += caller[i]->type->size; |
} |
maxargoffset = maxoffset = argoffset = offset = 0; |
gencode(caller, callee); |
print("proc %s %d %d\n", f->x.name, maxoffset, maxargoffset); |
emitcode(); |
print("endproc %s %d %d\n", f->x.name, maxoffset, maxargoffset); |
|
} |
|
static void gen02(Node p) { |
assert(p); |
if (generic(p->op) == ARG) { |
assert(p->syms[0]); |
argoffset += (p->syms[0]->u.c.v.i < 4 ? 4 : p->syms[0]->u.c.v.i); |
} else if (generic(p->op) == CALL) { |
maxargoffset = (argoffset > maxargoffset ? argoffset : maxargoffset); |
argoffset = 0; |
} |
} |
|
static void gen01(Node p) { |
if (p) { |
gen01(p->kids[0]); |
gen01(p->kids[1]); |
gen02(p); |
} |
} |
|
static Node I(gen)(Node p) { |
Node q; |
|
assert(p); |
for (q = p; q; q = q->link) |
gen01(q); |
return p; |
} |
|
static void I(global)(Symbol p) { |
print("align %d\n", p->type->align > 4 ? 4 : p->type->align); |
print("LABELV %s\n", p->x.name); |
} |
|
static void I(import)(Symbol p) { |
print("import %s\n", p->x.name); |
} |
|
static void I(local)(Symbol p) { |
offset = roundup(offset, p->type->align); |
p->x.name = stringf("%d", offset); |
p->x.offset = offset; |
offset += p->type->size; |
} |
|
static void I(progbeg)(int argc, char *argv[]) {} |
|
static void I(progend)(void) {} |
|
static void I(space)(int n) { |
print("skip %d\n", n); |
} |
|
static void I(stabline)(Coordinate *cp) { |
static char *prevfile; |
static int prevline; |
|
if (cp->file && (prevfile == NULL || strcmp(prevfile, cp->file) != 0)) { |
print("file \"%s\"\n", prevfile = cp->file); |
prevline = 0; |
} |
if (cp->y != prevline) |
print("line %d\n", prevline = cp->y); |
} |
|
#define b_blockbeg blockbeg |
#define b_blockend blockend |
|
Interface bytecodeIR = { |
1, 1, 0, /* char */ |
2, 2, 0, /* short */ |
4, 4, 0, /* int */ |
4, 4, 0, /* long */ |
4, 4, 0, /* long long */ |
4, 4, 1, /* float */ |
8, 8, 1, /* double */ |
8, 8, 1, /* long double */ |
4, 4, 0, /* T* */ |
0, 4, 0, /* struct */ |
0, /* little_endian */ |
0, /* mulops_calls */ |
0, /* wants_callb */ |
0, /* wants_argb */ |
1, /* left_to_right */ |
0, /* wants_dag */ |
0, /* unsigned_char */ |
I(address), |
I(blockbeg), |
I(blockend), |
I(defaddress), |
I(defconst), |
I(defstring), |
I(defsymbol), |
I(emit), |
I(export), |
I(function), |
I(gen), |
I(global), |
I(import), |
I(local), |
I(progbeg), |
I(progend), |
I(segment), |
I(space), |
0, /* I(stabblock) */ |
0, /* I(stabend) */ |
0, /* I(stabfend) */ |
0, /* I(stabinit) */ |
I(stabline), |
0, /* I(stabsym) */ |
0, /* I(stabtype) */ |
}; |
/trace.c
0,0 → 1,170
#include "c.h" |
|
static char rcsid[] = "$Id: trace.c,v 1.1 2002/08/28 23:12:47 drh Exp $"; |
|
static char *fmt, *fp, *fmtend; /* format string, current & limit pointer */ |
static Tree args; /* printf arguments */ |
static Symbol frameno; /* local holding frame number */ |
|
/* appendstr - append str to the evolving format string, expanding it if necessary */ |
static void appendstr(char *str) { |
do |
if (fp == fmtend) |
if (fp) { |
char *s = allocate(2*(fmtend - fmt), FUNC); |
strncpy(s, fmt, fmtend - fmt); |
fp = s + (fmtend - fmt); |
fmtend = s + 2*(fmtend - fmt); |
fmt = s; |
} else { |
fp = fmt = allocate(80, FUNC); |
fmtend = fmt + 80; |
} |
while ((*fp++ = *str++) != 0); |
fp--; |
} |
|
/* tracevalue - append format and argument to print the value of e */ |
static void tracevalue(Tree e, int lev) { |
Type ty = unqual(e->type); |
|
switch (ty->op) { |
case INT: |
if (ty == chartype || ty == signedchar) |
appendstr("'\\x%02x'"); |
else if (ty == longtype) |
appendstr("0x%ld"); |
else |
appendstr("0x%d"); |
break; |
case UNSIGNED: |
if (ty == chartype || ty == unsignedchar) |
appendstr("'\\x%02x'"); |
else if (ty == unsignedlong) |
appendstr("0x%lx"); |
else |
appendstr("0x%x"); |
break; |
case FLOAT: |
if (ty == longdouble) |
appendstr("%Lg"); |
else |
appendstr("%g"); |
break; |
case POINTER: |
if (unqual(ty->type) == chartype |
|| unqual(ty->type) == signedchar |
|| unqual(ty->type) == unsignedchar) { |
static Symbol null; |
if (null == NULL) |
null = mkstr("(null)"); |
tracevalue(cast(e, unsignedtype), lev + 1); |
appendstr(" \"%.30s\""); |
e = condtree(e, e, pointer(idtree(null->u.c.loc))); |
} else { |
appendstr("("); appendstr(typestring(ty, "")); appendstr(")0x%x"); |
} |
break; |
case STRUCT: { |
Field q; |
appendstr("("); appendstr(typestring(ty, "")); appendstr("){"); |
for (q = ty->u.sym->u.s.flist; q; q = q->link) { |
appendstr(q->name); appendstr("="); |
tracevalue(field(addrof(e), q->name), lev + 1); |
if (q->link) |
appendstr(","); |
} |
appendstr("}"); |
return; |
} |
case UNION: |
appendstr("("); appendstr(typestring(ty, "")); appendstr("){...}"); |
return; |
case ARRAY: |
if (lev && ty->type->size > 0) { |
int i; |
e = pointer(e); |
appendstr("{"); |
for (i = 0; i < ty->size/ty->type->size; i++) { |
Tree p = (*optree['+'])(ADD, e, consttree(i, inttype)); |
if (isptr(p->type) && isarray(p->type->type)) |
p = retype(p, p->type->type); |
else |
p = rvalue(p); |
if (i) |
appendstr(","); |
tracevalue(p, lev + 1); |
} |
appendstr("}"); |
} else |
appendstr(typestring(ty, "")); |
return; |
default: |
assert(0); |
} |
e = cast(e, promote(ty)); |
args = tree(mkop(ARG,e->type), e->type, e, args); |
} |
|
/* tracefinis - complete & generate the trace call to print */ |
static void tracefinis(Symbol printer) { |
Tree *ap; |
Symbol p; |
|
*fp = 0; |
p = mkstr(string(fmt)); |
for (ap = &args; *ap; ap = &(*ap)->kids[1]) |
; |
*ap = tree(ARG+P, charptype, pointer(idtree(p->u.c.loc)), 0); |
walk(calltree(pointer(idtree(printer)), freturn(printer->type), args, NULL), 0, 0); |
args = 0; |
fp = fmtend = 0; |
} |
|
/* tracecall - generate code to trace entry to f */ |
static void tracecall(Symbol printer, Symbol f, void *ignore) { |
int i; |
Symbol counter = genident(STATIC, inttype, GLOBAL); |
|
defglobal(counter, BSS); |
(*IR->space)(counter->type->size); |
frameno = genident(AUTO, inttype, level); |
addlocal(frameno); |
appendstr(f->name); appendstr("#"); |
tracevalue(asgn(frameno, incr(INCR, idtree(counter), consttree(1, inttype))), 0); |
appendstr("("); |
for (i = 0; f->u.f.callee[i]; i++) { |
if (i) |
appendstr(","); |
appendstr(f->u.f.callee[i]->name); appendstr("="); |
tracevalue(idtree(f->u.f.callee[i]), 0); |
} |
if (variadic(f->type)) |
appendstr(",..."); |
appendstr(") called\n"); |
tracefinis(printer); |
} |
|
/* tracereturn - generate code to trace return e */ |
static void tracereturn(Symbol printer, Symbol f, Tree e) { |
appendstr(f->name); appendstr("#"); |
tracevalue(idtree(frameno), 0); |
appendstr(" returned"); |
if (freturn(f->type) != voidtype && e) { |
appendstr(" "); |
tracevalue(e, 0); |
} |
appendstr("\n"); |
tracefinis(printer); |
} |
|
/* traceInit - initialize for tracing */ |
void traceInit(char *arg) { |
if (strncmp(arg, "-t", 2) == 0 && strchr(arg, '=') == NULL) { |
Symbol printer = mksymbol(EXTERN, arg[2] ? &arg[2] : "printf", |
ftype(inttype, ptr(qual(CONST, chartype)), voidtype, NULL)); |
printer->defined = 0; |
attach((Apply)tracecall, printer, &events.entry); |
attach((Apply)tracereturn, printer, &events.returns); |
} |
} |
/stab.h
0,0 → 1,114
/* @(#)stab.h 1.11 92/05/11 SMI */ |
/* $Id: stab.h,v 1.1 2002/08/28 23:12:46 drh Exp $ */ |
/* |
* Copyright (c) 1990 by Sun Microsystems, Inc. |
*/ |
|
/* |
* This file gives definitions supplementing <a.out.h> |
* for permanent symbol table entries. |
* These must have one of the N_STAB bits on, |
* and are subject to relocation according to the masks in <a.out.h>. |
*/ |
|
#ifndef _STAB_H |
#define _STAB_H |
|
|
#if !defined(_a_out_h) && !defined(_A_OUT_H) |
/* this file contains fragments of a.out.h and stab.h relevant to |
* support of stabX processing within ELF files - see the |
* Format of a symbol table entry |
*/ |
struct nlist { |
union { |
char *n_name; /* for use when in-core */ |
long n_strx; /* index into file string table */ |
} n_un; |
unsigned char n_type; /* type flag (N_TEXT,..) */ |
char n_other; /* unused */ |
short n_desc; /* see <stab.h> */ |
unsigned long n_value; /* value of symbol (or sdb offset) */ |
}; |
|
/* |
* Simple values for n_type. |
*/ |
#define N_UNDF 0x0 /* undefined */ |
#define N_ABS 0x2 /* absolute */ |
#define N_TEXT 0x4 /* text */ |
#define N_DATA 0x6 /* data */ |
#define N_BSS 0x8 /* bss */ |
#define N_COMM 0x12 /* common (internal to ld) */ |
#define N_FN 0x1f /* file name symbol */ |
|
#define N_EXT 01 /* external bit, or'ed in */ |
#define N_TYPE 0x1e /* mask for all the type bits */ |
|
#endif |
|
/* |
* for symbolic debugger, sdb(1): |
*/ |
#define N_GSYM 0x20 /* global symbol: name,,0,type,0 */ |
#define N_FNAME 0x22 /* procedure name (f77 kludge): name,,0 */ |
#define N_FUN 0x24 /* procedure: name,,0,linenumber,address */ |
#define N_STSYM 0x26 /* static symbol: name,,0,type,address */ |
#define N_LCSYM 0x28 /* .lcomm symbol: name,,0,type,address */ |
#define N_MAIN 0x2a /* name of main routine : name,,0,0,0 */ |
#define N_ROSYM 0x2c /* ro_data objects */ |
#define N_OBJ 0x38 /* object file path or name */ |
#define N_OPT 0x3c /* compiler options */ |
#define N_RSYM 0x40 /* register sym: name,,0,type,register */ |
#define N_SLINE 0x44 /* src line: 0,,0,linenumber,address */ |
#define N_FLINE 0x4c /* function start.end */ |
#define N_SSYM 0x60 /* structure elt: name,,0,type,struct_offset */ |
#define N_ENDM 0x62 /* last stab emitted for module */ |
#define N_SO 0x64 /* source file name: name,,0,0,address */ |
#define N_LSYM 0x80 /* local sym: name,,0,type,offset */ |
#define N_BINCL 0x82 /* header file: name,,0,0,0 */ |
#define N_SOL 0x84 /* #included file name: name,,0,0,address */ |
#define N_PSYM 0xa0 /* parameter: name,,0,type,offset */ |
#define N_EINCL 0xa2 /* end of include file */ |
#define N_ENTRY 0xa4 /* alternate entry: name,linenumber,address */ |
#define N_LBRAC 0xc0 /* left bracket: 0,,0,nesting level,address */ |
#define N_EXCL 0xc2 /* excluded include file */ |
#define N_RBRAC 0xe0 /* right bracket: 0,,0,nesting level,address */ |
#define N_BCOMM 0xe2 /* begin common: name,, */ |
#define N_ECOMM 0xe4 /* end common: name,, */ |
#define N_ECOML 0xe8 /* end common (local name): ,,address */ |
#define N_LENG 0xfe /* second stab entry with length information */ |
|
/* |
* for the berkeley pascal compiler, pc(1): |
*/ |
#define N_PC 0x30 /* global pascal symbol: name,,0,subtype,line */ |
#define N_WITH 0xea /* pascal with statement: type,,0,0,offset */ |
|
/* |
* for code browser only |
*/ |
#define N_BROWS 0x48 /* path to associated .cb file */ |
|
/* |
* Optional langauge designations for N_SO |
*/ |
#define N_SO_AS 1 /* Assembler */ |
#define N_SO_C 2 /* C */ |
#define N_SO_ANSI_C 3 /* ANSI C */ |
#define N_SO_CC 4 /* C++ */ |
#define N_SO_FORTRAN 5 /* Fortran 77 */ |
#define N_SO_PASCAL 6 /* Pascal */ |
|
/* |
* Floating point type values |
*/ |
#define NF_NONE 0 /* Undefined type */ |
#define NF_SINGLE 1 /* IEEE 32 bit float */ |
#define NF_DOUBLE 2 /* IEEE 64 bit float */ |
#define NF_COMPLEX 3 /* Fortran complex */ |
#define NF_COMPLEX16 4 /* Fortran double complex */ |
#define NF_COMPLEX32 5 /* Fortran complex*16 */ |
#define NF_LDOUBLE 6 /* Long double */ |
|
#endif |
/output.c
0,0 → 1,135
#include "c.h" |
|
static char rcsid[] = "$Id: output.c,v 1.1 2002/08/28 23:12:45 drh Exp $"; |
|
static char *outs(const char *str, FILE *f, char *bp) { |
if (f) |
fputs(str, f); |
else |
while (*bp = *str++) |
bp++; |
return bp; |
} |
|
static char *outd(long n, FILE *f, char *bp) { |
unsigned long m; |
char buf[25], *s = buf + sizeof buf; |
|
*--s = '\0'; |
if (n < 0) |
m = -n; |
else |
m = n; |
do |
*--s = m%10 + '0'; |
while ((m /= 10) != 0); |
if (n < 0) |
*--s = '-'; |
return outs(s, f, bp); |
} |
|
static char *outu(unsigned long n, int base, FILE *f, char *bp) { |
char buf[25], *s = buf + sizeof buf; |
|
*--s = '\0'; |
do |
*--s = "0123456789abcdef"[n%base]; |
while ((n /= base) != 0); |
return outs(s, f, bp); |
} |
void print(const char *fmt, ...) { |
va_list ap; |
|
va_start(ap, fmt); |
vfprint(stdout, NULL, fmt, ap); |
va_end(ap); |
} |
/* fprint - formatted output to f */ |
void fprint(FILE *f, const char *fmt, ...) { |
va_list ap; |
|
va_start(ap, fmt); |
vfprint(f, NULL, fmt, ap); |
va_end(ap); |
} |
|
/* stringf - formatted output to a saved string */ |
char *stringf(const char *fmt, ...) { |
char buf[1024]; |
va_list ap; |
|
va_start(ap, fmt); |
vfprint(NULL, buf, fmt, ap); |
va_end(ap); |
return string(buf); |
} |
|
/* vfprint - formatted output to f or string bp */ |
void vfprint(FILE *f, char *bp, const char *fmt, va_list ap) { |
for (; *fmt; fmt++) |
if (*fmt == '%') |
switch (*++fmt) { |
case 'd': bp = outd(va_arg(ap, int), f, bp); break; |
case 'D': bp = outd(va_arg(ap, long), f, bp); break; |
case 'U': bp = outu(va_arg(ap, unsigned long), 10, f, bp); break; |
case 'u': bp = outu(va_arg(ap, unsigned), 10, f, bp); break; |
case 'o': bp = outu(va_arg(ap, unsigned), 8, f, bp); break; |
case 'X': bp = outu(va_arg(ap, unsigned long), 16, f, bp); break; |
case 'x': bp = outu(va_arg(ap, unsigned), 16, f, bp); break; |
case 'f': case 'e': |
case 'g': { |
static char format[] = "%f"; |
char buf[128]; |
format[1] = *fmt; |
sprintf(buf, format, va_arg(ap, double)); |
bp = outs(buf, f, bp); |
} |
; break; |
case 's': bp = outs(va_arg(ap, char *), f, bp); break; |
case 'p': { |
void *p = va_arg(ap, void *); |
if (p) |
bp = outs("0x", f, bp); |
bp = outu((unsigned long)p, 16, f, bp); |
break; |
} |
case 'c': if (f) fputc(va_arg(ap, int), f); else *bp++ = va_arg(ap, int); break; |
case 'S': { char *s = va_arg(ap, char *); |
int n = va_arg(ap, int); |
if (s) |
for ( ; n-- > 0; s++) |
if (f) (void)putc(*s, f); else *bp++ = *s; |
} break; |
case 'k': { int t = va_arg(ap, int); |
static char *tokens[] = { |
#define xx(a,b,c,d,e,f,g) g, |
#define yy(a,b,c,d,e,f,g) g, |
#include "token.h" |
}; |
assert(tokens[t&0177]); |
bp = outs(tokens[t&0177], f, bp); |
} break; |
case 't': { Type ty = va_arg(ap, Type); |
assert(f); |
outtype(ty ? ty : voidtype, f); |
} break; |
case 'w': { Coordinate *p = va_arg(ap, Coordinate *); |
if (p->file && *p->file) { |
bp = outs(p->file, f, bp); |
bp = outs(":", f, bp); |
} |
bp = outd(p->y, f, bp); |
} break; |
case 'I': { int n = va_arg(ap, int); |
while (--n >= 0) |
if (f) (void)putc(' ', f); else *bp++ = ' '; |
} break; |
default: if (f) (void)putc(*fmt, f); else *bp++ = *fmt; break; |
} |
else if (f) |
(void)putc(*fmt, f); |
else |
*bp++ = *fmt; |
if (!f) |
*bp = '\0'; |
} |
/x86.md
0,0 → 1,1012
%{ |
enum { EAX=0, ECX=1, EDX=2, EBX=3, ESI=6, EDI=7 }; |
#include "c.h" |
#define NODEPTR_TYPE Node |
#define OP_LABEL(p) ((p)->op) |
#define LEFT_CHILD(p) ((p)->kids[0]) |
#define RIGHT_CHILD(p) ((p)->kids[1]) |
#define STATE_LABEL(p) ((p)->x.state) |
static void address(Symbol, Symbol, long); |
static void blkfetch(int, int, int, int); |
static void blkloop(int, int, int, int, int, int[]); |
static void blkstore(int, int, int, int); |
static void defaddress(Symbol); |
static void defconst(int, int, Value); |
static void defstring(int, char *); |
static void defsymbol(Symbol); |
static void doarg(Node); |
static void emit2(Node); |
static void export(Symbol); |
static void clobber(Node); |
static void function(Symbol, Symbol [], Symbol [], int); |
static void global(Symbol); |
static void import(Symbol); |
static void local(Symbol); |
static void progbeg(int, char **); |
static void progend(void); |
static void segment(int); |
static void space(int); |
static void target(Node); |
extern int ckstack(Node, int); |
extern int memop(Node); |
extern int sametree(Node, Node); |
static Symbol charreg[32], shortreg[32], intreg[32]; |
static Symbol fltreg[32]; |
|
static Symbol charregw, shortregw, intregw, fltregw; |
|
static int cseg; |
|
static Symbol quo, rem; |
|
%} |
%start stmt |
%term CNSTF4=4113 |
%term CNSTF8=8209 |
%term CNSTF16=16401 |
%term CNSTI1=1045 |
%term CNSTI2=2069 |
%term CNSTI4=4117 |
%term CNSTI8=8213 |
%term CNSTP4=4119 |
%term CNSTP8=8215 |
%term CNSTU1=1046 |
%term CNSTU2=2070 |
%term CNSTU4=4118 |
%term CNSTU8=8214 |
|
%term ARGB=41 |
%term ARGF4=4129 |
%term ARGF8=8225 |
%term ARGF16=16417 |
%term ARGI4=4133 |
%term ARGI8=8229 |
%term ARGP4=4135 |
%term ARGP8=8231 |
%term ARGU4=4134 |
%term ARGU8=8230 |
|
%term ASGNB=57 |
%term ASGNF4=4145 |
%term ASGNF8=8241 |
%term ASGNF16=16433 |
%term ASGNI1=1077 |
%term ASGNI2=2101 |
%term ASGNI4=4149 |
%term ASGNI8=8245 |
%term ASGNP4=4151 |
%term ASGNP8=8247 |
%term ASGNU1=1078 |
%term ASGNU2=2102 |
%term ASGNU4=4150 |
%term ASGNU8=8246 |
|
%term INDIRB=73 |
%term INDIRF4=4161 |
%term INDIRF8=8257 |
%term INDIRF16=16449 |
%term INDIRI1=1093 |
%term INDIRI2=2117 |
%term INDIRI4=4165 |
%term INDIRI8=8261 |
%term INDIRP4=4167 |
%term INDIRP8=8263 |
%term INDIRU1=1094 |
%term INDIRU2=2118 |
%term INDIRU4=4166 |
%term INDIRU8=8262 |
|
%term CVFF4=4209 |
%term CVFF8=8305 |
%term CVFF16=16497 |
%term CVFI4=4213 |
%term CVFI8=8309 |
|
%term CVIF4=4225 |
%term CVIF8=8321 |
%term CVIF16=16513 |
%term CVII1=1157 |
%term CVII2=2181 |
%term CVII4=4229 |
%term CVII8=8325 |
%term CVIU1=1158 |
%term CVIU2=2182 |
%term CVIU4=4230 |
%term CVIU8=8326 |
|
%term CVPP4=4247 |
%term CVPP8=8343 |
%term CVPP16=16535 |
%term CVPU4=4246 |
%term CVPU8=8342 |
|
%term CVUI1=1205 |
%term CVUI2=2229 |
%term CVUI4=4277 |
%term CVUI8=8373 |
%term CVUP4=4279 |
%term CVUP8=8375 |
%term CVUP16=16567 |
%term CVUU1=1206 |
%term CVUU2=2230 |
%term CVUU4=4278 |
%term CVUU8=8374 |
|
%term NEGF4=4289 |
%term NEGF8=8385 |
%term NEGF16=16577 |
%term NEGI4=4293 |
%term NEGI8=8389 |
|
%term CALLB=217 |
%term CALLF4=4305 |
%term CALLF8=8401 |
%term CALLF16=16593 |
%term CALLI4=4309 |
%term CALLI8=8405 |
%term CALLP4=4311 |
%term CALLP8=8407 |
%term CALLU4=4310 |
%term CALLU8=8406 |
%term CALLV=216 |
|
%term RETF4=4337 |
%term RETF8=8433 |
%term RETF16=16625 |
%term RETI4=4341 |
%term RETI8=8437 |
%term RETP4=4343 |
%term RETP8=8439 |
%term RETU4=4342 |
%term RETU8=8438 |
%term RETV=248 |
|
%term ADDRGP4=4359 |
%term ADDRGP8=8455 |
|
%term ADDRFP4=4375 |
%term ADDRFP8=8471 |
|
%term ADDRLP4=4391 |
%term ADDRLP8=8487 |
|
%term ADDF4=4401 |
%term ADDF8=8497 |
%term ADDF16=16689 |
%term ADDI4=4405 |
%term ADDI8=8501 |
%term ADDP4=4407 |
%term ADDP8=8503 |
%term ADDU4=4406 |
%term ADDU8=8502 |
|
%term SUBF4=4417 |
%term SUBF8=8513 |
%term SUBF16=16705 |
%term SUBI4=4421 |
%term SUBI8=8517 |
%term SUBP4=4423 |
%term SUBP8=8519 |
%term SUBU4=4422 |
%term SUBU8=8518 |
|
%term LSHI4=4437 |
%term LSHI8=8533 |
%term LSHU4=4438 |
%term LSHU8=8534 |
|
%term MODI4=4453 |
%term MODI8=8549 |
%term MODU4=4454 |
%term MODU8=8550 |
|
%term RSHI4=4469 |
%term RSHI8=8565 |
%term RSHU4=4470 |
%term RSHU8=8566 |
|
%term BANDI4=4485 |
%term BANDI8=8581 |
%term BANDU4=4486 |
%term BANDU8=8582 |
|
%term BCOMI4=4501 |
%term BCOMI8=8597 |
%term BCOMU4=4502 |
%term BCOMU8=8598 |
|
%term BORI4=4517 |
%term BORI8=8613 |
%term BORU4=4518 |
%term BORU8=8614 |
|
%term BXORI4=4533 |
%term BXORI8=8629 |
%term BXORU4=4534 |
%term BXORU8=8630 |
|
%term DIVF4=4545 |
%term DIVF8=8641 |
%term DIVF16=16833 |
%term DIVI4=4549 |
%term DIVI8=8645 |
%term DIVU4=4550 |
%term DIVU8=8646 |
|
%term MULF4=4561 |
%term MULF8=8657 |
%term MULF16=16849 |
%term MULI4=4565 |
%term MULI8=8661 |
%term MULU4=4566 |
%term MULU8=8662 |
|
%term EQF4=4577 |
%term EQF8=8673 |
%term EQF16=16865 |
%term EQI4=4581 |
%term EQI8=8677 |
%term EQU4=4582 |
%term EQU8=8678 |
|
%term GEF4=4593 |
%term GEF8=8689 |
%term GEI4=4597 |
%term GEI8=8693 |
%term GEI16=16885 |
%term GEU4=4598 |
%term GEU8=8694 |
|
%term GTF4=4609 |
%term GTF8=8705 |
%term GTF16=16897 |
%term GTI4=4613 |
%term GTI8=8709 |
%term GTU4=4614 |
%term GTU8=8710 |
|
%term LEF4=4625 |
%term LEF8=8721 |
%term LEF16=16913 |
%term LEI4=4629 |
%term LEI8=8725 |
%term LEU4=4630 |
%term LEU8=8726 |
|
%term LTF4=4641 |
%term LTF8=8737 |
%term LTF16=16929 |
%term LTI4=4645 |
%term LTI8=8741 |
%term LTU4=4646 |
%term LTU8=8742 |
|
%term NEF4=4657 |
%term NEF8=8753 |
%term NEF16=16945 |
%term NEI4=4661 |
%term NEI8=8757 |
%term NEU4=4662 |
%term NEU8=8758 |
|
%term JUMPV=584 |
|
%term LABELV=600 |
|
%term LOADB=233 |
%term LOADF4=4321 |
%term LOADF8=8417 |
%term LOADF16=16609 |
%term LOADI1=1253 |
%term LOADI2=2277 |
%term LOADI4=4325 |
%term LOADI8=8421 |
%term LOADP4=4327 |
%term LOADP8=8423 |
%term LOADU1=1254 |
%term LOADU2=2278 |
%term LOADU4=4326 |
%term LOADU8=8422 |
|
%term VREGP=711 |
%% |
reg: INDIRI1(VREGP) "# read register\n" |
reg: INDIRU1(VREGP) "# read register\n" |
|
reg: INDIRI2(VREGP) "# read register\n" |
reg: INDIRU2(VREGP) "# read register\n" |
|
reg: INDIRF4(VREGP) "# read register\n" |
reg: INDIRI4(VREGP) "# read register\n" |
reg: INDIRP4(VREGP) "# read register\n" |
reg: INDIRU4(VREGP) "# read register\n" |
|
reg: INDIRF8(VREGP) "# read register\n" |
reg: INDIRI8(VREGP) "# read register\n" |
reg: INDIRP8(VREGP) "# read register\n" |
reg: INDIRU8(VREGP) "# read register\n" |
|
stmt: ASGNI1(VREGP,reg) "# write register\n" |
stmt: ASGNU1(VREGP,reg) "# write register\n" |
|
stmt: ASGNI2(VREGP,reg) "# write register\n" |
stmt: ASGNU2(VREGP,reg) "# write register\n" |
|
stmt: ASGNF4(VREGP,reg) "# write register\n" |
stmt: ASGNI4(VREGP,reg) "# write register\n" |
stmt: ASGNP4(VREGP,reg) "# write register\n" |
stmt: ASGNU4(VREGP,reg) "# write register\n" |
|
stmt: ASGNF8(VREGP,reg) "# write register\n" |
stmt: ASGNI8(VREGP,reg) "# write register\n" |
stmt: ASGNP8(VREGP,reg) "# write register\n" |
stmt: ASGNU8(VREGP,reg) "# write register\n" |
con: CNSTI1 "%a" |
con: CNSTU1 "%a" |
|
con: CNSTI2 "%a" |
con: CNSTU2 "%a" |
|
con: CNSTI4 "%a" |
con: CNSTU4 "%a" |
con: CNSTP4 "%a" |
|
con: CNSTI8 "%a" |
con: CNSTU8 "%a" |
con: CNSTP8 "%a" |
stmt: reg "" |
acon: ADDRGP4 "(%a)" |
acon: con "(%0)" |
base: ADDRGP4 "(%a)" |
base: reg "[%0]" |
base: ADDI4(reg,acon) "%1[%0]" |
base: ADDP4(reg,acon) "%1[%0]" |
base: ADDU4(reg,acon) "%1[%0]" |
base: ADDRFP4 "(%a)[ebp]" |
base: ADDRLP4 "(%a)[ebp]" |
index: reg "%0" |
index: LSHI4(reg,con1) "%0*2" |
index: LSHI4(reg,con2) "%0*4" |
index: LSHI4(reg,con3) "%0*8" |
|
con1: CNSTI4 "1" range(a, 1, 1) |
con1: CNSTU4 "1" range(a, 1, 1) |
con2: CNSTI4 "2" range(a, 2, 2) |
con2: CNSTU4 "2" range(a, 2, 2) |
con3: CNSTI4 "3" range(a, 3, 3) |
con3: CNSTU4 "3" range(a, 3, 3) |
index: LSHU4(reg,con1) "%0*2" |
index: LSHU4(reg,con2) "%0*4" |
index: LSHU4(reg,con3) "%0*8" |
addr: base "%0" |
addr: ADDI4(index,base) "%1[%0]" |
addr: ADDP4(index,base) "%1[%0]" |
addr: ADDU4(index,base) "%1[%0]" |
addr: index "[%0]" |
mem: INDIRI1(addr) "byte ptr %0" |
mem: INDIRI2(addr) "word ptr %0" |
mem: INDIRI4(addr) "dword ptr %0" |
mem: INDIRU1(addr) "byte ptr %0" |
mem: INDIRU2(addr) "word ptr %0" |
mem: INDIRU4(addr) "dword ptr %0" |
mem: INDIRP4(addr) "dword ptr %0" |
rc: reg "%0" |
rc: con "%0" |
|
mr: reg "%0" |
mr: mem "%0" |
|
mrc0: mem "%0" |
mrc0: rc "%0" |
mrc1: mem "%0" 1 |
mrc1: rc "%0" |
|
mrc3: mem "%0" 3 |
mrc3: rc "%0" |
reg: addr "lea %c,%0\n" 1 |
reg: mrc0 "mov %c,%0\n" 1 |
reg: LOADI1(reg) "# move\n" 1 |
reg: LOADI2(reg) "# move\n" 1 |
reg: LOADI4(reg) "# move\n" move(a) |
reg: LOADU1(reg) "# move\n" 1 |
reg: LOADU2(reg) "# move\n" 1 |
reg: LOADU4(reg) "# move\n" move(a) |
reg: LOADP4(reg) "# move\n" move(a) |
reg: ADDI4(reg,mrc1) "?mov %c,%0\nadd %c,%1\n" 1 |
reg: ADDP4(reg,mrc1) "?mov %c,%0\nadd %c,%1\n" 1 |
reg: ADDU4(reg,mrc1) "?mov %c,%0\nadd %c,%1\n" 1 |
reg: SUBI4(reg,mrc1) "?mov %c,%0\nsub %c,%1\n" 1 |
reg: SUBP4(reg,mrc1) "?mov %c,%0\nsub %c,%1\n" 1 |
reg: SUBU4(reg,mrc1) "?mov %c,%0\nsub %c,%1\n" 1 |
reg: BANDI4(reg,mrc1) "?mov %c,%0\nand %c,%1\n" 1 |
reg: BORI4(reg,mrc1) "?mov %c,%0\nor %c,%1\n" 1 |
reg: BXORI4(reg,mrc1) "?mov %c,%0\nxor %c,%1\n" 1 |
reg: BANDU4(reg,mrc1) "?mov %c,%0\nand %c,%1\n" 1 |
reg: BORU4(reg,mrc1) "?mov %c,%0\nor %c,%1\n" 1 |
reg: BXORU4(reg,mrc1) "?mov %c,%0\nxor %c,%1\n" 1 |
stmt: ASGNI4(addr,ADDI4(mem,con1)) "inc %1\n" memop(a) |
stmt: ASGNI4(addr,ADDU4(mem,con1)) "inc %1\n" memop(a) |
stmt: ASGNP4(addr,ADDP4(mem,con1)) "inc %1\n" memop(a) |
stmt: ASGNI4(addr,SUBI4(mem,con1)) "dec %1\n" memop(a) |
stmt: ASGNI4(addr,SUBU4(mem,con1)) "dec %1\n" memop(a) |
stmt: ASGNP4(addr,SUBP4(mem,con1)) "dec %1\n" memop(a) |
stmt: ASGNI4(addr,ADDI4(mem,rc)) "add %1,%2\n" memop(a) |
stmt: ASGNI4(addr,SUBI4(mem,rc)) "sub %1,%2\n" memop(a) |
stmt: ASGNU4(addr,ADDU4(mem,rc)) "add %1,%2\n" memop(a) |
stmt: ASGNU4(addr,SUBU4(mem,rc)) "sub %1,%2\n" memop(a) |
|
stmt: ASGNI4(addr,BANDI4(mem,rc)) "and %1,%2\n" memop(a) |
stmt: ASGNI4(addr,BORI4(mem,rc)) "or %1,%2\n" memop(a) |
stmt: ASGNI4(addr,BXORI4(mem,rc)) "xor %1,%2\n" memop(a) |
stmt: ASGNU4(addr,BANDU4(mem,rc)) "and %1,%2\n" memop(a) |
stmt: ASGNU4(addr,BORU4(mem,rc)) "or %1,%2\n" memop(a) |
stmt: ASGNU4(addr,BXORU4(mem,rc)) "xor %1,%2\n" memop(a) |
reg: BCOMI4(reg) "?mov %c,%0\nnot %c\n" 2 |
reg: BCOMU4(reg) "?mov %c,%0\nnot %c\n" 2 |
reg: NEGI4(reg) "?mov %c,%0\nneg %c\n" 2 |
|
stmt: ASGNI4(addr,BCOMI4(mem)) "not %1\n" memop(a) |
stmt: ASGNU4(addr,BCOMU4(mem)) "not %1\n" memop(a) |
stmt: ASGNI4(addr,NEGI4(mem)) "neg %1\n" memop(a) |
reg: LSHI4(reg,con5) "?mov %c,%0\nsal %c,%1\n" 2 |
reg: LSHU4(reg,con5) "?mov %c,%0\nshl %c,%1\n" 2 |
reg: RSHI4(reg,con5) "?mov %c,%0\nsar %c,%1\n" 2 |
reg: RSHU4(reg,con5) "?mov %c,%0\nshr %c,%1\n" 2 |
|
stmt: ASGNI4(addr,LSHI4(mem,con5)) "sal %1,%2\n" memop(a) |
stmt: ASGNI4(addr,LSHU4(mem,con5)) "shl %1,%2\n" memop(a) |
stmt: ASGNI4(addr,RSHI4(mem,con5)) "sar %1,%2\n" memop(a) |
stmt: ASGNI4(addr,RSHU4(mem,con5)) "shr %1,%2\n" memop(a) |
|
con5: CNSTI4 "%a" range(a, 0, 31) |
|
reg: LSHI4(reg,reg) "?mov %c,%0\nmov ecx,%1\nsal %c,cl\n" 3 |
reg: LSHU4(reg,reg) "?mov %c,%0\nmov ecx,%1\nshl %c,cl\n" 2 |
reg: RSHI4(reg,reg) "?mov %c,%0\nmov ecx,%1\nsar %c,cl\n" 2 |
reg: RSHU4(reg,reg) "?mov %c,%0\nmov ecx,%1\nshr %c,cl\n" 2 |
reg: MULI4(reg,mrc3) "?mov %c,%0\nimul %c,%1\n" 14 |
reg: MULI4(con,mr) "imul %c,%1,%0\n" 13 |
reg: MULU4(reg,mr) "mul %1\n" 13 |
reg: DIVU4(reg,reg) "xor edx,edx\ndiv %1\n" |
reg: MODU4(reg,reg) "xor edx,edx\ndiv %1\n" |
reg: DIVI4(reg,reg) "cdq\nidiv %1\n" |
reg: MODI4(reg,reg) "cdq\nidiv %1\n" |
reg: CVPU4(reg) "mov %c,%0\n" move(a) |
reg: CVUP4(reg) "mov %c,%0\n" move(a) |
reg: CVII4(INDIRI1(addr)) "movsx %c,byte ptr %0\n" 3 |
reg: CVII4(INDIRI2(addr)) "movsx %c,word ptr %0\n" 3 |
reg: CVUU4(INDIRU1(addr)) "movzx %c,byte ptr %0\n" 3 |
reg: CVUU4(INDIRU2(addr)) "movzx %c,word ptr %0\n" 3 |
reg: CVII4(reg) "# extend\n" 3 |
reg: CVIU4(reg) "# extend\n" 3 |
reg: CVUI4(reg) "# extend\n" 3 |
reg: CVUU4(reg) "# extend\n" 3 |
|
reg: CVII1(reg) "# truncate\n" 1 |
reg: CVII2(reg) "# truncate\n" 1 |
reg: CVUU1(reg) "# truncate\n" 1 |
reg: CVUU2(reg) "# truncate\n" 1 |
stmt: ASGNI1(addr,rc) "mov byte ptr %0,%1\n" 1 |
stmt: ASGNI2(addr,rc) "mov word ptr %0,%1\n" 1 |
stmt: ASGNI4(addr,rc) "mov dword ptr %0,%1\n" 1 |
stmt: ASGNU1(addr,rc) "mov byte ptr %0,%1\n" 1 |
stmt: ASGNU2(addr,rc) "mov word ptr %0,%1\n" 1 |
stmt: ASGNU4(addr,rc) "mov dword ptr %0,%1\n" 1 |
stmt: ASGNP4(addr,rc) "mov dword ptr %0,%1\n" 1 |
stmt: ARGI4(mrc3) "push %0\n" 1 |
stmt: ARGU4(mrc3) "push %0\n" 1 |
stmt: ARGP4(mrc3) "push %0\n" 1 |
stmt: ASGNB(reg,INDIRB(reg)) "mov ecx,%a\nrep movsb\n" |
stmt: ARGB(INDIRB(reg)) "# ARGB\n" |
memf: INDIRF8(addr) "qword ptr %0" |
memf: INDIRF4(addr) "dword ptr %0" |
memf: CVFF8(INDIRF4(addr)) "dword ptr %0" |
reg: memf "fld %0\n" 3 |
stmt: ASGNF8(addr,reg) "fstp qword ptr %0\n" 7 |
stmt: ASGNF4(addr,reg) "fstp dword ptr %0\n" 7 |
stmt: ASGNF4(addr,CVFF4(reg)) "fstp dword ptr %0\n" 7 |
stmt: ARGF8(reg) "sub esp,8\nfstp qword ptr [esp]\n" |
stmt: ARGF4(reg) "sub esp,4\nfstp dword ptr [esp]\n" |
reg: NEGF8(reg) "fchs\n" |
reg: NEGF4(reg) "fchs\n" |
flt: memf " %0" |
flt: reg "p st(1),st" |
reg: ADDF8(reg,flt) "fadd%1\n" |
reg: ADDF4(reg,flt) "fadd%1\n" |
reg: DIVF8(reg,flt) "fdiv%1\n" |
reg: DIVF4(reg,flt) "fdiv%1\n" |
reg: MULF8(reg,flt) "fmul%1\n" |
reg: MULF4(reg,flt) "fmul%1\n" |
reg: SUBF8(reg,flt) "fsub%1\n" |
reg: SUBF4(reg,flt) "fsub%1\n" |
reg: CVFF8(reg) "# CVFF8\n" |
reg: CVFF4(reg) "sub esp,4\nfstp dword ptr 0[esp]\nfld dword ptr 0[esp]\nadd esp,4\n" 12 |
|
reg: CVFI4(reg) "call __ftol\n" 31 |
reg: CVIF8(INDIRI4(addr)) "fild dword ptr %0\n" 10 |
reg: CVIF4(reg) "push %0\nfild dword ptr 0[esp]\nadd esp,4\n" 12 |
|
reg: CVIF8(reg) "push %0\nfild dword ptr 0[esp]\nadd esp,4\n" 12 |
|
addrj: ADDRGP4 "%a" |
addrj: reg "%0" 2 |
addrj: mem "%0" 2 |
|
stmt: JUMPV(addrj) "jmp %0\n" 3 |
stmt: LABELV "%a:\n" |
stmt: EQI4(mem,rc) "cmp %0,%1\nje %a\n" 5 |
stmt: GEI4(mem,rc) "cmp %0,%1\njge %a\n" 5 |
stmt: GTI4(mem,rc) "cmp %0,%1\njg %a\n" 5 |
stmt: LEI4(mem,rc) "cmp %0,%1\njle %a\n" 5 |
stmt: LTI4(mem,rc) "cmp %0,%1\njl %a\n" 5 |
stmt: NEI4(mem,rc) "cmp %0,%1\njne %a\n" 5 |
stmt: GEU4(mem,rc) "cmp %0,%1\njae %a\n" 5 |
stmt: GTU4(mem,rc) "cmp %0,%1\nja %a\n" 5 |
stmt: LEU4(mem,rc) "cmp %0,%1\njbe %a\n" 5 |
stmt: LTU4(mem,rc) "cmp %0,%1\njb %a\n" 5 |
stmt: EQI4(reg,mrc1) "cmp %0,%1\nje %a\n" 4 |
stmt: GEI4(reg,mrc1) "cmp %0,%1\njge %a\n" 4 |
stmt: GTI4(reg,mrc1) "cmp %0,%1\njg %a\n" 4 |
stmt: LEI4(reg,mrc1) "cmp %0,%1\njle %a\n" 4 |
stmt: LTI4(reg,mrc1) "cmp %0,%1\njl %a\n" 4 |
stmt: NEI4(reg,mrc1) "cmp %0,%1\njne %a\n" 4 |
|
stmt: EQU4(reg,mrc1) "cmp %0,%1\nje %a\n" 4 |
stmt: GEU4(reg,mrc1) "cmp %0,%1\njae %a\n" 4 |
stmt: GTU4(reg,mrc1) "cmp %0,%1\nja %a\n" 4 |
stmt: LEU4(reg,mrc1) "cmp %0,%1\njbe %a\n" 4 |
stmt: LTU4(reg,mrc1) "cmp %0,%1\njb %a\n" 4 |
stmt: NEU4(reg,mrc1) "cmp %0,%1\njne %a\n" 4 |
cmpf: memf " %0" |
cmpf: reg "p" |
stmt: EQF8(cmpf,reg) "fcomp%0\nfstsw ax\nsahf\njp %b\nje %a\n%b:\n" |
stmt: GEF8(cmpf,reg) "fcomp%0\nfstsw ax\nsahf\njp %a\njbe %a\n" |
stmt: GTF8(cmpf,reg) "fcomp%0\nfstsw ax\nsahf\njp %a\njb %a\n" |
stmt: LEF8(cmpf,reg) "fcomp%0\nfstsw ax\nsahf\njp %a\njae %a\n" |
stmt: LTF8(cmpf,reg) "fcomp%0\nfstsw ax\nsahf\njp %a\nja %a\n" |
stmt: NEF8(cmpf,reg) "fcomp%0\nfstsw ax\nsahf\njp %a\njne %a\n" |
|
stmt: EQF4(cmpf,reg) "fcomp%0\nfstsw ax\nsahf\njp %b\nje %a\n%b:\n" |
stmt: GEF4(cmpf,reg) "fcomp%0\nfstsw ax\nsahf\njp %a\njbe %a\n\n" |
stmt: GTF4(cmpf,reg) "fcomp%0\nfstsw ax\nsahf\njp %a\njb %a\n" |
stmt: LEF4(cmpf,reg) "fcomp%0\nfstsw ax\nsahf\njp %a\njae %a\n\n" |
stmt: LTF4(cmpf,reg) "fcomp%0\nfstsw ax\nsahf\njp %a\nja %a\n" |
stmt: NEF4(cmpf,reg) "fcomp%0\nfstsw ax\nsahf\njp %a\njne %a\n" |
reg: CALLI4(addrj) "call %0\nadd esp,%a\n" |
reg: CALLU4(addrj) "call %0\nadd esp,%a\n" |
reg: CALLP4(addrj) "call %0\nadd esp,%a\n" |
stmt: CALLV(addrj) "call %0\nadd esp,%a\n" |
reg: CALLF4(addrj) "call %0\nadd esp,%a\n" |
reg: CALLF8(addrj) "call %0\nadd esp,%a\n" |
stmt: CALLF4(addrj) "call %0\nadd esp,%a\nfstp\n" |
stmt: CALLF8(addrj) "call %0\nadd esp,%a\nfstp\n" |
|
stmt: RETI4(reg) "# ret\n" |
stmt: RETU4(reg) "# ret\n" |
stmt: RETP4(reg) "# ret\n" |
stmt: RETF4(reg) "# ret\n" |
stmt: RETF8(reg) "# ret\n" |
%% |
static void progbeg(int argc, char *argv[]) { |
int i; |
|
{ |
union { |
char c; |
int i; |
} u; |
u.i = 0; |
u.c = 1; |
swap = ((int)(u.i == 1)) != IR->little_endian; |
} |
parseflags(argc, argv); |
intreg[EAX] = mkreg("eax", EAX, 1, IREG); |
intreg[EDX] = mkreg("edx", EDX, 1, IREG); |
intreg[ECX] = mkreg("ecx", ECX, 1, IREG); |
intreg[EBX] = mkreg("ebx", EBX, 1, IREG); |
intreg[ESI] = mkreg("esi", ESI, 1, IREG); |
intreg[EDI] = mkreg("edi", EDI, 1, IREG); |
|
shortreg[EAX] = mkreg("ax", EAX, 1, IREG); |
shortreg[ECX] = mkreg("cx", ECX, 1, IREG); |
shortreg[EDX] = mkreg("dx", EDX, 1, IREG); |
shortreg[EBX] = mkreg("bx", EBX, 1, IREG); |
shortreg[ESI] = mkreg("si", ESI, 1, IREG); |
shortreg[EDI] = mkreg("di", EDI, 1, IREG); |
|
charreg[EAX] = mkreg("al", EAX, 1, IREG); |
charreg[ECX] = mkreg("cl", ECX, 1, IREG); |
charreg[EDX] = mkreg("dl", EDX, 1, IREG); |
charreg[EBX] = mkreg("bl", EBX, 1, IREG); |
for (i = 0; i < 8; i++) |
fltreg[i] = mkreg("%d", i, 0, FREG); |
charregw = mkwildcard(charreg); |
shortregw = mkwildcard(shortreg); |
intregw = mkwildcard(intreg); |
fltregw = mkwildcard(fltreg); |
|
tmask[IREG] = (1<<EDI) | (1<<ESI) | (1<<EBX) |
| (1<<EDX) | (1<<ECX) | (1<<EAX); |
vmask[IREG] = 0; |
tmask[FREG] = 0xff; |
vmask[FREG] = 0; |
print(".486\n"); |
print(".model flat\n"); |
print("extrn __fltused:near\n"); |
print("extrn __ftol:near\n"); |
cseg = 0; |
quo = mkreg("eax", EAX, 1, IREG); |
quo->x.regnode->mask |= 1<<EDX; |
rem = mkreg("edx", EDX, 1, IREG); |
rem->x.regnode->mask |= 1<<EAX; |
} |
static Symbol rmap(int opk) { |
switch (optype(opk)) { |
case B: case P: |
return intregw; |
case I: case U: |
if (opsize(opk) == 1) |
return charregw; |
else if (opsize(opk) == 2) |
return shortregw; |
else |
return intregw; |
case F: |
return fltregw; |
default: |
return 0; |
} |
} |
static void segment(int n) { |
if (n == cseg) |
return; |
if (cseg == CODE || cseg == LIT) |
print("_TEXT ends\n"); |
else if (cseg == DATA || cseg == BSS) |
print("_DATA ends\n"); |
cseg = n; |
if (cseg == CODE || cseg == LIT) |
print("_TEXT segment\n"); |
else if (cseg == DATA || cseg == BSS) |
print("_DATA segment\n"); |
} |
static void progend(void) { |
segment(0); |
print("end\n"); |
} |
static void target(Node p) { |
assert(p); |
switch (specific(p->op)) { |
case MUL+U: |
setreg(p, quo); |
rtarget(p, 0, intreg[EAX]); |
break; |
case DIV+I: case DIV+U: |
setreg(p, quo); |
rtarget(p, 0, quo); |
break; |
case MOD+I: case MOD+U: |
setreg(p, rem); |
rtarget(p, 0, quo); |
break; |
case ASGN+B: |
rtarget(p, 0, intreg[EDI]); |
rtarget(p->kids[1], 0, intreg[ESI]); |
break; |
case ARG+B: |
rtarget(p->kids[0], 0, intreg[ESI]); |
break; |
case CVF+I: |
setreg(p, intreg[EAX]); |
break; |
case CALL+I: case CALL+U: case CALL+P: case CALL+V: |
setreg(p, intreg[EAX]); |
break; |
case RET+I: case RET+U: case RET+P: |
rtarget(p, 0, intreg[EAX]); |
break; |
} |
} |
|
static void clobber(Node p) { |
static int nstack = 0; |
|
assert(p); |
nstack = ckstack(p, nstack); |
switch (specific(p->op)) { |
case RSH+I: case RSH+U: case LSH+I: case LSH+U: |
if (generic(p->kids[1]->op) != CNST |
&& !( generic(p->kids[1]->op) == INDIR |
&& specific(p->kids[1]->kids[0]->op) == VREG+P |
&& p->kids[1]->syms[RX]->u.t.cse |
&& generic(p->kids[1]->syms[RX]->u.t.cse->op) == CNST |
)) { |
spill(1<<ECX, 1, p); |
} |
break; |
case ASGN+B: case ARG+B: |
spill(1<<ECX | 1<<ESI | 1<<EDI, IREG, p); |
break; |
case EQ+F: case LE+F: case GE+F: case LT+F: case GT+F: case NE+F: |
spill(1<<EAX, IREG, p); |
if (specific(p->op) == EQ+F) |
p->syms[1] = findlabel(genlabel(1)); |
break; |
case CALL+F: |
spill(1<<EDX | 1<<EAX | 1<<ECX, IREG, p); |
break; |
case CALL+I: case CALL+U: case CALL+P: case CALL+V: |
spill(1<<EDX | 1<<ECX, IREG, p); |
break; |
} |
} |
#define isfp(p) (optype((p)->op)==F) |
|
int ckstack(Node p, int n) { |
int i; |
|
for (i = 0; i < NELEMS(p->x.kids) && p->x.kids[i]; i++) |
if (isfp(p->x.kids[i])) |
n--; |
if (isfp(p) && p->count > 0) |
n++; |
if (n > 8) |
error("expression too complicated\n"); |
debug(fprint(stderr, "(ckstack(%x)=%d)\n", p, n)); |
assert(n >= 0); |
return n; |
} |
int memop(Node p) { |
assert(p); |
assert(generic(p->op) == ASGN); |
assert(p->kids[0]); |
assert(p->kids[1]); |
if (generic(p->kids[1]->kids[0]->op) == INDIR |
&& sametree(p->kids[0], p->kids[1]->kids[0]->kids[0])) |
return 3; |
else |
return LBURG_MAX; |
} |
int sametree(Node p, Node q) { |
return p == NULL && q == NULL |
|| p && q && p->op == q->op && p->syms[0] == q->syms[0] |
&& sametree(p->kids[0], q->kids[0]) |
&& sametree(p->kids[1], q->kids[1]); |
} |
static void emit2(Node p) { |
int op = specific(p->op); |
#define preg(f) ((f)[getregnum(p->x.kids[0])]->x.name) |
|
if (op == CVI+I && opsize(p->op) == 4 && opsize(p->x.kids[0]->op) == 1) |
print("movsx %s,%s\n", p->syms[RX]->x.name |
, preg(charreg)); |
else if (op == CVI+U && opsize(p->op) == 4 && opsize(p->x.kids[0]->op) == 1) |
print("movsx %s,%s\n", p->syms[RX]->x.name |
, preg(charreg)); |
else if (op == CVI+I && opsize(p->op) == 4 && opsize(p->x.kids[0]->op) == 2) |
print("movsx %s,%s\n", p->syms[RX]->x.name |
, preg(shortreg)); |
else if (op == CVI+U && opsize(p->op) == 4 && opsize(p->x.kids[0]->op) == 2) |
print("movsx %s,%s\n", p->syms[RX]->x.name |
, preg(shortreg)); |
|
else if (op == CVU+I && opsize(p->op) == 4 && opsize(p->x.kids[0]->op) == 1) |
print("movzx %s,%s\n", p->syms[RX]->x.name |
, preg(charreg)); |
else if (op == CVU+U && opsize(p->op) == 4 && opsize(p->x.kids[0]->op) == 1) |
print("movzx %s,%s\n", p->syms[RX]->x.name |
, preg(charreg)); |
else if (op == CVU+I && opsize(p->op) == 4 && opsize(p->x.kids[0]->op) == 2) |
print("movzx %s,%s\n", p->syms[RX]->x.name |
, preg(shortreg)); |
else if (op == CVU+U && opsize(p->op) == 4 && opsize(p->x.kids[0]->op) == 2) |
print("movzx %s,%s\n", p->syms[RX]->x.name |
, preg(shortreg)); |
else if (generic(op) == CVI || generic(op) == CVU || generic(op) == LOAD) { |
char *dst = intreg[getregnum(p)]->x.name; |
char *src = preg(intreg); |
assert(opsize(p->op) <= opsize(p->x.kids[0]->op)); |
if (dst != src) |
print("mov %s,%s\n", dst, src); |
} |
else if (op == ARG+B) |
print("sub esp,%d\nmov edi,esp\nmov ecx,%d\nrep movsb\n", |
roundup(p->syms[0]->u.c.v.i, 4), p->syms[0]->u.c.v.i); |
} |
|
static void doarg(Node p) { |
assert(p && p->syms[0]); |
mkactual(4, p->syms[0]->u.c.v.i); |
} |
static void blkfetch(int k, int off, int reg, int tmp) {} |
static void blkstore(int k, int off, int reg, int tmp) {} |
static void blkloop(int dreg, int doff, int sreg, int soff, |
int size, int tmps[]) {} |
static void local(Symbol p) { |
if (isfloat(p->type)) |
p->sclass = AUTO; |
if (askregvar(p, (*IR->x.rmap)(ttob(p->type))) == 0) { |
assert(p->sclass == AUTO); |
offset = roundup(offset + p->type->size, |
p->type->align < 4 ? 4 : p->type->align); |
p->x.offset = -offset; |
p->x.name = stringd(-offset); |
} |
} |
static void function(Symbol f, Symbol caller[], Symbol callee[], int n) { |
int i; |
|
print("%s:\n", f->x.name); |
print("push ebx\n"); |
print("push esi\n"); |
print("push edi\n"); |
print("push ebp\n"); |
print("mov ebp,esp\n"); |
usedmask[0] = usedmask[1] = 0; |
freemask[0] = freemask[1] = ~(unsigned)0; |
offset = 16 + 4; |
for (i = 0; callee[i]; i++) { |
Symbol p = callee[i]; |
Symbol q = caller[i]; |
assert(q); |
p->x.offset = q->x.offset = offset; |
p->x.name = q->x.name = stringf("%d", p->x.offset); |
p->sclass = q->sclass = AUTO; |
offset += roundup(q->type->size, 4); |
} |
assert(caller[i] == 0); |
offset = maxoffset = 0; |
gencode(caller, callee); |
framesize = roundup(maxoffset, 4); |
if (framesize >= 4096) |
print("mov eax,%d\ncall __chkstk\n", framesize); |
else if (framesize > 0) |
print("sub esp,%d\n", framesize); |
emitcode(); |
print("mov esp,ebp\n"); |
print("pop ebp\n"); |
print("pop edi\n"); |
print("pop esi\n"); |
print("pop ebx\n"); |
print("ret\n"); |
if (framesize >= 4096) { |
int oldseg = cseg; |
segment(0); |
print("extrn __chkstk:near\n"); |
segment(oldseg); |
} |
} |
static void defsymbol(Symbol p) { |
if (p->scope >= LOCAL && p->sclass == STATIC) |
p->x.name = stringf("L%d", genlabel(1)); |
else if (p->generated) |
p->x.name = stringf("L%s", p->name); |
else if (p->scope == GLOBAL || p->sclass == EXTERN) |
p->x.name = stringf("_%s", p->name); |
else if (p->scope == CONSTANTS |
&& (isint(p->type) || isptr(p->type)) |
&& p->name[0] == '0' && p->name[1] == 'x') |
p->x.name = stringf("0%sH", &p->name[2]); |
else |
p->x.name = p->name; |
} |
static void address(Symbol q, Symbol p, long n) { |
if (p->scope == GLOBAL |
|| p->sclass == STATIC || p->sclass == EXTERN) |
q->x.name = stringf("%s%s%D", |
p->x.name, n >= 0 ? "+" : "", n); |
else { |
assert(n <= INT_MAX && n >= INT_MIN); |
q->x.offset = p->x.offset + n; |
q->x.name = stringd(q->x.offset); |
} |
} |
static void defconst(int suffix, int size, Value v) { |
if (suffix == I && size == 1) |
print("db %d\n", v.u); |
else if (suffix == I && size == 2) |
print("dw %d\n", v.i); |
else if (suffix == I && size == 4) |
print("dd %d\n", v.i); |
else if (suffix == U && size == 1) |
print("db 0%xH\n", (unsigned)((unsigned char)v.u)); |
else if (suffix == U && size == 2) |
print("dw 0%xH\n", (unsigned)((unsigned short)v.u)); |
else if (suffix == U && size == 4) |
print("dd 0%xH\n", (unsigned)v.u); |
else if (suffix == P && size == 4) |
print("dd 0%xH\n", (unsigned)v.p); |
else if (suffix == F && size == 4) { |
float f = v.d; |
print("dd 0%xH\n", *(unsigned *)&f); |
} |
else if (suffix == F && size == 8) { |
double d = v.d; |
unsigned *p = (unsigned *)&d; |
print("dd 0%xH\ndd 0%xH\n", p[swap], p[!swap]); |
} |
else assert(0); |
} |
static void defaddress(Symbol p) { |
print("dd %s\n", p->x.name); |
} |
static void defstring(int n, char *str) { |
char *s; |
|
for (s = str; s < str + n; s++) |
print("db %d\n", (*s)&0377); |
} |
static void export(Symbol p) { |
print("public %s\n", p->x.name); |
} |
static void import(Symbol p) { |
int oldseg = cseg; |
|
if (p->ref > 0) { |
segment(0); |
print("extrn %s:near\n", p->x.name); |
segment(oldseg); |
} |
} |
static void global(Symbol p) { |
print("align %d\n", |
p->type->align > 4 ? 4 : p->type->align); |
print("%s label byte\n", p->x.name); |
} |
static void space(int n) { |
print("db %d dup (0)\n", n); |
} |
Interface x86IR = { |
1, 1, 0, /* char */ |
2, 2, 0, /* short */ |
4, 4, 0, /* int */ |
4, 4, 0, /* long */ |
4, 4, 0, /* long long */ |
4, 4, 1, /* float */ |
8, 4, 1, /* double */ |
8, 4, 1, /* long double */ |
4, 4, 0, /* T * */ |
0, 1, 0, /* struct */ |
1, /* little_endian */ |
0, /* mulops_calls */ |
0, /* wants_callb */ |
1, /* wants_argb */ |
0, /* left_to_right */ |
0, /* wants_dag */ |
0, /* unsigned_char */ |
address, |
blockbeg, |
blockend, |
defaddress, |
defconst, |
defstring, |
defsymbol, |
emit, |
export, |
function, |
gen, |
global, |
import, |
local, |
progbeg, |
progend, |
segment, |
space, |
0, 0, 0, 0, 0, 0, 0, |
{1, rmap, |
blkfetch, blkstore, blkloop, |
_label, |
_rule, |
_nts, |
_kids, |
_string, |
_templates, |
_isinstruction, |
_ntname, |
emit2, |
doarg, |
target, |
clobber, |
} |
}; |
static char rcsid[] = "$Id: x86.md,v 1.1 2002/08/28 23:12:48 drh Exp $"; |
/init.c
0,0 → 1,319
#include "c.h" |
|
static char rcsid[] = "$Id: init.c,v 1.1 2002/08/28 23:12:43 drh Exp $"; |
|
static int curseg; /* current segment */ |
|
/* defpointer - initialize a pointer to p or to 0 if p==0 */ |
void defpointer(Symbol p) { |
if (p) { |
(*IR->defaddress)(p); |
p->ref++; |
} else { |
static Value v; |
(*IR->defconst)(P, voidptype->size, v); |
} |
} |
|
/* genconst - generate/check constant expression e; return size */ |
static int genconst(Tree e, int def) { |
for (;;) |
switch (generic(e->op)) { |
case ADDRG: |
if (def) |
(*IR->defaddress)(e->u.sym); |
return e->type->size; |
case CNST: |
if (e->op == CNST+P && isarray(e->type)) { |
e = cvtconst(e); |
continue; |
} |
if (def) |
(*IR->defconst)(e->type->op, e->type->size, e->u.v); |
return e->type->size; |
case RIGHT: |
assert(e->kids[0] || e->kids[1]); |
if (e->kids[1] && e->kids[0]) |
error("initializer must be constant\n"); |
e = e->kids[1] ? e->kids[1] : e->kids[0]; |
continue; |
case CVP: |
if (isarith(e->type)) |
error("cast from `%t' to `%t' is illegal in constant expressions\n", |
e->kids[0]->type, e->type); |
/* fall thru */ |
case CVI: case CVU: case CVF: |
e = e->kids[0]; |
continue; |
default: |
error("initializer must be constant\n"); |
if (def) |
genconst(consttree(0, inttype), def); |
return inttype->size; |
} |
} |
|
/* initvalue - evaluate a constant expression for a value of integer type ty */ |
static Tree initvalue(Type ty) { |
Type aty; |
Tree e; |
|
needconst++; |
e = expr1(0); |
if ((aty = assign(ty, e)) != NULL) |
e = cast(e, aty); |
else { |
error("invalid initialization type; found `%t' expected `%t'\n", |
e->type, ty); |
e = retype(consttree(0, inttype), ty); |
} |
needconst--; |
if (generic(e->op) != CNST) { |
error("initializer must be constant\n"); |
e = retype(consttree(0, inttype), ty); |
} |
return e; |
} |
|
/* initarray - initialize array of ty of <= len bytes; if len == 0, go to } */ |
static int initarray(int len, Type ty, int lev) { |
int n = 0; |
|
do { |
initializer(ty, lev); |
n += ty->size; |
if (len > 0 && n >= len || t != ',') |
break; |
t = gettok(); |
} while (t != '}'); |
return n; |
} |
|
/* initchar - initialize array of <= len ty characters; if len == 0, go to } */ |
static int initchar(int len, Type ty) { |
int n = 0; |
char buf[16], *s = buf; |
|
do { |
*s++ = initvalue(ty)->u.v.i; |
if (++n%inttype->size == 0) { |
(*IR->defstring)(inttype->size, buf); |
s = buf; |
} |
if (len > 0 && n >= len || t != ',') |
break; |
t = gettok(); |
} while (t != '}'); |
if (s > buf) |
(*IR->defstring)(s - buf, buf); |
return n; |
} |
|
/* initend - finish off an initialization at level lev; accepts trailing comma */ |
static void initend(int lev, char follow[]) { |
if (lev == 0 && t == ',') |
t = gettok(); |
test('}', follow); |
} |
|
/* initfields - initialize <= an unsigned's worth of bit fields in fields p to q */ |
static int initfields(Field p, Field q) { |
unsigned int bits = 0; |
int i, n = 0; |
|
do { |
i = initvalue(inttype)->u.v.i; |
if (fieldsize(p) < 8*p->type->size) { |
if (p->type == inttype && |
(i < -(int)(fieldmask(p)>>1)-1 || i > (int)(fieldmask(p)>>1)) |
|| p->type == unsignedtype && (i&~fieldmask(p)) != 0) |
warning("initializer exceeds bit-field width\n"); |
i &= fieldmask(p); |
} |
bits |= i<<fieldright(p); |
if (IR->little_endian) { |
if (fieldsize(p) + fieldright(p) > n) |
n = fieldsize(p) + fieldright(p); |
} else { |
if (fieldsize(p) + fieldleft(p) > n) |
n = fieldsize(p) + fieldleft(p); |
} |
if (p->link == q) |
break; |
p = p->link; |
} while (t == ',' && (t = gettok()) != 0); |
n = (n + 7)/8; |
for (i = 0; i < n; i++) { |
Value v; |
if (IR->little_endian) { |
v.u = (unsigned char)bits; |
bits >>= 8; |
} else { /* a big endian */ |
v.u = (unsigned char)(bits>>(8*(unsignedtype->size - 1))); |
bits <<= 8; |
} |
(*IR->defconst)(U, unsignedchar->size, v); |
} |
return n; |
} |
|
/* initstruct - initialize a struct ty of <= len bytes; if len == 0, go to } */ |
static int initstruct(int len, Type ty, int lev) { |
int a, n = 0; |
Field p = ty->u.sym->u.s.flist; |
|
do { |
if (p->offset > n) { |
(*IR->space)(p->offset - n); |
n += p->offset - n; |
} |
if (p->lsb) { |
Field q = p; |
while (q->link && q->link->offset == p->offset) |
q = q->link; |
n += initfields(p, q->link); |
p = q; |
} else { |
initializer(p->type, lev); |
n += p->type->size; |
} |
if (p->link) { |
p = p->link; |
a = p->type->align; |
} else |
a = ty->align; |
if (a && n%a) { |
(*IR->space)(a - n%a); |
n = roundup(n, a); |
} |
if (len > 0 && n >= len || t != ',') |
break; |
t = gettok(); |
} while (t != '}'); |
return n; |
} |
|
/* initializer - constexpr | { constexpr ( , constexpr )* [ , ] } */ |
Type initializer(Type ty, int lev) { |
int n = 0; |
Tree e; |
Type aty = NULL; |
static char follow[] = { IF, CHAR, STATIC, 0 }; |
|
ty = unqual(ty); |
if (isscalar(ty)) { |
needconst++; |
if (t == '{') { |
t = gettok(); |
e = expr1(0); |
initend(lev, follow); |
} else |
e = expr1(0); |
e = pointer(e); |
if ((aty = assign(ty, e)) != NULL) |
e = cast(e, aty); |
else |
error("invalid initialization type; found `%t' expected `%t'\n", |
e->type, ty); |
n = genconst(e, 1); |
deallocate(STMT); |
needconst--; |
} |
if ((isunion(ty) || isstruct(ty)) && ty->size == 0) { |
static char follow[] = { CHAR, STATIC, 0 }; |
error("cannot initialize undefined `%t'\n", ty); |
skipto(';', follow); |
return ty; |
} else if (isunion(ty)) { |
if (t == '{') { |
t = gettok(); |
n = initstruct(ty->u.sym->u.s.flist->type->size, ty, lev + 1); |
initend(lev, follow); |
} else { |
if (lev == 0) |
error("missing { in initialization of `%t'\n", ty); |
n = initstruct(ty->u.sym->u.s.flist->type->size, ty, lev + 1); |
} |
} else if (isstruct(ty)) { |
if (t == '{') { |
t = gettok(); |
n = initstruct(0, ty, lev + 1); |
test('}', follow); |
} else if (lev > 0) |
n = initstruct(ty->size, ty, lev + 1); |
else { |
error("missing { in initialization of `%t'\n", ty); |
n = initstruct(ty->u.sym->u.s.flist->type->size, ty, lev + 1); |
} |
} |
if (isarray(ty)) |
aty = unqual(ty->type); |
if (isarray(ty) && ischar(aty)) { |
if (t == SCON) { |
if (ty->size > 0 && ty->size == tsym->type->size - 1) |
tsym->type = array(chartype, ty->size, 0); |
n = tsym->type->size; |
(*IR->defstring)(tsym->type->size, tsym->u.c.v.p); |
t = gettok(); |
} else if (t == '{') { |
t = gettok(); |
if (t == SCON) { |
ty = initializer(ty, lev + 1); |
initend(lev, follow); |
return ty; |
} |
n = initchar(0, aty); |
test('}', follow); |
} else if (lev > 0 && ty->size > 0) |
n = initchar(ty->size, aty); |
else { /* eg, char c[] = 0; */ |
error("missing { in initialization of `%t'\n", ty); |
n = initchar(1, aty); |
} |
} else if (isarray(ty)) { |
if (t == SCON && aty == widechar) { |
int i; |
unsigned int *s = tsym->u.c.v.p; |
if (ty->size > 0 && ty->size == tsym->type->size - widechar->size) |
tsym->type = array(widechar, ty->size/widechar->size, 0); |
n = tsym->type->size; |
for (i = 0; i < n; i += widechar->size) { |
Value v; |
v.u = *s++; |
(*IR->defconst)(widechar->op, widechar->size, v); |
} |
t = gettok(); |
} else if (t == '{') { |
t = gettok(); |
if (t == SCON && aty == widechar) { |
ty = initializer(ty, lev + 1); |
initend(lev, follow); |
return ty; |
} |
n = initarray(0, aty, lev + 1); |
test('}', follow); |
} else if (lev > 0 && ty->size > 0) |
n = initarray(ty->size, aty, lev + 1); |
else { |
error("missing { in initialization of `%t'\n", ty); |
n = initarray(aty->size, aty, lev + 1); |
} |
} |
if (ty->size) { |
if (n > ty->size) |
error("too many initializers\n"); |
else if (n < ty->size) |
(*IR->space)(ty->size - n); |
} else if (isarray(ty) && ty->type->size > 0) |
ty = array(ty->type, n/ty->type->size, 0); |
else |
ty->size = n; |
return ty; |
} |
|
/* swtoseg - switch to segment seg, if necessary */ |
void swtoseg(int seg) { |
if (curseg != seg) |
(*IR->segment)(seg); |
curseg = seg; |
} |
/types.c
0,0 → 1,755
#include "c.h" |
#include <float.h> |
|
static char rcsid[] = "$Id: types.c,v 1.1 2002/08/28 23:12:47 drh Exp $"; |
|
static Field isfield(const char *, Field); |
static Type type(int, Type, int, int, void *); |
|
static struct entry { |
struct type type; |
struct entry *link; |
} *typetable[128]; |
static int maxlevel; |
|
static Symbol pointersym; |
|
Type chartype; /* char */ |
Type doubletype; /* double */ |
Type floattype; /* float */ |
Type inttype; /* signed int */ |
Type longdouble; /* long double */ |
Type longtype; /* long */ |
Type longlong; /* long long */ |
Type shorttype; /* signed short int */ |
Type signedchar; /* signed char */ |
Type unsignedchar; /* unsigned char */ |
Type unsignedlong; /* unsigned long int */ |
Type unsignedlonglong; /* unsigned long long int */ |
Type unsignedshort; /* unsigned short int */ |
Type unsignedtype; /* unsigned int */ |
Type funcptype; /* void (*)() */ |
Type charptype; /* char* */ |
Type voidptype; /* void* */ |
Type voidtype; /* basic types: void */ |
Type unsignedptr; /* unsigned type to hold void* */ |
Type signedptr; /* signed type to hold void* */ |
Type widechar; /* unsigned type that represents wchar_t */ |
|
static Type xxinit(int op, char *name, Metrics m) { |
Symbol p = install(string(name), &types, GLOBAL, PERM); |
Type ty = type(op, 0, m.size, m.align, p); |
|
assert(ty->align == 0 || ty->size%ty->align == 0); |
p->type = ty; |
p->addressed = m.outofline; |
switch (ty->op) { |
case INT: |
p->u.limits.max.i = ones(8*ty->size)>>1; |
p->u.limits.min.i = -p->u.limits.max.i - 1; |
break; |
case UNSIGNED: |
p->u.limits.max.u = ones(8*ty->size); |
p->u.limits.min.u = 0; |
break; |
case FLOAT: |
if (ty->size == sizeof (float)) |
p->u.limits.max.d = FLT_MAX; |
else if (ty->size == sizeof (double)) |
p->u.limits.max.d = DBL_MAX; |
else |
p->u.limits.max.d = LDBL_MAX; |
p->u.limits.min.d = -p->u.limits.max.d; |
break; |
default: assert(0); |
} |
return ty; |
} |
static Type type(int op, Type ty, int size, int align, void *sym) { |
unsigned h = (op^((unsigned long)ty>>3)) |
&(NELEMS(typetable)-1); |
struct entry *tn; |
|
if (op != FUNCTION && (op != ARRAY || size > 0)) |
for (tn = typetable[h]; tn; tn = tn->link) |
if (tn->type.op == op && tn->type.type == ty |
&& tn->type.size == size && tn->type.align == align |
&& tn->type.u.sym == sym) |
return &tn->type; |
NEW0(tn, PERM); |
tn->type.op = op; |
tn->type.type = ty; |
tn->type.size = size; |
tn->type.align = align; |
tn->type.u.sym = sym; |
tn->link = typetable[h]; |
typetable[h] = tn; |
return &tn->type; |
} |
void type_init(int argc, char *argv[]) { |
static int inited; |
int i; |
|
if (inited) |
return; |
inited = 1; |
if (!IR) |
return; |
for (i = 1; i < argc; i++) { |
int size, align, outofline; |
if (strncmp(argv[i], "-unsigned_char=", 15) == 0) |
IR->unsigned_char = argv[i][15] - '0'; |
#define xx(name) \ |
else if (sscanf(argv[i], "-" #name "=%d,%d,%d", &size, &align, &outofline) == 3) { \ |
IR->name.size = size; IR->name.align = align; \ |
IR->name.outofline = outofline; } |
xx(charmetric) |
xx(shortmetric) |
xx(intmetric) |
xx(longmetric) |
xx(longlongmetric) |
xx(floatmetric) |
xx(doublemetric) |
xx(longdoublemetric) |
xx(ptrmetric) |
xx(structmetric) |
#undef xx |
} |
#define xx(v,name,op,metrics) v=xxinit(op,name,IR->metrics) |
xx(chartype, "char", IR->unsigned_char ? UNSIGNED : INT,charmetric); |
xx(doubletype, "double", FLOAT, doublemetric); |
xx(floattype, "float", FLOAT, floatmetric); |
xx(inttype, "int", INT, intmetric); |
xx(longdouble, "long double", FLOAT, longdoublemetric); |
xx(longtype, "long int", INT, longmetric); |
xx(longlong, "long long int", INT, longlongmetric); |
xx(shorttype, "short", INT, shortmetric); |
xx(signedchar, "signed char", INT, charmetric); |
xx(unsignedchar, "unsigned char", UNSIGNED,charmetric); |
xx(unsignedlong, "unsigned long", UNSIGNED,longmetric); |
xx(unsignedshort, "unsigned short", UNSIGNED,shortmetric); |
xx(unsignedtype, "unsigned int", UNSIGNED,intmetric); |
xx(unsignedlonglong,"unsigned long long",UNSIGNED,longlongmetric); |
#undef xx |
{ |
Symbol p; |
p = install(string("void"), &types, GLOBAL, PERM); |
voidtype = type(VOID, NULL, 0, 0, p); |
p->type = voidtype; |
} |
pointersym = install(string("T*"), &types, GLOBAL, PERM); |
pointersym->addressed = IR->ptrmetric.outofline; |
pointersym->u.limits.max.p = (void*)ones(8*IR->ptrmetric.size); |
pointersym->u.limits.min.p = 0; |
voidptype = ptr(voidtype); |
funcptype = ptr(func(voidtype, NULL, 1)); |
charptype = ptr(chartype); |
#define xx(v,t) if (v==NULL && t->size==voidptype->size && t->align==voidptype->align) v=t |
xx(unsignedptr,unsignedshort); |
xx(unsignedptr,unsignedtype); |
xx(unsignedptr,unsignedlong); |
xx(unsignedptr,unsignedlonglong); |
if (unsignedptr == NULL) |
unsignedptr = type(UNSIGNED, NULL, voidptype->size, voidptype->align, voidptype->u.sym); |
xx(signedptr,shorttype); |
xx(signedptr,inttype); |
xx(signedptr,longtype); |
xx(signedptr,longlong); |
if (signedptr == NULL) |
signedptr = type(INT, NULL, voidptype->size, voidptype->align, voidptype->u.sym); |
#undef xx |
widechar = unsignedshort; |
for (i = 0; i < argc; i++) { |
#define xx(name,type) \ |
if (strcmp(argv[i], "-wchar_t=" #name) == 0) \ |
widechar = type; |
xx(unsigned_char,unsignedchar) |
xx(unsigned_int,unsignedtype) |
xx(unsigned_short,unsignedshort) |
} |
#undef xx |
} |
void rmtypes(int lev) { |
if (maxlevel >= lev) { |
int i; |
maxlevel = 0; |
for (i = 0; i < NELEMS(typetable); i++) { |
struct entry *tn, **tq = &typetable[i]; |
while ((tn = *tq) != NULL) |
if (tn->type.op == FUNCTION) |
tq = &tn->link; |
else if (tn->type.u.sym && tn->type.u.sym->scope >= lev) |
*tq = tn->link; |
else { |
if (tn->type.u.sym && tn->type.u.sym->scope > maxlevel) |
maxlevel = tn->type.u.sym->scope; |
tq = &tn->link; |
} |
|
} |
} |
} |
Type ptr(Type ty) { |
return type(POINTER, ty, IR->ptrmetric.size, |
IR->ptrmetric.align, pointersym); |
} |
Type deref(Type ty) { |
if (isptr(ty)) |
ty = ty->type; |
else |
error("type error: %s\n", "pointer expected"); |
return isenum(ty) ? unqual(ty)->type : ty; |
} |
Type array(Type ty, int n, int a) { |
assert(ty); |
if (isfunc(ty)) { |
error("illegal type `array of %t'\n", ty); |
return array(inttype, n, 0); |
} |
if (isarray(ty) && ty->size == 0) |
error("missing array size\n"); |
if (ty->size == 0) { |
if (unqual(ty) == voidtype) |
error("illegal type `array of %t'\n", ty); |
else if (Aflag >= 2) |
warning("declaring type array of %t' is undefined\n", ty); |
|
} else if (n > INT_MAX/ty->size) { |
error("size of `array of %t' exceeds %d bytes\n", |
ty, INT_MAX); |
n = 1; |
} |
return type(ARRAY, ty, n*ty->size, |
a ? a : ty->align, NULL); |
} |
Type atop(Type ty) { |
if (isarray(ty)) |
return ptr(ty->type); |
error("type error: %s\n", "array expected"); |
return ptr(ty); |
} |
Type qual(int op, Type ty) { |
if (isarray(ty)) |
ty = type(ARRAY, qual(op, ty->type), ty->size, |
ty->align, NULL); |
else if (isfunc(ty)) |
warning("qualified function type ignored\n"); |
else if (isconst(ty) && op == CONST |
|| isvolatile(ty) && op == VOLATILE) |
error("illegal type `%k %t'\n", op, ty); |
else { |
if (isqual(ty)) { |
op += ty->op; |
ty = ty->type; |
} |
ty = type(op, ty, ty->size, ty->align, NULL); |
} |
return ty; |
} |
Type func(Type ty, Type *proto, int style) { |
if (ty && (isarray(ty) || isfunc(ty))) |
error("illegal return type `%t'\n", ty); |
ty = type(FUNCTION, ty, 0, 0, NULL); |
ty->u.f.proto = proto; |
ty->u.f.oldstyle = style; |
return ty; |
} |
Type freturn(Type ty) { |
if (isfunc(ty)) |
return ty->type; |
error("type error: %s\n", "function expected"); |
return inttype; |
} |
int variadic(Type ty) { |
if (isfunc(ty) && ty->u.f.proto) { |
int i; |
for (i = 0; ty->u.f.proto[i]; i++) |
; |
return i > 1 && ty->u.f.proto[i-1] == voidtype; |
} |
return 0; |
} |
Type newstruct(int op, char *tag) { |
Symbol p; |
|
assert(tag); |
if (*tag == 0) |
tag = stringd(genlabel(1)); |
else |
if ((p = lookup(tag, types)) != NULL && (p->scope == level |
|| p->scope == PARAM && level == PARAM+1)) { |
if (p->type->op == op && !p->defined) |
return p->type; |
error("redefinition of `%s' previously defined at %w\n", |
p->name, &p->src); |
} |
p = install(tag, &types, level, PERM); |
p->type = type(op, NULL, 0, 0, p); |
if (p->scope > maxlevel) |
maxlevel = p->scope; |
p->src = src; |
return p->type; |
} |
Field newfield(char *name, Type ty, Type fty) { |
Field p, *q = &ty->u.sym->u.s.flist; |
|
if (name == NULL) |
name = stringd(genlabel(1)); |
for (p = *q; p; q = &p->link, p = *q) |
if (p->name == name) |
error("duplicate field name `%s' in `%t'\n", |
name, ty); |
NEW0(p, PERM); |
*q = p; |
p->name = name; |
p->type = fty; |
if (xref) { /* omit */ |
if (ty->u.sym->u.s.ftab == NULL) /* omit */ |
ty->u.sym->u.s.ftab = table(NULL, level); /* omit */ |
install(name, &ty->u.sym->u.s.ftab, 0, PERM)->src = src;/* omit */ |
} /* omit */ |
return p; |
} |
int eqtype(Type ty1, Type ty2, int ret) { |
if (ty1 == ty2) |
return 1; |
if (ty1->op != ty2->op) |
return 0; |
switch (ty1->op) { |
case ENUM: case UNION: case STRUCT: |
case UNSIGNED: case INT: case FLOAT: |
return 0; |
case POINTER: return eqtype(ty1->type, ty2->type, 1); |
case VOLATILE: case CONST+VOLATILE: |
case CONST: return eqtype(ty1->type, ty2->type, 1); |
case ARRAY: if (eqtype(ty1->type, ty2->type, 1)) { |
if (ty1->size == ty2->size) |
return 1; |
if (ty1->size == 0 || ty2->size == 0) |
return ret; |
} |
return 0; |
case FUNCTION: if (eqtype(ty1->type, ty2->type, 1)) { |
Type *p1 = ty1->u.f.proto, *p2 = ty2->u.f.proto; |
if (p1 == p2) |
return 1; |
if (p1 && p2) { |
for ( ; *p1 && *p2; p1++, p2++) |
if (eqtype(unqual(*p1), unqual(*p2), 1) == 0) |
return 0; |
if (*p1 == NULL && *p2 == NULL) |
return 1; |
} else { |
if (variadic(p1 ? ty1 : ty2)) |
return 0; |
if (p1 == NULL) |
p1 = p2; |
for ( ; *p1; p1++) { |
Type ty = unqual(*p1); |
if (promote(ty) != (isenum(ty) ? ty->type : ty)) |
return 0; |
} |
return 1; |
} |
} |
return 0; |
} |
assert(0); return 0; |
} |
Type promote(Type ty) { |
ty = unqual(ty); |
switch (ty->op) { |
case ENUM: |
return inttype; |
case INT: |
if (ty->size < inttype->size) |
return inttype; |
break; |
case UNSIGNED: |
if (ty->size < inttype->size) |
return inttype; |
if (ty->size < unsignedtype->size) |
return unsignedtype; |
break; |
case FLOAT: |
if (ty->size < doubletype->size) |
return doubletype; |
} |
return ty; |
} |
Type signedint(Type ty) { |
if (ty->op == INT) |
return ty; |
assert(ty->op == UNSIGNED); |
#define xx(t) if (ty->size == t->size) return t |
xx(inttype); |
xx(longtype); |
xx(longlong); |
#undef xx |
assert(0); return NULL; |
} |
Type compose(Type ty1, Type ty2) { |
if (ty1 == ty2) |
return ty1; |
assert(ty1->op == ty2->op); |
switch (ty1->op) { |
case POINTER: |
return ptr(compose(ty1->type, ty2->type)); |
case CONST+VOLATILE: |
return qual(CONST, qual(VOLATILE, |
compose(ty1->type, ty2->type))); |
case CONST: case VOLATILE: |
return qual(ty1->op, compose(ty1->type, ty2->type)); |
case ARRAY: { Type ty = compose(ty1->type, ty2->type); |
if (ty1->size && (ty1->type->size && ty2->size == 0 || ty1->size == ty2->size)) |
return array(ty, ty1->size/ty1->type->size, ty1->align); |
if (ty2->size && ty2->type->size && ty1->size == 0) |
return array(ty, ty2->size/ty2->type->size, ty2->align); |
return array(ty, 0, 0); } |
case FUNCTION: { Type *p1 = ty1->u.f.proto, *p2 = ty2->u.f.proto; |
Type ty = compose(ty1->type, ty2->type); |
List tlist = NULL; |
if (p1 == NULL && p2 == NULL) |
return func(ty, NULL, 1); |
if (p1 && p2 == NULL) |
return func(ty, p1, ty1->u.f.oldstyle); |
if (p2 && p1 == NULL) |
return func(ty, p2, ty2->u.f.oldstyle); |
for ( ; *p1 && *p2; p1++, p2++) { |
Type ty = compose(unqual(*p1), unqual(*p2)); |
if (isconst(*p1) || isconst(*p2)) |
ty = qual(CONST, ty); |
if (isvolatile(*p1) || isvolatile(*p2)) |
ty = qual(VOLATILE, ty); |
tlist = append(ty, tlist); |
} |
assert(*p1 == NULL && *p2 == NULL); |
return func(ty, ltov(&tlist, PERM), 0); } |
} |
assert(0); return NULL; |
} |
int ttob(Type ty) { |
switch (ty->op) { |
case CONST: case VOLATILE: case CONST+VOLATILE: |
return ttob(ty->type); |
case VOID: case INT: case UNSIGNED: case FLOAT: |
return ty->op + sizeop(ty->size); |
case POINTER: |
return POINTER + sizeop(voidptype->size); |
case FUNCTION: |
return POINTER + sizeop(funcptype->size); |
case ARRAY: case STRUCT: case UNION: |
return STRUCT; |
case ENUM: |
return INT + sizeop(inttype->size); |
} |
assert(0); return INT; |
} |
Type btot(int op, int size) { |
#define xx(ty) if (size == (ty)->size) return ty; |
switch (optype(op)) { |
case F: |
xx(floattype); |
xx(doubletype); |
xx(longdouble); |
assert(0); return 0; |
case I: |
if (chartype->op == INT) |
xx(chartype); |
xx(signedchar); |
xx(shorttype); |
xx(inttype); |
xx(longtype); |
xx(longlong); |
assert(0); return 0; |
case U: |
if (chartype->op == UNSIGNED) |
xx(chartype); |
xx(unsignedchar); |
xx(unsignedshort); |
xx(unsignedtype); |
xx(unsignedlong); |
xx(unsignedlonglong); |
assert(0); return 0; |
case P: |
xx(voidptype); |
xx(funcptype); |
assert(0); return 0; |
} |
#undef xx |
assert(0); return 0; |
} |
int hasproto(Type ty) { |
if (ty == 0) |
return 1; |
switch (ty->op) { |
case CONST: case VOLATILE: case CONST+VOLATILE: case POINTER: |
case ARRAY: |
return hasproto(ty->type); |
case FUNCTION: |
return hasproto(ty->type) && ty->u.f.proto; |
case STRUCT: case UNION: |
case VOID: case FLOAT: case ENUM: case INT: case UNSIGNED: |
return 1; |
} |
assert(0); return 0; |
} |
/* fieldlist - construct a flat list of fields in type ty */ |
Field fieldlist(Type ty) { |
return ty->u.sym->u.s.flist; |
} |
|
/* fieldref - find field name of type ty, return entry */ |
Field fieldref(const char *name, Type ty) { |
Field p = isfield(name, unqual(ty)->u.sym->u.s.flist); |
|
if (p && xref) { |
Symbol q; |
assert(unqual(ty)->u.sym->u.s.ftab); |
q = lookup(name, unqual(ty)->u.sym->u.s.ftab); |
assert(q); |
use(q, src); |
} |
return p; |
} |
|
/* ftype - return a function type for rty function (ty,...)' */ |
Type ftype(Type rty, ...) { |
va_list ap; |
Type ty = NULL; |
List list = NULL; |
|
va_start(ap, rty); |
ty = va_arg(ap, Type); |
for ( ; ty != NULL; ty = va_arg(ap, Type)) |
list = append(ty, list); |
va_end(ap); |
return func(rty, ltov(&list, PERM), 0); |
} |
|
/* isfield - if name is a field in flist, return pointer to the field structure */ |
static Field isfield(const char *name, Field flist) { |
for ( ; flist; flist = flist->link) |
if (flist->name == name) |
break; |
return flist; |
} |
|
/* outtype - output type ty */ |
void outtype(Type ty, FILE *f) { |
switch (ty->op) { |
case CONST+VOLATILE: case CONST: case VOLATILE: |
fprint(f, "%k %t", ty->op, ty->type); |
break; |
case STRUCT: case UNION: case ENUM: |
assert(ty->u.sym); |
if (ty->size == 0) |
fprint(f, "incomplete "); |
assert(ty->u.sym->name); |
if (*ty->u.sym->name >= '1' && *ty->u.sym->name <= '9') { |
Symbol p = findtype(ty); |
if (p == 0) |
fprint(f, "%k defined at %w", ty->op, &ty->u.sym->src); |
else |
fprint(f, p->name); |
} else { |
fprint(f, "%k %s", ty->op, ty->u.sym->name); |
if (ty->size == 0) |
fprint(f, " defined at %w", &ty->u.sym->src); |
} |
break; |
case VOID: case FLOAT: case INT: case UNSIGNED: |
fprint(f, ty->u.sym->name); |
break; |
case POINTER: |
fprint(f, "pointer to %t", ty->type); |
break; |
case FUNCTION: |
fprint(f, "%t function", ty->type); |
if (ty->u.f.proto && ty->u.f.proto[0]) { |
int i; |
fprint(f, "(%t", ty->u.f.proto[0]); |
for (i = 1; ty->u.f.proto[i]; i++) |
if (ty->u.f.proto[i] == voidtype) |
fprint(f, ",..."); |
else |
fprint(f, ",%t", ty->u.f.proto[i]); |
fprint(f, ")"); |
} else if (ty->u.f.proto && ty->u.f.proto[0] == 0) |
fprint(f, "(void)"); |
|
break; |
case ARRAY: |
if (ty->size > 0 && ty->type && ty->type->size > 0) { |
fprint(f, "array %d", ty->size/ty->type->size); |
while (ty->type && isarray(ty->type) && ty->type->type->size > 0) { |
ty = ty->type; |
fprint(f, ",%d", ty->size/ty->type->size); |
} |
} else |
fprint(f, "incomplete array"); |
if (ty->type) |
fprint(f, " of %t", ty->type); |
break; |
default: assert(0); |
} |
} |
|
/* printdecl - output a C declaration for symbol p of type ty */ |
void printdecl(Symbol p, Type ty) { |
switch (p->sclass) { |
case AUTO: |
fprint(stderr, "%s;\n", typestring(ty, p->name)); |
break; |
case STATIC: case EXTERN: |
fprint(stderr, "%k %s;\n", p->sclass, typestring(ty, p->name)); |
break; |
case TYPEDEF: case ENUM: |
break; |
default: assert(0); |
} |
} |
|
/* printproto - output a prototype declaration for function p */ |
void printproto(Symbol p, Symbol callee[]) { |
if (p->type->u.f.proto) |
printdecl(p, p->type); |
else { |
int i; |
List list = 0; |
if (callee[0] == 0) |
list = append(voidtype, list); |
else |
for (i = 0; callee[i]; i++) |
list = append(callee[i]->type, list); |
printdecl(p, func(freturn(p->type), ltov(&list, PERM), 0)); |
} |
} |
|
/* prtype - print details of type ty on f with given indent */ |
static void prtype(Type ty, FILE *f, int indent, unsigned mark) { |
switch (ty->op) { |
default: |
fprint(f, "(%d %d %d [%p])", ty->op, ty->size, ty->align, ty->u.sym); |
break; |
case FLOAT: case INT: case UNSIGNED: case VOID: |
fprint(f, "(%k %d %d [\"%s\"])", ty->op, ty->size, ty->align, ty->u.sym->name); |
break; |
case CONST+VOLATILE: case CONST: case VOLATILE: case POINTER: case ARRAY: |
fprint(f, "(%k %d %d ", ty->op, ty->size, ty->align); |
prtype(ty->type, f, indent+1, mark); |
fprint(f, ")"); |
break; |
case STRUCT: case UNION: |
fprint(f, "(%k %d %d [\"%s\"]", ty->op, ty->size, ty->align, ty->u.sym->name); |
if (ty->x.marked != mark) { |
Field p; |
ty->x.marked = mark; |
for (p = ty->u.sym->u.s.flist; p; p = p->link) { |
fprint(f, "\n%I", indent+1); |
prtype(p->type, f, indent+1, mark); |
fprint(f, " %s@%d", p->name, p->offset); |
if (p->lsb) |
fprint(f, ":%d..%d", |
fieldsize(p) + fieldright(p), fieldright(p)); |
} |
fprint(f, "\n%I", indent); |
} |
fprint(f, ")"); |
break; |
case ENUM: |
fprint(f, "(%k %d %d [\"%s\"]", ty->op, ty->size, ty->align, ty->u.sym->name); |
if (ty->x.marked != mark) { |
int i; |
Symbol *p = ty->u.sym->u.idlist; |
ty->x.marked = mark; |
for (i = 0; p[i] != NULL; i++) |
fprint(f, "%I%s=%d\n", indent+1, p[i]->name, p[i]->u.value); |
} |
fprint(f, ")"); |
break; |
case FUNCTION: |
fprint(f, "(%k %d %d ", ty->op, ty->size, ty->align); |
prtype(ty->type, f, indent+1, mark); |
if (ty->u.f.proto) { |
int i; |
fprint(f, "\n%I{", indent+1); |
for (i = 0; ty->u.f.proto[i]; i++) { |
if (i > 0) |
fprint(f, "%I", indent+2); |
prtype(ty->u.f.proto[i], f, indent+2, mark); |
fprint(f, "\n"); |
} |
fprint(f, "%I}", indent+1); |
} |
fprint(f, ")"); |
break; |
} |
} |
|
/* printtype - print details of type ty on fd */ |
void printtype(Type ty, int fd) { |
static unsigned mark; |
prtype(ty, fd == 1 ? stdout : stderr, 0, ++mark); |
fprint(fd == 1 ? stdout : stderr, "\n"); |
} |
|
/* typestring - return ty as C declaration for str, which may be "" */ |
char *typestring(Type ty, char *str) { |
for ( ; ty; ty = ty->type) { |
Symbol p; |
switch (ty->op) { |
case CONST+VOLATILE: case CONST: case VOLATILE: |
if (isptr(ty->type)) |
str = stringf("%k %s", ty->op, str); |
else |
return stringf("%k %s", ty->op, typestring(ty->type, str)); |
break; |
case STRUCT: case UNION: case ENUM: |
assert(ty->u.sym); |
if ((p = findtype(ty)) != NULL) |
return *str ? stringf("%s %s", p->name, str) : p->name; |
if (*ty->u.sym->name >= '1' && *ty->u.sym->name <= '9') |
warning("unnamed %k in prototype\n", ty->op); |
if (*str) |
return stringf("%k %s %s", ty->op, ty->u.sym->name, str); |
else |
return stringf("%k %s", ty->op, ty->u.sym->name); |
case VOID: case FLOAT: case INT: case UNSIGNED: |
return *str ? stringf("%s %s", ty->u.sym->name, str) : ty->u.sym->name; |
case POINTER: |
if (!ischar(ty->type) && (p = findtype(ty)) != NULL) |
return *str ? stringf("%s %s", p->name, str) : p->name; |
str = stringf(isarray(ty->type) || isfunc(ty->type) ? "(*%s)" : "*%s", str); |
break; |
case FUNCTION: |
if ((p = findtype(ty)) != NULL) |
return *str ? stringf("%s %s", p->name, str) : p->name; |
if (ty->u.f.proto == 0) |
str = stringf("%s()", str); |
else if (ty->u.f.proto[0]) { |
int i; |
str = stringf("%s(%s", str, typestring(ty->u.f.proto[0], "")); |
for (i = 1; ty->u.f.proto[i]; i++) |
if (ty->u.f.proto[i] == voidtype) |
str = stringf("%s, ...", str); |
else |
str = stringf("%s, %s", str, typestring(ty->u.f.proto[i], "")); |
str = stringf("%s)", str); |
} else |
str = stringf("%s(void)", str); |
break; |
case ARRAY: |
if ((p = findtype(ty)) != NULL) |
return *str ? stringf("%s %s", p->name, str) : p->name; |
if (ty->type && ty->type->size > 0) |
str = stringf("%s[%d]", str, ty->size/ty->type->size); |
else |
str = stringf("%s[]", str); |
break; |
default: assert(0); |
} |
} |
assert(0); return 0; |
} |
|
/string.c
0,0 → 1,123
#include "c.h" |
|
static char rcsid[] = "$Id: string.c,v 1.1 2002/08/28 23:12:46 drh Exp $"; |
|
static struct string { |
char *str; |
int len; |
struct string *link; |
} *buckets[1024]; |
static int scatter[] = { /* map characters to random values */ |
2078917053, 143302914, 1027100827, 1953210302, 755253631, |
2002600785, 1405390230, 45248011, 1099951567, 433832350, |
2018585307, 438263339, 813528929, 1703199216, 618906479, |
573714703, 766270699, 275680090, 1510320440, 1583583926, |
1723401032, 1965443329, 1098183682, 1636505764, 980071615, |
1011597961, 643279273, 1315461275, 157584038, 1069844923, |
471560540, 89017443, 1213147837, 1498661368, 2042227746, |
1968401469, 1353778505, 1300134328, 2013649480, 306246424, |
1733966678, 1884751139, 744509763, 400011959, 1440466707, |
1363416242, 973726663, 59253759, 1639096332, 336563455, |
1642837685, 1215013716, 154523136, 593537720, 704035832, |
1134594751, 1605135681, 1347315106, 302572379, 1762719719, |
269676381, 774132919, 1851737163, 1482824219, 125310639, |
1746481261, 1303742040, 1479089144, 899131941, 1169907872, |
1785335569, 485614972, 907175364, 382361684, 885626931, |
200158423, 1745777927, 1859353594, 259412182, 1237390611, |
48433401, 1902249868, 304920680, 202956538, 348303940, |
1008956512, 1337551289, 1953439621, 208787970, 1640123668, |
1568675693, 478464352, 266772940, 1272929208, 1961288571, |
392083579, 871926821, 1117546963, 1871172724, 1771058762, |
139971187, 1509024645, 109190086, 1047146551, 1891386329, |
994817018, 1247304975, 1489680608, 706686964, 1506717157, |
579587572, 755120366, 1261483377, 884508252, 958076904, |
1609787317, 1893464764, 148144545, 1415743291, 2102252735, |
1788268214, 836935336, 433233439, 2055041154, 2109864544, |
247038362, 299641085, 834307717, 1364585325, 23330161, |
457882831, 1504556512, 1532354806, 567072918, 404219416, |
1276257488, 1561889936, 1651524391, 618454448, 121093252, |
1010757900, 1198042020, 876213618, 124757630, 2082550272, |
1834290522, 1734544947, 1828531389, 1982435068, 1002804590, |
1783300476, 1623219634, 1839739926, 69050267, 1530777140, |
1802120822, 316088629, 1830418225, 488944891, 1680673954, |
1853748387, 946827723, 1037746818, 1238619545, 1513900641, |
1441966234, 367393385, 928306929, 946006977, 985847834, |
1049400181, 1956764878, 36406206, 1925613800, 2081522508, |
2118956479, 1612420674, 1668583807, 1800004220, 1447372094, |
523904750, 1435821048, 923108080, 216161028, 1504871315, |
306401572, 2018281851, 1820959944, 2136819798, 359743094, |
1354150250, 1843084537, 1306570817, 244413420, 934220434, |
672987810, 1686379655, 1301613820, 1601294739, 484902984, |
139978006, 503211273, 294184214, 176384212, 281341425, |
228223074, 147857043, 1893762099, 1896806882, 1947861263, |
1193650546, 273227984, 1236198663, 2116758626, 489389012, |
593586330, 275676551, 360187215, 267062626, 265012701, |
719930310, 1621212876, 2108097238, 2026501127, 1865626297, |
894834024, 552005290, 1404522304, 48964196, 5816381, |
1889425288, 188942202, 509027654, 36125855, 365326415, |
790369079, 264348929, 513183458, 536647531, 13672163, |
313561074, 1730298077, 286900147, 1549759737, 1699573055, |
776289160, 2143346068, 1975249606, 1136476375, 262925046, |
92778659, 1856406685, 1884137923, 53392249, 1735424165, |
1602280572 |
}; |
char *string(const char *str) { |
const char *s; |
|
for (s = str; *s; s++) |
; |
return stringn(str, s - str); |
} |
char *stringd(long n) { |
char str[25], *s = str + sizeof (str); |
unsigned long m; |
|
if (n == LONG_MIN) |
m = (unsigned long)LONG_MAX + 1; |
else if (n < 0) |
m = -n; |
else |
m = n; |
do |
*--s = m%10 + '0'; |
while ((m /= 10) != 0); |
if (n < 0) |
*--s = '-'; |
return stringn(s, str + sizeof (str) - s); |
} |
char *stringn(const char *str, int len) { |
int i; |
unsigned int h; |
const char *end; |
struct string *p; |
|
assert(str); |
for (h = 0, i = len, end = str; i > 0; i--) |
h = (h<<1) + scatter[*(unsigned char *)end++]; |
h &= NELEMS(buckets)-1; |
for (p = buckets[h]; p; p = p->link) |
if (len == p->len) { |
const char *s1 = str; |
char *s2 = p->str; |
do { |
if (s1 == end) |
return p->str; |
} while (*s1++ == *s2++); |
} |
{ |
static char *next, *strlimit; |
if (len + 1 >= strlimit - next) { |
int n = len + 4*1024; |
next = allocate(n, PERM); |
strlimit = next + n; |
} |
NEW(p, PERM); |
p->len = len; |
for (p->str = next; str < end; ) |
*next++ = *str++; |
*next++ = 0; |
p->link = buckets[h]; |
buckets[h] = p; |
return p->str; |
} |
} |
/decl.c
0,0 → 1,1163
#include "c.h" |
|
static char rcsid[] = "$Id: decl.c,v 1.1 2002/08/28 23:12:42 drh Exp $"; |
|
#define add(x,n) (x > inttype->u.sym->u.limits.max.i-(n) ? (overflow=1,x) : x+(n)) |
#define chkoverflow(x,n) ((void)add(x,n)) |
#define bits2bytes(n) (((n) + 7)/8) |
static int regcount; |
|
static List autos, registers; |
Symbol cfunc; /* current function */ |
Symbol retv; /* return value location for structs */ |
|
static void checkref(Symbol, void *); |
static Symbol dclglobal(int, char *, Type, Coordinate *); |
static Symbol dcllocal(int, char *, Type, Coordinate *); |
static Symbol dclparam(int, char *, Type, Coordinate *); |
static Type dclr(Type, char **, Symbol **, int); |
static Type dclr1(char **, Symbol **, int); |
static void decl(Symbol (*)(int, char *, Type, Coordinate *)); |
extern void doconst(Symbol, void *); |
static void doglobal(Symbol, void *); |
static void doextern(Symbol, void *); |
static void exitparams(Symbol []); |
static void fields(Type); |
static void funcdefn(int, char *, Type, Symbol [], Coordinate); |
static void initglobal(Symbol, int); |
static void oldparam(Symbol, void *); |
static Symbol *parameters(Type); |
static Type specifier(int *); |
static Type structdcl(int); |
static Type tnode(int, Type); |
void program(void) { |
int n; |
|
level = GLOBAL; |
for (n = 0; t != EOI; n++) |
if (kind[t] == CHAR || kind[t] == STATIC |
|| t == ID || t == '*' || t == '(') { |
decl(dclglobal); |
deallocate(STMT); |
if (!(glevel >= 3 || xref)) |
deallocate(FUNC); |
} else if (t == ';') { |
warning("empty declaration\n"); |
t = gettok(); |
} else { |
error("unrecognized declaration\n"); |
t = gettok(); |
} |
if (n == 0) |
warning("empty input file\n"); |
} |
static Type specifier(int *sclass) { |
int cls, cons, sign, size, type, vol; |
Type ty = NULL; |
|
cls = vol = cons = sign = size = type = 0; |
if (sclass == NULL) |
cls = AUTO; |
for (;;) { |
int *p, tt = t; |
switch (t) { |
case AUTO: |
case REGISTER: if (level <= GLOBAL && cls == 0) |
error("invalid use of `%k'\n", t); |
p = &cls; t = gettok(); break; |
case STATIC: case EXTERN: |
case TYPEDEF: p = &cls; t = gettok(); break; |
case CONST: p = &cons; t = gettok(); break; |
case VOLATILE: p = &vol; t = gettok(); break; |
case SIGNED: |
case UNSIGNED: p = &sign; t = gettok(); break; |
case LONG: if (size == LONG) { |
size = 0; |
tt = LONG+LONG; |
} |
p = &size; t = gettok(); break; |
case SHORT: p = &size; t = gettok(); break; |
case VOID: case CHAR: case INT: case FLOAT: |
case DOUBLE: p = &type; ty = tsym->type; |
t = gettok(); break; |
case ENUM: p = &type; ty = enumdcl(); break; |
case STRUCT: |
case UNION: p = &type; ty = structdcl(t); break; |
case ID: |
if (istypename(t, tsym) && type == 0 |
&& sign == 0 && size == 0) { |
use(tsym, src); |
ty = tsym->type; |
if (isqual(ty) |
&& ty->size != ty->type->size) { |
ty = unqual(ty); |
if (isconst(tsym->type)) |
ty = qual(CONST, ty); |
if (isvolatile(tsym->type)) |
ty = qual(VOLATILE, ty); |
tsym->type = ty; |
} |
p = &type; |
t = gettok(); |
} else |
p = NULL; |
break; |
default: p = NULL; |
} |
if (p == NULL) |
break; |
if (*p) |
error("invalid use of `%k'\n", tt); |
*p = tt; |
} |
if (sclass) |
*sclass = cls; |
if (type == 0) { |
type = INT; |
ty = inttype; |
} |
if (size == SHORT && type != INT |
|| size == LONG+LONG && type != INT |
|| size == LONG && type != INT && type != DOUBLE |
|| sign && type != INT && type != CHAR) |
error("invalid type specification\n"); |
if (type == CHAR && sign) |
ty = sign == UNSIGNED ? unsignedchar : signedchar; |
else if (size == SHORT) |
ty = sign == UNSIGNED ? unsignedshort : shorttype; |
else if (size == LONG && type == DOUBLE) |
ty = longdouble; |
else if (size == LONG+LONG) { |
ty = sign == UNSIGNED ? unsignedlonglong : longlong; |
if (Aflag >= 1) |
warning("`%t' is a non-ANSI type\n", ty); |
} else if (size == LONG) |
ty = sign == UNSIGNED ? unsignedlong : longtype; |
else if (sign == UNSIGNED && type == INT) |
ty = unsignedtype; |
if (cons == CONST) |
ty = qual(CONST, ty); |
if (vol == VOLATILE) |
ty = qual(VOLATILE, ty); |
return ty; |
} |
static void decl(Symbol (*dcl)(int, char *, Type, Coordinate *)) { |
int sclass; |
Type ty, ty1; |
static char stop[] = { CHAR, STATIC, ID, 0 }; |
|
ty = specifier(&sclass); |
if (t == ID || t == '*' || t == '(' || t == '[') { |
char *id; |
Coordinate pos; |
id = NULL; |
pos = src; |
if (level == GLOBAL) { |
Symbol *params = NULL; |
ty1 = dclr(ty, &id, ¶ms, 0); |
if (params && id && isfunc(ty1) |
&& (t == '{' || istypename(t, tsym) |
|| (kind[t] == STATIC && t != TYPEDEF))) { |
if (sclass == TYPEDEF) { |
error("invalid use of `typedef'\n"); |
sclass = EXTERN; |
} |
if (ty1->u.f.oldstyle) |
exitscope(); |
funcdefn(sclass, id, ty1, params, pos); |
return; |
} else if (params) |
exitparams(params); |
} else |
ty1 = dclr(ty, &id, NULL, 0); |
for (;;) { |
if (Aflag >= 1 && !hasproto(ty1)) |
warning("missing prototype\n"); |
if (id == NULL) |
error("missing identifier\n"); |
else if (sclass == TYPEDEF) |
{ |
Symbol p = lookup(id, identifiers); |
if (p && p->scope == level) |
error("redeclaration of `%s'\n", id); |
p = install(id, &identifiers, level, |
level < LOCAL ? PERM : FUNC); |
p->type = ty1; |
p->sclass = TYPEDEF; |
p->src = pos; |
} |
else |
(void)(*dcl)(sclass, id, ty1, &pos); |
if (t != ',') |
break; |
t = gettok(); |
id = NULL; |
pos = src; |
ty1 = dclr(ty, &id, NULL, 0); |
} |
} else if (ty == NULL |
|| !(isenum(ty) || |
isstruct(ty) && (*unqual(ty)->u.sym->name < '1' || *unqual(ty)->u.sym->name > '9'))) |
error("empty declaration\n"); |
test(';', stop); |
} |
static Symbol dclglobal(int sclass, char *id, Type ty, Coordinate *pos) { |
Symbol p; |
|
if (sclass == 0) |
sclass = AUTO; |
else if (sclass != EXTERN && sclass != STATIC) { |
error("invalid storage class `%k' for `%t %s'\n", |
sclass, ty, id); |
sclass = AUTO; |
} |
p = lookup(id, identifiers); |
if (p && p->scope == GLOBAL) { |
if (p->sclass != TYPEDEF && eqtype(ty, p->type, 1)) |
ty = compose(ty, p->type); |
else |
error("redeclaration of `%s' previously declared at %w\n", p->name, &p->src); |
|
if (!isfunc(ty) && p->defined && t == '=') |
error("redefinition of `%s' previously defined at %w\n", p->name, &p->src); |
|
if (p->sclass == EXTERN && sclass == STATIC |
|| p->sclass == STATIC && sclass == AUTO |
|| p->sclass == AUTO && sclass == STATIC) |
warning("inconsistent linkage for `%s' previously declared at %w\n", p->name, &p->src); |
|
} |
if (p == NULL || p->scope != GLOBAL) { |
Symbol q = lookup(id, externals); |
if (q) { |
if (sclass == STATIC || !eqtype(ty, q->type, 1)) |
warning("declaration of `%s' does not match previous declaration at %w\n", id, &q->src); |
|
p = relocate(id, externals, globals); |
p->sclass = sclass; |
} else { |
p = install(id, &globals, GLOBAL, PERM); |
p->sclass = sclass; |
(*IR->defsymbol)(p); |
} |
if (p->sclass != STATIC) { |
static int nglobals; |
nglobals++; |
if (Aflag >= 2 && nglobals == 512) |
warning("more than 511 external identifiers\n"); |
} |
} else if (p->sclass == EXTERN) |
p->sclass = sclass; |
p->type = ty; |
p->src = *pos; |
if (t == '=' && isfunc(p->type)) { |
error("illegal initialization for `%s'\n", p->name); |
t = gettok(); |
initializer(p->type, 0); |
} else if (t == '=') { |
initglobal(p, 0); |
if (glevel > 0 && IR->stabsym) { |
(*IR->stabsym)(p); swtoseg(p->u.seg); } |
} else if (p->sclass == STATIC && !isfunc(p->type) |
&& p->type->size == 0) |
error("undefined size for `%t %s'\n", p->type, p->name); |
return p; |
} |
static void initglobal(Symbol p, int flag) { |
Type ty; |
|
if (t == '=' || flag) { |
if (p->sclass == STATIC) { |
for (ty = p->type; isarray(ty); ty = ty->type) |
; |
defglobal(p, isconst(ty) ? LIT : DATA); |
} else |
defglobal(p, DATA); |
if (t == '=') |
t = gettok(); |
ty = initializer(p->type, 0); |
if (isarray(p->type) && p->type->size == 0) |
p->type = ty; |
if (p->sclass == EXTERN) |
p->sclass = AUTO; |
} |
} |
void defglobal(Symbol p, int seg) { |
p->u.seg = seg; |
swtoseg(p->u.seg); |
if (p->sclass != STATIC) |
(*IR->export)(p); |
(*IR->global)(p); |
p->defined = 1; |
} |
|
static Type dclr(Type basety, char **id, Symbol **params, int abstract) { |
Type ty = dclr1(id, params, abstract); |
|
for ( ; ty; ty = ty->type) |
switch (ty->op) { |
case POINTER: |
basety = ptr(basety); |
break; |
case FUNCTION: |
basety = func(basety, ty->u.f.proto, |
ty->u.f.oldstyle); |
break; |
case ARRAY: |
basety = array(basety, ty->size, 0); |
break; |
case CONST: case VOLATILE: |
basety = qual(ty->op, basety); |
break; |
default: assert(0); |
} |
if (Aflag >= 2 && basety->size > 32767) |
warning("more than 32767 bytes in `%t'\n", basety); |
return basety; |
} |
static Type tnode(int op, Type type) { |
Type ty; |
|
NEW0(ty, STMT); |
ty->op = op; |
ty->type = type; |
return ty; |
} |
static Type dclr1(char **id, Symbol **params, int abstract) { |
Type ty = NULL; |
|
switch (t) { |
case ID: if (id) |
*id = token; |
else |
error("extraneous identifier `%s'\n", token); |
t = gettok(); break; |
case '*': t = gettok(); if (t == CONST || t == VOLATILE) { |
Type ty1; |
ty1 = ty = tnode(t, NULL); |
while ((t = gettok()) == CONST || t == VOLATILE) |
ty1 = tnode(t, ty1); |
ty->type = dclr1(id, params, abstract); |
ty = ty1; |
} else |
ty = dclr1(id, params, abstract); |
ty = tnode(POINTER, ty); break; |
case '(': t = gettok(); if (abstract |
&& (t == REGISTER || istypename(t, tsym) || t == ')')) { |
Symbol *args; |
ty = tnode(FUNCTION, ty); |
enterscope(); |
if (level > PARAM) |
enterscope(); |
args = parameters(ty); |
exitparams(args); |
} else { |
ty = dclr1(id, params, abstract); |
expect(')'); |
if (abstract && ty == NULL |
&& (id == NULL || *id == NULL)) |
return tnode(FUNCTION, NULL); |
} break; |
case '[': break; |
default: return ty; |
} |
while (t == '(' || t == '[') |
switch (t) { |
case '(': t = gettok(); { Symbol *args; |
ty = tnode(FUNCTION, ty); |
enterscope(); |
if (level > PARAM) |
enterscope(); |
args = parameters(ty); |
if (params && *params == NULL) |
*params = args; |
else |
exitparams(args); |
} |
break; |
case '[': t = gettok(); { int n = 0; |
if (kind[t] == ID) { |
n = intexpr(']', 1); |
if (n <= 0) { |
error("`%d' is an illegal array size\n", n); |
n = 1; |
} |
} else |
expect(']'); |
ty = tnode(ARRAY, ty); |
ty->size = n; } break; |
default: assert(0); |
} |
return ty; |
} |
static Symbol *parameters(Type fty) { |
List list = NULL; |
Symbol *params; |
|
if (kind[t] == STATIC || istypename(t, tsym)) { |
int n = 0; |
Type ty1 = NULL; |
for (;;) { |
Type ty; |
int sclass = 0; |
char *id = NULL; |
if (ty1 && t == ELLIPSIS) { |
static struct symbol sentinel; |
if (sentinel.type == NULL) { |
sentinel.type = voidtype; |
sentinel.defined = 1; |
} |
if (ty1 == voidtype) |
error("illegal formal parameter types\n"); |
list = append(&sentinel, list); |
t = gettok(); |
break; |
} |
if (!istypename(t, tsym) && t != REGISTER) |
error("missing parameter type\n"); |
n++; |
ty = dclr(specifier(&sclass), &id, NULL, 1); |
if ( ty == voidtype && (ty1 || id) |
|| ty1 == voidtype) |
error("illegal formal parameter types\n"); |
if (id == NULL) |
id = stringd(n); |
if (ty != voidtype) |
list = append(dclparam(sclass, id, ty, &src), list); |
if (Aflag >= 1 && !hasproto(ty)) |
warning("missing prototype\n"); |
if (ty1 == NULL) |
ty1 = ty; |
if (t != ',') |
break; |
t = gettok(); |
} |
fty->u.f.proto = newarray(length(list) + 1, |
sizeof (Type *), PERM); |
params = ltov(&list, FUNC); |
for (n = 0; params[n]; n++) |
fty->u.f.proto[n] = params[n]->type; |
fty->u.f.proto[n] = NULL; |
fty->u.f.oldstyle = 0; |
} else { |
if (t == ID) |
for (;;) { |
Symbol p; |
if (t != ID) { |
error("expecting an identifier\n"); |
break; |
} |
p = dclparam(0, token, inttype, &src); |
p->defined = 0; |
list = append(p, list); |
t = gettok(); |
if (t != ',') |
break; |
t = gettok(); |
} |
params = ltov(&list, FUNC); |
fty->u.f.proto = NULL; |
fty->u.f.oldstyle = 1; |
} |
if (t != ')') { |
static char stop[] = { CHAR, STATIC, IF, ')', 0 }; |
expect(')'); |
skipto('{', stop); |
} |
if (t == ')') |
t = gettok(); |
return params; |
} |
static void exitparams(Symbol params[]) { |
assert(params); |
if (params[0] && !params[0]->defined) |
error("extraneous old-style parameter list\n"); |
if (level > PARAM) |
exitscope(); |
exitscope(); |
} |
|
static Symbol dclparam(int sclass, char *id, Type ty, Coordinate *pos) { |
Symbol p; |
|
if (isfunc(ty)) |
ty = ptr(ty); |
else if (isarray(ty)) |
ty = atop(ty); |
if (sclass == 0) |
sclass = AUTO; |
else if (sclass != REGISTER) { |
error("invalid storage class `%k' for `%t%s\n", |
sclass, ty, stringf(id ? " %s'" : "' parameter", id)); |
sclass = AUTO; |
} else if (isvolatile(ty) || isstruct(ty)) { |
warning("register declaration ignored for `%t%s\n", |
ty, stringf(id ? " %s'" : "' parameter", id)); |
sclass = AUTO; |
} |
|
p = lookup(id, identifiers); |
if (p && p->scope == level) |
error("duplicate declaration for `%s' previously declared at %w\n", id, &p->src); |
|
else |
p = install(id, &identifiers, level, FUNC); |
p->sclass = sclass; |
p->src = *pos; |
p->type = ty; |
p->defined = 1; |
if (t == '=') { |
error("illegal initialization for parameter `%s'\n", id); |
t = gettok(); |
(void)expr1(0); |
} |
return p; |
} |
static Type structdcl(int op) { |
char *tag; |
Type ty; |
Symbol p; |
Coordinate pos; |
|
t = gettok(); |
pos = src; |
if (t == ID) { |
tag = token; |
t = gettok(); |
} else |
tag = ""; |
if (t == '{') { |
static char stop[] = { IF, ',', 0 }; |
ty = newstruct(op, tag); |
ty->u.sym->src = pos; |
ty->u.sym->defined = 1; |
t = gettok(); |
if (istypename(t, tsym)) |
fields(ty); |
else |
error("invalid %k field declarations\n", op); |
test('}', stop); |
} |
else if (*tag && (p = lookup(tag, types)) != NULL |
&& p->type->op == op) { |
ty = p->type; |
if (t == ';' && p->scope < level) |
ty = newstruct(op, tag); |
} |
else { |
if (*tag == 0) |
error("missing %k tag\n", op); |
ty = newstruct(op, tag); |
} |
if (*tag && xref) |
use(ty->u.sym, pos); |
return ty; |
} |
static void fields(Type ty) { |
{ int n = 0; |
while (istypename(t, tsym)) { |
static char stop[] = { IF, CHAR, '}', 0 }; |
Type ty1 = specifier(NULL); |
for (;;) { |
Field p; |
char *id = NULL; |
Type fty = dclr(ty1, &id, NULL, 0); |
p = newfield(id, ty, fty); |
if (Aflag >= 1 && !hasproto(p->type)) |
warning("missing prototype\n"); |
if (t == ':') { |
if (unqual(p->type) != inttype |
&& unqual(p->type) != unsignedtype) { |
error("`%t' is an illegal bit-field type\n", |
p->type); |
p->type = inttype; |
} |
t = gettok(); |
p->bitsize = intexpr(0, 0); |
if (p->bitsize > 8*inttype->size || p->bitsize < 0) { |
error("`%d' is an illegal bit-field size\n", |
p->bitsize); |
p->bitsize = 8*inttype->size; |
} else if (p->bitsize == 0 && id) { |
warning("extraneous 0-width bit field `%t %s' ignored\n", p->type, id); |
|
p->name = stringd(genlabel(1)); |
} |
p->lsb = 1; |
} |
else { |
if (id == NULL) |
error("field name missing\n"); |
else if (isfunc(p->type)) |
error("`%t' is an illegal field type\n", p->type); |
else if (p->type->size == 0) |
error("undefined size for field `%t %s'\n", |
p->type, id); |
} |
if (isconst(p->type)) |
ty->u.sym->u.s.cfields = 1; |
if (isvolatile(p->type)) |
ty->u.sym->u.s.vfields = 1; |
n++; |
if (Aflag >= 2 && n == 128) |
warning("more than 127 fields in `%t'\n", ty); |
if (t != ',') |
break; |
t = gettok(); |
} |
test(';', stop); |
} } |
{ int bits = 0, off = 0, overflow = 0; |
Field p, *q = &ty->u.sym->u.s.flist; |
ty->align = IR->structmetric.align; |
for (p = *q; p; p = p->link) { |
int a = p->type->align ? p->type->align : 1; |
if (p->lsb) |
a = unsignedtype->align; |
if (ty->op == UNION) |
off = bits = 0; |
else if (p->bitsize == 0 || bits == 0 |
|| bits - 1 + p->bitsize > 8*unsignedtype->size) { |
off = add(off, bits2bytes(bits-1)); |
bits = 0; |
chkoverflow(off, a - 1); |
off = roundup(off, a); |
} |
if (a > ty->align) |
ty->align = a; |
p->offset = off; |
|
if (p->lsb) { |
if (bits == 0) |
bits = 1; |
if (IR->little_endian) |
p->lsb = bits; |
else |
p->lsb = 8*unsignedtype->size - bits + 1 |
- p->bitsize + 1; |
bits += p->bitsize; |
} else |
off = add(off, p->type->size); |
if (off + bits2bytes(bits-1) > ty->size) |
ty->size = off + bits2bytes(bits-1); |
if (p->name == NULL |
|| !('1' <= *p->name && *p->name <= '9')) { |
*q = p; |
q = &p->link; |
} |
} |
*q = NULL; |
chkoverflow(ty->size, ty->align - 1); |
ty->size = roundup(ty->size, ty->align); |
if (overflow) { |
error("size of `%t' exceeds %d bytes\n", ty, inttype->u.sym->u.limits.max.i); |
ty->size = inttype->u.sym->u.limits.max.i&(~(ty->align - 1)); |
} } |
} |
static void funcdefn(int sclass, char *id, Type ty, Symbol params[], Coordinate pt) { |
int i, n; |
Symbol *callee, *caller, p; |
Type rty = freturn(ty); |
|
if (isstruct(rty) && rty->size == 0) |
error("illegal use of incomplete type `%t'\n", rty); |
for (n = 0; params[n]; n++) |
; |
if (n > 0 && params[n-1]->name == NULL) |
params[--n] = NULL; |
if (Aflag >= 2 && n > 31) |
warning("more than 31 parameters in function `%s'\n", id); |
if (ty->u.f.oldstyle) { |
if (Aflag >= 1) |
warning("old-style function definition for `%s'\n", id); |
caller = params; |
callee = newarray(n + 1, sizeof *callee, FUNC); |
memcpy(callee, caller, (n+1)*sizeof *callee); |
enterscope(); |
assert(level == PARAM); |
while (kind[t] == STATIC || istypename(t, tsym)) |
decl(dclparam); |
foreach(identifiers, PARAM, oldparam, callee); |
|
for (i = 0; (p = callee[i]) != NULL; i++) { |
if (!p->defined) |
callee[i] = dclparam(0, p->name, inttype, &p->src); |
*caller[i] = *p; |
caller[i]->sclass = AUTO; |
caller[i]->type = promote(p->type); |
} |
p = lookup(id, identifiers); |
if (p && p->scope == GLOBAL && isfunc(p->type) |
&& p->type->u.f.proto) { |
Type *proto = p->type->u.f.proto; |
for (i = 0; caller[i] && proto[i]; i++) { |
Type ty = unqual(proto[i]); |
if (eqtype(isenum(ty) ? ty->type : ty, |
unqual(caller[i]->type), 1) == 0) |
break; |
else if (isenum(ty) && !isenum(unqual(caller[i]->type))) |
warning("compatibility of `%t' and `%t' is compiler dependent\n", |
proto[i], caller[i]->type); |
} |
if (proto[i] || caller[i]) |
error("conflicting argument declarations for function `%s'\n", id); |
|
} |
else { |
Type *proto = newarray(n + 1, sizeof *proto, PERM); |
if (Aflag >= 1) |
warning("missing prototype for `%s'\n", id); |
for (i = 0; i < n; i++) |
proto[i] = caller[i]->type; |
proto[i] = NULL; |
ty = func(rty, proto, 1); |
} |
} else { |
callee = params; |
caller = newarray(n + 1, sizeof *caller, FUNC); |
for (i = 0; (p = callee[i]) != NULL && p->name; i++) { |
NEW(caller[i], FUNC); |
*caller[i] = *p; |
if (isint(p->type)) |
caller[i]->type = promote(p->type); |
caller[i]->sclass = AUTO; |
if ('1' <= *p->name && *p->name <= '9') |
error("missing name for parameter %d to function `%s'\n", i + 1, id); |
|
} |
caller[i] = NULL; |
} |
for (i = 0; (p = callee[i]) != NULL; i++) |
if (p->type->size == 0) { |
error("undefined size for parameter `%t %s'\n", |
p->type, p->name); |
caller[i]->type = p->type = inttype; |
} |
if (Aflag >= 2 && sclass != STATIC && strcmp(id, "main") == 0) { |
if (ty->u.f.oldstyle) |
warning("`%t %s()' is a non-ANSI definition\n", rty, id); |
else if (!(rty == inttype |
&& (n == 0 && callee[0] == NULL |
|| n == 2 && callee[0]->type == inttype |
&& isptr(callee[1]->type) && callee[1]->type->type == charptype |
&& !variadic(ty)))) |
warning("`%s' is a non-ANSI definition\n", typestring(ty, id)); |
} |
p = lookup(id, identifiers); |
if (p && isfunc(p->type) && p->defined) |
error("redefinition of `%s' previously defined at %w\n", |
p->name, &p->src); |
cfunc = dclglobal(sclass, id, ty, &pt); |
cfunc->u.f.label = genlabel(1); |
cfunc->u.f.callee = callee; |
cfunc->u.f.pt = src; |
cfunc->defined = 1; |
if (xref) |
use(cfunc, cfunc->src); |
if (Pflag) |
printproto(cfunc, cfunc->u.f.callee); |
if (ncalled >= 0) |
ncalled = findfunc(cfunc->name, pt.file); |
labels = table(NULL, LABELS); |
stmtlabs = table(NULL, LABELS); |
refinc = 1.0; |
regcount = 0; |
codelist = &codehead; |
codelist->next = NULL; |
if (!IR->wants_callb && isstruct(rty)) |
retv = genident(AUTO, ptr(unqual(rty)), PARAM); |
compound(0, NULL, 0); |
|
definelab(cfunc->u.f.label); |
if (events.exit) |
apply(events.exit, cfunc, NULL); |
walk(NULL, 0, 0); |
exitscope(); |
assert(level == PARAM); |
foreach(identifiers, level, checkref, NULL); |
if (!IR->wants_callb && isstruct(rty)) { |
Symbol *a; |
a = newarray(n + 2, sizeof *a, FUNC); |
a[0] = retv; |
memcpy(&a[1], callee, (n+1)*sizeof *callee); |
callee = a; |
a = newarray(n + 2, sizeof *a, FUNC); |
NEW(a[0], FUNC); |
*a[0] = *retv; |
memcpy(&a[1], caller, (n+1)*sizeof *callee); |
caller = a; |
} |
if (!IR->wants_argb) |
for (i = 0; caller[i]; i++) |
if (isstruct(caller[i]->type)) { |
caller[i]->type = ptr(caller[i]->type); |
callee[i]->type = ptr(callee[i]->type); |
caller[i]->structarg = callee[i]->structarg = 1; |
} |
if (glevel > 1) for (i = 0; callee[i]; i++) callee[i]->sclass = AUTO; |
if (cfunc->sclass != STATIC) |
(*IR->export)(cfunc); |
if (glevel && IR->stabsym) { |
swtoseg(CODE); (*IR->stabsym)(cfunc); } |
swtoseg(CODE); |
(*IR->function)(cfunc, caller, callee, cfunc->u.f.ncalls); |
if (glevel && IR->stabfend) |
(*IR->stabfend)(cfunc, lineno); |
foreach(stmtlabs, LABELS, checklab, NULL); |
exitscope(); |
expect('}'); |
labels = stmtlabs = NULL; |
retv = NULL; |
cfunc = NULL; |
} |
static void oldparam(Symbol p, void *cl) { |
int i; |
Symbol *callee = cl; |
|
for (i = 0; callee[i]; i++) |
if (p->name == callee[i]->name) { |
callee[i] = p; |
return; |
} |
error("declared parameter `%s' is missing\n", p->name); |
} |
void compound(int loop, struct swtch *swp, int lev) { |
Code cp; |
int nregs; |
|
walk(NULL, 0, 0); |
cp = code(Blockbeg); |
enterscope(); |
assert(level >= LOCAL); |
if (level == LOCAL && events.entry) |
apply(events.entry, cfunc, NULL); |
definept(NULL); |
expect('{'); |
autos = registers = NULL; |
if (level == LOCAL && IR->wants_callb |
&& isstruct(freturn(cfunc->type))) { |
retv = genident(AUTO, ptr(unqual(freturn(cfunc->type))), level); |
retv->defined = 1; |
retv->ref = 1; |
registers = append(retv, registers); |
} |
while (kind[t] == CHAR || kind[t] == STATIC |
|| istypename(t, tsym) && getchr() != ':') |
decl(dcllocal); |
{ |
int i; |
Symbol *a = ltov(&autos, STMT); |
nregs = length(registers); |
for (i = 0; a[i]; i++) |
registers = append(a[i], registers); |
cp->u.block.locals = ltov(®isters, FUNC); |
} |
if (events.blockentry) |
apply(events.blockentry, cp->u.block.locals, NULL); |
while (kind[t] == IF || kind[t] == ID) |
statement(loop, swp, lev); |
walk(NULL, 0, 0); |
foreach(identifiers, level, checkref, NULL); |
{ |
int i = nregs, j; |
Symbol p; |
for ( ; (p = cp->u.block.locals[i]) != NULL; i++) { |
for (j = i; j > nregs |
&& cp->u.block.locals[j-1]->ref < p->ref; j--) |
cp->u.block.locals[j] = cp->u.block.locals[j-1]; |
cp->u.block.locals[j] = p; |
} |
} |
if (level == LOCAL) { |
Code cp; |
for (cp = codelist; cp->kind < Label; cp = cp->prev) |
; |
if (cp->kind != Jump) { |
if (freturn(cfunc->type) != voidtype) { |
warning("missing return value\n"); |
retcode(cnsttree(inttype, 0L)); |
} else |
retcode(NULL); |
} |
} |
if (events.blockexit) |
apply(events.blockexit, cp->u.block.locals, NULL); |
cp->u.block.level = level; |
cp->u.block.identifiers = identifiers; |
cp->u.block.types = types; |
code(Blockend)->u.begin = cp; |
if (reachable(Gen)) |
definept(NULL); |
if (level > LOCAL) { |
exitscope(); |
expect('}'); |
} |
} |
static void checkref(Symbol p, void *cl) { |
if (p->scope >= PARAM |
&& (isvolatile(p->type) || isfunc(p->type))) |
p->addressed = 1; |
if (Aflag >= 2 && p->defined && p->ref == 0) { |
if (p->sclass == STATIC) |
warning("static `%t %s' is not referenced\n", |
p->type, p->name); |
else if (p->scope == PARAM) |
warning("parameter `%t %s' is not referenced\n", |
p->type, p->name); |
else if (p->scope >= LOCAL && p->sclass != EXTERN) |
warning("local `%t %s' is not referenced\n", |
p->type, p->name); |
} |
if (p->sclass == AUTO |
&& (p->scope == PARAM && regcount == 0 |
|| p->scope >= LOCAL) |
&& !p->addressed && isscalar(p->type) && p->ref >= 3.0) |
p->sclass = REGISTER; |
if (level == GLOBAL && p->sclass == STATIC && !p->defined |
&& isfunc(p->type) && p->ref) |
error("undefined static `%t %s'\n", p->type, p->name); |
assert(!(level == GLOBAL && p->sclass == STATIC && !p->defined && !isfunc(p->type))); |
} |
static Symbol dcllocal(int sclass, char *id, Type ty, Coordinate *pos) { |
Symbol p, q; |
|
if (sclass == 0) |
sclass = isfunc(ty) ? EXTERN : AUTO; |
else if (isfunc(ty) && sclass != EXTERN) { |
error("invalid storage class `%k' for `%t %s'\n", |
sclass, ty, id); |
sclass = EXTERN; |
} else if (sclass == REGISTER |
&& (isvolatile(ty) || isstruct(ty) || isarray(ty))) { |
warning("register declaration ignored for `%t %s'\n", |
ty, id); |
sclass = AUTO; |
} |
q = lookup(id, identifiers); |
if (q && q->scope >= level |
|| q && q->scope == PARAM && level == LOCAL) |
if (sclass == EXTERN && q->sclass == EXTERN |
&& eqtype(q->type, ty, 1)) |
ty = compose(ty, q->type); |
else |
error("redeclaration of `%s' previously declared at %w\n", q->name, &q->src); |
|
assert(level >= LOCAL); |
p = install(id, &identifiers, level, sclass == STATIC || sclass == EXTERN ? PERM : FUNC); |
p->type = ty; |
p->sclass = sclass; |
p->src = *pos; |
switch (sclass) { |
case EXTERN: q = lookup(id, globals); |
if (q == NULL || q->sclass == TYPEDEF || q->sclass == ENUM) { |
q = lookup(id, externals); |
if (q == NULL) { |
q = install(p->name, &externals, GLOBAL, PERM); |
q->type = p->type; |
q->sclass = EXTERN; |
q->src = src; |
(*IR->defsymbol)(q); |
} |
} |
if (!eqtype(p->type, q->type, 1)) |
warning("declaration of `%s' does not match previous declaration at %w\n", q->name, &q->src); |
|
p->u.alias = q; break; |
case STATIC: (*IR->defsymbol)(p); |
initglobal(p, 0); |
if (!p->defined) |
if (p->type->size > 0) { |
defglobal(p, BSS); |
(*IR->space)(p->type->size); |
} else |
error("undefined size for `%t %s'\n", |
p->type, p->name); |
p->defined = 1; break; |
case REGISTER: registers = append(p, registers); |
regcount++; |
p->defined = 1; |
break; |
case AUTO: autos = append(p, autos); |
p->defined = 1; |
if (isarray(ty)) |
p->addressed = 1; break; |
default: assert(0); |
} |
if (t == '=') { |
Tree e; |
if (sclass == EXTERN) |
error("illegal initialization of `extern %s'\n", id); |
t = gettok(); |
definept(NULL); |
if (isscalar(p->type) |
|| isstruct(p->type) && t != '{') { |
if (t == '{') { |
t = gettok(); |
e = expr1(0); |
expect('}'); |
} else |
e = expr1(0); |
} else { |
Symbol t1; |
Type ty = p->type, ty1 = ty; |
while (isarray(ty1)) |
ty1 = ty1->type; |
if (!isconst(ty) && (!isarray(ty) || !isconst(ty1))) |
ty = qual(CONST, ty); |
t1 = genident(STATIC, ty, GLOBAL); |
initglobal(t1, 1); |
if (isarray(p->type) && p->type->size == 0 |
&& t1->type->size > 0) |
p->type = array(p->type->type, |
t1->type->size/t1->type->type->size, 0); |
e = idtree(t1); |
} |
walk(root(asgn(p, e)), 0, 0); |
p->ref = 1; |
} |
if (!isfunc(p->type) && p->defined && p->type->size <= 0) |
error("undefined size for `%t %s'\n", p->type, id); |
return p; |
} |
void finalize(void) { |
foreach(externals, GLOBAL, doextern, NULL); |
foreach(identifiers, GLOBAL, doglobal, NULL); |
foreach(identifiers, GLOBAL, checkref, NULL); |
foreach(constants, CONSTANTS, doconst, NULL); |
} |
static void doextern(Symbol p, void *cl) { |
(*IR->import)(p); |
} |
static void doglobal(Symbol p, void *cl) { |
if (!p->defined && (p->sclass == EXTERN |
|| isfunc(p->type) && p->sclass == AUTO)) |
(*IR->import)(p); |
else if (!p->defined && !isfunc(p->type) |
&& (p->sclass == AUTO || p->sclass == STATIC)) { |
if (isarray(p->type) |
&& p->type->size == 0 && p->type->type->size > 0) |
p->type = array(p->type->type, 1, 0); |
if (p->type->size > 0) { |
defglobal(p, BSS); |
(*IR->space)(p->type->size); |
if (glevel > 0 && IR->stabsym) |
(*IR->stabsym)(p); |
} else |
error("undefined size for `%t %s'\n", |
p->type, p->name); |
p->defined = 1; |
} |
if (Pflag |
&& !isfunc(p->type) |
&& !p->generated && p->sclass != EXTERN) |
printdecl(p, p->type); |
} |
void doconst(Symbol p, void *cl) { |
if (p->u.c.loc) { |
assert(p->u.c.loc->u.seg == 0); |
defglobal(p->u.c.loc, LIT); |
if (isarray(p->type) && p->type->type == widechar) { |
unsigned int *s = p->u.c.v.p; |
int n = p->type->size/widechar->size; |
while (n-- > 0) { |
Value v; |
v.u = *s++; |
(*IR->defconst)(widechar->op, widechar->size, v); |
} |
} else if (isarray(p->type)) |
(*IR->defstring)(p->type->size, p->u.c.v.p); |
else |
(*IR->defconst)(p->type->op, p->type->size, p->u.c.v); |
p->u.c.loc = NULL; |
} |
} |
void checklab(Symbol p, void *cl) { |
if (!p->defined) |
error("undefined label `%s'\n", p->name); |
p->defined = 1; |
} |
|
Type enumdcl(void) { |
char *tag; |
Type ty; |
Symbol p; |
Coordinate pos; |
|
t = gettok(); |
pos = src; |
if (t == ID) { |
tag = token; |
t = gettok(); |
} else |
tag = ""; |
if (t == '{') { |
static char follow[] = { IF, 0 }; |
int n = 0; |
long k = -1; |
List idlist = 0; |
ty = newstruct(ENUM, tag); |
t = gettok(); |
if (t != ID) |
error("expecting an enumerator identifier\n"); |
while (t == ID) { |
char *id = token; |
Coordinate s; |
if (tsym && tsym->scope == level) |
error("redeclaration of `%s' previously declared at %w\n", |
token, &tsym->src); |
s = src; |
t = gettok(); |
if (t == '=') { |
t = gettok(); |
k = intexpr(0, 0); |
} else { |
if (k == inttype->u.sym->u.limits.max.i) |
error("overflow in value for enumeration constant `%s'\n", id); |
k++; |
} |
p = install(id, &identifiers, level, level < LOCAL ? PERM : FUNC); |
p->src = s; |
p->type = ty; |
p->sclass = ENUM; |
p->u.value = k; |
idlist = append(p, idlist); |
n++; |
if (Aflag >= 2 && n == 128) |
warning("more than 127 enumeration constants in `%t'\n", ty); |
if (t != ',') |
break; |
t = gettok(); |
if (Aflag >= 2 && t == '}') |
warning("non-ANSI trailing comma in enumerator list\n"); |
} |
test('}', follow); |
ty->type = inttype; |
ty->size = ty->type->size; |
ty->align = ty->type->align; |
ty->u.sym->u.idlist = ltov(&idlist, PERM); |
ty->u.sym->defined = 1; |
} else if ((p = lookup(tag, types)) != NULL && p->type->op == ENUM) { |
ty = p->type; |
if (t == ';') |
error("empty declaration\n"); |
} else { |
error("unknown enumeration `%s'\n", tag); |
ty = newstruct(ENUM, tag); |
ty->type = inttype; |
} |
if (*tag && xref) |
use(p, pos); |
return ty; |
} |
|
Type typename(void) { |
Type ty = specifier(NULL); |
|
if (t == '*' || t == '(' || t == '[') { |
ty = dclr(ty, NULL, NULL, 1); |
if (Aflag >= 1 && !hasproto(ty)) |
warning("missing prototype\n"); |
} |
return ty; |
} |
|
/dagcheck.md
0,0 → 1,212
%{ |
#include "c.h" |
typedef Node NODEPTR_TYPE; |
#define OP_LABEL(p) (specific((p)->op)) |
#define LEFT_CHILD(p) ((p)->kids[0]) |
#define RIGHT_CHILD(p) ((p)->kids[1]) |
#define STATE_LABEL(p) ((p)->x.state) |
#define PANIC error |
%} |
%term CNSTF=17 CNSTI=21 CNSTP=23 CNSTU=22 |
%term ARGB=41 ARGF=33 ARGI=37 ARGP=39 ARGU=38 |
%term ASGNB=57 ASGNF=49 ASGNI=53 ASGNP=55 ASGNU=54 |
%term INDIRB=73 INDIRF=65 INDIRI=69 INDIRP=71 INDIRU=70 |
%term CVFF=113 CVFI=117 |
%term CVIF=129 CVII=133 CVIU=134 |
%term CVPP=151 CVPU=150 |
%term CVUI=181 CVUP=183 CVUU=182 |
%term NEGF=193 NEGI=197 |
%term CALLB=217 CALLF=209 CALLI=213 CALLP=215 CALLU=214 CALLV=216 |
%term RETF=241 RETI=245 RETP=247 RETU=246 RETV=248 |
%term ADDRGP=263 |
%term ADDRFP=279 |
%term ADDRLP=295 |
%term ADDF=305 ADDI=309 ADDP=311 ADDU=310 |
%term SUBF=321 SUBI=325 SUBP=327 SUBU=326 |
%term LSHI=341 LSHU=342 |
%term MODI=357 MODU=358 |
%term RSHI=373 RSHU=374 |
%term BANDI=389 BANDU=390 |
%term BCOMI=405 BCOMU=406 |
%term BORI=421 BORU=422 |
%term BXORI=437 BXORU=438 |
%term DIVF=449 DIVI=453 DIVU=454 |
%term MULF=465 MULI=469 MULU=470 |
%term EQF=481 EQI=485 EQU=486 |
%term GEF=497 GEI=501 GEU=502 |
%term GTF=513 GTI=517 GTU=518 |
%term LEF=529 LEI=533 LEU=534 |
%term LTF=545 LTI=549 LTU=550 |
%term NEF=561 NEI=565 NEU=566 |
%term JUMPV=584 |
%term LABELV=600 |
%% |
stmt: INDIRB(P) "" |
stmt: INDIRF(P) "" |
stmt: INDIRI(P) "" |
stmt: INDIRU(P) "" |
stmt: INDIRP(P) "" |
stmt: CALLF(P) "" |
stmt: CALLI(P) "" |
stmt: CALLU(P) "" |
stmt: CALLP(P) "" |
stmt: V "" |
bogus: I "" 1 |
bogus: U "" 1 |
bogus: P "" 1 |
bogus: F "" 1 |
bogus: B "" 1 |
bogus: V "" 1 |
I: bogus "" 1 |
U: bogus "" 1 |
P: bogus "" 1 |
F: bogus "" 1 |
B: bogus "" 1 |
V: bogus "" 1 |
F: CNSTF "" |
I: CNSTI "" |
P: CNSTP "" |
U: CNSTU "" |
V: ARGB(B) "" |
V: ARGF(F) "" |
V: ARGI(I) "" |
V: ARGU(U) "" |
V: ARGP(P) "" |
V: ASGNB(P,B) "" |
V: ASGNF(P,F) "" |
V: ASGNI(P,I) "" |
V: ASGNU(P,U) "" |
V: ASGNP(P,P) "" |
B: INDIRB(P) "" |
F: INDIRF(P) "" |
I: INDIRI(P) "" |
U: INDIRU(P) "" |
P: INDIRP(P) "" |
I: CVII(I) "" |
I: CVUI(U) "" |
I: CVFI(F) "" |
U: CVIU(I) "" |
U: CVUU(U) "" |
U: CVPU(P) "" |
F: CVIF(I) "" |
F: CVFF(F) "" |
P: CVUP(U) "" |
P: CVPP(P) "" |
F: NEGF(F) "" |
I: NEGI(I) "" |
V: CALLB(P,P) "" |
F: CALLF(P) "" |
I: CALLI(P) "" |
U: CALLU(P) "" |
P: CALLP(P) "" |
V: CALLV(P) "" |
V: RETF(F) "" |
V: RETI(I) "" |
V: RETU(U) "" |
V: RETP(P) "" |
V: RETV "" |
P: ADDRGP "" |
P: ADDRFP "" |
P: ADDRLP "" |
F: ADDF(F,F) "" |
I: ADDI(I,I) "" |
P: ADDP(P,I) "" |
P: ADDP(I,P) "" |
P: ADDP(U,P) "" |
P: ADDP(P,U) "" |
U: ADDU(U,U) "" |
F: SUBF(F,F) "" |
I: SUBI(I,I) "" |
P: SUBP(P,I) "" |
P: SUBP(P,U) "" |
U: SUBU(U,U) "" |
I: LSHI(I,I) "" |
U: LSHU(U,I) "" |
I: MODI(I,I) "" |
U: MODU(U,U) "" |
I: RSHI(I,I) "" |
U: RSHU(U,I) "" |
U: BANDU(U,U) "" |
I: BANDI(I,I) "" |
U: BCOMU(U) "" |
I: BCOMI(I) "" |
I: BORI(I,I) "" |
U: BORU(U,U) "" |
U: BXORU(U,U) "" |
I: BXORI(I,I) "" |
F: DIVF(F,F) "" |
I: DIVI(I,I) "" |
U: DIVU(U,U) "" |
F: MULF(F,F) "" |
I: MULI(I,I) "" |
U: MULU(U,U) "" |
V: EQF(F,F) "" |
V: EQI(I,I) "" |
V: EQU(U,U) "" |
V: GEF(F,F) "" |
V: GEI(I,I) "" |
V: GEU(U,U) "" |
V: GTF(F,F) "" |
V: GTI(I,I) "" |
V: GTU(U,U) "" |
V: LEF(F,F) "" |
V: LEI(I,I) "" |
V: LEU(U,U) "" |
V: LTF(F,F) "" |
V: LTI(I,I) "" |
V: LTU(U,U) "" |
V: NEF(F,F) "" |
V: NEI(I,I) "" |
V: NEU(U,U) "" |
V: JUMPV(P) "" |
V: LABELV "" |
%% |
|
static void reduce(NODEPTR_TYPE p, int goalnt) { |
int i, sz = opsize(p->op), rulenumber = _rule(p->x.state, goalnt); |
short *nts = _nts[rulenumber]; |
NODEPTR_TYPE kids[10]; |
|
assert(rulenumber); |
_kids(p, rulenumber, kids); |
for (i = 0; nts[i]; i++) |
reduce(kids[i], nts[i]); |
switch (optype(p->op)) { |
#define xx(ty) if (sz == ty->size) return |
case I: |
case U: |
xx(chartype); |
xx(shorttype); |
xx(inttype); |
xx(longtype); |
xx(longlong); |
xx(signedptr); |
xx(unsignedptr); |
break; |
case F: |
xx(floattype); |
xx(doubletype); |
xx(longdouble); |
break; |
case P: |
xx(voidptype); |
xx(funcptype); |
break; |
case V: |
case B: if (sz == 0) return; |
#undef xx |
} |
printdag(p, 2); |
assert(0); |
} |
|
void check(Node p) { |
struct _state { short cost[1]; }; |
|
_label(p); |
if (((struct _state *)p->x.state)->cost[1] > 0) { |
printdag(p, 2); |
assert(0); |
} |
reduce(p, 1); |
} |
/simp.c
0,0 → 1,600
#include "c.h" |
#include <float.h> |
|
static char rcsid[] = "$Id: simp.c,v 1.1 2002/08/28 23:12:45 drh Exp $"; |
|
#define foldcnst(TYPE,VAR,OP) \ |
if (l->op == CNST+TYPE && r->op == CNST+TYPE) \ |
return cnsttree(ty, l->u.v.VAR OP r->u.v.VAR) |
#define commute(L,R) \ |
if (generic(R->op) == CNST && generic(L->op) != CNST) \ |
do { Tree t = L; L = R; R = t; } while(0) |
#define xfoldcnst(TYPE,VAR,OP,FUNC)\ |
if (l->op == CNST+TYPE && r->op == CNST+TYPE\ |
&& FUNC(l->u.v.VAR,r->u.v.VAR,\ |
ty->u.sym->u.limits.min.VAR,\ |
ty->u.sym->u.limits.max.VAR, needconst)) \ |
return cnsttree(ty, l->u.v.VAR OP r->u.v.VAR) |
#define xcvtcnst(FTYPE,SRC,DST,VAR,EXPR) \ |
if (l->op == CNST+FTYPE) do {\ |
if (!explicitCast\ |
&& ((SRC) < DST->u.sym->u.limits.min.VAR || (SRC) > DST->u.sym->u.limits.max.VAR))\ |
warning("overflow in converting constant expression from `%t' to `%t'\n", l->type, DST);\ |
if (needconst\ |
|| !((SRC) < DST->u.sym->u.limits.min.VAR || (SRC) > DST->u.sym->u.limits.max.VAR))\ |
return cnsttree(ty, (EXPR)); } while(0) |
#define identity(X,Y,TYPE,VAR,VAL) \ |
if (X->op == CNST+TYPE && X->u.v.VAR == VAL) return Y |
#define zerofield(OP,TYPE,VAR) \ |
if (l->op == FIELD \ |
&& r->op == CNST+TYPE && r->u.v.VAR == 0)\ |
return eqtree(OP, bittree(BAND, l->kids[0],\ |
cnsttree(unsignedtype, \ |
(unsigned long)fieldmask(l->u.field)<<fieldright(l->u.field))), r) |
#define cfoldcnst(TYPE,VAR,OP) \ |
if (l->op == CNST+TYPE && r->op == CNST+TYPE) \ |
return cnsttree(inttype, (long)(l->u.v.VAR OP r->u.v.VAR)) |
#define foldaddp(L,R,RTYPE,VAR) \ |
if (L->op == CNST+P && R->op == CNST+RTYPE) { \ |
Tree e = tree(CNST+P, ty, NULL, NULL);\ |
e->u.v.p = (char *)L->u.v.p + R->u.v.VAR;\ |
return e; } |
#define ufoldcnst(TYPE,EXP) if (l->op == CNST+TYPE) return EXP |
#define sfoldcnst(OP) \ |
if (l->op == CNST+U && r->op == CNST+I \ |
&& r->u.v.i >= 0 && r->u.v.i < 8*l->type->size) \ |
return cnsttree(ty, (unsigned long)(l->u.v.u OP r->u.v.i)) |
#define geu(L,R,V) \ |
if (R->op == CNST+U && R->u.v.u == 0) do { \ |
warning("result of unsigned comparison is constant\n"); \ |
return tree(RIGHT, inttype, root(L), cnsttree(inttype, (long)(V))); } while(0) |
#define idempotent(OP) if (l->op == OP) return l->kids[0] |
|
int needconst; |
int explicitCast; |
static int addi(long x, long y, long min, long max, int needconst) { |
int cond = x == 0 || y == 0 |
|| x < 0 && y < 0 && x >= min - y |
|| x < 0 && y > 0 |
|| x > 0 && y < 0 |
|| x > 0 && y > 0 && x <= max - y; |
if (!cond && needconst) { |
warning("overflow in constant expression\n"); |
cond = 1; |
} |
return cond; |
|
|
} |
|
static int addd(double x, double y, double min, double max, int needconst) { |
int cond = x == 0 || y == 0 |
|| x < 0 && y < 0 && x >= min - y |
|| x < 0 && y > 0 |
|| x > 0 && y < 0 |
|| x > 0 && y > 0 && x <= max - y; |
if (!cond && needconst) { |
warning("overflow in constant expression\n"); |
cond = 1; |
} |
return cond; |
|
|
} |
|
static Tree addrtree(Tree e, long n, Type ty) { |
Symbol p = e->u.sym, q; |
|
if (p->scope == GLOBAL |
|| p->sclass == STATIC || p->sclass == EXTERN) |
NEW0(q, PERM); |
else |
NEW0(q, FUNC); |
q->name = stringd(genlabel(1)); |
q->sclass = p->sclass; |
q->scope = p->scope; |
assert(isptr(ty) || isarray(ty)); |
q->type = isptr(ty) ? ty->type : ty; |
q->temporary = p->temporary; |
q->generated = p->generated; |
q->addressed = p->addressed; |
q->computed = 1; |
q->defined = 1; |
q->ref = 1; |
assert(IR->address); |
if (p->scope == GLOBAL |
|| p->sclass == STATIC || p->sclass == EXTERN) { |
if (p->sclass == AUTO) |
q->sclass = STATIC; |
(*IR->address)(q, p, n); |
} else { |
Code cp; |
addlocal(p); |
cp = code(Address); |
cp->u.addr.sym = q; |
cp->u.addr.base = p; |
cp->u.addr.offset = n; |
} |
e = tree(e->op, ty, NULL, NULL); |
e->u.sym = q; |
return e; |
} |
|
/* div[id] - return 1 if min <= x/y <= max, 0 otherwise */ |
static int divi(long x, long y, long min, long max, int needconst) { |
int cond = y != 0 && !(x == min && y == -1); |
if (!cond && needconst) { |
warning("overflow in constant expression\n"); |
cond = 1; |
} |
return cond; |
|
|
} |
|
static int divd(double x, double y, double min, double max, int needconst) { |
int cond; |
|
if (x < 0) x = -x; |
if (y < 0) y = -y; |
cond = y != 0 && !(y < 1 && x > max*y); |
if (!cond && needconst) { |
warning("overflow in constant expression\n"); |
cond = 1; |
} |
return cond; |
|
} |
|
/* mul[id] - return 1 if min <= x*y <= max, 0 otherwise */ |
static int muli(long x, long y, long min, long max, int needconst) { |
int cond = x > -1 && x <= 1 || y > -1 && y <= 1 |
|| x < 0 && y < 0 && -x <= max/-y |
|| x < 0 && y > 0 && x >= min/y |
|| x > 0 && y < 0 && y >= min/x |
|| x > 0 && y > 0 && x <= max/y; |
if (!cond && needconst) { |
warning("overflow in constant expression\n"); |
cond = 1; |
} |
return cond; |
|
|
} |
|
static int muld(double x, double y, double min, double max, int needconst) { |
int cond = x >= -1 && x <= 1 || y >= -1 && y <= 1 |
|| x < 0 && y < 0 && -x <= max/-y |
|| x < 0 && y > 0 && x >= min/y |
|| x > 0 && y < 0 && y >= min/x |
|| x > 0 && y > 0 && x <= max/y; |
if (!cond && needconst) { |
warning("overflow in constant expression\n"); |
cond = 1; |
} |
return cond; |
|
|
} |
/* sub[id] - return 1 if min <= x-y <= max, 0 otherwise */ |
static int subi(long x, long y, long min, long max, int needconst) { |
return addi(x, -y, min, max, needconst); |
} |
|
static int subd(double x, double y, double min, double max, int needconst) { |
return addd(x, -y, min, max, needconst); |
} |
Tree constexpr(int tok) { |
Tree p; |
|
needconst++; |
p = expr1(tok); |
needconst--; |
return p; |
} |
|
int intexpr(int tok, int n) { |
Tree p = constexpr(tok); |
|
needconst++; |
if (p->op == CNST+I || p->op == CNST+U) |
n = cast(p, inttype)->u.v.i; |
else |
error("integer expression must be constant\n"); |
needconst--; |
return n; |
} |
Tree simplify(int op, Type ty, Tree l, Tree r) { |
int n; |
Tree p; |
|
if (optype(op) == 0) |
op = mkop(op, ty); |
switch (op) { |
case ADD+U: |
foldcnst(U,u,+); |
commute(r,l); |
identity(r,l,U,u,0); |
break; |
case ADD+I: |
xfoldcnst(I,i,+,addi); |
commute(r,l); |
identity(r,l,I,i,0); |
break; |
case CVI+I: |
xcvtcnst(I,l->u.v.i,ty,i,(long)extend(l->u.v.i,ty)); |
break; |
case CVU+I: |
if (l->op == CNST+U) { |
if (!explicitCast && l->u.v.u > ty->u.sym->u.limits.max.i) |
warning("overflow in converting constant expression from `%t' to `%t'\n", l->type, ty); |
if (needconst || !(l->u.v.u > ty->u.sym->u.limits.max.i)) |
return cnsttree(ty, (long)extend(l->u.v.u,ty)); |
} |
break; |
case CVP+U: |
xcvtcnst(P,(unsigned long)l->u.v.p,ty,u,(unsigned long)l->u.v.p); |
break; |
case CVU+P: |
xcvtcnst(U,(void*)l->u.v.u,ty,p,(void*)l->u.v.u); |
break; |
case CVP+P: |
xcvtcnst(P,l->u.v.p,ty,p,l->u.v.p); |
break; |
case CVI+U: |
xcvtcnst(I,l->u.v.i,ty,u,((unsigned long)l->u.v.i)&ones(8*ty->size)); |
break; |
case CVU+U: |
xcvtcnst(U,l->u.v.u,ty,u,l->u.v.u&ones(8*ty->size)); |
break; |
|
case CVI+F: |
xcvtcnst(I,l->u.v.i,ty,d,(long double)l->u.v.i); |
case CVU+F: |
xcvtcnst(U,l->u.v.u,ty,d,(long double)l->u.v.u); |
break; |
case CVF+I: |
xcvtcnst(F,l->u.v.d,ty,i,(long)l->u.v.d); |
break; |
case CVF+F: { |
float d; |
if (l->op == CNST+F) |
if (l->u.v.d < ty->u.sym->u.limits.min.d) |
d = ty->u.sym->u.limits.min.d; |
else if (l->u.v.d > ty->u.sym->u.limits.max.d) |
d = ty->u.sym->u.limits.max.d; |
else |
d = l->u.v.d; |
xcvtcnst(F,l->u.v.d,ty,d,(long double)d); |
break; |
} |
case BAND+U: |
foldcnst(U,u,&); |
commute(r,l); |
identity(r,l,U,u,ones(8*ty->size)); |
if (r->op == CNST+U && r->u.v.u == 0) |
return tree(RIGHT, ty, root(l), cnsttree(ty, 0UL)); |
break; |
case BAND+I: |
foldcnst(I,i,&); |
commute(r,l); |
identity(r,l,I,i,ones(8*ty->size)); |
if (r->op == CNST+I && r->u.v.u == 0) |
return tree(RIGHT, ty, root(l), cnsttree(ty, 0L)); |
break; |
|
case MUL+U: |
commute(l,r); |
if (l->op == CNST+U && (n = ispow2(l->u.v.u)) != 0) |
return simplify(LSH, ty, r, cnsttree(inttype, (long)n)); |
foldcnst(U,u,*); |
identity(r,l,U,u,1); |
break; |
case NE+I: |
cfoldcnst(I,i,!=); |
commute(r,l); |
zerofield(NE,I,i); |
break; |
|
case EQ+I: |
cfoldcnst(I,i,==); |
commute(r,l); |
zerofield(EQ,I,i); |
break; |
case ADD+P: |
foldaddp(l,r,I,i); |
foldaddp(l,r,U,u); |
foldaddp(r,l,I,i); |
foldaddp(r,l,U,u); |
commute(r,l); |
identity(r,retype(l,ty),I,i,0); |
identity(r,retype(l,ty),U,u,0); |
/* |
Some assemblers, e.g., the MIPS, can't handle offsets |
larger than 16 bits. A better solution would be to change |
the interface so that address() could fail. |
*/ |
if (l->op == ADDRG+P && l->u.sym->generated |
&& (r->op == CNST+I && (r->u.v.i > 32767 || r->u.v.i < -32768) |
|| r->op == CNST+U && r->u.v.u > 65536)) |
break; |
if (IR->address |
&& isaddrop(l->op) |
&& (r->op == CNST+I && r->u.v.i <= longtype->u.sym->u.limits.max.i |
&& r->u.v.i >= longtype->u.sym->u.limits.min.i |
|| r->op == CNST+U && r->u.v.u <= longtype->u.sym->u.limits.max.i)) |
return addrtree(l, cast(r, longtype)->u.v.i, ty); |
if (IR->address |
&& l->op == ADD+P && isaddrop(l->kids[1]->op) |
&& (r->op == CNST+I && r->u.v.i <= longtype->u.sym->u.limits.max.i |
&& r->u.v.i >= longtype->u.sym->u.limits.min.i |
|| r->op == CNST+U && r->u.v.u <= longtype->u.sym->u.limits.max.i)) |
return simplify(ADD+P, ty, l->kids[0], |
addrtree(l->kids[1], cast(r, longtype)->u.v.i, ty)); |
if ((l->op == ADD+I || l->op == SUB+I) |
&& l->kids[1]->op == CNST+I && isaddrop(r->op)) |
return simplify(ADD+P, ty, l->kids[0], |
simplify(generic(l->op)+P, ty, r, l->kids[1])); |
if (l->op == ADD+P && generic(l->kids[1]->op) == CNST |
&& generic(r->op) == CNST) |
return simplify(ADD+P, ty, l->kids[0], |
simplify(ADD, l->kids[1]->type, l->kids[1], r)); |
if (l->op == ADD+I && generic(l->kids[1]->op) == CNST |
&& r->op == ADD+P && generic(r->kids[1]->op) == CNST) |
return simplify(ADD+P, ty, l->kids[0], |
simplify(ADD+P, ty, r->kids[0], |
simplify(ADD, r->kids[1]->type, l->kids[1], r->kids[1]))); |
if (l->op == RIGHT && l->kids[1]) |
return tree(RIGHT, ty, l->kids[0], |
simplify(ADD+P, ty, l->kids[1], r)); |
else if (l->op == RIGHT && l->kids[0]) |
return tree(RIGHT, ty, |
simplify(ADD+P, ty, l->kids[0], r), NULL); |
break; |
|
case ADD+F: |
xfoldcnst(F,d,+,addd); |
commute(r,l); |
break; |
case AND+I: |
op = AND; |
ufoldcnst(I,l->u.v.i ? cond(r) : l); /* 0&&r => 0, 1&&r => r */ |
break; |
case OR+I: |
op = OR; |
/* 0||r => r, 1||r => 1 */ |
ufoldcnst(I,l->u.v.i ? cnsttree(ty, 1L) : cond(r)); |
break; |
case BCOM+I: |
ufoldcnst(I,cnsttree(ty, (long)extend((~l->u.v.i)&ones(8*ty->size), ty))); |
idempotent(BCOM+U); |
break; |
case BCOM+U: |
ufoldcnst(U,cnsttree(ty, (unsigned long)((~l->u.v.u)&ones(8*ty->size)))); |
idempotent(BCOM+U); |
break; |
case BOR+U: |
foldcnst(U,u,|); |
commute(r,l); |
identity(r,l,U,u,0); |
break; |
case BOR+I: |
foldcnst(I,i,|); |
commute(r,l); |
identity(r,l,I,i,0); |
break; |
case BXOR+U: |
foldcnst(U,u,^); |
commute(r,l); |
identity(r,l,U,u,0); |
break; |
case BXOR+I: |
foldcnst(I,i,^); |
commute(r,l); |
identity(r,l,I,i,0); |
break; |
case DIV+F: |
xfoldcnst(F,d,/,divd); |
break; |
case DIV+I: |
identity(r,l,I,i,1); |
if (r->op == CNST+I && r->u.v.i == 0 |
|| l->op == CNST+I && l->u.v.i == ty->u.sym->u.limits.min.i |
&& r->op == CNST+I && r->u.v.i == -1) |
break; |
xfoldcnst(I,i,/,divi); |
break; |
case DIV+U: |
identity(r,l,U,u,1); |
if (r->op == CNST+U && r->u.v.u == 0) |
break; |
if (r->op == CNST+U && (n = ispow2(r->u.v.u)) != 0) |
return simplify(RSH, ty, l, cnsttree(inttype, (long)n)); |
foldcnst(U,u,/); |
break; |
case EQ+F: |
cfoldcnst(F,d,==); |
commute(r,l); |
break; |
case EQ+U: |
cfoldcnst(U,u,==); |
commute(r,l); |
zerofield(EQ,U,u); |
break; |
case GE+F: cfoldcnst(F,d,>=); break; |
case GE+I: cfoldcnst(I,i,>=); break; |
case GE+U: |
geu(l,r,1); /* l >= 0 => (l,1) */ |
cfoldcnst(U,u,>=); |
if (l->op == CNST+U && l->u.v.u == 0) /* 0 >= r => r == 0 */ |
return eqtree(EQ, r, l); |
break; |
case GT+F: cfoldcnst(F,d, >); break; |
case GT+I: cfoldcnst(I,i, >); break; |
case GT+U: |
geu(r,l,0); /* 0 > r => (r,0) */ |
cfoldcnst(U,u, >); |
if (r->op == CNST+U && r->u.v.u == 0) /* l > 0 => l != 0 */ |
return eqtree(NE, l, r); |
break; |
case LE+F: cfoldcnst(F,d,<=); break; |
case LE+I: cfoldcnst(I,i,<=); break; |
case LE+U: |
geu(r,l,1); /* 0 <= r => (r,1) */ |
cfoldcnst(U,u,<=); |
if (r->op == CNST+U && r->u.v.u == 0) /* l <= 0 => l == 0 */ |
return eqtree(EQ, l, r); |
break; |
case LSH+I: |
identity(r,l,I,i,0); |
if (l->op == CNST+I && r->op == CNST+I |
&& r->u.v.i >= 0 && r->u.v.i < 8*l->type->size |
&& muli(l->u.v.i, 1<<r->u.v.i, ty->u.sym->u.limits.min.i, ty->u.sym->u.limits.max.i, needconst)) |
return cnsttree(ty, (long)(l->u.v.i<<r->u.v.i)); |
if (r->op == CNST+I && (r->u.v.i >= 8*ty->size || r->u.v.i < 0)) { |
warning("shifting an `%t' by %d bits is undefined\n", ty, r->u.v.i); |
break; |
} |
|
break; |
case LSH+U: |
identity(r,l,I,i,0); |
sfoldcnst(<<); |
if (r->op == CNST+I && (r->u.v.i >= 8*ty->size || r->u.v.i < 0)) { |
warning("shifting an `%t' by %d bits is undefined\n", ty, r->u.v.i); |
break; |
} |
|
break; |
|
case LT+F: cfoldcnst(F,d, <); break; |
case LT+I: cfoldcnst(I,i, <); break; |
case LT+U: |
geu(l,r,0); /* l < 0 => (l,0) */ |
cfoldcnst(U,u, <); |
if (l->op == CNST+U && l->u.v.u == 0) /* 0 < r => r != 0 */ |
return eqtree(NE, r, l); |
break; |
case MOD+I: |
if (r->op == CNST+I && r->u.v.i == 0 |
|| l->op == CNST+I && l->u.v.i == ty->u.sym->u.limits.min.i |
&& r->op == CNST+I && r->u.v.i == -1) |
break; |
xfoldcnst(I,i,%,divi); |
if (r->op == CNST+I && r->u.v.i == 1) /* l%1 => (l,0) */ |
return tree(RIGHT, ty, root(l), cnsttree(ty, 0L)); |
break; |
case MOD+U: |
if (r->op == CNST+U && ispow2(r->u.v.u)) /* l%2^n => l&(2^n-1) */ |
return bittree(BAND, l, cnsttree(ty, r->u.v.u - 1)); |
if (r->op == CNST+U && r->u.v.u == 0) |
break; |
foldcnst(U,u,%); |
break; |
case MUL+F: |
xfoldcnst(F,d,*,muld); |
commute(l,r); |
break; |
case MUL+I: |
commute(l,r); |
xfoldcnst(I,i,*,muli); |
if (l->op == CNST+I && r->op == ADD+I && r->kids[1]->op == CNST+I) |
/* c1*(x + c2) => c1*x + c1*c2 */ |
return simplify(ADD, ty, simplify(MUL, ty, l, r->kids[0]), |
simplify(MUL, ty, l, r->kids[1])); |
if (l->op == CNST+I && r->op == SUB+I && r->kids[1]->op == CNST+I) |
/* c1*(x - c2) => c1*x - c1*c2 */ |
return simplify(SUB, ty, simplify(MUL, ty, l, r->kids[0]), |
simplify(MUL, ty, l, r->kids[1])); |
if (l->op == CNST+I && l->u.v.i > 0 && (n = ispow2(l->u.v.i)) != 0) |
/* 2^n * r => r<<n */ |
return simplify(LSH, ty, r, cnsttree(inttype, (long)n)); |
identity(r,l,I,i,1); |
break; |
case NE+F: |
cfoldcnst(F,d,!=); |
commute(r,l); |
break; |
case NE+U: |
cfoldcnst(U,u,!=); |
commute(r,l); |
zerofield(NE,U,u); |
break; |
case NEG+F: |
ufoldcnst(F,cnsttree(ty, -l->u.v.d)); |
idempotent(NEG+F); |
break; |
case NEG+I: |
if (l->op == CNST+I) { |
if (needconst && l->u.v.i == ty->u.sym->u.limits.min.i) |
warning("overflow in constant expression\n"); |
if (needconst || l->u.v.i != ty->u.sym->u.limits.min.i) |
return cnsttree(ty, -l->u.v.i); |
} |
idempotent(NEG+I); |
break; |
case NOT+I: |
op = NOT; |
ufoldcnst(I,cnsttree(ty, !l->u.v.i)); |
break; |
case RSH+I: |
identity(r,l,I,i,0); |
if (l->op == CNST+I && r->op == CNST+I |
&& r->u.v.i >= 0 && r->u.v.i < 8*l->type->size) { |
long n = l->u.v.i>>r->u.v.i; |
if (l->u.v.i < 0) |
n |= ~0UL<<(8*l->type->size - r->u.v.i); |
return cnsttree(ty, n); |
} |
if (r->op == CNST+I && (r->u.v.i >= 8*ty->size || r->u.v.i < 0)) { |
warning("shifting an `%t' by %d bits is undefined\n", ty, r->u.v.i); |
break; |
} |
|
break; |
case RSH+U: |
identity(r,l,I,i,0); |
sfoldcnst(>>); |
if (r->op == CNST+I && (r->u.v.i >= 8*ty->size || r->u.v.i < 0)) { |
warning("shifting an `%t' by %d bits is undefined\n", ty, r->u.v.i); |
break; |
} |
|
break; |
case SUB+F: |
xfoldcnst(F,d,-,subd); |
break; |
case SUB+I: |
xfoldcnst(I,i,-,subi); |
identity(r,l,I,i,0); |
break; |
case SUB+U: |
foldcnst(U,u,-); |
identity(r,l,U,u,0); |
break; |
case SUB+P: |
if (l->op == CNST+P && r->op == CNST+P) |
return cnsttree(ty, (long)((char *)l->u.v.p - (char *)r->u.v.p)); |
if (r->op == CNST+I || r->op == CNST+U) |
return simplify(ADD, ty, l, |
cnsttree(inttype, r->op == CNST+I ? -r->u.v.i : -(long)r->u.v.u)); |
if (isaddrop(l->op) && r->op == ADD+I && r->kids[1]->op == CNST+I) |
/* l - (x + c) => l-c - x */ |
return simplify(SUB, ty, |
simplify(SUB, ty, l, r->kids[1]), r->kids[0]); |
break; |
default:assert(0); |
} |
return tree(op, ty, l, r); |
} |
/* ispow2 - if u > 1 && u == 2^n, return n, otherwise return 0 */ |
int ispow2(unsigned long u) { |
int n; |
|
if (u > 1 && (u&(u-1)) == 0) |
for (n = 0; u; u >>= 1, n++) |
if (u&1) |
return n; |
return 0; |
} |
|
/sym.c
0,0 → 1,332
#include "c.h" |
#include <stdio.h> |
|
static char rcsid[] = "$Id: sym.c,v 1.1 2002/08/28 23:12:47 drh Exp $"; |
|
#define equalp(x) v.x == p->sym.u.c.v.x |
|
struct table { |
int level; |
Table previous; |
struct entry { |
struct symbol sym; |
struct entry *link; |
} *buckets[256]; |
Symbol all; |
}; |
#define HASHSIZE NELEMS(((Table)0)->buckets) |
static struct table |
cns = { CONSTANTS }, |
ext = { GLOBAL }, |
ids = { GLOBAL }, |
tys = { GLOBAL }; |
Table constants = &cns; |
Table externals = &ext; |
Table identifiers = &ids; |
Table globals = &ids; |
Table types = &tys; |
Table labels; |
int level = GLOBAL; |
static int tempid; |
List loci, symbols; |
|
Table newtable(int arena) { |
Table new; |
|
NEW0(new, arena); |
return new; |
} |
|
Table table(Table tp, int level) { |
Table new = newtable(FUNC); |
new->previous = tp; |
new->level = level; |
if (tp) |
new->all = tp->all; |
return new; |
} |
void foreach(Table tp, int lev, void (*apply)(Symbol, void *), void *cl) { |
assert(tp); |
while (tp && tp->level > lev) |
tp = tp->previous; |
if (tp && tp->level == lev) { |
Symbol p; |
Coordinate sav; |
sav = src; |
for (p = tp->all; p && p->scope == lev; p = p->up) { |
src = p->src; |
(*apply)(p, cl); |
} |
src = sav; |
} |
} |
void enterscope(void) { |
if (++level == LOCAL) |
tempid = 0; |
} |
void exitscope(void) { |
rmtypes(level); |
if (types->level == level) |
types = types->previous; |
if (identifiers->level == level) { |
if (Aflag >= 2) { |
int n = 0; |
Symbol p; |
for (p = identifiers->all; p && p->scope == level; p = p->up) |
if (++n > 127) { |
warning("more than 127 identifiers declared in a block\n"); |
break; |
} |
} |
identifiers = identifiers->previous; |
} |
assert(level >= GLOBAL); |
--level; |
} |
Symbol install(const char *name, Table *tpp, int level, int arena) { |
Table tp = *tpp; |
struct entry *p; |
unsigned h = (unsigned long)name&(HASHSIZE-1); |
|
assert(level == 0 || level >= tp->level); |
if (level > 0 && tp->level < level) |
tp = *tpp = table(tp, level); |
NEW0(p, arena); |
p->sym.name = (char *)name; |
p->sym.scope = level; |
p->sym.up = tp->all; |
tp->all = &p->sym; |
p->link = tp->buckets[h]; |
tp->buckets[h] = p; |
return &p->sym; |
} |
Symbol relocate(const char *name, Table src, Table dst) { |
struct entry *p, **q; |
Symbol *r; |
unsigned h = (unsigned long)name&(HASHSIZE-1); |
|
for (q = &src->buckets[h]; *q; q = &(*q)->link) |
if (name == (*q)->sym.name) |
break; |
assert(*q); |
/* |
Remove the entry from src's hash chain |
and from its list of all symbols. |
*/ |
p = *q; |
*q = (*q)->link; |
for (r = &src->all; *r && *r != &p->sym; r = &(*r)->up) |
; |
assert(*r == &p->sym); |
*r = p->sym.up; |
/* |
Insert the entry into dst's hash chain |
and into its list of all symbols. |
Return the symbol-table entry. |
*/ |
p->link = dst->buckets[h]; |
dst->buckets[h] = p; |
p->sym.up = dst->all; |
dst->all = &p->sym; |
return &p->sym; |
} |
Symbol lookup(const char *name, Table tp) { |
struct entry *p; |
unsigned h = (unsigned long)name&(HASHSIZE-1); |
|
assert(tp); |
do |
for (p = tp->buckets[h]; p; p = p->link) |
if (name == p->sym.name) |
return &p->sym; |
while ((tp = tp->previous) != NULL); |
return NULL; |
} |
int genlabel(int n) { |
static int label = 1; |
|
label += n; |
return label - n; |
} |
Symbol findlabel(int lab) { |
struct entry *p; |
unsigned h = lab&(HASHSIZE-1); |
|
for (p = labels->buckets[h]; p; p = p->link) |
if (lab == p->sym.u.l.label) |
return &p->sym; |
NEW0(p, FUNC); |
p->sym.name = stringd(lab); |
p->sym.scope = LABELS; |
p->sym.up = labels->all; |
labels->all = &p->sym; |
p->link = labels->buckets[h]; |
labels->buckets[h] = p; |
p->sym.generated = 1; |
p->sym.u.l.label = lab; |
(*IR->defsymbol)(&p->sym); |
return &p->sym; |
} |
Symbol constant(Type ty, Value v) { |
struct entry *p; |
unsigned h = v.u&(HASHSIZE-1); |
static union { int x; char endian; } little = { 1 }; |
|
ty = unqual(ty); |
for (p = constants->buckets[h]; p; p = p->link) |
if (eqtype(ty, p->sym.type, 1)) |
switch (ty->op) { |
case INT: if (equalp(i)) return &p->sym; break; |
case UNSIGNED: if (equalp(u)) return &p->sym; break; |
case FLOAT: |
if (v.d == 0.0) { |
float z1 = v.d, z2 = p->sym.u.c.v.d; |
char *b1 = (char *)&z1, *b2 = (char *)&z2; |
if (z1 == z2 |
&& (!little.endian && b1[0] == b2[0] |
|| little.endian && b1[sizeof (z1)-1] == b2[sizeof (z2)-1])) |
return &p->sym; |
} else if (equalp(d)) |
return &p->sym; |
break; |
case FUNCTION: if (equalp(g)) return &p->sym; break; |
case ARRAY: |
case POINTER: if (equalp(p)) return &p->sym; break; |
default: assert(0); |
} |
NEW0(p, PERM); |
p->sym.name = vtoa(ty, v); |
p->sym.scope = CONSTANTS; |
p->sym.type = ty; |
p->sym.sclass = STATIC; |
p->sym.u.c.v = v; |
p->link = constants->buckets[h]; |
p->sym.up = constants->all; |
constants->all = &p->sym; |
constants->buckets[h] = p; |
if (ty->u.sym && !ty->u.sym->addressed) |
(*IR->defsymbol)(&p->sym); |
p->sym.defined = 1; |
return &p->sym; |
} |
Symbol intconst(int n) { |
Value v; |
|
v.i = n; |
return constant(inttype, v); |
} |
Symbol genident(int scls, Type ty, int lev) { |
Symbol p; |
|
NEW0(p, lev >= LOCAL ? FUNC : PERM); |
p->name = stringd(genlabel(1)); |
p->scope = lev; |
p->sclass = scls; |
p->type = ty; |
p->generated = 1; |
if (lev == GLOBAL) |
(*IR->defsymbol)(p); |
return p; |
} |
|
Symbol temporary(int scls, Type ty) { |
Symbol p; |
|
NEW0(p, FUNC); |
p->name = stringd(++tempid); |
p->scope = level < LOCAL ? LOCAL : level; |
p->sclass = scls; |
p->type = ty; |
p->temporary = 1; |
p->generated = 1; |
return p; |
} |
Symbol newtemp(int sclass, int tc, int size) { |
Symbol p = temporary(sclass, btot(tc, size)); |
|
(*IR->local)(p); |
p->defined = 1; |
return p; |
} |
|
Symbol allsymbols(Table tp) { |
return tp->all; |
} |
|
void locus(Table tp, Coordinate *cp) { |
loci = append(cp, loci); |
symbols = append(allsymbols(tp), symbols); |
} |
|
void use(Symbol p, Coordinate src) { |
Coordinate *cp; |
|
NEW(cp, PERM); |
*cp = src; |
p->uses = append(cp, p->uses); |
} |
/* findtype - find type ty in identifiers */ |
Symbol findtype(Type ty) { |
Table tp = identifiers; |
int i; |
struct entry *p; |
|
assert(tp); |
do |
for (i = 0; i < HASHSIZE; i++) |
for (p = tp->buckets[i]; p; p = p->link) |
if (p->sym.type == ty && p->sym.sclass == TYPEDEF) |
return &p->sym; |
while ((tp = tp->previous) != NULL); |
return NULL; |
} |
|
/* mkstr - make a string constant */ |
Symbol mkstr(char *str) { |
Value v; |
Symbol p; |
|
v.p = str; |
p = constant(array(chartype, strlen(v.p) + 1, 0), v); |
if (p->u.c.loc == NULL) |
p->u.c.loc = genident(STATIC, p->type, GLOBAL); |
return p; |
} |
|
/* mksymbol - make a symbol for name, install in &globals if sclass==EXTERN */ |
Symbol mksymbol(int sclass, const char *name, Type ty) { |
Symbol p; |
|
if (sclass == EXTERN) |
p = install(string(name), &globals, GLOBAL, PERM); |
else { |
NEW0(p, PERM); |
p->name = string(name); |
p->scope = GLOBAL; |
} |
p->sclass = sclass; |
p->type = ty; |
(*IR->defsymbol)(p); |
p->defined = 1; |
return p; |
} |
|
/* vtoa - return string for the constant v of type ty */ |
char *vtoa(Type ty, Value v) { |
char buf[50]; |
|
ty = unqual(ty); |
switch (ty->op) { |
case INT: return stringd(v.i); |
case UNSIGNED: return stringf((v.u&~0x7FFF) ? "0x%X" : "%U", v.u); |
case FLOAT: return stringf("%g", (double)v.d); |
case ARRAY: |
if (ty->type == chartype || ty->type == signedchar |
|| ty->type == unsignedchar) |
return v.p; |
return stringf("%p", v.p); |
case POINTER: return stringf("%p", v.p); |
case FUNCTION: return stringf("%p", v.g); |
} |
assert(0); return NULL; |
} |
/config.h
0,0 → 1,101
/* $Id: config.h,v 1.1 2002/08/28 23:12:42 drh Exp $ */ |
typedef struct { |
unsigned char max_unaligned_load; |
Symbol (*rmap)(int); |
|
void (*blkfetch)(int size, int off, int reg, int tmp); |
void (*blkstore)(int size, int off, int reg, int tmp); |
void (*blkloop)(int dreg, int doff, |
int sreg, int soff, |
int size, int tmps[]); |
void (*_label)(Node); |
int (*_rule)(void*, int); |
short **_nts; |
void (*_kids)(Node, int, Node*); |
char **_string; |
char **_templates; |
char *_isinstruction; |
char **_ntname; |
void (*emit2)(Node); |
void (*doarg)(Node); |
void (*target)(Node); |
void (*clobber)(Node); |
} Xinterface; |
extern int askregvar(Symbol, Symbol); |
extern void blkcopy(int, int, int, int, int, int[]); |
extern unsigned emitasm(Node, int); |
extern int getregnum(Node); |
extern int mayrecalc(Node); |
extern int mkactual(int, int); |
extern void mkauto(Symbol); |
extern Symbol mkreg(char *, int, int, int); |
extern Symbol mkwildcard(Symbol *); |
extern int move(Node); |
extern int notarget(Node); |
extern void parseflags(int, char **); |
extern int range(Node, int, int); |
extern unsigned regloc(Symbol); /* omit */ |
extern void rtarget(Node, int, Symbol); |
extern void setreg(Node, Symbol); |
extern void spill(unsigned, int, Node); |
|
extern int argoffset, maxargoffset; |
extern int bflag, dflag; |
extern int dalign, salign; |
extern int framesize; |
extern unsigned freemask[], usedmask[]; |
extern int offset, maxoffset; |
extern int swap; |
extern unsigned tmask[], vmask[]; |
typedef struct { |
unsigned listed:1; |
unsigned registered:1; |
unsigned emitted:1; |
unsigned copy:1; |
unsigned equatable:1; |
unsigned spills:1; |
unsigned mayrecalc:1; |
void *state; |
short inst; |
Node kids[3]; |
Node prev, next; |
Node prevuse; |
short argno; |
} Xnode; |
typedef struct { |
Symbol vbl; |
short set; |
short number; |
unsigned mask; |
} *Regnode; |
enum { IREG=0, FREG=1 }; |
typedef struct { |
char *name; |
unsigned int eaddr; /* omit */ |
int offset; |
Node lastuse; |
int usecount; |
Regnode regnode; |
Symbol *wildcard; |
} Xsymbol; |
enum { RX=2 }; |
typedef struct { |
int offset; |
unsigned freemask[2]; |
} Env; |
|
#define LBURG_MAX SHRT_MAX |
|
enum { VREG=(44<<4) }; |
|
/* Exported for the front end */ |
extern void blockbeg(Env *); |
extern void blockend(Env *); |
extern void emit(Node); |
extern Node gen(Node); |
|
#ifdef NDEBUG |
#define debug(x) (void)0 |
#else |
#define debug(x) (void)(dflag&&((x),0)) |
#endif |
/null.c
0,0 → 1,75
#include "c.h" |
#define I(f) null_##f |
|
static Node I(gen)(Node p) { return p; } |
static void I(address)(Symbol q, Symbol p, long n) {} |
static void I(blockbeg)(Env *e) {} |
static void I(blockend)(Env *e) {} |
static void I(defaddress)(Symbol p) {} |
static void I(defconst)(int suffix, int size, Value v) {} |
static void I(defstring)(int len, char *s) {} |
static void I(defsymbol)(Symbol p) {} |
static void I(emit)(Node p) {} |
static void I(export)(Symbol p) {} |
static void I(function)(Symbol f, Symbol caller[], Symbol callee[], int ncalls) {} |
static void I(global)(Symbol p) {} |
static void I(import)(Symbol p) {} |
static void I(local)(Symbol p) {} |
static void I(progbeg)(int argc, char *argv[]) {} |
static void I(progend)(void) {} |
static void I(segment)(int s) {} |
static void I(space)(int n) {} |
static void I(stabblock)(int brace, int lev, Symbol *p) {} |
static void I(stabend)(Coordinate *cp, Symbol p, Coordinate **cpp, Symbol *sp, Symbol *stab) {} |
static void I(stabfend)(Symbol p, int lineno) {} |
static void I(stabinit)(char *file, int argc, char *argv[]) {} |
static void I(stabline)(Coordinate *cp) {} |
static void I(stabsym)(Symbol p) {} |
static void I(stabtype)(Symbol p) {} |
|
static char rcsid[] = "$Id: null.c,v 1.1 2002/08/28 23:12:45 drh Exp $"; |
|
Interface nullIR = { |
1, 1, 0, /* char */ |
2, 2, 0, /* short */ |
4, 4, 0, /* int */ |
8, 8, 1, /* long */ |
8 ,8, 1, /* long long */ |
4, 4, 1, /* float */ |
8, 8, 1, /* double */ |
16,16,1, /* long double */ |
4, 4, 0, /* T* */ |
0, 4, 0, /* struct */ |
1, /* little_endian */ |
0, /* mulops_calls */ |
0, /* wants_callb */ |
0, /* wants_argb */ |
1, /* left_to_right */ |
0, /* wants_dag */ |
0, /* unsigned_char */ |
I(address), |
I(blockbeg), |
I(blockend), |
I(defaddress), |
I(defconst), |
I(defstring), |
I(defsymbol), |
I(emit), |
I(export), |
I(function), |
I(gen), |
I(global), |
I(import), |
I(local), |
I(progbeg), |
I(progend), |
I(segment), |
I(space), |
I(stabblock), |
I(stabend), |
I(stabfend), |
I(stabinit), |
I(stabline), |
I(stabsym), |
I(stabtype) |
}; |
/eco32.md.SAVE-0
0,0 → 1,884
%{ |
|
/* |
* eco32.md -- ECO32 back-end specification |
* |
* register usage: |
* $0 always zero |
* $1 reserved for assembler |
* $2 func return value |
* $3 func return value |
* $4 proc/func argument |
* $5 proc/func argument |
* $6 proc/func argument |
* $7 proc/func argument |
* $8 temporary register (caller-save) |
* $9 temporary register (caller-save) |
* $10 temporary register (caller-save) |
* $11 temporary register (caller-save) |
* $12 temporary register (caller-save) |
* $13 temporary register (caller-save) |
* $14 temporary register (caller-save) |
* $15 temporary register (caller-save) |
* $16 register variable (callee-save) |
* $17 register variable (callee-save) |
* $18 register variable (callee-save) |
* $19 register variable (callee-save) |
* $20 register variable (callee-save) |
* $21 register variable (callee-save) |
* $22 register variable (callee-save) |
* $23 register variable (callee-save) |
* $24 temporary register (caller-save) |
* $25 temporary register (caller-save) |
* $26 reserved for OS kernel |
* $27 reserved for OS kernel |
* $28 reserved for OS kernel |
* $29 stack pointer |
* $30 interrupt return address |
* $31 proc/func return address |
* caller-save registers are not preserved across procedure calls |
* callee-save registers are preserved across procedure calls |
* |
* tree grammar terminals produced by: |
* ops c=1 s=2 i=4 l=4 h=4 f=4 d=8 x=8 p=4 |
*/ |
|
#include "c.h" |
|
#define NODEPTR_TYPE Node |
#define OP_LABEL(p) ((p)->op) |
#define LEFT_CHILD(p) ((p)->kids[0]) |
#define RIGHT_CHILD(p) ((p)->kids[1]) |
#define STATE_LABEL(p) ((p)->x.state) |
|
static void address(Symbol, Symbol, long); |
static void defaddress(Symbol); |
static void defconst(int, int, Value); |
static void defstring(int, char *); |
static void defsymbol(Symbol); |
static void export(Symbol); |
static void function(Symbol, Symbol [], Symbol [], int); |
static void global(Symbol); |
static void import(Symbol); |
static void local(Symbol); |
static void progbeg(int, char * []); |
static void progend(void); |
static void segment(int); |
static void space(int); |
static Symbol rmap(int); |
static void blkfetch(int, int, int, int); |
static void blkstore(int, int, int, int); |
static void blkloop(int, int, int, int, int, int []); |
static void emit2(Node); |
static void doarg(Node); |
static void target(Node); |
static void clobber(Node); |
|
#define INTTMP 0x0100FF00 |
#define INTVAR 0x00FF0000 |
#define INTRET 0x00000004 |
#define FLTTMP 0x000F0FF0 |
#define FLTVAR 0xFFF00000 |
#define FLTRET 0x00000003 |
|
static Symbol ireg[32]; |
static Symbol iregw; |
static Symbol freg2[32]; |
static Symbol freg2w; |
|
%} |
|
%start stmt |
|
%term CNSTF4=4113 CNSTF8=8209 |
%term CNSTI1=1045 CNSTI2=2069 CNSTI4=4117 |
%term CNSTP4=4119 |
%term CNSTU1=1046 CNSTU2=2070 CNSTU4=4118 |
|
%term ARGB=41 |
%term ARGF4=4129 ARGF8=8225 |
%term ARGI4=4133 |
%term ARGP4=4135 |
%term ARGU4=4134 |
|
%term ASGNB=57 |
%term ASGNF4=4145 ASGNF8=8241 |
%term ASGNI1=1077 ASGNI2=2101 ASGNI4=4149 |
%term ASGNP4=4151 |
%term ASGNU1=1078 ASGNU2=2102 ASGNU4=4150 |
|
%term INDIRB=73 |
%term INDIRF4=4161 INDIRF8=8257 |
%term INDIRI1=1093 INDIRI2=2117 INDIRI4=4165 |
%term INDIRP4=4167 |
%term INDIRU1=1094 INDIRU2=2118 INDIRU4=4166 |
|
%term CVFF4=4209 CVFF8=8305 |
%term CVFI4=4213 |
|
%term CVIF4=4225 CVIF8=8321 |
%term CVII1=1157 CVII2=2181 CVII4=4229 |
%term CVIU1=1158 CVIU2=2182 CVIU4=4230 |
|
%term CVPU4=4246 |
|
%term CVUI1=1205 CVUI2=2229 CVUI4=4277 |
%term CVUP4=4279 |
%term CVUU1=1206 CVUU2=2230 CVUU4=4278 |
|
%term NEGF4=4289 NEGF8=8385 |
%term NEGI4=4293 |
|
%term CALLB=217 |
%term CALLF4=4305 CALLF8=8401 |
%term CALLI4=4309 |
%term CALLP4=4311 |
%term CALLU4=4310 |
%term CALLV=216 |
|
%term RETF4=4337 RETF8=8433 |
%term RETI4=4341 |
%term RETP4=4343 |
%term RETU4=4342 |
%term RETV=248 |
|
%term ADDRGP4=4359 |
|
%term ADDRFP4=4375 |
|
%term ADDRLP4=4391 |
|
%term ADDF4=4401 ADDF8=8497 |
%term ADDI4=4405 |
%term ADDP4=4407 |
%term ADDU4=4406 |
|
%term SUBF4=4417 SUBF8=8513 |
%term SUBI4=4421 |
%term SUBP4=4423 |
%term SUBU4=4422 |
|
%term LSHI4=4437 |
%term LSHU4=4438 |
|
%term MODI4=4453 |
%term MODU4=4454 |
|
%term RSHI4=4469 |
%term RSHU4=4470 |
|
%term BANDI4=4485 |
%term BANDU4=4486 |
|
%term BCOMI4=4501 |
%term BCOMU4=4502 |
|
%term BORI4=4517 |
%term BORU4=4518 |
|
%term BXORI4=4533 |
%term BXORU4=4534 |
|
%term DIVF4=4545 DIVF8=8641 |
%term DIVI4=4549 |
%term DIVU4=4550 |
|
%term MULF4=4561 MULF8=8657 |
%term MULI4=4565 |
%term MULU4=4566 |
|
%term EQF4=4577 EQF8=8673 |
%term EQI4=4581 |
%term EQU4=4582 |
|
%term GEF4=4593 GEF8=8689 |
%term GEI4=4597 |
%term GEU4=4598 |
|
%term GTF4=4609 GTF8=8705 |
%term GTI4=4613 |
%term GTU4=4614 |
|
%term LEF4=4625 LEF8=8721 |
%term LEI4=4629 |
%term LEU4=4630 |
|
%term LTF4=4641 LTF8=8737 |
%term LTI4=4645 |
%term LTU4=4646 |
|
%term NEF4=4657 NEF8=8753 |
%term NEI4=4661 |
%term NEU4=4662 |
|
%term JUMPV=584 |
|
%term LABELV=600 |
|
%term LOADB=233 |
%term LOADF4=4321 LOADF8=8417 |
%term LOADI1=1253 LOADI2=2277 LOADI4=4325 |
%term LOADP4=4327 |
%term LOADU1=1254 LOADU2=2278 LOADU4=4326 |
|
%term VREGP=711 |
|
|
%% |
|
|
reg: INDIRI1(VREGP) "# read register\n" |
reg: INDIRI2(VREGP) "# read register\n" |
reg: INDIRI4(VREGP) "# read register\n" |
reg: INDIRP4(VREGP) "# read register\n" |
reg: INDIRU1(VREGP) "# read register\n" |
reg: INDIRU2(VREGP) "# read register\n" |
reg: INDIRU4(VREGP) "# read register\n" |
|
stmt: ASGNI1(VREGP,reg) "# write register\n" |
stmt: ASGNI2(VREGP,reg) "# write register\n" |
stmt: ASGNI4(VREGP,reg) "# write register\n" |
stmt: ASGNP4(VREGP,reg) "# write register\n" |
stmt: ASGNU1(VREGP,reg) "# write register\n" |
stmt: ASGNU2(VREGP,reg) "# write register\n" |
stmt: ASGNU4(VREGP,reg) "# write register\n" |
|
con: CNSTI1 "%a" |
con: CNSTI2 "%a" |
con: CNSTI4 "%a" |
con: CNSTP4 "%a" |
con: CNSTU1 "%a" |
con: CNSTU2 "%a" |
con: CNSTU4 "%a" |
|
stmt: reg "" |
|
acon: con "%0" |
acon: ADDRGP4 "%a" |
|
addr: ADDI4(reg,acon) "$%0,%1" |
addr: ADDP4(reg,acon) "$%0,%1" |
addr: ADDU4(reg,acon) "$%0,%1" |
|
addr: acon "$0,%0" |
addr: reg "$%0,0" |
addr: ADDRFP4 "$29,%a+%F" |
addr: ADDRLP4 "$29,%a+%F" |
|
reg: addr "\tadd\t$%c,%0\n" 1 |
|
reg: CNSTI1 "# reg\n" range(a, 0, 0) |
reg: CNSTI2 "# reg\n" range(a, 0, 0) |
reg: CNSTI4 "# reg\n" range(a, 0, 0) |
reg: CNSTP4 "# reg\n" range(a, 0, 0) |
reg: CNSTU1 "# reg\n" range(a, 0, 0) |
reg: CNSTU2 "# reg\n" range(a, 0, 0) |
reg: CNSTU4 "# reg\n" range(a, 0, 0) |
|
stmt: ASGNI1(addr,reg) "\tstb\t$%1,%0\n" 1 |
stmt: ASGNI2(addr,reg) "\tsth\t$%1,%0\n" 1 |
stmt: ASGNI4(addr,reg) "\tstw\t$%1,%0\n" 1 |
stmt: ASGNP4(addr,reg) "\tstw\t$%1,%0\n" 1 |
stmt: ASGNU1(addr,reg) "\tstb\t$%1,%0\n" 1 |
stmt: ASGNU2(addr,reg) "\tsth\t$%1,%0\n" 1 |
stmt: ASGNU4(addr,reg) "\tstw\t$%1,%0\n" 1 |
|
reg: INDIRI1(addr) "\tldb\t$%c,%0\n" 1 |
reg: INDIRI2(addr) "\tldh\t$%c,%0\n" 1 |
reg: INDIRI4(addr) "\tldw\t$%c,%0\n" 1 |
reg: INDIRP4(addr) "\tldw\t$%c,%0\n" 1 |
reg: INDIRU1(addr) "\tldbu\t$%c,%0\n" 1 |
reg: INDIRU2(addr) "\tldhu\t$%c,%0\n" 1 |
reg: INDIRU4(addr) "\tldw\t$%c,%0\n" 1 |
|
reg: CVII4(INDIRI1(addr)) "\tldb\t$%c,%0\n" 1 |
reg: CVII4(INDIRI2(addr)) "\tldh\t$%c,%0\n" 1 |
reg: CVUU4(INDIRU1(addr)) "\tldbu\t$%c,%0\n" 1 |
reg: CVUU4(INDIRU2(addr)) "\tldhu\t$%c,%0\n" 1 |
reg: CVUI4(INDIRU1(addr)) "\tldbu\t$%c,%0\n" 1 |
reg: CVUI4(INDIRU2(addr)) "\tldhu\t$%c,%0\n" 1 |
|
rc: con "%0" |
rc: reg "$%0" |
|
reg: ADDI4(reg,rc) "\tadd\t$%c,$%0,%1\n" 1 |
reg: ADDP4(reg,rc) "\tadd\t$%c,$%0,%1\n" 1 |
reg: ADDU4(reg,rc) "\tadd\t$%c,$%0,%1\n" 1 |
reg: SUBI4(reg,rc) "\tsub\t$%c,$%0,%1\n" 1 |
reg: SUBP4(reg,rc) "\tsub\t$%c,$%0,%1\n" 1 |
reg: SUBU4(reg,rc) "\tsub\t$%c,$%0,%1\n" 1 |
reg: NEGI4(reg) "\tsub\t$%c,$0,$%0\n" 1 |
|
reg: MULI4(reg,rc) "\tmul\t$%c,$%0,%1\n" 1 |
reg: MULU4(reg,rc) "\tmulu\t$%c,$%0,%1\n" 1 |
reg: DIVI4(reg,rc) "\tdiv\t$%c,$%0,%1\n" 1 |
reg: DIVU4(reg,rc) "\tdivu\t$%c,$%0,%1\n" 1 |
reg: MODI4(reg,rc) "\trem\t$%c,$%0,%1\n" 1 |
reg: MODU4(reg,rc) "\tremu\t$%c,$%0,%1\n" 1 |
|
reg: BANDI4(reg,rc) "\tand\t$%c,$%0,%1\n" 1 |
reg: BANDU4(reg,rc) "\tand\t$%c,$%0,%1\n" 1 |
reg: BORI4(reg,rc) "\tor\t$%c,$%0,%1\n" 1 |
reg: BORU4(reg,rc) "\tor\t$%c,$%0,%1\n" 1 |
reg: BXORI4(reg,rc) "\txor\t$%c,$%0,%1\n" 1 |
reg: BXORU4(reg,rc) "\txor\t$%c,$%0,%1\n" 1 |
reg: BCOMI4(reg) "\txnor\t$%c,$0,$%0\n" 1 |
reg: BCOMU4(reg) "\txnor\t$%c,$0,$%0\n" 1 |
|
rc5: CNSTI4 "%a" range(a, 0, 31) |
rc5: reg "$%0" |
|
reg: LSHI4(reg,rc5) "\tsll\t$%c,$%0,%1\n" 1 |
reg: LSHU4(reg,rc5) "\tsll\t$%c,$%0,%1\n" 1 |
reg: RSHI4(reg,rc5) "\tsar\t$%c,$%0,%1\n" 1 |
reg: RSHU4(reg,rc5) "\tslr\t$%c,$%0,%1\n" 1 |
|
reg: LOADI1(reg) "\tadd\t$%c,$0,$%0\n" move(a) |
reg: LOADI2(reg) "\tadd\t$%c,$0,$%0\n" move(a) |
reg: LOADI4(reg) "\tadd\t$%c,$0,$%0\n" move(a) |
reg: LOADP4(reg) "\tadd\t$%c,$0,$%0\n" move(a) |
reg: LOADU1(reg) "\tadd\t$%c,$0,$%0\n" move(a) |
reg: LOADU2(reg) "\tadd\t$%c,$0,$%0\n" move(a) |
reg: LOADU4(reg) "\tadd\t$%c,$0,$%0\n" move(a) |
|
reg: CVII4(reg) "\tsll\t$%c,$%0,8*(4-%a)\n\tsar\t$%c,$%c,8*(4-%a)\n" 2 |
reg: CVUI4(reg) "\tand\t$%c,$%0,(1<<(8*%a))-1\n" 1 |
reg: CVUU4(reg) "\tand\t$%c,$%0,(1<<(8*%a))-1\n" 1 |
|
stmt: LABELV "%a:\n" |
stmt: JUMPV(acon) "\tj\t%0\n" 1 |
stmt: JUMPV(reg) "\tjr\t$%0\n" 1 |
|
stmt: EQI4(reg,reg) "\tbeq\t$%0,$%1,%a\n" 1 |
stmt: EQU4(reg,reg) "\tbeq\t$%0,$%1,%a\n" 1 |
stmt: NEI4(reg,reg) "\tbne\t$%0,$%1,%a\n" 1 |
stmt: NEU4(reg,reg) "\tbne\t$%0,$%1,%a\n" 1 |
stmt: LEI4(reg,reg) "\tble\t$%0,$%1,%a\n" 1 |
stmt: LEU4(reg,reg) "\tbleu\t$%0,$%1,%a\n" 1 |
stmt: LTI4(reg,reg) "\tblt\t$%0,$%1,%a\n" 1 |
stmt: LTU4(reg,reg) "\tbltu\t$%0,$%1,%a\n" 1 |
stmt: GEI4(reg,reg) "\tbge\t$%0,$%1,%a\n" 1 |
stmt: GEU4(reg,reg) "\tbgeu\t$%0,$%1,%a\n" 1 |
stmt: GTI4(reg,reg) "\tbgt\t$%0,$%1,%a\n" 1 |
stmt: GTU4(reg,reg) "\tbgtu\t$%0,$%1,%a\n" 1 |
|
reg: CALLI4(ar) "\tjal\t%0\n" 1 |
reg: CALLP4(ar) "\tjal\t%0\n" 1 |
reg: CALLU4(ar) "\tjal\t%0\n" 1 |
stmt: CALLV(ar) "\tjal\t%0\n" 1 |
|
ar: ADDRGP4 "%a" |
ar: reg "$%0" |
ar: CNSTP4 "%a" range(a, 0, 0x03FFFFFF) |
|
stmt: RETI4(reg) "# ret\n" 1 |
stmt: RETP4(reg) "# ret\n" 1 |
stmt: RETU4(reg) "# ret\n" 1 |
stmt: RETV(reg) "# ret\n" 1 |
|
stmt: ARGI4(reg) "# arg\n" 1 |
stmt: ARGP4(reg) "# arg\n" 1 |
stmt: ARGU4(reg) "# arg\n" 1 |
|
|
%% |
|
|
static void address(Symbol s1, Symbol s2, long n) { |
if (s2->scope == GLOBAL || |
s2->sclass == STATIC || |
s2->sclass == EXTERN) { |
s1->x.name = stringf("%s%s%D", s2->x.name, n >= 0 ? "+" : "", n); |
} else { |
assert(n >= INT_MIN && n <= INT_MAX); |
s1->x.offset = s2->x.offset + n; |
s1->x.name = stringd(s1->x.offset); |
} |
} |
|
|
static void defaddress(Symbol s) { |
print("\t.word\t%s\n", s->x.name); |
} |
|
|
static void defconst(int suffix, int size, Value v) { |
float f; |
double d; |
|
if (suffix == F && size == 4) { |
f = v.d; |
/* float not supported */ |
} else |
if (suffix == F && size == 8) { |
d = v.d; |
/* double not supported */ |
} else |
if (suffix == P) { |
print("\t.word\t0x%x\n", (unsigned) v.p); |
} else |
if (size == 1) { |
print("\t.byte\t0x%x\n", |
(unsigned) ((unsigned char) (suffix == I ? v.i : v.u))); |
} else |
if (size == 2) { |
print("\t.half\t0x%x\n", |
(unsigned) ((unsigned short) (suffix == I ? v.i : v.u))); |
} else |
if (size == 4) { |
print("\t.word\t0x%x\n", (unsigned) (suffix == I ? v.i : v.u)); |
} |
} |
|
|
static void defstring(int n, char *str) { |
char *s; |
|
for (s = str; s < str + n; s++) { |
print("\t.byte\t0x%x\n", (*s) & 0xFF); |
} |
} |
|
|
static void defsymbol(Symbol s) { |
if (s->scope >= LOCAL && s->sclass == STATIC) { |
s->x.name = stringf("L.%d", genlabel(1)); |
} else |
if (s->generated) { |
s->x.name = stringf("L.%s", s->name); |
} else { |
assert(s->scope != CONSTANTS || isint(s->type) || isptr(s->type)); |
s->x.name = s->name; |
} |
} |
|
|
static void export(Symbol s) { |
print("\t.export\t%s\n", s->name); |
} |
|
|
static int bitcount(unsigned mask) { |
unsigned i, n; |
|
n = 0; |
for (i = 1; i != 0; i <<= 1) { |
if (mask & i) { |
n++; |
} |
} |
return n; |
} |
|
|
static Symbol argreg(int argno, int offset, int ty, int sz, int ty0) { |
assert((offset & 3) == 0); |
if (offset > 12) { |
return NULL; |
} |
return ireg[(offset / 4) + 4]; |
} |
|
|
static void function(Symbol f, Symbol caller[], Symbol callee[], int ncalls) { |
int i; |
Symbol p, q; |
Symbol r; |
int sizeisave; |
int saved; |
Symbol argregs[4]; |
|
usedmask[0] = usedmask[1] = 0; |
freemask[0] = freemask[1] = ~((unsigned) 0); |
offset = 0; |
maxoffset = 0; |
maxargoffset = 0; |
for (i = 0; callee[i] != NULL; i++) { |
p = callee[i]; |
q = caller[i]; |
assert(q != NULL); |
offset = roundup(offset, q->type->align); |
p->x.offset = q->x.offset = offset; |
p->x.name = q->x.name = stringd(offset); |
r = argreg(i, offset, optype(ttob(q->type)), |
q->type->size, optype(ttob(caller[0]->type))); |
if (i < 4) { |
argregs[i] = r; |
} |
offset = roundup(offset + q->type->size, 4); |
if (variadic(f->type)) { |
p->sclass = AUTO; |
} else |
if (r != NULL && ncalls == 0 && !isstruct(q->type) && |
!p->addressed && !(isfloat(q->type) && r->x.regnode->set == IREG)) { |
p->sclass = q->sclass = REGISTER; |
askregvar(p, r); |
assert(p->x.regnode && p->x.regnode->vbl == p); |
q->x = p->x; |
q->type = p->type; |
} else |
if (askregvar(p, rmap(ttob(p->type))) && |
r != NULL && (isint(p->type) || p->type == q->type)) { |
assert(q->sclass != REGISTER); |
p->sclass = q->sclass = REGISTER; |
q->type = p->type; |
} |
} |
assert(caller[i] == NULL); |
offset = 0; |
gencode(caller, callee); |
if (ncalls != 0) { |
usedmask[IREG] |= ((unsigned) 1) << 31; |
} |
usedmask[IREG] &= 0x80FF0000; |
usedmask[FREG] &= 0xFFF00000; |
maxargoffset = roundup(maxargoffset, 4); |
if (ncalls != 0 && maxargoffset < 16) { |
maxargoffset = 16; |
} |
sizeisave = 4 * bitcount(usedmask[IREG]); |
framesize = roundup(maxargoffset + sizeisave + maxoffset, 16); |
segment(CODE); |
print("\t.align\t4\n"); |
print("%s:\n", f->x.name); |
if (framesize > 0) { |
print("\tsub\t$29,$29,%d\n", framesize); |
} |
saved = maxargoffset; |
for (i = 16; i < 32; i++) { |
if (usedmask[IREG] & (1 << i)) { |
print("\tstw\t$%d,$29,%d\n", i, saved); |
saved += 4; |
} |
} |
for (i = 0; i < 4 && callee[i] != NULL; i++) { |
r = argregs[i]; |
if (r && r->x.regnode != callee[i]->x.regnode) { |
Symbol out = callee[i]; |
Symbol in = caller[i]; |
int rn = r->x.regnode->number; |
int rs = r->x.regnode->set; |
int tyin = ttob(in->type); |
assert(out && in && r && r->x.regnode); |
assert(out->sclass != REGISTER || out->x.regnode); |
if (out->sclass == REGISTER && |
(isint(out->type) || out->type == in->type)) { |
int outn = out->x.regnode->number; |
print("\tadd\t$%d,$0,$%d\n", outn, rn); |
} else { |
int off = in->x.offset + framesize; |
int n = (in->type->size + 3) / 4; |
int i; |
for (i = rn; i < rn + n && i <= 7; i++) { |
print("\tstw\t$%d,$29,%d\n", i, off + (i - rn) * 4); |
} |
} |
} |
} |
if (variadic(f->type) && callee[i - 1] != NULL) { |
i = callee[i - 1]->x.offset + callee[i - 1]->type->size; |
for (i = roundup(i, 4)/4; i <= 3; i++) { |
print("\tstw\t$%d,$29,%d\n", i + 4, framesize + 4 * i); |
} |
} |
emitcode(); |
saved = maxargoffset; |
for (i = 16; i < 32; i++) { |
if (usedmask[IREG] & (1 << i)) { |
print("\tldw\t$%d,$29,%d\n", i, saved); |
saved += 4; |
} |
} |
if (framesize > 0) { |
print("\tadd\t$29,$29,%d\n", framesize); |
} |
print("\tjr\t$31\n"); |
print("\n"); |
} |
|
|
static void global(Symbol s) { |
print("\t.align\t%d\n", s->type->align); |
print("%s:\n", s->x.name); |
} |
|
|
static void import(Symbol s) { |
print("\t.import\t%s\n", s->name); |
} |
|
|
static void local(Symbol s) { |
if (askregvar(s, rmap(ttob(s->type))) == 0) { |
mkauto(s); |
} |
} |
|
|
static void setSwap(void) { |
union { |
char c; |
int i; |
} u; |
|
u.i = 0; |
u.c = 1; |
swap = ((u.i == 1) != IR->little_endian); |
} |
|
|
static void progbeg(int argc, char *argv[]) { |
int i; |
|
setSwap(); |
segment(CODE); |
parseflags(argc, argv); |
for (i = 0; i < 32; i++) { |
ireg[i] = mkreg("%d", i, 1, IREG); |
} |
iregw = mkwildcard(ireg); |
for (i = 0; i < 32; i += 2) { |
freg2[i] = mkreg("%d", i, 3, FREG); |
} |
freg2w = mkwildcard(freg2); |
tmask[IREG] = INTTMP; |
vmask[IREG] = INTVAR; |
tmask[FREG] = FLTTMP; |
vmask[FREG] = FLTVAR; |
} |
|
|
static void progend(void) { |
} |
|
|
static void segment(int n) { |
static int currSeg = -1; |
int newSeg; |
|
switch (n) { |
case CODE: |
newSeg = CODE; |
break; |
case BSS: |
newSeg = BSS; |
break; |
case DATA: |
newSeg = DATA; |
break; |
case LIT: |
newSeg = DATA; |
break; |
} |
if (currSeg == newSeg) { |
return; |
} |
switch (newSeg) { |
case CODE: |
print("\t.code\n"); |
break; |
case BSS: |
print("\t.bss\n"); |
break; |
case DATA: |
print("\t.data\n"); |
break; |
} |
currSeg = newSeg; |
} |
|
|
static void space(int n) { |
print("\t.space\t%d\n", n); |
} |
|
|
static Symbol rmap(int opk) { |
switch (optype(opk)) { |
case I: |
case U: |
case P: |
case B: |
return iregw; |
case F: |
return freg2w; |
default: |
return 0; |
} |
} |
|
|
static void blkfetch(int n1, int n2, int n3, int n4) { |
/* not supported yet */ |
} |
|
|
static void blkstore(int n1, int n2, int n3, int n4) { |
/* not supported yet */ |
} |
|
|
static void blkloop(int n1, int n2, int n3, int n4, int n5, int n6[]) { |
/* not supported yet */ |
} |
|
|
static void emit2(Node p) { |
static int ty0; |
int ty, sz; |
Symbol q; |
int src; |
|
switch (specific(p->op)) { |
case ARG+I: |
case ARG+P: |
case ARG+U: |
ty = optype(p->op); |
sz = opsize(p->op); |
if (p->x.argno == 0) { |
ty0 = ty; |
} |
q = argreg(p->x.argno, p->syms[2]->u.c.v.i, ty, sz, ty0); |
src = getregnum(p->x.kids[0]); |
if (q == NULL) { |
print("\tstw\t$%d,$29,%d\n", src, p->syms[2]->u.c.v.i); |
} |
break; |
} |
} |
|
|
static void doarg(Node p) { |
static int argno; |
int align; |
|
if (argoffset == 0) { |
argno = 0; |
} |
p->x.argno = argno++; |
align = p->syms[1]->u.c.v.i < 4 ? 4 : p->syms[1]->u.c.v.i; |
p->syms[2] = intconst(mkactual(align, p->syms[0]->u.c.v.i)); |
} |
|
|
static void target(Node p) { |
static int ty0; |
int ty; |
Symbol q; |
|
assert(p); |
switch (specific(p->op)) { |
case CNST+I: |
case CNST+P: |
case CNST+U: |
if (range(p, 0, 0) == 0) { |
setreg(p, ireg[0]); |
p->x.registered = 1; |
} |
break; |
case CALL+I: |
case CALL+P: |
case CALL+U: |
rtarget(p, 0, ireg[25]); |
setreg(p, ireg[2]); |
break; |
case CALL+V: |
rtarget(p, 0, ireg[25]); |
break; |
case RET+I: |
case RET+P: |
case RET+U: |
rtarget(p, 0, ireg[2]); |
break; |
case ARG+I: |
case ARG+P: |
case ARG+U: |
ty = optype(p->op); |
q = argreg(p->x.argno, p->syms[2]->u.c.v.i, ty, opsize(p->op), ty0); |
if (p->x.argno == 0) { |
ty0 = ty; |
} |
if (q && !(ty == F && q->x.regnode->set == IREG)) { |
rtarget(p, 0, q); |
} |
break; |
} |
} |
|
|
static void clobber(Node p) { |
assert(p); |
switch (specific(p->op)) { |
case CALL+F: |
spill(INTTMP | INTRET, IREG, p); |
spill(FLTTMP, FREG, p); |
break; |
case CALL+I: |
case CALL+P: |
case CALL+U: |
spill(INTTMP, IREG, p); |
spill(FLTTMP | FLTRET, FREG, p); |
break; |
case CALL+V: |
spill(INTTMP | INTRET, IREG, p); |
spill(FLTTMP | FLTRET, FREG, p); |
break; |
} |
} |
|
|
Interface eco32IR = { |
1, 1, 0, /* char */ |
2, 2, 0, /* short */ |
4, 4, 0, /* int */ |
4, 4, 0, /* long */ |
4, 4, 0, /* long long */ |
4, 4, 1, /* float */ |
8, 8, 1, /* double */ |
8, 8, 1, /* long double */ |
4, 4, 0, /* T * */ |
0, 1, 0, /* struct */ |
0, /* little_endian */ |
0, /* mulops_calls */ |
0, /* wants_callb */ |
1, /* wants_argb */ |
1, /* left_to_right */ |
0, /* wants_dag */ |
0, /* unsigned_char */ |
address, |
blockbeg, |
blockend, |
defaddress, |
defconst, |
defstring, |
defsymbol, |
emit, |
export, |
function, |
gen, |
global, |
import, |
local, |
progbeg, |
progend, |
segment, |
space, |
0, 0, 0, 0, 0, 0, 0, |
{ |
1, /* max_unaligned_load */ |
rmap, |
blkfetch, blkstore, blkloop, |
_label, |
_rule, |
_nts, |
_kids, |
_string, |
_templates, |
_isinstruction, |
_ntname, |
emit2, |
doarg, |
target, |
clobber |
} |
}; |
/eco32.md.SAVE-1
0,0 → 1,946
%{ |
|
/* |
* eco32.md -- ECO32 back-end specification |
* |
* register usage: |
* $0 always zero |
* $1 reserved for assembler |
* $2 func return value |
* $3 func return value |
* $4 proc/func argument |
* $5 proc/func argument |
* $6 proc/func argument |
* $7 proc/func argument |
* $8 temporary register (caller-save) |
* $9 temporary register (caller-save) |
* $10 temporary register (caller-save) |
* $11 temporary register (caller-save) |
* $12 temporary register (caller-save) |
* $13 temporary register (caller-save) |
* $14 temporary register (caller-save) |
* $15 temporary register (caller-save) |
* $16 register variable (callee-save) |
* $17 register variable (callee-save) |
* $18 register variable (callee-save) |
* $19 register variable (callee-save) |
* $20 register variable (callee-save) |
* $21 register variable (callee-save) |
* $22 register variable (callee-save) |
* $23 register variable (callee-save) |
* $24 temporary register (caller-save) |
* $25 temporary register (caller-save) |
* $26 reserved for OS kernel |
* $27 reserved for OS kernel |
* $28 reserved for OS kernel |
* $29 stack pointer |
* $30 interrupt return address |
* $31 proc/func return address |
* caller-save registers are not preserved across procedure calls |
* callee-save registers are preserved across procedure calls |
* |
* tree grammar terminals produced by: |
* ops c=1 s=2 i=4 l=4 h=4 f=4 d=8 x=8 p=4 |
*/ |
|
#include "c.h" |
|
#define NODEPTR_TYPE Node |
#define OP_LABEL(p) ((p)->op) |
#define LEFT_CHILD(p) ((p)->kids[0]) |
#define RIGHT_CHILD(p) ((p)->kids[1]) |
#define STATE_LABEL(p) ((p)->x.state) |
|
static void address(Symbol, Symbol, long); |
static void defaddress(Symbol); |
static void defconst(int, int, Value); |
static void defstring(int, char *); |
static void defsymbol(Symbol); |
static void export(Symbol); |
static void function(Symbol, Symbol [], Symbol [], int); |
static void global(Symbol); |
static void import(Symbol); |
static void local(Symbol); |
static void progbeg(int, char * []); |
static void progend(void); |
static void segment(int); |
static void space(int); |
static Symbol rmap(int); |
static void blkfetch(int, int, int, int); |
static void blkstore(int, int, int, int); |
static void blkloop(int, int, int, int, int, int []); |
static void emit2(Node); |
static void doarg(Node); |
static void target(Node); |
static void clobber(Node); |
|
#define INTTMP 0x0100FF00 |
#define INTVAR 0x00FF0000 |
#define INTRET 0x00000004 |
#define FLTTMP 0x000F0FF0 |
#define FLTVAR 0xFFF00000 |
#define FLTRET 0x00000003 |
|
static Symbol ireg[32]; |
static Symbol iregw; |
static Symbol freg2[32]; |
static Symbol freg2w; |
static Symbol blkreg; |
static int tmpregs[] = { 3, 9, 10 }; |
|
%} |
|
%start stmt |
|
%term CNSTF4=4113 CNSTF8=8209 |
%term CNSTI1=1045 CNSTI2=2069 CNSTI4=4117 |
%term CNSTP4=4119 |
%term CNSTU1=1046 CNSTU2=2070 CNSTU4=4118 |
|
%term ARGB=41 |
%term ARGF4=4129 ARGF8=8225 |
%term ARGI4=4133 |
%term ARGP4=4135 |
%term ARGU4=4134 |
|
%term ASGNB=57 |
%term ASGNF4=4145 ASGNF8=8241 |
%term ASGNI1=1077 ASGNI2=2101 ASGNI4=4149 |
%term ASGNP4=4151 |
%term ASGNU1=1078 ASGNU2=2102 ASGNU4=4150 |
|
%term INDIRB=73 |
%term INDIRF4=4161 INDIRF8=8257 |
%term INDIRI1=1093 INDIRI2=2117 INDIRI4=4165 |
%term INDIRP4=4167 |
%term INDIRU1=1094 INDIRU2=2118 INDIRU4=4166 |
|
%term CVFF4=4209 CVFF8=8305 |
%term CVFI4=4213 |
|
%term CVIF4=4225 CVIF8=8321 |
%term CVII1=1157 CVII2=2181 CVII4=4229 |
%term CVIU1=1158 CVIU2=2182 CVIU4=4230 |
|
%term CVPU4=4246 |
|
%term CVUI1=1205 CVUI2=2229 CVUI4=4277 |
%term CVUP4=4279 |
%term CVUU1=1206 CVUU2=2230 CVUU4=4278 |
|
%term NEGF4=4289 NEGF8=8385 |
%term NEGI4=4293 |
|
%term CALLB=217 |
%term CALLF4=4305 CALLF8=8401 |
%term CALLI4=4309 |
%term CALLP4=4311 |
%term CALLU4=4310 |
%term CALLV=216 |
|
%term RETF4=4337 RETF8=8433 |
%term RETI4=4341 |
%term RETP4=4343 |
%term RETU4=4342 |
%term RETV=248 |
|
%term ADDRGP4=4359 |
|
%term ADDRFP4=4375 |
|
%term ADDRLP4=4391 |
|
%term ADDF4=4401 ADDF8=8497 |
%term ADDI4=4405 |
%term ADDP4=4407 |
%term ADDU4=4406 |
|
%term SUBF4=4417 SUBF8=8513 |
%term SUBI4=4421 |
%term SUBP4=4423 |
%term SUBU4=4422 |
|
%term LSHI4=4437 |
%term LSHU4=4438 |
|
%term MODI4=4453 |
%term MODU4=4454 |
|
%term RSHI4=4469 |
%term RSHU4=4470 |
|
%term BANDI4=4485 |
%term BANDU4=4486 |
|
%term BCOMI4=4501 |
%term BCOMU4=4502 |
|
%term BORI4=4517 |
%term BORU4=4518 |
|
%term BXORI4=4533 |
%term BXORU4=4534 |
|
%term DIVF4=4545 DIVF8=8641 |
%term DIVI4=4549 |
%term DIVU4=4550 |
|
%term MULF4=4561 MULF8=8657 |
%term MULI4=4565 |
%term MULU4=4566 |
|
%term EQF4=4577 EQF8=8673 |
%term EQI4=4581 |
%term EQU4=4582 |
|
%term GEF4=4593 GEF8=8689 |
%term GEI4=4597 |
%term GEU4=4598 |
|
%term GTF4=4609 GTF8=8705 |
%term GTI4=4613 |
%term GTU4=4614 |
|
%term LEF4=4625 LEF8=8721 |
%term LEI4=4629 |
%term LEU4=4630 |
|
%term LTF4=4641 LTF8=8737 |
%term LTI4=4645 |
%term LTU4=4646 |
|
%term NEF4=4657 NEF8=8753 |
%term NEI4=4661 |
%term NEU4=4662 |
|
%term JUMPV=584 |
|
%term LABELV=600 |
|
%term LOADB=233 |
%term LOADF4=4321 LOADF8=8417 |
%term LOADI1=1253 LOADI2=2277 LOADI4=4325 |
%term LOADP4=4327 |
%term LOADU1=1254 LOADU2=2278 LOADU4=4326 |
|
%term VREGP=711 |
|
|
%% |
|
|
reg: INDIRI1(VREGP) "# read register\n" |
reg: INDIRI2(VREGP) "# read register\n" |
reg: INDIRI4(VREGP) "# read register\n" |
reg: INDIRP4(VREGP) "# read register\n" |
reg: INDIRU1(VREGP) "# read register\n" |
reg: INDIRU2(VREGP) "# read register\n" |
reg: INDIRU4(VREGP) "# read register\n" |
|
stmt: ASGNI1(VREGP,reg) "# write register\n" |
stmt: ASGNI2(VREGP,reg) "# write register\n" |
stmt: ASGNI4(VREGP,reg) "# write register\n" |
stmt: ASGNP4(VREGP,reg) "# write register\n" |
stmt: ASGNU1(VREGP,reg) "# write register\n" |
stmt: ASGNU2(VREGP,reg) "# write register\n" |
stmt: ASGNU4(VREGP,reg) "# write register\n" |
|
con: CNSTI1 "%a" |
con: CNSTI2 "%a" |
con: CNSTI4 "%a" |
con: CNSTP4 "%a" |
con: CNSTU1 "%a" |
con: CNSTU2 "%a" |
con: CNSTU4 "%a" |
|
stmt: reg "" |
|
acon: con "%0" |
acon: ADDRGP4 "%a" |
|
addr: ADDI4(reg,acon) "$%0,%1" |
addr: ADDP4(reg,acon) "$%0,%1" |
addr: ADDU4(reg,acon) "$%0,%1" |
|
addr: acon "$0,%0" |
addr: reg "$%0,0" |
addr: ADDRFP4 "$29,%a+%F" |
addr: ADDRLP4 "$29,%a+%F" |
|
reg: addr "\tadd\t$%c,%0\n" 1 |
|
reg: CNSTI1 "# reg\n" range(a, 0, 0) |
reg: CNSTI2 "# reg\n" range(a, 0, 0) |
reg: CNSTI4 "# reg\n" range(a, 0, 0) |
reg: CNSTP4 "# reg\n" range(a, 0, 0) |
reg: CNSTU1 "# reg\n" range(a, 0, 0) |
reg: CNSTU2 "# reg\n" range(a, 0, 0) |
reg: CNSTU4 "# reg\n" range(a, 0, 0) |
|
stmt: ASGNI1(addr,reg) "\tstb\t$%1,%0\n" 1 |
stmt: ASGNI2(addr,reg) "\tsth\t$%1,%0\n" 1 |
stmt: ASGNI4(addr,reg) "\tstw\t$%1,%0\n" 1 |
stmt: ASGNP4(addr,reg) "\tstw\t$%1,%0\n" 1 |
stmt: ASGNU1(addr,reg) "\tstb\t$%1,%0\n" 1 |
stmt: ASGNU2(addr,reg) "\tsth\t$%1,%0\n" 1 |
stmt: ASGNU4(addr,reg) "\tstw\t$%1,%0\n" 1 |
|
reg: INDIRI1(addr) "\tldb\t$%c,%0\n" 1 |
reg: INDIRI2(addr) "\tldh\t$%c,%0\n" 1 |
reg: INDIRI4(addr) "\tldw\t$%c,%0\n" 1 |
reg: INDIRP4(addr) "\tldw\t$%c,%0\n" 1 |
reg: INDIRU1(addr) "\tldbu\t$%c,%0\n" 1 |
reg: INDIRU2(addr) "\tldhu\t$%c,%0\n" 1 |
reg: INDIRU4(addr) "\tldw\t$%c,%0\n" 1 |
|
reg: CVII4(INDIRI1(addr)) "\tldb\t$%c,%0\n" 1 |
reg: CVII4(INDIRI2(addr)) "\tldh\t$%c,%0\n" 1 |
reg: CVUU4(INDIRU1(addr)) "\tldbu\t$%c,%0\n" 1 |
reg: CVUU4(INDIRU2(addr)) "\tldhu\t$%c,%0\n" 1 |
reg: CVUI4(INDIRU1(addr)) "\tldbu\t$%c,%0\n" 1 |
reg: CVUI4(INDIRU2(addr)) "\tldhu\t$%c,%0\n" 1 |
|
rc: con "%0" |
rc: reg "$%0" |
|
reg: ADDI4(reg,rc) "\tadd\t$%c,$%0,%1\n" 1 |
reg: ADDP4(reg,rc) "\tadd\t$%c,$%0,%1\n" 1 |
reg: ADDU4(reg,rc) "\tadd\t$%c,$%0,%1\n" 1 |
reg: SUBI4(reg,rc) "\tsub\t$%c,$%0,%1\n" 1 |
reg: SUBP4(reg,rc) "\tsub\t$%c,$%0,%1\n" 1 |
reg: SUBU4(reg,rc) "\tsub\t$%c,$%0,%1\n" 1 |
reg: NEGI4(reg) "\tsub\t$%c,$0,$%0\n" 1 |
|
reg: MULI4(reg,rc) "\tmul\t$%c,$%0,%1\n" 1 |
reg: MULU4(reg,rc) "\tmulu\t$%c,$%0,%1\n" 1 |
reg: DIVI4(reg,rc) "\tdiv\t$%c,$%0,%1\n" 1 |
reg: DIVU4(reg,rc) "\tdivu\t$%c,$%0,%1\n" 1 |
reg: MODI4(reg,rc) "\trem\t$%c,$%0,%1\n" 1 |
reg: MODU4(reg,rc) "\tremu\t$%c,$%0,%1\n" 1 |
|
reg: BANDI4(reg,rc) "\tand\t$%c,$%0,%1\n" 1 |
reg: BANDU4(reg,rc) "\tand\t$%c,$%0,%1\n" 1 |
reg: BORI4(reg,rc) "\tor\t$%c,$%0,%1\n" 1 |
reg: BORU4(reg,rc) "\tor\t$%c,$%0,%1\n" 1 |
reg: BXORI4(reg,rc) "\txor\t$%c,$%0,%1\n" 1 |
reg: BXORU4(reg,rc) "\txor\t$%c,$%0,%1\n" 1 |
reg: BCOMI4(reg) "\txnor\t$%c,$0,$%0\n" 1 |
reg: BCOMU4(reg) "\txnor\t$%c,$0,$%0\n" 1 |
|
rc5: CNSTI4 "%a" range(a, 0, 31) |
rc5: reg "$%0" |
|
reg: LSHI4(reg,rc5) "\tsll\t$%c,$%0,%1\n" 1 |
reg: LSHU4(reg,rc5) "\tsll\t$%c,$%0,%1\n" 1 |
reg: RSHI4(reg,rc5) "\tsar\t$%c,$%0,%1\n" 1 |
reg: RSHU4(reg,rc5) "\tslr\t$%c,$%0,%1\n" 1 |
|
reg: LOADI1(reg) "\tadd\t$%c,$0,$%0\n" move(a) |
reg: LOADI2(reg) "\tadd\t$%c,$0,$%0\n" move(a) |
reg: LOADI4(reg) "\tadd\t$%c,$0,$%0\n" move(a) |
reg: LOADP4(reg) "\tadd\t$%c,$0,$%0\n" move(a) |
reg: LOADU1(reg) "\tadd\t$%c,$0,$%0\n" move(a) |
reg: LOADU2(reg) "\tadd\t$%c,$0,$%0\n" move(a) |
reg: LOADU4(reg) "\tadd\t$%c,$0,$%0\n" move(a) |
|
reg: CVII4(reg) "\tsll\t$%c,$%0,8*(4-%a)\n\tsar\t$%c,$%c,8*(4-%a)\n" 2 |
reg: CVUI4(reg) "\tand\t$%c,$%0,(1<<(8*%a))-1\n" 1 |
reg: CVUU4(reg) "\tand\t$%c,$%0,(1<<(8*%a))-1\n" 1 |
|
stmt: LABELV "%a:\n" |
stmt: JUMPV(acon) "\tj\t%0\n" 1 |
stmt: JUMPV(reg) "\tjr\t$%0\n" 1 |
|
stmt: EQI4(reg,reg) "\tbeq\t$%0,$%1,%a\n" 1 |
stmt: EQU4(reg,reg) "\tbeq\t$%0,$%1,%a\n" 1 |
stmt: NEI4(reg,reg) "\tbne\t$%0,$%1,%a\n" 1 |
stmt: NEU4(reg,reg) "\tbne\t$%0,$%1,%a\n" 1 |
stmt: LEI4(reg,reg) "\tble\t$%0,$%1,%a\n" 1 |
stmt: LEU4(reg,reg) "\tbleu\t$%0,$%1,%a\n" 1 |
stmt: LTI4(reg,reg) "\tblt\t$%0,$%1,%a\n" 1 |
stmt: LTU4(reg,reg) "\tbltu\t$%0,$%1,%a\n" 1 |
stmt: GEI4(reg,reg) "\tbge\t$%0,$%1,%a\n" 1 |
stmt: GEU4(reg,reg) "\tbgeu\t$%0,$%1,%a\n" 1 |
stmt: GTI4(reg,reg) "\tbgt\t$%0,$%1,%a\n" 1 |
stmt: GTU4(reg,reg) "\tbgtu\t$%0,$%1,%a\n" 1 |
|
reg: CALLI4(ar) "\tjal\t%0\n" 1 |
reg: CALLP4(ar) "\tjal\t%0\n" 1 |
reg: CALLU4(ar) "\tjal\t%0\n" 1 |
stmt: CALLV(ar) "\tjal\t%0\n" 1 |
|
ar: ADDRGP4 "%a" |
ar: reg "$%0" |
ar: CNSTP4 "%a" range(a, 0, 0x03FFFFFF) |
|
stmt: RETI4(reg) "# ret\n" 1 |
stmt: RETP4(reg) "# ret\n" 1 |
stmt: RETU4(reg) "# ret\n" 1 |
stmt: RETV(reg) "# ret\n" 1 |
|
stmt: ARGI4(reg) "# arg\n" 1 |
stmt: ARGP4(reg) "# arg\n" 1 |
stmt: ARGU4(reg) "# arg\n" 1 |
|
stmt: ARGB(INDIRB(reg)) "# argb %0\n" 1 |
stmt: ASGNB(reg,INDIRB(reg)) "# asgnb %0 %1\n" 1 |
|
|
%% |
|
|
static void address(Symbol s1, Symbol s2, long n) { |
if (s2->scope == GLOBAL || |
s2->sclass == STATIC || |
s2->sclass == EXTERN) { |
s1->x.name = stringf("%s%s%D", s2->x.name, n >= 0 ? "+" : "", n); |
} else { |
assert(n >= INT_MIN && n <= INT_MAX); |
s1->x.offset = s2->x.offset + n; |
s1->x.name = stringd(s1->x.offset); |
} |
} |
|
|
static void defaddress(Symbol s) { |
print("\t.word\t%s\n", s->x.name); |
} |
|
|
static void defconst(int suffix, int size, Value v) { |
float f; |
double d; |
|
if (suffix == F && size == 4) { |
f = v.d; |
/* float not supported */ |
} else |
if (suffix == F && size == 8) { |
d = v.d; |
/* double not supported */ |
} else |
if (suffix == P) { |
print("\t.word\t0x%x\n", (unsigned) v.p); |
} else |
if (size == 1) { |
print("\t.byte\t0x%x\n", |
(unsigned) ((unsigned char) (suffix == I ? v.i : v.u))); |
} else |
if (size == 2) { |
print("\t.half\t0x%x\n", |
(unsigned) ((unsigned short) (suffix == I ? v.i : v.u))); |
} else |
if (size == 4) { |
print("\t.word\t0x%x\n", (unsigned) (suffix == I ? v.i : v.u)); |
} |
} |
|
|
static void defstring(int n, char *str) { |
char *s; |
|
for (s = str; s < str + n; s++) { |
print("\t.byte\t0x%x\n", (*s) & 0xFF); |
} |
} |
|
|
static void defsymbol(Symbol s) { |
if (s->scope >= LOCAL && s->sclass == STATIC) { |
s->x.name = stringf("L.%d", genlabel(1)); |
} else |
if (s->generated) { |
s->x.name = stringf("L.%s", s->name); |
} else { |
assert(s->scope != CONSTANTS || isint(s->type) || isptr(s->type)); |
s->x.name = s->name; |
} |
} |
|
|
static void export(Symbol s) { |
print("\t.export\t%s\n", s->name); |
} |
|
|
static int bitcount(unsigned mask) { |
unsigned i, n; |
|
n = 0; |
for (i = 1; i != 0; i <<= 1) { |
if (mask & i) { |
n++; |
} |
} |
return n; |
} |
|
|
static Symbol argreg(int argno, int offset, int ty, int sz, int ty0) { |
assert((offset & 3) == 0); |
if (offset > 12) { |
return NULL; |
} |
return ireg[(offset / 4) + 4]; |
} |
|
|
static void function(Symbol f, Symbol caller[], Symbol callee[], int ncalls) { |
int i; |
Symbol p, q; |
Symbol r; |
int sizeisave; |
int saved; |
Symbol argregs[4]; |
|
usedmask[0] = usedmask[1] = 0; |
freemask[0] = freemask[1] = ~((unsigned) 0); |
offset = 0; |
maxoffset = 0; |
maxargoffset = 0; |
for (i = 0; callee[i] != NULL; i++) { |
p = callee[i]; |
q = caller[i]; |
assert(q != NULL); |
offset = roundup(offset, q->type->align); |
p->x.offset = q->x.offset = offset; |
p->x.name = q->x.name = stringd(offset); |
r = argreg(i, offset, optype(ttob(q->type)), |
q->type->size, optype(ttob(caller[0]->type))); |
if (i < 4) { |
argregs[i] = r; |
} |
offset = roundup(offset + q->type->size, 4); |
if (variadic(f->type)) { |
p->sclass = AUTO; |
} else |
if (r != NULL && ncalls == 0 && !isstruct(q->type) && |
!p->addressed && !(isfloat(q->type) && r->x.regnode->set == IREG)) { |
p->sclass = q->sclass = REGISTER; |
askregvar(p, r); |
assert(p->x.regnode && p->x.regnode->vbl == p); |
q->x = p->x; |
q->type = p->type; |
} else |
if (askregvar(p, rmap(ttob(p->type))) && |
r != NULL && (isint(p->type) || p->type == q->type)) { |
assert(q->sclass != REGISTER); |
p->sclass = q->sclass = REGISTER; |
q->type = p->type; |
} |
} |
assert(caller[i] == NULL); |
offset = 0; |
gencode(caller, callee); |
if (ncalls != 0) { |
usedmask[IREG] |= ((unsigned) 1) << 31; |
} |
usedmask[IREG] &= 0x80FF0000; |
usedmask[FREG] &= 0xFFF00000; |
maxargoffset = roundup(maxargoffset, 4); |
if (ncalls != 0 && maxargoffset < 16) { |
maxargoffset = 16; |
} |
sizeisave = 4 * bitcount(usedmask[IREG]); |
framesize = roundup(maxargoffset + sizeisave + maxoffset, 16); |
segment(CODE); |
print("\t.align\t4\n"); |
print("%s:\n", f->x.name); |
if (framesize > 0) { |
print("\tsub\t$29,$29,%d\n", framesize); |
} |
saved = maxargoffset; |
for (i = 16; i < 32; i++) { |
if (usedmask[IREG] & (1 << i)) { |
print("\tstw\t$%d,$29,%d\n", i, saved); |
saved += 4; |
} |
} |
for (i = 0; i < 4 && callee[i] != NULL; i++) { |
r = argregs[i]; |
if (r && r->x.regnode != callee[i]->x.regnode) { |
Symbol out = callee[i]; |
Symbol in = caller[i]; |
int rn = r->x.regnode->number; |
int rs = r->x.regnode->set; |
int tyin = ttob(in->type); |
assert(out && in && r && r->x.regnode); |
assert(out->sclass != REGISTER || out->x.regnode); |
if (out->sclass == REGISTER && |
(isint(out->type) || out->type == in->type)) { |
int outn = out->x.regnode->number; |
print("\tadd\t$%d,$0,$%d\n", outn, rn); |
} else { |
int off = in->x.offset + framesize; |
int n = (in->type->size + 3) / 4; |
int i; |
for (i = rn; i < rn + n && i <= 7; i++) { |
print("\tstw\t$%d,$29,%d\n", i, off + (i - rn) * 4); |
} |
} |
} |
} |
if (variadic(f->type) && callee[i - 1] != NULL) { |
i = callee[i - 1]->x.offset + callee[i - 1]->type->size; |
for (i = roundup(i, 4)/4; i <= 3; i++) { |
print("\tstw\t$%d,$29,%d\n", i + 4, framesize + 4 * i); |
} |
} |
emitcode(); |
saved = maxargoffset; |
for (i = 16; i < 32; i++) { |
if (usedmask[IREG] & (1 << i)) { |
print("\tldw\t$%d,$29,%d\n", i, saved); |
saved += 4; |
} |
} |
if (framesize > 0) { |
print("\tadd\t$29,$29,%d\n", framesize); |
} |
print("\tjr\t$31\n"); |
print("\n"); |
} |
|
|
static void global(Symbol s) { |
print("\t.align\t%d\n", s->type->align); |
print("%s:\n", s->x.name); |
} |
|
|
static void import(Symbol s) { |
print("\t.import\t%s\n", s->name); |
} |
|
|
static void local(Symbol s) { |
if (askregvar(s, rmap(ttob(s->type))) == 0) { |
mkauto(s); |
} |
} |
|
|
static void setSwap(void) { |
union { |
char c; |
int i; |
} u; |
|
u.i = 0; |
u.c = 1; |
swap = ((u.i == 1) != IR->little_endian); |
} |
|
|
static void progbeg(int argc, char *argv[]) { |
int i; |
|
setSwap(); |
segment(CODE); |
parseflags(argc, argv); |
for (i = 0; i < 32; i++) { |
ireg[i] = mkreg("%d", i, 1, IREG); |
} |
iregw = mkwildcard(ireg); |
for (i = 0; i < 32; i += 2) { |
freg2[i] = mkreg("%d", i, 3, FREG); |
} |
freg2w = mkwildcard(freg2); |
tmask[IREG] = INTTMP; |
vmask[IREG] = INTVAR; |
tmask[FREG] = FLTTMP; |
vmask[FREG] = FLTVAR; |
blkreg = mkreg("8", 8, 7, IREG); |
} |
|
|
static void progend(void) { |
} |
|
|
static void segment(int n) { |
static int currSeg = -1; |
int newSeg; |
|
switch (n) { |
case CODE: |
newSeg = CODE; |
break; |
case BSS: |
newSeg = BSS; |
break; |
case DATA: |
newSeg = DATA; |
break; |
case LIT: |
newSeg = DATA; |
break; |
} |
if (currSeg == newSeg) { |
return; |
} |
switch (newSeg) { |
case CODE: |
print("\t.code\n"); |
break; |
case BSS: |
print("\t.bss\n"); |
break; |
case DATA: |
print("\t.data\n"); |
break; |
} |
currSeg = newSeg; |
} |
|
|
static void space(int n) { |
print("\t.space\t%d\n", n); |
} |
|
|
static Symbol rmap(int opk) { |
switch (optype(opk)) { |
case I: |
case U: |
case P: |
case B: |
return iregw; |
case F: |
return freg2w; |
default: |
return 0; |
} |
} |
|
|
static void blkfetch(int size, int off, int reg, int tmp) { |
assert(size == 1 || size == 2 || size == 4); |
if (size == 1) { |
print("\tldbu\t$%d,$%d,%d\n", tmp, reg, off); |
} else |
if (size == 2) { |
print("\tldhu\t$%d,$%d,%d\n", tmp, reg, off); |
} else |
if (size == 4) { |
print("\tldw\t$%d,$%d,%d\n", tmp, reg, off); |
} |
} |
|
|
static void blkstore(int size, int off, int reg, int tmp) { |
assert(size == 1 || size == 2 || size == 4); |
if (size == 1) { |
print("\tstb\t$%d,$%d,%d\n", tmp, reg, off); |
} else |
if (size == 2) { |
print("\tsth\t$%d,$%d,%d\n", tmp, reg, off); |
} else |
if (size == 4) { |
print("\tstw\t$%d,$%d,%d\n", tmp, reg, off); |
} |
} |
|
|
static void blkloop(int dreg, int doff, |
int sreg, int soff, |
int size, int tmps[]) { |
int label; |
|
label = genlabel(1); |
print("\tadd\t$%d,$%d,%d\n", sreg, sreg, size & ~7); |
print("\tadd\t$%d,$%d,%d\n", tmps[2], dreg, size & ~7); |
blkcopy(tmps[2], doff, sreg, soff, size & 7, tmps); |
print("L.%d:\n", label); |
print("\tsub\t$%d,$%d,%d\n", sreg, sreg, 8); |
print("\tsub\t$%d,$%d,%d\n", tmps[2], tmps[2], 8); |
blkcopy(tmps[2], doff, sreg, soff, 8, tmps); |
print("\tbltu\t$%d,$%d,L.%d\n", dreg, tmps[2], label); |
} |
|
|
static void emit2(Node p) { |
static int ty0; |
int ty, sz; |
Symbol q; |
int src; |
int dst, n; |
|
switch (specific(p->op)) { |
case ARG+I: |
case ARG+P: |
case ARG+U: |
ty = optype(p->op); |
sz = opsize(p->op); |
if (p->x.argno == 0) { |
ty0 = ty; |
} |
q = argreg(p->x.argno, p->syms[2]->u.c.v.i, ty, sz, ty0); |
src = getregnum(p->x.kids[0]); |
if (q == NULL) { |
print("\tstw\t$%d,$29,%d\n", src, p->syms[2]->u.c.v.i); |
} |
break; |
case ASGN+B: |
dalign = p->syms[1]->u.c.v.i; |
salign = p->syms[1]->u.c.v.i; |
blkcopy(getregnum(p->x.kids[0]), 0, |
getregnum(p->x.kids[1]), 0, |
p->syms[0]->u.c.v.i, tmpregs); |
break; |
case ARG+B: |
dalign = 4; |
salign = p->syms[1]->u.c.v.i; |
blkcopy(29, p->syms[2]->u.c.v.i, |
getregnum(p->x.kids[0]), 0, |
p->syms[0]->u.c.v.i, tmpregs); |
n = p->syms[2]->u.c.v.i + p->syms[0]->u.c.v.i; |
dst = p->syms[2]->u.c.v.i; |
for (; dst <= 12 && dst < n; dst += 4) { |
print("\tldw\t$%d,$29,%d\n", (dst / 4) + 4, dst); |
} |
break; |
} |
} |
|
|
static void doarg(Node p) { |
static int argno; |
int align; |
|
if (argoffset == 0) { |
argno = 0; |
} |
p->x.argno = argno++; |
align = p->syms[1]->u.c.v.i < 4 ? 4 : p->syms[1]->u.c.v.i; |
p->syms[2] = intconst(mkactual(align, p->syms[0]->u.c.v.i)); |
} |
|
|
static void target(Node p) { |
static int ty0; |
int ty; |
Symbol q; |
|
assert(p); |
switch (specific(p->op)) { |
case CNST+I: |
case CNST+P: |
case CNST+U: |
if (range(p, 0, 0) == 0) { |
setreg(p, ireg[0]); |
p->x.registered = 1; |
} |
break; |
case CALL+I: |
case CALL+P: |
case CALL+U: |
rtarget(p, 0, ireg[25]); |
setreg(p, ireg[2]); |
break; |
case CALL+V: |
rtarget(p, 0, ireg[25]); |
break; |
case RET+I: |
case RET+P: |
case RET+U: |
rtarget(p, 0, ireg[2]); |
break; |
case ARG+I: |
case ARG+P: |
case ARG+U: |
ty = optype(p->op); |
q = argreg(p->x.argno, p->syms[2]->u.c.v.i, ty, opsize(p->op), ty0); |
if (p->x.argno == 0) { |
ty0 = ty; |
} |
if (q && !(ty == F && q->x.regnode->set == IREG)) { |
rtarget(p, 0, q); |
} |
break; |
case ASGN+B: |
rtarget(p->kids[1], 0, blkreg); |
break; |
case ARG+B: |
rtarget(p->kids[0], 0, blkreg); |
break; |
} |
} |
|
|
static void clobber(Node p) { |
assert(p); |
switch (specific(p->op)) { |
case CALL+F: |
spill(INTTMP | INTRET, IREG, p); |
spill(FLTTMP, FREG, p); |
break; |
case CALL+I: |
case CALL+P: |
case CALL+U: |
spill(INTTMP, IREG, p); |
spill(FLTTMP | FLTRET, FREG, p); |
break; |
case CALL+V: |
spill(INTTMP | INTRET, IREG, p); |
spill(FLTTMP | FLTRET, FREG, p); |
break; |
} |
} |
|
|
Interface eco32IR = { |
1, 1, 0, /* char */ |
2, 2, 0, /* short */ |
4, 4, 0, /* int */ |
4, 4, 0, /* long */ |
4, 4, 0, /* long long */ |
4, 4, 1, /* float */ |
8, 8, 1, /* double */ |
8, 8, 1, /* long double */ |
4, 4, 0, /* T * */ |
0, 1, 0, /* struct */ |
0, /* little_endian */ |
0, /* mulops_calls */ |
0, /* wants_callb */ |
1, /* wants_argb */ |
1, /* left_to_right */ |
0, /* wants_dag */ |
0, /* unsigned_char */ |
address, |
blockbeg, |
blockend, |
defaddress, |
defconst, |
defstring, |
defsymbol, |
emit, |
export, |
function, |
gen, |
global, |
import, |
local, |
progbeg, |
progend, |
segment, |
space, |
0, 0, 0, 0, 0, 0, 0, |
{ |
1, /* max_unaligned_load */ |
rmap, |
blkfetch, blkstore, blkloop, |
_label, |
_rule, |
_nts, |
_kids, |
_string, |
_templates, |
_isinstruction, |
_ntname, |
emit2, |
doarg, |
target, |
clobber |
} |
}; |
/eco32.md.SAVE-2
0,0 → 1,1007
%{ |
|
/* |
* eco32.md -- ECO32 back-end specification |
* |
* register usage: |
* $0 always zero |
* $1 reserved for assembler |
* $2 func return value |
* $3 func return value |
* $4 proc/func argument |
* $5 proc/func argument |
* $6 proc/func argument |
* $7 proc/func argument |
* $8 temporary register (caller-save) |
* $9 temporary register (caller-save) |
* $10 temporary register (caller-save) |
* $11 temporary register (caller-save) |
* $12 temporary register (caller-save) |
* $13 temporary register (caller-save) |
* $14 temporary register (caller-save) |
* $15 temporary register (caller-save) |
* $16 register variable (callee-save) |
* $17 register variable (callee-save) |
* $18 register variable (callee-save) |
* $19 register variable (callee-save) |
* $20 register variable (callee-save) |
* $21 register variable (callee-save) |
* $22 register variable (callee-save) |
* $23 register variable (callee-save) |
* $24 temporary register (caller-save) |
* $25 temporary register (caller-save) |
* $26 reserved for OS kernel |
* $27 reserved for OS kernel |
* $28 reserved for OS kernel |
* $29 stack pointer |
* $30 interrupt return address |
* $31 proc/func return address |
* caller-save registers are not preserved across procedure calls |
* callee-save registers are preserved across procedure calls |
* |
* tree grammar terminals produced by: |
* ops c=1 s=2 i=4 l=4 h=4 f=4 d=8 x=8 p=4 |
*/ |
|
#include "c.h" |
|
#define NODEPTR_TYPE Node |
#define OP_LABEL(p) ((p)->op) |
#define LEFT_CHILD(p) ((p)->kids[0]) |
#define RIGHT_CHILD(p) ((p)->kids[1]) |
#define STATE_LABEL(p) ((p)->x.state) |
|
static void address(Symbol, Symbol, long); |
static void defaddress(Symbol); |
static void defconst(int, int, Value); |
static void defstring(int, char *); |
static void defsymbol(Symbol); |
static void export(Symbol); |
static void function(Symbol, Symbol [], Symbol [], int); |
static void global(Symbol); |
static void import(Symbol); |
static void local(Symbol); |
static void progbeg(int, char * []); |
static void progend(void); |
static void segment(int); |
static void space(int); |
static Symbol rmap(int); |
static void blkfetch(int, int, int, int); |
static void blkstore(int, int, int, int); |
static void blkloop(int, int, int, int, int, int []); |
static void emit2(Node); |
static void doarg(Node); |
static void target(Node); |
static void clobber(Node); |
|
#define INTTMP 0x0100FF00 |
#define INTVAR 0x00FF0000 |
#define INTRET 0x00000004 |
#define FLTTMP 0x000F0FF0 |
#define FLTVAR 0xFFF00000 |
#define FLTRET 0x00000003 |
|
static Symbol ireg[32]; |
static Symbol iregw; |
static Symbol freg2[32]; |
static Symbol freg2w; |
static Symbol blkreg; |
static int tmpregs[] = { 3, 9, 10 }; |
|
%} |
|
%start stmt |
|
%term CNSTF4=4113 CNSTF8=8209 |
%term CNSTI1=1045 CNSTI2=2069 CNSTI4=4117 |
%term CNSTP4=4119 |
%term CNSTU1=1046 CNSTU2=2070 CNSTU4=4118 |
|
%term ARGB=41 |
%term ARGF4=4129 ARGF8=8225 |
%term ARGI4=4133 |
%term ARGP4=4135 |
%term ARGU4=4134 |
|
%term ASGNB=57 |
%term ASGNF4=4145 ASGNF8=8241 |
%term ASGNI1=1077 ASGNI2=2101 ASGNI4=4149 |
%term ASGNP4=4151 |
%term ASGNU1=1078 ASGNU2=2102 ASGNU4=4150 |
|
%term INDIRB=73 |
%term INDIRF4=4161 INDIRF8=8257 |
%term INDIRI1=1093 INDIRI2=2117 INDIRI4=4165 |
%term INDIRP4=4167 |
%term INDIRU1=1094 INDIRU2=2118 INDIRU4=4166 |
|
%term CVFF4=4209 CVFF8=8305 |
%term CVFI4=4213 |
|
%term CVIF4=4225 CVIF8=8321 |
%term CVII1=1157 CVII2=2181 CVII4=4229 |
%term CVIU1=1158 CVIU2=2182 CVIU4=4230 |
|
%term CVPU4=4246 |
|
%term CVUI1=1205 CVUI2=2229 CVUI4=4277 |
%term CVUP4=4279 |
%term CVUU1=1206 CVUU2=2230 CVUU4=4278 |
|
%term NEGF4=4289 NEGF8=8385 |
%term NEGI4=4293 |
|
%term CALLB=217 |
%term CALLF4=4305 CALLF8=8401 |
%term CALLI4=4309 |
%term CALLP4=4311 |
%term CALLU4=4310 |
%term CALLV=216 |
|
%term RETF4=4337 RETF8=8433 |
%term RETI4=4341 |
%term RETP4=4343 |
%term RETU4=4342 |
%term RETV=248 |
|
%term ADDRGP4=4359 |
|
%term ADDRFP4=4375 |
|
%term ADDRLP4=4391 |
|
%term ADDF4=4401 ADDF8=8497 |
%term ADDI4=4405 |
%term ADDP4=4407 |
%term ADDU4=4406 |
|
%term SUBF4=4417 SUBF8=8513 |
%term SUBI4=4421 |
%term SUBP4=4423 |
%term SUBU4=4422 |
|
%term LSHI4=4437 |
%term LSHU4=4438 |
|
%term MODI4=4453 |
%term MODU4=4454 |
|
%term RSHI4=4469 |
%term RSHU4=4470 |
|
%term BANDI4=4485 |
%term BANDU4=4486 |
|
%term BCOMI4=4501 |
%term BCOMU4=4502 |
|
%term BORI4=4517 |
%term BORU4=4518 |
|
%term BXORI4=4533 |
%term BXORU4=4534 |
|
%term DIVF4=4545 DIVF8=8641 |
%term DIVI4=4549 |
%term DIVU4=4550 |
|
%term MULF4=4561 MULF8=8657 |
%term MULI4=4565 |
%term MULU4=4566 |
|
%term EQF4=4577 EQF8=8673 |
%term EQI4=4581 |
%term EQU4=4582 |
|
%term GEF4=4593 GEF8=8689 |
%term GEI4=4597 |
%term GEU4=4598 |
|
%term GTF4=4609 GTF8=8705 |
%term GTI4=4613 |
%term GTU4=4614 |
|
%term LEF4=4625 LEF8=8721 |
%term LEI4=4629 |
%term LEU4=4630 |
|
%term LTF4=4641 LTF8=8737 |
%term LTI4=4645 |
%term LTU4=4646 |
|
%term NEF4=4657 NEF8=8753 |
%term NEI4=4661 |
%term NEU4=4662 |
|
%term JUMPV=584 |
|
%term LABELV=600 |
|
%term LOADB=233 |
%term LOADF4=4321 LOADF8=8417 |
%term LOADI1=1253 LOADI2=2277 LOADI4=4325 |
%term LOADP4=4327 |
%term LOADU1=1254 LOADU2=2278 LOADU4=4326 |
|
%term VREGP=711 |
|
|
%% |
|
|
reg: INDIRI1(VREGP) "# read register\n" |
reg: INDIRI2(VREGP) "# read register\n" |
reg: INDIRI4(VREGP) "# read register\n" |
reg: INDIRP4(VREGP) "# read register\n" |
reg: INDIRU1(VREGP) "# read register\n" |
reg: INDIRU2(VREGP) "# read register\n" |
reg: INDIRU4(VREGP) "# read register\n" |
|
stmt: ASGNI1(VREGP,reg) "# write register\n" |
stmt: ASGNI2(VREGP,reg) "# write register\n" |
stmt: ASGNI4(VREGP,reg) "# write register\n" |
stmt: ASGNP4(VREGP,reg) "# write register\n" |
stmt: ASGNU1(VREGP,reg) "# write register\n" |
stmt: ASGNU2(VREGP,reg) "# write register\n" |
stmt: ASGNU4(VREGP,reg) "# write register\n" |
|
con: CNSTI1 "%a" |
con: CNSTI2 "%a" |
con: CNSTI4 "%a" |
con: CNSTP4 "%a" |
con: CNSTU1 "%a" |
con: CNSTU2 "%a" |
con: CNSTU4 "%a" |
|
stmt: reg "" |
|
acon: con "%0" |
acon: ADDRGP4 "%a" |
|
addr: ADDI4(reg,acon) "$%0,%1" |
addr: ADDP4(reg,acon) "$%0,%1" |
addr: ADDU4(reg,acon) "$%0,%1" |
|
addr: acon "$0,%0" |
addr: reg "$%0,0" |
addr: ADDRFP4 "$29,%a+%F" |
addr: ADDRLP4 "$29,%a+%F" |
|
reg: addr "\tadd\t$%c,%0\n" 1 |
|
reg: CNSTI1 "# reg\n" range(a, 0, 0) |
reg: CNSTI2 "# reg\n" range(a, 0, 0) |
reg: CNSTI4 "# reg\n" range(a, 0, 0) |
reg: CNSTP4 "# reg\n" range(a, 0, 0) |
reg: CNSTU1 "# reg\n" range(a, 0, 0) |
reg: CNSTU2 "# reg\n" range(a, 0, 0) |
reg: CNSTU4 "# reg\n" range(a, 0, 0) |
|
stmt: ASGNI1(addr,reg) "\tstb\t$%1,%0\n" 1 |
stmt: ASGNI2(addr,reg) "\tsth\t$%1,%0\n" 1 |
stmt: ASGNI4(addr,reg) "\tstw\t$%1,%0\n" 1 |
stmt: ASGNP4(addr,reg) "\tstw\t$%1,%0\n" 1 |
stmt: ASGNU1(addr,reg) "\tstb\t$%1,%0\n" 1 |
stmt: ASGNU2(addr,reg) "\tsth\t$%1,%0\n" 1 |
stmt: ASGNU4(addr,reg) "\tstw\t$%1,%0\n" 1 |
|
reg: INDIRI1(addr) "\tldb\t$%c,%0\n" 1 |
reg: INDIRI2(addr) "\tldh\t$%c,%0\n" 1 |
reg: INDIRI4(addr) "\tldw\t$%c,%0\n" 1 |
reg: INDIRP4(addr) "\tldw\t$%c,%0\n" 1 |
reg: INDIRU1(addr) "\tldbu\t$%c,%0\n" 1 |
reg: INDIRU2(addr) "\tldhu\t$%c,%0\n" 1 |
reg: INDIRU4(addr) "\tldw\t$%c,%0\n" 1 |
|
reg: CVII4(INDIRI1(addr)) "\tldb\t$%c,%0\n" 1 |
reg: CVII4(INDIRI2(addr)) "\tldh\t$%c,%0\n" 1 |
reg: CVUU4(INDIRU1(addr)) "\tldbu\t$%c,%0\n" 1 |
reg: CVUU4(INDIRU2(addr)) "\tldhu\t$%c,%0\n" 1 |
reg: CVUI4(INDIRU1(addr)) "\tldbu\t$%c,%0\n" 1 |
reg: CVUI4(INDIRU2(addr)) "\tldhu\t$%c,%0\n" 1 |
|
rc: con "%0" |
rc: reg "$%0" |
|
reg: ADDI4(reg,rc) "\tadd\t$%c,$%0,%1\n" 1 |
reg: ADDP4(reg,rc) "\tadd\t$%c,$%0,%1\n" 1 |
reg: ADDU4(reg,rc) "\tadd\t$%c,$%0,%1\n" 1 |
reg: SUBI4(reg,rc) "\tsub\t$%c,$%0,%1\n" 1 |
reg: SUBP4(reg,rc) "\tsub\t$%c,$%0,%1\n" 1 |
reg: SUBU4(reg,rc) "\tsub\t$%c,$%0,%1\n" 1 |
reg: NEGI4(reg) "\tsub\t$%c,$0,$%0\n" 1 |
|
reg: MULI4(reg,rc) "\tmul\t$%c,$%0,%1\n" 1 |
reg: MULU4(reg,rc) "\tmulu\t$%c,$%0,%1\n" 1 |
reg: DIVI4(reg,rc) "\tdiv\t$%c,$%0,%1\n" 1 |
reg: DIVU4(reg,rc) "\tdivu\t$%c,$%0,%1\n" 1 |
reg: MODI4(reg,rc) "\trem\t$%c,$%0,%1\n" 1 |
reg: MODU4(reg,rc) "\tremu\t$%c,$%0,%1\n" 1 |
|
reg: BANDI4(reg,rc) "\tand\t$%c,$%0,%1\n" 1 |
reg: BANDU4(reg,rc) "\tand\t$%c,$%0,%1\n" 1 |
reg: BORI4(reg,rc) "\tor\t$%c,$%0,%1\n" 1 |
reg: BORU4(reg,rc) "\tor\t$%c,$%0,%1\n" 1 |
reg: BXORI4(reg,rc) "\txor\t$%c,$%0,%1\n" 1 |
reg: BXORU4(reg,rc) "\txor\t$%c,$%0,%1\n" 1 |
reg: BCOMI4(reg) "\txnor\t$%c,$0,$%0\n" 1 |
reg: BCOMU4(reg) "\txnor\t$%c,$0,$%0\n" 1 |
|
rc5: CNSTI4 "%a" range(a, 0, 31) |
rc5: reg "$%0" |
|
reg: LSHI4(reg,rc5) "\tsll\t$%c,$%0,%1\n" 1 |
reg: LSHU4(reg,rc5) "\tsll\t$%c,$%0,%1\n" 1 |
reg: RSHI4(reg,rc5) "\tsar\t$%c,$%0,%1\n" 1 |
reg: RSHU4(reg,rc5) "\tslr\t$%c,$%0,%1\n" 1 |
|
reg: LOADI1(reg) "\tadd\t$%c,$0,$%0\n" move(a) |
reg: LOADI2(reg) "\tadd\t$%c,$0,$%0\n" move(a) |
reg: LOADI4(reg) "\tadd\t$%c,$0,$%0\n" move(a) |
reg: LOADP4(reg) "\tadd\t$%c,$0,$%0\n" move(a) |
reg: LOADU1(reg) "\tadd\t$%c,$0,$%0\n" move(a) |
reg: LOADU2(reg) "\tadd\t$%c,$0,$%0\n" move(a) |
reg: LOADU4(reg) "\tadd\t$%c,$0,$%0\n" move(a) |
|
reg: CVII4(reg) "\tsll\t$%c,$%0,8*(4-%a)\n\tsar\t$%c,$%c,8*(4-%a)\n" 2 |
reg: CVUI4(reg) "\tand\t$%c,$%0,(1<<(8*%a))-1\n" 1 |
reg: CVUU4(reg) "\tand\t$%c,$%0,(1<<(8*%a))-1\n" 1 |
|
stmt: LABELV "%a:\n" |
stmt: JUMPV(acon) "\tj\t%0\n" 1 |
stmt: JUMPV(reg) "\tjr\t$%0\n" 1 |
|
stmt: EQI4(reg,reg) "\tbeq\t$%0,$%1,%a\n" 1 |
stmt: EQU4(reg,reg) "\tbeq\t$%0,$%1,%a\n" 1 |
stmt: NEI4(reg,reg) "\tbne\t$%0,$%1,%a\n" 1 |
stmt: NEU4(reg,reg) "\tbne\t$%0,$%1,%a\n" 1 |
stmt: LEI4(reg,reg) "\tble\t$%0,$%1,%a\n" 1 |
stmt: LEU4(reg,reg) "\tbleu\t$%0,$%1,%a\n" 1 |
stmt: LTI4(reg,reg) "\tblt\t$%0,$%1,%a\n" 1 |
stmt: LTU4(reg,reg) "\tbltu\t$%0,$%1,%a\n" 1 |
stmt: GEI4(reg,reg) "\tbge\t$%0,$%1,%a\n" 1 |
stmt: GEU4(reg,reg) "\tbgeu\t$%0,$%1,%a\n" 1 |
stmt: GTI4(reg,reg) "\tbgt\t$%0,$%1,%a\n" 1 |
stmt: GTU4(reg,reg) "\tbgtu\t$%0,$%1,%a\n" 1 |
|
reg: CALLI4(ar) "\tjal\t%0\n" 1 |
reg: CALLP4(ar) "\tjal\t%0\n" 1 |
reg: CALLU4(ar) "\tjal\t%0\n" 1 |
stmt: CALLV(ar) "\tjal\t%0\n" 1 |
|
ar: ADDRGP4 "%a" |
ar: reg "$%0" |
ar: CNSTP4 "%a" range(a, 0, 0x03FFFFFF) |
|
stmt: RETI4(reg) "# ret\n" 1 |
stmt: RETP4(reg) "# ret\n" 1 |
stmt: RETU4(reg) "# ret\n" 1 |
stmt: RETV(reg) "# ret\n" 1 |
|
stmt: ARGI4(reg) "# arg\n" 1 |
stmt: ARGP4(reg) "# arg\n" 1 |
stmt: ARGU4(reg) "# arg\n" 1 |
|
stmt: ARGB(INDIRB(reg)) "# argb %0\n" 1 |
stmt: ASGNB(reg,INDIRB(reg)) "# asgnb %0 %1\n" 1 |
|
reg: INDIRF4(VREGP) "# read register\n" |
stmt: ASGNF4(VREGP,reg) "# write register\n" |
reg: INDIRF4(addr) ";FP: l.s $f%c,%0\n" 1 |
stmt: ASGNF4(addr,reg) ";FP: s.s $f%1,%0\n" 1 |
reg: ADDF4(reg,reg) ";FP: add.s $f%c,$f%0,$f%1\n" 1 |
reg: SUBF4(reg,reg) ";FP: sub.s $f%c,$f%0,$f%1\n" 1 |
reg: MULF4(reg,reg) ";FP: mul.s $f%c,$f%0,$f%1\n" 1 |
reg: DIVF4(reg,reg) ";FP: div.s $f%c,$f%0,$f%1\n" 1 |
reg: LOADF4(reg) ";FP: mov.s $f%c,$f%0\n" 1 |
reg: NEGF4(reg) ";FP: neg.s $f%c,$f%0\n" 1 |
reg: CVFF4(reg) ";FP: cvt.s.d $f%c,$f%0\n" 1 |
reg: CVIF4(reg) ";FP: mtc1 $%0,$f%c; cvt.s.w $f%c,$f%c\n" 1 |
reg: CVFI4(reg) ";FP: trunc.w.s $f2,$f%0,$%c; mfc1 $%c,$f2\n" (a->syms[0]->u.c.v.i == 4 ? 1 : LBURG_MAX) |
stmt: EQF4(reg,reg) ";FP: c.eq.s $f%0,$f%1; bc1t %a\n" 1 |
stmt: LEF4(reg,reg) ";FP: c.ule.s $f%0,$f%1; bc1t %a\n" 1 |
stmt: LTF4(reg,reg) ";FP: c.ult.s $f%0,$f%1; bc1t %a\n" 1 |
stmt: GEF4(reg,reg) ";FP: c.lt.s $f%0,$f%1; bc1f %a\n" 1 |
stmt: GTF4(reg,reg) ";FP: c.le.s $f%0,$f%1; bc1f %a\n" 1 |
stmt: NEF4(reg,reg) ";FP: c.eq.s $f%0,$f%1; bc1f %a\n" 1 |
reg: CALLF4(ar) "\tjal\t%0\n" 1 |
stmt: RETF4(reg) "# ret\n" 1 |
stmt: ARGF4(reg) "# arg\n" 1 |
|
reg: INDIRF8(VREGP) "# read register\n" |
stmt: ASGNF8(VREGP,reg) "# write register\n" |
reg: INDIRF8(addr) ";FP: l.d $f%c,%0\n" 1 |
stmt: ASGNF8(addr,reg) ";FP: s.d $f%1,%0\n" 1 |
reg: ADDF8(reg,reg) ";FP: add.d $f%c,$f%0,$f%1\n" 1 |
reg: SUBF8(reg,reg) ";FP: sub.d $f%c,$f%0,$f%1\n" 1 |
reg: MULF8(reg,reg) ";FP: mul.d $f%c,$f%0,$f%1\n" 1 |
reg: DIVF8(reg,reg) ";FP: div.d $f%c,$f%0,$f%1\n" 1 |
reg: LOADF8(reg) ";FP: mov.d $f%c,$f%0\n" 1 |
reg: NEGF8(reg) ";FP: neg.d $f%c,$f%0\n" 1 |
reg: CVFF8(reg) ";FP: cvt.d.s $f%c,$f%0\n" 1 |
reg: CVIF8(reg) ";FP: mtc1 $%0,$f%c; cvt.d.w $f%c,$f%c\n" 1 |
reg: CVFI4(reg) ";FP: trunc.w.d $f2,$f%0,$%c; mfc1 $%c,$f2\n" (a->syms[0]->u.c.v.i == 8 ? 1 : LBURG_MAX) |
stmt: EQF8(reg,reg) ";FP: c.eq.d $f%0,$f%1; bc1t %a\n" 1 |
stmt: LEF8(reg,reg) ";FP: c.ule.d $f%0,$f%1; bc1t %a\n" 1 |
stmt: LTF8(reg,reg) ";FP: c.ult.d $f%0,$f%1; bc1t %a\n" 1 |
stmt: GEF8(reg,reg) ";FP: c.lt.d $f%0,$f%1; bc1f %a\n" 1 |
stmt: GTF8(reg,reg) ";FP: c.le.d $f%0,$f%1; bc1f %a\n" 1 |
stmt: NEF8(reg,reg) ";FP: c.eq.d $f%0,$f%1; bc1f %a\n" 1 |
reg: CALLF8(ar) "\tjal\t%0\n" 1 |
stmt: RETF8(reg) "# ret\n" 1 |
stmt: ARGF8(reg) "# arg\n" 1 |
|
|
%% |
|
|
static void address(Symbol s1, Symbol s2, long n) { |
if (s2->scope == GLOBAL || |
s2->sclass == STATIC || |
s2->sclass == EXTERN) { |
s1->x.name = stringf("%s%s%D", s2->x.name, n >= 0 ? "+" : "", n); |
} else { |
assert(n >= INT_MIN && n <= INT_MAX); |
s1->x.offset = s2->x.offset + n; |
s1->x.name = stringd(s1->x.offset); |
} |
} |
|
|
static void defaddress(Symbol s) { |
print("\t.word\t%s\n", s->x.name); |
} |
|
|
static void defconst(int suffix, int size, Value v) { |
float f; |
double d; |
unsigned *p; |
|
if (suffix == F && size == 4) { |
f = v.d; |
print("\t.word\t0x%x\n", * (unsigned *) &f); |
} else |
if (suffix == F && size == 8) { |
d = v.d; |
p = (unsigned *) &d; |
print("\t.word\t0x%x\n", p[swap]); |
print("\t.word\t0x%x\n", p[1 - swap]); |
} else |
if (suffix == P) { |
print("\t.word\t0x%x\n", (unsigned) v.p); |
} else |
if (size == 1) { |
print("\t.byte\t0x%x\n", |
(unsigned) ((unsigned char) (suffix == I ? v.i : v.u))); |
} else |
if (size == 2) { |
print("\t.half\t0x%x\n", |
(unsigned) ((unsigned short) (suffix == I ? v.i : v.u))); |
} else |
if (size == 4) { |
print("\t.word\t0x%x\n", (unsigned) (suffix == I ? v.i : v.u)); |
} |
} |
|
|
static void defstring(int n, char *str) { |
char *s; |
|
for (s = str; s < str + n; s++) { |
print("\t.byte\t0x%x\n", (*s) & 0xFF); |
} |
} |
|
|
static void defsymbol(Symbol s) { |
if (s->scope >= LOCAL && s->sclass == STATIC) { |
s->x.name = stringf("L.%d", genlabel(1)); |
} else |
if (s->generated) { |
s->x.name = stringf("L.%s", s->name); |
} else { |
assert(s->scope != CONSTANTS || isint(s->type) || isptr(s->type)); |
s->x.name = s->name; |
} |
} |
|
|
static void export(Symbol s) { |
print("\t.export\t%s\n", s->name); |
} |
|
|
static int bitcount(unsigned mask) { |
unsigned i, n; |
|
n = 0; |
for (i = 1; i != 0; i <<= 1) { |
if (mask & i) { |
n++; |
} |
} |
return n; |
} |
|
|
static Symbol argreg(int argno, int offset, int ty, int sz, int ty0) { |
assert((offset & 3) == 0); |
if (offset > 12) { |
return NULL; |
} |
return ireg[(offset / 4) + 4]; |
} |
|
|
static void function(Symbol f, Symbol caller[], Symbol callee[], int ncalls) { |
int i; |
Symbol p, q; |
Symbol r; |
int sizeisave; |
int saved; |
Symbol argregs[4]; |
|
usedmask[0] = usedmask[1] = 0; |
freemask[0] = freemask[1] = ~((unsigned) 0); |
offset = 0; |
maxoffset = 0; |
maxargoffset = 0; |
for (i = 0; callee[i] != NULL; i++) { |
p = callee[i]; |
q = caller[i]; |
assert(q != NULL); |
offset = roundup(offset, q->type->align); |
p->x.offset = q->x.offset = offset; |
p->x.name = q->x.name = stringd(offset); |
r = argreg(i, offset, optype(ttob(q->type)), |
q->type->size, optype(ttob(caller[0]->type))); |
if (i < 4) { |
argregs[i] = r; |
} |
offset = roundup(offset + q->type->size, 4); |
if (variadic(f->type)) { |
p->sclass = AUTO; |
} else |
if (r != NULL && ncalls == 0 && !isstruct(q->type) && |
!p->addressed && !(isfloat(q->type) && r->x.regnode->set == IREG)) { |
p->sclass = q->sclass = REGISTER; |
askregvar(p, r); |
assert(p->x.regnode && p->x.regnode->vbl == p); |
q->x = p->x; |
q->type = p->type; |
} else |
if (askregvar(p, rmap(ttob(p->type))) && |
r != NULL && (isint(p->type) || p->type == q->type)) { |
assert(q->sclass != REGISTER); |
p->sclass = q->sclass = REGISTER; |
q->type = p->type; |
} |
} |
assert(caller[i] == NULL); |
offset = 0; |
gencode(caller, callee); |
if (ncalls != 0) { |
usedmask[IREG] |= ((unsigned) 1) << 31; |
} |
usedmask[IREG] &= 0x80FF0000; |
usedmask[FREG] &= 0xFFF00000; |
maxargoffset = roundup(maxargoffset, 4); |
if (ncalls != 0 && maxargoffset < 16) { |
maxargoffset = 16; |
} |
sizeisave = 4 * bitcount(usedmask[IREG]); |
framesize = roundup(maxargoffset + sizeisave + maxoffset, 16); |
segment(CODE); |
print("\t.align\t4\n"); |
print("%s:\n", f->x.name); |
if (framesize > 0) { |
print("\tsub\t$29,$29,%d\n", framesize); |
} |
saved = maxargoffset; |
for (i = 16; i < 32; i++) { |
if (usedmask[IREG] & (1 << i)) { |
print("\tstw\t$%d,$29,%d\n", i, saved); |
saved += 4; |
} |
} |
for (i = 0; i < 4 && callee[i] != NULL; i++) { |
r = argregs[i]; |
if (r && r->x.regnode != callee[i]->x.regnode) { |
Symbol out = callee[i]; |
Symbol in = caller[i]; |
int rn = r->x.regnode->number; |
int rs = r->x.regnode->set; |
int tyin = ttob(in->type); |
assert(out && in && r && r->x.regnode); |
assert(out->sclass != REGISTER || out->x.regnode); |
if (out->sclass == REGISTER && |
(isint(out->type) || out->type == in->type)) { |
int outn = out->x.regnode->number; |
print("\tadd\t$%d,$0,$%d\n", outn, rn); |
} else { |
int off = in->x.offset + framesize; |
int n = (in->type->size + 3) / 4; |
int i; |
for (i = rn; i < rn + n && i <= 7; i++) { |
print("\tstw\t$%d,$29,%d\n", i, off + (i - rn) * 4); |
} |
} |
} |
} |
if (variadic(f->type) && callee[i - 1] != NULL) { |
i = callee[i - 1]->x.offset + callee[i - 1]->type->size; |
for (i = roundup(i, 4)/4; i <= 3; i++) { |
print("\tstw\t$%d,$29,%d\n", i + 4, framesize + 4 * i); |
} |
} |
emitcode(); |
saved = maxargoffset; |
for (i = 16; i < 32; i++) { |
if (usedmask[IREG] & (1 << i)) { |
print("\tldw\t$%d,$29,%d\n", i, saved); |
saved += 4; |
} |
} |
if (framesize > 0) { |
print("\tadd\t$29,$29,%d\n", framesize); |
} |
print("\tjr\t$31\n"); |
print("\n"); |
} |
|
|
static void global(Symbol s) { |
if (s->type->align != 0) { |
print("\t.align\t%d\n", s->type->align); |
} else { |
print("\t.align\t%d\n", 4); |
} |
print("%s:\n", s->x.name); |
} |
|
|
static void import(Symbol s) { |
print("\t.import\t%s\n", s->name); |
} |
|
|
static void local(Symbol s) { |
if (askregvar(s, rmap(ttob(s->type))) == 0) { |
mkauto(s); |
} |
} |
|
|
static void setSwap(void) { |
union { |
char c; |
int i; |
} u; |
|
u.i = 0; |
u.c = 1; |
swap = ((u.i == 1) != IR->little_endian); |
} |
|
|
static void progbeg(int argc, char *argv[]) { |
int i; |
|
setSwap(); |
segment(CODE); |
parseflags(argc, argv); |
for (i = 0; i < 32; i++) { |
ireg[i] = mkreg("%d", i, 1, IREG); |
} |
iregw = mkwildcard(ireg); |
for (i = 0; i < 32; i += 2) { |
freg2[i] = mkreg("%d", i, 3, FREG); |
} |
freg2w = mkwildcard(freg2); |
tmask[IREG] = INTTMP; |
vmask[IREG] = INTVAR; |
tmask[FREG] = FLTTMP; |
vmask[FREG] = FLTVAR; |
blkreg = mkreg("8", 8, 7, IREG); |
} |
|
|
static void progend(void) { |
} |
|
|
static void segment(int n) { |
static int currSeg = -1; |
int newSeg; |
|
switch (n) { |
case CODE: |
newSeg = CODE; |
break; |
case BSS: |
newSeg = BSS; |
break; |
case DATA: |
newSeg = DATA; |
break; |
case LIT: |
newSeg = DATA; |
break; |
} |
if (currSeg == newSeg) { |
return; |
} |
switch (newSeg) { |
case CODE: |
print("\t.code\n"); |
break; |
case BSS: |
print("\t.bss\n"); |
break; |
case DATA: |
print("\t.data\n"); |
break; |
} |
currSeg = newSeg; |
} |
|
|
static void space(int n) { |
print("\t.space\t%d\n", n); |
} |
|
|
static Symbol rmap(int opk) { |
switch (optype(opk)) { |
case I: |
case U: |
case P: |
case B: |
return iregw; |
case F: |
return freg2w; |
default: |
return 0; |
} |
} |
|
|
static void blkfetch(int size, int off, int reg, int tmp) { |
assert(size == 1 || size == 2 || size == 4); |
if (size == 1) { |
print("\tldbu\t$%d,$%d,%d\n", tmp, reg, off); |
} else |
if (size == 2) { |
print("\tldhu\t$%d,$%d,%d\n", tmp, reg, off); |
} else |
if (size == 4) { |
print("\tldw\t$%d,$%d,%d\n", tmp, reg, off); |
} |
} |
|
|
static void blkstore(int size, int off, int reg, int tmp) { |
assert(size == 1 || size == 2 || size == 4); |
if (size == 1) { |
print("\tstb\t$%d,$%d,%d\n", tmp, reg, off); |
} else |
if (size == 2) { |
print("\tsth\t$%d,$%d,%d\n", tmp, reg, off); |
} else |
if (size == 4) { |
print("\tstw\t$%d,$%d,%d\n", tmp, reg, off); |
} |
} |
|
|
static void blkloop(int dreg, int doff, |
int sreg, int soff, |
int size, int tmps[]) { |
int label; |
|
label = genlabel(1); |
print("\tadd\t$%d,$%d,%d\n", sreg, sreg, size & ~7); |
print("\tadd\t$%d,$%d,%d\n", tmps[2], dreg, size & ~7); |
blkcopy(tmps[2], doff, sreg, soff, size & 7, tmps); |
print("L.%d:\n", label); |
print("\tsub\t$%d,$%d,%d\n", sreg, sreg, 8); |
print("\tsub\t$%d,$%d,%d\n", tmps[2], tmps[2], 8); |
blkcopy(tmps[2], doff, sreg, soff, 8, tmps); |
print("\tbltu\t$%d,$%d,L.%d\n", dreg, tmps[2], label); |
} |
|
|
static void emit2(Node p) { |
static int ty0; |
int ty, sz; |
Symbol q; |
int src; |
int dst, n; |
|
switch (specific(p->op)) { |
case ARG+I: |
case ARG+P: |
case ARG+U: |
ty = optype(p->op); |
sz = opsize(p->op); |
if (p->x.argno == 0) { |
ty0 = ty; |
} |
q = argreg(p->x.argno, p->syms[2]->u.c.v.i, ty, sz, ty0); |
src = getregnum(p->x.kids[0]); |
if (q == NULL) { |
print("\tstw\t$%d,$29,%d\n", src, p->syms[2]->u.c.v.i); |
} |
break; |
case ASGN+B: |
dalign = p->syms[1]->u.c.v.i; |
salign = p->syms[1]->u.c.v.i; |
blkcopy(getregnum(p->x.kids[0]), 0, |
getregnum(p->x.kids[1]), 0, |
p->syms[0]->u.c.v.i, tmpregs); |
break; |
case ARG+B: |
dalign = 4; |
salign = p->syms[1]->u.c.v.i; |
blkcopy(29, p->syms[2]->u.c.v.i, |
getregnum(p->x.kids[0]), 0, |
p->syms[0]->u.c.v.i, tmpregs); |
n = p->syms[2]->u.c.v.i + p->syms[0]->u.c.v.i; |
dst = p->syms[2]->u.c.v.i; |
for (; dst <= 12 && dst < n; dst += 4) { |
print("\tldw\t$%d,$29,%d\n", (dst / 4) + 4, dst); |
} |
break; |
} |
} |
|
|
static void doarg(Node p) { |
static int argno; |
int align; |
|
if (argoffset == 0) { |
argno = 0; |
} |
p->x.argno = argno++; |
align = p->syms[1]->u.c.v.i < 4 ? 4 : p->syms[1]->u.c.v.i; |
p->syms[2] = intconst(mkactual(align, p->syms[0]->u.c.v.i)); |
} |
|
|
static void target(Node p) { |
static int ty0; |
int ty; |
Symbol q; |
|
assert(p); |
switch (specific(p->op)) { |
case CNST+I: |
case CNST+P: |
case CNST+U: |
if (range(p, 0, 0) == 0) { |
setreg(p, ireg[0]); |
p->x.registered = 1; |
} |
break; |
case CALL+I: |
case CALL+P: |
case CALL+U: |
rtarget(p, 0, ireg[25]); |
setreg(p, ireg[2]); |
break; |
case CALL+F: |
rtarget(p, 0, ireg[25]); |
setreg(p, freg2[0]); |
break; |
case CALL+V: |
rtarget(p, 0, ireg[25]); |
break; |
case RET+I: |
case RET+P: |
case RET+U: |
rtarget(p, 0, ireg[2]); |
break; |
case RET+F: |
rtarget(p, 0, freg2[0]); |
break; |
case ARG+I: |
case ARG+P: |
case ARG+U: |
case ARG+F: |
ty = optype(p->op); |
q = argreg(p->x.argno, p->syms[2]->u.c.v.i, ty, opsize(p->op), ty0); |
if (p->x.argno == 0) { |
ty0 = ty; |
} |
if (q && !(ty == F && q->x.regnode->set == IREG)) { |
rtarget(p, 0, q); |
} |
break; |
case ASGN+B: |
rtarget(p->kids[1], 0, blkreg); |
break; |
case ARG+B: |
rtarget(p->kids[0], 0, blkreg); |
break; |
} |
} |
|
|
static void clobber(Node p) { |
assert(p); |
switch (specific(p->op)) { |
case CALL+F: |
spill(INTTMP | INTRET, IREG, p); |
spill(FLTTMP, FREG, p); |
break; |
case CALL+I: |
case CALL+P: |
case CALL+U: |
spill(INTTMP, IREG, p); |
spill(FLTTMP | FLTRET, FREG, p); |
break; |
case CALL+V: |
spill(INTTMP | INTRET, IREG, p); |
spill(FLTTMP | FLTRET, FREG, p); |
break; |
} |
} |
|
|
Interface eco32IR = { |
1, 1, 0, /* char */ |
2, 2, 0, /* short */ |
4, 4, 0, /* int */ |
4, 4, 0, /* long */ |
4, 4, 0, /* long long */ |
4, 4, 1, /* float */ |
8, 8, 1, /* double */ |
8, 8, 1, /* long double */ |
4, 4, 0, /* T * */ |
0, 1, 0, /* struct */ |
0, /* little_endian */ |
0, /* mulops_calls */ |
0, /* wants_callb */ |
1, /* wants_argb */ |
1, /* left_to_right */ |
0, /* wants_dag */ |
0, /* unsigned_char */ |
address, |
blockbeg, |
blockend, |
defaddress, |
defconst, |
defstring, |
defsymbol, |
emit, |
export, |
function, |
gen, |
global, |
import, |
local, |
progbeg, |
progend, |
segment, |
space, |
0, 0, 0, 0, 0, 0, 0, |
{ |
1, /* max_unaligned_load */ |
rmap, |
blkfetch, blkstore, blkloop, |
_label, |
_rule, |
_nts, |
_kids, |
_string, |
_templates, |
_isinstruction, |
_ntname, |
emit2, |
doarg, |
target, |
clobber |
} |
}; |
/sparc.md
0,0 → 1,1177
%{ |
#include "c.h" |
#define NODEPTR_TYPE Node |
#define OP_LABEL(p) ((p)->op) |
#define LEFT_CHILD(p) ((p)->kids[0]) |
#define RIGHT_CHILD(p) ((p)->kids[1]) |
#define STATE_LABEL(p) ((p)->x.state) |
static void address(Symbol, Symbol, long); |
static void blkfetch(int, int, int, int); |
static void blkloop(int, int, int, int, int, int[]); |
static void blkstore(int, int, int, int); |
static void defaddress(Symbol); |
static void defconst(int, int, Value); |
static void defstring(int, char *); |
static void defsymbol(Symbol); |
static void doarg(Node); |
static void emit2(Node); |
static void export(Symbol); |
static void clobber(Node); |
static void function(Symbol, Symbol [], Symbol [], int); |
static void global(Symbol); |
static void import(Symbol); |
static void local(Symbol); |
static void progbeg(int, char **); |
static void progend(void); |
static void segment(int); |
static void space(int); |
static void target(Node); |
static int imm(Node); |
static void renameregs(void); |
extern Interface sparcIR, solarisIR; |
static void defsymbol2(Symbol); |
static void export2(Symbol); |
static void globalend(void); |
static void global2(Symbol); |
static void segment2(int); |
static void progend2(void); |
|
extern char *stabprefix; |
extern void stabblock(int, int, Symbol*); |
extern void stabend(Coordinate *, Symbol, Coordinate **, Symbol *, Symbol *); |
extern void stabfend(Symbol, int); |
extern void stabinit(char *, int, char *[]); |
extern void stabline(Coordinate *); |
extern void stabsym(Symbol); |
extern void stabtype(Symbol); |
static Symbol greg[32], gregw; |
static Symbol *oreg = &greg[8], *ireg = &greg[24]; |
static Symbol freg[32], freg2[32]; |
static Symbol fregw, freg2w; |
|
static int regvars; |
static int retstruct; |
|
static int pflag = 0; |
|
static int cseg; |
|
%} |
%start stmt |
%term CNSTF4=4113 |
%term CNSTF8=8209 |
%term CNSTF16=16401 |
%term CNSTI1=1045 |
%term CNSTI2=2069 |
%term CNSTI4=4117 |
%term CNSTI8=8213 |
%term CNSTP4=4119 |
%term CNSTP8=8215 |
%term CNSTU1=1046 |
%term CNSTU2=2070 |
%term CNSTU4=4118 |
%term CNSTU8=8214 |
|
%term ARGB=41 |
%term ARGF4=4129 |
%term ARGF8=8225 |
%term ARGF16=16417 |
%term ARGI4=4133 |
%term ARGI8=8229 |
%term ARGP4=4135 |
%term ARGP8=8231 |
%term ARGU4=4134 |
%term ARGU8=8230 |
|
%term ASGNB=57 |
%term ASGNF4=4145 |
%term ASGNF8=8241 |
%term ASGNF16=16433 |
%term ASGNI1=1077 |
%term ASGNI2=2101 |
%term ASGNI4=4149 |
%term ASGNI8=8245 |
%term ASGNP4=4151 |
%term ASGNP8=8247 |
%term ASGNU1=1078 |
%term ASGNU2=2102 |
%term ASGNU4=4150 |
%term ASGNU8=8246 |
|
%term INDIRB=73 |
%term INDIRF4=4161 |
%term INDIRF8=8257 |
%term INDIRF16=16449 |
%term INDIRI1=1093 |
%term INDIRI2=2117 |
%term INDIRI4=4165 |
%term INDIRI8=8261 |
%term INDIRP4=4167 |
%term INDIRP8=8263 |
%term INDIRU1=1094 |
%term INDIRU2=2118 |
%term INDIRU4=4166 |
%term INDIRU8=8262 |
|
%term CVFF4=4209 |
%term CVFF8=8305 |
%term CVFF16=16497 |
%term CVFI4=4213 |
%term CVFI8=8309 |
|
%term CVIF4=4225 |
%term CVIF8=8321 |
%term CVIF16=16513 |
%term CVII1=1157 |
%term CVII2=2181 |
%term CVII4=4229 |
%term CVII8=8325 |
%term CVIU1=1158 |
%term CVIU2=2182 |
%term CVIU4=4230 |
%term CVIU8=8326 |
|
%term CVPP4=4247 |
%term CVPP8=8343 |
%term CVPP16=16535 |
%term CVPU4=4246 |
%term CVPU8=8342 |
|
%term CVUI1=1205 |
%term CVUI2=2229 |
%term CVUI4=4277 |
%term CVUI8=8373 |
%term CVUP4=4279 |
%term CVUP8=8375 |
%term CVUP16=16567 |
%term CVUU1=1206 |
%term CVUU2=2230 |
%term CVUU4=4278 |
%term CVUU8=8374 |
|
%term NEGF4=4289 |
%term NEGF8=8385 |
%term NEGF16=16577 |
%term NEGI4=4293 |
%term NEGI8=8389 |
|
%term CALLB=217 |
%term CALLF4=4305 |
%term CALLF8=8401 |
%term CALLF16=16593 |
%term CALLI4=4309 |
%term CALLI8=8405 |
%term CALLP4=4311 |
%term CALLP8=8407 |
%term CALLU4=4310 |
%term CALLU8=8406 |
%term CALLV=216 |
|
%term RETF4=4337 |
%term RETF8=8433 |
%term RETF16=16625 |
%term RETI4=4341 |
%term RETI8=8437 |
%term RETP4=4343 |
%term RETP8=8439 |
%term RETU4=4342 |
%term RETU8=8438 |
%term RETV=248 |
|
%term ADDRGP4=4359 |
%term ADDRGP8=8455 |
|
%term ADDRFP4=4375 |
%term ADDRFP8=8471 |
|
%term ADDRLP4=4391 |
%term ADDRLP8=8487 |
|
%term ADDF4=4401 |
%term ADDF8=8497 |
%term ADDF16=16689 |
%term ADDI4=4405 |
%term ADDI8=8501 |
%term ADDP4=4407 |
%term ADDP8=8503 |
%term ADDU4=4406 |
%term ADDU8=8502 |
|
%term SUBF4=4417 |
%term SUBF8=8513 |
%term SUBF16=16705 |
%term SUBI4=4421 |
%term SUBI8=8517 |
%term SUBP4=4423 |
%term SUBP8=8519 |
%term SUBU4=4422 |
%term SUBU8=8518 |
|
%term LSHI4=4437 |
%term LSHI8=8533 |
%term LSHU4=4438 |
%term LSHU8=8534 |
|
%term MODI4=4453 |
%term MODI8=8549 |
%term MODU4=4454 |
%term MODU8=8550 |
|
%term RSHI4=4469 |
%term RSHI8=8565 |
%term RSHU4=4470 |
%term RSHU8=8566 |
|
%term BANDI4=4485 |
%term BANDI8=8581 |
%term BANDU4=4486 |
%term BANDU8=8582 |
|
%term BCOMI4=4501 |
%term BCOMI8=8597 |
%term BCOMU4=4502 |
%term BCOMU8=8598 |
|
%term BORI4=4517 |
%term BORI8=8613 |
%term BORU4=4518 |
%term BORU8=8614 |
|
%term BXORI4=4533 |
%term BXORI8=8629 |
%term BXORU4=4534 |
%term BXORU8=8630 |
|
%term DIVF4=4545 |
%term DIVF8=8641 |
%term DIVF16=16833 |
%term DIVI4=4549 |
%term DIVI8=8645 |
%term DIVU4=4550 |
%term DIVU8=8646 |
|
%term MULF4=4561 |
%term MULF8=8657 |
%term MULF16=16849 |
%term MULI4=4565 |
%term MULI8=8661 |
%term MULU4=4566 |
%term MULU8=8662 |
|
%term EQF4=4577 |
%term EQF8=8673 |
%term EQF16=16865 |
%term EQI4=4581 |
%term EQI8=8677 |
%term EQU4=4582 |
%term EQU8=8678 |
|
%term GEF4=4593 |
%term GEF8=8689 |
%term GEI4=4597 |
%term GEI8=8693 |
%term GEI16=16885 |
%term GEU4=4598 |
%term GEU8=8694 |
|
%term GTF4=4609 |
%term GTF8=8705 |
%term GTF16=16897 |
%term GTI4=4613 |
%term GTI8=8709 |
%term GTU4=4614 |
%term GTU8=8710 |
|
%term LEF4=4625 |
%term LEF8=8721 |
%term LEF16=16913 |
%term LEI4=4629 |
%term LEI8=8725 |
%term LEU4=4630 |
%term LEU8=8726 |
|
%term LTF4=4641 |
%term LTF8=8737 |
%term LTF16=16929 |
%term LTI4=4645 |
%term LTI8=8741 |
%term LTU4=4646 |
%term LTU8=8742 |
|
%term NEF4=4657 |
%term NEF8=8753 |
%term NEF16=16945 |
%term NEI4=4661 |
%term NEI8=8757 |
%term NEU4=4662 |
%term NEU8=8758 |
|
%term JUMPV=584 |
|
%term LABELV=600 |
|
%term LOADB=233 |
%term LOADF4=4321 |
%term LOADF8=8417 |
%term LOADF16=16609 |
%term LOADI1=1253 |
%term LOADI2=2277 |
%term LOADI4=4325 |
%term LOADI8=8421 |
%term LOADP4=4327 |
%term LOADP8=8423 |
%term LOADU1=1254 |
%term LOADU2=2278 |
%term LOADU4=4326 |
%term LOADU8=8422 |
|
%term VREGP=711 |
%% |
reg: INDIRI1(VREGP) "# read register\n" |
reg: INDIRU1(VREGP) "# read register\n" |
|
reg: INDIRI2(VREGP) "# read register\n" |
reg: INDIRU2(VREGP) "# read register\n" |
|
reg: INDIRF4(VREGP) "# read register\n" |
reg: INDIRI4(VREGP) "# read register\n" |
reg: INDIRP4(VREGP) "# read register\n" |
reg: INDIRU4(VREGP) "# read register\n" |
|
reg: INDIRF8(VREGP) "# read register\n" |
reg: INDIRI8(VREGP) "# read register\n" |
reg: INDIRP8(VREGP) "# read register\n" |
reg: INDIRU8(VREGP) "# read register\n" |
|
stmt: ASGNI1(VREGP,reg) "# write register\n" |
stmt: ASGNU1(VREGP,reg) "# write register\n" |
|
stmt: ASGNI2(VREGP,reg) "# write register\n" |
stmt: ASGNU2(VREGP,reg) "# write register\n" |
|
stmt: ASGNF4(VREGP,reg) "# write register\n" |
stmt: ASGNI4(VREGP,reg) "# write register\n" |
stmt: ASGNP4(VREGP,reg) "# write register\n" |
stmt: ASGNU4(VREGP,reg) "# write register\n" |
|
stmt: ASGNF8(VREGP,reg) "# write register\n" |
stmt: ASGNI8(VREGP,reg) "# write register\n" |
stmt: ASGNP8(VREGP,reg) "# write register\n" |
stmt: ASGNU8(VREGP,reg) "# write register\n" |
con: CNSTI1 "%a" |
con: CNSTU1 "%a" |
|
con: CNSTI2 "%a" |
con: CNSTU2 "%a" |
|
con: CNSTI4 "%a" |
con: CNSTU4 "%a" |
con: CNSTP4 "%a" |
|
con: CNSTI8 "%a" |
con: CNSTU8 "%a" |
con: CNSTP8 "%a" |
stmt: reg "" |
reg: ADDRGP4 "set %a,%%%c\n" 1 |
stk13: ADDRFP4 "%a" imm(a) |
stk13: ADDRLP4 "%a" imm(a) |
reg: stk13 "add %0,%%fp,%%%c\n" 1 |
stk: ADDRFP4 "set %a,%%%c\n" 2 |
stk: ADDRLP4 "set %a,%%%c\n" 2 |
reg: ADDRFP4 "set %a,%%%c\nadd %%%c,%%fp,%%%c\n" 3 |
reg: ADDRLP4 "set %a,%%%c\nadd %%%c,%%fp,%%%c\n" 3 |
con13: CNSTI1 "%a" imm(a) |
con13: CNSTI2 "%a" imm(a) |
con13: CNSTI4 "%a" imm(a) |
con13: CNSTU1 "%a" imm(a) |
con13: CNSTU2 "%a" imm(a) |
con13: CNSTU4 "%a" imm(a) |
con13: CNSTP4 "%a" imm(a) |
base: ADDI4(reg,con13) "%%%0+%1" |
base: ADDP4(reg,con13) "%%%0+%1" |
base: ADDU4(reg,con13) "%%%0+%1" |
base: reg "%%%0" |
base: con13 "%0" |
base: stk13 "%%fp+%0" |
addr: base "%0" |
addr: ADDI4(reg,reg) "%%%0+%%%1" |
addr: ADDP4(reg,reg) "%%%0+%%%1" |
addr: ADDU4(reg,reg) "%%%0+%%%1" |
addr: stk "%%fp+%%%0" |
reg: INDIRI1(addr) "ldsb [%0],%%%c\n" 1 |
reg: INDIRI2(addr) "ldsh [%0],%%%c\n" 1 |
reg: INDIRI4(addr) "ld [%0],%%%c\n" 1 |
reg: INDIRU1(addr) "ldub [%0],%%%c\n" 1 |
reg: INDIRU2(addr) "lduh [%0],%%%c\n" 1 |
reg: INDIRU4(addr) "ld [%0],%%%c\n" 1 |
reg: INDIRP4(addr) "ld [%0],%%%c\n" 1 |
reg: INDIRF4(addr) "ld [%0],%%f%c\n" 1 |
stmt: ASGNI1(addr,reg) "stb %%%1,[%0]\n" 1 |
stmt: ASGNI2(addr,reg) "sth %%%1,[%0]\n" 1 |
stmt: ASGNI4(addr,reg) "st %%%1,[%0]\n" 1 |
stmt: ASGNU1(addr,reg) "stb %%%1,[%0]\n" 1 |
stmt: ASGNU2(addr,reg) "sth %%%1,[%0]\n" 1 |
stmt: ASGNU4(addr,reg) "st %%%1,[%0]\n" 1 |
stmt: ASGNP4(addr,reg) "st %%%1,[%0]\n" 1 |
stmt: ASGNF4(addr,reg) "st %%f%1,[%0]\n" 1 |
addrl: ADDRLP4 "%%%fp+%a" imm(a) |
|
reg: INDIRF8(addrl) "ldd [%0],%%f%c\n" 1 |
stmt: ASGNF8(addrl,reg) "std %%f%1,[%0]\n" 1 |
reg: INDIRF8(base) "# ld2 [%0],%%f%c\n" 2 |
stmt: ASGNF8(base,reg) "# st2 %%f%1,[%0]\n" 2 |
spill: ADDRLP4 "%a" !imm(a) |
|
stmt: ASGNI1(spill,reg) "set %0,%%g1\nstb %%%1,[%%fp+%%g1]\n" |
stmt: ASGNI2(spill,reg) "set %0,%%g1\nsth %%%1,[%%fp+%%g1]\n" |
stmt: ASGNI4(spill,reg) "set %0,%%g1\nst %%%1,[%%fp+%%g1]\n" |
stmt: ASGNU1(spill,reg) "set %0,%%g1\nstb %%%1,[%%fp+%%g1]\n" |
stmt: ASGNU2(spill,reg) "set %0,%%g1\nsth %%%1,[%%fp+%%g1]\n" |
stmt: ASGNU4(spill,reg) "set %0,%%g1\nst %%%1,[%%fp+%%g1]\n" |
stmt: ASGNP4(spill,reg) "set %0,%%g1\nst %%%1,[%%fp+%%g1]\n" |
stmt: ASGNF4(spill,reg) "set %0,%%g1\nst %%f%1,[%%fp+%%g1]\n" |
stmt: ASGNF8(spill,reg) "set %0,%%g1\nstd %%f%1,[%%fp+%%g1]\n" |
reg: CVII4(INDIRI1(addr)) "ldsb [%0],%%%c\n" 1 |
reg: CVII4(INDIRI2(addr)) "ldsh [%0],%%%c\n" 1 |
reg: CVUU4(INDIRU1(addr)) "ldub [%0],%%%c\n" 1 |
reg: CVUU4(INDIRU2(addr)) "lduh [%0],%%%c\n" 1 |
reg: CVUI4(INDIRU1(addr)) "ldub [%0],%%%c\n" 1 |
reg: CVUI4(INDIRU2(addr)) "lduh [%0],%%%c\n" 1 |
reg: LOADI1(reg) "mov %%%0,%%%c\n" move(a) |
reg: LOADI2(reg) "mov %%%0,%%%c\n" move(a) |
reg: LOADI4(reg) "mov %%%0,%%%c\n" move(a) |
reg: LOADP4(reg) "mov %%%0,%%%c\n" move(a) |
reg: LOADU1(reg) "mov %%%0,%%%c\n" move(a) |
reg: LOADU2(reg) "mov %%%0,%%%c\n" move(a) |
reg: LOADU4(reg) "mov %%%0,%%%c\n" move(a) |
reg: CNSTI1 "# reg\n" range(a, 0, 0) |
reg: CNSTI2 "# reg\n" range(a, 0, 0) |
reg: CNSTI4 "# reg\n" range(a, 0, 0) |
reg: CNSTP4 "# reg\n" range(a, 0, 0) |
reg: CNSTU1 "# reg\n" range(a, 0, 0) |
reg: CNSTU2 "# reg\n" range(a, 0, 0) |
reg: CNSTU4 "# reg\n" range(a, 0, 0) |
reg: con "set %0,%%%c\n" 1 |
rc: con13 "%0" |
rc: reg "%%%0" |
reg: ADDI4(reg,rc) "add %%%0,%1,%%%c\n" 1 |
reg: ADDP4(reg,rc) "add %%%0,%1,%%%c\n" 1 |
reg: ADDU4(reg,rc) "add %%%0,%1,%%%c\n" 1 |
reg: BANDI4(reg,rc) "and %%%0,%1,%%%c\n" 1 |
reg: BORI4(reg,rc) "or %%%0,%1,%%%c\n" 1 |
reg: BXORI4(reg,rc) "xor %%%0,%1,%%%c\n" 1 |
reg: BANDU4(reg,rc) "and %%%0,%1,%%%c\n" 1 |
reg: BORU4(reg,rc) "or %%%0,%1,%%%c\n" 1 |
reg: BXORU4(reg,rc) "xor %%%0,%1,%%%c\n" 1 |
reg: SUBI4(reg,rc) "sub %%%0,%1,%%%c\n" 1 |
reg: SUBP4(reg,rc) "sub %%%0,%1,%%%c\n" 1 |
reg: SUBU4(reg,rc) "sub %%%0,%1,%%%c\n" 1 |
rc5: CNSTI4 "%a" range(a, 0, 31) |
rc5: reg "%%%0" |
reg: LSHI4(reg,rc5) "sll %%%0,%1,%%%c\n" 1 |
reg: LSHU4(reg,rc5) "sll %%%0,%1,%%%c\n" 1 |
reg: RSHI4(reg,rc5) "sra %%%0,%1,%%%c\n" 1 |
reg: RSHU4(reg,rc5) "srl %%%0,%1,%%%c\n" 1 |
reg: BANDI4(reg,BCOMI4(rc)) "andn %%%0,%1,%%%c\n" 1 |
reg: BORI4(reg,BCOMI4(rc)) "orn %%%0,%1,%%%c\n" 1 |
reg: BXORI4(reg,BCOMI4(rc)) "xnor %%%0,%1,%%%c\n" 1 |
reg: BANDU4(reg,BCOMU4(rc)) "andn %%%0,%1,%%%c\n" 1 |
reg: BORU4(reg,BCOMU4(rc)) "orn %%%0,%1,%%%c\n" 1 |
reg: BXORU4(reg,BCOMU4(rc)) "xnor %%%0,%1,%%%c\n" 1 |
reg: NEGI4(reg) "neg %%%0,%%%c\n" 1 |
reg: BCOMI4(reg) "not %%%0,%%%c\n" 1 |
reg: BCOMU4(reg) "not %%%0,%%%c\n" 1 |
reg: CVII4(reg) "sll %%%0,8*(4-%a),%%%c; sra %%%c,8*(4-%a),%%%c\n" 2 |
reg: CVUU4(reg) "sll %%%0,8*(4-%a),%%%c; srl %%%c,8*(4-%a),%%%c\n" 2 |
reg: CVUU4(reg) "and %%%0,0xff,%%%c\n" (a->syms[0]->u.c.v.i == 1 ? 1 : LBURG_MAX) |
reg: CVUU4(reg) "set 0xffff,%%g1; and %%%0,%%g1,%%%c\n" 2 |
reg: CVUI4(reg) "and %%%0,0xff,%%%c\n" (a->syms[0]->u.c.v.i == 1 ? 1 : LBURG_MAX) |
reg: CVUI4(reg) "set 0xffff,%%g1; and %%%0,%%g1,%%%c\n" 2 |
addrg: ADDRGP4 "%a" |
stmt: JUMPV(addrg) "ba %0; nop\n" 2 |
stmt: JUMPV(addr) "jmp %0; nop\n" 2 |
stmt: LABELV "%a:\n" |
stmt: EQI4(reg,rc) "cmp %%%0,%1; be %a; nop\n" 3 |
stmt: EQU4(reg,rc) "cmp %%%0,%1; be %a; nop\n" 3 |
stmt: GEI4(reg,rc) "cmp %%%0,%1; bge %a; nop\n" 3 |
stmt: GEU4(reg,rc) "cmp %%%0,%1; bgeu %a; nop\n" 3 |
stmt: GTI4(reg,rc) "cmp %%%0,%1; bg %a; nop\n" 3 |
stmt: GTU4(reg,rc) "cmp %%%0,%1; bgu %a; nop\n" 3 |
stmt: LEI4(reg,rc) "cmp %%%0,%1; ble %a; nop\n" 3 |
stmt: LEU4(reg,rc) "cmp %%%0,%1; bleu %a; nop\n" 3 |
stmt: LTI4(reg,rc) "cmp %%%0,%1; bl %a; nop\n" 3 |
stmt: LTU4(reg,rc) "cmp %%%0,%1; blu %a; nop\n" 3 |
stmt: NEI4(reg,rc) "cmp %%%0,%1; bne %a; nop\n" 3 |
stmt: NEU4(reg,rc) "cmp %%%0,%1; bne %a; nop\n" 3 |
call: ADDRGP4 "%a" |
call: addr "%0" |
reg: CALLF8(call) "call %0; nop\n" 2 |
reg: CALLF4(call) "call %0; nop\n" 2 |
reg: CALLI4(call) "call %0; nop\n" 2 |
reg: CALLP4(call) "call %0; nop\n" 2 |
reg: CALLU4(call) "call %0; nop\n" 2 |
stmt: CALLV(call) "call %0; nop\n" 2 |
stmt: CALLB(call,reg) "call %0; st %%%1,[%%sp+64]; unimp %b&0xfff\n" 3 |
|
stmt: RETF8(reg) "# ret\n" 1 |
stmt: RETF4(reg) "# ret\n" 1 |
stmt: RETI4(reg) "# ret\n" 1 |
stmt: RETU4(reg) "# ret\n" 1 |
stmt: RETP4(reg) "# ret\n" 1 |
stmt: ARGI4(reg) "st %%%0,[%%sp+4*%c+68]\n" 1 |
stmt: ARGU4(reg) "st %%%0,[%%sp+4*%c+68]\n" 1 |
stmt: ARGP4(reg) "st %%%0,[%%sp+4*%c+68]\n" 1 |
stmt: ARGF4(reg) "# ARGF4\n" 1 |
stmt: ARGF8(reg) "# ARGF8\n" 1 |
|
reg: DIVI4(reg,rc) "sra %%%0,31,%%g1; wr %%g0,%%g1,%%y; nop; nop; nop; sdiv %%%0,%1,%%%c\n" 6 |
|
reg: DIVU4(reg,rc) "wr %%g0,%%g0,%%y; nop; nop; nop; udiv %%%0,%1,%%%c\n" 5 |
|
reg: MODI4(reg,rc) "sra %%%0,31,%%g1; wr %%g0,%%g1,%%y; nop; nop; nop; sdiv %%%0,%1,%%g1\n; smul %%g1,%1,%%g1; sub %%%0,%%g1,%%%c\n" 8 |
|
|
reg: MODU4(reg,rc) "wr %%g0,%%g0,%%y; nop; nop; nop; udiv %%%0,%1,%%g1\n; umul %%g1,%1,%%g1; sub %%%0,%%g1,%%%c\n" 7 |
|
|
reg: MULI4(rc,reg) "smul %%%1,%0,%%%c\n" 1 |
reg: MULU4(rc,reg) "umul %%%1,%0,%%%c\n" 1 |
reg: ADDF8(reg,reg) "faddd %%f%0,%%f%1,%%f%c\n" 1 |
reg: ADDF4(reg,reg) "fadds %%f%0,%%f%1,%%f%c\n" 1 |
reg: DIVF8(reg,reg) "fdivd %%f%0,%%f%1,%%f%c\n" 1 |
reg: DIVF4(reg,reg) "fdivs %%f%0,%%f%1,%%f%c\n" 1 |
reg: MULF8(reg,reg) "fmuld %%f%0,%%f%1,%%f%c\n" 1 |
reg: MULF4(reg,reg) "fmuls %%f%0,%%f%1,%%f%c\n" 1 |
reg: SUBF8(reg,reg) "fsubd %%f%0,%%f%1,%%f%c\n" 1 |
reg: SUBF4(reg,reg) "fsubs %%f%0,%%f%1,%%f%c\n" 1 |
reg: NEGF4(reg) "fnegs %%f%0,%%f%c\n" 1 |
reg: LOADF4(reg) "fmovs %%f%0,%%f%c\n" 1 |
reg: CVFF4(reg) "fdtos %%f%0,%%f%c\n" 1 |
reg: CVFF8(reg) "fstod %%f%0,%%f%c\n" 1 |
reg: CVFI4(reg) "fstoi %%f%0,%%f0; st %%f0,[%%sp+64]; ld [%%sp+64],%%%c\n" (a->syms[0]->u.c.v.i==4?3:LBURG_MAX) |
|
reg: CVFI4(reg) "fdtoi %%f%0,%%f0; st %%f0,[%%sp+64]; ld [%%sp+64],%%%c\n" (a->syms[0]->u.c.v.i==8?3:LBURG_MAX) |
|
reg: CVIF4(reg) "st %%%0,[%%sp+64]; ld [%%sp+64],%%f%c; fitos %%f%c,%%f%c\n" 3 |
|
reg: CVIF8(reg) "st %%%0,[%%sp+64]; ld [%%sp+64],%%f%c; fitod %%f%c,%%f%c\n" 3 |
|
rel: EQF8(reg,reg) "fcmpd %%f%0,%%f%1; nop; fbe" |
rel: EQF4(reg,reg) "fcmps %%f%0,%%f%1; nop; fbe" |
rel: GEF8(reg,reg) "fcmpd %%f%0,%%f%1; nop; fbuge" |
rel: GEF4(reg,reg) "fcmps %%f%0,%%f%1; nop; fbuge" |
rel: GTF8(reg,reg) "fcmpd %%f%0,%%f%1; nop; fbug" |
rel: GTF4(reg,reg) "fcmps %%f%0,%%f%1; nop; fbug" |
rel: LEF8(reg,reg) "fcmpd %%f%0,%%f%1; nop; fbule" |
rel: LEF4(reg,reg) "fcmps %%f%0,%%f%1; nop; fbule" |
rel: LTF8(reg,reg) "fcmpd %%f%0,%%f%1; nop; fbul" |
rel: LTF4(reg,reg) "fcmps %%f%0,%%f%1; nop; fbul" |
rel: NEF8(reg,reg) "fcmpd %%f%0,%%f%1; nop; fbne" |
rel: NEF4(reg,reg) "fcmps %%f%0,%%f%1; nop; fbne" |
|
stmt: rel "%0 %a; nop\n" 4 |
reg: LOADF8(reg) "# LOADD\n" 2 |
|
reg: NEGF8(reg) "# NEGD\n" 2 |
|
stmt: ASGNB(reg,INDIRB(reg)) "# ASGNB\n" |
|
%% |
static void progend(void){} |
static void progbeg(int argc, char *argv[]) { |
int i; |
|
{ |
union { |
char c; |
int i; |
} u; |
u.i = 0; |
u.c = 1; |
swap = ((int)(u.i == 1)) != IR->little_endian; |
} |
parseflags(argc, argv); |
for (i = 0; i < argc; i++) |
if (strcmp(argv[i], "-p") == 0 || strcmp(argv[i], "-pg") == 0) |
pflag = 1; |
if (IR == &solarisIR) |
stabprefix = ".LL"; |
else |
stabprefix = "L"; |
for (i = 0; i < 8; i++) { |
greg[i + 0] = mkreg(stringf("g%d", i), i + 0, 1, IREG); |
greg[i + 8] = mkreg(stringf("o%d", i), i + 8, 1, IREG); |
greg[i + 16] = mkreg(stringf("l%d", i), i + 16, 1, IREG); |
greg[i + 24] = mkreg(stringf("i%d", i), i + 24, 1, IREG); |
} |
gregw = mkwildcard(greg); |
for (i = 0; i < 32; i++) |
freg[i] = mkreg("%d", i, 1, FREG); |
for (i = 0; i < 31; i += 2) |
freg2[i] = mkreg("%d", i, 3, FREG); |
fregw = mkwildcard(freg); |
freg2w = mkwildcard(freg2); |
tmask[IREG] = 0x3fff3e00; |
vmask[IREG] = 0x3ff00000; |
tmask[FREG] = ~(unsigned)0; |
vmask[FREG] = 0; |
} |
static Symbol rmap(int opk) { |
switch (optype(opk)) { |
case I: case U: case P: case B: |
return gregw; |
case F: |
return opsize(opk) == 4 ? fregw : freg2w; |
default: |
return 0; |
} |
} |
static void target(Node p) { |
assert(p); |
switch (specific(p->op)) { |
case CNST+I: case CNST+U: case CNST+P: |
if (range(p, 0, 0) == 0) { |
setreg(p, greg[0]); |
p->x.registered = 1; |
} |
break; |
case CALL+B: |
assert(p->syms[1] && p->syms[1]->type && isfunc(p->syms[1]->type)); |
p->syms[1] = intconst(freturn(p->syms[1]->type)->size); |
break; |
case CALL+F: setreg(p, opsize(p->op)==4?freg[0]:freg2[0]); break; |
case CALL+I: case CALL+P: case CALL+U: |
case CALL+V: setreg(p, oreg[0]); break; |
case RET+F: rtarget(p, 0, opsize(p->op)==4?freg[0]:freg2[0]); break; |
case RET+I: case RET+P: case RET+U: |
rtarget(p, 0, ireg[0]); |
p->kids[0]->x.registered = 1; |
break; |
case ARG+I: case ARG+P: case ARG+U: |
if (p->syms[RX]->u.c.v.i < 6) { |
rtarget(p, 0, oreg[p->syms[RX]->u.c.v.i]); |
p->op = LOAD+opkind(p->op); |
setreg(p, oreg[p->syms[RX]->u.c.v.i]); |
} |
break; |
} |
} |
static void clobber(Node p) { |
assert(p); |
switch (specific(p->op)) { |
case CALL+B: case CALL+F: case CALL+I: |
spill(~(unsigned)3, FREG, p); |
break; |
case CALL+V: |
spill(oreg[0]->x.regnode->mask, IREG, p); |
spill(~(unsigned)3, FREG, p); |
break; |
case ARG+F: |
if (opsize(p->op) == 4 && p->syms[2]->u.c.v.i <= 6) |
spill((1<<(p->syms[2]->u.c.v.i + 8)), IREG, p); |
else if (opsize(p->op) == 8 && p->syms[2]->u.c.v.i <= 5) |
spill((3<<(p->syms[2]->u.c.v.i + 8))&0xff00, IREG, p); |
break; |
} |
} |
static int imm(Node p) { |
return range(p, -4096, 4091); |
} |
static void doarg(Node p) { |
assert(p && p->syms[0] && p->op != ARG+B); |
p->syms[RX] = intconst(mkactual(4, |
p->syms[0]->u.c.v.i)/4); |
} |
static void emit2(Node p) { |
switch (p->op) { |
case INDIR+F+sizeop(8): |
if (generic(p->kids[0]->op) != VREG) { |
int dst = getregnum(p); |
print("ld ["); emitasm(p->kids[0], _base_NT); print( "],%%f%d; ", dst); |
print("ld ["); emitasm(p->kids[0], _base_NT); print("+4],%%f%d\n", dst+1); |
} |
break; |
case ASGN+F+sizeop(8): |
if (generic(p->kids[0]->op) != VREG) { |
int src = getregnum(p->kids[1]); |
print("st %%f%d,[", src); emitasm(p->kids[0], _base_NT); print("]; "); |
print("st %%f%d,[", src+1); emitasm(p->kids[0], _base_NT); print("+4]\n"); |
} |
break; |
case ARG+F+sizeop(4): { |
int n = p->syms[RX]->u.c.v.i; |
print("st %%f%d,[%%sp+4*%d+68]\n", |
getregnum(p->x.kids[0]), n); |
if (n <= 5) |
print("ld [%%sp+4*%d+68],%%o%d\n", n, n); |
break; |
} |
case ARG+F+sizeop(8): { |
int n = p->syms[RX]->u.c.v.i; |
int src = getregnum(p->x.kids[0]); |
print("st %%f%d,[%%sp+4*%d+68]\n", src, n); |
print("st %%f%d,[%%sp+4*%d+68]\n", src+1, n+1); |
if (n <= 5) |
print("ld [%%sp+4*%d+68],%%o%d\n", n, n); |
if (n <= 4) |
print("ld [%%sp+4*%d+68],%%o%d\n", n+1, n+1); |
break; |
} |
case LOAD+F+sizeop(8): { |
int dst = getregnum(p); |
int src = getregnum(p->x.kids[0]); |
print("fmovs %%f%d,%%f%d; ", src, dst); |
print("fmovs %%f%d,%%f%d\n", src+1, dst+1); |
break; |
} |
case NEG+F+sizeop(8): { |
int dst = getregnum(p); |
int src = getregnum(p->x.kids[0]); |
print("fnegs %%f%d,%%f%d; ", src, dst); |
print("fmovs %%f%d,%%f%d\n", src+1, dst+1); |
break; |
} |
case ASGN+B: { |
static int tmpregs[] = { 1, 2, 3 }; |
dalign = salign = p->syms[1]->u.c.v.i; |
blkcopy(getregnum(p->x.kids[0]), 0, |
getregnum(p->x.kids[1]), 0, |
p->syms[0]->u.c.v.i, tmpregs); |
break; |
} |
} |
} |
static void local(Symbol p) { |
if (retstruct) { |
assert(p == retv); |
p->x.name = stringd(4*16); |
p->x.offset = 4*16; |
p->sclass = AUTO; |
retstruct = 0; |
return; |
} |
if (isscalar(p->type) && !p->addressed && !isfloat(p->type)) |
p->sclass = REGISTER; |
if (askregvar(p, rmap(ttob(p->type))) == 0) |
mkauto(p); |
else if (p->scope > LOCAL) |
regvars++; |
} |
static void function(Symbol f, Symbol caller[], Symbol callee[], int ncalls) { |
int autos = 0, i, leaf, reg, varargs; |
|
if (IR == &solarisIR) |
globalend(); |
regvars = 0; |
for (i = 0; callee[i]; i++) |
; |
varargs = variadic(f->type) |
|| i > 0 && strcmp(callee[i-1]->name, |
"__builtin_va_alist") == 0; |
usedmask[0] = usedmask[1] = 0; |
freemask[0] = freemask[1] = ~(unsigned)0; |
for (i = 0; i < 8; i++) |
ireg[i]->x.regnode->vbl = NULL; |
offset = 68; |
maxargoffset = 24; |
reg = 0; |
for (i = 0; callee[i]; i++) { |
Symbol p = callee[i], q = caller[i]; |
int size = roundup(q->type->size, 4); |
assert(q); |
if (isfloat(p->type) || reg >= 6) { |
p->x.offset = q->x.offset = offset; |
p->x.name = q->x.name = stringd(offset); |
p->sclass = q->sclass = AUTO; |
autos++; |
} |
else if (p->addressed || varargs) { |
p->x.offset = offset; |
p->x.name = stringd(p->x.offset); |
p->sclass = AUTO; |
q->sclass = REGISTER; |
askregvar(q, ireg[reg]); |
assert(q->x.regnode); |
autos++; |
} |
else { |
p->sclass = q->sclass = REGISTER; |
askregvar(p, ireg[reg]); |
assert(p->x.regnode); |
q->x.name = p->x.name; |
} |
offset += size; |
reg += isstruct(p->type) ? 1 : size/4; |
} |
assert(caller[i] == 0); |
offset = maxoffset = 0; |
retstruct = isstruct(freturn(f->type)); |
gencode(caller, callee); |
maxargoffset = roundup(maxargoffset, 4); |
framesize = roundup(maxoffset + maxargoffset + 4*(16+1), 8); |
assert(!varargs || autos); |
leaf = (!ncalls |
&& !maxoffset && !autos && !regvars |
&& !isstruct(freturn(f->type)) |
&& !(usedmask[IREG]&0x00ffff01) |
&& !(usedmask[FREG]&~(unsigned)3) |
&& !pflag && !glevel); |
print(".align 4\n%s:\n", f->x.name); |
if (leaf) { |
for (i = 0; caller[i] && callee[i]; i++) { |
Symbol p = caller[i], q = callee[i]; |
if (p->sclass == REGISTER && q->sclass == REGISTER) { |
assert(q->x.regnode); |
assert(q->x.regnode->set == IREG); |
assert(q->x.regnode->number >= 24); |
assert(q->x.regnode->number <= 31); |
p->x.name = greg[q->x.regnode->number - 16]->x.name; |
} |
} |
renameregs(); |
} else if (framesize <= 4095) |
print("save %%sp,%d,%%sp\n", -framesize); |
else |
print("set %d,%%g1; save %%sp,%%g1,%%sp\n", -framesize); |
if (varargs) |
for (; reg < 6; reg++) |
print("st %%i%d,[%%fp+%d]\n", reg, 4*reg + 68); |
else { |
offset = 4*(16 + 1); |
reg = 0; |
for (i = 0; caller[i]; i++) { |
Symbol p = caller[i]; |
if (isfloat(p->type) && p->type->size == 8 && reg <= 4) { |
print("st %%r%d,[%%fp+%d]\n", |
ireg[reg++]->x.regnode->number, offset); |
print("st %%r%d,[%%fp+%d]\n", |
ireg[reg++]->x.regnode->number, offset + 4); |
} else if (isfloat(p->type) && p->type->size == 4 && reg <= 5) |
print("st %%r%d,[%%fp+%d]\n", |
ireg[reg++]->x.regnode->number, offset); |
else |
reg++; |
offset += roundup(p->type->size, 4); |
} |
} |
if (pflag) { |
int lab = genlabel(1); |
print("set L%d,%%o0; call mcount; nop\n", lab); |
print(".seg \"data\"\n.align 4; L%d:.word 0\n.seg \"text\"\n", lab); |
} |
emitcode(); |
if (isstruct(freturn(f->type))) |
print("jmp %%i7+12; restore\n"); |
else if (!leaf) |
print("ret; restore\n"); |
else { |
renameregs(); |
print("retl; nop\n"); |
} |
if (IR == &solarisIR) { |
print(".type %s,#function\n", f->x.name); |
print(".size %s,.-%s\n", f->x.name, f->x.name); |
} |
} |
#define exch(x, y, t) (((t) = x), ((x) = (y)), ((y) = (t))) |
|
static void renameregs(void) { |
int i; |
|
for (i = 0; i < 8; i++) { |
char *ptmp; |
int itmp; |
if (ireg[i]->x.regnode->vbl) |
ireg[i]->x.regnode->vbl->x.name = oreg[i]->x.name; |
exch(ireg[i]->x.name, oreg[i]->x.name, ptmp); |
exch(ireg[i]->x.regnode->number, |
oreg[i]->x.regnode->number, itmp); |
} |
} |
static void defconst(int suffix, int size, Value v) { |
if (suffix == F && size == 4) { |
float f = v.d; |
print(".word 0x%x\n", *(unsigned *)&f); |
} else if (suffix == F && size == 8) { |
double d = v.d; |
unsigned *p = (unsigned *)&d; |
print(".word 0x%x\n.word 0x%x\n", p[swap], p[!swap]); |
} else if (suffix == P) |
print(".word 0x%x\n", (unsigned)v.p); |
else if (size == 1) |
print(".byte 0x%x\n", (unsigned)((unsigned char)(suffix == I ? v.i : v.u))); |
else if (size == 2) |
print(".half 0x%x\n", (unsigned)((unsigned short)(suffix == I ? v.i : v.u))); |
else if (size == 4) |
print(".word 0x%x\n", (unsigned)(suffix == I ? v.i : v.u)); |
else assert(0); |
} |
|
static void defaddress(Symbol p) { |
print(".word %s\n", p->x.name); |
} |
|
static void defstring(int n, char *str) { |
char *s; |
|
for (s = str; s < str + n; s++) |
print(".byte %d\n", (*s)&0377); |
} |
|
static void address(Symbol q, Symbol p, long n) { |
if (p->scope == GLOBAL || p->sclass == STATIC || p->sclass == EXTERN) |
q->x.name = stringf("%s%s%D", p->x.name, n >= 0 ? "+" : "", n); |
else { |
assert(n <= INT_MAX && n >= INT_MIN); |
q->x.offset = p->x.offset + n; |
q->x.name = stringd(q->x.offset); |
} |
} |
static void export(Symbol p) { |
print(".global %s\n", p->x.name); |
} |
static void import(Symbol p) {} |
static void defsymbol(Symbol p) { |
if (p->scope >= LOCAL && p->sclass == STATIC) |
p->x.name = stringf("%d", genlabel(1)); |
else |
assert(p->scope != CONSTANTS || isint(p->type) || isptr(p->type)), |
p->x.name = p->name; |
if (p->scope >= LABELS) |
p->x.name = stringf(p->generated ? "L%s" : "_%s", |
p->x.name); |
} |
static void segment(int n) { |
cseg = n; |
switch (n) { |
case CODE: print(".seg \"text\"\n"); break; |
case BSS: print(".seg \"bss\"\n"); break; |
case DATA: print(".seg \"data\"\n"); break; |
case LIT: print(".seg \"text\"\n"); break; |
} |
} |
static void space(int n) { |
if (cseg != BSS) |
print(".skip %d\n", n); |
} |
static void global(Symbol p) { |
print(".align %d\n", p->type->align); |
assert(p->u.seg); |
if (p->u.seg == BSS |
&& (p->sclass == STATIC || Aflag >= 2)) |
print(".reserve %s,%d\n", p->x.name, p->type->size); |
else if (p->u.seg == BSS) |
print(".common %s,%d\n", p->x.name, p->type->size); |
else |
print("%s:\n", p->x.name); |
} |
static void blkfetch(int k, int off, int reg, int tmp) { |
assert(k == 1 || k == 2 || k == 4); |
assert(salign >= k); |
if (k == 1) |
print("ldub [%%r%d+%d],%%r%d\n", reg, off, tmp); |
else if (k == 2) |
print("lduh [%%r%d+%d],%%r%d\n", reg, off, tmp); |
else |
print("ld [%%r%d+%d],%%r%d\n", reg, off, tmp); |
} |
static void blkstore(int k, int off, int reg, int tmp) { |
assert(k == 1 || k == 2 || k == 4); |
assert(dalign >= k); |
if (k == 1) |
print("stb %%r%d,[%%r%d+%d]\n", tmp, reg, off); |
else if (k == 2) |
print("sth %%r%d,[%%r%d+%d]\n", tmp, reg, off); |
else |
print("st %%r%d,[%%r%d+%d]\n", tmp, reg, off); |
} |
static void blkloop(int dreg, int doff, int sreg, int soff, int size, int tmps[]) { |
if ((size&~7) < 4096) { |
print("add %%r%d,%d,%%r%d\n", sreg, size&~7, sreg); |
print("add %%r%d,%d,%%r%d\n", dreg, size&~7, tmps[2]); |
} else { |
print("set %d,%%r%d\n", size&~7, tmps[2]); |
print("add %%r%d,%%r%d,%%r%d\n", sreg, tmps[2], sreg); |
print("add %%r%d,%%r%d,%%r%d\n", dreg, tmps[2], tmps[2]); |
} |
blkcopy(tmps[2], doff, sreg, soff, size&7, tmps); |
print("1: dec 8,%%r%d\n", tmps[2]); |
blkcopy(tmps[2], doff, sreg, soff - 8, 8, tmps); |
print("cmp %%r%d,%%r%d; ", tmps[2], dreg); |
print("bgt 1b; "); |
print("dec 8,%%r%d\n", sreg); |
} |
static void defsymbol2(Symbol p) { |
if (p->scope >= LOCAL && p->sclass == STATIC) |
p->x.name = stringf(".%d", genlabel(1)); |
else |
assert(p->scope != CONSTANTS || isint(p->type) || isptr(p->type)), |
p->x.name = p->name; |
if (p->scope >= LABELS) |
p->x.name = stringf(p->generated ? ".L%s" : "%s", |
p->x.name); |
} |
|
static Symbol prevg; |
|
static void globalend(void) { |
if (prevg && prevg->type->size > 0) |
print(".size %s,%d\n", prevg->x.name, prevg->type->size); |
prevg = NULL; |
} |
|
static void export2(Symbol p) { |
globalend(); |
print(".global %s\n", p->x.name); |
} |
|
static void progend2(void) { |
globalend(); |
} |
|
static void global2(Symbol p) { |
globalend(); |
assert(p->u.seg); |
if (!p->generated) { |
print(".type %s,#%s\n", p->x.name, |
isfunc(p->type) ? "function" : "object"); |
if (p->type->size > 0) |
print(".size %s,%d\n", p->x.name, p->type->size); |
else |
prevg = p; |
} |
if (p->u.seg == BSS && p->sclass == STATIC) |
print(".local %s\n.common %s,%d,%d\n", p->x.name, p->x.name, |
p->type->size, p->type->align); |
else if (p->u.seg == BSS && Aflag >= 2) |
print(".align %d\n%s:.skip %d\n", p->type->align, p->x.name, |
p->type->size); |
else if (p->u.seg == BSS) |
print(".common %s,%d,%d\n", p->x.name, p->type->size, p->type->align); |
else |
print(".align %d\n%s:\n", p->type->align, p->x.name); |
} |
|
static void segment2(int n) { |
cseg = n; |
switch (n) { |
case CODE: print(".section \".text\"\n"); break; |
case BSS: print(".section \".bss\"\n"); break; |
case DATA: print(".section \".data\"\n"); break; |
case LIT: print(".section \".rodata\"\n"); break; |
} |
} |
Interface sparcIR = { |
1, 1, 0, /* char */ |
2, 2, 0, /* short */ |
4, 4, 0, /* int */ |
4, 4, 0, /* long */ |
4, 4, 0, /* long long */ |
4, 4, 1, /* float */ |
8, 8, 1, /* double */ |
8, 8, 1, /* long double */ |
4, 4, 0, /* T * */ |
0, 1, 0, /* struct */ |
0, /* little_endian */ |
0, /* mulops_calls */ |
1, /* wants_callb */ |
0, /* wants_argb */ |
1, /* left_to_right */ |
0, /* wants_dag */ |
0, /* unsigned_char */ |
address, |
blockbeg, |
blockend, |
defaddress, |
defconst, |
defstring, |
defsymbol, |
emit, |
export, |
function, |
gen, |
global, |
import, |
local, |
progbeg, |
progend, |
segment, |
space, |
stabblock, 0, 0, stabinit, stabline, stabsym, stabtype, |
{ |
1, /* max_unaligned_load */ |
rmap, |
blkfetch, blkstore, blkloop, |
_label, |
_rule, |
_nts, |
_kids, |
_string, |
_templates, |
_isinstruction, |
_ntname, |
emit2, |
doarg, |
target, |
clobber, |
|
} |
}; |
|
Interface solarisIR = { |
1, 1, 0, /* char */ |
2, 2, 0, /* short */ |
4, 4, 0, /* int */ |
4, 4, 0, /* long */ |
4, 4, 0, /* long long */ |
4, 4, 1, /* float */ |
8, 8, 1, /* double */ |
8, 8, 1, /* long double */ |
4, 4, 0, /* T * */ |
0, 1, 0, /* struct */ |
0, /* little_endian */ |
0, /* mulops_calls */ |
1, /* wants_callb */ |
0, /* wants_argb */ |
1, /* left_to_right */ |
0, /* wants_dag */ |
0, /* unsigned_char */ |
address, |
blockbeg, |
blockend, |
defaddress, |
defconst, |
defstring, |
defsymbol2, |
emit, |
export2, |
function, |
gen, |
global2, |
import, |
local, |
progbeg, |
progend2, |
segment2, |
space, |
stabblock, 0, 0, stabinit, stabline, stabsym, stabtype, |
{ |
1, /* max_unaligned_load */ |
rmap, |
blkfetch, blkstore, blkloop, |
_label, |
_rule, |
_nts, |
_kids, |
_string, |
_templates, |
_isinstruction, |
_ntname, |
emit2, |
doarg, |
target, |
clobber, |
|
} |
}; |
static char rcsid[] = "$Id: sparc.md,v 1.1 2002/08/28 23:12:46 drh Exp $"; |
/mips.md
0,0 → 1,1120
%{ |
#define INTTMP 0x0100ff00 |
#define INTVAR 0x40ff0000 |
#define FLTTMP 0x000f0ff0 |
#define FLTVAR 0xfff00000 |
|
#define INTRET 0x00000004 |
#define FLTRET 0x00000003 |
|
#define readsreg(p) \ |
(generic((p)->op)==INDIR && (p)->kids[0]->op==VREG+P) |
#define setsrc(d) ((d) && (d)->x.regnode && \ |
(d)->x.regnode->set == src->x.regnode->set && \ |
(d)->x.regnode->mask&src->x.regnode->mask) |
|
#define relink(a, b) ((b)->x.prev = (a), (a)->x.next = (b)) |
|
#include "c.h" |
#define NODEPTR_TYPE Node |
#define OP_LABEL(p) ((p)->op) |
#define LEFT_CHILD(p) ((p)->kids[0]) |
#define RIGHT_CHILD(p) ((p)->kids[1]) |
#define STATE_LABEL(p) ((p)->x.state) |
static void address(Symbol, Symbol, long); |
static void blkfetch(int, int, int, int); |
static void blkloop(int, int, int, int, int, int[]); |
static void blkstore(int, int, int, int); |
static void defaddress(Symbol); |
static void defconst(int, int, Value); |
static void defstring(int, char *); |
static void defsymbol(Symbol); |
static void doarg(Node); |
static void emit2(Node); |
static void export(Symbol); |
static void clobber(Node); |
static void function(Symbol, Symbol [], Symbol [], int); |
static void global(Symbol); |
static void import(Symbol); |
static void local(Symbol); |
static void progbeg(int, char **); |
static void progend(void); |
static void segment(int); |
static void space(int); |
static void target(Node); |
static int bitcount (unsigned); |
static Symbol argreg (int, int, int, int, int); |
|
static Symbol ireg[32], freg2[32], d6; |
static Symbol iregw, freg2w; |
static int tmpregs[] = {3, 9, 10}; |
static Symbol blkreg; |
|
static int gnum = 8; |
static int pic; |
|
static int cseg; |
%} |
%start stmt |
%term CNSTF4=4113 |
%term CNSTF8=8209 |
%term CNSTF16=16401 |
%term CNSTI1=1045 |
%term CNSTI2=2069 |
%term CNSTI4=4117 |
%term CNSTI8=8213 |
%term CNSTP4=4119 |
%term CNSTP8=8215 |
%term CNSTU1=1046 |
%term CNSTU2=2070 |
%term CNSTU4=4118 |
%term CNSTU8=8214 |
|
%term ARGB=41 |
%term ARGF4=4129 |
%term ARGF8=8225 |
%term ARGF16=16417 |
%term ARGI4=4133 |
%term ARGI8=8229 |
%term ARGP4=4135 |
%term ARGP8=8231 |
%term ARGU4=4134 |
%term ARGU8=8230 |
|
%term ASGNB=57 |
%term ASGNF4=4145 |
%term ASGNF8=8241 |
%term ASGNF16=16433 |
%term ASGNI1=1077 |
%term ASGNI2=2101 |
%term ASGNI4=4149 |
%term ASGNI8=8245 |
%term ASGNP4=4151 |
%term ASGNP8=8247 |
%term ASGNU1=1078 |
%term ASGNU2=2102 |
%term ASGNU4=4150 |
%term ASGNU8=8246 |
|
%term INDIRB=73 |
%term INDIRF4=4161 |
%term INDIRF8=8257 |
%term INDIRF16=16449 |
%term INDIRI1=1093 |
%term INDIRI2=2117 |
%term INDIRI4=4165 |
%term INDIRI8=8261 |
%term INDIRP4=4167 |
%term INDIRP8=8263 |
%term INDIRU1=1094 |
%term INDIRU2=2118 |
%term INDIRU4=4166 |
%term INDIRU8=8262 |
|
%term CVFF4=4209 |
%term CVFF8=8305 |
%term CVFF16=16497 |
%term CVFI4=4213 |
%term CVFI8=8309 |
|
%term CVIF4=4225 |
%term CVIF8=8321 |
%term CVIF16=16513 |
%term CVII1=1157 |
%term CVII2=2181 |
%term CVII4=4229 |
%term CVII8=8325 |
%term CVIU1=1158 |
%term CVIU2=2182 |
%term CVIU4=4230 |
%term CVIU8=8326 |
|
%term CVPP4=4247 |
%term CVPP8=8343 |
%term CVPP16=16535 |
%term CVPU4=4246 |
%term CVPU8=8342 |
|
%term CVUI1=1205 |
%term CVUI2=2229 |
%term CVUI4=4277 |
%term CVUI8=8373 |
%term CVUP4=4279 |
%term CVUP8=8375 |
%term CVUP16=16567 |
%term CVUU1=1206 |
%term CVUU2=2230 |
%term CVUU4=4278 |
%term CVUU8=8374 |
|
%term NEGF4=4289 |
%term NEGF8=8385 |
%term NEGF16=16577 |
%term NEGI4=4293 |
%term NEGI8=8389 |
|
%term CALLB=217 |
%term CALLF4=4305 |
%term CALLF8=8401 |
%term CALLF16=16593 |
%term CALLI4=4309 |
%term CALLI8=8405 |
%term CALLP4=4311 |
%term CALLP8=8407 |
%term CALLU4=4310 |
%term CALLU8=8406 |
%term CALLV=216 |
|
%term RETF4=4337 |
%term RETF8=8433 |
%term RETF16=16625 |
%term RETI4=4341 |
%term RETI8=8437 |
%term RETP4=4343 |
%term RETP8=8439 |
%term RETU4=4342 |
%term RETU8=8438 |
%term RETV=248 |
|
%term ADDRGP4=4359 |
%term ADDRGP8=8455 |
|
%term ADDRFP4=4375 |
%term ADDRFP8=8471 |
|
%term ADDRLP4=4391 |
%term ADDRLP8=8487 |
|
%term ADDF4=4401 |
%term ADDF8=8497 |
%term ADDF16=16689 |
%term ADDI4=4405 |
%term ADDI8=8501 |
%term ADDP4=4407 |
%term ADDP8=8503 |
%term ADDU4=4406 |
%term ADDU8=8502 |
|
%term SUBF4=4417 |
%term SUBF8=8513 |
%term SUBF16=16705 |
%term SUBI4=4421 |
%term SUBI8=8517 |
%term SUBP4=4423 |
%term SUBP8=8519 |
%term SUBU4=4422 |
%term SUBU8=8518 |
|
%term LSHI4=4437 |
%term LSHI8=8533 |
%term LSHU4=4438 |
%term LSHU8=8534 |
|
%term MODI4=4453 |
%term MODI8=8549 |
%term MODU4=4454 |
%term MODU8=8550 |
|
%term RSHI4=4469 |
%term RSHI8=8565 |
%term RSHU4=4470 |
%term RSHU8=8566 |
|
%term BANDI4=4485 |
%term BANDI8=8581 |
%term BANDU4=4486 |
%term BANDU8=8582 |
|
%term BCOMI4=4501 |
%term BCOMI8=8597 |
%term BCOMU4=4502 |
%term BCOMU8=8598 |
|
%term BORI4=4517 |
%term BORI8=8613 |
%term BORU4=4518 |
%term BORU8=8614 |
|
%term BXORI4=4533 |
%term BXORI8=8629 |
%term BXORU4=4534 |
%term BXORU8=8630 |
|
%term DIVF4=4545 |
%term DIVF8=8641 |
%term DIVF16=16833 |
%term DIVI4=4549 |
%term DIVI8=8645 |
%term DIVU4=4550 |
%term DIVU8=8646 |
|
%term MULF4=4561 |
%term MULF8=8657 |
%term MULF16=16849 |
%term MULI4=4565 |
%term MULI8=8661 |
%term MULU4=4566 |
%term MULU8=8662 |
|
%term EQF4=4577 |
%term EQF8=8673 |
%term EQF16=16865 |
%term EQI4=4581 |
%term EQI8=8677 |
%term EQU4=4582 |
%term EQU8=8678 |
|
%term GEF4=4593 |
%term GEF8=8689 |
%term GEI4=4597 |
%term GEI8=8693 |
%term GEI16=16885 |
%term GEU4=4598 |
%term GEU8=8694 |
|
%term GTF4=4609 |
%term GTF8=8705 |
%term GTF16=16897 |
%term GTI4=4613 |
%term GTI8=8709 |
%term GTU4=4614 |
%term GTU8=8710 |
|
%term LEF4=4625 |
%term LEF8=8721 |
%term LEF16=16913 |
%term LEI4=4629 |
%term LEI8=8725 |
%term LEU4=4630 |
%term LEU8=8726 |
|
%term LTF4=4641 |
%term LTF8=8737 |
%term LTF16=16929 |
%term LTI4=4645 |
%term LTI8=8741 |
%term LTU4=4646 |
%term LTU8=8742 |
|
%term NEF4=4657 |
%term NEF8=8753 |
%term NEF16=16945 |
%term NEI4=4661 |
%term NEI8=8757 |
%term NEU4=4662 |
%term NEU8=8758 |
|
%term JUMPV=584 |
|
%term LABELV=600 |
|
%term LOADB=233 |
%term LOADF4=4321 |
%term LOADF8=8417 |
%term LOADF16=16609 |
%term LOADI1=1253 |
%term LOADI2=2277 |
%term LOADI4=4325 |
%term LOADI8=8421 |
%term LOADP4=4327 |
%term LOADP8=8423 |
%term LOADU1=1254 |
%term LOADU2=2278 |
%term LOADU4=4326 |
%term LOADU8=8422 |
|
%term VREGP=711 |
%% |
reg: INDIRI1(VREGP) "# read register\n" |
reg: INDIRU1(VREGP) "# read register\n" |
|
reg: INDIRI2(VREGP) "# read register\n" |
reg: INDIRU2(VREGP) "# read register\n" |
|
reg: INDIRF4(VREGP) "# read register\n" |
reg: INDIRI4(VREGP) "# read register\n" |
reg: INDIRP4(VREGP) "# read register\n" |
reg: INDIRU4(VREGP) "# read register\n" |
|
reg: INDIRF8(VREGP) "# read register\n" |
reg: INDIRI8(VREGP) "# read register\n" |
reg: INDIRP8(VREGP) "# read register\n" |
reg: INDIRU8(VREGP) "# read register\n" |
|
stmt: ASGNI1(VREGP,reg) "# write register\n" |
stmt: ASGNU1(VREGP,reg) "# write register\n" |
|
stmt: ASGNI2(VREGP,reg) "# write register\n" |
stmt: ASGNU2(VREGP,reg) "# write register\n" |
|
stmt: ASGNF4(VREGP,reg) "# write register\n" |
stmt: ASGNI4(VREGP,reg) "# write register\n" |
stmt: ASGNP4(VREGP,reg) "# write register\n" |
stmt: ASGNU4(VREGP,reg) "# write register\n" |
|
stmt: ASGNF8(VREGP,reg) "# write register\n" |
stmt: ASGNI8(VREGP,reg) "# write register\n" |
stmt: ASGNP8(VREGP,reg) "# write register\n" |
stmt: ASGNU8(VREGP,reg) "# write register\n" |
con: CNSTI1 "%a" |
con: CNSTU1 "%a" |
|
con: CNSTI2 "%a" |
con: CNSTU2 "%a" |
|
con: CNSTI4 "%a" |
con: CNSTU4 "%a" |
con: CNSTP4 "%a" |
|
con: CNSTI8 "%a" |
con: CNSTU8 "%a" |
con: CNSTP8 "%a" |
stmt: reg "" |
acon: con "%0" |
acon: ADDRGP4 "%a" |
addr: ADDI4(reg,acon) "%1($%0)" |
addr: ADDU4(reg,acon) "%1($%0)" |
addr: ADDP4(reg,acon) "%1($%0)" |
addr: acon "%0" |
addr: reg "($%0)" |
addr: ADDRFP4 "%a+%F($sp)" |
addr: ADDRLP4 "%a+%F($sp)" |
reg: addr "la $%c,%0\n" 1 |
reg: CNSTI1 "# reg\n" range(a, 0, 0) |
reg: CNSTI2 "# reg\n" range(a, 0, 0) |
reg: CNSTI4 "# reg\n" range(a, 0, 0) |
reg: CNSTU1 "# reg\n" range(a, 0, 0) |
reg: CNSTU2 "# reg\n" range(a, 0, 0) |
reg: CNSTU4 "# reg\n" range(a, 0, 0) |
reg: CNSTP4 "# reg\n" range(a, 0, 0) |
stmt: ASGNI1(addr,reg) "sb $%1,%0\n" 1 |
stmt: ASGNU1(addr,reg) "sb $%1,%0\n" 1 |
stmt: ASGNI2(addr,reg) "sh $%1,%0\n" 1 |
stmt: ASGNU2(addr,reg) "sh $%1,%0\n" 1 |
stmt: ASGNI4(addr,reg) "sw $%1,%0\n" 1 |
stmt: ASGNU4(addr,reg) "sw $%1,%0\n" 1 |
stmt: ASGNP4(addr,reg) "sw $%1,%0\n" 1 |
reg: INDIRI1(addr) "lb $%c,%0\n" 1 |
reg: INDIRU1(addr) "lbu $%c,%0\n" 1 |
reg: INDIRI2(addr) "lh $%c,%0\n" 1 |
reg: INDIRU2(addr) "lhu $%c,%0\n" 1 |
reg: INDIRI4(addr) "lw $%c,%0\n" 1 |
reg: INDIRU4(addr) "lw $%c,%0\n" 1 |
reg: INDIRP4(addr) "lw $%c,%0\n" 1 |
|
reg: CVII4(INDIRI1(addr)) "lb $%c,%0\n" 1 |
reg: CVII4(INDIRI2(addr)) "lh $%c,%0\n" 1 |
reg: CVUU4(INDIRU1(addr)) "lbu $%c,%0\n" 1 |
reg: CVUU4(INDIRU2(addr)) "lhu $%c,%0\n" 1 |
reg: CVUI4(INDIRU1(addr)) "lbu $%c,%0\n" 1 |
reg: CVUI4(INDIRU2(addr)) "lhu $%c,%0\n" 1 |
reg: INDIRF4(addr) "l.s $f%c,%0\n" 1 |
reg: INDIRF8(addr) "l.d $f%c,%0\n" 1 |
stmt: ASGNF4(addr,reg) "s.s $f%1,%0\n" 1 |
stmt: ASGNF8(addr,reg) "s.d $f%1,%0\n" 1 |
reg: DIVI4(reg,reg) "div $%c,$%0,$%1\n" 1 |
reg: DIVU4(reg,reg) "divu $%c,$%0,$%1\n" 1 |
reg: MODI4(reg,reg) "rem $%c,$%0,$%1\n" 1 |
reg: MODU4(reg,reg) "remu $%c,$%0,$%1\n" 1 |
reg: MULI4(reg,reg) "mul $%c,$%0,$%1\n" 1 |
reg: MULU4(reg,reg) "mul $%c,$%0,$%1\n" 1 |
rc: con "%0" |
rc: reg "$%0" |
|
reg: ADDI4(reg,rc) "addu $%c,$%0,%1\n" 1 |
reg: ADDP4(reg,rc) "addu $%c,$%0,%1\n" 1 |
reg: ADDU4(reg,rc) "addu $%c,$%0,%1\n" 1 |
reg: BANDI4(reg,rc) "and $%c,$%0,%1\n" 1 |
reg: BORI4(reg,rc) "or $%c,$%0,%1\n" 1 |
reg: BXORI4(reg,rc) "xor $%c,$%0,%1\n" 1 |
reg: BANDU4(reg,rc) "and $%c,$%0,%1\n" 1 |
reg: BORU4(reg,rc) "or $%c,$%0,%1\n" 1 |
reg: BXORU4(reg,rc) "xor $%c,$%0,%1\n" 1 |
reg: SUBI4(reg,rc) "subu $%c,$%0,%1\n" 1 |
reg: SUBP4(reg,rc) "subu $%c,$%0,%1\n" 1 |
reg: SUBU4(reg,rc) "subu $%c,$%0,%1\n" 1 |
rc5: CNSTI4 "%a" range(a,0,31) |
rc5: reg "$%0" |
|
reg: LSHI4(reg,rc5) "sll $%c,$%0,%1\n" 1 |
reg: LSHU4(reg,rc5) "sll $%c,$%0,%1\n" 1 |
reg: RSHI4(reg,rc5) "sra $%c,$%0,%1\n" 1 |
reg: RSHU4(reg,rc5) "srl $%c,$%0,%1\n" 1 |
reg: BCOMI4(reg) "not $%c,$%0\n" 1 |
reg: BCOMU4(reg) "not $%c,$%0\n" 1 |
reg: NEGI4(reg) "negu $%c,$%0\n" 1 |
reg: LOADI1(reg) "move $%c,$%0\n" move(a) |
reg: LOADU1(reg) "move $%c,$%0\n" move(a) |
reg: LOADI2(reg) "move $%c,$%0\n" move(a) |
reg: LOADU2(reg) "move $%c,$%0\n" move(a) |
reg: LOADI4(reg) "move $%c,$%0\n" move(a) |
reg: LOADP4(reg) "move $%c,$%0\n" move(a) |
reg: LOADU4(reg) "move $%c,$%0\n" move(a) |
reg: ADDF4(reg,reg) "add.s $f%c,$f%0,$f%1\n" 1 |
reg: ADDF8(reg,reg) "add.d $f%c,$f%0,$f%1\n" 1 |
reg: DIVF4(reg,reg) "div.s $f%c,$f%0,$f%1\n" 1 |
reg: DIVF8(reg,reg) "div.d $f%c,$f%0,$f%1\n" 1 |
reg: MULF4(reg,reg) "mul.s $f%c,$f%0,$f%1\n" 1 |
reg: MULF8(reg,reg) "mul.d $f%c,$f%0,$f%1\n" 1 |
reg: SUBF4(reg,reg) "sub.s $f%c,$f%0,$f%1\n" 1 |
reg: SUBF8(reg,reg) "sub.d $f%c,$f%0,$f%1\n" 1 |
reg: LOADF4(reg) "mov.s $f%c,$f%0\n" move(a) |
reg: LOADF8(reg) "mov.d $f%c,$f%0\n" move(a) |
reg: NEGF4(reg) "neg.s $f%c,$f%0\n" 1 |
reg: NEGF8(reg) "neg.d $f%c,$f%0\n" 1 |
reg: CVII4(reg) "sll $%c,$%0,8*(4-%a); sra $%c,$%c,8*(4-%a)\n" 2 |
reg: CVUI4(reg) "and $%c,$%0,(1<<(8*%a))-1\n" 1 |
reg: CVUU4(reg) "and $%c,$%0,(1<<(8*%a))-1\n" 1 |
reg: CVFF4(reg) "cvt.s.d $f%c,$f%0\n" 1 |
reg: CVFF8(reg) "cvt.d.s $f%c,$f%0\n" 1 |
reg: CVIF4(reg) "mtc1 $%0,$f%c; cvt.s.w $f%c,$f%c\n" 2 |
reg: CVIF8(reg) "mtc1 $%0,$f%c; cvt.d.w $f%c,$f%c\n" 2 |
reg: CVFI4(reg) "trunc.w.s $f2,$f%0,$%c; mfc1 $%c,$f2\n" (a->syms[0]->u.c.v.i==4?2:LBURG_MAX) |
reg: CVFI4(reg) "trunc.w.d $f2,$f%0,$%c; mfc1 $%c,$f2\n" (a->syms[0]->u.c.v.i==8?2:LBURG_MAX) |
stmt: LABELV "%a:\n" |
stmt: JUMPV(acon) "b %0\n" 1 |
stmt: JUMPV(reg) ".cpadd $%0\nj $%0\n" !pic |
stmt: JUMPV(reg) "j $%0\n" pic |
stmt: EQI4(reg,reg) "beq $%0,$%1,%a\n" 1 |
stmt: EQU4(reg,reg) "beq $%0,$%1,%a\n" 1 |
stmt: GEI4(reg,reg) "bge $%0,$%1,%a\n" 1 |
stmt: GEU4(reg,reg) "bgeu $%0,$%1,%a\n" 1 |
stmt: GTI4(reg,reg) "bgt $%0,$%1,%a\n" 1 |
stmt: GTU4(reg,reg) "bgtu $%0,$%1,%a\n" 1 |
stmt: LEI4(reg,reg) "ble $%0,$%1,%a\n" 1 |
stmt: LEU4(reg,reg) "bleu $%0,$%1,%a\n" 1 |
stmt: LTI4(reg,reg) "blt $%0,$%1,%a\n" 1 |
stmt: LTU4(reg,reg) "bltu $%0,$%1,%a\n" 1 |
stmt: NEI4(reg,reg) "bne $%0,$%1,%a\n" 1 |
stmt: NEU4(reg,reg) "bne $%0,$%1,%a\n" 1 |
stmt: EQF4(reg,reg) "c.eq.s $f%0,$f%1; bc1t %a\n" 2 |
stmt: EQF8(reg,reg) "c.eq.d $f%0,$f%1; bc1t %a\n" 2 |
stmt: LEF4(reg,reg) "c.ule.s $f%0,$f%1; bc1t %a\n" 2 |
stmt: LEF8(reg,reg) "c.ule.d $f%0,$f%1; bc1t %a\n" 2 |
stmt: LTF4(reg,reg) "c.ult.s $f%0,$f%1; bc1t %a\n" 2 |
stmt: LTF8(reg,reg) "c.ult.d $f%0,$f%1; bc1t %a\n" 2 |
stmt: GEF4(reg,reg) "c.lt.s $f%0,$f%1; bc1f %a\n" 2 |
stmt: GEF8(reg,reg) "c.lt.d $f%0,$f%1; bc1f %a\n" 2 |
stmt: GTF4(reg,reg) "c.le.s $f%0,$f%1; bc1f %a\n" 2 |
stmt: GTF8(reg,reg) "c.le.d $f%0,$f%1; bc1f %a\n" 2 |
stmt: NEF4(reg,reg) "c.eq.s $f%0,$f%1; bc1f %a\n" 2 |
stmt: NEF8(reg,reg) "c.eq.d $f%0,$f%1; bc1f %a\n" 2 |
ar: ADDRGP4 "%a" |
|
reg: CALLF4(ar) "jal %0\n" 1 |
reg: CALLF8(ar) "jal %0\n" 1 |
reg: CALLI4(ar) "jal %0\n" 1 |
reg: CALLP4(ar) "jal %0\n" 1 |
reg: CALLU4(ar) "jal %0\n" 1 |
stmt: CALLV(ar) "jal %0\n" 1 |
ar: reg "$%0" |
ar: CNSTP4 "%a" range(a, 0, 0x0fffffff) |
stmt: RETF4(reg) "# ret\n" 1 |
stmt: RETF8(reg) "# ret\n" 1 |
stmt: RETI4(reg) "# ret\n" 1 |
stmt: RETU4(reg) "# ret\n" 1 |
stmt: RETP4(reg) "# ret\n" 1 |
stmt: RETV(reg) "# ret\n" 1 |
stmt: ARGF4(reg) "# arg\n" 1 |
stmt: ARGF8(reg) "# arg\n" 1 |
stmt: ARGI4(reg) "# arg\n" 1 |
stmt: ARGP4(reg) "# arg\n" 1 |
stmt: ARGU4(reg) "# arg\n" 1 |
|
stmt: ARGB(INDIRB(reg)) "# argb %0\n" 1 |
stmt: ASGNB(reg,INDIRB(reg)) "# asgnb %0 %1\n" 1 |
%% |
static void progend(void){} |
static void progbeg(int argc, char *argv[]) { |
int i; |
|
{ |
union { |
char c; |
int i; |
} u; |
u.i = 0; |
u.c = 1; |
swap = ((int)(u.i == 1)) != IR->little_endian; |
} |
print(".set reorder\n"); |
pic = !IR->little_endian; |
parseflags(argc, argv); |
for (i = 0; i < argc; i++) |
if (strncmp(argv[i], "-G", 2) == 0) |
gnum = atoi(argv[i] + 2); |
else if (strcmp(argv[i], "-pic=1") == 0 |
|| strcmp(argv[i], "-pic=0") == 0) |
pic = argv[i][5]-'0'; |
for (i = 0; i < 31; i += 2) |
freg2[i] = mkreg("%d", i, 3, FREG); |
for (i = 0; i < 32; i++) |
ireg[i] = mkreg("%d", i, 1, IREG); |
ireg[29]->x.name = "sp"; |
d6 = mkreg("6", 6, 3, IREG); |
freg2w = mkwildcard(freg2); |
iregw = mkwildcard(ireg); |
tmask[IREG] = INTTMP; tmask[FREG] = FLTTMP; |
vmask[IREG] = INTVAR; vmask[FREG] = FLTVAR; |
blkreg = mkreg("8", 8, 7, IREG); |
} |
static Symbol rmap(int opk) { |
switch (optype(opk)) { |
case I: case U: case P: case B: |
return iregw; |
case F: |
return freg2w; |
default: |
return 0; |
} |
} |
static void target(Node p) { |
assert(p); |
switch (specific(p->op)) { |
case CNST+I: case CNST+U: case CNST+P: |
if (range(p, 0, 0) == 0) { |
setreg(p, ireg[0]); |
p->x.registered = 1; |
} |
break; |
case CALL+V: |
rtarget(p, 0, ireg[25]); |
break; |
case CALL+F: |
rtarget(p, 0, ireg[25]); |
setreg(p, freg2[0]); |
break; |
case CALL+I: case CALL+P: case CALL+U: |
rtarget(p, 0, ireg[25]); |
setreg(p, ireg[2]); |
break; |
case RET+F: |
rtarget(p, 0, freg2[0]); |
break; |
case RET+I: case RET+U: case RET+P: |
rtarget(p, 0, ireg[2]); |
break; |
case ARG+F: case ARG+I: case ARG+P: case ARG+U: { |
static int ty0; |
int ty = optype(p->op); |
Symbol q; |
|
q = argreg(p->x.argno, p->syms[2]->u.c.v.i, ty, opsize(p->op), ty0); |
if (p->x.argno == 0) |
ty0 = ty; |
if (q && |
!(ty == F && q->x.regnode->set == IREG)) |
rtarget(p, 0, q); |
break; |
} |
case ASGN+B: rtarget(p->kids[1], 0, blkreg); break; |
case ARG+B: rtarget(p->kids[0], 0, blkreg); break; |
} |
} |
static void clobber(Node p) { |
assert(p); |
switch (specific(p->op)) { |
case CALL+F: |
spill(INTTMP | INTRET, IREG, p); |
spill(FLTTMP, FREG, p); |
break; |
case CALL+I: case CALL+P: case CALL+U: |
spill(INTTMP, IREG, p); |
spill(FLTTMP | FLTRET, FREG, p); |
break; |
case CALL+V: |
spill(INTTMP | INTRET, IREG, p); |
spill(FLTTMP | FLTRET, FREG, p); |
break; |
} |
} |
static void emit2(Node p) { |
int dst, n, src, sz, ty; |
static int ty0; |
Symbol q; |
|
switch (specific(p->op)) { |
case ARG+F: case ARG+I: case ARG+P: case ARG+U: |
ty = optype(p->op); |
sz = opsize(p->op); |
if (p->x.argno == 0) |
ty0 = ty; |
q = argreg(p->x.argno, p->syms[2]->u.c.v.i, ty, sz, ty0); |
src = getregnum(p->x.kids[0]); |
if (q == NULL && ty == F && sz == 4) |
print("s.s $f%d,%d($sp)\n", src, p->syms[2]->u.c.v.i); |
else if (q == NULL && ty == F) |
print("s.d $f%d,%d($sp)\n", src, p->syms[2]->u.c.v.i); |
else if (q == NULL) |
print("sw $%d,%d($sp)\n", src, p->syms[2]->u.c.v.i); |
else if (ty == F && sz == 4 && q->x.regnode->set == IREG) |
print("mfc1 $%d,$f%d\n", q->x.regnode->number, src); |
else if (ty == F && q->x.regnode->set == IREG) |
print("mfc1.d $%d,$f%d\n", q->x.regnode->number, src); |
break; |
case ASGN+B: |
dalign = salign = p->syms[1]->u.c.v.i; |
blkcopy(getregnum(p->x.kids[0]), 0, |
getregnum(p->x.kids[1]), 0, |
p->syms[0]->u.c.v.i, tmpregs); |
break; |
case ARG+B: |
dalign = 4; |
salign = p->syms[1]->u.c.v.i; |
blkcopy(29, p->syms[2]->u.c.v.i, |
getregnum(p->x.kids[0]), 0, |
p->syms[0]->u.c.v.i, tmpregs); |
n = p->syms[2]->u.c.v.i + p->syms[0]->u.c.v.i; |
dst = p->syms[2]->u.c.v.i; |
for ( ; dst <= 12 && dst < n; dst += 4) |
print("lw $%d,%d($sp)\n", (dst/4)+4, dst); |
break; |
} |
} |
static Symbol argreg(int argno, int offset, int ty, int sz, int ty0) { |
assert((offset&3) == 0); |
if (offset > 12) |
return NULL; |
else if (argno == 0 && ty == F) |
return freg2[12]; |
else if (argno == 1 && ty == F && ty0 == F) |
return freg2[14]; |
else if (argno == 1 && ty == F && sz == 8) |
return d6; /* Pair! */ |
else |
return ireg[(offset/4) + 4]; |
} |
static void doarg(Node p) { |
static int argno; |
int align; |
|
if (argoffset == 0) |
argno = 0; |
p->x.argno = argno++; |
align = p->syms[1]->u.c.v.i < 4 ? 4 : p->syms[1]->u.c.v.i; |
p->syms[2] = intconst(mkactual(align, |
p->syms[0]->u.c.v.i)); |
} |
static void local(Symbol p) { |
if (askregvar(p, rmap(ttob(p->type))) == 0) |
mkauto(p); |
} |
static void function(Symbol f, Symbol caller[], Symbol callee[], int ncalls) { |
int i, saved, sizefsave, sizeisave, varargs; |
Symbol r, argregs[4]; |
|
usedmask[0] = usedmask[1] = 0; |
freemask[0] = freemask[1] = ~(unsigned)0; |
offset = maxoffset = maxargoffset = 0; |
for (i = 0; callee[i]; i++) |
; |
varargs = variadic(f->type) |
|| i > 0 && strcmp(callee[i-1]->name, "va_alist") == 0; |
for (i = 0; callee[i]; i++) { |
Symbol p = callee[i]; |
Symbol q = caller[i]; |
assert(q); |
offset = roundup(offset, q->type->align); |
p->x.offset = q->x.offset = offset; |
p->x.name = q->x.name = stringd(offset); |
r = argreg(i, offset, optype(ttob(q->type)), q->type->size, optype(ttob(caller[0]->type))); |
if (i < 4) |
argregs[i] = r; |
offset = roundup(offset + q->type->size, 4); |
if (varargs) |
p->sclass = AUTO; |
else if (r && ncalls == 0 && |
!isstruct(q->type) && !p->addressed && |
!(isfloat(q->type) && r->x.regnode->set == IREG) |
) { |
p->sclass = q->sclass = REGISTER; |
askregvar(p, r); |
assert(p->x.regnode && p->x.regnode->vbl == p); |
q->x = p->x; |
q->type = p->type; |
} |
else if (askregvar(p, rmap(ttob(p->type))) |
&& r != NULL |
&& (isint(p->type) || p->type == q->type)) { |
assert(q->sclass != REGISTER); |
p->sclass = q->sclass = REGISTER; |
q->type = p->type; |
} |
} |
assert(!caller[i]); |
offset = 0; |
gencode(caller, callee); |
if (ncalls) |
usedmask[IREG] |= ((unsigned)1)<<31; |
usedmask[IREG] &= 0xc0ff0000; |
usedmask[FREG] &= 0xfff00000; |
if (pic && ncalls) |
usedmask[IREG] |= 1<<25; |
maxargoffset = roundup(maxargoffset, usedmask[FREG] ? 8 : 4); |
if (ncalls && maxargoffset < 16) |
maxargoffset = 16; |
sizefsave = 4*bitcount(usedmask[FREG]); |
sizeisave = 4*bitcount(usedmask[IREG]); |
framesize = roundup(maxargoffset + sizefsave |
+ sizeisave + maxoffset, 16); |
segment(CODE); |
print(".align 2\n"); |
print(".ent %s\n", f->x.name); |
print("%s:\n", f->x.name); |
i = maxargoffset + sizefsave - framesize; |
print(".frame $sp,%d,$31\n", framesize); |
if (pic) |
print(".set noreorder\n.cpload $25\n.set reorder\n"); |
if (framesize > 0) |
print("addu $sp,$sp,%d\n", -framesize); |
if (usedmask[FREG]) |
print(".fmask 0x%x,%d\n", usedmask[FREG], i - 8); |
if (usedmask[IREG]) |
print(".mask 0x%x,%d\n", usedmask[IREG], |
i + sizeisave - 4); |
saved = maxargoffset; |
for (i = 20; i <= 30; i += 2) |
if (usedmask[FREG]&(3<<i)) { |
print("s.d $f%d,%d($sp)\n", i, saved); |
saved += 8; |
} |
|
for (i = 16; i <= 31; i++) |
if (usedmask[IREG]&(1<<i)) { |
if (i == 25) |
print(".cprestore %d\n", saved); |
else |
print("sw $%d,%d($sp)\n", i, saved); |
saved += 4; |
} |
for (i = 0; i < 4 && callee[i]; i++) { |
r = argregs[i]; |
if (r && r->x.regnode != callee[i]->x.regnode) { |
Symbol out = callee[i]; |
Symbol in = caller[i]; |
int rn = r->x.regnode->number; |
int rs = r->x.regnode->set; |
int tyin = ttob(in->type); |
|
assert(out && in && r && r->x.regnode); |
assert(out->sclass != REGISTER || out->x.regnode); |
if (out->sclass == REGISTER |
&& (isint(out->type) || out->type == in->type)) { |
int outn = out->x.regnode->number; |
if (rs == FREG && tyin == F+sizeop(8)) |
print("mov.d $f%d,$f%d\n", outn, rn); |
else if (rs == FREG && tyin == F+sizeop(4)) |
print("mov.s $f%d,$f%d\n", outn, rn); |
else if (rs == IREG && tyin == F+sizeop(8)) |
print("mtc1.d $%d,$f%d\n", rn, outn); |
else if (rs == IREG && tyin == F+sizeop(4)) |
print("mtc1 $%d,$f%d\n", rn, outn); |
else |
print("move $%d,$%d\n", outn, rn); |
} else { |
int off = in->x.offset + framesize; |
if (rs == FREG && tyin == F+sizeop(8)) |
print("s.d $f%d,%d($sp)\n", rn, off); |
else if (rs == FREG && tyin == F+sizeop(4)) |
print("s.s $f%d,%d($sp)\n", rn, off); |
else { |
int i, n = (in->type->size + 3)/4; |
for (i = rn; i < rn+n && i <= 7; i++) |
print("sw $%d,%d($sp)\n", i, off + (i-rn)*4); |
} |
} |
} |
} |
if (varargs && callee[i-1]) { |
i = callee[i-1]->x.offset + callee[i-1]->type->size; |
for (i = roundup(i, 4)/4; i <= 3; i++) |
print("sw $%d,%d($sp)\n", i + 4, framesize + 4*i); |
} |
emitcode(); |
saved = maxargoffset; |
for (i = 20; i <= 30; i += 2) |
if (usedmask[FREG]&(3<<i)) { |
print("l.d $f%d,%d($sp)\n", i, saved); |
saved += 8; |
} |
for (i = 16; i <= 31; i++) |
if (usedmask[IREG]&(1<<i)) { |
print("lw $%d,%d($sp)\n", i, saved); |
saved += 4; |
} |
if (framesize > 0) |
print("addu $sp,$sp,%d\n", framesize); |
print("j $31\n"); |
print(".end %s\n", f->x.name); |
} |
static void defconst(int suffix, int size, Value v) { |
if (suffix == F && size == 4) { |
float f = v.d; |
print(".word 0x%x\n", *(unsigned *)&f); |
} |
else if (suffix == F && size == 8) { |
double d = v.d; |
unsigned *p = (unsigned *)&d; |
print(".word 0x%x\n.word 0x%x\n", p[swap], p[!swap]); |
} |
else if (suffix == P) |
print(".word 0x%x\n", (unsigned)v.p); |
else if (size == 1) |
print(".byte 0x%x\n", (unsigned)((unsigned char)(suffix == I ? v.i : v.u))); |
else if (size == 2) |
print(".half 0x%x\n", (unsigned)((unsigned short)(suffix == I ? v.i : v.u))); |
else if (size == 4) |
print(".word 0x%x\n", (unsigned)(suffix == I ? v.i : v.u)); |
} |
static void defaddress(Symbol p) { |
if (pic && p->scope == LABELS) |
print(".gpword %s\n", p->x.name); |
else |
print(".word %s\n", p->x.name); |
} |
static void defstring(int n, char *str) { |
char *s; |
|
for (s = str; s < str + n; s++) |
print(".byte %d\n", (*s)&0377); |
} |
static void export(Symbol p) { |
print(".globl %s\n", p->x.name); |
} |
static void import(Symbol p) { |
if (!isfunc(p->type)) |
print(".extern %s %d\n", p->name, p->type->size); |
} |
static void defsymbol(Symbol p) { |
if (p->scope >= LOCAL && p->sclass == STATIC) |
p->x.name = stringf("L.%d", genlabel(1)); |
else if (p->generated) |
p->x.name = stringf("L.%s", p->name); |
else |
assert(p->scope != CONSTANTS || isint(p->type) || isptr(p->type)), |
p->x.name = p->name; |
} |
static void address(Symbol q, Symbol p, long n) { |
if (p->scope == GLOBAL |
|| p->sclass == STATIC || p->sclass == EXTERN) |
q->x.name = stringf("%s%s%D", p->x.name, |
n >= 0 ? "+" : "", n); |
else { |
assert(n <= INT_MAX && n >= INT_MIN); |
q->x.offset = p->x.offset + n; |
q->x.name = stringd(q->x.offset); |
} |
} |
static void global(Symbol p) { |
if (p->u.seg == BSS) { |
if (p->sclass == STATIC || Aflag >= 2) |
print(".lcomm %s,%d\n", p->x.name, p->type->size); |
else |
print( ".comm %s,%d\n", p->x.name, p->type->size); |
} else { |
if (p->u.seg == DATA |
&& (p->type->size == 0 || p->type->size > gnum)) |
print(".data\n"); |
else if (p->u.seg == DATA) |
print(".sdata\n"); |
print(".align %c\n", ".01.2...3"[p->type->align]); |
print("%s:\n", p->x.name); |
} |
} |
static void segment(int n) { |
cseg = n; |
switch (n) { |
case CODE: print(".text\n"); break; |
case LIT: print(".rdata\n"); break; |
} |
} |
static void space(int n) { |
if (cseg != BSS) |
print(".space %d\n", n); |
} |
static void blkloop(int dreg, int doff, int sreg, int soff, int size, int tmps[]) { |
int lab = genlabel(1); |
|
print("addu $%d,$%d,%d\n", sreg, sreg, size&~7); |
print("addu $%d,$%d,%d\n", tmps[2], dreg, size&~7); |
blkcopy(tmps[2], doff, sreg, soff, size&7, tmps); |
print("L.%d:\n", lab); |
print("addu $%d,$%d,%d\n", sreg, sreg, -8); |
print("addu $%d,$%d,%d\n", tmps[2], tmps[2], -8); |
blkcopy(tmps[2], doff, sreg, soff, 8, tmps); |
print("bltu $%d,$%d,L.%d\n", dreg, tmps[2], lab); |
} |
static void blkfetch(int size, int off, int reg, int tmp) { |
assert(size == 1 || size == 2 || size == 4); |
if (size == 1) |
print("lbu $%d,%d($%d)\n", tmp, off, reg); |
else if (salign >= size && size == 2) |
print("lhu $%d,%d($%d)\n", tmp, off, reg); |
else if (salign >= size) |
print("lw $%d,%d($%d)\n", tmp, off, reg); |
else if (size == 2) |
print("ulhu $%d,%d($%d)\n", tmp, off, reg); |
else |
print("ulw $%d,%d($%d)\n", tmp, off, reg); |
} |
static void blkstore(int size, int off, int reg, int tmp) { |
if (size == 1) |
print("sb $%d,%d($%d)\n", tmp, off, reg); |
else if (dalign >= size && size == 2) |
print("sh $%d,%d($%d)\n", tmp, off, reg); |
else if (dalign >= size) |
print("sw $%d,%d($%d)\n", tmp, off, reg); |
else if (size == 2) |
print("ush $%d,%d($%d)\n", tmp, off, reg); |
else |
print("usw $%d,%d($%d)\n", tmp, off, reg); |
} |
static void stabinit(char *, int, char *[]); |
static void stabline(Coordinate *); |
static void stabsym(Symbol); |
|
static char *currentfile; |
|
static int bitcount(unsigned mask) { |
unsigned i, n = 0; |
|
for (i = 1; i; i <<= 1) |
if (mask&i) |
n++; |
return n; |
} |
|
/* stabinit - initialize stab output */ |
static void stabinit(char *file, int argc, char *argv[]) { |
if (file) { |
print(".file 2,\"%s\"\n", file); |
currentfile = file; |
} |
} |
|
/* stabline - emit stab entry for source coordinate *cp */ |
static void stabline(Coordinate *cp) { |
if (cp->file && cp->file != currentfile) { |
print(".file 2,\"%s\"\n", cp->file); |
currentfile = cp->file; |
} |
print(".loc 2,%d\n", cp->y); |
} |
|
/* stabsym - output a stab entry for symbol p */ |
static void stabsym(Symbol p) { |
if (p == cfunc && IR->stabline) |
(*IR->stabline)(&p->src); |
} |
Interface mipsebIR = { |
1, 1, 0, /* char */ |
2, 2, 0, /* short */ |
4, 4, 0, /* int */ |
4, 4, 0, /* long */ |
4, 4, 0, /* long long */ |
4, 4, 1, /* float */ |
8, 8, 1, /* double */ |
8, 8, 1, /* long double */ |
4, 4, 0, /* T * */ |
0, 1, 0, /* struct */ |
0, /* little_endian */ |
0, /* mulops_calls */ |
0, /* wants_callb */ |
1, /* wants_argb */ |
1, /* left_to_right */ |
0, /* wants_dag */ |
0, /* unsigned_char */ |
address, |
blockbeg, |
blockend, |
defaddress, |
defconst, |
defstring, |
defsymbol, |
emit, |
export, |
function, |
gen, |
global, |
import, |
local, |
progbeg, |
progend, |
segment, |
space, |
0, 0, 0, stabinit, stabline, stabsym, 0, |
{ |
4, /* max_unaligned_load */ |
rmap, |
blkfetch, blkstore, blkloop, |
_label, |
_rule, |
_nts, |
_kids, |
_string, |
_templates, |
_isinstruction, |
_ntname, |
emit2, |
doarg, |
target, |
clobber, |
|
} |
}, mipselIR = { |
1, 1, 0, /* char */ |
2, 2, 0, /* short */ |
4, 4, 0, /* int */ |
4, 4, 0, /* long */ |
4, 4, 0, /* long long */ |
4, 4, 1, /* float */ |
8, 8, 1, /* double */ |
8, 8, 1, /* long double */ |
4, 4, 0, /* T * */ |
0, 1, 0, /* struct */ |
1, /* little_endian */ |
0, /* mulops_calls */ |
0, /* wants_callb */ |
1, /* wants_argb */ |
1, /* left_to_right */ |
0, /* wants_dag */ |
0, /* unsigned_char */ |
address, |
blockbeg, |
blockend, |
defaddress, |
defconst, |
defstring, |
defsymbol, |
emit, |
export, |
function, |
gen, |
global, |
import, |
local, |
progbeg, |
progend, |
segment, |
space, |
0, 0, 0, stabinit, stabline, stabsym, 0, |
{ |
4, /* max_unaligned_load */ |
rmap, |
blkfetch, blkstore, blkloop, |
_label, |
_rule, |
_nts, |
_kids, |
_string, |
_templates, |
_isinstruction, |
_ntname, |
emit2, |
doarg, |
target, |
clobber, |
|
} |
}; |
static char rcsid[] = "$Id: mips.md,v 1.1 2002/08/28 23:12:44 drh Exp $"; |
/eco32.md.SAVE-3
0,0 → 1,1014
%{ |
|
/* |
* eco32.md -- ECO32 back-end specification |
* |
* register usage: |
* $0 always zero |
* $1 reserved for assembler |
* $2 func return value |
* $3 func return value |
* $4 proc/func argument |
* $5 proc/func argument |
* $6 proc/func argument |
* $7 proc/func argument |
* $8 temporary register (caller-save) |
* $9 temporary register (caller-save) |
* $10 temporary register (caller-save) |
* $11 temporary register (caller-save) |
* $12 temporary register (caller-save) |
* $13 temporary register (caller-save) |
* $14 temporary register (caller-save) |
* $15 temporary register (caller-save) |
* $16 register variable (callee-save) |
* $17 register variable (callee-save) |
* $18 register variable (callee-save) |
* $19 register variable (callee-save) |
* $20 register variable (callee-save) |
* $21 register variable (callee-save) |
* $22 register variable (callee-save) |
* $23 register variable (callee-save) |
* $24 temporary register (caller-save) |
* $25 temporary register (caller-save) |
* $26 reserved for OS kernel |
* $27 reserved for OS kernel |
* $28 reserved for OS kernel |
* $29 stack pointer |
* $30 interrupt return address |
* $31 proc/func return address |
* caller-save registers are not preserved across procedure calls |
* callee-save registers are preserved across procedure calls |
* |
* tree grammar terminals produced by: |
* ops c=1 s=2 i=4 l=4 h=4 f=4 d=8 x=8 p=4 |
*/ |
|
#include "c.h" |
|
#define NODEPTR_TYPE Node |
#define OP_LABEL(p) ((p)->op) |
#define LEFT_CHILD(p) ((p)->kids[0]) |
#define RIGHT_CHILD(p) ((p)->kids[1]) |
#define STATE_LABEL(p) ((p)->x.state) |
|
static void address(Symbol, Symbol, long); |
static void defaddress(Symbol); |
static void defconst(int, int, Value); |
static void defstring(int, char *); |
static void defsymbol(Symbol); |
static void export(Symbol); |
static void function(Symbol, Symbol [], Symbol [], int); |
static void global(Symbol); |
static void import(Symbol); |
static void local(Symbol); |
static void progbeg(int, char * []); |
static void progend(void); |
static void segment(int); |
static void space(int); |
static Symbol rmap(int); |
static void blkfetch(int, int, int, int); |
static void blkstore(int, int, int, int); |
static void blkloop(int, int, int, int, int, int []); |
static void emit2(Node); |
static void doarg(Node); |
static void target(Node); |
static void clobber(Node); |
|
#define INTTMP 0x0100FF00 |
#define INTVAR 0x00FF0000 |
#define INTRET 0x00000004 |
#define FLTTMP 0x000F0FF0 |
#define FLTVAR 0xFFF00000 |
#define FLTRET 0x00000003 |
|
static Symbol ireg[32]; |
static Symbol iregw; |
static Symbol freg2[32]; |
static Symbol freg2w; |
static Symbol blkreg; |
static int tmpregs[] = { 3, 9, 10 }; |
|
%} |
|
%start stmt |
|
%term CNSTF4=4113 CNSTF8=8209 |
%term CNSTI1=1045 CNSTI2=2069 CNSTI4=4117 |
%term CNSTP4=4119 |
%term CNSTU1=1046 CNSTU2=2070 CNSTU4=4118 |
|
%term ARGB=41 |
%term ARGF4=4129 ARGF8=8225 |
%term ARGI4=4133 |
%term ARGP4=4135 |
%term ARGU4=4134 |
|
%term ASGNB=57 |
%term ASGNF4=4145 ASGNF8=8241 |
%term ASGNI1=1077 ASGNI2=2101 ASGNI4=4149 |
%term ASGNP4=4151 |
%term ASGNU1=1078 ASGNU2=2102 ASGNU4=4150 |
|
%term INDIRB=73 |
%term INDIRF4=4161 INDIRF8=8257 |
%term INDIRI1=1093 INDIRI2=2117 INDIRI4=4165 |
%term INDIRP4=4167 |
%term INDIRU1=1094 INDIRU2=2118 INDIRU4=4166 |
|
%term CVFF4=4209 CVFF8=8305 |
%term CVFI4=4213 |
|
%term CVIF4=4225 CVIF8=8321 |
%term CVII1=1157 CVII2=2181 CVII4=4229 |
%term CVIU1=1158 CVIU2=2182 CVIU4=4230 |
|
%term CVPU4=4246 |
|
%term CVUI1=1205 CVUI2=2229 CVUI4=4277 |
%term CVUP4=4279 |
%term CVUU1=1206 CVUU2=2230 CVUU4=4278 |
|
%term NEGF4=4289 NEGF8=8385 |
%term NEGI4=4293 |
|
%term CALLB=217 |
%term CALLF4=4305 CALLF8=8401 |
%term CALLI4=4309 |
%term CALLP4=4311 |
%term CALLU4=4310 |
%term CALLV=216 |
|
%term RETF4=4337 RETF8=8433 |
%term RETI4=4341 |
%term RETP4=4343 |
%term RETU4=4342 |
%term RETV=248 |
|
%term ADDRGP4=4359 |
|
%term ADDRFP4=4375 |
|
%term ADDRLP4=4391 |
|
%term ADDF4=4401 ADDF8=8497 |
%term ADDI4=4405 |
%term ADDP4=4407 |
%term ADDU4=4406 |
|
%term SUBF4=4417 SUBF8=8513 |
%term SUBI4=4421 |
%term SUBP4=4423 |
%term SUBU4=4422 |
|
%term LSHI4=4437 |
%term LSHU4=4438 |
|
%term MODI4=4453 |
%term MODU4=4454 |
|
%term RSHI4=4469 |
%term RSHU4=4470 |
|
%term BANDI4=4485 |
%term BANDU4=4486 |
|
%term BCOMI4=4501 |
%term BCOMU4=4502 |
|
%term BORI4=4517 |
%term BORU4=4518 |
|
%term BXORI4=4533 |
%term BXORU4=4534 |
|
%term DIVF4=4545 DIVF8=8641 |
%term DIVI4=4549 |
%term DIVU4=4550 |
|
%term MULF4=4561 MULF8=8657 |
%term MULI4=4565 |
%term MULU4=4566 |
|
%term EQF4=4577 EQF8=8673 |
%term EQI4=4581 |
%term EQU4=4582 |
|
%term GEF4=4593 GEF8=8689 |
%term GEI4=4597 |
%term GEU4=4598 |
|
%term GTF4=4609 GTF8=8705 |
%term GTI4=4613 |
%term GTU4=4614 |
|
%term LEF4=4625 LEF8=8721 |
%term LEI4=4629 |
%term LEU4=4630 |
|
%term LTF4=4641 LTF8=8737 |
%term LTI4=4645 |
%term LTU4=4646 |
|
%term NEF4=4657 NEF8=8753 |
%term NEI4=4661 |
%term NEU4=4662 |
|
%term JUMPV=584 |
|
%term LABELV=600 |
|
%term LOADB=233 |
%term LOADF4=4321 LOADF8=8417 |
%term LOADI1=1253 LOADI2=2277 LOADI4=4325 |
%term LOADP4=4327 |
%term LOADU1=1254 LOADU2=2278 LOADU4=4326 |
|
%term VREGP=711 |
|
|
%% |
|
|
reg: INDIRI1(VREGP) "# read register\n" |
reg: INDIRI2(VREGP) "# read register\n" |
reg: INDIRI4(VREGP) "# read register\n" |
reg: INDIRP4(VREGP) "# read register\n" |
reg: INDIRU1(VREGP) "# read register\n" |
reg: INDIRU2(VREGP) "# read register\n" |
reg: INDIRU4(VREGP) "# read register\n" |
|
stmt: ASGNI1(VREGP,reg) "# write register\n" |
stmt: ASGNI2(VREGP,reg) "# write register\n" |
stmt: ASGNI4(VREGP,reg) "# write register\n" |
stmt: ASGNP4(VREGP,reg) "# write register\n" |
stmt: ASGNU1(VREGP,reg) "# write register\n" |
stmt: ASGNU2(VREGP,reg) "# write register\n" |
stmt: ASGNU4(VREGP,reg) "# write register\n" |
|
con: CNSTI1 "%a" |
con: CNSTI2 "%a" |
con: CNSTI4 "%a" |
con: CNSTP4 "%a" |
con: CNSTU1 "%a" |
con: CNSTU2 "%a" |
con: CNSTU4 "%a" |
|
stmt: reg "" |
|
acon: con "%0" |
acon: ADDRGP4 "%a" |
|
addr: ADDI4(reg,acon) "$%0,%1" |
addr: ADDP4(reg,acon) "$%0,%1" |
addr: ADDU4(reg,acon) "$%0,%1" |
|
addr: acon "$0,%0" |
addr: reg "$%0,0" |
addr: ADDRFP4 "$29,%a+%F" |
addr: ADDRLP4 "$29,%a+%F" |
|
reg: addr "\tadd\t$%c,%0\n" 1 |
|
reg: CNSTI1 "# reg\n" range(a, 0, 0) |
reg: CNSTI2 "# reg\n" range(a, 0, 0) |
reg: CNSTI4 "# reg\n" range(a, 0, 0) |
reg: CNSTP4 "# reg\n" range(a, 0, 0) |
reg: CNSTU1 "# reg\n" range(a, 0, 0) |
reg: CNSTU2 "# reg\n" range(a, 0, 0) |
reg: CNSTU4 "# reg\n" range(a, 0, 0) |
|
stmt: ASGNI1(addr,reg) "\tstb\t$%1,%0\n" 1 |
stmt: ASGNI2(addr,reg) "\tsth\t$%1,%0\n" 1 |
stmt: ASGNI4(addr,reg) "\tstw\t$%1,%0\n" 1 |
stmt: ASGNP4(addr,reg) "\tstw\t$%1,%0\n" 1 |
stmt: ASGNU1(addr,reg) "\tstb\t$%1,%0\n" 1 |
stmt: ASGNU2(addr,reg) "\tsth\t$%1,%0\n" 1 |
stmt: ASGNU4(addr,reg) "\tstw\t$%1,%0\n" 1 |
|
reg: INDIRI1(addr) "\tldb\t$%c,%0\n" 1 |
reg: INDIRI2(addr) "\tldh\t$%c,%0\n" 1 |
reg: INDIRI4(addr) "\tldw\t$%c,%0\n" 1 |
reg: INDIRP4(addr) "\tldw\t$%c,%0\n" 1 |
reg: INDIRU1(addr) "\tldbu\t$%c,%0\n" 1 |
reg: INDIRU2(addr) "\tldhu\t$%c,%0\n" 1 |
reg: INDIRU4(addr) "\tldw\t$%c,%0\n" 1 |
|
reg: CVII4(INDIRI1(addr)) "\tldb\t$%c,%0\n" 1 |
reg: CVII4(INDIRI2(addr)) "\tldh\t$%c,%0\n" 1 |
reg: CVUU4(INDIRU1(addr)) "\tldbu\t$%c,%0\n" 1 |
reg: CVUU4(INDIRU2(addr)) "\tldhu\t$%c,%0\n" 1 |
reg: CVUI4(INDIRU1(addr)) "\tldbu\t$%c,%0\n" 1 |
reg: CVUI4(INDIRU2(addr)) "\tldhu\t$%c,%0\n" 1 |
|
rc: con "%0" |
rc: reg "$%0" |
|
reg: ADDI4(reg,rc) "\tadd\t$%c,$%0,%1\n" 1 |
reg: ADDP4(reg,rc) "\tadd\t$%c,$%0,%1\n" 1 |
reg: ADDU4(reg,rc) "\tadd\t$%c,$%0,%1\n" 1 |
reg: SUBI4(reg,rc) "\tsub\t$%c,$%0,%1\n" 1 |
reg: SUBP4(reg,rc) "\tsub\t$%c,$%0,%1\n" 1 |
reg: SUBU4(reg,rc) "\tsub\t$%c,$%0,%1\n" 1 |
reg: NEGI4(reg) "\tsub\t$%c,$0,$%0\n" 1 |
|
reg: MULI4(reg,rc) "\tmul\t$%c,$%0,%1\n" 1 |
reg: MULU4(reg,rc) "\tmulu\t$%c,$%0,%1\n" 1 |
reg: DIVI4(reg,rc) "\tdiv\t$%c,$%0,%1\n" 1 |
reg: DIVU4(reg,rc) "\tdivu\t$%c,$%0,%1\n" 1 |
reg: MODI4(reg,rc) "\trem\t$%c,$%0,%1\n" 1 |
reg: MODU4(reg,rc) "\tremu\t$%c,$%0,%1\n" 1 |
|
reg: BANDI4(reg,rc) "\tand\t$%c,$%0,%1\n" 1 |
reg: BANDU4(reg,rc) "\tand\t$%c,$%0,%1\n" 1 |
reg: BORI4(reg,rc) "\tor\t$%c,$%0,%1\n" 1 |
reg: BORU4(reg,rc) "\tor\t$%c,$%0,%1\n" 1 |
reg: BXORI4(reg,rc) "\txor\t$%c,$%0,%1\n" 1 |
reg: BXORU4(reg,rc) "\txor\t$%c,$%0,%1\n" 1 |
reg: BCOMI4(reg) "\txnor\t$%c,$0,$%0\n" 1 |
reg: BCOMU4(reg) "\txnor\t$%c,$0,$%0\n" 1 |
|
rc5: CNSTI4 "%a" range(a, 0, 31) |
rc5: reg "$%0" |
|
reg: LSHI4(reg,rc5) "\tsll\t$%c,$%0,%1\n" 1 |
reg: LSHU4(reg,rc5) "\tsll\t$%c,$%0,%1\n" 1 |
reg: RSHI4(reg,rc5) "\tsar\t$%c,$%0,%1\n" 1 |
reg: RSHU4(reg,rc5) "\tslr\t$%c,$%0,%1\n" 1 |
|
reg: LOADI1(reg) "\tadd\t$%c,$0,$%0\n" move(a) |
reg: LOADI2(reg) "\tadd\t$%c,$0,$%0\n" move(a) |
reg: LOADI4(reg) "\tadd\t$%c,$0,$%0\n" move(a) |
reg: LOADP4(reg) "\tadd\t$%c,$0,$%0\n" move(a) |
reg: LOADU1(reg) "\tadd\t$%c,$0,$%0\n" move(a) |
reg: LOADU2(reg) "\tadd\t$%c,$0,$%0\n" move(a) |
reg: LOADU4(reg) "\tadd\t$%c,$0,$%0\n" move(a) |
|
reg: CVII4(reg) "\tsll\t$%c,$%0,8*(4-%a)\n\tsar\t$%c,$%c,8*(4-%a)\n" 2 |
reg: CVUI4(reg) "\tand\t$%c,$%0,(1<<(8*%a))-1\n" 1 |
reg: CVUU4(reg) "\tand\t$%c,$%0,(1<<(8*%a))-1\n" 1 |
|
stmt: LABELV "%a:\n" |
stmt: JUMPV(acon) "\tj\t%0\n" 1 |
stmt: JUMPV(reg) "\tjr\t$%0\n" 1 |
|
stmt: EQI4(reg,reg) "\tbeq\t$%0,$%1,%a\n" 1 |
stmt: EQU4(reg,reg) "\tbeq\t$%0,$%1,%a\n" 1 |
stmt: NEI4(reg,reg) "\tbne\t$%0,$%1,%a\n" 1 |
stmt: NEU4(reg,reg) "\tbne\t$%0,$%1,%a\n" 1 |
stmt: LEI4(reg,reg) "\tble\t$%0,$%1,%a\n" 1 |
stmt: LEU4(reg,reg) "\tbleu\t$%0,$%1,%a\n" 1 |
stmt: LTI4(reg,reg) "\tblt\t$%0,$%1,%a\n" 1 |
stmt: LTU4(reg,reg) "\tbltu\t$%0,$%1,%a\n" 1 |
stmt: GEI4(reg,reg) "\tbge\t$%0,$%1,%a\n" 1 |
stmt: GEU4(reg,reg) "\tbgeu\t$%0,$%1,%a\n" 1 |
stmt: GTI4(reg,reg) "\tbgt\t$%0,$%1,%a\n" 1 |
stmt: GTU4(reg,reg) "\tbgtu\t$%0,$%1,%a\n" 1 |
|
reg: CALLI4(ar) "\tjal\t%0\n" 1 |
reg: CALLP4(ar) "\tjal\t%0\n" 1 |
reg: CALLU4(ar) "\tjal\t%0\n" 1 |
stmt: CALLV(ar) "\tjal\t%0\n" 1 |
|
ar: ADDRGP4 "%a" |
ar: reg "$%0" |
ar: CNSTP4 "%a" range(a, 0, 0x03FFFFFF) |
|
stmt: RETI4(reg) "# ret\n" 1 |
stmt: RETP4(reg) "# ret\n" 1 |
stmt: RETU4(reg) "# ret\n" 1 |
stmt: RETV(reg) "# ret\n" 1 |
|
stmt: ARGI4(reg) "# arg\n" 1 |
stmt: ARGP4(reg) "# arg\n" 1 |
stmt: ARGU4(reg) "# arg\n" 1 |
|
stmt: ARGB(INDIRB(reg)) "# argb %0\n" 1 |
stmt: ASGNB(reg,INDIRB(reg)) "# asgnb %0 %1\n" 1 |
|
reg: INDIRF4(VREGP) "# read register\n" |
stmt: ASGNF4(VREGP,reg) "# write register\n" |
reg: INDIRF4(addr) ";FP: l.s $f%c,%0\n" 1 |
stmt: ASGNF4(addr,reg) ";FP: s.s $f%1,%0\n" 1 |
reg: ADDF4(reg,reg) ";FP: add.s $f%c,$f%0,$f%1\n" 1 |
reg: SUBF4(reg,reg) ";FP: sub.s $f%c,$f%0,$f%1\n" 1 |
reg: MULF4(reg,reg) ";FP: mul.s $f%c,$f%0,$f%1\n" 1 |
reg: DIVF4(reg,reg) ";FP: div.s $f%c,$f%0,$f%1\n" 1 |
reg: LOADF4(reg) ";FP: mov.s $f%c,$f%0\n" 1 |
reg: NEGF4(reg) ";FP: neg.s $f%c,$f%0\n" 1 |
reg: CVFF4(reg) ";FP: cvt.s.d $f%c,$f%0\n" 1 |
reg: CVIF4(reg) ";FP: mtc1 $%0,$f%c; cvt.s.w $f%c,$f%c\n" 1 |
reg: CVFI4(reg) ";FP: trunc.w.s $f2,$f%0,$%c; mfc1 $%c,$f2\n" (a->syms[0]->u.c.v.i == 4 ? 1 : LBURG_MAX) |
stmt: EQF4(reg,reg) ";FP: c.eq.s $f%0,$f%1; bc1t %a\n" 1 |
stmt: LEF4(reg,reg) ";FP: c.ule.s $f%0,$f%1; bc1t %a\n" 1 |
stmt: LTF4(reg,reg) ";FP: c.ult.s $f%0,$f%1; bc1t %a\n" 1 |
stmt: GEF4(reg,reg) ";FP: c.lt.s $f%0,$f%1; bc1f %a\n" 1 |
stmt: GTF4(reg,reg) ";FP: c.le.s $f%0,$f%1; bc1f %a\n" 1 |
stmt: NEF4(reg,reg) ";FP: c.eq.s $f%0,$f%1; bc1f %a\n" 1 |
reg: CALLF4(ar) "\tjal\t%0\n" 1 |
stmt: RETF4(reg) "# ret\n" 1 |
stmt: ARGF4(reg) "# arg\n" 1 |
|
reg: INDIRF8(VREGP) "# read register\n" |
stmt: ASGNF8(VREGP,reg) "# write register\n" |
reg: INDIRF8(addr) ";FP: l.d $f%c,%0\n" 1 |
stmt: ASGNF8(addr,reg) ";FP: s.d $f%1,%0\n" 1 |
reg: ADDF8(reg,reg) ";FP: add.d $f%c,$f%0,$f%1\n" 1 |
reg: SUBF8(reg,reg) ";FP: sub.d $f%c,$f%0,$f%1\n" 1 |
reg: MULF8(reg,reg) ";FP: mul.d $f%c,$f%0,$f%1\n" 1 |
reg: DIVF8(reg,reg) ";FP: div.d $f%c,$f%0,$f%1\n" 1 |
reg: LOADF8(reg) ";FP: mov.d $f%c,$f%0\n" 1 |
reg: NEGF8(reg) ";FP: neg.d $f%c,$f%0\n" 1 |
reg: CVFF8(reg) ";FP: cvt.d.s $f%c,$f%0\n" 1 |
reg: CVIF8(reg) ";FP: mtc1 $%0,$f%c; cvt.d.w $f%c,$f%c\n" 1 |
reg: CVFI4(reg) ";FP: trunc.w.d $f2,$f%0,$%c; mfc1 $%c,$f2\n" (a->syms[0]->u.c.v.i == 8 ? 1 : LBURG_MAX) |
stmt: EQF8(reg,reg) ";FP: c.eq.d $f%0,$f%1; bc1t %a\n" 1 |
stmt: LEF8(reg,reg) ";FP: c.ule.d $f%0,$f%1; bc1t %a\n" 1 |
stmt: LTF8(reg,reg) ";FP: c.ult.d $f%0,$f%1; bc1t %a\n" 1 |
stmt: GEF8(reg,reg) ";FP: c.lt.d $f%0,$f%1; bc1f %a\n" 1 |
stmt: GTF8(reg,reg) ";FP: c.le.d $f%0,$f%1; bc1f %a\n" 1 |
stmt: NEF8(reg,reg) ";FP: c.eq.d $f%0,$f%1; bc1f %a\n" 1 |
reg: CALLF8(ar) "\tjal\t%0\n" 1 |
stmt: RETF8(reg) "# ret\n" 1 |
stmt: ARGF8(reg) "# arg\n" 1 |
|
|
%% |
|
|
static void address(Symbol s1, Symbol s2, long n) { |
if (s2->scope == GLOBAL || |
s2->sclass == STATIC || |
s2->sclass == EXTERN) { |
s1->x.name = stringf("%s%s%D", s2->x.name, n >= 0 ? "+" : "", n); |
} else { |
assert(n >= INT_MIN && n <= INT_MAX); |
s1->x.offset = s2->x.offset + n; |
s1->x.name = stringd(s1->x.offset); |
} |
} |
|
|
static void defaddress(Symbol s) { |
print("\t.word\t%s\n", s->x.name); |
} |
|
|
static void defconst(int suffix, int size, Value v) { |
float f; |
double d; |
unsigned *p; |
|
if (suffix == F && size == 4) { |
f = v.d; |
print("\t.word\t0x%x\n", * (unsigned *) &f); |
} else |
if (suffix == F && size == 8) { |
d = v.d; |
p = (unsigned *) &d; |
print("\t.word\t0x%x\n", p[swap]); |
print("\t.word\t0x%x\n", p[1 - swap]); |
} else |
if (suffix == P) { |
print("\t.word\t0x%x\n", (unsigned) v.p); |
} else |
if (size == 1) { |
print("\t.byte\t0x%x\n", |
(unsigned) ((unsigned char) (suffix == I ? v.i : v.u))); |
} else |
if (size == 2) { |
print("\t.half\t0x%x\n", |
(unsigned) ((unsigned short) (suffix == I ? v.i : v.u))); |
} else |
if (size == 4) { |
print("\t.word\t0x%x\n", (unsigned) (suffix == I ? v.i : v.u)); |
} |
} |
|
|
static void defstring(int n, char *str) { |
char *s; |
|
for (s = str; s < str + n; s++) { |
print("\t.byte\t0x%x\n", (*s) & 0xFF); |
} |
} |
|
|
static void defsymbol(Symbol s) { |
if (s->scope >= LOCAL && s->sclass == STATIC) { |
s->x.name = stringf("L.%d", genlabel(1)); |
} else |
if (s->generated) { |
s->x.name = stringf("L.%s", s->name); |
} else { |
assert(s->scope != CONSTANTS || isint(s->type) || isptr(s->type)); |
s->x.name = s->name; |
} |
} |
|
|
static void export(Symbol s) { |
print("\t.export\t%s\n", s->name); |
} |
|
|
static int bitcount(unsigned mask) { |
unsigned i, n; |
|
n = 0; |
for (i = 1; i != 0; i <<= 1) { |
if (mask & i) { |
n++; |
} |
} |
return n; |
} |
|
|
static Symbol argreg(int argno, int offset, int ty, int sz, int ty0) { |
assert((offset & 3) == 0); |
if (offset > 12) { |
return NULL; |
} |
return ireg[(offset / 4) + 4]; |
} |
|
|
static void function(Symbol f, Symbol caller[], Symbol callee[], int ncalls) { |
int i; |
Symbol p, q; |
Symbol r; |
int sizeisave; |
int saved; |
Symbol argregs[4]; |
|
usedmask[0] = usedmask[1] = 0; |
freemask[0] = freemask[1] = ~((unsigned) 0); |
offset = 0; |
maxoffset = 0; |
maxargoffset = 0; |
for (i = 0; callee[i] != NULL; i++) { |
p = callee[i]; |
q = caller[i]; |
assert(q != NULL); |
offset = roundup(offset, q->type->align); |
p->x.offset = q->x.offset = offset; |
p->x.name = q->x.name = stringd(offset); |
r = argreg(i, offset, optype(ttob(q->type)), |
q->type->size, optype(ttob(caller[0]->type))); |
if (i < 4) { |
argregs[i] = r; |
} |
offset = roundup(offset + q->type->size, 4); |
if (variadic(f->type)) { |
p->sclass = AUTO; |
} else |
if (r != NULL && ncalls == 0 && !isstruct(q->type) && |
!p->addressed && !(isfloat(q->type) && r->x.regnode->set == IREG)) { |
p->sclass = q->sclass = REGISTER; |
askregvar(p, r); |
assert(p->x.regnode && p->x.regnode->vbl == p); |
q->x = p->x; |
q->type = p->type; |
} else |
if (askregvar(p, rmap(ttob(p->type))) && |
r != NULL && (isint(p->type) || p->type == q->type)) { |
assert(q->sclass != REGISTER); |
p->sclass = q->sclass = REGISTER; |
q->type = p->type; |
} |
} |
assert(caller[i] == NULL); |
offset = 0; |
gencode(caller, callee); |
if (ncalls != 0) { |
usedmask[IREG] |= ((unsigned) 1) << 31; |
} |
usedmask[IREG] &= 0x80FF0000; |
usedmask[FREG] &= 0xFFF00000; |
maxargoffset = roundup(maxargoffset, 4); |
if (ncalls != 0 && maxargoffset < 16) { |
maxargoffset = 16; |
} |
sizeisave = 4 * bitcount(usedmask[IREG]); |
framesize = roundup(maxargoffset + sizeisave + maxoffset, 16); |
segment(CODE); |
print("\t.align\t4\n"); |
print("%s:\n", f->x.name); |
if (framesize > 0) { |
print("\tsub\t$29,$29,%d\n", framesize); |
} |
saved = maxargoffset; |
for (i = 16; i < 32; i++) { |
if (usedmask[IREG] & (1 << i)) { |
print("\tstw\t$%d,$29,%d\n", i, saved); |
saved += 4; |
} |
} |
for (i = 0; i < 4 && callee[i] != NULL; i++) { |
r = argregs[i]; |
if (r && r->x.regnode != callee[i]->x.regnode) { |
Symbol out = callee[i]; |
Symbol in = caller[i]; |
int rn = r->x.regnode->number; |
int rs = r->x.regnode->set; |
int tyin = ttob(in->type); |
assert(out && in && r && r->x.regnode); |
assert(out->sclass != REGISTER || out->x.regnode); |
if (out->sclass == REGISTER && |
(isint(out->type) || out->type == in->type)) { |
int outn = out->x.regnode->number; |
print("\tadd\t$%d,$0,$%d\n", outn, rn); |
} else { |
int off = in->x.offset + framesize; |
int n = (in->type->size + 3) / 4; |
int i; |
for (i = rn; i < rn + n && i <= 7; i++) { |
print("\tstw\t$%d,$29,%d\n", i, off + (i - rn) * 4); |
} |
} |
} |
} |
if (variadic(f->type) && callee[i - 1] != NULL) { |
i = callee[i - 1]->x.offset + callee[i - 1]->type->size; |
for (i = roundup(i, 4)/4; i <= 3; i++) { |
print("\tstw\t$%d,$29,%d\n", i + 4, framesize + 4 * i); |
} |
} |
emitcode(); |
saved = maxargoffset; |
for (i = 16; i < 32; i++) { |
if (usedmask[IREG] & (1 << i)) { |
print("\tldw\t$%d,$29,%d\n", i, saved); |
saved += 4; |
} |
} |
if (framesize > 0) { |
print("\tadd\t$29,$29,%d\n", framesize); |
} |
print("\tjr\t$31\n"); |
print("\n"); |
} |
|
|
static void global(Symbol s) { |
if (s->type->align != 0) { |
print("\t.align\t%d\n", s->type->align); |
} else { |
print("\t.align\t%d\n", 4); |
} |
print("%s:\n", s->x.name); |
} |
|
|
static void import(Symbol s) { |
print("\t.import\t%s\n", s->name); |
} |
|
|
static void local(Symbol s) { |
if (askregvar(s, rmap(ttob(s->type))) == 0) { |
mkauto(s); |
} |
} |
|
|
static void setSwap(void) { |
union { |
char c; |
int i; |
} u; |
|
u.i = 0; |
u.c = 1; |
swap = ((u.i == 1) != IR->little_endian); |
} |
|
|
static void progbeg(int argc, char *argv[]) { |
int i; |
|
setSwap(); |
segment(CODE); |
parseflags(argc, argv); |
for (i = 0; i < 32; i++) { |
ireg[i] = mkreg("%d", i, 1, IREG); |
} |
iregw = mkwildcard(ireg); |
for (i = 0; i < 32; i += 2) { |
freg2[i] = mkreg("%d", i, 3, FREG); |
} |
freg2w = mkwildcard(freg2); |
tmask[IREG] = INTTMP; |
vmask[IREG] = INTVAR; |
tmask[FREG] = FLTTMP; |
vmask[FREG] = FLTVAR; |
blkreg = mkreg("8", 8, 7, IREG); |
} |
|
|
static void progend(void) { |
} |
|
|
static void segment(int n) { |
static int currSeg = -1; |
int newSeg; |
|
switch (n) { |
case CODE: |
newSeg = CODE; |
break; |
case BSS: |
newSeg = BSS; |
break; |
case DATA: |
newSeg = DATA; |
break; |
case LIT: |
newSeg = DATA; |
break; |
} |
if (currSeg == newSeg) { |
return; |
} |
switch (newSeg) { |
case CODE: |
print("\t.code\n"); |
break; |
case BSS: |
print("\t.bss\n"); |
break; |
case DATA: |
print("\t.data\n"); |
break; |
} |
currSeg = newSeg; |
} |
|
|
static void space(int n) { |
print("\t.space\t%d\n", n); |
} |
|
|
static Symbol rmap(int opk) { |
switch (optype(opk)) { |
case I: |
case U: |
case P: |
case B: |
return iregw; |
case F: |
return freg2w; |
default: |
return 0; |
} |
} |
|
|
static void blkfetch(int size, int off, int reg, int tmp) { |
assert(size == 1 || size == 2 || size == 4); |
if (size == 1) { |
print("\tldbu\t$%d,$%d,%d\n", tmp, reg, off); |
} else |
if (size == 2) { |
print("\tldhu\t$%d,$%d,%d\n", tmp, reg, off); |
} else |
if (size == 4) { |
print("\tldw\t$%d,$%d,%d\n", tmp, reg, off); |
} |
} |
|
|
static void blkstore(int size, int off, int reg, int tmp) { |
assert(size == 1 || size == 2 || size == 4); |
if (size == 1) { |
print("\tstb\t$%d,$%d,%d\n", tmp, reg, off); |
} else |
if (size == 2) { |
print("\tsth\t$%d,$%d,%d\n", tmp, reg, off); |
} else |
if (size == 4) { |
print("\tstw\t$%d,$%d,%d\n", tmp, reg, off); |
} |
} |
|
|
static void blkloop(int dreg, int doff, |
int sreg, int soff, |
int size, int tmps[]) { |
int label; |
|
label = genlabel(1); |
print("\tadd\t$%d,$%d,%d\n", sreg, sreg, size & ~7); |
print("\tadd\t$%d,$%d,%d\n", tmps[2], dreg, size & ~7); |
blkcopy(tmps[2], doff, sreg, soff, size & 7, tmps); |
print("L.%d:\n", label); |
print("\tsub\t$%d,$%d,%d\n", sreg, sreg, 8); |
print("\tsub\t$%d,$%d,%d\n", tmps[2], tmps[2], 8); |
blkcopy(tmps[2], doff, sreg, soff, 8, tmps); |
print("\tbltu\t$%d,$%d,L.%d\n", dreg, tmps[2], label); |
} |
|
|
static void emit2(Node p) { |
static int ty0; |
int ty, sz; |
Symbol q; |
int src; |
int dst, n; |
|
switch (specific(p->op)) { |
case ARG+I: |
case ARG+P: |
case ARG+U: |
ty = optype(p->op); |
sz = opsize(p->op); |
if (p->x.argno == 0) { |
ty0 = ty; |
} |
q = argreg(p->x.argno, p->syms[2]->u.c.v.i, ty, sz, ty0); |
src = getregnum(p->x.kids[0]); |
if (q == NULL) { |
print("\tstw\t$%d,$29,%d\n", src, p->syms[2]->u.c.v.i); |
} |
break; |
case ASGN+B: |
dalign = p->syms[1]->u.c.v.i; |
salign = p->syms[1]->u.c.v.i; |
blkcopy(getregnum(p->x.kids[0]), 0, |
getregnum(p->x.kids[1]), 0, |
p->syms[0]->u.c.v.i, tmpregs); |
break; |
case ARG+B: |
dalign = 4; |
salign = p->syms[1]->u.c.v.i; |
blkcopy(29, p->syms[2]->u.c.v.i, |
getregnum(p->x.kids[0]), 0, |
p->syms[0]->u.c.v.i, tmpregs); |
n = p->syms[2]->u.c.v.i + p->syms[0]->u.c.v.i; |
dst = p->syms[2]->u.c.v.i & ~3; |
for (; dst <= 12 && dst < n; dst += 4) { |
print("\tldw\t$%d,$29,%d\n", (dst / 4) + 4, dst); |
} |
break; |
} |
} |
|
|
static void doarg(Node p) { |
static int argno; |
int align; |
int size; |
int offset; |
|
if (argoffset == 0) { |
argno = 0; |
} |
p->x.argno = argno++; |
align = p->syms[1]->u.c.v.i < 4 ? 4 : p->syms[1]->u.c.v.i; |
size = p->syms[0]->u.c.v.i < 4 ? 4 : p->syms[0]->u.c.v.i; |
offset = mkactual(align, size); |
if (p->syms[0]->u.c.v.i < 4) { |
offset += 4 - p->syms[0]->u.c.v.i; |
} |
p->syms[2] = intconst(offset); |
} |
|
|
static void target(Node p) { |
static int ty0; |
int ty; |
Symbol q; |
|
assert(p); |
switch (specific(p->op)) { |
case CNST+I: |
case CNST+P: |
case CNST+U: |
if (range(p, 0, 0) == 0) { |
setreg(p, ireg[0]); |
p->x.registered = 1; |
} |
break; |
case CALL+I: |
case CALL+P: |
case CALL+U: |
rtarget(p, 0, ireg[25]); |
setreg(p, ireg[2]); |
break; |
case CALL+F: |
rtarget(p, 0, ireg[25]); |
setreg(p, freg2[0]); |
break; |
case CALL+V: |
rtarget(p, 0, ireg[25]); |
break; |
case RET+I: |
case RET+P: |
case RET+U: |
rtarget(p, 0, ireg[2]); |
break; |
case RET+F: |
rtarget(p, 0, freg2[0]); |
break; |
case ARG+I: |
case ARG+P: |
case ARG+U: |
case ARG+F: |
ty = optype(p->op); |
q = argreg(p->x.argno, p->syms[2]->u.c.v.i, ty, opsize(p->op), ty0); |
if (p->x.argno == 0) { |
ty0 = ty; |
} |
if (q && !(ty == F && q->x.regnode->set == IREG)) { |
rtarget(p, 0, q); |
} |
break; |
case ASGN+B: |
rtarget(p->kids[1], 0, blkreg); |
break; |
case ARG+B: |
rtarget(p->kids[0], 0, blkreg); |
break; |
} |
} |
|
|
static void clobber(Node p) { |
assert(p); |
switch (specific(p->op)) { |
case CALL+F: |
spill(INTTMP | INTRET, IREG, p); |
spill(FLTTMP, FREG, p); |
break; |
case CALL+I: |
case CALL+P: |
case CALL+U: |
spill(INTTMP, IREG, p); |
spill(FLTTMP | FLTRET, FREG, p); |
break; |
case CALL+V: |
spill(INTTMP | INTRET, IREG, p); |
spill(FLTTMP | FLTRET, FREG, p); |
break; |
} |
} |
|
|
Interface eco32IR = { |
1, 1, 0, /* char */ |
2, 2, 0, /* short */ |
4, 4, 0, /* int */ |
4, 4, 0, /* long */ |
4, 4, 0, /* long long */ |
4, 4, 1, /* float */ |
8, 4, 1, /* double */ |
8, 4, 1, /* long double */ |
4, 4, 0, /* T * */ |
0, 1, 0, /* struct */ |
0, /* little_endian */ |
0, /* mulops_calls */ |
0, /* wants_callb */ |
1, /* wants_argb */ |
1, /* left_to_right */ |
0, /* wants_dag */ |
0, /* unsigned_char */ |
address, |
blockbeg, |
blockend, |
defaddress, |
defconst, |
defstring, |
defsymbol, |
emit, |
export, |
function, |
gen, |
global, |
import, |
local, |
progbeg, |
progend, |
segment, |
space, |
0, 0, 0, 0, 0, 0, 0, |
{ |
1, /* max_unaligned_load */ |
rmap, |
blkfetch, blkstore, blkloop, |
_label, |
_rule, |
_nts, |
_kids, |
_string, |
_templates, |
_isinstruction, |
_ntname, |
emit2, |
doarg, |
target, |
clobber |
} |
}; |
/lex.c.ORIG
0,0 → 1,928
#include "c.h" |
#include <float.h> |
#include <errno.h> |
|
static char rcsid[] = "$Id: lex.c,v 1.1 2002/08/28 23:12:44 drh Exp $"; |
|
#define MAXTOKEN 32 |
|
enum { BLANK=01, NEWLINE=02, LETTER=04, |
DIGIT=010, HEX=020, OTHER=040 }; |
|
static unsigned char map[256] = { /* 000 nul */ 0, |
/* 001 soh */ 0, |
/* 002 stx */ 0, |
/* 003 etx */ 0, |
/* 004 eot */ 0, |
/* 005 enq */ 0, |
/* 006 ack */ 0, |
/* 007 bel */ 0, |
/* 010 bs */ 0, |
/* 011 ht */ BLANK, |
/* 012 nl */ NEWLINE, |
/* 013 vt */ BLANK, |
/* 014 ff */ BLANK, |
/* 015 cr */ 0, |
/* 016 so */ 0, |
/* 017 si */ 0, |
/* 020 dle */ 0, |
/* 021 dc1 */ 0, |
/* 022 dc2 */ 0, |
/* 023 dc3 */ 0, |
/* 024 dc4 */ 0, |
/* 025 nak */ 0, |
/* 026 syn */ 0, |
/* 027 etb */ 0, |
/* 030 can */ 0, |
/* 031 em */ 0, |
/* 032 sub */ 0, |
/* 033 esc */ 0, |
/* 034 fs */ 0, |
/* 035 gs */ 0, |
/* 036 rs */ 0, |
/* 037 us */ 0, |
/* 040 sp */ BLANK, |
/* 041 ! */ OTHER, |
/* 042 " */ OTHER, |
/* 043 # */ OTHER, |
/* 044 $ */ 0, |
/* 045 % */ OTHER, |
/* 046 & */ OTHER, |
/* 047 ' */ OTHER, |
/* 050 ( */ OTHER, |
/* 051 ) */ OTHER, |
/* 052 * */ OTHER, |
/* 053 + */ OTHER, |
/* 054 , */ OTHER, |
/* 055 - */ OTHER, |
/* 056 . */ OTHER, |
/* 057 / */ OTHER, |
/* 060 0 */ DIGIT, |
/* 061 1 */ DIGIT, |
/* 062 2 */ DIGIT, |
/* 063 3 */ DIGIT, |
/* 064 4 */ DIGIT, |
/* 065 5 */ DIGIT, |
/* 066 6 */ DIGIT, |
/* 067 7 */ DIGIT, |
/* 070 8 */ DIGIT, |
/* 071 9 */ DIGIT, |
/* 072 : */ OTHER, |
/* 073 ; */ OTHER, |
/* 074 < */ OTHER, |
/* 075 = */ OTHER, |
/* 076 > */ OTHER, |
/* 077 ? */ OTHER, |
/* 100 @ */ 0, |
/* 101 A */ LETTER|HEX, |
/* 102 B */ LETTER|HEX, |
/* 103 C */ LETTER|HEX, |
/* 104 D */ LETTER|HEX, |
/* 105 E */ LETTER|HEX, |
/* 106 F */ LETTER|HEX, |
/* 107 G */ LETTER, |
/* 110 H */ LETTER, |
/* 111 I */ LETTER, |
/* 112 J */ LETTER, |
/* 113 K */ LETTER, |
/* 114 L */ LETTER, |
/* 115 M */ LETTER, |
/* 116 N */ LETTER, |
/* 117 O */ LETTER, |
/* 120 P */ LETTER, |
/* 121 Q */ LETTER, |
/* 122 R */ LETTER, |
/* 123 S */ LETTER, |
/* 124 T */ LETTER, |
/* 125 U */ LETTER, |
/* 126 V */ LETTER, |
/* 127 W */ LETTER, |
/* 130 X */ LETTER, |
/* 131 Y */ LETTER, |
/* 132 Z */ LETTER, |
/* 133 [ */ OTHER, |
/* 134 \ */ OTHER, |
/* 135 ] */ OTHER, |
/* 136 ^ */ OTHER, |
/* 137 _ */ LETTER, |
/* 140 ` */ 0, |
/* 141 a */ LETTER|HEX, |
/* 142 b */ LETTER|HEX, |
/* 143 c */ LETTER|HEX, |
/* 144 d */ LETTER|HEX, |
/* 145 e */ LETTER|HEX, |
/* 146 f */ LETTER|HEX, |
/* 147 g */ LETTER, |
/* 150 h */ LETTER, |
/* 151 i */ LETTER, |
/* 152 j */ LETTER, |
/* 153 k */ LETTER, |
/* 154 l */ LETTER, |
/* 155 m */ LETTER, |
/* 156 n */ LETTER, |
/* 157 o */ LETTER, |
/* 160 p */ LETTER, |
/* 161 q */ LETTER, |
/* 162 r */ LETTER, |
/* 163 s */ LETTER, |
/* 164 t */ LETTER, |
/* 165 u */ LETTER, |
/* 166 v */ LETTER, |
/* 167 w */ LETTER, |
/* 170 x */ LETTER, |
/* 171 y */ LETTER, |
/* 172 z */ LETTER, |
/* 173 { */ OTHER, |
/* 174 | */ OTHER, |
/* 175 } */ OTHER, |
/* 176 ~ */ OTHER, }; |
static struct symbol tval; |
static char cbuf[BUFSIZE+1]; |
static unsigned int wcbuf[BUFSIZE+1]; |
|
Coordinate src; /* current source coordinate */ |
int t; |
char *token; /* current token */ |
Symbol tsym; /* symbol table entry for current token */ |
|
static void *cput(int c, void *cl); |
static void *wcput(int c, void *cl); |
static void *scon(int q, void *put(int c, void *cl), void *cl); |
static int backslash(int q); |
static Symbol fcon(void); |
static Symbol icon(unsigned long, int, int); |
static void ppnumber(char *); |
|
int gettok(void) { |
for (;;) { |
register unsigned char *rcp = cp; |
while (map[*rcp]&BLANK) |
rcp++; |
if (limit - rcp < MAXTOKEN) { |
cp = rcp; |
fillbuf(); |
rcp = cp; |
} |
src.file = file; |
src.x = (char *)rcp - line; |
src.y = lineno; |
cp = rcp + 1; |
switch (*rcp++) { |
case '/': if (*rcp == '*') { |
int c = 0; |
for (rcp++; *rcp != '/' || c != '*'; ) |
if (map[*rcp]&NEWLINE) { |
if (rcp < limit) |
c = *rcp; |
cp = rcp + 1; |
nextline(); |
rcp = cp; |
if (rcp == limit) |
break; |
} else |
c = *rcp++; |
if (rcp < limit) |
rcp++; |
else |
error("unclosed comment\n"); |
cp = rcp; |
continue; |
} |
return '/'; |
case '<': |
if (*rcp == '=') return cp++, LEQ; |
if (*rcp == '<') return cp++, LSHIFT; |
return '<'; |
case '>': |
if (*rcp == '=') return cp++, GEQ; |
if (*rcp == '>') return cp++, RSHIFT; |
return '>'; |
case '-': |
if (*rcp == '>') return cp++, DEREF; |
if (*rcp == '-') return cp++, DECR; |
return '-'; |
case '=': return *rcp == '=' ? cp++, EQL : '='; |
case '!': return *rcp == '=' ? cp++, NEQ : '!'; |
case '|': return *rcp == '|' ? cp++, OROR : '|'; |
case '&': return *rcp == '&' ? cp++, ANDAND : '&'; |
case '+': return *rcp == '+' ? cp++, INCR : '+'; |
case ';': case ',': case ':': |
case '*': case '~': case '%': case '^': case '?': |
case '[': case ']': case '{': case '}': case '(': case ')': |
return rcp[-1]; |
case '\n': case '\v': case '\r': case '\f': |
nextline(); |
if (cp == limit) { |
tsym = NULL; |
return EOI; |
} |
continue; |
|
case 'i': |
if (rcp[0] == 'f' |
&& !(map[rcp[1]]&(DIGIT|LETTER))) { |
cp = rcp + 1; |
return IF; |
} |
if (rcp[0] == 'n' |
&& rcp[1] == 't' |
&& !(map[rcp[2]]&(DIGIT|LETTER))) { |
cp = rcp + 2; |
tsym = inttype->u.sym; |
return INT; |
} |
goto id; |
case 'h': case 'j': case 'k': case 'm': case 'n': case 'o': |
case 'p': case 'q': case 'x': case 'y': case 'z': |
case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': |
case 'G': case 'H': case 'I': case 'J': case 'K': |
case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': |
case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': |
case 'Y': case 'Z': |
id: |
if (limit - rcp < MAXLINE) { |
cp = rcp - 1; |
fillbuf(); |
rcp = ++cp; |
} |
assert(cp == rcp); |
token = (char *)rcp - 1; |
while (map[*rcp]&(DIGIT|LETTER)) |
rcp++; |
token = stringn(token, (char *)rcp - token); |
tsym = lookup(token, identifiers); |
cp = rcp; |
return ID; |
case '0': case '1': case '2': case '3': case '4': |
case '5': case '6': case '7': case '8': case '9': { |
unsigned long n = 0; |
if (limit - rcp < MAXLINE) { |
cp = rcp - 1; |
fillbuf(); |
rcp = ++cp; |
} |
assert(cp == rcp); |
token = (char *)rcp - 1; |
if (*token == '0' && (*rcp == 'x' || *rcp == 'X')) { |
int d, overflow = 0; |
while (*++rcp) { |
if (map[*rcp]&DIGIT) |
d = *rcp - '0'; |
else if (*rcp >= 'a' && *rcp <= 'f') |
d = *rcp - 'a' + 10; |
else if (*rcp >= 'A' && *rcp <= 'F') |
d = *rcp - 'A' + 10; |
else |
break; |
if (n&~(~0UL >> 4)) |
overflow = 1; |
else |
n = (n<<4) + d; |
} |
if ((char *)rcp - token <= 2) |
error("invalid hexadecimal constant `%S'\n", token, (char *)rcp-token); |
cp = rcp; |
tsym = icon(n, overflow, 16); |
} else if (*token == '0') { |
int err = 0, overflow = 0; |
for ( ; map[*rcp]&DIGIT; rcp++) { |
if (*rcp == '8' || *rcp == '9') |
err = 1; |
if (n&~(~0UL >> 3)) |
overflow = 1; |
else |
n = (n<<3) + (*rcp - '0'); |
} |
if (*rcp == '.' || *rcp == 'e' || *rcp == 'E') { |
cp = rcp; |
tsym = fcon(); |
return FCON; |
} |
cp = rcp; |
tsym = icon(n, overflow, 8); |
if (err) |
error("invalid octal constant `%S'\n", token, (char*)cp-token); |
} else { |
int overflow = 0; |
for (n = *token - '0'; map[*rcp]&DIGIT; ) { |
int d = *rcp++ - '0'; |
if (n > (ULONG_MAX - d)/10) |
overflow = 1; |
else |
n = 10*n + d; |
} |
if (*rcp == '.' || *rcp == 'e' || *rcp == 'E') { |
cp = rcp; |
tsym = fcon(); |
return FCON; |
} |
cp = rcp; |
tsym = icon(n, overflow, 10); |
} |
return ICON; |
} |
case '.': |
if (rcp[0] == '.' && rcp[1] == '.') { |
cp += 2; |
return ELLIPSIS; |
} |
if ((map[*rcp]&DIGIT) == 0) |
return '.'; |
if (limit - rcp < MAXLINE) { |
cp = rcp - 1; |
fillbuf(); |
rcp = ++cp; |
} |
assert(cp == rcp); |
cp = rcp - 1; |
token = (char *)cp; |
tsym = fcon(); |
return FCON; |
case 'L': |
if (*rcp == '\'') { |
unsigned int *s = scon(*cp, wcput, wcbuf); |
if (s - wcbuf > 2) |
warning("excess characters in wide-character literal ignored\n"); |
tval.type = widechar; |
tval.u.c.v.u = wcbuf[0]; |
tsym = &tval; |
return ICON; |
} else if (*rcp == '"') { |
unsigned int *s = scon(*cp, wcput, wcbuf); |
tval.type = array(widechar, s - wcbuf, 0); |
tval.u.c.v.p = wcbuf; |
tsym = &tval; |
return SCON; |
} else |
goto id; |
case '\'': { |
char *s = scon(*--cp, cput, cbuf); |
if (s - cbuf > 2) |
warning("excess characters in multibyte character literal ignored\n"); |
tval.type = inttype; |
if (chartype->op == INT) |
tval.u.c.v.i = extend(cbuf[0], chartype); |
else |
tval.u.c.v.i = cbuf[0]&0xFF; |
tsym = &tval; |
return ICON; |
} |
case '"': { |
char *s = scon(*--cp, cput, cbuf); |
tval.type = array(chartype, s - cbuf, 0); |
tval.u.c.v.p = cbuf; |
tsym = &tval; |
return SCON; |
} |
case 'a': |
if (rcp[0] == 'u' |
&& rcp[1] == 't' |
&& rcp[2] == 'o' |
&& !(map[rcp[3]]&(DIGIT|LETTER))) { |
cp = rcp + 3; |
return AUTO; |
} |
goto id; |
case 'b': |
if (rcp[0] == 'r' |
&& rcp[1] == 'e' |
&& rcp[2] == 'a' |
&& rcp[3] == 'k' |
&& !(map[rcp[4]]&(DIGIT|LETTER))) { |
cp = rcp + 4; |
return BREAK; |
} |
goto id; |
case 'c': |
if (rcp[0] == 'a' |
&& rcp[1] == 's' |
&& rcp[2] == 'e' |
&& !(map[rcp[3]]&(DIGIT|LETTER))) { |
cp = rcp + 3; |
return CASE; |
} |
if (rcp[0] == 'h' |
&& rcp[1] == 'a' |
&& rcp[2] == 'r' |
&& !(map[rcp[3]]&(DIGIT|LETTER))) { |
cp = rcp + 3; |
tsym = chartype->u.sym; |
return CHAR; |
} |
if (rcp[0] == 'o' |
&& rcp[1] == 'n' |
&& rcp[2] == 's' |
&& rcp[3] == 't' |
&& !(map[rcp[4]]&(DIGIT|LETTER))) { |
cp = rcp + 4; |
return CONST; |
} |
if (rcp[0] == 'o' |
&& rcp[1] == 'n' |
&& rcp[2] == 't' |
&& rcp[3] == 'i' |
&& rcp[4] == 'n' |
&& rcp[5] == 'u' |
&& rcp[6] == 'e' |
&& !(map[rcp[7]]&(DIGIT|LETTER))) { |
cp = rcp + 7; |
return CONTINUE; |
} |
goto id; |
case 'd': |
if (rcp[0] == 'e' |
&& rcp[1] == 'f' |
&& rcp[2] == 'a' |
&& rcp[3] == 'u' |
&& rcp[4] == 'l' |
&& rcp[5] == 't' |
&& !(map[rcp[6]]&(DIGIT|LETTER))) { |
cp = rcp + 6; |
return DEFAULT; |
} |
if (rcp[0] == 'o' |
&& rcp[1] == 'u' |
&& rcp[2] == 'b' |
&& rcp[3] == 'l' |
&& rcp[4] == 'e' |
&& !(map[rcp[5]]&(DIGIT|LETTER))) { |
cp = rcp + 5; |
tsym = doubletype->u.sym; |
return DOUBLE; |
} |
if (rcp[0] == 'o' |
&& !(map[rcp[1]]&(DIGIT|LETTER))) { |
cp = rcp + 1; |
return DO; |
} |
goto id; |
case 'e': |
if (rcp[0] == 'l' |
&& rcp[1] == 's' |
&& rcp[2] == 'e' |
&& !(map[rcp[3]]&(DIGIT|LETTER))) { |
cp = rcp + 3; |
return ELSE; |
} |
if (rcp[0] == 'n' |
&& rcp[1] == 'u' |
&& rcp[2] == 'm' |
&& !(map[rcp[3]]&(DIGIT|LETTER))) { |
cp = rcp + 3; |
return ENUM; |
} |
if (rcp[0] == 'x' |
&& rcp[1] == 't' |
&& rcp[2] == 'e' |
&& rcp[3] == 'r' |
&& rcp[4] == 'n' |
&& !(map[rcp[5]]&(DIGIT|LETTER))) { |
cp = rcp + 5; |
return EXTERN; |
} |
goto id; |
case 'f': |
if (rcp[0] == 'l' |
&& rcp[1] == 'o' |
&& rcp[2] == 'a' |
&& rcp[3] == 't' |
&& !(map[rcp[4]]&(DIGIT|LETTER))) { |
cp = rcp + 4; |
tsym = floattype->u.sym; |
return FLOAT; |
} |
if (rcp[0] == 'o' |
&& rcp[1] == 'r' |
&& !(map[rcp[2]]&(DIGIT|LETTER))) { |
cp = rcp + 2; |
return FOR; |
} |
goto id; |
case 'g': |
if (rcp[0] == 'o' |
&& rcp[1] == 't' |
&& rcp[2] == 'o' |
&& !(map[rcp[3]]&(DIGIT|LETTER))) { |
cp = rcp + 3; |
return GOTO; |
} |
goto id; |
case 'l': |
if (rcp[0] == 'o' |
&& rcp[1] == 'n' |
&& rcp[2] == 'g' |
&& !(map[rcp[3]]&(DIGIT|LETTER))) { |
cp = rcp + 3; |
return LONG; |
} |
goto id; |
case 'r': |
if (rcp[0] == 'e' |
&& rcp[1] == 'g' |
&& rcp[2] == 'i' |
&& rcp[3] == 's' |
&& rcp[4] == 't' |
&& rcp[5] == 'e' |
&& rcp[6] == 'r' |
&& !(map[rcp[7]]&(DIGIT|LETTER))) { |
cp = rcp + 7; |
return REGISTER; |
} |
if (rcp[0] == 'e' |
&& rcp[1] == 't' |
&& rcp[2] == 'u' |
&& rcp[3] == 'r' |
&& rcp[4] == 'n' |
&& !(map[rcp[5]]&(DIGIT|LETTER))) { |
cp = rcp + 5; |
return RETURN; |
} |
goto id; |
case 's': |
if (rcp[0] == 'h' |
&& rcp[1] == 'o' |
&& rcp[2] == 'r' |
&& rcp[3] == 't' |
&& !(map[rcp[4]]&(DIGIT|LETTER))) { |
cp = rcp + 4; |
return SHORT; |
} |
if (rcp[0] == 'i' |
&& rcp[1] == 'g' |
&& rcp[2] == 'n' |
&& rcp[3] == 'e' |
&& rcp[4] == 'd' |
&& !(map[rcp[5]]&(DIGIT|LETTER))) { |
cp = rcp + 5; |
return SIGNED; |
} |
if (rcp[0] == 'i' |
&& rcp[1] == 'z' |
&& rcp[2] == 'e' |
&& rcp[3] == 'o' |
&& rcp[4] == 'f' |
&& !(map[rcp[5]]&(DIGIT|LETTER))) { |
cp = rcp + 5; |
return SIZEOF; |
} |
if (rcp[0] == 't' |
&& rcp[1] == 'a' |
&& rcp[2] == 't' |
&& rcp[3] == 'i' |
&& rcp[4] == 'c' |
&& !(map[rcp[5]]&(DIGIT|LETTER))) { |
cp = rcp + 5; |
return STATIC; |
} |
if (rcp[0] == 't' |
&& rcp[1] == 'r' |
&& rcp[2] == 'u' |
&& rcp[3] == 'c' |
&& rcp[4] == 't' |
&& !(map[rcp[5]]&(DIGIT|LETTER))) { |
cp = rcp + 5; |
return STRUCT; |
} |
if (rcp[0] == 'w' |
&& rcp[1] == 'i' |
&& rcp[2] == 't' |
&& rcp[3] == 'c' |
&& rcp[4] == 'h' |
&& !(map[rcp[5]]&(DIGIT|LETTER))) { |
cp = rcp + 5; |
return SWITCH; |
} |
goto id; |
case 't': |
if (rcp[0] == 'y' |
&& rcp[1] == 'p' |
&& rcp[2] == 'e' |
&& rcp[3] == 'd' |
&& rcp[4] == 'e' |
&& rcp[5] == 'f' |
&& !(map[rcp[6]]&(DIGIT|LETTER))) { |
cp = rcp + 6; |
return TYPEDEF; |
} |
goto id; |
case 'u': |
if (rcp[0] == 'n' |
&& rcp[1] == 'i' |
&& rcp[2] == 'o' |
&& rcp[3] == 'n' |
&& !(map[rcp[4]]&(DIGIT|LETTER))) { |
cp = rcp + 4; |
return UNION; |
} |
if (rcp[0] == 'n' |
&& rcp[1] == 's' |
&& rcp[2] == 'i' |
&& rcp[3] == 'g' |
&& rcp[4] == 'n' |
&& rcp[5] == 'e' |
&& rcp[6] == 'd' |
&& !(map[rcp[7]]&(DIGIT|LETTER))) { |
cp = rcp + 7; |
return UNSIGNED; |
} |
goto id; |
case 'v': |
if (rcp[0] == 'o' |
&& rcp[1] == 'i' |
&& rcp[2] == 'd' |
&& !(map[rcp[3]]&(DIGIT|LETTER))) { |
cp = rcp + 3; |
tsym = voidtype->u.sym; |
return VOID; |
} |
if (rcp[0] == 'o' |
&& rcp[1] == 'l' |
&& rcp[2] == 'a' |
&& rcp[3] == 't' |
&& rcp[4] == 'i' |
&& rcp[5] == 'l' |
&& rcp[6] == 'e' |
&& !(map[rcp[7]]&(DIGIT|LETTER))) { |
cp = rcp + 7; |
return VOLATILE; |
} |
goto id; |
case 'w': |
if (rcp[0] == 'h' |
&& rcp[1] == 'i' |
&& rcp[2] == 'l' |
&& rcp[3] == 'e' |
&& !(map[rcp[4]]&(DIGIT|LETTER))) { |
cp = rcp + 4; |
return WHILE; |
} |
goto id; |
case '_': |
if (rcp[0] == '_' |
&& rcp[1] == 't' |
&& rcp[2] == 'y' |
&& rcp[3] == 'p' |
&& rcp[4] == 'e' |
&& rcp[5] == 'c' |
&& rcp[6] == 'o' |
&& rcp[7] == 'd' |
&& rcp[8] == 'e' |
&& !(map[rcp[9]]&(DIGIT|LETTER))) { |
cp = rcp + 9; |
return TYPECODE; |
} |
if (rcp[0] == '_' |
&& rcp[1] == 'f' |
&& rcp[2] == 'i' |
&& rcp[3] == 'r' |
&& rcp[4] == 's' |
&& rcp[5] == 't' |
&& rcp[6] == 'a' |
&& rcp[7] == 'r' |
&& rcp[8] == 'g' |
&& !(map[rcp[9]]&(DIGIT|LETTER))) { |
cp = rcp + 9; |
return FIRSTARG; |
} |
goto id; |
default: |
if ((map[cp[-1]]&BLANK) == 0) |
if (cp[-1] < ' ' || cp[-1] >= 0177) |
error("illegal character `\\0%o'\n", cp[-1]); |
else |
error("illegal character `%c'\n", cp[-1]); |
} |
} |
} |
static Symbol icon(unsigned long n, int overflow, int base) { |
if ((*cp=='u'||*cp=='U') && (cp[1]=='l'||cp[1]=='L') |
|| (*cp=='l'||*cp=='L') && (cp[1]=='u'||cp[1]=='U')) { |
tval.type = unsignedlong; |
cp += 2; |
} else if (*cp == 'u' || *cp == 'U') { |
if (overflow || n > unsignedtype->u.sym->u.limits.max.i) |
tval.type = unsignedlong; |
else |
tval.type = unsignedtype; |
cp += 1; |
} else if (*cp == 'l' || *cp == 'L') { |
if (overflow || n > longtype->u.sym->u.limits.max.i) |
tval.type = unsignedlong; |
else |
tval.type = longtype; |
cp += 1; |
} else if (overflow || n > longtype->u.sym->u.limits.max.i) |
tval.type = unsignedlong; |
else if (n > inttype->u.sym->u.limits.max.i) |
tval.type = longtype; |
else if (base != 10 && n > inttype->u.sym->u.limits.max.i) |
tval.type = unsignedtype; |
else |
tval.type = inttype; |
switch (tval.type->op) { |
case INT: |
if (overflow || n > tval.type->u.sym->u.limits.max.i) { |
warning("overflow in constant `%S'\n", token, |
(char*)cp - token); |
tval.u.c.v.i = tval.type->u.sym->u.limits.max.i; |
} else |
tval.u.c.v.i = n; |
break; |
case UNSIGNED: |
if (overflow || n > tval.type->u.sym->u.limits.max.u) { |
warning("overflow in constant `%S'\n", token, |
(char*)cp - token); |
tval.u.c.v.u = tval.type->u.sym->u.limits.max.u; |
} else |
tval.u.c.v.u = n; |
break; |
default: assert(0); |
} |
ppnumber("integer"); |
return &tval; |
} |
static void ppnumber(char *which) { |
unsigned char *rcp = cp--; |
|
for ( ; (map[*cp]&(DIGIT|LETTER)) || *cp == '.'; cp++) |
if ((cp[0] == 'E' || cp[0] == 'e') |
&& (cp[1] == '-' || cp[1] == '+')) |
cp++; |
if (cp > rcp) |
error("`%S' is a preprocessing number but an invalid %s constant\n", token, |
|
(char*)cp-token, which); |
} |
static Symbol fcon(void) { |
if (*cp == '.') |
do |
cp++; |
while (map[*cp]&DIGIT); |
if (*cp == 'e' || *cp == 'E') { |
if (*++cp == '-' || *cp == '+') |
cp++; |
if (map[*cp]&DIGIT) |
do |
cp++; |
while (map[*cp]&DIGIT); |
else |
error("invalid floating constant `%S'\n", token, |
(char*)cp - token); |
} |
|
errno = 0; |
tval.u.c.v.d = strtod(token, NULL); |
if (errno == ERANGE) |
warning("overflow in floating constant `%S'\n", token, |
(char*)cp - token); |
if (*cp == 'f' || *cp == 'F') { |
++cp; |
if (tval.u.c.v.d > floattype->u.sym->u.limits.max.d) |
warning("overflow in floating constant `%S'\n", token, |
(char*)cp - token); |
tval.type = floattype; |
} else if (*cp == 'l' || *cp == 'L') { |
cp++; |
tval.type = longdouble; |
} else { |
if (tval.u.c.v.d > doubletype->u.sym->u.limits.max.d) |
warning("overflow in floating constant `%S'\n", token, |
(char*)cp - token); |
tval.type = doubletype; |
} |
ppnumber("floating"); |
return &tval; |
} |
|
static void *cput(int c, void *cl) { |
char *s = cl; |
|
if (c < 0 || c > 255) |
warning("overflow in escape sequence with resulting value `%d'\n", c); |
*s++ = c; |
return s; |
} |
|
static void *wcput(int c, void *cl) { |
unsigned int *s = cl; |
|
*s++ = c; |
return s; |
} |
|
static void *scon(int q, void *put(int c, void *cl), void *cl) { |
int n = 0, nbad = 0; |
|
do { |
cp++; |
while (*cp != q) { |
int c; |
if (map[*cp]&NEWLINE) { |
if (cp < limit) |
break; |
cp++; |
nextline(); |
if (cp == limit) |
break; |
continue; |
} |
c = *cp++; |
if (c == '\\') { |
if (map[*cp]&NEWLINE) { |
if (cp++ < limit) |
continue; |
nextline(); |
} |
if (limit - cp < MAXTOKEN) |
fillbuf(); |
c = backslash(q); |
} else if (c < 0 || c > 255 || map[c] == 0) |
nbad++; |
if (n++ < BUFSIZE) |
cl = put(c, cl); |
} |
if (*cp == q) |
cp++; |
else |
error("missing %c\n", q); |
if (q == '"' && put == wcput && getchr() == 'L') { |
if (limit - cp < 2) |
fillbuf(); |
if (cp[1] == '"') |
cp++; |
} |
} while (q == '"' && getchr() == '"'); |
cl = put(0, cl); |
if (n >= BUFSIZE) |
error("%s literal too long\n", q == '"' ? "string" : "character"); |
if (Aflag >= 2 && q == '"' && n > 509) |
warning("more than 509 characters in a string literal\n"); |
if (Aflag >= 2 && nbad > 0) |
warning("%s literal contains non-portable characters\n", |
q == '"' ? "string" : "character"); |
return cl; |
} |
int getchr(void) { |
for (;;) { |
while (map[*cp]&BLANK) |
cp++; |
if (!(map[*cp]&NEWLINE)) |
return *cp; |
cp++; |
nextline(); |
if (cp == limit) |
return EOI; |
} |
} |
static int backslash(int q) { |
unsigned int c; |
|
switch (*cp++) { |
case 'a': return 7; |
case 'b': return '\b'; |
case 'f': return '\f'; |
case 'n': return '\n'; |
case 'r': return '\r'; |
case 't': return '\t'; |
case 'v': return '\v'; |
case '\'': case '"': case '\\': case '\?': break; |
case 'x': { |
int overflow = 0; |
if ((map[*cp]&(DIGIT|HEX)) == 0) { |
if (*cp < ' ' || *cp == 0177) |
error("ill-formed hexadecimal escape sequence\n"); |
else |
error("ill-formed hexadecimal escape sequence `\\x%c'\n", *cp); |
if (*cp != q) |
cp++; |
return 0; |
} |
for (c = 0; map[*cp]&(DIGIT|HEX); cp++) { |
if (c >> (8*widechar->size - 4)) |
overflow = 1; |
if (map[*cp]&DIGIT) |
c = (c<<4) + *cp - '0'; |
else |
c = (c<<4) + (*cp&~040) - 'A' + 10; |
} |
if (overflow) |
warning("overflow in hexadecimal escape sequence\n"); |
return c&ones(8*widechar->size); |
} |
case '0': case '1': case '2': case '3': |
case '4': case '5': case '6': case '7': |
c = *(cp-1) - '0'; |
if (*cp >= '0' && *cp <= '7') { |
c = (c<<3) + *cp++ - '0'; |
if (*cp >= '0' && *cp <= '7') |
c = (c<<3) + *cp++ - '0'; |
} |
return c; |
default: |
if (cp[-1] < ' ' || cp[-1] >= 0177) |
warning("unrecognized character escape sequence\n"); |
else |
warning("unrecognized character escape sequence `\\%c'\n", cp[-1]); |
} |
return cp[-1]; |
} |
/stmt.c
0,0 → 1,708
#include "c.h" |
|
static char rcsid[] = "$Id: stmt.c,v 1.1 2002/08/28 23:12:46 drh Exp $"; |
|
#define SWSIZE 512 |
|
#define den(i,j) ((j-buckets[i]+1.0)/(v[j]-v[buckets[i]]+1)) |
|
struct code codehead = { Start }; |
Code codelist = &codehead; |
float density = 0.5; |
Table stmtlabs; |
|
static int foldcond(Tree e1, Tree e2); |
static void caselabel(Swtch, long, int); |
static void cmp(int, Symbol, long, int); |
static Tree conditional(int); |
static void dostmt(int, Swtch, int); |
static int equal(Symbol, Symbol); |
static void forstmt(int, Swtch, int); |
static void ifstmt(int, int, Swtch, int); |
static Symbol localaddr(Tree); |
static void stmtlabel(void); |
static void swstmt(int, int, int); |
static void whilestmt(int, Swtch, int); |
Code code(int kind) { |
Code cp; |
|
if (!reachable(kind)) |
warning("unreachable code\n"); |
|
NEW(cp, FUNC); |
cp->kind = kind; |
cp->prev = codelist; |
cp->next = NULL; |
codelist->next = cp; |
codelist = cp; |
return cp; |
} |
int reachable(int kind) { |
Code cp; |
|
if (kind > Start) { |
Code cp; |
for (cp = codelist; cp->kind < Label; ) |
cp = cp->prev; |
if (cp->kind == Jump || cp->kind == Switch) |
return 0; |
} |
return 1; |
} |
void addlocal(Symbol p) { |
if (!p->defined) { |
code(Local)->u.var = p; |
p->defined = 1; |
p->scope = level; |
} |
} |
void definept(Coordinate *p) { |
Code cp = code(Defpoint); |
|
cp->u.point.src = p ? *p : src; |
cp->u.point.point = npoints; |
if (ncalled > 0) { |
int n = findcount(cp->u.point.src.file, |
cp->u.point.src.x, cp->u.point.src.y); |
if (n > 0) |
refinc = (float)n/ncalled; |
} |
if (glevel > 2) locus(identifiers, &cp->u.point.src); |
if (events.points && reachable(Gen)) |
{ |
Tree e = NULL; |
apply(events.points, &cp->u.point.src, &e); |
if (e) |
listnodes(e, 0, 0); |
} |
} |
void statement(int loop, Swtch swp, int lev) { |
float ref = refinc; |
|
if (Aflag >= 2 && lev == 15) |
warning("more than 15 levels of nested statements\n"); |
switch (t) { |
case IF: ifstmt(genlabel(2), loop, swp, lev + 1); |
break; |
case WHILE: whilestmt(genlabel(3), swp, lev + 1); break; |
case DO: dostmt(genlabel(3), swp, lev + 1); expect(';'); |
break; |
|
case FOR: forstmt(genlabel(4), swp, lev + 1); |
break; |
case BREAK: walk(NULL, 0, 0); |
definept(NULL); |
if (swp && swp->lab > loop) |
branch(swp->lab + 1); |
else if (loop) |
branch(loop + 2); |
else |
error("illegal break statement\n"); |
t = gettok(); expect(';'); |
break; |
|
case CONTINUE: walk(NULL, 0, 0); |
definept(NULL); |
if (loop) |
branch(loop + 1); |
else |
error("illegal continue statement\n"); |
t = gettok(); expect(';'); |
break; |
|
case SWITCH: swstmt(loop, genlabel(2), lev + 1); |
break; |
case CASE: { |
int lab = genlabel(1); |
if (swp == NULL) |
error("illegal case label\n"); |
definelab(lab); |
while (t == CASE) { |
static char stop[] = { IF, ID, 0 }; |
Tree p; |
t = gettok(); |
p = constexpr(0); |
if (generic(p->op) == CNST && isint(p->type)) { |
if (swp) { |
needconst++; |
p = cast(p, swp->sym->type); |
if (p->type->op == UNSIGNED) |
p->u.v.i = extend(p->u.v.u, p->type); |
needconst--; |
caselabel(swp, p->u.v.i, lab); |
} |
} else |
error("case label must be a constant integer expression\n"); |
|
test(':', stop); |
} |
statement(loop, swp, lev); |
} break; |
case DEFAULT: if (swp == NULL) |
error("illegal default label\n"); |
else if (swp->deflab) |
error("extra default label\n"); |
else { |
swp->deflab = findlabel(swp->lab); |
definelab(swp->deflab->u.l.label); |
} |
t = gettok(); |
expect(':'); |
statement(loop, swp, lev); break; |
case RETURN: { |
Type rty = freturn(cfunc->type); |
t = gettok(); |
definept(NULL); |
if (t != ';') |
if (rty == voidtype) { |
error("extraneous return value\n"); |
expr(0); |
retcode(NULL); |
} else |
retcode(expr(0)); |
else { |
if (rty != voidtype) { |
warning("missing return value\n"); |
retcode(cnsttree(inttype, 0L)); |
} else |
retcode(NULL); |
} |
branch(cfunc->u.f.label); |
} expect(';'); |
break; |
|
case '{': compound(loop, swp, lev + 1); break; |
case ';': definept(NULL); t = gettok(); break; |
case GOTO: walk(NULL, 0, 0); |
definept(NULL); |
t = gettok(); |
if (t == ID) { |
Symbol p = lookup(token, stmtlabs); |
if (p == NULL) { |
p = install(token, &stmtlabs, 0, FUNC); |
p->scope = LABELS; |
p->u.l.label = genlabel(1); |
p->src = src; |
} |
use(p, src); |
branch(p->u.l.label); |
t = gettok(); |
} else |
error("missing label in goto\n"); expect(';'); |
break; |
|
case ID: if (getchr() == ':') { |
stmtlabel(); |
statement(loop, swp, lev); |
break; |
} |
default: definept(NULL); |
if (kind[t] != ID) { |
error("unrecognized statement\n"); |
t = gettok(); |
} else { |
Tree e = expr0(0); |
listnodes(e, 0, 0); |
if (nodecount == 0 || nodecount > 200) |
walk(NULL, 0, 0); |
else if (glevel) walk(NULL, 0, 0); |
deallocate(STMT); |
} expect(';'); |
break; |
|
} |
if (kind[t] != IF && kind[t] != ID |
&& t != '}' && t != EOI) { |
static char stop[] = { IF, ID, '}', 0 }; |
error("illegal statement termination\n"); |
skipto(0, stop); |
} |
refinc = ref; |
} |
|
static void ifstmt(int lab, int loop, Swtch swp, int lev) { |
t = gettok(); |
expect('('); |
definept(NULL); |
walk(conditional(')'), 0, lab); |
refinc /= 2.0; |
statement(loop, swp, lev); |
if (t == ELSE) { |
branch(lab + 1); |
t = gettok(); |
definelab(lab); |
statement(loop, swp, lev); |
if (findlabel(lab + 1)->ref) |
definelab(lab + 1); |
} else |
definelab(lab); |
} |
static Tree conditional(int tok) { |
Tree p = expr(tok); |
|
if (Aflag > 1 && isfunc(p->type)) |
warning("%s used in a conditional expression\n", |
funcname(p)); |
return cond(p); |
} |
static void stmtlabel(void) { |
Symbol p = lookup(token, stmtlabs); |
|
if (p == NULL) { |
p = install(token, &stmtlabs, 0, FUNC); |
p->scope = LABELS; |
p->u.l.label = genlabel(1); |
p->src = src; |
} |
if (p->defined) |
error("redefinition of label `%s' previously defined at %w\n", p->name, &p->src); |
|
p->defined = 1; |
definelab(p->u.l.label); |
t = gettok(); |
expect(':'); |
} |
static void forstmt(int lab, Swtch swp, int lev) { |
int once = 0; |
Tree e1 = NULL, e2 = NULL, e3 = NULL; |
Coordinate pt2, pt3; |
|
t = gettok(); |
expect('('); |
definept(NULL); |
if (kind[t] == ID) |
e1 = texpr(expr0, ';', FUNC); |
else |
expect(';'); |
walk(e1, 0, 0); |
pt2 = src; |
refinc *= 10.0; |
if (kind[t] == ID) |
e2 = texpr(conditional, ';', FUNC); |
else |
expect(';'); |
pt3 = src; |
if (kind[t] == ID) |
e3 = texpr(expr0, ')', FUNC); |
else { |
static char stop[] = { IF, ID, '}', 0 }; |
test(')', stop); |
} |
if (e2) { |
once = foldcond(e1, e2); |
if (!once) |
branch(lab + 3); |
} |
definelab(lab); |
statement(lab, swp, lev); |
definelab(lab + 1); |
definept(&pt3); |
if (e3) |
walk(e3, 0, 0); |
if (e2) { |
if (!once) |
definelab(lab + 3); |
definept(&pt2); |
walk(e2, lab, 0); |
} else { |
definept(&pt2); |
branch(lab); |
} |
if (findlabel(lab + 2)->ref) |
definelab(lab + 2); |
} |
static void swstmt(int loop, int lab, int lev) { |
Tree e; |
struct swtch sw; |
Code head, tail; |
|
t = gettok(); |
expect('('); |
definept(NULL); |
e = expr(')'); |
if (!isint(e->type)) { |
error("illegal type `%t' in switch expression\n", |
e->type); |
e = retype(e, inttype); |
} |
e = cast(e, promote(e->type)); |
if (generic(e->op) == INDIR && isaddrop(e->kids[0]->op) |
&& e->kids[0]->u.sym->type == e->type |
&& !isvolatile(e->kids[0]->u.sym->type)) { |
sw.sym = e->kids[0]->u.sym; |
walk(NULL, 0, 0); |
} else { |
sw.sym = genident(REGISTER, e->type, level); |
addlocal(sw.sym); |
walk(asgn(sw.sym, e), 0, 0); |
} |
head = code(Switch); |
sw.lab = lab; |
sw.deflab = NULL; |
sw.ncases = 0; |
sw.size = SWSIZE; |
sw.values = newarray(SWSIZE, sizeof *sw.values, FUNC); |
sw.labels = newarray(SWSIZE, sizeof *sw.labels, FUNC); |
refinc /= 10.0; |
statement(loop, &sw, lev); |
if (sw.deflab == NULL) { |
sw.deflab = findlabel(lab); |
definelab(lab); |
if (sw.ncases == 0) |
warning("switch statement with no cases\n"); |
} |
if (findlabel(lab + 1)->ref) |
definelab(lab + 1); |
tail = codelist; |
codelist = head->prev; |
codelist->next = head->prev = NULL; |
if (sw.ncases > 0) |
swgen(&sw); |
branch(lab); |
head->next->prev = codelist; |
codelist->next = head->next; |
codelist = tail; |
} |
static void caselabel(Swtch swp, long val, int lab) { |
int k; |
|
if (swp->ncases >= swp->size) |
{ |
long *vals = swp->values; |
Symbol *labs = swp->labels; |
swp->size *= 2; |
swp->values = newarray(swp->size, sizeof *swp->values, FUNC); |
swp->labels = newarray(swp->size, sizeof *swp->labels, FUNC); |
for (k = 0; k < swp->ncases; k++) { |
swp->values[k] = vals[k]; |
swp->labels[k] = labs[k]; |
} |
} |
k = swp->ncases; |
for ( ; k > 0 && swp->values[k-1] >= val; k--) { |
swp->values[k] = swp->values[k-1]; |
swp->labels[k] = swp->labels[k-1]; |
} |
if (k < swp->ncases && swp->values[k] == val) |
error("duplicate case label `%d'\n", val); |
swp->values[k] = val; |
swp->labels[k] = findlabel(lab); |
++swp->ncases; |
if (Aflag >= 2 && swp->ncases == 258) |
warning("more than 257 cases in a switch\n"); |
} |
void swgen(Swtch swp) { |
int *buckets, k, n; |
long *v = swp->values; |
|
buckets = newarray(swp->ncases + 1, |
sizeof *buckets, FUNC); |
for (n = k = 0; k < swp->ncases; k++, n++) { |
buckets[n] = k; |
while (n > 0 && den(n-1, k) >= density) |
n--; |
} |
buckets[n] = swp->ncases; |
swcode(swp, buckets, 0, n - 1); |
} |
void swcode(Swtch swp, int b[], int lb, int ub) { |
int hilab, lolab, l, u, k = (lb + ub)/2; |
long *v = swp->values; |
|
if (k > lb && k < ub) { |
lolab = genlabel(1); |
hilab = genlabel(1); |
} else if (k > lb) { |
lolab = genlabel(1); |
hilab = swp->deflab->u.l.label; |
} else if (k < ub) { |
lolab = swp->deflab->u.l.label; |
hilab = genlabel(1); |
} else |
lolab = hilab = swp->deflab->u.l.label; |
l = b[k]; |
u = b[k+1] - 1; |
if (u - l + 1 <= 3) |
{ |
int i; |
for (i = l; i <= u; i++) |
cmp(EQ, swp->sym, v[i], swp->labels[i]->u.l.label); |
if (k > lb && k < ub) |
cmp(GT, swp->sym, v[u], hilab); |
else if (k > lb) |
cmp(GT, swp->sym, v[u], hilab); |
else if (k < ub) |
cmp(LT, swp->sym, v[l], lolab); |
else |
assert(lolab == hilab), |
branch(lolab); |
walk(NULL, 0, 0); |
} |
else { |
Tree e; |
Type ty = signedint(swp->sym->type); |
Symbol table = genident(STATIC, |
array(voidptype, u - l + 1, 0), GLOBAL); |
(*IR->defsymbol)(table); |
if (!isunsigned(swp->sym->type) || v[l] != 0) |
cmp(LT, swp->sym, v[l], lolab); |
cmp(GT, swp->sym, v[u], hilab); |
e = (*optree['-'])(SUB, cast(idtree(swp->sym), ty), cnsttree(ty, v[l])); |
if (e->type->size < unsignedptr->size) |
e = cast(e, unsignedlong); |
walk(tree(JUMP, voidtype, |
rvalue((*optree['+'])(ADD, pointer(idtree(table)), e)), NULL), |
0, 0); |
code(Switch); |
codelist->u.swtch.table = table; |
codelist->u.swtch.sym = swp->sym; |
codelist->u.swtch.deflab = swp->deflab; |
codelist->u.swtch.size = u - l + 1; |
codelist->u.swtch.values = &v[l]; |
codelist->u.swtch.labels = &swp->labels[l]; |
if (v[u] - v[l] + 1 >= 10000) |
warning("switch generates a huge table\n"); |
} |
if (k > lb) { |
assert(lolab != swp->deflab->u.l.label); |
definelab(lolab); |
swcode(swp, b, lb, k - 1); |
} |
if (k < ub) { |
assert(hilab != swp->deflab->u.l.label); |
definelab(hilab); |
swcode(swp, b, k + 1, ub); |
} |
} |
static void cmp(int op, Symbol p, long n, int lab) { |
Type ty = signedint(p->type); |
|
listnodes(eqtree(op, |
cast(idtree(p), ty), |
cnsttree(ty, n)), |
lab, 0); |
} |
void retcode(Tree p) { |
Type ty; |
|
if (p == NULL) { |
if (events.returns) |
apply(events.returns, cfunc, NULL); |
return; |
} |
p = pointer(p); |
ty = assign(freturn(cfunc->type), p); |
if (ty == NULL) { |
error("illegal return type; found `%t' expected `%t'\n", |
p->type, freturn(cfunc->type)); |
return; |
} |
p = cast(p, ty); |
if (retv) |
{ |
if (iscallb(p)) |
p = tree(RIGHT, p->type, |
tree(CALL+B, p->type, |
p->kids[0]->kids[0], idtree(retv)), |
rvalue(idtree(retv))); |
else { |
Type ty = retv->type->type; |
assert(isstruct(ty)); |
if (ty->u.sym->u.s.cfields) { |
ty->u.sym->u.s.cfields = 0; |
p = asgntree(ASGN, rvalue(idtree(retv)), p); |
ty->u.sym->u.s.cfields = 1; |
} else |
p = asgntree(ASGN, rvalue(idtree(retv)), p); |
} |
walk(p, 0, 0); |
if (events.returns) |
apply(events.returns, cfunc, rvalue(idtree(retv))); |
return; |
} |
if (events.returns) |
{ |
Symbol t1 = genident(AUTO, p->type, level); |
addlocal(t1); |
walk(asgn(t1, p), 0, 0); |
apply(events.returns, cfunc, idtree(t1)); |
p = idtree(t1); |
} |
if (!isfloat(p->type)) |
p = cast(p, promote(p->type)); |
if (isptr(p->type)) |
{ |
Symbol q = localaddr(p); |
if (q && (q->computed || q->generated)) |
warning("pointer to a %s is an illegal return value\n", |
q->scope == PARAM ? "parameter" : "local"); |
else if (q) |
warning("pointer to %s `%s' is an illegal return value\n", |
q->scope == PARAM ? "parameter" : "local", q->name); |
} |
walk(tree(mkop(RET,p->type), p->type, p, NULL), 0, 0); |
} |
void definelab(int lab) { |
Code cp; |
Symbol p = findlabel(lab); |
|
assert(lab); |
walk(NULL, 0, 0); |
code(Label)->u.forest = newnode(LABEL+V, NULL, NULL, p); |
for (cp = codelist->prev; cp->kind <= Label; ) |
cp = cp->prev; |
while ( cp->kind == Jump |
&& cp->u.forest->kids[0] |
&& specific(cp->u.forest->kids[0]->op) == ADDRG+P |
&& cp->u.forest->kids[0]->syms[0] == p) { |
assert(cp->u.forest->kids[0]->syms[0]->u.l.label == lab); |
p->ref--; |
assert(cp->next); |
assert(cp->prev); |
cp->prev->next = cp->next; |
cp->next->prev = cp->prev; |
cp = cp->prev; |
while (cp->kind <= Label) |
cp = cp->prev; |
} |
} |
Node jump(int lab) { |
Symbol p = findlabel(lab); |
|
p->ref++; |
return newnode(JUMP+V, newnode(ADDRG+ttob(voidptype), NULL, NULL, p), |
NULL, NULL); |
} |
void branch(int lab) { |
Code cp; |
Symbol p = findlabel(lab); |
|
assert(lab); |
walk(NULL, 0, 0); |
code(Label)->u.forest = jump(lab); |
for (cp = codelist->prev; cp->kind < Label; ) |
cp = cp->prev; |
while ( cp->kind == Label |
&& cp->u.forest->op == LABEL+V |
&& !equal(cp->u.forest->syms[0], p)) { |
equatelab(cp->u.forest->syms[0], p); |
assert(cp->next); |
assert(cp->prev); |
cp->prev->next = cp->next; |
cp->next->prev = cp->prev; |
cp = cp->prev; |
while (cp->kind < Label) |
cp = cp->prev; |
} |
if (cp->kind == Jump || cp->kind == Switch) { |
p->ref--; |
codelist->prev->next = NULL; |
codelist = codelist->prev; |
} else { |
codelist->kind = Jump; |
if (cp->kind == Label |
&& cp->u.forest->op == LABEL+V |
&& equal(cp->u.forest->syms[0], p)) |
warning("source code specifies an infinite loop\n"); |
} |
} |
void equatelab(Symbol old, Symbol new) { |
assert(old->u.l.equatedto == NULL); |
old->u.l.equatedto = new; |
new->ref++; |
} |
static int equal(Symbol lprime, Symbol dst) { |
assert(dst && lprime); |
for ( ; dst; dst = dst->u.l.equatedto) |
if (lprime == dst) |
return 1; |
return 0; |
} |
/* dostmt - do statement while ( expression ) */ |
static void dostmt(int lab, Swtch swp, int lev) { |
refinc *= 10.0; |
t = gettok(); |
definelab(lab); |
statement(lab, swp, lev); |
definelab(lab + 1); |
expect(WHILE); |
expect('('); |
definept(NULL); |
walk(conditional(')'), lab, 0); |
if (findlabel(lab + 2)->ref) |
definelab(lab + 2); |
} |
|
/* foldcond - check if initial test in for(e1;e2;e3) S is necessary */ |
static int foldcond(Tree e1, Tree e2) { |
int op = generic(e2->op); |
Symbol v; |
|
if (e1 == 0 || e2 == 0) |
return 0; |
if (generic(e1->op) == ASGN && isaddrop(e1->kids[0]->op) |
&& generic(e1->kids[1]->op) == CNST) { |
v = e1->kids[0]->u.sym; |
e1 = e1->kids[1]; |
} else |
return 0; |
if ((op==LE || op==LT || op==EQ || op==NE || op==GT || op==GE) |
&& generic(e2->kids[0]->op) == INDIR |
&& e2->kids[0]->kids[0]->u.sym == v |
&& e2->kids[1]->op == e1->op) { |
e1 = simplify(op, e2->type, e1, e2->kids[1]); |
if (e1->op == CNST+I) |
return e1->u.v.i; |
} |
return 0; |
} |
|
/* localaddr - returns q if p yields the address of local/parameter q; otherwise returns 0 */ |
static Symbol localaddr(Tree p) { |
if (p == NULL) |
return NULL; |
switch (generic(p->op)) { |
case INDIR: case CALL: case ARG: |
return NULL; |
case ADDRL: case ADDRF: |
return p->u.sym; |
case RIGHT: case ASGN: |
if (p->kids[1]) |
return localaddr(p->kids[1]); |
return localaddr(p->kids[0]); |
case COND: { |
Symbol q; |
assert(p->kids[1] && p->kids[1]->op == RIGHT); |
if ((q = localaddr(p->kids[1]->kids[0])) != NULL) |
return q; |
return localaddr(p->kids[1]->kids[1]); |
} |
default: { |
Symbol q; |
if (p->kids[0] && (q = localaddr(p->kids[0])) != NULL) |
return q; |
return localaddr(p->kids[1]); |
} |
} |
} |
|
/* whilestmt - while ( expression ) statement */ |
static void whilestmt(int lab, Swtch swp, int lev) { |
Coordinate pt; |
Tree e; |
|
refinc *= 10.0; |
t = gettok(); |
expect('('); |
walk(NULL, 0, 0); |
pt = src; |
e = texpr(conditional, ')', FUNC); |
branch(lab + 1); |
definelab(lab); |
statement(lab, swp, lev); |
definelab(lab + 1); |
definept(&pt); |
walk(e, lab, 0); |
if (findlabel(lab + 2)->ref) |
definelab(lab + 2); |
} |
/error.c
0,0 → 1,138
#include "c.h" |
|
static char rcsid[] = "$Id: error.c,v 1.1 2002/08/28 23:12:43 drh Exp $"; |
|
static void printtoken(void); |
int errcnt = 0; |
int errlimit = 20; |
char kind[] = { |
#define xx(a,b,c,d,e,f,g) f, |
#define yy(a,b,c,d,e,f,g) f, |
#include "token.h" |
}; |
int wflag; /* != 0 to suppress warning messages */ |
|
void test(int tok, char set[]) { |
if (t == tok) |
t = gettok(); |
else { |
expect(tok); |
skipto(tok, set); |
if (t == tok) |
t = gettok(); |
} |
} |
void expect(int tok) { |
if (t == tok) |
t = gettok(); |
else { |
error("syntax error; found"); |
printtoken(); |
fprint(stderr, " expecting `%k'\n", tok); |
} |
} |
void error(const char *fmt, ...) { |
va_list ap; |
|
if (errcnt++ >= errlimit) { |
errcnt = -1; |
error("too many errors\n"); |
exit(1); |
} |
va_start(ap, fmt); |
if (firstfile != file && firstfile && *firstfile) |
fprint(stderr, "%s: ", firstfile); |
fprint(stderr, "%w: ", &src); |
vfprint(stderr, NULL, fmt, ap); |
va_end(ap); |
} |
|
void skipto(int tok, char set[]) { |
int n; |
char *s; |
|
assert(set); |
for (n = 0; t != EOI && t != tok; t = gettok()) { |
for (s = set; *s && kind[t] != *s; s++) |
; |
if (kind[t] == *s) |
break; |
if (n++ == 0) |
error("skipping"); |
if (n <= 8) |
printtoken(); |
else if (n == 9) |
fprint(stderr, " ..."); |
} |
if (n > 8) { |
fprint(stderr, " up to"); |
printtoken(); |
} |
if (n > 0) |
fprint(stderr, "\n"); |
} |
/* fatal - issue fatal error message and exit */ |
int fatal(const char *name, const char *fmt, int n) { |
print("\n"); |
errcnt = -1; |
error("compiler error in %s--", name); |
fprint(stderr, fmt, n); |
exit(EXIT_FAILURE); |
return 0; |
} |
|
/* printtoken - print current token preceeded by a space */ |
static void printtoken(void) { |
switch (t) { |
case ID: fprint(stderr, " `%s'", token); break; |
case ICON: |
fprint(stderr, " `%s'", vtoa(tsym->type, tsym->u.c.v)); |
break; |
case SCON: { |
int i, n; |
if (ischar(tsym->type->type)) { |
char *s = tsym->u.c.v.p; |
n = tsym->type->size; |
fprint(stderr, " \""); |
for (i = 0; i < 20 && i < n && *s; s++, i++) |
if (*s < ' ' || *s >= 0177) |
fprint(stderr, "\\%o", *s); |
else |
fprint(stderr, "%c", *s); |
} else { /* wchar_t string */ |
unsigned int *s = tsym->u.c.v.p; |
assert(tsym->type->type->size == widechar->size); |
n = tsym->type->size/widechar->size; |
fprint(stderr, " L\""); |
for (i = 0; i < 20 && i < n && *s; s++, i++) |
if (*s < ' ' || *s >= 0177) |
fprint(stderr, "\\x%x", *s); |
else |
fprint(stderr, "%c", *s); |
} |
if (i < n) |
fprint(stderr, " ..."); |
else |
fprint(stderr, "\""); |
break; |
} |
case FCON: |
fprint(stderr, " `%S'", token, (char*)cp - token); |
break; |
case '`': case '\'': fprint(stderr, " \"%k\"", t); break; |
default: fprint(stderr, " `%k'", t); |
} |
} |
|
/* warning - issue warning error message */ |
void warning(const char *fmt, ...) { |
va_list ap; |
|
va_start(ap, fmt); |
if (wflag == 0) { |
errcnt--; |
error("warning: "); |
vfprint(stderr, NULL, fmt, ap); |
} |
va_end(ap); |
} |
/enode.c
0,0 → 1,550
#include "c.h" |
|
static char rcsid[] = "$Id: enode.c,v 1.1 2002/08/28 23:12:42 drh Exp $"; |
|
static Tree addtree(int, Tree, Tree); |
static Tree andtree(int, Tree, Tree); |
static Tree cmptree(int, Tree, Tree); |
static int compatible(Type, Type); |
static int isnullptr(Tree e); |
static Tree multree(int, Tree, Tree); |
static Tree subtree(int, Tree, Tree); |
#define isvoidptr(ty) \ |
(isptr(ty) && unqual(ty->type) == voidtype) |
|
Tree (*optree[])(int, Tree, Tree) = { |
#define xx(a,b,c,d,e,f,g) e, |
#define yy(a,b,c,d,e,f,g) e, |
#include "token.h" |
}; |
Tree call(Tree f, Type fty, Coordinate src) { |
int n = 0; |
Tree args = NULL, r = NULL, e; |
Type *proto, rty = unqual(freturn(fty)); |
Symbol t3 = NULL; |
|
if (fty->u.f.oldstyle) |
proto = NULL; |
else |
proto = fty->u.f.proto; |
if (hascall(f)) |
r = f; |
if (isstruct(rty)) |
{ |
t3 = temporary(AUTO, unqual(rty)); |
if (rty->size == 0) |
error("illegal use of incomplete type `%t'\n", rty); |
} |
if (t != ')') |
for (;;) { |
Tree q = pointer(expr1(0)); |
if (proto && *proto && *proto != voidtype) |
{ |
Type aty; |
q = value(q); |
aty = assign(*proto, q); |
if (aty) |
q = cast(q, aty); |
else |
error("type error in argument %d to %s; found `%t' expected `%t'\n", n + 1, funcname(f), |
|
q->type, *proto); |
if ((isint(q->type) || isenum(q->type)) |
&& q->type->size != inttype->size) |
q = cast(q, promote(q->type)); |
++proto; |
} |
else |
{ |
if (!fty->u.f.oldstyle && *proto == NULL) |
error("too many arguments to %s\n", funcname(f)); |
q = value(q); |
if (isarray(q->type) || q->type->size == 0) |
error("type error in argument %d to %s; `%t' is illegal\n", n + 1, funcname(f), q->type); |
|
else |
q = cast(q, promote(q->type)); |
} |
if (!IR->wants_argb && isstruct(q->type)) |
if (iscallb(q)) |
q = addrof(q); |
else { |
Symbol t1 = temporary(AUTO, unqual(q->type)); |
q = asgn(t1, q); |
q = tree(RIGHT, ptr(t1->type), |
root(q), lvalue(idtree(t1))); |
} |
if (q->type->size == 0) |
q->type = inttype; |
if (hascall(q)) |
r = r ? tree(RIGHT, voidtype, r, q) : q; |
args = tree(mkop(ARG, q->type), q->type, q, args); |
n++; |
if (Aflag >= 2 && n == 32) |
warning("more than 31 arguments in a call to %s\n", |
funcname(f)); |
if (t != ',') |
break; |
t = gettok(); |
} |
expect(')'); |
if (proto && *proto && *proto != voidtype) |
error("insufficient number of arguments to %s\n", |
funcname(f)); |
if (r) |
args = tree(RIGHT, voidtype, r, args); |
e = calltree(f, rty, args, t3); |
if (events.calls) |
apply(events.calls, &src, &e); |
return e; |
} |
Tree calltree(Tree f, Type ty, Tree args, Symbol t3) { |
Tree p; |
|
if (args) |
f = tree(RIGHT, f->type, args, f); |
if (isstruct(ty)) |
assert(t3), |
p = tree(RIGHT, ty, |
tree(CALL+B, ty, f, addrof(idtree(t3))), |
idtree(t3)); |
else { |
Type rty = ty; |
if (isenum(ty)) |
rty = unqual(ty)->type; |
if (!isfloat(rty)) |
rty = promote(rty); |
p = tree(mkop(CALL, rty), rty, f, NULL); |
if (isptr(ty) || p->type->size > ty->size) |
p = cast(p, ty); |
} |
return p; |
} |
Tree vcall(Symbol func, Type ty, ...) { |
va_list ap; |
Tree args = NULL, e, f = pointer(idtree(func)), r = NULL; |
|
assert(isfunc(func->type)); |
if (ty == NULL) |
ty = freturn(func->type); |
va_start(ap, ty); |
while ((e = va_arg(ap, Tree)) != NULL) { |
if (hascall(e)) |
r = r == NULL ? e : tree(RIGHT, voidtype, r, e); |
args = tree(mkop(ARG, e->type), e->type, e, args); |
} |
va_end(ap); |
if (r != NULL) |
args = tree(RIGHT, voidtype, r, args); |
return calltree(f, ty, args, NULL); |
} |
int iscallb(Tree e) { |
return e->op == RIGHT && e->kids[0] && e->kids[1] |
&& e->kids[0]->op == CALL+B |
&& e->kids[1]->op == INDIR+B |
&& isaddrop(e->kids[1]->kids[0]->op) |
&& e->kids[1]->kids[0]->u.sym->temporary; |
} |
|
static Tree addtree(int op, Tree l, Tree r) { |
Type ty = inttype; |
|
if (isarith(l->type) && isarith(r->type)) { |
ty = binary(l->type, r->type); |
l = cast(l, ty); |
r = cast(r, ty); |
} else if (isptr(l->type) && isint(r->type)) |
return addtree(ADD, r, l); |
else if ( isptr(r->type) && isint(l->type) |
&& !isfunc(r->type->type)) |
{ |
long n; |
ty = unqual(r->type); |
n = unqual(ty->type)->size; |
if (n == 0) |
error("unknown size for type `%t'\n", ty->type); |
l = cast(l, promote(l->type)); |
if (n > 1) |
l = multree(MUL, cnsttree(signedptr, n), l); |
if (isunsigned(l->type)) |
l = cast(l, unsignedptr); |
else |
l = cast(l, signedptr); |
if (YYcheck && !isaddrop(r->op)) /* omit */ |
return nullcall(ty, YYcheck, r, l); /* omit */ |
return simplify(ADD, ty, l, r); |
} |
|
else |
typeerror(op, l, r); |
return simplify(op, ty, l, r); |
} |
|
Tree cnsttree(Type ty, ...) { |
Tree p = tree(mkop(CNST,ty), ty, NULL, NULL); |
va_list ap; |
|
va_start(ap, ty); |
switch (ty->op) { |
case INT: p->u.v.i = va_arg(ap, long); break; |
case UNSIGNED:p->u.v.u = va_arg(ap, unsigned long)&ones(8*ty->size); break; |
case FLOAT: p->u.v.d = va_arg(ap, long double); break; |
case POINTER: p->u.v.p = va_arg(ap, void *); break; |
default: assert(0); |
} |
va_end(ap); |
return p; |
} |
|
Tree consttree(unsigned n, Type ty) { |
if (isarray(ty)) |
ty = atop(ty); |
else assert(isint(ty)); |
return cnsttree(ty, (unsigned long)n); |
} |
static Tree cmptree(int op, Tree l, Tree r) { |
Type ty; |
|
if (isarith(l->type) && isarith(r->type)) { |
ty = binary(l->type, r->type); |
l = cast(l, ty); |
r = cast(r, ty); |
} else if (compatible(l->type, r->type)) { |
ty = unsignedptr; |
l = cast(l, ty); |
r = cast(r, ty); |
} else { |
ty = unsignedtype; |
typeerror(op, l, r); |
} |
return simplify(mkop(op,ty), inttype, l, r); |
} |
static int compatible(Type ty1, Type ty2) { |
ty1 = unqual(ty1); |
ty2 = unqual(ty2); |
return isptr(ty1) && !isfunc(ty1->type) |
&& isptr(ty2) && !isfunc(ty2->type) |
&& eqtype(unqual(ty1->type), unqual(ty2->type), 0); |
} |
static int isnullptr(Tree e) { |
Type ty = unqual(e->type); |
|
return generic(e->op) == CNST |
&& (ty->op == INT && e->u.v.i == 0 |
|| ty->op == UNSIGNED && e->u.v.u == 0 |
|| isvoidptr(ty) && e->u.v.p == NULL); |
} |
Tree eqtree(int op, Tree l, Tree r) { |
Type xty = unqual(l->type), yty = unqual(r->type); |
|
if (isptr(xty) && isnullptr(r) |
|| isptr(xty) && !isfunc(xty->type) && isvoidptr(yty) |
|| (isptr(xty) && isptr(yty) |
&& eqtype(unqual(xty->type), unqual(yty->type), 1))) { |
Type ty = unsignedptr; |
l = cast(l, ty); |
r = cast(r, ty); |
return simplify(mkop(op,ty), inttype, l, r); |
} |
if (isptr(yty) && isnullptr(l) |
|| isptr(yty) && !isfunc(yty->type) && isvoidptr(xty)) |
return eqtree(op, r, l); |
return cmptree(op, l, r); |
} |
|
Type assign(Type xty, Tree e) { |
Type yty = unqual(e->type); |
|
xty = unqual(xty); |
if (isenum(xty)) |
xty = xty->type; |
if (xty->size == 0 || yty->size == 0) |
return NULL; |
if ( isarith(xty) && isarith(yty) |
|| isstruct(xty) && xty == yty) |
return xty; |
if (isptr(xty) && isnullptr(e)) |
return xty; |
if ((isvoidptr(xty) && isptr(yty) |
|| isptr(xty) && isvoidptr(yty)) |
&& ( (isconst(xty->type) || !isconst(yty->type)) |
&& (isvolatile(xty->type) || !isvolatile(yty->type)))) |
return xty; |
|
if ((isptr(xty) && isptr(yty) |
&& eqtype(unqual(xty->type), unqual(yty->type), 1)) |
&& ( (isconst(xty->type) || !isconst(yty->type)) |
&& (isvolatile(xty->type) || !isvolatile(yty->type)))) |
return xty; |
if (isptr(xty) && isptr(yty) |
&& ( (isconst(xty->type) || !isconst(yty->type)) |
&& (isvolatile(xty->type) || !isvolatile(yty->type)))) { |
Type lty = unqual(xty->type), rty = unqual(yty->type); |
if (isenum(lty) && rty == inttype |
|| isenum(rty) && lty == inttype) { |
if (Aflag >= 1) |
warning("assignment between `%t' and `%t' is compiler-dependent\n", |
xty, yty); |
return xty; |
} |
} |
return NULL; |
} |
Tree asgntree(int op, Tree l, Tree r) { |
Type aty, ty; |
|
r = pointer(r); |
ty = assign(l->type, r); |
if (ty) |
r = cast(r, ty); |
else { |
typeerror(ASGN, l, r); |
if (r->type == voidtype) |
r = retype(r, inttype); |
ty = r->type; |
} |
if (l->op != FIELD) |
l = lvalue(l); |
aty = l->type; |
if (isptr(aty)) |
aty = unqual(aty)->type; |
if ( isconst(aty) |
|| isstruct(aty) && unqual(aty)->u.sym->u.s.cfields) |
if (isaddrop(l->op) |
&& !l->u.sym->computed && !l->u.sym->generated) |
error("assignment to const identifier `%s'\n", |
l->u.sym->name); |
else |
error("assignment to const location\n"); |
if (l->op == FIELD) { |
long n = 8*l->u.field->type->size - fieldsize(l->u.field); |
if (n > 0 && isunsigned(l->u.field->type)) |
r = bittree(BAND, r, |
cnsttree(r->type, (unsigned long)fieldmask(l->u.field))); |
else if (n > 0) { |
if (r->op == CNST+I) { |
n = r->u.v.i; |
if (n&(1<<(fieldsize(l->u.field)-1))) |
n |= ~0UL<<fieldsize(l->u.field); |
r = cnsttree(r->type, n); |
} else |
r = shtree(RSH, |
shtree(LSH, r, cnsttree(inttype, n)), |
cnsttree(inttype, n)); |
} |
} |
if (isstruct(ty) && isaddrop(l->op) && iscallb(r)) |
return tree(RIGHT, ty, |
tree(CALL+B, ty, r->kids[0]->kids[0], l), |
idtree(l->u.sym)); |
return tree(mkop(op,ty), ty, l, r); |
} |
Tree condtree(Tree e, Tree l, Tree r) { |
Symbol t1; |
Type ty, xty = l->type, yty = r->type; |
Tree p; |
|
if (isarith(xty) && isarith(yty)) |
ty = binary(xty, yty); |
else if (eqtype(xty, yty, 1)) |
ty = unqual(xty); |
else if (isptr(xty) && isnullptr(r)) |
ty = xty; |
else if (isnullptr(l) && isptr(yty)) |
ty = yty; |
else if (isptr(xty) && !isfunc(xty->type) && isvoidptr(yty) |
|| isptr(yty) && !isfunc(yty->type) && isvoidptr(xty)) |
ty = voidptype; |
else if ((isptr(xty) && isptr(yty) |
&& eqtype(unqual(xty->type), unqual(yty->type), 1))) |
ty = xty; |
else { |
typeerror(COND, l, r); |
return consttree(0, inttype); |
} |
if (isptr(ty)) { |
ty = unqual(unqual(ty)->type); |
if (isptr(xty) && isconst(unqual(xty)->type) |
|| isptr(yty) && isconst(unqual(yty)->type)) |
ty = qual(CONST, ty); |
if (isptr(xty) && isvolatile(unqual(xty)->type) |
|| isptr(yty) && isvolatile(unqual(yty)->type)) |
ty = qual(VOLATILE, ty); |
ty = ptr(ty); |
} |
switch (e->op) { |
case CNST+I: return cast(e->u.v.i != 0 ? l : r, ty); |
case CNST+U: return cast(e->u.v.u != 0 ? l : r, ty); |
case CNST+P: return cast(e->u.v.p != 0 ? l : r, ty); |
case CNST+F: return cast(e->u.v.d != 0.0 ? l : r, ty); |
} |
if (ty != voidtype && ty->size > 0) { |
t1 = genident(REGISTER, unqual(ty), level); |
/* t1 = temporary(REGISTER, unqual(ty)); */ |
l = asgn(t1, l); |
r = asgn(t1, r); |
} else |
t1 = NULL; |
p = tree(COND, ty, cond(e), |
tree(RIGHT, ty, root(l), root(r))); |
p->u.sym = t1; |
return p; |
} |
/* addrof - address of p */ |
Tree addrof(Tree p) { |
Tree q = p; |
|
for (;;) |
switch (generic(q->op)) { |
case RIGHT: |
assert(q->kids[0] || q->kids[1]); |
q = q->kids[1] ? q->kids[1] : q->kids[0]; |
continue; |
case ASGN: |
q = q->kids[1]; |
continue; |
case COND: { |
Symbol t1 = q->u.sym; |
q->u.sym = 0; |
q = idtree(t1); |
/* fall thru */ |
} |
case INDIR: |
if (p == q) |
return q->kids[0]; |
q = q->kids[0]; |
return tree(RIGHT, q->type, root(p), q); |
default: |
error("addressable object required\n"); |
return value(p); |
} |
} |
|
/* andtree - construct tree for l [&& ||] r */ |
static Tree andtree(int op, Tree l, Tree r) { |
if (!isscalar(l->type) || !isscalar(r->type)) |
typeerror(op, l, r); |
return simplify(op, inttype, cond(l), cond(r)); |
} |
|
/* asgn - generate tree for assignment of expr e to symbol p sans qualifiers */ |
Tree asgn(Symbol p, Tree e) { |
if (isarray(p->type)) |
e = tree(ASGN+B, p->type, idtree(p), |
tree(INDIR+B, e->type, e, NULL)); |
else { |
Type ty = p->type; |
p->type = unqual(p->type); |
if (isstruct(p->type) && p->type->u.sym->u.s.cfields) { |
p->type->u.sym->u.s.cfields = 0; |
e = asgntree(ASGN, idtree(p), e); |
p->type->u.sym->u.s.cfields = 1; |
} else |
e = asgntree(ASGN, idtree(p), e); |
p->type = ty; |
} |
return e; |
} |
|
/* bittree - construct tree for l [& | ^ %] r */ |
Tree bittree(int op, Tree l, Tree r) { |
Type ty = inttype; |
|
if (isint(l->type) && isint(r->type)) { |
ty = binary(l->type, r->type); |
l = cast(l, ty); |
r = cast(r, ty); |
} else |
typeerror(op, l, r); |
return simplify(op, ty, l, r); |
} |
|
/* multree - construct tree for l [* /] r */ |
static Tree multree(int op, Tree l, Tree r) { |
Type ty = inttype; |
|
if (isarith(l->type) && isarith(r->type)) { |
ty = binary(l->type, r->type); |
l = cast(l, ty); |
r = cast(r, ty); |
} else |
typeerror(op, l, r); |
return simplify(op, ty, l, r); |
} |
|
/* shtree - construct tree for l [>> <<] r */ |
Tree shtree(int op, Tree l, Tree r) { |
Type ty = inttype; |
|
if (isint(l->type) && isint(r->type)) { |
ty = promote(l->type); |
l = cast(l, ty); |
r = cast(r, inttype); |
} else |
typeerror(op, l, r); |
return simplify(op, ty, l, r); |
} |
|
/* subtree - construct tree for l - r */ |
static Tree subtree(int op, Tree l, Tree r) { |
long n; |
Type ty = inttype; |
|
if (isarith(l->type) && isarith(r->type)) { |
ty = binary(l->type, r->type); |
l = cast(l, ty); |
r = cast(r, ty); |
} else if (isptr(l->type) && !isfunc(l->type->type) && isint(r->type)) { |
ty = unqual(l->type); |
n = unqual(ty->type)->size; |
if (n == 0) |
error("unknown size for type `%t'\n", ty->type); |
r = cast(r, promote(r->type)); |
if (n > 1) |
r = multree(MUL, cnsttree(signedptr, n), r); |
if (isunsigned(r->type)) |
r = cast(r, unsignedptr); |
else |
r = cast(r, signedptr); |
return simplify(SUB+P, ty, l, r); |
} else if (compatible(l->type, r->type)) { |
ty = unqual(l->type); |
n = unqual(ty->type)->size; |
if (n == 0) |
error("unknown size for type `%t'\n", ty->type); |
l = simplify(SUB+U, unsignedptr, |
cast(l, unsignedptr), cast(r, unsignedptr)); |
return simplify(DIV+I, longtype, |
cast(l, longtype), cnsttree(longtype, n)); |
} else |
typeerror(op, l, r); |
return simplify(op, ty, l, r); |
} |
|
/* typeerror - issue "operands of op have illegal types `l' and `r'" */ |
void typeerror(int op, Tree l, Tree r) { |
int i; |
static struct { int op; char *name; } ops[] = { |
ASGN, "=", INDIR, "*", NEG, "-", |
ADD, "+", SUB, "-", LSH, "<<", |
MOD, "%", RSH, ">>", BAND, "&", |
BCOM, "~", BOR, "|", BXOR, "^", |
DIV, "/", MUL, "*", EQ, "==", |
GE, ">=", GT, ">", LE, "<=", |
LT, "<", NE, "!=", AND, "&&", |
NOT, "!", OR, "||", COND, "?:", |
0, 0 |
}; |
|
op = generic(op); |
for (i = 0; ops[i].op; i++) |
if (op == ops[i].op) |
break; |
assert(ops[i].name); |
if (r) |
error("operands of %s have illegal types `%t' and `%t'\n", |
ops[i].name, l->type, r->type); |
else |
error("operand of unary %s has illegal type `%t'\n", ops[i].name, |
l->type); |
} |
/dag.c
0,0 → 1,740
#include "c.h" |
|
static char rcsid[] = "$Id: dag.c,v 1.1 2002/08/28 23:12:42 drh Exp $"; |
|
#define iscall(op) (generic(op) == CALL \ |
|| IR->mulops_calls \ |
&& (generic(op)==DIV||generic(op)==MOD||generic(op)==MUL) \ |
&& ( optype(op)==U || optype(op)==I)) |
static Node forest; |
static struct dag { |
struct node node; |
struct dag *hlink; |
} *buckets[16]; |
int nodecount; |
static Tree firstarg; |
int assignargs = 1; |
int prunetemps = -1; |
static Node *tail; |
|
static int depth = 0; |
static Node replace(Node); |
static Node prune(Node); |
static Node asgnnode(Symbol, Node); |
static struct dag *dagnode(int, Node, Node, Symbol); |
static Symbol equated(Symbol); |
static void fixup(Node); |
static void labelnode(int); |
static void list(Node); |
static void killnodes(Symbol); |
static Node node(int, Node, Node, Symbol); |
static void printdag1(Node, int, int); |
static void printnode(Node, int, int); |
static void reset(void); |
static Node tmpnode(Node); |
static void typestab(Symbol, void *); |
static Node undag(Node); |
static Node visit(Node, int); |
static void unlist(void); |
void walk(Tree tp, int tlab, int flab) { |
listnodes(tp, tlab, flab); |
if (forest) { |
Node list = forest->link; |
forest->link = NULL; |
if (!IR->wants_dag && errcnt == 0) |
list = undag(list); |
code(Gen)->u.forest = list; |
forest = NULL; |
} |
reset(); |
deallocate(STMT); |
} |
|
static Node node(int op, Node l, Node r, Symbol sym) { |
int i; |
struct dag *p; |
|
i = (opindex(op)^((unsigned long)sym>>2))&(NELEMS(buckets)-1); |
for (p = buckets[i]; p; p = p->hlink) |
if (p->node.op == op && p->node.syms[0] == sym |
&& p->node.kids[0] == l && p->node.kids[1] == r) |
return &p->node; |
p = dagnode(op, l, r, sym); |
p->hlink = buckets[i]; |
buckets[i] = p; |
++nodecount; |
return &p->node; |
} |
static struct dag *dagnode(int op, Node l, Node r, Symbol sym) { |
struct dag *p; |
|
NEW0(p, FUNC); |
p->node.op = op; |
if ((p->node.kids[0] = l) != NULL) |
++l->count; |
if ((p->node.kids[1] = r) != NULL) |
++r->count; |
p->node.syms[0] = sym; |
return p; |
} |
Node newnode(int op, Node l, Node r, Symbol sym) { |
return &dagnode(op, l, r, sym)->node; |
} |
static void killnodes(Symbol p) { |
int i; |
struct dag **q; |
|
for (i = 0; i < NELEMS(buckets); i++) |
for (q = &buckets[i]; *q; ) |
if (generic((*q)->node.op) == INDIR && |
(!isaddrop((*q)->node.kids[0]->op) |
|| (*q)->node.kids[0]->syms[0] == p)) { |
*q = (*q)->hlink; |
--nodecount; |
} else |
q = &(*q)->hlink; |
} |
static void reset(void) { |
if (nodecount > 0) |
memset(buckets, 0, sizeof buckets); |
nodecount = 0; |
} |
Node listnodes(Tree tp, int tlab, int flab) { |
Node p = NULL, l, r; |
int op; |
|
assert(tlab || flab || tlab == 0 && flab == 0); |
if (tp == NULL) |
return NULL; |
if (tp->node) |
return tp->node; |
if (isarray(tp->type)) |
op = tp->op + sizeop(voidptype->size); |
else |
op = tp->op + sizeop(tp->type->size); |
switch (generic(tp->op)) { |
case AND: { if (depth++ == 0) reset(); |
if (flab) { |
listnodes(tp->kids[0], 0, flab); |
listnodes(tp->kids[1], 0, flab); |
} else { |
listnodes(tp->kids[0], 0, flab = genlabel(1)); |
listnodes(tp->kids[1], tlab, 0); |
labelnode(flab); |
} |
depth--; } break; |
case OR: { if (depth++ == 0) |
reset(); |
if (tlab) { |
listnodes(tp->kids[0], tlab, 0); |
listnodes(tp->kids[1], tlab, 0); |
} else { |
tlab = genlabel(1); |
listnodes(tp->kids[0], tlab, 0); |
listnodes(tp->kids[1], 0, flab); |
labelnode(tlab); |
} |
depth--; |
} break; |
case NOT: { return listnodes(tp->kids[0], flab, tlab); } |
case COND: { Tree q = tp->kids[1]; |
assert(tlab == 0 && flab == 0); |
if (tp->u.sym) |
addlocal(tp->u.sym); |
flab = genlabel(2); |
listnodes(tp->kids[0], 0, flab); |
assert(q && q->op == RIGHT); |
reset(); |
listnodes(q->kids[0], 0, 0); |
if (forest->op == LABEL+V) { |
equatelab(forest->syms[0], findlabel(flab + 1)); |
unlist(); |
} |
list(jump(flab + 1)); |
labelnode(flab); |
listnodes(q->kids[1], 0, 0); |
if (forest->op == LABEL+V) { |
equatelab(forest->syms[0], findlabel(flab + 1)); |
unlist(); |
} |
labelnode(flab + 1); |
|
if (tp->u.sym) |
p = listnodes(idtree(tp->u.sym), 0, 0); } break; |
case CNST: { Type ty = unqual(tp->type); |
assert(ty->u.sym); |
if (tlab || flab) { |
assert(ty == inttype); |
if (tlab && tp->u.v.i != 0) |
list(jump(tlab)); |
else if (flab && tp->u.v.i == 0) |
list(jump(flab)); |
} |
else if (ty->u.sym->addressed) |
p = listnodes(cvtconst(tp), 0, 0); |
else |
p = node(op, NULL, NULL, constant(ty, tp->u.v)); } break; |
case RIGHT: { if ( tp->kids[0] && tp->kids[1] |
&& generic(tp->kids[1]->op) == ASGN |
&& (generic(tp->kids[0]->op) == INDIR |
&& tp->kids[0]->kids[0] == tp->kids[1]->kids[0] |
|| (tp->kids[0]->op == FIELD |
&& tp->kids[0] == tp->kids[1]->kids[0]))) { |
assert(tlab == 0 && flab == 0); |
if (generic(tp->kids[0]->op) == INDIR) { |
p = listnodes(tp->kids[0], 0, 0); |
list(p); |
listnodes(tp->kids[1], 0, 0); |
} |
else { |
assert(generic(tp->kids[0]->kids[0]->op) == INDIR); |
list(listnodes(tp->kids[0]->kids[0], 0, 0)); |
p = listnodes(tp->kids[0], 0, 0); |
listnodes(tp->kids[1], 0, 0); |
} |
} else if (tp->kids[1]) { |
listnodes(tp->kids[0], 0, 0); |
p = listnodes(tp->kids[1], tlab, flab); |
} else |
p = listnodes(tp->kids[0], tlab, flab); } break; |
case JUMP: { assert(tlab == 0 && flab == 0); |
assert(tp->u.sym == 0); |
assert(tp->kids[0]); |
l = listnodes(tp->kids[0], 0, 0); |
list(newnode(JUMP+V, l, NULL, NULL)); |
reset(); } break; |
case CALL: { Tree save = firstarg; |
firstarg = NULL; |
assert(tlab == 0 && flab == 0); |
if (tp->op == CALL+B && !IR->wants_callb) { |
Tree arg0 = tree(ARG+P, tp->kids[1]->type, |
tp->kids[1], NULL); |
if (IR->left_to_right) |
firstarg = arg0; |
l = listnodes(tp->kids[0], 0, 0); |
if (!IR->left_to_right || firstarg) { |
firstarg = NULL; |
listnodes(arg0, 0, 0); |
} |
p = newnode(CALL+V, l, NULL, NULL); |
} else { |
l = listnodes(tp->kids[0], 0, 0); |
r = listnodes(tp->kids[1], 0, 0); |
p = newnode(tp->op == CALL+B ? tp->op : op, l, r, NULL); |
} |
NEW0(p->syms[0], FUNC); |
assert(isptr(tp->kids[0]->type)); |
assert(isfunc(tp->kids[0]->type->type)); |
p->syms[0]->type = tp->kids[0]->type->type; |
list(p); |
reset(); |
cfunc->u.f.ncalls++; |
firstarg = save; |
} break; |
case ARG: { assert(tlab == 0 && flab == 0); |
if (IR->left_to_right) |
listnodes(tp->kids[1], 0, 0); |
if (firstarg) { |
Tree arg = firstarg; |
firstarg = NULL; |
listnodes(arg, 0, 0); |
} |
l = listnodes(tp->kids[0], 0, 0); |
list(newnode(tp->op == ARG+B ? tp->op : op, l, NULL, NULL)); |
forest->syms[0] = intconst(tp->type->size); |
forest->syms[1] = intconst(tp->type->align); |
if (!IR->left_to_right) |
listnodes(tp->kids[1], 0, 0); } break; |
case EQ: case NE: case GT: case GE: case LE: |
case LT: { assert(tp->u.sym == 0); |
assert(errcnt || tlab || flab); |
l = listnodes(tp->kids[0], 0, 0); |
r = listnodes(tp->kids[1], 0, 0); |
assert(errcnt || opkind(l->op) == opkind(r->op)); |
assert(errcnt || optype(op) == optype(l->op)); |
if (tlab) |
assert(flab == 0), |
list(newnode(generic(tp->op) + opkind(l->op), l, r, findlabel(tlab))); |
else if (flab) { |
switch (generic(tp->op)) { |
case EQ: op = NE; break; |
case NE: op = EQ; break; |
case GT: op = LE; break; |
case LT: op = GE; break; |
case GE: op = LT; break; |
case LE: op = GT; break; |
default: assert(0); |
} |
list(newnode(op + opkind(l->op), l, r, findlabel(flab))); |
} |
if (forest && forest->syms[0]) |
forest->syms[0]->ref++; } break; |
case ASGN: { assert(tlab == 0 && flab == 0); |
if (tp->kids[0]->op == FIELD) { |
Tree x = tp->kids[0]->kids[0]; |
Field f = tp->kids[0]->u.field; |
assert(generic(x->op) == INDIR); |
reset(); |
l = listnodes(lvalue(x), 0, 0); |
if (fieldsize(f) < 8*f->type->size) { |
unsigned int fmask = fieldmask(f); |
unsigned int mask = fmask<<fieldright(f); |
Tree q = tp->kids[1]; |
if (q->op == CNST+I && q->u.v.i == 0 |
|| q->op == CNST+U && q->u.v.u == 0) |
q = bittree(BAND, x, cnsttree(unsignedtype, (unsigned long)~mask)); |
else if (q->op == CNST+I && (q->u.v.i&fmask) == fmask |
|| q->op == CNST+U && (q->u.v.u&fmask) == fmask) |
q = bittree(BOR, x, cnsttree(unsignedtype, (unsigned long)mask)); |
else { |
listnodes(q, 0, 0); |
q = bittree(BOR, |
bittree(BAND, rvalue(lvalue(x)), |
cnsttree(unsignedtype, (unsigned long)~mask)), |
bittree(BAND, shtree(LSH, cast(q, unsignedtype), |
cnsttree(unsignedtype, (unsigned long)fieldright(f))), |
cnsttree(unsignedtype, (unsigned long)mask))); |
} |
r = listnodes(q, 0, 0); |
op = ASGN + ttob(q->type); |
} else { |
r = listnodes(tp->kids[1], 0, 0); |
op = ASGN + ttob(tp->kids[1]->type); |
} |
} else { |
l = listnodes(tp->kids[0], 0, 0); |
r = listnodes(tp->kids[1], 0, 0); |
} |
list(newnode(tp->op == ASGN+B ? tp->op : op, l, r, NULL)); |
forest->syms[0] = intconst(tp->kids[1]->type->size); |
forest->syms[1] = intconst(tp->kids[1]->type->align); |
if (isaddrop(tp->kids[0]->op) |
&& !tp->kids[0]->u.sym->computed) |
killnodes(tp->kids[0]->u.sym); |
else |
reset(); |
p = listnodes(tp->kids[1], 0, 0); } break; |
case BOR: case BAND: case BXOR: |
case ADD: case SUB: case RSH: |
case LSH: { assert(tlab == 0 && flab == 0); |
l = listnodes(tp->kids[0], 0, 0); |
r = listnodes(tp->kids[1], 0, 0); |
p = node(op, l, r, NULL); } break; |
case DIV: case MUL: |
case MOD: { assert(tlab == 0 && flab == 0); |
l = listnodes(tp->kids[0], 0, 0); |
r = listnodes(tp->kids[1], 0, 0); |
p = node(op, l, r, NULL); |
if (IR->mulops_calls && isint(tp->type)) { |
list(p); |
cfunc->u.f.ncalls++; |
} } break; |
case RET: { assert(tlab == 0 && flab == 0); |
l = listnodes(tp->kids[0], 0, 0); |
list(newnode(op, l, NULL, NULL)); } break; |
case CVF: case CVI: case CVP: |
case CVU: { assert(tlab == 0 && flab == 0); |
assert(optype(tp->kids[0]->op) != optype(tp->op) || tp->kids[0]->type->size != tp->type->size); |
l = listnodes(tp->kids[0], 0, 0); |
p = node(op, l, NULL, intconst(tp->kids[0]->type->size)); |
} break; |
case BCOM: |
case NEG: { assert(tlab == 0 && flab == 0); |
l = listnodes(tp->kids[0], 0, 0); |
p = node(op, l, NULL, NULL); } break; |
case INDIR: { Type ty = tp->kids[0]->type; |
assert(tlab == 0 && flab == 0); |
l = listnodes(tp->kids[0], 0, 0); |
if (isptr(ty)) |
ty = unqual(ty)->type; |
if (isvolatile(ty) |
|| (isstruct(ty) && unqual(ty)->u.sym->u.s.vfields)) |
p = newnode(tp->op == INDIR+B ? tp->op : op, l, NULL, NULL); |
else |
p = node(tp->op == INDIR+B ? tp->op : op, l, NULL, NULL); } break; |
case FIELD: { Tree q = tp->kids[0]; |
if (tp->type == inttype) { |
long n = fieldleft(tp->u.field); |
q = shtree(RSH, |
shtree(LSH, q, cnsttree(inttype, n)), |
cnsttree(inttype, n + fieldright(tp->u.field))); |
} else if (fieldsize(tp->u.field) < 8*tp->u.field->type->size) |
q = bittree(BAND, |
shtree(RSH, q, cnsttree(inttype, (long)fieldright(tp->u.field))), |
cnsttree(unsignedtype, (unsigned long)fieldmask(tp->u.field))); |
assert(tlab == 0 && flab == 0); |
p = listnodes(q, 0, 0); } break; |
case ADDRG: |
case ADDRF: { assert(tlab == 0 && flab == 0); |
p = node(tp->op + sizeop(voidptype->size), NULL, NULL, tp->u.sym); |
} break; |
case ADDRL: { assert(tlab == 0 && flab == 0); |
if (tp->u.sym->generated) |
addlocal(tp->u.sym); |
p = node(tp->op + sizeop(voidptype->size), NULL, NULL, tp->u.sym); } break; |
default:assert(0); |
} |
tp->node = p; |
return p; |
} |
static void list(Node p) { |
if (p && p->link == NULL) { |
if (forest) { |
p->link = forest->link; |
forest->link = p; |
} else |
p->link = p; |
forest = p; |
} |
} |
static void labelnode(int lab) { |
assert(lab); |
if (forest && forest->op == LABEL+V) |
equatelab(findlabel(lab), forest->syms[0]); |
else |
list(newnode(LABEL+V, NULL, NULL, findlabel(lab))); |
reset(); |
} |
static void unlist(void) { |
Node p; |
|
assert(forest); |
assert(forest != forest->link); |
p = forest->link; |
while (p->link != forest) |
p = p->link; |
p->link = forest->link; |
forest = p; |
} |
Tree cvtconst(Tree p) { |
Symbol q = constant(p->type, p->u.v); |
Tree e; |
|
if (q->u.c.loc == NULL) |
q->u.c.loc = genident(STATIC, p->type, GLOBAL); |
if (isarray(p->type)) { |
e = simplify(ADDRG, atop(p->type), NULL, NULL); |
e->u.sym = q->u.c.loc; |
} else |
e = idtree(q->u.c.loc); |
return e; |
} |
void gencode(Symbol caller[], Symbol callee[]) { |
Code cp; |
Coordinate save; |
|
if (prunetemps == -1) |
prunetemps = !IR->wants_dag; |
save = src; |
if (assignargs) { |
int i; |
Symbol p, q; |
cp = codehead.next->next; |
codelist = codehead.next; |
for (i = 0; (p = callee[i]) != NULL |
&& (q = caller[i]) != NULL; i++) |
if (p->sclass != q->sclass || p->type != q->type) |
walk(asgn(p, idtree(q)), 0, 0); |
codelist->next = cp; |
cp->prev = codelist; |
} |
if (glevel && IR->stabsym) { |
int i; |
Symbol p, q; |
for (i = 0; (p = callee[i]) != NULL |
&& (q = caller[i]) != NULL; i++) { |
(*IR->stabsym)(p); |
if (p->sclass != q->sclass || p->type != q->type) |
(*IR->stabsym)(q); |
} |
swtoseg(CODE); |
} |
cp = codehead.next; |
for ( ; errcnt <= 0 && cp; cp = cp->next) |
switch (cp->kind) { |
case Address: assert(IR->address); |
(*IR->address)(cp->u.addr.sym, cp->u.addr.base, |
cp->u.addr.offset); break; |
case Blockbeg: { |
Symbol *p = cp->u.block.locals; |
(*IR->blockbeg)(&cp->u.block.x); |
for ( ; *p; p++) |
if ((*p)->ref != 0.0) |
(*IR->local)(*p); |
else if (glevel) (*IR->local)(*p); |
} |
break; |
case Blockend: (*IR->blockend)(&cp->u.begin->u.block.x); break; |
case Defpoint: src = cp->u.point.src; break; |
case Gen: case Jump: |
case Label: if (prunetemps) |
cp->u.forest = prune(cp->u.forest); |
fixup(cp->u.forest); |
cp->u.forest = (*IR->gen)(cp->u.forest); break; |
case Local: (*IR->local)(cp->u.var); break; |
case Switch: break; |
default: assert(0); |
} |
src = save; |
} |
static void fixup(Node p) { |
for ( ; p; p = p->link) |
switch (generic(p->op)) { |
case JUMP: |
if (specific(p->kids[0]->op) == ADDRG+P) |
p->kids[0]->syms[0] = |
equated(p->kids[0]->syms[0]); |
break; |
case LABEL: assert(p->syms[0] == equated(p->syms[0])); break; |
case EQ: case GE: case GT: case LE: case LT: case NE: |
assert(p->syms[0]); |
p->syms[0] = equated(p->syms[0]); |
} |
} |
static Symbol equated(Symbol p) { |
{ Symbol q; for (q = p->u.l.equatedto; q; q = q->u.l.equatedto) assert(p != q); } |
while (p->u.l.equatedto) |
p = p->u.l.equatedto; |
return p; |
} |
void emitcode(void) { |
Code cp; |
Coordinate save; |
|
save = src; |
cp = codehead.next; |
for ( ; errcnt <= 0 && cp; cp = cp->next) |
switch (cp->kind) { |
case Address: break; |
case Blockbeg: if (glevel && IR->stabblock) { |
(*IR->stabblock)('{', cp->u.block.level - LOCAL, cp->u.block.locals); |
swtoseg(CODE); |
} |
break; |
case Blockend: if (glevel && IR->stabblock) { |
Code bp = cp->u.begin; |
foreach(bp->u.block.identifiers, bp->u.block.level, typestab, NULL); |
foreach(bp->u.block.types, bp->u.block.level, typestab, NULL); |
(*IR->stabblock)('}', bp->u.block.level - LOCAL, bp->u.block.locals); |
swtoseg(CODE); |
} |
break; |
case Defpoint: src = cp->u.point.src; |
if (glevel > 0 && IR->stabline) { |
(*IR->stabline)(&cp->u.point.src); swtoseg(CODE); } break; |
case Gen: case Jump: |
case Label: if (cp->u.forest) |
(*IR->emit)(cp->u.forest); break; |
case Local: if (glevel && IR->stabsym) { |
(*IR->stabsym)(cp->u.var); |
swtoseg(CODE); |
} break; |
case Switch: { int i; |
defglobal(cp->u.swtch.table, LIT); |
(*IR->defaddress)(equated(cp->u.swtch.labels[0])); |
for (i = 1; i < cp->u.swtch.size; i++) { |
long k = cp->u.swtch.values[i-1]; |
while (++k < cp->u.swtch.values[i]) |
assert(k < LONG_MAX), |
(*IR->defaddress)(equated(cp->u.swtch.deflab)); |
(*IR->defaddress)(equated(cp->u.swtch.labels[i])); |
} |
swtoseg(CODE); |
} break; |
default: assert(0); |
} |
src = save; |
} |
|
static Node undag(Node forest) { |
Node p; |
|
tail = &forest; |
for (p = forest; p; p = p->link) |
if (generic(p->op) == INDIR) { |
assert(p->count >= 1); |
visit(p, 1); |
if (p->syms[2]) { |
assert(p->syms[2]->u.t.cse); |
p->syms[2]->u.t.cse = NULL; |
addlocal(p->syms[2]); |
} |
} else if (iscall(p->op) && p->count >= 1) |
visit(p, 1); |
else { |
assert(p->count == 0), |
visit(p, 1); |
*tail = p; |
tail = &p->link; |
} |
*tail = NULL; |
return forest; |
} |
static Node replace(Node p) { |
if (p && ( generic(p->op) == INDIR |
&& generic(p->kids[0]->op) == ADDRL |
&& p->kids[0]->syms[0]->temporary |
&& p->kids[0]->syms[0]->u.t.replace)) { |
p = p->kids[0]->syms[0]->u.t.cse; |
if (generic(p->op) == INDIR && isaddrop(p->kids[0]->op)) |
p = newnode(p->op, newnode(p->kids[0]->op, NULL, NULL, |
p->kids[0]->syms[0]), NULL, NULL); |
else if (generic(p->op) == ADDRG) |
p = newnode(p->op, NULL, NULL, p->syms[0]); |
else |
assert(0); |
p->count = 1; |
} else if (p) { |
p->kids[0] = replace(p->kids[0]); |
p->kids[1] = replace(p->kids[1]); |
} |
return p; |
} |
static Node prune(Node forest) { |
Node p, *tail = &forest; |
int count = 0; |
|
for (p = forest; p; p = p->link) { |
if (count > 0) { |
p->kids[0] = replace(p->kids[0]); |
p->kids[1] = replace(p->kids[1]); |
} |
if (( generic(p->op) == ASGN |
&& generic(p->kids[0]->op) == ADDRL |
&& p->kids[0]->syms[0]->temporary |
&& p->kids[0]->syms[0]->u.t.cse == p->kids[1])) { |
Symbol tmp = p->kids[0]->syms[0]; |
if (!tmp->defined) |
(*IR->local)(tmp); |
tmp->defined = 1; |
if (( generic(p->kids[1]->op) == INDIR |
&& isaddrop(p->kids[1]->kids[0]->op) |
&& p->kids[1]->kids[0]->syms[0]->sclass == REGISTER) |
|| (( generic(p->kids[1]->op) == INDIR |
&& isaddrop(p->kids[1]->kids[0]->op)) && tmp->sclass == AUTO) |
|| (generic(p->kids[1]->op) == ADDRG && tmp->sclass == AUTO)) { |
tmp->u.t.replace = 1; |
count++; |
continue; /* and omit the assignment */ |
} |
} |
/* keep the assignment and other roots */ |
*tail = p; |
tail = &(*tail)->link; |
} |
assert(*tail == NULL); |
return forest; |
} |
static Node visit(Node p, int listed) { |
if (p) |
if (p->syms[2]) |
p = tmpnode(p); |
else if (p->count <= 1 && !iscall(p->op) |
|| p->count == 0 && iscall(p->op)) { |
p->kids[0] = visit(p->kids[0], 0); |
p->kids[1] = visit(p->kids[1], 0); |
} |
|
else if (specific(p->op) == ADDRL+P || specific(p->op) == ADDRF+P) { |
assert(!listed); |
p = newnode(p->op, NULL, NULL, p->syms[0]); |
p->count = 1; |
} |
else if (p->op == INDIR+B) { |
p = newnode(p->op, p->kids[0], NULL, NULL); |
p->count = 1; |
p->kids[0] = visit(p->kids[0], 0); |
p->kids[1] = visit(p->kids[1], 0); |
} |
else { |
p->kids[0] = visit(p->kids[0], 0); |
p->kids[1] = visit(p->kids[1], 0); |
p->syms[2] = temporary(REGISTER, btot(p->op, opsize(p->op))); |
assert(!p->syms[2]->defined); |
p->syms[2]->ref = 1; |
p->syms[2]->u.t.cse = p; |
|
*tail = asgnnode(p->syms[2], p); |
tail = &(*tail)->link; |
if (!listed) |
p = tmpnode(p); |
}; |
return p; |
} |
static Node tmpnode(Node p) { |
Symbol tmp = p->syms[2]; |
|
assert(tmp); |
if (--p->count == 0) |
p->syms[2] = NULL; |
p = newnode(INDIR + ttob(tmp->type), |
newnode(ADDRL + ttob(voidptype), NULL, NULL, tmp), NULL, NULL); |
p->count = 1; |
return p; |
} |
static Node asgnnode(Symbol tmp, Node p) { |
p = newnode(ASGN + ttob(tmp->type), |
newnode(ADDRL + ttob(voidptype), NULL, NULL, tmp), p, NULL); |
p->syms[0] = intconst(tmp->type->size); |
p->syms[1] = intconst(tmp->type->align); |
return p; |
} |
/* printdag - print dag p on fd, or the node list if p == 0 */ |
void printdag(Node p, int fd) { |
FILE *f = fd == 1 ? stdout : stderr; |
|
printed(0); |
if (p == 0) { |
if ((p = forest) != NULL) |
do { |
p = p->link; |
printdag1(p, fd, 0); |
} while (p != forest); |
} else if (*printed(nodeid((Tree)p))) |
fprint(f, "node'%d printed above\n", nodeid((Tree)p)); |
else |
printdag1(p, fd, 0); |
} |
|
/* printdag1 - recursively print dag p */ |
static void printdag1(Node p, int fd, int lev) { |
int id, i; |
|
if (p == 0 || *printed(id = nodeid((Tree)p))) |
return; |
*printed(id) = 1; |
for (i = 0; i < NELEMS(p->kids); i++) |
printdag1(p->kids[i], fd, lev + 1); |
printnode(p, fd, lev); |
} |
|
/* printnode - print fields of dag p */ |
static void printnode(Node p, int fd, int lev) { |
if (p) { |
FILE *f = fd == 1 ? stdout : stderr; |
int i, id = nodeid((Tree)p); |
fprint(f, "%c%d%s", lev == 0 ? '\'' : '#', id, |
&" "[id < 10 ? 0 : id < 100 ? 1 : 2]); |
fprint(f, "%s count=%d", opname(p->op), p->count); |
for (i = 0; i < NELEMS(p->kids) && p->kids[i]; i++) |
fprint(f, " #%d", nodeid((Tree)p->kids[i])); |
if (generic(p->op) == CALL && p->syms[0] && p->syms[0]->type) |
fprint(f, " {%t}", p->syms[0]->type); |
else |
for (i = 0; i < NELEMS(p->syms) && p->syms[i]; i++) |
if (p->syms[i]->name) |
fprint(f, " %s", p->syms[i]->name); |
else |
fprint(f, " %p", p->syms[i]); |
fprint(f, "\n"); |
} |
} |
|
/* typestab - emit stab entries for p */ |
static void typestab(Symbol p, void *cl) { |
if (!isfunc(p->type) && (p->sclass == EXTERN || p->sclass == STATIC) && IR->stabsym) |
(*IR->stabsym)(p); |
else if ((p->sclass == TYPEDEF || p->sclass == 0) && IR->stabtype) |
(*IR->stabtype)(p); |
} |
|
/profio.c
0,0 → 1,286
/* C compiler: prof.out input |
|
prof.out format: |
#files |
name |
... (#files-1 times) |
#functions |
name file# x y count caller file x y |
... (#functions-1 times) |
#points |
file# x y count |
... (#points-1 times) |
*/ |
#include "c.h" |
|
static char rcsid[] = "$Id: profio.c,v 1.1 2002/08/28 23:12:45 drh Exp $"; |
|
struct count { /* count data: */ |
int x, y; /* source coordinate */ |
int count; /* associated execution count */ |
}; |
|
#define MAXTOKEN 64 |
|
struct file { /* per-file prof.out data: */ |
struct file *link; /* link to next file */ |
char *name; /* file name */ |
int size; /* size of counts[] */ |
int count; /* counts[0..count-1] hold valid data */ |
struct count *counts; /* count data */ |
struct func { /* function data: */ |
struct func *link; /* link to next function */ |
char *name; /* function name */ |
struct count count; /* total number of calls */ |
struct caller { /* caller data: */ |
struct caller *link; /* link to next caller */ |
char *name; /* caller's name */ |
char *file; /* call site: file, x, y */ |
int x, y; |
int count; /* number of calls from this site */ |
} *callers; |
} *funcs; /* list of functions */ |
} *filelist; |
FILE *fp; |
|
/* acaller - add caller and site (file,x,y) to callee's callers list */ |
static void acaller(char *caller, char *file, int x, int y, int count, struct func *callee) { |
struct caller *q; |
|
assert(callee); |
for (q = callee->callers; q && (caller != q->name |
|| file != q->file || x != q->x || y != q->y); q = q->link) |
; |
if (!q) { |
struct caller **r; |
NEW(q, PERM); |
q->name = caller; |
q->file = file; |
q->x = x; |
q->y = y; |
q->count = 0; |
for (r = &callee->callers; *r && (strcmp(q->name, (*r)->name) > 0 |
|| strcmp(q->file, (*r)->file) > 0 || q->y > (*r)->y || q->y > (*r)->y); r = &(*r)->link) |
; |
q->link = *r; |
*r = q; |
} |
q->count += count; |
} |
|
/* compare - return <0, 0, >0 if a<b, a==b, a>b, resp. */ |
static int compare(const void *x, const void *y) { |
struct count *a = (struct count *)x, *b = (struct count *)y; |
|
if (a->y == b->y) |
return a->x - b->x; |
return a->y - b->y; |
} |
|
/* findfile - return file name's file list entry, or 0 */ |
static struct file *findfile(char *name) { |
struct file *p; |
|
for (p = filelist; p; p = p->link) |
if (p->name == name) |
return p; |
return 0; |
} |
|
/* afunction - add function name and its data to file's function list */ |
static struct func *afunction(char *name, char *file, int x, int y, int count) { |
struct file *p = findfile(file); |
struct func *q; |
|
assert(p); |
for (q = p->funcs; q && name != q->name; q = q->link) |
; |
if (!q) { |
struct func **r; |
NEW(q, PERM); |
q->name = name; |
q->count.x = x; |
q->count.y = y; |
q->count.count = 0; |
q->callers = 0; |
for (r = &p->funcs; *r && compare(&q->count, &(*r)->count) > 0; r = &(*r)->link) |
; |
q->link = *r; |
*r = q; |
} |
q->count.count += count; |
return q; |
} |
|
/* apoint - append execution point i to file's data */ |
static void apoint(int i, char *file, int x, int y, int count) { |
struct file *p = findfile(file); |
|
assert(p); |
if (i >= p->size) { |
int j; |
if (p->size == 0) { |
p->size = i >= 200 ? 2*i : 200; |
p->counts = newarray(p->size, sizeof *p->counts, PERM); |
} else { |
struct count *new; |
p->size = 2*i; |
new = newarray(p->size, sizeof *new, PERM); |
for (j = 0; j < p->count; j++) |
new[j] = p->counts[j]; |
p->counts = new; |
} |
for (j = p->count; j < p->size; j++) { |
static struct count z; |
p->counts[j] = z; |
} |
} |
if (p->counts[i].x != x || p->counts[i].y != y) |
for (i = 0; i < p->count; i++) |
if (p->counts[i].x == x && p->counts[i].y == y) |
break; |
if (i >= p->count) |
if (i >= p->size) |
apoint(i, file, x, y, count); |
else { |
p->count = i + 1; |
p->counts[i].x = x; |
p->counts[i].y = y; |
p->counts[i].count = count; |
} |
else |
p->counts[i].count += count; |
} |
|
/* findcount - return count associated with (file,x,y) or -1 */ |
int findcount(char *file, int x, int y) { |
static struct file *cursor; |
|
if (cursor == 0 || cursor->name != file) |
cursor = findfile(file); |
if (cursor) { |
int l, u; |
struct count *c = cursor->counts; |
for (l = 0, u = cursor->count - 1; l <= u; ) { |
int k = (l + u)/2; |
if (c[k].y > y || c[k].y == y && c[k].x > x) |
u = k - 1; |
else if (c[k].y < y || c[k].y == y && c[k].x < x) |
l = k + 1; |
else |
return c[k].count; |
} |
} |
return -1; |
} |
|
/* findfunc - return count associated with function name in file or -1 */ |
int findfunc(char *name, char *file) { |
static struct file *cursor; |
|
if (cursor == 0 || cursor->name != file) |
cursor = findfile(file); |
if (cursor) { |
struct func *p; |
for (p = cursor->funcs; p; p = p->link) |
if (p->name == name) |
return p->count.count; |
} |
return -1; |
} |
|
/* getd - read a nonnegative number */ |
static int getd(void) { |
int c, n = 0; |
|
while ((c = getc(fp)) != EOF && (c == ' ' || c == '\n' || c == '\t')) |
; |
if (c >= '0' && c <= '9') { |
do |
n = 10*n + (c - '0'); |
while ((c = getc(fp)) >= '0' && c <= '9'); |
return n; |
} |
return -1; |
} |
|
/* getstr - read a string */ |
static char *getstr(void) { |
int c; |
char buf[MAXTOKEN], *s = buf; |
|
while ((c = getc(fp)) != EOF && c != ' ' && c != '\n' && c != '\t') |
if (s - buf < (int)sizeof buf - 2) |
*s++ = c; |
*s = 0; |
return s == buf ? (char *)0 : string(buf); |
} |
|
/* gather - read prof.out data from fd */ |
static int gather(void) { |
int i, nfiles, nfuncs, npoints; |
char *files[64]; |
|
if ((nfiles = getd()) < 0) |
return 0; |
assert(nfiles < NELEMS(files)); |
for (i = 0; i < nfiles; i++) { |
if ((files[i] = getstr()) == 0) |
return -1; |
if (!findfile(files[i])) { |
struct file *new; |
NEW(new, PERM); |
new->name = files[i]; |
new->size = new->count = 0; |
new->counts = 0; |
new->funcs = 0; |
new->link = filelist; |
filelist = new; |
} |
} |
if ((nfuncs = getd()) < 0) |
return -1; |
for (i = 0; i < nfuncs; i++) { |
struct func *q; |
char *name, *file; |
int f, x, y, count; |
if ((name = getstr()) == 0 || (f = getd()) <= 0 |
|| (x = getd()) < 0 || (y = getd()) < 0 || (count = getd()) < 0) |
return -1; |
q = afunction(name, files[f-1], x, y, count); |
if ((name = getstr()) == 0 || (file = getstr()) == 0 |
|| (x = getd()) < 0 || (y = getd()) < 0) |
return -1; |
if (*name != '?') |
acaller(name, file, x, y, count, q); |
} |
if ((npoints = getd()) < 0) |
return -1; |
for (i = 0; i < npoints; i++) { |
int f, x, y, count; |
if ((f = getd()) < 0 || (x = getd()) < 0 || (y = getd()) < 0 |
|| (count = getd()) < 0) |
return -1; |
if (f) |
apoint(i, files[f-1], x, y, count); |
} |
return 1; |
} |
|
/* process - read prof.out data from file */ |
int process(char *file) { |
int more; |
|
if ((fp = fopen(file, "r")) != NULL) { |
struct file *p; |
while ((more = gather()) > 0) |
; |
fclose(fp); |
if (more < 0) |
return more; |
for (p = filelist; p; p = p->link) |
qsort(p->counts, p->count, sizeof *p->counts, compare); |
return 1; |
} |
return 0; |
} |
/tree.c
0,0 → 1,242
#include "c.h" |
|
static char rcsid[] = "$Id: tree.c,v 1.1 2002/08/28 23:12:47 drh Exp $"; |
|
int where = STMT; |
static int warn; |
static int nid = 1; /* identifies trees & nodes in debugging output */ |
static struct nodeid { |
int printed; |
Tree node; |
} ids[500]; /* if ids[i].node == p, then p's id is i */ |
|
static void printtree1(Tree, int, int); |
|
Tree tree(int op, Type type, Tree left, Tree right) { |
Tree p; |
|
NEW0(p, where); |
p->op = op; |
p->type = type; |
p->kids[0] = left; |
p->kids[1] = right; |
return p; |
} |
|
Tree texpr(Tree (*f)(int), int tok, int a) { |
int save = where; |
Tree p; |
|
where = a; |
p = (*f)(tok); |
where = save; |
return p; |
} |
static Tree root1(Tree p) { |
if (p == NULL) |
return p; |
if (p->type == voidtype) |
warn++; |
switch (generic(p->op)) { |
case COND: { |
Tree q = p->kids[1]; |
assert(q && q->op == RIGHT); |
if (p->u.sym && q->kids[0] && generic(q->kids[0]->op) == ASGN) |
q->kids[0] = root1(q->kids[0]->kids[1]); |
else |
q->kids[0] = root1(q->kids[0]); |
if (p->u.sym && q->kids[1] && generic(q->kids[1]->op) == ASGN) |
q->kids[1] = root1(q->kids[1]->kids[1]); |
else |
q->kids[1] = root1(q->kids[1]); |
p->u.sym = 0; |
if (q->kids[0] == 0 && q->kids[1] == 0) |
p = root1(p->kids[0]); |
} |
break; |
case AND: case OR: |
if ((p->kids[1] = root1(p->kids[1])) == 0) |
p = root1(p->kids[0]); |
break; |
case NOT: |
if (warn++ == 0) |
warning("expression with no effect elided\n"); |
return root1(p->kids[0]); |
case RIGHT: |
if (p->kids[1] == 0) |
return root1(p->kids[0]); |
if (p->kids[0] && p->kids[0]->op == CALL+B |
&& p->kids[1] && p->kids[1]->op == INDIR+B) |
/* avoid premature release of the CALL+B temporary */ |
return p->kids[0]; |
if (p->kids[0] && p->kids[0]->op == RIGHT |
&& p->kids[1] == p->kids[0]->kids[0]) |
/* de-construct e++ construction */ |
return p->kids[0]->kids[1]; |
p = tree(RIGHT, p->type, root1(p->kids[0]), root1(p->kids[1])); |
return p->kids[0] || p->kids[1] ? p : (Tree)0; |
case EQ: case NE: case GT: case GE: case LE: case LT: |
case ADD: case SUB: case MUL: case DIV: case MOD: |
case LSH: case RSH: case BAND: case BOR: case BXOR: |
if (warn++ == 0) |
warning("expression with no effect elided\n"); |
p = tree(RIGHT, p->type, root1(p->kids[0]), root1(p->kids[1])); |
return p->kids[0] || p->kids[1] ? p : (Tree)0; |
case INDIR: |
if (p->type->size == 0 && unqual(p->type) != voidtype) |
warning("reference to `%t' elided\n", p->type); |
if (isptr(p->kids[0]->type) && isvolatile(p->kids[0]->type->type)) |
warning("reference to `volatile %t' elided\n", p->type); |
/* fall thru */ |
case NEG: case BCOM: case FIELD: |
if (warn++ == 0) |
warning("expression with no effect elided\n"); |
return root1(p->kids[0]); |
case ADDRL: case ADDRG: case ADDRF: case CNST: |
if (needconst) |
return p; |
if (warn++ == 0) |
warning("expression with no effect elided\n"); |
return NULL; |
case CVF: |
if (optype(p->op) == I |
|| p->type->size < p->kids[0]->type->size) |
if (warn++ == 0) |
warning("expression with no effect elided\n"); |
return root1(p->kids[0]); |
case CVI: |
if ((optype(p->op) == U || optype(p->op) == I) |
&& p->type->size < p->kids[0]->type->size |
&& specific(p->kids[0]->op) != CALL+I) |
if (warn++ == 0) |
warning("expression with no effect elided\n"); |
return root1(p->kids[0]); |
case CVU: case CVP: |
if (optype(p->op) == U && p->type->size < p->kids[0]->type->size |
|| optype(p->op) == I && p->type->size <= p->kids[0]->type->size) |
if (warn++ == 0) |
warning("expression with no effect elided\n"); |
return root1(p->kids[0]); |
case ARG: case ASGN: case CALL: case JUMP: case LABEL: |
break; |
default: assert(0); |
} |
return p; |
} |
|
Tree root(Tree p) { |
warn = 0; |
return root1(p); |
} |
|
char *opname(int op) { |
static char *opnames[] = { |
"", |
"CNST", |
"ARG", |
"ASGN", |
"INDIR", |
"CVC", |
"CVD", |
"CVF", |
"CVI", |
"CVP", |
"CVS", |
"CVU", |
"NEG", |
"CALL", |
"*LOAD*", |
"RET", |
"ADDRG", |
"ADDRF", |
"ADDRL", |
"ADD", |
"SUB", |
"LSH", |
"MOD", |
"RSH", |
"BAND", |
"BCOM", |
"BOR", |
"BXOR", |
"DIV", |
"MUL", |
"EQ", |
"GE", |
"GT", |
"LE", |
"LT", |
"NE", |
"JUMP", |
"LABEL", |
"AND", |
"NOT", |
"OR", |
"COND", |
"RIGHT", |
"FIELD" |
}, *suffixes[] = { |
"0", "F", "D", "C", "S", "I", "U", "P", "V", "B", |
"10","11","12","13","14","15" |
}; |
|
if (generic(op) >= AND && generic(op) <= FIELD && opsize(op) == 0) |
return opnames[opindex(op)]; |
return stringf("%s%s%s", |
opindex(op) > 0 && opindex(op) < NELEMS(opnames) ? |
opnames[opindex(op)] : stringd(opindex(op)), |
suffixes[optype(op)], opsize(op) > 0 ? stringd(opsize(op)) : ""); |
} |
|
int nodeid(Tree p) { |
int i = 1; |
|
ids[nid].node = p; |
while (ids[i].node != p) |
i++; |
if (i == nid) |
ids[nid++].printed = 0; |
return i; |
} |
|
/* printed - return pointer to ids[id].printed */ |
int *printed(int id) { |
if (id) |
return &ids[id].printed; |
nid = 1; |
return 0; |
} |
|
/* printtree - print tree p on fd */ |
void printtree(Tree p, int fd) { |
(void)printed(0); |
printtree1(p, fd, 1); |
} |
|
/* printtree1 - recursively print tree p */ |
static void printtree1(Tree p, int fd, int lev) { |
FILE *f = fd == 1 ? stdout : stderr; |
int i; |
static char blanks[] = " "; |
|
if (p == 0 || *printed(i = nodeid(p))) |
return; |
fprint(f, "#%d%S%S", i, blanks, i < 10 ? 2 : i < 100 ? 1 : 0, blanks, lev); |
fprint(f, "%s %t", opname(p->op), p->type); |
*printed(i) = 1; |
for (i = 0; i < NELEMS(p->kids); i++) |
if (p->kids[i]) |
fprint(f, " #%d", nodeid(p->kids[i])); |
if (p->op == FIELD && p->u.field) |
fprint(f, " %s %d..%d", p->u.field->name, |
fieldsize(p->u.field) + fieldright(p->u.field), fieldright(p->u.field)); |
else if (generic(p->op) == CNST) |
fprint(f, " %s", vtoa(p->type, p->u.v)); |
else if (p->u.sym) |
fprint(f, " %s", p->u.sym->name); |
if (p->node) |
fprint(f, " node=%p", p->node); |
fprint(f, "\n"); |
for (i = 0; i < NELEMS(p->kids); i++) |
printtree1(p->kids[i], fd, lev + 1); |
} |
/input.c
0,0 → 1,146
#include "c.h" |
|
static char rcsid[] = "$Id: input.c,v 1.1 2002/08/28 23:12:44 drh Exp $"; |
|
static void pragma(void); |
static void resynch(void); |
|
static int bsize; |
static unsigned char buffer[MAXLINE+1 + BUFSIZE+1]; |
unsigned char *cp; /* current input character */ |
char *file; /* current input file name */ |
char *firstfile; /* first input file */ |
unsigned char *limit; /* points to last character + 1 */ |
char *line; /* current line */ |
int lineno; /* line number of current line */ |
|
void nextline(void) { |
do { |
if (cp >= limit) { |
fillbuf(); |
if (cp >= limit) |
cp = limit; |
if (cp == limit) |
return; |
} else { |
lineno++; |
for (line = (char *)cp; *cp==' ' || *cp=='\t'; cp++) |
; |
if (*cp == '#') { |
resynch(); |
nextline(); |
} |
} |
} while (*cp == '\n' && cp == limit); |
} |
void fillbuf(void) { |
if (bsize == 0) |
return; |
if (cp >= limit) |
cp = &buffer[MAXLINE+1]; |
else |
{ |
int n = limit - cp; |
unsigned char *s = &buffer[MAXLINE+1] - n; |
assert(s >= buffer); |
line = (char *)s - ((char *)cp - line); |
while (cp < limit) |
*s++ = *cp++; |
cp = &buffer[MAXLINE+1] - n; |
} |
if (feof(stdin)) |
bsize = 0; |
else |
bsize = fread(&buffer[MAXLINE+1], 1, BUFSIZE, stdin); |
if (bsize < 0) { |
error("read error\n"); |
exit(EXIT_FAILURE); |
} |
limit = &buffer[MAXLINE+1+bsize]; |
*limit = '\n'; |
} |
void input_init(int argc, char *argv[]) { |
static int inited; |
|
if (inited) |
return; |
inited = 1; |
main_init(argc, argv); |
limit = cp = &buffer[MAXLINE+1]; |
bsize = -1; |
lineno = 0; |
file = NULL; |
fillbuf(); |
if (cp >= limit) |
cp = limit; |
nextline(); |
} |
|
/* ident - handle #ident "string" */ |
static void ident(void) { |
while (*cp != '\n' && *cp != '\0') |
cp++; |
} |
|
/* pragma - handle #pragma ref id... */ |
static void pragma(void) { |
if ((t = gettok()) == ID && strcmp(token, "ref") == 0) |
for (;;) { |
while (*cp == ' ' || *cp == '\t') |
cp++; |
if (*cp == '\n' || *cp == 0) |
break; |
if ((t = gettok()) == ID && tsym) { |
tsym->ref++; |
use(tsym, src); |
} |
} |
} |
|
/* resynch - set line number/file name in # n [ "file" ], #pragma, etc. */ |
static void resynch(void) { |
for (cp++; *cp == ' ' || *cp == '\t'; ) |
cp++; |
if (limit - cp < MAXLINE) |
fillbuf(); |
if (strncmp((char *)cp, "pragma", 6) == 0) { |
cp += 6; |
pragma(); |
} else if (strncmp((char *)cp, "ident", 5) == 0) { |
cp += 5; |
ident(); |
} else if (*cp >= '0' && *cp <= '9') { |
line: for (lineno = 0; *cp >= '0' && *cp <= '9'; ) |
lineno = 10*lineno + *cp++ - '0'; |
lineno--; |
while (*cp == ' ' || *cp == '\t') |
cp++; |
if (*cp == '"') { |
file = (char *)++cp; |
while (*cp && *cp != '"' && *cp != '\n') |
cp++; |
file = stringn(file, (char *)cp - file); |
if (*cp == '\n') |
warning("missing \" in preprocessor line\n"); |
if (firstfile == 0) |
firstfile = file; |
} |
} else if (strncmp((char *)cp, "line", 4) == 0) { |
for (cp += 4; *cp == ' ' || *cp == '\t'; ) |
cp++; |
if (*cp >= '0' && *cp <= '9') |
goto line; |
if (Aflag >= 2) |
warning("unrecognized control line\n"); |
} else if (Aflag >= 2 && *cp != '\n') |
warning("unrecognized control line\n"); |
while (*cp) |
if (*cp++ == '\n') |
if (cp == limit + 1) { |
nextline(); |
if (cp == limit) |
break; |
} else |
break; |
} |
|
/alpha.md
0,0 → 1,1192
%{ |
#define INTTMP ((0xff<<1)|(1<<22)|(1<<25)|(1<<27)) |
#define INTVAR (0x3f<<9) |
#define FLTTMP ((0x3f<<10)|(0x1ff<<22)) |
#define FLTVAR (0xff<<2) |
|
#define INTRET 0x00000001 |
#define FLTRET 0x00000003 |
|
#define readsreg(p) \ |
(generic((p)->op)==INDIR && (p)->kids[0]->op==VREG+P) |
#define setsrc(d) ((d) && (d)->x.regnode && \ |
(d)->x.regnode->set == src->x.regnode->set && \ |
(d)->x.regnode->mask&src->x.regnode->mask) |
|
#define relink(a, b) ((b)->x.prev = (a), (a)->x.next = (b)) |
|
#include "c.h" |
#define NODEPTR_TYPE Node |
#define OP_LABEL(p) ((p)->op) |
#define LEFT_CHILD(p) ((p)->kids[0]) |
#define RIGHT_CHILD(p) ((p)->kids[1]) |
#define STATE_LABEL(p) ((p)->x.state) |
static void address(Symbol, Symbol, long); |
static void blkfetch(int, int, int, int); |
static void blkloop(int, int, int, int, int, int[]); |
static void blkstore(int, int, int, int); |
static void defaddress(Symbol); |
static void defconst(int, int, Value); |
static void defstring(int, char *); |
static void defsymbol(Symbol); |
static void doarg(Node); |
static void emit2(Node); |
static void export(Symbol); |
static void clobber(Node); |
static void function(Symbol, Symbol [], Symbol [], int); |
static void global(Symbol); |
static void import(Symbol); |
static void local(Symbol); |
static void progbeg(int, char **); |
static void progend(void); |
static void segment(int); |
static void space(int); |
static void target(Node); |
static Symbol ireg[32], freg[32]; |
static Symbol iregw, fregw; |
|
static int tmpregs[] = {4, 2, 3}; |
static Symbol blkreg; |
|
static int cseg; |
|
static char *currentfile; |
|
%} |
%start stmt |
%term CNSTF4=4113 |
%term CNSTF8=8209 |
%term CNSTF16=16401 |
%term CNSTI1=1045 |
%term CNSTI2=2069 |
%term CNSTI4=4117 |
%term CNSTI8=8213 |
%term CNSTP4=4119 |
%term CNSTP8=8215 |
%term CNSTU1=1046 |
%term CNSTU2=2070 |
%term CNSTU4=4118 |
%term CNSTU8=8214 |
|
%term ARGB=41 |
%term ARGF4=4129 |
%term ARGF8=8225 |
%term ARGF16=16417 |
%term ARGI4=4133 |
%term ARGI8=8229 |
%term ARGP4=4135 |
%term ARGP8=8231 |
%term ARGU4=4134 |
%term ARGU8=8230 |
|
%term ASGNB=57 |
%term ASGNF4=4145 |
%term ASGNF8=8241 |
%term ASGNF16=16433 |
%term ASGNI1=1077 |
%term ASGNI2=2101 |
%term ASGNI4=4149 |
%term ASGNI8=8245 |
%term ASGNP4=4151 |
%term ASGNP8=8247 |
%term ASGNU1=1078 |
%term ASGNU2=2102 |
%term ASGNU4=4150 |
%term ASGNU8=8246 |
|
%term INDIRB=73 |
%term INDIRF4=4161 |
%term INDIRF8=8257 |
%term INDIRF16=16449 |
%term INDIRI1=1093 |
%term INDIRI2=2117 |
%term INDIRI4=4165 |
%term INDIRI8=8261 |
%term INDIRP4=4167 |
%term INDIRP8=8263 |
%term INDIRU1=1094 |
%term INDIRU2=2118 |
%term INDIRU4=4166 |
%term INDIRU8=8262 |
|
%term CVFF4=4209 |
%term CVFF8=8305 |
%term CVFF16=16497 |
%term CVFI4=4213 |
%term CVFI8=8309 |
|
%term CVIF4=4225 |
%term CVIF8=8321 |
%term CVIF16=16513 |
%term CVII1=1157 |
%term CVII2=2181 |
%term CVII4=4229 |
%term CVII8=8325 |
%term CVIU1=1158 |
%term CVIU2=2182 |
%term CVIU4=4230 |
%term CVIU8=8326 |
|
%term CVPP4=4247 |
%term CVPP8=8343 |
%term CVPP16=16535 |
%term CVPU4=4246 |
%term CVPU8=8342 |
|
%term CVUI1=1205 |
%term CVUI2=2229 |
%term CVUI4=4277 |
%term CVUI8=8373 |
%term CVUP4=4279 |
%term CVUP8=8375 |
%term CVUP16=16567 |
%term CVUU1=1206 |
%term CVUU2=2230 |
%term CVUU4=4278 |
%term CVUU8=8374 |
|
%term NEGF4=4289 |
%term NEGF8=8385 |
%term NEGF16=16577 |
%term NEGI4=4293 |
%term NEGI8=8389 |
|
%term CALLB=217 |
%term CALLF4=4305 |
%term CALLF8=8401 |
%term CALLF16=16593 |
%term CALLI4=4309 |
%term CALLI8=8405 |
%term CALLP4=4311 |
%term CALLP8=8407 |
%term CALLU4=4310 |
%term CALLU8=8406 |
%term CALLV=216 |
|
%term RETF4=4337 |
%term RETF8=8433 |
%term RETF16=16625 |
%term RETI4=4341 |
%term RETI8=8437 |
%term RETP4=4343 |
%term RETP8=8439 |
%term RETU4=4342 |
%term RETU8=8438 |
%term RETV=248 |
|
%term ADDRGP4=4359 |
%term ADDRGP8=8455 |
|
%term ADDRFP4=4375 |
%term ADDRFP8=8471 |
|
%term ADDRLP4=4391 |
%term ADDRLP8=8487 |
|
%term ADDF4=4401 |
%term ADDF8=8497 |
%term ADDF16=16689 |
%term ADDI4=4405 |
%term ADDI8=8501 |
%term ADDP4=4407 |
%term ADDP8=8503 |
%term ADDU4=4406 |
%term ADDU8=8502 |
|
%term SUBF4=4417 |
%term SUBF8=8513 |
%term SUBF16=16705 |
%term SUBI4=4421 |
%term SUBI8=8517 |
%term SUBP4=4423 |
%term SUBP8=8519 |
%term SUBU4=4422 |
%term SUBU8=8518 |
|
%term LSHI4=4437 |
%term LSHI8=8533 |
%term LSHU4=4438 |
%term LSHU8=8534 |
|
%term MODI4=4453 |
%term MODI8=8549 |
%term MODU4=4454 |
%term MODU8=8550 |
|
%term RSHI4=4469 |
%term RSHI8=8565 |
%term RSHU4=4470 |
%term RSHU8=8566 |
|
%term BANDI4=4485 |
%term BANDI8=8581 |
%term BANDU4=4486 |
%term BANDU8=8582 |
|
%term BCOMI4=4501 |
%term BCOMI8=8597 |
%term BCOMU4=4502 |
%term BCOMU8=8598 |
|
%term BORI4=4517 |
%term BORI8=8613 |
%term BORU4=4518 |
%term BORU8=8614 |
|
%term BXORI4=4533 |
%term BXORI8=8629 |
%term BXORU4=4534 |
%term BXORU8=8630 |
|
%term DIVF4=4545 |
%term DIVF8=8641 |
%term DIVF16=16833 |
%term DIVI4=4549 |
%term DIVI8=8645 |
%term DIVU4=4550 |
%term DIVU8=8646 |
|
%term MULF4=4561 |
%term MULF8=8657 |
%term MULF16=16849 |
%term MULI4=4565 |
%term MULI8=8661 |
%term MULU4=4566 |
%term MULU8=8662 |
|
%term EQF4=4577 |
%term EQF8=8673 |
%term EQF16=16865 |
%term EQI4=4581 |
%term EQI8=8677 |
%term EQU4=4582 |
%term EQU8=8678 |
|
%term GEF4=4593 |
%term GEF8=8689 |
%term GEI4=4597 |
%term GEI8=8693 |
%term GEI16=16885 |
%term GEU4=4598 |
%term GEU8=8694 |
|
%term GTF4=4609 |
%term GTF8=8705 |
%term GTF16=16897 |
%term GTI4=4613 |
%term GTI8=8709 |
%term GTU4=4614 |
%term GTU8=8710 |
|
%term LEF4=4625 |
%term LEF8=8721 |
%term LEF16=16913 |
%term LEI4=4629 |
%term LEI8=8725 |
%term LEU4=4630 |
%term LEU8=8726 |
|
%term LTF4=4641 |
%term LTF8=8737 |
%term LTF16=16929 |
%term LTI4=4645 |
%term LTI8=8741 |
%term LTU4=4646 |
%term LTU8=8742 |
|
%term NEF4=4657 |
%term NEF8=8753 |
%term NEF16=16945 |
%term NEI4=4661 |
%term NEI8=8757 |
%term NEU4=4662 |
%term NEU8=8758 |
|
%term JUMPV=584 |
|
%term LABELV=600 |
|
%term LOADB=233 |
%term LOADF4=4321 |
%term LOADF8=8417 |
%term LOADF16=16609 |
%term LOADI1=1253 |
%term LOADI2=2277 |
%term LOADI4=4325 |
%term LOADI8=8421 |
%term LOADP4=4327 |
%term LOADP8=8423 |
%term LOADU1=1254 |
%term LOADU2=2278 |
%term LOADU4=4326 |
%term LOADU8=8422 |
|
%term VREGP=711 |
%% |
reg: INDIRI1(VREGP) "# read register\n" |
reg: INDIRU1(VREGP) "# read register\n" |
|
reg: INDIRI2(VREGP) "# read register\n" |
reg: INDIRU2(VREGP) "# read register\n" |
|
reg: INDIRF4(VREGP) "# read register\n" |
reg: INDIRI4(VREGP) "# read register\n" |
reg: INDIRP4(VREGP) "# read register\n" |
reg: INDIRU4(VREGP) "# read register\n" |
|
reg: INDIRF8(VREGP) "# read register\n" |
reg: INDIRI8(VREGP) "# read register\n" |
reg: INDIRP8(VREGP) "# read register\n" |
reg: INDIRU8(VREGP) "# read register\n" |
|
stmt: ASGNI1(VREGP,reg) "# write register\n" |
stmt: ASGNU1(VREGP,reg) "# write register\n" |
|
stmt: ASGNI2(VREGP,reg) "# write register\n" |
stmt: ASGNU2(VREGP,reg) "# write register\n" |
|
stmt: ASGNF4(VREGP,reg) "# write register\n" |
stmt: ASGNI4(VREGP,reg) "# write register\n" |
stmt: ASGNP4(VREGP,reg) "# write register\n" |
stmt: ASGNU4(VREGP,reg) "# write register\n" |
|
stmt: ASGNF8(VREGP,reg) "# write register\n" |
stmt: ASGNI8(VREGP,reg) "# write register\n" |
stmt: ASGNP8(VREGP,reg) "# write register\n" |
stmt: ASGNU8(VREGP,reg) "# write register\n" |
con: CNSTI1 "%a" |
con: CNSTU1 "%a" |
|
con: CNSTI2 "%a" |
con: CNSTU2 "%a" |
|
con: CNSTI4 "%a" |
con: CNSTU4 "%a" |
con: CNSTP4 "%a" |
|
con: CNSTI8 "%a" |
con: CNSTU8 "%a" |
con: CNSTP8 "%a" |
stmt: reg "" |
acon: con "%0" |
acon: ADDRGP8 "%a" |
|
addr: ADDI4(reg,acon) "%1($%0)" |
addr: ADDI8(reg,acon) "%1($%0)" |
addr: ADDU8(reg,acon) "%1($%0)" |
addr: ADDP8(reg,acon) "%1($%0)" |
|
addr: acon "%0" |
addr: reg "($%0)" |
|
addr: ADDRFP8 "%a+%F($sp)" |
addr: ADDRLP8 "%a+%F($sp)" |
|
reg: addr "lda $%c,%0\n" 1 |
|
reg: CNSTI1 "# reg\n" range(a, 0, 0) |
reg: CNSTI2 "# reg\n" range(a, 0, 0) |
reg: CNSTI4 "# reg\n" range(a, 0, 0) |
reg: CNSTI8 "# reg\n" range(a, 0, 0) |
reg: CNSTU1 "# reg\n" range(a, 0, 0) |
reg: CNSTU2 "# reg\n" range(a, 0, 0) |
reg: CNSTU4 "# reg\n" range(a, 0, 0) |
reg: CNSTU8 "# reg\n" range(a, 0, 0) |
reg: CNSTP8 "# reg\n" range(a, 0, 0) |
|
stmt: ASGNI1(addr,reg) "stb $%1,%0\n" 1 |
stmt: ASGNU1(addr,reg) "stb $%1,%0\n" 1 |
stmt: ASGNI2(addr,reg) "stw $%1,%0\n" 1 |
stmt: ASGNU2(addr,reg) "stw $%1,%0\n" 1 |
|
stmt: ASGNI4(addr,reg) "stl $%1,%0\n" 1 |
stmt: ASGNU4(addr,reg) "stl $%1,%0\n" 1 |
stmt: ASGNI8(addr,reg) "stq $%1,%0\n" 1 |
stmt: ASGNU8(addr,reg) "stq $%1,%0\n" 1 |
stmt: ASGNP8(addr,reg) "stq $%1,%0\n" 1 |
|
reg: INDIRI1(reg) "ldb $%c,($%0)\n" 1 |
reg: INDIRI2(reg) "ldw $%c,($%0)\n" 1 |
reg: INDIRI4(addr) "ldl $%c,%0\n" 1 |
reg: INDIRI8(addr) "ldq $%c,%0\n" 1 |
reg: INDIRP8(addr) "ldq $%c,%0\n" 1 |
reg: INDIRU1(reg) "ldbu $%c,($%0)\n" 1 |
reg: INDIRU2(reg) "ldwu $%c,($%0)\n" 1 |
reg: INDIRU4(addr) "ldl $%c,%0\nzap $%c,240,$%c\n" 2 |
reg: INDIRU8(addr) "ldq $%c,%0\n" 1 |
|
reg: CVII4(INDIRI1(reg)) "ldb $%c,($%0)\n" 1 |
reg: CVII8(INDIRI1(reg)) "ldb $%c,($%0)\n" 1 |
reg: CVII4(INDIRI2(reg)) "ldw $%c,($%0)\n" 1 |
reg: CVII8(INDIRI2(reg)) "ldw $%c,($%0)\n" 1 |
reg: CVII8(INDIRI4(addr)) "ldl $%c,%0\n" 1 |
|
reg: CVUU4(INDIRU1(reg)) "ldbu $%c,($%0)\n" 1 |
reg: CVUU8(INDIRU1(reg)) "ldbu $%c,($%0)\n" 1 |
reg: CVUU4(INDIRU2(reg)) "ldwu $%c,($%0)\n" 1 |
reg: CVUU8(INDIRU2(reg)) "ldwu $%c,($%0)\n" 1 |
reg: CVUU8(INDIRU4(addr)) "ldl $%c,%0\nzap $%c,240,$%c\n" 2 |
|
reg: CVUI4(INDIRU1(reg)) "ldbu $%c,($%0)\n" 1 |
reg: CVUI8(INDIRU1(reg)) "ldbu $%c,($%0)\n" 1 |
reg: CVUI4(INDIRU2(reg)) "ldwu $%c,($%0)\n" 1 |
reg: CVUI8(INDIRU2(reg)) "ldwu $%c,($%0)\n" 1 |
reg: CVUI8(INDIRU4(addr)) "ldl $%c,%0\nzap $%c,240,$%c\n" 2 |
|
reg: CVIU8(reg) "mov $%0,$%c\n" move(a) |
|
reg: INDIRF4(addr) "lds $f%c,%0\n" 1 |
reg: INDIRF8(addr) "ldt $f%c,%0\n" 1 |
stmt: ASGNF4(addr,reg) "sts $f%1,%0\n" 1 |
stmt: ASGNF8(addr,reg) "stt $f%1,%0\n" 1 |
|
reg: MULI4(reg,rc) "mull $%0,%1,$%c\n" 1 |
reg: MULI8(reg,rc) "mulq $%0,%1,$%c\n" 1 |
reg: MULU4(reg,rc) "mull $%0,%1,$%c\nzap $%c,240,$%c\n" 2 |
reg: MULU8(reg,rc) "mulq $%0,%1,$%c\n" 1 |
|
reg: DIVI4(reg,rc) "divl $%0,%1,$%c\n" 1 |
reg: DIVI8(reg,rc) "divq $%0,%1,$%c\n" 1 |
reg: DIVU4(reg,rc) "divlu $%0,%1,$%c\n" 1 |
reg: DIVU8(reg,rc) "divqu $%0,%1,$%c\n" 1 |
reg: MODI4(reg,rc) "reml $%0,%1,$%c\n" 1 |
reg: MODI8(reg,rc) "remq $%0,%1,$%c\n" 1 |
reg: MODU4(reg,rc) "remlu $%0,%1,$%c\n" 1 |
reg: MODU8(reg,rc) "remqu $%0,%1,$%c\n" 1 |
|
rc: con "%0" |
rc: reg "$%0" |
|
reg: ADDI4(reg,rc) "addl $%0,%1,$%c\n" 1 |
reg: ADDI8(reg,rc) "addq $%0,%1,$%c\n" 1 |
reg: ADDP8(reg,rc) "addq $%0,%1,$%c\n" 1 |
reg: ADDU4(reg,rc) "addl $%0,%1,$%c\nzap $%c,240,$%c\n" 2 |
reg: ADDU8(reg,rc) "addq $%0,%1,$%c\n" 1 |
reg: SUBI4(reg,rc) "subl $%0,%1,$%c\n" 1 |
reg: SUBI8(reg,rc) "subq $%0,%1,$%c\n" 1 |
reg: SUBP8(reg,rc) "subq $%0,%1,$%c\n" 1 |
reg: SUBU4(reg,rc) "subl $%0,%1,$%c\nzap $%c,240,$%c\n" 2 |
reg: SUBU8(reg,rc) "subq $%0,%1,$%c\n" 1 |
|
reg: BANDI4(reg,rc) "and $%0,%1,$%c\naddl $%c,0,$%c\n" 2 |
reg: BANDI8(reg,rc) "and $%0,%1,$%c\n" 1 |
reg: BANDU4(reg,rc) "and $%0,%1,$%c\n" 1 |
reg: BANDU8(reg,rc) "and $%0,%1,$%c\n" 1 |
reg: BORI4(reg,rc) "or $%0,%1,$%c\naddl $%c,0,$%c\n" 2 |
reg: BORI8(reg,rc) "or $%0,%1,$%c\n" 1 |
reg: BORU4(reg,rc) "or $%0,%1,$%c\n" 1 |
reg: BORU8(reg,rc) "or $%0,%1,$%c\n" 1 |
reg: BXORI4(reg,rc) "xor $%0,%1,$%c\naddl $%c,0,$%c\n" 2 |
reg: BXORI8(reg,rc) "xor $%0,%1,$%c\n" 1 |
reg: BXORU4(reg,rc) "xor $%0,%1,$%c\n" 1 |
reg: BXORU8(reg,rc) "xor $%0,%1,$%c\n" 1 |
|
rc6: CNSTI4 "%a" range(a,0,63) |
rc6: CNSTI8 "%a" range(a,0,63) |
rc6: reg "$%0" |
|
reg: LSHI4(reg,rc6) "sll $%0,%1,$%c\naddl $%c,0,$%c\n" 2 |
reg: LSHI8(reg,rc6) "sll $%0,%1,$%c\n" 1 |
reg: LSHU4(reg,rc6) "sll $%0,%1,$%c\nzap $%c,240,$%c\n" 2 |
reg: LSHU8(reg,rc6) "sll $%0,%1,$%c\n" 1 |
reg: RSHI4(reg,rc6) "sra $%0,%1,$%c\naddl $%c,0,$%c\n" 2 |
reg: RSHI8(reg,rc6) "sra $%0,%1,$%c\n" 1 |
reg: RSHU4(reg,rc6) "srl $%0,%1,$%c\n" 1 |
reg: RSHU8(reg,rc6) "srl $%0,%1,$%c\n" 1 |
|
reg: BCOMI4(reg) "not $%0,$%c\naddl $%c,0,$%c\n" 2 |
reg: BCOMU4(reg) "not $%0,$%c\nzap $%c,240,$%c\n" 2 |
reg: BCOMI8(reg) "not $%0,$%c\n" 1 |
reg: BCOMU8(reg) "not $%0,$%c\n" 1 |
reg: NEGI4(reg) "negl $%0,$%c\n" 1 |
reg: NEGI8(reg) "negq $%0,$%c\n" 1 |
reg: LOADI1(reg) "mov $%0,$%c\n" move(a) |
reg: LOADI2(reg) "mov $%0,$%c\n" move(a) |
reg: LOADI4(reg) "mov $%0,$%c\n" move(a) |
reg: LOADI8(reg) "mov $%0,$%c\n" move(a) |
reg: LOADP8(reg) "mov $%0,$%c\n" move(a) |
reg: LOADU1(reg) "mov $%0,$%c\n" move(a) |
reg: LOADU2(reg) "mov $%0,$%c\n" move(a) |
reg: LOADU4(reg) "mov $%0,$%c\n" move(a) |
reg: LOADU8(reg) "mov $%0,$%c\n" move(a) |
|
reg: ADDF4(reg,reg) "adds $f%0,$f%1,$f%c\n" 1 |
reg: ADDF8(reg,reg) "addt $f%0,$f%1,$f%c\n" 1 |
reg: DIVF4(reg,reg) "divs $f%0,$f%1,$f%c\n" 1 |
reg: DIVF8(reg,reg) "divt $f%0,$f%1,$f%c\n" 1 |
reg: MULF4(reg,reg) "muls $f%0,$f%1,$f%c\n" 1 |
reg: MULF8(reg,reg) "mult $f%0,$f%1,$f%c\n" 1 |
reg: SUBF4(reg,reg) "subs $f%0,$f%1,$f%c\n" 1 |
reg: SUBF8(reg,reg) "subt $f%0,$f%1,$f%c\n" 1 |
reg: LOADF4(reg) "fmov $f%0,$f%c\n" move(a) |
reg: LOADF8(reg) "fmov $f%0,$f%c\n" move(a) |
reg: NEGF4(reg) "negs $f%0,$f%c\n" 1 |
reg: NEGF8(reg) "negt $f%0,$f%c\n" 1 |
reg: CVII4(reg) "sll $%0,8*(8-%a),$%c\nsra $%c,8*(8-%a),$%c\n" 2 |
reg: CVII8(reg) "sll $%0,8*(8-%a),$%c\nsra $%c,8*(8-%a),$%c\n" 2 |
reg: CVUI4(reg) "and $%0,(1<<(8*%a))-1,$%c\n" 1 |
reg: CVUI8(reg) "and $%0,(1<<(8*%a))-1,$%c\n" 1 |
reg: CVUU4(reg) "and $%0,(1<<(8*%a))-1,$%c\n" 1 |
reg: CVUU8(reg) "and $%0,(1<<(8*%a))-1,$%c\n" 1 |
|
reg: CVUP8(reg) "and $%0,(1<<(8*%a))-1,$%c\n" 1 |
|
reg: CVFF4(reg) "cvtts $f%0,$f%c\n" 1 |
reg: CVFF8(reg) "cvtst $f%0,$f%c\n" 1 |
|
reg: CVIF4(reg) "stq $%0,-56+%F($sp)\nldt $%f%c,-56+%F($sp)\ncvtqs $f%c,$f%c\n" 3 |
reg: CVIF8(reg) "stq $%0,-56+%F($sp)\nldt $%f%c,-56+%F($sp)\ncvtqt $f%c,$f%c\n" 3 |
reg: CVIF4(INDIRI4(addr)) "lds $f%c,%0\ncvtlq $f%c,$f%c\ncvtqs $f%c,$f%c\n" 3 |
reg: CVIF4(INDIRI8(addr)) "ldt $f%c,%0\ncvtqs $f%c,$f%c\n" 2 |
reg: CVIF8(INDIRI4(addr)) "lds $f%c,%0\ncvtlq $f%c,$f%c\ncvtqt $f%c,$f%c\n" 3 |
reg: CVIF8(INDIRI8(addr)) "ldt $f%c,%0\ncvtqt $f%c,$f%c\n" 2 |
|
reg: CVFI4(reg) "cvttqc $f%0,$f1\ncvtql $f1,$f1\nsts $f1,-56+%F($sp)\nldl $%c,-56+%F($sp)\n" 4 |
reg: CVFI8(reg) "cvttqc $f%0,$f1\nstt $f1,-56+%F($sp)\nldq $%c,-56+%F($sp)\n" 3 |
|
stmt: LABELV "%a:\n" |
|
stmt: JUMPV(acon) "br %0\n" 1 |
stmt: JUMPV(reg) "jmp ($%0)\n" 1 |
|
stmt: EQI4(reg,rc6) "cmpeq $%0,%1,$23\nbne $23,%a\n" 2 |
stmt: EQU4(reg,rc6) "cmpeq $%0,%1,$23\nbne $23,%a\n" 2 |
stmt: EQI8(reg,rc6) "cmpeq $%0,%1,$23\nbne $23,%a\n" 2 |
stmt: EQU8(reg,rc6) "cmpeq $%0,%1,$23\nbne $23,%a\n" 2 |
stmt: NEI4(reg,rc6) "cmpeq $%0,%1,$23\nbeq $23,%a\n" 2 |
stmt: NEU4(reg,rc6) "cmpeq $%0,%1,$23\nbeq $23,%a\n" 2 |
stmt: NEI8(reg,rc6) "cmpeq $%0,%1,$23\nbeq $23,%a\n" 2 |
stmt: NEU8(reg,rc6) "cmpeq $%0,%1,$23\nbeq $23,%a\n" 2 |
stmt: GEI4(reg,rc6) "cmplt $%0,%1,$23\nbeq $23,%a\n" 2 |
stmt: GEI8(reg,rc6) "cmplt $%0,%1,$23\nbeq $23,%a\n" 2 |
stmt: GEU4(reg,rc6) "cmpult $%0,%1,$23\nbeq $23,%a\n" 1 |
stmt: GEU8(reg,rc6) "cmpult $%0,%1,$23\nbeq $23,%a\n" 1 |
stmt: GTI4(reg,rc6) "cmple $%0,%1,$23\nbeq $23,%a\n" 2 |
stmt: GTI8(reg,rc6) "cmple $%0,%1,$23\nbeq $23,%a\n" 2 |
stmt: GTU4(reg,rc6) "cmpule $%0,%1,$23\nbeq $23,%a\n" 1 |
stmt: GTU8(reg,rc6) "cmpule $%0,%1,$23\nbeq $23,%a\n" 1 |
stmt: LEI4(reg,rc6) "cmple $%0,%1,$23\nbne $23,%a\n" 2 |
stmt: LEI8(reg,rc6) "cmple $%0,%1,$23\nbne $23,%a\n" 2 |
stmt: LEU4(reg,rc6) "cmpule $%0,%1,$23\nbne $23,%a\n" 2 |
stmt: LEU8(reg,rc6) "cmpule $%0,%1,$23\nbne $23,%a\n" 2 |
stmt: LTI4(reg,rc6) "cmplt $%0,%1,$23\nbne $23,%a\n" 2 |
stmt: LTI8(reg,rc6) "cmplt $%0,%1,$23\nbne $23,%a\n" 2 |
stmt: LTU4(reg,rc6) "cmpult $%0,%1,$23\nbne $23,%a\n" 2 |
stmt: LTU8(reg,rc6) "cmpult $%0,%1,$23\nbne $23,%a\n" 2 |
|
stmt: EQF4(reg,reg) "cmpteq $f%0,$f%1,$f1\nfbne $f1,%a\n" 2 |
stmt: EQF8(reg,reg) "cmpteq $f%0,$f%1,$f1\nfbne $f1,%a\n" 2 |
stmt: LEF4(reg,reg) "cmptle $f%0,$f%1,$f1\nfbne $f1,%a\n" 2 |
stmt: LEF8(reg,reg) "cmptle $f%0,$f%1,$f1\nfbne $f1,%a\n" 2 |
stmt: LTF4(reg,reg) "cmptlt $f%0,$f%1,$f1\nfbne $f1,%a\n" 2 |
stmt: LTF8(reg,reg) "cmptlt $f%0,$f%1,$f1\nfbne $f1,%a\n" 2 |
|
stmt: NEF4(reg,reg) "cmpteq $f%0,$f%1,$f1\nfbeq $f1,%a\n" 2 |
stmt: NEF8(reg,reg) "cmpteq $f%0,$f%1,$f1\nfbeq $f1,%a\n" 2 |
stmt: GEF4(reg,reg) "cmptlt $f%0,$f%1,$f1\nfbeq $f1,%a\n" 2 |
stmt: GEF8(reg,reg) "cmptlt $f%0,$f%1,$f1\nfbeq $f1,%a\n" 2 |
stmt: GTF4(reg,reg) "cmptle $f%0,$f%1,$f1\nfbeq $f1,%a\n" 2 |
stmt: GTF8(reg,reg) "cmptle $f%0,$f%1,$f1\nfbeq $f1,%a\n" 2 |
|
ar: ADDRGP8 "%a" |
ar: reg "($%0)" |
|
reg: CALLF4(ar) "jsr $26,%0\nldgp $gp,0($26)\n" 2 |
reg: CALLF8(ar) "jsr $26,%0\nldgp $gp,0($26)\n" 2 |
reg: CALLI4(ar) "jsr $26,%0\nldgp $gp,0($26)\n" 2 |
reg: CALLI8(ar) "jsr $26,%0\nldgp $gp,0($26)\n" 2 |
reg: CALLP8(ar) "jsr $26,%0\nldgp $gp,0($26)\n" 2 |
reg: CALLU4(ar) "jsr $26,%0\nldgp $gp,0($26)\n" 2 |
reg: CALLU8(ar) "jsr $26,%0\nldgp $gp,0($26)\n" 2 |
stmt: CALLV(ar) "jsr $26,%0\nldgp $gp,0($26)\n" 2 |
|
stmt: RETF4(reg) "# ret\n" 1 |
stmt: RETF8(reg) "# ret\n" 1 |
stmt: RETI4(reg) "# ret\n" 1 |
stmt: RETU4(reg) "# ret\n" 1 |
stmt: RETI8(reg) "# ret\n" 1 |
stmt: RETU8(reg) "# ret\n" 1 |
stmt: RETP8(reg) "# ret\n" 1 |
stmt: RETV(reg) "# ret\n" 1 |
|
stmt: ARGF4(reg) "# arg\n" 1 |
stmt: ARGF8(reg) "# arg\n" 1 |
stmt: ARGI4(reg) "# arg\n" 1 |
stmt: ARGI8(reg) "# arg\n" 1 |
stmt: ARGP8(reg) "# arg\n" 1 |
stmt: ARGU4(reg) "# arg\n" 1 |
stmt: ARGU8(reg) "# arg\n" 1 |
|
stmt: ARGB(INDIRB(reg)) "# argb %0\n" 1 |
stmt: ASGNB(reg,INDIRB(reg)) "# asgnb %0 %1\n" 1 |
|
%% |
static void progend(void){} |
|
static void progbeg(int argc, char *argv[]) { |
int i; |
|
{ |
union { |
char c; |
int i; |
} u; |
u.i = 0; |
u.c = 1; |
swap = ((int)(u.i == 1)) != IR->little_endian; |
} |
parseflags(argc, argv); |
|
for (i = 0; i < 32; i++) |
freg[i] = mkreg("%d", i, 1, FREG); |
for (i = 0; i < 32; i++) |
ireg[i] = mkreg("%d", i, 1, IREG); |
ireg[29]->x.name = "gp"; |
ireg[30]->x.name = "sp"; |
fregw = mkwildcard(freg); |
iregw = mkwildcard(ireg); |
|
tmask[IREG] = INTTMP; tmask[FREG] = FLTTMP; |
vmask[IREG] = INTVAR; vmask[FREG] = FLTVAR; |
|
blkreg = mkreg("1", 1, 0xf, IREG); |
|
} |
|
static Symbol rmap(int opk) { |
switch (optype(opk)) { |
case I: case U: case P: case B: |
return iregw; |
case F: |
return fregw; |
default: |
return 0; |
} |
} |
|
static Symbol argreg(int offset, int ty) { |
if (offset >= 48) |
return NULL; |
else if (ty == F) |
return freg[(offset/8) + 16]; |
else |
return ireg[(offset/8) + 16]; |
} |
|
static void target(Node p) { |
assert(p); |
switch (specific(p->op)) { |
case CNST+I: case CNST+U: case CNST+P: |
if (range(p, 0, 0) == 0) { |
setreg(p, ireg[31]); |
p->x.registered = 1; |
} |
break; |
case CNST+F: |
if (p->syms[0]->u.c.v.d == 0) { |
setreg(p, freg[31]); |
p->x.registered = 1; |
} |
break; |
|
case CALL+V: |
rtarget(p, 0, ireg[27]); |
break; |
case CALL+F: |
rtarget(p, 0, ireg[27]); |
setreg(p, freg[0]); |
break; |
case CALL+I: case CALL+P: case CALL+U: |
rtarget(p, 0, ireg[27]); |
setreg(p, ireg[0]); |
break; |
case RET+F: |
rtarget(p, 0, freg[0]); |
break; |
case RET+I: case RET+U: case RET+P: |
rtarget(p, 0, ireg[0]); |
break; |
|
case ARG+F: case ARG+I: case ARG+P: case ARG+U: { |
Symbol q = argreg(p->syms[2]->u.c.v.i, optype(p->op)); |
if (q) |
rtarget(p, 0, q); |
break; |
} |
|
|
case ASGN+B: rtarget(p->kids[1], 0, blkreg); break; |
case ARG+B: rtarget(p->kids[0], 0, blkreg); break; |
|
} |
} |
|
static void clobber(Node p) { |
assert(p); |
switch (specific(p->op)) { |
case ASGN+I: case ASGN+U: |
if (opsize(p->op) <= 2) |
spill(1<<24, IREG, p); |
break; |
|
case DIV+I: case DIV+U: case MOD+I: case MOD+U: |
spill(((1<<27)|(3<<24))&~p->syms[RX]->x.regnode->mask, IREG, p); |
break; |
|
case CALL+F: |
spill(INTTMP | INTRET, IREG, p); |
spill(FLTTMP, FREG, p); |
break; |
case CALL+I: case CALL+P: case CALL+U: |
spill(INTTMP, IREG, p); |
spill(FLTTMP | FLTRET, FREG, p); |
break; |
case CALL+V: |
spill(INTTMP | INTRET, IREG, p); |
spill(FLTTMP | FLTRET, FREG, p); |
break; |
|
} |
} |
|
static void emit2(Node p) { |
int dst, n, src, sz, ty; |
static int ty0; |
Symbol q; |
|
switch (specific(p->op)) { |
case ARG+F: case ARG+I: case ARG+P: case ARG+U: |
ty = optype(p->op); |
sz = opsize(p->op); |
q = argreg(p->syms[2]->u.c.v.i, ty); |
src = getregnum(p->x.kids[0]); |
if (q) |
break; |
else if (ty == F && sz == 4) |
print("sts $f%d,%d($sp)\n", src, p->syms[2]->u.c.v.i - 48); |
else if (ty == F && sz == 8) |
print("stt $f%d,%d($sp)\n", src, p->syms[2]->u.c.v.i - 48); |
else if (sz == 4) |
print("stq $%d,%d($sp)\n", src, p->syms[2]->u.c.v.i - 48); |
else if (sz == 8) |
print("stq $%d,%d($sp)\n", src, p->syms[2]->u.c.v.i - 48); |
else |
assert(0); |
break; |
|
case ASGN+B: |
dalign = salign = p->syms[1]->u.c.v.i; |
blkcopy(getregnum(p->x.kids[0]), 0, |
getregnum(p->x.kids[1]), 0, |
p->syms[0]->u.c.v.i, tmpregs); |
break; |
|
|
case ARG+B: { |
int doff = p->syms[2]->u.c.v.i, soff = 0, sreg = getregnum(p->x.kids[0]); |
dalign = 8; |
salign = p->syms[1]->u.c.v.i; |
n = p->syms[0]->u.c.v.i; |
for ( ; doff <= 40 && n > 0; doff += 8) { |
print("uldq $%d,%d($%d)\n", (doff/8)+16, soff, sreg); |
soff += 8; |
n -= 8; |
} |
if (n > 0) |
blkcopy(30, doff - 48, sreg, soff, n, tmpregs); |
break; |
} |
|
} |
} |
|
static void doarg(Node p) { |
p->syms[2] = intconst(mkactual(8, roundup(p->syms[0]->u.c.v.i,8))); |
} |
|
static void local(Symbol p) { |
if (askregvar(p, rmap(ttob(p->type))) == 0) |
mkauto(p); |
} |
|
static int bitcount(unsigned mask) { |
unsigned i, n = 0; |
|
for (i = 1; i; i <<= 1) |
if (mask&i) |
n++; |
return n; |
} |
|
static void function(Symbol f, Symbol caller[], Symbol callee[], int ncalls) { |
int i, sizeargs, saved, sizefsave, sizeisave, varargs; |
Symbol r, argregs[6]; |
|
usedmask[0] = usedmask[1] = 0; |
freemask[0] = freemask[1] = ~(unsigned)0; |
maxargoffset = offset = maxoffset = 0; |
|
for (i = 0; callee[i]; i++) |
; |
varargs = variadic(f->type) |
|| i > 0 && strcmp(callee[i-1]->name, "va_alist") == 0; |
if (varargs) |
sizeargs = 2*48; |
else |
sizeargs = 48; |
|
for (i = 0; callee[i]; i++) { |
Symbol p = callee[i]; |
Symbol q = caller[i]; |
assert(q); |
if (isfloat(p->type) && varargs) { |
p->x.offset = q->x.offset = offset - 2*48; |
p->x.name = q->x.name = stringd(offset - 2*48); |
} else { |
p->x.offset = q->x.offset = offset - 48; |
p->x.name = q->x.name = stringd(offset - 48); |
} |
offset = roundup(offset, q->type->align); |
r = argreg(offset, optype(ttob(q->type))); |
if (i < 6) |
argregs[i] = r; |
offset = roundup(offset + q->type->size, 8); |
if (varargs) |
p->sclass = AUTO; |
else if (r && ncalls == 0 && !isstruct(q->type) && !p->addressed |
) { |
p->sclass = q->sclass = REGISTER; |
askregvar(p, r); |
assert(p->x.regnode && p->x.regnode->vbl == p); |
q->x = p->x; |
q->type = p->type; |
} else if (askregvar(p, rmap(ttob(p->type))) |
&& r != NULL /* |
&& (isint(p->type) || p->type == q->type) */ |
) { |
assert(q->sclass != REGISTER); |
p->sclass = q->sclass = REGISTER; |
q->type = p->type; |
} |
|
} |
assert(!caller[i]); |
|
offset = sizeargs + 8; |
gencode(caller, callee); |
usedmask[IREG] &= ~(INTTMP|(0x3f<<16)|INTRET); |
usedmask[FREG] &= ~(FLTTMP|(0x3f<<16)|FLTRET); |
if (ncalls || usedmask[IREG] || usedmask[FREG]) |
usedmask[IREG] |= 1<<26; |
sizefsave = 8*bitcount(usedmask[FREG]); |
sizeisave = 8*bitcount(usedmask[IREG]); |
if (maxargoffset > 48) |
maxargoffset -= 48; |
else |
maxargoffset = 0; |
if (maxoffset < sizeargs) |
maxoffset = sizeargs; |
framesize = roundup(maxargoffset + sizefsave + sizeisave + maxoffset, 16); |
segment(CODE); |
print(".ent %s\n", f->x.name); |
print("%s:\n", f->x.name); |
print("ldgp $gp,0($27)\n"); |
i = maxargoffset + sizefsave - framesize; |
if (framesize > 0) |
print("lda $sp,%d($sp)\n", -framesize); |
if (usedmask[FREG]) |
print(".fmask 0x%x,%d\n", usedmask[FREG], i - 8); |
if (usedmask[IREG]) |
print(".mask 0x%x,%d\n", usedmask[IREG], i + sizeisave - 8); |
print(".frame $sp,%d,$26,%d\n", framesize, sizeargs); |
|
saved = maxargoffset; |
for (i = 2; i <= 9; i++) |
if (usedmask[FREG]&(1<<i)) { |
print("stt $f%d,%d($sp)\n", i, saved); |
saved += 8; |
} |
|
for (i = 9; i <= 26; i++) |
if (usedmask[IREG]&(1<<i)) { |
print("stq $%d,%d($sp)\n", i, saved); |
saved += 8; |
} |
for (i = 0; i < 6 && callee[i]; i++) { |
r = argregs[i]; |
if (r && r->x.regnode != callee[i]->x.regnode) { |
Symbol out = callee[i]; |
Symbol in = caller[i]; |
int rn = r->x.regnode->number; |
int rs = r->x.regnode->set; |
int tyin = ttob(in->type); |
|
assert(out && in && r && r->x.regnode); |
assert(out->sclass != REGISTER || out->x.regnode); |
if (out->sclass == REGISTER) { |
if (rs == FREG) |
print("fmov $f%d,$f%d\n", rn, out->x.regnode->number); |
else |
print("mov $%d,$%d\n", rn, out->x.regnode->number); |
|
} else { |
int off = in->x.offset + framesize; |
if (rs == FREG && tyin == F+sizeop(8)) |
print("stt $f%d,%d($sp)\n", rn, off); |
else if (rs == FREG && tyin == F+sizeop(4)) |
print("sts $f%d,%d($sp)\n", rn, off); |
else { |
int i, n = (in->type->size + 7)/8; |
for (i = rn; i < rn+n && i <= 21; i++) |
print("stq $%d,%d($sp)\n", i, off + (i-rn)*8); |
} |
|
} |
|
} |
} |
if (varargs && callee[i-1]) { |
i = callee[i-1]->x.offset + roundup(callee[i-1]->type->size, 8); |
for (i = (48+i)/8; i < 6; i++) { |
print("stq $%d,%d($sp)\n", i + 16, framesize - 48 + 8*i); |
print("stt $f%d,%d($sp)\n", i + 16, framesize - 2*48 + 8*i); |
} |
} |
print(".prologue 1\n"); |
|
emitcode(); |
saved = maxargoffset; |
for (i = 2; i <= 9; i++) |
if (usedmask[FREG]&(1<<i)) { |
print("ldt $f%d,%d($sp)\n", i, saved); |
saved += 8; |
} |
for (i = 9; i <= 26; i++) |
if (usedmask[IREG]&(1<<i)) { |
print("ldq $%d,%d($sp)\n", i, saved); |
saved += 8; |
} |
if (framesize > 0) |
print("lda $sp,%d($sp)\n", framesize); |
print("ret\n"); |
print(".end %s\n", f->x.name); |
|
} |
|
static void defconst(int suffix, int size, Value v) { |
if (suffix == F && size == 4) { |
float f = v.d; |
print(".long 0x%x\n", *(unsigned *)&f); |
} else if (suffix == F && size == 8) { |
double d = v.d; |
unsigned *p = (unsigned *)&d; |
print(".long 0x%x\n.long 0x%x\n", p[swap], p[!swap]); |
} else if (suffix == P) |
print(".quad 0x%X\n", v.p); |
else if (size == 1) |
print(".byte 0x%x\n", suffix == I ? v.i : v.u); |
else if (size == 2) |
print(".word 0x%x\n", suffix == I ? v.i&0xFFFF : v.u&0xFFFF); |
else if (size == 4) |
print(".long 0x%x\n", suffix == I ? v.i : v.u); |
else if (size == 8) |
print(".quad 0x%X\n", suffix == I ? v.i : v.u); |
|
} |
|
static void defaddress(Symbol p) { |
print(".quad %s\n", p->x.name); |
} |
|
static void defstring(int n, char *str) { |
char *s; |
|
for (s = str; s < str + n; s++) |
print(".byte %d\n", (*s)&0377); |
} |
|
static void export(Symbol p) { |
print(".globl %s\n", p->x.name); |
} |
|
static void import(Symbol p) { |
if (!isfunc(p->type)) |
print(".extern %s %d\n", p->name, p->type->size); |
} |
|
static void defsymbol(Symbol p) { |
if (p->scope >= LOCAL && p->sclass == STATIC) |
p->x.name = stringf("L.%d", genlabel(1)); |
else if (p->generated) |
p->x.name = stringf("L.%s", p->name); |
else |
assert(p->scope != CONSTANTS || isint(p->type) || isptr(p->type)), |
p->x.name = p->name; |
} |
|
static void address(Symbol q, Symbol p, long n) { |
if (p->scope == GLOBAL |
|| p->sclass == STATIC || p->sclass == EXTERN) |
q->x.name = stringf("%s%s%D", p->x.name, |
n >= 0 ? "+" : "", n); |
else { |
assert(n <= INT_MAX && n >= INT_MIN); |
q->x.offset = p->x.offset + n; |
q->x.name = stringd(q->x.offset); |
} |
} |
|
static void global(Symbol p) { |
if (p->u.seg == DATA || p->u.seg == LIT) { |
assert(p->type->align <= 8); |
print(".align %c\n", ".01.2...3"[p->type->align]); |
print("%s:\n", p->x.name); |
} else if (p->sclass == STATIC || Aflag >= 2) |
print(".lcomm %s,%d\n", p->x.name, p->type->size); |
else |
print( ".comm %s,%d\n", p->x.name, p->type->size); |
} |
|
static void segment(int n) { |
cseg = n; |
switch (n) { |
case DATA: print(".sdata\n"); break; |
case CODE: print(".text\n"); break; |
case LIT: print(".rdata\n"); break; |
} |
} |
|
static void space(int n) { |
if (cseg != BSS) |
print(".space %d\n", n); |
} |
|
static void blkloop(int dreg, int doff, int sreg, int soff, int size, int tmps[]) { |
int lab = genlabel(1); |
|
print("addq $%d,%d,$%d\n", sreg, size&~7, sreg); |
print("addq $%d,%d,$%d\n", dreg, size&~7, tmps[2]); |
blkcopy(tmps[2], doff, sreg, soff, size&7, tmps); |
print("L.%d:\n", lab); |
print("addq $%d,%d,$%d\n", sreg, -8, sreg); |
print("addq $%d,%d,$%d\n", tmps[2], -8, tmps[2]); |
blkcopy(tmps[2], doff, sreg, soff, 8, tmps); |
print("cmpult $%d,$%d,$23\nbne $23,L.%d\n", dreg, tmps[2], lab); |
} |
|
static void blkfetch(int size, int off, int reg, int tmp) { |
assert(size == 1 || size == 2 || size == 4 || size == 8); |
if (size == 1) |
print("ldb $%d,%d($%d)\n", tmp, off, reg); |
else if (size == 2) |
print("ldw $%d,%d($%d)\n", tmp, off, reg); |
else if (salign >= size && size == 4) |
print("ldl $%d,%d($%d)\n", tmp, off, reg); |
else if (salign >= size && size == 8) |
print("ldq $%d,%d($%d)\n", tmp, off, reg); |
else if (size == 4) |
print("uldl $%d,%d($%d)\n", tmp, off, reg); |
else |
print("uldq $%d,%d($%d)\n", tmp, off, reg); |
} |
|
static void blkstore(int size, int off, int reg, int tmp) { |
assert(size == 1 || size == 2 || size == 4 || size == 8); |
if (size == 1) |
print("stb $%d,%d($%d)\n", tmp, off, reg); |
else if (size == 2) |
print("stw $%d,%d($%d)\n", tmp, off, reg); |
else if (dalign >= size && size == 4) |
print("stl $%d,%d($%d)\n", tmp, off, reg); |
else if (dalign >= size && size == 8) |
print("stq $%d,%d($%d)\n", tmp, off, reg); |
else if (size == 4) |
print("ustl $%d,%d($%d)\n", tmp, off, reg); |
else |
print("ustq $%d,%d($%d)\n", tmp, off, reg); |
} |
|
/* stabinit - initialize stab output */ |
static void stabinit(char *file, int argc, char *argv[]) { |
if (file) { |
print(".file 2,\"%s\"\n", file); |
currentfile = file; |
} |
} |
|
/* stabline - emit stab entry for source coordinate *cp */ |
static void stabline(Coordinate *cp) { |
if (cp->file && cp->file != currentfile) { |
print(".file 2,\"%s\"\n", cp->file); |
currentfile = cp->file; |
} |
print(".loc 2,%d\n", cp->y); |
} |
|
/* stabsym - output a stab entry for symbol p */ |
static void stabsym(Symbol p) { |
if (p == cfunc && IR->stabline) |
(*IR->stabline)(&p->src); |
} |
Interface alphaIR = { |
1, 1, 0, /* char */ |
2, 2, 0, /* short */ |
4, 4, 0, /* int */ |
8, 8, 0, /* long */ |
8, 8, 0, /* long long */ |
4, 4, 1, /* float */ |
8, 8, 1, /* double */ |
8, 8, 1, /* long double */ |
8, 8, 0, /* T * */ |
0, 1, 0, /* struct */ |
|
1, /* little_endian */ |
0, /* mulops_calls */ |
0, /* wants_callb */ |
1, /* wants_argb */ |
1, /* left_to_right */ |
0, /* wants_dag */ |
0, /* unsigned_char */ |
address, |
blockbeg, |
blockend, |
defaddress, |
defconst, |
defstring, |
defsymbol, |
emit, |
export, |
function, |
gen, |
global, |
import, |
local, |
progbeg, |
progend, |
segment, |
space, |
0, 0, 0, stabinit, stabline, stabsym, 0, |
{ |
1, /* max_unaligned_load */ |
rmap, |
blkfetch, blkstore, blkloop, |
_label, |
_rule, |
_nts, |
_kids, |
_string, |
_templates, |
_isinstruction, |
_ntname, |
emit2, |
doarg, |
target, |
clobber, |
|
} |
|
}; |
|
|
static char rcsid[] = "$Id: alpha.md,v 1.1 2002/08/28 23:12:41 drh Exp $"; |
|
/ops.h
0,0 → 1,133
/* $Id: ops.h,v 1.2 2002/09/03 23:39:33 drh Exp $ */ |
|
gop(CNST,1) |
op(CNST,F,fdx) |
op(CNST,I,csilh) |
op(CNST,P,p) |
op(CNST,U,csilh) |
gop(ARG,2) |
op(ARG,B,-) |
op(ARG,F,fdx) |
op(ARG,I,ilh) |
op(ARG,P,p) |
op(ARG,U,ilh) |
gop(ASGN,3) |
op(ASGN,B,-) |
op(ASGN,F,fdx) |
op(ASGN,I,csilh) |
op(ASGN,P,p) |
op(ASGN,U,csilh) |
gop(INDIR,4) |
op(INDIR,B,-) |
op(INDIR,F,fdx) |
op(INDIR,I,csilh) |
op(INDIR,P,p) |
op(INDIR,U,csilh) |
gop(CVF,7) |
op(CVF,F,fdx) |
op(CVF,I,ilh) |
gop(CVI,8) |
op(CVI,F,fdx) |
op(CVI,I,csilh) |
op(CVI,U,csilhp) |
gop(CVP,9) |
op(CVP,U,p) |
gop(CVU,11) |
op(CVU,I,csilh) |
op(CVU,P,p) |
op(CVU,U,csilh) |
gop(NEG,12) |
op(NEG,F,fdx) |
op(NEG,I,ilh) |
gop(CALL,13) |
op(CALL,B,-) |
op(CALL,F,fdx) |
op(CALL,I,ilh) |
op(CALL,P,p) |
op(CALL,U,ilh) |
op(CALL,V,-) |
gop(RET,15) |
op(RET,F,fdx) |
op(RET,I,ilh) |
op(RET,P,p) |
op(RET,U,ilh) |
op(RET,V,-) |
gop(ADDRG,16) |
op(ADDRG,P,p) |
gop(ADDRF,17) |
op(ADDRF,P,p) |
gop(ADDRL,18) |
op(ADDRL,P,p) |
gop(ADD,19) |
op(ADD,F,fdx) |
op(ADD,I,ilh) |
op(ADD,P,p) |
op(ADD,U,ilhp) |
gop(SUB,20) |
op(SUB,F,fdx) |
op(SUB,I,ilh) |
op(SUB,P,p) |
op(SUB,U,ilhp) |
gop(LSH,21) |
op(LSH,I,ilh) |
op(LSH,U,ilh) |
gop(MOD,22) |
op(MOD,I,ilh) |
op(MOD,U,ilh) |
gop(RSH,23) |
op(RSH,I,ilh) |
op(RSH,U,ilh) |
gop(BAND,24) |
op(BAND,I,ilh) |
op(BAND,U,ilh) |
gop(BCOM,25) |
op(BCOM,I,ilh) |
op(BCOM,U,ilh) |
gop(BOR,26) |
op(BOR,I,ilh) |
op(BOR,U,ilh) |
gop(BXOR,27) |
op(BXOR,I,ilh) |
op(BXOR,U,ilh) |
gop(DIV,28) |
op(DIV,F,fdx) |
op(DIV,I,ilh) |
op(DIV,U,ilh) |
gop(MUL,29) |
op(MUL,F,fdx) |
op(MUL,I,ilh) |
op(MUL,U,ilh) |
gop(EQ,30) |
op(EQ,F,fdx) |
op(EQ,I,ilh) |
op(EQ,U,ilhp) |
gop(GE,31) |
op(GE,F,fdx) |
op(GE,I,ilh) |
op(GE,U,ilhp) |
gop(GT,32) |
op(GT,F,fdx) |
op(GT,I,ilh) |
op(GT,U,ilhp) |
gop(LE,33) |
op(LE,F,fdx) |
op(LE,I,ilh) |
op(LE,U,ilhp) |
gop(LT,34) |
op(LT,F,fdx) |
op(LT,I,ilh) |
op(LT,U,ilhp) |
gop(NE,35) |
op(NE,F,fdx) |
op(NE,I,ilh) |
op(NE,U,ilhp) |
gop(JUMP,36) |
op(JUMP,V,-) |
gop(LABEL,37) |
op(LABEL,V,-) |
gop(LOAD,14) |
op(LOAD,B,-) |
op(LOAD,F,fdx) |
op(LOAD,I,csilh) |
op(LOAD,P,p) |
op(LOAD,U,csilhp) |
/prof.c
0,0 → 1,233
#include "c.h" |
|
static char rcsid[] = "$Id: prof.c,v 1.1 2002/08/28 23:12:45 drh Exp $"; |
|
struct callsite { |
char *file, *name; |
union coordinate { |
unsigned int coord; |
struct { unsigned int y:16,x:10,index:6; } le; |
struct { unsigned int index:6,x:10,y:16; } be; |
} u; |
}; |
struct func { |
struct func *link; |
struct caller *callers; |
char *name; |
union coordinate src; |
}; |
struct map { /* source code map; 200 coordinates/map */ |
int size; |
union coordinate u[200]; |
}; |
|
int npoints; /* # of execution points if -b specified */ |
int ncalled = -1; /* #times prof.out says current function was called */ |
static Symbol YYlink; /* symbol for file's struct _bbdata */ |
static Symbol YYcounts; /* symbol for _YYcounts if -b specified */ |
static List maplist; /* list of struct map *'s */ |
static List filelist; /* list of file names */ |
static Symbol funclist; /* list of struct func *'s */ |
static Symbol afunc; /* current function's struct func */ |
|
/* bbpad - emit space, if necessary, to make size%align == 0; return new size */ |
static int bbpad(int size, int align) { |
if (size%align) { |
(*IR->space)(align - size%align); |
size = roundup(size, align); |
} |
return size; |
} |
|
/* bbcall - build tree to set _callsite at call site *cp, emit call site data */ |
static void bbcall(Symbol yycounts, Coordinate *cp, Tree *e) { |
static Symbol caller; |
Value v; |
union coordinate u; |
Symbol p = genident(STATIC, array(voidptype, 0, 0), GLOBAL); |
Tree t; |
|
defglobal(p, LIT); |
defpointer(cp->file ? mkstr(cp->file)->u.c.loc : (Symbol)0); |
defpointer(mkstr(cfunc->name)->u.c.loc); |
if (IR->little_endian) { |
u.le.x = cp->x; |
u.le.y = cp->y; |
} else { |
u.be.x = cp->x; |
u.be.y = cp->y; |
} |
(*IR->defconst)(U, unsignedtype->size, (v.u = u.coord, v)); |
bbpad(2*voidptype->size + unsignedtype->size, p->type->align); |
if (caller == 0) { |
caller = mksymbol(EXTERN, "_caller", ptr(voidptype)); |
caller->defined = 0; |
} |
for (t = *e; generic(t->op) != CALL; t = t->kids[0]) |
assert(t->op == RIGHT || !t->kids[1]); |
assert(generic(t->op) == CALL); |
t = tree(t->op, t->type, |
tree(RIGHT, t->kids[0]->type, |
t->kids[0], |
tree(RIGHT, t->kids[0]->type, asgn(caller, idtree(p)), t->kids[0])), |
t->kids[1]); |
for ( ; generic((*e)->op) != CALL; e = &(*e)->kids[0]) |
; |
*e = t; |
} |
|
/* bbentry - return tree for _prologue(&afunc, &YYlink)' */ |
static void bbentry(Symbol yylink, Symbol f, void *ignore) { |
static Symbol prologue; |
|
afunc = genident(STATIC, array(voidptype, 4, 0), GLOBAL); |
if (prologue == 0) { |
prologue = mksymbol(EXTERN, "_prologue", ftype(inttype, voidptype, voidptype, NULL)); |
prologue->defined = 0; |
} |
walk(vcall(prologue, voidtype, pointer(idtree(afunc)), pointer(idtree(yylink)), NULL), 0, 0); |
} |
|
/* bbexit - return tree for _epilogue(&afunc)' */ |
static void bbexit(Symbol yylink, Symbol f, Tree e) { |
static Symbol epilogue; |
|
if (epilogue == 0) { |
epilogue = mksymbol(EXTERN, "_epilogue", ftype(inttype, voidptype, NULL)); |
epilogue->defined = 0; |
} |
walk(vcall(epilogue, voidtype, pointer(idtree(afunc)), NULL), 0, 0); |
} |
|
/* bbfile - add file to list of file names, return its index */ |
static int bbfile(char *file) { |
if (file) { |
List lp; |
int i = 1; |
if ((lp = filelist) != NULL) |
do { |
lp = lp->link; |
if (((Symbol)lp->x)->u.c.v.p == file) |
return i; |
i++; |
} while (lp != filelist); |
filelist = append(mkstr(file), filelist); |
return i; |
} |
return 0; |
} |
|
/* bbfunc - emit function name and src coordinates */ |
static void bbfunc(Symbol yylink, Symbol f, void *ignore) { |
Value v; |
union coordinate u; |
|
defglobal(afunc, DATA); |
defpointer(funclist); |
defpointer(NULL); |
defpointer(mkstr(f->name)->u.c.loc); |
if (IR->little_endian) { |
u.le.x = f->u.f.pt.x; |
u.le.y = f->u.f.pt.y; |
u.le.index = bbfile(f->u.f.pt.file); |
} else { |
u.be.x = f->u.f.pt.x; |
u.be.y = f->u.f.pt.y; |
u.be.index = bbfile(f->u.f.pt.file); |
} |
(*IR->defconst)(U, unsignedtype->size, (v.u = u.coord, v)); |
bbpad(3*voidptype->size + unsignedtype->size, afunc->type->align); |
funclist = afunc; |
} |
|
/* bbincr - build tree to increment execution point at *cp */ |
static void bbincr(Symbol yycounts, Coordinate *cp, Tree *e) { |
struct map *mp = maplist->x; |
Tree t; |
|
if (needconst) |
return; |
/* append *cp to source map */ |
if (mp->size >= NELEMS(mp->u)) { |
NEW(mp, PERM); |
mp->size = 0; |
maplist = append(mp, maplist); |
} |
if (IR->little_endian) { |
mp->u[mp->size].le.x = cp->x; |
mp->u[mp->size].le.y = cp->y; |
mp->u[mp->size++].le.index = bbfile(cp->file); |
} else { |
mp->u[mp->size].be.x = cp->x; |
mp->u[mp->size].be.y = cp->y; |
mp->u[mp->size++].be.index = bbfile(cp->file); |
} |
t = incr('+', rvalue((*optree['+'])(ADD, pointer(idtree(yycounts)), |
consttree(npoints++, inttype))), consttree(1, inttype)); |
if (*e) |
*e = tree(RIGHT, (*e)->type, t, *e); |
else |
*e = t; |
} |
|
/* bbvars - emit definition for basic block counting data */ |
static void bbvars(Symbol yylink, void *ignore, void *ignore2) { |
int i, j, n = npoints; |
Value v; |
struct map **mp; |
Symbol coords, files, *p; |
|
if (!YYcounts && !yylink) |
return; |
if (YYcounts) { |
if (n <= 0) |
n = 1; |
YYcounts->type = array(inttype, n, 0); |
defglobal(YYcounts, BSS); |
(*IR->space)(YYcounts->type->size); |
} |
files = genident(STATIC, array(charptype, 1, 0), GLOBAL); |
defglobal(files, LIT); |
for (p = ltov(&filelist, PERM); *p; p++) |
defpointer((*p)->u.c.loc); |
defpointer(NULL); |
coords = genident(STATIC, array(unsignedtype, n, 0), GLOBAL); |
defglobal(coords, LIT); |
for (i = n, mp = ltov(&maplist, PERM); *mp; i -= (*mp)->size, mp++) |
for (j = 0; j < (*mp)->size; j++) |
(*IR->defconst)(U, unsignedtype->size, (v.u = (*mp)->u[j].coord, v)); |
if (i > 0) |
(*IR->space)(i*coords->type->type->size); |
(*IR->defconst)(U, unsignedtype->size, (v.u = 0, v)); |
defglobal(yylink, DATA); |
defpointer(NULL); |
(*IR->defconst)(U, inttype->size, (v.u = n, v)); |
bbpad(voidptype->size + inttype->size, yylink->type->align); |
defpointer(YYcounts); |
defpointer(coords); |
defpointer(files); |
defpointer(funclist); |
} |
|
/* profInit - initialize basic block profiling options */ |
void profInit(char *arg) { |
if (strncmp(arg, "-a", 2) == 0) { |
if (ncalled == -1 |
&& process(arg[2] ? &arg[2] : "prof.out") > 0) |
ncalled = 0; |
} else if ((strcmp(arg, "-b") == 0 |
|| strcmp(arg, "-C") == 0) && YYlink == 0) { |
YYlink = genident(STATIC, array(voidptype, 0, 0), GLOBAL); |
attach((Apply)bbentry, YYlink, &events.entry); |
attach((Apply)bbexit, YYlink, &events.returns); |
attach((Apply)bbfunc, YYlink, &events.exit); |
attach((Apply)bbvars, YYlink, &events.end); |
if (strcmp(arg, "-b") == 0) { |
YYcounts = genident(STATIC, array(inttype, 0, 0), GLOBAL); |
maplist = append(allocate(sizeof (struct map), PERM), maplist); |
((struct map *)maplist->x)->size = 0; |
attach((Apply)bbcall, YYcounts, &events.calls); |
attach((Apply)bbincr, YYcounts, &events.points); |
} |
} |
} |
/gen.c
0,0 → 1,830
#include "c.h" |
|
static char rcsid[] = "$Id: gen.c,v 1.1 2002/08/28 23:12:43 drh Exp $"; |
|
#define readsreg(p) \ |
(generic((p)->op)==INDIR && (p)->kids[0]->op==VREG+P) |
#define setsrc(d) ((d) && (d)->x.regnode && \ |
(d)->x.regnode->set == src->x.regnode->set && \ |
(d)->x.regnode->mask&src->x.regnode->mask) |
|
#define relink(a, b) ((b)->x.prev = (a), (a)->x.next = (b)) |
|
static Symbol askfixedreg(Symbol); |
static Symbol askreg(Symbol, unsigned*); |
static void blkunroll(int, int, int, int, int, int, int[]); |
static void docall(Node); |
static void dumpcover(Node, int, int); |
static void dumpregs(char *, char *, char *); |
static void dumprule(int); |
static void dumptree(Node); |
static void genreload(Node, Symbol, int); |
static void genspill(Symbol, Node, Symbol); |
static Symbol getreg(Symbol, unsigned*, Node); |
static int getrule(Node, int); |
static void linearize(Node, Node); |
static int moveself(Node); |
static void prelabel(Node); |
static Node* prune(Node, Node*); |
static void putreg(Symbol); |
static void ralloc(Node); |
static void reduce(Node, int); |
static int reprune(Node*, int, int, Node); |
static int requate(Node); |
static Node reuse(Node, int); |
static void rewrite(Node); |
static Symbol spillee(Symbol, unsigned mask[], Node); |
static void spillr(Symbol, Node); |
static int uses(Node, Regnode); |
|
int offset; |
|
int maxoffset; |
|
int framesize; |
int argoffset; |
|
int maxargoffset; |
|
int dalign, salign; |
int bflag = 0; /* omit */ |
int dflag = 0; |
|
int swap; |
|
unsigned (*emitter)(Node, int) = emitasm; |
static char NeedsReg[] = { |
0, /* unused */ |
1, /* CNST */ |
0, 0, /* ARG ASGN */ |
1, /* INDIR */ |
0, 0, 1, 1, /* - - CVF CVI */ |
1, 0, 1, 1, /* CVP - CVU NEG */ |
1, /* CALL */ |
1, /* LOAD */ |
0, /* RET */ |
1, 1, 1, /* ADDRG ADDRF ADDRL */ |
1, 1, 1, 1, 1, /* ADD SUB LSH MOD RSH */ |
1, 1, 1, 1, /* BAND BCOM BOR BXOR */ |
1, 1, /* DIV MUL */ |
0, 0, 0, 0, 0, 0, /* EQ GE GT LE LT NE */ |
0, 0 /* JUMP LABEL */ |
}; |
Node head; |
|
unsigned freemask[2]; |
unsigned usedmask[2]; |
unsigned tmask[2]; |
unsigned vmask[2]; |
Symbol mkreg(char *fmt, int n, int mask, int set) { |
Symbol p; |
|
NEW0(p, PERM); |
p->name = p->x.name = stringf(fmt, n); |
NEW0(p->x.regnode, PERM); |
p->x.regnode->number = n; |
p->x.regnode->mask = mask<<n; |
p->x.regnode->set = set; |
return p; |
} |
Symbol mkwildcard(Symbol *syms) { |
Symbol p; |
|
NEW0(p, PERM); |
p->name = p->x.name = "wildcard"; |
p->x.wildcard = syms; |
return p; |
} |
void mkauto(Symbol p) { |
assert(p->sclass == AUTO); |
offset = roundup(offset + p->type->size, p->type->align); |
p->x.offset = -offset; |
p->x.name = stringd(-offset); |
} |
void blockbeg(Env *e) { |
e->offset = offset; |
e->freemask[IREG] = freemask[IREG]; |
e->freemask[FREG] = freemask[FREG]; |
} |
void blockend(Env *e) { |
if (offset > maxoffset) |
maxoffset = offset; |
offset = e->offset; |
freemask[IREG] = e->freemask[IREG]; |
freemask[FREG] = e->freemask[FREG]; |
} |
int mkactual(int align, int size) { |
int n = roundup(argoffset, align); |
|
argoffset = n + size; |
return n; |
} |
static void docall(Node p) { |
p->syms[1] = p->syms[0]; |
p->syms[0] = intconst(argoffset); |
if (argoffset > maxargoffset) |
maxargoffset = argoffset; |
argoffset = 0; |
} |
void blkcopy(int dreg, int doff, int sreg, int soff, int size, int tmp[]) { |
assert(size >= 0); |
if (size == 0) |
return; |
else if (size <= 2) |
blkunroll(size, dreg, doff, sreg, soff, size, tmp); |
else if (size == 3) { |
blkunroll(2, dreg, doff, sreg, soff, 2, tmp); |
blkunroll(1, dreg, doff+2, sreg, soff+2, 1, tmp); |
} |
else if (size <= 16) { |
blkunroll(4, dreg, doff, sreg, soff, size&~3, tmp); |
blkcopy(dreg, doff+(size&~3), |
sreg, soff+(size&~3), size&3, tmp); |
} |
else |
(*IR->x.blkloop)(dreg, doff, sreg, soff, size, tmp); |
} |
static void blkunroll(int k, int dreg, int doff, int sreg, int soff, int size, int tmp[]) { |
int i; |
|
assert(IR->x.max_unaligned_load); |
if (k > IR->x.max_unaligned_load |
&& (k > salign || k > dalign)) |
k = IR->x.max_unaligned_load; |
for (i = 0; i+k < size; i += 2*k) { |
(*IR->x.blkfetch)(k, soff+i, sreg, tmp[0]); |
(*IR->x.blkfetch)(k, soff+i+k, sreg, tmp[1]); |
(*IR->x.blkstore)(k, doff+i, dreg, tmp[0]); |
(*IR->x.blkstore)(k, doff+i+k, dreg, tmp[1]); |
} |
if (i < size) { |
(*IR->x.blkfetch)(k, i+soff, sreg, tmp[0]); |
(*IR->x.blkstore)(k, i+doff, dreg, tmp[0]); |
} |
} |
void parseflags(int argc, char *argv[]) { |
int i; |
|
for (i = 0; i < argc; i++) |
if (strcmp(argv[i], "-d") == 0) |
dflag = 1; |
else if (strcmp(argv[i], "-b") == 0) /* omit */ |
bflag = 1; /* omit */ |
} |
static int getrule(Node p, int nt) { |
int rulenum; |
|
assert(p); |
rulenum = (*IR->x._rule)(p->x.state, nt); |
if (!rulenum) { |
fprint(stderr, "(%x->op=%s at %w is corrupt.)\n", p, opname(p->op), &src); |
assert(0); |
} |
return rulenum; |
} |
static void reduce(Node p, int nt) { |
int rulenum, i; |
short *nts; |
Node kids[10]; |
|
p = reuse(p, nt); |
rulenum = getrule(p, nt); |
nts = IR->x._nts[rulenum]; |
(*IR->x._kids)(p, rulenum, kids); |
for (i = 0; nts[i]; i++) |
reduce(kids[i], nts[i]); |
if (IR->x._isinstruction[rulenum]) { |
assert(p->x.inst == 0 || p->x.inst == nt); |
p->x.inst = nt; |
if (p->syms[RX] && p->syms[RX]->temporary) { |
debug(fprint(stderr, "(using %s)\n", p->syms[RX]->name)); |
p->syms[RX]->x.usecount++; |
} |
} |
} |
static Node reuse(Node p, int nt) { |
struct _state { |
short cost[1]; |
}; |
Symbol r = p->syms[RX]; |
|
if (generic(p->op) == INDIR && p->kids[0]->op == VREG+P |
&& r->u.t.cse && p->x.mayrecalc |
&& ((struct _state*)r->u.t.cse->x.state)->cost[nt] == 0) |
return r->u.t.cse; |
else |
return p; |
} |
|
int mayrecalc(Node p) { |
int op; |
|
assert(p && p->syms[RX]); |
if (p->syms[RX]->u.t.cse == NULL) |
return 0; |
op = generic(p->syms[RX]->u.t.cse->op); |
if (op == CNST || op == ADDRF || op == ADDRG || op == ADDRL) { |
p->x.mayrecalc = 1; |
return 1; |
} else |
return 0; |
} |
static Node *prune(Node p, Node pp[]) { |
if (p == NULL) |
return pp; |
p->x.kids[0] = p->x.kids[1] = p->x.kids[2] = NULL; |
if (p->x.inst == 0) |
return prune(p->kids[1], prune(p->kids[0], pp)); |
else if (p->syms[RX] && p->syms[RX]->temporary |
&& p->syms[RX]->x.usecount < 2) { |
p->x.inst = 0; |
debug(fprint(stderr, "(clobbering %s)\n", p->syms[RX]->name)); |
return prune(p->kids[1], prune(p->kids[0], pp)); |
} |
else { |
prune(p->kids[1], prune(p->kids[0], &p->x.kids[0])); |
*pp = p; |
return pp + 1; |
} |
} |
|
#define ck(i) return (i) ? 0 : LBURG_MAX |
|
int range(Node p, int lo, int hi) { |
Symbol s = p->syms[0]; |
|
switch (specific(p->op)) { |
case ADDRF+P: |
case ADDRL+P: ck(s->x.offset >= lo && s->x.offset <= hi); |
case CNST+I: ck(s->u.c.v.i >= lo && s->u.c.v.i <= hi); |
case CNST+U: ck(s->u.c.v.u >= lo && s->u.c.v.u <= hi); |
case CNST+P: ck(s->u.c.v.p == 0 && lo <= 0 && hi >= 0); |
} |
return LBURG_MAX; |
} |
static void dumptree(Node p) { |
if (p->op == VREG+P && p->syms[0]) { |
fprint(stderr, "VREGP(%s)", p->syms[0]->name); |
return; |
} else if (generic(p->op) == LOAD) { |
fprint(stderr, "LOAD("); |
dumptree(p->kids[0]); |
fprint(stderr, ")"); |
return; |
} |
fprint(stderr, "%s(", opname(p->op)); |
switch (generic(p->op)) { |
case CNST: case LABEL: |
case ADDRG: case ADDRF: case ADDRL: |
if (p->syms[0]) |
fprint(stderr, "%s", p->syms[0]->name); |
break; |
case RET: |
if (p->kids[0]) |
dumptree(p->kids[0]); |
break; |
case CVF: case CVI: case CVP: case CVU: case JUMP: |
case ARG: case BCOM: case NEG: case INDIR: |
dumptree(p->kids[0]); |
break; |
case CALL: |
if (optype(p->op) != B) { |
dumptree(p->kids[0]); |
break; |
} |
/* else fall thru */ |
case EQ: case NE: case GT: case GE: case LE: case LT: |
case ASGN: case BOR: case BAND: case BXOR: case RSH: case LSH: |
case ADD: case SUB: case DIV: case MUL: case MOD: |
dumptree(p->kids[0]); |
fprint(stderr, ", "); |
dumptree(p->kids[1]); |
break; |
default: assert(0); |
} |
fprint(stderr, ")"); |
} |
static void dumpcover(Node p, int nt, int in) { |
int rulenum, i; |
short *nts; |
Node kids[10]; |
|
p = reuse(p, nt); |
rulenum = getrule(p, nt); |
nts = IR->x._nts[rulenum]; |
fprint(stderr, "dumpcover(%x) = ", p); |
for (i = 0; i < in; i++) |
fprint(stderr, " "); |
dumprule(rulenum); |
(*IR->x._kids)(p, rulenum, kids); |
for (i = 0; nts[i]; i++) |
dumpcover(kids[i], nts[i], in+1); |
} |
|
static void dumprule(int rulenum) { |
assert(rulenum); |
fprint(stderr, "%s / %s", IR->x._string[rulenum], |
IR->x._templates[rulenum]); |
if (!IR->x._isinstruction[rulenum]) |
fprint(stderr, "\n"); |
} |
unsigned emitasm(Node p, int nt) { |
int rulenum; |
short *nts; |
char *fmt; |
Node kids[10]; |
|
p = reuse(p, nt); |
rulenum = getrule(p, nt); |
nts = IR->x._nts[rulenum]; |
fmt = IR->x._templates[rulenum]; |
assert(fmt); |
if (IR->x._isinstruction[rulenum] && p->x.emitted) |
print("%s", p->syms[RX]->x.name); |
else if (*fmt == '#') |
(*IR->x.emit2)(p); |
else { |
if (*fmt == '?') { |
fmt++; |
assert(p->kids[0]); |
if (p->syms[RX] == p->x.kids[0]->syms[RX]) |
while (*fmt++ != '\n') |
; |
} |
for ((*IR->x._kids)(p, rulenum, kids); *fmt; fmt++) |
if (*fmt != '%') |
(void)putchar(*fmt); |
else if (*++fmt == 'F') |
print("%d", framesize); |
else if (*fmt >= '0' && *fmt <= '9') |
emitasm(kids[*fmt - '0'], nts[*fmt - '0']); |
else if (*fmt >= 'a' && *fmt < 'a' + NELEMS(p->syms)) |
fputs(p->syms[*fmt - 'a']->x.name, stdout); |
else |
(void)putchar(*fmt); |
} |
return 0; |
} |
void emit(Node p) { |
for (; p; p = p->x.next) { |
assert(p->x.registered); |
if (p->x.equatable && requate(p) || moveself(p)) |
; |
else |
(*emitter)(p, p->x.inst); |
p->x.emitted = 1; |
} |
} |
static int moveself(Node p) { |
return p->x.copy |
&& p->syms[RX]->x.name == p->x.kids[0]->syms[RX]->x.name; |
} |
int move(Node p) { |
p->x.copy = 1; |
return 1; |
} |
static int requate(Node q) { |
Symbol src = q->x.kids[0]->syms[RX]; |
Symbol tmp = q->syms[RX]; |
Node p; |
int n = 0; |
|
debug(fprint(stderr, "(requate(%x): tmp=%s src=%s)\n", q, tmp->x.name, src->x.name)); |
for (p = q->x.next; p; p = p->x.next) |
if (p->x.copy && p->syms[RX] == src |
&& p->x.kids[0]->syms[RX] == tmp) |
debug(fprint(stderr, "(requate arm 0 at %x)\n", p)), |
p->syms[RX] = tmp; |
else if (setsrc(p->syms[RX]) && !moveself(p) && !readsreg(p)) |
return 0; |
else if (p->x.spills) |
return 0; |
else if (generic(p->op) == CALL && p->x.next) |
return 0; |
else if (p->op == LABEL+V && p->x.next) |
return 0; |
else if (p->syms[RX] == tmp && readsreg(p)) |
debug(fprint(stderr, "(requate arm 5 at %x)\n", p)), |
n++; |
else if (p->syms[RX] == tmp) |
break; |
debug(fprint(stderr, "(requate arm 7 at %x)\n", p)); |
assert(n > 0); |
for (p = q->x.next; p; p = p->x.next) |
if (p->syms[RX] == tmp && readsreg(p)) { |
p->syms[RX] = src; |
if (--n <= 0) |
break; |
} |
return 1; |
} |
static void prelabel(Node p) { |
if (p == NULL) |
return; |
prelabel(p->kids[0]); |
prelabel(p->kids[1]); |
if (NeedsReg[opindex(p->op)]) |
setreg(p, (*IR->x.rmap)(opkind(p->op))); |
switch (generic(p->op)) { |
case ADDRF: case ADDRL: |
if (p->syms[0]->sclass == REGISTER) |
p->op = VREG+P; |
break; |
case INDIR: |
if (p->kids[0]->op == VREG+P) |
setreg(p, p->kids[0]->syms[0]); |
break; |
case ASGN: |
if (p->kids[0]->op == VREG+P) |
rtarget(p, 1, p->kids[0]->syms[0]); |
break; |
case CVI: case CVU: case CVP: |
if (optype(p->op) != F |
&& opsize(p->op) <= p->syms[0]->u.c.v.i) |
p->op = LOAD + opkind(p->op); |
break; |
} |
(IR->x.target)(p); |
} |
void setreg(Node p, Symbol r) { |
p->syms[RX] = r; |
} |
void rtarget(Node p, int n, Symbol r) { |
Node q = p->kids[n]; |
|
assert(q); |
assert(r); |
assert(r->sclass == REGISTER || !r->x.wildcard); |
assert(q->syms[RX]); |
if (r != q->syms[RX] && !q->syms[RX]->x.wildcard) { |
q = newnode(LOAD + opkind(q->op), |
q, NULL, q->syms[0]); |
if (r->u.t.cse == p->kids[n]) |
r->u.t.cse = q; |
p->kids[n] = p->x.kids[n] = q; |
q->x.kids[0] = q->kids[0]; |
} |
setreg(q, r); |
debug(fprint(stderr, "(targeting %x->x.kids[%d]=%x to %s)\n", p, n, p->kids[n], r->x.name)); |
} |
static void rewrite(Node p) { |
assert(p->x.inst == 0); |
prelabel(p); |
debug(dumptree(p)); |
debug(fprint(stderr, "\n")); |
(*IR->x._label)(p); |
debug(dumpcover(p, 1, 0)); |
reduce(p, 1); |
} |
Node gen(Node forest) { |
int i; |
struct node sentinel; |
Node dummy, p; |
|
head = forest; |
for (p = forest; p; p = p->link) { |
assert(p->count == 0); |
if (generic(p->op) == CALL) |
docall(p); |
else if ( generic(p->op) == ASGN |
&& generic(p->kids[1]->op) == CALL) |
docall(p->kids[1]); |
else if (generic(p->op) == ARG) |
(*IR->x.doarg)(p); |
rewrite(p); |
p->x.listed = 1; |
} |
for (p = forest; p; p = p->link) |
prune(p, &dummy); |
relink(&sentinel, &sentinel); |
for (p = forest; p; p = p->link) |
linearize(p, &sentinel); |
forest = sentinel.x.next; |
assert(forest); |
sentinel.x.next->x.prev = NULL; |
sentinel.x.prev->x.next = NULL; |
for (p = forest; p; p = p->x.next) |
for (i = 0; i < NELEMS(p->x.kids) && p->x.kids[i]; i++) { |
assert(p->x.kids[i]->syms[RX]); |
if (p->x.kids[i]->syms[RX]->temporary) { |
p->x.kids[i]->x.prevuse = |
p->x.kids[i]->syms[RX]->x.lastuse; |
p->x.kids[i]->syms[RX]->x.lastuse = p->x.kids[i]; |
} |
} |
for (p = forest; p; p = p->x.next) { |
ralloc(p); |
if (p->x.listed && NeedsReg[opindex(p->op)] |
&& (*IR->x.rmap)(opkind(p->op))) { |
assert(generic(p->op) == CALL || generic(p->op) == LOAD); |
putreg(p->syms[RX]); |
} |
} |
return forest; |
} |
int notarget(Node p) { |
return p->syms[RX]->x.wildcard ? 0 : LBURG_MAX; |
} |
static void putreg(Symbol r) { |
assert(r && r->x.regnode); |
freemask[r->x.regnode->set] |= r->x.regnode->mask; |
debug(dumpregs("(freeing %s)\n", r->x.name, NULL)); |
} |
static Symbol askfixedreg(Symbol s) { |
Regnode r = s->x.regnode; |
int n = r->set; |
|
if (r->mask&~freemask[n]) |
return NULL; |
else { |
freemask[n] &= ~r->mask; |
usedmask[n] |= r->mask; |
return s; |
} |
} |
static Symbol askreg(Symbol rs, unsigned rmask[]) { |
int i; |
|
if (rs->x.wildcard == NULL) |
return askfixedreg(rs); |
for (i = 31; i >= 0; i--) { |
Symbol r = rs->x.wildcard[i]; |
if (r != NULL |
&& !(r->x.regnode->mask&~rmask[r->x.regnode->set]) |
&& askfixedreg(r)) |
return r; |
} |
return NULL; |
} |
|
static Symbol getreg(Symbol s, unsigned mask[], Node p) { |
Symbol r = askreg(s, mask); |
if (r == NULL) { |
r = spillee(s, mask, p); |
assert(r && r->x.regnode); |
spill(r->x.regnode->mask, r->x.regnode->set, p); |
r = askreg(s, mask); |
} |
assert(r && r->x.regnode); |
r->x.regnode->vbl = NULL; |
return r; |
} |
int askregvar(Symbol p, Symbol regs) { |
Symbol r; |
|
assert(p); |
if (p->sclass != REGISTER) |
return 0; |
else if (!isscalar(p->type)) { |
p->sclass = AUTO; |
return 0; |
} |
else if (p->temporary) { |
p->x.name = "?"; |
return 1; |
} |
else if ((r = askreg(regs, vmask)) != NULL) { |
p->x.regnode = r->x.regnode; |
p->x.regnode->vbl = p; |
p->x.name = r->x.name; |
debug(dumpregs("(allocating %s to symbol %s)\n", p->x.name, p->name)); |
return 1; |
} |
else { |
p->sclass = AUTO; |
return 0; |
} |
} |
static void linearize(Node p, Node next) { |
int i; |
|
for (i = 0; i < NELEMS(p->x.kids) && p->x.kids[i]; i++) |
linearize(p->x.kids[i], next); |
relink(next->x.prev, p); |
relink(p, next); |
debug(fprint(stderr, "(listing %x)\n", p)); |
} |
static void ralloc(Node p) { |
int i; |
unsigned mask[2]; |
|
mask[0] = tmask[0]; |
mask[1] = tmask[1]; |
assert(p); |
debug(fprint(stderr, "(rallocing %x)\n", p)); |
for (i = 0; i < NELEMS(p->x.kids) && p->x.kids[i]; i++) { |
Node kid = p->x.kids[i]; |
Symbol r = kid->syms[RX]; |
assert(r && kid->x.registered); |
if (r->sclass != REGISTER && r->x.lastuse == kid) |
putreg(r); |
} |
if (!p->x.registered && NeedsReg[opindex(p->op)] |
&& (*IR->x.rmap)(opkind(p->op))) { |
Symbol sym = p->syms[RX], set = sym; |
assert(sym); |
if (sym->temporary) |
set = (*IR->x.rmap)(opkind(p->op)); |
assert(set); |
if (set->sclass != REGISTER) { |
Symbol r; |
if (*IR->x._templates[getrule(p, p->x.inst)] == '?') |
for (i = 1; i < NELEMS(p->x.kids) && p->x.kids[i]; i++) { |
Symbol r = p->x.kids[i]->syms[RX]; |
assert(p->x.kids[i]->x.registered); |
assert(r && r->x.regnode); |
assert(sym->x.wildcard || sym != r); |
mask[r->x.regnode->set] &= ~r->x.regnode->mask; |
} |
r = getreg(set, mask, p); |
if (sym->temporary) { |
Node q; |
r->x.lastuse = sym->x.lastuse; |
for (q = sym->x.lastuse; q; q = q->x.prevuse) { |
q->syms[RX] = r; |
q->x.registered = 1; |
if (sym->u.t.cse && q->x.copy) |
q->x.equatable = 1; |
} |
} else { |
p->syms[RX] = r; |
r->x.lastuse = p; |
} |
debug(dumpregs("(allocating %s to node %x)\n", r->x.name, (char *) p)); |
} |
} |
p->x.registered = 1; |
(*IR->x.clobber)(p); |
} |
static Symbol spillee(Symbol set, unsigned mask[], Node here) { |
Symbol bestreg = NULL; |
int bestdist = -1, i; |
|
assert(set); |
if (!set->x.wildcard) |
bestreg = set; |
else { |
for (i = 31; i >= 0; i--) { |
Symbol ri = set->x.wildcard[i]; |
if ( |
ri != NULL && |
ri->x.lastuse && |
(ri->x.regnode->mask&tmask[ri->x.regnode->set]&mask[ri->x.regnode->set]) |
) { |
Regnode rn = ri->x.regnode; |
Node q = here; |
int dist = 0; |
for (; q && !uses(q, rn); q = q->x.next) |
dist++; |
if (q && dist > bestdist) { |
bestdist = dist; |
bestreg = ri; |
} |
} |
} |
} |
assert(bestreg); /* Must be able to spill something. Reconfigure the register allocator |
to ensure that we can allocate a register for all nodes without spilling |
the node's necessary input regs. */ |
assert(bestreg->x.regnode->vbl == NULL); /* Can't spill register variables because |
the reload site might be in other blocks. Reconfigure the register allocator |
to ensure that this register is never allocated to a variable. */ |
return bestreg; |
} |
static int uses(Node p, Regnode rn) { |
int i; |
|
for (i = 0; i < NELEMS(p->x.kids); i++) |
if ( |
p->x.kids[i] && |
p->x.kids[i]->x.registered && |
rn->set == p->x.kids[i]->syms[RX]->x.regnode->set && |
(rn->mask&p->x.kids[i]->syms[RX]->x.regnode->mask) |
) |
return 1; |
return 0; |
} |
static void spillr(Symbol r, Node here) { |
int i; |
Symbol tmp; |
Node p = r->x.lastuse; |
assert(p); |
while (p->x.prevuse) |
assert(r == p->syms[RX]), |
p = p->x.prevuse; |
assert(p->x.registered && !readsreg(p)); |
tmp = newtemp(AUTO, optype(p->op), opsize(p->op)); |
genspill(r, p, tmp); |
for (p = here->x.next; p; p = p->x.next) |
for (i = 0; i < NELEMS(p->x.kids) && p->x.kids[i]; i++) { |
Node k = p->x.kids[i]; |
if (k->x.registered && k->syms[RX] == r) |
genreload(p, tmp, i); |
} |
putreg(r); |
} |
static void genspill(Symbol r, Node last, Symbol tmp) { |
Node p, q; |
Symbol s; |
unsigned ty; |
|
debug(fprint(stderr, "(spilling %s to local %s)\n", r->x.name, tmp->x.name)); |
debug(fprint(stderr, "(genspill: ")); |
debug(dumptree(last)); |
debug(fprint(stderr, ")\n")); |
ty = opkind(last->op); |
NEW0(s, FUNC); |
s->sclass = REGISTER; |
s->name = s->x.name = r->x.name; |
s->x.regnode = r->x.regnode; |
q = newnode(ADDRL+P + sizeop(IR->ptrmetric.size), NULL, NULL, s); |
q = newnode(INDIR + ty, q, NULL, NULL); |
p = newnode(ADDRL+P + sizeop(IR->ptrmetric.size), NULL, NULL, tmp); |
p = newnode(ASGN + ty, p, q, NULL); |
p->x.spills = 1; |
rewrite(p); |
prune(p, &q); |
q = last->x.next; |
linearize(p, q); |
for (p = last->x.next; p != q; p = p->x.next) { |
ralloc(p); |
assert(!p->x.listed || !NeedsReg[opindex(p->op)] || !(*IR->x.rmap)(opkind(p->op))); |
} |
} |
|
static void genreload(Node p, Symbol tmp, int i) { |
Node q; |
int ty; |
|
debug(fprint(stderr, "(replacing %x with a reload from %s)\n", p->x.kids[i], tmp->x.name)); |
debug(fprint(stderr, "(genreload: ")); |
debug(dumptree(p->x.kids[i])); |
debug(fprint(stderr, ")\n")); |
ty = opkind(p->x.kids[i]->op); |
q = newnode(ADDRL+P + sizeop(IR->ptrmetric.size), NULL, NULL, tmp); |
p->x.kids[i] = newnode(INDIR + ty, q, NULL, NULL); |
rewrite(p->x.kids[i]); |
prune(p->x.kids[i], &q); |
reprune(&p->kids[1], reprune(&p->kids[0], 0, i, p), i, p); |
prune(p, &q); |
linearize(p->x.kids[i], p); |
} |
static int reprune(Node *pp, int k, int n, Node p) { |
struct node x, *q = *pp; |
|
if (q == NULL || k > n) |
return k; |
else if (q->x.inst == 0) |
return reprune(&q->kids[1], |
reprune(&q->kids[0], k, n, p), n, p); |
if (k == n) { |
debug(fprint(stderr, "(reprune changes %x from %x to %x)\n", pp, *pp, p->x.kids[n])); |
*pp = p->x.kids[n]; |
x = *p; |
(IR->x.target)(&x); |
} |
return k + 1; |
} |
void spill(unsigned mask, int n, Node here) { |
int i; |
Node p; |
|
here->x.spills = 1; |
usedmask[n] |= mask; |
if (mask&~freemask[n]) { |
|
assert( /* It makes no sense for a node to clobber() its target. */ |
here->x.registered == 0 || /* call isn't coming through clobber() */ |
here->syms[RX] == NULL || |
here->syms[RX]->x.regnode == NULL || |
here->syms[RX]->x.regnode->set != n || |
(here->syms[RX]->x.regnode->mask&mask) == 0 |
); |
|
for (p = here; p; p = p->x.next) |
for (i = 0; i < NELEMS(p->x.kids) && p->x.kids[i]; i++) { |
Symbol r = p->x.kids[i]->syms[RX]; |
assert(r); |
if (p->x.kids[i]->x.registered && r->x.regnode->set == n |
&& r->x.regnode->mask&mask) |
spillr(r, here); |
} |
} |
} |
static void dumpregs(char *msg, char *a, char *b) { |
fprint(stderr, msg, a, b); |
fprint(stderr, "(free[0]=%x)\n", freemask[0]); |
fprint(stderr, "(free[1]=%x)\n", freemask[1]); |
} |
|
int getregnum(Node p) { |
assert(p && p->syms[RX] && p->syms[RX]->x.regnode); |
return p->syms[RX]->x.regnode->number; |
} |
|
|
unsigned regloc(Symbol p) { |
assert(p && p->sclass == REGISTER && p->sclass == REGISTER && p->x.regnode); |
return p->x.regnode->set<<8 | p->x.regnode->number; |
} |
|
/config.h.ORIG
0,0 → 1,104
/* $Id: config.h,v 1.1 2002/08/28 23:12:42 drh Exp $ */ |
typedef struct { |
unsigned char max_unaligned_load; |
Symbol (*rmap)(int); |
|
void (*blkfetch)(int size, int off, int reg, int tmp); |
void (*blkstore)(int size, int off, int reg, int tmp); |
void (*blkloop)(int dreg, int doff, |
int sreg, int soff, |
int size, int tmps[]); |
void (*_label)(Node); |
int (*_rule)(void*, int); |
short **_nts; |
void (*_kids)(Node, int, Node*); |
char **_string; |
char **_templates; |
char *_isinstruction; |
char **_ntname; |
void (*emit2)(Node); |
void (*doarg)(Node); |
void (*target)(Node); |
void (*clobber)(Node); |
} Xinterface; |
extern int askregvar(Symbol, Symbol); |
extern void blkcopy(int, int, int, int, int, int[]); |
extern unsigned emitasm(Node, int); |
extern int getregnum(Node); |
extern int mayrecalc(Node); |
extern int mkactual(int, int); |
extern void mkauto(Symbol); |
extern Symbol mkreg(char *, int, int, int); |
extern Symbol mkwildcard(Symbol *); |
extern int move(Node); |
extern int notarget(Node); |
extern void parseflags(int, char **); |
extern int range(Node, int, int); |
extern unsigned regloc(Symbol); /* omit */ |
extern void rtarget(Node, int, Symbol); |
extern void setreg(Node, Symbol); |
extern void spill(unsigned, int, Node); |
extern int widens(Node); |
|
extern int argoffset, maxargoffset; |
extern int bflag, dflag; |
extern int dalign, salign; |
extern int framesize; |
extern unsigned freemask[], usedmask[]; |
extern int offset, maxoffset; |
extern int swap; |
extern unsigned tmask[], vmask[]; |
typedef struct { |
unsigned listed:1; |
unsigned registered:1; |
unsigned emitted:1; |
unsigned copy:1; |
unsigned equatable:1; |
unsigned spills:1; |
unsigned mayrecalc:1; |
void *state; |
short inst; |
Node kids[3]; |
Node prev, next; |
Node prevuse; |
short argno; |
} Xnode; |
typedef struct { |
Symbol vbl; |
short set; |
short number; |
unsigned mask; |
} *Regnode; |
enum { IREG=0, FREG=1 }; |
typedef struct { |
char *name; |
unsigned int eaddr; /* omit */ |
int offset; |
Node lastuse; |
int usecount; |
Regnode regnode; |
Symbol *wildcard; |
} Xsymbol; |
enum { RX=2 }; |
typedef struct { |
int offset; |
unsigned freemask[2]; |
} Env; |
|
#define LBURG_MAX SHRT_MAX |
|
enum { VREG=(44<<4) }; |
|
/* Exported for the front end */ |
extern void blockbeg(Env *); |
extern void blockend(Env *); |
extern void emit(Node); |
extern Node gen(Node); |
|
extern unsigned emitbin(Node, int); |
|
#ifdef NDEBUG |
#define debug(x) (void)0 |
#else |
#define debug(x) (void)(dflag&&((x),0)) |
#endif |
/list.c
0,0 → 1,57
#include "c.h" |
|
static char rcsid[] = "$Id: list.c,v 1.1 2002/08/28 23:12:44 drh Exp $"; |
|
static List freenodes; /* free list nodes */ |
|
/* append - append x to list, return new list */ |
List append(void *x, List list) { |
List new; |
|
if ((new = freenodes) != NULL) |
freenodes = freenodes->link; |
else |
NEW(new, PERM); |
if (list) { |
new->link = list->link; |
list->link = new; |
} else |
new->link = new; |
new->x = x; |
return new; |
} |
|
/* length - # elements in list */ |
int length(List list) { |
int n = 0; |
|
if (list) { |
List lp = list; |
do |
n++; |
while ((lp = lp->link) != list); |
} |
return n; |
} |
|
/* ltov - convert list to an NULL-terminated vector allocated in arena */ |
void *ltov(List *list, unsigned arena) { |
int i = 0; |
void **array = newarray(length(*list) + 1, sizeof array[0], arena); |
|
if (*list) { |
List lp = *list; |
do { |
lp = lp->link; |
array[i++] = lp->x; |
} while (lp != *list); |
#ifndef PURIFY |
lp = (*list)->link; |
(*list)->link = freenodes; |
freenodes = lp; |
#endif |
} |
*list = NULL; |
array[i] = NULL; |
return array; |
} |
/bind.c
0,0 → 1,30
#include "c.h" |
#undef yy |
#define yy \ |
xx(alpha/osf, alphaIR) \ |
xx(mips/irix, mipsebIR) \ |
xx(eco32/linux, eco32IR) \ |
xx(eco32/netbsd, eco32IR) \ |
xx(eco32/eos32, eco32IR) \ |
xx(sparc/sun, sparcIR) \ |
xx(sparc/solaris,solarisIR) \ |
xx(x86/win32, x86IR) \ |
xx(x86/linux, x86linuxIR) \ |
xx(symbolic/osf, symbolic64IR) \ |
xx(symbolic/irix,symbolicIR) \ |
xx(symbolic, symbolicIR) \ |
xx(bytecode, bytecodeIR) \ |
xx(null, nullIR) |
|
#undef xx |
#define xx(a,b) extern Interface b; |
yy |
|
Binding bindings[] = { |
#undef xx |
#define xx(a,b) #a, &b, |
yy |
NULL, NULL |
}; |
#undef yy |
#undef xx |
/expr.c
0,0 → 1,711
#include "c.h" |
|
static char rcsid[] = "$Id: expr.c,v 1.1 2002/08/28 23:12:43 drh Exp $"; |
|
static char prec[] = { |
#define xx(a,b,c,d,e,f,g) c, |
#define yy(a,b,c,d,e,f,g) c, |
#include "token.h" |
}; |
static int oper[] = { |
#define xx(a,b,c,d,e,f,g) d, |
#define yy(a,b,c,d,e,f,g) d, |
#include "token.h" |
}; |
float refinc = 1.0; |
static Tree expr2(void); |
static Tree expr3(int); |
static Tree nullcheck(Tree); |
static Tree postfix(Tree); |
static Tree unary(void); |
static Tree primary(void); |
static Type super(Type ty); |
|
static Type super(Type ty) { |
switch (ty->op) { |
case INT: |
if (ty->size < inttype->size) |
return inttype; |
break; |
case UNSIGNED: |
if (ty->size < unsignedtype->size) |
return unsignedtype; |
break; |
case POINTER: |
return unsignedptr; |
} |
return ty; |
} |
Tree expr(int tok) { |
static char stop[] = { IF, ID, '}', 0 }; |
Tree p = expr1(0); |
|
while (t == ',') { |
Tree q; |
t = gettok(); |
q = pointer(expr1(0)); |
p = tree(RIGHT, q->type, root(value(p)), q); |
} |
if (tok) |
test(tok, stop); |
return p; |
} |
Tree expr0(int tok) { |
return root(expr(tok)); |
} |
Tree expr1(int tok) { |
static char stop[] = { IF, ID, 0 }; |
Tree p = expr2(); |
|
if (t == '=' |
|| (prec[t] >= 6 && prec[t] <= 8) |
|| (prec[t] >= 11 && prec[t] <= 13)) { |
int op = t; |
t = gettok(); |
if (oper[op] == ASGN) |
p = asgntree(ASGN, p, value(expr1(0))); |
else |
{ |
expect('='); |
p = incr(op, p, expr1(0)); |
} |
} |
if (tok) |
test(tok, stop); |
return p; |
} |
Tree incr(int op, Tree v, Tree e) { |
return asgntree(ASGN, v, (*optree[op])(oper[op], v, e)); |
} |
static Tree expr2(void) { |
Tree p = expr3(4); |
|
if (t == '?') { |
Tree l, r; |
Coordinate pts[2]; |
if (Aflag > 1 && isfunc(p->type)) |
warning("%s used in a conditional expression\n", |
funcname(p)); |
p = pointer(p); |
t = gettok(); |
pts[0] = src; |
l = pointer(expr(':')); |
pts[1] = src; |
r = pointer(expr2()); |
if (generic(p->op) != CNST && events.points) |
{ |
apply(events.points, &pts[0], &l); |
apply(events.points, &pts[1], &r); |
} |
p = condtree(p, l, r); |
} |
return p; |
} |
Tree value(Tree p) { |
int op = generic(rightkid(p)->op); |
|
if (p->type != voidtype |
&& (op==AND || op==OR || op==NOT || op==EQ || op==NE |
|| op== LE || op==LT || op== GE || op==GT)) |
p = condtree(p, consttree(1, inttype), |
consttree(0, inttype)); |
return p; |
} |
static Tree expr3(int k) { |
int k1; |
Tree p = unary(); |
|
for (k1 = prec[t]; k1 >= k; k1--) |
while (prec[t] == k1 && *cp != '=') { |
Tree r; |
Coordinate pt; |
int op = t; |
t = gettok(); |
pt = src; |
p = pointer(p); |
if (op == ANDAND || op == OROR) { |
r = pointer(expr3(k1)); |
if (events.points) |
apply(events.points, &pt, &r); |
} else |
r = pointer(expr3(k1 + 1)); |
p = (*optree[op])(oper[op], p, r); |
} |
return p; |
} |
static Tree unary(void) { |
Tree p; |
|
switch (t) { |
case '*': t = gettok(); p = unary(); p = pointer(p); |
if (isptr(p->type) |
&& (isfunc(p->type->type) || isarray(p->type->type))) |
p = retype(p, p->type->type); |
else { |
if (YYnull) |
p = nullcheck(p); |
p = rvalue(p); |
} break; |
case '&': t = gettok(); p = unary(); if (isarray(p->type) || isfunc(p->type)) |
p = retype(p, ptr(p->type)); |
else |
p = lvalue(p); |
if (isaddrop(p->op) && p->u.sym->sclass == REGISTER) |
error("invalid operand of unary &; `%s' is declared register\n", p->u.sym->name); |
|
else if (isaddrop(p->op)) |
p->u.sym->addressed = 1; |
break; |
case '+': t = gettok(); p = unary(); p = pointer(p); |
if (isarith(p->type)) |
p = cast(p, promote(p->type)); |
else |
typeerror(ADD, p, NULL); break; |
case '-': t = gettok(); p = unary(); p = pointer(p); |
if (isarith(p->type)) { |
Type ty = promote(p->type); |
p = cast(p, ty); |
if (isunsigned(ty)) { |
warning("unsigned operand of unary -\n"); |
p = simplify(ADD, ty, simplify(BCOM, ty, p, NULL), cnsttree(ty, 1UL)); |
} else |
p = simplify(NEG, ty, p, NULL); |
} else |
typeerror(SUB, p, NULL); break; |
case '~': t = gettok(); p = unary(); p = pointer(p); |
if (isint(p->type)) { |
Type ty = promote(p->type); |
p = simplify(BCOM, ty, cast(p, ty), NULL); |
} else |
typeerror(BCOM, p, NULL); break; |
case '!': t = gettok(); p = unary(); p = pointer(p); |
if (isscalar(p->type)) |
p = simplify(NOT, inttype, cond(p), NULL); |
else |
typeerror(NOT, p, NULL); break; |
case INCR: t = gettok(); p = unary(); p = incr(INCR, pointer(p), consttree(1, inttype)); break; |
case DECR: t = gettok(); p = unary(); p = incr(DECR, pointer(p), consttree(1, inttype)); break; |
case TYPECODE: case SIZEOF: { int op = t; |
Type ty; |
p = NULL; |
t = gettok(); |
if (t == '(') { |
t = gettok(); |
if (istypename(t, tsym)) { |
ty = typename(); |
expect(')'); |
} else { |
p = postfix(expr(')')); |
ty = p->type; |
} |
} else { |
p = unary(); |
ty = p->type; |
} |
assert(ty); |
if (op == TYPECODE) |
p = cnsttree(inttype, (long)ty->op); |
else { |
if (isfunc(ty) || ty->size == 0) |
error("invalid type argument `%t' to `sizeof'\n", ty); |
else if (p && rightkid(p)->op == FIELD) |
error("`sizeof' applied to a bit field\n"); |
p = cnsttree(unsignedlong, (unsigned long)ty->size); |
} } break; |
case '(': |
t = gettok(); |
if (istypename(t, tsym)) { |
Type ty, ty1 = typename(), pty; |
expect(')'); |
ty = unqual(ty1); |
if (isenum(ty)) { |
Type ty2 = ty->type; |
if (isconst(ty1)) |
ty2 = qual(CONST, ty2); |
if (isvolatile(ty1)) |
ty2 = qual(VOLATILE, ty2); |
ty1 = ty2; |
ty = ty->type; |
} |
p = pointer(unary()); |
pty = p->type; |
if (isenum(pty)) |
pty = pty->type; |
if (isarith(pty) && isarith(ty) |
|| isptr(pty) && isptr(ty)) { |
explicitCast++; |
p = cast(p, ty); |
explicitCast--; |
} else if (isptr(pty) && isint(ty) |
|| isint(pty) && isptr(ty)) { |
if (Aflag >= 1 && ty->size < pty->size) |
warning("conversion from `%t' to `%t' is compiler dependent\n", p->type, ty); |
|
p = cast(p, ty); |
} else if (ty != voidtype) { |
error("cast from `%t' to `%t' is illegal\n", |
p->type, ty1); |
ty1 = inttype; |
} |
if (generic(p->op) == INDIR || ty->size == 0) |
p = tree(RIGHT, ty1, NULL, p); |
else |
p = retype(p, ty1); |
} else |
p = postfix(expr(')')); |
break; |
default: |
p = postfix(primary()); |
} |
return p; |
} |
|
static Tree postfix(Tree p) { |
for (;;) |
switch (t) { |
case INCR: p = tree(RIGHT, p->type, |
tree(RIGHT, p->type, |
p, |
incr(t, p, consttree(1, inttype))), |
p); |
t = gettok(); break; |
case DECR: p = tree(RIGHT, p->type, |
tree(RIGHT, p->type, |
p, |
incr(t, p, consttree(1, inttype))), |
p); |
t = gettok(); break; |
case '[': { |
Tree q; |
t = gettok(); |
q = expr(']'); |
if (YYnull) |
if (isptr(p->type)) |
p = nullcheck(p); |
else if (isptr(q->type)) |
q = nullcheck(q); |
p = (*optree['+'])(ADD, pointer(p), pointer(q)); |
if (isptr(p->type) && isarray(p->type->type)) |
p = retype(p, p->type->type); |
else |
p = rvalue(p); |
} break; |
case '(': { |
Type ty; |
Coordinate pt; |
p = pointer(p); |
if (isptr(p->type) && isfunc(p->type->type)) |
ty = p->type->type; |
else { |
error("found `%t' expected a function\n", p->type); |
ty = func(voidtype, NULL, 1); |
p = retype(p, ptr(ty)); |
} |
pt = src; |
t = gettok(); |
p = call(p, ty, pt); |
} break; |
case '.': t = gettok(); |
if (t == ID) { |
if (isstruct(p->type)) { |
Tree q = addrof(p); |
p = field(q, token); |
q = rightkid(q); |
if (isaddrop(q->op) && q->u.sym->temporary) |
p = tree(RIGHT, p->type, p, NULL); |
} else |
error("left operand of . has incompatible type `%t'\n", |
p->type); |
t = gettok(); |
} else |
error("field name expected\n"); break; |
case DEREF: t = gettok(); |
p = pointer(p); |
if (t == ID) { |
if (isptr(p->type) && isstruct(p->type->type)) { |
if (YYnull) |
p = nullcheck(p); |
p = field(p, token); |
} else |
error("left operand of -> has incompatible type `%t'\n", p->type); |
|
t = gettok(); |
} else |
error("field name expected\n"); break; |
default: |
return p; |
} |
} |
static Tree primary(void) { |
Tree p; |
|
assert(t != '('); |
switch (t) { |
case ICON: |
case FCON: p = tree(mkop(CNST,tsym->type), tsym->type, NULL, NULL); |
p->u.v = tsym->u.c.v; |
break; |
case SCON: if (ischar(tsym->type->type)) |
tsym->u.c.v.p = stringn(tsym->u.c.v.p, tsym->type->size); |
else |
tsym->u.c.v.p = memcpy(allocate((tsym->type->size/widechar->size)*sizeof (int), PERM), |
tsym->u.c.v.p, (tsym->type->size/widechar->size)*sizeof (int)); |
tsym = constant(tsym->type, tsym->u.c.v); |
if (tsym->u.c.loc == NULL) |
tsym->u.c.loc = genident(STATIC, tsym->type, GLOBAL); |
p = idtree(tsym->u.c.loc); break; |
case ID: if (tsym == NULL) |
{ |
Symbol p = install(token, &identifiers, level, PERM); |
p->src = src; |
if (getchr() == '(') { |
Symbol q = lookup(token, externals); |
p->type = func(inttype, NULL, 1); |
p->sclass = EXTERN; |
if (Aflag >= 1) |
warning("missing prototype\n"); |
if (q && !eqtype(q->type, p->type, 1)) |
warning("implicit declaration of `%s' does not match previous declaration at %w\n", q->name, &q->src); |
|
if (q == NULL) { |
q = install(p->name, &externals, GLOBAL, PERM); |
q->type = p->type; |
q->sclass = EXTERN; |
q->src = src; |
(*IR->defsymbol)(q); |
} |
p->u.alias = q; |
} else { |
error("undeclared identifier `%s'\n", p->name); |
p->sclass = AUTO; |
p->type = inttype; |
if (p->scope == GLOBAL) |
(*IR->defsymbol)(p); |
else |
addlocal(p); |
} |
t = gettok(); |
if (xref) |
use(p, src); |
return idtree(p); |
} |
if (xref) |
use(tsym, src); |
if (tsym->sclass == ENUM) |
p = consttree(tsym->u.value, inttype); |
else { |
if (tsym->sclass == TYPEDEF) |
error("illegal use of type name `%s'\n", tsym->name); |
p = idtree(tsym); |
} break; |
case FIRSTARG: |
if (level > PARAM && cfunc && cfunc->u.f.callee[0]) |
p = idtree(cfunc->u.f.callee[0]); |
else { |
error("illegal use of `%k'\n", FIRSTARG); |
p = cnsttree(inttype, 0L); |
} |
break; |
default: |
error("illegal expression\n"); |
p = cnsttree(inttype, 0L); |
} |
t = gettok(); |
return p; |
} |
Tree idtree(Symbol p) { |
int op; |
Tree e; |
Type ty = p->type ? unqual(p->type) : voidptype; |
|
if (p->scope == GLOBAL || p->sclass == STATIC) |
op = ADDRG; |
else if (p->scope == PARAM) { |
op = ADDRF; |
if (isstruct(p->type) && !IR->wants_argb) |
{ |
e = tree(mkop(op,voidptype), ptr(ptr(p->type)), NULL, NULL); |
e->u.sym = p; |
return rvalue(rvalue(e)); |
} |
} else if (p->sclass == EXTERN) { |
assert(p->u.alias); |
p = p->u.alias; |
op = ADDRG; |
} else |
op = ADDRL; |
p->ref += refinc; |
if (isarray(ty)) |
e = tree(mkop(op,voidptype), p->type, NULL, NULL); |
else if (isfunc(ty)) |
e = tree(mkop(op,funcptype), p->type, NULL, NULL); |
else |
e = tree(mkop(op,voidptype), ptr(p->type), NULL, NULL); |
e->u.sym = p; |
if (isptr(e->type)) |
e = rvalue(e); |
return e; |
} |
|
Tree rvalue(Tree p) { |
Type ty = deref(p->type); |
|
ty = unqual(ty); |
return tree(mkop(INDIR,ty), ty, p, NULL); |
} |
Tree lvalue(Tree p) { |
if (generic(p->op) != INDIR) { |
error("lvalue required\n"); |
return value(p); |
} else if (unqual(p->type) == voidtype) |
warning("`%t' used as an lvalue\n", p->type); |
return p->kids[0]; |
} |
Tree retype(Tree p, Type ty) { |
Tree q; |
|
if (p->type == ty) |
return p; |
q = tree(p->op, ty, p->kids[0], p->kids[1]); |
q->node = p->node; |
q->u = p->u; |
return q; |
} |
Tree rightkid(Tree p) { |
while (p && p->op == RIGHT) |
if (p->kids[1]) |
p = p->kids[1]; |
else if (p->kids[0]) |
p = p->kids[0]; |
else |
assert(0); |
assert(p); |
return p; |
} |
int hascall(Tree p) { |
if (p == 0) |
return 0; |
if (generic(p->op) == CALL || (IR->mulops_calls && |
(p->op == DIV+I || p->op == MOD+I || p->op == MUL+I |
|| p->op == DIV+U || p->op == MOD+U || p->op == MUL+U))) |
return 1; |
return hascall(p->kids[0]) || hascall(p->kids[1]); |
} |
Type binary(Type xty, Type yty) { |
#define xx(t) if (xty == t || yty == t) return t |
xx(longdouble); |
xx(doubletype); |
xx(floattype); |
xx(unsignedlonglong); |
xx(longlong); |
xx(unsignedlong); |
if (xty == longtype && yty == unsignedtype |
|| xty == unsignedtype && yty == longtype) |
if (longtype->size > unsignedtype->size) |
return longtype; |
else |
return unsignedlong; |
xx(longtype); |
xx(unsignedtype); |
return inttype; |
#undef xx |
} |
Tree pointer(Tree p) { |
if (isarray(p->type)) |
/* assert(p->op != RIGHT || p->u.sym == NULL), */ |
p = retype(p, atop(p->type)); |
else if (isfunc(p->type)) |
p = retype(p, ptr(p->type)); |
return p; |
} |
Tree cond(Tree p) { |
int op = generic(rightkid(p)->op); |
|
if (op == AND || op == OR || op == NOT |
|| op == EQ || op == NE |
|| op == LE || op == LT || op == GE || op == GT) |
return p; |
p = pointer(p); |
return (*optree[NEQ])(NE, p, consttree(0, inttype)); |
} |
Tree cast(Tree p, Type type) { |
Type src, dst; |
|
p = value(p); |
if (p->type == type) |
return p; |
dst = unqual(type); |
src = unqual(p->type); |
if (src->op != dst->op || src->size != dst->size) { |
switch (src->op) { |
case INT: |
if (src->size < inttype->size) |
p = simplify(CVI, inttype, p, NULL); |
break; |
case UNSIGNED: |
if (src->size < inttype->size) |
p = simplify(CVU, inttype, p, NULL); |
else if (src->size < unsignedtype->size) |
p = simplify(CVU, unsignedtype, p, NULL); |
break; |
case ENUM: |
p = retype(p, inttype); |
break; |
case POINTER: |
if (isint(dst) && src->size > dst->size) |
warning("conversion from `%t' to `%t' is undefined\n", p->type, type); |
p = simplify(CVP, super(src), p, NULL); |
break; |
case FLOAT: |
break; |
default: assert(0); |
} |
{ |
src = unqual(p->type); |
dst = super(dst); |
if (src->op != dst->op) |
switch (src->op) { |
case INT: |
p = simplify(CVI, dst, p, NULL); |
break; |
case UNSIGNED: |
if (isfloat(dst)) { |
Type ssrc = signedint(src); |
Tree two = cnsttree(longdouble, (long double)2.0); |
p = (*optree['+'])(ADD, |
(*optree['*'])(MUL, |
two, |
simplify(CVU, ssrc, |
simplify(RSH, src, |
p, consttree(1, inttype)), NULL)), |
simplify(CVU, ssrc, |
simplify(BAND, src, |
p, consttree(1, unsignedtype)), NULL)); |
} else |
p = simplify(CVU, dst, p, NULL); |
break; |
case FLOAT: |
if (isunsigned(dst)) { |
Type sdst = signedint(dst); |
Tree c = cast(cnsttree(longdouble, (long double)sdst->u.sym->u.limits.max.i + 1), src); |
p = condtree( |
simplify(GE, src, p, c), |
(*optree['+'])(ADD, |
cast(cast(simplify(SUB, src, p, c), sdst), dst), |
cast(cnsttree(unsignedlong, (unsigned long)sdst->u.sym->u.limits.max.i + 1), dst)), |
simplify(CVF, sdst, p, NULL)); |
} else |
p = simplify(CVF, dst, p, NULL); |
break; |
default: assert(0); |
} |
dst = unqual(type); |
} |
} |
src = unqual(p->type); |
switch (src->op) { |
case INT: |
if (src->op != dst->op || src->size != dst->size) |
p = simplify(CVI, dst, p, NULL); |
break; |
case UNSIGNED: |
if (src->op != dst->op || src->size != dst->size) |
p = simplify(CVU, dst, p, NULL); |
break; |
case FLOAT: |
if (src->op != dst->op || src->size != dst->size) |
p = simplify(CVF, dst, p, NULL); |
break; |
case POINTER: |
if (src->op != dst->op) |
p = simplify(CVP, dst, p, NULL); |
else { |
if (isfunc(src->type) && !isfunc(dst->type) |
|| !isfunc(src->type) && isfunc(dst->type)) |
warning("conversion from `%t' to `%t' is compiler dependent\n", p->type, type); |
|
if (src->size != dst->size) |
p = simplify(CVP, dst, p, NULL); |
} |
break; |
default: assert(0); |
} |
return retype(p, type); |
} |
Tree field(Tree p, const char *name) { |
Field q; |
Type ty1, ty = p->type; |
|
if (isptr(ty)) |
ty = deref(ty); |
ty1 = ty; |
ty = unqual(ty); |
if ((q = fieldref(name, ty)) != NULL) { |
if (isarray(q->type)) { |
ty = q->type->type; |
if (isconst(ty1) && !isconst(ty)) |
ty = qual(CONST, ty); |
if (isvolatile(ty1) && !isvolatile(ty)) |
ty = qual(VOLATILE, ty); |
ty = array(ty, q->type->size/ty->size, q->type->align); |
} else { |
ty = q->type; |
if (isconst(ty1) && !isconst(ty)) |
ty = qual(CONST, ty); |
if (isvolatile(ty1) && !isvolatile(ty)) |
ty = qual(VOLATILE, ty); |
ty = ptr(ty); |
} |
if (YYcheck && !isaddrop(p->op) && q->offset > 0) /* omit */ |
p = nullcall(ty, YYcheck, p, consttree(q->offset, inttype)); /* omit */ |
else /* omit */ |
p = simplify(ADD+P, ty, p, consttree(q->offset, signedptr)); |
|
if (q->lsb) { |
p = tree(FIELD, ty->type, rvalue(p), NULL); |
p->u.field = q; |
} else if (!isarray(q->type)) |
p = rvalue(p); |
|
} else { |
error("unknown field `%s' of `%t'\n", name, ty); |
p = rvalue(retype(p, ptr(inttype))); |
} |
return p; |
} |
/* funcname - return name of function f or a function' */ |
char *funcname(Tree f) { |
if (isaddrop(f->op)) |
return stringf("`%s'", f->u.sym->name); |
return "a function"; |
} |
static Tree nullcheck(Tree p) { |
if (!needconst && YYnull && isptr(p->type)) { |
p = value(p); |
if (strcmp(YYnull->name, "_YYnull") == 0) { |
Symbol t1 = temporary(REGISTER, voidptype); |
p = tree(RIGHT, p->type, |
tree(OR, voidtype, |
cond(asgn(t1, cast(p, voidptype))), |
vcall(YYnull, voidtype, (file && *file ? pointer(idtree(mkstr(file)->u.c.loc)) : cnsttree(voidptype, NULL)), cnsttree(inttype, (long)lineno) , NULL)), |
idtree(t1)); |
} |
|
else |
p = nullcall(p->type, YYnull, p, cnsttree(inttype, 0L)); |
|
} |
return p; |
} |
Tree nullcall(Type pty, Symbol f, Tree p, Tree e) { |
Type ty; |
|
if (isarray(pty)) |
return retype(nullcall(atop(pty), f, p, e), pty); |
ty = unqual(unqual(p->type)->type); |
return vcall(f, pty, |
p, e, |
cnsttree(inttype, (long)ty->size), |
cnsttree(inttype, (long)ty->align), |
(file && *file ? pointer(idtree(mkstr(file)->u.c.loc)) : cnsttree(voidptype, NULL)), cnsttree(inttype, (long)lineno) , NULL); |
} |
/event.c
0,0 → 1,29
#include "c.h" |
|
static char rcsid[] = "$Id: event.c,v 1.1 2002/08/28 23:12:43 drh Exp $"; |
|
struct entry { |
Apply func; |
void *cl; |
}; |
|
Events events; |
void attach(Apply func, void *cl, List *list) { |
struct entry *p; |
|
NEW(p, PERM); |
p->func = func; |
p->cl = cl; |
*list = append(p, *list); |
} |
void apply(List event, void *arg1, void *arg2) { |
if (event) { |
List lp = event; |
do { |
struct entry *p = lp->x; |
(*p->func)(p->cl, arg1, arg2); |
lp = lp->link; |
} while (lp != event); |
} |
} |
|
/symbolic.c
0,0 → 1,525
#include <time.h> |
#include <ctype.h> |
#include "c.h" |
|
#define I(f) s_##f |
static char rcsid[] = "$Id: symbolic.c,v 1.1 2002/08/28 23:12:47 drh Exp $"; |
|
static Node *tail; |
static int off, maxoff, uid = 0, verbose = 0, html = 0; |
|
static const char *yyBEGIN(const char *tag) { |
if (html) |
print("<%s>", tag); |
return tag; |
} |
|
static void yyEND(const char *tag) { |
if (html) |
print("</%s>", tag); |
if (isupper(*tag)) |
print("\n"); |
} |
|
#define BEGIN(tag) do { const char *yytag=yyBEGIN(#tag) |
#define END yyEND(yytag); } while (0) |
#define ITEM BEGIN(li) |
#define START BEGIN(LI) |
#define ANCHOR(attr,code) do { const char *yytag="a"; if (html) { printf("<a " #attr "=\""); code; print("\">"); } |
#define NEWLINE print(html ? "<br>\n" : "\n") |
|
static void emitCoord(Coordinate src) { |
if (src.file && *src.file) { |
ANCHOR(href,print("%s", src.file)); print("%s", src.file); END; |
print(":"); |
} |
print("%d.%d", src.y, src.x); |
} |
|
static void emitString(int len, const char *s) { |
for ( ; len-- > 0; s++) |
if (*s == '&' && html) |
print("&"); |
else if (*s == '<' && html) |
print("<"); |
else if (*s == '>' && html) |
print("<"); |
else if (*s == '"' || *s == '\\') |
print("\\%c", *s); |
else if (*s >= ' ' && *s < 0177) |
print("%c", *s); |
else |
print("\\%d%d%d", (*s>>6)&3, (*s>>3)&7, *s&7); |
} |
|
static void emitSymRef(Symbol p) { |
(*IR->defsymbol)(p); |
ANCHOR(href,print("#%s", p->x.name)); BEGIN(code); print("%s", p->name); END; END; |
} |
|
static void emitSymbol(Symbol p) { |
(*IR->defsymbol)(p); |
ANCHOR(name,print("%s", p->x.name)); BEGIN(code); print("%s", p->name); END; END; |
BEGIN(ul); |
#define xx(field,code) ITEM; if (!html) print(" "); print(#field "="); code; END |
if (verbose && (src.y || src.x)) |
xx(src,emitCoord(p->src)); |
xx(type,print("%t", p->type)); |
xx(sclass,print("%k", p->sclass)); |
switch (p->scope) { |
case CONSTANTS: xx(scope,print("CONSTANTS")); break; |
case LABELS: xx(scope,print("LABELS")); break; |
case GLOBAL: xx(scope,print("GLOBAL")); break; |
case PARAM: xx(scope,print("PARAM")); break; |
case LOCAL: xx(scope,print("LOCAL")); break; |
default: |
if (p->scope > LOCAL) |
xx(scope,print("LOCAL+%d", p->scope-LOCAL)); |
else |
xx(scope,print("%d", p->scope)); |
} |
ITEM; |
int n = 0; |
if (!html) |
print(" "); |
print("flags="); |
#define yy(f) if (p->f) { if (n++) print("|"); print(#f); } |
yy(structarg) |
yy(addressed) |
yy(computed) |
yy(temporary) |
yy(generated) |
#undef yy |
if (n == 0) |
print("0"); |
END; |
if (p->scope >= PARAM && p->sclass != STATIC) |
xx(offset,print("%d", p->x.offset)); |
xx(ref,print("%f", p->ref)); |
if (p->temporary && p->u.t.cse) |
xx(u.t.cse,print("%p", p->u.t.cse)); |
END; |
#undef xx |
} |
|
/* address - initialize q for addressing expression p+n */ |
static void I(address)(Symbol q, Symbol p, long n) { |
q->name = stringf("%s%s%D", p->name, n > 0 ? "+" : "", n); |
(*IR->defsymbol)(q); |
START; print("address "); emitSymbol(q); END; |
} |
|
/* blockbeg - start a block */ |
static void I(blockbeg)(Env *e) { |
e->offset = off; |
START; print("blockbeg off=%d", off); END; |
} |
|
/* blockend - start a block */ |
static void I(blockend)(Env *e) { |
if (off > maxoff) |
maxoff = off; |
START; print("blockend off=%d", off); END; |
off = e->offset; |
} |
|
/* defaddress - initialize an address */ |
static void I(defaddress)(Symbol p){ |
START; print("defaddress "); emitSymRef(p); END; |
} |
|
/* defconst - define a constant */ |
static void I(defconst)(int suffix, int size, Value v) { |
START; |
print("defconst "); |
switch (suffix) { |
case I: |
print("int.%d ", size); |
BEGIN(code); |
if (size > sizeof (int)) |
print("%D", v.i); |
else |
print("%d", (int)v.i); |
END; |
break; |
case U: |
print("unsigned.%d ", size); |
BEGIN(code); |
if (size > sizeof (unsigned)) |
print("%U", v.u); |
else |
print("%u", (unsigned)v.u); |
END; |
break; |
case P: print("void*.%d ", size); BEGIN(code); print("%p", v.p); END; break; |
case F: |
print("float.%d ", size); |
BEGIN(code); |
double d = v.d; |
if (d == 0.0) { |
static union { int x; char endian; } little = { 1 }; |
signed char *b = (signed char *)&d; |
if (!little.endian && b[0] < 0 |
|| little.endian && b[sizeof (d)-1] < 0) |
print("-0.0"); |
else |
print("0.0"); |
} else |
print("%g", d); |
END; |
break; |
default: assert(0); |
} |
END; |
} |
|
/* defstring - emit a string constant */ |
static void I(defstring)(int len, char *s) { |
START; print("defstring "); |
BEGIN(code); print("\""); emitString(len, s); print("\""); END; |
END; |
} |
|
/* defsymbol - define a symbol: initialize p->x */ |
static void I(defsymbol)(Symbol p) { |
if (p->x.name == NULL) |
p->x.name = stringd(++uid); |
} |
|
/* emit - emit the dags on list p */ |
static void I(emit)(Node p){ |
ITEM; |
if (!html) |
print(" "); |
for (; p; p = p->x.next) { |
if (p->op == LABEL+V) { |
assert(p->syms[0]); |
ANCHOR(name,print("%s", p->syms[0]->x.name)); |
BEGIN(code); print("%s", p->syms[0]->name); END; |
END; |
print(":"); |
} else { |
int i; |
if (p->x.listed) { |
BEGIN(strong); print("%d", p->x.inst); END; print("'"); |
print(" %s", opname(p->op)); |
} else |
print("%d. %s", p->x.inst, opname(p->op)); |
if (p->count > 1) |
print(" count=%d", p->count); |
for (i = 0; i < NELEMS(p->kids) && p->kids[i]; i++) |
print(" #%d", p->kids[i]->x.inst); |
if (generic(p->op) == CALL && p->syms[0] && p->syms[0]->type) |
print(" {%t}", p->syms[0]->type); |
else |
for (i = 0; i < NELEMS(p->syms) && p->syms[i]; i++) { |
print(" "); |
if (p->syms[i]->scope == CONSTANTS) |
print(p->syms[i]->name); |
else |
emitSymRef(p->syms[i]); |
} |
} |
NEWLINE; |
} |
END; |
} |
|
/* export - announce p as exported */ |
static void I(export)(Symbol p) { |
START; print("export "); emitSymRef(p); END; |
} |
|
/* function - generate code for a function */ |
static void I(function)(Symbol f, Symbol caller[], Symbol callee[], int ncalls) { |
int i; |
|
(*IR->defsymbol)(f); |
off = 0; |
for (i = 0; caller[i] && callee[i]; i++) { |
off = roundup(off, caller[i]->type->align); |
caller[i]->x.offset = callee[i]->x.offset = off; |
off += caller[i]->type->size; |
} |
if (!html) { |
print("function "); |
emitSymbol(f); |
print(" ncalls=%d\n", ncalls); |
for (i = 0; caller[i]; i++) |
START; print("caller "); emitSymbol(caller[i]); END; |
for (i = 0; callee[i]; i++) |
START; print("callee "); emitSymbol(callee[i]); END; |
} else { |
START; |
print("function"); |
BEGIN(UL); |
#define xx(field,code) ITEM; print(#field "="); code; END |
xx(f,emitSymbol(f)); |
xx(ncalls,print("%d", ncalls)); |
if (caller[0]) { |
ITEM; print("caller"); BEGIN(OL); |
for (i = 0; caller[i]; i++) |
ITEM; emitSymbol(caller[i]); END; |
END; END; |
ITEM; print("callee"); BEGIN(OL); |
for (i = 0; callee[i]; i++) |
ITEM; emitSymbol(callee[i]); END; |
END; END; |
} else { |
xx(caller,BEGIN(em); print("empty"); END); |
xx(callee,BEGIN(em); print("empty"); END); |
} |
END; |
END; |
} |
maxoff = off = 0; |
gencode(caller, callee); |
if (html) |
START; print("emitcode"); BEGIN(ul); emitcode(); END; END; |
else |
emitcode(); |
START; print("maxoff=%d", maxoff); END; |
#undef xx |
} |
|
/* visit - generate code for *p */ |
static int visit(Node p, int n) { |
if (p && p->x.inst == 0) { |
p->x.inst = ++n; |
n = visit(p->kids[0], n); |
n = visit(p->kids[1], n); |
*tail = p; |
tail = &p->x.next; |
} |
return n; |
} |
|
/* gen0 - generate code for the dags on list p */ |
static Node I(gen)(Node p) { |
int n; |
Node nodelist; |
|
tail = &nodelist; |
for (n = 0; p; p = p->link) { |
switch (generic(p->op)) { /* check for valid forest */ |
case CALL: |
assert(IR->wants_dag || p->count == 0); |
break; |
case ARG: |
case ASGN: case JUMP: case LABEL: case RET: |
case EQ: case GE: case GT: case LE: case LT: case NE: |
assert(p->count == 0); |
break; |
case INDIR: |
assert(IR->wants_dag && p->count > 0); |
break; |
default: |
assert(0); |
} |
check(p); |
p->x.listed = 1; |
n = visit(p, n); |
} |
*tail = 0; |
return nodelist; |
} |
|
/* global - announce a global */ |
static void I(global)(Symbol p) { |
START; print("global "); emitSymbol(p); END; |
} |
|
/* import - import a symbol */ |
static void I(import)(Symbol p) { |
START; print("import "); emitSymRef(p); END; |
} |
|
/* local - local variable */ |
static void I(local)(Symbol p) { |
if (p->temporary) |
p->name = stringf("t%s", p->name); |
(*IR->defsymbol)(p); |
off = roundup(off, p->type->align); |
p->x.offset = off; |
off += p->type->size; |
START; print(p->temporary ? "temporary " : "local "); emitSymbol(p); END; |
} |
|
/* progbeg - beginning of program */ |
static void I(progbeg)(int argc, char *argv[]) { |
int i; |
|
for (i = 1; i < argc; i++) |
if (strcmp(argv[i], "-v") == 0) |
verbose++; |
else if (strcmp(argv[i], "-html") == 0) |
html++; |
if (html) { |
print("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2 Final//EN\">\n"); |
print("<html>"); |
BEGIN(head); |
if (firstfile && *firstfile) |
BEGIN(title); emitString(strlen(firstfile), firstfile); END; |
print("<link rev=made href=\"mailto:drh@microsoft.com\">\n"); |
END; |
print("<body>\n"); |
if (firstfile && *firstfile) |
BEGIN(h1); emitString(strlen(firstfile), firstfile); END; |
BEGIN(P); BEGIN(em); |
print("Links lead from uses of identifiers and labels to their definitions."); |
END; END; |
print("<ul>\n"); |
START; |
print("progbeg"); |
BEGIN(ol); |
for (i = 1; i < argc; i++) { |
ITEM; |
BEGIN(code); print("\""); emitString(strlen(argv[i]), argv[i]); print("\""); END; |
END; |
} |
END; |
END; |
} |
} |
|
/* progend - end of program */ |
static void I(progend)(void) { |
START; print("progend"); END; |
if (html) { |
time_t t; |
print("</ul>\n"); |
time(&t); |
print("<hr><address>%s</address>\n", ctime(&t)); |
print("</body></html>\n"); |
} |
} |
|
/* segment - switch to segment s */ |
static void I(segment)(int s) { |
START; print("segment %s", &"text\0bss\0.data\0lit\0.sym\0."[5*s-5]); END; |
} |
|
/* space - initialize n bytes of space */ |
static void I(space)(int n) { |
START; print("space %d", n); END; |
} |
|
static void I(stabblock)(int brace, int lev, Symbol *p) {} |
|
/* stabend - finalize stab output */ |
static void I(stabend)(Coordinate *cp, Symbol p, Coordinate **cpp, Symbol *sp, Symbol *stab) { |
int i; |
|
if (p) |
emitSymRef(p); |
print("\n"); |
if (cpp && sp) |
for (i = 0; cpp[i] && sp[i]; i++) { |
print("%w.%d: ", cpp[i], cpp[i]->x); |
emitSymRef(sp[i]); |
print("\n"); |
} |
} |
|
static void I(stabfend)(Symbol p, int lineno) {} |
static void I(stabinit)(char *file, int argc, char *argv[]) {} |
|
/* stabline - emit line number information for source coordinate *cp */ |
static void I(stabline)(Coordinate *cp) { |
if (cp->file) |
print("%s:", cp->file); |
print("%d.%d:\n", cp->y, cp->x); |
} |
|
static void I(stabsym)(Symbol p) {} |
static void I(stabtype)(Symbol p) {} |
|
Interface symbolicIR = { |
1, 1, 0, /* char */ |
2, 2, 0, /* short */ |
4, 4, 0, /* int */ |
4, 4, 0, /* long */ |
4, 4, 0, /* long long */ |
4, 4, 1, /* float */ |
8, 8, 1, /* double */ |
8, 8, 1, /* long double */ |
4, 4, 0, /* T* */ |
0, 4, 0, /* struct */ |
0, /* little_endian */ |
0, /* mulops_calls */ |
0, /* wants_callb */ |
1, /* wants_argb */ |
1, /* left_to_right */ |
1, /* wants_dag */ |
0, /* unsigned_char */ |
I(address), |
I(blockbeg), |
I(blockend), |
I(defaddress), |
I(defconst), |
I(defstring), |
I(defsymbol), |
I(emit), |
I(export), |
I(function), |
I(gen), |
I(global), |
I(import), |
I(local), |
I(progbeg), |
I(progend), |
I(segment), |
I(space), |
I(stabblock), |
I(stabend), |
I(stabfend), |
I(stabinit), |
I(stabline), |
I(stabsym), |
I(stabtype) |
}; |
|
Interface symbolic64IR = { |
1, 1, 0, /* char */ |
2, 2, 0, /* short */ |
4, 4, 0, /* int */ |
8, 8, 0, /* long */ |
8, 8, 0, /* long long */ |
4, 4, 1, /* float */ |
8, 8, 1, /* double */ |
8, 8, 1, /* long double */ |
8, 8, 0, /* T* */ |
0, 1, 0, /* struct */ |
1, /* little_endian */ |
0, /* mulops_calls */ |
0, /* wants_callb */ |
1, /* wants_argb */ |
1, /* left_to_right */ |
1, /* wants_dag */ |
0, /* unsigned_char */ |
I(address), |
I(blockbeg), |
I(blockend), |
I(defaddress), |
I(defconst), |
I(defstring), |
I(defsymbol), |
I(emit), |
I(export), |
I(function), |
I(gen), |
I(global), |
I(import), |
I(local), |
I(progbeg), |
I(progend), |
I(segment), |
I(space), |
I(stabblock), |
I(stabend), |
I(stabfend), |
I(stabinit), |
I(stabline), |
I(stabsym), |
I(stabtype) |
}; |
/x86linux.md
0,0 → 1,1079
%{ |
/* x86/linux lburg spec. Derived from x86.md by |
Marcos Ramirez <marcos@inf.utfsm.cl> |
Horst von Brand <vonbrand@sleipnir.valparaiso.cl> |
Jacob Navia <jacob@jacob.remcomp.fr> |
*/ |
enum { EAX=0, ECX=1, EDX=2, EBX=3, ESI=6, EDI=7 }; |
#include "c.h" |
#define NODEPTR_TYPE Node |
#define OP_LABEL(p) ((p)->op) |
#define LEFT_CHILD(p) ((p)->kids[0]) |
#define RIGHT_CHILD(p) ((p)->kids[1]) |
#define STATE_LABEL(p) ((p)->x.state) |
extern int ckstack(Node, int); |
extern int memop(Node); |
extern int sametree(Node, Node); |
static Symbol charreg[32], shortreg[32], intreg[32]; |
static Symbol fltreg[32]; |
|
static Symbol charregw, shortregw, intregw, fltregw; |
|
static int cseg; |
|
static Symbol quo, rem; |
|
extern char *stabprefix; |
extern void stabblock(int, int, Symbol*); |
extern void stabend(Coordinate *, Symbol, Coordinate **, Symbol *, Symbol *); |
extern void stabfend(Symbol, int); |
extern void stabinit(char *, int, char *[]); |
extern void stabline(Coordinate *); |
extern void stabsym(Symbol); |
extern void stabtype(Symbol); |
|
static int pflag = 0; |
static char rcsid[] = "$Id: x86linux.md,v 1.1 2002/08/28 23:12:48 drh Exp $"; |
|
#define hasargs(p) (p->syms[0] && p->syms[0]->u.c.v.i > 0 ? 0 : LBURG_MAX) |
%} |
%start stmt |
%term CNSTF4=4113 |
%term CNSTF8=8209 |
%term CNSTF16=16401 |
%term CNSTI1=1045 |
%term CNSTI2=2069 |
%term CNSTI4=4117 |
%term CNSTI8=8213 |
%term CNSTP4=4119 |
%term CNSTP8=8215 |
%term CNSTU1=1046 |
%term CNSTU2=2070 |
%term CNSTU4=4118 |
%term CNSTU8=8214 |
|
%term ARGB=41 |
%term ARGF4=4129 |
%term ARGF8=8225 |
%term ARGF16=16417 |
%term ARGI4=4133 |
%term ARGI8=8229 |
%term ARGP4=4135 |
%term ARGP8=8231 |
%term ARGU4=4134 |
%term ARGU8=8230 |
|
%term ASGNB=57 |
%term ASGNF4=4145 |
%term ASGNF8=8241 |
%term ASGNF16=16433 |
%term ASGNI1=1077 |
%term ASGNI2=2101 |
%term ASGNI4=4149 |
%term ASGNI8=8245 |
%term ASGNP4=4151 |
%term ASGNP8=8247 |
%term ASGNU1=1078 |
%term ASGNU2=2102 |
%term ASGNU4=4150 |
%term ASGNU8=8246 |
|
%term INDIRB=73 |
%term INDIRF4=4161 |
%term INDIRF8=8257 |
%term INDIRF16=16449 |
%term INDIRI1=1093 |
%term INDIRI2=2117 |
%term INDIRI4=4165 |
%term INDIRI8=8261 |
%term INDIRP4=4167 |
%term INDIRP8=8263 |
%term INDIRU1=1094 |
%term INDIRU2=2118 |
%term INDIRU4=4166 |
%term INDIRU8=8262 |
|
%term CVFF4=4209 |
%term CVFF8=8305 |
%term CVFF16=16497 |
%term CVFI4=4213 |
%term CVFI8=8309 |
|
%term CVIF4=4225 |
%term CVIF8=8321 |
%term CVIF16=16513 |
%term CVII1=1157 |
%term CVII2=2181 |
%term CVII4=4229 |
%term CVII8=8325 |
%term CVIU1=1158 |
%term CVIU2=2182 |
%term CVIU4=4230 |
%term CVIU8=8326 |
|
%term CVPP4=4247 |
%term CVPP8=8343 |
%term CVPP16=16535 |
%term CVPU4=4246 |
%term CVPU8=8342 |
|
%term CVUI1=1205 |
%term CVUI2=2229 |
%term CVUI4=4277 |
%term CVUI8=8373 |
%term CVUP4=4279 |
%term CVUP8=8375 |
%term CVUP16=16567 |
%term CVUU1=1206 |
%term CVUU2=2230 |
%term CVUU4=4278 |
%term CVUU8=8374 |
|
%term NEGF4=4289 |
%term NEGF8=8385 |
%term NEGF16=16577 |
%term NEGI4=4293 |
%term NEGI8=8389 |
|
%term CALLB=217 |
%term CALLF4=4305 |
%term CALLF8=8401 |
%term CALLF16=16593 |
%term CALLI4=4309 |
%term CALLI8=8405 |
%term CALLP4=4311 |
%term CALLP8=8407 |
%term CALLU4=4310 |
%term CALLU8=8406 |
%term CALLV=216 |
|
%term RETF4=4337 |
%term RETF8=8433 |
%term RETF16=16625 |
%term RETI4=4341 |
%term RETI8=8437 |
%term RETP4=4343 |
%term RETP8=8439 |
%term RETU4=4342 |
%term RETU8=8438 |
%term RETV=248 |
|
%term ADDRGP4=4359 |
%term ADDRGP8=8455 |
|
%term ADDRFP4=4375 |
%term ADDRFP8=8471 |
|
%term ADDRLP4=4391 |
%term ADDRLP8=8487 |
|
%term ADDF4=4401 |
%term ADDF8=8497 |
%term ADDF16=16689 |
%term ADDI4=4405 |
%term ADDI8=8501 |
%term ADDP4=4407 |
%term ADDP8=8503 |
%term ADDU4=4406 |
%term ADDU8=8502 |
|
%term SUBF4=4417 |
%term SUBF8=8513 |
%term SUBF16=16705 |
%term SUBI4=4421 |
%term SUBI8=8517 |
%term SUBP4=4423 |
%term SUBP8=8519 |
%term SUBU4=4422 |
%term SUBU8=8518 |
|
%term LSHI4=4437 |
%term LSHI8=8533 |
%term LSHU4=4438 |
%term LSHU8=8534 |
|
%term MODI4=4453 |
%term MODI8=8549 |
%term MODU4=4454 |
%term MODU8=8550 |
|
%term RSHI4=4469 |
%term RSHI8=8565 |
%term RSHU4=4470 |
%term RSHU8=8566 |
|
%term BANDI4=4485 |
%term BANDI8=8581 |
%term BANDU4=4486 |
%term BANDU8=8582 |
|
%term BCOMI4=4501 |
%term BCOMI8=8597 |
%term BCOMU4=4502 |
%term BCOMU8=8598 |
|
%term BORI4=4517 |
%term BORI8=8613 |
%term BORU4=4518 |
%term BORU8=8614 |
|
%term BXORI4=4533 |
%term BXORI8=8629 |
%term BXORU4=4534 |
%term BXORU8=8630 |
|
%term DIVF4=4545 |
%term DIVF8=8641 |
%term DIVF16=16833 |
%term DIVI4=4549 |
%term DIVI8=8645 |
%term DIVU4=4550 |
%term DIVU8=8646 |
|
%term MULF4=4561 |
%term MULF8=8657 |
%term MULF16=16849 |
%term MULI4=4565 |
%term MULI8=8661 |
%term MULU4=4566 |
%term MULU8=8662 |
|
%term EQF4=4577 |
%term EQF8=8673 |
%term EQF16=16865 |
%term EQI4=4581 |
%term EQI8=8677 |
%term EQU4=4582 |
%term EQU8=8678 |
|
%term GEF4=4593 |
%term GEF8=8689 |
%term GEI4=4597 |
%term GEI8=8693 |
%term GEI16=16885 |
%term GEU4=4598 |
%term GEU8=8694 |
|
%term GTF4=4609 |
%term GTF8=8705 |
%term GTF16=16897 |
%term GTI4=4613 |
%term GTI8=8709 |
%term GTU4=4614 |
%term GTU8=8710 |
|
%term LEF4=4625 |
%term LEF8=8721 |
%term LEF16=16913 |
%term LEI4=4629 |
%term LEI8=8725 |
%term LEU4=4630 |
%term LEU8=8726 |
|
%term LTF4=4641 |
%term LTF8=8737 |
%term LTF16=16929 |
%term LTI4=4645 |
%term LTI8=8741 |
%term LTU4=4646 |
%term LTU8=8742 |
|
%term NEF4=4657 |
%term NEF8=8753 |
%term NEF16=16945 |
%term NEI4=4661 |
%term NEI8=8757 |
%term NEU4=4662 |
%term NEU8=8758 |
|
%term JUMPV=584 |
|
%term LABELV=600 |
|
%term LOADB=233 |
%term LOADF4=4321 |
%term LOADF8=8417 |
%term LOADF16=16609 |
%term LOADI1=1253 |
%term LOADI2=2277 |
%term LOADI4=4325 |
%term LOADI8=8421 |
%term LOADP4=4327 |
%term LOADP8=8423 |
%term LOADU1=1254 |
%term LOADU2=2278 |
%term LOADU4=4326 |
%term LOADU8=8422 |
|
%term VREGP=711 |
%% |
reg: INDIRI1(VREGP) "# read register\n" |
reg: INDIRU1(VREGP) "# read register\n" |
|
reg: INDIRI2(VREGP) "# read register\n" |
reg: INDIRU2(VREGP) "# read register\n" |
|
reg: INDIRI4(VREGP) "# read register\n" |
reg: INDIRP4(VREGP) "# read register\n" |
reg: INDIRU4(VREGP) "# read register\n" |
|
reg: INDIRI8(VREGP) "# read register\n" |
reg: INDIRP8(VREGP) "# read register\n" |
reg: INDIRU8(VREGP) "# read register\n" |
|
freg: INDIRF4(VREGP) "# read register\n" |
freg: INDIRF8(VREGP) "# read register\n" |
|
stmt: ASGNI1(VREGP,reg) "# write register\n" |
stmt: ASGNU1(VREGP,reg) "# write register\n" |
|
stmt: ASGNI2(VREGP,reg) "# write register\n" |
stmt: ASGNU2(VREGP,reg) "# write register\n" |
|
stmt: ASGNF4(VREGP,reg) "# write register\n" |
stmt: ASGNI4(VREGP,reg) "# write register\n" |
stmt: ASGNP4(VREGP,reg) "# write register\n" |
stmt: ASGNU4(VREGP,reg) "# write register\n" |
|
stmt: ASGNF8(VREGP,reg) "# write register\n" |
stmt: ASGNI8(VREGP,reg) "# write register\n" |
stmt: ASGNP8(VREGP,reg) "# write register\n" |
stmt: ASGNU8(VREGP,reg) "# write register\n" |
|
cnst: CNSTI1 "%a" |
cnst: CNSTU1 "%a" |
|
cnst: CNSTI2 "%a" |
cnst: CNSTU2 "%a" |
|
cnst: CNSTI4 "%a" |
cnst: CNSTU4 "%a" |
cnst: CNSTP4 "%a" |
|
cnst: CNSTI8 "%a" |
cnst: CNSTU8 "%a" |
cnst: CNSTP8 "%a" |
|
con: cnst "$%0" |
|
stmt: reg "" |
stmt: freg "" |
|
acon: ADDRGP4 "%a" |
acon: ADDRGP8 "%a" |
acon: cnst "%0" |
|
baseaddr: ADDRGP4 "%a" |
base: reg "(%0)" |
base: ADDI4(reg,acon) "%1(%0)" |
base: ADDP4(reg,acon) "%1(%0)" |
base: ADDU4(reg,acon) "%1(%0)" |
base: ADDRFP4 "%a(%%ebp)" |
base: ADDRLP4 "%a(%%ebp)" |
|
index: reg "%0" |
index: LSHI4(reg,con1) "%0,2" |
index: LSHI4(reg,con2) "%0,4" |
index: LSHI4(reg,con3) "%0,8" |
index: LSHU4(reg,con1) "%0,2" |
index: LSHU4(reg,con2) "%0,4" |
index: LSHU4(reg,con3) "%0,8" |
|
con0: CNSTI4 "1" range(a, 0, 0) |
con0: CNSTU4 "1" range(a, 0, 0) |
con1: CNSTI4 "1" range(a, 1, 1) |
con1: CNSTU4 "1" range(a, 1, 1) |
con2: CNSTI4 "2" range(a, 2, 2) |
con2: CNSTU4 "2" range(a, 2, 2) |
con3: CNSTI4 "3" range(a, 3, 3) |
con3: CNSTU4 "3" range(a, 3, 3) |
|
addr: base "%0" |
addr: baseaddr "%0" |
addr: ADDI4(index,baseaddr) "%1(,%0)" |
addr: ADDP4(index,baseaddr) "%1(,%0)" |
addr: ADDU4(index,baseaddr) "%1(,%0)" |
|
addr: ADDI4(reg,baseaddr) "%1(%0)" |
addr: ADDP4(reg,baseaddr) "%1(%0)" |
addr: ADDU4(reg,baseaddr) "%1(%0)" |
|
addr: ADDI4(index,reg) "(%1,%0)" |
addr: ADDP4(index,reg) "(%1,%0)" |
addr: ADDU4(index,reg) "(%1,%0)" |
|
addr: index "(,%0)" |
|
mem1: INDIRI1(addr) "%0" |
mem1: INDIRU1(addr) "%0" |
mem2: INDIRI2(addr) "%0" |
mem2: INDIRU2(addr) "%0" |
mem4: INDIRI4(addr) "%0" |
mem4: INDIRU4(addr) "%0" |
mem4: INDIRP4(addr) "%0" |
|
rc: reg "%0" |
rc: con "%0" |
|
mr: reg "%0" |
mr: mem4 "%0" |
|
mr1: reg "%0" |
mr1: mem1 "%0" |
|
mr2: reg "%0" |
mr2: mem2 "%0" |
|
mrc: mem4 "%0" 1 |
mrc: mem1 "%0" 1 |
mrc: mem2 "%0" 1 |
mrc: rc "%0" |
|
reg: addr "leal %0,%c\n" 1 |
reg: mr "movl %0,%c\n" 1 |
reg: mr1 "movb %0,%c\n" 1 |
reg: mr2 "movw %0,%c\n" 1 |
reg: con "mov %0,%c\n" 1 |
|
reg: LOADI1(reg) "# move\n" 1 |
reg: LOADI2(reg) "# move\n" 1 |
reg: LOADI4(reg) "# move\n" move(a) |
reg: LOADU1(reg) "# move\n" 1 |
reg: LOADU2(reg) "# move\n" 1 |
reg: LOADU4(reg) "# move\n" move(a) |
reg: LOADP4(reg) "# move\n" move(a) |
reg: ADDI4(reg,mrc) "?movl %0,%c\naddl %1,%c\n" 1 |
reg: ADDP4(reg,mrc) "?movl %0,%c\naddl %1,%c\n" 1 |
reg: ADDU4(reg,mrc) "?movl %0,%c\naddl %1,%c\n" 1 |
reg: SUBI4(reg,mrc) "?movl %0,%c\nsubl %1,%c\n" 1 |
reg: SUBP4(reg,mrc) "?movl %0,%c\nsubl %1,%c\n" 1 |
reg: SUBU4(reg,mrc) "?movl %0,%c\nsubl %1,%c\n" 1 |
reg: BANDI4(reg,mrc) "?movl %0,%c\nandl %1,%c\n" 1 |
reg: BORI4(reg,mrc) "?movl %0,%c\norl %1,%c\n" 1 |
reg: BXORI4(reg,mrc) "?movl %0,%c\nxorl %1,%c\n" 1 |
reg: BANDU4(reg,mrc) "?movl %0,%c\nandl %1,%c\n" 1 |
reg: BORU4(reg,mrc) "?movl %0,%c\norl %1,%c\n" 1 |
reg: BXORU4(reg,mrc) "?movl %0,%c\nxorl %1,%c\n" 1 |
|
stmt: ASGNI4(addr,ADDI4(mem4,con1)) "incl %1\n" memop(a) |
stmt: ASGNI4(addr,ADDU4(mem4,con1)) "incl %1\n" memop(a) |
stmt: ASGNP4(addr,ADDP4(mem4,con1)) "incl %1\n" memop(a) |
stmt: ASGNI4(addr,SUBI4(mem4,con1)) "decl %1\n" memop(a) |
stmt: ASGNI4(addr,SUBU4(mem4,con1)) "decl %1\n" memop(a) |
stmt: ASGNP4(addr,SUBP4(mem4,con1)) "decl %1\n" memop(a) |
stmt: ASGNI4(addr,ADDI4(mem4,rc)) "addl %2,%1\n" memop(a) |
stmt: ASGNI4(addr,SUBI4(mem4,rc)) "subl %2,%1\n" memop(a) |
stmt: ASGNU4(addr,ADDU4(mem4,rc)) "addl %2,%1\n" memop(a) |
stmt: ASGNU4(addr,SUBU4(mem4,rc)) "subl %2,%1\n" memop(a) |
|
stmt: ASGNI4(addr,BANDI4(mem4,rc)) "andl %2,%1\n" memop(a) |
stmt: ASGNI4(addr,BORI4(mem4,rc)) "orl %2,%1\n" memop(a) |
stmt: ASGNI4(addr,BXORI4(mem4,rc)) "xorl %2,%1\n" memop(a) |
stmt: ASGNU4(addr,BANDU4(mem4,rc)) "andl %2,%1\n" memop(a) |
stmt: ASGNU4(addr,BORU4(mem4,rc)) "orl %2,%1\n" memop(a) |
stmt: ASGNU4(addr,BXORU4(mem4,rc)) "xorl %2,%1\n" memop(a) |
reg: BCOMI4(reg) "?movl %0,%c\nnotl %c\n" 2 |
reg: BCOMU4(reg) "?movl %0,%c\nnotl %c\n" 2 |
reg: NEGI4(reg) "?movl %0,%c\nnegl %c\n" 2 |
|
stmt: ASGNI4(addr,BCOMI4(mem4)) "notl %1\n" memop(a) |
stmt: ASGNU4(addr,BCOMU4(mem4)) "notl %1\n" memop(a) |
stmt: ASGNI4(addr,NEGI4(mem4)) "negl %1\n" memop(a) |
reg: LSHI4(reg,rc5) "?movl %0,%c\nsall %1,%c\n" 2 |
reg: LSHU4(reg,rc5) "?movl %0,%c\nshll %1,%c\n" 2 |
reg: RSHI4(reg,rc5) "?movl %0,%c\nsarl %1,%c\n" 2 |
reg: RSHU4(reg,rc5) "?movl %0,%c\nshrl %1,%c\n" 2 |
|
stmt: ASGNI4(addr,LSHI4(mem4,rc5)) "sall %2,%1\n" memop(a) |
stmt: ASGNI4(addr,LSHU4(mem4,rc5)) "shll %2,%1\n" memop(a) |
stmt: ASGNI4(addr,RSHI4(mem4,rc5)) "sarl %2,%1\n" memop(a) |
stmt: ASGNI4(addr,RSHU4(mem4,rc5)) "shrl %2,%1\n" memop(a) |
|
rc5: CNSTI4 "$%a" range(a, 0, 31) |
rc5: reg "%%cl" |
reg: MULI4(reg,mrc) "?movl %0,%c\nimull %1,%c\n" 14 |
reg: MULI4(con,mr) "imul %0,%1,%c\n" 13 |
reg: MULU4(reg,mr) "mull %1\n" 13 |
reg: DIVU4(reg,reg) "xorl %%edx,%%edx\ndivl %1\n" |
reg: MODU4(reg,reg) "xorl %%edx,%%edx\ndivl %1\n" |
reg: DIVI4(reg,reg) "cdq\nidivl %1\n" |
reg: MODI4(reg,reg) "cdq\nidivl %1\n" |
reg: CVPU4(reg) "movl %0,%c\n" move(a) |
reg: CVUP4(reg) "movl %0,%c\n" move(a) |
reg: CVII4(INDIRI1(addr)) "movsbl %0,%c\n" 3 |
reg: CVII4(INDIRI2(addr)) "movswl %0,%c\n" 3 |
reg: CVUU4(INDIRU1(addr)) "movzbl %0,%c\n" 3 |
reg: CVUU4(INDIRU2(addr)) "movzwl %0,%c\n" 3 |
reg: CVII4(reg) "# extend\n" 3 |
reg: CVIU4(reg) "# extend\n" 3 |
reg: CVUI4(reg) "# extend\n" 3 |
reg: CVUU4(reg) "# extend\n" 3 |
|
reg: CVII1(reg) "# truncate\n" 1 |
reg: CVII2(reg) "# truncate\n" 1 |
reg: CVUU1(reg) "# truncate\n" 1 |
reg: CVUU2(reg) "# truncate\n" 1 |
|
mrca: mem4 "%0" |
mrca: rc "%0" |
mrca: ADDRGP4 "$%a" |
mrca: ADDRGP8 "$%a" |
|
stmt: ASGNI1(addr,rc) "movb %1,%0\n" 1 |
stmt: ASGNI2(addr,rc) "movw %1,%0\n" 1 |
stmt: ASGNI4(addr,rc) "movl %1,%0\n" 1 |
stmt: ASGNU1(addr,rc) "movb %1,%0\n" 1 |
stmt: ASGNU2(addr,rc) "movw %1,%0\n" 1 |
stmt: ASGNU4(addr,rc) "movl %1,%0\n" 1 |
stmt: ASGNP4(addr,rc) "movl %1,%0\n" 1 |
stmt: ARGI4(mrca) "pushl %0\n" 1 |
stmt: ARGU4(mrca) "pushl %0\n" 1 |
stmt: ARGP4(mrca) "pushl %0\n" 1 |
stmt: ASGNB(reg,INDIRB(reg)) "movl $%a,%%ecx\nrep\nmovsb\n" |
stmt: ARGB(INDIRB(reg)) "# ARGB\n" |
|
memf: INDIRF8(addr) "l %0" |
memf: INDIRF4(addr) "s %0" |
memf: CVFF8(INDIRF4(addr)) "s %0" |
memf: CVFF4(INDIRF8(addr)) "l %0" |
|
freg: memf "fld%0\n" 3 |
|
stmt: ASGNF8(addr,freg) "fstpl %0\n" 7 |
stmt: ASGNF4(addr,freg) "fstps %0\n" 7 |
stmt: ASGNF4(addr,CVFF4(freg)) "fstps %0\n" 7 |
|
stmt: ARGF8(freg) "subl $8,%%esp\nfstpl (%%esp)\n" |
stmt: ARGF4(freg) "subl $4,%%esp\nfstps (%%esp)\n" |
freg: NEGF8(freg) "fchs\n" |
freg: NEGF4(freg) "fchs\n" |
|
flt: memf "%0" |
flt: freg "p %%st,%%st(1)" |
flt2: memf "%0" |
flt2: freg "rp %%st,%%st(1)" |
|
freg: ADDF4(freg,flt) "fadd%1\n" |
freg: ADDF8(freg,flt) "fadd%1\n" |
|
freg: DIVF4(freg,flt2) "fdiv%1\n" |
freg: DIVF8(freg,flt2) "fdiv%1\n" |
|
freg: MULF4(freg,flt) "fmul%1\n" |
freg: MULF8(freg,flt) "fmul%1\n" |
|
freg: SUBF4(freg,flt2) "fsub%1\n" |
freg: SUBF8(freg,flt2) "fsub%1\n" |
|
freg: CVFF8(freg) "# CVFF8\n" |
freg: CVFF4(freg) "sub $4,%%esp\nfstps (%%esp)\nflds (%%esp)\naddl $4,%%esp\n" 12 |
|
reg: CVFI4(freg) "subl $8,%%esp\nfnstcw 4(%%esp)\nmovl 4(%%esp),%%edx\nmovb $12,%%dh\nmovl %%edx,0(%%esp)\nfldcw 0(%%esp)\nfistpl 0(%%esp)\npopl %c\nfldcw 0(%%esp)\naddl $4,%%esp\n" 31 |
|
freg: CVIF8(INDIRI4(addr)) "fildl %0\n" 10 |
freg: CVIF8(reg) "pushl %0\nfildl (%%esp)\naddl $4,%%esp\n" 12 |
|
freg: CVIF4(INDIRI4(addr)) "fildl %0\n" 10 |
freg: CVIF4(reg) "pushl %0\nfildl (%%esp)\naddl $4,%%esp\n" 12 |
|
addrj: ADDRGP4 "%a" |
addrj: reg "*%0" 2 |
addrj: mem4 "*%0" 2 |
|
stmt: LABELV "%a:\n" |
stmt: JUMPV(addrj) "jmp %0\n" 3 |
stmt: EQI4(mem4,rc) "cmpl %1,%0\nje %a\n" 5 |
stmt: GEI4(mem4,rc) "cmpl %1,%0\njge %a\n" 5 |
stmt: GTI4(mem4,rc) "cmpl %1,%0\njg %a\n" 5 |
stmt: LEI4(mem4,rc) "cmpl %1,%0\njle %a\n" 5 |
stmt: LTI4(mem4,rc) "cmpl %1,%0\njl %a\n" 5 |
stmt: NEI4(mem4,rc) "cmpl %1,%0\njne %a\n" 5 |
stmt: GEU4(mem4,rc) "cmpl %1,%0\njae %a\n" 5 |
stmt: GTU4(mem4,rc) "cmpl %1,%0\nja %a\n" 5 |
stmt: LEU4(mem4,rc) "cmpl %1,%0\njbe %a\n" 5 |
stmt: LTU4(mem4,rc) "cmpl %1,%0\njb %a\n" 5 |
stmt: EQI4(reg,mrc) "cmpl %1,%0\nje %a\n" 4 |
stmt: GEI4(reg,mrc) "cmpl %1,%0\njge %a\n" 4 |
stmt: GTI4(reg,mrc) "cmpl %1,%0\njg %a\n" 4 |
stmt: LEI4(reg,mrc) "cmpl %1,%0\njle %a\n" 4 |
stmt: LTI4(reg,mrc) "cmpl %1,%0\njl %a\n" 4 |
stmt: NEI4(reg,mrc) "cmpl %1,%0\njne %a\n" 4 |
|
stmt: EQU4(reg,mrc) "cmpl %1,%0\nje %a\n" 4 |
stmt: GEU4(reg,mrc) "cmpl %1,%0\njae %a\n" 4 |
stmt: GTU4(reg,mrc) "cmpl %1,%0\nja %a\n" 4 |
stmt: LEU4(reg,mrc) "cmpl %1,%0\njbe %a\n" 4 |
stmt: LTU4(reg,mrc) "cmpl %1,%0\njb %a\n" 4 |
stmt: NEU4(reg,mrc) "cmpl %1,%0\njne %a\n" 4 |
|
stmt: EQI4(BANDU4(mr,con),con0) "testl %1,%0\nje %a\n" 3 |
stmt: NEI4(BANDU4(mr,con),con0) "testl %1,%0\njne %a\n" |
|
stmt: EQI4(BANDU4(CVII2(INDIRI2(addr)),con),con0) "testw %1,%0\nje %a\n" |
stmt: NEI4(BANDU4(CVII2(INDIRI2(addr)),con),con0) "testw %1,%0\njne %a\n" |
stmt: EQI4(BANDU4(CVIU2(INDIRI2(addr)),con),con0) "testw %1,%0\nje %a\n" |
stmt: NEI4(BANDU4(CVIU2(INDIRI2(addr)),con),con0) "testw %1,%0\njne %a\n" |
stmt: EQI4(BANDU4(CVII1(INDIRI1(addr)),con),con0) "testb %1,%0\nje %a\n" |
|
cmpf: INDIRF8(addr) "l %0" |
cmpf: INDIRF4(addr) "s %0" |
cmpf: CVFF8(INDIRF4(addr)) "s %0" |
cmpf: freg "p" |
|
stmt: EQF8(cmpf,freg) "fcomp%0\nfstsw %%ax\nsahf\njp 1f\nje %a\n1:\n" |
stmt: GEF8(cmpf,freg) "fcomp%0\nfstsw %%ax\nsahf\njp %a\njbe %a\n" |
stmt: GTF8(cmpf,freg) "fcomp%0\nfstsw %%ax\nsahf\njp %a\njb %a\n" |
stmt: LEF8(cmpf,freg) "fcomp%0\nfstsw %%ax\nsahf\njp %a\njae %a\n" |
stmt: LTF8(cmpf,freg) "fcomp%0\nfstsw %%ax\nsahf\njp %a\nja %a\n" |
stmt: NEF8(cmpf,freg) "fcomp%0\nfstsw %%ax\nsahf\njp %a\njne %a\n" |
|
stmt: EQF4(cmpf,freg) "fcomp%0\nfstsw %%ax\nsahf\njp 1f\nje %a\n1:\n" |
stmt: GEF4(cmpf,freg) "fcomp%0\nfstsw %%ax\nsahf\njp %a\njbe %a\n" |
stmt: GTF4(cmpf,freg) "fcomp%0\nfstsw %%ax\nsahf\njp %a\njb %a\n" |
stmt: LEF4(cmpf,freg) "fcomp%0\nfstsw %%ax\nsahf\njp %a\njae %a\n" |
stmt: LTF4(cmpf,freg) "fcomp%0\nfstsw %%ax\nsahf\njp %a\nja %a\n" |
stmt: NEF4(cmpf,freg) "fcomp%0\nfstsw %%ax\nsahf\njp %a\njne %a\n" |
|
freg: DIVF8(freg,CVIF8(INDIRI4(addr))) "fidivl %1\n" |
freg: DIVF8(CVIF8(INDIRI4(addr)),freg) "fidivrl %0\n" |
freg: DIVF8(freg,CVIF8(CVII2(INDIRI2(addr)))) "fidivs %1\n" |
freg: DIVF8(CVIF8(CVII2(INDIRI2(addr))),freg) "fidivrs %0\n" |
freg: MULF8(freg,CVIF8(INDIRI4(addr))) "fimull %1\n" |
freg: MULF8(freg,CVIF8(CVII2(INDIRI2(addr)))) "fimuls %1\n" |
freg: SUBF8(freg,CVIF8(INDIRI4(addr))) "fisubl %1\n" |
freg: SUBF8(CVIF8(INDIRI4(addr)),freg) "fisubrl %0\n" |
freg: SUBF8(freg,CVIF8(CVII2(INDIRI2(addr)))) "fisubs %1\n" |
freg: SUBF8(CVIF8(CVII2(INDIRI2(addr))),freg) "fisubrs %0\n" |
freg: ADDF8(freg,CVIF8(INDIRI4(addr))) "fiaddl %1\n" |
freg: ADDF8(freg,CVIF8(CVII2(INDIRI2(addr)))) "fiadds %1\n" |
freg: ADDF8(freg,CVFF8(INDIRF4(addr))) "fdivs %1\n" |
freg: SUBF8(freg,CVFF8(INDIRF4(addr))) "fsubs %1\n" |
freg: MULF8(freg,CVFF8(INDIRF4(addr))) "fmuls %1\n" |
freg: DIVF8(freg,CVFF8(INDIRF4(addr))) "fdivs %1\n" |
freg: LOADF8(memf) "fld%0\n" |
|
reg: CALLI4(addrj) "call %0\naddl $%a,%%esp\n" hasargs(a) |
reg: CALLU4(addrj) "call %0\naddl $%a,%%esp\n" hasargs(a) |
reg: CALLP4(addrj) "call %0\naddl $%a,%%esp\n" hasargs(a) |
|
reg: CALLI4(addrj) "call %0\n" 1 |
reg: CALLU4(addrj) "call %0\n" 1 |
reg: CALLP4(addrj) "call %0\n" 1 |
|
stmt: CALLV(addrj) "call %0\naddl $%a,%%esp\n" hasargs(a) |
stmt: CALLV(addrj) "call %0\n" 1 |
|
freg: CALLF4(addrj) "call %0\naddl $%a,%%esp\n" hasargs(a) |
freg: CALLF4(addrj) "call %0\n" 1 |
|
stmt: CALLF4(addrj) "call %0\naddl $%a,%%esp\nfstp %%st(0)\n" hasargs(a) |
stmt: CALLF4(addrj) "call %0\nfstp %%st(0)\n" 1 |
|
freg: CALLF8(addrj) "call %0\naddl $%a,%%esp\n" hasargs(a) |
freg: CALLF8(addrj) "call %0\n" 1 |
|
stmt: CALLF8(addrj) "call %0\naddl $%a,%%esp\nfstp %%st(0)\n" hasargs(a) |
stmt: CALLF8(addrj) "call %0\nfstp %%st(0)\n" 1 |
|
stmt: RETI4(reg) "# ret\n" |
stmt: RETU4(reg) "# ret\n" |
stmt: RETP4(reg) "# ret\n" |
stmt: RETF4(freg) "# ret\n" |
stmt: RETF8(freg) "# ret\n" |
%% |
static void progbeg(int argc, char *argv[]) { |
int i; |
extern Interface x86IR, x86linuxIR; |
|
#define xx(f) assert(!x86linuxIR.f); x86linuxIR.f = x86IR.f |
xx(address); |
xx(local); |
xx(x.blkfetch); |
xx(x.blkstore); |
xx(x.blkloop); |
xx(x.doarg); |
#undef xx |
{ |
union { |
char c; |
int i; |
} u; |
u.i = 0; |
u.c = 1; |
swap = ((int)(u.i == 1)) != IR->little_endian; |
} |
parseflags(argc, argv); |
for (i = 0; i < argc; i++) |
if (strcmp(argv[i], "-p") == 0 || strcmp(argv[i], "-pg") == 0) |
pflag = 1; |
intreg[EAX] = mkreg("%%eax", EAX, 1, IREG); |
intreg[EDX] = mkreg("%%edx", EDX, 1, IREG); |
intreg[ECX] = mkreg("%%ecx", ECX, 1, IREG); |
intreg[EBX] = mkreg("%%ebx", EBX, 1, IREG); |
intreg[ESI] = mkreg("%%esi", ESI, 1, IREG); |
intreg[EDI] = mkreg("%%edi", EDI, 1, IREG); |
shortreg[EAX] = mkreg("%%ax", EAX, 1, IREG); |
shortreg[ECX] = mkreg("%%cx", ECX, 1, IREG); |
shortreg[EDX] = mkreg("%%dx", EDX, 1, IREG); |
shortreg[EBX] = mkreg("%%bx", EBX, 1, IREG); |
shortreg[ESI] = mkreg("%%si", ESI, 1, IREG); |
shortreg[EDI] = mkreg("%%di", EDI, 1, IREG); |
charreg[EAX] = mkreg("%%al", EAX, 1, IREG); |
charreg[ECX] = mkreg("%%cl", ECX, 1, IREG); |
charreg[EDX] = mkreg("%%dl", EDX, 1, IREG); |
charreg[EBX] = mkreg("%%bl", EBX, 1, IREG); |
for (i = 0; i < 8; i++) |
fltreg[i] = mkreg("%d", i, 0, FREG); |
charregw = mkwildcard(charreg); |
shortregw = mkwildcard(shortreg); |
intregw = mkwildcard(intreg); |
fltregw = mkwildcard(fltreg); |
|
tmask[IREG] = (1<<EDI) | (1<<ESI) | (1<<EBX) |
| (1<<EDX) | (1<<ECX) | (1<<EAX); |
vmask[IREG] = 0; |
tmask[FREG] = 0xff; |
vmask[FREG] = 0; |
|
cseg = 0; |
quo = mkreg("%%eax", EAX, 1, IREG); |
quo->x.regnode->mask |= 1<<EDX; |
rem = mkreg("%%edx", EDX, 1, IREG); |
rem->x.regnode->mask |= 1<<EAX; |
|
stabprefix = ".LL"; |
} |
|
static Symbol rmap(int opk) { |
switch (optype(opk)) { |
case B: case P: |
return intregw; |
case I: case U: |
if (opsize(opk) == 1) |
return charregw; |
else if (opsize(opk) == 2) |
return shortregw; |
else |
return intregw; |
case F: |
return fltregw; |
default: |
return 0; |
} |
} |
|
static Symbol prevg; |
|
static void globalend(void) { |
if (prevg && prevg->type->size > 0) |
print(".size %s,%d\n", prevg->x.name, prevg->type->size); |
prevg = NULL; |
} |
|
static void progend(void) { |
globalend(); |
(*IR->segment)(CODE); |
print(".ident \"LCC: 4.1\"\n"); |
} |
|
static void target(Node p) { |
assert(p); |
switch (specific(p->op)) { |
case RSH+I: case RSH+U: case LSH+I: case LSH+U: |
if (generic(p->kids[1]->op) != CNST |
&& !( generic(p->kids[1]->op) == INDIR |
&& specific(p->kids[1]->kids[0]->op) == VREG+P |
&& p->kids[1]->syms[RX]->u.t.cse |
&& generic(p->kids[1]->syms[RX]->u.t.cse->op) == CNST)) { |
rtarget(p, 1, intreg[ECX]); |
setreg(p, intreg[EAX]); |
} |
break; |
case MUL+U: |
setreg(p, quo); |
rtarget(p, 0, intreg[EAX]); |
break; |
case DIV+I: case DIV+U: |
setreg(p, quo); |
rtarget(p, 0, intreg[EAX]); |
rtarget(p, 1, intreg[ECX]); |
break; |
case MOD+I: case MOD+U: |
setreg(p, rem); |
rtarget(p, 0, intreg[EAX]); |
rtarget(p, 1, intreg[ECX]); |
break; |
case ASGN+B: |
rtarget(p, 0, intreg[EDI]); |
rtarget(p->kids[1], 0, intreg[ESI]); |
break; |
case ARG+B: |
rtarget(p->kids[0], 0, intreg[ESI]); |
break; |
case CVF+I: |
setreg(p, intreg[EAX]); |
break; |
case CALL+I: case CALL+U: case CALL+P: case CALL+V: |
setreg(p, intreg[EAX]); |
break; |
case RET+I: case RET+U: case RET+P: |
rtarget(p, 0, intreg[EAX]); |
break; |
} |
} |
|
static void clobber(Node p) { |
static int nstack = 0; |
|
assert(p); |
nstack = ckstack(p, nstack); |
switch (specific(p->op)) { |
case ASGN+B: case ARG+B: |
spill(1<<ECX | 1<<ESI | 1<<EDI, IREG, p); |
break; |
case EQ+F: case LE+F: case GE+F: case LT+F: case GT+F: case NE+F: |
spill(1<<EAX, IREG, p); |
break; |
case CVF+I: |
spill(1<<EDX, IREG, p); |
break; |
case CALL+F: |
spill(1<<EDX | 1<<EAX | 1<<ECX, IREG, p); |
break; |
case CALL+I: case CALL+U: case CALL+P: case CALL+V: |
spill(1<<EDX | 1<<ECX, IREG, p); |
break; |
} |
} |
|
static void emit2(Node p) { |
int op = specific(p->op); |
#define preg(f) ((f)[getregnum(p->x.kids[0])]->x.name) |
|
if (op == CVI+I && opsize(p->op) == 4 && opsize(p->x.kids[0]->op) == 1) |
print("movsbl %s,%s\n", preg(charreg), p->syms[RX]->x.name); |
else if (op == CVI+U && opsize(p->op) == 4 && opsize(p->x.kids[0]->op) == 1) |
print("movsbl %s,%s\n", preg(charreg), p->syms[RX]->x.name); |
else if (op == CVI+I && opsize(p->op) == 4 && opsize(p->x.kids[0]->op) == 2) |
print("movswl %s,%s\n", preg(shortreg), p->syms[RX]->x.name); |
else if (op == CVI+U && opsize(p->op) == 4 && opsize(p->x.kids[0]->op) == 2) |
print("movswl %s,%s\n", preg(shortreg), p->syms[RX]->x.name); |
else if (op == CVU+I && opsize(p->op) == 4 && opsize(p->x.kids[0]->op) == 1) |
print("movzbl %s,%s\n", preg(charreg), p->syms[RX]->x.name); |
else if (op == CVU+U && opsize(p->op) == 4 && opsize(p->x.kids[0]->op) == 1) |
print("movzbl %s,%s\n", preg(charreg), p->syms[RX]->x.name); |
else if (op == CVU+I && opsize(p->op) == 4 && opsize(p->x.kids[0]->op) == 2) |
print("movzwl %s,%s\n", preg(shortreg), p->syms[RX]->x.name); |
else if (op == CVU+U && opsize(p->op) == 4 && opsize(p->x.kids[0]->op) == 2) |
print("movzwl %s,%s\n", preg(shortreg), p->syms[RX]->x.name); |
else if (generic(op) == CVI || generic(op) == CVU || generic(op) == LOAD) { |
char *dst = intreg[getregnum(p)]->x.name; |
char *src = preg(intreg); |
assert(opsize(p->op) <= opsize(p->x.kids[0]->op)); |
if (dst != src) |
print("movl %s,%s\n", src, dst); |
} else if (op == ARG+B) |
print("subl $%d,%%esp\nmovl %%esp,%%edi\nmovl $%d,%%ecx\nrep\nmovsb\n", |
roundup(p->syms[0]->u.c.v.i, 4), p->syms[0]->u.c.v.i); |
} |
|
static void function(Symbol f, Symbol caller[], Symbol callee[], int n) { |
int i; |
|
globalend(); |
print(".align 16\n"); |
print(".type %s,@function\n", f->x.name); |
print("%s:\n", f->x.name); |
print("pushl %%ebp\n"); |
if (pflag) { |
static int plab; |
print("movl %%esp,%%ebp\n"); |
(*IR->segment)(DATA); |
print(".align 4\n.LP%d:\n.long 0\n", plab); |
(*IR->segment)(CODE); |
print("movl $.LP%d,%%edx\ncall mcount\n", plab); |
plab++; |
} |
print("pushl %%ebx\n"); |
print("pushl %%esi\n"); |
print("pushl %%edi\n"); |
print("movl %%esp,%%ebp\n"); |
|
usedmask[0] = usedmask[1] = 0; |
freemask[0] = freemask[1] = ~0U; |
offset = 16 + 4; |
for (i = 0; callee[i]; i++) { |
Symbol p = callee[i]; |
Symbol q = caller[i]; |
assert(q); |
offset = roundup(offset, q->type->align); |
p->x.offset = q->x.offset = offset; |
p->x.name = q->x.name = stringf("%d", p->x.offset); |
p->sclass = q->sclass = AUTO; |
offset += roundup(q->type->size, 4); |
} |
assert(caller[i] == 0); |
offset = maxoffset = 0; |
gencode(caller, callee); |
framesize = roundup(maxoffset, 4); |
if (framesize > 0) |
print("subl $%d,%%esp\n", framesize); |
emitcode(); |
print("movl %%ebp,%%esp\n"); |
print("popl %%edi\n"); |
print("popl %%esi\n"); |
print("popl %%ebx\n"); |
print("popl %%ebp\n"); |
print("ret\n"); |
{ int l = genlabel(1); |
print(".Lf%d:\n", l); |
print(".size %s,.Lf%d-%s\n", f->x.name, l, f->x.name); |
} |
} |
|
static void defsymbol(Symbol p) { |
if (p->scope >= LOCAL && p->sclass == STATIC) |
p->x.name = stringf("%s.%d", p->name, genlabel(1)); |
else if (p->generated) |
p->x.name = stringf(".LC%s", p->name); |
else if (p->scope == GLOBAL || p->sclass == EXTERN) |
p->x.name = stringf("%s", p->name); |
else |
p->x.name = p->name; |
} |
|
static void segment(int n) { |
if (n == cseg) |
return; |
cseg = n; |
if (cseg == CODE) |
print(".text\n"); |
else if (cseg == BSS) |
print(".bss\n"); |
else if (cseg == DATA || cseg == LIT) |
print(".data\n"); |
} |
|
static void defconst(int suffix, int size, Value v) { |
if (suffix == I && size == 1) |
print(".byte %d\n", (int)v.u); |
else if (suffix == I && size == 2) |
print(".word %d\n", (int)v.i); |
else if (suffix == I && size == 4) |
print(".long %d\n", (int)v.i); |
else if (suffix == U && size == 1) |
print(".byte %d\n", (int)((char)v.u)); |
else if (suffix == U && size == 2) |
print(".word %d\n", (int)v.u); |
else if (suffix == U && size == 4) |
print(".long %d\n", (int)v.u); |
else if (suffix == P && size == 4) |
print(".long %d\n", (int)v.p); |
else if (suffix == F && size == 4) { |
float f = v.d; |
print(".long %d\n", (int)(*(unsigned *)&f)); |
} else if (suffix == F && size == 8) { |
double d = v.d; |
unsigned *p = (unsigned *)&d; |
print(".long %d\n.long %d\n", (int)p[swap], (int)p[!swap]); |
} |
else assert(0); |
} |
|
static void defaddress(Symbol p) { |
print(".long %s\n", p->x.name); |
} |
|
static void defstring(int n, char *str) { |
char *s; |
|
for (s = str; s < str + n; s++) |
print(".byte %d\n", (*s)&0377); |
} |
|
static void export(Symbol p) { |
globalend(); |
print(".globl %s\n", p->x.name); |
} |
|
static void import(Symbol p) {} |
|
static void global(Symbol p) { |
globalend(); |
print(".align %d\n", p->type->align > 4 ? 4 : p->type->align); |
if (!p->generated) { |
print(".type %s,@%s\n", p->x.name, |
isfunc(p->type) ? "function" : "object"); |
if (p->type->size > 0) |
print(".size %s,%d\n", p->x.name, p->type->size); |
else |
prevg = p; |
} |
if (p->u.seg == BSS) { |
if (p->sclass == STATIC) |
print(".lcomm %s,%d\n", p->x.name, p->type->size); |
else |
print(".comm %s,%d\n", p->x.name, p->type->size); |
} else { |
print("%s:\n", p->x.name); |
} |
} |
|
static void space(int n) { |
if (cseg != BSS) |
print(".space %d\n", n); |
} |
|
Interface x86linuxIR = { |
1, 1, 0, /* char */ |
2, 2, 0, /* short */ |
4, 4, 0, /* int */ |
4, 4, 0, /* long */ |
4, 4, 0, /* long long */ |
4, 4, 1, /* float */ |
8, 4, 1, /* double */ |
8, 4, 1, /* long double */ |
4, 4, 0, /* T * */ |
0, 1, 0, /* struct */ |
1, /* little_endian */ |
0, /* mulops_calls */ |
0, /* wants_callb */ |
1, /* wants_argb */ |
0, /* left_to_right */ |
0, /* wants_dag */ |
0, /* unsigned_char */ |
0, /* address */ |
blockbeg, |
blockend, |
defaddress, |
defconst, |
defstring, |
defsymbol, |
emit, |
export, |
function, |
gen, |
global, |
import, |
0, /* local */ |
progbeg, |
progend, |
segment, |
space, |
stabblock, stabend, 0, stabinit, stabline, stabsym, stabtype, |
{1, rmap, |
0, 0, 0, /* blkfetch, blkstore, blkloop */ |
_label, |
_rule, |
_nts, |
_kids, |
_string, |
_templates, |
_isinstruction, |
_ntname, |
emit2, |
0, /* doarg */ |
target, |
clobber, |
} |
}; |
/main.c
0,0 → 1,230
#include "c.h" |
|
static char rcsid[] = "$Name: v4_2 $($Id: main.c,v 1.1 2002/08/28 23:12:44 drh Exp $)"; |
|
static void typestab(Symbol, void *); |
|
static void stabline(Coordinate *); |
static void stabend(Coordinate *, Symbol, Coordinate **, Symbol *, Symbol *); |
Interface *IR = NULL; |
|
int Aflag; /* >= 0 if -A specified */ |
int Pflag; /* != 0 if -P specified */ |
int glevel; /* == [0-9] if -g[0-9] specified */ |
int xref; /* != 0 for cross-reference data */ |
Symbol YYnull; /* _YYnull symbol if -n or -nvalidate specified */ |
Symbol YYcheck; /* _YYcheck symbol if -nvalidate,check specified */ |
|
static char *comment; |
static Interface stabIR; |
static char *currentfile; /* current file name */ |
static int currentline; /* current line number */ |
static FILE *srcfp; /* stream for current file, if non-NULL */ |
static int srcpos; /* position of srcfp, if srcfp is non-NULL */ |
int main(int argc, char *argv[]) { |
int i, j; |
for (i = argc - 1; i > 0; i--) |
if (strncmp(argv[i], "-target=", 8) == 0) |
break; |
if (i > 0) { |
char *s = strchr(argv[i], '\\'); |
if (s != NULL) |
*s = '/'; |
for (j = 0; bindings[j].name && bindings[j].ir; j++) |
if (strcmp(&argv[i][8], bindings[j].name) == 0) { |
IR = bindings[j].ir; |
break; |
} |
if (s != NULL) |
*s = '\\'; |
} |
if (!IR) { |
fprint(stderr, "%s: unknown target", argv[0]); |
if (i > 0) |
fprint(stderr, " `%s'", &argv[i][8]); |
fprint(stderr, "; must specify one of\n"); |
for (i = 0; bindings[i].name; i++) |
fprint(stderr, "\t-target=%s\n", bindings[i].name); |
exit(EXIT_FAILURE); |
} |
init(argc, argv); |
t = gettok(); |
(*IR->progbeg)(argc, argv); |
for (i = 1; i < argc; i++) |
if (strcmp(argv[i], "-n") == 0) { |
if (!YYnull) { |
YYnull = install(string("_YYnull"), &globals, GLOBAL, PERM); |
YYnull->type = func(voidptype, NULL, 1); |
YYnull->sclass = EXTERN; |
(*IR->defsymbol)(YYnull); |
} |
} else if (strncmp(argv[i], "-n", 2) == 0) { /* -nvalid[,check] */ |
char *p = strchr(argv[i], ','); |
if (p) { |
YYcheck = install(string(p+1), &globals, GLOBAL, PERM); |
YYcheck->type = func(voidptype, NULL, 1); |
YYcheck->sclass = EXTERN; |
(*IR->defsymbol)(YYcheck); |
p = stringn(argv[i]+2, p - (argv[i]+2)); |
} else |
p = string(argv[i]+2); |
YYnull = install(p, &globals, GLOBAL, PERM); |
YYnull->type = func(voidptype, NULL, 1); |
YYnull->sclass = EXTERN; |
(*IR->defsymbol)(YYnull); |
} else { |
profInit(argv[i]); |
traceInit(argv[i]); |
} |
if (glevel && IR->stabinit) |
(*IR->stabinit)(firstfile, argc, argv); |
program(); |
if (events.end) |
apply(events.end, NULL, NULL); |
memset(&events, 0, sizeof events); |
if (glevel || xref) { |
Symbol symroot = NULL; |
Coordinate src; |
foreach(types, GLOBAL, typestab, &symroot); |
foreach(identifiers, GLOBAL, typestab, &symroot); |
src.file = firstfile; |
src.x = 0; |
src.y = lineno; |
if ((glevel > 2 || xref) && IR->stabend) |
(*IR->stabend)(&src, symroot, |
ltov(&loci, PERM), |
ltov(&symbols, PERM), NULL); |
else if (IR->stabend) |
(*IR->stabend)(&src, NULL, NULL, NULL, NULL); |
} |
finalize(); |
(*IR->progend)(); |
deallocate(PERM); |
return errcnt > 0; |
} |
/* main_init - process program arguments */ |
void main_init(int argc, char *argv[]) { |
char *infile = NULL, *outfile = NULL; |
int i; |
static int inited; |
|
if (inited) |
return; |
inited = 1; |
type_init(argc, argv); |
for (i = 1; i < argc; i++) |
if (strcmp(argv[i], "-g") == 0 || strcmp(argv[i], "-g2") == 0) |
glevel = 2; |
else if (strncmp(argv[i], "-g", 2) == 0) { /* -gn[,x] */ |
char *p = strchr(argv[i], ','); |
glevel = atoi(argv[i]+2); |
if (p) { |
comment = p + 1; |
if (glevel == 0) |
glevel = 1; |
if (stabIR.stabline == NULL) { |
stabIR.stabline = IR->stabline; |
stabIR.stabend = IR->stabend; |
IR->stabline = stabline; |
IR->stabend = stabend; |
} |
} |
} else if (strcmp(argv[i], "-x") == 0) |
xref++; |
else if (strcmp(argv[i], "-A") == 0) { |
++Aflag; |
} else if (strcmp(argv[i], "-P") == 0) |
Pflag++; |
else if (strcmp(argv[i], "-w") == 0) |
wflag++; |
else if (strcmp(argv[i], "-v") == 0) |
fprint(stderr, "%s %s\n", argv[0], rcsid); |
else if (strncmp(argv[i], "-s", 2) == 0) |
density = strtod(&argv[i][2], NULL); |
else if (strncmp(argv[i], "-errout=", 8) == 0) { |
FILE *f = fopen(argv[i]+8, "w"); |
if (f == NULL) { |
fprint(stderr, "%s: can't write errors to `%s'\n", argv[0], argv[i]+8); |
exit(EXIT_FAILURE); |
} |
fclose(f); |
f = freopen(argv[i]+8, "w", stderr); |
assert(f); |
} else if (strncmp(argv[i], "-e", 2) == 0) { |
int x; |
if ((x = strtol(&argv[i][2], NULL, 0)) > 0) |
errlimit = x; |
} else if (strncmp(argv[i], "-little_endian=", 15) == 0) |
IR->little_endian = argv[i][15] - '0'; |
else if (strncmp(argv[i], "-mulops_calls=", 18) == 0) |
IR->mulops_calls = argv[i][18] - '0'; |
else if (strncmp(argv[i], "-wants_callb=", 13) == 0) |
IR->wants_callb = argv[i][13] - '0'; |
else if (strncmp(argv[i], "-wants_argb=", 12) == 0) |
IR->wants_argb = argv[i][12] - '0'; |
else if (strncmp(argv[i], "-left_to_right=", 15) == 0) |
IR->left_to_right = argv[i][15] - '0'; |
else if (strncmp(argv[i], "-wants_dag=", 11) == 0) |
IR->wants_dag = argv[i][11] - '0'; |
else if (*argv[i] != '-' || strcmp(argv[i], "-") == 0) { |
if (infile == NULL) |
infile = argv[i]; |
else if (outfile == NULL) |
outfile = argv[i]; |
} |
|
if (infile != NULL && strcmp(infile, "-") != 0 |
&& freopen(infile, "r", stdin) == NULL) { |
fprint(stderr, "%s: can't read `%s'\n", argv[0], infile); |
exit(EXIT_FAILURE); |
} |
if (outfile != NULL && strcmp(outfile, "-") != 0 |
&& freopen(outfile, "w", stdout) == NULL) { |
fprint(stderr, "%s: can't write `%s'\n", argv[0], outfile); |
exit(EXIT_FAILURE); |
} |
} |
/* typestab - emit stab entries for p */ |
static void typestab(Symbol p, void *cl) { |
if (*(Symbol *)cl == 0 && p->sclass && p->sclass != TYPEDEF) |
*(Symbol *)cl = p; |
if ((p->sclass == TYPEDEF || p->sclass == 0) && IR->stabtype) |
(*IR->stabtype)(p); |
} |
|
/* stabline - emit source code for source coordinate *cp */ |
static void stabline(Coordinate *cp) { |
if (cp->file && cp->file != currentfile) { |
if (srcfp) |
fclose(srcfp); |
currentfile = cp->file; |
srcfp = fopen(currentfile, "r"); |
srcpos = 0; |
currentline = 0; |
} |
if (currentline != cp->y && srcfp) { |
char buf[512]; |
if (srcpos > cp->y) { |
rewind(srcfp); |
srcpos = 0; |
} |
for ( ; srcpos < cp->y; srcpos++) |
if (fgets(buf, sizeof buf, srcfp) == NULL) { |
fclose(srcfp); |
srcfp = NULL; |
break; |
} |
if (srcfp && srcpos == cp->y) |
print("%s%s", comment, buf); |
} |
currentline = cp->y; |
if (stabIR.stabline) |
(*stabIR.stabline)(cp); |
} |
|
static void stabend(Coordinate *cp, Symbol p, Coordinate **cpp, Symbol *sp, Symbol *stab) { |
if (stabIR.stabend) |
(*stabIR.stabend)(cp, p, cpp, sp, stab); |
if (srcfp) |
fclose(srcfp); |
} |
/token.h
0,0 → 1,134
/* $Id: token.h,v 1.1 2002/08/28 23:12:47 drh Exp $ */ |
/* |
xx(symbol, value, prec, op, optree, kind, string) |
*/ |
yy(0, 0, 0, 0, 0, 0, 0) |
xx(FLOAT, 1, 0, 0, 0, CHAR, "float") |
xx(DOUBLE, 2, 0, 0, 0, CHAR, "double") |
xx(CHAR, 3, 0, 0, 0, CHAR, "char") |
xx(SHORT, 4, 0, 0, 0, CHAR, "short") |
xx(INT, 5, 0, 0, 0, CHAR, "int") |
xx(UNSIGNED, 6, 0, 0, 0, CHAR, "unsigned") |
xx(POINTER, 7, 0, 0, 0, 0, "pointer") |
xx(VOID, 8, 0, 0, 0, CHAR, "void") |
xx(STRUCT, 9, 0, 0, 0, CHAR, "struct") |
xx(UNION, 10, 0, 0, 0, CHAR, "union") |
xx(FUNCTION, 11, 0, 0, 0, 0, "function") |
xx(ARRAY, 12, 0, 0, 0, 0, "array") |
xx(ENUM, 13, 0, 0, 0, CHAR, "enum") |
xx(LONG, 14, 0, 0, 0, CHAR, "long") |
xx(CONST, 15, 0, 0, 0, CHAR, "const") |
xx(VOLATILE, 16, 0, 0, 0, CHAR, "volatile") |
yy(0, 17, 0, 0, 0, 0, 0) |
yy(0, 18, 0, 0, 0, 0, 0) |
yy(0, 19, 0, 0, 0, 0, 0) |
yy(0, 20, 0, 0, 0, 0, 0) |
yy(0, 21, 0, 0, 0, 0, 0) |
yy(0, 22, 0, 0, 0, 0, 0) |
yy(0, 23, 0, 0, 0, 0, 0) |
yy(0, 24, 0, 0, 0, 0, 0) |
yy(0, 25, 0, 0, 0, 0, 0) |
yy(0, 26, 0, 0, 0, 0, 0) |
yy(0, 27, 0, 0, 0, 0, 0) |
yy(0, 28, 0, 0, 0, 0, "long long") |
yy(0, 29, 0, 0, 0, 0, 0) |
yy(0, 30, 0, 0, 0, 0, 0) |
yy(0, 31, 0, 0, 0, 0, "const volatile") |
xx(ID, 32, 0, 0, 0, ID, "identifier") |
yy(0, 33, 0, 0, 0, ID, "!") |
xx(FCON, 34, 0, 0, 0, ID, "floating constant") |
xx(ICON, 35, 0, 0, 0, ID, "integer constant") |
xx(SCON, 36, 0, 0, 0, ID, "string constant") |
yy(0, 37, 13, MOD, bittree,'%', "%") |
yy(0, 38, 8, BAND, bittree,ID, "&") |
xx(INCR, 39, 0, ADD, addtree,ID, "++") |
yy(0, 40, 0, 0, 0, ID, "(") |
yy(0, 41, 0, 0, 0, ')', ")") |
yy(0, 42, 13, MUL, multree,ID, "*") |
yy(0, 43, 12, ADD, addtree,ID, "+") |
yy(0, 44, 1, 0, 0, ',', ",") |
yy(0, 45, 12, SUB, subtree,ID, "-") |
yy(0, 46, 0, 0, 0, '.', ".") |
yy(0, 47, 13, DIV, multree,'/', "/") |
xx(DECR, 48, 0, SUB, subtree,ID, "--") |
xx(DEREF, 49, 0, 0, 0, DEREF, "->") |
xx(ANDAND, 50, 5, AND, andtree,ANDAND, "&&") |
xx(OROR, 51, 4, OR, andtree,OROR, "||") |
xx(LEQ, 52, 10, LE, cmptree,LEQ, "<=") |
xx(EQL, 53, 9, EQ, eqtree, EQL, "==") |
xx(NEQ, 54, 9, NE, eqtree, NEQ, "!=") |
xx(GEQ, 55, 10, GE, cmptree,GEQ, ">=") |
xx(RSHIFT, 56, 11, RSH, shtree, RSHIFT, ">>") |
xx(LSHIFT, 57, 11, LSH, shtree, LSHIFT, "<<") |
yy(0, 58, 0, 0, 0, ':', ":") |
yy(0, 59, 0, 0, 0, IF, ";") |
yy(0, 60, 10, LT, cmptree,'<', "<") |
yy(0, 61, 2, ASGN, asgntree,'=', "=") |
yy(0, 62, 10, GT, cmptree,'>', ">") |
yy(0, 63, 0, 0, 0, '?', "?") |
xx(ELLIPSIS, 64, 0, 0, 0, ELLIPSIS,"...") |
xx(SIZEOF, 65, 0, 0, 0, ID, "sizeof") |
yy(0, 66, 0, 0, 0, 0, 0) |
xx(AUTO, 67, 0, 0, 0, STATIC, "auto") |
xx(BREAK, 68, 0, 0, 0, IF, "break") |
xx(CASE, 69, 0, 0, 0, IF, "case") |
xx(CONTINUE, 70, 0, 0, 0, IF, "continue") |
xx(DEFAULT, 71, 0, 0, 0, IF, "default") |
xx(DO, 72, 0, 0, 0, IF, "do") |
xx(ELSE, 73, 0, 0, 0, IF, "else") |
xx(EXTERN, 74, 0, 0, 0, STATIC, "extern") |
xx(FOR, 75, 0, 0, 0, IF, "for") |
xx(GOTO, 76, 0, 0, 0, IF, "goto") |
xx(IF, 77, 0, 0, 0, IF, "if") |
xx(REGISTER, 78, 0, 0, 0, STATIC, "register") |
xx(RETURN, 79, 0, 0, 0, IF, "return") |
xx(SIGNED, 80, 0, 0, 0, CHAR, "signed") |
xx(STATIC, 81, 0, 0, 0, STATIC, "static") |
xx(SWITCH, 82, 0, 0, 0, IF, "switch") |
xx(TYPEDEF, 83, 0, 0, 0, STATIC, "typedef") |
xx(WHILE, 84, 0, 0, 0, IF, "while") |
xx(TYPECODE, 85, 0, 0, 0, ID, "__typecode") |
xx(FIRSTARG, 86, 0, 0, 0, ID, "__firstarg") |
yy(0, 87, 0, 0, 0, 0, 0) |
yy(0, 88, 0, 0, 0, 0, 0) |
yy(0, 89, 0, 0, 0, 0, 0) |
yy(0, 90, 0, 0, 0, 0, 0) |
yy(0, 91, 0, 0, 0, '[', "[") |
yy(0, 92, 0, 0, 0, 0, 0) |
yy(0, 93, 0, 0, 0, ']', "]") |
yy(0, 94, 7, BXOR, bittree,'^', "^") |
yy(0, 95, 0, 0, 0, 0, 0) |
yy(0, 96, 0, 0, 0, 0, 0) |
yy(0, 97, 0, 0, 0, 0, 0) |
yy(0, 98, 0, 0, 0, 0, 0) |
yy(0, 99, 0, 0, 0, 0, 0) |
yy(0, 100, 0, 0, 0, 0, 0) |
yy(0, 101, 0, 0, 0, 0, 0) |
yy(0, 102, 0, 0, 0, 0, 0) |
yy(0, 103, 0, 0, 0, 0, 0) |
yy(0, 104, 0, 0, 0, 0, 0) |
yy(0, 105, 0, 0, 0, 0, 0) |
yy(0, 106, 0, 0, 0, 0, 0) |
yy(0, 107, 0, 0, 0, 0, 0) |
yy(0, 108, 0, 0, 0, 0, 0) |
yy(0, 109, 0, 0, 0, 0, 0) |
yy(0, 110, 0, 0, 0, 0, 0) |
yy(0, 111, 0, 0, 0, 0, 0) |
yy(0, 112, 0, 0, 0, 0, 0) |
yy(0, 113, 0, 0, 0, 0, 0) |
yy(0, 114, 0, 0, 0, 0, 0) |
yy(0, 115, 0, 0, 0, 0, 0) |
yy(0, 116, 0, 0, 0, 0, 0) |
yy(0, 117, 0, 0, 0, 0, 0) |
yy(0, 118, 0, 0, 0, 0, 0) |
yy(0, 119, 0, 0, 0, 0, 0) |
yy(0, 120, 0, 0, 0, 0, 0) |
yy(0, 121, 0, 0, 0, 0, 0) |
yy(0, 122, 0, 0, 0, 0, 0) |
yy(0, 123, 0, 0, 0, IF, "{") |
yy(0, 124, 6, BOR, bittree,'|', "|") |
yy(0, 125, 0, 0, 0, '}', "}") |
yy(0, 126, 0, BCOM, 0, ID, "~") |
xx(EOI, 127, 0, 0, 0, EOI, "end of input") |
#undef xx |
#undef yy |
/inits.c
0,0 → 1,5
void init(int argc, char *argv[]) { |
{extern void input_init(int, char *[]); input_init(argc, argv);} |
{extern void main_init(int, char *[]); main_init(argc, argv);} |
{extern void type_init(int, char *[]); type_init(argc, argv);} |
} |
/c.h
0,0 → 1,600
/* $Id: c.h,v 1.1 2002/08/28 23:12:41 drh Exp $ */ |
#include <assert.h> |
#include <stdarg.h> |
#include <stdio.h> |
#include <stdlib.h> |
#include <limits.h> |
#include <string.h> |
|
#define NEW(p,a) ((p) = allocate(sizeof *(p), (a))) |
#define NEW0(p,a) memset(NEW((p),(a)), 0, sizeof *(p)) |
#define isaddrop(op) (specific(op)==ADDRG+P || specific(op)==ADDRL+P \ |
|| specific(op)==ADDRF+P) |
|
#define MAXLINE 512 |
#define BUFSIZE 4096 |
|
#define istypename(t,tsym) (kind[t] == CHAR \ |
|| t == ID && tsym && tsym->sclass == TYPEDEF) |
#define sizeop(n) ((n)<<10) |
#define generic(op) ((op)&0x3F0) |
#define specific(op) ((op)&0x3FF) |
#define opindex(op) (((op)>>4)&0x3F) |
#define opkind(op) ((op)&~0x3F0) |
#define opsize(op) ((op)>>10) |
#define optype(op) ((op)&0xF) |
#ifdef __LCC__ |
#ifndef __STDC__ |
#define __STDC__ |
#endif |
#endif |
#define NELEMS(a) ((int)(sizeof (a)/sizeof ((a)[0]))) |
#undef roundup |
#define roundup(x,n) (((x)+((n)-1))&(~((n)-1))) |
#define mkop(op,ty) (specific((op) + ttob(ty))) |
|
#define extend(x,ty) ((x)&(1<<(8*(ty)->size-1)) ? (x)|((~0UL)<<(8*(ty)->size-1)) : (x)&ones(8*(ty)->size)) |
#define ones(n) ((n)>=8*sizeof (unsigned long) ? ~0UL : ~((~0UL)<<(n))) |
|
#define isqual(t) ((t)->op >= CONST) |
#define unqual(t) (isqual(t) ? (t)->type : (t)) |
|
#define isvolatile(t) ((t)->op == VOLATILE \ |
|| (t)->op == CONST+VOLATILE) |
#define isconst(t) ((t)->op == CONST \ |
|| (t)->op == CONST+VOLATILE) |
#define isarray(t) (unqual(t)->op == ARRAY) |
#define isstruct(t) (unqual(t)->op == STRUCT \ |
|| unqual(t)->op == UNION) |
#define isunion(t) (unqual(t)->op == UNION) |
#define isfunc(t) (unqual(t)->op == FUNCTION) |
#define isptr(t) (unqual(t)->op == POINTER) |
#define ischar(t) ((t)->size == 1 && isint(t)) |
#define isint(t) (unqual(t)->op == INT \ |
|| unqual(t)->op == UNSIGNED) |
#define isfloat(t) (unqual(t)->op == FLOAT) |
#define isarith(t) (unqual(t)->op <= UNSIGNED) |
#define isunsigned(t) (unqual(t)->op == UNSIGNED) |
#define isscalar(t) (unqual(t)->op <= POINTER \ |
|| unqual(t)->op == ENUM) |
#define isenum(t) (unqual(t)->op == ENUM) |
#define fieldsize(p) (p)->bitsize |
#define fieldright(p) ((p)->lsb - 1) |
#define fieldleft(p) (8*(p)->type->size - \ |
fieldsize(p) - fieldright(p)) |
#define fieldmask(p) (~(fieldsize(p) < 8*unsignedtype->size ? ~0u<<fieldsize(p) : 0u)) |
typedef struct node *Node; |
|
typedef struct list *List; |
|
typedef struct code *Code; |
|
typedef struct swtch *Swtch; |
|
typedef struct symbol *Symbol; |
|
typedef struct coord { |
char *file; |
unsigned x, y; |
} Coordinate; |
typedef struct table *Table; |
|
typedef union value { |
long i; |
unsigned long u; |
long double d; |
void *p; |
void (*g)(void); |
} Value; |
typedef struct tree *Tree; |
|
typedef struct type *Type; |
|
typedef struct field *Field; |
|
typedef struct { |
unsigned printed:1; |
unsigned marked; |
unsigned short typeno; |
void *xt; |
} Xtype; |
|
#include "config.h" |
typedef struct metrics { |
unsigned char size, align, outofline; |
} Metrics; |
typedef struct interface { |
Metrics charmetric; |
Metrics shortmetric; |
Metrics intmetric; |
Metrics longmetric; |
Metrics longlongmetric; |
Metrics floatmetric; |
Metrics doublemetric; |
Metrics longdoublemetric; |
Metrics ptrmetric; |
Metrics structmetric; |
unsigned little_endian:1; |
unsigned mulops_calls:1; |
unsigned wants_callb:1; |
unsigned wants_argb:1; |
unsigned left_to_right:1; |
unsigned wants_dag:1; |
unsigned unsigned_char:1; |
void (*address)(Symbol p, Symbol q, long n); |
void (*blockbeg)(Env *); |
void (*blockend)(Env *); |
void (*defaddress)(Symbol); |
void (*defconst) (int suffix, int size, Value v); |
void (*defstring)(int n, char *s); |
void (*defsymbol)(Symbol); |
void (*emit) (Node); |
void (*export)(Symbol); |
void (*function)(Symbol, Symbol[], Symbol[], int); |
Node (*gen) (Node); |
void (*global)(Symbol); |
void (*import)(Symbol); |
void (*local)(Symbol); |
void (*progbeg)(int argc, char *argv[]); |
void (*progend)(void); |
void (*segment)(int); |
void (*space)(int); |
void (*stabblock)(int, int, Symbol*); |
void (*stabend) (Coordinate *, Symbol, Coordinate **, Symbol *, Symbol *); |
void (*stabfend) (Symbol, int); |
void (*stabinit) (char *, int, char *[]); |
void (*stabline) (Coordinate *); |
void (*stabsym) (Symbol); |
void (*stabtype) (Symbol); |
Xinterface x; |
} Interface; |
typedef struct binding { |
char *name; |
Interface *ir; |
} Binding; |
|
extern Binding bindings[]; |
extern Interface *IR; |
typedef struct { |
List blockentry; |
List blockexit; |
List entry; |
List exit; |
List returns; |
List points; |
List calls; |
List end; |
} Events; |
|
enum { |
#define xx(a,b,c,d,e,f,g) a=b, |
#define yy(a,b,c,d,e,f,g) |
#include "token.h" |
LAST |
}; |
struct node { |
short op; |
short count; |
Symbol syms[3]; |
Node kids[2]; |
Node link; |
Xnode x; |
}; |
enum { |
F=FLOAT, |
I=INT, |
U=UNSIGNED, |
P=POINTER, |
V=VOID, |
B=STRUCT |
}; |
#define gop(name,value) name=value<<4, |
#define op(name,type,sizes) |
|
enum { |
#include "ops.h" |
LASTOP |
}; |
|
#undef gop |
#undef op |
enum { CODE=1, BSS, DATA, LIT }; |
enum { PERM=0, FUNC, STMT }; |
struct list { |
void *x; |
List link; |
}; |
|
struct code { |
enum { Blockbeg, Blockend, Local, Address, Defpoint, |
Label, Start, Gen, Jump, Switch |
} kind; |
Code prev, next; |
union { |
struct { |
int level; |
Symbol *locals; |
Table identifiers, types; |
Env x; |
} block; |
Code begin; |
Symbol var; |
|
struct { |
Symbol sym; |
Symbol base; |
long offset; |
} addr; |
struct { |
Coordinate src; |
int point; |
} point; |
Node forest; |
struct { |
Symbol sym; |
Symbol table; |
Symbol deflab; |
int size; |
long *values; |
Symbol *labels; |
} swtch; |
|
} u; |
}; |
struct swtch { |
Symbol sym; |
int lab; |
Symbol deflab; |
int ncases; |
int size; |
long *values; |
Symbol *labels; |
}; |
struct symbol { |
char *name; |
int scope; |
Coordinate src; |
Symbol up; |
List uses; |
int sclass; |
unsigned structarg:1; |
|
unsigned addressed:1; |
unsigned computed:1; |
unsigned temporary:1; |
unsigned generated:1; |
unsigned defined:1; |
Type type; |
float ref; |
union { |
struct { |
int label; |
Symbol equatedto; |
} l; |
struct { |
unsigned cfields:1; |
unsigned vfields:1; |
Table ftab; /* omit */ |
Field flist; |
} s; |
int value; |
Symbol *idlist; |
struct { |
Value min, max; |
} limits; |
struct { |
Value v; |
Symbol loc; |
} c; |
struct { |
Coordinate pt; |
int label; |
int ncalls; |
Symbol *callee; |
} f; |
int seg; |
Symbol alias; |
struct { |
Node cse; |
int replace; |
Symbol next; |
} t; |
} u; |
Xsymbol x; |
}; |
enum { CONSTANTS=1, LABELS, GLOBAL, PARAM, LOCAL }; |
struct tree { |
int op; |
Type type; |
Tree kids[2]; |
Node node; |
union { |
Value v; |
Symbol sym; |
|
Field field; |
} u; |
}; |
enum { |
AND=38<<4, |
NOT=39<<4, |
OR=40<<4, |
COND=41<<4, |
RIGHT=42<<4, |
FIELD=43<<4 |
}; |
struct type { |
int op; |
Type type; |
int align; |
int size; |
union { |
Symbol sym; |
struct { |
unsigned oldstyle:1; |
Type *proto; |
} f; |
} u; |
Xtype x; |
}; |
struct field { |
char *name; |
Type type; |
int offset; |
short bitsize; |
short lsb; |
Field link; |
}; |
extern int assignargs; |
extern int prunetemps; |
extern int nodecount; |
extern Symbol cfunc; |
extern Symbol retv; |
extern Tree (*optree[])(int, Tree, Tree); |
|
extern char kind[]; |
extern int errcnt; |
extern int errlimit; |
extern int wflag; |
extern Events events; |
extern float refinc; |
|
extern unsigned char *cp; |
extern unsigned char *limit; |
extern char *firstfile; |
extern char *file; |
extern char *line; |
extern int lineno; |
extern int t; |
extern char *token; |
extern Symbol tsym; |
extern Coordinate src; |
extern int Aflag; |
extern int Pflag; |
extern Symbol YYnull; |
extern Symbol YYcheck; |
extern int glevel; |
extern int xref; |
|
extern int ncalled; |
extern int npoints; |
|
extern int needconst; |
extern int explicitCast; |
extern struct code codehead; |
extern Code codelist; |
extern Table stmtlabs; |
extern float density; |
extern Table constants; |
extern Table externals; |
extern Table globals; |
extern Table identifiers; |
extern Table labels; |
extern Table types; |
extern int level; |
|
extern List loci, symbols; |
|
extern List symbols; |
|
extern int where; |
extern Type chartype; |
extern Type doubletype; |
extern Type floattype; |
extern Type inttype; |
extern Type longdouble; |
extern Type longtype; |
extern Type longlong; |
extern Type shorttype; |
extern Type signedchar; |
extern Type unsignedchar; |
extern Type unsignedlonglong; |
extern Type unsignedlong; |
extern Type unsignedshort; |
extern Type unsignedtype; |
extern Type charptype; |
extern Type funcptype; |
extern Type voidptype; |
extern Type voidtype; |
extern Type unsignedptr; |
extern Type signedptr; |
extern Type widechar; |
extern void *allocate(unsigned long n, unsigned a); |
extern void deallocate(unsigned a); |
extern void *newarray(unsigned long m, unsigned long n, unsigned a); |
extern void walk(Tree e, int tlab, int flab); |
extern Node listnodes(Tree e, int tlab, int flab); |
extern Node newnode(int op, Node left, Node right, Symbol p); |
extern Tree cvtconst(Tree); |
extern void printdag(Node, int); |
extern void compound(int, Swtch, int); |
extern void defglobal(Symbol, int); |
extern void finalize(void); |
extern void program(void); |
|
extern Tree vcall(Symbol func, Type ty, ...); |
extern Tree addrof(Tree); |
extern Tree asgn(Symbol, Tree); |
extern Tree asgntree(int, Tree, Tree); |
extern Type assign(Type, Tree); |
extern Tree bittree(int, Tree, Tree); |
extern Tree call(Tree, Type, Coordinate); |
extern Tree calltree(Tree, Type, Tree, Symbol); |
extern Tree condtree(Tree, Tree, Tree); |
extern Tree cnsttree(Type, ...); |
extern Tree consttree(unsigned int, Type); |
extern Tree eqtree(int, Tree, Tree); |
extern int iscallb(Tree); |
extern Tree shtree(int, Tree, Tree); |
extern void typeerror(int, Tree, Tree); |
|
extern void test(int tok, char set[]); |
extern void expect(int tok); |
extern void skipto(int tok, char set[]); |
extern void error(const char *, ...); |
extern int fatal(const char *, const char *, int); |
extern void warning(const char *, ...); |
|
typedef void (*Apply)(void *, void *, void *); |
extern void attach(Apply, void *, List *); |
extern void apply(List event, void *arg1, void *arg2); |
extern Tree retype(Tree p, Type ty); |
extern Tree rightkid(Tree p); |
extern int hascall(Tree p); |
extern Type binary(Type, Type); |
extern Tree cast(Tree, Type); |
extern Tree cond(Tree); |
extern Tree expr0(int); |
extern Tree expr(int); |
extern Tree expr1(int); |
extern Tree field(Tree, const char *); |
extern char *funcname(Tree); |
extern Tree idtree(Symbol); |
extern Tree incr(int, Tree, Tree); |
extern Tree lvalue(Tree); |
extern Tree nullcall(Type, Symbol, Tree, Tree); |
extern Tree pointer(Tree); |
extern Tree rvalue(Tree); |
extern Tree value(Tree); |
|
extern void defpointer(Symbol); |
extern Type initializer(Type, int); |
extern void swtoseg(int); |
|
extern void input_init(int, char *[]); |
extern void fillbuf(void); |
extern void nextline(void); |
|
extern int getchr(void); |
extern int gettok(void); |
|
extern void emitcode(void); |
extern void gencode (Symbol[], Symbol[]); |
extern void fprint(FILE *f, const char *fmt, ...); |
extern char *stringf(const char *, ...); |
extern void check(Node); |
extern void print(const char *, ...); |
|
extern List append(void *x, List list); |
extern int length(List list); |
extern void *ltov (List *list, unsigned a); |
extern void init(int, char *[]); |
|
extern Type typename(void); |
extern void checklab(Symbol p, void *cl); |
extern Type enumdcl(void); |
extern void main_init(int, char *[]); |
extern int main(int, char *[]); |
|
extern void vfprint(FILE *, char *, const char *, va_list); |
|
void profInit(char *); |
extern int process(char *); |
extern int findfunc(char *, char *); |
extern int findcount(char *, int, int); |
|
extern Tree constexpr(int); |
extern int intexpr(int, int); |
extern Tree simplify(int, Type, Tree, Tree); |
extern int ispow2(unsigned long u); |
|
extern int reachable(int); |
|
extern void addlocal(Symbol); |
extern void branch(int); |
extern Code code(int); |
extern void definelab(int); |
extern void definept(Coordinate *); |
extern void equatelab(Symbol, Symbol); |
extern Node jump(int); |
extern void retcode(Tree); |
extern void statement(int, Swtch, int); |
extern void swcode(Swtch, int *, int, int); |
extern void swgen(Swtch); |
|
extern char * string(const char *str); |
extern char *stringn(const char *str, int len); |
extern char *stringd(long n); |
extern Symbol relocate(const char *name, Table src, Table dst); |
extern void use(Symbol p, Coordinate src); |
extern void locus(Table tp, Coordinate *cp); |
extern Symbol allsymbols(Table); |
|
extern Symbol constant(Type, Value); |
extern void enterscope(void); |
extern void exitscope(void); |
extern Symbol findlabel(int); |
extern Symbol findtype(Type); |
extern void foreach(Table, int, void (*)(Symbol, void *), void *); |
extern Symbol genident(int, Type, int); |
extern int genlabel(int); |
extern Symbol install(const char *, Table *, int, int); |
extern Symbol intconst(int); |
extern Symbol lookup(const char *, Table); |
extern Symbol mkstr(char *); |
extern Symbol mksymbol(int, const char *, Type); |
extern Symbol newtemp(int, int, int); |
extern Table newtable(int); |
extern Table table(Table, int); |
extern Symbol temporary(int, Type); |
extern char *vtoa(Type, Value); |
|
extern void traceInit(char *); |
extern int nodeid(Tree); |
extern char *opname(int); |
extern int *printed(int); |
extern void printtree(Tree, int); |
extern Tree root(Tree); |
extern Tree texpr(Tree (*)(int), int, int); |
extern Tree tree(int, Type, Tree, Tree); |
|
extern void type_init(int, char *[]); |
|
extern Type signedint(Type); |
|
extern int hasproto(Type); |
extern void outtype(Type, FILE *); |
extern void printdecl (Symbol p, Type ty); |
extern void printproto(Symbol p, Symbol args[]); |
extern char *typestring(Type ty, char *id); |
extern Field fieldref(const char *name, Type ty); |
extern Type array(Type, int, int); |
extern Type atop(Type); |
extern Type btot(int, int); |
extern Type compose(Type, Type); |
extern Type deref(Type); |
extern int eqtype(Type, Type, int); |
extern Field fieldlist(Type); |
extern Type freturn(Type); |
extern Type ftype(Type, ...); |
extern Type func(Type, Type *, int); |
extern Field newfield(char *, Type, Type); |
extern Type newstruct(int, char *); |
extern void printtype(Type, int); |
extern Type promote(Type); |
extern Type ptr(Type); |
extern Type qual(int, Type); |
extern void rmtypes(int); |
extern int ttob(Type); |
extern int variadic(Type); |
|
/stab.c.ORIG
0,0 → 1,331
#include <string.h> |
#include <stdlib.h> |
#include "c.h" |
#include "stab.h" |
|
static char rcsid[] = "$Id: stab.c,v 1.1 2002/08/28 23:12:46 drh Exp $"; |
|
static char *currentfile; /* current file name */ |
static int ntypes; |
|
extern Interface sparcIR; |
|
char *stabprefix = "L"; |
|
extern char *stabprefix; |
extern void stabblock(int, int, Symbol*); |
extern void stabend(Coordinate *, Symbol, Coordinate **, Symbol *, Symbol *); |
extern void stabfend(Symbol, int); |
extern void stabinit(char *, int, char *[]); |
extern void stabline(Coordinate *); |
extern void stabsym(Symbol); |
extern void stabtype(Symbol); |
|
static void asgncode(Type, int); |
static void dbxout(Type); |
static int dbxtype(Type); |
static int emittype(Type, int, int); |
|
/* asgncode - assign type code to ty */ |
static void asgncode(Type ty, int lev) { |
if (ty->x.marked || ty->x.typeno) |
return; |
ty->x.marked = 1; |
switch (ty->op) { |
case VOLATILE: case CONST: case VOLATILE+CONST: |
asgncode(ty->type, lev); |
ty->x.typeno = ty->type->x.typeno; |
break; |
case POINTER: case FUNCTION: case ARRAY: |
asgncode(ty->type, lev + 1); |
/* fall thru */ |
case VOID: case INT: case UNSIGNED: case FLOAT: |
break; |
case STRUCT: case UNION: { |
Field p; |
for (p = fieldlist(ty); p; p = p->link) |
asgncode(p->type, lev + 1); |
/* fall thru */ |
case ENUM: |
if (ty->x.typeno == 0) |
ty->x.typeno = ++ntypes; |
if (lev > 0 && (*ty->u.sym->name < '0' || *ty->u.sym->name > '9')) |
dbxout(ty); |
break; |
} |
default: |
assert(0); |
} |
} |
|
/* dbxout - output .stabs entry for type ty */ |
static void dbxout(Type ty) { |
ty = unqual(ty); |
if (!ty->x.printed) { |
int col = 0; |
print(".stabs \""), col += 8; |
if (ty->u.sym && !(isfunc(ty) || isarray(ty) || isptr(ty))) |
print("%s", ty->u.sym->name), col += strlen(ty->u.sym->name); |
print(":%c", isstruct(ty) || isenum(ty) ? 'T' : 't'), col += 2; |
emittype(ty, 0, col); |
print("\",%d,0,0,0\n", N_LSYM); |
} |
} |
|
/* dbxtype - emit a stabs entry for type ty, return type code */ |
static int dbxtype(Type ty) { |
asgncode(ty, 0); |
dbxout(ty); |
return ty->x.typeno; |
} |
|
/* |
* emittype - emit ty's type number, emitting its definition if necessary. |
* Returns the output column number after emission; col is the approximate |
* output column before emission and is used to emit continuation lines for long |
* struct, union, and enum types. Continuations are not emitted for other types, |
* even if the definition is long. lev is the depth of calls to emittype. |
*/ |
static int emittype(Type ty, int lev, int col) { |
int tc = ty->x.typeno; |
|
if (isconst(ty) || isvolatile(ty)) { |
col = emittype(ty->type, lev, col); |
ty->x.typeno = ty->type->x.typeno; |
ty->x.printed = 1; |
return col; |
} |
if (tc == 0) { |
ty->x.typeno = tc = ++ntypes; |
/* fprint(2,"`%t'=%d\n", ty, tc); */ |
} |
print("%d", tc), col += 3; |
if (ty->x.printed) |
return col; |
ty->x.printed = 1; |
switch (ty->op) { |
case VOID: /* void is defined as itself */ |
print("=%d", tc), col += 1+3; |
break; |
case INT: |
if (ty == chartype) /* plain char is a subrange of itself */ |
print("=r%d;%d;%d;", tc, ty->u.sym->u.limits.min.i, ty->u.sym->u.limits.max.i), |
col += 2+3+2*2.408*ty->size+2; |
else /* other signed ints are subranges of int */ |
print("=r1;%D;%D;", ty->u.sym->u.limits.min.i, ty->u.sym->u.limits.max.i), |
col += 4+2*2.408*ty->size+2; |
break; |
case UNSIGNED: |
if (ty == chartype) /* plain char is a subrange of itself */ |
print("=r%d;0;%u;", tc, ty->u.sym->u.limits.max.i), |
col += 2+3+2+2.408*ty->size+1; |
else /* other signed ints are subranges of int */ |
print("=r1;0;%U;", ty->u.sym->u.limits.max.i), |
col += 4+2.408*ty->size+1; |
break; |
case FLOAT: /* float, double, long double get sizes, not ranges */ |
print("=r1;%d;0;", ty->size), col += 4+1+3; |
break; |
case POINTER: |
print("=*"), col += 2; |
col = emittype(ty->type, lev + 1, col); |
break; |
case FUNCTION: |
print("=f"), col += 2; |
col = emittype(ty->type, lev + 1, col); |
break; |
case ARRAY: /* array includes subscript as an int range */ |
if (ty->size && ty->type->size) |
print("=ar1;0;%d;", ty->size/ty->type->size - 1), col += 7+3+1; |
else |
print("=ar1;0;-1;"), col += 10; |
col = emittype(ty->type, lev + 1, col); |
break; |
case STRUCT: case UNION: { |
Field p; |
if (!ty->u.sym->defined) { |
print("=x%c%s:", ty->op == STRUCT ? 's' : 'u', ty->u.sym->name); |
col += 2+1+strlen(ty->u.sym->name)+1; |
break; |
} |
if (lev > 0 && (*ty->u.sym->name < '0' || *ty->u.sym->name > '9')) { |
ty->x.printed = 0; |
break; |
} |
print("=%c%d", ty->op == STRUCT ? 's' : 'u', ty->size), col += 1+1+3; |
for (p = fieldlist(ty); p; p = p->link) { |
if (p->name) |
print("%s:", p->name), col += strlen(p->name)+1; |
else |
print(":"), col += 1; |
col = emittype(p->type, lev + 1, col); |
if (p->lsb) |
print(",%d,%d;", 8*p->offset + |
(IR->little_endian ? fieldright(p) : fieldleft(p)), |
fieldsize(p)); |
else |
print(",%d,%d;", 8*p->offset, 8*p->type->size); |
col += 1+3+1+3+1; /* accounts for ,%d,%d; */ |
if (col >= 80 && p->link) { |
print("\\\\\",%d,0,0,0\n.stabs \"", N_LSYM); |
col = 8; |
} |
} |
print(";"), col += 1; |
break; |
} |
case ENUM: { |
Symbol *p; |
if (lev > 0 && (*ty->u.sym->name < '0' || *ty->u.sym->name > '9')) { |
ty->x.printed = 0; |
break; |
} |
print("=e"), col += 2; |
for (p = ty->u.sym->u.idlist; *p; p++) { |
print("%s:%d,", (*p)->name, (*p)->u.value), col += strlen((*p)->name)+3; |
if (col >= 80 && p[1]) { |
print("\\\\\",%d,0,0,0\n.stabs \"", N_LSYM); |
col = 8; |
} |
} |
print(";"), col += 1; |
break; |
} |
default: |
assert(0); |
} |
return col; |
} |
|
/* stabblock - output a stab entry for '{' or '}' at level lev */ |
void stabblock(int brace, int lev, Symbol *p) { |
if (brace == '{') |
while (*p) |
stabsym(*p++); |
if (IR == &sparcIR) |
print(".stabd 0x%x,0,%d\n", brace == '{' ? N_LBRAC : N_RBRAC, lev); |
else { |
int lab = genlabel(1); |
print(".stabn 0x%x,0,%d,%s%d-%s\n", brace == '{' ? N_LBRAC : N_RBRAC, lev, |
stabprefix, lab, cfunc->x.name); |
print("%s%d:\n", stabprefix, lab); |
} |
} |
|
/* stabinit - initialize stab output */ |
void stabinit(char *file, int argc, char *argv[]) { |
typedef void (*Closure)(Symbol, void *); |
extern char *getcwd(char *, size_t); |
|
print(".stabs \"lcc4_compiled.\",0x%x,0,0,0\n", N_OPT); |
if (file && *file) { |
char buf[1024], *cwd = getcwd(buf, sizeof buf); |
if (cwd) |
print(".stabs \"%s/\",0x%x,0,3,%stext0\n", cwd, N_SO, stabprefix); |
print(".stabs \"%s\",0x%x,0,3,%stext0\n", file, N_SO, stabprefix); |
(*IR->segment)(CODE); |
print("%stext0:\n", stabprefix, N_SO); |
currentfile = file; |
} |
dbxtype(inttype); |
dbxtype(chartype); |
dbxtype(doubletype); |
dbxtype(floattype); |
dbxtype(longdouble); |
dbxtype(longtype); |
dbxtype(longlong); |
dbxtype(shorttype); |
dbxtype(signedchar); |
dbxtype(unsignedchar); |
dbxtype(unsignedlong); |
dbxtype(unsignedlonglong); |
dbxtype(unsignedshort); |
dbxtype(unsignedtype); |
dbxtype(voidtype); |
foreach(types, GLOBAL, (Closure)stabtype, NULL); |
} |
|
/* stabline - emit stab entry for source coordinate *cp */ |
void stabline(Coordinate *cp) { |
if (cp->file && cp->file != currentfile) { |
int lab = genlabel(1); |
print(".stabs \"%s\",0x%x,0,0,%s%d\n", cp->file, N_SOL, stabprefix, lab); |
print("%s%d:\n", stabprefix, lab); |
currentfile = cp->file; |
} |
if (IR == &sparcIR) |
print(".stabd 0x%x,0,%d\n", N_SLINE, cp->y); |
else { |
int lab = genlabel(1); |
print(".stabn 0x%x,0,%d,%s%d-%s\n", N_SLINE, cp->y, |
stabprefix, lab, cfunc->x.name); |
print("%s%d:\n", stabprefix, lab); |
} |
} |
|
/* stabsym - output a stab entry for symbol p */ |
void stabsym(Symbol p) { |
int code, tc, sz = p->type->size; |
|
if (p->generated || p->computed) |
return; |
if (isfunc(p->type)) { |
print(".stabs \"%s:%c%d\",%d,0,0,%s\n", p->name, |
p->sclass == STATIC ? 'f' : 'F', dbxtype(freturn(p->type)), |
N_FUN, p->x.name); |
return; |
} |
if (!IR->wants_argb && p->scope == PARAM && p->structarg) { |
assert(isptr(p->type) && isstruct(p->type->type)); |
tc = dbxtype(p->type->type); |
sz = p->type->type->size; |
} else |
tc = dbxtype(p->type); |
if (p->sclass == AUTO && p->scope == GLOBAL || p->sclass == EXTERN) { |
print(".stabs \"%s:G", p->name); |
code = N_GSYM; |
} else if (p->sclass == STATIC) { |
print(".stabs \"%s:%c%d\",%d,0,0,%s\n", p->name, p->scope == GLOBAL ? 'S' : 'V', |
tc, p->u.seg == BSS ? N_LCSYM : N_STSYM, p->x.name); |
return; |
} else if (p->sclass == REGISTER) { |
if (p->x.regnode) { |
int r = p->x.regnode->number; |
if (p->x.regnode->set == FREG) |
r += 32; /* floating point */ |
print(".stabs \"%s:%c%d\",%d,0,", p->name, |
p->scope == PARAM ? 'P' : 'r', tc, N_RSYM); |
print("%d,%d\n", sz, r); |
} |
return; |
} else if (p->scope == PARAM) { |
print(".stabs \"%s:p", p->name); |
code = N_PSYM; |
} else if (p->scope >= LOCAL) { |
print(".stabs \"%s:", p->name); |
code = N_LSYM; |
} else |
assert(0); |
print("%d\",%d,0,0,%s\n", tc, code, |
p->scope >= PARAM && p->sclass != EXTERN ? p->x.name : "0"); |
} |
|
/* stabtype - output a stab entry for type *p */ |
void stabtype(Symbol p) { |
if (p->type) { |
if (p->sclass == 0) |
dbxtype(p->type); |
else if (p->sclass == TYPEDEF) |
print(".stabs \"%s:t%d\",%d,0,0,0\n", p->name, dbxtype(p->type), N_LSYM); |
} |
} |
|
/* stabend - finalize a function */ |
void stabfend(Symbol p, int lineno) {} |
|
/* stabend - finalize stab output */ |
void stabend(Coordinate *cp, Symbol p, Coordinate **cpp, Symbol *sp, Symbol *stab) { |
(*IR->segment)(CODE); |
print(".stabs \"\", %d, 0, 0,%setext\n", N_SO, stabprefix); |
print("%setext:\n", stabprefix); |
} |
/lex.c
0,0 → 1,930
#include "c.h" |
#include <float.h> |
#include <errno.h> |
|
static char rcsid[] = "$Id: lex.c,v 1.1 2002/08/28 23:12:44 drh Exp $"; |
|
#define MAXTOKEN 32 |
|
enum { BLANK=01, NEWLINE=02, LETTER=04, |
DIGIT=010, HEX=020, OTHER=040 }; |
|
static unsigned char map[256] = { /* 000 nul */ 0, |
/* 001 soh */ 0, |
/* 002 stx */ 0, |
/* 003 etx */ 0, |
/* 004 eot */ 0, |
/* 005 enq */ 0, |
/* 006 ack */ 0, |
/* 007 bel */ 0, |
/* 010 bs */ 0, |
/* 011 ht */ BLANK, |
/* 012 nl */ NEWLINE, |
/* 013 vt */ BLANK, |
/* 014 ff */ BLANK, |
/* 015 cr */ 0, |
/* 016 so */ 0, |
/* 017 si */ 0, |
/* 020 dle */ 0, |
/* 021 dc1 */ 0, |
/* 022 dc2 */ 0, |
/* 023 dc3 */ 0, |
/* 024 dc4 */ 0, |
/* 025 nak */ 0, |
/* 026 syn */ 0, |
/* 027 etb */ 0, |
/* 030 can */ 0, |
/* 031 em */ 0, |
/* 032 sub */ 0, |
/* 033 esc */ 0, |
/* 034 fs */ 0, |
/* 035 gs */ 0, |
/* 036 rs */ 0, |
/* 037 us */ 0, |
/* 040 sp */ BLANK, |
/* 041 ! */ OTHER, |
/* 042 " */ OTHER, |
/* 043 # */ OTHER, |
/* 044 $ */ 0, |
/* 045 % */ OTHER, |
/* 046 & */ OTHER, |
/* 047 ' */ OTHER, |
/* 050 ( */ OTHER, |
/* 051 ) */ OTHER, |
/* 052 * */ OTHER, |
/* 053 + */ OTHER, |
/* 054 , */ OTHER, |
/* 055 - */ OTHER, |
/* 056 . */ OTHER, |
/* 057 / */ OTHER, |
/* 060 0 */ DIGIT, |
/* 061 1 */ DIGIT, |
/* 062 2 */ DIGIT, |
/* 063 3 */ DIGIT, |
/* 064 4 */ DIGIT, |
/* 065 5 */ DIGIT, |
/* 066 6 */ DIGIT, |
/* 067 7 */ DIGIT, |
/* 070 8 */ DIGIT, |
/* 071 9 */ DIGIT, |
/* 072 : */ OTHER, |
/* 073 ; */ OTHER, |
/* 074 < */ OTHER, |
/* 075 = */ OTHER, |
/* 076 > */ OTHER, |
/* 077 ? */ OTHER, |
/* 100 @ */ 0, |
/* 101 A */ LETTER|HEX, |
/* 102 B */ LETTER|HEX, |
/* 103 C */ LETTER|HEX, |
/* 104 D */ LETTER|HEX, |
/* 105 E */ LETTER|HEX, |
/* 106 F */ LETTER|HEX, |
/* 107 G */ LETTER, |
/* 110 H */ LETTER, |
/* 111 I */ LETTER, |
/* 112 J */ LETTER, |
/* 113 K */ LETTER, |
/* 114 L */ LETTER, |
/* 115 M */ LETTER, |
/* 116 N */ LETTER, |
/* 117 O */ LETTER, |
/* 120 P */ LETTER, |
/* 121 Q */ LETTER, |
/* 122 R */ LETTER, |
/* 123 S */ LETTER, |
/* 124 T */ LETTER, |
/* 125 U */ LETTER, |
/* 126 V */ LETTER, |
/* 127 W */ LETTER, |
/* 130 X */ LETTER, |
/* 131 Y */ LETTER, |
/* 132 Z */ LETTER, |
/* 133 [ */ OTHER, |
/* 134 \ */ OTHER, |
/* 135 ] */ OTHER, |
/* 136 ^ */ OTHER, |
/* 137 _ */ LETTER, |
/* 140 ` */ 0, |
/* 141 a */ LETTER|HEX, |
/* 142 b */ LETTER|HEX, |
/* 143 c */ LETTER|HEX, |
/* 144 d */ LETTER|HEX, |
/* 145 e */ LETTER|HEX, |
/* 146 f */ LETTER|HEX, |
/* 147 g */ LETTER, |
/* 150 h */ LETTER, |
/* 151 i */ LETTER, |
/* 152 j */ LETTER, |
/* 153 k */ LETTER, |
/* 154 l */ LETTER, |
/* 155 m */ LETTER, |
/* 156 n */ LETTER, |
/* 157 o */ LETTER, |
/* 160 p */ LETTER, |
/* 161 q */ LETTER, |
/* 162 r */ LETTER, |
/* 163 s */ LETTER, |
/* 164 t */ LETTER, |
/* 165 u */ LETTER, |
/* 166 v */ LETTER, |
/* 167 w */ LETTER, |
/* 170 x */ LETTER, |
/* 171 y */ LETTER, |
/* 172 z */ LETTER, |
/* 173 { */ OTHER, |
/* 174 | */ OTHER, |
/* 175 } */ OTHER, |
/* 176 ~ */ OTHER, }; |
static struct symbol tval; |
static char cbuf[BUFSIZE+1]; |
static unsigned int wcbuf[BUFSIZE+1]; |
|
Coordinate src; /* current source coordinate */ |
int t; |
char *token; /* current token */ |
Symbol tsym; /* symbol table entry for current token */ |
|
static void *cput(int c, void *cl); |
static void *wcput(int c, void *cl); |
static void *scon(int q, void *put(int c, void *cl), void *cl); |
static int backslash(int q); |
static Symbol fcon(void); |
static Symbol icon(unsigned long, int, int); |
static void ppnumber(char *); |
|
int gettok(void) { |
for (;;) { |
register unsigned char *rcp = cp; |
while (map[*rcp]&BLANK) |
rcp++; |
if (limit - rcp < MAXTOKEN) { |
cp = rcp; |
fillbuf(); |
rcp = cp; |
} |
src.file = file; |
src.x = (char *)rcp - line; |
src.y = lineno; |
cp = rcp + 1; |
switch (*rcp++) { |
case '/': if (*rcp == '*') { |
int c = 0; |
for (rcp++; *rcp != '/' || c != '*'; ) |
if (map[*rcp]&NEWLINE) { |
if (rcp < limit) |
c = *rcp; |
cp = rcp + 1; |
nextline(); |
rcp = cp; |
if (rcp == limit) |
break; |
} else |
c = *rcp++; |
if (rcp < limit) |
rcp++; |
else |
error("unclosed comment\n"); |
cp = rcp; |
continue; |
} |
return '/'; |
case '<': |
if (*rcp == '=') return cp++, LEQ; |
if (*rcp == '<') return cp++, LSHIFT; |
return '<'; |
case '>': |
if (*rcp == '=') return cp++, GEQ; |
if (*rcp == '>') return cp++, RSHIFT; |
return '>'; |
case '-': |
if (*rcp == '>') return cp++, DEREF; |
if (*rcp == '-') return cp++, DECR; |
return '-'; |
case '=': return *rcp == '=' ? cp++, EQL : '='; |
case '!': return *rcp == '=' ? cp++, NEQ : '!'; |
case '|': return *rcp == '|' ? cp++, OROR : '|'; |
case '&': return *rcp == '&' ? cp++, ANDAND : '&'; |
case '+': return *rcp == '+' ? cp++, INCR : '+'; |
case ';': case ',': case ':': |
case '*': case '~': case '%': case '^': case '?': |
case '[': case ']': case '{': case '}': case '(': case ')': |
return rcp[-1]; |
case '\n': case '\v': case '\r': case '\f': |
nextline(); |
if (cp == limit) { |
tsym = NULL; |
return EOI; |
} |
continue; |
|
case 'i': |
if (rcp[0] == 'f' |
&& !(map[rcp[1]]&(DIGIT|LETTER))) { |
cp = rcp + 1; |
return IF; |
} |
if (rcp[0] == 'n' |
&& rcp[1] == 't' |
&& !(map[rcp[2]]&(DIGIT|LETTER))) { |
cp = rcp + 2; |
tsym = inttype->u.sym; |
return INT; |
} |
goto id; |
case 'h': case 'j': case 'k': case 'm': case 'n': case 'o': |
case 'p': case 'q': case 'x': case 'y': case 'z': |
case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': |
case 'G': case 'H': case 'I': case 'J': case 'K': |
case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': |
case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': |
case 'Y': case 'Z': |
id: |
if (limit - rcp < MAXLINE) { |
cp = rcp - 1; |
fillbuf(); |
rcp = ++cp; |
} |
assert(cp == rcp); |
token = (char *)rcp - 1; |
while (map[*rcp]&(DIGIT|LETTER)) |
rcp++; |
token = stringn(token, (char *)rcp - token); |
tsym = lookup(token, identifiers); |
cp = rcp; |
return ID; |
case '0': case '1': case '2': case '3': case '4': |
case '5': case '6': case '7': case '8': case '9': { |
unsigned long n = 0; |
if (limit - rcp < MAXLINE) { |
cp = rcp - 1; |
fillbuf(); |
rcp = ++cp; |
} |
assert(cp == rcp); |
token = (char *)rcp - 1; |
if (*token == '0' && (*rcp == 'x' || *rcp == 'X')) { |
int d, overflow = 0; |
while (*++rcp) { |
if (map[*rcp]&DIGIT) |
d = *rcp - '0'; |
else if (*rcp >= 'a' && *rcp <= 'f') |
d = *rcp - 'a' + 10; |
else if (*rcp >= 'A' && *rcp <= 'F') |
d = *rcp - 'A' + 10; |
else |
break; |
if (n&~(~0UL >> 4)) |
overflow = 1; |
else |
n = (n<<4) + d; |
} |
if ((char *)rcp - token <= 2) |
error("invalid hexadecimal constant `%S'\n", token, (char *)rcp-token); |
cp = rcp; |
tsym = icon(n, overflow, 16); |
} else if (*token == '0') { |
int err = 0, overflow = 0; |
for ( ; map[*rcp]&DIGIT; rcp++) { |
if (*rcp == '8' || *rcp == '9') |
err = 1; |
if (n&~(~0UL >> 3)) |
overflow = 1; |
else |
n = (n<<3) + (*rcp - '0'); |
} |
if (*rcp == '.' || *rcp == 'e' || *rcp == 'E') { |
cp = rcp; |
tsym = fcon(); |
return FCON; |
} |
cp = rcp; |
tsym = icon(n, overflow, 8); |
if (err) |
error("invalid octal constant `%S'\n", token, (char*)cp-token); |
} else { |
int overflow = 0; |
for (n = *token - '0'; map[*rcp]&DIGIT; ) { |
int d = *rcp++ - '0'; |
if (n > (ULONG_MAX - d)/10) |
overflow = 1; |
else |
n = 10*n + d; |
} |
if (*rcp == '.' || *rcp == 'e' || *rcp == 'E') { |
cp = rcp; |
tsym = fcon(); |
return FCON; |
} |
cp = rcp; |
tsym = icon(n, overflow, 10); |
} |
return ICON; |
} |
case '.': |
if (rcp[0] == '.' && rcp[1] == '.') { |
cp += 2; |
return ELLIPSIS; |
} |
if ((map[*rcp]&DIGIT) == 0) |
return '.'; |
if (limit - rcp < MAXLINE) { |
cp = rcp - 1; |
fillbuf(); |
rcp = ++cp; |
} |
assert(cp == rcp); |
cp = rcp - 1; |
token = (char *)cp; |
tsym = fcon(); |
return FCON; |
case 'L': |
if (*rcp == '\'') { |
unsigned int *s = scon(*cp, wcput, wcbuf); |
if (s - wcbuf > 2) |
warning("excess characters in wide-character literal ignored\n"); |
tval.type = widechar; |
tval.u.c.v.u = wcbuf[0]; |
tsym = &tval; |
return ICON; |
} else if (*rcp == '"') { |
unsigned int *s = scon(*cp, wcput, wcbuf); |
tval.type = array(widechar, s - wcbuf, 0); |
tval.u.c.v.p = wcbuf; |
tsym = &tval; |
return SCON; |
} else |
goto id; |
case '\'': { |
char *s = scon(*--cp, cput, cbuf); |
if (s - cbuf > 2) |
warning("excess characters in multibyte character literal ignored\n"); |
tval.type = inttype; |
if (chartype->op == INT) |
tval.u.c.v.i = extend(cbuf[0], chartype); |
else |
tval.u.c.v.i = cbuf[0]&0xFF; |
tsym = &tval; |
return ICON; |
} |
case '"': { |
char *s = scon(*--cp, cput, cbuf); |
tval.type = array(chartype, s - cbuf, 0); |
tval.u.c.v.p = cbuf; |
tsym = &tval; |
return SCON; |
} |
case 'a': |
if (rcp[0] == 'u' |
&& rcp[1] == 't' |
&& rcp[2] == 'o' |
&& !(map[rcp[3]]&(DIGIT|LETTER))) { |
cp = rcp + 3; |
return AUTO; |
} |
goto id; |
case 'b': |
if (rcp[0] == 'r' |
&& rcp[1] == 'e' |
&& rcp[2] == 'a' |
&& rcp[3] == 'k' |
&& !(map[rcp[4]]&(DIGIT|LETTER))) { |
cp = rcp + 4; |
return BREAK; |
} |
goto id; |
case 'c': |
if (rcp[0] == 'a' |
&& rcp[1] == 's' |
&& rcp[2] == 'e' |
&& !(map[rcp[3]]&(DIGIT|LETTER))) { |
cp = rcp + 3; |
return CASE; |
} |
if (rcp[0] == 'h' |
&& rcp[1] == 'a' |
&& rcp[2] == 'r' |
&& !(map[rcp[3]]&(DIGIT|LETTER))) { |
cp = rcp + 3; |
tsym = chartype->u.sym; |
return CHAR; |
} |
if (rcp[0] == 'o' |
&& rcp[1] == 'n' |
&& rcp[2] == 's' |
&& rcp[3] == 't' |
&& !(map[rcp[4]]&(DIGIT|LETTER))) { |
cp = rcp + 4; |
return CONST; |
} |
if (rcp[0] == 'o' |
&& rcp[1] == 'n' |
&& rcp[2] == 't' |
&& rcp[3] == 'i' |
&& rcp[4] == 'n' |
&& rcp[5] == 'u' |
&& rcp[6] == 'e' |
&& !(map[rcp[7]]&(DIGIT|LETTER))) { |
cp = rcp + 7; |
return CONTINUE; |
} |
goto id; |
case 'd': |
if (rcp[0] == 'e' |
&& rcp[1] == 'f' |
&& rcp[2] == 'a' |
&& rcp[3] == 'u' |
&& rcp[4] == 'l' |
&& rcp[5] == 't' |
&& !(map[rcp[6]]&(DIGIT|LETTER))) { |
cp = rcp + 6; |
return DEFAULT; |
} |
if (rcp[0] == 'o' |
&& rcp[1] == 'u' |
&& rcp[2] == 'b' |
&& rcp[3] == 'l' |
&& rcp[4] == 'e' |
&& !(map[rcp[5]]&(DIGIT|LETTER))) { |
cp = rcp + 5; |
tsym = doubletype->u.sym; |
return DOUBLE; |
} |
if (rcp[0] == 'o' |
&& !(map[rcp[1]]&(DIGIT|LETTER))) { |
cp = rcp + 1; |
return DO; |
} |
goto id; |
case 'e': |
if (rcp[0] == 'l' |
&& rcp[1] == 's' |
&& rcp[2] == 'e' |
&& !(map[rcp[3]]&(DIGIT|LETTER))) { |
cp = rcp + 3; |
return ELSE; |
} |
if (rcp[0] == 'n' |
&& rcp[1] == 'u' |
&& rcp[2] == 'm' |
&& !(map[rcp[3]]&(DIGIT|LETTER))) { |
cp = rcp + 3; |
return ENUM; |
} |
if (rcp[0] == 'x' |
&& rcp[1] == 't' |
&& rcp[2] == 'e' |
&& rcp[3] == 'r' |
&& rcp[4] == 'n' |
&& !(map[rcp[5]]&(DIGIT|LETTER))) { |
cp = rcp + 5; |
return EXTERN; |
} |
goto id; |
case 'f': |
if (rcp[0] == 'l' |
&& rcp[1] == 'o' |
&& rcp[2] == 'a' |
&& rcp[3] == 't' |
&& !(map[rcp[4]]&(DIGIT|LETTER))) { |
cp = rcp + 4; |
tsym = floattype->u.sym; |
return FLOAT; |
} |
if (rcp[0] == 'o' |
&& rcp[1] == 'r' |
&& !(map[rcp[2]]&(DIGIT|LETTER))) { |
cp = rcp + 2; |
return FOR; |
} |
goto id; |
case 'g': |
if (rcp[0] == 'o' |
&& rcp[1] == 't' |
&& rcp[2] == 'o' |
&& !(map[rcp[3]]&(DIGIT|LETTER))) { |
cp = rcp + 3; |
return GOTO; |
} |
goto id; |
case 'l': |
if (rcp[0] == 'o' |
&& rcp[1] == 'n' |
&& rcp[2] == 'g' |
&& !(map[rcp[3]]&(DIGIT|LETTER))) { |
cp = rcp + 3; |
return LONG; |
} |
goto id; |
case 'r': |
if (rcp[0] == 'e' |
&& rcp[1] == 'g' |
&& rcp[2] == 'i' |
&& rcp[3] == 's' |
&& rcp[4] == 't' |
&& rcp[5] == 'e' |
&& rcp[6] == 'r' |
&& !(map[rcp[7]]&(DIGIT|LETTER))) { |
cp = rcp + 7; |
return REGISTER; |
} |
if (rcp[0] == 'e' |
&& rcp[1] == 't' |
&& rcp[2] == 'u' |
&& rcp[3] == 'r' |
&& rcp[4] == 'n' |
&& !(map[rcp[5]]&(DIGIT|LETTER))) { |
cp = rcp + 5; |
return RETURN; |
} |
goto id; |
case 's': |
if (rcp[0] == 'h' |
&& rcp[1] == 'o' |
&& rcp[2] == 'r' |
&& rcp[3] == 't' |
&& !(map[rcp[4]]&(DIGIT|LETTER))) { |
cp = rcp + 4; |
return SHORT; |
} |
if (rcp[0] == 'i' |
&& rcp[1] == 'g' |
&& rcp[2] == 'n' |
&& rcp[3] == 'e' |
&& rcp[4] == 'd' |
&& !(map[rcp[5]]&(DIGIT|LETTER))) { |
cp = rcp + 5; |
return SIGNED; |
} |
if (rcp[0] == 'i' |
&& rcp[1] == 'z' |
&& rcp[2] == 'e' |
&& rcp[3] == 'o' |
&& rcp[4] == 'f' |
&& !(map[rcp[5]]&(DIGIT|LETTER))) { |
cp = rcp + 5; |
return SIZEOF; |
} |
if (rcp[0] == 't' |
&& rcp[1] == 'a' |
&& rcp[2] == 't' |
&& rcp[3] == 'i' |
&& rcp[4] == 'c' |
&& !(map[rcp[5]]&(DIGIT|LETTER))) { |
cp = rcp + 5; |
return STATIC; |
} |
if (rcp[0] == 't' |
&& rcp[1] == 'r' |
&& rcp[2] == 'u' |
&& rcp[3] == 'c' |
&& rcp[4] == 't' |
&& !(map[rcp[5]]&(DIGIT|LETTER))) { |
cp = rcp + 5; |
return STRUCT; |
} |
if (rcp[0] == 'w' |
&& rcp[1] == 'i' |
&& rcp[2] == 't' |
&& rcp[3] == 'c' |
&& rcp[4] == 'h' |
&& !(map[rcp[5]]&(DIGIT|LETTER))) { |
cp = rcp + 5; |
return SWITCH; |
} |
goto id; |
case 't': |
if (rcp[0] == 'y' |
&& rcp[1] == 'p' |
&& rcp[2] == 'e' |
&& rcp[3] == 'd' |
&& rcp[4] == 'e' |
&& rcp[5] == 'f' |
&& !(map[rcp[6]]&(DIGIT|LETTER))) { |
cp = rcp + 6; |
return TYPEDEF; |
} |
goto id; |
case 'u': |
if (rcp[0] == 'n' |
&& rcp[1] == 'i' |
&& rcp[2] == 'o' |
&& rcp[3] == 'n' |
&& !(map[rcp[4]]&(DIGIT|LETTER))) { |
cp = rcp + 4; |
return UNION; |
} |
if (rcp[0] == 'n' |
&& rcp[1] == 's' |
&& rcp[2] == 'i' |
&& rcp[3] == 'g' |
&& rcp[4] == 'n' |
&& rcp[5] == 'e' |
&& rcp[6] == 'd' |
&& !(map[rcp[7]]&(DIGIT|LETTER))) { |
cp = rcp + 7; |
return UNSIGNED; |
} |
goto id; |
case 'v': |
if (rcp[0] == 'o' |
&& rcp[1] == 'i' |
&& rcp[2] == 'd' |
&& !(map[rcp[3]]&(DIGIT|LETTER))) { |
cp = rcp + 3; |
tsym = voidtype->u.sym; |
return VOID; |
} |
if (rcp[0] == 'o' |
&& rcp[1] == 'l' |
&& rcp[2] == 'a' |
&& rcp[3] == 't' |
&& rcp[4] == 'i' |
&& rcp[5] == 'l' |
&& rcp[6] == 'e' |
&& !(map[rcp[7]]&(DIGIT|LETTER))) { |
cp = rcp + 7; |
return VOLATILE; |
} |
goto id; |
case 'w': |
if (rcp[0] == 'h' |
&& rcp[1] == 'i' |
&& rcp[2] == 'l' |
&& rcp[3] == 'e' |
&& !(map[rcp[4]]&(DIGIT|LETTER))) { |
cp = rcp + 4; |
return WHILE; |
} |
goto id; |
case '_': |
if (rcp[0] == '_' |
&& rcp[1] == 't' |
&& rcp[2] == 'y' |
&& rcp[3] == 'p' |
&& rcp[4] == 'e' |
&& rcp[5] == 'c' |
&& rcp[6] == 'o' |
&& rcp[7] == 'd' |
&& rcp[8] == 'e' |
&& !(map[rcp[9]]&(DIGIT|LETTER))) { |
cp = rcp + 9; |
return TYPECODE; |
} |
if (rcp[0] == '_' |
&& rcp[1] == 'f' |
&& rcp[2] == 'i' |
&& rcp[3] == 'r' |
&& rcp[4] == 's' |
&& rcp[5] == 't' |
&& rcp[6] == 'a' |
&& rcp[7] == 'r' |
&& rcp[8] == 'g' |
&& !(map[rcp[9]]&(DIGIT|LETTER))) { |
cp = rcp + 9; |
return FIRSTARG; |
} |
goto id; |
default: |
if ((map[cp[-1]]&BLANK) == 0) |
if (cp[-1] < ' ' || cp[-1] >= 0177) |
error("illegal character `\\0%o'\n", cp[-1]); |
else |
error("illegal character `%c'\n", cp[-1]); |
} |
} |
} |
static Symbol icon(unsigned long n, int overflow, int base) { |
if ((*cp=='u'||*cp=='U') && (cp[1]=='l'||cp[1]=='L') |
|| (*cp=='l'||*cp=='L') && (cp[1]=='u'||cp[1]=='U')) { |
tval.type = unsignedlong; |
cp += 2; |
} else if (*cp == 'u' || *cp == 'U') { |
if (overflow || n > unsignedtype->u.sym->u.limits.max.i) |
tval.type = unsignedlong; |
else |
tval.type = unsignedtype; |
cp += 1; |
} else if (*cp == 'l' || *cp == 'L') { |
if (overflow || n > longtype->u.sym->u.limits.max.i) |
tval.type = unsignedlong; |
else |
tval.type = longtype; |
cp += 1; |
} else if (overflow || n > longtype->u.sym->u.limits.max.i) |
tval.type = unsignedlong; |
else if (base != 10 && |
n > inttype->u.sym->u.limits.max.i && |
n <= unsignedtype->u.sym->u.limits.max.i) |
tval.type = unsignedtype; |
else if (n > inttype->u.sym->u.limits.max.i) |
tval.type = longtype; |
else |
tval.type = inttype; |
switch (tval.type->op) { |
case INT: |
if (overflow || n > tval.type->u.sym->u.limits.max.i) { |
warning("overflow in constant `%S'\n", token, |
(char*)cp - token); |
tval.u.c.v.i = tval.type->u.sym->u.limits.max.i; |
} else |
tval.u.c.v.i = n; |
break; |
case UNSIGNED: |
if (overflow || n > tval.type->u.sym->u.limits.max.u) { |
warning("overflow in constant `%S'\n", token, |
(char*)cp - token); |
tval.u.c.v.u = tval.type->u.sym->u.limits.max.u; |
} else |
tval.u.c.v.u = n; |
break; |
default: assert(0); |
} |
ppnumber("integer"); |
return &tval; |
} |
static void ppnumber(char *which) { |
unsigned char *rcp = cp--; |
|
for ( ; (map[*cp]&(DIGIT|LETTER)) || *cp == '.'; cp++) |
if ((cp[0] == 'E' || cp[0] == 'e') |
&& (cp[1] == '-' || cp[1] == '+')) |
cp++; |
if (cp > rcp) |
error("`%S' is a preprocessing number but an invalid %s constant\n", token, |
|
(char*)cp-token, which); |
} |
static Symbol fcon(void) { |
if (*cp == '.') |
do |
cp++; |
while (map[*cp]&DIGIT); |
if (*cp == 'e' || *cp == 'E') { |
if (*++cp == '-' || *cp == '+') |
cp++; |
if (map[*cp]&DIGIT) |
do |
cp++; |
while (map[*cp]&DIGIT); |
else |
error("invalid floating constant `%S'\n", token, |
(char*)cp - token); |
} |
|
errno = 0; |
tval.u.c.v.d = strtod(token, NULL); |
if (errno == ERANGE) |
warning("overflow in floating constant `%S'\n", token, |
(char*)cp - token); |
if (*cp == 'f' || *cp == 'F') { |
++cp; |
if (tval.u.c.v.d > floattype->u.sym->u.limits.max.d) |
warning("overflow in floating constant `%S'\n", token, |
(char*)cp - token); |
tval.type = floattype; |
} else if (*cp == 'l' || *cp == 'L') { |
cp++; |
tval.type = longdouble; |
} else { |
if (tval.u.c.v.d > doubletype->u.sym->u.limits.max.d) |
warning("overflow in floating constant `%S'\n", token, |
(char*)cp - token); |
tval.type = doubletype; |
} |
ppnumber("floating"); |
return &tval; |
} |
|
static void *cput(int c, void *cl) { |
char *s = cl; |
|
if (c < 0 || c > 255) |
warning("overflow in escape sequence with resulting value `%d'\n", c); |
*s++ = c; |
return s; |
} |
|
static void *wcput(int c, void *cl) { |
unsigned int *s = cl; |
|
*s++ = c; |
return s; |
} |
|
static void *scon(int q, void *put(int c, void *cl), void *cl) { |
int n = 0, nbad = 0; |
|
do { |
cp++; |
while (*cp != q) { |
int c; |
if (map[*cp]&NEWLINE) { |
if (cp < limit) |
break; |
cp++; |
nextline(); |
if (cp == limit) |
break; |
continue; |
} |
c = *cp++; |
if (c == '\\') { |
if (map[*cp]&NEWLINE) { |
if (cp++ < limit) |
continue; |
nextline(); |
} |
if (limit - cp < MAXTOKEN) |
fillbuf(); |
c = backslash(q); |
} else if (c < 0 || c > 255 || map[c] == 0) |
nbad++; |
if (n++ < BUFSIZE) |
cl = put(c, cl); |
} |
if (*cp == q) |
cp++; |
else |
error("missing %c\n", q); |
if (q == '"' && put == wcput && getchr() == 'L') { |
if (limit - cp < 2) |
fillbuf(); |
if (cp[1] == '"') |
cp++; |
} |
} while (q == '"' && getchr() == '"'); |
cl = put(0, cl); |
if (n >= BUFSIZE) |
error("%s literal too long\n", q == '"' ? "string" : "character"); |
if (Aflag >= 2 && q == '"' && n > 509) |
warning("more than 509 characters in a string literal\n"); |
if (Aflag >= 2 && nbad > 0) |
warning("%s literal contains non-portable characters\n", |
q == '"' ? "string" : "character"); |
return cl; |
} |
int getchr(void) { |
for (;;) { |
while (map[*cp]&BLANK) |
cp++; |
if (!(map[*cp]&NEWLINE)) |
return *cp; |
cp++; |
nextline(); |
if (cp == limit) |
return EOI; |
} |
} |
static int backslash(int q) { |
unsigned int c; |
|
switch (*cp++) { |
case 'a': return 7; |
case 'b': return '\b'; |
case 'f': return '\f'; |
case 'n': return '\n'; |
case 'r': return '\r'; |
case 't': return '\t'; |
case 'v': return '\v'; |
case '\'': case '"': case '\\': case '\?': break; |
case 'x': { |
int overflow = 0; |
if ((map[*cp]&(DIGIT|HEX)) == 0) { |
if (*cp < ' ' || *cp == 0177) |
error("ill-formed hexadecimal escape sequence\n"); |
else |
error("ill-formed hexadecimal escape sequence `\\x%c'\n", *cp); |
if (*cp != q) |
cp++; |
return 0; |
} |
for (c = 0; map[*cp]&(DIGIT|HEX); cp++) { |
if (c >> (8*widechar->size - 4)) |
overflow = 1; |
if (map[*cp]&DIGIT) |
c = (c<<4) + *cp - '0'; |
else |
c = (c<<4) + (*cp&~040) - 'A' + 10; |
} |
if (overflow) |
warning("overflow in hexadecimal escape sequence\n"); |
return c&ones(8*widechar->size); |
} |
case '0': case '1': case '2': case '3': |
case '4': case '5': case '6': case '7': |
c = *(cp-1) - '0'; |
if (*cp >= '0' && *cp <= '7') { |
c = (c<<3) + *cp++ - '0'; |
if (*cp >= '0' && *cp <= '7') |
c = (c<<3) + *cp++ - '0'; |
} |
return c; |
default: |
if (cp[-1] < ' ' || cp[-1] >= 0177) |
warning("unrecognized character escape sequence\n"); |
else |
warning("unrecognized character escape sequence `\\%c'\n", cp[-1]); |
} |
return cp[-1]; |
} |
/eco32.md
0,0 → 1,1014
%{ |
|
/* |
* eco32.md -- ECO32 back-end specification |
* |
* register usage: |
* $0 always zero |
* $1 reserved for assembler |
* $2 func return value |
* $3 func return value |
* $4 proc/func argument |
* $5 proc/func argument |
* $6 proc/func argument |
* $7 proc/func argument |
* $8 temporary register (caller-save) |
* $9 temporary register (caller-save) |
* $10 temporary register (caller-save) |
* $11 temporary register (caller-save) |
* $12 temporary register (caller-save) |
* $13 temporary register (caller-save) |
* $14 temporary register (caller-save) |
* $15 temporary register (caller-save) |
* $16 register variable (callee-save) |
* $17 register variable (callee-save) |
* $18 register variable (callee-save) |
* $19 register variable (callee-save) |
* $20 register variable (callee-save) |
* $21 register variable (callee-save) |
* $22 register variable (callee-save) |
* $23 register variable (callee-save) |
* $24 temporary register (caller-save) |
* $25 temporary register (caller-save) |
* $26 reserved for OS kernel |
* $27 reserved for OS kernel |
* $28 reserved for OS kernel |
* $29 stack pointer |
* $30 interrupt return address |
* $31 proc/func return address |
* caller-save registers are not preserved across procedure calls |
* callee-save registers are preserved across procedure calls |
* |
* tree grammar terminals produced by: |
* ops c=1 s=2 i=4 l=4 h=4 f=4 d=8 x=8 p=4 |
*/ |
|
#include "c.h" |
|
#define NODEPTR_TYPE Node |
#define OP_LABEL(p) ((p)->op) |
#define LEFT_CHILD(p) ((p)->kids[0]) |
#define RIGHT_CHILD(p) ((p)->kids[1]) |
#define STATE_LABEL(p) ((p)->x.state) |
|
static void address(Symbol, Symbol, long); |
static void defaddress(Symbol); |
static void defconst(int, int, Value); |
static void defstring(int, char *); |
static void defsymbol(Symbol); |
static void export(Symbol); |
static void function(Symbol, Symbol [], Symbol [], int); |
static void global(Symbol); |
static void import(Symbol); |
static void local(Symbol); |
static void progbeg(int, char * []); |
static void progend(void); |
static void segment(int); |
static void space(int); |
static Symbol rmap(int); |
static void blkfetch(int, int, int, int); |
static void blkstore(int, int, int, int); |
static void blkloop(int, int, int, int, int, int []); |
static void emit2(Node); |
static void doarg(Node); |
static void target(Node); |
static void clobber(Node); |
|
#define INTTMP 0x0100FF00 |
#define INTVAR 0x00FF0000 |
#define INTRET 0x00000004 |
#define FLTTMP 0x000F0FF0 |
#define FLTVAR 0xFFF00000 |
#define FLTRET 0x00000003 |
|
static Symbol ireg[32]; |
static Symbol iregw; |
static Symbol freg2[32]; |
static Symbol freg2w; |
static Symbol blkreg; |
static int tmpregs[] = { 3, 9, 10 }; |
|
%} |
|
%start stmt |
|
%term CNSTF4=4113 CNSTF8=8209 |
%term CNSTI1=1045 CNSTI2=2069 CNSTI4=4117 |
%term CNSTP4=4119 |
%term CNSTU1=1046 CNSTU2=2070 CNSTU4=4118 |
|
%term ARGB=41 |
%term ARGF4=4129 ARGF8=8225 |
%term ARGI4=4133 |
%term ARGP4=4135 |
%term ARGU4=4134 |
|
%term ASGNB=57 |
%term ASGNF4=4145 ASGNF8=8241 |
%term ASGNI1=1077 ASGNI2=2101 ASGNI4=4149 |
%term ASGNP4=4151 |
%term ASGNU1=1078 ASGNU2=2102 ASGNU4=4150 |
|
%term INDIRB=73 |
%term INDIRF4=4161 INDIRF8=8257 |
%term INDIRI1=1093 INDIRI2=2117 INDIRI4=4165 |
%term INDIRP4=4167 |
%term INDIRU1=1094 INDIRU2=2118 INDIRU4=4166 |
|
%term CVFF4=4209 CVFF8=8305 |
%term CVFI4=4213 |
|
%term CVIF4=4225 CVIF8=8321 |
%term CVII1=1157 CVII2=2181 CVII4=4229 |
%term CVIU1=1158 CVIU2=2182 CVIU4=4230 |
|
%term CVPU4=4246 |
|
%term CVUI1=1205 CVUI2=2229 CVUI4=4277 |
%term CVUP4=4279 |
%term CVUU1=1206 CVUU2=2230 CVUU4=4278 |
|
%term NEGF4=4289 NEGF8=8385 |
%term NEGI4=4293 |
|
%term CALLB=217 |
%term CALLF4=4305 CALLF8=8401 |
%term CALLI4=4309 |
%term CALLP4=4311 |
%term CALLU4=4310 |
%term CALLV=216 |
|
%term RETF4=4337 RETF8=8433 |
%term RETI4=4341 |
%term RETP4=4343 |
%term RETU4=4342 |
%term RETV=248 |
|
%term ADDRGP4=4359 |
|
%term ADDRFP4=4375 |
|
%term ADDRLP4=4391 |
|
%term ADDF4=4401 ADDF8=8497 |
%term ADDI4=4405 |
%term ADDP4=4407 |
%term ADDU4=4406 |
|
%term SUBF4=4417 SUBF8=8513 |
%term SUBI4=4421 |
%term SUBP4=4423 |
%term SUBU4=4422 |
|
%term LSHI4=4437 |
%term LSHU4=4438 |
|
%term MODI4=4453 |
%term MODU4=4454 |
|
%term RSHI4=4469 |
%term RSHU4=4470 |
|
%term BANDI4=4485 |
%term BANDU4=4486 |
|
%term BCOMI4=4501 |
%term BCOMU4=4502 |
|
%term BORI4=4517 |
%term BORU4=4518 |
|
%term BXORI4=4533 |
%term BXORU4=4534 |
|
%term DIVF4=4545 DIVF8=8641 |
%term DIVI4=4549 |
%term DIVU4=4550 |
|
%term MULF4=4561 MULF8=8657 |
%term MULI4=4565 |
%term MULU4=4566 |
|
%term EQF4=4577 EQF8=8673 |
%term EQI4=4581 |
%term EQU4=4582 |
|
%term GEF4=4593 GEF8=8689 |
%term GEI4=4597 |
%term GEU4=4598 |
|
%term GTF4=4609 GTF8=8705 |
%term GTI4=4613 |
%term GTU4=4614 |
|
%term LEF4=4625 LEF8=8721 |
%term LEI4=4629 |
%term LEU4=4630 |
|
%term LTF4=4641 LTF8=8737 |
%term LTI4=4645 |
%term LTU4=4646 |
|
%term NEF4=4657 NEF8=8753 |
%term NEI4=4661 |
%term NEU4=4662 |
|
%term JUMPV=584 |
|
%term LABELV=600 |
|
%term LOADB=233 |
%term LOADF4=4321 LOADF8=8417 |
%term LOADI1=1253 LOADI2=2277 LOADI4=4325 |
%term LOADP4=4327 |
%term LOADU1=1254 LOADU2=2278 LOADU4=4326 |
|
%term VREGP=711 |
|
|
%% |
|
|
reg: INDIRI1(VREGP) "# read register\n" |
reg: INDIRI2(VREGP) "# read register\n" |
reg: INDIRI4(VREGP) "# read register\n" |
reg: INDIRP4(VREGP) "# read register\n" |
reg: INDIRU1(VREGP) "# read register\n" |
reg: INDIRU2(VREGP) "# read register\n" |
reg: INDIRU4(VREGP) "# read register\n" |
|
stmt: ASGNI1(VREGP,reg) "# write register\n" |
stmt: ASGNI2(VREGP,reg) "# write register\n" |
stmt: ASGNI4(VREGP,reg) "# write register\n" |
stmt: ASGNP4(VREGP,reg) "# write register\n" |
stmt: ASGNU1(VREGP,reg) "# write register\n" |
stmt: ASGNU2(VREGP,reg) "# write register\n" |
stmt: ASGNU4(VREGP,reg) "# write register\n" |
|
con: CNSTI1 "%a" |
con: CNSTI2 "%a" |
con: CNSTI4 "%a" |
con: CNSTP4 "%a" |
con: CNSTU1 "%a" |
con: CNSTU2 "%a" |
con: CNSTU4 "%a" |
|
stmt: reg "" |
|
acon: con "%0" |
acon: ADDRGP4 "%a" |
|
addr: ADDI4(reg,acon) "$%0,%1" |
addr: ADDP4(reg,acon) "$%0,%1" |
addr: ADDU4(reg,acon) "$%0,%1" |
|
addr: acon "$0,%0" |
addr: reg "$%0,0" |
addr: ADDRFP4 "$29,%a+%F" |
addr: ADDRLP4 "$29,%a+%F" |
|
reg: addr "\tadd\t$%c,%0\n" 1 |
|
reg: CNSTI1 "# reg\n" range(a, 0, 0) |
reg: CNSTI2 "# reg\n" range(a, 0, 0) |
reg: CNSTI4 "# reg\n" range(a, 0, 0) |
reg: CNSTP4 "# reg\n" range(a, 0, 0) |
reg: CNSTU1 "# reg\n" range(a, 0, 0) |
reg: CNSTU2 "# reg\n" range(a, 0, 0) |
reg: CNSTU4 "# reg\n" range(a, 0, 0) |
|
stmt: ASGNI1(addr,reg) "\tstb\t$%1,%0\n" 1 |
stmt: ASGNI2(addr,reg) "\tsth\t$%1,%0\n" 1 |
stmt: ASGNI4(addr,reg) "\tstw\t$%1,%0\n" 1 |
stmt: ASGNP4(addr,reg) "\tstw\t$%1,%0\n" 1 |
stmt: ASGNU1(addr,reg) "\tstb\t$%1,%0\n" 1 |
stmt: ASGNU2(addr,reg) "\tsth\t$%1,%0\n" 1 |
stmt: ASGNU4(addr,reg) "\tstw\t$%1,%0\n" 1 |
|
reg: INDIRI1(addr) "\tldb\t$%c,%0\n" 1 |
reg: INDIRI2(addr) "\tldh\t$%c,%0\n" 1 |
reg: INDIRI4(addr) "\tldw\t$%c,%0\n" 1 |
reg: INDIRP4(addr) "\tldw\t$%c,%0\n" 1 |
reg: INDIRU1(addr) "\tldbu\t$%c,%0\n" 1 |
reg: INDIRU2(addr) "\tldhu\t$%c,%0\n" 1 |
reg: INDIRU4(addr) "\tldw\t$%c,%0\n" 1 |
|
reg: CVII4(INDIRI1(addr)) "\tldb\t$%c,%0\n" 1 |
reg: CVII4(INDIRI2(addr)) "\tldh\t$%c,%0\n" 1 |
reg: CVUU4(INDIRU1(addr)) "\tldbu\t$%c,%0\n" 1 |
reg: CVUU4(INDIRU2(addr)) "\tldhu\t$%c,%0\n" 1 |
reg: CVUI4(INDIRU1(addr)) "\tldbu\t$%c,%0\n" 1 |
reg: CVUI4(INDIRU2(addr)) "\tldhu\t$%c,%0\n" 1 |
|
rc: con "%0" |
rc: reg "$%0" |
|
reg: ADDI4(reg,rc) "\tadd\t$%c,$%0,%1\n" 1 |
reg: ADDP4(reg,rc) "\tadd\t$%c,$%0,%1\n" 1 |
reg: ADDU4(reg,rc) "\tadd\t$%c,$%0,%1\n" 1 |
reg: SUBI4(reg,rc) "\tsub\t$%c,$%0,%1\n" 1 |
reg: SUBP4(reg,rc) "\tsub\t$%c,$%0,%1\n" 1 |
reg: SUBU4(reg,rc) "\tsub\t$%c,$%0,%1\n" 1 |
reg: NEGI4(reg) "\tsub\t$%c,$0,$%0\n" 1 |
|
reg: MULI4(reg,rc) "\tmul\t$%c,$%0,%1\n" 1 |
reg: MULU4(reg,rc) "\tmulu\t$%c,$%0,%1\n" 1 |
reg: DIVI4(reg,rc) "\tdiv\t$%c,$%0,%1\n" 1 |
reg: DIVU4(reg,rc) "\tdivu\t$%c,$%0,%1\n" 1 |
reg: MODI4(reg,rc) "\trem\t$%c,$%0,%1\n" 1 |
reg: MODU4(reg,rc) "\tremu\t$%c,$%0,%1\n" 1 |
|
reg: BANDI4(reg,rc) "\tand\t$%c,$%0,%1\n" 1 |
reg: BANDU4(reg,rc) "\tand\t$%c,$%0,%1\n" 1 |
reg: BORI4(reg,rc) "\tor\t$%c,$%0,%1\n" 1 |
reg: BORU4(reg,rc) "\tor\t$%c,$%0,%1\n" 1 |
reg: BXORI4(reg,rc) "\txor\t$%c,$%0,%1\n" 1 |
reg: BXORU4(reg,rc) "\txor\t$%c,$%0,%1\n" 1 |
reg: BCOMI4(reg) "\txnor\t$%c,$0,$%0\n" 1 |
reg: BCOMU4(reg) "\txnor\t$%c,$0,$%0\n" 1 |
|
rc5: CNSTI4 "%a" range(a, 0, 31) |
rc5: reg "$%0" |
|
reg: LSHI4(reg,rc5) "\tsll\t$%c,$%0,%1\n" 1 |
reg: LSHU4(reg,rc5) "\tsll\t$%c,$%0,%1\n" 1 |
reg: RSHI4(reg,rc5) "\tsar\t$%c,$%0,%1\n" 1 |
reg: RSHU4(reg,rc5) "\tslr\t$%c,$%0,%1\n" 1 |
|
reg: LOADI1(reg) "\tadd\t$%c,$0,$%0\n" move(a) |
reg: LOADI2(reg) "\tadd\t$%c,$0,$%0\n" move(a) |
reg: LOADI4(reg) "\tadd\t$%c,$0,$%0\n" move(a) |
reg: LOADP4(reg) "\tadd\t$%c,$0,$%0\n" move(a) |
reg: LOADU1(reg) "\tadd\t$%c,$0,$%0\n" move(a) |
reg: LOADU2(reg) "\tadd\t$%c,$0,$%0\n" move(a) |
reg: LOADU4(reg) "\tadd\t$%c,$0,$%0\n" move(a) |
|
reg: CVII4(reg) "\tsll\t$%c,$%0,8*(4-%a)\n\tsar\t$%c,$%c,8*(4-%a)\n" 2 |
reg: CVUI4(reg) "\tand\t$%c,$%0,(1<<(8*%a))-1\n" 1 |
reg: CVUU4(reg) "\tand\t$%c,$%0,(1<<(8*%a))-1\n" 1 |
|
stmt: LABELV "%a:\n" |
stmt: JUMPV(acon) "\tj\t%0\n" 1 |
stmt: JUMPV(reg) "\tjr\t$%0\n" 1 |
|
stmt: EQI4(reg,reg) "\tbeq\t$%0,$%1,%a\n" 1 |
stmt: EQU4(reg,reg) "\tbeq\t$%0,$%1,%a\n" 1 |
stmt: NEI4(reg,reg) "\tbne\t$%0,$%1,%a\n" 1 |
stmt: NEU4(reg,reg) "\tbne\t$%0,$%1,%a\n" 1 |
stmt: LEI4(reg,reg) "\tble\t$%0,$%1,%a\n" 1 |
stmt: LEU4(reg,reg) "\tbleu\t$%0,$%1,%a\n" 1 |
stmt: LTI4(reg,reg) "\tblt\t$%0,$%1,%a\n" 1 |
stmt: LTU4(reg,reg) "\tbltu\t$%0,$%1,%a\n" 1 |
stmt: GEI4(reg,reg) "\tbge\t$%0,$%1,%a\n" 1 |
stmt: GEU4(reg,reg) "\tbgeu\t$%0,$%1,%a\n" 1 |
stmt: GTI4(reg,reg) "\tbgt\t$%0,$%1,%a\n" 1 |
stmt: GTU4(reg,reg) "\tbgtu\t$%0,$%1,%a\n" 1 |
|
reg: CALLI4(ar) "\tjal\t%0\n" 1 |
reg: CALLP4(ar) "\tjal\t%0\n" 1 |
reg: CALLU4(ar) "\tjal\t%0\n" 1 |
stmt: CALLV(ar) "\tjal\t%0\n" 1 |
|
ar: ADDRGP4 "%a" |
ar: reg "$%0" |
ar: CNSTP4 "%a" range(a, 0, 0x03FFFFFF) |
|
stmt: RETI4(reg) "# ret\n" 1 |
stmt: RETP4(reg) "# ret\n" 1 |
stmt: RETU4(reg) "# ret\n" 1 |
stmt: RETV(reg) "# ret\n" 1 |
|
stmt: ARGI4(reg) "# arg\n" 1 |
stmt: ARGP4(reg) "# arg\n" 1 |
stmt: ARGU4(reg) "# arg\n" 1 |
|
stmt: ARGB(INDIRB(reg)) "# argb %0\n" 1 |
stmt: ASGNB(reg,INDIRB(reg)) "# asgnb %0 %1\n" 1 |
|
reg: INDIRF4(VREGP) "# read register\n" |
stmt: ASGNF4(VREGP,reg) "# write register\n" |
reg: INDIRF4(addr) ";FP: l.s $f%c,%0\n" 1 |
stmt: ASGNF4(addr,reg) ";FP: s.s $f%1,%0\n" 1 |
reg: ADDF4(reg,reg) ";FP: add.s $f%c,$f%0,$f%1\n" 1 |
reg: SUBF4(reg,reg) ";FP: sub.s $f%c,$f%0,$f%1\n" 1 |
reg: MULF4(reg,reg) ";FP: mul.s $f%c,$f%0,$f%1\n" 1 |
reg: DIVF4(reg,reg) ";FP: div.s $f%c,$f%0,$f%1\n" 1 |
reg: LOADF4(reg) ";FP: mov.s $f%c,$f%0\n" 1 |
reg: NEGF4(reg) ";FP: neg.s $f%c,$f%0\n" 1 |
reg: CVFF4(reg) ";FP: cvt.s.d $f%c,$f%0\n" 1 |
reg: CVIF4(reg) ";FP: mtc1 $%0,$f%c; cvt.s.w $f%c,$f%c\n" 1 |
reg: CVFI4(reg) ";FP: trunc.w.s $f2,$f%0,$%c; mfc1 $%c,$f2\n" (a->syms[0]->u.c.v.i == 4 ? 1 : LBURG_MAX) |
stmt: EQF4(reg,reg) ";FP: c.eq.s $f%0,$f%1; bc1t %a\n" 1 |
stmt: LEF4(reg,reg) ";FP: c.ule.s $f%0,$f%1; bc1t %a\n" 1 |
stmt: LTF4(reg,reg) ";FP: c.ult.s $f%0,$f%1; bc1t %a\n" 1 |
stmt: GEF4(reg,reg) ";FP: c.lt.s $f%0,$f%1; bc1f %a\n" 1 |
stmt: GTF4(reg,reg) ";FP: c.le.s $f%0,$f%1; bc1f %a\n" 1 |
stmt: NEF4(reg,reg) ";FP: c.eq.s $f%0,$f%1; bc1f %a\n" 1 |
reg: CALLF4(ar) "\tjal\t%0\n" 1 |
stmt: RETF4(reg) "# ret\n" 1 |
stmt: ARGF4(reg) "# arg\n" 1 |
|
reg: INDIRF8(VREGP) "# read register\n" |
stmt: ASGNF8(VREGP,reg) "# write register\n" |
reg: INDIRF8(addr) ";FP: l.d $f%c,%0\n" 1 |
stmt: ASGNF8(addr,reg) ";FP: s.d $f%1,%0\n" 1 |
reg: ADDF8(reg,reg) ";FP: add.d $f%c,$f%0,$f%1\n" 1 |
reg: SUBF8(reg,reg) ";FP: sub.d $f%c,$f%0,$f%1\n" 1 |
reg: MULF8(reg,reg) ";FP: mul.d $f%c,$f%0,$f%1\n" 1 |
reg: DIVF8(reg,reg) ";FP: div.d $f%c,$f%0,$f%1\n" 1 |
reg: LOADF8(reg) ";FP: mov.d $f%c,$f%0\n" 1 |
reg: NEGF8(reg) ";FP: neg.d $f%c,$f%0\n" 1 |
reg: CVFF8(reg) ";FP: cvt.d.s $f%c,$f%0\n" 1 |
reg: CVIF8(reg) ";FP: mtc1 $%0,$f%c; cvt.d.w $f%c,$f%c\n" 1 |
reg: CVFI4(reg) ";FP: trunc.w.d $f2,$f%0,$%c; mfc1 $%c,$f2\n" (a->syms[0]->u.c.v.i == 8 ? 1 : LBURG_MAX) |
stmt: EQF8(reg,reg) ";FP: c.eq.d $f%0,$f%1; bc1t %a\n" 1 |
stmt: LEF8(reg,reg) ";FP: c.ule.d $f%0,$f%1; bc1t %a\n" 1 |
stmt: LTF8(reg,reg) ";FP: c.ult.d $f%0,$f%1; bc1t %a\n" 1 |
stmt: GEF8(reg,reg) ";FP: c.lt.d $f%0,$f%1; bc1f %a\n" 1 |
stmt: GTF8(reg,reg) ";FP: c.le.d $f%0,$f%1; bc1f %a\n" 1 |
stmt: NEF8(reg,reg) ";FP: c.eq.d $f%0,$f%1; bc1f %a\n" 1 |
reg: CALLF8(ar) "\tjal\t%0\n" 1 |
stmt: RETF8(reg) "# ret\n" 1 |
stmt: ARGF8(reg) "# arg\n" 1 |
|
|
%% |
|
|
static void address(Symbol s1, Symbol s2, long n) { |
if (s2->scope == GLOBAL || |
s2->sclass == STATIC || |
s2->sclass == EXTERN) { |
s1->x.name = stringf("%s%s%D", s2->x.name, n >= 0 ? "+" : "", n); |
} else { |
assert(n >= INT_MIN && n <= INT_MAX); |
s1->x.offset = s2->x.offset + n; |
s1->x.name = stringd(s1->x.offset); |
} |
} |
|
|
static void defaddress(Symbol s) { |
print("\t.word\t%s\n", s->x.name); |
} |
|
|
static void defconst(int suffix, int size, Value v) { |
float f; |
double d; |
unsigned *p; |
|
if (suffix == F && size == 4) { |
f = v.d; |
print("\t.word\t0x%x\n", * (unsigned *) &f); |
} else |
if (suffix == F && size == 8) { |
d = v.d; |
p = (unsigned *) &d; |
print("\t.word\t0x%x\n", p[swap]); |
print("\t.word\t0x%x\n", p[1 - swap]); |
} else |
if (suffix == P) { |
print("\t.word\t0x%x\n", (unsigned) v.p); |
} else |
if (size == 1) { |
print("\t.byte\t0x%x\n", |
(unsigned) ((unsigned char) (suffix == I ? v.i : v.u))); |
} else |
if (size == 2) { |
print("\t.half\t0x%x\n", |
(unsigned) ((unsigned short) (suffix == I ? v.i : v.u))); |
} else |
if (size == 4) { |
print("\t.word\t0x%x\n", (unsigned) (suffix == I ? v.i : v.u)); |
} |
} |
|
|
static void defstring(int n, char *str) { |
char *s; |
|
for (s = str; s < str + n; s++) { |
print("\t.byte\t0x%x\n", (*s) & 0xFF); |
} |
} |
|
|
static void defsymbol(Symbol s) { |
if (s->scope >= LOCAL && s->sclass == STATIC) { |
s->x.name = stringf("L.%d", genlabel(1)); |
} else |
if (s->generated) { |
s->x.name = stringf("L.%s", s->name); |
} else { |
assert(s->scope != CONSTANTS || isint(s->type) || isptr(s->type)); |
s->x.name = s->name; |
} |
} |
|
|
static void export(Symbol s) { |
print("\t.export\t%s\n", s->name); |
} |
|
|
static int bitcount(unsigned mask) { |
unsigned i, n; |
|
n = 0; |
for (i = 1; i != 0; i <<= 1) { |
if (mask & i) { |
n++; |
} |
} |
return n; |
} |
|
|
static Symbol argreg(int argno, int offset, int ty, int sz, int ty0) { |
assert((offset & 3) == 0); |
if (offset > 12) { |
return NULL; |
} |
return ireg[(offset / 4) + 4]; |
} |
|
|
static void function(Symbol f, Symbol caller[], Symbol callee[], int ncalls) { |
int i; |
Symbol p, q; |
Symbol r; |
int sizeisave; |
int saved; |
Symbol argregs[4]; |
|
usedmask[0] = usedmask[1] = 0; |
freemask[0] = freemask[1] = ~((unsigned) 0); |
offset = 0; |
maxoffset = 0; |
maxargoffset = 0; |
for (i = 0; callee[i] != NULL; i++) { |
p = callee[i]; |
q = caller[i]; |
assert(q != NULL); |
offset = roundup(offset, q->type->align); |
p->x.offset = q->x.offset = offset; |
p->x.name = q->x.name = stringd(offset); |
r = argreg(i, offset, optype(ttob(q->type)), |
q->type->size, optype(ttob(caller[0]->type))); |
if (i < 4) { |
argregs[i] = r; |
} |
offset = roundup(offset + q->type->size, 4); |
if (variadic(f->type)) { |
p->sclass = AUTO; |
} else |
if (r != NULL && ncalls == 0 && !isstruct(q->type) && |
!p->addressed && !(isfloat(q->type) && r->x.regnode->set == IREG)) { |
p->sclass = q->sclass = REGISTER; |
askregvar(p, r); |
assert(p->x.regnode && p->x.regnode->vbl == p); |
q->x = p->x; |
q->type = p->type; |
} else |
if (askregvar(p, rmap(ttob(p->type))) && |
r != NULL && (isint(p->type) || p->type == q->type)) { |
assert(q->sclass != REGISTER); |
p->sclass = q->sclass = REGISTER; |
q->type = p->type; |
} |
} |
assert(caller[i] == NULL); |
offset = 0; |
gencode(caller, callee); |
if (ncalls != 0) { |
usedmask[IREG] |= ((unsigned) 1) << 31; |
} |
usedmask[IREG] &= 0x80FF0000; |
usedmask[FREG] &= 0xFFF00000; |
maxargoffset = roundup(maxargoffset, 4); |
if (ncalls != 0 && maxargoffset < 16) { |
maxargoffset = 16; |
} |
sizeisave = 4 * bitcount(usedmask[IREG]); |
framesize = roundup(maxargoffset + sizeisave + maxoffset, 16); |
segment(CODE); |
print("\t.align\t4\n"); |
print("%s:\n", f->x.name); |
if (framesize > 0) { |
print("\tsub\t$29,$29,%d\n", framesize); |
} |
saved = maxargoffset; |
for (i = 16; i < 32; i++) { |
if (usedmask[IREG] & (1 << i)) { |
print("\tstw\t$%d,$29,%d\n", i, saved); |
saved += 4; |
} |
} |
for (i = 0; i < 4 && callee[i] != NULL; i++) { |
r = argregs[i]; |
if (r && r->x.regnode != callee[i]->x.regnode) { |
Symbol out = callee[i]; |
Symbol in = caller[i]; |
int rn = r->x.regnode->number; |
int rs = r->x.regnode->set; |
int tyin = ttob(in->type); |
assert(out && in && r && r->x.regnode); |
assert(out->sclass != REGISTER || out->x.regnode); |
if (out->sclass == REGISTER && |
(isint(out->type) || out->type == in->type)) { |
int outn = out->x.regnode->number; |
print("\tadd\t$%d,$0,$%d\n", outn, rn); |
} else { |
int off = in->x.offset + framesize; |
int n = (in->type->size + 3) / 4; |
int i; |
for (i = rn; i < rn + n && i <= 7; i++) { |
print("\tstw\t$%d,$29,%d\n", i, off + (i - rn) * 4); |
} |
} |
} |
} |
if (variadic(f->type) && callee[i - 1] != NULL) { |
i = callee[i - 1]->x.offset + callee[i - 1]->type->size; |
for (i = roundup(i, 4)/4; i <= 3; i++) { |
print("\tstw\t$%d,$29,%d\n", i + 4, framesize + 4 * i); |
} |
} |
emitcode(); |
saved = maxargoffset; |
for (i = 16; i < 32; i++) { |
if (usedmask[IREG] & (1 << i)) { |
print("\tldw\t$%d,$29,%d\n", i, saved); |
saved += 4; |
} |
} |
if (framesize > 0) { |
print("\tadd\t$29,$29,%d\n", framesize); |
} |
print("\tjr\t$31\n"); |
print("\n"); |
} |
|
|
static void global(Symbol s) { |
if (s->type->align != 0) { |
print("\t.align\t%d\n", s->type->align); |
} else { |
print("\t.align\t%d\n", 4); |
} |
print("%s:\n", s->x.name); |
} |
|
|
static void import(Symbol s) { |
print("\t.import\t%s\n", s->name); |
} |
|
|
static void local(Symbol s) { |
if (askregvar(s, rmap(ttob(s->type))) == 0) { |
mkauto(s); |
} |
} |
|
|
static void setSwap(void) { |
union { |
char c; |
int i; |
} u; |
|
u.i = 0; |
u.c = 1; |
swap = ((u.i == 1) != IR->little_endian); |
} |
|
|
static void progbeg(int argc, char *argv[]) { |
int i; |
|
setSwap(); |
segment(CODE); |
parseflags(argc, argv); |
for (i = 0; i < 32; i++) { |
ireg[i] = mkreg("%d", i, 1, IREG); |
} |
iregw = mkwildcard(ireg); |
for (i = 0; i < 32; i += 2) { |
freg2[i] = mkreg("%d", i, 3, FREG); |
} |
freg2w = mkwildcard(freg2); |
tmask[IREG] = INTTMP; |
vmask[IREG] = INTVAR; |
tmask[FREG] = FLTTMP; |
vmask[FREG] = FLTVAR; |
blkreg = mkreg("8", 8, 7, IREG); |
} |
|
|
static void progend(void) { |
} |
|
|
static void segment(int n) { |
static int currSeg = -1; |
int newSeg; |
|
switch (n) { |
case CODE: |
newSeg = CODE; |
break; |
case BSS: |
newSeg = BSS; |
break; |
case DATA: |
newSeg = DATA; |
break; |
case LIT: |
newSeg = DATA; |
break; |
} |
if (currSeg == newSeg) { |
return; |
} |
switch (newSeg) { |
case CODE: |
print("\t.code\n"); |
break; |
case BSS: |
print("\t.bss\n"); |
break; |
case DATA: |
print("\t.data\n"); |
break; |
} |
currSeg = newSeg; |
} |
|
|
static void space(int n) { |
print("\t.space\t%d\n", n); |
} |
|
|
static Symbol rmap(int opk) { |
switch (optype(opk)) { |
case I: |
case U: |
case P: |
case B: |
return iregw; |
case F: |
return freg2w; |
default: |
return 0; |
} |
} |
|
|
static void blkfetch(int size, int off, int reg, int tmp) { |
assert(size == 1 || size == 2 || size == 4); |
if (size == 1) { |
print("\tldbu\t$%d,$%d,%d\n", tmp, reg, off); |
} else |
if (size == 2) { |
print("\tldhu\t$%d,$%d,%d\n", tmp, reg, off); |
} else |
if (size == 4) { |
print("\tldw\t$%d,$%d,%d\n", tmp, reg, off); |
} |
} |
|
|
static void blkstore(int size, int off, int reg, int tmp) { |
assert(size == 1 || size == 2 || size == 4); |
if (size == 1) { |
print("\tstb\t$%d,$%d,%d\n", tmp, reg, off); |
} else |
if (size == 2) { |
print("\tsth\t$%d,$%d,%d\n", tmp, reg, off); |
} else |
if (size == 4) { |
print("\tstw\t$%d,$%d,%d\n", tmp, reg, off); |
} |
} |
|
|
static void blkloop(int dreg, int doff, |
int sreg, int soff, |
int size, int tmps[]) { |
int label; |
|
label = genlabel(1); |
print("\tadd\t$%d,$%d,%d\n", sreg, sreg, size & ~7); |
print("\tadd\t$%d,$%d,%d\n", tmps[2], dreg, size & ~7); |
blkcopy(tmps[2], doff, sreg, soff, size & 7, tmps); |
print("L.%d:\n", label); |
print("\tsub\t$%d,$%d,%d\n", sreg, sreg, 8); |
print("\tsub\t$%d,$%d,%d\n", tmps[2], tmps[2], 8); |
blkcopy(tmps[2], doff, sreg, soff, 8, tmps); |
print("\tbltu\t$%d,$%d,L.%d\n", dreg, tmps[2], label); |
} |
|
|
static void emit2(Node p) { |
static int ty0; |
int ty, sz; |
Symbol q; |
int src; |
int dst, n; |
|
switch (specific(p->op)) { |
case ARG+I: |
case ARG+P: |
case ARG+U: |
ty = optype(p->op); |
sz = opsize(p->op); |
if (p->x.argno == 0) { |
ty0 = ty; |
} |
q = argreg(p->x.argno, p->syms[2]->u.c.v.i, ty, sz, ty0); |
src = getregnum(p->x.kids[0]); |
if (q == NULL) { |
print("\tstw\t$%d,$29,%d\n", src, p->syms[2]->u.c.v.i); |
} |
break; |
case ASGN+B: |
dalign = p->syms[1]->u.c.v.i; |
salign = p->syms[1]->u.c.v.i; |
blkcopy(getregnum(p->x.kids[0]), 0, |
getregnum(p->x.kids[1]), 0, |
p->syms[0]->u.c.v.i, tmpregs); |
break; |
case ARG+B: |
dalign = 4; |
salign = p->syms[1]->u.c.v.i; |
blkcopy(29, p->syms[2]->u.c.v.i, |
getregnum(p->x.kids[0]), 0, |
p->syms[0]->u.c.v.i, tmpregs); |
n = p->syms[2]->u.c.v.i + p->syms[0]->u.c.v.i; |
dst = p->syms[2]->u.c.v.i; |
for (; dst <= 12 && dst < n; dst += 4) { |
print("\tldw\t$%d,$29,%d\n", (dst / 4) + 4, dst); |
} |
break; |
} |
} |
|
|
static void doarg(Node p) { |
static int argno; |
int align; |
int size; |
int offset; |
|
if (argoffset == 0) { |
argno = 0; |
} |
p->x.argno = argno++; |
align = p->syms[1]->u.c.v.i; |
if (align < 4) { |
align = 4; |
} |
size = p->syms[0]->u.c.v.i; |
offset = mkactual(align, size); |
p->syms[2] = intconst(offset); |
} |
|
|
static void target(Node p) { |
static int ty0; |
int ty; |
Symbol q; |
|
assert(p); |
switch (specific(p->op)) { |
case CNST+I: |
case CNST+P: |
case CNST+U: |
if (range(p, 0, 0) == 0) { |
setreg(p, ireg[0]); |
p->x.registered = 1; |
} |
break; |
case CALL+I: |
case CALL+P: |
case CALL+U: |
rtarget(p, 0, ireg[25]); |
setreg(p, ireg[2]); |
break; |
case CALL+F: |
rtarget(p, 0, ireg[25]); |
setreg(p, freg2[0]); |
break; |
case CALL+V: |
rtarget(p, 0, ireg[25]); |
break; |
case RET+I: |
case RET+P: |
case RET+U: |
rtarget(p, 0, ireg[2]); |
break; |
case RET+F: |
rtarget(p, 0, freg2[0]); |
break; |
case ARG+I: |
case ARG+P: |
case ARG+U: |
case ARG+F: |
ty = optype(p->op); |
q = argreg(p->x.argno, p->syms[2]->u.c.v.i, ty, opsize(p->op), ty0); |
if (p->x.argno == 0) { |
ty0 = ty; |
} |
if (q && !(ty == F && q->x.regnode->set == IREG)) { |
rtarget(p, 0, q); |
} |
break; |
case ASGN+B: |
rtarget(p->kids[1], 0, blkreg); |
break; |
case ARG+B: |
rtarget(p->kids[0], 0, blkreg); |
break; |
} |
} |
|
|
static void clobber(Node p) { |
assert(p); |
switch (specific(p->op)) { |
case CALL+F: |
spill(INTTMP | INTRET, IREG, p); |
spill(FLTTMP, FREG, p); |
break; |
case CALL+I: |
case CALL+P: |
case CALL+U: |
spill(INTTMP, IREG, p); |
spill(FLTTMP | FLTRET, FREG, p); |
break; |
case CALL+V: |
spill(INTTMP | INTRET, IREG, p); |
spill(FLTTMP | FLTRET, FREG, p); |
break; |
} |
} |
|
|
Interface eco32IR = { |
1, 1, 0, /* char */ |
2, 2, 0, /* short */ |
4, 4, 0, /* int */ |
4, 4, 0, /* long */ |
4, 4, 0, /* long long */ |
4, 4, 1, /* float */ |
8, 4, 1, /* double */ |
8, 4, 1, /* long double */ |
4, 4, 0, /* T * */ |
0, 1, 0, /* struct */ |
0, /* little_endian */ |
0, /* mulops_calls */ |
0, /* wants_callb */ |
1, /* wants_argb */ |
1, /* left_to_right */ |
0, /* wants_dag */ |
0, /* unsigned_char */ |
address, |
blockbeg, |
blockend, |
defaddress, |
defconst, |
defstring, |
defsymbol, |
emit, |
export, |
function, |
gen, |
global, |
import, |
local, |
progbeg, |
progend, |
segment, |
space, |
0, 0, 0, 0, 0, 0, 0, |
{ |
1, /* max_unaligned_load */ |
rmap, |
blkfetch, blkstore, blkloop, |
_label, |
_rule, |
_nts, |
_kids, |
_string, |
_templates, |
_isinstruction, |
_ntname, |
emit2, |
doarg, |
target, |
clobber |
} |
}; |
/stab.c
0,0 → 1,327
#include <string.h> |
#include <stdlib.h> |
#include "c.h" |
#include "stab.h" |
|
static char rcsid[] = "$Id: stab.c,v 1.1 2002/08/28 23:12:46 drh Exp $"; |
|
static char *currentfile; /* current file name */ |
static int ntypes; |
|
extern Interface sparcIR; |
|
char *stabprefix = "L"; |
|
extern char *stabprefix; |
extern void stabblock(int, int, Symbol*); |
extern void stabend(Coordinate *, Symbol, Coordinate **, Symbol *, Symbol *); |
extern void stabfend(Symbol, int); |
extern void stabinit(char *, int, char *[]); |
extern void stabline(Coordinate *); |
extern void stabsym(Symbol); |
extern void stabtype(Symbol); |
|
static void asgncode(Type, int); |
static void dbxout(Type); |
static int dbxtype(Type); |
static int emittype(Type, int, int); |
|
/* asgncode - assign type code to ty */ |
static void asgncode(Type ty, int lev) { |
if (ty->x.marked || ty->x.typeno) |
return; |
ty->x.marked = 1; |
switch (ty->op) { |
case VOLATILE: case CONST: case VOLATILE+CONST: |
asgncode(ty->type, lev); |
ty->x.typeno = ty->type->x.typeno; |
break; |
case POINTER: case FUNCTION: case ARRAY: |
asgncode(ty->type, lev + 1); |
/* fall thru */ |
case VOID: case INT: case UNSIGNED: case FLOAT: |
break; |
case STRUCT: case UNION: { |
Field p; |
for (p = fieldlist(ty); p; p = p->link) |
asgncode(p->type, lev + 1); |
/* fall thru */ |
case ENUM: |
if (ty->x.typeno == 0) |
ty->x.typeno = ++ntypes; |
if (lev > 0 && (*ty->u.sym->name < '0' || *ty->u.sym->name > '9')) |
dbxout(ty); |
break; |
} |
default: |
assert(0); |
} |
} |
|
/* dbxout - output .stabs entry for type ty */ |
static void dbxout(Type ty) { |
ty = unqual(ty); |
if (!ty->x.printed) { |
int col = 0; |
print(".stabs \""), col += 8; |
if (ty->u.sym && !(isfunc(ty) || isarray(ty) || isptr(ty))) |
print("%s", ty->u.sym->name), col += strlen(ty->u.sym->name); |
print(":%c", isstruct(ty) || isenum(ty) ? 'T' : 't'), col += 2; |
emittype(ty, 0, col); |
print("\",%d,0,0,0\n", N_LSYM); |
} |
} |
|
/* dbxtype - emit a stabs entry for type ty, return type code */ |
static int dbxtype(Type ty) { |
asgncode(ty, 0); |
dbxout(ty); |
return ty->x.typeno; |
} |
|
/* |
* emittype - emit ty's type number, emitting its definition if necessary. |
* Returns the output column number after emission; col is the approximate |
* output column before emission and is used to emit continuation lines for long |
* struct, union, and enum types. Continuations are not emitted for other types, |
* even if the definition is long. lev is the depth of calls to emittype. |
*/ |
static int emittype(Type ty, int lev, int col) { |
int tc = ty->x.typeno; |
|
if (isconst(ty) || isvolatile(ty)) { |
col = emittype(ty->type, lev, col); |
ty->x.typeno = ty->type->x.typeno; |
ty->x.printed = 1; |
return col; |
} |
if (tc == 0) { |
ty->x.typeno = tc = ++ntypes; |
/* fprint(2,"`%t'=%d\n", ty, tc); */ |
} |
print("%d", tc), col += 3; |
if (ty->x.printed) |
return col; |
ty->x.printed = 1; |
switch (ty->op) { |
case VOID: /* void is defined as itself */ |
print("=%d", tc), col += 1+3; |
break; |
case INT: |
if (ty == chartype) /* plain char is a subrange of itself */ |
print("=r%d;%d;%d;", tc, ty->u.sym->u.limits.min.i, ty->u.sym->u.limits.max.i), |
col += 2+3+2*2.408*ty->size+2; |
else /* other signed ints are subranges of int */ |
print("=r1;%D;%D;", ty->u.sym->u.limits.min.i, ty->u.sym->u.limits.max.i), |
col += 4+2*2.408*ty->size+2; |
break; |
case UNSIGNED: |
if (ty == chartype) /* plain char is a subrange of itself */ |
print("=r%d;0;%u;", tc, ty->u.sym->u.limits.max.i), |
col += 2+3+2+2.408*ty->size+1; |
else /* other signed ints are subranges of int */ |
print("=r1;0;%U;", ty->u.sym->u.limits.max.i), |
col += 4+2.408*ty->size+1; |
break; |
case FLOAT: /* float, double, long double get sizes, not ranges */ |
print("=r1;%d;0;", ty->size), col += 4+1+3; |
break; |
case POINTER: |
print("=*"), col += 2; |
col = emittype(ty->type, lev + 1, col); |
break; |
case FUNCTION: |
print("=f"), col += 2; |
col = emittype(ty->type, lev + 1, col); |
break; |
case ARRAY: /* array includes subscript as an int range */ |
if (ty->size && ty->type->size) |
print("=ar1;0;%d;", ty->size/ty->type->size - 1), col += 7+3+1; |
else |
print("=ar1;0;-1;"), col += 10; |
col = emittype(ty->type, lev + 1, col); |
break; |
case STRUCT: case UNION: { |
Field p; |
if (!ty->u.sym->defined) { |
print("=x%c%s:", ty->op == STRUCT ? 's' : 'u', ty->u.sym->name); |
col += 2+1+strlen(ty->u.sym->name)+1; |
break; |
} |
if (lev > 0 && (*ty->u.sym->name < '0' || *ty->u.sym->name > '9')) { |
ty->x.printed = 0; |
break; |
} |
print("=%c%d", ty->op == STRUCT ? 's' : 'u', ty->size), col += 1+1+3; |
for (p = fieldlist(ty); p; p = p->link) { |
if (p->name) |
print("%s:", p->name), col += strlen(p->name)+1; |
else |
print(":"), col += 1; |
col = emittype(p->type, lev + 1, col); |
if (p->lsb) |
print(",%d,%d;", 8*p->offset + |
(IR->little_endian ? fieldright(p) : fieldleft(p)), |
fieldsize(p)); |
else |
print(",%d,%d;", 8*p->offset, 8*p->type->size); |
col += 1+3+1+3+1; /* accounts for ,%d,%d; */ |
if (col >= 80 && p->link) { |
print("\\\\\",%d,0,0,0\n.stabs \"", N_LSYM); |
col = 8; |
} |
} |
print(";"), col += 1; |
break; |
} |
case ENUM: { |
Symbol *p; |
if (lev > 0 && (*ty->u.sym->name < '0' || *ty->u.sym->name > '9')) { |
ty->x.printed = 0; |
break; |
} |
print("=e"), col += 2; |
for (p = ty->u.sym->u.idlist; *p; p++) { |
print("%s:%d,", (*p)->name, (*p)->u.value), col += strlen((*p)->name)+3; |
if (col >= 80 && p[1]) { |
print("\\\\\",%d,0,0,0\n.stabs \"", N_LSYM); |
col = 8; |
} |
} |
print(";"), col += 1; |
break; |
} |
default: |
assert(0); |
} |
return col; |
} |
|
/* stabblock - output a stab entry for '{' or '}' at level lev */ |
void stabblock(int brace, int lev, Symbol *p) { |
if (brace == '{') |
while (*p) |
stabsym(*p++); |
if (IR == &sparcIR) |
print(".stabd 0x%x,0,%d\n", brace == '{' ? N_LBRAC : N_RBRAC, lev); |
else { |
int lab = genlabel(1); |
print(".stabn 0x%x,0,%d,%s%d-%s\n", brace == '{' ? N_LBRAC : N_RBRAC, lev, |
stabprefix, lab, cfunc->x.name); |
print("%s%d:\n", stabprefix, lab); |
} |
} |
|
/* stabinit - initialize stab output */ |
void stabinit(char *file, int argc, char *argv[]) { |
typedef void (*Closure)(Symbol, void *); |
|
print(".stabs \"lcc4_compiled.\",0x%x,0,0,0\n", N_OPT); |
if (file && *file) { |
print(".stabs \"%s\",0x%x,0,3,%stext0\n", file, N_SO, stabprefix); |
(*IR->segment)(CODE); |
print("%stext0:\n", stabprefix, N_SO); |
currentfile = file; |
} |
dbxtype(inttype); |
dbxtype(chartype); |
dbxtype(doubletype); |
dbxtype(floattype); |
dbxtype(longdouble); |
dbxtype(longtype); |
dbxtype(longlong); |
dbxtype(shorttype); |
dbxtype(signedchar); |
dbxtype(unsignedchar); |
dbxtype(unsignedlong); |
dbxtype(unsignedlonglong); |
dbxtype(unsignedshort); |
dbxtype(unsignedtype); |
dbxtype(voidtype); |
foreach(types, GLOBAL, (Closure)stabtype, NULL); |
} |
|
/* stabline - emit stab entry for source coordinate *cp */ |
void stabline(Coordinate *cp) { |
if (cp->file && cp->file != currentfile) { |
int lab = genlabel(1); |
print(".stabs \"%s\",0x%x,0,0,%s%d\n", cp->file, N_SOL, stabprefix, lab); |
print("%s%d:\n", stabprefix, lab); |
currentfile = cp->file; |
} |
if (IR == &sparcIR) |
print(".stabd 0x%x,0,%d\n", N_SLINE, cp->y); |
else { |
int lab = genlabel(1); |
print(".stabn 0x%x,0,%d,%s%d-%s\n", N_SLINE, cp->y, |
stabprefix, lab, cfunc->x.name); |
print("%s%d:\n", stabprefix, lab); |
} |
} |
|
/* stabsym - output a stab entry for symbol p */ |
void stabsym(Symbol p) { |
int code, tc, sz = p->type->size; |
|
if (p->generated || p->computed) |
return; |
if (isfunc(p->type)) { |
print(".stabs \"%s:%c%d\",%d,0,0,%s\n", p->name, |
p->sclass == STATIC ? 'f' : 'F', dbxtype(freturn(p->type)), |
N_FUN, p->x.name); |
return; |
} |
if (!IR->wants_argb && p->scope == PARAM && p->structarg) { |
assert(isptr(p->type) && isstruct(p->type->type)); |
tc = dbxtype(p->type->type); |
sz = p->type->type->size; |
} else |
tc = dbxtype(p->type); |
if (p->sclass == AUTO && p->scope == GLOBAL || p->sclass == EXTERN) { |
print(".stabs \"%s:G", p->name); |
code = N_GSYM; |
} else if (p->sclass == STATIC) { |
print(".stabs \"%s:%c%d\",%d,0,0,%s\n", p->name, p->scope == GLOBAL ? 'S' : 'V', |
tc, p->u.seg == BSS ? N_LCSYM : N_STSYM, p->x.name); |
return; |
} else if (p->sclass == REGISTER) { |
if (p->x.regnode) { |
int r = p->x.regnode->number; |
if (p->x.regnode->set == FREG) |
r += 32; /* floating point */ |
print(".stabs \"%s:%c%d\",%d,0,", p->name, |
p->scope == PARAM ? 'P' : 'r', tc, N_RSYM); |
print("%d,%d\n", sz, r); |
} |
return; |
} else if (p->scope == PARAM) { |
print(".stabs \"%s:p", p->name); |
code = N_PSYM; |
} else if (p->scope >= LOCAL) { |
print(".stabs \"%s:", p->name); |
code = N_LSYM; |
} else |
assert(0); |
print("%d\",%d,0,0,%s\n", tc, code, |
p->scope >= PARAM && p->sclass != EXTERN ? p->x.name : "0"); |
} |
|
/* stabtype - output a stab entry for type *p */ |
void stabtype(Symbol p) { |
if (p->type) { |
if (p->sclass == 0) |
dbxtype(p->type); |
else if (p->sclass == TYPEDEF) |
print(".stabs \"%s:t%d\",%d,0,0,0\n", p->name, dbxtype(p->type), N_LSYM); |
} |
} |
|
/* stabend - finalize a function */ |
void stabfend(Symbol p, int lineno) {} |
|
/* stabend - finalize stab output */ |
void stabend(Coordinate *cp, Symbol p, Coordinate **cpp, Symbol *sp, Symbol *stab) { |
(*IR->segment)(CODE); |
print(".stabs \"\", %d, 0, 0,%setext\n", N_SO, stabprefix); |
print("%setext:\n", stabprefix); |
} |
/alloc.c
0,0 → 1,94
#include "c.h" |
struct block { |
struct block *next; |
char *limit; |
char *avail; |
}; |
union align { |
long l; |
char *p; |
double d; |
int (*f)(void); |
}; |
union header { |
struct block b; |
union align a; |
}; |
#ifdef PURIFY |
union header *arena[3]; |
|
void *allocate(unsigned long n, unsigned a) { |
union header *new = malloc(sizeof *new + n); |
|
assert(a < NELEMS(arena)); |
if (new == NULL) { |
error("insufficient memory\n"); |
exit(1); |
} |
new->b.next = (void *)arena[a]; |
arena[a] = new; |
return new + 1; |
} |
|
void deallocate(unsigned a) { |
union header *p, *q; |
|
assert(a < NELEMS(arena)); |
for (p = arena[a]; p; p = q) { |
q = (void *)p->b.next; |
free(p); |
} |
arena[a] = NULL; |
} |
|
void *newarray(unsigned long m, unsigned long n, unsigned a) { |
return allocate(m*n, a); |
} |
#else |
static struct block |
first[] = { { NULL }, { NULL }, { NULL } }, |
*arena[] = { &first[0], &first[1], &first[2] }; |
static struct block *freeblocks; |
|
void *allocate(unsigned long n, unsigned a) { |
struct block *ap; |
|
assert(a < NELEMS(arena)); |
assert(n > 0); |
ap = arena[a]; |
n = roundup(n, sizeof (union align)); |
while (n > ap->limit - ap->avail) { |
if ((ap->next = freeblocks) != NULL) { |
freeblocks = freeblocks->next; |
ap = ap->next; |
} else |
{ |
unsigned m = sizeof (union header) + n + roundup(10*1024, sizeof (union align)); |
ap->next = malloc(m); |
ap = ap->next; |
if (ap == NULL) { |
error("insufficient memory\n"); |
exit(1); |
} |
ap->limit = (char *)ap + m; |
} |
ap->avail = (char *)((union header *)ap + 1); |
ap->next = NULL; |
arena[a] = ap; |
|
} |
ap->avail += n; |
return ap->avail - n; |
} |
|
void *newarray(unsigned long m, unsigned long n, unsigned a) { |
return allocate(m*n, a); |
} |
void deallocate(unsigned a) { |
assert(a < NELEMS(arena)); |
arena[a]->next = freeblocks; |
freeblocks = first[a].next; |
first[a].next = NULL; |
arena[a] = &first[a]; |
} |
#endif |
/run.sh
0,0 → 1,52
#!/bin/sh |
# $Id: run.sh,v 1.11 1997/07/03 00:15:10 drh Exp $ |
# run .../target/os/tst/foo.s [ remotehost ] |
|
# set -x |
target=`echo $1 | awk -F/ '{ print $(NF-3) }'` |
os=`echo $1 | awk -F/ '{ print $(NF-2) }'` |
dir=$target/$os |
|
case "$1" in |
*symbolic/irix*) idir=include/mips/irix; remotehost=noexecute ;; |
*symbolic/osf*) idir=include/alpha/osf; remotehost=noexecute ;; |
*) idir=include/$dir; remotehost=${2-$REMOTEHOST} ;; |
esac |
|
if [ ! -d "$target/$os" -o ! -d "$idir" ]; then |
echo 2>&1 $0: unknown combination '"'$target/$os'"' |
exit 1 |
fi |
|
C=`basename $1 .s` |
BUILDDIR=${BUILDDIR-.} LCC="${LCC-${BUILDDIR}/lcc} -Wo-lccdir=$BUILDDIR" |
TSTDIR=${TSTDIR-${BUILDDIR}/$dir/tst} |
if [ ! -d $TSTDIR ]; then mkdir -p $TSTDIR; fi |
|
echo ${BUILDDIR}/rcc$EXE -target=$target/$os $1: 1>&2 |
$LCC -S -I$idir -Ualpha -Usun -Uvax -Umips -Ux86 \ |
-Wf-errout=$TSTDIR/$C.2 -D$target -Wf-g0 \ |
-Wf-target=$target/$os -o $1 tst/$C.c |
if [ $? != 0 ]; then remotehost=noexecute; fi |
if [ -r $dir/tst/$C.2bk ]; then |
diff $dir/tst/$C.2bk $TSTDIR/$C.2 |
fi |
if [ -r $dir/tst/$C.sbk ]; then |
if diff $dir/tst/$C.sbk $TSTDIR/$C.s; then exit 0; fi |
fi |
|
case "$remotehost" in |
noexecute) exit 0 ;; |
""|"-") $LCC -o $TSTDIR/$C$EXE $1; $TSTDIR/$C$EXE <tst/$C.0 >$TSTDIR/$C.1 ;; |
*) rcp $1 $remotehost: |
if expr "$remotehost" : '.*@' >/dev/null ; then |
remotehost="`expr $remotehost : '.*@\(.*\)'` -l `expr $remotehost : '\(.*\)@'`" |
fi |
rsh $remotehost "cc -o $C$EXE $C.s -lm;./$C$EXE;rm -f $C$EXE $C.[so]" <tst/$C.0 >$TSTDIR/$C.1 |
;; |
esac |
if [ -r $dir/tst/$C.1bk ]; then |
diff $dir/tst/$C.1bk $TSTDIR/$C.1 |
exit $? |
fi |
exit 0 |