| 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 |