Skip to content

Commit 98dae93

Browse files
committed
Enhance encodings.py to verify all files in arch/inst
Signed-off-by: Afonso Oliveira <[email protected]>
1 parent 998b010 commit 98dae93

File tree

1 file changed

+90
-28
lines changed

1 file changed

+90
-28
lines changed

ext/binutils-gdb/encoding.py

Lines changed: 90 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import os
22
import re
33
import sys
4+
import yaml
45
from collections import defaultdict
56

67
def parse_header_files(header_files):
@@ -188,29 +189,65 @@ def format_encoding(encoding_str):
188189
formatted_str = f"{group1}{group2}{group3}{group4}{group5}"
189190
return formatted_str
190191

191-
def get_instruction_names_from_directory(directory_path):
192+
def get_instruction_yaml_files(directory_path):
192193
"""
193-
Lists all .yaml files in the specified directory and extracts instruction names.
194+
Recursively finds all .yaml files in the specified directory and its subdirectories,
195+
and maps instruction names to their YAML file paths.
194196
195197
Args:
196198
directory_path (str): Path to the directory containing YAML files.
197199
198200
Returns:
199-
instr_names (set): A set of instruction names without the .yaml extension.
201+
instr_yaml_map (dict): Mapping from instruction name to YAML file path.
200202
"""
201-
try:
202-
files = os.listdir(directory_path)
203-
except FileNotFoundError:
204-
print(f"Error: Directory '{directory_path}' not found.")
205-
return set()
203+
instr_yaml_map = {}
204+
for root, dirs, files in os.walk(directory_path):
205+
for file in files:
206+
if file.endswith('.yaml'):
207+
instr_name = os.path.splitext(file)[0]
208+
yaml_path = os.path.join(root, file)
209+
if instr_name in instr_yaml_map:
210+
print(f"Warning: Multiple YAML files found for instruction '{instr_name}'. "
211+
f"Using '{instr_yaml_map[instr_name]}' and ignoring '{yaml_path}'.")
212+
else:
213+
instr_yaml_map[instr_name] = yaml_path
214+
return instr_yaml_map
215+
216+
def parse_yaml_encoding(yaml_file_path):
217+
"""
218+
Parses the YAML file to extract the 'encoding: match' string.
206219
207-
instr_names = set()
208-
for file in files:
209-
if file.endswith('.yaml'):
210-
instr_name = os.path.splitext(file)[0]
211-
instr_names.add(instr_name)
220+
Args:
221+
yaml_file_path (str): Path to the YAML file.
212222
213-
return instr_names
223+
Returns:
224+
match_encoding (str): The 32-character match encoding string.
225+
"""
226+
try:
227+
with open(yaml_file_path, 'r') as yaml_file:
228+
yaml_content = yaml.safe_load(yaml_file)
229+
if not isinstance(yaml_content, dict) or not yaml_content:
230+
print(f"Warning: YAML file '{yaml_file_path}' is empty or not properly formatted.")
231+
return ''
232+
233+
# Assuming the YAML structure has the instruction name as the top key
234+
# and 'encoding' as a subkey
235+
# Example:
236+
# add:
237+
# encoding:
238+
# match: "0000000----------000-----0110011"
239+
instr_name = list(yaml_content.keys())[0]
240+
encoding = yaml_content[instr_name].get('encoding', {})
241+
match_encoding = encoding.get('match', '')
242+
if not match_encoding:
243+
print(f"Warning: 'encoding.match' not found in YAML file '{yaml_file_path}'.")
244+
return match_encoding
245+
except FileNotFoundError:
246+
print(f"Error: YAML file '{yaml_file_path}' not found.")
247+
return ''
248+
except yaml.YAMLError as e:
249+
print(f"Error: Failed to parse YAML file '{yaml_file_path}': {e}")
250+
return ''
214251

215252
def main():
216253
"""
@@ -229,13 +266,13 @@ def main():
229266
]
230267

231268
# Define the path to the directory containing YAML files
232-
yaml_directory = '../../arch/inst/V' # Replace with your actual directory path
269+
yaml_directory = '../../arch/inst/' # Replace with your actual directory path
233270

234-
# Get instruction names from the YAML directory
235-
yaml_instr_names = get_instruction_names_from_directory(yaml_directory)
236-
if not yaml_instr_names:
237-
print("No instruction names found. Exiting.")
238-
sys.exit(1) # Exit if no instruction names are found
271+
# Get instruction YAML mappings from the YAML directory recursively
272+
instr_yaml_map = get_instruction_yaml_files(yaml_directory)
273+
if not instr_yaml_map:
274+
print("No YAML files found. Exiting.")
275+
sys.exit(1) # Exit if no YAML files are found
239276

240277
# Parse header files to get all #define constants
241278
defines = parse_header_files(header_files)
@@ -252,16 +289,33 @@ def main():
252289
# Group instructions by name
253290
instr_group = defaultdict(list)
254291
for instr in instructions:
255-
if instr['name'] in yaml_instr_names and 'INSN_ALIAS' not in instr['flags']:
292+
if instr['name'] in instr_yaml_map and 'INSN_ALIAS' not in instr['flags']:
256293
instr_group[instr['name']].append(instr)
257294

258295
if not instr_group:
259296
print("No matching non-alias instructions found between YAML files and instruction definitions.")
260297
sys.exit(1) # Exit if no matching instructions are found
261298

299+
# Initialize a flag to track mismatches
300+
mismatches_found = False
301+
262302
# Process each instruction group
263303
for name, defs in instr_group.items():
264304
success_encodings = []
305+
yaml_encoding = ''
306+
yaml_file_path = instr_yaml_map.get(name, '')
307+
308+
if not yaml_file_path:
309+
# No YAML file found for this instruction
310+
print(f"Warning: No YAML file found for instruction '{name}'. Skipping comparison.")
311+
continue
312+
313+
yaml_encoding = parse_yaml_encoding(yaml_file_path)
314+
315+
if not yaml_encoding:
316+
# Skip comparison if YAML encoding is missing
317+
continue
318+
265319
for d in defs:
266320
try:
267321
# Evaluate MATCH expression
@@ -279,23 +333,31 @@ def main():
279333
continue
280334

281335
if success_encodings:
282-
# Print all successful encodings for this instruction
283336
for class_, encoding in success_encodings:
284-
print(f'Instruction: {name}')
285-
print(f' Class: {class_}')
286-
print(f' match: {encoding}\n')
337+
if encoding != yaml_encoding:
338+
mismatches_found = True
339+
print(f"Error: Encoding mismatch for instruction '{name}' in YAML file '{yaml_file_path}'.")
340+
print(f" YAML match : {yaml_encoding}")
341+
print(f" Generated match: {encoding}\n")
287342
else:
288343
# No valid definitions could be processed for this instruction
289-
print(f"Error: Could not evaluate any MATCH/MASK expressions for instruction '{name}'. Exiting.")
290-
sys.exit(1) # Terminate the script
344+
print(f"Error: Could not evaluate any MATCH/MASK expressions for instruction '{name}' in YAML file '{yaml_file_path}'.\n")
345+
mismatches_found = True
291346

292347
# Optionally, notify about YAML files without corresponding instruction definitions
293348
defined_instr_names = set(instr['name'] for instr in instructions)
349+
yaml_instr_names = set(instr_yaml_map.keys())
294350
undefined_yaml_instr = yaml_instr_names - defined_instr_names
295351
if undefined_yaml_instr:
296352
print("Warning: The following instructions from YAML directory do not have definitions:")
297-
for instr in undefined_yaml_instr:
353+
for instr in sorted(undefined_yaml_instr):
298354
print(f" - {instr}")
299355

356+
# Exit with appropriate status code
357+
if mismatches_found:
358+
sys.exit(1) # Exit with error code if any mismatches are found
359+
else:
360+
sys.exit(0) # Successful execution
361+
300362
if __name__ == "__main__":
301363
main()

0 commit comments

Comments
 (0)