aboutsummaryrefslogtreecommitdiff
path: root/src/prc1/cgen/qbe/from.c
blob: 40b2724f1fd008a46e312846894f2c13d6716e0e (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
#include "from.h"
#include "stmt.h"
#include "cgen.h"
#include "qbe.h"
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>

static int loadvar(const struct from_it *st, struct cgen *c)
{
    const struct stentry *e = st->u.e;
    size_t sz = e->t->sz;
    const char *tmp = cgen_tmp(sz);

    printf("%%%s =%s load%s ", tmp, cgen_sz(sz), cgen_load(e->t));
    cgen_printvar(c->fn, e);
    putchar('\n');
    return 0;
}

/* TODO: de-duplicate function */
static unsigned long long tonum(const char *s)
{
    unsigned long long v;
    char *end;

    errno = 0;
    v = strtoull(s, &end, 0);

    if (*s == '-' || errno || *end)
        return strtoll(s, NULL, 0);

    return v;
}

static int loadval(const struct from *fr, struct cgen *c)
{
    const struct stentry *dst = fr->var;
    const struct from_it *st = &fr->start;
    unsigned long long v = tonum(st->u.tk->s);

    printf("store%s %llu, ", cgen_sz(dst->t->sz), v);
    cgen_printvar(c->fn, dst);
    putchar('\n');
    return 0;
}

static int endvar(const struct from *fr, struct cgen *c)
{
    fprintf(stderr, "%s: TODO\n", __func__);
    return -1;
}

static int endval(const struct from *fr, struct cgen *c)
{
    const struct stentry *src = fr->var;
    size_t sz = src->t->sz;
    const char *tmp = cgen_tmp(sz);
    const struct from_it *end = &fr->end;
    const struct tk *tk = end->u.tk;
    int neg = *tk->s == '-';
    size_t bl = fr->block_i;

    printf("%%%s =%s load%s ", tmp, cgen_sz(sz), cgen_load(src->t));
    cgen_printvar(c->fn, src);
    putchar('\n');
    printf("%%%s =%s c", tmp, cgen_sz(sz));
    fputs(neg ? "sge" : "uge", stdout);
    printf("%s ", cgen_sz(sz));
    printf("%%%s, %s\n", tmp, tk->s);
    printf("jnz %%%s, @__end%zu, @__blockbody%zu\n", tmp, bl, bl);
    printf("@__blockbody%zu\n", bl);
    return 0;
}

static int from_var(const struct from *fr, struct cgen *c)
{
    const struct from_it *st = &fr->start;

    switch (st->type)
    {
    case FR_VAR:
        if (loadvar(st, c))
            return -1;
        break;

    case FR_VAL:
        if (loadval(fr, c))
            return -1;
        break;
    }

    printf("@__block%zu\n", fr->block_i);

    switch (fr->end.type)
    {
    case FR_VAR:
        if (endvar(fr, c))
            return -1;
        break;

    case FR_VAL:
        if (endval(fr, c))
            return -1;
        break;
    }

    return 0;
}

int from_end(const struct stmt *s, struct cgen *c)
{
    const struct from *fr = &s->u.from;
    const struct stentry *src = fr->var;
    const struct type *t = src->t;
    size_t sz = t->sz;
    const char *tmp = cgen_tmp(sz);
    const struct fn *fn = c->fn;

    printf("%%%s =%s load%s ", tmp, cgen_sz(sz), cgen_load(t));
    cgen_printvar(fn, src);
    putchar('\n');
    printf("%%%s =%s add %%%s, 1\n", tmp, cgen_sz(sz), tmp);
    printf("store%s %%%s, ", cgen_sz(sz), tmp);
    cgen_printvar(fn, src);
    putchar('\n');
    printf("jmp @__block%zu\n", fr->block_i);
    return 0;
}

int qbe_from(const struct from *fr, struct cgen *c)
{
    return from_var(fr, c);
}