-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathop_code.h
136 lines (117 loc) · 3.28 KB
/
op_code.h
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
#pragma once
#include <cassert>
#include <cstdint>
/*
TODO:
x = 1 <= 2 && 3 != 4
With short circuit:
if (!(1 <= 2)) { JMP :false }
if (!(3 != 4)) { JMP :false }
PUSHC 1
JMP :done
:false
PUSHC 0
:done
->
PUSHC 2
PUSHC 1
CMPLE
JMP0 :false
PUSHC 4
PUSHC 3
CMPNE
JMP0 :false
PUSHC 1
JMP :done
:false
PUSHC 0
:done
x = 1 <= 2 || 3 != 4
With short circuit:
if (1 <= 2) { JMP :true }
if (3 != 4) { JMP :true }
PUSHC 0
JMP :done
:true
PUSHC 1
:done
->
PUSHC 2
PUSHC 1
CMPLE
JMP1 :true
PUSHC 4
PUSHC 3
CMPNE
JMP0 :true
PUSHC 0
JMP :done
:true
PUSHC 0
:done
*/
enum OpCode : uint8_t
{
// Memory operations
PUSHC, // value = read i64; push i64 value;
LOADR, // offs = read i64; push i64 *(RSP + offs);
LOAD, // addr = read i64; push i64 *addr;
STORER, // offs = read i64; value = pop i64; *(RSP + offs) = value;
ADDRSP, // offs = read i64; RSP += offs
// Integer arithmetic operations
ADD, // a = pop i64; b = pop i64; push i64 a + b
SUB, // a = pop i64; b = pop i64; push i64 a - b
MUL, // a = pop i64; b = pop i64; push i64 a * b
DIV, // a = pop i64; b = pop i64; push i64 a / b
MOD, // a = pop i64; b = pop i64; push i64 a % b
BITAND, // a = pop i64; b = pop i64; push i64 a & b
BITOR, // a = pop i64; b = pop i64; push i64 a | b
BITXOR, // a = pop i64; b = pop i64; push i64 a ^ b
LSH, // a = pop i64; b = pop i64; push i64 a << b
RSH, // a = pop i64; b = pop i64; push i64 a >> b
// (Conditional) jumping
CMPEQ, // dst = read i64; a = pop i64; b = pop i64; push a == b ? 1 : 0;
CMPNE, // dst = read i64; a = pop i64; b = pop i64; push a != b ? 1 : 0;
CMPLT, // dst = read i64; a = pop i64; b = pop i64; push a < b ? 1 : 0;
CMPLE, // dst = read i64; a = pop i64; b = pop i64; push a <= b ? 1 : 0;
CMPGT, // dst = read i64; a = pop i64; b = pop i64; push a > b ? 1 : 0;
CMPGE, // dst = read i64; a = pop i64; b = pop i64; push a >= b ? 1 : 0;
JMP0, // dst = read i64; a = pop i64; if a == 0 jmp dst;
JMP1, // dst = read i64; a = pop i64; if a != 0 jmp dst;
JMP, // dst = read i64; jmp dst;
CALL, // TODO: Make a version of this instruction with the target address baked in statically
RET, // value = pop i64; ret = pop i64; push i64 value; jmp ret;
};
inline const char *to_string(OpCode op)
{
switch (op)
{
case PUSHC: return "PUSHC";
case LOADR: return "LOADR";
case LOAD: return "LOAD";
case STORER: return "STORER";
case ADDRSP: return "ADDRSP";
case ADD: return "ADD";
case SUB: return "SUB";
case MUL: return "MUL";
case DIV: return "DIV";
case MOD: return "MOD";
case BITAND: return "BITAND";
case BITOR: return "BITOR";
case BITXOR: return "BITXOR";
case LSH: return "LSH";
case RSH: return "RSH";
case CMPEQ: return "CMPEQ";
case CMPNE: return "CMPNE";
case CMPLT: return "CMPLT";
case CMPLE: return "CMPLE";
case CMPGT: return "CMPGT";
case CMPGE: return "CMPGE";
case JMP0: return "JMP0";
case JMP1: return "JMP1";
case JMP: return "JMP";
case CALL: return "CALL";
case RET: return "RET";
}
assert(false);
};