Skip to content

Commit 3cb6850

Browse files
committed
#330 Instruction chooser takes ASA and OSA override into account.
1 parent d8b56bd commit 3cb6850

File tree

5 files changed

+325
-12
lines changed

5 files changed

+325
-12
lines changed

check/internal-tests/Makefile.am

+2
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ fcml_internal_check_SOURCES = main.c \
4141
modrm_decoder_t.h \
4242
modrm_encoder_t.c \
4343
modrm_encoder_t.h \
44+
instruction_chooser_t.c \
45+
instruction_chooser_t.h \
4446
stream_t.c \
4547
stream_t.h \
4648
utils_t.c \
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,257 @@
1+
/*
2+
* FCML - Free Code Manipulation Library.
3+
* Copyright (C) 2010-2024 Slawomir Wojtasiak
4+
*
5+
* This library is free software; you can redistribute it and/or
6+
* modify it under the terms of the GNU Lesser General Public
7+
* License as published by the Free Software Foundation; either
8+
* version 2.1 of the License, or (at your option) any later version.
9+
*
10+
* This library is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13+
* Lesser General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU Lesser General Public
16+
* License along with this library; if not, write to the Free Software
17+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18+
*/
19+
20+
#include "common_utils_t.h"
21+
22+
#include <fcml_assembler.h>
23+
#include <fcml_choosers.h>
24+
25+
static void fcml_ifn_chooser_extract(fcml_ptr instruction,
26+
fcml_st_instruction_code *instruction_code) {
27+
fcml_st_assembled_instruction *inst =
28+
(fcml_st_assembled_instruction*)instruction;
29+
instruction_code->code = inst->code;
30+
instruction_code->code_length = inst->code_length;
31+
instruction_code->details = inst->details;
32+
}
33+
34+
static fcml_ptr fcml_ifn_chooser_next(fcml_ptr instruction) {
35+
fcml_st_assembled_instruction *inst =
36+
(fcml_st_assembled_instruction*)instruction;
37+
return inst->next;
38+
}
39+
40+
fcml_bool fcml_tf_instruction_chooser_suite_init(void) {
41+
return FCML_TRUE;
42+
}
43+
44+
fcml_bool fcml_tf_instruction_chooser_suite_cleanup(void) {
45+
return FCML_TRUE;
46+
}
47+
48+
void fcml_tf_instruction_chooser_no_override(void) {
49+
fcml_uint8_t code1[4] = {0x01, 0x02, 0x03, 0x04};
50+
fcml_st_assembled_instruction instruction1 = {0};
51+
instruction1.code = &code1[0];
52+
instruction1.code_length = 4;
53+
instruction1.details.asa_override = FCML_FALSE;
54+
instruction1.details.osa_override = FCML_FALSE;
55+
instruction1.details.instruction_group = FCML_AMT_GPI;
56+
57+
fcml_uint8_t code2[3] = {0x01, 0x02, 0x03};
58+
fcml_st_assembled_instruction instruction2 = {0};
59+
instruction2.code = &code2[0];
60+
instruction2.code_length = 3;
61+
instruction2.details.asa_override = FCML_FALSE;
62+
instruction2.details.osa_override = FCML_FALSE;
63+
instruction2.details.instruction_group = FCML_AMT_GPI;
64+
65+
fcml_uint8_t code3[5] = {0x01, 0x02, 0x03, 0x04, 0x05};
66+
fcml_st_assembled_instruction instruction3 = {0};
67+
instruction3.code = &code3[0];
68+
instruction3.code_length = 5;
69+
instruction3.details.asa_override = FCML_FALSE;
70+
instruction3.details.osa_override = FCML_FALSE;
71+
instruction3.details.instruction_group = FCML_AMT_GPI;
72+
73+
instruction1.next = &instruction2;
74+
instruction2.next = &instruction3;
75+
76+
fcml_st_chooser_context context = {0};
77+
context.extract = &fcml_ifn_chooser_extract;
78+
context.next = &fcml_ifn_chooser_next;
79+
context.instruction = &instruction1;
80+
81+
fcml_ptr choosen = fcml_fn_asm_default_instruction_chooser(&context);
82+
83+
STF_ASSERT_PTR_NOT_NULL( choosen );
84+
STF_ASSERT_EQUAL( choosen, &instruction2 );
85+
}
86+
87+
void fcml_tf_instruction_chooser_no_override_one(void) {
88+
fcml_uint8_t code1[4] = {0x01, 0x02, 0x03, 0x04};
89+
fcml_st_assembled_instruction instruction1 = {0};
90+
instruction1.code = &code1[0];
91+
instruction1.code_length = 4;
92+
instruction1.details.asa_override = FCML_FALSE;
93+
instruction1.details.osa_override = FCML_FALSE;
94+
instruction1.details.instruction_group = FCML_AMT_GPI;
95+
96+
fcml_st_chooser_context context = {0};
97+
context.extract = &fcml_ifn_chooser_extract;
98+
context.next = &fcml_ifn_chooser_next;
99+
context.instruction = &instruction1;
100+
101+
fcml_ptr choosen = fcml_fn_asm_default_instruction_chooser(&context);
102+
103+
STF_ASSERT_PTR_NOT_NULL( choosen );
104+
STF_ASSERT_EQUAL( choosen, &instruction1 );
105+
}
106+
107+
void fcml_tf_instruction_chooser_no_override_has_higher_priority_osa(void) {
108+
fcml_uint8_t code1[4] = {0x01, 0x02, 0x03, 0x04};
109+
fcml_st_assembled_instruction instruction1 = {0};
110+
instruction1.code = &code1[0];
111+
instruction1.code_length = 4;
112+
instruction1.details.asa_override = FCML_FALSE;
113+
instruction1.details.osa_override = FCML_FALSE;
114+
instruction1.details.instruction_group = FCML_AMT_GPI;
115+
116+
fcml_uint8_t code2[3] = {0x01, 0x02, 0x03};
117+
fcml_st_assembled_instruction instruction2 = {0};
118+
instruction2.code = &code2[0];
119+
instruction2.code_length = 3;
120+
instruction2.details.asa_override = FCML_TRUE;
121+
instruction2.details.osa_override = FCML_FALSE;
122+
instruction2.details.instruction_group = FCML_AMT_GPI;
123+
124+
fcml_uint8_t code3[5] = {0x01, 0x02, 0x03, 0x04, 0x05};
125+
fcml_st_assembled_instruction instruction3 = {0};
126+
instruction3.code = &code3[0];
127+
instruction3.code_length = 5;
128+
instruction3.details.asa_override = FCML_FALSE;
129+
instruction3.details.osa_override = FCML_FALSE;
130+
instruction3.details.instruction_group = FCML_AMT_GPI;
131+
132+
instruction1.next = &instruction2;
133+
instruction2.next = &instruction3;
134+
135+
fcml_st_chooser_context context = {0};
136+
context.extract = &fcml_ifn_chooser_extract;
137+
context.next = &fcml_ifn_chooser_next;
138+
context.instruction = &instruction1;
139+
140+
fcml_ptr choosen = fcml_fn_asm_default_instruction_chooser(&context);
141+
142+
STF_ASSERT_PTR_NOT_NULL( choosen );
143+
STF_ASSERT_EQUAL( choosen, &instruction1 );
144+
}
145+
146+
void fcml_tf_instruction_chooser_no_override_has_higher_priority_asa(void) {
147+
fcml_uint8_t code1[4] = {0x01, 0x02, 0x03, 0x04};
148+
fcml_st_assembled_instruction instruction1 = {0};
149+
instruction1.code = &code1[0];
150+
instruction1.code_length = 4;
151+
instruction1.details.asa_override = FCML_FALSE;
152+
instruction1.details.osa_override = FCML_FALSE;
153+
instruction1.details.instruction_group = FCML_AMT_GPI;
154+
155+
fcml_uint8_t code2[3] = {0x01, 0x02, 0x03};
156+
fcml_st_assembled_instruction instruction2 = {0};
157+
instruction2.code = &code2[0];
158+
instruction2.code_length = 3;
159+
instruction2.details.asa_override = FCML_FALSE;
160+
instruction2.details.osa_override = FCML_TRUE;
161+
instruction2.details.instruction_group = FCML_AMT_GPI;
162+
163+
fcml_uint8_t code3[5] = {0x01, 0x02, 0x03, 0x04, 0x05};
164+
fcml_st_assembled_instruction instruction3 = {0};
165+
instruction3.code = &code3[0];
166+
instruction3.code_length = 5;
167+
instruction3.details.asa_override = FCML_FALSE;
168+
instruction3.details.osa_override = FCML_FALSE;
169+
instruction3.details.instruction_group = FCML_AMT_GPI;
170+
171+
instruction1.next = &instruction2;
172+
instruction2.next = &instruction3;
173+
174+
fcml_st_chooser_context context = {0};
175+
context.extract = &fcml_ifn_chooser_extract;
176+
context.next = &fcml_ifn_chooser_next;
177+
context.instruction = &instruction1;
178+
179+
fcml_ptr choosen = fcml_fn_asm_default_instruction_chooser(&context);
180+
181+
STF_ASSERT_PTR_NOT_NULL( choosen );
182+
STF_ASSERT_EQUAL( choosen, &instruction1 );
183+
}
184+
185+
void fcml_tf_instruction_chooser_no_override_has_higher_priority_one(void) {
186+
fcml_uint8_t code1[4] = {0x01, 0x02, 0x03, 0x04};
187+
fcml_st_assembled_instruction instruction1 = {0};
188+
instruction1.code = &code1[0];
189+
instruction1.code_length = 4;
190+
instruction1.details.asa_override = FCML_TRUE;
191+
instruction1.details.osa_override = FCML_TRUE;
192+
instruction1.details.instruction_group = FCML_AMT_GPI;
193+
194+
fcml_st_chooser_context context = {0};
195+
context.extract = &fcml_ifn_chooser_extract;
196+
context.next = &fcml_ifn_chooser_next;
197+
context.instruction = &instruction1;
198+
199+
fcml_ptr choosen = fcml_fn_asm_default_instruction_chooser(&context);
200+
201+
STF_ASSERT_PTR_NOT_NULL( choosen );
202+
STF_ASSERT_EQUAL( choosen, &instruction1 );
203+
}
204+
205+
void fcml_tf_instruction_chooser_ignore_override_for_non_gpi(void) {
206+
fcml_uint8_t code1[4] = {0x01, 0x02, 0x03, 0x04};
207+
fcml_st_assembled_instruction instruction1 = {0};
208+
instruction1.code = &code1[0];
209+
instruction1.code_length = 4;
210+
instruction1.details.asa_override = FCML_FALSE;
211+
instruction1.details.osa_override = FCML_FALSE;
212+
instruction1.details.instruction_group = FCML_AMT_AVX2;
213+
214+
fcml_uint8_t code2[3] = {0x01, 0x02, 0x03};
215+
fcml_st_assembled_instruction instruction2 = {0};
216+
instruction2.code = &code2[0];
217+
instruction2.code_length = 3;
218+
instruction2.details.asa_override = FCML_TRUE;
219+
instruction2.details.osa_override = FCML_FALSE;
220+
instruction2.details.instruction_group = FCML_AMT_AVX2;
221+
222+
fcml_uint8_t code3[5] = {0x01, 0x02, 0x03, 0x04, 0x05};
223+
fcml_st_assembled_instruction instruction3 = {0};
224+
instruction3.code = &code3[0];
225+
instruction3.code_length = 5;
226+
instruction3.details.asa_override = FCML_FALSE;
227+
instruction3.details.osa_override = FCML_FALSE;
228+
instruction3.details.instruction_group = FCML_AMT_AVX2;
229+
230+
instruction1.next = &instruction2;
231+
instruction2.next = &instruction3;
232+
233+
fcml_st_chooser_context context = {0};
234+
context.extract = &fcml_ifn_chooser_extract;
235+
context.next = &fcml_ifn_chooser_next;
236+
context.instruction = &instruction1;
237+
238+
fcml_ptr choosen = fcml_fn_asm_default_instruction_chooser(&context);
239+
240+
STF_ASSERT_PTR_NOT_NULL( choosen );
241+
STF_ASSERT_EQUAL( choosen, &instruction2 );
242+
}
243+
244+
fcml_stf_test_case fcml_ti_instruction_chooser[] = {
245+
{ "fcml_tf_instruction_chooser_no_override", fcml_tf_instruction_chooser_no_override },
246+
{ "fcml_tf_instruction_chooser_no_override_has_higher_priority_osa", fcml_tf_instruction_chooser_no_override_has_higher_priority_osa },
247+
{ "fcml_tf_instruction_chooser_no_override_has_higher_priority_asa", fcml_tf_instruction_chooser_no_override_has_higher_priority_asa },
248+
{ "fcml_tf_instruction_chooser_ignore_override_for_non_gpi", fcml_tf_instruction_chooser_ignore_override_for_non_gpi },
249+
{ "fcml_tf_instruction_chooser_no_override_one", fcml_tf_instruction_chooser_no_override_one },
250+
{ "fcml_tf_instruction_chooser_no_override_has_higher_priority_one", fcml_tf_instruction_chooser_no_override_has_higher_priority_one },
251+
FCML_STF_NULL_TEST
252+
};
253+
254+
fcml_stf_test_suite fcml_si_instruction_chooser = {
255+
"suite-fcml-instruction-chooser", fcml_tf_instruction_chooser_suite_init, fcml_tf_instruction_chooser_suite_cleanup, fcml_ti_instruction_chooser
256+
};
257+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/*
2+
* FCML - Free Code Manipulation Library.
3+
* Copyright (C) 2010-2024 Slawomir Wojtasiak
4+
*
5+
* This library is free software; you can redistribute it and/or
6+
* modify it under the terms of the GNU Lesser General Public
7+
* License as published by the Free Software Foundation; either
8+
* version 2.1 of the License, or (at your option) any later version.
9+
*
10+
* This library is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13+
* Lesser General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU Lesser General Public
16+
* License along with this library; if not, write to the Free Software
17+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18+
*/
19+
20+
#ifndef INSTRUCTION_CHOOSER_T_H_
21+
#define INSTRUCTION_CHOOSER_T_H_
22+
23+
#include <fcml_stf.h>
24+
25+
extern fcml_stf_test_suite fcml_si_instruction_chooser;
26+
27+
#endif /* INSTRUCTION_CHOOSER_T_H_ */

check/internal-tests/main.c

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*
22
* FCML - Free Code Manipulation Library.
3-
* Copyright (C) 2010-2021 Slawomir Wojtasiak
3+
* Copyright (C) 2010-2024 Slawomir Wojtasiak
44
*
55
* This library is free software; you can redistribute it and/or
66
* modify it under the terms of the GNU Lesser General Public
@@ -35,6 +35,7 @@
3535
#include "env_t.h"
3636
#include "ceh_t.h"
3737
#include "common_utils_t.h"
38+
#include "instruction_chooser_t.h"
3839
#include "symbols_t.h"
3940

4041
fcml_stf_test_suite *fcml_arr_suites[] = {
@@ -50,6 +51,7 @@ fcml_stf_test_suite *fcml_arr_suites[] = {
5051
&fcml_si_env,
5152
&fcml_si_ceh,
5253
&fcml_si_common_utils,
54+
&fcml_si_instruction_chooser,
5355
&fctl_si_symbols,
5456
FCML_STF_NULL_SUITE
5557
};

src/fcml_choosers.c

+36-11
Original file line numberDiff line numberDiff line change
@@ -24,29 +24,54 @@
2424

2525
#include "fcml_coll.h"
2626

27+
struct instruction_holder {
28+
fcml_ptr instruction;
29+
fcml_usize code_length;
30+
};
31+
2732
fcml_ptr LIB_CALL fcml_fn_asm_no_instruction_chooser(
2833
fcml_st_chooser_context *context) {
2934
return NULL;
3035
}
3136

37+
static void fcml_ifn_replace_shortest(struct instruction_holder *shortest,
38+
fcml_ptr instruction, fcml_st_instruction_code *instruction_code) {
39+
if (!shortest->instruction ||
40+
instruction_code->code_length < shortest->code_length) {
41+
shortest->instruction = instruction;
42+
shortest->code_length = instruction_code->code_length;
43+
}
44+
}
45+
3246
fcml_ptr LIB_CALL fcml_fn_asm_default_instruction_chooser(
3347
fcml_st_chooser_context *context) {
3448
fcml_st_instruction_code instruction_code;
3549
fcml_ptr instruction = context->instruction;
36-
fcml_ptr shortest = NULL;
37-
fcml_usize shortest_code_length = 0;
50+
51+
struct instruction_holder shortest = {0};
52+
struct instruction_holder shortest_no_override = {0};
53+
3854
while (instruction) {
3955
context->extract(instruction, &instruction_code);
40-
if (!shortest) {
41-
shortest = instruction;
42-
shortest_code_length = instruction_code.code_length;
43-
} else {
44-
if (instruction_code.code_length < shortest_code_length) {
45-
shortest = instruction;
46-
shortest_code_length = instruction_code.code_length;
47-
}
56+
57+
/* Keep the shortest GPI instruction which doesn't override anything. */
58+
if ((instruction_code.details.instruction_group & FCML_AMT_GPI) != 0 &&
59+
!instruction_code.details.osa_override &&
60+
!instruction_code.details.asa_override) {
61+
fcml_ifn_replace_shortest(&shortest_no_override, instruction,
62+
&instruction_code);
4863
}
64+
65+
fcml_ifn_replace_shortest(&shortest, instruction, &instruction_code);
66+
4967
instruction = context->next(instruction);
5068
}
51-
return shortest;
69+
70+
/* Return the shortest instruction which doesn't override ASA and OSA
71+
if there is any. */
72+
if (shortest_no_override.instruction != NULL) {
73+
return shortest_no_override.instruction;
74+
}
75+
76+
return shortest.instruction;
5277
}

0 commit comments

Comments
 (0)