aboutsummaryrefslogtreecommitdiffhomepage
path: root/ir.h
blob: 6507fe0977e1cfa68ac96d0d77486b0be74ff3df (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
#include "common.h"

enum irclass {
   KXXX,
   KI4, KI8, KPTR,
   KF4, KF8,
};

#define kisint(k) in_range((k), KI4, KPTR)
#define kisflt(k) in_range((k), KF4, KF8)

union irtype {
   struct { ushort _     : 1, cls : 15; };
   struct { ushort isagg : 1, dat : 15; };
   ushort bits;
};

struct irdat {
   uchar align : 6, mut : 1, globl : 1;
   uint siz;
   union {
      vec_of(uchar) dat;
      uchar sdat[8];
   };
   const char *name;
   struct symref {
      struct symref *next;
      const char *sym;
      uint off;
      vlong addend;
   } *syms;
};

struct xcon {
   bool issym, isdat, deref;
   uchar cls;
   union {
      const char *sym;
      int dat;
      vlong i;
      double f;
   };
};

struct abiarg {
   union irtype ty;
   union {
      short reg; /* >= 0 */
      short stk; /* < 0 */
   };
};

struct call {
   union irtype ret;
   ushort narg;
   short vararg; /* first variadic arg or -1 */
   struct abiarg *abiarg;
   struct abiarg abiret[2];
};

enum refkind {
   RXXX,  /* used for empty ref (zeros), undef, and the special args of call,phi,etc */
   RTMP,  /* reference to another instruction's result */
   RREG,  /* machine register */
   RICON, /* small integer constants */
   RXCON, /* other constants (incl. external symbols) */
   RADDR, /* target-specific addressing mode */
   RTYPE, /* irtype */
};

union ref {
   struct { unsigned t : 3; signed i : 29; };
   uint bits;
};

struct addr {
   union ref base, index;
   int shift, disp;
};

#define insrescls(ins) (oiscmp((ins).op) ? KI4 : (ins).cls)
#define NOREF ((union ref) {0})
#define UNDREF ((union ref) {{ 0, -1 }})
#define ZEROREF ((union ref) {{ RICON, 0 }})
#define mkref(t, x) ((union ref) {{ (t), (x) }})
#define mktyperef(t) ((union ref) {{ RTYPE, (t).bits }})
#define ref2type(r) ((union irtype) {.bits = (r).i})

enum op {
   Oxxx,
#define _(o,...) O##o,
#include "op.def"
#undef _
};

#define oiscmp(o) in_range(o, Oequ, Ougte)
#define oisalloca(o) in_range(o, Oalloca1, Oalloca16)
#define oisstore(o) in_range(o, Ostore1, Ostore8)
#define oisload(o) in_range(o, Oloads1, Oloadf8)
extern const char *opnames[];

enum intrin {
   INxxx,
#define _(b,...) IN##b,
#include "intrin.def"
#undef _
};

struct instr {
   uchar op,
         cls; /* operation data class; also result class except for cmp ops (always i4) */
   uchar skip : 1, /* ignore during codegen: forms part of one machine instruction */
         keep : 1; /* for codegen, keep instr even if result seems unused */
   uchar inplace : 1; /* set (by isel) for instructions which modify its first arg in place */
   uchar reg; /* 0 -> no reg; else reg + 1 */
   union ref l, r;
};

enum jumpkind { JXXX, Jb, Jret, };

struct block {
   int id;
   int npred;
   int visit;
   union {
      struct block *_pred0;
      struct block **_pred;
   };
   struct block *lprev, *lnext;
   struct block *s1, *s2;
   vec_of(ushort) phi;
   vec_of(ushort) ins;
   struct { uchar t; union ref arg[2]; } jmp;
};

#define blkpred(blk, i) 0[(blk)->npred < 2 ? &(blk)->_pred0 : &(blk)->_pred[i]]

enum { USERJUMP = 0xFFFF };
struct use { struct block *blk; ushort u; };

enum { MAXREGS = 64 };

struct function {
   struct arena *arena;
   const char *name;
   struct block *entry, *curblk;
   struct use *use;
   short *nuse;
   union type fnty, retty;
   struct abiarg *abiarg, abiret[2];
   uint nblk;
   int stksiz;
   ushort nabiarg, nabiret;
   bool globl;
   bool isleaf;
   regset regusage;
};

enum objkind { OBJELF };
enum mcisa { ISamd64 };

struct mctarg {
   short gpr0, /* first gpr */
         ngpr, /* gpr count */
         bpr,  /* frame/base pointer reg */
         fpr0, /* first fpr */
         nfpr; /* fpr count */
   regset rcallee, /* callee-saved */
          rglob;   /* globally live (never used for regalloc) */
   const char (*rnames)[6];
   enum objkind objkind;
   enum mcisa isa;
   /* abiret: lower return type:
    *  scalar/small struct -> returns number of regs (1..2),
    *                         r & cls filled with reg and irclass of each scalar return
    *  big struct -> returns 0, is passed via hidden pointer argument,
    *                r[0] contains register for returning said pointer or -1,
    *                r[1] contains register for hidden pointer argument,
    *                     *ni is set to 1 if said register is the first ABI integer argument
    */
   int (*abiret)(short r[2], uchar cls[2], int *ni, union irtype);
   /* abiarg: lower argument type:
    *  scalar/small struct -> returns number of regs (1..2),
    *                         r & cls filled with reg and irclass of each scalar arg
    *                         if reg == -1 -> stack
    *  big struct -> returns 0,
    *                if passed in stack   cls[0] == 0, r[0] == negative SP offset
    *                if passed by pointer cls[0] == KPTR, r[0] contains integer register
    *                                                     or negative SP offset if stack
    */
   int (*abiarg)(short r[2], uchar cls[2], int *ni, int *nf, int *ns, union irtype);

   void (*isel)(struct function *);
   void (*emit)(struct function *);
};

enum { MAXINSTR = 1<<14 };

extern uchar type2cls[];
extern uchar cls2siz[];
extern const uchar siz2intcls[];
extern struct instr instrtab[];
extern struct use *instruse[];
extern short instrnuse[];
extern struct xcon conht[];
extern struct calltab {vec_of(struct call);} calltab;
extern struct phitab {vec_of(union ref *);} phitab;
extern struct dattab {vec_of(struct irdat);} dattab;
extern struct addr addrht[];
extern int visitmark;
#define mkinstr(O, C, ...) ((struct instr) { .op = (O), .cls = (C), .reg=0, __VA_ARGS__ })
#define mkarginstr(ty, x) mkinstr(Oarg, 0, mktyperef(ty), (x))
void irinit(struct function *);
void irfini(struct function *);
#define cls2type(k) ((union irtype){.cls=(k)})
union irtype mkirtype(union type);
union ref mkintcon(enum irclass, vlong);
union ref mkfltcon(enum irclass, double);
#define iscon(r) in_range((r).t, RICON, RXCON)
#define concls(r) ((r).t == RICON ? KI4 : conht[(r).i].cls)
#define isintcon(r) (iscon(r) && kisint(concls(r)))
#define isfltcon(r) ((r).t == RXCON && kisflt(conht[(r).i].cls))
#define isnumcon(r) ((r).t == RICON || ((r).t == RXCON && conht[(r).i].cls))
#define intconval(r) ((r).t == RICON ? (r).i : conht[(r).i].i)
#define fltconval(r) (conht[(r).i].f)
union ref mksymref(const char *);
union ref mkdatref(const char *name, uint siz, uint align, const void *, uint n, bool deref);
const char *xcon2sym(int ref);
struct instr mkalloca(uint siz, uint align);
void conputdat(struct irdat *, uint off, enum typetag t, const void *dat);
union ref mkcallarg(union irtype ret, uint narg, int vararg);
#define mkintrin(B, C, N) mkinstr(Ointrin, C, {.t=RICON,B}, mkcallarg((union irtype){{0}},N,-1))
union ref mkaddr(struct addr);
void addpred(struct block *blk, struct block *p);

struct block *insertblk(struct function *, struct block *pred, struct block *subst);
void adduse(struct block *ublk, int ui, union ref r);
union ref insertinstr(struct block *, int idx, struct instr);
union ref insertphi(struct block *, enum irclass cls);
void replcuses(union ref from, union ref to);
void deluses(int ins);
void delinstr(struct block *, int idx);
void delphi(struct block *, int idx);
void fillblkids(struct function *);
#define startbbvisit() (void)(++visitmark)
#define wasvisited(blk) ((blk)->visit == visitmark)
#define markvisited(blk) ((blk)->visit = visitmark)

/* IR builder functions */
union ref addinstr(struct function *, struct instr);
union ref addphi(struct function *, enum irclass, union ref []);
struct block *newblk(struct function *);
void useblk(struct function *, struct block *);
void putbranch(struct function *, struct block *);
void putcondbranch(struct function *, union ref arg, struct block *t, struct block *f);
void putreturn(struct function *, union ref r0, union ref r1);

void irdump(struct function *);

void filluses(struct function *);
void copyopt(struct function *);

void abi0(struct function *);
void abi0_call(struct function *, struct instr *, struct block *blk, int *curi);
void mem2reg(struct function *);
void lowerintrin(struct function *);
void regalloc(struct function *);

/* vim:set ts=3 sw=3 expandtab: */