674618597a328ba7175be94b3be02d04227a6087
[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.32 $
9  * $Date: 2000/06/15 13:23:51 $
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 #ifdef XMLAMBDA
865 static void emit_i_ALLOC_ROW( AsmBCO bco, int n )
866 {
867   ASSERT(n >= 0);
868   if (n < 256)
869       emiti_8 ( bco, i_ALLOC_ROW, n ); else
870       emiti_16( bco, i_ALLOC_ROW_big, n );
871 }
872
873 static void emit_i_PACK_ROW (AsmBCO bco, int var )
874 {
875    ASSERT(var >= 0);
876    if (var < 256)
877       emiti_8 ( bco, i_PACK_ROW, var ); else
878       emiti_16( bco, i_PACK_ROW_big, var );
879 }
880
881 static void emit_i_PACK_INJ (AsmBCO bco, int var )
882 {
883    ASSERT(var >= 0);
884    if (var < 256)
885       emiti_8 ( bco, i_PACK_INJ, var ); else
886       emiti_16( bco, i_PACK_INJ_big, var );
887 }
888
889 static void emit_i_TEST_INJ (AsmBCO bco, int var )
890 {
891    ASSERT(var >= 0);
892    if (var < 256)
893       emiti_8_16 ( bco, i_TEST_INJ, var, 0 ); else
894       emiti_16_16( bco, i_TEST_INJ_big, var, 0 );
895 }
896 #endif
897
898 /* --------------------------------------------------------------------------
899  * Arg checks.
900  * ------------------------------------------------------------------------*/
901
902 AsmSp  asmBeginArgCheck ( AsmBCO bco )
903 {
904     ASSERT(bco->sp == 0);
905     return bco->sp;
906 }
907
908 void   asmEndArgCheck   ( AsmBCO bco, AsmSp last_arg )
909 {
910     nat args = bco->sp - last_arg;
911     if (args != 0) { /* optimisation */
912         emiti_8(bco,i_ARG_CHECK,args);
913     }
914 }
915
916 /* --------------------------------------------------------------------------
917  * Creating and using "variables"
918  * ------------------------------------------------------------------------*/
919
920 AsmVar asmBind          ( AsmBCO bco, AsmRep rep )
921 {
922     incSp(bco,repSizeW(rep));
923     return bco->sp;
924 }
925
926 void   asmVar           ( AsmBCO bco, AsmVar v, AsmRep rep )
927 {
928     int offset;
929
930     if (rep == VOID_REP) {
931         emiti_(bco,i_VOID);
932         incSp(bco,repSizeW(rep));
933         return;
934     }
935
936     offset = bco->sp - v;
937     switch (rep) {
938     case BOOL_REP:
939     case INT_REP:
940             emit_i_VAR_INT(bco,offset);
941             break;
942     case THREADID_REP:
943     case WORD_REP:
944             emit_i_VAR_WORD(bco,offset);
945             break;
946     case ADDR_REP:
947             emit_i_VAR_ADDR(bco,offset);
948             break;
949     case CHAR_REP:
950             emit_i_VAR_CHAR(bco,offset);
951             break;
952     case FLOAT_REP:
953             emit_i_VAR_FLOAT(bco,offset);
954             break;
955     case DOUBLE_REP:
956             emit_i_VAR_DOUBLE(bco,offset);
957             break;
958     case STABLE_REP:
959             emit_i_VAR_STABLE(bco,offset);
960             break;
961
962     case INTEGER_REP:
963 #ifdef PROVIDE_WEAK
964     case WEAK_REP: 
965 #endif
966 #ifdef PROVIDE_FOREIGN
967     case FOREIGN_REP:
968 #endif
969     case ALPHA_REP:    /* a                        */ 
970     case BETA_REP:     /* b                        */
971     case GAMMA_REP:    /* c                        */ 
972     case DELTA_REP:    /* d                        */ 
973     case HANDLER_REP:  /* IOError -> IO a          */
974     case ERROR_REP:    /* IOError                  */
975     case ARR_REP    :  /* PrimArray              a */
976     case BARR_REP   :  /* PrimByteArray          a */
977     case REF_REP    :  /* Ref                  s a */
978     case MUTARR_REP :  /* PrimMutableArray     s a */
979     case MUTBARR_REP:  /* PrimMutableByteArray s a */
980     case MVAR_REP:     /* MVar a                   */
981     case PTR_REP:
982             emit_i_VAR(bco,offset);
983             break;
984     default:
985             barf("asmVar %d",rep);
986     }
987     incSp(bco,repSizeW(rep));
988 }
989
990 /* --------------------------------------------------------------------------
991  * Tail calls
992  * ------------------------------------------------------------------------*/
993
994 AsmSp asmBeginEnter( AsmBCO bco )
995 {
996     return bco->sp;
997 }
998
999 void asmEndEnter( AsmBCO bco, AsmSp sp1, AsmSp sp2 )
1000 {
1001     int x = bco->sp - sp1;
1002     int y = sp1 - sp2;
1003     ASSERT(x >= 0 && y >= 0);
1004     if (y != 0) {
1005         emit_i_SLIDE(bco,x,y);
1006         decSp(bco,sp1 - sp2);
1007     }
1008     emiti_(bco,i_ENTER);
1009     decSp(bco,sizeofW(StgPtr));
1010 }
1011
1012 /* --------------------------------------------------------------------------
1013  * Build boxed Ints, Floats, etc
1014  * ------------------------------------------------------------------------*/
1015
1016 AsmVar asmBox( AsmBCO bco, AsmRep rep )
1017 {
1018     switch (rep) {
1019     case CHAR_REP:
1020             emiti_(bco,i_PACK_CHAR);
1021             break;
1022     case INT_REP:
1023             emiti_(bco,i_PACK_INT);
1024             break;
1025     case THREADID_REP:
1026     case WORD_REP:
1027             emiti_(bco,i_PACK_WORD);
1028             break;
1029     case ADDR_REP:
1030             emiti_(bco,i_PACK_ADDR);
1031             break;
1032     case FLOAT_REP:
1033             emiti_(bco,i_PACK_FLOAT);
1034             break;
1035     case DOUBLE_REP:
1036             emiti_(bco,i_PACK_DOUBLE);
1037             break;
1038     case STABLE_REP:
1039             emiti_(bco,i_PACK_STABLE);
1040             break;
1041
1042     default:
1043             barf("asmBox %d",rep);
1044     }
1045     /* NB: these operations DO pop their arg       */
1046     decSp(bco, repSizeW(rep));   /* pop unboxed arg */
1047     incSp(bco, sizeofW(StgPtr)); /* push box        */
1048     return bco->sp;
1049 }
1050
1051 /* --------------------------------------------------------------------------
1052  * Unbox Ints, Floats, etc
1053  * ------------------------------------------------------------------------*/
1054
1055 AsmVar asmUnbox( AsmBCO bco, AsmRep rep )
1056 {
1057     switch (rep) {
1058     case INT_REP:
1059             emiti_(bco,i_UNPACK_INT);
1060             break;
1061     case THREADID_REP:
1062     case WORD_REP:
1063             emiti_(bco,i_UNPACK_WORD);
1064             break;
1065     case ADDR_REP:
1066             emiti_(bco,i_UNPACK_ADDR);
1067             break;
1068     case CHAR_REP:
1069             emiti_(bco,i_UNPACK_CHAR);
1070             break;
1071     case FLOAT_REP:
1072             emiti_(bco,i_UNPACK_FLOAT);
1073             break;
1074     case DOUBLE_REP:
1075             emiti_(bco,i_UNPACK_DOUBLE);
1076             break;
1077     case STABLE_REP:
1078             emiti_(bco,i_UNPACK_STABLE);
1079             break;
1080     default:
1081             barf("asmUnbox %d",rep);
1082     }
1083     /* NB: these operations DO NOT pop their arg  */
1084     incSp(bco, repSizeW(rep)); /* push unboxed arg */
1085     return bco->sp;
1086 }
1087
1088
1089 /* --------------------------------------------------------------------------
1090  * Push unboxed Ints, Floats, etc
1091  * ------------------------------------------------------------------------*/
1092
1093 void asmConstInt( AsmBCO bco, AsmInt x )
1094 {
1095     emit_i_CONST_INT(bco,bco->n_words);
1096     asmAddNonPtrWords(bco,AsmInt,x);
1097     incSp(bco, repSizeW(INT_REP));
1098 }
1099
1100 void asmConstInteger( AsmBCO bco, AsmString x )
1101 {
1102     emit_i_CONST_INTEGER(bco,bco->n_words);
1103     asmAddNonPtrWords(bco,AsmString,x);
1104     incSp(bco, repSizeW(INTEGER_REP));
1105 }
1106
1107 void asmConstAddr( AsmBCO bco, AsmAddr x )
1108 {
1109     emit_i_CONST_ADDR(bco,bco->n_words);
1110     asmAddNonPtrWords(bco,AsmAddr,x);
1111     incSp(bco, repSizeW(ADDR_REP));
1112 }
1113
1114 void asmConstWord( AsmBCO bco, AsmWord x )
1115 {
1116     emit_i_CONST_INT(bco,bco->n_words);
1117     asmAddNonPtrWords(bco,AsmWord,(AsmInt)x);
1118     incSp(bco, repSizeW(WORD_REP));
1119 }
1120
1121 void asmConstChar( AsmBCO bco, AsmChar x )
1122 {
1123     emit_i_CONST_CHAR(bco,bco->n_words);
1124     asmAddNonPtrWords(bco,AsmChar,x);
1125     incSp(bco, repSizeW(CHAR_REP));
1126 }
1127
1128 void asmConstFloat( AsmBCO bco, AsmFloat x )
1129 {
1130     emit_i_CONST_FLOAT(bco,bco->n_words);
1131     asmAddNonPtrWords(bco,AsmFloat,x);
1132     incSp(bco, repSizeW(FLOAT_REP));
1133 }
1134
1135 void asmConstDouble( AsmBCO bco, AsmDouble x )
1136 {
1137     emit_i_CONST_DOUBLE(bco,bco->n_words);
1138     asmAddNonPtrWords(bco,AsmDouble,x);
1139     incSp(bco, repSizeW(DOUBLE_REP));
1140 }
1141
1142 /* --------------------------------------------------------------------------
1143  * Algebraic case helpers
1144  * ------------------------------------------------------------------------*/
1145
1146 /* a mildly bogus pair of functions... */
1147 AsmSp asmBeginCase( AsmBCO bco )
1148 {
1149     return bco->sp;
1150 }
1151
1152 void asmEndCase( AsmBCO bco __attribute__ ((unused)) )
1153 {
1154 }
1155
1156 AsmSp asmContinuation( AsmBCO bco, AsmBCO ret_addr )
1157 {
1158     emit_i_RETADDR(bco,bco->n_refs);
1159     asmAddRefObject(bco,ret_addr);
1160     incSp(bco, 2 * sizeofW(StgPtr));
1161     return bco->sp;
1162 }
1163
1164 AsmBCO asmBeginContinuation ( AsmSp sp, int /*List*/ alts )
1165 {
1166     AsmBCO bco = asmBeginBCO(alts);
1167     setSp(bco, sp);
1168     return bco;
1169 }
1170
1171 void asmEndContinuation ( AsmBCO bco )
1172 {
1173     asmEndBCO(bco);
1174 }
1175
1176
1177 /* --------------------------------------------------------------------------
1178  * Branches
1179  * ------------------------------------------------------------------------*/
1180
1181 AsmSp asmBeginAlt( AsmBCO bco )
1182 {
1183     return bco->sp;
1184 }
1185
1186 void asmEndAlt( AsmBCO bco, AsmSp  sp )
1187 {
1188     setSp(bco,sp);
1189 }
1190
1191 AsmPc asmTest( AsmBCO bco, AsmWord tag )
1192 {
1193     emiti_8_16(bco,i_TEST,tag,0);
1194     return bco->n_insns;
1195 }
1196
1197 AsmPc asmTestInt ( AsmBCO bco, AsmVar v, AsmInt x )
1198 {
1199     asmVar(bco,v,INT_REP);
1200     asmConstInt(bco,x);
1201     emiti_16(bco,i_TEST_INT,0);
1202     decSp(bco, 2*repSizeW(INT_REP));
1203     return bco->n_insns;
1204 }
1205
1206 void asmFixBranch ( AsmBCO bco, AsmPc from )
1207 {
1208     int distance = bco->n_insns - from;
1209     ASSERT(distance >= 0);
1210     ASSERT(distance < 65536);
1211     setInstrs(bco,from-2,distance/256);
1212     setInstrs(bco,from-1,distance%256);
1213 }
1214
1215 void asmPanic( AsmBCO bco )
1216 {
1217     emiti_(bco,i_PANIC); /* "irrefutable" pattern failed - oops! */
1218 }
1219
1220 /* --------------------------------------------------------------------------
1221  * Primops
1222  * ------------------------------------------------------------------------*/
1223
1224 AsmSp asmBeginPrim( AsmBCO bco )
1225 {
1226     return bco->sp;
1227 }
1228
1229 void asmEndPrim( AsmBCO bco, const AsmPrim* prim, AsmSp base )
1230 {
1231     emiti_8(bco,prim->prefix,prim->opcode);
1232     setSp(bco, base);
1233 }
1234
1235 char* asmGetPrimopName ( AsmPrim* p )
1236 {
1237    return p->name;
1238 }
1239
1240 /* Hugs used to let you add arbitrary primops with arbitrary types
1241  * just by editing Prelude.hs or any other file you wanted.
1242  * We deliberately avoided that approach because we wanted more
1243  * control over which primops are provided.
1244  */
1245 AsmPrim asmPrimOps[] = {
1246
1247     /* Char# operations */
1248       { "primGtChar",                "CC", "B",  MONAD_Id, i_PRIMOP1, i_gtChar }
1249     , { "primGeChar",                "CC", "B",  MONAD_Id, i_PRIMOP1, i_geChar }
1250     , { "primEqChar",                "CC", "B",  MONAD_Id, i_PRIMOP1, i_eqChar }
1251     , { "primNeChar",                "CC", "B",  MONAD_Id, i_PRIMOP1, i_neChar }
1252     , { "primLtChar",                "CC", "B",  MONAD_Id, i_PRIMOP1, i_ltChar }
1253     , { "primLeChar",                "CC", "B",  MONAD_Id, i_PRIMOP1, i_leChar }
1254     , { "primCharToInt",             "C",  "I",  MONAD_Id, i_PRIMOP1, i_charToInt }
1255     , { "primIntToChar",             "I",  "C",  MONAD_Id, i_PRIMOP1, i_intToChar }
1256
1257     /* Int# operations */
1258     , { "primGtInt",                 "II", "B",  MONAD_Id, i_PRIMOP1, i_gtInt }
1259     , { "primGeInt",                 "II", "B",  MONAD_Id, i_PRIMOP1, i_geInt }
1260     , { "primEqInt",                 "II", "B",  MONAD_Id, i_PRIMOP1, i_eqInt }
1261     , { "primNeInt",                 "II", "B",  MONAD_Id, i_PRIMOP1, i_neInt }
1262     , { "primLtInt",                 "II", "B",  MONAD_Id, i_PRIMOP1, i_ltInt }
1263     , { "primLeInt",                 "II", "B",  MONAD_Id, i_PRIMOP1, i_leInt }
1264     , { "primMinInt",                "",   "I",  MONAD_Id, i_PRIMOP1, i_minInt }
1265     , { "primMaxInt",                "",   "I",  MONAD_Id, i_PRIMOP1, i_maxInt }
1266     , { "primPlusInt",               "II", "I",  MONAD_Id, i_PRIMOP1, i_plusInt }
1267     , { "primMinusInt",              "II", "I",  MONAD_Id, i_PRIMOP1, i_minusInt }
1268     , { "primTimesInt",              "II", "I",  MONAD_Id, i_PRIMOP1, i_timesInt }
1269     , { "primQuotInt",               "II", "I",  MONAD_Id, i_PRIMOP1, i_quotInt }
1270     , { "primRemInt",                "II", "I",  MONAD_Id, i_PRIMOP1, i_remInt }
1271     , { "primQuotRemInt",            "II", "II", MONAD_Id, i_PRIMOP1, i_quotRemInt }
1272     , { "primNegateInt",             "I",  "I",  MONAD_Id, i_PRIMOP1, i_negateInt }
1273
1274     , { "primAndInt",                "II", "I",  MONAD_Id, i_PRIMOP1, i_andInt }
1275     , { "primOrInt",                 "II", "I",  MONAD_Id, i_PRIMOP1, i_orInt }
1276     , { "primXorInt",                "II", "I",  MONAD_Id, i_PRIMOP1, i_xorInt }
1277     , { "primNotInt",                "I",  "I",  MONAD_Id, i_PRIMOP1, i_notInt }
1278     , { "primShiftLInt",             "II", "I",  MONAD_Id, i_PRIMOP1, i_shiftLInt }
1279     , { "primShiftRAInt",            "II", "I",  MONAD_Id, i_PRIMOP1, i_shiftRAInt }
1280     , { "primShiftRLInt",            "II", "I",  MONAD_Id, i_PRIMOP1, i_shiftRLInt }
1281
1282     /* Word# operations */
1283     , { "primGtWord",                "WW", "B",  MONAD_Id, i_PRIMOP1, i_gtWord }
1284     , { "primGeWord",                "WW", "B",  MONAD_Id, i_PRIMOP1, i_geWord }
1285     , { "primEqWord",                "WW", "B",  MONAD_Id, i_PRIMOP1, i_eqWord }
1286     , { "primNeWord",                "WW", "B",  MONAD_Id, i_PRIMOP1, i_neWord }
1287     , { "primLtWord",                "WW", "B",  MONAD_Id, i_PRIMOP1, i_ltWord }
1288     , { "primLeWord",                "WW", "B",  MONAD_Id, i_PRIMOP1, i_leWord }
1289     , { "primMinWord",               "",   "W",  MONAD_Id, i_PRIMOP1, i_minWord }
1290     , { "primMaxWord",               "",   "W",  MONAD_Id, i_PRIMOP1, i_maxWord }
1291     , { "primPlusWord",              "WW", "W",  MONAD_Id, i_PRIMOP1, i_plusWord }
1292     , { "primMinusWord",             "WW", "W",  MONAD_Id, i_PRIMOP1, i_minusWord }
1293     , { "primTimesWord",             "WW", "W",  MONAD_Id, i_PRIMOP1, i_timesWord }
1294     , { "primQuotWord",              "WW", "W",  MONAD_Id, i_PRIMOP1, i_quotWord }
1295     , { "primRemWord",               "WW", "W",  MONAD_Id, i_PRIMOP1, i_remWord }
1296     , { "primQuotRemWord",           "WW", "WW", MONAD_Id, i_PRIMOP1, i_quotRemWord }
1297     , { "primNegateWord",            "W",  "W",  MONAD_Id, i_PRIMOP1, i_negateWord }
1298
1299     , { "primAndWord",               "WW", "W",  MONAD_Id, i_PRIMOP1, i_andWord }
1300     , { "primOrWord",                "WW", "W",  MONAD_Id, i_PRIMOP1, i_orWord }
1301     , { "primXorWord",               "WW", "W",  MONAD_Id, i_PRIMOP1, i_xorWord }
1302     , { "primNotWord",               "W",  "W",  MONAD_Id, i_PRIMOP1, i_notWord }
1303     , { "primShiftLWord",            "WW", "W",  MONAD_Id, i_PRIMOP1, i_shiftLWord }
1304     , { "primShiftRAWord",           "WW", "W",  MONAD_Id, i_PRIMOP1, i_shiftRAWord }
1305     , { "primShiftRLWord",           "WW", "W",  MONAD_Id, i_PRIMOP1, i_shiftRLWord }
1306
1307     , { "primIntToWord",             "I",  "W",  MONAD_Id, i_PRIMOP1, i_intToWord }
1308     , { "primWordToInt",             "W",  "I",  MONAD_Id, i_PRIMOP1, i_wordToInt }
1309
1310     /* Addr# operations */
1311     , { "primGtAddr",                "AA", "B",  MONAD_Id, i_PRIMOP1, i_gtAddr }
1312     , { "primGeAddr",                "AA", "B",  MONAD_Id, i_PRIMOP1, i_geAddr }
1313     , { "primEqAddr",                "AA", "B",  MONAD_Id, i_PRIMOP1, i_eqAddr }
1314     , { "primNeAddr",                "AA", "B",  MONAD_Id, i_PRIMOP1, i_neAddr }
1315     , { "primLtAddr",                "AA", "B",  MONAD_Id, i_PRIMOP1, i_ltAddr }
1316     , { "primLeAddr",                "AA", "B",  MONAD_Id, i_PRIMOP1, i_leAddr }
1317     , { "primIntToAddr",             "I",  "A",  MONAD_Id, i_PRIMOP1, i_intToAddr }
1318     , { "primAddrToInt",             "A",  "I",  MONAD_Id, i_PRIMOP1, i_addrToInt }
1319
1320     , { "primIndexCharOffAddr",      "AI", "C",  MONAD_Id, i_PRIMOP1, i_indexCharOffAddr }
1321     , { "primIndexIntOffAddr",       "AI", "I",  MONAD_Id, i_PRIMOP1, i_indexIntOffAddr }
1322     , { "primIndexWordOffAddr",      "AI", "W",  MONAD_Id, i_PRIMOP1, i_indexWordOffAddr }
1323     , { "primIndexAddrOffAddr",      "AI", "A",  MONAD_Id, i_PRIMOP1, i_indexAddrOffAddr }
1324     , { "primIndexFloatOffAddr",     "AI", "F",  MONAD_Id, i_PRIMOP1, i_indexFloatOffAddr }
1325     , { "primIndexDoubleOffAddr",    "AI", "D",  MONAD_Id, i_PRIMOP1, i_indexDoubleOffAddr }
1326     , { "primIndexStableOffAddr",    "AI", "s",  MONAD_Id, i_PRIMOP1, i_indexStableOffAddr }
1327
1328     /* Stable# operations */
1329     , { "primIntToStablePtr",        "I",  "s",  MONAD_Id, i_PRIMOP1, i_intToStable }
1330     , { "primStablePtrToInt",        "s",  "I",  MONAD_Id, i_PRIMOP1, i_stableToInt }
1331
1332     /* These ops really ought to be in the IO monad */
1333     , { "primReadCharOffAddr",       "AI", "C",  MONAD_ST, i_PRIMOP1, i_readCharOffAddr }
1334     , { "primReadIntOffAddr",        "AI", "I",  MONAD_ST, i_PRIMOP1, i_readIntOffAddr }
1335     , { "primReadWordOffAddr",       "AI", "W",  MONAD_ST, i_PRIMOP1, i_readWordOffAddr }
1336     , { "primReadAddrOffAddr",       "AI", "A",  MONAD_ST, i_PRIMOP1, i_readAddrOffAddr }
1337     , { "primReadFloatOffAddr",      "AI", "F",  MONAD_ST, i_PRIMOP1, i_readFloatOffAddr }
1338     , { "primReadDoubleOffAddr",     "AI", "D",  MONAD_ST, i_PRIMOP1, i_readDoubleOffAddr }
1339     , { "primReadStableOffAddr",     "AI", "s",  MONAD_ST, i_PRIMOP1, i_readStableOffAddr }
1340
1341     /* These ops really ought to be in the IO monad */
1342     , { "primWriteCharOffAddr",      "AIC", "",  MONAD_ST, i_PRIMOP1, i_writeCharOffAddr }
1343     , { "primWriteIntOffAddr",       "AII", "",  MONAD_ST, i_PRIMOP1, i_writeIntOffAddr }
1344     , { "primWriteWordOffAddr",      "AIW", "",  MONAD_ST, i_PRIMOP1, i_writeWordOffAddr }
1345     , { "primWriteAddrOffAddr",      "AIA", "",  MONAD_ST, i_PRIMOP1, i_writeAddrOffAddr }
1346     , { "primWriteFloatOffAddr",     "AIF", "",  MONAD_ST, i_PRIMOP1, i_writeFloatOffAddr }
1347     , { "primWriteDoubleOffAddr",    "AID", "",  MONAD_ST, i_PRIMOP1, i_writeDoubleOffAddr }
1348     , { "primWriteStableOffAddr",    "AIs", "",  MONAD_ST, i_PRIMOP1, i_writeStableOffAddr }
1349
1350     /* Integer operations */
1351     , { "primCompareInteger",        "ZZ", "I",  MONAD_Id, i_PRIMOP1, i_compareInteger }
1352     , { "primNegateInteger",         "Z",  "Z",  MONAD_Id, i_PRIMOP1, i_negateInteger }
1353     , { "primPlusInteger",           "ZZ", "Z",  MONAD_Id, i_PRIMOP1, i_plusInteger }
1354     , { "primMinusInteger",          "ZZ", "Z",  MONAD_Id, i_PRIMOP1, i_minusInteger }
1355     , { "primTimesInteger",          "ZZ", "Z",  MONAD_Id, i_PRIMOP1, i_timesInteger }
1356     , { "primQuotRemInteger",        "ZZ", "ZZ", MONAD_Id, i_PRIMOP1, i_quotRemInteger }
1357     , { "primDivModInteger",         "ZZ", "ZZ", MONAD_Id, i_PRIMOP1, i_divModInteger }
1358     , { "primIntegerToInt",          "Z",  "I",  MONAD_Id, i_PRIMOP1, i_integerToInt }
1359     , { "primIntToInteger",          "I",  "Z",  MONAD_Id, i_PRIMOP1, i_intToInteger }
1360     , { "primIntegerToWord",         "Z",  "W",  MONAD_Id, i_PRIMOP1, i_integerToWord }
1361     , { "primWordToInteger",         "W",  "Z",  MONAD_Id, i_PRIMOP1, i_wordToInteger }
1362     , { "primIntegerToFloat",        "Z",  "F",  MONAD_Id, i_PRIMOP1, i_integerToFloat }
1363     , { "primFloatToInteger",        "F",  "Z",  MONAD_Id, i_PRIMOP1, i_floatToInteger }
1364     , { "primIntegerToDouble",       "Z",  "D",  MONAD_Id, i_PRIMOP1, i_integerToDouble }
1365     , { "primDoubleToInteger",       "D",  "Z",  MONAD_Id, i_PRIMOP1, i_doubleToInteger }
1366
1367     /* Float# operations */
1368     , { "primGtFloat",               "FF", "B",  MONAD_Id, i_PRIMOP1, i_gtFloat }
1369     , { "primGeFloat",               "FF", "B",  MONAD_Id, i_PRIMOP1, i_geFloat }
1370     , { "primEqFloat",               "FF", "B",  MONAD_Id, i_PRIMOP1, i_eqFloat }
1371     , { "primNeFloat",               "FF", "B",  MONAD_Id, i_PRIMOP1, i_neFloat }
1372     , { "primLtFloat",               "FF", "B",  MONAD_Id, i_PRIMOP1, i_ltFloat }
1373     , { "primLeFloat",               "FF", "B",  MONAD_Id, i_PRIMOP1, i_leFloat }
1374     , { "primMinFloat",              "",   "F",  MONAD_Id, i_PRIMOP1, i_minFloat }
1375     , { "primMaxFloat",              "",   "F",  MONAD_Id, i_PRIMOP1, i_maxFloat }
1376     , { "primRadixFloat",            "",   "I",  MONAD_Id, i_PRIMOP1, i_radixFloat }
1377     , { "primDigitsFloat",           "",   "I",  MONAD_Id, i_PRIMOP1, i_digitsFloat }
1378     , { "primMinExpFloat",           "",   "I",  MONAD_Id, i_PRIMOP1, i_minExpFloat }
1379     , { "primMaxExpFloat",           "",   "I",  MONAD_Id, i_PRIMOP1, i_maxExpFloat }
1380     , { "primPlusFloat",             "FF", "F",  MONAD_Id, i_PRIMOP1, i_plusFloat }
1381     , { "primMinusFloat",            "FF", "F",  MONAD_Id, i_PRIMOP1, i_minusFloat }
1382     , { "primTimesFloat",            "FF", "F",  MONAD_Id, i_PRIMOP1, i_timesFloat }
1383     , { "primDivideFloat",           "FF", "F",  MONAD_Id, i_PRIMOP1, i_divideFloat }
1384     , { "primNegateFloat",           "F",  "F",  MONAD_Id, i_PRIMOP1, i_negateFloat }
1385     , { "primFloatToInt",            "F",  "I",  MONAD_Id, i_PRIMOP1, i_floatToInt }
1386     , { "primIntToFloat",            "I",  "F",  MONAD_Id, i_PRIMOP1, i_intToFloat }
1387     , { "primExpFloat",              "F",  "F",  MONAD_Id, i_PRIMOP1, i_expFloat }
1388     , { "primLogFloat",              "F",  "F",  MONAD_Id, i_PRIMOP1, i_logFloat }
1389     , { "primSqrtFloat",             "F",  "F",  MONAD_Id, i_PRIMOP1, i_sqrtFloat }
1390     , { "primSinFloat",              "F",  "F",  MONAD_Id, i_PRIMOP1, i_sinFloat }
1391     , { "primCosFloat",              "F",  "F",  MONAD_Id, i_PRIMOP1, i_cosFloat }
1392     , { "primTanFloat",              "F",  "F",  MONAD_Id, i_PRIMOP1, i_tanFloat }
1393     , { "primAsinFloat",             "F",  "F",  MONAD_Id, i_PRIMOP1, i_asinFloat }
1394     , { "primAcosFloat",             "F",  "F",  MONAD_Id, i_PRIMOP1, i_acosFloat }
1395     , { "primAtanFloat",             "F",  "F",  MONAD_Id, i_PRIMOP1, i_atanFloat }
1396     , { "primSinhFloat",             "F",  "F",  MONAD_Id, i_PRIMOP1, i_sinhFloat }
1397     , { "primCoshFloat",             "F",  "F",  MONAD_Id, i_PRIMOP1, i_coshFloat }
1398     , { "primTanhFloat",             "F",  "F",  MONAD_Id, i_PRIMOP1, i_tanhFloat }
1399     , { "primPowerFloat",            "FF", "F",  MONAD_Id, i_PRIMOP1, i_powerFloat }
1400     , { "primDecodeFloatZ",          "F",  "ZI", MONAD_Id, i_PRIMOP1, i_decodeFloatZ }
1401     , { "primEncodeFloatZ",          "ZI", "F",  MONAD_Id, i_PRIMOP1, i_encodeFloatZ }
1402     , { "primIsNaNFloat",            "F",  "B",  MONAD_Id, i_PRIMOP1, i_isNaNFloat }
1403     , { "primIsInfiniteFloat",       "F",  "B",  MONAD_Id, i_PRIMOP1, i_isInfiniteFloat }
1404     , { "primIsDenormalizedFloat",   "F",  "B",  MONAD_Id, i_PRIMOP1, i_isDenormalizedFloat }
1405     , { "primIsNegativeZeroFloat",   "F",  "B",  MONAD_Id, i_PRIMOP1, i_isNegativeZeroFloat }
1406     , { "primIsIEEEFloat",           "",   "B",  MONAD_Id, i_PRIMOP1, i_isIEEEFloat }
1407
1408     /* Double# operations */
1409     , { "primGtDouble",              "DD", "B",  MONAD_Id, i_PRIMOP1, i_gtDouble }
1410     , { "primGeDouble",              "DD", "B",  MONAD_Id, i_PRIMOP1, i_geDouble }
1411     , { "primEqDouble",              "DD", "B",  MONAD_Id, i_PRIMOP1, i_eqDouble }
1412     , { "primNeDouble",              "DD", "B",  MONAD_Id, i_PRIMOP1, i_neDouble }
1413     , { "primLtDouble",              "DD", "B",  MONAD_Id, i_PRIMOP1, i_ltDouble }
1414     , { "primLeDouble",              "DD", "B",  MONAD_Id, i_PRIMOP1, i_leDouble }
1415     , { "primMinDouble",             "",   "D",  MONAD_Id, i_PRIMOP1, i_minDouble }
1416     , { "primMaxDouble",             "",   "D",  MONAD_Id, i_PRIMOP1, i_maxDouble }
1417     , { "primRadixDouble",           "",   "I",  MONAD_Id, i_PRIMOP1, i_radixDouble }
1418     , { "primDigitsDouble",          "",   "I",  MONAD_Id, i_PRIMOP1, i_digitsDouble }
1419     , { "primMinExpDouble",          "",   "I",  MONAD_Id, i_PRIMOP1, i_minExpDouble }
1420     , { "primMaxExpDouble",          "",   "I",  MONAD_Id, i_PRIMOP1, i_maxExpDouble }
1421     , { "primPlusDouble",            "DD", "D",  MONAD_Id, i_PRIMOP1, i_plusDouble }
1422     , { "primMinusDouble",           "DD", "D",  MONAD_Id, i_PRIMOP1, i_minusDouble }
1423     , { "primTimesDouble",           "DD", "D",  MONAD_Id, i_PRIMOP1, i_timesDouble }
1424     , { "primDivideDouble",          "DD", "D",  MONAD_Id, i_PRIMOP1, i_divideDouble }
1425     , { "primNegateDouble",          "D",  "D",  MONAD_Id, i_PRIMOP1, i_negateDouble }
1426     , { "primDoubleToInt",           "D",  "I",  MONAD_Id, i_PRIMOP1, i_doubleToInt }
1427     , { "primIntToDouble",           "I",  "D",  MONAD_Id, i_PRIMOP1, i_intToDouble }
1428     , { "primDoubleToFloat",         "D",  "F",  MONAD_Id, i_PRIMOP1, i_doubleToFloat }
1429     , { "primFloatToDouble",         "F",  "D",  MONAD_Id, i_PRIMOP1, i_floatToDouble }
1430     , { "primExpDouble",             "D",  "D",  MONAD_Id, i_PRIMOP1, i_expDouble }
1431     , { "primLogDouble",             "D",  "D",  MONAD_Id, i_PRIMOP1, i_logDouble }
1432     , { "primSqrtDouble",            "D",  "D",  MONAD_Id, i_PRIMOP1, i_sqrtDouble }
1433     , { "primSinDouble",             "D",  "D",  MONAD_Id, i_PRIMOP1, i_sinDouble }
1434     , { "primCosDouble",             "D",  "D",  MONAD_Id, i_PRIMOP1, i_cosDouble }
1435     , { "primTanDouble",             "D",  "D",  MONAD_Id, i_PRIMOP1, i_tanDouble }
1436     , { "primAsinDouble",            "D",  "D",  MONAD_Id, i_PRIMOP1, i_asinDouble }
1437     , { "primAcosDouble",            "D",  "D",  MONAD_Id, i_PRIMOP1, i_acosDouble }
1438     , { "primAtanDouble",            "D",  "D",  MONAD_Id, i_PRIMOP1, i_atanDouble }
1439     , { "primSinhDouble",            "D",  "D",  MONAD_Id, i_PRIMOP1, i_sinhDouble }
1440     , { "primCoshDouble",            "D",  "D",  MONAD_Id, i_PRIMOP1, i_coshDouble }
1441     , { "primTanhDouble",            "D",  "D",  MONAD_Id, i_PRIMOP1, i_tanhDouble }
1442     , { "primPowerDouble",           "DD", "D",  MONAD_Id, i_PRIMOP1, i_powerDouble }
1443     , { "primDecodeDoubleZ",         "D",  "ZI", MONAD_Id, i_PRIMOP1, i_decodeDoubleZ }
1444     , { "primEncodeDoubleZ",         "ZI",  "D", MONAD_Id, i_PRIMOP1, i_encodeDoubleZ }
1445     , { "primIsNaNDouble",           "D",  "B",  MONAD_Id, i_PRIMOP1, i_isNaNDouble }
1446     , { "primIsInfiniteDouble",      "D",  "B",  MONAD_Id, i_PRIMOP1, i_isInfiniteDouble }
1447     , { "primIsDenormalizedDouble",  "D",  "B",  MONAD_Id, i_PRIMOP1, i_isDenormalizedDouble }
1448     , { "primIsNegativeZeroDouble",  "D",  "B",  MONAD_Id, i_PRIMOP1, i_isNegativeZeroDouble }
1449     , { "primIsIEEEDouble",          "",   "B",  MONAD_Id, i_PRIMOP1, i_isIEEEDouble }
1450
1451 #ifdef XMLAMBDA
1452     /* primitive row operations. */
1453     , { "primRowInsertAt",           "XIa","X",  MONAD_Id, i_PRIMOP2, i_rowInsertAt }
1454     , { "primRowRemoveAt",           "XI", "aX", MONAD_Id, i_PRIMOP2, i_rowRemoveAt }
1455 #endif
1456
1457     /* Ref operations */
1458     , { "primNewRef",                "a",  "R",  MONAD_ST, i_PRIMOP2, i_newRef }
1459     , { "primWriteRef",              "Ra", "",   MONAD_ST, i_PRIMOP2, i_writeRef }
1460     , { "primReadRef",               "R",  "a",  MONAD_ST, i_PRIMOP2, i_readRef }
1461     , { "primSameRef",               "RR", "B",  MONAD_Id, i_PRIMOP2, i_sameRef }
1462
1463     /* PrimArray operations */
1464     , { "primSameMutableArray",      "MM",  "B", MONAD_Id, i_PRIMOP2, i_sameMutableArray }
1465     , { "primUnsafeFreezeArray",     "M",   "X", MONAD_ST, i_PRIMOP2, i_unsafeFreezeArray }
1466     , { "primNewArray",              "Ia",  "M", MONAD_ST, i_PRIMOP2, i_newArray }
1467     , { "primWriteArray",            "MIa", "",  MONAD_ST, i_PRIMOP2, i_writeArray }
1468     , { "primReadArray",             "MI",  "a", MONAD_ST, i_PRIMOP2, i_readArray }
1469     , { "primIndexArray",            "XI",  "a", MONAD_Id, i_PRIMOP2, i_indexArray }
1470     , { "primSizeArray",             "X",   "I", MONAD_Id, i_PRIMOP2, i_sizeArray }
1471     , { "primSizeMutableArray",      "M",   "I", MONAD_Id, i_PRIMOP2, i_sizeMutableArray }
1472
1473     /* Prim[Mutable]ByteArray operations */
1474     , { "primSameMutableByteArray",  "mm", "B", MONAD_Id, i_PRIMOP2, i_sameMutableByteArray }
1475     , { "primUnsafeFreezeByteArray", "m",  "x", MONAD_ST, i_PRIMOP2, i_unsafeFreezeByteArray }
1476     
1477     , { "primNewByteArray",          "I",  "m", MONAD_ST, i_PRIMOP2, i_newByteArray }
1478
1479     , { "primWriteCharArray",        "mIC", "", MONAD_ST, i_PRIMOP2, i_writeCharArray }
1480     , { "primReadCharArray",         "mI", "C", MONAD_ST, i_PRIMOP2, i_readCharArray }
1481     , { "primIndexCharArray",        "xI", "C", MONAD_Id, i_PRIMOP2, i_indexCharArray }
1482     
1483     , { "primWriteIntArray",         "mII", "",  MONAD_ST, i_PRIMOP2, i_writeIntArray }
1484     , { "primReadIntArray",          "mI",  "I", MONAD_ST, i_PRIMOP2, i_readIntArray }
1485     , { "primIndexIntArray",         "xI",  "I", MONAD_Id, i_PRIMOP2, i_indexIntArray }
1486
1487     /* {new,write,read,index}IntegerArray not provided */
1488
1489     , { "primWriteWordArray",        "mIW", "",  MONAD_ST, i_PRIMOP2, i_writeWordArray }
1490     , { "primReadWordArray",         "mI",  "W", MONAD_ST, i_PRIMOP2, i_readWordArray }
1491     , { "primIndexWordArray",        "xI",  "W", MONAD_Id, i_PRIMOP2, i_indexWordArray }
1492     , { "primWriteAddrArray",        "mIA", "",  MONAD_ST, i_PRIMOP2, i_writeAddrArray }
1493     , { "primReadAddrArray",         "mI",  "A", MONAD_ST, i_PRIMOP2, i_readAddrArray }
1494     , { "primIndexAddrArray",        "xI",  "A", MONAD_Id, i_PRIMOP2, i_indexAddrArray }
1495     , { "primWriteFloatArray",       "mIF", "",  MONAD_ST, i_PRIMOP2, i_writeFloatArray }
1496     , { "primReadFloatArray",        "mI",  "F", MONAD_ST, i_PRIMOP2, i_readFloatArray }
1497     , { "primIndexFloatArray",       "xI",  "F", MONAD_Id, i_PRIMOP2, i_indexFloatArray }
1498     , { "primWriteDoubleArray" ,     "mID", "",  MONAD_ST, i_PRIMOP2, i_writeDoubleArray }
1499     , { "primReadDoubleArray",       "mI",  "D", MONAD_ST, i_PRIMOP2, i_readDoubleArray }
1500     , { "primIndexDoubleArray",      "xI",  "D", MONAD_Id, i_PRIMOP2, i_indexDoubleArray }
1501
1502 #if 0
1503 #ifdef PROVIDE_STABLE
1504     , { "primWriteStableArray",      "mIs", "",  MONAD_ST, i_PRIMOP2, i_writeStableArray }
1505     , { "primReadStableArray",       "mI",  "s", MONAD_ST, i_PRIMOP2, i_readStableArray }
1506     , { "primIndexStableArray",      "xI",  "s", MONAD_Id, i_PRIMOP2, i_indexStableArray }
1507 #endif
1508 #endif
1509     /* {new,write,read,index}ForeignObjArray not provided */
1510
1511
1512 #ifdef PROVIDE_FOREIGN
1513     /* ForeignObj# operations */
1514     , { "primMkForeignObj",          "A",  "f",  MONAD_IO, i_PRIMOP2, i_mkForeignObj }
1515 #endif
1516 #ifdef PROVIDE_WEAK
1517     /* WeakPair# operations */
1518     , { "primMakeWeak",              "bac", "w",  MONAD_IO, i_PRIMOP2, i_makeWeak }
1519     , { "primDeRefWeak",             "w",   "Ia", MONAD_IO, i_PRIMOP2, i_deRefWeak }
1520 #endif
1521     /* StablePtr# operations */
1522     , { "primMakeStablePtr",         "a", "s",   MONAD_IO, i_PRIMOP2, i_makeStablePtr }
1523     , { "primDeRefStablePtr",        "s", "a",   MONAD_IO, i_PRIMOP2, i_deRefStablePtr }
1524     , { "primFreeStablePtr",         "s", "",    MONAD_IO, i_PRIMOP2, i_freeStablePtr }
1525
1526     /* foreign export dynamic support */
1527     , { "primCreateAdjThunkARCH",    "sAC","A",  MONAD_IO, i_PRIMOP2, i_createAdjThunkARCH }
1528
1529     /* misc handy hacks */
1530     , { "primGetArgc",               "",   "I",  MONAD_IO, i_PRIMOP2, i_getArgc }
1531     , { "primGetArgv",               "I",  "A",  MONAD_IO, i_PRIMOP2, i_getArgv }
1532
1533 #ifdef PROVIDE_PTREQUALITY
1534     , { "primReallyUnsafePtrEquality", "aa", "B",MONAD_Id, i_PRIMOP2, i_reallyUnsafePtrEquality }
1535 #endif
1536 #ifdef PROVIDE_COERCE
1537     , { "primUnsafeCoerce",          "a", "b",   MONAD_Id, i_PRIMOP2, i_unsafeCoerce }
1538 #endif
1539 #ifdef PROVIDE_CONCURRENT
1540     /* Concurrency operations */
1541     , { "primForkIO",                "a", "T",   MONAD_IO, i_PRIMOP2, i_forkIO }
1542     , { "primKillThread",            "T", "",    MONAD_IO, i_PRIMOP2, i_killThread }
1543     , { "primRaiseInThread",         "TE", "",   MONAD_IO, i_PRIMOP2, i_raiseInThread }
1544
1545     , { "primWaitRead",              "I", "",    MONAD_IO, i_PRIMOP2, i_waitRead }
1546     , { "primWaitWrite",             "I", "",    MONAD_IO, i_PRIMOP2, i_waitWrite }
1547     , { "primYield",                 "", "",     MONAD_IO, i_PRIMOP2, i_yield }    , { "primDelay",                 "I", "",    MONAD_IO, i_PRIMOP2, i_delay }
1548     , { "primGetThreadId",           "",   "T",  MONAD_IO, i_PRIMOP2, i_getThreadId }
1549     , { "primCmpThreadIds",          "TT", "I",  MONAD_Id, i_PRIMOP2, i_cmpThreadIds }
1550 #endif
1551     , { "primNewEmptyMVar",          "",  "r",   MONAD_IO, i_PRIMOP2, i_newMVar }
1552       /* primTakeMVar is handwritten bytecode */
1553     , { "primPutMVar",               "ra", "",   MONAD_IO, i_PRIMOP2, i_putMVar } 
1554     , { "primSameMVar",              "rr", "B",  MONAD_Id, i_PRIMOP2, i_sameMVar }
1555
1556   
1557     /* Ccall is polyadic - so it's excluded from this table */
1558
1559     , { 0,0,0,0,0,0 }
1560 };
1561
1562 AsmPrim ccall_ccall_Id
1563    = { "ccall", 0, 0, MONAD_IO, i_PRIMOP2, i_ccall_ccall_Id };
1564 AsmPrim ccall_ccall_IO
1565    = { "ccall", 0, 0, MONAD_IO, i_PRIMOP2, i_ccall_ccall_IO };
1566 AsmPrim ccall_stdcall_Id 
1567    = { "ccall", 0, 0, MONAD_IO, i_PRIMOP2, i_ccall_stdcall_Id };
1568 AsmPrim ccall_stdcall_IO 
1569    = { "ccall", 0, 0, MONAD_IO, i_PRIMOP2, i_ccall_stdcall_IO };
1570
1571 #ifdef DEBUG
1572 void checkBytecodeCount( void );
1573 void checkBytecodeCount( void ) 
1574 {
1575   if (MAX_Primop1 >= 255) {
1576     printf("Too many Primop1 bytecodes (%d)\n",MAX_Primop1);
1577   }
1578   if (MAX_Primop2 >= 255) {
1579     printf("Too many Primop2 bytecodes (%d)\n",MAX_Primop2);
1580   }
1581 }
1582 #endif
1583
1584 AsmPrim* asmFindPrim( char* s )
1585 {
1586     int i;
1587     for (i=0; asmPrimOps[i].name; ++i) {
1588         if (strcmp(s,asmPrimOps[i].name)==0) {
1589             return &asmPrimOps[i];
1590         }
1591     }
1592     return 0;
1593 }
1594
1595 AsmPrim* asmFindPrimop( AsmInstr prefix, AsmInstr op )
1596 {
1597     nat i;
1598     for (i=0; asmPrimOps[i].name; ++i) {
1599         if (asmPrimOps[i].prefix == prefix && asmPrimOps[i].opcode == op) {
1600             return &asmPrimOps[i];
1601         }
1602     }
1603     return 0;
1604 }
1605
1606 /* --------------------------------------------------------------------------
1607  * Handwritten primops
1608  * ------------------------------------------------------------------------*/
1609
1610 void* /* StgBCO* */ asm_BCO_catch ( void )
1611 {
1612    AsmBCO  bco;
1613    StgBCO* closure;
1614    asmInitialise();
1615
1616    bco = asmBeginBCO(0 /*NIL*/);
1617    emiti_8(bco,i_ARG_CHECK,2);
1618    emiti_8(bco,i_PRIMOP1,i_pushcatchframe);
1619    incSp(bco, (1-2)*sizeofW(StgPtr) + sizeofW(StgCatchFrame));
1620    emiti_(bco,i_ENTER);
1621    decSp(bco, sizeofW(StgPtr));
1622    asmEndBCO(bco);
1623
1624    asmAllocateHeapSpace();
1625    asmCopyAndLink();
1626    closure = (StgBCO*)(bco->closure);
1627    asmShutdown();
1628    return closure;
1629 }
1630
1631 void* /* StgBCO* */ asm_BCO_raise ( void )
1632 {
1633    AsmBCO bco;
1634    StgBCO* closure;
1635    asmInitialise();
1636
1637    bco = asmBeginBCO(0 /*NIL*/);
1638    emiti_8(bco,i_ARG_CHECK,1);
1639    emiti_8(bco,i_PRIMOP2,i_raise);
1640    decSp(bco,sizeofW(StgPtr));
1641    asmEndBCO(bco);
1642
1643    asmAllocateHeapSpace();
1644    asmCopyAndLink();
1645    closure = (StgBCO*)(bco->closure);
1646    asmShutdown();
1647    return closure;
1648 }
1649
1650 void* /* StgBCO* */ asm_BCO_seq ( void )
1651 {
1652    AsmBCO eval, cont;
1653    StgBCO* closure;
1654    asmInitialise();
1655
1656    cont = asmBeginBCO(0 /*NIL*/);
1657    emiti_8(cont,i_ARG_CHECK,2);   /* should never fail */
1658    emit_i_VAR(cont,1);
1659    emit_i_SLIDE(cont,1,2);
1660    emiti_(cont,i_ENTER);
1661    incSp(cont, 3*sizeofW(StgPtr));
1662    asmEndBCO(cont);
1663
1664    eval = asmBeginBCO(0 /*NIL*/);
1665    emiti_8(eval,i_ARG_CHECK,2);
1666    emit_i_RETADDR(eval,eval->n_refs);
1667    asmAddRefObject(eval,cont);
1668    emit_i_VAR(eval,2);
1669    emit_i_SLIDE(eval,3,1);
1670    emiti_8(eval,i_PRIMOP1,i_pushseqframe);
1671    emiti_(eval,i_ENTER);
1672    incSp(eval, sizeofW(StgSeqFrame) + 4*sizeofW(StgPtr));
1673    asmEndBCO(eval);
1674
1675    asmAllocateHeapSpace();
1676    asmCopyAndLink();
1677    closure = (StgBCO*)(eval->closure);
1678    asmShutdown();
1679    return closure;
1680 }
1681
1682 void* /* StgBCO* */ asm_BCO_takeMVar ( void )
1683 {
1684    AsmBCO kase, casecont, take;
1685    StgBCO* closure;
1686    asmInitialise();
1687
1688    take = asmBeginBCO(0 /*NIL*/);
1689    emit_i_VAR(take,0);
1690    emiti_8(take,i_PRIMOP2,i_takeMVar);
1691    emit_i_VAR(take,3);
1692    emit_i_VAR(take,1);
1693    emit_i_VAR(take,4);
1694    emit_i_SLIDE(take,3,4);
1695    emiti_(take,i_ENTER);
1696    incSp(take,20);
1697    asmEndBCO(take);
1698
1699    casecont = asmBeginBCO(0 /*NIL*/);
1700    emiti_(casecont,i_UNPACK);
1701    emit_i_VAR(casecont,4);
1702    emit_i_VAR(casecont,4);
1703    emit_i_VAR(casecont,2);
1704    emit_i_CONST(casecont,casecont->n_refs);
1705    asmAddRefObject(casecont,take);
1706    emit_i_SLIDE(casecont,4,5);
1707    emiti_(casecont,i_ENTER);
1708    incSp(casecont,20);
1709    asmEndBCO(casecont);
1710
1711    kase = asmBeginBCO(0 /*NIL*/);
1712    emiti_8(kase,i_ARG_CHECK,3);
1713    emit_i_RETADDR(kase,kase->n_refs);
1714    asmAddRefObject(kase,casecont);
1715    emit_i_VAR(kase,2);
1716    emiti_(kase,i_ENTER);
1717    incSp(kase,20);
1718    asmEndBCO(kase);
1719
1720    asmAllocateHeapSpace();
1721    asmCopyAndLink();
1722    closure = (StgBCO*)(kase->closure);
1723    asmShutdown();
1724    return closure;
1725 }
1726
1727
1728 /* --------------------------------------------------------------------------
1729  * Heap manipulation
1730  * ------------------------------------------------------------------------*/
1731
1732 AsmVar asmAllocCONSTR   ( AsmBCO bco, AsmInfo info )
1733 {
1734     int i;
1735     ASSERT( sizeW_fromITBL(info) >= MIN_NONUPD_SIZE + sizeofW(StgHeader) );
1736
1737     /* Look in this bco's collection of nonpointers (literals)
1738        to see if the itbl pointer is already there.  If so, re-use it. */
1739     i = asmFindInNonPtrs ( bco, (StgWord)info );
1740
1741     if (i == -1) {
1742        emit_i_ALLOC_CONSTR(bco,bco->n_words);
1743        asmAddNonPtrWords(bco,AsmInfo,info);
1744     } else {
1745        emit_i_ALLOC_CONSTR(bco,i);
1746     }
1747
1748     incSp(bco, sizeofW(StgClosurePtr));
1749     return bco->sp;
1750 }
1751
1752 AsmSp asmBeginPack( AsmBCO bco )
1753 {
1754     return bco->sp;
1755 }
1756
1757 void asmEndPack( AsmBCO bco, AsmVar v, AsmSp start, AsmInfo info )
1758 {
1759     nat size = bco->sp - start;
1760     ASSERT(bco->sp >= start);
1761     ASSERT(start >= v);
1762     /* only reason to include info is for this assertion */
1763     ASSERT(info->layout.payload.ptrs == size);
1764     emit_i_PACK(bco, bco->sp - v);
1765     setSp(bco, start);
1766 }
1767
1768 void asmBeginUnpack( AsmBCO bco __attribute__ ((unused)) )
1769 {
1770     /* dummy to make it look prettier */
1771 }
1772
1773 void asmEndUnpack( AsmBCO bco )
1774 {
1775     emiti_(bco,i_UNPACK);
1776 }
1777
1778 AsmVar asmAllocAP( AsmBCO bco, AsmNat words )
1779 {
1780     emiti_8(bco,i_ALLOC_AP,words);
1781     incSp(bco, sizeofW(StgPtr));
1782     return bco->sp;
1783 }
1784
1785 AsmSp asmBeginMkAP( AsmBCO bco )
1786 {
1787     return bco->sp;
1788 }
1789
1790 void asmEndMkAP( AsmBCO bco, AsmVar v, AsmSp start )
1791 {
1792     emit_i_MKAP(bco,bco->sp-v,bco->sp-start-1);
1793             /* -1 because fun isn't counted */
1794     setSp(bco, start);
1795 }
1796
1797 AsmVar asmAllocPAP( AsmBCO bco, AsmNat size )
1798 {
1799     emiti_8(bco,i_ALLOC_PAP,size);
1800     incSp(bco, sizeofW(StgPtr));
1801     return bco->sp;
1802 }
1803
1804 AsmSp asmBeginMkPAP( AsmBCO bco )
1805 {
1806     return bco->sp;
1807 }
1808
1809 void asmEndMkPAP( AsmBCO bco, AsmVar v, AsmSp start )
1810 {
1811     emiti_8_8(bco,i_MKPAP,bco->sp-v,bco->sp-start-1);
1812             /* -1 because fun isn't counted */
1813     setSp(bco, start);
1814 }
1815
1816 AsmVar asmPushRefHugs ( AsmBCO bco, int /*Name*/ n )
1817 {
1818     emit_i_CONST(bco,bco->n_refs);
1819     asmAddRefHugs(bco,n);
1820     incSp(bco, sizeofW(StgPtr));
1821     return bco->sp;
1822 }
1823
1824 AsmVar asmPushRefObject ( AsmBCO bco, AsmObject p )
1825 {
1826     emit_i_CONST(bco,bco->n_refs);
1827     asmAddRefObject(bco,p);
1828     incSp(bco, sizeofW(StgPtr));
1829     return bco->sp;
1830 }
1831
1832 AsmVar asmPushRefNoOp ( AsmBCO bco, StgPtr p )
1833 {
1834     emit_i_CONST(bco,bco->n_refs);
1835     asmAddRefNoOp(bco,p);
1836     incSp(bco, sizeofW(StgPtr));
1837     return bco->sp;
1838 }
1839
1840
1841 /* --------------------------------------------------------------------------
1842  * Building InfoTables
1843  * ------------------------------------------------------------------------*/
1844
1845 AsmInfo asmMkInfo( AsmNat tag, AsmNat ptrs )
1846 {
1847     StgInfoTable* info = stgMallocBytes( sizeof(StgInfoTable),"asmMkInfo");
1848     /* Note: the evaluator automatically pads objects with the right number
1849      * of non-ptrs to satisfy MIN_NONUPD_SIZE restrictions.
1850      */
1851     AsmNat nptrs = stg_max(0,MIN_NONUPD_SIZE-ptrs);
1852
1853     /* initialisation code based on INFO_TABLE_CONSTR */
1854     info->layout.payload.ptrs  = ptrs;
1855     info->layout.payload.nptrs = nptrs;
1856     info->srt_len = tag;
1857     info->type    = CONSTR;
1858 #ifdef USE_MINIINTERPRETER
1859     info->entry   = stgCast(StgFunPtr,&Hugs_CONSTR_entry);
1860 #else
1861 #warning asmMkInfo: Need to insert entry code in some cunning way
1862 #endif
1863     ASSERT( sizeW_fromITBL(info) >= MIN_NONUPD_SIZE + sizeofW(StgHeader) );
1864     return info;
1865 }
1866
1867 #ifdef XMLAMBDA
1868 /* -----------------------------------------------------------------------
1869  All the XMLambda primitives.
1870 ------------------------------------------------------------------------*/
1871
1872 /* -----------------------------------------------------------------------
1873  allocation & unpacking of rows  
1874 ------------------------------------------------------------------------*/
1875 AsmVar asmAllocRow   ( AsmBCO bco, AsmNat n /*number of fields*/ )
1876 {
1877     emit_i_ALLOC_ROW(bco,n);             
1878
1879     incSp(bco, sizeofW(StgClosurePtr));
1880     return bco->sp;
1881 }
1882
1883 AsmSp asmBeginPackRow( AsmBCO bco )
1884 {
1885     return bco->sp;
1886 }
1887
1888 void asmEndPackRow( AsmBCO bco, AsmVar v, AsmSp start, AsmNat n /*#fields*/ )
1889 {
1890     nat size = bco->sp - start;
1891     ASSERT(bco->sp >= start);
1892     ASSERT(start >= v);
1893     /* only reason to include n is for this assertion */
1894     ASSERT(n == size);
1895     emit_i_PACK_ROW(bco,bco->sp - v);  
1896     setSp(bco, start);
1897 }
1898
1899 void asmBeginUnpackRow( AsmBCO bco )
1900 {
1901     /* dummy to make it look prettier */
1902 }
1903
1904 void asmEndUnpackRow( AsmBCO bco )
1905 {
1906     emiti_(bco,i_UNPACK_ROW);
1907 }
1908
1909 /*------------------------------------------------------------------------
1910  Inj primitives.
1911  The Inj constructor contains the value and its index: an unboxed int 
1912  data Inj = forall a. Inj a Int# 
1913  There is no "big" form for the INJ_CONST instructions. The index
1914  is therefore still limited to 256 values.
1915 ------------------------------------------------------------------------*/
1916 AsmVar asmInj( AsmBCO bco, AsmVar index )
1917 {    
1918     emit_i_PACK_INJ( bco, bco->sp - index );
1919
1920     decSp(bco, sizeofW(StgPtr));    /* pop argument value */
1921     incSp(bco, sizeofW(StgPtr));    /* push Inj result    */
1922     return bco->sp;
1923 }
1924
1925 AsmVar asmInjConst( AsmBCO bco, AsmIndex x )
1926 {
1927     ASSERT( x >= 0 && x <= 255 );
1928     emiti_8 (bco, i_PACK_INJ_CONST, x );
1929
1930     decSp(bco, sizeofW(StgPtr));   /* pop argument value */
1931     incSp(bco, sizeofW(StgPtr));   /* push Inj result */
1932     return bco->sp;
1933 }
1934
1935 /* UNPACK_INJ only returns the value; the index should be
1936    tested using the TEST_INJ instructions. */
1937 AsmVar asmUnInj( AsmBCO bco )
1938 {
1939     emiti_(bco,i_UNPACK_INJ);
1940     incSp(bco, sizeofW(StgPtr));  /* push the value */
1941     return bco->sp;
1942 }
1943
1944 AsmPc asmTestInj( AsmBCO bco, AsmVar index )
1945 {
1946     emit_i_TEST_INJ(bco,bco->sp - index);
1947     return bco->n_insns;
1948 }
1949
1950 AsmPc asmTestInjConst( AsmBCO bco, AsmIndex x )
1951 {
1952     ASSERT( x >= 0 && x <= 255 );
1953     emiti_8_16 (bco, i_TEST_INJ_CONST, x, 0 );
1954     return bco->n_insns;
1955 }
1956
1957 AsmVar asmConstIndex( AsmBCO bco, AsmIndex x )
1958 {
1959     ASSERT( x >= 0 && x <= 65535 );
1960     asmConstInt(bco,x);
1961     return bco->sp;
1962 }
1963 #endif
1964
1965 /*-------------------------------------------------------------------------*/
1966
1967 #endif /* INTERPRETER */