forked from intelxed/xed
-
Notifications
You must be signed in to change notification settings - Fork 0
/
enc2gen.py
executable file
·5642 lines (4827 loc) · 191 KB
/
enc2gen.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
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#!/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
# This is the "fast" encoder generator known as "enc2".
from __future__ import print_function
import os
import sys
import copy
import re
import argparse
import itertools
import collections
import traceback
import find_dir # finds mbuild and adds it to sys.path
import mbuild
import codegen
import read_xed_db
import gen_setup
import enc2test
import enc2argcheck
from enc2common import *
def get_fname(depth=1): # default is current caller
#return sys._getframe(depth).f_code.co_name
return traceback.extract_stack(None, depth+1)[0][2]
gpr_nt_widths_dict = {}
# list indexed by OSZ (o16,o32,o64)
gpr_nt_widths_dict['GPRv_SB'] = [16,32,64]
gpr_nt_widths_dict['GPRv_R'] = [16,32,64]
gpr_nt_widths_dict['GPRv_B'] = [16,32,64]
gpr_nt_widths_dict['GPRz_R'] = [16,32,32]
gpr_nt_widths_dict['GPRz_B'] = [16,32,32]
gpr_nt_widths_dict['GPRy_R'] = [32,32,64]
gpr_nt_widths_dict['GPRy_B'] = [32,32,64]
gpr_nt_widths_dict['GPR8_R'] = [8,8,8]
gpr_nt_widths_dict['GPR8_B'] = [8,8,8]
gpr_nt_widths_dict['GPR8_SB'] = [8,8,8]
gpr_nt_widths_dict['GPR16_R'] = [16,16,16]
gpr_nt_widths_dict['GPR16_B'] = [16,16,16]
gpr_nt_widths_dict['GPR32_B'] = [32,32,32]
gpr_nt_widths_dict['GPR32_R'] = [32,32,32]
gpr_nt_widths_dict['GPR64_B'] = [64,64,64]
gpr_nt_widths_dict['GPR64_R'] = [64,64,64]
gpr_nt_widths_dict['VGPR32_B'] = [32,32,32]
gpr_nt_widths_dict['VGPR32_R'] = [32,32,32]
gpr_nt_widths_dict['VGPR32_N'] = [32,32,32]
gpr_nt_widths_dict['VGPRy_N'] = [32,32,64]
gpr_nt_widths_dict['VGPR64_B'] = [64,64,64]
gpr_nt_widths_dict['VGPR64_R'] = [64,64,64]
gpr_nt_widths_dict['VGPR64_N'] = [64,64,64]
gpr_nt_widths_dict['A_GPR_R' ] = 'ASZ-SIZED-GPR' # SPECIAL
gpr_nt_widths_dict['A_GPR_B' ] = 'ASZ-SIZED-GPR'
# everything else is not typically used in scalable way. look at other
# operand.
oc2_widths_dict = {}
oc2_widths_dict['v'] = [16,32,64]
oc2_widths_dict['y'] = [32,32,64]
oc2_widths_dict['z'] = [16,32,32]
oc2_widths_dict['b'] = [8,8,8]
oc2_widths_dict['w'] = [16,16,16]
oc2_widths_dict['d'] = [32,32,32]
oc2_widths_dict['q'] = [64,64,64]
enc_fn_prefix = "xed_enc"
arg_reg_type = 'xed_reg_enum_t '
var_base = 'base'
arg_base = 'xed_reg_enum_t ' + var_base
var_index = 'index'
arg_index = 'xed_reg_enum_t ' + var_index
var_indexx = 'index_xmm'
arg_indexx = 'xed_reg_enum_t ' + var_indexx
var_indexy = 'index_ymm'
arg_indexy = 'xed_reg_enum_t ' + var_indexy
var_indexz = 'index_zmm'
arg_indexz = 'xed_reg_enum_t ' + var_indexz
var_vsib_index_dct = { 'xmm': var_indexx,
'ymm': var_indexy,
'zmm': var_indexz }
var_scale = 'scale'
arg_scale = 'xed_uint_t ' + var_scale
var_disp8 = 'disp8'
arg_disp8 = 'xed_int8_t ' + var_disp8
var_disp16 = 'disp16'
arg_disp16 = 'xed_int16_t ' + var_disp16
var_disp32 = 'disp32'
arg_disp32 = 'xed_int32_t ' + var_disp32
var_disp64 = 'disp64'
arg_disp64 = 'xed_int64_t ' + var_disp64
var_request = 'r'
arg_request = 'xed_enc2_req_t* ' + var_request
var_reg0 = 'reg0'
arg_reg0 = 'xed_reg_enum_t ' + var_reg0
var_reg1 = 'reg1'
arg_reg1 = 'xed_reg_enum_t ' + var_reg1
var_reg2 = 'reg2'
arg_reg2 = 'xed_reg_enum_t ' + var_reg2
var_reg3 = 'reg3'
arg_reg3 = 'xed_reg_enum_t ' + var_reg3
var_reg4 = 'reg4'
arg_reg4 = 'xed_reg_enum_t ' + var_reg4
var_kmask = 'kmask'
arg_kmask = 'xed_reg_enum_t ' + var_kmask
var_kreg0 = 'kreg0'
arg_kreg0 = 'xed_reg_enum_t ' + var_kreg0
var_kreg1 = 'kreg1'
arg_kreg1 = 'xed_reg_enum_t ' + var_kreg1
var_kreg2 = 'kreg2'
arg_kreg2 = 'xed_reg_enum_t ' + var_kreg2
var_rcsae = 'rcsae'
arg_rcsae = 'xed_uint_t ' + var_rcsae
var_zeroing = 'zeroing'
arg_zeroing = 'xed_bool_t ' + var_zeroing
var_imm8 = 'imm8'
arg_imm8 = 'xed_uint8_t ' + var_imm8
var_imm8_2 = 'imm8_2'
arg_imm8_2 = 'xed_uint8_t ' + var_imm8_2
var_imm16 = 'imm16'
arg_imm16 = 'xed_uint16_t ' + var_imm16
var_imm16_2 = 'imm16_2'
arg_imm16_2 = 'xed_uint16_t ' + var_imm16_2
var_imm32 = 'imm32'
arg_imm32 = 'xed_uint32_t ' + var_imm32
var_imm64 = 'imm64'
arg_imm64 = 'xed_uint64_t ' + var_imm64
def special_index_cases(ii):
if ii.avx512_vsib or ii.avx_vsib or ii.sibmem:
return True
return False
# if I wanted to prune the number of memory variants, I could set
# index_vals to just [True].
index_vals = [False,True]
def get_index_vals(ii):
global index_vals
if special_index_cases(ii):
return [True]
return index_vals
gprv_index_names = { 16:'gpr16_index', 32:'gpr32_index', 64:'gpr64_index'}
gprv_names = { 8:'gpr8', 16:'gpr16', 32:'gpr32', 64:'gpr64'} # added gpr8 for convenience
gpry_names = { 16:'gpr32', 32:'gpr32', 64:'gpr64'}
gprz_names = { 16:'gpr16', 32:'gpr32', 64:'gpr32'}
vl2names = { '128':'xmm', '256':'ymm', '512':'zmm',
'LIG':'xmm', 'LLIG':'xmm' }
vl2func_names = { '128':'128', '256':'256', '512':'512',
'LIG':'', 'LLIG':'' }
bits_to_widths = {8:'b', 16:'w', 32:'d', 64:'q' }
arg_immz_dct = { 0: '', 8: arg_imm8, 16: arg_imm16, 32: arg_imm32, 64: arg_imm32 }
var_immz_dct = { 0: '', 8: var_imm8, 16: var_imm16, 32: var_imm32, 64: var_imm32 }
arg_immz_meta = { 0: '', 8:'int8', 16: 'int16', 32: 'int32', 64: 'int32' }
arg_immv_dct = { 0: '', 8: arg_imm8, 16: arg_imm16, 32: arg_imm32, 64: arg_imm64 }
var_immv_dct = { 0: '', 8: var_imm8, 16: var_imm16, 32: var_imm32, 64: var_imm64 }
arg_immv_meta = { 0: '', 8:'int8', 16: 'int16', 32: 'int32', 64: 'int64' }
arg_dispv = { 8: arg_disp8, 16: arg_disp16, 32: arg_disp32, 64: arg_disp64 } # index by dispsz
var_dispv = { 8: arg_disp8, 16:var_disp16, 32:var_disp32, 64:var_disp64 }
arg_dispz = { 16: arg_disp16, 32: arg_disp32, 64: arg_disp32 } # index by dispsz
tag_dispz = { 16: 'int16', 32: 'int32', 64: 'int32' } # index by dispsz
var_dispz = { 16:var_disp16, 32:var_disp32, 64:var_disp32 }
arg_dispv_meta = { 8:'int8', 16:'int16', 32:'int32', 64:'int64' }
widths_to_bits = {'b':8, 'w':16, 'd':32, 'q':64 }
widths_to_bits_y = {'w':32, 'd':32, 'q':64 }
widths_to_bits_z = {'w':16, 'd':32, 'q':32 }
# if I cut the number of displacements by removing 0, I would have to
# add some sort of gizmo to omit the displacent if the value of the
# displacement is 0, but then that creates a problem for people who
# what zero displacements for patching. I could also consider merging
# disp8 and disp16/32 and then chose the smallest displacement that
# fits, but that also takes away control from the user.
def get_dispsz_list(env):
return [0,8,16] if env.asz == 16 else [0,8,32]
def get_osz_list(env):
return [16,32,64] if env.mode == 64 else [16,32]
_modvals = { 0: 0, 8: 1, 16: 2, 32: 2 } # index by dispsz
def get_modval(dispsz):
global _modvals
return _modvals[dispsz]
def _gen_opnds(ii): # generator
# filter out write-mask operands and suppressed operands
for op in ii.parsed_operands:
if op.lookupfn_name in [ 'MASK1', 'MASKNOT0']:
continue
if op.visibility == 'SUPPRESSED':
continue
if op.name == 'BCAST':
continue
yield op
def _gen_opnds_nomem(ii): # generator
# filter out write-mask operands and suppressed operands and memops
for op in ii.parsed_operands:
if op.name.startswith('MEM'):
continue
if op.lookupfn_name == 'MASK1':
continue
if op.lookupfn_name == 'MASKNOT0':
continue
if op.visibility == 'SUPPRESSED':
continue
if op.name == 'BCAST':
continue
yield op
def first_opnd(ii):
op = next(_gen_opnds(ii))
return op
def first_opnd_nonmem(ii):
op = next(_gen_opnds_nomem(ii))
return op
#def second_opnd(ii):
# for i,op in enumerate(_gen_opnds(ii)):
# if i==1:
# return op
def op_mask_reg(op):
return op_luf_start(op,'MASK')
def op_masknot0(op):
return op_luf_start(op,'MASKNOT0')
def op_scalable_v(op):
if op_luf_start(op,'GPRv'):
return True
if op.oc2 == 'v':
return True
return False
def op_gpr8(op):
if op_luf_start(op,'GPR8'):
return True
if op_reg(op) and op.oc2 == 'b':
return True
return False
def op_gpr16(op):
if op_luf_start(op,'GPR16'):
return True
if op_reg(op) and op.oc2 == 'w':
return True
return False
def op_seg(op):
return op_luf_start(op,'SEG')
def op_cr(op):
return op_luf_start(op,'CR')
def op_dr(op):
return op_luf_start(op,'DR')
def op_gprz(op):
return op_luf_start(op,'GPRz')
def op_gprv(op):
return op_luf_start(op,'GPRv')
def op_gpry(op):
return op_luf_start(op,'GPRy')
def op_vgpr32(op):
return op_luf_start(op,'VGPR32')
def op_vgpr64(op):
return op_luf_start(op,'VGPR64')
def op_gpr32(op):
return op_luf_start(op,'GPR32')
def op_gpr64(op):
return op_luf_start(op,'GPR64')
def op_ptr(op):
if 'PTR' in op.name:
return True
return False
def op_reg(op):
if 'REG' in op.name:
return True
return False
def op_mem(op):
if 'MEM' in op.name:
return True
return False
def op_agen(op): # LEA
if 'AGEN' in op.name:
return True
return False
def op_tmm(op):
if op.lookupfn_name:
if 'TMM' in op.lookupfn_name:
return True
return False
def op_xmm(op):
if op.lookupfn_name:
if 'XMM' in op.lookupfn_name:
return True
return False
def op_ymm(op):
if op.lookupfn_name:
if 'YMM' in op.lookupfn_name:
return True
return False
def op_zmm(op):
if op.lookupfn_name:
if 'ZMM' in op.lookupfn_name:
return True
return False
def op_mmx(op):
if op.lookupfn_name:
if 'MMX' in op.lookupfn_name:
return True
return False
def op_x87(op):
if op.lookupfn_name:
if 'X87' in op.lookupfn_name:
return True
elif (op.name.startswith('REG') and
op.lookupfn_name == None and
re.match(r'XED_REG_ST[0-7]',op.bits) ):
return True
return False
def one_scalable_gpr_and_one_mem(ii): # allows optional imm8,immz, one implicit specific reg
implicit,n,r,i = 0,0,0,0
for op in _gen_opnds(ii):
if op_mem(op):
n += 1
elif op_reg(op) and op_implicit_specific_reg(op):
implicit += 1
elif op_gprv(op): #or op_gpry(op):
r += 1
elif op_imm8(op) or op_immz(op):
i += 1
else:
return False
return n==1 and r==1 and i<=1 and implicit <= 1
def one_gpr_reg_one_mem_scalable(ii):
n,r = 0,0
for op in _gen_opnds(ii):
if op_agen(op) or (op_mem(op) and op.oc2 in ['v']):
n += 1
elif op_gprv(op):
r += 1
else:
return False
return n==1 and r==1
def one_gpr_reg_one_mem_zp(ii):
n,r = 0,0
for op in _gen_opnds(ii):
if op_mem(op) and op.oc2 in ['p','z']:
n += 1
elif op_gprz(op):
r += 1
else:
return False
return n==1 and r==1
def one_gpr_reg_one_mem_fixed(ii):
n,r = 0,0
for op in _gen_opnds(ii):
# FIXME: sloppy could bemixing b and d operands, for example
if op_mem(op) and op.oc2 in ['b', 'w', 'd', 'q','dq']:
n += 1
elif op_gpr8(op) or op_gpr16(op) or op_gpr32(op) or op_gpr64(op):
r += 1
else:
return False
return n==1 and r==1
simd_widths = ['b','w','xud', 'qq', 'dq', 'q', 'ps','pd', 'ss', 'sd', 'd', 'm384', 'm512', 'xuq', 'zd']
def one_xmm_reg_one_mem_fixed_opti8(ii): # allows gpr32, gpr64, mmx too
global simd_widths
i,r,n=0,0,0
for op in _gen_opnds(ii):
if op_mem(op) and op.oc2 in simd_widths:
n = n + 1
elif (op_xmm(op) or op_mmx(op) or op_gpr32(op) or op_gpr64(op)) and op.oc2 in simd_widths:
r = r + 1
elif op_imm8(op):
i = i + 1
else:
return False
return n==1 and r==1 and i<=1
def one_mem_common(ii): # b,w,d,q,dq, v, y, etc.
n = 0
for op in _gen_opnds(ii):
if op_mem(op) and op.oc2 in ['b','w','d','q','dq','v', 'y', 's',
'mem14','mem28','mem94','mem108',
'mxsave', 'mprefetch',
'mem16', 's64', 'mfpxenv',
'm384', 'm512' ]:
n = n + 1
else:
return False
return n==1
def is_gather_prefetch(ii):
if 'GATHER' in ii.attributes:
if 'PREFETCH' in ii.attributes:
return True
return False
def is_far_xfer_mem(ii):
if 'FAR_XFER' in ii.attributes:
for op in _gen_opnds(ii):
if op_mem(op) and op.oc2 in ['p','p2']:
return True
return False
def is_far_xfer_nonmem(ii):
p,i=0,0
if 'FAR_XFER' in ii.attributes:
for op in _gen_opnds(ii):
if op_ptr(op):
p =+ 1
elif op_imm16(op):
i += 1
else:
return False
return True
return i==1 and p==1
def op_reg_invalid(op):
if op.bits and op.bits != '1':
if op.bits == 'XED_REG_INVALID':
return True
return False
def one_mem_common_one_implicit_gpr(ii):
'''memop can be b,w,d,q,dq, v, y, etc. with
GPR8 or GPRv'''
n,g = 0,0
for op in _gen_opnds(ii):
if op_mem(op) and op.oc2 in ['b','w','d','q','dq','v', 'y',
'mem14','mem28','mem94','mem108',
'mxsave', 'mprefetch' ]:
n += 1
elif op_reg(op) and op_implicit(op) and not op_reg_invalid(op):
# FIXME: could improve the accuracy by enforcing GPR. but
# not sure if that is strictly necessary. Encoding works...
g += 1
else:
return False
return n==1 and g==1
def one_mem_fixed_imm8(ii): # b,w,d,q,dq, etc.
n = 0
i = 0
for op in _gen_opnds(ii):
if op_mem(op) and op.oc2 in ['b','w','d','q','dq', 'v', 'y',
'mem14','mem28','mem94','mem108']:
n = n + 1
elif op_imm8(op):
i = i + 1
else:
return False
return n==1 and i==1
def one_mem_fixed_immz(ii): # b,w,d,q,dq, etc.
n = 0
i = 0
for op in _gen_opnds(ii):
if op_mem(op) and op.oc2 in ['b','w','d','q','dq', 'v', 'y',
'mem14','mem28','mem94','mem108']:
n = n + 1
elif op_immz(op):
i = i + 1
else:
return False
return n==1 and i==1
def two_gpr_one_scalable_one_fixed(ii):
f,v = 0,0
for op in _gen_opnds(ii):
if op_reg(op) and op_scalable_v(op):
v += 1
elif op_reg(op) and (op_gpr8(op) or op_gpr16(op) or op_gpr32(op)):
f += 1
else:
return False
return v==1 and f==1
def two_scalable_regs(ii): # allow optional imm8, immz, allow one implicit GPR
n,i,implicit = 0,0,0
for op in _gen_opnds(ii):
if op_reg(op) and op_scalable_v(op):
n += 1
elif op_reg(op) and op_implicit_specific_reg(op):
implicit += 1
elif op_imm8(op) or op_immz(op):
i += 1
else:
return False
return n==2 and i <= 1 and implicit <= 1
def op_implicit(op):
return op.visibility == 'IMPLICIT'
def op_implicit_or_suppressed(op):
return op.visibility in ['IMPLICIT','SUPPRESSED']
def one_x87_reg(ii):
n = 0
for op in _gen_opnds(ii):
if op_reg(op) and op_x87(op) and not op_implicit(op):
n = n + 1
else:
return False
return n==1
def two_x87_reg(ii): # one implicit
n = 0
implicit = 0
for op in _gen_opnds(ii):
if op_reg(op) and op_x87(op):
n = n + 1
if op_implicit(op):
implicit = implicit + 1
else:
return False
return n==2 and implicit == 1
def one_x87_implicit_reg_one_memop(ii):
mem,implicit_reg = 0,0
for op in _gen_opnds(ii):
if op_reg(op) and op_x87(op):
if op_implicit(op):
implicit_reg = implicit_reg + 1
else:
return False
elif op_mem(op):
mem = mem + 1
else:
return False
return mem==1 and implicit_reg==1
def zero_operands(ii):# allow all implicit regs
n = 0
for op in _gen_opnds(ii):
if op_implicit(op):
continue
n = n + 1
return n == 0
def one_implicit_gpr_imm8(ii):
'''this allows implicit operands'''
n = 0
for op in _gen_opnds(ii):
if op_imm8(op):
n = n + 1
elif op_implicit(op):
continue
else:
return False
return n == 1
def op_implicit_specific_reg(op):
if op.name.startswith('REG'):
if op.bits and op.bits.startswith('XED_REG_'):
return True
return False
def one_gprv_one_implicit(ii):
n,implicit = 0,0
for op in _gen_opnds(ii):
if op_gprv(op):
n += 1
elif op_implicit_specific_reg(op):
implicit += 1
else:
return False
return n == 1 and implicit == 1
def one_gpr8_one_implicit(ii):
n,implicit = 0,0
for op in _gen_opnds(ii):
if op_gpr8(op):
n += 1
elif op_implicit_specific_reg(op):
implicit += 1
else:
return False
return n == 1 and implicit == 1
def one_nonmem_operand(ii):
n = 0
for op in _gen_opnds(ii):
if op_mem(op):
return False
if op_implicit_or_suppressed(op): # for RCL/ROR etc with implicit imm8
continue
n = n + 1
return n == 1
def two_gpr8_regs(ii):
n = 0
for op in _gen_opnds(ii):
if op_reg(op) and op_gpr8(op):
n = n + 1
else:
return False
return n==2
def op_immz(op):
if op.name == 'IMM0':
if op.oc2 == 'z':
return True
return False
def op_immv(op):
if op.name == 'IMM0':
if op.oc2 == 'v':
return True
return False
def op_imm8(op):
if op.name == 'IMM0':
if op.oc2 == 'b':
if op_implicit_or_suppressed(op):
return False
return True
return False
def op_imm16(op):
if op.name == 'IMM0':
if op.oc2 == 'w':
return True
return False
def op_imm8_2(op):
if op.name == 'IMM1':
if op.oc2 == 'b':
return True
return False
def one_mmx_reg_imm8(ii):
n = 0
for i,op in enumerate(_gen_opnds(ii)):
if op_reg(op) and op_mmx(op):
n = n + 1
elif i == 1 and op_imm8(op):
continue
else:
return False
return n==1
def one_xmm_reg_imm8(ii): # also allows SSE4 2-imm8 instr
i,j,n=0,0,0
for op in _gen_opnds(ii):
if op_reg(op) and op_xmm(op):
n += 1
elif op_imm8(op):
i += 1
elif op_imm8_2(op):
j += 1
else:
return False
return n==1 and i==1 and j<=1
def two_xmm_regs_imm8(ii):
n = 0
for i,op in enumerate(_gen_opnds(ii)):
if op_reg(op) and op_xmm(op):
n = n + 1
elif i == 2 and op_imm8(op):
continue
else:
return False
return n==2
def gen_osz_list(mode, osz_list):
"""skip osz 64 outside of 64b mode"""
for osz in osz_list:
if mode != 64 and osz == 64:
continue
yield osz
def modrm_reg_first_operand(ii):
op = first_opnd(ii)
if op.lookupfn_name:
if op.lookupfn_name.endswith('_R'):
return True
if op.lookupfn_name.startswith('SEG'):
return True
return False
def emit_required_legacy_prefixes(ii,fo):
if ii.iclass.endswith('_LOCK'):
fo.add_code_eol('emit(r,0xF0)')
if ii.f2_required:
fo.add_code_eol('emit(r,0xF2)', 'required by instr')
if ii.f3_required:
fo.add_code_eol('emit(r,0xF3)', 'required by instr')
if ii.osz_required:
fo.add_code_eol('emit(r,0x66)', 'required by instr')
def emit_67_prefix(fo):
fo.add_code_eol('emit(r,0x67)', 'change EASZ')
def emit_required_legacy_map_escapes(ii,fo):
if ii.map == 1:
fo.add_code_eol('emit(r,0x0F)', 'escape map 1')
elif ii.map == 2:
fo.add_code_eol('emit(r,0x0F)', 'escape map 2')
fo.add_code_eol('emit(r,0x38)', 'escape map 2')
elif ii.map == 3:
fo.add_code_eol('emit(r,0x0F)', 'escape map 3')
fo.add_code_eol('emit(r,0x3A)', 'escape map 3')
elif ii.amd_3dnow_opcode:
fo.add_code_eol('emit(r,0x0F)', 'escape map 3dNOW')
fo.add_code_eol('emit(r,0x0F)', 'escape map 3dNOW')
def get_implicit_operand_name(op):
if op_implicit(op):
if op.name.startswith('REG'):
if op.bits and op.bits.startswith('XED_REG_'):
reg_name = re.sub('XED_REG_','',op.bits).lower()
return reg_name
elif op.lookupfn_name:
ntluf = op.lookupfn_name
return ntluf
elif op.name == 'IMM0' and op.type == 'imm_const' and op.bits == '1':
return 'one'
die("Unhandled implicit operand {}".format(op))
return None
def _gather_implicit_regs(ii):
names = []
for op in _gen_opnds(ii):
nm = get_implicit_operand_name(op)
if nm:
names.append(nm)
return names
def _implicit_reg_names(ii):
extra_names = _gather_implicit_regs(ii)
if extra_names:
extra_names = '_' + '_'.join( extra_names )
else:
extra_names = ''
return extra_names
def emit_vex_prefix(env, ii, fo, register_only=False):
if ii.map == 1 and ii.rexw_prefix != '1':
# if any of x,b are set, need c4, else can use c5
# performance: we know statically if something is register
# only. In which case, we can avoid testing rexx.
if env.mode == 64:
if register_only:
fo.add_code('if (get_rexb(r))')
else:
fo.add_code('if (get_rexx(r) || get_rexb(r))')
fo.add_code_eol(' emit_vex_c4(r)')
fo.add_code('else')
fo.add_code_eol(' emit_vex_c5(r)')
else:
fo.add_code_eol('emit_vex_c5(r)')
else:
fo.add_code_eol('emit_vex_c4(r)')
def emit_opcode(ii,fo):
if ii.amd_3dnow_opcode:
return # handled later. See add_enc_func()
opcode = "0x{:02X}".format(ii.opcode_base10)
fo.add_code_eol('emit(r,{})'.format(opcode),
'opcode')
def create_modrm_byte(ii,fo):
mod,reg,rm = 0,0,0
modrm_required = False
if ii.mod_required:
if ii.mod_required in ['unspecified']:
pass
elif ii.mod_required in ['00/01/10']:
modrm_requried = True
else:
mod = ii.mod_required
modrm_required = True
if ii.reg_required:
if ii.reg_required in ['unspecified']:
pass
else:
reg = ii.reg_required
modrm_required = True
if ii.rm_required:
if ii.rm_required in ['unspecified']:
pass
else:
rm = ii.rm_required
modrm_required = True
if modrm_required:
modrm = (mod << 6) | (reg<<3) | rm
fo.add_comment('MODRM = 0x{:02x}'.format(modrm))
if mod: # ZERO INIT OPTIMIZATION
fo.add_code_eol('set_mod(r,{})'.format(mod))
if reg: # ZERO INIT OPTIMIZATION
fo.add_code_eol('set_reg(r,{})'.format(reg))
if rm: # ZERO INIT OPTIMIZATION
fo.add_code_eol('set_rm(r,{})'.format(rm))
return modrm_required
numbered_function_creators = collections.defaultdict(int)
def dump_numbered_function_creators():
global numbered_function_creators
for k,val in sorted(numbered_function_creators.items(),
key=lambda x: x[1]):
print("NUMBERED FN CREATORS: {:5d} {:30s}".format(val,k))
numbered_functions = 0
def make_function_object(env, ii, fname, return_value='void', asz=None):
'''Create function object. Augment function name for conventions '''
global numbered_functions
global numbered_function_creators
if 'AMDONLY' in ii.attributes:
fname += '_amd'
if ii.space == 'evex':
fname += '_e'
# Distinguish the 16/32b mode register-only functions to avoid
# name collisions. The stuff references memory has an
# "_a"+env.asz suffix. The non-memory stuff can still have name
# collisions. To avoid those collisions, I append _md16 or _md32
# to the function names.
if asz:
fname += '_a{}'.format(asz)
elif env.mode in [16,32]:
fname += '_md{}'.format(env.mode)
if fname in env.function_names:
numbered_functions += 1
t = env.function_names[fname] + 1
env.function_names[fname] = t
fname = '{}_vr{}'.format(fname,t)
numbered_function_creators[get_fname(2)] += 1
#msge("Numbered function name for: {} from {}".format(fname, get_fname(2)))
else:
env.function_names[fname] = 0
fo = codegen.function_object_t(fname, return_value, dll_export=True)
if ii.iform:
fo.add_comment(ii.iform)
return fo
def make_opnd_signature(env, ii, using_width=None, broadcasting=False, special_xchg=False):
'''This is the heart of the naming conventions for the encode
functions. If using_width is present, it is used for GPRv and
GPRy operations to specify a width. '''
global vl2func_names, widths_to_bits, widths_to_bits_y, widths_to_bits_z
def _translate_rax_name(w):
rax_names = { 16: 'ax', 32:'eax', 64:'rax' }
osz = _translate_width_int(w)
return rax_names[osz]
def _translate_eax_name(w):
eax_names = { 16: 'ax', 32:'eax', 64:'eax' }
osz = _translate_width_int(w)
return eax_names[osz]
def _translate_r8_name(w):
# uppercase to try to differentiate r8 (generic 8b reg) from R8 64b reg
r8_names = { 16: 'R8W', 32:'R8D', 64:'R8' }
osz = _translate_width_int(w)
return r8_names[osz]
def _translate_width_int(w):
if w in [8,16,32,64]:
return w
return widths_to_bits[w]
def _translate_width(w):
return str(_translate_width_int(w))
def _translate_width_y(w):
if w in [32,64]:
return str(w)
elif w == 16:
return '32'
return str(widths_to_bits_y[w])
def _translate_width_z(w):
if w in [16,32]:
return str(w)
elif w == 64:
return '32'
return str(widths_to_bits_z[w])
def _convert_to_osz(w):
if w in [16,32,64]:
return w
elif w in widths_to_bits:
return widths_to_bits[w]
else:
die("Cannot convert {}".format(w) )
s = []
for op in _gen_opnds(ii):
if op_implicit(op):
nm = get_implicit_operand_name(op)
if nm in ['OrAX'] and using_width:
s.append( _translate_rax_name(using_width) )
elif nm in ['OeAX'] and using_width:
s.append( _translate_eax_name(using_width) )
else:
s.append(nm)
continue
# for the modrm-less MOV instr
if op.name.startswith('BASE'):
continue
if op.name.startswith('INDEX'):
continue
if op_tmm(op):
s.append('t')
elif op_xmm(op):
s.append('x')
elif op_ymm(op):
s.append('y')
elif op_zmm(op):
s.append('z')
elif op_mask_reg(op):
s.append('k')
elif op_vgpr32(op):
s.append('r32')
elif op_vgpr64(op):
s.append('r64') #FIXME something else
elif op_gpr8(op):
s.append('r8')
elif op_gpr16(op):
s.append('r16')
elif op_gpr32(op):
s.append('r32')
elif op_gpr64(op):
s.append('r64') #FIXME something else
elif op_gprv(op):
if special_xchg:
s.append(_translate_r8_name(using_width))
else: