Line | Branch | Exec | Source |
---|---|---|---|
1 | #include <limits.h> | ||
2 | #include "gwion_util.h" | ||
3 | #include "gwion_ast.h" | ||
4 | #include "gwion_env.h" | ||
5 | #include "vm.h" | ||
6 | #include "instr.h" | ||
7 | #include "emit.h" | ||
8 | #include "gwion.h" | ||
9 | #include "object.h" | ||
10 | #include "operator.h" | ||
11 | #include "import.h" | ||
12 | #include "gwi.h" | ||
13 | #include "array.h" | ||
14 | #include "gack.h" | ||
15 | #include "traverse.h" | ||
16 | |||
17 | 1 | static GACK(gack_prim) { | |
18 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
|
2 | for(m_uint i = 0; i < t->actual_size; i++) { |
19 | 1 | const m_bit *value = VALUE + i; | |
20 |
2/2✓ Branch 0 taken 8 times.
✓ Branch 1 taken 1 times.
|
9 | for(unsigned char mask = 1U << (CHAR_BIT-1); mask; mask >>= 1) |
21 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 7 times.
|
8 | INTERP_PRINTF("%c", *(uint8_t*)value & mask ? '1' : '0'); |
22 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if(i < t->actual_size - 1) |
23 | ✗ | INTERP_PRINTF(" "); | |
24 | } | ||
25 | 1 | } | |
26 | |||
27 | 1 | static INSTR(bit_set) { | |
28 | 1 | POP_REG(shred, SZ_INT); | |
29 | 1 | const m_int offset = *(m_int*)REG(0); | |
30 | 1 | const m_uint byte = offset / CHAR_BIT; | |
31 | 1 | const m_uint idx = offset % CHAR_BIT; | |
32 | 1 | uint8_t *val = *(uint8_t**)REG(-SZ_INT); | |
33 | 1 | val += byte; | |
34 | 1 | const m_int key = *(m_int*)REG(-SZ_INT*2); | |
35 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | if(key) *val = ((1 << idx) | (*val)); |
36 | ✗ | else **(m_bit**)REG(-SZ_INT) = ((*val) & (~(1 << (idx)))); | |
37 | 1 | *(m_bit**)REG(-SZ_INT) = REG(0); | |
38 | 1 | } | |
39 | |||
40 | 1 | static INSTR(bit_set_fast) { | |
41 | 1 | uint8_t *val = *(uint8_t**)REG(-SZ_INT); | |
42 | 1 | val += instr->m_val; | |
43 | 1 | const m_uint idx = instr->m_val2; | |
44 | 1 | const m_int key = *(m_int*)REG(-SZ_INT*2); | |
45 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | if(key) *val = ((1 << idx) | (*val)); |
46 | ✗ | else **(m_bit**)REG(-SZ_INT) = ((*val) & (~(1 << (idx)))); | |
47 | 1 | *(m_bit**)REG(-SZ_INT) = REG(0); | |
48 | 1 | } | |
49 | |||
50 | 3 | static INSTR(bit_check) { | |
51 | 3 | const m_int offset = *(m_int*)REG(-SZ_INT); | |
52 |
3/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 2 times.
|
3 | if(offset < 0 || offset >= (m_int)instr->m_val) |
53 | 1 | handle(shred, "OutOfBoundByteAccess"); | |
54 | 3 | } | |
55 | |||
56 | 2 | ANN static bool _bit_get(const uint8_t val, const m_uint idx) { | |
57 | 2 | const int mask = 1 << idx; | |
58 | 2 | const int masked_n = val & mask; | |
59 | 2 | return masked_n >> idx; | |
60 | } | ||
61 | |||
62 | 1 | static INSTR(bit_get) { | |
63 | 1 | POP_REG(shred, instr->m_val); | |
64 | 1 | const m_int offset = *(m_int*)REG(0); | |
65 | 1 | const m_uint byte = offset / CHAR_BIT; | |
66 | 1 | const uint8_t val = *(uint8_t*)REG(byte - SZ_INT); | |
67 | 1 | *(m_int*)REG(-SZ_INT) = _bit_get(val, offset % CHAR_BIT); | |
68 | 1 | } | |
69 | |||
70 | 1 | static INSTR(bit_get_fast) { | |
71 | 1 | const uint8_t val = *(uint8_t*)REG((int16_t)instr->udata.two); | |
72 | 1 | *(m_int*)REG(-instr->m_val) = _bit_get(val, instr->udata.one); | |
73 | 1 | } | |
74 | |||
75 | 5 | static OP_EMIT(opem_bit_access) { | |
76 | 5 | struct ArrayAccessInfo *const info = (struct ArrayAccessInfo *)data; | |
77 |
2/2✓ Branch 1 taken 3 times.
✓ Branch 2 taken 2 times.
|
5 | if(!is_prim_int(info->array.exp)) { |
78 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
|
3 | CHECK_BB(emit_exp(emit, info->array.exp)); |
79 | 3 | const Instr check = emit_add_instr(emit, bit_check); | |
80 | 3 | check->m_val = info->array.type->actual_size * CHAR_BIT; | |
81 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
|
3 | if(!info->is_var) { |
82 | 2 | const Instr instr = emit_add_instr(emit, bit_get); | |
83 | 2 | instr->m_val = info->array.type->size; | |
84 | 1 | } else emit_add_instr(emit, bit_set); | |
85 | } else { | ||
86 | 2 | const m_uint offset = info->array.exp->d.prim.d.num; | |
87 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
|
2 | if(!info->is_var) { |
88 | 1 | const Instr instr = emit_add_instr(emit, bit_get_fast); | |
89 | 1 | instr->m_val = info->type->size; | |
90 | 1 | instr->udata.one = offset % CHAR_BIT; | |
91 | 1 | instr->udata.two = (m_int)((offset / CHAR_BIT) - SZ_INT); | |
92 | } else { | ||
93 | 1 | const Instr instr = emit_add_instr(emit, bit_set_fast); | |
94 | 1 | instr->m_val2 = offset % CHAR_BIT; | |
95 | 1 | instr->m_val = (offset / CHAR_BIT); | |
96 | } | ||
97 | } | ||
98 | 5 | return GW_OK; | |
99 | } | ||
100 | |||
101 | 5 | static OP_EMIT(opem_bit_exp) { | |
102 | 5 | bool *var = data; | |
103 | 5 | var[1] = var[0]; | |
104 | 5 | return GW_OK; | |
105 | } | ||
106 | |||
107 | 7 | static OP_CHECK(opck_bit_access) { | |
108 | 7 | Array_Sub array = data; | |
109 | 7 | const Exp e = array->exp; | |
110 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 6 times.
|
7 | if(e->next) ERR_N(e->next->pos, "too many expressions for bit access"); |
111 |
2/2✓ Branch 1 taken 3 times.
✓ Branch 2 taken 3 times.
|
6 | if(is_prim_int(e)) { |
112 | 3 | m_int idx = e->d.prim.d.num; | |
113 |
3/4✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
|
3 | if(idx < 0 || idx >= (m_int)array->type->size * CHAR_BIT) |
114 | 1 | ERR_N(e->pos, "bit access out of bound"); | |
115 | } | ||
116 | 5 | return env->gwion->type[et_bool]; | |
117 | } | ||
118 | |||
119 | 2552 | ANN static void scan_prim_op(const Env env, const Type t){ | |
120 | 2552 | struct Op_Func opfunc = { .ck = opck_bit_access, .em = opem_bit_access }; | |
121 | 2552 | struct Op_Import opi = { | |
122 | 2552 | .op = insert_symbol(env->gwion->st, "[]"), | |
123 | 2552 | .lhs = env->gwion->type[et_int], | |
124 | .rhs = t, | ||
125 | .func = &opfunc | ||
126 | }; | ||
127 | 2552 | add_op(env->gwion, &opi); | |
128 | 2552 | } | |
129 | |||
130 | 2552 | ANN static void scan_prim_op2(const Env env, const Type t){ | |
131 | 2552 | struct Op_Func opfunc = {.em = opem_bit_exp }; | |
132 | 2552 | struct Op_Import opi = { | |
133 | 2552 | .op = insert_symbol(env->gwion->st, "@array_init"), | |
134 | .lhs = t, | ||
135 | 2552 | .ret = env->gwion->type[et_bool], | |
136 | .func = &opfunc | ||
137 | }; | ||
138 | 2552 | add_op(env->gwion, &opi); | |
139 | 2552 | } | |
140 | |||
141 | ✗ | static INSTR(bitset) { | |
142 | ✗ | POP_REG(shred, SZ_INT); | |
143 | ✗ | memcpy(*(uint8_t**)REG(0), REG(-SZ_INT), instr->m_val); | |
144 | } | ||
145 | |||
146 | ✗ | static OP_EMIT(opem_bitset) { | |
147 | ✗ | Exp_Binary *bin = data; | |
148 | ✗ | const Instr instr = emit_add_instr(emit, bitset); | |
149 | ✗ | const Type t = isa(bin->rhs->type, emit->gwion->type[et_int]) > 0 | |
150 | ✗ | ? bin->lhs->type | |
151 | ✗ | : bin->rhs->type; | |
152 | ✗ | instr->m_val = t->actual_size; | |
153 | ✗ | return GW_OK; | |
154 | } | ||
155 | |||
156 | ✗ | static INSTR(bitcast) { | |
157 | ✗ | memset(REG((m_int)instr->m_val), 0, instr->m_val2); | |
158 | } | ||
159 | |||
160 | ✗ | static OP_EMIT(opem_bitcast) { | |
161 | ✗ | Exp_Cast *cast = data; | |
162 | ✗ | const Type t = isa(cast->exp->type, emit->gwion->type[et_int]) > 0 | |
163 | ✗ | ? known_type(emit->env, cast->td) | |
164 | ✗ | : cast->exp->type; | |
165 | ✗ | const Instr instr = emit_add_instr(emit, bitcast); | |
166 | ✗ | instr->m_val = -SZ_INT + t->actual_size; | |
167 | ✗ | instr->m_val2 = SZ_INT - t->actual_size; | |
168 | ✗ | return GW_OK; | |
169 | } | ||
170 | |||
171 | 5104 | ANN2(1,2,3,5) static void prim_op(const Env env, const Type t, const m_str op, const opck ck, const opem em){ | |
172 | 5104 | struct Op_Func opfunc = { .ck = ck, .em = em }; | |
173 | 5104 | struct Op_Import opi = { | |
174 | 5104 | .op = insert_symbol(env->gwion->st, op), | |
175 | 5104 | .lhs = env->gwion->type[et_int], | |
176 | .rhs = t, | ||
177 | .ret = t, | ||
178 | .func = &opfunc | ||
179 | }; | ||
180 | 5104 | add_op(env->gwion, &opi); | |
181 | 5104 | opi.lhs = t; | |
182 | 5104 | opi.rhs = opi.ret = env->gwion->type[et_int]; | |
183 | 5104 | add_op(env->gwion, &opi); | |
184 | 5104 | } | |
185 | |||
186 | 2552 | ANN static void prim_implicit(const Env env, const Type t){ | |
187 | 2552 | struct Op_Import opi = { | |
188 | 2552 | .op = insert_symbol(env->gwion->st, "@implicit"), | |
189 | .lhs = t, | ||
190 | 2552 | .rhs = env->gwion->type[et_int], | |
191 | 2552 | .ret = env->gwion->type[et_int], | |
192 | }; | ||
193 | 2552 | add_op(env->gwion, &opi); | |
194 | 2552 | } | |
195 | |||
196 | 2552 | ANN Type mk_primitive(const Env env, const m_str name, const m_uint size) { | |
197 | 2552 | m_uint sz = SZ_INT; | |
198 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2552 times.
|
2552 | while(sz < size) sz += SZ_INT; |
199 | 2552 | const Type t = new_type(env->gwion->mp, name, NULL); | |
200 | 2552 | t->size = sz; | |
201 | 2552 | t->actual_size = size; | |
202 | 2552 | scan_prim_op(env, t); | |
203 | 2552 | scan_prim_op2(env, t); | |
204 |
2/2✓ Branch 0 taken 1914 times.
✓ Branch 1 taken 638 times.
|
2552 | if(size < SZ_INT) { |
205 | 1914 | prim_op(env, t, ":=>", opck_rassign, opem_bitset); | |
206 | 1914 | prim_op(env, t, "$", NULL, opem_bitcast); | |
207 | 1914 | prim_implicit(env, t); | |
208 |
1/2✓ Branch 0 taken 638 times.
✗ Branch 1 not taken.
|
638 | } else if(size == SZ_INT) { |
209 | 638 | prim_op(env, t, ":=>", opck_rassign, (opem)dummy_func); | |
210 | 638 | prim_op(env, t, "$", NULL, (opem)dummy_func); | |
211 | 638 | prim_implicit(env, t); | |
212 | } // else provide function to get slices | ||
213 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 2552 times.
|
2552 | CHECK_BO(mk_gack(env->gwion->mp, t, gack_prim)); |
214 | 2552 | return t; | |
215 | } | ||
216 | |||
217 | 2552 | ANN m_bool gwi_primitive(const Gwi gwi, const m_str name, const m_uint size, const ae_flag flag) { | |
218 | 2552 | const Env env = gwi->gwion->env; | |
219 | 2552 | const Prim_Def pdef = new_prim_def(gwi->gwion->mp, insert_symbol(gwi->gwion->st, name), size, gwi->loc, flag); | |
220 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2552 times.
|
2552 | if(gwi->gwion->data->cdoc)gwfmt_prim_def(gwi->gwfmt, pdef); |
221 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 2552 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
|
2552 | if(!env->class_def || !tflag(env->class_def, tflag_tmpl)) { |
222 | 2552 | const m_bool ret = scan0_prim_def(gwi->gwion->env, pdef); | |
223 | 2552 | free_prim_def(gwi->gwion->mp, pdef); | |
224 | 2552 | return ret; | |
225 | } | ||
226 | ✗ | Section section = MK_SECTION(primitive, prim_def, pdef); | |
227 | ✗ | gwi_body(gwi, §ion); | |
228 | ✗ | return GW_OK; | |
229 | } | ||
230 |