simdref 0.0.16__tar.gz → 0.0.17__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {simdref-0.0.16/src/simdref.egg-info → simdref-0.0.17}/PKG-INFO +3 -2
- {simdref-0.0.16 → simdref-0.0.17}/README.md +1 -0
- {simdref-0.0.16 → simdref-0.0.17}/pyproject.toml +2 -2
- {simdref-0.0.16 → simdref-0.0.17}/src/simdref/annotate.py +144 -27
- {simdref-0.0.16 → simdref-0.0.17}/src/simdref/arm_instructions.py +0 -1
- {simdref-0.0.16 → simdref-0.0.17}/src/simdref/asm_identity.py +131 -86
- {simdref-0.0.16 → simdref-0.0.17}/src/simdref/asmline.py +106 -7
- {simdref-0.0.16 → simdref-0.0.17}/src/simdref/catkey.py +10 -1
- {simdref-0.0.16 → simdref-0.0.17}/src/simdref/cli.py +119 -67
- {simdref-0.0.16 → simdref-0.0.17}/src/simdref/display.py +2 -0
- {simdref-0.0.16 → simdref-0.0.17}/src/simdref/filters.py +1 -0
- {simdref-0.0.16 → simdref-0.0.17}/src/simdref/ingest.py +2 -0
- {simdref-0.0.16 → simdref-0.0.17}/src/simdref/ingest_catalog.py +7 -1
- {simdref-0.0.16 → simdref-0.0.17}/src/simdref/ingest_sources.py +28 -0
- {simdref-0.0.16 → simdref-0.0.17}/src/simdref/lsp.py +191 -25
- {simdref-0.0.16 → simdref-0.0.17}/src/simdref/manpages.py +20 -8
- simdref-0.0.17/src/simdref/ptx.py +759 -0
- {simdref-0.0.16 → simdref-0.0.17}/src/simdref/riscv.py +0 -1
- {simdref-0.0.16 → simdref-0.0.17}/src/simdref/storage.py +10 -0
- {simdref-0.0.16 → simdref-0.0.17/src/simdref.egg-info}/PKG-INFO +3 -2
- {simdref-0.0.16 → simdref-0.0.17}/src/simdref.egg-info/SOURCES.txt +5 -0
- {simdref-0.0.16 → simdref-0.0.17}/src/simdref.egg-info/requires.txt +1 -1
- simdref-0.0.17/tests/test_annotate_scans.py +52 -0
- {simdref-0.0.16 → simdref-0.0.17}/tests/test_auto_update_on_version_change.py +1 -0
- {simdref-0.0.16 → simdref-0.0.17}/tests/test_catkey.py +2 -0
- {simdref-0.0.16 → simdref-0.0.17}/tests/test_cli_bare_query.py +34 -0
- simdref-0.0.17/tests/test_fetch_retry.py +175 -0
- {simdref-0.0.16 → simdref-0.0.17}/tests/test_ingest_sources.py +20 -0
- {simdref-0.0.16 → simdref-0.0.17}/tests/test_issue_65_identity.py +40 -15
- simdref-0.0.17/tests/test_lsp_ptx.py +311 -0
- {simdref-0.0.16 → simdref-0.0.17}/tests/test_lsp_stdio.py +202 -1
- {simdref-0.0.16 → simdref-0.0.17}/tests/test_presentation.py +25 -0
- simdref-0.0.17/tests/test_ptx.py +253 -0
- {simdref-0.0.16 → simdref-0.0.17}/LICENSE +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/setup.cfg +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/src/simdref/__init__.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/src/simdref/__main__.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/src/simdref/export.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/src/simdref/htmltext.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/src/simdref/ingest_pdf.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/src/simdref/models.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/src/simdref/operands.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/src/simdref/pdfparse/__init__.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/src/simdref/pdfparse/base.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/src/simdref/pdfparse/intel.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/src/simdref/pdfparse/registry.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/src/simdref/pdfparse/types.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/src/simdref/pdfrefs.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/src/simdref/perf.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/src/simdref/perf_sources/__init__.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/src/simdref/perf_sources/amd_swopt.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/src/simdref/perf_sources/arm_swopt.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/src/simdref/perf_sources/cores.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/src/simdref/perf_sources/instlatx64.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/src/simdref/perf_sources/intel_guide.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/src/simdref/perf_sources/intel_optref.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/src/simdref/perf_sources/llvm_mca.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/src/simdref/perf_sources/llvm_scheduling.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/src/simdref/perf_sources/merge.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/src/simdref/queries.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/src/simdref/regtable.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/src/simdref/search.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/src/simdref/tablecols.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/src/simdref/tui.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/src/simdref/ui_labels.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/src/simdref.egg-info/dependency_links.txt +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/src/simdref.egg-info/entry_points.txt +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/src/simdref.egg-info/top_level.txt +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/tests/test_a1_sdm_parser.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/tests/test_a2_perf_rule.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/tests/test_a4_arm_pdfrefs.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/tests/test_a5_offline_aarchmrs.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/tests/test_amd_match_llvm_mc.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/tests/test_annotate.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/tests/test_annotate_positions.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/tests/test_arrangement_tail.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/tests/test_asm_identity.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/tests/test_asm_wire.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/tests/test_asmline.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/tests/test_audit_coverage.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/tests/test_b1_latency_pairs.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/tests/test_b2_metadata.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/tests/test_b3_sdm_forms.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/tests/test_b4_descriptions_provenance.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/tests/test_b5_linking.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/tests/test_b5_perf_family.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/tests/test_b5_sme.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/tests/test_c0_perf_priority.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/tests/test_cli_bootstrap_progress.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/tests/test_cli_help.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/tests/test_cli_llm.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/tests/test_coverage_live.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/tests/test_coverage_parity.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/tests/test_display.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/tests/test_display_scanners.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/tests/test_export.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/tests/test_export_viz.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/tests/test_filters.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/tests/test_fixui_display.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/tests/test_htmltext.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/tests/test_ingest_enc_fields.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/tests/test_int_arm_isa_label.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/tests/test_int_core_ids.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/tests/test_int_ingest_registration.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/tests/test_int_sdm_family_fallback.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/tests/test_intel_operation_and_url.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/tests/test_isa_detect_llvm_mc.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/tests/test_issue2_fixes.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/tests/test_issue_51.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/tests/test_issue_52.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/tests/test_issue_53_54.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/tests/test_issue_55.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/tests/test_issue_56_57a.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/tests/test_issue_57_cpi.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/tests/test_issue_60_c1.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/tests/test_issue_60_contract.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/tests/test_issue_60_crossarch.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/tests/test_issue_60_matcher.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/tests/test_issue_65_arm_alias.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/tests/test_issue_65_compressed.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/tests/test_issue_65_m1.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/tests/test_issue_65_perfdata.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/tests/test_issue_65_text.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/tests/test_issue_65_timing.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/tests/test_issues_23_24_25.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/tests/test_issues_51_57_join.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/tests/test_leftover_arm_form_pick.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/tests/test_leftover_arm_postindex.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/tests/test_leftover_att_movx.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/tests/test_leftover_autoupdate.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/tests/test_leftover_catalog_gaps.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/tests/test_leftover_ingest_isa_merge.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/tests/test_leftover_intel_size.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/tests/test_leftover_perf_join.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/tests/test_leftover_riscv_shared.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/tests/test_lsp_web.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/tests/test_models.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/tests/test_no_catalog_row.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/tests/test_objdump_listings.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/tests/test_operands.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/tests/test_pdfparse.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/tests/test_perf.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/tests/test_perf_source_amd_swopt.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/tests/test_perf_source_arm_swopt.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/tests/test_perf_source_instlatx64.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/tests/test_perf_source_intel_guide.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/tests/test_perf_source_intel_optref.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/tests/test_perf_sources.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/tests/test_preset_persistence.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/tests/test_regtable.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/tests/test_release_tag_pin.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/tests/test_riscv_docs_pages.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/tests/test_search.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/tests/test_search_pushdown.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/tests/test_shared_source_helpers.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/tests/test_source_kind_filter.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/tests/test_source_validation.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/tests/test_storage_alnum.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/tests/test_storage_payload.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/tests/test_storage_schema.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/tests/test_tablecols.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/tests/test_tui.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/tests/test_ui_labels_parity.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/tests/test_update_build_stamp.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/tests/test_vendor_riscv_categories.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/tests/test_vendor_riscv_sources.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/tests/test_version_matches_pyproject.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/tests/test_x86_key_widths.py +0 -0
- {simdref-0.0.16 → simdref-0.0.17}/tests/test_x86_linking.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: simdref
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.17
|
|
4
4
|
Summary: Searchable SIMD intrinsic and instruction reference with CLI, manpages, TUI, and LSP.
|
|
5
5
|
Author: Marco
|
|
6
6
|
License: GPL-3.0-or-later
|
|
@@ -25,7 +25,7 @@ Requires-Dist: msgpack<2,>=1.2.4
|
|
|
25
25
|
Requires-Dist: PyYAML<7,>=6.0.3
|
|
26
26
|
Requires-Dist: rapidfuzz<4,>=3.14.6
|
|
27
27
|
Requires-Dist: rich<16,>=15.0.0
|
|
28
|
-
Requires-Dist: simdref-llvm-mc==23.1.4; (sys_platform == "linux" and (platform_machine == "x86_64" or platform_machine == "aarch64")) or (sys_platform == "darwin" and (platform_machine == "arm64" or platform_machine == "x86_64")) or (sys_platform == "win32" and platform_machine == "AMD64")
|
|
28
|
+
Requires-Dist: simdref-llvm-mc==23.1.4.post1; (sys_platform == "linux" and (platform_machine == "x86_64" or platform_machine == "aarch64")) or (sys_platform == "darwin" and (platform_machine == "arm64" or platform_machine == "x86_64")) or (sys_platform == "win32" and platform_machine == "AMD64")
|
|
29
29
|
Requires-Dist: textual<9,>=8.2.8
|
|
30
30
|
Requires-Dist: typer<1,>=0.27.3
|
|
31
31
|
Provides-Extra: ingest
|
|
@@ -177,6 +177,7 @@ Dev commands
|
|
|
177
177
|
| Arm AARCHMRS (A64) | Base instruction forms and operand tables | live-only² |
|
|
178
178
|
| riscv-rvv-intrinsic-doc | RVV intrinsics with deterministic instruction refs | 77,285 intrinsics |
|
|
179
179
|
| RISC-V unified-db | RVV instruction forms, ISA tags, description, operation | 3,666 instructions |
|
|
180
|
+
| NVIDIA PTX ISA | Instruction ops, syntax, qualifiers, versions, sm_XX | 1,088 instructions |
|
|
180
181
|
| Intel Guide perf tables | Per-core latency and throughput | 9,134 rows |
|
|
181
182
|
| Intel Optimization Ref. | Latency and throughput tables (volume 2) | 3,155 rows |
|
|
182
183
|
| InstLatX64 | Measured latency and throughput dumps | 16,235 rows |
|
|
@@ -142,6 +142,7 @@ Dev commands
|
|
|
142
142
|
| Arm AARCHMRS (A64) | Base instruction forms and operand tables | live-only² |
|
|
143
143
|
| riscv-rvv-intrinsic-doc | RVV intrinsics with deterministic instruction refs | 77,285 intrinsics |
|
|
144
144
|
| RISC-V unified-db | RVV instruction forms, ISA tags, description, operation | 3,666 instructions |
|
|
145
|
+
| NVIDIA PTX ISA | Instruction ops, syntax, qualifiers, versions, sm_XX | 1,088 instructions |
|
|
145
146
|
| Intel Guide perf tables | Per-core latency and throughput | 9,134 rows |
|
|
146
147
|
| Intel Optimization Ref. | Latency and throughput tables (volume 2) | 3,155 rows |
|
|
147
148
|
| InstLatX64 | Measured latency and throughput dumps | 16,235 rows |
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "simdref"
|
|
7
|
-
version = "0.0.
|
|
7
|
+
version = "0.0.17"
|
|
8
8
|
description = "Searchable SIMD intrinsic and instruction reference with CLI, manpages, TUI, and LSP."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.11"
|
|
@@ -42,7 +42,7 @@ dependencies = [
|
|
|
42
42
|
# manylinux x86_64 aarch64, macOS arm64 x86_64 and win_amd64, so the
|
|
43
43
|
# marker keeps the dependency off every other platform (musl included),
|
|
44
44
|
# where pip must see no candidate instead of failing to resolve.
|
|
45
|
-
'simdref-llvm-mc==23.1.4; (sys_platform == "linux" and (platform_machine == "x86_64" or platform_machine == "aarch64")) or (sys_platform == "darwin" and (platform_machine == "arm64" or platform_machine == "x86_64")) or (sys_platform == "win32" and platform_machine == "AMD64")',
|
|
45
|
+
'simdref-llvm-mc==23.1.4.post1; (sys_platform == "linux" and (platform_machine == "x86_64" or platform_machine == "aarch64")) or (sys_platform == "darwin" and (platform_machine == "arm64" or platform_machine == "x86_64")) or (sys_platform == "win32" and platform_machine == "AMD64")',
|
|
46
46
|
"textual>=8.2.8,<9",
|
|
47
47
|
"typer>=0.27.3,<1",
|
|
48
48
|
]
|
|
@@ -9,7 +9,6 @@ simdref catalog.
|
|
|
9
9
|
from __future__ import annotations
|
|
10
10
|
|
|
11
11
|
import json
|
|
12
|
-
import re
|
|
13
12
|
import sqlite3
|
|
14
13
|
import statistics
|
|
15
14
|
import string
|
|
@@ -18,6 +17,7 @@ from enum import Enum
|
|
|
18
17
|
from typing import Any, Iterable, Iterator
|
|
19
18
|
|
|
20
19
|
from simdref import perf
|
|
20
|
+
from simdref.arm_instructions import _CONDITION_CODES
|
|
21
21
|
from simdref.asm_identity import isa_by_acceptance
|
|
22
22
|
from simdref.catkey import ISA_FAMILY, isa_family as _isa_family
|
|
23
23
|
from simdref.lsp import NO_CATALOG_ROW, _document_arch, identity_keys
|
|
@@ -507,11 +507,33 @@ def _lookup_variants(mnemonic: str) -> list[str]:
|
|
|
507
507
|
|
|
508
508
|
|
|
509
509
|
# AArch64 condition-code branches: b.<cond>, no register table covers them.
|
|
510
|
-
|
|
511
|
-
|
|
510
|
+
# The vocabulary is the first spelling of each cond value in the A64 row table
|
|
511
|
+
# (cs/cc alias the hs/lo spellings the llvm-objdump printers print).
|
|
512
|
+
_A64_BCOND_CODES = frozenset(
|
|
513
|
+
dict(reversed([(cond, code) for code, cond in _CONDITION_CODES])).values()
|
|
512
514
|
)
|
|
513
515
|
|
|
514
516
|
|
|
517
|
+
def _bcond_hits(text: str) -> int:
|
|
518
|
+
"""Count b.<cond> branch mnemonics with word boundaries on both sides."""
|
|
519
|
+
count = 0
|
|
520
|
+
i = text.find("b.")
|
|
521
|
+
while i >= 0:
|
|
522
|
+
tail = text[i + 2 : i + 4]
|
|
523
|
+
before = text[i - 1 : i]
|
|
524
|
+
after = text[i + 4 : i + 5]
|
|
525
|
+
if (
|
|
526
|
+
tail in _A64_BCOND_CODES
|
|
527
|
+
and not (before and (before.isalnum() or before == "_"))
|
|
528
|
+
and not (after and (after.isalnum() or after == "_"))
|
|
529
|
+
):
|
|
530
|
+
count += 1
|
|
531
|
+
i = text.find("b.", i + 4)
|
|
532
|
+
else:
|
|
533
|
+
i = text.find("b.", i + 2)
|
|
534
|
+
return count
|
|
535
|
+
|
|
536
|
+
|
|
515
537
|
def _drop_symbol_annotations(text: str) -> str:
|
|
516
538
|
"""Drop objdump symbol annotations ("<x0+0x50>"): a target, never input."""
|
|
517
539
|
out: list[str] = []
|
|
@@ -646,7 +668,7 @@ def detect_isa(lines: Iterable[str]) -> str | None:
|
|
|
646
668
|
# a register (review finding 1).
|
|
647
669
|
text = _drop_symbol_annotations(f"{parsed.mnemonic} {parsed.operands}")
|
|
648
670
|
vote_arm, vote_riscv, vote_shared = _isa_votes(text)
|
|
649
|
-
excl_arm += vote_arm +
|
|
671
|
+
excl_arm += vote_arm + _bcond_hits(text)
|
|
650
672
|
excl_riscv += vote_riscv
|
|
651
673
|
shared += vote_shared
|
|
652
674
|
if excl_arm or excl_riscv:
|
|
@@ -682,10 +704,36 @@ def lookup(
|
|
|
682
704
|
return []
|
|
683
705
|
|
|
684
706
|
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
)
|
|
707
|
+
_SIZE_WORDS = frozenset({"byte", "word", "dword", "qword", "xmmword", "ymmword", "zmmword"})
|
|
708
|
+
|
|
709
|
+
|
|
710
|
+
def _has_size_ptr(text: str) -> bool:
|
|
711
|
+
"""True for a size keyword with a trailing "ptr" ("byte ptr [rdx]")."""
|
|
712
|
+
n = len(text)
|
|
713
|
+
i = 0
|
|
714
|
+
while i + 3 <= n:
|
|
715
|
+
if text[i : i + 3].lower() != "ptr":
|
|
716
|
+
i += 1
|
|
717
|
+
continue
|
|
718
|
+
if i + 3 < n and (text[i + 3].isalnum() or text[i + 3] == "_"):
|
|
719
|
+
i += 1
|
|
720
|
+
continue
|
|
721
|
+
j = i
|
|
722
|
+
while j > 0 and text[j - 1].isspace():
|
|
723
|
+
j -= 1
|
|
724
|
+
if j == i:
|
|
725
|
+
i += 1
|
|
726
|
+
continue
|
|
727
|
+
for word in _SIZE_WORDS:
|
|
728
|
+
k = j - len(word)
|
|
729
|
+
if (
|
|
730
|
+
k >= 0
|
|
731
|
+
and text[k:j].lower() == word
|
|
732
|
+
and not (k > 0 and (text[k - 1].isalnum() or text[k - 1] == "_"))
|
|
733
|
+
):
|
|
734
|
+
return True
|
|
735
|
+
i += 1
|
|
736
|
+
return False
|
|
689
737
|
|
|
690
738
|
|
|
691
739
|
def _x86_reg_class(name: str) -> str | None:
|
|
@@ -750,6 +798,26 @@ def _imm_kind(value: int) -> str:
|
|
|
750
798
|
return "I64"
|
|
751
799
|
|
|
752
800
|
|
|
801
|
+
def _is_number(text: str) -> bool:
|
|
802
|
+
"""True for the literal ``-?0x<hex>`` or ``-?<digits>`` the scans matched."""
|
|
803
|
+
body = text[1:] if text[:1] == "-" else text
|
|
804
|
+
if body[:2] == "0x":
|
|
805
|
+
body = body[2:]
|
|
806
|
+
return bool(body) and all(char in string.hexdigits for char in body)
|
|
807
|
+
return bool(body) and body.isdecimal()
|
|
808
|
+
|
|
809
|
+
|
|
810
|
+
def _is_symbol(text: str) -> bool:
|
|
811
|
+
"""True for ``[A-Za-z_.$]`` heads with ``\\w.$@`` tails (a plain symbol)."""
|
|
812
|
+
head = text[:1]
|
|
813
|
+
return (
|
|
814
|
+
bool(head)
|
|
815
|
+
and head.isascii()
|
|
816
|
+
and (head.isalpha() or head in "_.$")
|
|
817
|
+
and all(char.isalnum() or char in "_.$@" for char in text[1:])
|
|
818
|
+
)
|
|
819
|
+
|
|
820
|
+
|
|
753
821
|
def _classify_operand(op: str) -> tuple[str, str | None]:
|
|
754
822
|
"""Return ``(kind, reg_name_lower)`` for one operand.
|
|
755
823
|
|
|
@@ -763,17 +831,22 @@ def _classify_operand(op: str) -> tuple[str, str | None]:
|
|
|
763
831
|
if not s:
|
|
764
832
|
return "?", None
|
|
765
833
|
# objdump branch target: an address followed by a <symbol> annotation.
|
|
766
|
-
|
|
767
|
-
|
|
834
|
+
lt = s.find("<")
|
|
835
|
+
if lt > 0 and s.endswith(">") and ">" not in s[lt + 1 : -1]:
|
|
836
|
+
k = lt
|
|
837
|
+
while k > 0 and s[k - 1].isspace():
|
|
838
|
+
k -= 1
|
|
839
|
+
if k < lt and _is_number(s[:k]):
|
|
840
|
+
return "REL", None
|
|
768
841
|
# AT&T immediate: $... ; Intel immediate: bare number / 0x... / '$'-less literal
|
|
769
|
-
if s.startswith("$") or
|
|
842
|
+
if s.startswith("$") or _is_number(s):
|
|
770
843
|
try:
|
|
771
844
|
return _imm_kind(int(s.lstrip("$"), 0)), None
|
|
772
845
|
except ValueError:
|
|
773
846
|
return "I", None
|
|
774
847
|
# AT&T memory: ``(%reg)``, ``disp(%reg,%idx,scale)``, or plain symbol
|
|
775
848
|
# with a ``(...)`` section; Intel memory: ``[...]`` or explicit size ptr.
|
|
776
|
-
if "(" in s or "[" in s or
|
|
849
|
+
if "(" in s or "[" in s or _has_size_ptr(s):
|
|
777
850
|
return "M", None
|
|
778
851
|
# Pure register?
|
|
779
852
|
name = (s[1:] if s[:1] == "%" else s).casefold()
|
|
@@ -781,7 +854,7 @@ def _classify_operand(op: str) -> tuple[str, str | None]:
|
|
|
781
854
|
if tok is not None or _is_vec_shaped(name):
|
|
782
855
|
return tok or "?", name
|
|
783
856
|
# Plain symbol (branch target) or unknown.
|
|
784
|
-
if
|
|
857
|
+
if _is_symbol(s):
|
|
785
858
|
return "REL", None
|
|
786
859
|
return "?", None
|
|
787
860
|
|
|
@@ -802,9 +875,6 @@ def _operand_shape(operands: str) -> tuple[list[tuple[str, str | None]], bool]:
|
|
|
802
875
|
return slots, aliased
|
|
803
876
|
|
|
804
877
|
|
|
805
|
-
_FORM_OPS_RE = re.compile(r"\(([^)]*)\)\s*$")
|
|
806
|
-
|
|
807
|
-
|
|
808
878
|
def _form_operand_tokens(form_or_key: str) -> list[str]:
|
|
809
879
|
"""Extract the comma-separated operand tokens from a catalog form/key.
|
|
810
880
|
|
|
@@ -812,14 +882,25 @@ def _form_operand_tokens(form_or_key: str) -> list[str]:
|
|
|
812
882
|
``"RET_NEAR"`` returns ``[]``. Tokens are upper-cased.
|
|
813
883
|
"""
|
|
814
884
|
s = str(form_or_key or "")
|
|
815
|
-
|
|
816
|
-
if not
|
|
885
|
+
tail = s.rstrip()
|
|
886
|
+
if not tail or tail[-1] != ")":
|
|
817
887
|
return []
|
|
818
|
-
|
|
888
|
+
close = len(tail) - 1
|
|
889
|
+
# The inner text starts at the first "(" after the last ")" before the
|
|
890
|
+
# closing one, so no ")" splits it (the old group matched the same span).
|
|
891
|
+
start = tail.find("(", tail.rfind(")", 0, close) + 1)
|
|
892
|
+
if start < 0:
|
|
893
|
+
return []
|
|
894
|
+
inner = tail[start + 1 : close]
|
|
819
895
|
return [t.strip().upper() for t in inner.split(",") if t.strip()]
|
|
820
896
|
|
|
821
897
|
|
|
822
|
-
|
|
898
|
+
def _is_broadcast_token(token: str) -> bool:
|
|
899
|
+
"""True for a form token with a ``_1toN`` tail (``M16_1to8``)."""
|
|
900
|
+
start = len(token)
|
|
901
|
+
while start > 0 and token[start - 1].isdecimal():
|
|
902
|
+
start -= 1
|
|
903
|
+
return start < len(token) and start >= 4 and token[start - 4 : start] == "_1TO"
|
|
823
904
|
|
|
824
905
|
|
|
825
906
|
def _token_matches_slot(form_tok: str, slot_kind: str) -> bool:
|
|
@@ -867,7 +948,7 @@ def _slot_token_score(form_tok: str, slot_kind: str) -> int:
|
|
|
867
948
|
if not _token_matches_slot(ft, sk):
|
|
868
949
|
# Weak near-misses: a broadcast row wants a {1toN} annotation, and a
|
|
869
950
|
# register can ride a memory row (mov r,r against MOV (M32, R32)).
|
|
870
|
-
if sk == "M" and
|
|
951
|
+
if sk == "M" and _is_broadcast_token(ft):
|
|
871
952
|
return 2
|
|
872
953
|
if sk.startswith("R") and ("M" + sk[1:]) == ft:
|
|
873
954
|
return 2
|
|
@@ -1219,8 +1300,45 @@ def collect_ports(
|
|
|
1219
1300
|
return ports or None
|
|
1220
1301
|
|
|
1221
1302
|
|
|
1222
|
-
|
|
1223
|
-
|
|
1303
|
+
def _summary_bits(summary: str) -> str | None:
|
|
1304
|
+
"""The digits of the first "NNN - bit" phrase ("32-bit" -> "32"), else None.
|
|
1305
|
+
|
|
1306
|
+
shortcut: str.lower folds no Turkish dotted i in "bit", upgrade if an
|
|
1307
|
+
SDM summary ever carries one
|
|
1308
|
+
"""
|
|
1309
|
+
for j in range(len(summary) - 2):
|
|
1310
|
+
if summary[j : j + 3].lower() != "bit":
|
|
1311
|
+
continue
|
|
1312
|
+
k = j
|
|
1313
|
+
while k > 0 and summary[k - 1].isspace():
|
|
1314
|
+
k -= 1
|
|
1315
|
+
if k > 0 and summary[k - 1] == "-":
|
|
1316
|
+
k -= 1
|
|
1317
|
+
while k > 0 and summary[k - 1].isspace():
|
|
1318
|
+
k -= 1
|
|
1319
|
+
end = k
|
|
1320
|
+
while k > 0 and summary[k - 1].isdecimal():
|
|
1321
|
+
k -= 1
|
|
1322
|
+
if k < end:
|
|
1323
|
+
return summary[k:end]
|
|
1324
|
+
return None
|
|
1325
|
+
|
|
1326
|
+
|
|
1327
|
+
def _form_widths(key: str) -> list[str]:
|
|
1328
|
+
"""The digit groups of the ``M64``-style width tokens of one key."""
|
|
1329
|
+
out: list[str] = []
|
|
1330
|
+
i = 0
|
|
1331
|
+
n = len(key)
|
|
1332
|
+
while i < n:
|
|
1333
|
+
if key[i] in "MRI" and i + 1 < n and key[i + 1].isdecimal():
|
|
1334
|
+
j = i + 1
|
|
1335
|
+
while j < n and key[j].isdecimal():
|
|
1336
|
+
j += 1
|
|
1337
|
+
out.append(key[i + 1 : j])
|
|
1338
|
+
i = j
|
|
1339
|
+
else:
|
|
1340
|
+
i += 1
|
|
1341
|
+
return out
|
|
1224
1342
|
|
|
1225
1343
|
|
|
1226
1344
|
def _summary_matches_form(summary: str, record: InstructionRecord) -> bool:
|
|
@@ -1229,10 +1347,9 @@ def _summary_matches_form(summary: str, record: InstructionRecord) -> bool:
|
|
|
1229
1347
|
|
|
1230
1348
|
We only flag a summary as wrong when it declares an explicit bit-width
|
|
1231
1349
|
that appears nowhere among the form's operand widths."""
|
|
1232
|
-
|
|
1233
|
-
if
|
|
1350
|
+
declared = _summary_bits(summary or "")
|
|
1351
|
+
if declared is None:
|
|
1234
1352
|
return True
|
|
1235
|
-
declared = m.group(1)
|
|
1236
1353
|
widths: list[str] = []
|
|
1237
1354
|
for op in record.operand_details or []:
|
|
1238
1355
|
w = op.get("width")
|
|
@@ -1240,7 +1357,7 @@ def _summary_matches_form(summary: str, record: InstructionRecord) -> bool:
|
|
|
1240
1357
|
widths.append(str(w))
|
|
1241
1358
|
if not widths:
|
|
1242
1359
|
key = str(getattr(record, "key", "") or "")
|
|
1243
|
-
widths =
|
|
1360
|
+
widths = _form_widths(key)
|
|
1244
1361
|
if not widths:
|
|
1245
1362
|
return True
|
|
1246
1363
|
return declared in widths
|
|
@@ -26,38 +26,139 @@ the platforms it has wheels for; everywhere else point the env vars at a
|
|
|
26
26
|
|
|
27
27
|
from __future__ import annotations
|
|
28
28
|
|
|
29
|
+
import hashlib
|
|
29
30
|
import json
|
|
30
31
|
import os
|
|
31
32
|
import sqlite3
|
|
32
33
|
import subprocess
|
|
33
34
|
import tempfile
|
|
35
|
+
from concurrent.futures import ThreadPoolExecutor
|
|
34
36
|
from dataclasses import dataclass, field
|
|
35
37
|
from pathlib import Path
|
|
36
38
|
|
|
37
39
|
from simdref.catkey import ISA_FAMILY
|
|
38
40
|
|
|
39
41
|
# Measured invocation of the 144/401/703 corpora probes (asm-pip/probe).
|
|
42
|
+
# The riscv entries carry no "mattr": _mattr_for derives it from the tool.
|
|
40
43
|
_ARCH_CFG: dict[str, dict] = {
|
|
41
|
-
"x86": {
|
|
42
|
-
|
|
43
|
-
"mattr": "+avx512f,+avx512bw,+avx512dq,+avx512vl,+avx512vbmi,+avx512vbmi2,"
|
|
44
|
-
"+avx512vnni,+avx512bitalg,+avx512vpopcntdq,+avx512ifma,+vaes,+vpclmulqdq,"
|
|
45
|
-
"+avx,+avx2,+fma,+f16c,+bmi,+bmi2,+lzcnt,+movbe",
|
|
46
|
-
},
|
|
47
|
-
"aarch64": {
|
|
48
|
-
"triple": "aarch64-unknown-linux-gnu",
|
|
49
|
-
"mattr": "+sve,+sve2,+sve2p1,+sme,+sme2,+sme2p1,+lse,+gcs,+aes",
|
|
50
|
-
},
|
|
44
|
+
"x86": {"triple": "x86_64-unknown-linux-gnu", "mattr": ""},
|
|
45
|
+
"aarch64": {"triple": "aarch64-unknown-linux-gnu", "mattr": "+all"},
|
|
51
46
|
"arm": {"triple": "armv7-unknown-linux-gnueabihf", "mattr": "+neon"},
|
|
52
|
-
"riscv32": {
|
|
53
|
-
|
|
54
|
-
"mattr": "+m,+a,+f,+d,+c,+v,+zba,+zbb,+zbs",
|
|
55
|
-
},
|
|
56
|
-
"riscv64": {
|
|
57
|
-
"triple": "riscv64-unknown-linux-gnu",
|
|
58
|
-
"mattr": "+m,+a,+f,+d,+c,+v,+zba,+zbb,+zbs,+zvbb,+zvkb,+zvkned,+zfh",
|
|
59
|
-
},
|
|
47
|
+
"riscv32": {"triple": "riscv32-unknown-linux-gnu"},
|
|
48
|
+
"riscv64": {"triple": "riscv64-unknown-linux-gnu"},
|
|
60
49
|
}
|
|
50
|
+
# The ratified profile each riscv derivation anchors on (spike feat H2).
|
|
51
|
+
_RV_ANCHOR = {"riscv32": "+m,+a,+f,+d,+c,+v", "riscv64": "+rva23u64"}
|
|
52
|
+
_RV_MATTR_CACHE: dict[tuple[str, str], str] = {}
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def _rv_help_names(llvm_mc: str, arch: str) -> list[str]:
|
|
56
|
+
"""Extension names of ``llvm-mc -mattr=help``, in help order.
|
|
57
|
+
|
|
58
|
+
An extension line has the shape ``name - 'Name' (...)``. A tuning flag
|
|
59
|
+
(fusion-*, reserve-x*) has no quoted name, so the quote check keeps only
|
|
60
|
+
extensions. Vendor (x*) and experimental names drop out: the vendor ones
|
|
61
|
+
reuse the custom opcode spaces."""
|
|
62
|
+
# stdin=DEVNULL: -mattr=help keeps reading stdin, and in the LSP server
|
|
63
|
+
# stdin is the JSON-RPC stream (the derive would eat requests and block).
|
|
64
|
+
run = subprocess.run(
|
|
65
|
+
[llvm_mc, f"--triple={_ARCH_CFG[arch]['triple']}", "-mattr=help"],
|
|
66
|
+
stdin=subprocess.DEVNULL,
|
|
67
|
+
capture_output=True,
|
|
68
|
+
text=True,
|
|
69
|
+
)
|
|
70
|
+
_head, sep, tail = (run.stdout + run.stderr).partition("Available features for this target:")
|
|
71
|
+
names = []
|
|
72
|
+
for line in tail.splitlines() if sep else []:
|
|
73
|
+
left, sep2, _desc = line.strip().partition(" - '")
|
|
74
|
+
name = left.strip()
|
|
75
|
+
if sep2 and name and not any(ch.isspace() for ch in name):
|
|
76
|
+
if not name.startswith(("x", "experimental-")):
|
|
77
|
+
names.append(name)
|
|
78
|
+
return names
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def _rv_accepts(llvm_mc: str, arch: str, mattr: str) -> bool:
|
|
82
|
+
"""True when llvm-mc assembles one x31 instruction under ``mattr``."""
|
|
83
|
+
run = subprocess.run(
|
|
84
|
+
[llvm_mc, f"--triple={_ARCH_CFG[arch]['triple']}", f"-mattr={mattr}", "-show-encoding"],
|
|
85
|
+
# x31: a base-shrinking entry (e) fails here.
|
|
86
|
+
input="add t6, t6, t6\n",
|
|
87
|
+
capture_output=True,
|
|
88
|
+
text=True,
|
|
89
|
+
)
|
|
90
|
+
return run.returncode == 0 and "encoding" in run.stdout
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def _rv_mattr(llvm_mc: str, arch: str) -> str:
|
|
94
|
+
"""The riscv ``-mattr``, derived from llvm-mc and cached per tool path.
|
|
95
|
+
|
|
96
|
+
Never a hand list (spike feat H2): probe each non-vendor extension next
|
|
97
|
+
to the ratified anchor and keep what assembles, then keep a name only
|
|
98
|
+
when it also joins the union so far. The anchor decides each
|
|
99
|
+
incompatible pair (F over Zfinx, Zcd over Zcmp), and an extension that
|
|
100
|
+
conflicts with it drops out; a pair conflict can need a third
|
|
101
|
+
extension's implication, so the union test covers that.
|
|
102
|
+
|
|
103
|
+
The cache outlives the process (the derive costs about a second and the
|
|
104
|
+
CLI is one-shot): one file per tool path, size and mtime, so a rebuilt
|
|
105
|
+
tool re-derives."""
|
|
106
|
+
cached = _RV_MATTR_CACHE.get((llvm_mc, arch))
|
|
107
|
+
if cached is not None:
|
|
108
|
+
return cached
|
|
109
|
+
cache_file = _rv_mattr_cache_file(llvm_mc, arch)
|
|
110
|
+
try:
|
|
111
|
+
cached = cache_file.read_text().strip()
|
|
112
|
+
except OSError:
|
|
113
|
+
cached = ""
|
|
114
|
+
if not cached:
|
|
115
|
+
names = _rv_help_names(llvm_mc, arch)
|
|
116
|
+
# Ratified extensions first: on a conflict the earlier one stays.
|
|
117
|
+
names.sort(key=lambda name: name.startswith("experimental-"))
|
|
118
|
+
anchor = _RV_ANCHOR[arch]
|
|
119
|
+
with ThreadPoolExecutor(16) as pool:
|
|
120
|
+
verdict = list(
|
|
121
|
+
pool.map(lambda name: _rv_accepts(llvm_mc, arch, f"{anchor},+{name}"), names)
|
|
122
|
+
)
|
|
123
|
+
kept: list[str] = []
|
|
124
|
+
for name, ok in zip(names, verdict):
|
|
125
|
+
union = ",".join([anchor] + [f"+{k}" for k in kept + [name]])
|
|
126
|
+
if ok and _rv_accepts(llvm_mc, arch, union):
|
|
127
|
+
kept.append(name)
|
|
128
|
+
cached = ",".join([anchor] + [f"+{k}" for k in kept])
|
|
129
|
+
try:
|
|
130
|
+
cache_file.parent.mkdir(parents=True, exist_ok=True)
|
|
131
|
+
tmp = cache_file.with_name(f"{cache_file.name}.tmp{os.getpid()}")
|
|
132
|
+
tmp.write_text(cached)
|
|
133
|
+
os.replace(tmp, cache_file)
|
|
134
|
+
except OSError:
|
|
135
|
+
pass # a read-only cache dir costs one re-derive per process
|
|
136
|
+
_RV_MATTR_CACHE[(llvm_mc, arch)] = cached
|
|
137
|
+
return cached
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def _rv_mattr_cache_file(llvm_mc: str, arch: str) -> Path:
|
|
141
|
+
"""The cache file for one tool path: keyed by path, size and mtime."""
|
|
142
|
+
try:
|
|
143
|
+
stat = os.stat(llvm_mc)
|
|
144
|
+
stamp = f"{llvm_mc}:{stat.st_size}:{stat.st_mtime_ns}:{arch}"
|
|
145
|
+
except OSError:
|
|
146
|
+
stamp = f"{llvm_mc}:{arch}"
|
|
147
|
+
name = hashlib.sha256(stamp.encode()).hexdigest()[:16]
|
|
148
|
+
base = os.environ.get("XDG_CACHE_HOME") or os.path.join(Path.home(), ".cache")
|
|
149
|
+
return Path(base) / "simdref" / f"rv-mattr-{name}"
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
def _mattr_for(arch: str, llvm_mc: str) -> str:
|
|
153
|
+
"""The ``-mattr`` string for one arch.
|
|
154
|
+
|
|
155
|
+
x86 needs none (its assembler accepts every extension by default) and
|
|
156
|
+
arm keeps its one flag. The riscv string comes from _rv_mattr."""
|
|
157
|
+
if arch.startswith("riscv"):
|
|
158
|
+
return _rv_mattr(llvm_mc, arch)
|
|
159
|
+
return _ARCH_CFG[arch]["mattr"]
|
|
160
|
+
|
|
161
|
+
|
|
61
162
|
_X86_SYNTAX_FLAG = {"att": "-x86-asm-syntax=att", "intel": "-x86-asm-syntax=intel"}
|
|
62
163
|
# uops.info eosz attribute values per effective operand size.
|
|
63
164
|
_EOSZ_ATTR = {16: "1", 32: "2", 64: "3"}
|
|
@@ -303,8 +404,9 @@ def _probe_lines_uncached(
|
|
|
303
404
|
every other instruction line reports no row (review E1/E2)."""
|
|
304
405
|
cfg = _ARCH_CFG[arch]
|
|
305
406
|
cmd = [llvm_mc, f"--triple={cfg['triple']}", "-show-encoding", "-show-inst"]
|
|
306
|
-
|
|
307
|
-
|
|
407
|
+
use = mattr or _mattr_for(arch, llvm_mc)
|
|
408
|
+
if use:
|
|
409
|
+
cmd.append(f"-mattr={use}")
|
|
308
410
|
if arch == "x86":
|
|
309
411
|
cmd.append(_X86_SYNTAX_FLAG[syntax])
|
|
310
412
|
|
|
@@ -441,7 +543,9 @@ def _probe_lines_split(lines: list[str], arch: str, syntax: str, llvm_mc: str) -
|
|
|
441
543
|
continue
|
|
442
544
|
mattr = None
|
|
443
545
|
if not is_compressed:
|
|
444
|
-
|
|
546
|
+
# -c,-zca drops every Zc* family (zcb, zcmop, zcd), which the
|
|
547
|
+
# derived set names and a "+c" strip would leave on.
|
|
548
|
+
mattr = _mattr_for(arch, llvm_mc) + ",-c,-zca"
|
|
445
549
|
sub = _probe_lines([lines[i] for i in indexes], arch, syntax, llvm_mc, mattr=mattr)
|
|
446
550
|
for index, entry in zip(indexes, sub):
|
|
447
551
|
merged = dict(entry)
|
|
@@ -808,8 +912,9 @@ def _string_spans_lines(lines: list[str], arch: str, syntax: str, llvm_mc: str |
|
|
|
808
912
|
raise ToolUnavailableError("llvm-mc not found (set SIMDREF_LLVM_MC)")
|
|
809
913
|
cfg = _ARCH_CFG[arch]
|
|
810
914
|
cmd = [llvm_mc, f"--triple={cfg['triple']}"]
|
|
811
|
-
|
|
812
|
-
|
|
915
|
+
use = _mattr_for(arch, llvm_mc)
|
|
916
|
+
if use:
|
|
917
|
+
cmd.append(f"-mattr={use}")
|
|
813
918
|
if arch == "x86":
|
|
814
919
|
cmd.append(_X86_SYNTAX_FLAG[syntax])
|
|
815
920
|
pending = []
|
|
@@ -963,62 +1068,6 @@ def identify(
|
|
|
963
1068
|
# whose printed mnemonic equals the line's own text mnemonic (objdump prints
|
|
964
1069
|
# the expanded or alias name too: jal, flw, sext.w). Both or neither match
|
|
965
1070
|
# keeps the rv64 result (the current default).
|
|
966
|
-
def _rv64_only_ext(line: str) -> str | None:
|
|
967
|
-
"""The extension name in an "'X' is only supported for 'rv64'" error line.
|
|
968
|
-
|
|
969
|
-
Returns None for any other line. The name sits after the last single quote
|
|
970
|
-
before the fixed tail, so a prefix like "error: ..." is ignored.
|
|
971
|
-
"""
|
|
972
|
-
head, sep, _tail = line.partition("' is only supported for 'rv64'")
|
|
973
|
-
if not sep:
|
|
974
|
-
return None
|
|
975
|
-
return head.rpartition("'")[2] or None
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
_RV32_MATTR_CACHE: dict[tuple[str, str], str] = {}
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
def _rv32_decode_mattr(llvm_mc: str) -> str:
|
|
982
|
-
"""The riscv32 decode -mattr: the riscv64 one minus rv64-only extensions.
|
|
983
|
-
|
|
984
|
-
Derived from llvm-mc's own errors (never hand-listed): the tool rejects
|
|
985
|
-
an rv64-only extension on the rv32 triple by name. shortcut: an extension
|
|
986
|
-
named differently in the error keeps its token, upgrade if a tool build
|
|
987
|
-
rejects it silently."""
|
|
988
|
-
base = _ARCH_CFG["riscv64"]["mattr"]
|
|
989
|
-
cached = _RV32_MATTR_CACHE.get((llvm_mc, base))
|
|
990
|
-
if cached is None:
|
|
991
|
-
tokens = base.split(",")
|
|
992
|
-
while True:
|
|
993
|
-
run = subprocess.run(
|
|
994
|
-
[
|
|
995
|
-
llvm_mc,
|
|
996
|
-
f"--triple={_ARCH_CFG['riscv32']['triple']}",
|
|
997
|
-
f"-mattr={','.join(tokens)}",
|
|
998
|
-
"-show-encoding",
|
|
999
|
-
],
|
|
1000
|
-
input="",
|
|
1001
|
-
capture_output=True,
|
|
1002
|
-
text=True,
|
|
1003
|
-
)
|
|
1004
|
-
drop = {
|
|
1005
|
-
name.casefold()
|
|
1006
|
-
for line in run.stderr.splitlines()
|
|
1007
|
-
for name in [_rv64_only_ext(line)]
|
|
1008
|
-
if name
|
|
1009
|
-
}
|
|
1010
|
-
if not drop:
|
|
1011
|
-
break
|
|
1012
|
-
remaining = [token for token in tokens if token.lstrip("+").casefold() not in drop]
|
|
1013
|
-
# guard: the tool names an extension absent from the token list,
|
|
1014
|
-
# so nothing shrank; break here or the loop spins forever
|
|
1015
|
-
if len(remaining) == len(tokens):
|
|
1016
|
-
break
|
|
1017
|
-
tokens = remaining
|
|
1018
|
-
cached = _RV32_MATTR_CACHE[(llvm_mc, base)] = ",".join(tokens)
|
|
1019
|
-
return cached
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
1071
|
def _parse_disasm(listing: str) -> dict[bytes, tuple[str, str]]:
|
|
1023
1072
|
"""One (printed mnemonic, MCInst opcode) per decoded word.
|
|
1024
1073
|
|
|
@@ -1052,7 +1101,7 @@ def _rv_xlen_decodes(
|
|
|
1052
1101
|
gate: only an undecided RVC line pays the decode)."""
|
|
1053
1102
|
missing = [raw for raw in dict.fromkeys(raws) if (llvm_mc, xlen, raw) not in _RV_DECODE_CACHE]
|
|
1054
1103
|
if missing:
|
|
1055
|
-
mattr =
|
|
1104
|
+
mattr = _mattr_for(f"riscv{xlen}", llvm_mc)
|
|
1056
1105
|
hexed = [" ".join(f"0x{byte:02x}" for byte in raw) for raw in missing]
|
|
1057
1106
|
run = subprocess.run(
|
|
1058
1107
|
[
|
|
@@ -1282,9 +1331,6 @@ def _identify_words(probed, results, catalog: _Catalog, arch: str) -> None:
|
|
|
1282
1331
|
_rv_xlen_resolve(probed, results, catalog)
|
|
1283
1332
|
|
|
1284
1333
|
|
|
1285
|
-
_ENDBR_BYTES = {"f30f1efa": "ENDBR64", "f30f1efb": "ENDBR32"}
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
1334
|
def _identify_x86(probed, results, catalog: _Catalog, xed: str) -> None:
|
|
1289
1335
|
pending = []
|
|
1290
1336
|
for entry, result in zip(probed, results):
|
|
@@ -1300,7 +1346,7 @@ def _identify_x86(probed, results, catalog: _Catalog, xed: str) -> None:
|
|
|
1300
1346
|
if not pending:
|
|
1301
1347
|
return
|
|
1302
1348
|
hexes = [_bytes_to_words(entry.get("bytes")).hex() for entry, _result in pending]
|
|
1303
|
-
for (entry, result), facts
|
|
1349
|
+
for (entry, result), facts in zip(pending, _xed_facts(hexes, xed)):
|
|
1304
1350
|
# A fixup placeholder covers the immediate value (audit A1): the
|
|
1305
1351
|
# pick must not read it, and a row carrying an immzero claim about
|
|
1306
1352
|
# it would be a guess either way.
|
|
@@ -1308,8 +1354,7 @@ def _identify_x86(probed, results, catalog: _Catalog, xed: str) -> None:
|
|
|
1308
1354
|
if "error" in facts:
|
|
1309
1355
|
result.reason = f"no catalog row (XED {facts['error']})"
|
|
1310
1356
|
continue
|
|
1311
|
-
|
|
1312
|
-
pool = catalog.iform_pools.get(_ENDBR_BYTES.get(hexed, facts["iform"]), [])
|
|
1357
|
+
pool = catalog.iform_pools.get(facts["iform"], [])
|
|
1313
1358
|
if not pool:
|
|
1314
1359
|
result.reason = f"no catalog row (iform {facts['iform']} absent)"
|
|
1315
1360
|
continue
|