~maelkum/viuavm

f46df6a89c22f6992614198faef30b686fc04e65 — Marek Marecki 13 days ago 34975a9 devel
Use F format for FLOAT instruction

There is no reason to go through .rodata if the 32-bit float fits into
the immediate field of an F format instruction.
M new/include/viua/arch/ins.h => new/include/viua/arch/ins.h +6 -6
@@ 240,12 240,6 @@ struct STRING : Instruction {
    STRING(viua::arch::ops::S i) : instruction{i}
    {}
};
struct FLOAT : Instruction {
    viua::arch::ops::S instruction;

    FLOAT(viua::arch::ops::S i) : instruction{i}
    {}
};
struct DOUBLE : Instruction {
    viua::arch::ops::S instruction;



@@ 277,6 271,12 @@ struct LLI : Instruction {
    LLI(viua::arch::ops::F i) : instruction{i}
    {}
};
struct FLOAT : Instruction {
    viua::arch::ops::F instruction;

    FLOAT(viua::arch::ops::F i) : instruction{i}
    {}
};

struct CAST : Instruction {
    viua::arch::ops::E instruction;

M new/include/viua/arch/ops.h => new/include/viua/arch/ops.h +7 -7
@@ 269,13 269,13 @@ enum class OPCODE : opcode_type {
    FRAME  = (FORMAT_S | 0x0001),
    RETURN = (FORMAT_S | 0x0002),
    ATOM   = (FORMAT_S | 0x0003),
    FLOAT  = (FORMAT_S | 0x0004),
    DOUBLE = (FORMAT_S | 0x0005),
    SELF   = (FORMAT_S | 0x0006),
    DOUBLE = (FORMAT_S | 0x0004),
    SELF   = (FORMAT_S | 0x0005),

    LUI  = (FORMAT_F | 0x0001),
    LUIU = (FORMAT_F | 0x0001 | UNSIGNED),
    LLI  = (FORMAT_F | 0x0002),
    LUI   = (FORMAT_F | 0x0001),
    LUIU  = (FORMAT_F | 0x0001 | UNSIGNED),
    LLI   = (FORMAT_F | 0x0002),
    FLOAT = (FORMAT_F | 0x0003),

    CAST  = (FORMAT_E | 0x0001),
    ARODP = (FORMAT_E | 0x0002),


@@ 345,7 345,6 @@ enum class OPCODE_S : opcode_type {
    Make_entry(FRAME),
    Make_entry(RETURN),
    Make_entry(ATOM),
    Make_entry(FLOAT),
    Make_entry(DOUBLE),
    Make_entry(SELF),
};


@@ 353,6 352,7 @@ enum class OPCODE_F : opcode_type {
    Make_entry(LUI),
    Make_entry(LUIU),
    Make_entry(LLI),
    Make_entry(FLOAT),
};
enum class OPCODE_E : opcode_type {
    Make_entry(CAST),

M new/src/arch/ops.cpp => new/src/arch/ops.cpp +12 -3
@@ 17,6 17,8 @@
 *  along with Viua VM.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <string.h>

#include <stdexcept>
#include <string>
#include <string_view>


@@ 116,20 118,27 @@ auto F::decode(instruction_type const raw) -> F
    auto opcode =
        static_cast<viua::arch::opcode_type>(raw & 0x000000000000ffff);
    auto out   = Register_access::decode((raw & 0x00000000ffff0000) >> 16);
    auto value = static_cast<uint32_t>(raw >> 32);
    auto value = le32toh(static_cast<uint32_t>(raw >> 32));
    return F{opcode, out, value};
}
auto F::encode() const -> instruction_type
{
    auto base            = uint64_t{opcode};
    auto output_register = uint64_t{out.encode()};
    auto value           = uint64_t{immediate};
    auto value           = uint64_t{htole32(immediate)};
    return base | (output_register << 16) | (value << 32);
}
auto F::to_string() const -> std::string
{
    auto imm_str = std::to_string(immediate);
    using viua::arch::ops::OPCODE;
    if (static_cast<OPCODE>(opcode) == OPCODE::FLOAT) {
        auto tmp = float{};
        memcpy(&tmp, &immediate, sizeof(immediate));
        imm_str = std::to_string(tmp);
    }
    return (viua::arch::ops::to_string(opcode) + " " + out.to_string() + ", "
            + std::to_string(immediate));
            + imm_str);
}
}  // namespace viua::arch::ops
namespace viua::arch::ops {

M new/src/tools/exec/dis.cpp => new/src/tools/exec/dis.cpp +0 -13
@@ 245,19 245,6 @@ auto demangle_symbol_load(Cooked_text& raw,
        ++i;
        return;
    }
    if (m(i + 1, FLOAT) and S::decode(ins_at(i + 1)).out == out) {
        auto ins = raw.at(i + 1);
        cooked.pop_back();

        auto const sv = view_data(rodata, immediate);
        auto x        = float{};
        memcpy(&x, sv.data(), sizeof(x));

        cooked.emplace_back(ins.with_text(
            ("float " + out.to_string() + ", " + std::to_string(x))));
        ++i;
        return;
    }
    if (m(i + 1, DOUBLE) and S::decode(ins_at(i + 1)).out == out) {
        auto ins = raw.at(i + 1);
        cooked.pop_back();

M new/src/tools/libs/stage.cpp => new/src/tools/libs/stage.cpp +10 -28
@@ 675,28 675,6 @@ auto cook_long_immediates(viua::libs::parser::ast::Instruction insn,
            std::to_string(saved_at) + 'u';

        cooked.push_back(synth);
    } else if (insn.opcode == "float" or insn.opcode == "g.float") {
        constexpr auto SIZE_OF_SINGLE_PRECISION_FLOAT = size_t{4};
        auto f = std::stof(insn.operands.back().ingredients.front().text);
        auto s = std::string(SIZE_OF_SINGLE_PRECISION_FLOAT, '\0');
        memcpy(s.data(), &f, SIZE_OF_SINGLE_PRECISION_FLOAT);
        auto const saved_at = save_buffer_to_rodata(rodata_buf, s);

        auto synth = viua::libs::parser::ast::Instruction{};
        {
            synth.opcode         = insn.opcode;
            synth.opcode.text    = "g.li";
            synth.physical_index = insn.physical_index;

            synth.operands.push_back(insn.operands.front());
            synth.operands.push_back(insn.operands.back());
            synth.operands.back().ingredients.front().text =
                std::to_string(saved_at) + 'u';
        }
        expand_li(cooked, synth, true);

        insn.operands.pop_back();
        cooked.push_back(std::move(insn));
    } else if (insn.opcode == "double" or insn.opcode == "g.double") {
        constexpr auto SIZE_OF_DOUBLE_PRECISION_FLOAT = size_t{8};
        auto f = std::stod(insn.operands.back().ingredients.front().text);


@@ 1352,6 1330,7 @@ auto emit_instruction(viua::libs::parser::ast::Instruction const insn)
{
    using viua::arch::opcode_type;
    using viua::arch::ops::FORMAT;
    using viua::arch::ops::OPCODE;
    using viua::arch::ops::FORMAT_MASK;

    auto opcode = opcode_type{};


@@ 1384,14 1363,17 @@ auto emit_instruction(viua::libs::parser::ast::Instruction const insn)
                                  operand_or_throw(insn, 0).make_access()}
            .encode();
    case FORMAT::F:
    {
        auto const raw = operand_or_throw(insn, 1).ingredients.front().text;
        auto val       = static_cast<uint32_t>(std::stoul(raw, nullptr, 0));
        if (static_cast<OPCODE>(opcode) == OPCODE::FLOAT) {
            auto tmp = std::stof(raw);
            memcpy(&val, &tmp, sizeof(val));
        }
        return viua::arch::ops::F{
            opcode,
            operand_or_throw(insn, 0).make_access(),
            static_cast<uint32_t>(
                std::stoul(operand_or_throw(insn, 1).ingredients.front().text,
                           nullptr,
                           0))}
            opcode, operand_or_throw(insn, 0).make_access(), val}
            .encode();
    }
    case FORMAT::E:
        return viua::arch::ops::E{
            opcode,

M new/src/vm/ins.cpp => new/src/vm/ins.cpp +5 -20
@@ 118,7 118,6 @@ auto execute(viua::vm::Stack& stack,
            Work(FRAME);
            Flow(RETURN);
            Work(ATOM);
            Work(FLOAT);
            Work(DOUBLE);
            Work(SELF);
#undef Work


@@ 143,6 142,7 @@ auto execute(viua::vm::Stack& stack,
            Work(LUI);
            Work(LUIU);
            Work(LLI);
            Work(FLOAT);
#undef Work
        }
        break;


@@ 1148,30 1148,15 @@ auto execute(ARODP const op, Stack& stack, ip_type const) -> void

auto execute(FLOAT const op, Stack& stack, ip_type const) -> void
{
    auto target = mutable_proxy(stack, op.instruction.out);

    auto const& strtab = *stack.proc->strtab;

    auto const data_offset = target.get<uint64_t>();
    if (not data_offset.has_value()) {
        throw abort_execution{stack, "invalid operand"};
    }

    auto const data_size = [&strtab, data_offset]() -> uint64_t {
        auto const size_offset = (*data_offset - sizeof(uint64_t));
        auto tmp               = uint64_t{};
        memcpy(&tmp, &strtab[size_offset], sizeof(uint64_t));
        return le64toh(tmp);
    }();
    auto out = mutable_proxy(stack, op.instruction.out);

    auto tmp = uint32_t{};
    memcpy(&tmp, (&strtab[0] + *data_offset), data_size);
    tmp = le32toh(tmp);
    memcpy(&tmp, &op.instruction.immediate, sizeof(tmp));

    auto v = float{};
    memcpy(&v, &tmp, data_size);
    memcpy(&v, &tmp, sizeof(v));

    target = v;
    out = v;
}
auto execute(DOUBLE const op, Stack& stack, ip_type const) -> void
{