[project @ 1999-11-22 17:18:02 by sewardj]
[ghc-hetmet.git] / ghc / interpreter / translate.c
1
2 /* --------------------------------------------------------------------------
3  * Translator: generates stg code from output of pattern matching
4  * compiler.
5  *
6  * The Hugs 98 system is Copyright (c) Mark P Jones, Alastair Reid, the
7  * Yale Haskell Group, and the Oregon Graduate Institute of Science and
8  * Technology, 1994-1999, All rights reserved.  It is distributed as
9  * free software under the license in the file "License", which is
10  * included in the distribution.
11  *
12  * $RCSfile: translate.c,v $
13  * $Revision: 1.17 $
14  * $Date: 1999/11/22 17:18:02 $
15  * ------------------------------------------------------------------------*/
16
17 #include "prelude.h"
18 #include "storage.h"
19 #include "backend.h"
20 #include "connect.h"
21 #include "errors.h"
22 #include "link.h"
23 #include "dynamic.h"
24 #include "Assembler.h"
25
26
27 /* ---------------------------------------------------------------- */
28
29 static StgVar  local stgOffset       Args((Offset,List));
30 static StgVar  local stgText         Args((Text,List));
31 static StgRhs  local stgRhs          Args((Cell,Int,List,StgExpr));
32 static StgCaseAlt local stgCaseAlt   Args((Cell,Int,List,StgExpr));
33 static StgExpr local stgExpr         Args((Cell,Int,List,StgExpr));
34
35 /* ---------------------------------------------------------------- */
36
37 /* Association list storing globals assigned to                     */
38 /* dictionaries, tuples, etc                                        */
39 List stgGlobals = NIL;
40
41 static StgVar local getSTGTupleVar  Args((Cell));
42
43 static StgVar local getSTGTupleVar( Cell d )
44 {
45     Pair p = cellAssoc(d,stgGlobals);
46     /* Yoiks - only the Prelude sees Tuple decls! */
47     if (isNull(p)) {
48         implementTuple(tupleOf(d));
49         p = cellAssoc(d,stgGlobals);
50     }
51     assert(nonNull(p));
52     return snd(p);
53 }
54
55 /* ---------------------------------------------------------------- */
56
57 static Cell local stgOffset(Offset o, List sc)
58 {
59     Cell r = cellAssoc(o,sc);
60     assert(nonNull(r));
61     return snd(r);
62 }
63
64 static Cell local stgText(Text t,List sc)
65 {
66     List xs = sc;
67     for (; nonNull(xs); xs=tl(xs)) {
68         Cell x = hd(xs);
69         Cell v = fst(x);
70         if (!isOffset(v) && t == textOf(v)) {
71             return snd(x);
72         }
73     }
74     internal("stgText");
75 }
76
77 /* ---------------------------------------------------------------- */
78
79 static StgRhs local stgRhs(e,co,sc,failExpr)
80 Cell e; 
81 Int  co; 
82 List sc;
83 StgExpr failExpr; {
84     switch (whatIs(e)) {
85
86     /* Identifiers */
87     case OFFSET:
88             return stgOffset(e,sc);
89     case VARIDCELL:
90     case VAROPCELL:
91             return stgText(textOf(e),sc);
92     case TUPLE: 
93             return getSTGTupleVar(e);
94     case NAME:
95             return e;
96     /* Literals */
97     case CHARCELL:
98             return mkStgCon(nameMkC,singleton(e));
99     case INTCELL:
100             return mkStgCon(nameMkI,singleton(e));
101     case BIGCELL:
102             return mkStgCon(nameMkInteger,singleton(e));
103     case FLOATCELL:
104             return mkStgCon(nameMkD,singleton(e));
105     case STRCELL:
106 #if USE_ADDR_FOR_STRINGS
107         {
108             StgVar v = mkStgVar(mkStgCon(nameMkA,singleton(e)),NIL);
109             return mkStgLet(singleton(v),
110                             makeStgApp(nameUnpackString,singleton(v)));
111         }                            
112 #else
113             return mkStgApp(nameUnpackString,singleton(e));
114 #endif
115     case AP:
116             return stgExpr(e,co,sc,namePMFail);
117     case NIL:
118             internal("stgRhs2");
119     default:
120             return stgExpr(e,co,sc,failExpr/*namePMFail*/);
121     }
122 }
123
124 static StgCaseAlt local stgCaseAlt(alt,co,sc,failExpr)
125 Cell alt;
126 Int co;
127 List sc;
128 StgExpr failExpr;
129 {
130     StgDiscr d     = fst(alt);
131     Int      da    = discrArity(d);
132     Cell     vs    = NIL;
133     Int  i;
134     for(i=1; i<=da; ++i) {
135         StgVar nv = mkStgVar(NIL,NIL);
136         vs    = cons(nv,vs);
137         sc    = cons(pair(mkOffset(co+i),nv),sc);
138     }
139     return mkStgCaseAlt(d,vs,stgExpr(snd(alt),co+da,sc,failExpr));
140 }
141
142 static StgExpr local stgExpr(e,co,sc,failExpr)
143 Cell e; 
144 Int  co; 
145 List sc; 
146 StgExpr failExpr; 
147 {
148     switch (whatIs(e)) {
149     case COND:
150         {
151             return makeStgIf(stgExpr(fst3(snd(e)),co,sc,namePMFail),
152                              stgExpr(snd3(snd(e)),co,sc,failExpr),
153                              stgExpr(thd3(snd(e)),co,sc,failExpr));
154         }
155     case GUARDED:
156         {   
157             List guards = reverse(snd(e));
158             e = failExpr;
159             for(; nonNull(guards); guards=tl(guards)) {
160                 Cell g   = hd(guards);
161                 Cell c   = stgExpr(fst(g),co,sc,namePMFail);
162                 Cell rhs = stgExpr(snd(g),co,sc,failExpr);
163                 e = makeStgIf(c,rhs,e);
164             }
165             return e;
166         }
167     case FATBAR:
168         {
169             StgExpr e2 = stgExpr(snd(snd(e)),co,sc,failExpr);
170             StgVar alt = mkStgVar(e2,NIL);
171             return mkStgLet(singleton(alt),stgExpr(fst(snd(e)),co,sc,alt));
172         }
173     case CASE:
174         {   
175             List alts  = snd(snd(e));
176             Cell scrut = stgExpr(fst(snd(e)),co,sc,namePMFail);
177             if (isNull(alts)) {
178                 return failExpr;
179             } else if (isChar(fst(hd(alts)))) {
180                 Cell     alt  = hd(alts);
181                 StgDiscr d    = fst(alt);
182                 StgVar   c    = mkStgVar(
183                                    mkStgCon(nameMkC,singleton(d)),NIL);
184                 StgExpr  test = nameEqChar;
185                 /* duplicates scrut but it should be atomic */
186                 return makeStgIf(
187                           makeStgLet(singleton(c),
188                              makeStgApp(test,doubleton(scrut,c))),
189                           stgExpr(snd(alt),co,sc,failExpr),
190                           stgExpr(ap(CASE,pair(fst(snd(e)),
191                              tl(alts))),co,sc,failExpr));
192             } else {
193                 List as    = NIL;
194                 for(; nonNull(alts); alts=tl(alts)) {
195                     as = cons(stgCaseAlt(hd(alts),co,sc,failExpr),as);
196                 }
197                 return mkStgCase(
198                           scrut,
199                           revOnto(
200                              as, 
201                              singleton(mkStgDefault(mkStgVar(NIL,NIL),
202                                        failExpr))));
203             }
204         }
205     case NUMCASE:
206         {
207             Triple nc    = snd(e);
208             Offset o     = fst3(nc);
209             Cell   discr = snd3(nc);
210             Cell   r     = thd3(nc);
211             Cell   scrut = stgOffset(o,sc);
212             Cell   h     = getHead(discr);
213             Int    da    = discrArity(discr);
214
215 #if NPLUSK
216             if (whatIs(h) == ADDPAT && argCount == 1) {
217                 /*   ADDPAT num dictIntegral
218                  * ==>
219                  *   let n = fromInteger num in 
220                  *   if pmLe dictIntegral n scrut
221                  *   then let v = pmSubtract dictIntegral scrut v
222                  *   else fail
223                  */
224                 Cell   n            = snd(h);
225                 Cell   dictIntegral = arg(discr);  /* Integral dictionary */
226                 StgVar v            = NIL;
227                 List   binds        = NIL;
228                 StgVar dIntegral    = NIL;
229
230                 /* bind dictionary */
231                 dIntegral = stgRhs(dictIntegral,co,sc,namePMFail);
232                 if (!isAtomic(dIntegral)) { /* wasn't atomic */
233                     dIntegral = mkStgVar(dIntegral,NIL);
234                     binds = cons(dIntegral,binds);
235                 }
236                 /* box number */
237                 n = mkStgVar(mkStgCon(nameMkInteger,singleton(n)),NIL);
238                 binds = cons(n,binds);
239
240                 /* coerce number to right type (using Integral dict) */
241                 n = mkStgVar(mkStgApp(
242                        namePmFromInteger,doubleton(dIntegral,n)),NIL);
243                 binds = cons(n,binds);
244
245                 ++co;
246                 v = mkStgVar(mkStgApp(
247                        namePmSubtract,tripleton(dIntegral,scrut,n)),NIL);
248                 return 
249                    mkStgLet(
250                       binds,
251                       makeStgIf(
252                          mkStgApp(namePmLe,tripleton(dIntegral,n,scrut)),
253                          mkStgLet(singleton(v),
254                                   stgExpr(r,
255                                           co,
256                                           cons(pair(mkOffset(co),v),sc),
257                                           failExpr)),
258                          failExpr));
259             }
260 #endif /* NPLUSK */
261
262             assert(isName(h) && argCount == 2);
263             {
264                 /* This code is rather ugly.
265                  * We ought to desugar it using one of the following:
266                  *   if (==) dEq (fromInt     dNum        pat) scrut
267                  *   if (==) dEq (fromInteger dNum        pat) scrut
268                  *   if (==) dEq (fromFloat   dFractional pat) scrut
269                  * But it would be very hard to obtain the Eq dictionary
270                  * from the Num or Fractional dictionary we have.
271                  * Instead, we rely on the Prelude to supply 3 helper
272                  * functions which do the test for us.
273                  *   primPmInt     :: Num a => Int -> a -> Bool
274                  *   primPmInteger :: Num a => Integer -> a -> Bool
275                  *   primPmDouble  :: Fractional a => Double -> a -> Bool
276                  */
277                 Cell   n      = arg(discr);
278                 Cell   dict   = arg(fun(discr));
279                 StgExpr d     = NIL;
280                 List    binds = NIL;
281                 //StgExpr m     = NIL;
282                 Name   box
283                     = h == nameFromInt     ? nameMkI
284                     : h == nameFromInteger ? nameMkInteger
285                     :                        nameMkD;
286                 Name   testFun
287                     = h == nameFromInt     ? namePmInt
288                     : h == nameFromInteger ? namePmInteger 
289                     :                        namePmDouble;
290                 Cell   altsc  = sc;
291                 Cell   vs     = NIL;
292                 Int    i;
293
294                 for(i=1; i<=da; ++i) {
295                     Cell nv = mkStgVar(NIL,NIL);
296                     vs    = cons(nv,vs);
297                     altsc = cons(pair(mkOffset(co+i),nv),altsc);
298                 }
299                 /* bind dictionary */
300                 d = stgRhs(dict,co,sc,namePMFail);
301                 if (!isAtomic(d)) { /* wasn't atomic */
302                     d = mkStgVar(d,NIL);
303                     binds = cons(d,binds);
304                 }
305                 /* bind number */
306                 n = mkStgVar(mkStgCon(box,singleton(n)),NIL);
307                 binds = cons(n,binds);
308
309                 return 
310                    makeStgIf(
311                       mkStgLet(binds,
312                                mkStgApp(testFun,tripleton(d,n,scrut))),
313                       stgExpr(r,co+da,altsc,failExpr),
314                       failExpr
315                    );
316             }
317         }
318
319     case LETREC:
320         {
321             List binds = NIL;
322             List vs = NIL;
323             List bs;
324             /* allocate variables, extend scope */
325             for(bs = snd(fst(snd(e))); nonNull(bs); bs=tl(bs)) {
326                 Cell nv  = mkStgVar(NIL,NIL);
327                 sc = cons(pair(fst3(hd(bs)),nv),sc);
328                 binds = cons(nv,binds);
329                 vs = cons(nv,vs);
330             }
331             for(bs = fst(fst(snd(e))); nonNull(bs); bs=tl(bs)) {
332                 Cell nv  = mkStgVar(NIL,NIL);
333                 sc = cons(pair(mkOffset(++co),nv),sc);
334                 binds = cons(nv,binds);
335                 vs = cons(nv,vs);
336             }
337             vs = rev(vs);
338             /* transform functions */
339             for(bs = snd(fst(snd(e))); nonNull(bs); bs=tl(bs), vs=tl(vs)) {
340                 Cell fun = hd(bs);
341                 Cell nv  = hd(vs);
342                 List as = NIL;
343                 List funsc = sc;
344                 Int  arity = intOf(snd3(fun));
345                 Int  i;
346                 for(i=1; i<=arity; ++i) {
347                     Cell v = mkStgVar(NIL,NIL);
348                     as = cons(v,as);
349                     funsc = cons(pair(mkOffset(co+i),v),funsc);
350                 }
351                 stgVarBody(nv) 
352                    = mkStgLambda(
353                         as,
354                         stgExpr(thd3(thd3(fun)),co+arity,funsc,namePMFail));
355             }
356             /* transform expressions */
357             for(bs = fst(fst(snd(e))); nonNull(bs); bs=tl(bs), vs=tl(vs)) {
358                 Cell rhs = hd(bs);
359                 Cell nv  = hd(vs);
360                 stgVarBody(nv) = stgRhs(rhs,co,sc,namePMFail);
361             }
362             return mkStgLet(binds,stgRhs(snd(snd(e)),co,sc,failExpr/*namePMFail*/));
363         }
364
365     default: /* convert to an StgApp or StgVar plus some bindings */
366         {   
367             List args  = NIL;
368             List binds = NIL;
369             List as    = NIL;
370
371             /* Unwind args */
372             while (isAp(e)) {
373                 Cell arg = arg(e);
374                 e        = fun(e);
375                 args = cons(arg,args);
376             }
377
378             /* Special cases */
379             if (e == nameSel && length(args) == 3) {
380                 Cell   con   = hd(args);
381 #if 0
382                 StgVar v     = stgOffset(hd(tl(args)),sc);
383 #else
384                 StgExpr v    = stgExpr(hd(tl(args)),co,sc,namePMFail);
385 #endif
386                 Int    ix    = intOf(hd(tl(tl(args))));
387                 Int    da    = discrArity(con);
388                 List   vs    = NIL;
389                 Int    i;
390                 for(i=1; i<=da; ++i) {
391                     Cell nv = mkStgVar(NIL,NIL);
392                     vs=cons(nv,vs);
393                 }
394                 return 
395                    mkStgCase(v,
396                              doubleton(mkStgCaseAlt(con,vs,nth(ix-1,vs)),
397                              mkStgDefault(mkStgVar(NIL,NIL),namePMFail)));
398             }
399             
400             /* Arguments must be StgAtoms */
401             for(as=args; nonNull(as); as=tl(as)) {
402                 StgRhs a = stgRhs(hd(as),co,sc,namePMFail);
403 #if 1 /* optional flattening of let bindings */
404                 if (whatIs(a) == LETREC) {
405                     binds = appendOnto(stgLetBinds(a),binds);
406                     a = stgLetBody(a);
407                 }
408 #endif
409                     
410                 if (!isAtomic(a)) {
411                     a     = mkStgVar(a,NIL);
412                     binds = cons(a,binds);
413                 }
414                 hd(as) = a;
415             }
416
417             /* Function must be StgVar or Name */
418             e = stgRhs(e,co,sc,namePMFail);
419             if (!isStgVar(e) && !isName(e)) {
420                 e = mkStgVar(e,NIL);
421                 binds = cons(e,binds);
422             }
423
424             return makeStgLet(binds,makeStgApp(e,args));
425         }
426     }
427 }
428
429 #if 0 /* apparently not used */
430 static Void ppExp( Name n, Int arity, Cell e )
431 {
432     if (1 || debugCode) {
433         Int i;
434         printf("%s", textToStr(name(n).text));
435         for (i = arity; i > 0; i--) {
436             printf(" o%d", i);
437         }
438         printf(" = ");
439         printExp(stdout,e); 
440         printf("\n");
441     }
442 }
443 #endif
444
445
446 Void stgDefn( Name n, Int arity, Cell e )
447 {
448     List vs = NIL;
449     List sc = NIL;
450     Int i, s;
451     for (i = 1; i <= arity; ++i) {
452         Cell nv = mkStgVar(NIL,NIL);
453         vs = cons(nv,vs);
454         sc = cons(pair(mkOffset(i),nv),sc);
455     }
456     stgVarBody(name(n).stgVar) 
457        = makeStgLambda(vs,stgExpr(e,arity,sc,namePMFail));
458 }
459
460 Void implementCfun(c,scs)               /* Build implementation for constr */
461 Name c;                                 /* fun c.  scs lists integers (1..)*/
462 List scs; {                             /* in incr order of strict comps.  */
463     Int a = name(c).arity;
464
465     if (a > 0) {
466         StgVar  vcurr, e1, v, vsi;
467         List    args  = makeArgs(a);
468         StgVar  v0    = mkStgVar(mkStgCon(c,args),NIL);
469         List    binds = singleton(v0);
470
471         vcurr = v0;
472         for (; nonNull(scs); scs=tl(scs)) {
473            vsi   = nth(intOf(hd(scs))-1,args);
474            vcurr = mkStgVar(mkStgApp(namePrimSeq,doubleton(vsi,vcurr)), NIL);
475            binds = cons(vcurr,binds);
476         }
477         binds = rev(binds);
478         e1    = mkStgLet(binds,vcurr);
479         v     = mkStgVar(mkStgLambda(args,e1),NIL);
480         name(c).stgVar = v;
481     } else {
482         StgVar v = mkStgVar(mkStgCon(c,NIL),NIL);
483         name(c).stgVar = v;
484     }
485     stgGlobals = cons(pair(c,name(c).stgVar),stgGlobals); 
486     /* printStg(stderr, name(c).stgVar); fprintf(stderr,"\n\n"); */
487 }
488
489 /* --------------------------------------------------------------------------
490  * Foreign function calls and primops
491  * ------------------------------------------------------------------------*/
492
493 /* Outbound denotes data moving from Haskell world to elsewhere.
494    Inbound denotes data moving from elsewhere to Haskell world.
495 */
496 static String  charListToString   ( List cs );
497 static Cell    foreignTy          ( Bool outBound, Type t );
498 static Cell    foreignOutboundTy  ( Type t );
499 static Cell    foreignInboundTy   ( Type t );
500 static Name    repToBox           ( char c );
501 static StgRhs  makeStgPrim        ( Name,Bool,List,String,String );
502
503 static String charListToString( List cs )
504 {
505     static char s[100];
506
507     Int i = 0;
508     assert( length(cs) < 100 );
509     for(; nonNull(cs); ++i, cs=tl(cs)) {
510         s[i] = charOf(hd(cs));
511     }
512     s[i] = '\0';
513     return textToStr(findText(s));
514 }
515
516 static Cell foreignTy ( Bool outBound, Type t )
517 {
518     if      (t == typeChar)   return mkChar(CHAR_REP);
519     else if (t == typeInt)    return mkChar(INT_REP);
520 #if 0
521     else if (t == typeInteger)return mkChar(INTEGER_REP);
522 #endif
523     else if (t == typeWord)   return mkChar(WORD_REP);
524     else if (t == typeAddr)   return mkChar(ADDR_REP);
525     else if (t == typeFloat)  return mkChar(FLOAT_REP);
526     else if (t == typeDouble) return mkChar(DOUBLE_REP);
527     else if (t == typeStable) return mkChar(STABLE_REP);
528 #ifdef PROVIDE_FOREIGN
529     else if (t == typeForeign)return mkChar(FOREIGN_REP); 
530          /* ToDo: argty only! */
531 #endif
532 #if 0
533     else if (t == typePrimByteArray) return mkChar(BARR_REP); 
534          /* ToDo: argty only! */
535     else if (whatIs(t) == AP) {
536         Type h = getHead(t);
537         if (h == typePrimMutableByteArray) return mkChar(MUTBARR_REP); 
538          /* ToDo: argty only! */
539     }
540 #endif
541    /* ToDo: decent line numbers! */
542    if (outBound) {
543       ERRMSG(0) "Illegal outbound (away from Haskell) type" ETHEN
544       ERRTEXT " \"" ETHEN ERRTYPE(t);
545       ERRTEXT "\""
546       EEND;
547    } else {
548       ERRMSG(0) "Illegal inbound (towards Haskell) type" ETHEN
549       ERRTEXT " \"" ETHEN ERRTYPE(t);
550       ERRTEXT "\""
551       EEND;
552    }
553 }
554
555 static Cell foreignOutboundTy ( Type t )
556 {
557     return foreignTy ( TRUE, t );
558 }
559
560 static Cell foreignInboundTy ( Type t )
561 {
562     return foreignTy ( FALSE, t );
563 }
564
565 static Name repToBox( char c )
566 {
567     switch (c) {
568     case CHAR_REP:     return nameMkC;
569     case INT_REP:      return nameMkI;
570     case INTEGER_REP:  return nameMkInteger;
571     case WORD_REP:     return nameMkW;
572     case ADDR_REP:     return nameMkA;
573     case FLOAT_REP:    return nameMkF;
574     case DOUBLE_REP:   return nameMkD;
575     case ARR_REP:      return nameMkPrimArray;            
576     case BARR_REP:     return nameMkPrimByteArray;
577     case REF_REP:      return nameMkRef;                  
578     case MUTARR_REP:   return nameMkPrimMutableArray;     
579     case MUTBARR_REP:  return nameMkPrimMutableByteArray; 
580     case STABLE_REP:   return nameMkStable;
581     case THREADID_REP: return nameMkThreadId;
582     case MVAR_REP:     return nameMkPrimMVar;
583 #ifdef PROVIDE_WEAK
584     case WEAK_REP:  return nameMkWeak;
585 #endif
586 #ifdef PROVIDE_FOREIGN
587     case FOREIGN_REP: return nameMkForeign;
588 #endif
589     default: return NIL;
590     }
591 }
592
593 static StgPrimAlt boxResults( String reps, StgVar state )
594 {
595     List rs = NIL;     /* possibly unboxed results     */
596     List bs = NIL;     /* boxed results of wrapper     */
597     List rbinds = NIL; /* bindings used to box results */
598     StgExpr e   = NIL;
599     Int i;
600     for(i=0; reps[i] != '\0'; ++i) {
601         StgRep k = mkStgRep(reps[i]);
602         Cell v   = mkStgPrimVar(NIL,k,NIL);
603         Name box = repToBox(reps[i]);
604         if (isNull(box)) {
605             bs = cons(v,bs);
606         } else {
607             StgRhs rhs = mkStgCon(box,singleton(v));
608             StgVar bv = mkStgVar(rhs,NIL); /* boxed */
609             bs     = cons(bv,bs);
610             rbinds = cons(bv,rbinds);
611         }
612         rs = cons(v,rs);
613     }
614
615     /* Construct tuple of results */
616     if (i == 0) {
617         e = nameUnit;
618     } else
619     if (i == 1) {
620         e = hd(bs);
621     } else {
622         StgVar r = mkStgVar(mkStgCon(mkTuple(i),rev(bs)),NIL);
623         rbinds = cons(r,rbinds);
624         e = r;
625     }
626     /* construct result pair if needed */
627     if (nonNull(state)) {
628         /* Note that this builds a tuple directly - we know it's
629          * saturated.
630          */
631         StgVar r = mkStgVar(mkStgCon(mkTuple(2),doubleton(e,state)),NIL);
632         rbinds   = cons(r,rbinds);
633         rs       = cons(state,rs);      /* last result is a state */
634         e = r;
635     }
636     return mkStgPrimAlt(rev(rs),makeStgLet(rbinds,e));
637 }
638
639 static List mkUnboxedVars( String reps )
640 {
641     List as = NIL;
642     Int i;
643     for(i=0; reps[i] != '\0'; ++i) {
644         Cell v = mkStgPrimVar(NIL,mkStgRep(reps[i]),NIL);
645         as = cons(v,as);
646     }
647     return rev(as);
648 }
649
650 static List mkBoxedVars( String reps )
651 {
652     List as = NIL;
653     Int i;
654     for(i=0; reps[i] != '\0'; ++i) {
655         as = cons(mkStgVar(NIL,NIL),as);
656     }
657     return rev(as);
658 }
659
660 static StgRhs unboxVars( String reps, List b_args, List u_args, StgExpr e )
661 {
662     if (nonNull(b_args)) {
663         StgVar b_arg = hd(b_args); /* boxed arg   */
664         StgVar u_arg = hd(u_args); /* unboxed arg */
665         Name   box   = repToBox(*reps);
666         e = unboxVars(reps+1,tl(b_args),tl(u_args),e);
667         if (isNull(box)) {
668             /* Use a trivial let-binding */
669             stgVarBody(u_arg) = b_arg;
670             return mkStgLet(singleton(u_arg),e);
671         } else {
672             StgCaseAlt alt = mkStgCaseAlt(box,singleton(u_arg),e);
673             return mkStgCase(b_arg,singleton(alt));
674         }
675     } else {
676         return e;
677     }
678 }
679
680 /* Generate wrapper for primop based on list of arg types and result types:
681  *
682  * makeStgPrim op# False "II" "II" =
683  *   \ x y -> "case x of { I# x# -> 
684  *             case y of { I# y# -> 
685  *             case op#{x#,y#} of { r1# r2# ->
686  *             let r1 = I# r1#; r2 = I# r2# in
687  *             (r1, r2)
688  *             }}}"
689  */
690 static StgRhs local makeStgPrim(op,addState,extra_args,a_reps,r_reps)
691 Name   op;
692 Bool   addState;
693 List   extra_args;
694 String a_reps;
695 String r_reps; {
696     List b_args = NIL; /* boxed args to primop            */
697     List u_args = NIL; /* possibly unboxed args to primop */
698     List alts   = NIL; 
699     StgVar s0 = addState ? mkStgVar(NIL,NIL) : NIL;
700     StgVar s1 = addState ? mkStgVar(NIL,NIL) : NIL;
701
702     /* box results */
703     if (strcmp(r_reps,"B") == 0) {
704         StgPrimAlt altF 
705            = mkStgPrimAlt(singleton(
706                             mkStgPrimVar(mkInt(0),
707                                          mkStgRep(INT_REP),NIL)
708                           ),
709                           nameFalse);
710         StgPrimAlt altT 
711            = mkStgPrimAlt(
712                 singleton(mkStgPrimVar(NIL,mkStgRep(INT_REP),NIL)),
713                 nameTrue);
714         alts = doubleton(altF,altT); 
715         assert(nonNull(nameTrue));
716         assert(!addState);
717     } else {
718         alts = singleton(boxResults(r_reps,s1));
719     }
720     b_args = mkBoxedVars(a_reps);
721     u_args = mkUnboxedVars(a_reps);
722     if (addState) {
723         List actual_args 
724            = appendOnto(extra_args,dupListOnto(u_args,singleton(s0)));
725         StgRhs rhs 
726            = makeStgLambda(singleton(s0),
727                            unboxVars(a_reps,b_args,u_args,
728                                      mkStgPrimCase(mkStgPrim(op,actual_args),
729                                                    alts)));
730         StgVar m = mkStgVar(rhs,NIL);
731         return makeStgLambda(b_args,
732                              mkStgLet(singleton(m),
733                                       mkStgApp(nameMkIO,singleton(m))));
734     } else {
735         List actual_args = appendOnto(extra_args,u_args);
736         return makeStgLambda(
737                   b_args,
738                   unboxVars(a_reps,b_args,u_args,
739                             mkStgPrimCase(mkStgPrim(op,actual_args),alts))
740                );
741     }
742 }    
743
744 Void implementPrim ( n )
745 Name n; {
746     const AsmPrim* p = name(n).primop;
747     StgRhs   rhs = makeStgPrim(n,p->monad!=MONAD_Id,NIL,p->args,p->results);
748     StgVar   v   = mkStgVar(rhs,NIL);
749     name(n).stgVar   = v;
750     stgGlobals=cons(pair(n,v),stgGlobals);  /* so it will get codegened */
751 }
752
753 /* Generate wrapper code from (in,out) type lists.
754  *
755  * For example:
756  * 
757  *     inTypes  = [Int,Float]
758  *     outTypes = [Char,Addr]
759  * ==>
760  *     \ fun a1 a2 -> 
761  *       let m = (\ s0 ->
762  *           case a1 of { I# a1# ->
763  *           case s2 of { F# a2# ->
764  *           case ccall# "IF" "CA" fun a1# a2# s0 of { r1# r2# s1 ->
765  *           let r1 = C# r1# in
766  *           let r2 = A# r2# in
767  *           let r  = (r1,r2) in
768  *           (r,s1)
769  *           }}})
770  *       in primMkIO m
771  *       ::
772  *       Addr -> (Int -> Float -> IO (Char,Addr))
773  */
774 Void implementForeignImport ( Name n )
775 {
776     Type t         = name(n).type;
777     List argTys    = NIL;
778     List resultTys = NIL;
779     CFunDescriptor* descriptor = 0;
780     Bool addState = TRUE;
781     while (getHead(t)==typeArrow && argCount==2) {
782         Type ta = fullExpand(arg(fun(t)));
783         Type tr = arg(t);
784         argTys = cons(ta,argTys);
785         t = tr;
786     }
787     argTys = rev(argTys);
788     if (getHead(t) == typeIO) {
789         resultTys = getArgs(t);
790         assert(length(resultTys) == 1);
791         resultTys = hd(resultTys);
792         addState = TRUE;
793     } else {
794         resultTys = t;
795         addState = FALSE;
796     }
797     resultTys = fullExpand(resultTys);
798     if (isTuple(getHead(resultTys))) {
799         resultTys = getArgs(resultTys);
800     } else if (getHead(resultTys) == typeUnit) {
801         resultTys = NIL;
802     } else {
803         resultTys = singleton(resultTys);
804     }
805     mapOver(foreignOutboundTy,argTys);  /* allows foreignObj, byteArrays, etc */
806     mapOver(foreignInboundTy,resultTys); /* doesn't */
807     descriptor = mkDescriptor(charListToString(argTys),
808                               charListToString(resultTys));
809     if (!descriptor) {
810        ERRMSG(name(n).line) "Can't allocate memory for call descriptor"
811        EEND;
812     }
813
814     /* ccall is the default convention, if it wasn't specified */
815     if (isNull(name(n).callconv)
816         || name(n).callconv == textCcall) {
817        name(n).primop = addState ? &ccall_ccall_IO : &ccall_ccall_Id;
818     } 
819     else if (name(n).callconv == textStdcall) {
820        if (!stdcallAllowed()) {
821           ERRMSG(name(n).line) "stdcall is not supported on this platform"
822           EEND;
823        }
824        name(n).primop = addState ? &ccall_stdcall_IO : &ccall_stdcall_Id;
825     }
826     else
827        internal ( "implementForeignImport: unknown calling convention");
828
829     {
830         Pair    extName = name(n).defn;
831         void*   funPtr  = getDLLSymbol(name(n).line,
832                                        textToStr(textOf(fst(extName))),
833                                        textToStr(textOf(snd(extName))));
834         List extra_args = doubleton(mkPtr(descriptor),mkPtr(funPtr));
835         StgRhs rhs = makeStgPrim(n,addState,extra_args,descriptor->arg_tys,
836                                  descriptor->result_tys);
837         StgVar v   = mkStgVar(rhs,NIL);
838         if (funPtr == 0) {
839             ERRMSG(name(n).line) "Could not find foreign function \"%s\" in \"%s\"", 
840                 textToStr(textOf(snd(extName))),
841                 textToStr(textOf(fst(extName)))
842             EEND;
843         }
844         name(n).defn     = NIL;
845         name(n).stgVar   = v;
846         stgGlobals=cons(pair(n,v),stgGlobals);/*so it will get codegen'd */
847     }
848 }
849
850
851 /* Generate code:
852  *
853  * \ fun s0 ->
854      let e1 = A# "...."
855          e3 = C# 'c' -- (ccall), or 's' (stdcall)
856      in  primMkAdjThunk fun e1 e3 s0
857
858    we require, and check that,
859      fun :: prim_arg* -> IO prim_result
860  */
861 Void implementForeignExport ( Name n )
862 {
863     Type t         = name(n).type;
864     List argTys    = NIL;
865     List resultTys = NIL;
866     Char cc_char;
867
868     if (getHead(t)==typeArrow && argCount==2) {
869        t = arg(fun(t));
870     } else {
871         ERRMSG(name(n).line) "foreign export has illegal type" ETHEN
872         ERRTEXT " \"" ETHEN ERRTYPE(t);
873         ERRTEXT "\""
874         EEND;        
875     }
876
877     while (getHead(t)==typeArrow && argCount==2) {
878         Type ta = fullExpand(arg(fun(t)));
879         Type tr = arg(t);
880         argTys = cons(ta,argTys);
881         t = tr;
882     }
883     argTys = rev(argTys);
884     if (getHead(t) == typeIO) {
885         resultTys = getArgs(t);
886         assert(length(resultTys) == 1);
887         resultTys = hd(resultTys);
888     } else {
889         ERRMSG(name(n).line) "foreign export doesn't return an IO type" ETHEN
890         ERRTEXT " \"" ETHEN ERRTYPE(t);
891         ERRTEXT "\""
892         EEND;        
893     }
894     resultTys = fullExpand(resultTys);
895
896     mapOver(foreignInboundTy,argTys);
897
898     /* ccall is the default convention, if it wasn't specified */
899     if (isNull(name(n).callconv)
900         || name(n).callconv == textCcall) {
901         cc_char = 'c';
902     } 
903     else if (name(n).callconv == textStdcall) {
904        if (!stdcallAllowed()) {
905           ERRMSG(name(n).line) "stdcall is not supported on this platform"
906           EEND;
907        }
908        cc_char = 's';
909     }
910     else
911        internal ( "implementForeignExport: unknown calling convention");
912
913
914     {
915     List     tdList;
916     Text     tdText;
917     List     args;
918     StgVar   e1, e2, e3, v;
919     StgExpr  fun;
920
921     tdList = cons(mkChar(':'),argTys);
922     if (resultTys != typeUnit)
923        tdList = cons(foreignOutboundTy(resultTys),tdList);
924
925     tdText = findText(charListToString ( tdList ));
926     args   = makeArgs(2);
927     e1     = mkStgVar(
928                 mkStgCon(nameMkA,singleton(ap(STRCELL,tdText))),
929                 NIL
930              );
931     e2     = mkStgVar(
932                 mkStgApp(nameUnpackString,singleton(e1)),
933                 NIL
934              );
935     e3     = mkStgVar(
936                 mkStgCon(nameMkC,singleton(mkChar(cc_char))),
937                 NIL
938              );
939     fun    = mkStgLambda(
940                 args,
941                 mkStgLet(
942                    tripleton(e1,e2,e3),
943                    mkStgApp(
944                       nameCreateAdjThunk,
945                       cons(hd(args),cons(e2,cons(e3,cons(hd(tl(args)),NIL))))
946                    )
947                 )
948              );
949
950     v = mkStgVar(fun,NIL);
951
952     name(n).defn     = NIL;    
953     name(n).stgVar   = v;
954     stgGlobals       = cons(pair(n,v),stgGlobals);
955     }
956 }
957
958 // ToDo: figure out how to set inlineMe for these (non-Name) things
959 Void implementTuple(size)
960 Int size; {
961     if (size > 0) {
962         Cell    t    = mkTuple(size);
963         List    args = makeArgs(size);
964         StgVar  tv   = mkStgVar(mkStgCon(t,args),NIL);
965         StgExpr e    = mkStgLet(singleton(tv),tv);
966         StgVar  v    = mkStgVar(mkStgLambda(args,e),NIL);
967         stgGlobals   = cons(pair(t,v),stgGlobals);   /* so we can see it */
968     } else {
969         StgVar  tv   = mkStgVar(mkStgCon(nameUnit,NIL),NIL);
970         stgGlobals   = cons(pair(nameUnit,tv),stgGlobals);      /* ditto */
971     }        
972 }
973
974 /* --------------------------------------------------------------------------
975  * Compiler control:
976  * ------------------------------------------------------------------------*/
977
978 Void translateControl(what)
979 Int what; {
980     switch (what) {
981     case INSTALL:
982         {
983             /* deliberate fall through */
984         }
985     case RESET: 
986             stgGlobals=NIL;
987             break;
988     case MARK: 
989             mark(stgGlobals);
990             break;
991     }
992 }
993
994 /*-------------------------------------------------------------------------*/