aboutsummaryrefslogtreecommitdiff
path: root/vm/src/vm.h
blob: 03dfc88c5f8e6d5171a0f95f2fea2e53a7c2a53b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
#pragma once

#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>

typedef enum Op {
  Exit, // Pop value from the stack and return as exit code. Return 0 if the
        // stack is empty.
  Push,
  Pop,
  Add,
  Sub,
  Mul,
  Div,
  Dec,   // Decrement the top of the stack by 1.
  Empty, // Check whether the stack is empty. Pushes a bool.
  Cmp,   // Pop the top of the stack and compare it with the payload. Pushes a
         // bool.
  /* Blocks */
  End,   // Marks the end of a block.
  Break, // Exit the current block.
  Loop,  // Push a loop block. Payload (i32): label.
  /* Branches */
  Br, // Branch. Payload (i64): [(i32) conditional? | (i32) label].
      // A condtional branch pops a bool from the stack and branches if true.
      // The condition can also be negated. See br_if().
  /* Functions */
  Func,
  Arg,
  Call,
  /* Locals */
  Local,   // Create a local variable.
  LocalRd, // Load a local variable into the top of the stack.
  LocalWr, // Pop the top of the stack and store it in a local variable.
} Op;

typedef enum Type {
  I32,
  F32,
} Type;

// Label type for blocks and locals.
typedef uint32_t Label;

typedef struct Branch {
  Label label;
  bool  conditional : 1; // True for conditional branches.
  bool  expected    : 1; // Comparison value for conditional branches.
} Branch;

typedef struct Function {
  Label label;
} Function;

typedef struct Value {
  union {
    uint64_t u64;
    int32_t  i32;
    float    f32;
    Branch   branch;
    Label    label;
  };
} Value;

typedef struct Inst {
  Op    op   : 5;
  Type  type : 2;
  Value payload;
} Inst;

typedef struct Vm Vm;

// -----------------------------------------------------------------------------
// VM API

/// Create a new virtual machine.
Vm* vm_new();

/// Destroy the virtual machine.
void vm_del(Vm**);

/// Execute code on the virtual machine.
///
/// Returns the program exit code if an exit operation is executed, 0 otherwise.
int vm_run(Vm*, const Inst[], size_t count);

/// Prints the virtual machine's stack to stdout.
void vm_print_stack(const Vm*);

// -----------------------------------------------------------------------------
// Programming API

/// Exit the program.
static inline Inst vmExit() { return (Inst){.op = Exit}; }

/// Push a value.
static inline Inst vmPushI32(int32_t value) {
  return (Inst){.op = Push, .type = I32, .payload = (Value){.i32 = value}};
}

/// Pop a value.
static inline Inst vmPop(Type type) { return (Inst){.op = Pop, .type = type}; }

/// Add two values.
static inline Inst vmAdd(Type type) { return (Inst){.op = Add, .type = type}; }

/// Decrement a value.
static inline Inst vmDec(Type type) { return (Inst){.op = Dec, .type = type}; }

/// Compare a value.
static inline Inst vmCmpI32(int32_t value) {
  return (Inst){.op = Cmp, .type = I32, .payload = (Value){.i32 = value}};
}

/// End the current block.
static inline Inst vmEnd() { return (Inst){.op = End}; }

/// Create a loop.
static inline Inst vmLoop(Label label) {
  return (Inst){.op = Loop, .payload = (Value){.label = label}};
}

/// Create the payload of a conditional branch.
static inline Inst vmBr_if(bool value, Label label) {
  return (Inst){
      .op      = Br,
      .payload = (Value){
          .branch = {
              .label       = label,
              .conditional = 1,
              .expected    = value,
          }}};
}

/// Create a function.
static inline Inst vmFunc(Label label) {
  return (Inst){.op = Func, .payload = (Value){.label = label}};
}

/// Create a function argument.
static inline Inst vmArg(Type type, Label label) {
  return (Inst){.op = Arg, .type = type, .payload = (Value){.label = label}};
}

/// Call a function.
static inline Inst vmCall(Label label) {
  return (Inst){.op = Call, .payload = (Value){.label = label}};
}

/// Create a local variable.
static inline Inst vmLocal(Type type, Label label) {
  return (Inst){.op = Local, .type = type, .payload = (Value){.label = label}};
}

/// Read a local variable.
static inline Inst vmLocalRd(Type type, Label label) {
  return (Inst){
      .op = LocalRd, .type = type, .payload = (Value){.label = label}};
}

/// Write a local variable.
static inline Inst vmLocalWr(Type type, Label label) {
  return (Inst){
      .op = LocalWr, .type = type, .payload = (Value){.label = label}};
}