forked from intelxed/xed
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathenc2test.py
420 lines (329 loc) · 12.3 KB
/
enc2test.py
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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
#!/usr/bin/env python3
# -*- python -*-
#BEGIN_LEGAL
#
#Copyright (c) 2019 Intel Corporation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
#END_LEGAL
from __future__ import print_function
import sys
import collections
import codegen
from enc2common import *
def _make_test_function_object(env, enc_fn):
encoder_fn = enc_fn.get_function_name()
versions = env.test_function_names[encoder_fn]
fname = 'test_{}_{}'.format(versions, encoder_fn)
if env.test_checked_interface:
fname = '{}_chk'.format(fname)
env.test_function_names[encoder_fn] += 1
fo = codegen.function_object_t(fname, return_type='xed_uint32_t')
return fo
def _add_test_function(ii,fo):
ii.enc_test_functions.append(fo)
dbg("TEST FUNCTION:")
dbg(fo.emit())
# generate all the register names
gpr64 = "RAX RCX RDX RBX RSI RDI RBP RSP R8 R9 R10 R11 R12 R13 R14 R15".split()
gpr64_index = "RAX RCX RDX RBX RSI RDI RBP R8 R9 R10 R11 R12 R13 R14 R15".split()
gpr32_not64 = "EAX ECX EDX EBX ESI EDI EBP ESP".split()
gpr32_not64 = "EAX ECX EDX EBX ESI EDI EBP ESP".split()
gpr32_index_not64 = "EAX ECX EDX EBX ESI EDI EBP".split()
gpr16_not64 = "AX CX DX BX SI DI BP SP".split()
gpr16_index = "SI DI".split()
gpr8_not64 = "AL CL DL BL".split()
gpr32_index_m64 = gpr32_index_not64 + "R8D R9D R10D R11D R12D R13D R14D R15D".split()
gpr32_m64 = gpr32_not64 + "R8D R9D R10D R11D R12D R13D R14D R15D".split()
gpr16_m64 = gpr16_not64 + "R8W R9W R10W R11W R12W R13W R14W R15W".split()
gpr8_m64 = gpr8_not64 + "SIL DIL BPL SPL R8B R9B R10B R11B R12B R13B R14B R15B".split()
gpr8h = "AH CH DH BH".split()
mmx = [ 'MMX{}'.format(i) for i in range(0,8)]
x87 = [ 'ST{}'.format(i) for i in range(0,8)]
kreg = [ 'K{}'.format(i) for i in range(0,8)]
kreg_not0 = [ 'K{}'.format(i) for i in range(1,8)]
xmm_vex_m64 = [ 'XMM{}'.format(i) for i in range(0,16)]
ymm_vex_m64 = [ 'YMM{}'.format(i) for i in range(0,16)]
xmm_evex_m64 = [ 'XMM{}'.format(i) for i in range(0,32)]
ymm_evex_m64 = [ 'YMM{}'.format(i) for i in range(0,32)]
zmm_evex_m64 = [ 'ZMM{}'.format(i) for i in range(0,32)]
xmm_not64 = [ 'XMM{}'.format(i) for i in range(0,8)]
ymm_not64 = [ 'YMM{}'.format(i) for i in range(0,8)]
zmm_not64 = [ 'ZMM{}'.format(i) for i in range(0,8)]
seg = 'ES CS SS DS FS GS'.split()
seg_no_cs = 'ES SS DS FS GS'.split()
cr_64 = 'CR0 CR2 CR3 CR4 CR8'.split()
cr_not64 = 'CR0 CR2 CR3 CR4'.split()
dr = [ 'DR{}'.format(i) for i in range(0,8)]
rcsae = [0,1,2,3]
scale = [1,2,4,8]
zeroing = [0,1]
def set_test_gen_counters(env):
env.test_gen_counters = collections.defaultdict(int)
env.test_gen_regs = {
# the index versions skip ESP/RSP as it cannot be an index register
'gpr64_index': gpr64_index,
'gpr32_index': gpr32_index_m64 if env.mode==64 else gpr32_index_not64,
'gpr16_index': gpr16_index,
'gpr64': gpr64,
'gpr32': gpr32_m64 if env.mode==64 else gpr32_not64,
'gpr16': gpr16_m64 if env.mode==64 else gpr16_not64,
'gpr8': gpr8_m64 if env.mode==64 else gpr8_not64,
'gpr8h': gpr8h,
'mmx' : mmx,
'x87' : x87,
# FIXME: avoiding k0 to avoid uncontrolled interactions ith
#zeroing bit. XED ILD checks for evex.aaa=0b000 with evex.z=1.
#'kreg': kreg,
'kreg': kreg_not0,
'kreg!0': kreg_not0,
'xmm': xmm_vex_m64 if env.mode==64 else xmm_not64,
'ymm': ymm_vex_m64 if env.mode==64 else ymm_not64,
'xmm_evex': xmm_evex_m64 if env.mode==64 else xmm_not64,
'ymm_evex': ymm_evex_m64 if env.mode==64 else ymm_not64,
'zmm_evex': zmm_evex_m64 if env.mode==64 else zmm_not64,
# FIXME: avoiding CS because of MOV SEG limitation
#'seg': seg,
'seg': seg_no_cs,
'cr' : cr_64 if env.mode==64 else cr_not64,
'dr' : dr,
'rcsae' : rcsae,
'zeroing': zeroing,
'scale' : scale
}
env.test_gen_reg_limit = {}
for k in env.test_gen_regs.keys():
env.test_gen_reg_limit[k] = len(env.test_gen_regs[k])
# the xmm,ymm,zmm regs have the same limit. Just using zmm to get
# a limit value
env.test_gen_reg_limit['simd_unified'] = len(env.test_gen_regs['xmm'])
env.test_gen_reg_limit['simd_unified_evex'] = len(env.test_gen_regs['zmm_evex'])
def get_bump(env, regkind):
v = env.test_gen_counters[regkind]
testreg = env.test_gen_regs[regkind][v]
# increment and roll the counter based on the limits for tht reg kind
n = v + 1
if n >= env.test_gen_reg_limit[regkind]:
n = 0
env.test_gen_counters[regkind] = n
return testreg
def get_bump_unified(env,regkind,evex):
'''Gathers require that we use different regs for the simd registers
but often gathers use different vector length reg for the
different things if addresses and data are different sizes. So we
make a common counter that gathers can use to avoid accidental
independent counters lining up for xmm,ymm and zmm... which does
happen.'''
if evex:
special_regkind = 'simd_unified_evex'
else:
special_regkind = 'simd_unified'
v = env.test_gen_counters[special_regkind]
try:
testreg = env.test_gen_regs[regkind][v] # use regkind to get the register name
except:
sys.stderr.write("ERROR: EVEX={} REGKIND={} V={}\n".format(evex,regkind,v))
sys.exit(1)
# increment and roll the counter based on the limits for tht reg kind
n = v + 1
if n >= env.test_gen_reg_limit[special_regkind]:
n = 0
env.test_gen_counters[special_regkind] = n
return testreg
def gen_reg_simd_unified(env,regkind, evex=True):
return 'XED_REG_{}'.format(get_bump_unified(env,regkind,evex))
def gen_reg(env,regkind):
return 'XED_REG_{}'.format(get_bump(env,regkind))
def gen_int(env,regkind):
return '{}'.format(get_bump(env,regkind))
# can vary output randomly, vary by number of calls in this
# instruction, etc.
def get_gpr64_index(env, ii):
return gen_reg(env,'gpr64_index')
def get_gpr32_index(env, ii):
return gen_reg(env,'gpr32_index')
def get_gpr16_index(env, ii):
return gen_reg(env,'gpr16_index')
def get_gpr64(env, ii):
return gen_reg(env,'gpr64')
def get_gpr32(env, ii):
return gen_reg(env,'gpr32')
def get_gpr16(env, ii):
return gen_reg(env,'gpr16')
def get_gpr8(env, ii): # FIXME: figure out how to use gpr8h values
return gen_reg(env,'gpr8')
def is_gather(ii):
return 'GATHER' in ii.iclass
def get_xmm(env, ii):
if is_gather(ii):
if ii.space == 'evex':
return gen_reg_simd_unified(env,'xmm_evex', True)
return gen_reg_simd_unified(env,'xmm', False)
if ii.space == 'evex':
return gen_reg(env,'xmm_evex')
return gen_reg(env,'xmm')
def get_ymm(env, ii):
if is_gather(ii):
if ii.space == 'evex':
return gen_reg_simd_unified(env,'ymm_evex', True)
return gen_reg_simd_unified(env,'ymm', False)
if ii.space == 'evex':
return gen_reg(env,'ymm_evex')
return gen_reg(env,'ymm')
def get_zmm(env, ii):
if is_gather(ii):
return gen_reg_simd_unified(env,'zmm_evex', True)
return gen_reg(env,'zmm_evex')
def get_kreg(env, ii):
return gen_reg(env,'kreg')
def get_kreg_not0(env, ii):
return gen_reg(env,'kreg!0')
def get_x87(env, ii):
return gen_reg(env,'x87')
def get_mmx(env, ii):
return gen_reg(env,'mmx')
def get_cr(env, ii):
return gen_reg(env,'cr')
def get_dr(env, ii):
return gen_reg(env,'dr')
def get_seg(env, ii):
return gen_reg(env,'seg')
# INTEGER VALUES
def get_zeroing(env, ii): # 0(merging),1(zeroing)
return gen_int(env,'zeroing')
def get_rcsae(env, ii): # 0,1,2
return gen_int(env,'rcsae')
def get_scale(env, ii): # 1,2,4,8
return gen_int(env,'scale')
# FIXED VALUES
def get_ax(env, ii): # always this value
return 'XED_REG_AX'
def get_eax(env, ii): # always this value
return 'XED_REG_EAX'
def get_rax(env, ii): # always this value
return 'XED_REG_RAX'
# IMMEDIATES AND DISPLACMENTS - FIXME VARY THESE
def get_imm8(env, ii): # FIXME: signed vs unsigned. These are used for displacements too currently
return '0x7E'
def get_imm16(env, ii):
return '0x7EED'
def get_imm32(env, ii):
return '0xAABBCCDD'
def get_imm64(env, ii):
return '0xAABBCCDDEEFF1122'
def get_disp8(env, ii):
return '0x15'
def get_disp16(env, ii):
return '0x1234'
def get_disp32(env, ii):
return '0x12345678'
def get_disp64(env, ii):
return '0x1122334455667788'
arginfo2value_creator = {
'gpr64_index': get_gpr64_index,
'gpr32_index': get_gpr32_index,
'gpr16_index': get_gpr16_index,
'gpr64': get_gpr64,
'gpr32': get_gpr32,
'gpr16': get_gpr16,
'gpr8': get_gpr8,
'xmm': get_xmm,
'ymm': get_ymm,
'zmm': get_zmm,
'kreg': get_kreg,
'kreg!0': get_kreg_not0,
'x87': get_x87,
'mmx': get_mmx,
'imm8': get_imm8,
'imm16': get_imm16,
'imm32': get_imm32,
'imm64': get_imm64,
'int8': get_imm8, # using imm8...
'int16': get_imm16,
'int32': get_imm32,
'int64': get_imm64,
'disp8': get_disp8,
'disp16': get_disp16,
'disp32': get_disp32,
'disp64': get_disp64,
'cr': get_cr,
'dr': get_dr,
'seg': get_seg,
'zeroing': get_zeroing,
'rcsae': get_rcsae,
'scale': get_scale,
'ax': get_ax,
'eax': get_eax,
'rax': get_rax
}
def _create_enc_test_functions(env, ii, encfn):
global arginfo2value_creator
testfn = _make_test_function_object(env,encfn)
testfn.add_arg('xed_uint8_t* output_buffer')
# gather args
args = []
for arg,arginfo in encfn.get_args():
arg_chunks = arg.split(' ')
argtype = " ".join(arg_chunks[:-1])
argname = arg_chunks[-1]
args.append((argtype,argname,arginfo))
request_arg = None
for argtype,argname,arginfo in args:
if arginfo == 'req':
request_arg = argname
if not request_arg:
die("NO REQUEST ARG FOUND")
# arg var decls
for i,(argtype,argname,arginfo) in enumerate(args):
testfn.add_code_eol('{} {}'.format(argtype, argname))
# common configuration
testfn.add_code_eol('xed_enc2_req_t request')
#testfn.add_code_eol('xed_uint8_t output_buffer[XED_MAX_INSTRUCTION_BYTES]')
# set vars to test values
for argtype,argname,arginfo in args:
if arginfo == 'req':
# set up the request structure and output buffer
testfn.add_code_eol('xed_enc2_req_t_init(&request, output_buffer)')
testfn.add_code_eol('{} = &request'.format(request_arg) )
else:
if not arginfo:
die("NO ARGINFO FOR {} {} in {}".format(argtype, argname, ii.iclass))
try:
vfn = arginfo2value_creator[arginfo]
except:
die("FIXME: MESSED UP ARGUMENTS FOR {} {} {} from {}".format(argtype, argname, arginfo, ii.iclass))
v = vfn(env,ii)
testfn.add_code_eol('{} = {}'.format(argname, v))
# test function call
s = []
fname = encfn.get_function_name()
if env.test_checked_interface:
fname = '{}_chk'.format(fname)
s.append( fname )
s.append( '(' )
for i,(argtype,argname,arginfo) in enumerate(args):
if i>0:
s.append(',')
s.append("{} /*{}*/".format(argname,arginfo))
s.append( ')' )
testfn.add_code_eol(''.join(s))
# return the output length
testfn.add_code_eol('return xed_enc2_encoded_length({})'.format(request_arg))
_add_test_function(ii, testfn)
def create_test_fn_main(env, ii):
env.test_function_names = collections.defaultdict(int)
ii.enc_test_functions = []
for encfn in ii.encoder_functions:
for n in range(0,env.tests_per_form):
_create_enc_test_functions(env, ii, encfn)