diff options
Diffstat (limited to 'erts/emulator/beam/emu/generators.tab')
-rw-r--r-- | erts/emulator/beam/emu/generators.tab | 160 |
1 files changed, 160 insertions, 0 deletions
diff --git a/erts/emulator/beam/emu/generators.tab b/erts/emulator/beam/emu/generators.tab index f9988f2399..397ddb97e7 100644 --- a/erts/emulator/beam/emu/generators.tab +++ b/erts/emulator/beam/emu/generators.tab @@ -831,3 +831,163 @@ gen.init_yregs(N, Yregs) { $INIT_YREGS(S, N.val); return first; } + +gen.create_bin(Fail, Alloc, Live, Unit, Dst, N, Segments) { + BeamOp* op; + int fixed_args; + BeamOpArg* src; + BeamOpArg* dst; + BeamOpArg* endp; + + endp = Segments + N.val; + N.val = 5*N.val/6; + + $NewBeamOp(S, op); + $BeamOpNameArity(op, i_bs_create_bin, 5); + fixed_args = op->arity; + $BeamOpArity(op, (N.val + fixed_args)); + + op->a[0] = Fail; + op->a[1] = Alloc; + op->a[2] = Live; + op->a[3] = Dst; + op->a[4] = N; + + for (src = Segments, dst = op->a+fixed_args; src < endp; src += 6, dst += 5) { + UWord unit; + BeamOpArg Flags; + Uint flags = 0; + BeamOpArg Size; + Uint type; + Uint segment; + + ASSERT(src[0].type = TAG_a); + ASSERT(src[1].type == TAG_u); + ASSERT(src[2].type == TAG_u); + segment = src[1].val; + + /* Get unit. */ + dst[1] = src[2]; + unit = dst[1].val; + + /* Translate flags. */ + Flags = src[3]; /* Flags */ + if (Flags.type != TAG_n) { + if (Flags.type == TAG_q) { + Eterm term = beamfile_get_literal(&S->beam, Flags.val); + while (is_list(term)) { + Eterm* consp = list_val(term); + Eterm elem = CAR(consp); + switch (elem) { + case am_little: + flags |= BSF_LITTLE; + break; + case am_native: + flags |= BSF_NATIVE; + break; + } + term = CDR(consp); + } + ASSERT(is_nil(term)); + } + } + Flags.type = TAG_u; + Flags.val = flags; + $NativeEndian(Flags); + Flags.val = (segment << 3) | Flags.val; + dst[2] = Flags; + + /* Store source. */ + dst[3] = src[4]; /* Src */ + + /* Get size */ + Size = src[5]; /* Size */ + + /* Translate type. */ + switch (src[0].val) { + case am_append: + type = BSC_APPEND; + break; + case am_private_append: + type = BSC_PRIVATE_APPEND; + break; + case am_binary: + { + UWord bits; + type = BSC_BINARY; + if (Size.type == TAG_a && Size.val == am_all) { + type = BSC_BINARY_ALL; + } else if (Size.type == TAG_i && + (Sint) Size.val >= 0 && + beam_load_safe_mul(Size.val, unit, &bits) && + (bits >> (sizeof(Uint)-1)*8) == 0) { + type = BSC_BINARY_FIXED_SIZE; + Size.type = TAG_u; + Size.val = bits; + unit = 0; + } + } + break; + case am_float: + { + UWord bits; + type = BSC_FLOAT; + if (Size.type == TAG_i && + (Sint) Size.val >= 0 && + beam_load_safe_mul(Size.val, unit, &bits) && + (bits >> (sizeof(Uint)-1)*8) == 0) { + type = BSC_FLOAT_FIXED_SIZE; + Size.type = TAG_u; + Size.val = bits; + unit = 0; + } + } + break; + case am_integer: + { + UWord bits; + type = BSC_INTEGER; + if (Size.type == TAG_i && + (Sint) Size.val >= 0 && + beam_load_safe_mul(Size.val, unit, &bits) && + (bits >> (sizeof(Uint)-1)*8) == 0) { + type = BSC_INTEGER_FIXED_SIZE; + Size.type = TAG_u; + Size.val = bits; + unit = 0; + } + } + break; + case am_string: + type = BSC_STRING; + ASSERT(Size.type == TAG_i); + ASSERT(unit == 8); + Size.type = TAG_u; + Size.val = Size.val; /* Size of string in bytes. */ + unit = 0; + break; + case am_utf8: + type = BSC_UTF8; + break; + case am_utf16: + type = BSC_UTF16; + break; + case am_utf32: + type = BSC_UTF32; + Size.type = TAG_u; + Size.val = 32; + break; + default: + abort(); + } + dst[0].type = TAG_u; + dst[0].val = type; + + /* Store value of unit. */ + dst[1].val = unit; + + /* Store size. */ + dst[4] = Size; + } + return op; +} |