xref: /inferno-os/libinterp/comp-arm.c (revision d3641b487cf5cdc46e9b537d30eb37736e5c7b1a)
1 #include "lib9.h"
2 #include "isa.h"
3 #include "interp.h"
4 #include "raise.h"
5 
6 /*
7  * to do:
8  *	eliminate litpool?
9  *	eliminate long constants in comi/comd
10  *	enable and check inline FP code (not much point with fpemu)
11  */
12 
13 #define	RESCHED 1	/* check for interpreter reschedule */
14 #define	SOFTFP	1
15 
16 enum
17 {
18 	R0	= 0,
19 	R1	= 1,
20 	R2	= 2,
21 	R3	= 3,
22 	R4	= 4,
23 	R5	= 5,
24 	R6	= 6,
25 	R7	= 7,
26 	R8	= 8,
27 	R9	= 9,
28 	R10	= 10,
29 	R11	= 11,
30 	R12	= 12,		/* C's SB */
31 	R13	= 13,		/* C's SP */
32 	R14	= 14,		/* Link Register */
33 	R15	= 15,		/* PC */
34 
35 	RLINK	= 14,
36 
37 	RFP	= R9,		/* Frame Pointer */
38 	RMP	= R8,		/* Module Pointer */
39 	RTA	= R7,		/* Intermediate address for double indirect */
40 	RCON	= R6,		/* Constant builder */
41 	RREG	= R5,		/* Pointer to REG */
42 	RA3	= R4,		/* gpr 3 */
43 	RA2	= R3,		/* gpr 2 2+3 = L */
44 	RA1	= R2,		/* gpr 1 */
45 	RA0	= R1,		/* gpr 0 0+1 = L */
46 
47 
48 	FA2	= 2,		/* Floating */
49 	FA3	= 3,
50 	FA4	= 4,
51 	FA5	= 5,
52 
53 	EQ	= 0,
54 	NE	= 1,
55 	CS	= 2,
56 	CC	= 3,
57 	MI	= 4,
58 	PL	= 5,
59 	VS	= 6,
60 	VC	= 7,
61 	HI	= 8,
62 	LS	= 9,
63 	GE	= 10,
64 	LT	= 11,
65 	GT	= 12,
66 	LE	= 13,
67 	AL	= 14,
68 	NV	= 15,
69 
70 	HS	= CS,
71 	LO	= CC,
72 
73 	And	= 0,
74 	Eor	= 1,
75 	Sub	= 2,
76 	Rsb	= 3,
77 	Add	= 4,
78 	Adc	= 5,
79 	Sbc	= 6,
80 	Rsc	= 7,
81 	Tst	= 8,
82 	Teq	= 9,
83 	Cmp	= 10,
84 	Cmn	= 11,
85 	Orr	= 12,
86 	Mov	= 13,
87 	Bic	= 14,
88 	Mvn	= 15,
89 
90 	Adf	= 0,
91 	Muf	= 1,
92 	Suf	= 2,
93 	Rsf	= 3,
94 	Dvf	= 4,
95 	Rdf	= 5,
96 	Rmf	= 8,
97 
98 	Mvf	= 0,
99 	Mnf	= 1,
100 	Abs	= 2,
101 	Rnd	= 3,
102 
103 	Flt	= 0,
104 	Fix	= 1,
105 
106 	Cmf	= 4,
107 	Cnf	= 5,
108 
109 	Lea	= 100,		/* macro memory ops */
110 	Ldw,
111 	Ldb,
112 	Stw,
113 	Stb,
114 	Ldf,
115 	Stf,
116 	Ldh,
117 
118 	Blo	= 0,	/* offset of low order word in big */
119 	Bhi	= 4,	/* offset of high order word in big */
120 
121 	Lg2Rune	= 2,
122 
123 	NCON	= (0xFFC-8)/4,
124 
125 	SRCOP	= (1<<0),
126 	DSTOP	= (1<<1),
127 	WRTPC	= (1<<2),
128 	TCHECK	= (1<<3),
129 	NEWPC	= (1<<4),
130 	DBRAN	= (1<<5),
131 	THREOP	= (1<<6),
132 
133 	ANDAND	= 1,
134 	OROR	= 2,
135 	EQAND	= 3,
136 
137 	MacFRP	= 0,
138 	MacRET,
139 	MacCASE,
140 	MacCOLR,
141 	MacMCAL,
142 	MacFRAM,
143 	MacMFRA,
144 	MacRELQ,
145 	NMACRO
146 };
147 
148 #define BITS(B)				(1<<B)
149 #define IMM(O)				(O & ((1<<12)-1))
150 #define SBIT	(1<<20)
151 #define PBIT	(1<<24)
152 #define UPBIT	(1<<23)
153 
154 #define LDW(C, Rn, Rd, O)		*code++ = (C<<28)|(1<<26)|(1<<24)|(1<<23)|(1<<20)|\
155 					  (Rn<<16)|(Rd<<12)|IMM(O)
156 #define STW(C, Rn, Rd, O)		*code++ = (C<<28)|(1<<26)|(1<<24)|(1<<23)|\
157 					  (Rn<<16)|(Rd<<12)|IMM(O)
158 #define LDB(C, Rn, Rd, O)		*code++ = (C<<28)|(1<<26)|(1<<24)|(1<<23)|(1<<20)|(1<<22)|\
159 					  (Rn<<16)|(Rd<<12)|IMM(O)
160 #define STB(C, Rn, Rd, O)		*code++ = (C<<28)|(1<<26)|(1<<24)|(1<<23)|(1<<22)|\
161 					  (Rn<<16)|(Rd<<12)|IMM(O)
162 
163 #define LDxP(C, Rn, Rd, O, B)		*code++ = (C<<28)|(1<<26)|(B<<22)|(1<<23)|(1<<20)|\
164 					  (Rn<<16)|(Rd<<12)|IMM(O)
165 #define STxP(C, Rn, Rd, O, B)		*code++ = (C<<28)|(1<<26)|(B<<22)|(1<<23)|\
166 					  (Rn<<16)|(Rd<<12)|IMM(O)
167 #define LDRW(C, Rn, Rd, SH, R)		*code++ = (C<<28)|(3<<25)|(1<<24)|(1<<23)|(1<<20)|\
168 					  (Rn<<16)|(Rd<<12)|(SH<<4)|R
169 #define STRW(C, Rn, Rd, SH, R)		*code++ = (C<<28)|(3<<25)|(1<<24)|(1<<23)|\
170 					  (Rn<<16)|(Rd<<12)|(SH<<4)|R
171 #define LDRB(C, Rn, Rd, SH, R)		*code++ = (C<<28)|(3<<25)|(1<<24)|(1<<23)|(1<<20)|(1<<22)|\
172 					  (Rn<<16)|(Rd<<12)|(SH<<4)|R
173 #define STRB(C, Rn, Rd, SH, R)		*code++ = (C<<28)|(3<<25)|(1<<24)|(1<<23)|(1<<22)|\
174 					  (Rn<<16)|(Rd<<12)|(SH<<4)|R
175 
176 #define DPI(C, Op, Rn, Rd, RO, O)	*code++ = (C<<28)|(1<<25)|(Op<<21)|\
177 					  (Rn<<16)|(Rd<<12)|(RO<<8)|((O)&0xff)
178 #define DP(C, Op, Rn, Rd, Sh, Ro)	*code++ = (C<<28)|(Op<<21)|(Rn<<16)|\
179 					  (Rd<<12)|((Sh)<<4)|Ro
180 #define CMPI(C, Rn, Rd, RO, O)	*code++ = (C<<28)|(1<<25)|(Cmp<<21)|(1<<20)|\
181 					  (Rn<<16)|(Rd<<12)|(RO<<8)|((O)&0xff)
182 #define CMNI(C, Rn, Rd, RO, O)	*code++ = (C<<28)|(1<<25)|(Cmn<<21)|(1<<20)|\
183 					  (Rn<<16)|(Rd<<12)|(RO<<8)|((O)&0xff)
184 #define CMP(C, Rn, Rd, Sh, Ro)	*code++ = (C<<28)|(Cmp<<21)|(Rn<<16)|(1<<20)|\
185 					  (Rd<<12)|((Sh)<<4)|Ro
186 #define CMN(C, Rn, Rd, Sh, Ro)	*code++ = (C<<28)|(Cmn<<21)|(Rn<<16)|(1<<20)|\
187 					  (Rd<<12)|((Sh)<<4)|Ro
188 #define MUL(C, Rm, Rs, Rd)		*code++ = (C<<28)|(Rd<<16)|(Rm<<0)|(Rs<<8)|\
189 					  (9<<4)
190 
191 #define LDF(C, Rn, Fd, O)		*code++ = (C<<28)|(6<<25)|(1<<24)|(1<<23)|(1<<20)|\
192 					  (Rn<<16)|(1<<15)|(Fd<<12)|(1<<8)|((O)&0xff)
193 #define STF(C, Rn, Fd, O)		*code++ = (C<<28)|(6<<25)|(1<<24)|(1<<23)|\
194 					  (Rn<<16)|(1<<15)|(Fd<<12)|(1<<8)|((O)&0xff)
195 #define CMF(C, Fn, Fm)	*code++ = (C<<28)|(7<<25)|(4<<21)|(1<<20)|(Fn<<16)|\
196 						(0xF<<12)|(1<<8)|(1<<4)|(Fm)
197 
198 #define LDH(C, Rn, Rd, O)		*code++ = (C<<28)|(0<<25)|(1<<24)|(1<<23)|(1<<22)|(1<<20)|\
199 					  (Rn<<16)|(Rd<<12)|(((O)&0xf0)<<4)|(0xb<<4)|((O)&0xf)
200 #define LDRH(C, Rn, Rd, Rm)		*code++ = (C<<28)|(0<<25)|(1<<24)|(1<<23)|(1<<20)|\
201 					  (Rn<<16)|(Rd<<12)|(0xb<<4)|Rm
202 
203 #define CPDO2(C, Op, Fn, Fd, Fm)	*code++ = (C<<28)|(0xE<<24)|(Op<<20)|(Fn<<16)|(Fd<<12)|(1<<8)|(1<<7)|(Fm)
204 #define CPDO1(C, Op, Fd, Fm)	CPDO2((C),(Op),0,(Fd),(Fm))|(1<<15)
205 #define CPFLT(C, Fn, Rd)	*code++ = (C<<28)|(0xE<<24)|(0<<20)|(Fn<<16)|(Rd<<12)|(1<<8)|(9<<4)
206 #define CPFIX(C, Rd, Fm)	*code++ = (C<<28)|(0xE<<24)|(1<<20)|(0<<16)|(Rd<<12)|(1<<8)|(9<<4)|(Fm)
207 
208 #define BRAW(C, o)			((C<<28)|(5<<25)|((o) & 0x00ffffff))
209 #define BRA(C, o)			gen(BRAW((C),(o)))
210 #define IA(s, o)			(ulong)(base+s[o])
211 #define BRADIS(C, o)			BRA(C, (IA(patch, o)-(ulong)code-8)>>2)
212 #define BRAMAC(r, o)			BRA(r, (IA(macro, o)-(ulong)code-8)>>2)
213 #define BRANCH(C, o)				gen(BRAW(C, ((ulong)(o)-(ulong)code-8)>>2))
214 #define CALL(o)				gen(BRAW(AL, ((ulong)(o)-(ulong)code-8)>>2)|(1<<24))
215 #define CCALL(C,o)				gen(BRAW((C), ((ulong)(o)-(ulong)code-8)>>2)|(1<<24))
216 #define CALLMAC(C,o)			gen(BRAW((C), (IA(macro, o)-(ulong)code-8)>>2)|(1<<24))
217 #define RELPC(pc)			(ulong)(base+(pc))
218 #define RETURN				DPI(AL, Add, RLINK, R15, 0, 0)
219 #define CRETURN(C)				DPI(C, Add, RLINK, R15, 0, 0)
220 #define PATCH(ptr)			*ptr |= (((ulong)code-(ulong)(ptr)-8)>>2) & 0x00ffffff
221 
222 #define MOV(src, dst)			DP(AL, Mov, 0, dst, 0, src)
223 
224 #define FITS12(v)	((ulong)(v)<BITS(12))
225 #define FITS8(v)	((ulong)(v)<BITS(8))
226 #define FITS5(v)	((ulong)(v)<BITS(5))
227 
228 /* assumes H==-1 */
229 #define CMPH(C, r)		CMNI(C, r, 0, 0, 1)
230 #define NOTNIL(r)	(CMPH(AL, (r)), CCALL(EQ, nullity))
231 
232 /* array bounds checking */
233 #define BCK(r, rb)	(CMP(AL, rb, 0, 0, r), CCALL(LS, bounds))
234 #define BCKI(i, rb)	(CMPI(AL, rb, 0, 0, i), CCALL(LS, bounds))
235 #define BCKR(i, rb)	(CMPI(AL, rb, 0, 0, 0)|(i), CCALL(LS, bounds))
236 
237 static	ulong*	code;
238 static	ulong*	base;
239 static	ulong*	patch;
240 static	ulong	codeoff;
241 static	int	pass;
242 static	int	puntpc = 1;
243 static	Module*	mod;
244 static	uchar*	tinit;
245 static	ulong*	litpool;
246 static	int	nlit;
247 static	ulong	macro[NMACRO];
248 	void	(*comvec)(void);
249 static	void	macfrp(void);
250 static	void	macret(void);
251 static	void	maccase(void);
252 static	void	maccolr(void);
253 static	void	macmcal(void);
254 static	void	macfram(void);
255 static	void	macmfra(void);
256 static	void	macrelq(void);
257 static	void movmem(Inst*);
258 static	void mid(Inst*, int, int);
259 extern	void	das(ulong*, int);
260 
261 #define T(r)	*((void**)(R.r))
262 
263 struct
264 {
265 	int	idx;
266 	void	(*gen)(void);
267 	char*	name;
268 } mactab[] =
269 {
270 	MacFRP,		macfrp,		"FRP", 	/* decrement and free pointer */
271 	MacRET,		macret,		"RET",	/* return instruction */
272 	MacCASE,	maccase,	"CASE",	/* case instruction */
273 	MacCOLR,	maccolr,	"COLR",	/* increment and color pointer */
274 	MacMCAL,	macmcal,	"MCAL",	/* mcall bottom half */
275 	MacFRAM,	macfram,	"FRAM",	/* frame instruction */
276 	MacMFRA,	macmfra,	"MFRA",	/* punt mframe because t->initialize==0 */
277 	MacRELQ,		macrelq,	/* reschedule */
278 };
279 
280 typedef struct Const Const;
281 struct Const
282 {
283 	ulong	o;
284 	ulong*	code;
285 	ulong*	pc;
286 };
287 
288 typedef struct Con Con;
289 struct Con
290 {
291 	int	ptr;
292 	Const	table[NCON];
293 };
294 static Con rcon;
295 
296 static void
297 rdestroy(void)
298 {
299 	destroy(R.s);
300 }
301 
302 static void
303 rmcall(void)
304 {
305 	Frame *f;
306 	Prog *p;
307 
308 	if((void*)R.dt == H)
309 		error(exModule);
310 
311 	f = (Frame*)R.FP;
312 	if(f == H)
313 		error(exModule);
314 
315 	f->mr = nil;
316 	((void(*)(Frame*))R.dt)(f);
317 	R.SP = (uchar*)f;
318 	R.FP = f->fp;
319 	if(f->t == nil)
320 		unextend(f);
321 	else
322 		freeptrs(f, f->t);
323 	p = currun();
324 	if(p->kill != nil)
325 		error(p->kill);
326 }
327 
328 static void
329 rmfram(void)
330 {
331 	Type *t;
332 	Frame *f;
333 	uchar *nsp;
334 
335 	if(R.d == H)
336 		error(exModule);
337 	t = (Type*)R.s;
338 	if(t == H)
339 		error(exModule);
340 	nsp = R.SP + t->size;
341 	if(nsp >= R.TS) {
342 		R.s = t;
343 		extend();
344 		T(d) = R.s;
345 		return;
346 	}
347 	f = (Frame*)R.SP;
348 	R.SP = nsp;
349 	f->t = t;
350 	f->mr = nil;
351 	initmem(t, f);
352 	T(d) = f;
353 }
354 
355 static void
356 urk(char *s)
357 {
358 	USED(s);
359 	error(exCompile);	//production
360 	//panic("compile failed: urk: %s\n", s);	//debugging
361 }
362 
363 static void
364 gen(ulong w)
365 {
366 	*code++ = w;
367 }
368 
369 static long
370 immrot(ulong v)
371 {
372 	int i;
373 
374 	for(i=0; i<16; i++) {
375 		if((v & ~0xff) == 0)
376 			return (i<<8) | v | (1<<25);
377 		v = (v<<2) | (v>>30);
378 	}
379 	return 0;
380 }
381 
382 static long
383 immaddr(long v)
384 {
385 
386 	if(v >= 0 && v <= 0xfff)
387 		return (v & 0xfff) |
388 			(1<<24) |	/* pre indexing */
389 			(1<<23);	/* pre indexing, up */
390 	if(v >= -0xfff && v < 0)
391 		return (-v & 0xfff) |
392 			(1<<24);	/* pre indexing */
393 	return 0;
394 }
395 
396 static void
397 flushcon(int genbr)
398 {
399 	int i;
400 	Const *c;
401 	ulong disp;
402 
403 	if(rcon.ptr == 0)
404 		return;
405 	if(genbr){
406 		if(0)print("BR %d(PC)=%8.8p (len=%d)\n", (rcon.ptr*4+4-8)>>2, code+rcon.ptr+1, rcon.ptr);
407 		BRA(AL, (rcon.ptr*4+4-8)>>2);
408 	}
409 	c = &rcon.table[0];
410 	for(i = 0; i < rcon.ptr; i++) {
411 		if(pass){
412 			disp = (code - c->code) * sizeof(*code) - 8;
413 			if(disp >= BITS(12))
414 				print("INVALID constant range %lud", disp);
415 			if(0)print("data %8.8p %8.8lux (%8.8p, ins=%8.8lux cpc=%8.8p)\n", code, c->o, c->code, *c->code, c->pc);
416 			*c->code |= (disp&0xfff);
417 		}
418 		*code++ = c->o;
419 		c++;
420 	}
421 	rcon.ptr = 0;
422 }
423 
424 static void
425 flushchk(void)
426 {
427 	if(rcon.ptr >= NCON || rcon.ptr > 0 && (code+codeoff+2-rcon.table[0].pc)*sizeof(*code) >= BITS(12)-256){  // 256 allows for a little delay in calling flushchk
428 		if(0)print("flushed constant table: len %ux disp %ld\n", rcon.ptr, (code+codeoff-rcon.table[0].pc)*sizeof(*code)-8);
429 		flushcon(1);
430 	}
431 }
432 
433 static void
434 ccon(int cc, ulong o, int r, int opt)
435 {
436 	ulong u;
437 	Const *c;
438 
439 	if(opt != 0) {
440 		u = o & ~0xff;
441 		if(u == 0) {
442 			DPI(cc, Mov, 0, r, 0, o);
443 			return;
444 		}
445 		if(u == ~0xff) {
446 			DPI(cc, Mvn, 0, r, 0, ~o);
447 			return;
448 		}
449 		u = immrot(o);
450 		if(u) {
451 			DPI(cc, Mov, 0, r, 0, 0) | u;
452 			return;
453 		}
454 		u = o & ~0xffff;
455 		if(u == 0) {
456 			DPI(cc, Mov, 0, r, 0, o);
457 			DPI(cc, Orr, r, r, (24/2), o>>8);
458 			return;
459 		}
460 	}
461 	flushchk();
462 	c = &rcon.table[rcon.ptr++];
463 	c->o = o;
464 	c->code = code;
465 	c->pc = code+codeoff;
466 	LDW(cc, R15, r, 0);
467 }
468 
469 static void
470 memc(int c, int inst, ulong disp, int rm, int r)
471 {
472 	int bit;
473 
474 	if(inst == Lea) {
475 		if(disp < BITS(8)) {
476 			if(disp != 0 || rm != r)
477 				DPI(c, Add, rm, r, 0, disp);
478 			return;
479 		}
480 		if(-disp < BITS(8)) {
481 			DPI(c, Sub, rm, r, 0, -disp);
482 			return;
483 		}
484 		bit = immrot(disp);
485 		if(bit) {
486 			DPI(c, Add, rm, r, 0, 0) | bit;
487 			return;
488 		}
489 		ccon(c, disp, RCON, 1);
490 		DP(c, Add, rm, r, 0, RCON);
491 		return;
492 	}
493 
494 	if(disp < BITS(12) || -disp < BITS(12)) {	/* Direct load */
495 		if(disp < BITS(12))
496 			bit = 0;
497 		else {
498 			disp = -disp;
499 			bit = UPBIT;
500 		}
501 		switch(inst) {
502 		case Ldw:
503 			LDW(c, rm, r, disp);
504 			break;
505 		case Ldb:
506 			LDB(c, rm, r, disp);
507 			break;
508 		case Stw:
509 			STW(c, rm, r, disp);
510 			break;
511 		case Stb:
512 			STB(c, rm, r, disp);
513 			break;
514 		}
515 		if(bit)
516 			code[-1] ^= bit;
517 		return;
518 	}
519 
520 	ccon(c, disp, RCON, 1);
521 	switch(inst) {
522 	case Ldw:
523 		LDRW(c, rm, r, 0, RCON);
524 		break;
525 	case Ldb:
526 		LDRB(c, rm, r, 0, RCON);
527 		break;
528 	case Stw:
529 		STRW(c, rm, r, 0, RCON);
530 		break;
531 	case Stb:
532 		STRB(c, rm, r, 0, RCON);
533 		break;
534 	}
535 }
536 
537 static void
538 con(ulong o, int r, int opt)
539 {
540 	ccon(AL, o, r, opt);
541 }
542 
543 static void
544 mem(int inst, ulong disp, int rm, int r)
545 {
546 	memc(AL, inst, disp, rm, r);
547 }
548 
549 static void
550 opx(int mode, Adr *a, int mi, int r, int li)
551 {
552 	int ir, rta;
553 
554 	switch(mode) {
555 	default:
556 		urk("opx");
557 	case AFP:
558 		mem(mi, a->ind, RFP, r);
559 		return;
560 	case AMP:
561 		mem(mi, a->ind, RMP, r);
562 		return;
563 	case AIMM:
564 		con(a->imm, r, 1);
565 		if(mi == Lea) {	/* could be simpler if con generates reachable literal */
566 			mem(Stw, li, RREG, r);
567 			mem(Lea, li, RREG, r);
568 		}
569 		return;
570 	case AIND|AFP:
571 		ir = RFP;
572 		break;
573 	case AIND|AMP:
574 		ir = RMP;
575 		break;
576 	}
577 	rta = RTA;
578 	if(mi == Lea)
579 		rta = r;
580 	mem(Ldw, a->i.f, ir, rta);
581 	mem(mi, a->i.s, rta, r);
582 }
583 
584 static void
585 opwld(Inst *i, int op, int reg)
586 {
587 	opx(USRC(i->add), &i->s, op, reg, O(REG, st));
588 }
589 
590 static void
591 opwst(Inst *i, int op, int reg)
592 {
593 	opx(UDST(i->add), &i->d, op, reg, O(REG, dt));
594 }
595 
596 static void
597 memfl(int cc, int inst, ulong disp, int rm, int r)
598 {
599 	int bit, wd;
600 
601 	wd = (disp&03)==0;
602 	bit = 0;
603 	if(wd && disp < BITS(10))
604 		disp >>= 2;	/* direct load */
605 	else if(wd && -disp < BITS(10)){
606 		bit = UPBIT;
607 		disp = -disp >> 2;
608 	}else{
609 		ccon(cc, disp, RCON, 1);
610 		DP(cc, Add, RCON, RCON, 0, rm);
611 		rm = RCON;
612 		disp = 0;
613 	}
614 	switch(inst) {
615 	case Ldf:
616 		LDF(cc, rm, r, disp);
617 		break;
618 	case Stf:
619 		STF(cc, rm, r, disp);
620 		break;
621 	}
622 	if(bit)
623 		code[-1] ^= bit;
624 }
625 
626 static void
627 opfl(Adr *a, int am, int mi, int r)
628 {
629 	int ir;
630 
631 	switch(am) {
632 	default:
633 		urk("opfl");
634 	case AFP:
635 		memfl(AL, mi, a->ind, RFP, r);
636 		return;
637 	case AMP:
638 		memfl(AL, mi, a->ind, RMP, r);
639 		return;
640 	case AIND|AFP:
641 		ir = RFP;
642 		break;
643 	case AIND|AMP:
644 		ir = RMP;
645 		break;
646 	}
647 	mem(Ldw, a->i.f, ir, RTA);
648 	memfl(AL, mi, a->i.s, RTA, r);
649 }
650 
651 static void
652 opflld(Inst *i, int mi, int r)
653 {
654 	opfl(&i->s, USRC(i->add), mi, r);
655 }
656 
657 static void
658 opflst(Inst *i, int mi, int r)
659 {
660 	opfl(&i->d, UDST(i->add), mi, r);
661 }
662 
663 static void
664 literal(ulong imm, int roff)
665 {
666 	nlit++;
667 
668 	con((ulong)litpool, RTA, 0);
669 	mem(Stw, roff, RREG, RTA);
670 
671 	if(pass == 0)
672 		return;
673 
674 	*litpool = imm;
675 	litpool++;
676 }
677 
678 static void
679 schedcheck(Inst *i)
680 {
681 	if(RESCHED && i->d.ins <= i){
682 		mem(Ldw, O(REG, IC), RREG, RA0);
683 		DPI(AL, Sub, RA0, RA0, 0, 1) | SBIT;
684 		mem(Stw, O(REG, IC), RREG, RA0);
685 		/* CMPI(AL, RA0, 0, 0, 1); */
686 		CALLMAC(LE, MacRELQ);
687 	}
688 }
689 
690 static void
691 bounds(void)
692 {
693 	/* mem(Stw, O(REG,FP), RREG, RFP); */
694 	error(exBounds);
695 }
696 
697 static void
698 nullity(void)
699 {
700 	/* mem(Stw, O(REG,FP), RREG, RFP); */
701 	error(exNilref);
702 }
703 
704 static void
705 punt(Inst *i, int m, void (*fn)(void))
706 {
707 	ulong pc;
708 
709 	if(m & SRCOP) {
710 		if(UXSRC(i->add) == SRC(AIMM))
711 			literal(i->s.imm, O(REG, s));
712 		else {
713 			opwld(i, Lea, RA0);
714 			mem(Stw, O(REG, s), RREG, RA0);
715 		}
716 	}
717 
718 	if(m & DSTOP) {
719 		opwst(i, Lea, RA0);
720 		mem(Stw, O(REG, d), RREG, RA0);
721 	}
722 	if(m & WRTPC) {
723 		con(RELPC(patch[i-mod->prog+1]), RA0, 0);
724 		mem(Stw, O(REG, PC), RREG, RA0);
725 	}
726 	if(m & DBRAN) {
727 		pc = patch[i->d.ins-mod->prog];
728 		literal((ulong)(base+pc), O(REG, d));
729 	}
730 
731 	switch(i->add&ARM) {
732 	case AXNON:
733 		if(m & THREOP) {
734 			mem(Ldw, O(REG, d), RREG, RA0);
735 			mem(Stw, O(REG, m), RREG, RA0);
736 		}
737 		break;
738 	case AXIMM:
739 		literal((short)i->reg, O(REG,m));
740 		break;
741 	case AXINF:
742 		mem(Lea, i->reg, RFP, RA2);
743 		mem(Stw, O(REG, m), RREG, RA2);
744 		break;
745 	case AXINM:
746 		mem(Lea, i->reg, RMP, RA2);
747 		mem(Stw, O(REG, m), RREG, RA2);
748 		break;
749 	}
750 	mem(Stw, O(REG, FP), RREG, RFP);
751 
752 	CALL(fn);
753 
754 	con((ulong)&R, RREG, 1);
755 	if(m & TCHECK) {
756 		mem(Ldw, O(REG, t), RREG, RA0);
757 		CMPI(AL, RA0, 0, 0, 0);
758 		memc(NE, Ldw, O(REG, xpc), RREG, RLINK);
759 		CRETURN(NE);		/* if(R.t) goto(R.xpc) */
760 	}
761 	mem(Ldw, O(REG, FP), RREG, RFP);
762 	mem(Ldw, O(REG, MP), RREG, RMP);
763 
764 	if(m & NEWPC){
765 		mem(Ldw, O(REG, PC), RREG, R15);
766 		flushcon(0);
767 	}
768 }
769 
770 static void
771 midfl(Inst *i, int mi, int r)
772 {
773 	int ir;
774 
775 	switch(i->add&ARM) {
776 	default:
777 		opflst(i, mi, r);
778 		return;
779 	case AXIMM:
780 		con((short)i->reg, r, 1);	// BUG
781 		return;
782 	case AXINF:
783 		ir = RFP;
784 		break;
785 	case AXINM:
786 		ir = RMP;
787 		break;
788 	}
789 	memfl(AL, mi, i->reg, ir, r);
790 }
791 
792 static void
793 mid(Inst *i, int mi, int r)
794 {
795 	int ir;
796 
797 	switch(i->add&ARM) {
798 	default:
799 		opwst(i, mi, r);
800 		return;
801 	case AXIMM:
802 		if(mi == Lea)
803 			urk("mid/lea");
804 		con((short)i->reg, r, 1);
805 		return;
806 	case AXINF:
807 		ir = RFP;
808 		break;
809 	case AXINM:
810 		ir = RMP;
811 		break;
812 	}
813 	mem(mi, i->reg, ir, r);
814 }
815 
816 static int
817 swapbraop(int b)
818 {
819 	switch(b) {
820 	case GE:
821 		return LE;
822 	case LE:
823 		return GE;
824 	case GT:
825 		return LT;
826 	case LT:
827 		return GT;
828 	}
829 	return b;
830 }
831 
832 static void
833 cbra(Inst *i, int r)
834 {
835 	if(RESCHED)
836 		schedcheck(i);
837 	if(UXSRC(i->add) == SRC(AIMM) && FITS8(i->s.imm)) {
838 		mid(i, Ldw, RA1);
839 		CMPI(AL, RA1, 0, 0, i->s.imm);
840 		r = swapbraop(r);
841 	} else if(UXSRC(i->add) == SRC(AIMM) && FITS8(-i->s.imm)) {
842 		mid(i, Ldw, RA1);
843 		CMNI(AL, RA1, 0, 0, -i->s.imm);
844 		r = swapbraop(r);
845 	} else if((i->add & ARM) == AXIMM && FITS8(i->reg)) {
846 		opwld(i, Ldw, RA1);
847 		CMPI(AL, RA1, 0, 0, i->reg);
848 	} else if((i->add & ARM) == AXIMM && FITS8(-(short)i->reg)) {
849 		opwld(i, Ldw, RA1);
850 		CMNI(AL, RA1, 0, 0, -(short)i->reg);
851 	} else {
852 		opwld(i, Ldw, RA0);
853 		mid(i, Ldw, RA1);
854 		CMP(AL, RA0, 0, 0, RA1);
855 	}
856 	BRADIS(r, i->d.ins-mod->prog);
857 }
858 
859 static void
860 cbrab(Inst *i, int r)
861 {
862 	if(RESCHED)
863 		schedcheck(i);
864 	if(UXSRC(i->add) == SRC(AIMM)) {
865 		mid(i, Ldb, RA1);
866 		CMPI(AL, RA1, 0, 0, i->s.imm&0xFF);
867 		r = swapbraop(r);
868 	} else if((i->add & ARM) == AXIMM) {
869 		opwld(i, Ldb, RA1);
870 		CMPI(AL, RA1, 0, 0, i->reg&0xFF);
871 	} else {
872 		opwld(i, Ldb, RA0);
873 		mid(i, Ldb, RA1);
874 		CMP(AL, RA0, 0, 0, RA1);
875 	}
876 	BRADIS(r, i->d.ins-mod->prog);
877 }
878 
879 static void
880 cbral(Inst *i, int jmsw, int jlsw, int mode)
881 {
882 	ulong dst, *label;
883 
884 	if(RESCHED)
885 		schedcheck(i);
886 	opwld(i, Lea, RA1);
887 	mid(i, Lea, RA3);
888 	mem(Ldw, Bhi, RA1, RA2);
889 	mem(Ldw, Bhi, RA3, RA0);
890 	CMP(AL, RA2, 0, 0, RA0);
891 	label = nil;
892 	dst = i->d.ins-mod->prog;
893 	switch(mode) {
894 	case ANDAND:
895 		label = code;
896 		BRA(jmsw, 0);
897 		break;
898 	case OROR:
899 		BRADIS(jmsw, dst);
900 		break;
901 	case EQAND:
902 		BRADIS(jmsw, dst);
903 		label = code;
904 		BRA(NE, 0);
905 		break;
906 	}
907 	mem(Ldw, Blo, RA3, RA0);
908 	mem(Ldw, Blo, RA1, RA2);
909 	CMP(AL, RA2, 0, 0, RA0);
910 	BRADIS(jlsw, dst);
911 	if(label != nil)
912 		PATCH(label);
913 }
914 
915 static void
916 cbraf(Inst *i, int r)
917 {
918 	if(RESCHED)
919 		schedcheck(i);
920 	if(!SOFTFP){
921 		ulong *s=code;
922 		opflld(i, Ldf, FA4);
923 		midfl(i, Ldf, FA2);
924 		CMF(AL, FA4, FA2);
925 		BRADIS(r, i->d.ins-mod->prog);
926 		if(pass){print("%D\n", i); das(s, code-s);}
927 	}else
928 		punt(i, SRCOP|THREOP|DBRAN|NEWPC|WRTPC, optab[i->op]);
929 }
930 
931 static void
932 comcase(Inst *i, int w)
933 {
934 	int l;
935 	WORD *t, *e;
936 
937 	if(w != 0) {
938 		opwld(i, Ldw, RA1);		// v
939 		opwst(i, Lea, RA3);		// table
940 		BRAMAC(AL, MacCASE);
941 	}
942 
943 	t = (WORD*)(mod->origmp+i->d.ind+4);
944 	l = t[-1];
945 
946 	/* have to take care not to relocate the same table twice -
947 	 * the limbo compiler can duplicate a case instruction
948 	 * during its folding phase
949 	 */
950 
951 	if(pass == 0) {
952 		if(l >= 0)
953 			t[-1] = -l-1;	/* Mark it not done */
954 		return;
955 	}
956 	if(l >= 0)			/* Check pass 2 done */
957 		return;
958 	t[-1] = -l-1;			/* Set real count */
959 	e = t + t[-1]*3;
960 	while(t < e) {
961 		t[2] = RELPC(patch[t[2]]);
962 		t += 3;
963 	}
964 	t[0] = RELPC(patch[t[0]]);
965 }
966 
967 static void
968 comcasel(Inst *i)
969 {
970 	int l;
971 	WORD *t, *e;
972 
973 	t = (WORD*)(mod->origmp+i->d.ind+8);
974 	l = t[-2];
975 	if(pass == 0) {
976 		if(l >= 0)
977 			t[-2] = -l-1;	/* Mark it not done */
978 		return;
979 	}
980 	if(l >= 0)			/* Check pass 2 done */
981 		return;
982 	t[-2] = -l-1;			/* Set real count */
983 	e = t + t[-2]*6;
984 	while(t < e) {
985 		t[4] = RELPC(patch[t[4]]);
986 		t += 6;
987 	}
988 	t[0] = RELPC(patch[t[0]]);
989 }
990 
991 static void
992 commframe(Inst *i)
993 {
994 	ulong *punt, *mlnil;
995 
996 	opwld(i, Ldw, RA0);
997 	CMPH(AL, RA0);
998 	mlnil = code;
999 	BRA(EQ, 0);
1000 
1001 	if((i->add&ARM) == AXIMM) {
1002 		mem(Ldw, OA(Modlink, links)+i->reg*sizeof(Modl)+O(Modl, frame), RA0, RA3);
1003 	} else {
1004 		mid(i, Ldw, RA1);
1005 		DP(AL, Add, RA0, RA1, (3<<3), RA1);	// assumes sizeof(Modl) == 8
1006 		mem(Ldw, OA(Modlink, links)+O(Modl, frame), RA1, RA3);
1007 	}
1008 
1009 	mem(Ldw, O(Type, initialize), RA3, RA1);
1010 	CMPI(AL, RA1, 0, 0, 0);
1011 	punt = code;
1012 	BRA(NE, 0);
1013 
1014 	opwst(i, Lea, RA0);
1015 
1016 	/* Type in RA3, destination in RA0 */
1017 	PATCH(mlnil);
1018 	con(RELPC(patch[i-mod->prog+1]), RLINK, 0);
1019 	BRAMAC(AL, MacMFRA);
1020 
1021 	/* Type in RA3 */
1022 	PATCH(punt);
1023 	CALLMAC(AL, MacFRAM);
1024 	opwst(i, Stw, RA2);
1025 }
1026 
1027 static void
1028 commcall(Inst *i)
1029 {
1030 	ulong *mlnil;
1031 
1032 	opwld(i, Ldw, RA2);
1033 	con(RELPC(patch[i-mod->prog+1]), RA0, 0);
1034 	mem(Stw, O(Frame, lr), RA2, RA0);
1035 	mem(Stw, O(Frame, fp), RA2, RFP);
1036 	mem(Ldw, O(REG, M), RREG, RA3);
1037 	mem(Stw, O(Frame, mr), RA2, RA3);
1038 	opwst(i, Ldw, RA3);
1039 	CMPH(AL, RA3);
1040 	mlnil = code;
1041 	BRA(EQ, 0);
1042 	if((i->add&ARM) == AXIMM) {
1043 		mem(Ldw, OA(Modlink, links)+i->reg*sizeof(Modl)+O(Modl, u.pc), RA3, RA0);
1044 	} else {
1045 		mid(i, Ldw, RA1);
1046 		DP(AL, Add, RA3, RA1, (3<<3), RA1);	// assumes sizeof(Modl) == 8
1047 		mem(Ldw, OA(Modlink, links)+O(Modl, u.pc), RA1, RA0);
1048 	}
1049 	PATCH(mlnil);
1050 	CALLMAC(AL, MacMCAL);
1051 }
1052 
1053 static void
1054 larith(Inst *i, int op, int opc)
1055 {
1056 	opwld(i, Lea, RA0);
1057 	mid(i, Lea, RA3);
1058 	mem(Ldw, Blo, RA0, RA1);	// ls
1059 	mem(Ldw, Blo, RA3, RA2);
1060 	DP(AL, op, RA2, RA2, 0, RA1) | SBIT;	// ls: RA2 = RA2 op RA1
1061 	mem(Ldw, Bhi, RA0, RA1);
1062 	mem(Ldw, Bhi, RA3, RA0);
1063 	DP(AL, opc, RA0, RA0, 0, RA1);	// ms: RA0 = RA0 opc RA1
1064 	if((i->add&ARM) != AXNON)
1065 		opwst(i, Lea, RA3);
1066 	mem(Stw, Blo, RA3, RA2);
1067 	mem(Stw, Bhi, RA3, RA0);
1068 }
1069 
1070 static void
1071 movloop(Inst *i, int s)
1072 {
1073 	int b;
1074 
1075 	b = (s==1);
1076 	opwst(i, Lea, RA2);
1077 	LDxP(AL, RA1, RA0, s, b);
1078 	STxP(AL, RA2, RA0, s, b);
1079 	DPI(AL, Sub, RA3, RA3, 0, 1) | SBIT;
1080 	BRA(NE, (-3*4-8)>>2);
1081 }
1082 
1083 static void
1084 movmem(Inst *i)
1085 {
1086 	ulong *cp;
1087 
1088 	// source address already in RA1
1089 	if((i->add&ARM) != AXIMM){
1090 		mid(i, Ldw, RA3);
1091 		CMPI(AL, RA3, 0, 0, 0);
1092 		cp = code;
1093 		BRA(LE, 0);
1094 		movloop(i, 1);
1095 		PATCH(cp);
1096 		return;
1097 	}
1098 	switch(i->reg){
1099 	case 0:
1100 		break;
1101 	case 4:
1102 		LDW(AL, RA1, RA2, 0);
1103 		opwst(i, Stw, RA2);
1104 		break;
1105 	case 8:
1106 		LDW(AL, RA1, RA2, 0);
1107 		opwst(i, Lea, RA3);
1108 		LDW(AL, RA1, RA1, 4);
1109 		STW(AL, RA3, RA2, 0);
1110 		STW(AL, RA3, RA1, 4);
1111 		break;
1112 	default:
1113 		// could use ldm/stm loop...
1114 		if((i->reg&3) == 0) {
1115 			con(i->reg>>2, RA3, 1);
1116 			movloop(i, 4);
1117 		} else {
1118 			con(i->reg, RA3, 1);
1119 			movloop(i, 1);
1120 		}
1121 		break;
1122 	}
1123 }
1124 
1125 static
1126 void
1127 compdbg(void)
1128 {
1129 	print("%s:%lud@%.8lux\n", R.M->m->name, *(ulong*)R.m, *(ulong*)R.s);
1130 }
1131 
1132 static void
1133 comgoto(Inst *i)
1134 {
1135 	WORD *t, *e;
1136 
1137 	opwld(i, Ldw, RA1);
1138 	opwst(i, Lea, RA0);
1139 	LDRW(AL, RA0, R15, (2<<3), RA1);
1140 	flushcon(0);
1141 
1142 	if(pass == 0)
1143 		return;
1144 
1145 	t = (WORD*)(mod->origmp+i->d.ind);
1146 	e = t + t[-1];
1147 	t[-1] = 0;
1148 	while(t < e) {
1149 		t[0] = RELPC(patch[t[0]]);
1150 		t++;
1151 	}
1152 }
1153 
1154 static void
1155 comp(Inst *i)
1156 {
1157 	int r, imm;
1158 	char buf[64];
1159 //ulong *s = code;
1160 	if(0) {
1161 		Inst xx;
1162 		xx.add = AXIMM|SRC(AIMM);
1163 		xx.s.imm = (ulong)code;
1164 		xx.reg = i-mod->prog;
1165 		puntpc = 0;
1166 		punt(&xx, SRCOP, compdbg);
1167 		puntpc = 1;
1168 		flushcon(1);
1169 	}
1170 	flushchk();
1171 
1172 	switch(i->op) {
1173 	default:
1174 		snprint(buf, sizeof buf, "%s compile, no '%D'", mod->name, i);
1175 		error(buf);
1176 		break;
1177 	case IMCALL:
1178 		if((i->add&ARM) == AXIMM)
1179 			commcall(i);
1180 		else
1181 			punt(i, SRCOP|DSTOP|THREOP|WRTPC|NEWPC, optab[i->op]);
1182 		break;
1183 	case ISEND:
1184 	case IRECV:
1185 	case IALT:
1186 		punt(i, SRCOP|DSTOP|TCHECK|WRTPC, optab[i->op]);
1187 		break;
1188 	case ISPAWN:
1189 		punt(i, SRCOP|DBRAN, optab[i->op]);
1190 		break;
1191 	case IBNEC:
1192 	case IBEQC:
1193 	case IBLTC:
1194 	case IBLEC:
1195 	case IBGTC:
1196 	case IBGEC:
1197 		punt(i, SRCOP|DBRAN|NEWPC|WRTPC, optab[i->op]);
1198 		break;
1199 	case ICASEC:
1200 		comcase(i, 0);
1201 		punt(i, SRCOP|DSTOP|NEWPC, optab[i->op]);
1202 		break;
1203 	case ICASEL:
1204 		comcasel(i);
1205 		punt(i, SRCOP|DSTOP|NEWPC, optab[i->op]);
1206 		break;
1207 	case IADDC:
1208 	case IMULL:
1209 	case IDIVL:
1210 	case IMODL:
1211 	case IMNEWZ:
1212 	case ILSRW:
1213 	case ILSRL:
1214 	case IMODW:
1215 	case IMODB:
1216 	case IDIVW:
1217 	case IDIVB:
1218 		punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
1219 		break;
1220 	case ILOAD:
1221 	case INEWA:
1222 	case INEWAZ:
1223 	case INEW:
1224 	case INEWZ:
1225 	case ISLICEA:
1226 	case ISLICELA:
1227 	case ICONSB:
1228 	case ICONSW:
1229 	case ICONSL:
1230 	case ICONSF:
1231 	case ICONSM:
1232 	case ICONSMP:
1233 	case ICONSP:
1234 	case IMOVMP:
1235 	case IHEADMP:
1236 	case IHEADB:
1237 	case IHEADW:
1238 	case IHEADL:
1239 	case IINSC:
1240 	case ICVTAC:
1241 	case ICVTCW:
1242 	case ICVTWC:
1243 	case ICVTLC:
1244 	case ICVTCL:
1245 	case ICVTFC:
1246 	case ICVTCF:
1247 	case ICVTRF:
1248 	case ICVTFR:
1249 	case ICVTWS:
1250 	case ICVTSW:
1251 	case IMSPAWN:
1252 	case ICVTCA:
1253 	case ISLICEC:
1254 	case INBALT:
1255 		punt(i, SRCOP|DSTOP, optab[i->op]);
1256 		break;
1257 	case INEWCM:
1258 	case INEWCMP:
1259 		punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
1260 		break;
1261 	case IMFRAME:
1262 		if((i->add&ARM) == AXIMM)
1263 			commframe(i);
1264 		else
1265 			punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
1266 		break;
1267 	case ICASE:
1268 		comcase(i, 1);
1269 		break;
1270 	case IGOTO:
1271 		comgoto(i);
1272 		break;
1273 	case IMOVF:
1274 		if(!SOFTFP){
1275 			opflld(i, Ldf, FA2);
1276 			opflst(i, Stf, FA2);
1277 			break;
1278 		}
1279 		/* if no hardware, just fall through */
1280 	case IMOVL:
1281 		opwld(i, Lea, RA1);
1282 		LDW(AL, RA1, RA2, 0);
1283 		LDW(AL, RA1, RA3, 4);
1284 		opwst(i, Lea, RA1);
1285 		STW(AL, RA1, RA2, 0);
1286 		STW(AL, RA1, RA3, 4);
1287 		break;
1288 		break;
1289 	case IHEADM:
1290 		opwld(i, Ldw, RA1);
1291 		NOTNIL(RA1);
1292 		if(OA(List,data) != 0)
1293 			DPI(AL, Add, RA1, RA1, 0, OA(List,data));
1294 		movmem(i);
1295 		break;
1296 /*
1297 	case IHEADW:
1298 		opwld(i, Ldw, RA0);
1299 		NOTNIL(RA0);
1300 		mem(Ldw, OA(List, data), RA0, RA0);
1301 		opwst(i, Stw, RA0);
1302 		break;
1303 */
1304 	case IMOVM:
1305 		opwld(i, Lea, RA1);
1306 		movmem(i);
1307 		break;
1308 	case IFRAME:
1309 		if(UXSRC(i->add) != SRC(AIMM)) {
1310 			punt(i, SRCOP|DSTOP, optab[i->op]);
1311 			break;
1312 		}
1313 		tinit[i->s.imm] = 1;
1314 		con((ulong)mod->type[i->s.imm], RA3, 1);
1315 		CALL(base+macro[MacFRAM]);
1316 		opwst(i, Stw, RA2);
1317 		break;
1318 	case INEWCB:
1319 	case INEWCW:
1320 	case INEWCF:
1321 	case INEWCP:
1322 	case INEWCL:
1323 		punt(i, DSTOP|THREOP, optab[i->op]);
1324 		break;
1325 	case IEXIT:
1326 		punt(i, 0, optab[i->op]);
1327 		break;
1328 	case ICVTBW:
1329 		opwld(i, Ldb, RA0);
1330 		opwst(i, Stw, RA0);
1331 		break;
1332 	case ICVTWB:
1333 		opwld(i, Ldw, RA0);
1334 		opwst(i, Stb, RA0);
1335 		break;
1336 	case ILEA:
1337 		opwld(i, Lea, RA0);
1338 		opwst(i, Stw, RA0);
1339 		break;
1340 	case IMOVW:
1341 		opwld(i, Ldw, RA0);
1342 		opwst(i, Stw, RA0);
1343 		break;
1344 	case IMOVB:
1345 		opwld(i, Ldb, RA0);
1346 		opwst(i, Stb, RA0);
1347 		break;
1348 	case ITAIL:
1349 		opwld(i, Ldw, RA0);
1350 		NOTNIL(RA0);
1351 		mem(Ldw, O(List, tail), RA0, RA1);
1352 		goto movp;
1353 	case IMOVP:
1354 		opwld(i, Ldw, RA1);
1355 		goto movp;
1356 	case IHEADP:
1357 		opwld(i, Ldw, RA0);
1358 		NOTNIL(RA0);
1359 		mem(Ldw, OA(List, data), RA0, RA1);
1360 	movp:
1361 		CMPH(AL, RA1);
1362 		CALLMAC(NE, MacCOLR);		// colour if not H
1363 		opwst(i, Lea, RA2);
1364 		mem(Ldw, 0,RA2, RA0);
1365 		mem(Stw, 0,RA2, RA1);
1366 		CALLMAC(AL, MacFRP);
1367 		break;
1368 	case ILENA:
1369 		opwld(i, Ldw, RA1);
1370 		con(0, RA0, 1);
1371 		CMPH(AL, RA1);
1372 		LDW(NE, RA1, RA0, O(Array,len));
1373 		opwst(i, Stw, RA0);
1374 		break;
1375 	case ILENC:
1376 		opwld(i, Ldw, RA1);
1377 		con(0, RA0, 1);
1378 		CMPH(AL, RA1);
1379 		memc(NE, Ldw, O(String,len),RA1, RA0);
1380 		CMPI(AL, RA0, 0, 0, 0);
1381 		DPI(LT, Rsb, RA0, RA0, 0, 0);
1382 		opwst(i, Stw, RA0);
1383 		break;
1384 	case ILENL:
1385 		con(0, RA0, 1);
1386 		opwld(i, Ldw, RA1);
1387 
1388 		CMPH(AL, RA1);
1389 		LDW(NE, RA1, RA1, O(List, tail));
1390 		DPI(NE, Add, RA0, RA0, 0, 1);
1391 		BRA(NE, (-4*3-8)>>2);
1392 
1393 		opwst(i, Stw, RA0);
1394 		break;
1395 	case ICALL:
1396 		opwld(i, Ldw, RA0);
1397 		con(RELPC(patch[i-mod->prog+1]), RA1, 0);
1398 		mem(Stw, O(Frame, lr), RA0, RA1);
1399 		mem(Stw, O(Frame, fp), RA0, RFP);
1400 		MOV(RA0, RFP);
1401 		BRADIS(AL, i->d.ins-mod->prog);
1402 		flushcon(0);
1403 		break;
1404 	case IJMP:
1405 		if(RESCHED)
1406 			schedcheck(i);
1407 		BRADIS(AL, i->d.ins-mod->prog);
1408 		flushcon(0);
1409 		break;
1410 	case IBEQW:
1411 		cbra(i, EQ);
1412 		break;
1413 	case IBNEW:
1414 		cbra(i, NE);
1415 		break;
1416 	case IBLTW:
1417 		cbra(i, LT);
1418 		break;
1419 	case IBLEW:
1420 		cbra(i, LE);
1421 		break;
1422 	case IBGTW:
1423 		cbra(i, GT);
1424 		break;
1425 	case IBGEW:
1426 		cbra(i, GE);
1427 		break;
1428 	case IBEQB:
1429 		cbrab(i, EQ);
1430 		break;
1431 	case IBNEB:
1432 		cbrab(i, NE);
1433 		break;
1434 	case IBLTB:
1435 		cbrab(i, LT);
1436 		break;
1437 	case IBLEB:
1438 		cbrab(i, LE);
1439 		break;
1440 	case IBGTB:
1441 		cbrab(i, GT);
1442 		break;
1443 	case IBGEB:
1444 		cbrab(i, GE);
1445 		break;
1446 	case IBEQF:
1447 		cbraf(i, EQ);
1448 		break;
1449 	case IBNEF:
1450 		cbraf(i, NE);
1451 		break;
1452 	case IBLTF:
1453 		cbraf(i, LT);
1454 		break;
1455 	case IBLEF:
1456 		cbraf(i, LE);
1457 		break;
1458 	case IBGTF:
1459 		cbraf(i, GT);
1460 		break;
1461 	case IBGEF:
1462 		cbraf(i, GE);
1463 		break;
1464 	case IRET:
1465 		mem(Ldw, O(Frame,t), RFP, RA1);
1466 		BRAMAC(AL, MacRET);
1467 		break;
1468 	case IMULW:
1469 		opwld(i, Ldw, RA1);
1470 		mid(i, Ldw, RA0);
1471 		MUL(AL, RA1, RA0, RA0);
1472 		opwst(i, Stw, RA0);
1473 		break;
1474 	case IMULB:
1475 		opwld(i, Ldb, RA1);
1476 		mid(i, Ldb, RA0);
1477 		MUL(AL, RA1, RA0, RA0);
1478 		opwst(i, Stb, RA0);
1479 		break;
1480 	case IORW:
1481 		r = Orr;
1482 		goto arithw;
1483 	case IANDW:
1484 		r = And;
1485 		goto arithw;
1486 	case IXORW:
1487 		r = Eor;
1488 		goto arithw;
1489 	case ISUBW:
1490 		r = Sub;
1491 		goto arithw;
1492 	case IADDW:
1493 		r = Add;
1494 	arithw:
1495 		mid(i, Ldw, RA1);
1496 		if(UXSRC(i->add) == SRC(AIMM) && FITS8(i->s.imm))
1497 			DPI(AL, r, RA1, RA0, 0, i->s.imm);
1498 		else if(UXSRC(i->add) == SRC(AIMM) && immrot(i->s.imm)){
1499 			DPI(AL, r, RA1, RA0, 0, 0) | immrot(i->s.imm);
1500 			//print("rot: %ux %ux\n", i->s.imm, immrot(i->s.imm)); das(code-1, 1);
1501 		} else {
1502 			opwld(i, Ldw, RA0);
1503 			DP(AL, r, RA1, RA0, 0, RA0);
1504 		}
1505 		opwst(i, Stw, RA0);
1506 		break;
1507 	case ISHRW:
1508 		r = 2;
1509 	shiftw:
1510 		mid(i, Ldw, RA1);
1511 		if(UXSRC(i->add) == SRC(AIMM) && FITS5(i->s.imm))
1512 			DP(AL, Mov, 0, RA0, ((i->s.imm&0x3F)<<3)|(r<<1), RA1);
1513 		else {
1514 			opwld(i, Ldw, RA0);
1515 			DP(AL, Mov, 0, RA0, (RA0<<4)|(r<<1)|1, RA1);
1516 		}
1517 		opwst(i, Stw, RA0);
1518 		break;
1519 	case ISHLW:
1520 		r = 0;
1521 		goto shiftw;
1522 		break;
1523 	case IORB:
1524 		r = Orr;
1525 		goto arithb;
1526 	case IANDB:
1527 		r = And;
1528 		goto arithb;
1529 	case IXORB:
1530 		r = Eor;
1531 		goto arithb;
1532 	case ISUBB:
1533 		r = Sub;
1534 		goto arithb;
1535 	case IADDB:
1536 		r = Add;
1537 	arithb:
1538 		mid(i, Ldb, RA1);
1539 		if(UXSRC(i->add) == SRC(AIMM))
1540 			DPI(AL, r, RA1, RA0, 0, i->s.imm);
1541 		else {
1542 			opwld(i, Ldb, RA0);
1543 			DP(AL, r, RA1, RA0, 0, RA0);
1544 		}
1545 		opwst(i, Stb, RA0);
1546 		break;
1547 	case ISHRB:
1548 		r = 2;
1549 		goto shiftb;
1550 	case ISHLB:
1551 		r = 0;
1552 	shiftb:
1553 		mid(i, Ldb, RA1);
1554 		if(UXSRC(i->add) == SRC(AIMM) && FITS5(i->s.imm))
1555 			DP(AL, Mov, 0, RA0, ((i->s.imm&0x3F)<<3)|(r<<1), RA1);
1556 		else {
1557 			opwld(i, Ldw, RA0);
1558 			DP(AL, Mov, 0, RA0, (RA0<<4)|(r<<1)|1, RA1);
1559 		}
1560 		opwst(i, Stb, RA0);
1561 		break;
1562 	case IINDC:
1563 		opwld(i, Ldw, RA1);			// RA1 = string
1564 		NOTNIL(RA1);
1565 		imm = 1;
1566 		if((i->add&ARM) != AXIMM || !FITS12((short)i->reg<<Lg2Rune) || immrot((short)i->reg) == 0){
1567 			mid(i, Ldw, RA2);			// RA2 = i
1568 			imm = 0;
1569 		}
1570 		mem(Ldw, O(String,len),RA1, RA0);	// len<0 => index Runes, otherwise bytes
1571 		if(bflag){
1572 			DPI(AL, Orr, RA0, RA3, 0, 0);
1573 			DPI(LT, Rsb, RA3, RA3, 0, 0);
1574 			if(imm)
1575 				BCKR(immrot((short)i->reg), RA3);
1576 			else
1577 				BCK(RA2, RA3);
1578 		}
1579 		DPI(AL, Add, RA1, RA1, 0, O(String,data));
1580 		CMPI(AL, RA0, 0, 0, 0);
1581 		if(imm){
1582 			LDB(GE, RA1, RA3, i->reg);
1583 			LDW(LT, RA1, RA3, (short)i->reg<<Lg2Rune);
1584 		} else {
1585 			LDRB(GE, RA1, RA3, 0, RA2);
1586 			DP(LT, Mov, 0, RA2, (Lg2Rune<<3), RA2);
1587 			LDRW(LT, RA1, RA3, 0, RA2);
1588 		}
1589 		opwst(i, Stw, RA3);
1590 //if(pass){print("%D\n", i); das(s, code-s);}
1591 		break;
1592 	case IINDL:
1593 	case IINDF:
1594 	case IINDW:
1595 	case IINDB:
1596 		opwld(i, Ldw, RA0);			/* a */
1597 		NOTNIL(RA0);
1598 		if(bflag)
1599 			mem(Ldw, O(Array, len), RA0, RA2);
1600 		mem(Ldw, O(Array, data), RA0, RA0);
1601 		r = 0;
1602 		switch(i->op) {
1603 		case IINDL:
1604 		case IINDF:
1605 			r = 3;
1606 			break;
1607 		case IINDW:
1608 			r = 2;
1609 			break;
1610 		}
1611 		if(UXDST(i->add) == DST(AIMM) && (imm = immrot(i->d.imm)) != 0) {
1612 			if(bflag)
1613 				BCKR(imm, RA2);
1614 			if(i->d.imm != 0)
1615 				DPI(AL, Add, RA0, RA0, 0, 0) | immrot(i->d.imm<<r);
1616 		} else {
1617 			opwst(i, Ldw, RA1);
1618 			if(bflag)
1619 				BCK(RA1, RA2);
1620 			DP(AL, Add, RA0, RA0, r<<3, RA1);
1621 		}
1622 		mid(i, Stw, RA0);
1623 //if(pass){print("%D\n", i); das(s, code-s);}
1624 		break;
1625 	case IINDX:
1626 		opwld(i, Ldw, RA0);			/* a */
1627 		NOTNIL(RA0);
1628 		opwst(i, Ldw, RA1);			/* i */
1629 
1630 		if(bflag){
1631 			mem(Ldw, O(Array, len), RA0, RA2);
1632 			BCK(RA1, RA2);
1633 		}
1634 		mem(Ldw, O(Array, t), RA0, RA2);
1635 		mem(Ldw, O(Array, data), RA0, RA0);
1636 		mem(Ldw, O(Type, size), RA2, RA2);
1637 		MUL(AL, RA2, RA1, RA1);
1638 		DP(AL, Add, RA1, RA0, 0, RA0);
1639 		mid(i, Stw, RA0);
1640 //if(pass){print("%D\n", i); das(s, code-s);}
1641 		break;
1642 	case IADDL:
1643 		larith(i, Add, Adc);
1644 		break;
1645 	case ISUBL:
1646 		larith(i, Sub, Sbc);
1647 		break;
1648 	case IORL:
1649 		larith(i, Orr, Orr);
1650 		break;
1651 	case IANDL:
1652 		larith(i, And, And);
1653 		break;
1654 	case IXORL:
1655 		larith(i, Eor, Eor);
1656 		break;
1657 	case ICVTWL:
1658 		opwld(i, Ldw, RA1);
1659 		opwst(i, Lea, RA2);
1660 		DP(AL, Mov, 0, RA0, (0<<3)|(2<<1), RA1);	// ASR 32
1661 		STW(AL, RA2, RA1, Blo);
1662 		STW(AL, RA2, RA0, Bhi);
1663 		break;
1664 	case ICVTLW:
1665 		opwld(i, Lea, RA0);
1666 		mem(Ldw, Blo, RA0, RA0);
1667 		opwst(i, Stw, RA0);
1668 		break;
1669 	case IBEQL:
1670 		cbral(i, NE, EQ, ANDAND);
1671 		break;
1672 	case IBNEL:
1673 		cbral(i, NE, NE, OROR);
1674 		break;
1675 	case IBLEL:
1676 		cbral(i, LT, LS, EQAND);
1677 		break;
1678 	case IBGTL:
1679 		cbral(i, GT, HI, EQAND);
1680 		break;
1681 	case IBLTL:
1682 		cbral(i, LT, CC, EQAND);
1683 		break;
1684 	case IBGEL:
1685 		cbral(i, GT, CS, EQAND);
1686 		break;
1687 	case ICVTFL:
1688 	case ICVTLF:
1689 		punt(i, SRCOP|DSTOP, optab[i->op]);
1690 		break;
1691 	case IDIVF:
1692 		r = Dvf;
1693 		goto arithf;
1694 	case IMULF:
1695 		r = Muf;
1696 		goto arithf;
1697 	case ISUBF:
1698 		r = Suf;
1699 		goto arithf;
1700 	case IADDF:
1701 		r = Adf;
1702 	arithf:
1703 		if(SOFTFP){
1704 			/* software fp */
1705 			USED(r);
1706 			punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
1707 			break;
1708 		}
1709 		opflld(i, Ldf, FA2);
1710 		midfl(i, Ldf, FA4);
1711 		CPDO2(AL, r, FA4, FA4, FA2);
1712 		opflst(i, Stf, FA4);
1713 		break;
1714 	case INEGF:
1715 		if(SOFTFP){
1716 			punt(i, SRCOP|DSTOP, optab[i->op]);
1717 			break;
1718 		}
1719 		opflld(i, Ldf, FA2);
1720 		CPDO1(AL, Mnf, FA2, FA2);
1721 		opflst(i, Stf, FA2);
1722 //if(pass){print("%D\n", i); das(s, code-s);}
1723 		break;
1724 	case ICVTWF:
1725 		if(SOFTFP){
1726 			punt(i, SRCOP|DSTOP, optab[i->op]);
1727 			break;
1728 		}
1729 		opwld(i, Ldw, RA2);
1730 		CPFLT(AL, FA2, RA2);
1731 		opflst(i, Stf, FA2);
1732 //if(pass){print("%D\n", i); das(s, code-s);}
1733 		break;
1734 	case ICVTFW:
1735 		if(SOFTFP){
1736 			punt(i, SRCOP|DSTOP, optab[i->op]);
1737 			break;
1738 		}
1739 		opflld(i, Ldf, FA2);
1740 		CPFIX(AL, RA2, FA2);
1741 		opwst(i, Stw, RA2);
1742 //if(pass){print("%D\n", i); das(s, code-s);}
1743 		break;
1744 	case ISHLL:
1745 		/* should do better */
1746 		punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
1747 		break;
1748 	case ISHRL:
1749 		/* should do better */
1750 		punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
1751 		break;
1752 	case IRAISE:
1753 		punt(i, SRCOP|WRTPC|NEWPC, optab[i->op]);
1754 		break;
1755 	case IMULX:
1756 	case IDIVX:
1757 	case ICVTXX:
1758 	case IMULX0:
1759 	case IDIVX0:
1760 	case ICVTXX0:
1761 	case IMULX1:
1762 	case IDIVX1:
1763 	case ICVTXX1:
1764 	case ICVTFX:
1765 	case ICVTXF:
1766 	case IEXPW:
1767 	case IEXPL:
1768 	case IEXPF:
1769 		punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
1770 		break;
1771 	case ISELF:
1772 		punt(i, DSTOP, optab[i->op]);
1773 		break;
1774 	}
1775 }
1776 
1777 static void
1778 preamble(void)
1779 {
1780 	if(comvec)
1781 		return;
1782 
1783 	comvec = malloc(10 * sizeof(*code));
1784 	if(comvec == nil)
1785 		error(exNomem);
1786 	code = (ulong*)comvec;
1787 
1788 	con((ulong)&R, RREG, 0);
1789 	mem(Stw, O(REG, xpc), RREG, RLINK);
1790 	mem(Ldw, O(REG, FP), RREG, RFP);
1791 	mem(Ldw, O(REG, MP), RREG, RMP);
1792 	mem(Ldw, O(REG, PC), RREG, R15);
1793 	pass++;
1794 	flushcon(0);
1795 	pass--;
1796 
1797 	segflush(comvec, 10 * sizeof(*code));
1798 }
1799 
1800 static void
1801 maccase(void)
1802 {
1803 	ulong *cp1, *loop, *inner;
1804 /*
1805  * RA1 = value (input arg), t
1806  * RA2 = count, n
1807  * RA3 = table pointer (input arg)
1808  * RA0  = n/2, n2
1809  * RCON  = pivot element t+n/2*3, l
1810  */
1811 	LDW(AL, RA3, RA2, 0);	// count from table
1812 	MOV(RA3, RLINK);	// initial table pointer
1813 
1814 	loop = code;			// loop:
1815 	CMPI(AL, RA2, 0, 0, 0);
1816 	cp1 = code;
1817 	BRA(LE, 0);	// n <= 0? goto out
1818 
1819 	inner = code;
1820 	DP(AL, Mov, 0, RA0, (1<<3)|2, RA2);	// n2 = n>>1
1821 	DP(AL, Add, RA0, RCON, (1<<3), RA0);	// n' = n2+(n2<<1) = 3*n2
1822 	DP(AL, Add, RA3, RCON, (2<<3), RCON);	// l = t + n2*3;
1823 
1824 	LDW(AL, RCON, RTA, 4);
1825 	CMP(AL, RA1, 0, 0, RTA);
1826 	DP(LT, Mov, 0, RA2, 0, RA0);	// v < l[1]? n=n2
1827 	BRANCH(LT, loop);	// v < l[1]? goto loop
1828 
1829 	LDW(AL, RCON, RTA, 8);
1830 	CMP(AL, RA1, 0, 0, RTA);
1831 	LDW(LT, RCON, R15, 12);	// v >= l[1] && v < l[2] => found; goto l[3]
1832 
1833 	// v >= l[2] (high)
1834 	DPI(AL, Add, RCON, RA3, 0, 12);	// t = l+3;
1835 	DPI(AL, Add, RA0, RTA, 0, 1);
1836 	DP(AL, Sub, RA2, RA2, 0, RTA) | SBIT;	// n -= n2+1
1837 	BRANCH(GT, inner);	// n > 0? goto loop
1838 
1839 	PATCH(cp1);	// out:
1840 	LDW(AL, RLINK, RA2, 0);		// initial n
1841 	DP(AL, Add, RA2, RA2, (1<<3), RA2);	// n = n+(n<<1) = 3*n
1842 	DP(AL, Add, RLINK, RLINK, (2<<3), RA2);	// t' = &(initial t)[n*3]
1843 	LDW(AL, RLINK, R15, 4);		// goto (initial t)[n*3+1]
1844 }
1845 
1846 static void
1847 macfrp(void)
1848 {
1849 	/* destroy the pointer in RA0 */
1850 	CMPH(AL, RA0);
1851 	CRETURN(EQ);		// arg == H? => return
1852 
1853 	mem(Ldw, O(Heap, ref)-sizeof(Heap), RA0, RA2);
1854 	DPI(AL, Sub, RA2, RA2, 0, 1) | SBIT;
1855 	memc(NE, Stw, O(Heap, ref)-sizeof(Heap), RA0, RA2);
1856 	CRETURN(NE);		// --h->ref != 0 => return
1857 
1858 	mem(Stw, O(REG, FP), RREG, RFP);
1859 	mem(Stw, O(REG, st), RREG, RLINK);
1860 	mem(Stw, O(REG, s), RREG, RA0);
1861 	CALL(rdestroy);
1862 	con((ulong)&R, RREG, 1);
1863 	mem(Ldw, O(REG, st), RREG, RLINK);
1864 	mem(Ldw, O(REG, FP), RREG, RFP);
1865 	mem(Ldw, O(REG, MP), RREG, RMP);
1866 	RETURN;
1867 	flushcon(0);
1868 }
1869 
1870 static void
1871 maccolr(void)
1872 {
1873 	/* color the pointer in RA1 */
1874 	mem(Ldw, O(Heap, ref)-sizeof(Heap), RA1, RA0);
1875 	DPI(AL, Add, RA0, RA0, 0, 1);
1876 	mem(Stw, O(Heap, ref)-sizeof(Heap), RA1, RA0);	// h->ref++
1877 	con((ulong)&mutator, RA2, 1);
1878 	mem(Ldw, O(Heap, color)-sizeof(Heap), RA1, RA0);
1879 	mem(Ldw, 0, RA2, RA2);
1880 	CMP(AL, RA0, 0, 0, RA2);
1881 	CRETURN(EQ);	// return if h->color == mutator
1882 	con(propagator, RA2, 1);
1883 	mem(Stw, O(Heap, color)-sizeof(Heap), RA1, RA2);	// h->color = propagator
1884 	con((ulong)&nprop, RA2, 1);
1885 	mem(Stw, 0, RA2, RA2);	// nprop = !0
1886 	RETURN;
1887 	flushcon(0);
1888 }
1889 
1890 static void
1891 macret(void)
1892 {
1893 	Inst i;
1894 	ulong *cp1, *cp2, *cp3, *cp4, *cp5, *linterp;
1895 
1896 	CMPI(AL, RA1, 0, 0, 0);
1897 	cp1 = code;
1898 	BRA(EQ, 0);				// t(Rfp) == 0
1899 
1900 	mem(Ldw, O(Type,destroy),RA1, RA0);
1901 	CMPI(AL, RA0, 0, 0, 0);
1902 	cp2 = code;
1903 	BRA(EQ, 0);				// destroy(t(fp)) == 0
1904 
1905 	mem(Ldw, O(Frame,fp),RFP, RA2);
1906 	CMPI(AL, RA2, 0, 0, 0);
1907 	cp3 = code;
1908 	BRA(EQ, 0);				// fp(Rfp) == 0
1909 
1910 	mem(Ldw, O(Frame,mr),RFP, RA3);
1911 	CMPI(AL, RA3, 0, 0, 0);
1912 	cp4 = code;
1913 	BRA(EQ, 0);				// mr(Rfp) == 0
1914 
1915 	mem(Ldw, O(REG,M),RREG, RA2);
1916 	mem(Ldw, O(Heap,ref)-sizeof(Heap),RA2, RA3);
1917 	DPI(AL, Sub, RA3, RA3, 0, 1) | SBIT;
1918 	cp5 = code;
1919 	BRA(EQ, 0);				// --ref(arg) == 0
1920 	mem(Stw, O(Heap,ref)-sizeof(Heap),RA2, RA3);
1921 
1922 	mem(Ldw, O(Frame,mr),RFP, RA1);
1923 	mem(Stw, O(REG,M),RREG, RA1);
1924 	mem(Ldw, O(Modlink,MP),RA1, RMP);
1925 	mem(Stw, O(REG,MP),RREG, RMP);
1926 	mem(Ldw, O(Modlink,compiled), RA1, RA3);	// R.M->compiled
1927 	CMPI(AL, RA3, 0, 0, 0);
1928 	linterp = code;
1929 	BRA(EQ, 0);
1930 
1931 	PATCH(cp4);
1932 	MOV(R15, R14);		// call destroy(t(fp))
1933 	MOV(RA0, R15);
1934 
1935 	mem(Stw, O(REG,SP),RREG, RFP);
1936 	mem(Ldw, O(Frame,lr),RFP, RA1);
1937 	mem(Ldw, O(Frame,fp),RFP, RFP);
1938 	mem(Stw, O(REG,FP),RREG, RFP);	// R.FP = RFP
1939 	DP(AL, Mov, 0, R15, 0, RA1);		// goto lr(Rfp), if compiled
1940 
1941 	PATCH(linterp);
1942 	MOV(R15, R14);		// call destroy(t(fp))
1943 	MOV(RA0, R15);
1944 
1945 	mem(Stw, O(REG,SP),RREG, RFP);
1946 	mem(Ldw, O(Frame,lr),RFP, RA1);
1947 	mem(Ldw, O(Frame,fp),RFP, RFP);
1948 	mem(Stw, O(REG,PC),RREG, RA1);	// R.PC = fp->lr
1949 	mem(Stw, O(REG,FP),RREG, RFP);	// R.FP = RFP
1950 	mem(Ldw, O(REG, xpc), RREG, RLINK);
1951 	RETURN;		// return to xec uncompiled code
1952 
1953 	PATCH(cp1);
1954 	PATCH(cp2);
1955 	PATCH(cp3);
1956 	PATCH(cp5);
1957 	i.add = AXNON;
1958 	punt(&i, TCHECK|NEWPC, optab[IRET]);
1959 }
1960 
1961 static void
1962 macmcal(void)
1963 {
1964 	ulong *lab;
1965 
1966 	CMPH(AL, RA0);
1967 	memc(NE, Ldw, O(Modlink, prog), RA3, RA1);	// RA0 != H
1968 	CMPI(NE, RA1, 0, 0, 0);	// RA0 != H
1969 	lab = code;
1970 	BRA(NE, 0);	// RA0 != H && m->prog!=0
1971 
1972 	mem(Stw, O(REG, st), RREG, RLINK);
1973 	mem(Stw, O(REG, FP), RREG, RA2);
1974 	mem(Stw, O(REG, dt), RREG, RA0);
1975 	CALL(rmcall);				// CALL rmcall
1976 
1977 	con((ulong)&R, RREG, 1);		// MOVL	$R, RREG
1978 	mem(Ldw, O(REG, st), RREG, RLINK);
1979 	mem(Ldw, O(REG, FP), RREG, RFP);
1980 	mem(Ldw, O(REG, MP), RREG, RMP);
1981 	RETURN;
1982 
1983 	PATCH(lab);				// patch:
1984 	DP(AL, Mov, 0, RFP, 0, RA2);
1985 	mem(Stw, O(REG, M), RREG, RA3);	// MOVL RA3, R.M
1986 	mem(Ldw, O(Heap, ref)-sizeof(Heap), RA3, RA1);
1987 	DPI(AL, Add, RA1, RA1, 0, 1);
1988 	mem(Stw, O(Heap, ref)-sizeof(Heap), RA3, RA1);
1989 	mem(Ldw, O(Modlink, MP), RA3, RMP);	// MOVL R.M->mp, RMP
1990 	mem(Stw, O(REG, MP), RREG, RMP);	// MOVL RA3, R.MP	R.MP = ml->m
1991 	mem(Ldw, O(Modlink,compiled), RA3, RA1);	// M.compiled?
1992 	CMPI(AL, RA1, 0, 0, 0);
1993 	DP(NE, Mov, 0, R15, 0, RA0);	// return to compiled code
1994 	mem(Stw, O(REG,FP),RREG, RFP);	// R.FP = RFP
1995 	mem(Stw, O(REG,PC),RREG, RA0);	// R.PC = RPC
1996 	mem(Ldw, O(REG, xpc), RREG, RLINK);
1997 	RETURN;		// return to xec uncompiled code
1998 	flushcon(0);
1999 }
2000 
2001 static void
2002 macfram(void)
2003 {
2004 	ulong *lab1;
2005 
2006 	mem(Ldw, O(REG, SP), RREG, RA0);	// MOVL	R.SP, RA0
2007 	mem(Ldw, O(Type, size), RA3, RA1);
2008 	DP(AL, Add, RA0, RA0, 0, RA1);		// nsp = R.SP + t->size
2009 	mem(Ldw, O(REG, TS), RREG, RA1);
2010 	CMP(AL, RA0, 0, 0, RA1);	// nsp :: R.TS
2011 	lab1 = code;
2012 	BRA(CS, 0);	// nsp >= R.TS; must expand
2013 
2014 	mem(Ldw, O(REG, SP), RREG, RA2);	// MOVL	R.SP, RA2
2015 	mem(Stw, O(REG, SP), RREG, RA0);	// MOVL	RA0, R.SP
2016 
2017 	mem(Stw, O(Frame, t), RA2, RA3);	// MOVL	RA3, t(RA2) f->t = t
2018 	con(0, RA0, 1);
2019 	mem(Stw, O(Frame,mr), RA2, RA0);     	// MOVL $0, mr(RA2) f->mr
2020 	mem(Ldw, O(Type, initialize), RA3, R15);	// become t->init(RA2), returning RA2
2021 
2022 	PATCH(lab1);
2023 	mem(Stw, O(REG, s), RREG, RA3);
2024 	mem(Stw, O(REG, st), RREG, RLINK);
2025 	mem(Stw, O(REG, FP), RREG, RFP);	// MOVL	RFP, R.FP
2026 	CALL(extend);				// CALL	extend
2027 
2028 	con((ulong)&R, RREG, 1);
2029 	mem(Ldw, O(REG, st), RREG, RLINK);
2030 	mem(Ldw, O(REG, FP), RREG, RFP);	// MOVL	R.FP, RFP
2031 	mem(Ldw, O(REG, s), RREG, RA2);	// MOVL	R.s, *R.d
2032 	mem(Ldw, O(REG, MP), RREG, RMP);	// MOVL R.MP, RMP
2033 	RETURN;					// RET
2034 }
2035 
2036 static void
2037 macmfra(void)
2038 {
2039 	mem(Stw, O(REG, st), RREG, RLINK);
2040 	mem(Stw, O(REG, s), RREG, RA3);	// Save type
2041 	mem(Stw, O(REG, d), RREG, RA0);	// Save destination
2042 	mem(Stw, O(REG, FP), RREG, RFP);
2043 	CALL(rmfram);				// CALL rmfram
2044 
2045 	con((ulong)&R, RREG, 1);
2046 	mem(Ldw, O(REG, st), RREG, RLINK);
2047 	mem(Ldw, O(REG, FP), RREG, RFP);
2048 	mem(Ldw, O(REG, MP), RREG, RMP);
2049 	RETURN;
2050 }
2051 
2052 static void
2053 macrelq(void)
2054 {
2055 	mem(Stw, O(REG,FP),RREG, RFP);	// R.FP = RFP
2056 	mem(Stw, O(REG,PC),RREG, RLINK);	// R.PC = RLINK
2057 	mem(Ldw, O(REG, xpc), RREG, RLINK);
2058 	RETURN;
2059 }
2060 
2061 void
2062 comd(Type *t)
2063 {
2064 	int i, j, m, c;
2065 
2066 	mem(Stw, O(REG, dt), RREG, RLINK);
2067 	for(i = 0; i < t->np; i++) {
2068 		c = t->map[i];
2069 		j = i<<5;
2070 		for(m = 0x80; m != 0; m >>= 1) {
2071 			if(c & m) {
2072 				mem(Ldw, j, RFP, RA0);
2073 				CALL(base+macro[MacFRP]);
2074 			}
2075 			j += sizeof(WORD*);
2076 		}
2077 		flushchk();
2078 	}
2079 	mem(Ldw, O(REG, dt), RREG, RLINK);
2080 	RETURN;
2081 	flushcon(0);
2082 }
2083 
2084 void
2085 comi(Type *t)
2086 {
2087 	int i, j, m, c;
2088 
2089 	con((ulong)H, RA0, 1);
2090 	for(i = 0; i < t->np; i++) {
2091 		c = t->map[i];
2092 		j = i<<5;
2093 		for(m = 0x80; m != 0; m >>= 1) {
2094 			if(c & m)
2095 				mem(Stw, j, RA2, RA0);
2096 			j += sizeof(WORD*);
2097 		}
2098 		flushchk();
2099 	}
2100 	RETURN;
2101 	flushcon(0);
2102 }
2103 
2104 void
2105 typecom(Type *t)
2106 {
2107 	int n;
2108 	ulong *tmp, *start;
2109 
2110 	if(t == nil || t->initialize != 0)
2111 		return;
2112 
2113 	tmp = mallocz(4096*sizeof(ulong), 0);
2114 	if(tmp == nil)
2115 		error(exNomem);
2116 
2117 	code = tmp;
2118 	comi(t);
2119 	n = code - tmp;
2120 	code = tmp;
2121 	comd(t);
2122 	n += code - tmp;
2123 	free(tmp);
2124 
2125 	n *= sizeof(*code);
2126 	code = mallocz(n, 0);
2127 	if(code == nil)
2128 		return;
2129 
2130 	start = code;
2131 	t->initialize = code;
2132 	comi(t);
2133 	t->destroy = code;
2134 	comd(t);
2135 
2136 	segflush(start, n);
2137 
2138 	if(cflag > 3)
2139 		print("typ= %.8p %4d i %.8p d %.8p asm=%d\n",
2140 			t, t->size, t->initialize, t->destroy, n);
2141 }
2142 
2143 static void
2144 patchex(Module *m, ulong *p)
2145 {
2146 	Handler *h;
2147 	Except *e;
2148 
2149 	if((h = m->htab) == nil)
2150 		return;
2151 	for( ; h->etab != nil; h++){
2152 		h->pc1 = p[h->pc1];
2153 		h->pc2 = p[h->pc2];
2154 		for(e = h->etab; e->s != nil; e++)
2155 			e->pc = p[e->pc];
2156 		if(e->pc != -1)
2157 			e->pc = p[e->pc];
2158 	}
2159 }
2160 
2161 int
2162 compile(Module *m, int size, Modlink *ml)
2163 {
2164 	Link *l;
2165 	Modl *e;
2166 	int i, n;
2167 	ulong *s, *tmp;
2168 
2169 	base = nil;
2170 	patch = mallocz(size*sizeof(*patch), 0);
2171 	tinit = malloc(m->ntype*sizeof(*tinit));
2172 	tmp = malloc(4096*sizeof(ulong));
2173 	if(tinit == nil || patch == nil || tmp == nil)
2174 		goto bad;
2175 
2176 	preamble();
2177 
2178 	mod = m;
2179 	n = 0;
2180 	pass = 0;
2181 	nlit = 0;
2182 
2183 	for(i = 0; i < size; i++) {
2184 		codeoff = n;
2185 		code = tmp;
2186 		comp(&m->prog[i]);
2187 		patch[i] = n;
2188 		n += code - tmp;
2189 	}
2190 
2191 	for(i = 0; i < nelem(mactab); i++) {
2192 		codeoff = n;
2193 		code = tmp;
2194 		mactab[i].gen();
2195 		macro[mactab[i].idx] = n;
2196 		n += code - tmp;
2197 	}
2198 	code = tmp;
2199 	flushcon(0);
2200 	n += code - tmp;
2201 
2202 	base = mallocz((n+nlit)*sizeof(*code), 0);
2203 	if(base == nil)
2204 		goto bad;
2205 
2206 	if(cflag > 3)
2207 		print("dis=%5d %5d 386=%5d asm=%.8p: %s\n",
2208 			size, size*sizeof(Inst), n, base, m->name);
2209 
2210 	pass++;
2211 	nlit = 0;
2212 	litpool = base+n;
2213 	code = base;
2214 	n = 0;
2215 	codeoff = 0;
2216 	for(i = 0; i < size; i++) {
2217 		s = code;
2218 		comp(&m->prog[i]);
2219 		if(patch[i] != n) {
2220 			print("%3d %D\n", i, &m->prog[i]);
2221 			print("%lud != %d\n", patch[i], n);
2222 			urk("phase error");
2223 		}
2224 		n += code - s;
2225 		if(cflag > 4) {
2226 			print("%3d %D\n", i, &m->prog[i]);
2227 			das(s, code-s);
2228 		}
2229 	}
2230 
2231 	for(i = 0; i < nelem(mactab); i++) {
2232 		s = code;
2233 		mactab[i].gen();
2234 		if(macro[mactab[i].idx] != n){
2235 			print("mac phase err: %lud != %d\n", macro[mactab[i].idx], n);
2236 			urk("phase error");
2237 		}
2238 		n += code - s;
2239 		if(cflag > 4) {
2240 			print("%s:\n", mactab[i].name);
2241 			das(s, code-s);
2242 		}
2243 	}
2244 	s = code;
2245 	flushcon(0);
2246 	n += code - s;
2247 
2248 	for(l = m->ext; l->name; l++) {
2249 		l->u.pc = (Inst*)RELPC(patch[l->u.pc-m->prog]);
2250 		typecom(l->frame);
2251 	}
2252 	if(ml != nil) {
2253 		e = &ml->links[0];
2254 		for(i = 0; i < ml->nlinks; i++) {
2255 			e->u.pc = (Inst*)RELPC(patch[e->u.pc-m->prog]);
2256 			typecom(e->frame);
2257 			e++;
2258 		}
2259 	}
2260 	for(i = 0; i < m->ntype; i++) {
2261 		if(tinit[i] != 0)
2262 			typecom(m->type[i]);
2263 	}
2264 	patchex(m, patch);
2265 	m->entry = (Inst*)RELPC(patch[mod->entry-mod->prog]);
2266 	free(patch);
2267 	free(tinit);
2268 	free(tmp);
2269 	free(m->prog);
2270 	m->prog = (Inst*)base;
2271 	m->compiled = 1;
2272 	segflush(base, n*sizeof(*base));
2273 	return 1;
2274 bad:
2275 	free(patch);
2276 	free(tinit);
2277 	free(base);
2278 	free(tmp);
2279 	return 0;
2280 }
2281