Skip to content

Commit c26dec0

Browse files
committed
5% performance gains by using computed gotos
1 parent 014403a commit c26dec0

File tree

2 files changed

+119
-94
lines changed

2 files changed

+119
-94
lines changed

src/brainfuck/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
add_compile_options(-Wall -Wextra -Werror -Wpedantic -Wsign-conversion -Wconversion -march=native)
1+
add_compile_options(-Wall -Wextra -Werror -Wsign-conversion -Wconversion -march=native)
22
add_library(brainfuck SHARED types.cpp format.cpp file.cpp parse.cpp execute.cpp debug.cpp)

src/brainfuck/execute.cpp

Lines changed: 118 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -13,104 +13,129 @@ Error execute(ByteCode instructions) {
1313

1414
// Debug debug{instructions};
1515

16-
next:
17-
// debug.trackInstruction(static_cast<size_t>(instruction - instructions.data()));
18-
switch (instruction->type) {
19-
case DATA_POINTER_ADD:
20-
data_pointer += instruction->offset;
21-
break;
22-
case INSTRUCTION_POINTER_SET_IF_NOT_ZERO: {
23-
const auto offset_data_pointer = data_pointer + instruction->offset;
24-
if (data[offset_data_pointer] % 256 != 0) {
25-
instruction = &instructions[static_cast<size_t>(instruction->value)];
26-
goto next;
27-
}
28-
break;
29-
}
30-
case DATA_TRANSFER: {
31-
const auto offset_data_pointer = data_pointer + instruction->offset;
32-
data[offset_data_pointer + instruction->value] += data[offset_data_pointer];
33-
data[offset_data_pointer] = 0;
34-
break;
35-
}
36-
case DATA_ADD: {
37-
data[data_pointer + instruction->offset] += instruction->value;
38-
break;
39-
}
40-
case DATA_MULTIPLY: {
41-
const auto offset_data_pointer = data_pointer + instruction->offset;
42-
const auto outputs = instruction->value;
43-
for (auto i = 0; i < outputs; i++) {
44-
instruction++;
45-
data[offset_data_pointer + instruction->offset] += instruction->value * data[offset_data_pointer];
46-
}
47-
data[offset_data_pointer] = 0;
48-
break;
49-
}
50-
case DATA_SET: {
51-
const auto offset_data_pointer = data_pointer + instruction->offset;
52-
data[offset_data_pointer] = instruction->value;
53-
break;
54-
}
55-
case INSTRUCTION_POINTER_SET_IF_ZERO: {
56-
const auto offset_data_pointer = data_pointer + instruction->offset;
57-
if (data[offset_data_pointer] % 256 == 0) {
58-
instruction = &instructions[static_cast<size_t>(instruction->value)];
59-
goto next;
60-
}
61-
break;
62-
}
63-
case DATA_POINTER_ADD_WHILE_NOT_ZERO:
64-
while (data[data_pointer + instruction->offset] % 256 != 0) {
65-
data_pointer += instruction->value;
66-
}
67-
break;
68-
case DATA_PRINT: {
69-
const auto offset_data_pointer = data_pointer + instruction->offset;
70-
for (int i = 0; i < instruction->value; i++) {
71-
std::cout << static_cast<char>(data[offset_data_pointer] % 256);
72-
}
73-
break;
74-
}
75-
case DATA_SET_FROM_INPUT: {
76-
const auto offset_data_pointer = data_pointer + instruction->offset;
77-
for (int i = 0; i < instruction->value; i++) {
78-
char input;
79-
std::cin >> std::noskipws >> input;
80-
if (!std::cin.eof()) {
81-
data[offset_data_pointer] = input;
82-
}
83-
}
84-
break;
85-
}
86-
case DATA_MULTIPLY_AND_DIVIDE: {
87-
const auto offset_data_pointer = data_pointer + instruction->offset;
88-
const auto outputs = instruction->value;
89-
instruction++;
90-
Value iterations = 0;
91-
while (data[offset_data_pointer] % 256 != 0) {
92-
data[offset_data_pointer] += instruction->value;
93-
iterations++;
94-
}
95-
96-
for (auto i = 0; i < outputs; i++) {
97-
instruction++;
98-
data[offset_data_pointer + instruction->offset] += instruction->value * iterations;
99-
}
100-
break;
16+
static void* jumpTable[] = {
17+
&&NOOP,
18+
&&DONE,
19+
&&DATA_ADD,
20+
&&DATA_SET,
21+
&&DATA_TRANSFER,
22+
&&DATA_MULTIPLY,
23+
&&DATA_MULTIPLY_AND_DIVIDE,
24+
&&DATA_SET_FROM_INPUT,
25+
&&DATA_PRINT,
26+
&&DATA_POINTER_ADD,
27+
&&DATA_POINTER_ADD_WHILE_NOT_ZERO,
28+
&&INSTRUCTION_POINTER_SET_IF_ZERO,
29+
&&INSTRUCTION_POINTER_SET_IF_NOT_ZERO,
30+
};
31+
32+
goto* jumpTable[instruction->type];
33+
34+
DATA_POINTER_ADD:
35+
data_pointer += instruction->offset;
36+
goto AFTER;
37+
38+
INSTRUCTION_POINTER_SET_IF_NOT_ZERO: {
39+
const auto offset_data_pointer = data_pointer + instruction->offset;
40+
if (data[offset_data_pointer] % 256 != 0) {
41+
instruction = &instructions[static_cast<size_t>(instruction->value)];
42+
goto* jumpTable[instruction->type];
43+
}
44+
goto AFTER;
45+
}
46+
47+
DATA_TRANSFER: {
48+
const auto offset_data_pointer = data_pointer + instruction->offset;
49+
data[offset_data_pointer + instruction->value] += data[offset_data_pointer];
50+
data[offset_data_pointer] = 0;
51+
goto AFTER;
52+
}
53+
54+
DATA_ADD: {
55+
data[data_pointer + instruction->offset] += instruction->value;
56+
goto AFTER;
57+
}
58+
59+
DATA_MULTIPLY: {
60+
const auto offset_data_pointer = data_pointer + instruction->offset;
61+
const auto outputs = instruction->value;
62+
for (auto i = 0; i < outputs; i++) {
63+
instruction++;
64+
data[offset_data_pointer + instruction->offset] += instruction->value * data[offset_data_pointer];
65+
}
66+
data[offset_data_pointer] = 0;
67+
goto AFTER;
68+
}
69+
70+
DATA_SET: {
71+
const auto offset_data_pointer = data_pointer + instruction->offset;
72+
data[offset_data_pointer] = instruction->value;
73+
goto AFTER;
74+
}
75+
76+
INSTRUCTION_POINTER_SET_IF_ZERO: {
77+
const auto offset_data_pointer = data_pointer + instruction->offset;
78+
if (data[offset_data_pointer] % 256 == 0) {
79+
instruction = &instructions[static_cast<size_t>(instruction->value)];
80+
goto* jumpTable[instruction->type];
81+
}
82+
goto AFTER;
83+
}
84+
85+
DATA_POINTER_ADD_WHILE_NOT_ZERO:
86+
while (data[data_pointer + instruction->offset] % 256 != 0) {
87+
data_pointer += instruction->value;
88+
}
89+
goto AFTER;
90+
91+
DATA_PRINT: {
92+
const auto offset_data_pointer = data_pointer + instruction->offset;
93+
for (int i = 0; i < instruction->value; i++) {
94+
std::cout << static_cast<char>(data[offset_data_pointer] % 256);
95+
}
96+
goto AFTER;
97+
}
98+
99+
DATA_SET_FROM_INPUT: {
100+
const auto offset_data_pointer = data_pointer + instruction->offset;
101+
for (int i = 0; i < instruction->value; i++) {
102+
char input;
103+
std::cin >> std::noskipws >> input;
104+
if (!std::cin.eof()) {
105+
data[offset_data_pointer] = input;
101106
}
102-
case DONE:
103-
// debug.done();
104-
return Error::NONE;
105-
case NOOP:
106-
break;
107-
default:
108-
__builtin_unreachable();
109107
}
108+
goto AFTER;
109+
}
110110

111+
DATA_MULTIPLY_AND_DIVIDE: {
112+
const auto offset_data_pointer = data_pointer + instruction->offset;
113+
const auto outputs = instruction->value;
111114
instruction++;
115+
Value iterations = 0;
116+
while (data[offset_data_pointer] % 256 != 0) {
117+
data[offset_data_pointer] += instruction->value;
118+
iterations++;
119+
}
120+
121+
for (auto i = 0; i < outputs; i++) {
122+
instruction++;
123+
data[offset_data_pointer + instruction->offset] += instruction->value * iterations;
124+
}
125+
goto AFTER;
126+
}
112127

113-
goto next;
128+
DONE:
129+
// debug.done();
130+
return Error::NONE;
131+
132+
NOOP:
133+
goto AFTER;
134+
135+
AFTER:
136+
// debug.trackInstruction(static_cast<size_t>(instruction - instructions.data()));
137+
instruction++;
138+
goto* jumpTable[instruction->type];
114139
};
115140

116141
} // namespace brainfuck

0 commit comments

Comments
 (0)