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