| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620 |
- #include <assert.h>
- #include <inttypes.h>
- #include <limits.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #define MAKESURE(what, x) typedef char make_sure_##what[(x)?1:-1]
- #define die(...) die_(__FILE__, __VA_ARGS__)
- typedef unsigned char uchar;
- typedef unsigned int uint;
- typedef unsigned long ulong;
- typedef unsigned long long bits;
- typedef struct BSet BSet;
- typedef struct Ref Ref;
- typedef struct Op Op;
- typedef struct Ins Ins;
- typedef struct Phi Phi;
- typedef struct Blk Blk;
- typedef struct Use Use;
- typedef struct Sym Sym;
- typedef struct Num Num;
- typedef struct Alias Alias;
- typedef struct Tmp Tmp;
- typedef struct Con Con;
- typedef struct Addr Mem;
- typedef struct Fn Fn;
- typedef struct Typ Typ;
- typedef struct Field Field;
- typedef struct Dat Dat;
- typedef struct Lnk Lnk;
- typedef struct Target Target;
- enum {
- NString = 80,
- NIns = 1 << 20,
- NAlign = 3,
- NField = 32,
- NBit = CHAR_BIT * sizeof(bits),
- };
- struct Target {
- char name[16];
- char apple;
- int gpr0; /* first general purpose reg */
- int ngpr;
- int fpr0; /* first floating point reg */
- int nfpr;
- bits rglob; /* globally live regs (e.g., sp, fp) */
- int nrglob;
- int *rsave; /* caller-save */
- int nrsave[2];
- bits (*retregs)(Ref, int[2]);
- bits (*argregs)(Ref, int[2]);
- int (*memargs)(int);
- void (*abi0)(Fn *);
- void (*abi1)(Fn *);
- void (*isel)(Fn *);
- void (*emitfn)(Fn *, FILE *);
- void (*emitfin)(FILE *);
- char asloc[4];
- char assym[4];
- };
- #define BIT(n) ((bits)1 << (n))
- enum {
- RXX = 0,
- Tmp0 = NBit, /* first non-reg temporary */
- };
- struct BSet {
- uint nt;
- bits *t;
- };
- struct Ref {
- uint type:3;
- uint val:29;
- };
- enum {
- RTmp,
- RCon,
- RInt,
- RType, /* last kind to come out of the parser */
- RSlot,
- RCall,
- RMem,
- };
- #define R (Ref){RTmp, 0}
- #define UNDEF (Ref){RCon, 0} /* represents uninitialized data */
- #define CON_Z (Ref){RCon, 1}
- #define TMP(x) (Ref){RTmp, x}
- #define CON(x) (Ref){RCon, x}
- #define SLOT(x) (Ref){RSlot, (x)&0x1fffffff}
- #define TYPE(x) (Ref){RType, x}
- #define CALL(x) (Ref){RCall, x}
- #define MEM(x) (Ref){RMem, x}
- #define INT(x) (Ref){RInt, (x)&0x1fffffff}
- static inline int req(Ref a, Ref b)
- {
- return a.type == b.type && a.val == b.val;
- }
- static inline int rtype(Ref r)
- {
- if (req(r, R))
- return -1;
- return r.type;
- }
- static inline int rsval(Ref r)
- {
- return ((int)r.val ^ 0x10000000) - 0x10000000;
- }
- enum CmpI {
- Cieq,
- Cine,
- Cisge,
- Cisgt,
- Cisle,
- Cislt,
- Ciuge,
- Ciugt,
- Ciule,
- Ciult,
- NCmpI,
- };
- enum CmpF {
- Cfeq,
- Cfge,
- Cfgt,
- Cfle,
- Cflt,
- Cfne,
- Cfo,
- Cfuo,
- NCmpF,
- NCmp = NCmpI + NCmpF,
- };
- enum O {
- Oxxx,
- #define O(op, x, y) O##op,
- #include "ops.h"
- NOp,
- };
- enum J {
- Jxxx,
- #define JMPS(X) \
- X(retw) X(retl) X(rets) X(retd) \
- X(retsb) X(retub) X(retsh) X(retuh) \
- X(retc) X(ret0) X(jmp) X(jnz) \
- X(jfieq) X(jfine) X(jfisge) X(jfisgt) \
- X(jfisle) X(jfislt) X(jfiuge) X(jfiugt) \
- X(jfiule) X(jfiult) X(jffeq) X(jffge) \
- X(jffgt) X(jffle) X(jfflt) X(jffne) \
- X(jffo) X(jffuo) X(hlt)
- #define X(j) J##j,
- JMPS(X)
- #undef X
- NJmp
- };
- enum {
- Ocmpw = Oceqw,
- Ocmpw1 = Ocultw,
- Ocmpl = Oceql,
- Ocmpl1 = Ocultl,
- Ocmps = Oceqs,
- Ocmps1 = Ocuos,
- Ocmpd = Oceqd,
- Ocmpd1 = Ocuod,
- Oalloc = Oalloc4,
- Oalloc1 = Oalloc16,
- Oflag = Oflagieq,
- Oflag1 = Oflagfuo,
- NPubOp = Onop,
- Jjf = Jjfieq,
- Jjf1 = Jjffuo,
- };
- #define INRANGE(x, l, u) ((unsigned)(x) - l <= u - l) /* linear in x */
- #define isstore(o) INRANGE(o, Ostoreb, Ostored)
- #define isload(o) INRANGE(o, Oloadsb, Oload)
- #define isalloc(o) INRANGE(o, Oalloc4, Oalloc16)
- #define isext(o) INRANGE(o, Oextsb, Oextuw)
- #define ispar(o) INRANGE(o, Opar, Opare)
- #define isarg(o) INRANGE(o, Oarg, Oargv)
- #define isret(j) INRANGE(j, Jretw, Jret0)
- #define isparbh(o) INRANGE(o, Oparsb, Oparuh)
- #define isargbh(o) INRANGE(o, Oargsb, Oarguh)
- #define isretbh(j) INRANGE(j, Jretsb, Jretuh)
- enum {
- Kx = -1, /* "top" class (see usecheck() and clsmerge()) */
- Kw,
- Kl,
- Ks,
- Kd
- };
- #define KWIDE(k) ((k)&1)
- #define KBASE(k) ((k)>>1)
- struct Op {
- char *name;
- short argcls[2][4];
- uint canfold:1;
- uint hasid:1; /* op identity value? */
- uint idval:1; /* identity value 0/1 */
- uint commutes:1; /* commutative op? */
- uint assoc:1; /* associative op? */
- uint idemp:1; /* idempotent op? */
- uint cmpeqwl:1; /* Kl/Kw cmp eq/ne? */
- uint cmplgtewl:1; /* Kl/Kw cmp lt/gt/le/ge? */
- uint eqval:1; /* 1 for eq; 0 for ne */
- uint pinned:1; /* GCM pinned op? */
- };
- struct Ins {
- uint op:30;
- uint cls:2;
- Ref to;
- Ref arg[2];
- };
- struct Phi {
- Ref to;
- Ref *arg;
- Blk **blk;
- uint narg;
- short cls;
- uint visit:1;
- Phi *link;
- };
- struct Blk {
- Phi *phi;
- Ins *ins;
- uint nins;
- struct {
- short type;
- Ref arg;
- } jmp;
- Blk *s1;
- Blk *s2;
- Blk *link;
- uint id;
- uint visit;
- Blk *idom;
- Blk *dom, *dlink;
- Blk **fron;
- uint nfron;
- int depth;
- Blk **pred;
- uint npred;
- BSet in[1], out[1], gen[1];
- int nlive[2];
- int loop;
- char name[NString];
- };
- struct Use {
- enum {
- UXXX,
- UPhi,
- UIns,
- UJmp,
- } type;
- uint bid;
- union {
- Ins *ins;
- Phi *phi;
- } u;
- };
- struct Sym {
- enum {
- SGlo,
- SThr,
- } type;
- uint32_t id;
- };
- struct Num {
- uchar n;
- uchar nl, nr;
- Ref l, r;
- };
- enum {
- NoAlias,
- MayAlias,
- MustAlias
- };
- struct Alias {
- enum {
- ABot = 0,
- ALoc = 1, /* stack local */
- ACon = 2,
- AEsc = 3, /* stack escaping */
- ASym = 4,
- AUnk = 6,
- #define astack(t) ((t) & 1)
- } type;
- int base;
- int64_t offset;
- union {
- Sym sym;
- struct {
- int sz; /* -1 if > NBit */
- bits m;
- } loc;
- } u;
- Alias *slot;
- };
- struct Tmp {
- char name[NString];
- Ins *def;
- Use *use;
- uint ndef, nuse;
- uint bid; /* id of a defining block */
- uint cost;
- int slot; /* -1 for unset */
- short cls;
- struct {
- int r; /* register or -1 */
- int w; /* weight */
- bits m; /* avoid these registers */
- } hint;
- int phi;
- Alias alias;
- enum {
- WFull,
- Wsb, /* must match Oload/Oext order */
- Wub,
- Wsh,
- Wuh,
- Wsw,
- Wuw
- } width;
- int visit;
- uint gcmbid;
- };
- struct Con {
- enum {
- CUndef,
- CBits,
- CAddr,
- } type;
- Sym sym;
- union {
- int64_t i;
- double d;
- float s;
- } bits;
- char flt; /* 1 to print as s, 2 to print as d */
- };
- typedef struct Addr Addr;
- struct Addr { /* amd64 addressing */
- Con offset;
- Ref base;
- Ref index;
- int scale;
- };
- struct Lnk {
- char export;
- char thread;
- char common;
- char align;
- char *sec;
- char *secf;
- };
- struct Fn {
- Blk *start;
- Tmp *tmp;
- Con *con;
- Mem *mem;
- int ntmp;
- int ncon;
- int nmem;
- uint nblk;
- int retty; /* index in typ[], -1 if no aggregate return */
- Ref retr;
- Blk **rpo;
- bits reg;
- int slot;
- int salign;
- char vararg;
- char dynalloc;
- char leaf;
- char name[NString];
- Lnk lnk;
- };
- struct Typ {
- char name[NString];
- char isdark;
- char isunion;
- int align;
- uint64_t size;
- uint nunion;
- struct Field {
- enum {
- FEnd,
- Fb,
- Fh,
- Fw,
- Fl,
- Fs,
- Fd,
- FPad,
- FTyp,
- } type;
- uint len; /* or index in typ[] for FTyp */
- } (*fields)[NField+1];
- };
- struct Dat {
- enum {
- DStart,
- DEnd,
- DB,
- DH,
- DW,
- DL,
- DZ
- } type;
- char *name;
- Lnk *lnk;
- union {
- int64_t num;
- double fltd;
- float flts;
- char *str;
- struct {
- char *name;
- int64_t off;
- } ref;
- } u;
- char isref;
- char isstr;
- };
- /* main.c */
- extern Target T;
- extern char debug['Z'+1];
- /* util.c */
- typedef enum {
- PHeap, /* free() necessary */
- PFn, /* discarded after processing the function */
- } Pool;
- extern Typ *typ;
- extern Ins insb[NIns], *curi;
- uint32_t hash(char *);
- void die_(char *, char *, ...) __attribute__((noreturn));
- void *emalloc(size_t);
- void *alloc(size_t);
- void freeall(void);
- void *vnew(ulong, size_t, Pool);
- void vfree(void *);
- void vgrow(void *, ulong);
- void addins(Ins **, uint *, Ins *);
- void addbins(Blk *, Ins **, uint *);
- void strf(char[NString], char *, ...);
- uint32_t intern(char *);
- char *str(uint32_t);
- int argcls(Ins *, int);
- int isreg(Ref);
- int iscmp(int, int *, int *);
- void igroup(Blk *, Ins *, Ins **, Ins **);
- void emit(int, int, Ref, Ref, Ref);
- void emiti(Ins);
- void idup(Blk *, Ins *, ulong);
- Ins *icpy(Ins *, Ins *, ulong);
- int cmpop(int);
- int cmpneg(int);
- int cmpwlneg(int);
- int clsmerge(short *, short);
- int phicls(int, Tmp *);
- uint phiargn(Phi *, Blk *);
- Ref phiarg(Phi *, Blk *);
- Ref newtmp(char *, int, Fn *);
- void chuse(Ref, int, Fn *);
- int symeq(Sym, Sym);
- Ref newcon(Con *, Fn *);
- Ref getcon(int64_t, Fn *);
- int addcon(Con *, Con *, int);
- int isconbits(Fn *fn, Ref r, int64_t *v);
- void salloc(Ref, Ref, Fn *);
- void dumpts(BSet *, Tmp *, FILE *);
- void runmatch(uchar *, Num *, Ref, Ref *);
- void bsinit(BSet *, uint);
- void bszero(BSet *);
- uint bscount(BSet *);
- void bsset(BSet *, uint);
- void bsclr(BSet *, uint);
- void bscopy(BSet *, BSet *);
- void bsunion(BSet *, BSet *);
- void bsinter(BSet *, BSet *);
- void bsdiff(BSet *, BSet *);
- int bsequal(BSet *, BSet *);
- int bsiter(BSet *, int *);
- static inline int
- bshas(BSet *bs, uint elt)
- {
- assert(elt < bs->nt * NBit);
- return (bs->t[elt/NBit] & BIT(elt%NBit)) != 0;
- }
- /* parse.c */
- extern Op optab[NOp];
- void parse(FILE *, char *, void (char *), void (Dat *), void (Fn *));
- void printfn(Fn *, FILE *);
- void printref(Ref, Fn *, FILE *);
- void err(char *, ...) __attribute__((noreturn));
- /* abi.c */
- void elimsb(Fn *);
- /* cfg.c */
- Blk *newblk(void);
- void fillpreds(Fn *);
- void fillcfg(Fn *);
- void filldom(Fn *);
- int sdom(Blk *, Blk *);
- int dom(Blk *, Blk *);
- void fillfron(Fn *);
- void loopiter(Fn *, void (*)(Blk *, Blk *));
- void filldepth(Fn *);
- Blk *lca(Blk *, Blk *);
- void fillloop(Fn *);
- void simpljmp(Fn *);
- int reaches(Fn *, Blk *, Blk *);
- int reachesnotvia(Fn *, Blk *, Blk *, Blk *);
- /* mem.c */
- void promote(Fn *);
- void coalesce(Fn *);
- /* alias.c */
- void fillalias(Fn *);
- void getalias(Alias *, Ref, Fn *);
- int alias(Ref, int, int, Ref, int, int *, Fn *);
- int escapes(Ref, Fn *);
- /* load.c */
- int loadsz(Ins *);
- int storesz(Ins *);
- void loadopt(Fn *);
- /* ssa.c */
- void adduse(Tmp *, int, Blk *, ...);
- void filluse(Fn *);
- void ssa(Fn *);
- void ssacheck(Fn *);
- /* copy.c */
- void narrowpars(Fn *fn);
- Ref copyref(Fn *, Blk *, Ins *);
- Ref phicopyref(Fn *, Blk *, Phi *);
- /* fold.c */
- int foldint(Con *, int, int, Con *, Con *);
- Ref foldref(Fn *, Ins *);
- /* gvn.c */
- extern Ref con01[2]; /* 0 and 1 */
- int zeroval(Fn *, Blk *, Ref, int, int *);
- void gvn(Fn *);
- /* gcm.c */
- int pinned(Ins *);
- void gcm(Fn *);
- /* simpl.c */
- void simpl(Fn *);
- /* live.c */
- void liveon(BSet *, Blk *, Blk *);
- void filllive(Fn *);
- /* spill.c */
- void fillcost(Fn *);
- void spill(Fn *);
- /* rega.c */
- void rega(Fn *);
- /* emit.c */
- void emitfnlnk(char *, Lnk *, FILE *);
- void emitdat(Dat *, FILE *);
- void emitdbgfile(char *, FILE *);
- void emitdbgloc(uint, uint, FILE *);
- int stashbits(bits, int);
- void elf_emitfnfin(char *, FILE *);
- void elf_emitfin(FILE *);
- void macho_emitfin(FILE *);
|