aboutsummaryrefslogtreecommitdiff
path: root/src/ssa/ssa.c
blob: 3433e8d58858c5416f4c9ab1a326478b1c90c0d8 (plain)
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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
#include "../../include/ssa/ssa.h"
#include "../../include/std/mem.h"
#include "../../include/std/log.h"
#include <assert.h>

static int compare_number(const void *a, const void *b) {
    const SsaNumber *lhs;
    const SsaNumber *rhs;
    lhs = a;
    rhs = b;
    if(rhs->type == lhs->type && rhs->value == lhs->value)
        return 0;
    return 1;
}

static usize hash_number(const u8 *data, usize size) {
    SsaNumber number;
    assert(size == sizeof(SsaNumber));
    am_memcpy(&number, data, size);
    return number.value;
}

SsaNumber create_ssa_number(i64 value, SsaNumberType type) {
    SsaNumber result;
    result.value = value;
    result.type = type;
    return result;
}

int ssa_init(Ssa *self, ScopedAllocator *allocator) {
    return_if_error(buffer_init(&self->instructions, allocator));
    return_if_error(hash_map_init(&self->intermediates, allocator, sizeof(SsaIntermediateIndex), compare_number, hash_number));
    self->intermediate_counter = 0;
    self->reg_counter = 0;
    self->func_counter = 0;
    return 0;
}

int ssa_get_unique_reg(Ssa *self, SsaRegister *result) {
    /* Overflow */
    if(self->reg_counter + 1 < self->reg_counter)
        return -1;
    *result = self->reg_counter++;
    return 0;
}

static CHECK_RESULT int ssa_try_add_intermediate(Ssa *self, i64 intermediate, SsaNumberType number_type, SsaIntermediateIndex *result_index) {
    SsaNumber number;
    bool exists;
    BufferView key;

    assert(result_index);
    number = create_ssa_number(intermediate, number_type);
    key = create_buffer_view((const char*)&number, sizeof(number));

    exists = hash_map_get(&self->intermediates, key, result_index);
    if(exists)
        return 0;
    
    /* Overflow */
    if(self->intermediate_counter + 1 < self->intermediate_counter)
        return -1;
    
    *result_index = self->intermediate_counter;
    ++self->intermediate_counter;
    return hash_map_insert(&self->intermediates, key, result_index);
}

static CHECK_RESULT int ssa_add_ins_form1(Ssa *self, SsaInstructionType ins_type, SsaRegister lhs, u16 rhs) {
    usize index;
    index = self->instructions.size;

    return_if_error(buffer_append(&self->instructions, NULL, sizeof(u8) + sizeof(SsaRegister) + sizeof(u16)));
    self->instructions.data[index + 0] = ins_type;
    *(SsaRegister*)&self->instructions.data[index + 1] = lhs;
    *(u16*)&self->instructions.data[index + 3] = rhs;
    return 0;
}

static CHECK_RESULT int ssa_add_ins_form2(Ssa *self, SsaInstructionType ins_type, SsaRegister lhs, SsaRegister rhs, SsaRegister *result) {
    usize index;
    index = self->instructions.size;

    /* Overflow */
    if(self->reg_counter + 1 < self->reg_counter)
        return -1;

    assert(result);
    return_if_error(buffer_append(&self->instructions, NULL, sizeof(u8) + sizeof(SsaRegister) + sizeof(SsaRegister) + sizeof(SsaRegister)));
    *result = self->reg_counter++;
    self->instructions.data[index + 0] = ins_type;
    *(SsaRegister*)&self->instructions.data[index + 1] = *result;
    *(SsaRegister*)&self->instructions.data[index + 3] = lhs;
    *(SsaRegister*)&self->instructions.data[index + 5] = rhs;
    amal_log_debug("r%u = r%u + r%u", *result, lhs, rhs);
    return 0;
}

int ssa_ins_assign_inter(Ssa *self, SsaRegister dest, SsaNumber number) {
    SsaIntermediateIndex index;
    return_if_error(ssa_try_add_intermediate(self, number.value, number.type, &index));
    amal_log_debug("r%u = i%u", dest, index);
    return ssa_add_ins_form1(self, SSA_ASSIGN_INTER, dest, index);
}

int ssa_ins_assign_reg(Ssa *self, SsaRegister dest, SsaRegister src) {
    amal_log_debug("r%u = r%u", dest, src);
    return ssa_add_ins_form1(self, SSA_ASSIGN_INTER, dest, src);
}

int ssa_ins_binop(Ssa *self, SsaInstructionType binop_type, SsaRegister lhs, SsaRegister rhs, SsaRegister *result) {
    assert(binop_type >= SSA_ADD && binop_type <= SSA_DIV);
    return ssa_add_ins_form2(self, binop_type, lhs, rhs, result);
}

int ssa_ins_func_start(Ssa *self, u8 num_args, SsaFuncIndex *result) {
    usize index;
    index = self->instructions.size;

    /* Overflow */
    if(self->func_counter + 1 < self->func_counter)
        return -1;

    return_if_error(buffer_append(&self->instructions, NULL, sizeof(u8) + sizeof(SsaFuncIndex) + sizeof(u8)));
    *result = self->func_counter++;
    self->instructions.data[index + 0] = SSA_FUNC_START;
    *(SsaFuncIndex*)&self->instructions.data[index + 1] = *result;
    self->instructions.data[index + 3] = num_args;
    amal_log_debug("FUNC_START f%u(%u)", *result, num_args);
    return 0;
}

int ssa_ins_func_end(Ssa *self) {
    SsaInstructionType ins;
    ins = SSA_FUNC_END;
    return buffer_append(&self->instructions, &ins, 1);
}

int ssa_ins_push(Ssa *self, SsaRegister reg) {
    usize index;
    index = self->instructions.size;

    return_if_error(buffer_append(&self->instructions, NULL, sizeof(u8) + sizeof(SsaRegister)));
    self->instructions.data[index + 0] = SSA_PUSH;
    *(SsaRegister*)&self->instructions.data[index + 1] = reg;
    amal_log_debug("PUSH r%u", reg);
    return 0;
}

int ssa_ins_call(Ssa *self, SsaFuncIndex func, SsaRegister *result) {
    usize index;
    index = self->instructions.size;

    /* Overflow */
    if(self->reg_counter + 1 < self->reg_counter)
        return -1;

    return_if_error(buffer_append(&self->instructions, NULL, sizeof(u8) + sizeof(SsaFuncIndex) + sizeof(SsaRegister)));
    *result = self->reg_counter++;
    self->instructions.data[index + 0] = SSA_CALL;
    *(SsaFuncIndex*)&self->instructions.data[index + 1] = func;
    *(SsaRegister*)&self->instructions.data[index + 3] = *result;
    amal_log_debug("r%u = CALL f%u", *result, func);
    return 0;
}