Skip to content

Commit bd0bf1d

Browse files
committed
jit/ir: Implement IR instruction management
Introduces IR instruction management, including instruction_t and instruction_list_t definitions and their implementations. It also added const-correctness to the value_t API. Signed-off-by: Ronald Caesar <github43132@proton.me>
1 parent ffea35b commit bd0bf1d

File tree

8 files changed

+375
-28
lines changed

8 files changed

+375
-28
lines changed

CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ add_subdirectory(src/targets/switch1/hardware)
111111
include(TestBigEndian)
112112
TEST_BIG_ENDIAN(WORDS_BIGENDIAN)
113113

114-
list(APPEND POUND_PROJECT_TARGETS common host pvm)
114+
list(APPEND POUND_PROJECT_TARGETS common host pvm jit)
115115
foreach(TARGET ${POUND_PROJECT_TARGETS})
116116
# Apply Endianness definitions to all our targets.
117117
if(WORDS_BIGENDIAN)

src/jit/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ target_sources(jit PRIVATE
55
${CMAKE_CURRENT_SOURCE_DIR}/ir/type.cpp
66
${CMAKE_CURRENT_SOURCE_DIR}/ir/value.cpp
77
${CMAKE_CURRENT_SOURCE_DIR}/ir/opcode.cpp
8+
${CMAKE_CURRENT_SOURCE_DIR}/ir/instruction.cpp
89
)
910

1011
target_link_libraries(jit PRIVATE common host)

src/jit/ir/instruction.cpp

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
#include "instruction.h"
2+
#include "common/passert.h"
3+
#include <stddef.h>
4+
5+
#define LOG_MODULE "jit"
6+
#include "common/logging.h"
7+
8+
namespace pound::jit::ir {
9+
10+
const value_t*
11+
instruction_get_arg (const instruction_t *instruction, const size_t arg_index)
12+
{
13+
PVM_ASSERT(nullptr != instruction);
14+
PVM_ASSERT(arg_index < MAX_IR_ARGS);
15+
16+
const value_t *arg = &instruction->args[arg_index];
17+
PVM_ASSERT(nullptr != arg);
18+
return arg;
19+
}
20+
21+
const uint64_t
22+
instruction_get_arg_u64(const instruction_t *instruction, const size_t arg_index)
23+
{
24+
PVM_ASSERT(nullptr != instruction);
25+
PVM_ASSERT(arg_index < MAX_IR_ARGS);
26+
27+
const value_t* arg = instruction_get_arg(instruction, arg_index);
28+
PVM_ASSERT(nullptr != arg);
29+
30+
PVM_ASSERT(IR_TYPE_U64 == arg->type);
31+
const uint64_t value = value_get_u64(arg);
32+
return value;
33+
}
34+
35+
const uint32_t
36+
instruction_get_arg_u32(const instruction_t *instruction, const size_t arg_index)
37+
{
38+
PVM_ASSERT(nullptr != instruction);
39+
PVM_ASSERT(arg_index < MAX_IR_ARGS);
40+
41+
const value_t* arg = instruction_get_arg(instruction, arg_index);
42+
PVM_ASSERT(nullptr != arg);
43+
44+
PVM_ASSERT(IR_TYPE_U32 == arg->type);
45+
const uint32_t value = value_get_u32(arg);
46+
return value;
47+
}
48+
49+
const uint8_t
50+
instruction_get_arg_u8(const instruction_t *instruction, const size_t arg_index)
51+
{
52+
PVM_ASSERT(nullptr != instruction);
53+
PVM_ASSERT(arg_index < MAX_IR_ARGS);
54+
55+
const value_t* arg = instruction_get_arg(instruction, arg_index);
56+
PVM_ASSERT(nullptr != arg);
57+
58+
PVM_ASSERT(IR_TYPE_U8 == arg->type);
59+
const uint8_t value = value_get_u8(arg);
60+
return value;
61+
}
62+
63+
const bool
64+
instruction_get_arg_u1(const instruction_t *instruction, const size_t arg_index)
65+
{
66+
PVM_ASSERT(nullptr != instruction);
67+
PVM_ASSERT(arg_index < MAX_IR_ARGS);
68+
69+
const value_t* arg = instruction_get_arg(instruction, arg_index);
70+
PVM_ASSERT(nullptr != arg);
71+
72+
PVM_ASSERT(IR_TYPE_U1 == arg->type);
73+
const uint8_t value = value_get_u1(arg);
74+
return value;
75+
}
76+
77+
const pound::jit::a32_register_t
78+
instruction_get_arg_a32_register(const instruction_t *instruction, const size_t arg_index)
79+
{
80+
PVM_ASSERT(nullptr != instruction);
81+
PVM_ASSERT(arg_index < MAX_IR_ARGS);
82+
83+
const value_t* arg = instruction_get_arg(instruction, arg_index);
84+
PVM_ASSERT(nullptr != arg);
85+
86+
PVM_ASSERT(IR_TYPE_A32_REGISTER == arg->type);
87+
const pound::jit::a32_register_t value = value_get_a32_register(arg);
88+
return value;
89+
}
90+
91+
const type_t
92+
instruction_get_return_type (const instruction_t *instruction)
93+
{
94+
PVM_ASSERT(nullptr != instruction);
95+
PVM_ASSERT(instruction->opcode < NUM_OPCODE);
96+
97+
const decoded_opcode_t *decoded_opcode = &g_opcodes[instruction->opcode];
98+
PVM_ASSERT(nullptr != decoded_opcode);
99+
100+
return decoded_opcode->type;
101+
}
102+
103+
const char*
104+
instruction_get_opcode_name(const instruction_t *instruction)
105+
{
106+
PVM_ASSERT(nullptr != instruction);
107+
108+
const decoded_opcode_t *decoded_opcode = &g_opcodes[instruction->opcode];
109+
PVM_ASSERT(nullptr != decoded_opcode);
110+
111+
const char *name = decoded_opcode->name;
112+
PVM_ASSERT(nullptr != name);
113+
114+
return name;
115+
}
116+
117+
void
118+
instruction_list_append (instruction_list_t *list, instruction_t *instruction)
119+
{
120+
PVM_ASSERT(nullptr != list);
121+
PVM_ASSERT(nullptr != instruction);
122+
123+
instruction->next = nullptr;
124+
instruction->previous = list->tail;
125+
if (nullptr != list->tail)
126+
{
127+
list->tail->next = instruction;
128+
}
129+
else
130+
{
131+
list->head = instruction;
132+
}
133+
list->tail = instruction;
134+
}
135+
136+
void
137+
instruction_list_remove (instruction_list_t *list, instruction_t *instruction)
138+
{
139+
PVM_ASSERT(nullptr != list);
140+
PVM_ASSERT(nullptr != instruction);
141+
142+
if (nullptr != instruction->previous)
143+
{
144+
instruction->previous->next = instruction->next;
145+
}
146+
else
147+
{
148+
list->head = instruction->next;
149+
}
150+
151+
if (nullptr != instruction->next)
152+
{
153+
instruction->next->previous = instruction->previous;
154+
}
155+
else
156+
{
157+
list->tail = instruction->previous;
158+
}
159+
160+
instruction->next = nullptr;
161+
instruction->previous = nullptr;
162+
}
163+
}

src/jit/ir/instruction.h

Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
#ifndef POUND_JIT_IR_INSTRUCTION_H
2+
#define POUND_JIT_IR_INSTRUCTION_H
3+
4+
#include "opcode.h"
5+
#include "value.h"
6+
#include <stddef.h>
7+
8+
namespace pound::jit::ir {
9+
// Maximum number of arguments an IR instruction can have.
10+
#define MAX_IR_ARGS 4
11+
12+
/*!
13+
* Represents a single instruction in the IR layer.
14+
*
15+
* Each instruction node encapsulates an opcode, its arguments, and pointers to
16+
* form an intrusive double-linked list.
17+
*/
18+
typedef struct instruction_t
19+
{
20+
// The opcode for this instruction.
21+
opcode_t opcode;
22+
23+
// An array of arguments for this instruction.
24+
value_t args[MAX_IR_ARGS];
25+
26+
// Pointer to the next instruction in the intrusive list.
27+
struct instruction_t *next;
28+
29+
// Pointer to the previous instruction the intrusive list.
30+
struct instruction_t *previous;
31+
} instruction_t;
32+
33+
/*!
34+
* @brief Represents a double-linked list of IR instructions.
35+
*
36+
* This structure holds the head and tail pointers of an intrusive list
37+
* composed of `instruction_t` nodes. It is used to store sequences
38+
*/
39+
typedef struct
40+
{
41+
// Pointer to the first instruction in the list.
42+
instruction_t *head;
43+
44+
// Pointer to the last instruction in the list.
45+
instruction_t *tail;
46+
} instruction_list_t;
47+
48+
/*!
49+
* @brief Gets a pointer to the argument at a specific index.
50+
*
51+
* @param instruction Pointer to the IR instruction.
52+
* @param arg_index The index of the argument to retrieve.
53+
*
54+
* @return A constant pointer to the argument at the specified index.
55+
* @pre `instruction` must not be NULL
56+
* @pre `arg_index` must be less than `MAX_IR_ARGS`.
57+
*/
58+
const value_t* instruction_get_arg (const instruction_t *instruction, const size_t arg_index);
59+
60+
/*!
61+
* Retrieves a U64 argument from an instruction.
62+
*
63+
* @param instruction Pointer to the IR instruction.
64+
* @apram arg_index The index of the argument to retrieve.
65+
*
66+
* @return The U64 value of the argument.
67+
* @pre `instruction` must not be NULL.
68+
* @pre `arg_index` must be less than `MAX_IR_ARGS`.
69+
* @pre The argument at `arg_index` must be of type `IR_TYPE_U64`.
70+
*/
71+
const uint64_t instruction_get_arg_u64(const instruction_t *instruction, const size_t arg_index);
72+
73+
/*!
74+
* @brief Retrieves a U32 argument from an instruction.
75+
*
76+
* @param instruction Pointer to the IR instruction.
77+
* @param arg_index The index of the argument to retrieve.
78+
*
79+
* @return The U32 value of the argument.
80+
* @pre `instruction` must not be NULL.
81+
* @pre `arg_index` must be less than `MAX_IR_ARGS`.
82+
* @pre The argument at `arg_index` must be of type `IR_TYPE_U32`.
83+
*/
84+
const uint32_t instruction_get_arg_u32(const instruction_t *instruction, const size_t arg_index);
85+
86+
/*!
87+
* Retrives a U8 argument from an instruction.
88+
*
89+
* @param instruction Pointer to the IR instruction.
90+
* @param arg_index The index of the argument to retrieve.
91+
*
92+
* @return The U8 value of the argument.
93+
* @pre `instruction` must not be NULL.
94+
* @pre `arg_index` must be less than `MAX_IR_ARGS`.
95+
* @pre The argument at `arg_index` must be of type `IR_TYPE_U8`.
96+
*/
97+
const uint8_t instruction_get_arg_u8(const instruction_t *instruction, const size_t arg_index);
98+
99+
/*!
100+
* @brief Retrieves a U1 (boolean) argument from an instruction.
101+
*
102+
* @param instruction Pointer to the IR instruction.
103+
* @param arg_index The index of the argument to retrieve.
104+
*
105+
* @return The boolean value of the argument.
106+
* @pre `instruction` must not be NULL.
107+
* @pre `arg_index` must be less than `MAX_IR_ARGS`.
108+
* @pre The argument at `arg_index` must be of type `IR_TYPE_U1`.
109+
*/
110+
const bool instruction_get_arg_u1(const instruction_t *instruction, const size_t arg_index);
111+
112+
/*!
113+
* @brief Retrieves an A32 register identifier argument from an instruction.
114+
*
115+
* @param instruction Pointer to the IR instruction.
116+
* @param arg_index The index of the argument to retrieve.
117+
*
118+
* @return The `a32_register_t` identifier.
119+
* @pre `instruction` must not be NULL.
120+
* @pre `arg_index` must be less than `MAX_IR_ARGS`.
121+
* @pre The argument at `arg_index` must be of type `IR_TYPE_A32_REGISTER`.
122+
*/
123+
const pound::jit::a32_register_t instruction_get_arg_a32_register(const instruction_t *instruction, const size_t arg_index);
124+
125+
/*!
126+
* @brief Gets the return type of an instruction based on its opcode.
127+
*
128+
* @param instruction Pointer to the IR instruction.
129+
*
130+
* @return The `type_t` that this instruction's opcode returns.
131+
* @pre `instruction` must not be NULL.
132+
* @pre `instruction->opcode` must be a valid opcode index (less than `NUM_OPCODE`).
133+
*/
134+
const type_t instruction_get_return_type (const instruction_t *instruction);
135+
136+
137+
/*!
138+
* @brief Gets the name of an instruction's opcode as a C-string.
139+
*
140+
* @param instruction Pointer to the IR instruction.
141+
*
142+
* @return A constant C-string containing the opcode's name.
143+
* @pre `instruction` must not be NULL.
144+
* @pre `instruction->opcode` must be a valid opcode index (less than `NUM_OPCODE`).
145+
* @pre The global `g_opcodes` array must be initialized and accessible.
146+
*/
147+
const char* instruction_get_opcode_name(const instruction_t *instruction);
148+
149+
/*!
150+
* @brief Appends an instruction to the tail of an instruction list.
151+
*
152+
* The instruction is added to the end of the list. If the list is empty,
153+
* the instruction becomes both the head and the tail.
154+
*
155+
* @param list Pointer to the instruction list to modify.
156+
* @param instruction Pointer to the `instruction_t` node to append.
157+
*
158+
* @pre `list` must not be NULL.
159+
* @pre `instruction` must not be NULL.
160+
*/
161+
void instruction_list_append (instruction_list_t *list, instruction_t *instruction);
162+
163+
/*!
164+
* @brief Removes an instruction from an instruction list.
165+
*
166+
* @param list Pointer to the instruction list to modify.
167+
* @param instruction Pointer to the `instruction_t` node to remove.
168+
*
169+
* @pre `list` must not be NULL.
170+
* @pre `instruction` must not be NULL.
171+
* @pre `instruction` must be a member of `list`.
172+
*/
173+
void instruction_list_remove (instruction_list_t *list, instruction_t *instruction);
174+
}
175+
#endif // POUND_JIT_IR_INSTRUCTION_H

src/jit/ir/opcode.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
* by including "opcode.inc", which is processed using X-macros.
88
*/
99

10+
#ifndef POUMD_JIT_IR_OPCODE_H
11+
#define POUMD_JIT_IR_OPCODE_H
1012
#include "type.h"
1113

1214
namespace pound::jit::ir {
@@ -56,3 +58,4 @@ extern decoded_opcode_t g_opcodes[NUM_OPCODE];
5658

5759
void opcode_init(void);
5860
}
61+
#endif // POUMD_JIT_IR_OPCODE_H

src/jit/ir/type.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77
* This header declares the `type_t ` enumeration, which forms the basis of
88
* type identification and checking within the JIT's IR.
99
*/
10-
10+
#ifndef POUND_JIT_IR_TYPE_H
11+
#define POUND_JIT_IR_TYPE_H
1112
namespace pound::jit::ir {
1213

1314
/*!
@@ -60,3 +61,4 @@ typedef enum
6061
*/
6162
bool are_types_compatible(const type_t t1, const type_t t2);
6263
} // namespace pound::jit::ir
64+
#endif // POUND_JIT_IR_TYPE_H

0 commit comments

Comments
 (0)