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