Skip to content
Snippets Groups Projects
Forked from Glasgow Haskell Compiler / GHC
65609 commits behind the upstream repository.
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
translate.c 32.25 KiB

/* --------------------------------------------------------------------------
 * Translator: generates stg code from output of pattern matching
 * compiler.
 *
 * Copyright (c) The University of Nottingham and Yale University, 1994-1997.
 * All rights reserved. See NOTICE for details and conditions of use etc...
 * Hugs version 1.4, December 1997
 *
 * $RCSfile: translate.c,v $
 * $Revision: 1.3 $
 * $Date: 1999/01/13 16:47:26 $
 * ------------------------------------------------------------------------*/

#include "prelude.h"
#include "storage.h"
#include "connect.h"
#include "errors.h"
#include "stg.h"
#include "compiler.h"
#include "pmc.h"  /* for discrArity                 */
#include "hugs.h" /* for debugCode                  */
#include "type.h" /* for conToTagType, tagToConType */
#include "link.h"
#include "pp.h"
#include "dynamic.h"
#include "Assembler.h"
#include "translate.h"

/* ---------------------------------------------------------------- */

static StgVar  local stgOffset       Args((Offset,List));
static StgVar  local stgText         Args((Text,List));
static StgRhs  local stgRhs          Args((Cell,Int,List));
static StgCaseAlt local stgCaseAlt   Args((Cell,Int,List,StgExpr));
static StgExpr local stgExpr         Args((Cell,Int,List,StgExpr));

/* ---------------------------------------------------------------- */

/* Association list storing globals assigned to dictionaries, tuples, etc */
List stgGlobals = NIL;

static StgVar local getSTGTupleVar  Args((Cell));

static StgVar local getSTGTupleVar( Cell d )
{
    Pair p = cellAssoc(d,stgGlobals);
    /* Yoiks - only the Prelude sees Tuple decls! */
    if (isNull(p)) {
        implementTuple(tupleOf(d));
        p = cellAssoc(d,stgGlobals);
    }
    assert(nonNull(p));
    return snd(p);
}

/* ---------------------------------------------------------------- */

static Cell local stgOffset(Offset o, List sc)
{
    Cell r = cellAssoc(o,sc);
    assert(nonNull(r));
    return snd(r);
}

static Cell local stgText(Text t,List sc)
{
    List xs = sc;
    for (; nonNull(xs); xs=tl(xs)) {
        Cell x = hd(xs);
        Cell v = fst(x);
        if (!isOffset(v) && t == textOf(v)) {
            return snd(x);
        }
    }
    internal("stgText");
}

/* ---------------------------------------------------------------- */

static StgRhs local stgRhs(e,co,sc)
Cell e; 
Int  co; 
List sc; {
    switch (whatIs(e)) {

    /* Identifiers */
    case OFFSET:
            return stgOffset(e,sc);
    case VARIDCELL:
    case VAROPCELL:
            return stgText(textOf(e),sc);
    case TUPLE: 
            return getSTGTupleVar(e);
    case NAME:
            return e;
    /* Literals */
    case CHARCELL:
            return mkStgCon(nameMkC,singleton(e));
    case INTCELL:
            return mkStgCon(nameMkI,singleton(e));
    case BIGCELL:
            return mkStgCon(nameMkBignum,singleton(e));
    case FLOATCELL:
            return mkStgCon(nameMkD,singleton(e));
    case STRCELL:
#if USE_ADDR_FOR_STRINGS
        {
            StgVar v = mkStgVar(mkStgCon(nameMkA,singleton(e)),NIL);
            return mkStgLet(singleton(v),
                            makeStgApp(nameUnpackString,singleton(v)));
        }                            
#else
            return mkStgApp(nameUnpackString,singleton(e));
#endif
    case AP:
            return stgExpr(e,co,sc,namePMFail);
    case NIL:
            internal("stgRhs2");
    default:
            return stgExpr(e,co,sc,namePMFail);
    }
}

static StgCaseAlt local stgCaseAlt(alt,co,sc,failExpr)
Cell alt;
Int co;
List sc;
StgExpr failExpr;
{
    StgDiscr d     = fst(alt);
    Int      da    = discrArity(d);
    Cell     vs    = NIL;
    Int  i;
    for(i=1; i<=da; ++i) {
        StgVar nv = mkStgVar(NIL,NIL);
        vs    = cons(nv,vs);
        sc    = cons(pair(mkOffset(co+i),nv),sc);
    }
    return mkStgCaseAlt(d,vs,stgExpr(snd(alt),co+da,sc,failExpr));
}

static StgExpr local stgExpr(e,co,sc,failExpr)
Cell e; 
Int  co; 
List sc; 
StgExpr failExpr; 
{
    switch (whatIs(e)) {
    case COND:
        {
            return makeStgIf(stgExpr(fst3(snd(e)),co,sc,namePMFail),
                             stgExpr(snd3(snd(e)),co,sc,failExpr),
                             stgExpr(thd3(snd(e)),co,sc,failExpr));
        }
    case GUARDED:
        {   
            List guards = reverse(snd(e));
            e = failExpr;
            for(; nonNull(guards); guards=tl(guards)) {
                Cell g   = hd(guards);
                Cell c   = stgExpr(fst(g),co,sc,namePMFail);
                Cell rhs = stgExpr(snd(g),co,sc,failExpr);
                e = makeStgIf(c,rhs,e);
            }
            return e;
        }
    case FATBAR:
        {
            StgExpr e2 = stgExpr(snd(snd(e)),co,sc,failExpr);
            StgVar alt = mkStgVar(e2,NIL);
            return mkStgLet(singleton(alt),stgExpr(fst(snd(e)),co,sc,alt));
        }
    case CASE:
        {   
            List alts  = snd(snd(e));
            Cell scrut = stgExpr(fst(snd(e)),co,sc,namePMFail);
            if (isNull(alts)) {
                return failExpr;
            } else if (isChar(fst(hd(alts)))) {
                Cell     alt  = hd(alts);
                StgDiscr d    = fst(alt);
                StgVar   c    = mkStgVar(mkStgCon(nameMkC,singleton(d)),NIL);
                StgExpr  test = nameEqChar;
                /* duplicates scrut but it should be atomic */
                return makeStgIf(makeStgLet(singleton(c),makeStgApp(test,doubleton(scrut,c))),
                                 stgExpr(snd(alt),co,sc,failExpr),
                                 stgExpr(ap(CASE,pair(fst(snd(e)),tl(alts))),co,sc,failExpr));
            } else {
                List as    = NIL;
                for(; nonNull(alts); alts=tl(alts)) {
                    as = cons(stgCaseAlt(hd(alts),co,sc,failExpr),as);
                }
                return mkStgCase(scrut, revOnto(as, singleton(mkStgDefault(mkStgVar(NIL,NIL),failExpr))));
            }
        }
    case NUMCASE:
#if OVERLOADED_CONSTANTS                
        {
            Triple nc    = snd(e);
            Offset o     = fst3(nc);
            Cell   discr = snd3(nc);
            Cell   r     = thd3(nc);
            Cell   scrut = stgOffset(o,sc);
            Cell   h     = getHead(discr);
            Int    da    = discrArity(discr);

#if NPLUSK
            if (whatIs(h) == ADDPAT && argCount == 1) {
                /*   ADDPAT num dictIntegral
                 * ==>
                 *   let n = fromInteger num in 
                 *   if pmLe dictIntegral n scrut
                 *   then let v = pmSubtract dictIntegral scrut v
                 *   else fail
                 */
                Cell   n            = snd(h);
                Cell   dictIntegral = arg(discr);  /* Integral dictionary */
                StgVar v            = NIL;
                List   binds        = NIL;
                StgVar dIntegral    = NIL;

                /* bind dictionary */
                dIntegral = stgRhs(dictIntegral,co,sc);
                if (!isAtomic(dIntegral)) { /* wasn't atomic */
                    dIntegral = mkStgVar(dIntegral,NIL);
                    binds = cons(dIntegral,binds);
                }
                /* box number */
                n = mkStgVar(mkStgCon(nameMkBignum,singleton(n)),NIL);
                binds = cons(n,binds);

                /* coerce number to right type (using Integral dict) */
                n = mkStgVar(mkStgApp(namePmFromInteger,doubleton(dIntegral,n)),NIL);
                binds = cons(n,binds);

                ++co;
                v = mkStgVar(mkStgApp(namePmSubtract,tripleton(dIntegral,scrut,n)),NIL);
                return mkStgLet(binds,
                                makeStgIf(mkStgApp(namePmLe,tripleton(dIntegral,n,scrut)),
                                          mkStgLet(singleton(v),
                                                   stgExpr(r,
                                                           co,
                                                           cons(pair(mkOffset(co),v),sc),
                                                           failExpr)),
                                          failExpr));
            }
#endif /* NPLUSK */

            assert(isName(h) && argCount == 2);
            {
                /* This code is rather ugly.
                 * We ought to desugar it using one of the following:
                 *   if (==) dEq (fromInt     dNum        pat) scrut
                 *   if (==) dEq (fromInteger dNum        pat) scrut
                 *   if (==) dEq (fromFloat   dFractional pat) scrut
                 * But it would be very hard to obtain the Eq dictionary
                 * from the Num or Fractional dictionary we have.
                 * Instead, we rely on the Prelude to supply 3 helper
                 * functions which do the test for us.
                 *   primPmInt     :: Num a => Int -> a -> Bool
                 *   primPmInteger :: Num a => Integer -> a -> Bool
                 *   primPmDouble  :: Fractional a => Double -> a -> Bool
                 */
                Cell   n      = arg(discr);
                Cell   dict   = arg(fun(discr));
                StgExpr d     = NIL;
                List    binds = NIL;
                StgExpr m     = NIL;
                Name   box
                    = h == nameFromInt     ? nameMkI
                    : h == nameFromInteger ? nameMkBignum
                    :                        nameMkD;
                Name   testFun
                    = h == nameFromInt     ? namePmInt
                    : h == nameFromInteger ? namePmInteger 
                    :                        namePmDouble;
                Cell   altsc  = sc;
                Cell   vs     = NIL;
                Int    i;

                for(i=1; i<=da; ++i) {
                    Cell nv = mkStgVar(NIL,NIL);
                    vs    = cons(nv,vs);
                    altsc = cons(pair(mkOffset(co+i),nv),altsc);
                }
                /* bind dictionary */
                d = stgRhs(dict,co,sc);
                if (!isAtomic(d)) { /* wasn't atomic */
                    d = mkStgVar(d,NIL);
                    binds = cons(d,binds);
                }
                /* bind number */
                n = mkStgVar(mkStgCon(box,singleton(n)),NIL);
                binds = cons(n,binds);

                return makeStgIf(mkStgLet(binds,
                                          mkStgApp(testFun,tripleton(d,n,scrut))),
                                 stgExpr(r,co+da,altsc,failExpr),
                                 failExpr);
            }
        }
#else /* ! OVERLOADED_CONSTANTS */
        {
            Triple nc    = snd(e);
            Offset o     = fst3(nc);
            Cell   discr = snd3(nc);
            Cell   r     = thd3(nc);
            Cell   scrut = stgOffset(o,sc);
            Cell   h     = getHead(discr);
            Int    da    = discrArity(discr);
            Cell   n     = discr;
            List   binds = NIL;
            Name   eq
                = isInt(discr)    ? nameEqInt
                : isBignum(discr) ? nameEqInteger
                :                   nameEqDouble;
            Name   box
                = isInt(discr)    ? nameMkI
                : isBignum(discr) ? nameMkBignum
                :                   nameMkD;
            StgExpr test = NIL;
            Cell   altsc = sc;
            Cell   vs    = NIL;
            Int    i;

            for(i=1; i<=da; ++i) {
                Cell nv = mkStgVar(NIL,NIL);
                vs    = cons(nv,vs);
                altsc = cons(pair(mkOffset(co+i),nv),altsc);
            }

            /* bind number */
            n = mkStgVar(mkStgCon(box,singleton(n)),NIL);
            binds = cons(n,binds);
            
            test = mkStgLet(binds, mkStgApp(eq, doubleton(n,scrut)));
            return makeStgIf(test,
                             stgExpr(r,co+da,altsc,failExpr),
                             failExpr);
        }
#endif /* ! OVERLOADED_CONSTANTS */
    case LETREC:
        {
            List binds = NIL;
            List vs = NIL;
            List bs;
            /* allocate variables, extend scope */
            for(bs = snd(fst(snd(e))); nonNull(bs); bs=tl(bs)) {
                Cell nv  = mkStgVar(NIL,NIL);
                sc = cons(pair(fst3(hd(bs)),nv),sc);
                binds = cons(nv,binds);
                vs = cons(nv,vs);
            }
            for(bs = fst(fst(snd(e))); nonNull(bs); bs=tl(bs)) {
                Cell nv  = mkStgVar(NIL,NIL);
                sc = cons(pair(mkOffset(++co),nv),sc);
                binds = cons(nv,binds);
                vs = cons(nv,vs);
            }
            vs = rev(vs);
            /* transform functions */
            for(bs = snd(fst(snd(e))); nonNull(bs); bs=tl(bs), vs=tl(vs)) {
                Cell fun = hd(bs);
                Cell nv  = hd(vs);
                List as = NIL;
                List funsc = sc;
                Int  arity = intOf(snd3(fun));
                Int  i;
                for(i=1; i<=arity; ++i) {
                    Cell v = mkStgVar(NIL,NIL);
                    as = cons(v,as);
                    funsc = cons(pair(mkOffset(co+i),v),funsc);
                }
                stgVarBody(nv) = mkStgLambda(as,stgExpr(thd3(thd3(fun)),co+arity,funsc,namePMFail));
            }
            /* transform expressions */
            for(bs = fst(fst(snd(e))); nonNull(bs); bs=tl(bs), vs=tl(vs)) {
                Cell rhs = hd(bs);
                Cell nv  = hd(vs);
                stgVarBody(nv) = stgRhs(rhs,co,sc);
            }
            return mkStgLet(binds,stgRhs(snd(snd(e)),co,sc));
        }
    default: /* convert to an StgApp or StgVar plus some bindings */
        {   
            List args  = NIL;
            List binds = NIL;
            List as    = NIL;

            /* Unwind args */
            while (isAp(e)) {
                Cell arg = arg(e);
                e        = fun(e);
                args = cons(arg,args);
            }

            /* Special cases */
            if (e == nameSel && length(args) == 3) {
                Cell   con   = hd(args);
#if 0
                StgVar v     = stgOffset(hd(tl(args)),sc);
#else
                StgExpr v    = stgExpr(hd(tl(args)),co,sc,namePMFail);
#endif
                Int    ix    = intOf(hd(tl(tl(args))));
                Int    da    = discrArity(con);
                List   vs    = NIL;
                Int    i;
                for(i=1; i<=da; ++i) {
                    Cell nv = mkStgVar(NIL,NIL);
                    vs=cons(nv,vs);
                }
                return mkStgCase(v,
                                 doubleton(mkStgCaseAlt(con,vs,nth(ix-1,vs)),
                                 mkStgDefault(mkStgVar(NIL,NIL),namePMFail)));
            }
            
            /* Arguments must be StgAtoms */
            for(as=args; nonNull(as); as=tl(as)) {
                StgRhs a = stgRhs(hd(as),co,sc);
#if 1 /* optional flattening of let bindings */
                if (whatIs(a) == LETREC) {
                    binds = appendOnto(stgLetBinds(a),binds);
                    a = stgLetBody(a);
                }
#endif
                    
                if (!isAtomic(a)) {
                    a     = mkStgVar(a,NIL);
                    binds = cons(a,binds);
                }
                hd(as) = a;
            }

            /* Function must be StgVar or Name */
            e = stgRhs(e,co,sc);
            if (!isStgVar(e) && !isName(e)) {
                e = mkStgVar(e,NIL);
                binds = cons(e,binds);
            }

            return makeStgLet(binds,makeStgApp(e,args));
        }
    }
}

static Void ppExp( Name n, Int arity, Cell e );
static Void ppExp( Name n, Int arity, Cell e )
{
#if DEBUG_CODE
    if (debugCode) {
        Int i;
        printf("%s", textToStr(name(n).text));
        for (i = arity; i > 0; i--) {
            printf(" o%d", i);
        }
        printf(" = ");
        printExp(stdout,e); 
        printf("\n");
    }
#endif
}

Void stgDefn( Name n, Int arity, Cell e )
{
    List vs = NIL;
    List sc = NIL;
    Int i;
//printf("\nBEGIN --------------- stgDefn-ppExp ----------------\n" );
//    ppExp(n,arity,e);
//printf("\nEND ----------------- stgDefn-ppExp ----------------\n" );
    for (i = 1; i <= arity; ++i) {
        Cell nv = mkStgVar(NIL,NIL);
        vs = cons(nv,vs);
        sc = cons(pair(mkOffset(i),nv),sc);
    }
    stgVarBody(name(n).stgVar) = makeStgLambda(vs,stgExpr(e,arity,sc,namePMFail));
//printf("\nBEGIN --------------- stgDefn-ppStg ----------------\n" );
//    ppStg(name(n).stgVar);
//printf("\nEND ----------------- stgDefn-ppStg ----------------\n" );
}

static StgExpr forceArgs( List is, List args, StgExpr e );

/* force the args numbered in is */
static StgExpr forceArgs( List is, List args, StgExpr e )
{
    for(; nonNull(is); is=tl(is)) {
        e = mkSeq(nth(intOf(hd(is))-1,args),e);
    }
    return e;
}

/* \ v -> case v of { ...; Ci _ _ -> i; ... } */
Void implementConToTag(t)
Tycon t; {                    
    if (isNull(tycon(t).conToTag)) {
        List   cs  = tycon(t).defn;
        Name   nm  = newName(inventText());
        StgVar v   = mkStgVar(NIL,NIL);
        List alts  = NIL; /* can't fail */

        assert(isTycon(t) && (tycon(t).what==DATATYPE || tycon(t).what==NEWTYPE));
        for (; hasCfun(cs); cs=tl(cs)) {
            Name    c   = hd(cs);
            Int     num = cfunOf(c) == 0 ? 0 : cfunOf(c)-1;
            StgVar  r   = mkStgVar(mkStgCon(nameMkI,singleton(mkInt(num))),NIL);
            StgExpr tag = mkStgLet(singleton(r),r);
            List    vs  = NIL;
            Int i;
            for(i=0; i < name(c).arity; ++i) {
                vs = cons(mkStgVar(NIL,NIL),vs);
            }
            alts = cons(mkStgCaseAlt(c,vs,tag),alts);
        }

        name(nm).line   = tycon(t).line;
        name(nm).type   = conToTagType(t);
        name(nm).arity  = 1;
        name(nm).stgVar = mkStgVar(mkStgLambda(singleton(v),mkStgCase(v,alts)),NIL);
        tycon(t).conToTag = nm;
        /* hack to make it print out */
        stgGlobals = cons(pair(nm,name(nm).stgVar),stgGlobals); 
    }
}

/* \ v -> case v of { ...; i -> Ci; ... } */
Void implementTagToCon(t)
Tycon t; {                    
    if (isNull(tycon(t).tagToCon)) {
        String etxt;
        String tyconname;
        List   cs;
        Name   nm;
        StgVar v1;
        StgVar v2;
        Cell   txt0;
        StgVar bind1;
        StgVar bind2;
        StgVar bind3;
        List   alts;

        assert(nameMkA);
        assert(nameUnpackString);
        assert(nameError);
        assert(isTycon(t) && (tycon(t).what==DATATYPE || tycon(t).what==NEWTYPE));

        tyconname  = textToStr(tycon(t).text);
        etxt       = malloc(100+strlen(tyconname));
        assert(etxt);
        sprintf(etxt, 
                "out-of-range arg for `toEnum' in (derived) `instance Enum %s'", 
                tyconname);
        
        cs  = tycon(t).defn;
        nm  = newName(inventText());
        v1  = mkStgVar(NIL,NIL);
        v2  = mkStgPrimVar(NIL,mkStgRep(INT_REP),NIL);
        txt0  = mkStr(findText(etxt));
        bind1 = mkStgVar(mkStgCon(nameMkA,singleton(txt0)),NIL);
        bind2 = mkStgVar(mkStgApp(nameUnpackString,singleton(bind1)), NIL);
        bind3 = mkStgVar(mkStgApp(nameError,singleton(bind2)), NIL);

        alts  = singleton(
                   mkStgPrimAlt(
                      singleton(
                         mkStgPrimVar(NIL,mkStgRep(INT_REP),NIL)
                      ),
                      makeStgLet ( tripleton(bind1,bind2,bind3), bind3 )
                   )
                );

        for (; hasCfun(cs); cs=tl(cs)) {
            Name   c   = hd(cs);
            Int    num = cfunOf(c) == 0 ? 0 : cfunOf(c)-1;
            StgVar pat = mkStgPrimVar(mkInt(num),mkStgRep(INT_REP),NIL);
            assert(name(c).arity==0);
            alts = cons(mkStgPrimAlt(singleton(pat),c),alts);
        }

        name(nm).line   = tycon(t).line;
        name(nm).type   = tagToConType(t);
        name(nm).arity  = 1;
        name(nm).stgVar = mkStgVar(mkStgLambda(singleton(v1),
                                               mkStgCase(v1,singleton(mkStgCaseAlt(nameMkI,singleton(v2),
                                                                                   mkStgPrimCase(v2,alts))))),NIL);
        tycon(t).tagToCon = nm;
        /* hack to make it print out */
        stgGlobals = cons(pair(nm,name(nm).stgVar),stgGlobals); 
        if (etxt) free(etxt);
    }
}

Void implementCfun(c,scs)               /* Build implementation for constr */
Name c;                                 /* fun c.  scs lists integers (1..)*/
List scs; {                             /* in incr order of strict comps.  */
    Int a = name(c).arity;
    if (name(c).arity > 0) {
        List    args = makeArgs(a);
        StgVar  tv   = mkStgVar(mkStgCon(c,args),NIL);
        StgExpr e1   = mkStgLet(singleton(tv),tv);
        StgExpr e2   = forceArgs(scs,args,e1);
        StgVar  v    = mkStgVar(mkStgLambda(args,e2),NIL);
        name(c).stgVar = v;
    } else {
        StgVar v = mkStgVar(mkStgCon(c,NIL),NIL);
        name(c).stgVar = v;
    }
    /* hack to make it print out */
    stgGlobals = cons(pair(c,name(c).stgVar),stgGlobals); 
}

/* --------------------------------------------------------------------------
 * Foreign function calls and primops
 * ------------------------------------------------------------------------*/

static String  charListToString( List cs );
static Cell    foreignResultTy( Type t );
static Cell    foreignArgTy( Type t );
static Name    repToBox        Args(( char c ));
static StgRhs  makeStgPrim     Args(( Name,Bool,List,String,String ));

static String charListToString( List cs )
{
    static char s[100];

    Int i = 0;
    assert( length(cs) < 100 );
    for(; nonNull(cs); ++i, cs=tl(cs)) {
        s[i] = charOf(hd(cs));
    }
    s[i] = '\0';
    return textToStr(findText(s));
}

static Cell foreignResultTy( Type t )
{
    if      (t == typeChar)   return mkChar(CHAR_REP);
    else if (t == typeInt)    return mkChar(INT_REP);
#ifdef PROVIDE_INT64
    else if (t == typeInt64)  return mkChar(INT64_REP);
#endif
#ifdef PROVIDE_INTEGER
    else if (t == typeInteger)return mkChar(INTEGER_REP);
#endif
#ifdef PROVIDE_WORD
    else if (t == typeWord)   return mkChar(WORD_REP);
#endif
#ifdef PROVIDE_ADDR
    else if (t == typeAddr)   return mkChar(ADDR_REP);
#endif
    else if (t == typeFloat)  return mkChar(FLOAT_REP);
    else if (t == typeDouble) return mkChar(DOUBLE_REP);
#ifdef PROVIDE_FOREIGN
    else if (t == typeForeign)return mkChar(FOREIGN_REP); /* ToDo: argty only! */
#endif
#ifdef PROVIDE_ARRAY
    else if (t == typePrimByteArray) return mkChar(BARR_REP); /* ToDo: argty only! */
    else if (whatIs(t) == AP) {
        Type h = getHead(t);
        if (h == typePrimMutableByteArray) return mkChar(MUTBARR_REP); /* ToDo: argty only! */
    }
#endif
   /* ToDo: decent line numbers! */
   ERRMSG(0) "Illegal foreign type" ETHEN
   ERRTEXT " \"" ETHEN ERRTYPE(t);
   ERRTEXT "\""
   EEND;
}

static Cell foreignArgTy( Type t )
{
    return foreignResultTy( t );
}

static Name repToBox( char c )
{
    switch (c) {
    case CHAR_REP:    return nameMkC;
    case INT_REP:     return nameMkI;
#ifdef PROVIDE_INT64
    case INT64_REP:   return nameMkInt64;
#endif
#ifdef PROVIDE_INTEGER
    case INTEGER_REP: return nameMkInteger;
#endif
#ifdef PROVIDE_WORD
    case WORD_REP:    return nameMkW;
#endif
#ifdef PROVIDE_ADDR
    case ADDR_REP:    return nameMkA;
#endif
    case FLOAT_REP:   return nameMkF;
    case DOUBLE_REP:  return nameMkD;
#ifdef PROVIDE_ARRAY
    case ARR_REP:     return nameMkPrimArray;            
    case BARR_REP:    return nameMkPrimByteArray;
    case REF_REP:     return nameMkRef;                  
    case MUTARR_REP:  return nameMkPrimMutableArray;     
    case MUTBARR_REP: return nameMkPrimMutableByteArray; 
#endif
#ifdef PROVIDE_STABLE
    case STABLE_REP:  return nameMkStable;
#endif
#ifdef PROVIDE_WEAK
    case WEAK_REP:  return nameMkWeak;
#endif
#ifdef PROVIDE_FOREIGN
    case FOREIGN_REP: return nameMkForeign;
#endif
#ifdef PROVIDE_CONCURRENT
    case THREADID_REP: return nameMkThreadId;
    case MVAR_REP:     return nameMkMVar;
#endif
    default: return NIL;
    }
}

static StgPrimAlt boxResults( String reps, StgVar state )
{
    List rs = NIL;     /* possibly unboxed results     */
    List bs = NIL;     /* boxed results of wrapper     */
    List rbinds = NIL; /* bindings used to box results */
    StgExpr e   = NIL;
    Int i;
    for(i=0; reps[i] != '\0'; ++i) {
        StgRep k = mkStgRep(reps[i]);
        Cell v   = mkStgPrimVar(NIL,k,NIL);
        Name box = repToBox(reps[i]);
        if (isNull(box)) {
            bs = cons(v,bs);
        } else {
            StgRhs rhs = mkStgCon(box,singleton(v));
            StgVar bv = mkStgVar(rhs,NIL); /* boxed */
            bs     = cons(bv,bs);
            rbinds = cons(bv,rbinds);
        }
        rs = cons(v,rs);
    }
    /* Construct tuple of results */
    if (i == 1) {
        e = hd(bs);
    } else { /* includes i==0 case */
        StgVar r = mkStgVar(mkStgCon(mkTuple(i),rev(bs)),NIL);
        rbinds = cons(r,rbinds);
        e = r;
    }
    /* construct result pair if needed */
    if (nonNull(state)) {
        /* Note that this builds a tuple directly - we know it's
         * saturated.
         */
        StgVar r = mkStgVar(mkStgCon(mkTuple(2),doubleton(e,state)),NIL);
        rbinds   = cons(r,rbinds);
        rs       = cons(state,rs);      /* last result is a state */
        e = r;
    }
    return mkStgPrimAlt(rev(rs),makeStgLet(rbinds,e));
}

static List mkUnboxedVars( String reps )
{
    List as = NIL;
    Int i;
    for(i=0; reps[i] != '\0'; ++i) {
        Cell v = mkStgPrimVar(NIL,mkStgRep(reps[i]),NIL);
        as = cons(v,as);
    }
    return rev(as);
}

static List mkBoxedVars( String reps )
{
    List as = NIL;
    Int i;
    for(i=0; reps[i] != '\0'; ++i) {
        as = cons(mkStgVar(NIL,NIL),as);
    }
    return rev(as);
}

static StgRhs unboxVars( String reps, List b_args, List u_args, StgExpr e )
{
    if (nonNull(b_args)) {
        StgVar b_arg = hd(b_args); /* boxed arg   */
        StgVar u_arg = hd(u_args); /* unboxed arg */
        StgRep k     = mkStgRep(*reps);
        Name   box   = repToBox(*reps);
        e = unboxVars(reps+1,tl(b_args),tl(u_args),e);
        if (isNull(box)) {
            /* Use a trivial let-binding */
            stgVarBody(u_arg) = b_arg;
            return mkStgLet(singleton(u_arg),e);
        } else {
            StgCaseAlt alt = mkStgCaseAlt(box,singleton(u_arg),e);
            return mkStgCase(b_arg,singleton(alt));
        }
    } else {
        return e;
    }
}

/* Generate wrapper for primop based on list of arg types and result types:
 *
 * makeStgPrim op# False "II" "II" =
 *   \ x y -> "case x of { I# x# -> 
 *             case y of { I# y# -> 
 *             case op#{x#,y#} of { r1# r2# ->
 *             let r1 = I# r1#; r2 = I# r2# in
 *             (r1, r2)
 *             }}}"
 */
static StgRhs local makeStgPrim(op,addState,extra_args,a_reps,r_reps)
Name   op;
Bool   addState;
List   extra_args;
String a_reps;
String r_reps; {
    List b_args = NIL; /* boxed args to primop            */
    List u_args = NIL; /* possibly unboxed args to primop */
    List alts   = NIL; 
    StgVar s0 = addState ? mkStgVar(NIL,NIL) : NIL;
    StgVar s1 = addState ? mkStgVar(NIL,NIL) : NIL;

    /* box results */
    if (strcmp(r_reps,"B") == 0) {
        StgPrimAlt altF = mkStgPrimAlt(singleton(mkStgPrimVar(mkInt(0),mkStgRep(INT_REP),NIL)),
                                       nameFalse);
        StgPrimAlt altT = mkStgPrimAlt(singleton(mkStgPrimVar(NIL,mkStgRep(INT_REP),NIL)),
                                       nameTrue);
        alts = doubleton(altF,altT); 
        assert(nonNull(nameTrue));
        assert(!addState);
    } else {
        alts = singleton(boxResults(r_reps,s1));
    }
    b_args = mkBoxedVars(a_reps);
    u_args = mkUnboxedVars(a_reps);
    if (addState) {
        List actual_args = appendOnto(extra_args,dupListOnto(u_args,singleton(s0)));
        StgRhs rhs = makeStgLambda(singleton(s0),
                                   unboxVars(a_reps,b_args,u_args,
                                             mkStgPrimCase(mkStgPrim(op,actual_args),
                                                           alts)));
        StgVar m = mkStgVar(rhs,NIL);
        return makeStgLambda(b_args,
                             mkStgLet(singleton(m),
                                      mkStgApp(nameMkIO,singleton(m))));
    } else {
        List actual_args = appendOnto(extra_args,u_args);
        return makeStgLambda(b_args,
                             unboxVars(a_reps,b_args,u_args,mkStgPrimCase(mkStgPrim(op,actual_args),alts)));
    }
}    

Void implementPrim( n )
Name n; {
    const AsmPrim* p = name(n).primop;
    StgRhs   rhs = makeStgPrim(n,p->monad!=MONAD_Id,NIL,p->args,p->results);
    StgVar   v   = mkStgVar(rhs,NIL);
    name(n).stgVar = v;
    stgGlobals=cons(pair(n,v),stgGlobals);  /* so it will get codegened */
}

/* Generate wrapper code from (in,out) type lists.
 *
 * For example:
 * 
 *     inTypes  = [Int,Float]
 *     outTypes = [Char,Addr]
 * ==>
 *     \ fun a1 a2 -> 
 *	 let m = (\ s0 ->
 *	     case a1 of { I# a1# ->
 *	     case s2 of { F# a2# ->
 *	     case ccall# "IF" "CA" fun a1# a2# s0 of { r1# r2# s1 ->
 *	     let r1 = C# r1# in
 *	     let r2 = A# r2# in
 *	     let r  = (r1,r2) in
 *	     (r,s1)
 *	     }}})
 *	 in primMkIO m
 *	 ::
 *	 Addr -> (Int -> Float -> IO (Char,Addr)
 */
Void implementForeignImport( Name n )
{
    Type t       = name(n).type;
    List argTys    = NIL;
    List resultTys = NIL;
    CFunDescriptor* descriptor = 0;
    Bool addState = TRUE;
    while (getHead(t)==typeArrow && argCount==2) {
        Type ta = fullExpand(arg(fun(t)));
        Type tr = arg(t);
        argTys = cons(ta,argTys);
        t = tr;
    }
    argTys = rev(argTys);
    if (getHead(t) == typeIO) {
        resultTys = getArgs(t);
        assert(length(resultTys) == 1);
        resultTys = hd(resultTys);
        addState = TRUE;
    } else {
        resultTys = t;
        addState = FALSE;
    }
    resultTys = fullExpand(resultTys);
    if (isTuple(getHead(resultTys))) {
        resultTys = getArgs(resultTys);
    } else if (getHead(resultTys) == typeUnit) {
        resultTys = NIL;
    } else {
        resultTys = singleton(resultTys);
    }
    mapOver(foreignArgTy,argTys);      /* allows foreignObj, byteArrays, etc */
    mapOver(foreignResultTy,resultTys);/* doesn't */
    descriptor = mkDescriptor(charListToString(argTys),
                              charListToString(resultTys));
    name(n).primop = addState ? &ccall_IO : &ccall_Id;
    {
        Pair    extName = name(n).defn;
        void*   funPtr  = getDLLSymbol(textToStr(textOf(fst(extName))),
                                       textToStr(textOf(snd(extName))));
        List extra_args = doubleton(mkPtr(descriptor),mkPtr(funPtr));
        StgRhs rhs = makeStgPrim(n,addState,extra_args,descriptor->arg_tys,descriptor->result_tys);
        StgVar v   = mkStgVar(rhs,NIL);
        if (funPtr == 0) {
            ERRMSG(0) "Could not find foreign function \"%s\" in \"%s\"", 
                textToStr(textOf(snd(extName))),
                textToStr(textOf(fst(extName)))
            EEND;
        }
        ppStg(v);
        name(n).defn = NIL;
        name(n).stgVar = v; 
        stgGlobals=cons(pair(n,v),stgGlobals);  /* so it will get codegened */
    }
}

Void implementForeignExport( Name n )
{
    internal("implementForeignExport: not implemented");
}

Void implementTuple(size)
Int size; {
    if (size > 0) {
        Cell    t    = mkTuple(size);
        List    args = makeArgs(size);
        StgVar  tv   = mkStgVar(mkStgCon(t,args),NIL);
        StgExpr e    = mkStgLet(singleton(tv),tv);
        StgVar  v    = mkStgVar(mkStgLambda(args,e),NIL);
        stgGlobals   = cons(pair(t,v),stgGlobals);   /* so we can see it */
    } else {
        StgVar  tv   = mkStgVar(mkStgCon(nameUnit,NIL),NIL);
        stgGlobals   = cons(pair(nameUnit,tv),stgGlobals);   /* so we can see it */
    }        
}

/* --------------------------------------------------------------------------
 * Compiler control:
 * ------------------------------------------------------------------------*/

Void translateControl(what)
Int what; {
    switch (what) {
    case INSTALL:
        {
            /* deliberate fall through */
        }
    case RESET: 
            stgGlobals=NIL;
            break;
    case MARK: 
            mark(stgGlobals);
            break;
    }
}

/*-------------------------------------------------------------------------*/