xref: /inferno-os/libinterp/comp-arm.c (revision d90014f6464dd122afdd1a8cd81933e72c72619a)
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 			if(sizeof(Rune) == 4){
1568 				DP(LT, Mov, 0, RA2, (2<<3), RA2);
1569 				LDRW(LT, RA1, RA3, RA2);
1570 			}else{
1571 				DP(LT, Mov, 0, RA2, (1<<3), RA2);
1572 				LDRH(LT, RA1, RA3, RA2);
1573 			}
1574 			if(bflag)
1575 				BCK(RA2, RA0);
1576 		}
1577 		opwst(i, Stw, RA3);
1578 		break;
1579 	case IINDL:
1580 	case IINDF:
1581 	case IINDW:
1582 	case IINDB:
1583 		opwld(i, Ldw, RA0);			/* a */
1584 		NOTNIL(RA0);
1585 		mem(Ldw, O(Array, data), RA0, RA0);
1586 		if(bflag)
1587 			mem(Ldw, O(Array, len), RA0, RA2);
1588 		r = 0;
1589 		switch(i->op) {
1590 		case IINDL:
1591 		case IINDF:
1592 			r = 3;
1593 			break;
1594 		case IINDW:
1595 			r = 2;
1596 			break;
1597 		}
1598 		if(UXDST(i->add) == DST(AIMM) && FITS8(i->d.imm<<r)) {
1599 			if(bflag)
1600 				BCKI(i->d.imm, RA2);
1601 			DPI(AL, Add, RA0, RA0, 0, (i->d.imm<<r));
1602 		} else {
1603 			opwst(i, Ldw, RA1);
1604 			if(bflag)
1605 				BCK(RA1, RA2);
1606 			DP(AL, Add, RA0, RA0, r<<3, RA1);
1607 		}
1608 		mid(i, Stw, RA0);
1609 		break;
1610 	case IINDX:
1611 		opwld(i, Ldw, RA0);			/* a */
1612 		NOTNIL(RA0);
1613 		opwst(i, Ldw, RA1);			/* i */
1614 
1615 		if(bflag){
1616 			mem(Ldw, O(Array, len), RA0, RA2);
1617 			BCK(RA1, RA2);
1618 		}
1619 		mem(Ldw, O(Array, t), RA0, RA2);
1620 		mem(Ldw, O(Array, data), RA0, RA0);
1621 		mem(Ldw, O(Type, size), RA2, RA2);
1622 		MUL(AL, RA2, RA1, RA1);
1623 		DP(AL, Add, RA1, RA0, 0, RA0);
1624 		mid(i, Stw, RA0);
1625 		break;
1626 	case IADDL:
1627 		larith(i, Add, Adc);
1628 		break;
1629 	case ISUBL:
1630 		larith(i, Sub, Sbc);
1631 		break;
1632 	case IORL:
1633 		larith(i, Orr, Orr);
1634 		break;
1635 	case IANDL:
1636 		larith(i, And, And);
1637 		break;
1638 	case IXORL:
1639 		larith(i, Eor, Eor);
1640 		break;
1641 	case ICVTWL:
1642 		opwld(i, Ldw, RA1);
1643 		opwst(i, Lea, RA2);
1644 		DP(AL, Mov, 0, RA0, (0<<3)|(2<<1), RA1);	// ASR 32
1645 		STW(AL, RA2, RA1, Blo);
1646 		STW(AL, RA2, RA0, Bhi);
1647 		break;
1648 	case ICVTLW:
1649 		opwld(i, Lea, RA0);
1650 		mem(Ldw, Blo, RA0, RA0);
1651 		opwst(i, Stw, RA0);
1652 		break;
1653 	case IBEQL:
1654 		cbral(i, NE, EQ, ANDAND);
1655 		break;
1656 	case IBNEL:
1657 		cbral(i, NE, NE, OROR);
1658 		break;
1659 	case IBLEL:
1660 		cbral(i, LT, LS, EQAND);
1661 		break;
1662 	case IBGTL:
1663 		cbral(i, GT, HI, EQAND);
1664 		break;
1665 	case IBLTL:
1666 		cbral(i, LT, CC, EQAND);
1667 		break;
1668 	case IBGEL:
1669 		cbral(i, GT, CS, EQAND);
1670 		break;
1671 	case ICVTFL:
1672 	case ICVTLF:
1673 		punt(i, SRCOP|DSTOP, optab[i->op]);
1674 		break;
1675 	case IDIVF:
1676 		r = Dvf;
1677 		goto arithf;
1678 	case IMULF:
1679 		r = Muf;
1680 		goto arithf;
1681 	case ISUBF:
1682 		r = Suf;
1683 		goto arithf;
1684 	case IADDF:
1685 		r = Adf;
1686 	arithf:
1687 		if(1){
1688 			/* software fp */
1689 			punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
1690 			break;
1691 		}
1692 		opflld(i, Ldf, FA2);
1693 		midfl(i, Ldf, FA4);
1694 		CPDO2(AL, r, FA4, FA4, FA2);
1695 		opflst(i, Stf, FA4);
1696 		break;
1697 	case INEGF:
1698 		if(1){
1699 			punt(i, SRCOP|DSTOP, optab[i->op]);
1700 			break;
1701 		}
1702 		opflld(i, Ldf, FA2);
1703 		CPDO1(AL, Mnf, FA2, FA2);
1704 		opflst(i, Stf, FA2);
1705 //if(pass){print("%D\n", i); das(s, code-s);}
1706 		break;
1707 	case ICVTWF:
1708 		if(1){
1709 			punt(i, SRCOP|DSTOP, optab[i->op]);
1710 			break;
1711 		}
1712 		opwld(i, Ldw, RA2);
1713 		CPFLT(AL, FA2, RA2);
1714 		opflst(i, Stf, FA2);
1715 //if(pass){print("%D\n", i); das(s, code-s);}
1716 		break;
1717 	case ICVTFW:
1718 		if(1){
1719 			punt(i, SRCOP|DSTOP, optab[i->op]);
1720 			break;
1721 		}
1722 		opflld(i, Ldf, FA2);
1723 		CPFIX(AL, RA2, FA2);
1724 		opwst(i, Stw, RA2);
1725 //if(pass){print("%D\n", i); das(s, code-s);}
1726 		break;
1727 	case ISHLL:
1728 		/* should do better */
1729 		punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
1730 		break;
1731 	case ISHRL:
1732 		/* should do better */
1733 		punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
1734 		break;
1735 	case IRAISE:
1736 		punt(i, SRCOP|WRTPC|NEWPC, optab[i->op]);
1737 		break;
1738 	case IMULX:
1739 	case IDIVX:
1740 	case ICVTXX:
1741 	case IMULX0:
1742 	case IDIVX0:
1743 	case ICVTXX0:
1744 	case IMULX1:
1745 	case IDIVX1:
1746 	case ICVTXX1:
1747 	case ICVTFX:
1748 	case ICVTXF:
1749 	case IEXPW:
1750 	case IEXPL:
1751 	case IEXPF:
1752 		punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
1753 		break;
1754 	case ISELF:
1755 		punt(i, DSTOP, optab[i->op]);
1756 		break;
1757 	}
1758 }
1759 
1760 static void
1761 preamble(void)
1762 {
1763 	if(comvec)
1764 		return;
1765 
1766 	comvec = malloc(10 * sizeof(*code));
1767 	if(comvec == nil)
1768 		error(exNomem);
1769 	code = (ulong*)comvec;
1770 
1771 	con((ulong)&R, RREG, 0);
1772 	mem(Stw, O(REG, xpc), RREG, RLINK);
1773 	mem(Ldw, O(REG, FP), RREG, RFP);
1774 	mem(Ldw, O(REG, MP), RREG, RMP);
1775 	mem(Ldw, O(REG, PC), RREG, R15);
1776 	pass++;
1777 	flushcon(0);
1778 	pass--;
1779 
1780 	segflush(comvec, 10 * sizeof(*code));
1781 }
1782 
1783 static void
1784 maccase(void)
1785 {
1786 	ulong *cp1, *loop, *inner;
1787 /*
1788  * RA1 = value (input arg), t
1789  * RA2 = count, n
1790  * RA3 = table pointer (input arg)
1791  * RA0  = n/2, n2
1792  * RCON  = pivot element t+n/2*3, l
1793  */
1794 	LDW(AL, RA3, RA2, 0);	// count from table
1795 	MOV(RA3, RLINK);	// initial table pointer
1796 
1797 	loop = code;			// loop:
1798 	CMPI(AL, RA2, 0, 0, 0);
1799 	cp1 = code;
1800 	BRA(LE, 0);	// n <= 0? goto out
1801 
1802 	inner = code;
1803 	DP(AL, Mov, 0, RA0, (1<<3)|2, RA2);	// n2 = n>>1
1804 	DP(AL, Add, RA0, RCON, (1<<3), RA0);	// n' = n2+(n2<<1) = 3*n2
1805 	DP(AL, Add, RA3, RCON, (2<<3), RCON);	// l = t + n2*3;
1806 
1807 	LDW(AL, RCON, RTA, 4);
1808 	CMP(AL, RA1, 0, 0, RTA);
1809 	DP(LT, Mov, 0, RA2, 0, RA0);	// v < l[1]? n=n2
1810 	BRANCH(LT, loop);	// v < l[1]? goto loop
1811 
1812 	LDW(AL, RCON, RTA, 8);
1813 	CMP(AL, RA1, 0, 0, RTA);
1814 	LDW(LT, RCON, R15, 12);	// v >= l[1] && v < l[2] => found; goto l[3]
1815 
1816 	// v >= l[2] (high)
1817 	DPI(AL, Add, RCON, RA3, 0, 12);	// t = l+3;
1818 	DPI(AL, Add, RA0, RTA, 0, 1);
1819 	DP(AL, Sub, RA2, RA2, 0, RTA) | SBIT;	// n -= n2+1
1820 	BRANCH(GT, inner);	// n > 0? goto loop
1821 
1822 	PATCH(cp1);	// out:
1823 	LDW(AL, RLINK, RA2, 0);		// initial n
1824 	DP(AL, Add, RA2, RA2, (1<<3), RA2);	// n = n+(n<<1) = 3*n
1825 	DP(AL, Add, RLINK, RLINK, (2<<3), RA2);	// t' = &(initial t)[n*3]
1826 	LDW(AL, RLINK, R15, 4);		// goto (initial t)[n*3+1]
1827 }
1828 
1829 static void
1830 macfrp(void)
1831 {
1832 	/* destroy the pointer in RA0 */
1833 	CMPH(AL, RA0);
1834 	CRETURN(EQ);		// arg == H? => return
1835 
1836 	mem(Ldw, O(Heap, ref)-sizeof(Heap), RA0, RA2);
1837 	DPI(AL, Sub, RA2, RA2, 0, 1) | SBIT;
1838 	memc(NE, Stw, O(Heap, ref)-sizeof(Heap), RA0, RA2);
1839 	CRETURN(NE);		// --h->ref != 0 => return
1840 
1841 	mem(Stw, O(REG, FP), RREG, RFP);
1842 	mem(Stw, O(REG, st), RREG, RLINK);
1843 	mem(Stw, O(REG, s), RREG, RA0);
1844 	CALL(rdestroy);
1845 	con((ulong)&R, RREG, 1);
1846 	mem(Ldw, O(REG, st), RREG, RLINK);
1847 	mem(Ldw, O(REG, FP), RREG, RFP);
1848 	mem(Ldw, O(REG, MP), RREG, RMP);
1849 	RETURN;
1850 	flushcon(0);
1851 }
1852 
1853 static void
1854 maccolr(void)
1855 {
1856 	/* color the pointer in RA1 */
1857 	mem(Ldw, O(Heap, ref)-sizeof(Heap), RA1, RA0);
1858 	DPI(AL, Add, RA0, RA0, 0, 1);
1859 	mem(Stw, O(Heap, ref)-sizeof(Heap), RA1, RA0);	// h->ref++
1860 	con((ulong)&mutator, RA2, 1);
1861 	mem(Ldw, O(Heap, color)-sizeof(Heap), RA1, RA0);
1862 	mem(Ldw, 0, RA2, RA2);
1863 	CMP(AL, RA0, 0, 0, RA2);
1864 	CRETURN(EQ);	// return if h->color == mutator
1865 	con(propagator, RA2, 1);
1866 	mem(Stw, O(Heap, color)-sizeof(Heap), RA1, RA2);	// h->color = propagator
1867 	con((ulong)&nprop, RA2, 1);
1868 	mem(Stw, 0, RA2, RA2);	// nprop = !0
1869 	RETURN;
1870 	flushcon(0);
1871 }
1872 
1873 static void
1874 macret(void)
1875 {
1876 	Inst i;
1877 	ulong *cp1, *cp2, *cp3, *cp4, *cp5, *linterp;
1878 
1879 	CMPI(AL, RA1, 0, 0, 0);
1880 	cp1 = code;
1881 	BRA(EQ, 0);				// t(Rfp) == 0
1882 
1883 	mem(Ldw, O(Type,destroy),RA1, RA0);
1884 	CMPI(AL, RA0, 0, 0, 0);
1885 	cp2 = code;
1886 	BRA(EQ, 0);				// destroy(t(fp)) == 0
1887 
1888 	mem(Ldw, O(Frame,fp),RFP, RA2);
1889 	CMPI(AL, RA2, 0, 0, 0);
1890 	cp3 = code;
1891 	BRA(EQ, 0);				// fp(Rfp) == 0
1892 
1893 	mem(Ldw, O(Frame,mr),RFP, RA3);
1894 	CMPI(AL, RA3, 0, 0, 0);
1895 	cp4 = code;
1896 	BRA(EQ, 0);				// mr(Rfp) == 0
1897 
1898 	mem(Ldw, O(REG,M),RREG, RA2);
1899 	mem(Ldw, O(Heap,ref)-sizeof(Heap),RA2, RA3);
1900 	DPI(AL, Sub, RA3, RA3, 0, 1) | SBIT;
1901 	cp5 = code;
1902 	BRA(EQ, 0);				// --ref(arg) == 0
1903 	mem(Stw, O(Heap,ref)-sizeof(Heap),RA2, RA3);
1904 
1905 	mem(Ldw, O(Frame,mr),RFP, RA1);
1906 	mem(Stw, O(REG,M),RREG, RA1);
1907 	mem(Ldw, O(Modlink,MP),RA1, RMP);
1908 	mem(Stw, O(REG,MP),RREG, RMP);
1909 	mem(Ldw, O(Modlink,compiled), RA1, RA3);	// R.M->compiled
1910 	CMPI(AL, RA3, 0, 0, 0);
1911 	linterp = code;
1912 	BRA(EQ, 0);
1913 
1914 	PATCH(cp4);
1915 	MOV(R15, R14);		// call destroy(t(fp))
1916 	MOV(RA0, R15);
1917 
1918 	mem(Stw, O(REG,SP),RREG, RFP);
1919 	mem(Ldw, O(Frame,lr),RFP, RA1);
1920 	mem(Ldw, O(Frame,fp),RFP, RFP);
1921 	mem(Stw, O(REG,FP),RREG, RFP);	// R.FP = RFP
1922 	DP(AL, Mov, 0, R15, 0, RA1);		// goto lr(Rfp), if compiled
1923 
1924 	PATCH(linterp);
1925 	MOV(R15, R14);		// call destroy(t(fp))
1926 	MOV(RA0, R15);
1927 
1928 	mem(Stw, O(REG,SP),RREG, RFP);
1929 	mem(Ldw, O(Frame,lr),RFP, RA1);
1930 	mem(Ldw, O(Frame,fp),RFP, RFP);
1931 	mem(Stw, O(REG,PC),RREG, RA1);	// R.PC = fp->lr
1932 	mem(Stw, O(REG,FP),RREG, RFP);	// R.FP = RFP
1933 	mem(Ldw, O(REG, xpc), RREG, RLINK);
1934 	RETURN;		// return to xec uncompiled code
1935 
1936 	PATCH(cp1);
1937 	PATCH(cp2);
1938 	PATCH(cp3);
1939 	PATCH(cp5);
1940 	i.add = AXNON;
1941 	punt(&i, TCHECK|NEWPC, optab[IRET]);
1942 }
1943 
1944 static void
1945 macmcal(void)
1946 {
1947 	ulong *lab;
1948 
1949 	CMPH(AL, RA0);
1950 	memc(NE, Ldw, O(Modlink, prog), RA3, RA1);	// RA0 != H
1951 	CMPI(NE, RA1, 0, 0, 0);	// RA0 != H
1952 	lab = code;
1953 	BRA(NE, 0);	// RA0 != H && m->prog!=0
1954 
1955 	mem(Stw, O(REG, st), RREG, RLINK);
1956 	mem(Stw, O(REG, FP), RREG, RA2);
1957 	mem(Stw, O(REG, dt), RREG, RA0);
1958 	CALL(rmcall);				// CALL rmcall
1959 
1960 	con((ulong)&R, RREG, 1);		// MOVL	$R, RREG
1961 	mem(Ldw, O(REG, st), RREG, RLINK);
1962 	mem(Ldw, O(REG, FP), RREG, RFP);
1963 	mem(Ldw, O(REG, MP), RREG, RMP);
1964 	RETURN;
1965 
1966 	PATCH(lab);				// patch:
1967 	DP(AL, Mov, 0, RFP, 0, RA2);
1968 	mem(Stw, O(REG, M), RREG, RA3);	// MOVL RA3, R.M
1969 	mem(Ldw, O(Heap, ref)-sizeof(Heap), RA3, RA1);
1970 	DPI(AL, Add, RA1, RA1, 0, 1);
1971 	mem(Stw, O(Heap, ref)-sizeof(Heap), RA3, RA1);
1972 	mem(Ldw, O(Modlink, MP), RA3, RMP);	// MOVL R.M->mp, RMP
1973 	mem(Stw, O(REG, MP), RREG, RMP);	// MOVL RA3, R.MP	R.MP = ml->m
1974 	mem(Ldw, O(Modlink,compiled), RA3, RA1);	// M.compiled?
1975 	CMPI(AL, RA1, 0, 0, 0);
1976 	DP(NE, Mov, 0, R15, 0, RA0);	// return to compiled code
1977 	mem(Stw, O(REG,FP),RREG, RFP);	// R.FP = RFP
1978 	mem(Stw, O(REG,PC),RREG, RA0);	// R.PC = RPC
1979 	mem(Ldw, O(REG, xpc), RREG, RLINK);
1980 	RETURN;		// return to xec uncompiled code
1981 	flushcon(0);
1982 }
1983 
1984 static void
1985 macfram(void)
1986 {
1987 	ulong *lab1;
1988 
1989 	mem(Ldw, O(REG, SP), RREG, RA0);	// MOVL	R.SP, RA0
1990 	mem(Ldw, O(Type, size), RA3, RA1);
1991 	DP(AL, Add, RA0, RA0, 0, RA1);		// nsp = R.SP + t->size
1992 	mem(Ldw, O(REG, TS), RREG, RA1);
1993 	CMP(AL, RA0, 0, 0, RA1);	// nsp :: R.TS
1994 	lab1 = code;
1995 	BRA(CS, 0);	// nsp >= R.TS; must expand
1996 
1997 	mem(Ldw, O(REG, SP), RREG, RA2);	// MOVL	R.SP, RA2
1998 	mem(Stw, O(REG, SP), RREG, RA0);	// MOVL	RA0, R.SP
1999 
2000 	mem(Stw, O(Frame, t), RA2, RA3);	// MOVL	RA3, t(RA2) f->t = t
2001 	con(0, RA0, 1);
2002 	mem(Stw, O(Frame,mr), RA2, RA0);     	// MOVL $0, mr(RA2) f->mr
2003 	mem(Ldw, O(Type, initialize), RA3, R15);	// become t->init(RA2), returning RA2
2004 
2005 	PATCH(lab1);
2006 	mem(Stw, O(REG, s), RREG, RA3);
2007 	mem(Stw, O(REG, st), RREG, RLINK);
2008 	mem(Stw, O(REG, FP), RREG, RFP);	// MOVL	RFP, R.FP
2009 	CALL(extend);				// CALL	extend
2010 
2011 	con((ulong)&R, RREG, 1);
2012 	mem(Ldw, O(REG, st), RREG, RLINK);
2013 	mem(Ldw, O(REG, FP), RREG, RFP);	// MOVL	R.FP, RFP
2014 	mem(Ldw, O(REG, s), RREG, RA2);	// MOVL	R.s, *R.d
2015 	mem(Ldw, O(REG, MP), RREG, RMP);	// MOVL R.MP, RMP
2016 	RETURN;					// RET
2017 }
2018 
2019 static void
2020 macmfra(void)
2021 {
2022 	mem(Stw, O(REG, st), RREG, RLINK);
2023 	mem(Stw, O(REG, s), RREG, RA3);	// Save type
2024 	mem(Stw, O(REG, d), RREG, RA0);	// Save destination
2025 	mem(Stw, O(REG, FP), RREG, RFP);
2026 	CALL(rmfram);				// CALL rmfram
2027 
2028 	con((ulong)&R, RREG, 1);
2029 	mem(Ldw, O(REG, st), RREG, RLINK);
2030 	mem(Ldw, O(REG, FP), RREG, RFP);
2031 	mem(Ldw, O(REG, MP), RREG, RMP);
2032 	RETURN;
2033 }
2034 
2035 static void
2036 macrelq(void)
2037 {
2038 	mem(Stw, O(REG,FP),RREG, RFP);	// R.FP = RFP
2039 	mem(Stw, O(REG,PC),RREG, RLINK);	// R.PC = RLINK
2040 	mem(Ldw, O(REG, xpc), RREG, RLINK);
2041 	RETURN;
2042 }
2043 
2044 void
2045 comd(Type *t)
2046 {
2047 	int i, j, m, c;
2048 
2049 	mem(Stw, O(REG, dt), RREG, RLINK);
2050 	for(i = 0; i < t->np; i++) {
2051 		c = t->map[i];
2052 		j = i<<5;
2053 		for(m = 0x80; m != 0; m >>= 1) {
2054 			if(c & m) {
2055 				mem(Ldw, j, RFP, RA0);
2056 				CALL(base+macro[MacFRP]);
2057 			}
2058 			j += sizeof(WORD*);
2059 		}
2060 		flushchk();
2061 	}
2062 	mem(Ldw, O(REG, dt), RREG, RLINK);
2063 	RETURN;
2064 	flushcon(0);
2065 }
2066 
2067 void
2068 comi(Type *t)
2069 {
2070 	int i, j, m, c;
2071 
2072 	con((ulong)H, RA0, 1);
2073 	for(i = 0; i < t->np; i++) {
2074 		c = t->map[i];
2075 		j = i<<5;
2076 		for(m = 0x80; m != 0; m >>= 1) {
2077 			if(c & m)
2078 				mem(Stw, j, RA2, RA0);
2079 			j += sizeof(WORD*);
2080 		}
2081 		flushchk();
2082 	}
2083 	RETURN;
2084 	flushcon(0);
2085 }
2086 
2087 void
2088 typecom(Type *t)
2089 {
2090 	int n;
2091 	ulong *tmp, *start;
2092 
2093 	if(t == nil || t->initialize != 0)
2094 		return;
2095 
2096 	tmp = mallocz(4096*sizeof(ulong), 0);
2097 	if(tmp == nil)
2098 		error(exNomem);
2099 
2100 	code = tmp;
2101 	comi(t);
2102 	n = code - tmp;
2103 	code = tmp;
2104 	comd(t);
2105 	n += code - tmp;
2106 	free(tmp);
2107 
2108 	n *= sizeof(*code);
2109 	code = mallocz(n, 0);
2110 	if(code == nil)
2111 		return;
2112 
2113 	start = code;
2114 	t->initialize = code;
2115 	comi(t);
2116 	t->destroy = code;
2117 	comd(t);
2118 
2119 	segflush(start, n);
2120 
2121 	if(cflag > 3)
2122 		print("typ= %.8p %4d i %.8p d %.8p asm=%d\n",
2123 			t, t->size, t->initialize, t->destroy, n);
2124 }
2125 
2126 static void
2127 patchex(Module *m, ulong *p)
2128 {
2129 	Handler *h;
2130 	Except *e;
2131 
2132 	if((h = m->htab) == nil)
2133 		return;
2134 	for( ; h->etab != nil; h++){
2135 		h->pc1 = p[h->pc1];
2136 		h->pc2 = p[h->pc2];
2137 		for(e = h->etab; e->s != nil; e++)
2138 			e->pc = p[e->pc];
2139 		if(e->pc != -1)
2140 			e->pc = p[e->pc];
2141 	}
2142 }
2143 
2144 int
2145 compile(Module *m, int size, Modlink *ml)
2146 {
2147 	Link *l;
2148 	Modl *e;
2149 	int i, n;
2150 	ulong *s, *tmp;
2151 
2152 	base = nil;
2153 	patch = mallocz(size*sizeof(*patch), 0);
2154 	tinit = malloc(m->ntype*sizeof(*tinit));
2155 	tmp = malloc(4096*sizeof(ulong));
2156 	if(tinit == nil || patch == nil || tmp == nil)
2157 		goto bad;
2158 
2159 	preamble();
2160 
2161 	mod = m;
2162 	n = 0;
2163 	pass = 0;
2164 	nlit = 0;
2165 
2166 	for(i = 0; i < size; i++) {
2167 		codeoff = n;
2168 		code = tmp;
2169 		comp(&m->prog[i]);
2170 		patch[i] = n;
2171 		n += code - tmp;
2172 	}
2173 
2174 	for(i = 0; i < nelem(mactab); i++) {
2175 		codeoff = n;
2176 		code = tmp;
2177 		mactab[i].gen();
2178 		macro[mactab[i].idx] = n;
2179 		n += code - tmp;
2180 	}
2181 	code = tmp;
2182 	flushcon(0);
2183 	n += code - tmp;
2184 
2185 	base = mallocz((n+nlit)*sizeof(*code), 0);
2186 	if(base == nil)
2187 		goto bad;
2188 
2189 	if(cflag > 3)
2190 		print("dis=%5d %5d 386=%5d asm=%.8p: %s\n",
2191 			size, size*sizeof(Inst), n, base, m->name);
2192 
2193 	pass++;
2194 	nlit = 0;
2195 	litpool = base+n;
2196 	code = base;
2197 	n = 0;
2198 	codeoff = 0;
2199 	for(i = 0; i < size; i++) {
2200 		s = code;
2201 		comp(&m->prog[i]);
2202 		if(patch[i] != n) {
2203 			print("%3d %D\n", i, &m->prog[i]);
2204 			print("%lud != %d\n", patch[i], n);
2205 			urk("phase error");
2206 		}
2207 		n += code - s;
2208 		if(cflag > 4) {
2209 			print("%3d %D\n", i, &m->prog[i]);
2210 			das(s, code-s);
2211 		}
2212 	}
2213 
2214 	for(i = 0; i < nelem(mactab); i++) {
2215 		s = code;
2216 		mactab[i].gen();
2217 		if(macro[mactab[i].idx] != n){
2218 			print("mac phase err: %lud != %d\n", macro[mactab[i].idx], n);
2219 			urk("phase error");
2220 		}
2221 		n += code - s;
2222 		if(cflag > 4) {
2223 			print("%s:\n", mactab[i].name);
2224 			das(s, code-s);
2225 		}
2226 	}
2227 	s = code;
2228 	flushcon(0);
2229 	n += code - s;
2230 
2231 	for(l = m->ext; l->name; l++) {
2232 		l->u.pc = (Inst*)RELPC(patch[l->u.pc-m->prog]);
2233 		typecom(l->frame);
2234 	}
2235 	if(ml != nil) {
2236 		e = &ml->links[0];
2237 		for(i = 0; i < ml->nlinks; i++) {
2238 			e->u.pc = (Inst*)RELPC(patch[e->u.pc-m->prog]);
2239 			typecom(e->frame);
2240 			e++;
2241 		}
2242 	}
2243 	for(i = 0; i < m->ntype; i++) {
2244 		if(tinit[i] != 0)
2245 			typecom(m->type[i]);
2246 	}
2247 	patchex(m, patch);
2248 	m->entry = (Inst*)RELPC(patch[mod->entry-mod->prog]);
2249 	free(patch);
2250 	free(tinit);
2251 	free(tmp);
2252 	free(m->prog);
2253 	m->prog = (Inst*)base;
2254 	m->compiled = 1;
2255 	segflush(base, n*sizeof(*base));
2256 	return 1;
2257 bad:
2258 	free(patch);
2259 	free(tinit);
2260 	free(base);
2261 	free(tmp);
2262 	return 0;
2263 }
2264