shithub: mc

ref: 36a3a5fa99dc4887ca46c7807436ad44da19422f
dir: /8/reduce.c/

View raw version
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <ctype.h>
#include <string.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

#include "parse.h"
#include "gen.h"


/* takes a list of nodes, and reduces it (and it's subnodes) to a list
 * following these constraints:
 *      - All nodes are expression nodes
 *      - Nodes with side effects are root nodes
 *      - All nodes operate on machine-primitive types and tuples
 */
typedef struct Simp Simp;
struct Simp {
    Node **blk;
    size_t nblk;
    Node *endlbl;
    Node *retval;
};

Node *simp(Simp *s, Node *n);

void append(Simp *s, Node *n)
{
    lappend(&s->blk, &s->nblk, n);
}

int isimpure(Node *n)
{
    return 0;
}

Node *genlbl(void)
{
    char buf[128];
    static int nextlbl;

    snprintf(buf, 128, ".L%d", nextlbl++);
    return mklbl(-1, buf);
}

Node *temp(Node *e)
{
    char buf[128];
    static int nexttmp;
    Node *n;
    Node *t;
    Sym *s;

    assert(e->type == Nexpr);
    snprintf(buf, 128, ".t%d", nexttmp++);
    n = mkname(-1, buf);
    s = mksym(-1, n, e->expr.type);
    t = mkdecl(-1, s);
    return mkexpr(-1, Ovar, t, NULL);
}

void cjmp(Simp *s, Node *cond, Node *iftrue, Node *iffalse)
{
    Node *jmp;

    jmp = mkexpr(-1, Ocjmp, cond, iftrue, iffalse, NULL);
    append(s, jmp);
}

void jmp(Simp *s, Node *lbl)
{
    append(s, mkexpr(-1, Ojmp, lbl, NULL));
}

Node *store(Node *t, Node *n)
{
    return mkexpr(-1, Oasn, t, n, NULL);
}

Node *storetmp(Node *n)
{
    return store(temp(n), n);
}

/* if foo; bar; else baz;;
 *      => cjmp (foo) :bar :baz */
void simpif(Simp *s, Node *n)
{
    Node *l1, *l2;
    Node *c;

    l1 = genlbl();
    l2 = genlbl();
    c = simp(s, n->ifstmt.cond);
    cjmp(s, c, l1, l2);
    simp(s, l1);
    simp(s, n->ifstmt.iftrue);
    simp(s, l2);
    simp(s, n->ifstmt.iffalse);
}

/* init; while cond; body;; 
 *    => init
 *       jmp :cond
 *       :body
 *           ...body...
 *       :cond
 *           ...cond...
 *       cjmp (cond) :body :end
 *       :end
 */
void simploop(Simp *s, Node *n)
{
    Node *lbody;
    Node *lend;
    Node *lcond;
    Node *c;

    lbody = genlbl();
    lcond = genlbl();
    lend = genlbl();

    simp(s, n->loopstmt.init);
    jmp(s, lcond);
    simp(s, lbody);
    simp(s, n->loopstmt.body);
    simp(s, n->loopstmt.step);
    simp(s, lcond);
    c = simp(s, n->loopstmt.cond);
    cjmp(s, c, lbody, lend);
    simp(s, lend);
}

void simpblk(Simp *s, Node *n)
{
    int i;
    Node *e;

    for (i = 0; i < n->block.nstmts; i++) {
        e = simp(s, n->block.stmts[i]);
        append(s, e);
    }
}

Node *simpexpr(Simp *s, Node *n)
{
    Node *r, *t;
    int i;

    switch (exprop(n)) {
        case Ovar:
            break;
        case Oret:
            if (n->expr.args[0]) {
                t = storetmp(simp(s, n->expr.args[0]));
                append(s, t);
            }
            jmp(s, s->endlbl);
            break;
        default:
            if (isimpure(n)) {
                r = simp(s, n);
                t = storetmp(r);
                append(s, t);
                return t;
            } else {
                for (i = 0; i < n->expr.nargs; i++)
                    n->expr.args[i] = simp(s, n->expr.args[i]);
            }
    }
    return n;
}

Node *simp(Simp *s, Node *n)
{
    Node *r;

    r = NULL;
    switch (n->type) {
        case Nblock:
            simpblk(s, n);
            break;
        case Nifstmt:
            simpif(s, n);
            break;
        case Nloopstmt:
            simploop(s, n);
            break;
        case Nexpr:
            r = simpexpr(s, n);
            break;
        case Nlit:
            r = n;
            break;
        case Ndecl:
            //declare(s, n);
            break;
        case Nlbl:
            append(s, n);
            break;
        default:
            die("Bad node passsed to simp()");
            break;
    }
    return r;
}

Node **reduce(Node *n, int *ret_nn)
{
    Simp s = {0,};

    s.nblk = 0;
    s.endlbl = genlbl();
    s.retval = NULL;
    switch (n->type) {
        /* these should never be inside functions */
        case Nnone:
        case Nfile:
            die("Bad node type in func");
            break;
        case Nfunc:
            die("FIXME: generate thunks");
            break;
            /* no code generated */
        case Nuse:
            break;
            /* complex nodes */
        case Nblock:
            simp(&s, n);
            break;
        case Nifstmt:
        case Nloopstmt:
        case Nexpr:
        case Nlit:
        case Nname:
        case Ndecl:
        case Nlbl:
            break;
    }
    append(&s, s.endlbl);

    *ret_nn = s.nblk;
    return s.blk;
}