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