Gwion coverage report


Directory: src/
File: src/import/import_prim.c
Date: 2023-01-30 18:32:28
Exec Total Coverage
Lines: 136 164 82.9%
Functions: 16 20 80.0%
Branches: 33 50 66.0%

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, &section);
228 return GW_OK;
229 }
230