[project @ 2000-03-13 10:53:55 by simonmar]
[ghc-hetmet.git] / ghc / rts / Assembler.c
1
2 /* --------------------------------------------------------------------------
3  * Bytecode assembler
4  *
5  * Copyright (c) 1994-1998.
6  *
7  * $RCSfile: Assembler.c,v $
8  * $Revision: 1.22 $
9  * $Date: 1999/12/07 11:49:09 $
10  *
11  * This module provides functions to construct BCOs and other closures
12  * required by the bytecode compiler.
13  *
14  * It is supposed to shield the compiler from platform dependent information
15  * such as:
16  *
17  * o sizeof(StgFloat)
18  * o sizeof(I#)
19  *
20  * and from details of how the abstract machine is implemented such as:
21  *
22  * o what does a BCO look like?
23  * o how many bytes does the "Push InfoTable" instruction require?
24  *
25  * Details of design:
26  * o (To handle letrecs) We allocate Aps, Paps and Cons using number of
27  *   heap allocated args to determine size.
28  *   We can't handle unboxed args :-(
29  * o All stack offsets are relative to position of Sp at start of
30  *   function or thunk (not BCO - consider continuations)
31  * o Active thunks must be roots during GC - how to achieve this?
32  * o Each BCO contains its own stack and heap check
33  *   We don't try to exploit the Hp check optimisation - easier to make
34  *   each thunk stand on its own.
35  * o asBind returns a "varid" (which is, in fact, a stack offset)
36  *   asVar acts on a "varid" - combining it with the current stack size to
37  *   determine actual position
38  * o Assembler.h uses totally neutral types: strings, floats, ints, etc
39  *   to minimise conflicts with other parts of the system.
40  * Simulated Stack
41  * ------------------------------------------------------------------------*/
42
43 #include "Rts.h"
44
45 #ifdef INTERPRETER
46
47 #include "RtsFlags.h"
48 #include "RtsUtils.h"
49 #include "Bytecodes.h"
50 #include "Printer.h"
51 #include "Disassembler.h"
52 #include "StgMiscClosures.h"
53 #include "Storage.h"
54 #include "Schedule.h"
55 #include "Evaluator.h"
56
57 #define INSIDE_ASSEMBLER_C
58 #include "Assembler.h"
59 #undef INSIDE_ASSEMBLER_C
60
61 /* --------------------------------------------------------------------------
62  * References between BCOs
63  *
64  * These are necessary because there can be circular references between 
65  * BCOs so we have to keep track of all the references to each object
66  * and fill in all the references once we're done.
67  *
68  * ToDo: generalise to allow references between any objects
69  * ------------------------------------------------------------------------*/
70
71 typedef struct {
72     AsmObject ref;  /* who refers to it                       */
73     AsmNat i;       /* index into some table held by referer  */
74 } AsmRef;
75
76 /* --------------------------------------------------------------------------
77  * Queues (of instructions, ptrs, nonptrs)
78  * ------------------------------------------------------------------------*/
79
80 #define Queue Instrs
81 #define Type  StgWord8
82 #define MAKE_findIn 0
83 #include "QueueTemplate.h"
84 #undef MAKE_findIn
85 #undef Type
86 #undef Queue
87
88 #define Queue Ptrs
89 #define Type  AsmObject
90 #define MAKE_findIn 0
91 #include "QueueTemplate.h"
92 #undef MAKE_findIn
93 #undef Type
94 #undef Queue
95
96 #define Queue Refs
97 #define Type  AsmRef
98 #define MAKE_findIn 0
99 #include "QueueTemplate.h"
100 #undef MAKE_findIn
101 #undef Type
102 #undef Queue
103
104 #define Queue NonPtrs
105 #define Type  StgWord
106 #define MAKE_findIn 1
107 #include "QueueTemplate.h"
108 #undef MAKE_findIn
109 #undef Type
110 #undef Queue
111
112 /* --------------------------------------------------------------------------
113  * AsmObjects are used to build heap objects.
114  *
115  * AsmObjects can contain circular references to each other
116  * so we have to keep track of all the references which can't be filled
117  * in yet.
118  *
119  * When we finish building an AsmObject, we allocate an actual heap object and
120  * fill in all the references to the asmObject with pointers to the heap object.
121  *
122  * We obtain a limited form of polymorphism through inheritance by putting 
123  * the AsmObject first in every structure (as in C++ implementations).
124  * We use the closure type of the allocated object to figure out
125  * where the payload lives in the closure.
126  * ------------------------------------------------------------------------*/
127 /* ToDo: clean up terminology: is Closure right or should it be object or ... */
128
129 struct AsmObject_ {
130     Refs           refs;
131     Ptrs           ptrs;
132     AsmNat         num_unresolved; /* number of unfilled references */
133     StgClosure*    closure;        /* where object was allocated    */
134 };
135     
136 struct AsmCon_ {
137     struct AsmObject_ object;  /* must be first in struct */
138
139     AsmInfo info;
140 };
141   
142 struct AsmCAF_ {
143     struct AsmObject_ object;  /* must be first in struct */
144 };
145
146 struct AsmBCO_ {
147     struct AsmObject_ object;  /* must be first in struct */
148
149     Instrs   is;          
150     NonPtrs  nps;
151
152     int /*StgExpr*/  stgexpr;    
153
154     /* abstract machine ("executed" during compilation) */
155     AsmSp    sp;          /* stack ptr */
156     AsmSp    max_sp;
157     Instr    lastOpc;
158 };
159
160 static void asmResolveRef( AsmObject obj, AsmNat i, AsmClosure reference )
161 {
162     ASSERT(obj->closure);
163     switch (get_itbl(obj->closure)->type) {
164     case BCO:
165         {
166             StgBCO* bco = stgCast(StgBCO*,obj->closure);
167             ASSERT(i < bco->n_ptrs && bcoConstPtr(bco,i) == NULL);
168             bcoConstCPtr(bco,i) = reference;
169             break;
170         }
171     case CAF_UNENTERED:
172         {
173             StgCAF* caf = stgCast(StgCAF*,obj->closure);
174             ASSERT(i == 0 && caf->body == NULL);
175             caf->body = reference;
176             break;
177         }
178     case CONSTR:
179         {
180             StgClosure* con = stgCast(StgClosure*,obj->closure);
181             ASSERT(i < get_itbl(con)->layout.payload.nptrs && payloadCPtr(con,i) == NULL);
182             payloadCPtr(con,i) = reference;
183             break;
184         }
185     case AP_UPD:
186         {
187             StgAP_UPD* ap = stgCast(StgAP_UPD*,obj->closure);
188             ASSERT(i < 1+ap->n_args);
189             if (i==0) {
190                 ASSERT(ap->fun == NULL);
191                 ap->fun = reference;
192             } else {
193                 ASSERT(payloadCPtr(ap,i-1) == NULL);
194                 payloadCPtr(ap,i-1) = reference;
195             }
196             break;
197         }
198     default:
199             barf("asmResolveRef");
200     }
201     obj->num_unresolved -= 1;
202 }
203
204 static void asmAddRef( AsmObject referent, AsmObject referer, AsmNat i )
205 {
206     if (referent->closure) {
207         asmResolveRef(referer,i,(AsmClosure)referent->closure);
208     } else {
209         insertRefs(&(referent->refs),(AsmRef){referer,i});
210     }
211 }
212
213 void asmAddPtr( AsmObject obj, AsmObject arg )
214 {
215     ASSERT(obj->closure == 0); /* can't extend an object once it's allocated */
216     insertPtrs( &obj->ptrs, arg );
217 }
218
219 static void asmBeginObject( AsmObject obj )
220 {
221     obj->closure = NULL;
222     obj->num_unresolved = 0;
223     initRefs(&obj->refs);
224     initPtrs(&obj->ptrs);
225 }
226
227 static void asmEndObject( AsmObject obj, StgClosure* c )
228 {
229     obj->num_unresolved = obj->ptrs.len;
230     obj->closure = c;
231     mapQueue(Ptrs,    AsmObject, obj->ptrs, asmAddRef(x,obj,i));
232     mapQueue(Refs,    AsmRef,    obj->refs, asmResolveRef(x.ref,x.i,c));
233
234     if (obj->num_unresolved == 0) {
235         freePtrs(&obj->ptrs);
236         freeRefs(&obj->refs);
237         /* we don't print until all ptrs are resolved */
238         IF_DEBUG(codegen,printObj(obj->closure));
239     }
240 }
241
242 int asmObjectHasClosure ( AsmObject obj )
243 {
244     return (obj->num_unresolved == 0 && obj->closure);
245 }
246
247 AsmClosure asmClosureOfObject ( AsmObject obj )
248 {
249     ASSERT(asmObjectHasClosure(obj));
250     return obj->closure;
251 }
252
253 void asmMarkObject ( AsmObject obj )
254 {
255     ASSERT(obj->num_unresolved == 0 && obj->closure);
256     obj->closure = MarkRoot(obj->closure);
257 }
258
259 /* --------------------------------------------------------------------------
260  * Heap allocation
261  * ------------------------------------------------------------------------*/
262
263 static StgClosure* asmAlloc( nat size )
264 {
265     StgClosure* o = stgCast(StgClosure*,allocate(size));
266     ASSERT( size >= MIN_NONUPD_SIZE + sizeofW(StgHeader) );
267     /* printf("Allocated %p .. %p\n", o, o+size-1); */
268     return o;
269 }
270
271 static void setSp( AsmBCO bco, AsmSp sp )
272 {
273     bco->max_sp = stg_max(bco->sp,bco->max_sp);
274     bco->sp     = sp;
275     bco->max_sp = stg_max(bco->sp,bco->max_sp);
276 }
277
278 static void incSp ( AsmBCO bco, int sp_delta )
279 {
280     bco->max_sp  = stg_max(bco->sp,bco->max_sp);
281     bco->sp     += sp_delta;
282     bco->max_sp  = stg_max(bco->sp,bco->max_sp);
283 }
284
285 static void decSp ( AsmBCO bco, int sp_delta )
286 {
287     bco->max_sp  = stg_max(bco->sp,bco->max_sp);
288     bco->sp     -= sp_delta;
289     bco->max_sp  = stg_max(bco->sp,bco->max_sp);
290 }
291
292 /* --------------------------------------------------------------------------
293  * 
294  * ------------------------------------------------------------------------*/
295
296 AsmObject asmMkObject( AsmClosure c )
297 {
298     AsmObject obj = malloc(sizeof(struct AsmObject_));
299     if (obj == NULL) {
300         barf("Can't allocate AsmObject");
301     }
302     asmBeginObject(obj);
303     asmEndObject(obj,c);
304     return obj;
305 }
306
307 AsmCon asmBeginCon( AsmInfo info )
308 {
309     AsmCon con = malloc(sizeof(struct AsmCon_));
310     if (con == NULL) {
311         barf("Can't allocate AsmCon");
312     }
313     asmBeginObject(&con->object);
314     con->info = info;
315     return con;
316 }
317
318 void asmEndCon( AsmCon con )
319 {
320     nat p  = con->object.ptrs.len;
321     nat np = stg_max(0,MIN_NONUPD_SIZE-p);
322
323     StgClosure* c = asmAlloc(CONSTR_sizeW(p,np));
324     StgClosure* o = stgCast(StgClosure*,c);
325     SET_HDR(o,con->info,??);
326     mapQueue(Ptrs,    AsmObject, con->object.ptrs, payloadCPtr(o,i) = NULL);
327     { nat i; for( i=0; i<np; ++i ) { payloadWord(o,p+i) = 0xdeadbeef; } }
328     asmEndObject(&con->object,c);
329 }
330
331 AsmCAF asmBeginCAF( void )
332 {
333     AsmCAF caf = malloc(sizeof(struct AsmCAF_));
334     if (caf == NULL) {
335         barf("Can't allocate AsmCAF");
336     }
337     asmBeginObject(&caf->object);
338     return caf;
339 }
340
341 void asmEndCAF( AsmCAF caf, AsmBCO body )
342 {
343     StgClosure* c = asmAlloc(CAF_sizeW());
344     StgCAF*     o = stgCast(StgCAF*,c);
345     SET_HDR(o,&CAF_UNENTERED_info,??);
346     o->body  = NULL;
347     o->value = stgCast(StgClosure*,0xdeadbeef);
348     o->link  = stgCast(StgCAF*,0xdeadbeef);
349     o->mut_link = NULL;
350     asmAddPtr(&caf->object,&body->object);
351     asmEndObject(&caf->object,c);
352 }
353
354 AsmBCO asmBeginBCO( int /*StgExpr*/ e )
355 {
356     AsmBCO bco = malloc(sizeof(struct AsmBCO_));
357     if (bco == NULL) {
358         barf("Can't allocate AsmBCO");
359     }
360     asmBeginObject(&bco->object);
361     initInstrs(&bco->is);
362     initNonPtrs(&bco->nps);
363
364     bco->stgexpr = e;
365     bco->max_sp = bco->sp = 0;
366     bco->lastOpc = i_INTERNAL_ERROR;
367     return bco;
368 }
369
370 void asmEndBCO( AsmBCO bco )
371 {
372     nat p  = bco->object.ptrs.len;
373     nat np = bco->nps.len;
374     nat is = bco->is.len + (bco->max_sp <= 255 ? 2 : 3);  /* 2 or 3 for stack check */
375
376     StgClosure* c = asmAlloc(BCO_sizeW(p,np,is));
377     StgBCO*     o = stgCast(StgBCO*,c);
378     SET_HDR(o,&BCO_info,??);
379     o->n_ptrs   = p;
380     o->n_words  = np;
381     o->n_instrs = is;
382     o->stgexpr  = bco->stgexpr;
383     mapQueue(Ptrs,    AsmObject, bco->object.ptrs, bcoConstCPtr(o,i) = NULL);
384     mapQueue(NonPtrs, StgWord,   bco->nps,  bcoConstWord(o,i) = x);
385     {
386         nat j = 0;
387         bco->max_sp = stg_max(bco->sp,bco->max_sp);
388
389         ASSERT(bco->max_sp <= 65535);
390         if (bco->max_sp <= 255) {
391            bcoInstr(o,j++) = i_STK_CHECK;
392            bcoInstr(o,j++) = bco->max_sp;
393         } else {
394            bcoInstr(o,j++) = i_STK_CHECK_big;
395            bcoInstr(o,j++) = bco->max_sp / 256;
396            bcoInstr(o,j++) = bco->max_sp % 256;
397         }
398
399         mapQueue(Instrs,  StgWord8,   bco->is,   bcoInstr(o,j++) = x);
400         ASSERT(j == is);
401     }
402     freeInstrs(&bco->is);
403     freeNonPtrs(&bco->nps);
404     asmEndObject(&bco->object,c);
405 }
406
407 /* --------------------------------------------------------------------------
408  * 
409  * ------------------------------------------------------------------------*/
410
411 static void asmInstrOp ( AsmBCO bco, StgWord i )
412 {
413     ASSERT(i <= BIGGEST_OPCODE); /* must be a valid opcode */
414     bco->lastOpc = i;
415     insertInstrs(&(bco->is),i);
416 }
417
418 static void asmInstr8 ( AsmBCO bco, StgWord i )
419 {
420   if (i >= 256) {
421     ASSERT(i < 256); /* must be a byte */
422   }
423     insertInstrs(&(bco->is),i);
424 }
425
426 static void asmInstr16 ( AsmBCO bco, StgWord i )
427 {
428     ASSERT(i < 65536); /* must be a short */
429     insertInstrs(&(bco->is),i / 256);
430     insertInstrs(&(bco->is),i % 256);
431 }
432
433 static Instr asmInstrBack ( AsmBCO bco, StgWord n )
434 {
435    return bco->is.elems[bco->is.len - n];
436 }
437
438 static void asmInstrRecede ( AsmBCO bco, StgWord n )
439 {
440    if (bco->is.len < n) barf("asmInstrRecede");
441    bco->is.len -= n;
442 }
443
444 static void asmPtr( AsmBCO bco, AsmObject x )
445 {
446     insertPtrs( &bco->object.ptrs, x );
447 }
448
449 static void asmWord( AsmBCO bco, StgWord i )
450 {
451     insertNonPtrs( &bco->nps, i );
452 }
453
454 static int asmFindInNonPtrs ( AsmBCO bco, StgWord i )
455 {
456    return findInNonPtrs ( &bco->nps, i );
457 }
458
459 #define asmWords(bco,ty,x)                               \
460     {                                                    \
461         union { ty a; AsmWord b[sizeofW(ty)]; } p;       \
462         nat i;                                           \
463         if (sizeof(ty) < sizeof(AsmWord)) p.b[0]=0;      \
464         p.a = x;                                         \
465         for( i = 0; i < sizeofW(ty); i++ ) {             \
466             asmWord(bco,p.b[i]);                         \
467         }                                                \
468     }
469
470 static StgWord repSizeW( AsmRep rep )
471 {
472     switch (rep) {
473     case CHAR_REP:    return sizeofW(StgWord) + sizeofW(StgChar);
474
475     case BOOL_REP:
476     case INT_REP:      return sizeofW(StgWord) + sizeofW(StgInt);
477     case THREADID_REP:
478     case WORD_REP:     return sizeofW(StgWord) + sizeofW(StgWord);
479     case ADDR_REP:     return sizeofW(StgWord) + sizeofW(StgAddr);
480     case FLOAT_REP:    return sizeofW(StgWord) + sizeofW(StgFloat);
481     case DOUBLE_REP:   return sizeofW(StgWord) + sizeofW(StgDouble);
482     case STABLE_REP:   return sizeofW(StgWord) + sizeofW(StgWord);
483
484     case INTEGER_REP: 
485 #ifdef PROVIDE_WEAK
486     case WEAK_REP: 
487 #endif
488 #ifdef PROVIDE_FOREIGN
489     case FOREIGN_REP: 
490 #endif
491     case ALPHA_REP:    /* a                        */ 
492     case BETA_REP:     /* b                        */ 
493     case GAMMA_REP:    /* c                        */ 
494     case DELTA_REP:    /* d                        */ 
495     case HANDLER_REP:  /* IOError -> IO a          */ 
496     case ERROR_REP:    /* IOError                  */ 
497     case ARR_REP    :  /* PrimArray              a */ 
498     case BARR_REP   :  /* PrimByteArray          a */ 
499     case REF_REP    :  /* Ref                  s a */ 
500     case MUTARR_REP :  /* PrimMutableArray     s a */ 
501     case MUTBARR_REP:  /* PrimMutableByteArray s a */ 
502     case MVAR_REP:     /* MVar a                   */ 
503     case PTR_REP:     return sizeofW(StgPtr);
504
505     case VOID_REP:    return sizeofW(StgWord);
506     default:          barf("repSizeW %d",rep);
507     }
508 }
509
510
511 int asmRepSizeW ( AsmRep rep )
512 {
513    return repSizeW ( rep );
514 }
515
516
517 /* --------------------------------------------------------------------------
518  * Instruction emission.  All instructions should be routed through here
519  * so that the peephole optimiser gets to see what's happening.
520  * ------------------------------------------------------------------------*/
521
522 static void emiti_ ( AsmBCO bco, Instr opcode )
523 {
524    StgInt x, y;
525    if (bco->lastOpc == i_SLIDE && opcode == i_ENTER) {
526       /* SLIDE x y ; ENTER   ===>  SE x y */
527       x = asmInstrBack(bco,2);
528       y = asmInstrBack(bco,1); 
529       asmInstrRecede(bco,3);
530       asmInstrOp(bco,i_SE); asmInstr8(bco,x); asmInstr8(bco,y);
531    }
532    else
533    if (bco->lastOpc == i_RV && opcode == i_ENTER) {
534       /* RV x y ; ENTER ===> RVE x (y-2)
535          Because RETADDR pushes 2 words on the stack, y must be at least 2. */
536       x = asmInstrBack(bco,2);
537       y = asmInstrBack(bco,1);
538       if (y < 2) barf("emiti_: RVE: impossible y value");
539       asmInstrRecede(bco,3);
540       asmInstrOp(bco, i_RVE); asmInstr8(bco,x); asmInstr8(bco,y-2);
541    }
542    else {
543       asmInstrOp(bco,opcode);
544    }
545 }
546
547 static void emiti_8 ( AsmBCO bco, Instr opcode, int arg1 )
548 {
549    StgInt x;
550    if (bco->lastOpc == i_VAR && opcode == i_VAR) {
551       /* VAR x ; VAR y ===>  VV x y */
552       x = asmInstrBack(bco,1);
553       asmInstrRecede(bco,2);
554       asmInstrOp(bco,i_VV); asmInstr8(bco,x); asmInstr8(bco,arg1);
555    } 
556    else 
557    if (bco->lastOpc == i_RETADDR && opcode == i_VAR) {
558       /* RETADDR x ; VAR y ===> RV x y */
559       x = asmInstrBack(bco,1);
560       asmInstrRecede(bco,2);
561       asmInstrOp(bco, i_RV); asmInstr8(bco,x); asmInstr8(bco,arg1);
562    }
563    else {
564       asmInstrOp(bco,opcode);
565       asmInstr8(bco,arg1);
566    }
567 }
568
569 static void emiti_16 ( AsmBCO bco, Instr opcode, int arg1 )
570 {
571    asmInstrOp(bco,opcode);
572    asmInstr16(bco,arg1);
573 }
574
575 static void emiti_8_8 ( AsmBCO bco, Instr opcode, int arg1, int arg2 )
576 {
577    asmInstrOp(bco,opcode);
578    asmInstr8(bco,arg1);
579    asmInstr8(bco,arg2);
580 }
581
582 static void emiti_8_16 ( AsmBCO bco, Instr opcode, int arg1, int arg2 )
583 {
584    asmInstrOp(bco,opcode);
585    asmInstr8(bco,arg1);
586    asmInstr16(bco,arg2);
587 }
588
589 static void emiti_16_16 ( AsmBCO bco, Instr opcode, int arg1, int arg2 )
590 {
591    asmInstrOp(bco,opcode);
592    asmInstr16(bco,arg1);
593    asmInstr16(bco,arg2);
594 }
595
596
597 /* --------------------------------------------------------------------------
598  * Wrappers around the above fns
599  * ------------------------------------------------------------------------*/
600
601 static void emit_i_VAR_INT ( AsmBCO bco, int arg1 )
602 {
603    ASSERT(arg1 >= 0);
604    if (arg1 < 256)
605       emiti_8 (bco,i_VAR_INT,    arg1); else
606       emiti_16(bco,i_VAR_INT_big,arg1);
607 }
608
609 static void emit_i_VAR_WORD ( AsmBCO bco, int arg1 )
610 {
611    ASSERT(arg1 >= 0);
612    if (arg1 < 256)
613       emiti_8 (bco,i_VAR_WORD,    arg1); else
614       emiti_16(bco,i_VAR_WORD_big,arg1);
615 }
616
617 static void emit_i_VAR_ADDR ( AsmBCO bco, int arg1 )
618 {
619    ASSERT(arg1 >= 0);
620    if (arg1 < 256)
621       emiti_8 (bco,i_VAR_ADDR,    arg1); else
622       emiti_16(bco,i_VAR_ADDR_big,arg1);
623 }
624
625 static void emit_i_VAR_CHAR ( AsmBCO bco, int arg1 )
626 {
627    ASSERT(arg1 >= 0);
628    if (arg1 < 256)
629       emiti_8 (bco,i_VAR_CHAR,    arg1); else
630       emiti_16(bco,i_VAR_CHAR_big,arg1);
631 }
632
633 static void emit_i_VAR_FLOAT ( AsmBCO bco, int arg1 )
634 {
635    ASSERT(arg1 >= 0);
636    if (arg1 < 256)
637       emiti_8 (bco,i_VAR_FLOAT,    arg1); else
638       emiti_16(bco,i_VAR_FLOAT_big,arg1);
639 }
640
641 static void emit_i_VAR_DOUBLE ( AsmBCO bco, int arg1 )
642 {
643    ASSERT(arg1 >= 0);
644    if (arg1 < 256)
645       emiti_8 (bco,i_VAR_DOUBLE,    arg1); else
646       emiti_16(bco,i_VAR_DOUBLE_big,arg1);
647 }
648
649 static void emit_i_VAR_STABLE ( AsmBCO bco, int arg1 )
650 {
651    ASSERT(arg1 >= 0);
652    if (arg1 < 256)
653       emiti_8 (bco,i_VAR_STABLE,    arg1); else
654       emiti_16(bco,i_VAR_STABLE_big,arg1);
655 }
656
657 static void emit_i_VAR ( AsmBCO bco, int arg1 )
658 {
659    ASSERT(arg1 >= 0);
660    if (arg1 < 256)
661       emiti_8 (bco,i_VAR,    arg1); else
662       emiti_16(bco,i_VAR_big,arg1);
663 }
664
665 static void emit_i_PACK ( AsmBCO bco, int arg1 )
666 {
667    ASSERT(arg1 >= 0);
668    if (arg1 < 256)
669       emiti_8 (bco,i_PACK,    arg1); else
670       emiti_16(bco,i_PACK_big,arg1);
671 }
672
673 static void emit_i_SLIDE ( AsmBCO bco, int arg1, int arg2 )
674 {
675    ASSERT(arg1 >= 0);
676    ASSERT(arg2 >= 0);
677    if (arg1 < 256 && arg2 < 256)
678       emiti_8_8  (bco,i_SLIDE,    arg1,arg2); else
679       emiti_16_16(bco,i_SLIDE_big,arg1,arg2);
680 }
681
682 static void emit_i_MKAP ( AsmBCO bco, int arg1, int arg2 )
683 {
684    ASSERT(arg1 >= 0);
685    ASSERT(arg2 >= 0);
686    if (arg1 < 256 && arg2 < 256)
687       emiti_8_8  (bco,i_MKAP,    arg1,arg2); else
688       emiti_16_16(bco,i_MKAP_big,arg1,arg2);
689 }
690
691
692 static void emit_i_CONST_INT ( AsmBCO bco, int arg1 )
693 {
694    ASSERT(arg1 >= 0);
695    if (arg1 < 256)
696       emiti_8 (bco,i_CONST_INT,    arg1); else
697       emiti_16(bco,i_CONST_INT_big,arg1);
698 }
699
700 static void emit_i_CONST_INTEGER ( AsmBCO bco, int arg1 )
701 {
702    ASSERT(arg1 >= 0);
703    if (arg1 < 256)
704       emiti_8 (bco,i_CONST_INTEGER,    arg1); else
705       emiti_16(bco,i_CONST_INTEGER_big,arg1);
706 }
707
708 static void emit_i_CONST_ADDR ( AsmBCO bco, int arg1 )
709 {
710    ASSERT(arg1 >= 0);
711    if (arg1 < 256)
712       emiti_8 (bco,i_CONST_ADDR,    arg1); else
713       emiti_16(bco,i_CONST_ADDR_big,arg1);
714 }
715
716 static void emit_i_CONST_CHAR ( AsmBCO bco, int arg1 )
717 {
718    ASSERT(arg1 >= 0);
719    if (arg1 < 256)
720       emiti_8 (bco,i_CONST_CHAR,    arg1); else
721       emiti_16(bco,i_CONST_CHAR_big,arg1);
722 }
723
724 static void emit_i_CONST_FLOAT ( AsmBCO bco, int arg1 )
725 {
726    ASSERT(arg1 >= 0);
727    if (arg1 < 256)
728       emiti_8 (bco,i_CONST_FLOAT,    arg1); else
729       emiti_16(bco,i_CONST_FLOAT_big,arg1);
730 }
731
732 static void emit_i_CONST_DOUBLE ( AsmBCO bco, int arg1 )
733 {
734    ASSERT(arg1 >= 0);
735    if (arg1 < 256)
736       emiti_8 (bco,i_CONST_DOUBLE,    arg1); else
737       emiti_16(bco,i_CONST_DOUBLE_big,arg1);
738 }
739
740 static void emit_i_CONST ( AsmBCO bco, int arg1 )
741 {
742    ASSERT(arg1 >= 0);
743    if (arg1 < 256)
744       emiti_8 (bco,i_CONST,    arg1); else
745       emiti_16(bco,i_CONST_big,arg1);
746 }
747
748 static void emit_i_RETADDR ( AsmBCO bco, int arg1 )
749 {
750    ASSERT(arg1 >= 0);
751    if (arg1 < 256)
752       emiti_8 (bco,i_RETADDR,    arg1); else
753       emiti_16(bco,i_RETADDR_big,arg1);
754 }
755
756 static void emit_i_ALLOC_CONSTR ( AsmBCO bco, int arg1 )
757 {
758    ASSERT(arg1 >= 0);
759    if (arg1 < 256)
760       emiti_8 (bco,i_ALLOC_CONSTR,    arg1); else
761       emiti_16(bco,i_ALLOC_CONSTR_big,arg1);
762 }
763
764
765 /* --------------------------------------------------------------------------
766  * Arg checks.
767  * ------------------------------------------------------------------------*/
768
769 AsmSp  asmBeginArgCheck ( AsmBCO bco )
770 {
771     ASSERT(bco->sp == 0);
772     return bco->sp;
773 }
774
775 void   asmEndArgCheck   ( AsmBCO bco, AsmSp last_arg )
776 {
777     nat args = bco->sp - last_arg;
778     if (args != 0) { /* optimisation */
779         emiti_8(bco,i_ARG_CHECK,args);
780     }
781 }
782
783 /* --------------------------------------------------------------------------
784  * Creating and using "variables"
785  * ------------------------------------------------------------------------*/
786
787 AsmVar asmBind          ( AsmBCO bco, AsmRep rep )
788 {
789     incSp(bco,repSizeW(rep));
790     return bco->sp;
791 }
792
793 void   asmVar           ( AsmBCO bco, AsmVar v, AsmRep rep )
794 {
795     int offset;
796
797     if (rep == VOID_REP) {
798         emiti_(bco,i_VOID);
799         incSp(bco,repSizeW(rep));
800         return;
801     }
802
803     offset = bco->sp - v;
804     switch (rep) {
805     case BOOL_REP:
806     case INT_REP:
807             emit_i_VAR_INT(bco,offset);
808             break;
809     case THREADID_REP:
810     case WORD_REP:
811             emit_i_VAR_WORD(bco,offset);
812             break;
813     case ADDR_REP:
814             emit_i_VAR_ADDR(bco,offset);
815             break;
816     case CHAR_REP:
817             emit_i_VAR_CHAR(bco,offset);
818             break;
819     case FLOAT_REP:
820             emit_i_VAR_FLOAT(bco,offset);
821             break;
822     case DOUBLE_REP:
823             emit_i_VAR_DOUBLE(bco,offset);
824             break;
825     case STABLE_REP:
826             emit_i_VAR_STABLE(bco,offset);
827             break;
828
829     case INTEGER_REP:
830 #ifdef PROVIDE_WEAK
831     case WEAK_REP: 
832 #endif
833 #ifdef PROVIDE_FOREIGN
834     case FOREIGN_REP:
835 #endif
836     case ALPHA_REP:    /* a                        */ 
837     case BETA_REP:     /* b                        */
838     case GAMMA_REP:    /* c                        */ 
839     case DELTA_REP:    /* d                        */ 
840     case HANDLER_REP:  /* IOError -> IO a          */
841     case ERROR_REP:    /* IOError                  */
842     case ARR_REP    :  /* PrimArray              a */
843     case BARR_REP   :  /* PrimByteArray          a */
844     case REF_REP    :  /* Ref                  s a */
845     case MUTARR_REP :  /* PrimMutableArray     s a */
846     case MUTBARR_REP:  /* PrimMutableByteArray s a */
847     case MVAR_REP:     /* MVar a                   */
848     case PTR_REP:
849             emit_i_VAR(bco,offset);
850             break;
851     default:
852             barf("asmVar %d",rep);
853     }
854     incSp(bco,repSizeW(rep));
855 }
856
857 /* --------------------------------------------------------------------------
858  * Tail calls
859  * ------------------------------------------------------------------------*/
860
861 AsmSp asmBeginEnter( AsmBCO bco )
862 {
863     return bco->sp;
864 }
865
866 void asmEndEnter( AsmBCO bco, AsmSp sp1, AsmSp sp2 )
867 {
868     int x = bco->sp - sp1;
869     int y = sp1 - sp2;
870     ASSERT(x >= 0 && y >= 0);
871     if (y != 0) {
872         emit_i_SLIDE(bco,x,y);
873         decSp(bco,sp1 - sp2);
874     }
875     emiti_(bco,i_ENTER);
876     decSp(bco,sizeofW(StgPtr));
877 }
878
879 /* --------------------------------------------------------------------------
880  * Build boxed Ints, Floats, etc
881  * ------------------------------------------------------------------------*/
882
883 AsmVar asmBox( AsmBCO bco, AsmRep rep )
884 {
885     switch (rep) {
886     case CHAR_REP:
887             emiti_(bco,i_PACK_CHAR);
888             break;
889     case INT_REP:
890             emiti_(bco,i_PACK_INT);
891             break;
892     case THREADID_REP:
893     case WORD_REP:
894             emiti_(bco,i_PACK_WORD);
895             break;
896     case ADDR_REP:
897             emiti_(bco,i_PACK_ADDR);
898             break;
899     case FLOAT_REP:
900             emiti_(bco,i_PACK_FLOAT);
901             break;
902     case DOUBLE_REP:
903             emiti_(bco,i_PACK_DOUBLE);
904             break;
905     case STABLE_REP:
906             emiti_(bco,i_PACK_STABLE);
907             break;
908
909     default:
910             barf("asmBox %d",rep);
911     }
912     /* NB: these operations DO pop their arg       */
913     decSp(bco, repSizeW(rep));   /* pop unboxed arg */
914     incSp(bco, sizeofW(StgPtr)); /* push box        */
915     return bco->sp;
916 }
917
918 /* --------------------------------------------------------------------------
919  * Unbox Ints, Floats, etc
920  * ------------------------------------------------------------------------*/
921
922 AsmVar asmUnbox( AsmBCO bco, AsmRep rep )
923 {
924     switch (rep) {
925     case INT_REP:
926             emiti_(bco,i_UNPACK_INT);
927             break;
928     case THREADID_REP:
929     case WORD_REP:
930             emiti_(bco,i_UNPACK_WORD);
931             break;
932     case ADDR_REP:
933             emiti_(bco,i_UNPACK_ADDR);
934             break;
935     case CHAR_REP:
936             emiti_(bco,i_UNPACK_CHAR);
937             break;
938     case FLOAT_REP:
939             emiti_(bco,i_UNPACK_FLOAT);
940             break;
941     case DOUBLE_REP:
942             emiti_(bco,i_UNPACK_DOUBLE);
943             break;
944     case STABLE_REP:
945             emiti_(bco,i_UNPACK_STABLE);
946             break;
947     default:
948             barf("asmUnbox %d",rep);
949     }
950     /* NB: these operations DO NOT pop their arg  */
951     incSp(bco, repSizeW(rep)); /* push unboxed arg */
952     return bco->sp;
953 }
954
955
956 /* --------------------------------------------------------------------------
957  * Push unboxed Ints, Floats, etc
958  * ------------------------------------------------------------------------*/
959
960 void asmConstInt( AsmBCO bco, AsmInt x )
961 {
962     emit_i_CONST_INT(bco,bco->nps.len);
963     asmWords(bco,AsmInt,x);
964     incSp(bco, repSizeW(INT_REP));
965 }
966
967 void asmConstInteger( AsmBCO bco, AsmString x )
968 {
969     emit_i_CONST_INTEGER(bco,bco->nps.len);
970     asmWords(bco,AsmString,x);
971     incSp(bco, repSizeW(INTEGER_REP));
972 }
973
974 void asmConstAddr( AsmBCO bco, AsmAddr x )
975 {
976     emit_i_CONST_ADDR(bco,bco->nps.len);
977     asmWords(bco,AsmAddr,x);
978     incSp(bco, repSizeW(ADDR_REP));
979 }
980
981 void asmConstWord( AsmBCO bco, AsmWord x )
982 {
983     emit_i_CONST_INT(bco,bco->nps.len);
984     asmWords(bco,AsmWord,(AsmInt)x);
985     incSp(bco, repSizeW(WORD_REP));
986 }
987
988 void asmConstChar( AsmBCO bco, AsmChar x )
989 {
990     emit_i_CONST_CHAR(bco,bco->nps.len);
991     asmWords(bco,AsmChar,x);
992     incSp(bco, repSizeW(CHAR_REP));
993 }
994
995 void asmConstFloat( AsmBCO bco, AsmFloat x )
996 {
997     emit_i_CONST_FLOAT(bco,bco->nps.len);
998     asmWords(bco,AsmFloat,x);
999     incSp(bco, repSizeW(FLOAT_REP));
1000 }
1001
1002 void asmConstDouble( AsmBCO bco, AsmDouble x )
1003 {
1004     emit_i_CONST_DOUBLE(bco,bco->nps.len);
1005     asmWords(bco,AsmDouble,x);
1006     incSp(bco, repSizeW(DOUBLE_REP));
1007 }
1008
1009 /* --------------------------------------------------------------------------
1010  * Algebraic case helpers
1011  * ------------------------------------------------------------------------*/
1012
1013 /* a mildly bogus pair of functions... */
1014 AsmSp asmBeginCase( AsmBCO bco )
1015 {
1016     return bco->sp;
1017 }
1018
1019 void asmEndCase( AsmBCO bco )
1020 {
1021 }
1022
1023 AsmSp asmContinuation( AsmBCO bco, AsmBCO ret_addr )
1024 {
1025     emit_i_RETADDR(bco,bco->object.ptrs.len);
1026     asmPtr(bco,&(ret_addr->object));
1027     incSp(bco, 2 * sizeofW(StgPtr));
1028     return bco->sp;
1029 }
1030
1031 AsmBCO asmBeginContinuation ( AsmSp sp, int /*List*/ alts )
1032 {
1033     AsmBCO bco = asmBeginBCO(alts);
1034     setSp(bco, sp);
1035     return bco;
1036 }
1037
1038 void asmEndContinuation ( AsmBCO bco )
1039 {
1040     asmEndBCO(bco);
1041 }
1042
1043
1044 /* --------------------------------------------------------------------------
1045  * Branches
1046  * ------------------------------------------------------------------------*/
1047
1048 AsmSp asmBeginAlt( AsmBCO bco )
1049 {
1050     return bco->sp;
1051 }
1052
1053 void asmEndAlt( AsmBCO bco, AsmSp  sp )
1054 {
1055     setSp(bco,sp);
1056 }
1057
1058 AsmPc asmTest( AsmBCO bco, AsmWord tag )
1059 {
1060     emiti_8_16(bco,i_TEST,tag,0);
1061     return bco->is.len;
1062 }
1063
1064 AsmPc asmTestInt( AsmBCO bco, AsmVar v, AsmInt x )
1065 {
1066     asmVar(bco,v,INT_REP);
1067     asmConstInt(bco,x);
1068     emiti_16(bco,i_TEST_INT,0);
1069     decSp(bco, 2*repSizeW(INT_REP));
1070     return bco->is.len;
1071 }
1072
1073 void asmFixBranch( AsmBCO bco, AsmPc from )
1074 {
1075     int distance = bco->is.len - from;
1076     ASSERT(distance >= 0);
1077     ASSERT(distance < 65536);
1078     setInstrs(&(bco->is),from-2,distance/256);
1079     setInstrs(&(bco->is),from-1,distance%256);
1080 }
1081
1082 void asmPanic( AsmBCO bco )
1083 {
1084     emiti_(bco,i_PANIC); /* "irrefutable" pattern failed - oops! */
1085 }
1086
1087 /* --------------------------------------------------------------------------
1088  * Primops
1089  * ------------------------------------------------------------------------*/
1090
1091 AsmSp asmBeginPrim( AsmBCO bco )
1092 {
1093     return bco->sp;
1094 }
1095
1096 void asmEndPrim( AsmBCO bco, const AsmPrim* prim, AsmSp base )
1097 {
1098     emiti_8(bco,prim->prefix,prim->opcode);
1099     setSp(bco, base);
1100 }
1101
1102 char* asmGetPrimopName ( AsmPrim* p )
1103 {
1104    return p->name;
1105 }
1106
1107 /* Hugs used to let you add arbitrary primops with arbitrary types
1108  * just by editing Prelude.hs or any other file you wanted.
1109  * We deliberately avoided that approach because we wanted more
1110  * control over which primops are provided.
1111  */
1112 AsmPrim asmPrimOps[] = {
1113
1114     /* Char# operations */
1115       { "primGtChar",                "CC", "B",  MONAD_Id, i_PRIMOP1, i_gtChar }
1116     , { "primGeChar",                "CC", "B",  MONAD_Id, i_PRIMOP1, i_geChar }
1117     , { "primEqChar",                "CC", "B",  MONAD_Id, i_PRIMOP1, i_eqChar }
1118     , { "primNeChar",                "CC", "B",  MONAD_Id, i_PRIMOP1, i_neChar }
1119     , { "primLtChar",                "CC", "B",  MONAD_Id, i_PRIMOP1, i_ltChar }
1120     , { "primLeChar",                "CC", "B",  MONAD_Id, i_PRIMOP1, i_leChar }
1121     , { "primCharToInt",             "C",  "I",  MONAD_Id, i_PRIMOP1, i_charToInt }
1122     , { "primIntToChar",             "I",  "C",  MONAD_Id, i_PRIMOP1, i_intToChar }
1123
1124     /* Int# operations */
1125     , { "primGtInt",                 "II", "B",  MONAD_Id, i_PRIMOP1, i_gtInt }
1126     , { "primGeInt",                 "II", "B",  MONAD_Id, i_PRIMOP1, i_geInt }
1127     , { "primEqInt",                 "II", "B",  MONAD_Id, i_PRIMOP1, i_eqInt }
1128     , { "primNeInt",                 "II", "B",  MONAD_Id, i_PRIMOP1, i_neInt }
1129     , { "primLtInt",                 "II", "B",  MONAD_Id, i_PRIMOP1, i_ltInt }
1130     , { "primLeInt",                 "II", "B",  MONAD_Id, i_PRIMOP1, i_leInt }
1131     , { "primMinInt",                "",   "I",  MONAD_Id, i_PRIMOP1, i_minInt }
1132     , { "primMaxInt",                "",   "I",  MONAD_Id, i_PRIMOP1, i_maxInt }
1133     , { "primPlusInt",               "II", "I",  MONAD_Id, i_PRIMOP1, i_plusInt }
1134     , { "primMinusInt",              "II", "I",  MONAD_Id, i_PRIMOP1, i_minusInt }
1135     , { "primTimesInt",              "II", "I",  MONAD_Id, i_PRIMOP1, i_timesInt }
1136     , { "primQuotInt",               "II", "I",  MONAD_Id, i_PRIMOP1, i_quotInt }
1137     , { "primRemInt",                "II", "I",  MONAD_Id, i_PRIMOP1, i_remInt }
1138     , { "primQuotRemInt",            "II", "II", MONAD_Id, i_PRIMOP1, i_quotRemInt }
1139     , { "primNegateInt",             "I",  "I",  MONAD_Id, i_PRIMOP1, i_negateInt }
1140
1141     , { "primAndInt",                "II", "I",  MONAD_Id, i_PRIMOP1, i_andInt }
1142     , { "primOrInt",                 "II", "I",  MONAD_Id, i_PRIMOP1, i_orInt }
1143     , { "primXorInt",                "II", "I",  MONAD_Id, i_PRIMOP1, i_xorInt }
1144     , { "primNotInt",                "I",  "I",  MONAD_Id, i_PRIMOP1, i_notInt }
1145     , { "primShiftLInt",             "II", "I",  MONAD_Id, i_PRIMOP1, i_shiftLInt }
1146     , { "primShiftRAInt",            "II", "I",  MONAD_Id, i_PRIMOP1, i_shiftRAInt }
1147     , { "primShiftRLInt",            "II", "I",  MONAD_Id, i_PRIMOP1, i_shiftRLInt }
1148
1149     /* Word# operations */
1150     , { "primGtWord",                "WW", "B",  MONAD_Id, i_PRIMOP1, i_gtWord }
1151     , { "primGeWord",                "WW", "B",  MONAD_Id, i_PRIMOP1, i_geWord }
1152     , { "primEqWord",                "WW", "B",  MONAD_Id, i_PRIMOP1, i_eqWord }
1153     , { "primNeWord",                "WW", "B",  MONAD_Id, i_PRIMOP1, i_neWord }
1154     , { "primLtWord",                "WW", "B",  MONAD_Id, i_PRIMOP1, i_ltWord }
1155     , { "primLeWord",                "WW", "B",  MONAD_Id, i_PRIMOP1, i_leWord }
1156     , { "primMinWord",               "",   "W",  MONAD_Id, i_PRIMOP1, i_minWord }
1157     , { "primMaxWord",               "",   "W",  MONAD_Id, i_PRIMOP1, i_maxWord }
1158     , { "primPlusWord",              "WW", "W",  MONAD_Id, i_PRIMOP1, i_plusWord }
1159     , { "primMinusWord",             "WW", "W",  MONAD_Id, i_PRIMOP1, i_minusWord }
1160     , { "primTimesWord",             "WW", "W",  MONAD_Id, i_PRIMOP1, i_timesWord }
1161     , { "primQuotWord",              "WW", "W",  MONAD_Id, i_PRIMOP1, i_quotWord }
1162     , { "primRemWord",               "WW", "W",  MONAD_Id, i_PRIMOP1, i_remWord }
1163     , { "primQuotRemWord",           "WW", "WW", MONAD_Id, i_PRIMOP1, i_quotRemWord }
1164     , { "primNegateWord",            "W",  "W",  MONAD_Id, i_PRIMOP1, i_negateWord }
1165
1166     , { "primAndWord",               "WW", "W",  MONAD_Id, i_PRIMOP1, i_andWord }
1167     , { "primOrWord",                "WW", "W",  MONAD_Id, i_PRIMOP1, i_orWord }
1168     , { "primXorWord",               "WW", "W",  MONAD_Id, i_PRIMOP1, i_xorWord }
1169     , { "primNotWord",               "W",  "W",  MONAD_Id, i_PRIMOP1, i_notWord }
1170     , { "primShiftLWord",            "WW", "W",  MONAD_Id, i_PRIMOP1, i_shiftLWord }
1171     , { "primShiftRAWord",           "WW", "W",  MONAD_Id, i_PRIMOP1, i_shiftRAWord }
1172     , { "primShiftRLWord",           "WW", "W",  MONAD_Id, i_PRIMOP1, i_shiftRLWord }
1173
1174     , { "primIntToWord",             "I",  "W",  MONAD_Id, i_PRIMOP1, i_intToWord }
1175     , { "primWordToInt",             "W",  "I",  MONAD_Id, i_PRIMOP1, i_wordToInt }
1176
1177     /* Addr# operations */
1178     , { "primGtAddr",                "AA", "B",  MONAD_Id, i_PRIMOP1, i_gtAddr }
1179     , { "primGeAddr",                "AA", "B",  MONAD_Id, i_PRIMOP1, i_geAddr }
1180     , { "primEqAddr",                "AA", "B",  MONAD_Id, i_PRIMOP1, i_eqAddr }
1181     , { "primNeAddr",                "AA", "B",  MONAD_Id, i_PRIMOP1, i_neAddr }
1182     , { "primLtAddr",                "AA", "B",  MONAD_Id, i_PRIMOP1, i_ltAddr }
1183     , { "primLeAddr",                "AA", "B",  MONAD_Id, i_PRIMOP1, i_leAddr }
1184     , { "primIntToAddr",             "I",  "A",  MONAD_Id, i_PRIMOP1, i_intToAddr }
1185     , { "primAddrToInt",             "A",  "I",  MONAD_Id, i_PRIMOP1, i_addrToInt }
1186
1187     , { "primIndexCharOffAddr",      "AI", "C",  MONAD_Id, i_PRIMOP1, i_indexCharOffAddr }
1188     , { "primIndexIntOffAddr",       "AI", "I",  MONAD_Id, i_PRIMOP1, i_indexIntOffAddr }
1189     , { "primIndexWordOffAddr",      "AI", "W",  MONAD_Id, i_PRIMOP1, i_indexWordOffAddr }
1190     , { "primIndexAddrOffAddr",      "AI", "A",  MONAD_Id, i_PRIMOP1, i_indexAddrOffAddr }
1191     , { "primIndexFloatOffAddr",     "AI", "F",  MONAD_Id, i_PRIMOP1, i_indexFloatOffAddr }
1192     , { "primIndexDoubleOffAddr",    "AI", "D",  MONAD_Id, i_PRIMOP1, i_indexDoubleOffAddr }
1193     , { "primIndexStableOffAddr",    "AI", "s",  MONAD_Id, i_PRIMOP1, i_indexStableOffAddr }
1194
1195     /* Stable# operations */
1196     , { "primIntToStablePtr",        "I",  "s",  MONAD_Id, i_PRIMOP1, i_intToStable }
1197     , { "primStablePtrToInt",        "s",  "I",  MONAD_Id, i_PRIMOP1, i_stableToInt }
1198
1199     /* These ops really ought to be in the IO monad */
1200     , { "primReadCharOffAddr",       "AI", "C",  MONAD_ST, i_PRIMOP1, i_readCharOffAddr }
1201     , { "primReadIntOffAddr",        "AI", "I",  MONAD_ST, i_PRIMOP1, i_readIntOffAddr }
1202     , { "primReadWordOffAddr",       "AI", "W",  MONAD_ST, i_PRIMOP1, i_readWordOffAddr }
1203     , { "primReadAddrOffAddr",       "AI", "A",  MONAD_ST, i_PRIMOP1, i_readAddrOffAddr }
1204     , { "primReadFloatOffAddr",      "AI", "F",  MONAD_ST, i_PRIMOP1, i_readFloatOffAddr }
1205     , { "primReadDoubleOffAddr",     "AI", "D",  MONAD_ST, i_PRIMOP1, i_readDoubleOffAddr }
1206     , { "primReadStableOffAddr",     "AI", "s",  MONAD_ST, i_PRIMOP1, i_readStableOffAddr }
1207
1208     /* These ops really ought to be in the IO monad */
1209     , { "primWriteCharOffAddr",      "AIC", "",  MONAD_ST, i_PRIMOP1, i_writeCharOffAddr }
1210     , { "primWriteIntOffAddr",       "AII", "",  MONAD_ST, i_PRIMOP1, i_writeIntOffAddr }
1211     , { "primWriteWordOffAddr",      "AIW", "",  MONAD_ST, i_PRIMOP1, i_writeWordOffAddr }
1212     , { "primWriteAddrOffAddr",      "AIA", "",  MONAD_ST, i_PRIMOP1, i_writeAddrOffAddr }
1213     , { "primWriteFloatOffAddr",     "AIF", "",  MONAD_ST, i_PRIMOP1, i_writeFloatOffAddr }
1214     , { "primWriteDoubleOffAddr",    "AID", "",  MONAD_ST, i_PRIMOP1, i_writeDoubleOffAddr }
1215     , { "primWriteStableOffAddr",    "AIs", "",  MONAD_ST, i_PRIMOP1, i_writeStableOffAddr }
1216
1217     /* Integer operations */
1218     , { "primCompareInteger",        "ZZ", "I",  MONAD_Id, i_PRIMOP1, i_compareInteger }
1219     , { "primNegateInteger",         "Z",  "Z",  MONAD_Id, i_PRIMOP1, i_negateInteger }
1220     , { "primPlusInteger",           "ZZ", "Z",  MONAD_Id, i_PRIMOP1, i_plusInteger }
1221     , { "primMinusInteger",          "ZZ", "Z",  MONAD_Id, i_PRIMOP1, i_minusInteger }
1222     , { "primTimesInteger",          "ZZ", "Z",  MONAD_Id, i_PRIMOP1, i_timesInteger }
1223     , { "primQuotRemInteger",        "ZZ", "ZZ", MONAD_Id, i_PRIMOP1, i_quotRemInteger }
1224     , { "primDivModInteger",         "ZZ", "ZZ", MONAD_Id, i_PRIMOP1, i_divModInteger }
1225     , { "primIntegerToInt",          "Z",  "I",  MONAD_Id, i_PRIMOP1, i_integerToInt }
1226     , { "primIntToInteger",          "I",  "Z",  MONAD_Id, i_PRIMOP1, i_intToInteger }
1227     , { "primIntegerToWord",         "Z",  "W",  MONAD_Id, i_PRIMOP1, i_integerToWord }
1228     , { "primWordToInteger",         "W",  "Z",  MONAD_Id, i_PRIMOP1, i_wordToInteger }
1229     , { "primIntegerToFloat",        "Z",  "F",  MONAD_Id, i_PRIMOP1, i_integerToFloat }
1230     , { "primFloatToInteger",        "F",  "Z",  MONAD_Id, i_PRIMOP1, i_floatToInteger }
1231     , { "primIntegerToDouble",       "Z",  "D",  MONAD_Id, i_PRIMOP1, i_integerToDouble }
1232     , { "primDoubleToInteger",       "D",  "Z",  MONAD_Id, i_PRIMOP1, i_doubleToInteger }
1233
1234     /* Float# operations */
1235     , { "primGtFloat",               "FF", "B",  MONAD_Id, i_PRIMOP1, i_gtFloat }
1236     , { "primGeFloat",               "FF", "B",  MONAD_Id, i_PRIMOP1, i_geFloat }
1237     , { "primEqFloat",               "FF", "B",  MONAD_Id, i_PRIMOP1, i_eqFloat }
1238     , { "primNeFloat",               "FF", "B",  MONAD_Id, i_PRIMOP1, i_neFloat }
1239     , { "primLtFloat",               "FF", "B",  MONAD_Id, i_PRIMOP1, i_ltFloat }
1240     , { "primLeFloat",               "FF", "B",  MONAD_Id, i_PRIMOP1, i_leFloat }
1241     , { "primMinFloat",              "",   "F",  MONAD_Id, i_PRIMOP1, i_minFloat }
1242     , { "primMaxFloat",              "",   "F",  MONAD_Id, i_PRIMOP1, i_maxFloat }
1243     , { "primRadixFloat",            "",   "I",  MONAD_Id, i_PRIMOP1, i_radixFloat }
1244     , { "primDigitsFloat",           "",   "I",  MONAD_Id, i_PRIMOP1, i_digitsFloat }
1245     , { "primMinExpFloat",           "",   "I",  MONAD_Id, i_PRIMOP1, i_minExpFloat }
1246     , { "primMaxExpFloat",           "",   "I",  MONAD_Id, i_PRIMOP1, i_maxExpFloat }
1247     , { "primPlusFloat",             "FF", "F",  MONAD_Id, i_PRIMOP1, i_plusFloat }
1248     , { "primMinusFloat",            "FF", "F",  MONAD_Id, i_PRIMOP1, i_minusFloat }
1249     , { "primTimesFloat",            "FF", "F",  MONAD_Id, i_PRIMOP1, i_timesFloat }
1250     , { "primDivideFloat",           "FF", "F",  MONAD_Id, i_PRIMOP1, i_divideFloat }
1251     , { "primNegateFloat",           "F",  "F",  MONAD_Id, i_PRIMOP1, i_negateFloat }
1252     , { "primFloatToInt",            "F",  "I",  MONAD_Id, i_PRIMOP1, i_floatToInt }
1253     , { "primIntToFloat",            "I",  "F",  MONAD_Id, i_PRIMOP1, i_intToFloat }
1254     , { "primExpFloat",              "F",  "F",  MONAD_Id, i_PRIMOP1, i_expFloat }
1255     , { "primLogFloat",              "F",  "F",  MONAD_Id, i_PRIMOP1, i_logFloat }
1256     , { "primSqrtFloat",             "F",  "F",  MONAD_Id, i_PRIMOP1, i_sqrtFloat }
1257     , { "primSinFloat",              "F",  "F",  MONAD_Id, i_PRIMOP1, i_sinFloat }
1258     , { "primCosFloat",              "F",  "F",  MONAD_Id, i_PRIMOP1, i_cosFloat }
1259     , { "primTanFloat",              "F",  "F",  MONAD_Id, i_PRIMOP1, i_tanFloat }
1260     , { "primAsinFloat",             "F",  "F",  MONAD_Id, i_PRIMOP1, i_asinFloat }
1261     , { "primAcosFloat",             "F",  "F",  MONAD_Id, i_PRIMOP1, i_acosFloat }
1262     , { "primAtanFloat",             "F",  "F",  MONAD_Id, i_PRIMOP1, i_atanFloat }
1263     , { "primSinhFloat",             "F",  "F",  MONAD_Id, i_PRIMOP1, i_sinhFloat }
1264     , { "primCoshFloat",             "F",  "F",  MONAD_Id, i_PRIMOP1, i_coshFloat }
1265     , { "primTanhFloat",             "F",  "F",  MONAD_Id, i_PRIMOP1, i_tanhFloat }
1266     , { "primPowerFloat",            "FF", "F",  MONAD_Id, i_PRIMOP1, i_powerFloat }
1267     , { "primDecodeFloatZ",          "F",  "ZI", MONAD_Id, i_PRIMOP1, i_decodeFloatZ }
1268     , { "primEncodeFloatZ",          "ZI", "F",  MONAD_Id, i_PRIMOP1, i_encodeFloatZ }
1269     , { "primIsNaNFloat",            "F",  "B",  MONAD_Id, i_PRIMOP1, i_isNaNFloat }
1270     , { "primIsInfiniteFloat",       "F",  "B",  MONAD_Id, i_PRIMOP1, i_isInfiniteFloat }
1271     , { "primIsDenormalizedFloat",   "F",  "B",  MONAD_Id, i_PRIMOP1, i_isDenormalizedFloat }
1272     , { "primIsNegativeZeroFloat",   "F",  "B",  MONAD_Id, i_PRIMOP1, i_isNegativeZeroFloat }
1273     , { "primIsIEEEFloat",           "",   "B",  MONAD_Id, i_PRIMOP1, i_isIEEEFloat }
1274
1275     /* Double# operations */
1276     , { "primGtDouble",              "DD", "B",  MONAD_Id, i_PRIMOP1, i_gtDouble }
1277     , { "primGeDouble",              "DD", "B",  MONAD_Id, i_PRIMOP1, i_geDouble }
1278     , { "primEqDouble",              "DD", "B",  MONAD_Id, i_PRIMOP1, i_eqDouble }
1279     , { "primNeDouble",              "DD", "B",  MONAD_Id, i_PRIMOP1, i_neDouble }
1280     , { "primLtDouble",              "DD", "B",  MONAD_Id, i_PRIMOP1, i_ltDouble }
1281     , { "primLeDouble",              "DD", "B",  MONAD_Id, i_PRIMOP1, i_leDouble }
1282     , { "primMinDouble",             "",   "D",  MONAD_Id, i_PRIMOP1, i_minDouble }
1283     , { "primMaxDouble",             "",   "D",  MONAD_Id, i_PRIMOP1, i_maxDouble }
1284     , { "primRadixDouble",           "",   "I",  MONAD_Id, i_PRIMOP1, i_radixDouble }
1285     , { "primDigitsDouble",          "",   "I",  MONAD_Id, i_PRIMOP1, i_digitsDouble }
1286     , { "primMinExpDouble",          "",   "I",  MONAD_Id, i_PRIMOP1, i_minExpDouble }
1287     , { "primMaxExpDouble",          "",   "I",  MONAD_Id, i_PRIMOP1, i_maxExpDouble }
1288     , { "primPlusDouble",            "DD", "D",  MONAD_Id, i_PRIMOP1, i_plusDouble }
1289     , { "primMinusDouble",           "DD", "D",  MONAD_Id, i_PRIMOP1, i_minusDouble }
1290     , { "primTimesDouble",           "DD", "D",  MONAD_Id, i_PRIMOP1, i_timesDouble }
1291     , { "primDivideDouble",          "DD", "D",  MONAD_Id, i_PRIMOP1, i_divideDouble }
1292     , { "primNegateDouble",          "D",  "D",  MONAD_Id, i_PRIMOP1, i_negateDouble }
1293     , { "primDoubleToInt",           "D",  "I",  MONAD_Id, i_PRIMOP1, i_doubleToInt }
1294     , { "primIntToDouble",           "I",  "D",  MONAD_Id, i_PRIMOP1, i_intToDouble }
1295     , { "primDoubleToFloat",         "D",  "F",  MONAD_Id, i_PRIMOP1, i_doubleToFloat }
1296     , { "primFloatToDouble",         "F",  "D",  MONAD_Id, i_PRIMOP1, i_floatToDouble }
1297     , { "primExpDouble",             "D",  "D",  MONAD_Id, i_PRIMOP1, i_expDouble }
1298     , { "primLogDouble",             "D",  "D",  MONAD_Id, i_PRIMOP1, i_logDouble }
1299     , { "primSqrtDouble",            "D",  "D",  MONAD_Id, i_PRIMOP1, i_sqrtDouble }
1300     , { "primSinDouble",             "D",  "D",  MONAD_Id, i_PRIMOP1, i_sinDouble }
1301     , { "primCosDouble",             "D",  "D",  MONAD_Id, i_PRIMOP1, i_cosDouble }
1302     , { "primTanDouble",             "D",  "D",  MONAD_Id, i_PRIMOP1, i_tanDouble }
1303     , { "primAsinDouble",            "D",  "D",  MONAD_Id, i_PRIMOP1, i_asinDouble }
1304     , { "primAcosDouble",            "D",  "D",  MONAD_Id, i_PRIMOP1, i_acosDouble }
1305     , { "primAtanDouble",            "D",  "D",  MONAD_Id, i_PRIMOP1, i_atanDouble }
1306     , { "primSinhDouble",            "D",  "D",  MONAD_Id, i_PRIMOP1, i_sinhDouble }
1307     , { "primCoshDouble",            "D",  "D",  MONAD_Id, i_PRIMOP1, i_coshDouble }
1308     , { "primTanhDouble",            "D",  "D",  MONAD_Id, i_PRIMOP1, i_tanhDouble }
1309     , { "primPowerDouble",           "DD", "D",  MONAD_Id, i_PRIMOP1, i_powerDouble }
1310     , { "primDecodeDoubleZ",         "D",  "ZI", MONAD_Id, i_PRIMOP1, i_decodeDoubleZ }
1311     , { "primEncodeDoubleZ",         "ZI",  "D", MONAD_Id, i_PRIMOP1, i_encodeDoubleZ }
1312     , { "primIsNaNDouble",           "D",  "B",  MONAD_Id, i_PRIMOP1, i_isNaNDouble }
1313     , { "primIsInfiniteDouble",      "D",  "B",  MONAD_Id, i_PRIMOP1, i_isInfiniteDouble }
1314     , { "primIsDenormalizedDouble",  "D",  "B",  MONAD_Id, i_PRIMOP1, i_isDenormalizedDouble }
1315     , { "primIsNegativeZeroDouble",  "D",  "B",  MONAD_Id, i_PRIMOP1, i_isNegativeZeroDouble }
1316     , { "primIsIEEEDouble",          "",   "B",  MONAD_Id, i_PRIMOP1, i_isIEEEDouble }
1317
1318     /* Ref operations */
1319     , { "primNewRef",                "a",  "R",  MONAD_ST, i_PRIMOP2, i_newRef }
1320     , { "primWriteRef",              "Ra", "",   MONAD_ST, i_PRIMOP2, i_writeRef }
1321     , { "primReadRef",               "R",  "a",  MONAD_ST, i_PRIMOP2, i_readRef }
1322     , { "primSameRef",               "RR", "B",  MONAD_Id, i_PRIMOP2, i_sameRef }
1323
1324     /* PrimArray operations */
1325     , { "primSameMutableArray",      "MM",  "B", MONAD_Id, i_PRIMOP2, i_sameMutableArray }
1326     , { "primUnsafeFreezeArray",     "M",   "X", MONAD_ST, i_PRIMOP2, i_unsafeFreezeArray }
1327     , { "primNewArray",              "Ia",  "M", MONAD_ST, i_PRIMOP2, i_newArray }
1328     , { "primWriteArray",            "MIa", "",  MONAD_ST, i_PRIMOP2, i_writeArray }
1329     , { "primReadArray",             "MI",  "a", MONAD_ST, i_PRIMOP2, i_readArray }
1330     , { "primIndexArray",            "XI",  "a", MONAD_Id, i_PRIMOP2, i_indexArray }
1331     , { "primSizeArray",             "X",   "I", MONAD_Id, i_PRIMOP2, i_sizeArray }
1332     , { "primSizeMutableArray",      "M",   "I", MONAD_Id, i_PRIMOP2, i_sizeMutableArray }
1333
1334     /* Prim[Mutable]ByteArray operations */
1335     , { "primSameMutableByteArray",  "mm", "B", MONAD_Id, i_PRIMOP2, i_sameMutableByteArray }
1336     , { "primUnsafeFreezeByteArray", "m",  "x", MONAD_ST, i_PRIMOP2, i_unsafeFreezeByteArray }
1337     
1338     , { "primNewByteArray",          "I",  "m", MONAD_ST, i_PRIMOP2, i_newByteArray }
1339
1340     , { "primWriteCharArray",        "mIC", "", MONAD_ST, i_PRIMOP2, i_writeCharArray }
1341     , { "primReadCharArray",         "mI", "C", MONAD_ST, i_PRIMOP2, i_readCharArray }
1342     , { "primIndexCharArray",        "xI", "C", MONAD_Id, i_PRIMOP2, i_indexCharArray }
1343     
1344     , { "primWriteIntArray",         "mII", "",  MONAD_ST, i_PRIMOP2, i_writeIntArray }
1345     , { "primReadIntArray",          "mI",  "I", MONAD_ST, i_PRIMOP2, i_readIntArray }
1346     , { "primIndexIntArray",         "xI",  "I", MONAD_Id, i_PRIMOP2, i_indexIntArray }
1347
1348     /* {new,write,read,index}IntegerArray not provided */
1349
1350     , { "primWriteWordArray",        "mIW", "",  MONAD_ST, i_PRIMOP2, i_writeWordArray }
1351     , { "primReadWordArray",         "mI",  "W", MONAD_ST, i_PRIMOP2, i_readWordArray }
1352     , { "primIndexWordArray",        "xI",  "W", MONAD_Id, i_PRIMOP2, i_indexWordArray }
1353     , { "primWriteAddrArray",        "mIA", "",  MONAD_ST, i_PRIMOP2, i_writeAddrArray }
1354     , { "primReadAddrArray",         "mI",  "A", MONAD_ST, i_PRIMOP2, i_readAddrArray }
1355     , { "primIndexAddrArray",        "xI",  "A", MONAD_Id, i_PRIMOP2, i_indexAddrArray }
1356     , { "primWriteFloatArray",       "mIF", "",  MONAD_ST, i_PRIMOP2, i_writeFloatArray }
1357     , { "primReadFloatArray",        "mI",  "F", MONAD_ST, i_PRIMOP2, i_readFloatArray }
1358     , { "primIndexFloatArray",       "xI",  "F", MONAD_Id, i_PRIMOP2, i_indexFloatArray }
1359     , { "primWriteDoubleArray" ,     "mID", "",  MONAD_ST, i_PRIMOP2, i_writeDoubleArray }
1360     , { "primReadDoubleArray",       "mI",  "D", MONAD_ST, i_PRIMOP2, i_readDoubleArray }
1361     , { "primIndexDoubleArray",      "xI",  "D", MONAD_Id, i_PRIMOP2, i_indexDoubleArray }
1362
1363 #if 0
1364 #ifdef PROVIDE_STABLE
1365     , { "primWriteStableArray",      "mIs", "",  MONAD_ST, i_PRIMOP2, i_writeStableArray }
1366     , { "primReadStableArray",       "mI",  "s", MONAD_ST, i_PRIMOP2, i_readStableArray }
1367     , { "primIndexStableArray",      "xI",  "s", MONAD_Id, i_PRIMOP2, i_indexStableArray }
1368 #endif
1369 #endif
1370     /* {new,write,read,index}ForeignObjArray not provided */
1371
1372
1373 #ifdef PROVIDE_FOREIGN
1374     /* ForeignObj# operations */
1375     , { "primMakeForeignObj",        "A",  "f",  MONAD_IO, i_PRIMOP2, i_makeForeignObj }
1376 #endif
1377 #ifdef PROVIDE_WEAK
1378     /* WeakPair# operations */
1379     , { "primMakeWeak",              "bac", "w",  MONAD_IO, i_PRIMOP2, i_makeWeak }
1380     , { "primDeRefWeak",             "w",   "Ia", MONAD_IO, i_PRIMOP2, i_deRefWeak }
1381 #endif
1382     /* StablePtr# operations */
1383     , { "primMakeStablePtr",         "a", "s",   MONAD_IO, i_PRIMOP2, i_makeStablePtr }
1384     , { "primDeRefStablePtr",        "s", "a",   MONAD_IO, i_PRIMOP2, i_deRefStablePtr }
1385     , { "primFreeStablePtr",         "s", "",    MONAD_IO, i_PRIMOP2, i_freeStablePtr }
1386
1387     /* foreign export dynamic support */
1388     , { "primCreateAdjThunkARCH",    "sAC","A",  MONAD_IO, i_PRIMOP2, i_createAdjThunkARCH }
1389
1390     /* misc handy hacks */
1391     , { "primGetArgc",               "",   "I",  MONAD_IO, i_PRIMOP2, i_getArgc }
1392     , { "primGetArgv",               "I",  "A",  MONAD_IO, i_PRIMOP2, i_getArgv }
1393
1394 #ifdef PROVIDE_PTREQUALITY
1395     , { "primReallyUnsafePtrEquality", "aa", "B",MONAD_Id, i_PRIMOP2, i_reallyUnsafePtrEquality }
1396 #endif
1397 #ifdef PROVIDE_COERCE
1398     , { "primUnsafeCoerce",          "a", "b",   MONAD_Id, i_PRIMOP2, i_unsafeCoerce }
1399 #endif
1400 #ifdef PROVIDE_CONCURRENT
1401     /* Concurrency operations */
1402     , { "primFork",                  "a", "T",   MONAD_IO, i_PRIMOP2, i_fork }
1403     , { "primKillThread",            "T", "",    MONAD_IO, i_PRIMOP2, i_killThread }
1404     , { "primDelay",                 "I", "",    MONAD_IO, i_PRIMOP2, i_delay }
1405     , { "primWaitRead",              "I", "",    MONAD_IO, i_PRIMOP2, i_waitRead }
1406     , { "primWaitWrite",             "I", "",    MONAD_IO, i_PRIMOP2, i_waitWrite }
1407 #endif
1408     , { "primNewEmptyMVar",         "",  "r",   MONAD_IO, i_PRIMOP2, i_newMVar }
1409       /* primTakeMVar is handwritten bytecode */
1410     , { "primPutMVar",               "ra", "",   MONAD_IO, i_PRIMOP2, i_putMVar } 
1411     , { "primSameMVar",              "rr", "B",  MONAD_Id, i_PRIMOP2, i_sameMVar }
1412     , { "primGetThreadId",           "",   "T",  MONAD_IO, i_PRIMOP2, i_getThreadId }
1413     , { "primCmpThreadIds",          "TT", "I",  MONAD_Id, i_PRIMOP2, i_cmpThreadIds }
1414     , { "primForkIO",                 "a", "T",  MONAD_IO, i_PRIMOP2, i_forkIO }
1415   
1416     /* Ccall is polyadic - so it's excluded from this table */
1417
1418     , { 0,0,0,0,0,0 }
1419 };
1420
1421 AsmPrim ccall_ccall_Id
1422    = { "ccall", 0, 0, MONAD_IO, i_PRIMOP2, i_ccall_ccall_Id };
1423 AsmPrim ccall_ccall_IO
1424    = { "ccall", 0, 0, MONAD_IO, i_PRIMOP2, i_ccall_ccall_IO };
1425 AsmPrim ccall_stdcall_Id 
1426    = { "ccall", 0, 0, MONAD_IO, i_PRIMOP2, i_ccall_stdcall_Id };
1427 AsmPrim ccall_stdcall_IO 
1428    = { "ccall", 0, 0, MONAD_IO, i_PRIMOP2, i_ccall_stdcall_IO };
1429
1430
1431 AsmPrim* asmFindPrim( char* s )
1432 {
1433     int i;
1434     for (i=0; asmPrimOps[i].name; ++i) {
1435         if (strcmp(s,asmPrimOps[i].name)==0) {
1436             return &asmPrimOps[i];
1437         }
1438     }
1439     return 0;
1440 }
1441
1442 AsmPrim* asmFindPrimop( AsmInstr prefix, AsmInstr op )
1443 {
1444     nat i;
1445     for (i=0; asmPrimOps[i].name; ++i) {
1446         if (asmPrimOps[i].prefix == prefix && asmPrimOps[i].opcode == op) {
1447             return &asmPrimOps[i];
1448         }
1449     }
1450     return 0;
1451 }
1452
1453 /* --------------------------------------------------------------------------
1454  * Handwritten primops
1455  * ------------------------------------------------------------------------*/
1456
1457 AsmBCO asm_BCO_catch ( void )
1458 {
1459    AsmBCO bco = asmBeginBCO(0 /*NIL*/);
1460    emiti_8(bco,i_ARG_CHECK,2);
1461    emiti_8(bco,i_PRIMOP1,i_pushcatchframe);
1462    incSp(bco, (1-2)*sizeofW(StgPtr) + sizeofW(StgCatchFrame));
1463    emiti_(bco,i_ENTER);
1464    decSp(bco, sizeofW(StgPtr));
1465    asmEndBCO(bco);
1466    return bco;
1467 }
1468
1469 AsmBCO asm_BCO_raise ( void )
1470 {
1471    AsmBCO bco = asmBeginBCO(0 /*NIL*/);
1472    emiti_8(bco,i_ARG_CHECK,1);
1473    emiti_8(bco,i_PRIMOP2,i_raise);
1474    decSp(bco,sizeofW(StgPtr));
1475    asmEndBCO(bco);
1476    return bco;
1477 }
1478
1479 AsmBCO asm_BCO_seq ( void )
1480 {
1481    AsmBCO eval, cont;
1482
1483    cont = asmBeginBCO(0 /*NIL*/);
1484    emiti_8(cont,i_ARG_CHECK,2);   /* should never fail */
1485    emit_i_VAR(cont,1);
1486    emit_i_SLIDE(cont,1,2);
1487    emiti_(cont,i_ENTER);
1488    incSp(cont, 3*sizeofW(StgPtr));
1489    asmEndBCO(cont);
1490
1491    eval = asmBeginBCO(0 /*NIL*/);
1492    emiti_8(eval,i_ARG_CHECK,2);
1493    emit_i_RETADDR(eval,eval->object.ptrs.len);
1494    asmPtr(eval,&(cont->object));
1495    emit_i_VAR(eval,2);
1496    emit_i_SLIDE(eval,3,1);
1497    emiti_8(eval,i_PRIMOP1,i_pushseqframe);
1498    emiti_(eval,i_ENTER);
1499    incSp(eval, sizeofW(StgSeqFrame) + 4*sizeofW(StgPtr));
1500    asmEndBCO(eval);
1501
1502    return eval;
1503 }
1504
1505 AsmBCO asm_BCO_takeMVar ( void )
1506 {
1507    AsmBCO kase, casecont, take;
1508
1509    take = asmBeginBCO(0 /*NIL*/);
1510    emit_i_VAR(take,0);
1511    emiti_8(take,i_PRIMOP2,i_takeMVar);
1512    emit_i_VAR(take,3);
1513    emit_i_VAR(take,1);
1514    emit_i_VAR(take,4);
1515    emit_i_SLIDE(take,3,4);
1516    emiti_(take,i_ENTER);
1517    incSp(take,20);
1518    asmEndBCO(take);
1519
1520    casecont = asmBeginBCO(0 /*NIL*/);
1521    emiti_(casecont,i_UNPACK);
1522    emit_i_VAR(casecont,4);
1523    emit_i_VAR(casecont,4);
1524    emit_i_VAR(casecont,2);
1525    emit_i_CONST(casecont,casecont->object.ptrs.len);
1526    asmPtr(casecont,&(take->object));
1527    emit_i_SLIDE(casecont,4,5);
1528    emiti_(casecont,i_ENTER);
1529    incSp(casecont,20);
1530    asmEndBCO(casecont);
1531
1532    kase = asmBeginBCO(0 /*NIL*/);
1533    emiti_8(kase,i_ARG_CHECK,3);
1534    emit_i_RETADDR(kase,kase->object.ptrs.len);
1535    asmPtr(kase,&(casecont->object));
1536    emit_i_VAR(kase,2);
1537    emiti_(kase,i_ENTER);
1538    incSp(kase,20);
1539    asmEndBCO(kase);
1540
1541    return kase;
1542 }
1543
1544
1545 /* --------------------------------------------------------------------------
1546  * Heap manipulation
1547  * ------------------------------------------------------------------------*/
1548
1549 AsmVar asmAllocCONSTR   ( AsmBCO bco, AsmInfo info )
1550 {
1551     int i;
1552     ASSERT( sizeW_fromITBL(info) >= MIN_NONUPD_SIZE + sizeofW(StgHeader) );
1553
1554     /* Look in this bco's collection of nonpointers (literals)
1555        to see if the itbl pointer is already there.  If so, re-use it. */
1556     i = asmFindInNonPtrs ( bco, (StgWord)info );
1557
1558     if (i == -1) {
1559        emit_i_ALLOC_CONSTR(bco,bco->nps.len);
1560        asmWords(bco,AsmInfo,info);
1561     } else {
1562        emit_i_ALLOC_CONSTR(bco,i);
1563     }
1564
1565     incSp(bco, sizeofW(StgClosurePtr));
1566     return bco->sp;
1567 }
1568
1569 AsmSp asmBeginPack( AsmBCO bco )
1570 {
1571     return bco->sp;
1572 }
1573
1574 void asmEndPack( AsmBCO bco, AsmVar v, AsmSp start, AsmInfo info )
1575 {
1576     nat size = bco->sp - start;
1577     assert(bco->sp >= start);
1578     assert(start >= v);
1579     /* only reason to include info is for this assertion */
1580     assert(info->layout.payload.ptrs == size);
1581     emit_i_PACK(bco, bco->sp - v);
1582     setSp(bco, start);
1583 }
1584
1585 void asmBeginUnpack( AsmBCO bco )
1586 {
1587     /* dummy to make it look prettier */
1588 }
1589
1590 void asmEndUnpack( AsmBCO bco )
1591 {
1592     emiti_(bco,i_UNPACK);
1593 }
1594
1595 AsmVar asmAllocAP( AsmBCO bco, AsmNat words )
1596 {
1597     emiti_8(bco,i_ALLOC_AP,words);
1598     incSp(bco, sizeofW(StgPtr));
1599     return bco->sp;
1600 }
1601
1602 AsmSp asmBeginMkAP( AsmBCO bco )
1603 {
1604     return bco->sp;
1605 }
1606
1607 void asmEndMkAP( AsmBCO bco, AsmVar v, AsmSp start )
1608 {
1609     emit_i_MKAP(bco,bco->sp-v,bco->sp-start-1);
1610             /* -1 because fun isn't counted */
1611     setSp(bco, start);
1612 }
1613
1614 AsmVar asmAllocPAP( AsmBCO bco, AsmNat size )
1615 {
1616     emiti_8(bco,i_ALLOC_PAP,size);
1617     incSp(bco, sizeofW(StgPtr));
1618     return bco->sp;
1619 }
1620
1621 AsmSp asmBeginMkPAP( AsmBCO bco )
1622 {
1623     return bco->sp;
1624 }
1625
1626 void asmEndMkPAP( AsmBCO bco, AsmVar v, AsmSp start )
1627 {
1628     emiti_8_8(bco,i_MKPAP,bco->sp-v,bco->sp-start-1);
1629             /* -1 because fun isn't counted */
1630     setSp(bco, start);
1631 }
1632
1633 AsmVar asmClosure( AsmBCO bco, AsmObject p )
1634 {
1635     emit_i_CONST(bco,bco->object.ptrs.len);
1636     asmPtr(bco,p);
1637     incSp(bco, sizeofW(StgPtr));
1638     return bco->sp;
1639 }
1640
1641 AsmVar asmGHCClosure( AsmBCO bco, AsmObject p )
1642 {
1643     // A complete hack.  Pushes the address as a tagged int
1644     // and then uses SLIDE to get rid of the tag.  Appalling.
1645     asmConstInt(bco, (AsmInt)p);
1646     emit_i_SLIDE(bco,0,1); decSp(bco,1);
1647     return bco->sp;
1648 }
1649
1650
1651 /* --------------------------------------------------------------------------
1652  * Building InfoTables
1653  * ------------------------------------------------------------------------*/
1654
1655 AsmInfo asmMkInfo( AsmNat tag, AsmNat ptrs )
1656 {
1657     StgInfoTable* info = stgMallocBytes( sizeof(StgInfoTable),"asmMkInfo");
1658     /* Note: the evaluator automatically pads objects with the right number
1659      * of non-ptrs to satisfy MIN_NONUPD_SIZE restrictions.
1660      */
1661     AsmNat nptrs = stg_max(0,MIN_NONUPD_SIZE-ptrs);
1662
1663     /* initialisation code based on INFO_TABLE_CONSTR */
1664     info->layout.payload.ptrs  = ptrs;
1665     info->layout.payload.nptrs = nptrs;
1666     info->srt_len = tag;
1667     info->type    = CONSTR;
1668 #ifdef USE_MINIINTERPRETER
1669     info->entry   = stgCast(StgFunPtr,&Hugs_CONSTR_entry);
1670 #else
1671 #warning asmMkInfo: Need to insert entry code in some cunning way
1672 #endif
1673     ASSERT( sizeW_fromITBL(info) >= MIN_NONUPD_SIZE + sizeofW(StgHeader) );
1674     return info;
1675 }
1676
1677 /*-------------------------------------------------------------------------*/
1678
1679 #endif /* INTERPRETER */
1680