Generated Documentation

Contents

Generated Documentation#

namespace mizu#

Typedefs

using reg_t = uint16_t#
using instruction_t = void *(*)(struct opcode *pc, uint64_t *registers, struct registers_and_stack *env, uint8_t *sp)#

Function pointer type representing the interface every instruction is expected to have

Functions

constexpr reg_t x(std::size_t i)#

Generic register lookup

Parameters:

i – The register’s index

Returns:

constexpr reg_t associated value to store in an opcode

constexpr reg_t t(std::size_t i)#

Temporary register lookup

Parameters:

i – The temporary register’s index

Returns:

constexpr reg_t associated value to store in an opcode

constexpr reg_t a(std::size_t i)#

Argument register lookup

Parameters:

i – The argument register’s index

Returns:

constexpr reg_t associated value to store in an opcode

inline fp::dynarray<std::byte> to_portable(fp::view<const opcode> program, fp::view<std::byte> data = {nullptr, 0})#

Converts a Mizu program and some data into a portable program that can executed anywhere

Note

This function makes no account of different machine endianness or pointer sizes.

Parameters:
  • program – The program to serialize

  • data – The data to put at the bottom of the program’s stack

Returns:

fp::dynarray<std::byte> a dynamically allocated array of bytes representing the serialized program

inline fp::dynarray<std::byte> to_portable(fp::view<const opcode> program, registers_and_stack &env)#

Converts a Mizu program and an env into a snapshot of a portable program that can executed anywhere

Note

This function makes no account of different machine endianness or pointer sizes.

Parameters:
  • program – The program to snapshot

  • env – The program enviornment to snapshot

Returns:

fp::dynarray<std::byte> a dynamically allocated array of bytes representing the serialized program

inline std::pair<fp::dynarray<opcode>, registers_and_stack> from_portable(fp::view<const std::byte> binary)#

Converts a blob of binary data storing a portable Mizu program and stack data back into a Mizu program.

Note

This function makes no account of different machine endianness or pointer sizes.

Parameters:

binary – The binary blob to deserialize

Returns:

std::pair<fp::dynarray<opcode>, registers_and_stack> a dynamically allocated Mizu program and its enviornment

inline fp::string generate_header_file(fp::view<opcode> program, registers_and_stack &env, fp::string_view extra_includes = fp::string_view::from_cstr(""))#

Generates a C++ header file representing the provided Mizu program and env.

Parameters:
  • program – The program to generate a header for.

  • env – The enviornment the program should begin executing in.

  • extra_includes – If the program requires extra instruction headers (like SIMD or custom) they should be listed (one per line, including the #include) here

Returns:

fp::string a string storing the resulting headerfile.

inline fp::dynarray<std::byte> to_binary(fp::view<const opcode> _program)#

Converts a Mizu program into a byte array ready to be written to a file or sent over the network.

Note

This function makes no account of different machine endianness or pointer sizes.

Parameters:

program – The program to serialize

Returns:

fp::dynarray<std::byte> a dynamically allocated array of bytes representing the serialized program

inline fp::dynarray<opcode> from_binary(fp::view<const std::byte> binary)#

Converts a blob of binary data into a Mizu program

Note

This function makes no account of different machine endianness or pointer sizes.

Parameters:

binary – The binary blob to deserialize

Returns:

fp::dynarray<opcode> a dynamically allocated Mizu program

constexpr uint32_t label2immediate(const fp_string_view label)#

Converts a string label to an immediate value

Note

Only the first 4 characters of the label are relevant.

Parameters:

label – string_view to be converted

Returns:

constexpr uint32_t the immediate

constexpr uint32_t label2immediate(const fp_string label)#

Converts a string label to an immediate value

Note

Only the first 4 characters of the label are relevant.

Parameters:

label – string to be converted

Returns:

constexpr uint32_t the immediate

void *label(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Noop which marks a label that can be found using mizu::find_label and then jumped to using mizu::jump_to

Note

mizu::label2int can convert a string into an immediate for this function

Parameters:

immediate – Integer label value

void *find_label(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Finds the provided label and stores a pointer to it in out

Note

Unlike every other assembly this is a runtime function, time is spent scanning the program to find the label. It is this recommended to cluster these instructions near the beginning of the program where they won’t be executed multiple times.

Note

This function first searches below it in the program then searches above it if the label can’t be found. The closest matching label following these rules will be found if there is any ambiguity.

Parameters:
  • out – register to store the label pointer in

  • immediate – the label to search for

void *halt(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Ends execution of the program or thread.

void *debug_print(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Prints the value stored in a register in several formats

Parameters:

a – the register to print the value of

void *debug_print_binary(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Prints the value stored in a register in several formats including binary

Parameters:

a – the register to print the value of

void *load_immediate(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Stores an immediate value into a register

Note

Since immediate are only 32bit numbers this function sets the bottom 32 bits of our 64 bit registers.

Parameters:
  • out – the register to update

  • immediate – the value to store in out

void *load_upper_immediate(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Stores an immediate value into a register shifting it so that its content fills the upper 32bits.

Warning

The load immediate instruction overwrites the entire register, thus it should be called before load_upper_immediate!

Parameters:
  • out – the register to update

  • immediate – the value to store in out

void *convert_to_u64(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Converts a register to a 64 bit integer.

Parameters:
  • out – register to store the result in

  • a – register whose value to convert

void *convert_to_u32(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Converts a register to a 32 bit integer.

Parameters:
  • out – register to store the result in

  • a – register whose value to convert

void *convert_to_u16(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Converts a register to a 16 bit integer.

Parameters:
  • out – register to store the result in

  • a – register whose value to convert

void *convert_to_u8(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Converts a register to an 8 bit integer.

Parameters:
  • out – register to store the result in

  • a – register whose value to convert

void *stack_load_u64(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Loads a 64 bit integer from the stack

Parameters:
  • out – register to store the result in

  • a – register storing an offset to the current stack pointer (defaults to zero bytes)

void *stack_store_u64(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Copies a 64 bit integer from a register to the stack.

Parameters:
  • out – register to store another copy in

  • a – register storing the value to copy

  • b – register storing an offset to the current stack pointer (defaults to zero bytes)

void *stack_load_u32(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Loads a 32 bit integer from the stack

Parameters:
  • out – register to store the result in

  • a – register storing an offset to the current stack pointer (defaults to zero bytes)

void *stack_store_u32(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Copies a 32 bit integer from a register to the stack.

Parameters:
  • out – register to store another copy in

  • a – register storing the value to copy

  • b – register storing an offset to the current stack pointer (defaults to zero bytes)

void *stack_load_u16(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Loads a 16 bit integer from the stack

Parameters:
  • out – register to store the result in

  • a – register storing an offset to the current stack pointer (defaults to zero bytes)

void *stack_store_u16(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Copies a 16 bit integer from a register to the stack.

Parameters:
  • out – register to store another copy in

  • a – register storing the value to copy

  • b – register storing an offset to the current stack pointer (defaults to zero bytes)

void *stack_load_u8(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Loads an 8 bit integer from the stack

Parameters:
  • out – register to store the result in

  • a – register storing an offset to the current stack pointer (defaults to zero bytes)

void *stack_store_u8(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Copies a 8 bit integer from a register to the stack.

Parameters:
  • out – register to store another copy in

  • a – register storing the value to copy

  • b – register storing an offset to the current stack pointer (defaults to zero bytes)

void *stack_push(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Subtracts a value from the stack pointer. In other words reserves some additional memory on the stack.

Parameters:

a – register storing how many bytes to reserve

void *stack_push_immediate(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Subtracts a value from the stack pointer. In other words reserves some additional memory on the stack.

Parameters:

immediate – how many bytes to reserve

void *stack_pop(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Adds a value to stack pointer. In other words releases reserved memory on the stack.

Parameters:

a – register storing how many bytes to release

void *stack_pop_immediate(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Adds a value to stack pointer. In other words releases reserved memory on the stack.

Parameters:

immediate – how many bytes to release

void *offset_of_stack_bottom(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Returns the offset needed to load/store to the bottom of the stack

Parameters:
  • out – register to store the calculated offset in

  • a – register storing a signed offset relative to the bottom of the stack

void *jump_relative(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Moves the program counter by an offset. If the offset is zero this instruction is executed again. If it is one the next instruction is executed as usual. If it is negative a previous instruction is executed.

Note

a is interpreted as a signed integer, allowing for negative jumps

Parameters:
  • out – register to store the address of the instruction that should be executed next.

  • a – register storing how many instructions to jump

void *jump_relative_immediate(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Moves the program counter by an offset. If the offset is zero this instruction is executed again. If it is one the next instruction is executed as usual. If it is negative a previous instruction is executed.

Note

immediate is interpreted as a signed integer, allowing for negative jumps

Parameters:
  • out – register to store the address of the instruction that should be executed next.

  • immediate – how many instructions to jump

void *jump_to(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Sets the program counter to a value (usually the output of another jump)

Parameters:
  • out – register to store the address of the instruction that should be executed next.

  • a – register storing the address of the instruction to jump to.

void *branch_relative(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Moves the program counter by an offset similar to a jump, however only does so if the condition register is not zero

Note

b is interpreted as a signed integer, allowing for negative jumps

Parameters:
  • out – register to store the address of the instruction that should be executed next.

  • a – register storing a condition, zero indicates no jump while any other number indicates that a jump should occur

  • b – register storing how many instructions to jump

void *branch_relative_immediate(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Moves the program counter by an offset similar to a jump, however only does so if the condition register is not zero

Note

b is interpreted as a signed integer, allowing for negative jumps

Parameters:
  • out – register to store the address of the instruction that should be executed next.

  • a – register storing a condition, zero indicates no jump while any other number indicates that a jump should occur

  • b – (branch immediate) how many instructions to jump

void *branch_to(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Sets the program counter to a value (usually the output of another jump), however only does so if the condition register is not zero

Parameters:
  • out – register to store the address of the instruction that should be executed next.

  • a – register storing a condition, zero indicates no jump while any other number indicates that a jump should occur

  • b – register storing the address of the instruction to jump to.

void *set_if_equal(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Checks if two registers are equal

Parameters:
  • out – register to be set to one if a == b or zero otherwise

  • a – register storing the first value to compare

  • b – register storing the second value to compare

void *set_if_not_equal(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Checks if two registers are not equal

Parameters:
  • out – register to be set to one if a != b or zero otherwise

  • a – register storing the first value to compare

  • b – register storing the second value to compare

void *set_if_less(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Checks if a register is less than another

Parameters:
  • out – register to be set to one if a < b or zero otherwise

  • a – register storing the first value to compare

  • b – register storing the second value to compare

void *set_if_less_signed(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Checks if a register is less than another

Note

Both a and b are treated as being signed

Parameters:
  • out – register to be set to one if a == b or zero otherwise

  • a – register storing the first value to compare

  • b – register storing the second value to compare

void *set_if_greater_equal(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Checks if a register is greater or equal to another

Parameters:
  • out – register to be set to one if a >= b or zero otherwise

  • a – register storing the first value to compare

  • b – register storing the second value to compare

void *set_if_greater_equal_signed(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Checks if a register is greater or equal to another

Note

Both a and b are treated as being signed

Parameters:
  • out – register to be set to one if a >= b or zero otherwise

  • a – register storing the first value to compare

  • b – register storing the second value to compare

void *add(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Adds two numbers

Parameters:
  • out – register to store a + b in

  • a – register storing first value

  • b – register storing second value

void *subtract(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Subtracts two numbers

Parameters:
  • out – register to store a - b in

  • a – register storing first value

  • b – register storing second value

void *multiply(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Multiplies two numbers

Parameters:
  • out – register to store a * b in

  • a – register storing first value

  • b – register storing second value

void *divide(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Divides two numbers

Parameters:
  • out – register to store a / b in

  • a – register storing first value

  • b – register storing second value

void *modulus(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Finds the remainder of the division of two numbers

Parameters:
  • out – register to store a % b in

  • a – register storing first value

  • b – register storing second value

void *shift_left(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Shifts one number left by another

Parameters:
  • out – register to store a << b in

  • a – register storing first value

  • b – register storing second value

void *shift_right_logical(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Shifts one number right by another

Parameters:
  • out – register to store a >> b in

  • a – register storing first value

  • b – register storing second value

void *shift_right_arithmetic(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Shifts one number right by another, sign extending it

Parameters:
  • out – register to store a >> b in

  • a – register storing first value

  • b – register storing second value

void *bitwise_xor(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Xor’s two numbers

Parameters:
  • out – register to store a ^ b in

  • a – register storing first value

  • b – register storing second value

void *bitwise_and(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

And’s two numbers

Parameters:
  • out – register to store a & b in

  • a – register storing first value

  • b – register storing second value

void *bitwise_or(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Or’s two numbers

Parameters:
  • out – register to store a | b in

  • a – register storing first value

  • b – register storing second value

template<std::floating_point F>
inline F &float_register(uint64_t *registers, uint16_t index)#
void *convert_to_f32(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Converts the provided register into a float register

Parameters:
  • out – Register to store the result of the conversion in

  • a – Register to convert to an f32

void *convert_signed_to_f32(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Converts the provided (signed) register into a float register

Parameters:
  • out – Register to store the result of the conversion in

  • a – Register to convert to an f32

void *convert_from_f32(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Truncates the provided float register and stores it in the given register (as an unsigned number)

Parameters:
  • out – Register to store the result of the conversion in

  • a – Float register to convert to a u64

void *convert_signed_from_f32(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Truncates the provided float register and stores it in the given register

Parameters:
  • out – Register to store the result of the conversion in

  • a – Float register to convert to an i64

void *add_f32(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Adds two f32 numbers

Note

Both a and b must be f32s. If they aren’t they should be converted first

Parameters:
  • out – register to store a + b in

  • a – register storing first value

  • b – register storing second value

void *subtract_f32(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Subtracts two f32 numbers

Note

Both a and b must be f32s. If they aren’t they should be converted first

Parameters:
  • out – register to store a - b in

  • a – register storing first value

  • b – register storing second value

void *multiply_f32(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Multiplies two f32 numbers

Note

Both a and b must be f32s. If they aren’t they should be converted first

Parameters:
  • out – register to store a * b in

  • a – register storing first value

  • b – register storing second value

void *divide_f32(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Divides two f32 numbers

Note

Both a and b must be f32s. If they aren’t they should be converted first

Parameters:
  • out – register to store a / b in

  • a – register storing first value

  • b – register storing second value

void *max_f32(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Finds the max of two f32 numbers

Note

Both a and b must be f32s. If they aren’t they should be converted first

Parameters:
  • out – register to store max( a, b ) in

  • a – register storing first value

  • b – register storing second value

void *min_f32(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Finds the min of two f32 numbers

Note

Both a and b must be f32s. If they aren’t they should be converted first

Parameters:
  • out – register to store min( a, b ) in

  • a – register storing first value

  • b – register storing second value

void *sqrt_f32(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Finds the square root of a f32 number

Parameters:
  • out – register to store sqrt( a ) in

  • a – register storing the value

void *set_if_equal_f32(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Checks if two f32 registers are equal

Note

Both a and b must be f32s. If they aren’t they should be converted first

Parameters:
  • out – register to be set to one if a == b or zero otherwise

  • a – register storing the first value to compare

  • b – register storing the second value to compare

void *set_if_not_equal_f32(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Checks if two f32 registers are not equal

Note

Both a and b must be f32s. If they aren’t they should be converted first

Parameters:
  • out – register to be set to one if a != b or zero otherwise

  • a – register storing the first value to compare

  • b – register storing the second value to compare

void *set_if_less_f32(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Checks if one f32 register is less than another

Note

Both a and b must be f32s. If they aren’t they should be converted first

Parameters:
  • out – register to be set to one if a < b or zero otherwise

  • a – register storing the first value to compare

  • b – register storing the second value to compare

void *set_if_greater_equal_f32(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Checks if one f32 register is greater or equal to another

Note

Both a and b must be f32s. If they aren’t they should be converted first

Parameters:
  • out – register to be set to one if a >= b or zero otherwise

  • a – register storing the first value to compare

  • b – register storing the second value to compare

void *set_if_negative_f32(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Checks if a f32 register is negative

Parameters:
  • out – register to be set to one if a < 0 or zero otherwise

  • a – register storing the value to compare

void *set_if_positive_f32(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Checks if a f32 register is positive

Parameters:
  • out – register to be set to one if a > 0 or zero otherwise

  • a – register storing the value to compare

void *set_if_infinity_f32(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Checks if a f32 register is an infinity

Parameters:
  • out – register to be set to one if a == +/- infinity or zero otherwise

  • a – register storing the value to compare

void *set_if_nan_f32(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Checks if a f32 register is nan

Parameters:
  • out – register to be set to one if a == nan or zero otherwise

  • a – register storing the value to compare

void *convert_f32_to_f64(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Converts the provided f32 register to an f64 register

Parameters:
  • out – Register to store the f64 result in

  • a – Register storing the f32 to convert

void *convert_f64_to_f32(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Converts the provided f64 register to an f32 register

Parameters:
  • out – Register to store the f32 result in

  • a – Register storing the f64 to convert

void *convert_to_f64(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Converts the provided register into a float register

Parameters:
  • out – Register to store the result of the conversion in

  • a – Register to convert to an f64

void *convert_signed_to_f64(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Converts the provided (signed) register into a float register

Parameters:
  • out – Register to store the result of the conversion in

  • a – Register to convert to an f64

void *convert_from_f64(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Truncates the provided float register and stores it in the given register (as an unsigned number)

Parameters:
  • out – Register to store the result of the conversion in

  • a – Float register to convert to a u64

void *convert_signed_from_f64(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Truncates the provided float register and stores it in the given register

Parameters:
  • out – Register to store the result of the conversion in

  • a – Float register to convert to an i64

void *add_f64(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Adds two f64 numbers

Note

Both a and b must be f64s. If they aren’t they should be converted first

Parameters:
  • out – register to store a + b in

  • a – register storing first value

  • b – register storing second value

void *subtract_f64(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Subtracts two f64 numbers

Note

Both a and b must be f64s. If they aren’t they should be converted first

Parameters:
  • out – register to store a - b in

  • a – register storing first value

  • b – register storing second value

void *multiply_f64(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Multiplies two f64 numbers

Note

Both a and b must be f64s. If they aren’t they should be converted first

Parameters:
  • out – register to store a * b in

  • a – register storing first value

  • b – register storing second value

void *divide_f64(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Divides two f64 numbers

Note

Both a and b must be f64s. If they aren’t they should be converted first

Parameters:
  • out – register to store a / b in

  • a – register storing first value

  • b – register storing second value

void *max_f64(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Finds the max of two f64 numbers

Note

Both a and b must be f64s. If they aren’t they should be converted first

Parameters:
  • out – register to store max( a, b ) in

  • a – register storing first value

  • b – register storing second value

void *min_f64(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Finds the min of two f64 numbers

Note

Both a and b must be f64s. If they aren’t they should be converted first

Parameters:
  • out – register to store min( a, b ) in

  • a – register storing first value

  • b – register storing second value

void *sqrt_f64(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Finds the square root of a f64 number

Parameters:
  • out – register to store sqrt( a ) in

  • a – register storing the value

void *set_if_equal_f64(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Checks if two f64 registers are equal

Note

Both a and b must be f64s. If they aren’t they should be converted first

Parameters:
  • out – register to be set to one if a == b or zero otherwise

  • a – register storing the first value to compare

  • b – register storing the second value to compare

void *set_if_not_equal_f64(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Checks if two f64 registers are not equal

Note

Both a and b must be f64s. If they aren’t they should be converted first

Parameters:
  • out – register to be set to one if a != b or zero otherwise

  • a – register storing the first value to compare

  • b – register storing the second value to compare

void *set_if_less_f64(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Checks if one f64 register is less than another

Note

Both a and b must be f64s. If they aren’t they should be converted first

Parameters:
  • out – register to be set to one if a < b or zero otherwise

  • a – register storing the first value to compare

  • b – register storing the second value to compare

void *set_if_greater_equal_f64(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Checks if one f64 register is greater or equal to another

Note

Both a and b must be f64s. If they aren’t they should be converted first

Parameters:
  • out – register to be set to one if a >= b or zero otherwise

  • a – register storing the first value to compare

  • b – register storing the second value to compare

void *set_if_negative_f64(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Checks if a f64 register is negative

Parameters:
  • out – register to be set to one if a < 0 or zero otherwise

  • a – register storing the value to compare

void *set_if_positive_f64(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Checks if a f64 register is positive

Parameters:
  • out – register to be set to one if a > 0 or zero otherwise

  • a – register storing the value to compare

void *set_if_infinity_f64(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Checks if a f64 register is an infinity

Parameters:
  • out – register to be set to one if a == +/- infinity or zero otherwise

  • a – register storing the value to compare

void *set_if_nan_f64(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Checks if a f64 register is nan

Parameters:
  • out – register to be set to one if a == nan or zero otherwise

  • a – register storing the value to compare

inline uint64_t new_thread(opcode *pc, registers_and_stack *env, uint8_t *sp)#
inline void delay(std::chrono::microseconds time, opcode *&pc, uint64_t &storage_register)#
void *fork_relative(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Forks a new thread moving its program counter by an offset relative to the current thread’s program counter. If the offset is zero this instruction is executed again. If it is one the next instruction is executed as usual. If it is negative a previous instruction is executed.

Note

A new set of registers (copied from the current thread) are created for the new thread.

Note

a is interpreted as a signed integer, allowing for negative jumps

Parameters:
  • out – register to store the thread reference in

  • a – register storing how many instructions to jump

void *fork_relative_immediate(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Forks a new thread moving its program counter by an offset relative to the current thread’s program counter. If the offset is zero this instruction is executed again. If it is one the next instruction is executed as usual. If it is negative a previous instruction is executed.

Note

A new set of registers (copied from the current thread) are created for the new thread.

Note

immediate is interpreted as a signed integer, allowing for negative jumps

Parameters:
  • out – register to store the thread reference in

  • immediate – how many instructions to jump

void *fork_to(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Forks a new thread with its program counter set to a value (usually the output of another jump)

Note

A new set of registers (copied from the current thread) are created for the new thread.

Parameters:
  • out – register to store the thread reference in

  • a – register storing the address of the instruction to jump to.

void *join_thread(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Waits for the provided thread to finish and frees its reference

Parameters:
  • a – Register storing the thread to wait for

  • b – Register storing a value to overwrite a with (defaults to zero)

void *sleep_microseconds(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Sleeps the provided number of micro seconds

Parameters:

a – Register storing the number of microseconds to sleep

void *channel_create(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Creates an inter-thread communication channel. This channel can keep a buffer of values or a single value.

Note

Channels send and receive register sized binary blobs.

Parameters:
  • out – Register to store the channel reference in

  • a – Register storing the capacity of the channel buffer (defaults to a single item)

void *channel_close(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Closes the provided channel and frees its reference

Parameters:
  • a – Register storing the channel to free

  • b – Register storing a value to overwrite a with (defaults to zero)

void *channel_receive(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Blocks the current thread until there is an item to receive from the channel.

Parameters:
  • out – Register to store the binary blob read from the channel in.

  • a – Register storing the channel to read from.

void *channel_send(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Blocks the current thread until the channel has room to receive a new value.

Parameters:
  • a – Register storing the channel to send a message to

  • b – Register storing the binary blob to send to the channel.

void *mutex_create(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Creates a read/write lockable mutex

Parameters:

out – Register to store the mutex reference in

void *mutex_free(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Frees a mutex.

Parameters:
  • a – Register storing the mutex to free.

  • b – Register storing a value to overwrite a with (defaults to zero)

void *mutex_write_lock(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Blocks the current thread until an exclusive (writing) lock can be taken on the mutex

Parameters:

a – Register storing the mutex to lock.

void *mutex_try_write_lock(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Attemps to take an exclusive (writing) lock on the mutex

Parameters:
  • out – Register to store weather (1) or not (0) the lock was successfully taken in

  • a – Register storing the mutex to lock.

void *mutex_write_unlock(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Releases an exclusive (writing) lock on a mutex so that another thread can lock it.

Parameters:

a – Register storing the mutex to unlock.

void *mutex_read_lock(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Blocks the current thread until a shared (reading) lock can be taken on the mutex

Note

any number of threads can take a reading lock at the same time, but only one thread can have a writing lock.

Parameters:

a – Register storing the mutex to lock.

void *mutex_try_read_lock(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Attemps to take an shared (reading) lock on the mutex

Note

any number of threads can take a reading lock at the same time, but only one thread can have a writing lock.

Parameters:
  • out – Register to store weather (1) or not (0) the lock was successfully taken in

  • a – Register storing the mutex to lock.

void *mutex_read_unlock(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Releases a shared (reading) lock on a mutex so that another thread can lock it.

Parameters:

a – Register storing the mutex to unlock.

Variables

static constexpr reg_t zero = x(0)#
static constexpr reg_t return_address = x(21)#
static constexpr reg_t ra = return_address#
static constexpr size_t memory_size = 1024 * MIZU_STACK_SIZE / sizeof(uint64_t)#

How many registers long the memory space is.

Note

set using the MIZU_STACK_SIZE (measured in kilobytes) config option.

static constexpr size_t memory_size_bytes = memory_size * sizeof(uint64_t)#

How many bytes the memory space is.

Note

set using the MIZU_STACK_SIZE (measured in kilobytes) config option.

constexpr auto program_end = nullptr#
struct opcode#
#include <opcode.hpp>

Type which holds an instruction and (upto) 3 registers for it to act upon.

Note

Since instruction_t is a pointer, this struct will have different sizes on different machines. Thus Mizu binaries are only compatible with machines of the same pointer size and endianness.

struct registers_and_stack#
#include <opcode.hpp>

Type representing holding the registers and stack space for a Mizu program or thread.

struct serialization_opcode#
#include <serialize.hpp>

A version of the opcode which has fixed sizes for serialization purposes.

namespace debug#

Functions

void *breakpoint(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Noop which can be used to add breakpoints into code

namespace instructions#
namespace detail#

Typedefs

using id_t = size_t#

Functions

inline id_t register_instruction(std::string_view name, mizu::instruction_t ptr)#

Variables

std::unordered_map<std::string_view, id_t> reverse_name_lookup#
std::unordered_map<mizu::instruction_t, id_t> reverse_function_lookup#
std::unordered_map<id_t, std::pair<std::string_view, mizu::instruction_t>> lookup#
namespace ffi#

Functions

template<bool has_return>
void *call_impl(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#
void *push_type_void(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Adds void to the current type stack.

void *push_type_pointer(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Adds void* to the current type stack.

void *push_type_i32(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Adds int32_t to the current type stack.

void *push_type_u32(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Adds uint32_t to the current type stack.

void *push_type_i64(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Adds int64_t to the current type stack.

void *push_type_u64(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Adds uint64_t to the current type stack.

void *push_type_f32(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Adds float to the current type stack.

void *push_type_f64(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Adds double to the current type stack.

void *clear_type_stack(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Clears the current type stack.

void *create_interface(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Converts the current type stack into a interface that tells the ffi subsystem what the types of each argument are.

Note

The first type on the stack is interpreted as the return type, any types after that are parameters (that one return type is required! Use push_type_void to indicate no return.)

Parameters:

out – Register to store the resulting interface in

void *free_interface(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Frees the provided interface and overwrites it with the value in b (defaults to zero)

Parameters:
  • a – Register storing the interface to free.

  • b – Register storing the value to overwrite a with (defaults to zero)

void *call(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Calls an ffi function, the functions arguments are expected to be in the argument registers (a0, a1, etc…)

Parameters:
  • a – Register storing a pointer to the function to call.

  • b – Register storing the interface defining how the function’s arguments should be interpreted.

void *call_with_return(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Calls an ffi function with a returned value, the functions arguments are expected to be in the argument registers (a0, a1, etc…)

Parameters:
  • out – Register storing

  • a – Register storing a pointer to the function to call.

  • b – Register storing the interface defining how the function’s arguments should be interpreted.

void *load_library(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Loads a DLL (or platform equivalent) with the provided path.

Note

most platforms will search some set of library path for the given path

Parameters:
  • out – Register to store the resulting library pointer in

  • a – Register storing a null-terminated c-string pointer representing the path to search for the library.

void *load_first_library_that_exists(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Expects a list of null terminated c-string library paths in the first immediate argument registers. Tries to load each library and stores a pointer to the first to load in out

Parameters:
  • out – Register to store the resulting library in.

  • immediate – number of argument (a0, a1, etc…) registers storing paths to search

void *load_library_function(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Loads a function pointer from a library.

Parameters:
  • out – Register to store the resulting function pointer in

  • a – Register storing a pointer to the library to load the function from.

  • b – Register storing a null-terminated c-string pointer representing the (mangled) name of the function to load.

namespace instructions#
namespace wasm#

Typedefs

using variant = std::variant<std::monostate, int64_t, double, int32_t, float>#

Enums

enum class types#

Values:

enumerator Void#
enumerator I64#
enumerator F64#
enumerator I32#
enumerator F32#
namespace instructions#
namespace loader#

Functions

inline library *load_shared(std::string_view path, bool append_platform_decorator = false)#
inline library *load_dynamic(std::string_view path, bool append_platform_decorator = false)#
inline library *load_library(std::string_view path, bool append_platform_decorator = false)#
inline library *load_first_that_exists(fp::view<const std::string_view> paths, bool append_platform_decorator = false)#
inline library *load_current_executable()#
inline void *lookup(std::string_view name, library *lib = nullptr)#
inline void close(library *lib)#
struct error : public std::runtime_error#
namespace portable#
namespace registers#

  • x0 (zero) is always zero

  • x1-x20 (t0-t19) are temporary registers which are expected to be saved by the caller if necessary

  • x21 (ra) is the return address (callee saved)

  • x22-x256 (a0-a234) are the argument registers (callee saved)

Note

x22/a0 and x23/a1 are the canonical return registers

Functions

constexpr reg_t x(std::size_t i)#

Generic register lookup

Parameters:

i – The register’s index

Returns:

constexpr reg_t associated value to store in an opcode

constexpr reg_t t(std::size_t i)#

Temporary register lookup

Parameters:

i – The temporary register’s index

Returns:

constexpr reg_t associated value to store in an opcode

constexpr reg_t a(std::size_t i)#

Argument register lookup

Parameters:

i – The argument register’s index

Returns:

constexpr reg_t associated value to store in an opcode

Variables

static constexpr reg_t zero = x(0)#
static constexpr reg_t return_address = x(21)#
static constexpr reg_t ra = return_address#
namespace serialization#
struct serialization_opcode#
#include <serialize.hpp>

A version of the opcode which has fixed sizes for serialization purposes.

namespace unsafe#

Functions

void *allocate(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Allocates new memory on the host application heap.

Parameters:
  • out – Register in which a pointer to the allocated memory will be stored

  • a – Register storing how many bytes to allocate

void *free_allocated(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Frees an allocation alloacted with allocate.

Parameters:
  • a – Register storing the allocation to free

  • b – Register storing a value to overwrite a with (defaults to zero)

void *allocate_fat_pointer(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Allocates new memory on the host application heap. This memory knows how many element are stored in it.

Note

The total size of this allocation is a * b

Parameters:
  • out – Register in which a pointer to the allocated memory will be stored

  • a – Register storing the size of each element

  • b – Register storing how many elements there are

void *free_fat_pointer(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Frees an allocation alloacted with allocate_fat_pointer.

Parameters:
  • a – Register storing the allocation to free

  • b – Register storing a value to overwrite a with (defaults to zero)

void *pointer_to_stack(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Generates a pointer to memory on Mizu’s stack.

Parameters:
  • out – Register to store the pointer in

  • a – Register storing a (signed) offset from the current stack pointer.

void *pointer_to_stack_bottom(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Generates a pointer to memory on the bottom of Mizu’s stack.

Parameters:
  • out – Register to store the pointer in

  • a – Register storing a (signed) offset from the current stack pointer.

void *pointer_to_register(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Generates a pointer to one of Mizu’s registers

Parameters:
  • a – Register to take a pointer to.

  • out – Register to store the pointer in

void *copy_memory(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Copies memory from one pointer to another

Parameters:
  • out – Register storing a pointer that data should be copied to

  • a – Register storing a pointer that data should be copied from

  • b – Register storing how many bytes should be copied.

void *copy_memory_immediate(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Copies memory from one pointer to another

Parameters:
  • out – Register storing a pointer that data should be copied to

  • a – Register storing a pointer that data should be copied from

  • b – (branch immediate) number of bytes that should be copied

void *set_memory(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Sets all of the given memory to the provided byte

Parameters:
  • out – Register storing a pointer to what should be overwritten

  • a – Register storing a u8 to overwrite out with

  • b – Register storing how many bytes should be overwritten

void *set_memory_immediate(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)#

Sets all of the given memory to the provided byte

Parameters:
  • out – Register storing a pointer to what should be overwritten

  • a – Register storing a u8 to overwrite out with

  • b – (branch immediate) how many bytes should be overwritten

namespace instructions#

Indices and tables#