Reduct  v1.0.4-3-gdaf0d70
A functional and immutable language.
Loading...
Searching...
No Matches
inst.h
Go to the documentation of this file.
1#ifndef REDUCT_INST_H
2#define REDUCT_INST_H 1
3
4#include "defs.h"
5
6/**
7 * @file inst.h
8 * @brief Bytecode instruction format.
9 * @defgroup inst Instruction Format
10 *
11 * Instructions are 32-bit words
12 * with the following formats:
13 *
14 * - iABC: [ Opcode:6 | A:8 | B:8 | C:10 ]
15 * - iAsBx: [ Opcode:6 | A:8 | sBx:18 ]
16 *
17 * Fields:
18 * - A: Usually the target/destination register.
19 * - B: Usually the first operand (register).
20 * - C: Usually the second operand (register or constant).
21 * - sBx: Signed offsets for jumps.
22 *
23 * To determine if the C field is a register or a constant the `reduct_mode_t` flags are used to modify the opcode.
24 *
25 * @note The reason we avoid formats such as iABx, used within Lua, is that even if it increases the maximum constant
26 * capacity it means that operations such as `REDUCT_OPCODE_EQUAL` always need to act on registers, which introduces
27 * unnecessary `MOV` instructions to load constants into registers before they can be compared.
28 *
29 * @{
30 */
31
32/**
33 * @brief Opcode mode enumeration.
34 * @enum reduct_mode_t
35 */
36typedef enum
37{
38 REDUCT_MODE_NONE = -1, ///< Invalid mode.
39 REDUCT_MODE_TARGET = -2, ///< Compilation target hint mode.
40 REDUCT_MODE_REG = 0, ///< Register operand mode.
41 REDUCT_MODE_CONST = 1 << 5, ///< Constant operand mode.
43
44/**
45 * @brief Opcode enumeration.
46 * @enum reduct_opcode_t
47 */
48typedef enum
49{
51 REDUCT_OPCODE_LIST, ///< (A) Create a new list and store it in R(A).
52 REDUCT_OPCODE_JMP, ///< (sBx) Unconditional jump by relative offset sBx.
53 REDUCT_OPCODE_JMPF, ///< (A, sBx) Jump by sBx if R(A) is falsy.
54 REDUCT_OPCODE_JMPT, ///< (A, sBx) Jump by sBx if R(A) is truthy.
55 REDUCT_OPCODE_JEQ, ///< (A, C) Skip the next instruction if R(A) == R/K(C), else continue.
56 REDUCT_OPCODE_CALL, ///< (A, B, C) Call callable in R/K(C) with B args starting from R(A). Result in R(A).
57 REDUCT_OPCODE_MOV, ///< (A, C) Move value in R/K(C) to R(A).
58 REDUCT_OPCODE_RET, ///< (C) Return value in R/K(C).
59 REDUCT_OPCODE_APPEND, ///< (A, C) Append value in R/K(C) to the back of the list in R(A).
60 REDUCT_OPCODE_EQ, ///< (A, B, C) If R(B) == R/K(C) store true in R(A), else false.
61 REDUCT_OPCODE_NEQ, ///< (A, B, C) If R(B) != R/K(C) store true in R(A), else false.
62 REDUCT_OPCODE_SEQ, ///< (A, B, C) If R(B) === R/K(C) store true in R(A), else false.
63 REDUCT_OPCODE_SNEQ, ///< (A, B, C) If R(B) !== R/K(C) store true in R(A), else false.
64 REDUCT_OPCODE_LT, ///< (A, B, C) If R(B) < R/K(C) store true in R(A), else false.
65 REDUCT_OPCODE_LE, ///< (A, B, C) If R(B) <= R/K(C) store true in R(A), else false.
66 REDUCT_OPCODE_GT, ///< (A, B, C) If R(B) > R/K(C) store true in R(A), else false.
67 REDUCT_OPCODE_GE, ///< (A, B, C) If R(B) >= R/K(C) store true in R(A), else false.
68 REDUCT_OPCODE_ADD, ///< (A, B, C) R(A) = R(B) + R/K(C)
69 REDUCT_OPCODE_SUB, ///< (A, B, C) R(A) = R(B) - R/K(C)
70 REDUCT_OPCODE_MUL, ///< (A, B, C) R(A) = R(B) * R/K(C)
71 REDUCT_OPCODE_DIV, ///< (A, B, C) R(A) = R(B) / R/K(C)
72 REDUCT_OPCODE_MOD, ///< (A, B, C) R(A) = R(B) % R/K(C)
73 REDUCT_OPCODE_BAND, ///< (A, B, C) R(A) = R(B) & R/K(C)
74 REDUCT_OPCODE_BOR, ///< (A, B, C) R(A) = R(B) | R/K(C)
75 REDUCT_OPCODE_BXOR, ///< (A, B, C) R(A) = R(B) ^ R/K(C)
76 REDUCT_OPCODE_BNOT, ///< (A, C) R(A) = ~R/K(C)
77 REDUCT_OPCODE_SHL, ///< (A, B, C) R(A) = R(B) << R/K(C)
78 REDUCT_OPCODE_SHR, ///< (A, B, C) R(A) = R(B) >> R/K(C)
79 REDUCT_OPCODE_CLOSURE, ///< (A, C) Wrap the function prototype in K(C) in a closure and store in R(A).
80 REDUCT_OPCODE_CAPTURE, ///< (A, B, C) Capture R/K(C) into constant slot B in closure R(A).
81 REDUCT_OPCODE_TAILCALL, ///< (A, B, C) Tail call callable in R/K(C) with B args starting from R(A).
83
84/**
85 * @brief Register type.
86 */
88
89/**
90 * @brief Invalid register value.
91 */
92#define REDUCT_REG_INVALID ((reduct_reg_t) - 1)
93
94/**
95 * @brief Instruction type.
96 */
98
99#define REDUCT_INST_WIDTH_OPCODE 6ULL ///< Opcode width in bits.
100#define REDUCT_INST_WIDTH_A 8ULL ///< A operand width in bits.
101#define REDUCT_INST_WIDTH_B 8ULL ///< B operand width in bits.
102#define REDUCT_INST_WIDTH_C 10ULL ///< C operand width in bits.
103#define REDUCT_INST_WIDTH_SBX (REDUCT_INST_WIDTH_B + REDUCT_INST_WIDTH_C) ///< SBx operand width in bits.
104
105/**
106 * @brief The max number of registers per function frame.
107 */
108#define REDUCT_REGISTER_MAX (1ULL << REDUCT_INST_WIDTH_A)
109/**
110 * @brief The max number of constants per function.
111 */
112#define REDUCT_CONSTANT_MAX (1ULL << REDUCT_INST_WIDTH_C)
113
114#define REDUCT_INST_POS_OPCODE 0ULL ///< Opcode position in bits.
115#define REDUCT_INST_POS_A (REDUCT_INST_POS_OPCODE + REDUCT_INST_WIDTH_OPCODE) ///< A operand position in bits.
116#define REDUCT_INST_POS_B (REDUCT_INST_POS_A + REDUCT_INST_WIDTH_A) ///< B operand position in bits.
117#define REDUCT_INST_POS_C (REDUCT_INST_POS_B + REDUCT_INST_WIDTH_B) ///< C operand position in bits.
118
119#define REDUCT_INST_MASK_OPCODE ((1ULL << REDUCT_INST_WIDTH_OPCODE) - 1ULL) ///< Opcode mask.
120#define REDUCT_INST_MASK_A ((1ULL << REDUCT_INST_WIDTH_A) - 1ULL) ///< A operand mask.
121#define REDUCT_INST_MASK_B ((1ULL << REDUCT_INST_WIDTH_B) - 1ULL) ///< B operand mask.
122#define REDUCT_INST_MASK_C ((1ULL << REDUCT_INST_WIDTH_C) - 1ULL) ///< C operand mask.
123#define REDUCT_INST_MASK_SBX ((1ULL << REDUCT_INST_WIDTH_SBX) - 1ULL) ///< SBx operand mask.
124
125/**
126 * @brief Create an instruction with opcode, A, B, and C operands.
127 *
128 * @param _op Opcode operand.
129 * @param _a A operand.
130 * @param _b B operand.
131 * @param _c C operand.
132 */
133#define REDUCT_INST_MAKE_ABC(_op, _a, _b, _c) \
134 ((((reduct_inst_t)(_op)) & REDUCT_INST_MASK_OPCODE) << REDUCT_INST_POS_OPCODE | \
135 (((reduct_inst_t)(_a)) & REDUCT_INST_MASK_A) << REDUCT_INST_POS_A | \
136 (((reduct_inst_t)(_b)) & REDUCT_INST_MASK_B) << REDUCT_INST_POS_B | \
137 (((reduct_inst_t)(_c)) & REDUCT_INST_MASK_C) << REDUCT_INST_POS_C)
138
139/**
140 * @brief Create an instruction with opcode and A operands, and SBx B operand.
141 *
142 * @param _op Opcode operand.
143 * @param _a A operand.
144 * @param _sbx SBx operand.
145 */
146#define REDUCT_INST_MAKE_ASBX(_op, _a, _sbx) \
147 ((((reduct_inst_t)(_op)) & REDUCT_INST_MASK_OPCODE) << REDUCT_INST_POS_OPCODE | \
148 (((reduct_inst_t)(_a)) & REDUCT_INST_MASK_A) << REDUCT_INST_POS_A | \
149 (((reduct_inst_t)(_sbx)) & REDUCT_INST_MASK_SBX) << REDUCT_INST_POS_B)
150
151/**
152 * @brief Get the opcode from an instruction.
153 *
154 * @param _inst Instruction.
155 */
156#define REDUCT_INST_GET_OP(_inst) (((_inst) >> REDUCT_INST_POS_OPCODE) & REDUCT_INST_MASK_OPCODE)
157
158/**
159 * @brief Get the opcode base (without `reduct_mode_t`) from an instruction. Mask clears the `REDUCT_MODE_CONST` bit.
160 *
161 * @param _inst Instruction.
162 */
163#define REDUCT_INST_GET_OP_BASE(_inst) \
164 (((_inst) >> REDUCT_INST_POS_OPCODE) & (REDUCT_INST_MASK_OPCODE & ~REDUCT_MODE_CONST))
165
166/**
167 * @brief Get the A operand from an instruction.
168 *
169 * @param _inst Instruction.
170 */
171#define REDUCT_INST_GET_A(_inst) (((_inst) >> REDUCT_INST_POS_A) & REDUCT_INST_MASK_A)
172
173/**
174 * @brief Get the B operand from an instruction.
175 *
176 * @param _inst Instruction.
177 */
178#define REDUCT_INST_GET_B(_inst) (((_inst) >> REDUCT_INST_POS_B) & REDUCT_INST_MASK_B)
179
180/**
181 * @brief Get the C operand from an instruction.
182 *
183 * @param _inst Instruction.
184 */
185#define REDUCT_INST_GET_C(_inst) (((_inst) >> REDUCT_INST_POS_C) & REDUCT_INST_MASK_C)
186
187/**
188 * @brief Get the SBX operand from an instruction.
189 *
190 * @param _inst Instruction.
191 */
192#define REDUCT_INST_GET_SBX(_inst) \
193 ((reduct_int64_t)(((_inst) >> REDUCT_INST_POS_B) & REDUCT_INST_MASK_SBX) << (32ULL - REDUCT_INST_WIDTH_SBX) >> \
194 (32ULL - REDUCT_INST_WIDTH_SBX))
195
196/**
197 * @brief Set the A operand in an instruction.
198 *
199 * @param _inst Instruction.
200 * @param _a A operand value.
201 */
202#define REDUCT_INST_SET_A(_inst, _a) \
203 (((_inst) & ~(REDUCT_INST_MASK_A << REDUCT_INST_POS_A)) | (((_a) & REDUCT_INST_MASK_A) << REDUCT_INST_POS_A))
204
205/**
206 * @brief Set the SBX operand in an instruction.
207 *
208 * @param _inst Instruction.
209 * @param _sbx SBX operand value.
210 */
211#define REDUCT_INST_SET_SBX(_inst, _sbx) \
212 (((_inst) & ~(REDUCT_INST_MASK_SBX << REDUCT_INST_POS_B)) | (((_sbx) & REDUCT_INST_MASK_SBX) << REDUCT_INST_POS_B))
213
214#endif
uint32_t reduct_uint32_t
Definition defs.h:95
uint16_t reduct_uint16_t
Definition defs.h:97
reduct_mode_t
Opcode mode enumeration.
Definition inst.h:37
reduct_opcode_t
Opcode enumeration.
Definition inst.h:49
reduct_uint32_t reduct_inst_t
Instruction type.
Definition inst.h:97
reduct_uint16_t reduct_reg_t
Register type.
Definition inst.h:87
@ REDUCT_MODE_REG
Register operand mode.
Definition inst.h:40
@ REDUCT_MODE_NONE
Invalid mode.
Definition inst.h:38
@ REDUCT_MODE_CONST
Constant operand mode.
Definition inst.h:41
@ REDUCT_MODE_TARGET
Compilation target hint mode.
Definition inst.h:39
@ REDUCT_OPCODE_DIV
(A, B, C) R(A) = R(B) / R/K(C)
Definition inst.h:71
@ REDUCT_OPCODE_JMPF
(A, sBx) Jump by sBx if R(A) is falsy.
Definition inst.h:53
@ REDUCT_OPCODE_JMPT
(A, sBx) Jump by sBx if R(A) is truthy.
Definition inst.h:54
@ REDUCT_OPCODE_APPEND
(A, C) Append value in R/K(C) to the back of the list in R(A).
Definition inst.h:59
@ REDUCT_OPCODE_SHR
(A, B, C) R(A) = R(B) >> R/K(C)
Definition inst.h:78
@ REDUCT_OPCODE_SEQ
(A, B, C) If R(B) === R/K(C) store true in R(A), else false.
Definition inst.h:62
@ REDUCT_OPCODE_SHL
(A, B, C) R(A) = R(B) << R/K(C)
Definition inst.h:77
@ REDUCT_OPCODE_SUB
(A, B, C) R(A) = R(B) - R/K(C)
Definition inst.h:69
@ REDUCT_OPCODE_NEQ
(A, B, C) If R(B) != R/K(C) store true in R(A), else false.
Definition inst.h:61
@ REDUCT_OPCODE_MOV
(A, C) Move value in R/K(C) to R(A).
Definition inst.h:57
@ REDUCT_OPCODE_MUL
(A, B, C) R(A) = R(B) * R/K(C)
Definition inst.h:70
@ REDUCT_OPCODE_ADD
(A, B, C) R(A) = R(B) + R/K(C)
Definition inst.h:68
@ REDUCT_OPCODE_BAND
(A, B, C) R(A) = R(B) & R/K(C)
Definition inst.h:73
@ REDUCT_OPCODE_RET
(C) Return value in R/K(C).
Definition inst.h:58
@ REDUCT_OPCODE_BNOT
(A, C) R(A) = ~R/K(C)
Definition inst.h:76
@ REDUCT_OPCODE_EQ
(A, B, C) If R(B) == R/K(C) store true in R(A), else false.
Definition inst.h:60
@ REDUCT_OPCODE_CALL
(A, B, C) Call callable in R/K(C) with B args starting from R(A). Result in R(A).
Definition inst.h:56
@ REDUCT_OPCODE_GT
(A, B, C) If R(B) > R/K(C) store true in R(A), else false.
Definition inst.h:66
@ REDUCT_OPCODE_JMP
(sBx) Unconditional jump by relative offset sBx.
Definition inst.h:52
@ REDUCT_OPCODE_NONE
Definition inst.h:50
@ REDUCT_OPCODE_SNEQ
(A, B, C) If R(B) !== R/K(C) store true in R(A), else false.
Definition inst.h:63
@ REDUCT_OPCODE_GE
(A, B, C) If R(B) >= R/K(C) store true in R(A), else false.
Definition inst.h:67
@ REDUCT_OPCODE_BOR
(A, B, C) R(A) = R(B) | R/K(C)
Definition inst.h:74
@ REDUCT_OPCODE_CLOSURE
(A, C) Wrap the function prototype in K(C) in a closure and store in R(A).
Definition inst.h:79
@ REDUCT_OPCODE_JEQ
(A, C) Skip the next instruction if R(A) == R/K(C), else continue.
Definition inst.h:55
@ REDUCT_OPCODE_LE
(A, B, C) If R(B) <= R/K(C) store true in R(A), else false.
Definition inst.h:65
@ REDUCT_OPCODE_LIST
(A) Create a new list and store it in R(A).
Definition inst.h:51
@ REDUCT_OPCODE_TAILCALL
(A, B, C) Tail call callable in R/K(C) with B args starting from R(A).
Definition inst.h:81
@ REDUCT_OPCODE_BXOR
(A, B, C) R(A) = R(B) ^ R/K(C)
Definition inst.h:75
@ REDUCT_OPCODE_CAPTURE
(A, B, C) Capture R/K(C) into constant slot B in closure R(A).
Definition inst.h:80
@ REDUCT_OPCODE_MOD
(A, B, C) R(A) = R(B) % R/K(C)
Definition inst.h:72
@ REDUCT_OPCODE_LT
(A, B, C) If R(B) < R/K(C) store true in R(A), else false.
Definition inst.h:64