simdref 0.0.1__tar.gz → 0.0.4__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.1/src/simdref.egg-info → simdref-0.0.4}/PKG-INFO +3 -2
- {simdref-0.0.1 → simdref-0.0.4}/README.md +1 -1
- {simdref-0.0.1 → simdref-0.0.4}/pyproject.toml +2 -1
- simdref-0.0.4/src/simdref/__init__.py +10 -0
- {simdref-0.0.1 → simdref-0.0.4}/src/simdref/annotate.py +3 -2
- {simdref-0.0.1 → simdref-0.0.4}/src/simdref/cli.py +107 -3
- {simdref-0.0.1 → simdref-0.0.4}/src/simdref/ingest_catalog.py +24 -0
- {simdref-0.0.1 → simdref-0.0.4}/src/simdref/perf.py +8 -1
- {simdref-0.0.1 → simdref-0.0.4}/src/simdref/storage.py +21 -1
- {simdref-0.0.1 → simdref-0.0.4}/src/simdref/templates/app.js +155 -28
- {simdref-0.0.1 → simdref-0.0.4}/src/simdref/tui.py +61 -21
- {simdref-0.0.1 → simdref-0.0.4}/src/simdref/web.py +60 -15
- {simdref-0.0.1 → simdref-0.0.4/src/simdref.egg-info}/PKG-INFO +3 -2
- {simdref-0.0.1 → simdref-0.0.4}/src/simdref.egg-info/SOURCES.txt +5 -0
- {simdref-0.0.1 → simdref-0.0.4}/src/simdref.egg-info/requires.txt +1 -0
- {simdref-0.0.1 → simdref-0.0.4}/tests/test_annotate.py +16 -0
- simdref-0.0.4/tests/test_auto_update_on_version_change.py +174 -0
- {simdref-0.0.1 → simdref-0.0.4}/tests/test_cli_llm.py +19 -0
- simdref-0.0.4/tests/test_intel_operation_and_url.py +119 -0
- {simdref-0.0.1 → simdref-0.0.4}/tests/test_lsp_web.py +21 -17
- {simdref-0.0.1 → simdref-0.0.4}/tests/test_perf.py +21 -0
- {simdref-0.0.1 → simdref-0.0.4}/tests/test_presentation.py +21 -8
- simdref-0.0.4/tests/test_search_index_js.py +34 -0
- {simdref-0.0.1 → simdref-0.0.4}/tests/test_storage_schema.py +3 -3
- simdref-0.0.4/tests/test_version_matches_pyproject.py +32 -0
- simdref-0.0.4/tests/test_web_e2e.py +201 -0
- simdref-0.0.1/src/simdref/__init__.py +0 -5
- {simdref-0.0.1 → simdref-0.0.4}/LICENSE +0 -0
- {simdref-0.0.1 → simdref-0.0.4}/setup.cfg +0 -0
- {simdref-0.0.1 → simdref-0.0.4}/src/simdref/__main__.py +0 -0
- {simdref-0.0.1 → simdref-0.0.4}/src/simdref/arm_instructions.py +0 -0
- {simdref-0.0.1 → simdref-0.0.4}/src/simdref/display.py +0 -0
- {simdref-0.0.1 → simdref-0.0.4}/src/simdref/filters.py +0 -0
- {simdref-0.0.1 → simdref-0.0.4}/src/simdref/ingest.py +0 -0
- {simdref-0.0.1 → simdref-0.0.4}/src/simdref/ingest_pdf.py +0 -0
- {simdref-0.0.1 → simdref-0.0.4}/src/simdref/ingest_sources.py +0 -0
- {simdref-0.0.1 → simdref-0.0.4}/src/simdref/lsp.py +0 -0
- {simdref-0.0.1 → simdref-0.0.4}/src/simdref/manpages.py +0 -0
- {simdref-0.0.1 → simdref-0.0.4}/src/simdref/models.py +0 -0
- {simdref-0.0.1 → simdref-0.0.4}/src/simdref/pdfparse/__init__.py +0 -0
- {simdref-0.0.1 → simdref-0.0.4}/src/simdref/pdfparse/base.py +0 -0
- {simdref-0.0.1 → simdref-0.0.4}/src/simdref/pdfparse/intel.py +0 -0
- {simdref-0.0.1 → simdref-0.0.4}/src/simdref/pdfparse/registry.py +0 -0
- {simdref-0.0.1 → simdref-0.0.4}/src/simdref/pdfparse/types.py +0 -0
- {simdref-0.0.1 → simdref-0.0.4}/src/simdref/pdfrefs.py +0 -0
- {simdref-0.0.1 → simdref-0.0.4}/src/simdref/perf_sources/__init__.py +0 -0
- {simdref-0.0.1 → simdref-0.0.4}/src/simdref/perf_sources/cores.py +0 -0
- {simdref-0.0.1 → simdref-0.0.4}/src/simdref/perf_sources/llvm_mca.py +0 -0
- {simdref-0.0.1 → simdref-0.0.4}/src/simdref/perf_sources/llvm_scheduling.py +0 -0
- {simdref-0.0.1 → simdref-0.0.4}/src/simdref/perf_sources/merge.py +0 -0
- {simdref-0.0.1 → simdref-0.0.4}/src/simdref/profile/__init__.py +0 -0
- {simdref-0.0.1 → simdref-0.0.4}/src/simdref/profile/adapters/__init__.py +0 -0
- {simdref-0.0.1 → simdref-0.0.4}/src/simdref/profile/adapters/exegesis.py +0 -0
- {simdref-0.0.1 → simdref-0.0.4}/src/simdref/profile/adapters/mca.py +0 -0
- {simdref-0.0.1 → simdref-0.0.4}/src/simdref/profile/adapters/perf.py +0 -0
- {simdref-0.0.1 → simdref-0.0.4}/src/simdref/profile/adapters/uprof.py +0 -0
- {simdref-0.0.1 → simdref-0.0.4}/src/simdref/profile/adapters/vtune.py +0 -0
- {simdref-0.0.1 → simdref-0.0.4}/src/simdref/profile/adapters/xctrace.py +0 -0
- {simdref-0.0.1 → simdref-0.0.4}/src/simdref/profile/hotloop.py +0 -0
- {simdref-0.0.1 → simdref-0.0.4}/src/simdref/profile/merge.py +0 -0
- {simdref-0.0.1 → simdref-0.0.4}/src/simdref/profile/model.py +0 -0
- {simdref-0.0.1 → simdref-0.0.4}/src/simdref/profile/orchestrate.py +0 -0
- {simdref-0.0.1 → simdref-0.0.4}/src/simdref/profile/registry.py +0 -0
- {simdref-0.0.1 → simdref-0.0.4}/src/simdref/queries.py +0 -0
- {simdref-0.0.1 → simdref-0.0.4}/src/simdref/riscv.py +0 -0
- {simdref-0.0.1 → simdref-0.0.4}/src/simdref/search.py +0 -0
- {simdref-0.0.1 → simdref-0.0.4}/src/simdref/templates/__init__.py +0 -0
- {simdref-0.0.1 → simdref-0.0.4}/src/simdref/templates/favicon.svg +0 -0
- {simdref-0.0.1 → simdref-0.0.4}/src/simdref/templates/index.html +0 -0
- {simdref-0.0.1 → simdref-0.0.4}/src/simdref/templates/logo.svg +0 -0
- {simdref-0.0.1 → simdref-0.0.4}/src/simdref/templates/style.css +0 -0
- {simdref-0.0.1 → simdref-0.0.4}/src/simdref/ui_labels.py +0 -0
- {simdref-0.0.1 → simdref-0.0.4}/src/simdref.egg-info/dependency_links.txt +0 -0
- {simdref-0.0.1 → simdref-0.0.4}/src/simdref.egg-info/entry_points.txt +0 -0
- {simdref-0.0.1 → simdref-0.0.4}/src/simdref.egg-info/top_level.txt +0 -0
- {simdref-0.0.1 → simdref-0.0.4}/tests/test_audit_coverage.py +0 -0
- {simdref-0.0.1 → simdref-0.0.4}/tests/test_cli_bare_query.py +0 -0
- {simdref-0.0.1 → simdref-0.0.4}/tests/test_cli_bootstrap_progress.py +0 -0
- {simdref-0.0.1 → simdref-0.0.4}/tests/test_cli_help.py +0 -0
- {simdref-0.0.1 → simdref-0.0.4}/tests/test_coverage_live.py +0 -0
- {simdref-0.0.1 → simdref-0.0.4}/tests/test_coverage_parity.py +0 -0
- {simdref-0.0.1 → simdref-0.0.4}/tests/test_display.py +0 -0
- {simdref-0.0.1 → simdref-0.0.4}/tests/test_filters.py +0 -0
- {simdref-0.0.1 → simdref-0.0.4}/tests/test_ingest_sources.py +0 -0
- {simdref-0.0.1 → simdref-0.0.4}/tests/test_issue2_fixes.py +0 -0
- {simdref-0.0.1 → simdref-0.0.4}/tests/test_models.py +0 -0
- {simdref-0.0.1 → simdref-0.0.4}/tests/test_pdfparse.py +0 -0
- {simdref-0.0.1 → simdref-0.0.4}/tests/test_perf_sources.py +0 -0
- {simdref-0.0.1 → simdref-0.0.4}/tests/test_preset_persistence.py +0 -0
- {simdref-0.0.1 → simdref-0.0.4}/tests/test_search.py +0 -0
- {simdref-0.0.1 → simdref-0.0.4}/tests/test_search_pushdown.py +0 -0
- {simdref-0.0.1 → simdref-0.0.4}/tests/test_source_kind_filter.py +0 -0
- {simdref-0.0.1 → simdref-0.0.4}/tests/test_source_validation.py +0 -0
- {simdref-0.0.1 → simdref-0.0.4}/tests/test_tui.py +0 -0
- {simdref-0.0.1 → simdref-0.0.4}/tests/test_ui_labels_parity.py +0 -0
- {simdref-0.0.1 → simdref-0.0.4}/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.4
|
|
4
4
|
Summary: Searchable SIMD intrinsic and instruction reference with CLI, manpages, TUI, LSP, and static web export.
|
|
5
5
|
Author: Marco
|
|
6
6
|
License: GPL-3.0-or-later
|
|
@@ -18,6 +18,7 @@ Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
|
18
18
|
Requires-Python: >=3.11
|
|
19
19
|
Description-Content-Type: text/markdown
|
|
20
20
|
License-File: LICENSE
|
|
21
|
+
Requires-Dist: click<10,>=8.1
|
|
21
22
|
Requires-Dist: httpx<1,>=0.28
|
|
22
23
|
Requires-Dist: msgpack<2,>=1.0
|
|
23
24
|
Requires-Dist: pdfplumber<1,>=0.11
|
|
@@ -33,7 +34,7 @@ Dynamic: license-file
|
|
|
33
34
|
|
|
34
35
|
[](https://github.com/DiamonDinoia/simdref/actions/workflows/ci.yml)
|
|
35
36
|
[](https://test.pypi.org/project/simdref/)
|
|
36
|
-
[](https://
|
|
37
|
+
[](https://pypi.org/project/simdref/)
|
|
37
38
|
|
|
38
39
|
A single searchable reference for SIMD intrinsics and instructions across
|
|
39
40
|
**x86 (Intel + uops.info)**, **Arm (ACLE / AARCHMRS)**, and **RISC-V
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://github.com/DiamonDinoia/simdref/actions/workflows/ci.yml)
|
|
4
4
|
[](https://test.pypi.org/project/simdref/)
|
|
5
|
-
[](https://
|
|
5
|
+
[](https://pypi.org/project/simdref/)
|
|
6
6
|
|
|
7
7
|
A single searchable reference for SIMD intrinsics and instructions across
|
|
8
8
|
**x86 (Intel + uops.info)**, **Arm (ACLE / AARCHMRS)**, and **RISC-V
|
|
@@ -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.4"
|
|
8
8
|
description = "Searchable SIMD intrinsic and instruction reference with CLI, manpages, TUI, LSP, and static web export."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.11"
|
|
@@ -26,6 +26,7 @@ classifiers = [
|
|
|
26
26
|
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
27
27
|
]
|
|
28
28
|
dependencies = [
|
|
29
|
+
"click>=8.1,<10",
|
|
29
30
|
"httpx>=0.28,<1",
|
|
30
31
|
"msgpack>=1.0,<2",
|
|
31
32
|
"pdfplumber>=0.11,<1",
|
|
@@ -68,8 +68,6 @@ def parse_asm_line(line: str, *, track_positions: bool = False) -> AsmLine:
|
|
|
68
68
|
return AsmLine(LineKind.COMMENT, stripped)
|
|
69
69
|
if bare.startswith("."):
|
|
70
70
|
return AsmLine(LineKind.DIRECTIVE, stripped)
|
|
71
|
-
if _LABEL_RE.match(stripped):
|
|
72
|
-
return AsmLine(LineKind.LABEL, stripped)
|
|
73
71
|
|
|
74
72
|
address: int | None = None
|
|
75
73
|
if track_positions:
|
|
@@ -97,6 +95,9 @@ def parse_asm_line(line: str, *, track_positions: bool = False) -> AsmLine:
|
|
|
97
95
|
# source keywords ("return", "if", "for", ...) as mnemonics.
|
|
98
96
|
return AsmLine(LineKind.COMMENT, stripped)
|
|
99
97
|
|
|
98
|
+
if _LABEL_RE.match(stripped):
|
|
99
|
+
return AsmLine(LineKind.LABEL, stripped)
|
|
100
|
+
|
|
100
101
|
m = _INSTR_RE.match(stripped)
|
|
101
102
|
if not m:
|
|
102
103
|
return AsmLine(LineKind.COMMENT, stripped)
|
|
@@ -70,6 +70,7 @@ from simdref.ingest_sources import (
|
|
|
70
70
|
refresh_local_arm_intrinsics_bundle,
|
|
71
71
|
)
|
|
72
72
|
from simdref.manpages import open_manpage, write_manpages
|
|
73
|
+
from simdref import perf
|
|
73
74
|
from simdref.perf import variant_perf_summary
|
|
74
75
|
from simdref.queries import intrinsic_perf_summary_runtime, instruction_rows_for_intrinsic
|
|
75
76
|
from simdref.search import (
|
|
@@ -92,10 +93,12 @@ from simdref.storage import (
|
|
|
92
93
|
load_instructions_by_mnemonic_from_db,
|
|
93
94
|
load_instructions_by_mnemonic_prefix_from_db,
|
|
94
95
|
open_db,
|
|
96
|
+
read_installed_version_stamp,
|
|
95
97
|
save_catalog,
|
|
96
98
|
search_instruction_candidates_from_db,
|
|
97
99
|
search_intrinsic_candidates_from_db,
|
|
98
100
|
sqlite_schema_is_current,
|
|
101
|
+
write_installed_version_stamp,
|
|
99
102
|
)
|
|
100
103
|
from simdref.web import export_web
|
|
101
104
|
|
|
@@ -287,6 +290,18 @@ def _download_from_release() -> None:
|
|
|
287
290
|
f"failed to download {asset}: {exc.response.status_code}", style="red"
|
|
288
291
|
)
|
|
289
292
|
raise typer.Exit(code=1) from exc
|
|
293
|
+
except (
|
|
294
|
+
httpx.ConnectError,
|
|
295
|
+
httpx.ConnectTimeout,
|
|
296
|
+
httpx.ReadTimeout,
|
|
297
|
+
httpx.NetworkError,
|
|
298
|
+
) as exc:
|
|
299
|
+
err_console.print(
|
|
300
|
+
"[bold yellow]warning:[/bold yellow] no internet connectivity — "
|
|
301
|
+
f"could not reach the release server ({exc.__class__.__name__}). "
|
|
302
|
+
"Some features may not work correctly until the catalog is refreshed.",
|
|
303
|
+
)
|
|
304
|
+
raise typer.Exit(code=1) from exc
|
|
290
305
|
return False
|
|
291
306
|
|
|
292
307
|
for asset in ("catalog.msgpack", "catalog.db"):
|
|
@@ -444,6 +459,7 @@ def _build_runtime_locally(*, man_dir: Path, include_sdm: bool = False) -> None:
|
|
|
444
459
|
f"updated catalog with {len(catalog.intrinsics)} intrinsics and {len(catalog.instructions)} instructions",
|
|
445
460
|
style="green",
|
|
446
461
|
)
|
|
462
|
+
write_installed_version_stamp(__version__)
|
|
447
463
|
|
|
448
464
|
|
|
449
465
|
def _refresh_runtime_from_existing_catalog(*, man_dir: Path) -> None:
|
|
@@ -463,6 +479,7 @@ def _refresh_runtime_from_existing_catalog(*, man_dir: Path) -> None:
|
|
|
463
479
|
f"refreshed runtime from existing catalog with {len(catalog.intrinsics)} intrinsics and {len(catalog.instructions)} instructions",
|
|
464
480
|
style="green",
|
|
465
481
|
)
|
|
482
|
+
write_installed_version_stamp(__version__)
|
|
466
483
|
|
|
467
484
|
|
|
468
485
|
def _finalize_runtime_from_download(*, man_dir: Path) -> None:
|
|
@@ -476,6 +493,7 @@ def _finalize_runtime_from_download(*, man_dir: Path) -> None:
|
|
|
476
493
|
f"refreshed local web/man assets from downloaded catalog with {len(catalog.intrinsics)} intrinsics and {len(catalog.instructions)} instructions",
|
|
477
494
|
style="green",
|
|
478
495
|
)
|
|
496
|
+
write_installed_version_stamp(__version__)
|
|
479
497
|
|
|
480
498
|
|
|
481
499
|
def _download_release_or_fallback(*, man_dir: Path) -> None:
|
|
@@ -559,9 +577,16 @@ def ensure_catalog():
|
|
|
559
577
|
|
|
560
578
|
|
|
561
579
|
def ensure_runtime() -> None:
|
|
562
|
-
"""Ensure catalog + SQLite are present and current.
|
|
580
|
+
"""Ensure catalog + SQLite are present and current.
|
|
581
|
+
|
|
582
|
+
If the package version recorded in the data dir does not match the
|
|
583
|
+
currently installed version, transparently re-run the release-download
|
|
584
|
+
flow so users don't need to invoke ``simdref update`` manually after
|
|
585
|
+
a ``pip``/``uv`` install or upgrade. Honors ``SIMDREF_SKIP_AUTOUPDATE``.
|
|
586
|
+
"""
|
|
563
587
|
if not CATALOG_PATH.exists():
|
|
564
588
|
_bootstrap_interactive()
|
|
589
|
+
_maybe_auto_update_for_version_change()
|
|
565
590
|
return
|
|
566
591
|
if not sqlite_schema_is_current():
|
|
567
592
|
err_console.print(
|
|
@@ -569,6 +594,37 @@ def ensure_runtime() -> None:
|
|
|
569
594
|
style="yellow",
|
|
570
595
|
)
|
|
571
596
|
_refresh_runtime_from_existing_catalog(man_dir=DEFAULT_MAN_DIR)
|
|
597
|
+
_maybe_auto_update_for_version_change()
|
|
598
|
+
|
|
599
|
+
|
|
600
|
+
def _maybe_auto_update_for_version_change() -> None:
|
|
601
|
+
"""Refresh data when the package version differs from the stamped one."""
|
|
602
|
+
if os.environ.get("SIMDREF_SKIP_AUTOUPDATE"):
|
|
603
|
+
return
|
|
604
|
+
stamped = read_installed_version_stamp()
|
|
605
|
+
if stamped == __version__:
|
|
606
|
+
return
|
|
607
|
+
if stamped is None:
|
|
608
|
+
# First run after install: stamp without re-downloading. The catalog
|
|
609
|
+
# we just bootstrapped (or that already exists locally) is what the
|
|
610
|
+
# user expects to see.
|
|
611
|
+
write_installed_version_stamp(__version__)
|
|
612
|
+
return
|
|
613
|
+
err_console.print(
|
|
614
|
+
f"simdref upgraded from {stamped} to {__version__}; refreshing catalog "
|
|
615
|
+
"(set SIMDREF_SKIP_AUTOUPDATE=1 to disable)",
|
|
616
|
+
style="yellow",
|
|
617
|
+
)
|
|
618
|
+
try:
|
|
619
|
+
_download_release_or_fallback(man_dir=DEFAULT_MAN_DIR)
|
|
620
|
+
except typer.Exit:
|
|
621
|
+
err_console.print(
|
|
622
|
+
"[bold yellow]warning:[/bold yellow] auto-update failed; continuing with the existing catalog. "
|
|
623
|
+
"Some features may not work correctly until `simdref update` succeeds.",
|
|
624
|
+
)
|
|
625
|
+
# Stamp anyway so we don't retry on every invocation; the user has
|
|
626
|
+
# been warned and can re-run `simdref update` once back online.
|
|
627
|
+
write_installed_version_stamp(__version__)
|
|
572
628
|
|
|
573
629
|
|
|
574
630
|
def _catalog_meta(catalog) -> dict:
|
|
@@ -700,10 +756,11 @@ def _llm_result_payload(
|
|
|
700
756
|
intrinsic_map[result.key] = item
|
|
701
757
|
if item is not None:
|
|
702
758
|
lat, cpi = intrinsic_perf_summary_runtime(conn, item, instruction_map)
|
|
703
|
-
|
|
759
|
+
payload: dict = {
|
|
704
760
|
"query": item.name,
|
|
705
761
|
"intrinsic": item.name,
|
|
706
762
|
"signature": item.signature,
|
|
763
|
+
"url": getattr(item, "url", "") or "",
|
|
707
764
|
"instructions": item.instructions,
|
|
708
765
|
"instruction_refs": item.instruction_refs,
|
|
709
766
|
"summary": item.description,
|
|
@@ -711,6 +768,10 @@ def _llm_result_payload(
|
|
|
711
768
|
"lat": lat,
|
|
712
769
|
"cpi": cpi,
|
|
713
770
|
}
|
|
771
|
+
operation = _intrinsic_operation_text(item)
|
|
772
|
+
if operation:
|
|
773
|
+
payload["operation"] = operation
|
|
774
|
+
return payload
|
|
714
775
|
item = instruction_map.get(result.key)
|
|
715
776
|
if item is None:
|
|
716
777
|
item = load_instruction_from_db(conn, result.key)
|
|
@@ -739,7 +800,7 @@ def _llm_result_payload(
|
|
|
739
800
|
def _llm_intrinsic_payload(conn, intrinsic) -> dict:
|
|
740
801
|
instruction_map: dict[str, object] = {}
|
|
741
802
|
lat, cpi = intrinsic_perf_summary_runtime(conn, intrinsic, instruction_map)
|
|
742
|
-
|
|
803
|
+
payload: dict = {
|
|
743
804
|
"query": intrinsic.name,
|
|
744
805
|
"intrinsic": intrinsic.name,
|
|
745
806
|
"signature": intrinsic.signature,
|
|
@@ -751,6 +812,23 @@ def _llm_intrinsic_payload(conn, intrinsic) -> dict:
|
|
|
751
812
|
"cpi": cpi,
|
|
752
813
|
"summary": intrinsic.description,
|
|
753
814
|
}
|
|
815
|
+
operation = _intrinsic_operation_text(intrinsic)
|
|
816
|
+
if operation:
|
|
817
|
+
# Encodes algorithmic quirks (e.g. the bit-1 selector in
|
|
818
|
+
# ``_mm_permutevar_pd``) that the one-line summary cannot convey.
|
|
819
|
+
payload["operation"] = operation
|
|
820
|
+
return payload
|
|
821
|
+
|
|
822
|
+
|
|
823
|
+
def _intrinsic_operation_text(intrinsic) -> str:
|
|
824
|
+
"""Return the SDM-style ``Operation`` pseudocode for *intrinsic*, or ``""``.
|
|
825
|
+
|
|
826
|
+
Intel ingest stores it under ``doc_sections["Operation"]``; ARM ACLE under
|
|
827
|
+
``doc_sections["ACLE Operation"]``. Both are pseudocode the LLM payload
|
|
828
|
+
needs to surface so callers can reason about behavior beyond the summary.
|
|
829
|
+
"""
|
|
830
|
+
sections = getattr(intrinsic, "doc_sections", None) or {}
|
|
831
|
+
return (sections.get("Operation") or sections.get("ACLE Operation") or "").strip()
|
|
754
832
|
|
|
755
833
|
|
|
756
834
|
def _llm_instruction_payload(item) -> dict:
|
|
@@ -762,9 +840,24 @@ def _llm_instruction_payload(item) -> dict:
|
|
|
762
840
|
"lat": lat,
|
|
763
841
|
"cpi": cpi,
|
|
764
842
|
"summary": item.summary,
|
|
843
|
+
"source_kinds": _payload_source_kinds(item.arch_details),
|
|
765
844
|
}
|
|
766
845
|
|
|
767
846
|
|
|
847
|
+
def _payload_source_kinds(arch_details) -> list[str]:
|
|
848
|
+
"""Return the distinct provenance kinds present in an instruction's arch_details."""
|
|
849
|
+
if not isinstance(arch_details, dict):
|
|
850
|
+
return []
|
|
851
|
+
kinds: list[str] = []
|
|
852
|
+
for details in arch_details.values():
|
|
853
|
+
if not isinstance(details, dict):
|
|
854
|
+
continue
|
|
855
|
+
kind = perf._source_kind(details)
|
|
856
|
+
if kind not in kinds:
|
|
857
|
+
kinds.append(kind)
|
|
858
|
+
return kinds
|
|
859
|
+
|
|
860
|
+
|
|
768
861
|
# ---------------------------------------------------------------------------
|
|
769
862
|
# Search results
|
|
770
863
|
# ---------------------------------------------------------------------------
|
|
@@ -1184,6 +1277,9 @@ def _llm_filter_records(
|
|
|
1184
1277
|
|
|
1185
1278
|
def _record_has_source_kind(rec: dict, wanted: str) -> bool:
|
|
1186
1279
|
"""Check whether an llm payload dict carries at least one entry with *wanted* provenance."""
|
|
1280
|
+
slim = rec.get("source_kinds")
|
|
1281
|
+
if isinstance(slim, list) and any(k == wanted for k in slim):
|
|
1282
|
+
return True
|
|
1187
1283
|
arch_details = rec.get("arch_details") or {}
|
|
1188
1284
|
if isinstance(arch_details, dict):
|
|
1189
1285
|
for details in arch_details.values():
|
|
@@ -1323,6 +1419,14 @@ def _llm_schema_payload() -> dict:
|
|
|
1323
1419
|
"lat": {"type": "string"},
|
|
1324
1420
|
"cpi": {"type": "string"},
|
|
1325
1421
|
"summary": {"type": "string"},
|
|
1422
|
+
"url": {
|
|
1423
|
+
"type": "string",
|
|
1424
|
+
"description": "Vendor documentation URL (Intel Intrinsics Guide / ARM ACLE).",
|
|
1425
|
+
},
|
|
1426
|
+
"operation": {
|
|
1427
|
+
"type": "string",
|
|
1428
|
+
"description": "SDM-style pseudocode describing the intrinsic's behavior, when available.",
|
|
1429
|
+
},
|
|
1326
1430
|
},
|
|
1327
1431
|
},
|
|
1328
1432
|
"results": {"type": "array", "items": {"$ref": "#/properties/result"}},
|
|
@@ -275,6 +275,13 @@ def parse_intel_payload(text: str) -> list[IntrinsicRecord]:
|
|
|
275
275
|
name = node.attrib.get("name", "").strip()
|
|
276
276
|
if not name:
|
|
277
277
|
continue
|
|
278
|
+
operation_text = ""
|
|
279
|
+
op_node = node.find("./operation")
|
|
280
|
+
if op_node is not None:
|
|
281
|
+
# ``<operation>`` carries SDM-style pseudocode; preserve internal
|
|
282
|
+
# whitespace (it encodes the algorithm) but trim outer padding.
|
|
283
|
+
raw = "".join(op_node.itertext())
|
|
284
|
+
operation_text = raw.strip("\n").rstrip() if raw else ""
|
|
278
285
|
return_node = node.find("./return")
|
|
279
286
|
ret = (
|
|
280
287
|
node.attrib.get("rettype", "").strip()
|
|
@@ -321,6 +328,7 @@ def parse_intel_payload(text: str) -> list[IntrinsicRecord]:
|
|
|
321
328
|
header=(
|
|
322
329
|
(node.findtext("./header") or "").strip() or node.attrib.get("header", "")
|
|
323
330
|
),
|
|
331
|
+
url=_intel_intrinsic_url(name),
|
|
324
332
|
architecture="x86",
|
|
325
333
|
isa=_normalize_isa(
|
|
326
334
|
cpuid or node.attrib.get("isa", "") or node.attrib.get("tech", "")
|
|
@@ -332,6 +340,7 @@ def parse_intel_payload(text: str) -> list[IntrinsicRecord]:
|
|
|
332
340
|
subcategory=node.attrib.get("tech", "").strip(),
|
|
333
341
|
instructions=instructions,
|
|
334
342
|
instruction_refs=[ref | {"architecture": "x86"} for ref in instruction_refs],
|
|
343
|
+
doc_sections=({"Operation": operation_text} if operation_text else {}),
|
|
335
344
|
notes=notes,
|
|
336
345
|
aliases=[],
|
|
337
346
|
)
|
|
@@ -384,12 +393,16 @@ def parse_intel_payload(text: str) -> list[IntrinsicRecord]:
|
|
|
384
393
|
description = str(
|
|
385
394
|
item.get("description") or item.get("summary") or item.get("technology", "")
|
|
386
395
|
).strip()
|
|
396
|
+
operation_text = (
|
|
397
|
+
str(item.get("operation") or item.get("Operation") or "").strip("\n").rstrip()
|
|
398
|
+
)
|
|
387
399
|
records.append(
|
|
388
400
|
IntrinsicRecord(
|
|
389
401
|
name=name,
|
|
390
402
|
signature=signature,
|
|
391
403
|
description=description,
|
|
392
404
|
header=str(item.get("header") or item.get("include") or "").strip(),
|
|
405
|
+
url=str(item.get("url") or "").strip() or _intel_intrinsic_url(name),
|
|
393
406
|
architecture="x86",
|
|
394
407
|
isa=_normalize_isa(
|
|
395
408
|
item.get("isa") or item.get("tech") or item.get("instructionSet") or []
|
|
@@ -402,6 +415,7 @@ def parse_intel_payload(text: str) -> list[IntrinsicRecord]:
|
|
|
402
415
|
for value in instructions
|
|
403
416
|
if str(value).strip()
|
|
404
417
|
],
|
|
418
|
+
doc_sections=({"Operation": operation_text} if operation_text else {}),
|
|
405
419
|
notes=[str(value).strip() for value in notes if str(value).strip()],
|
|
406
420
|
aliases=[str(value).strip() for value in aliases if str(value).strip()],
|
|
407
421
|
)
|
|
@@ -476,6 +490,16 @@ def _arm_intrinsic_url(name: str) -> str:
|
|
|
476
490
|
return urljoin(_ARM_ACLE_INTRINSIC_BASE_URL, quote(name))
|
|
477
491
|
|
|
478
492
|
|
|
493
|
+
_INTEL_INTRINSIC_BASE_URL = (
|
|
494
|
+
"https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html"
|
|
495
|
+
)
|
|
496
|
+
|
|
497
|
+
|
|
498
|
+
def _intel_intrinsic_url(name: str) -> str:
|
|
499
|
+
"""Stable Intel Intrinsics Guide deep link for *name* (uses ``#text=`` fragment)."""
|
|
500
|
+
return f"{_INTEL_INTRINSIC_BASE_URL}#text={quote(name)}"
|
|
501
|
+
|
|
502
|
+
|
|
479
503
|
def _arm_slug(text: str) -> str:
|
|
480
504
|
slug = re.sub(r"[^a-z0-9]+", "-", text.casefold()).strip("-")
|
|
481
505
|
return slug or "intrinsics"
|
|
@@ -70,9 +70,16 @@ def latency_cycle_values(latencies: list[dict[str, Any]]) -> list[str]:
|
|
|
70
70
|
"""
|
|
71
71
|
values: list[str] = []
|
|
72
72
|
for latency in latencies:
|
|
73
|
+
mem_is_upper = latency.get("cycles_mem_is_upper_bound") == "1"
|
|
73
74
|
for key in ("cycles", "cycles_mem", "cycles_addr", "cycles_addr_index"):
|
|
74
75
|
value = latency.get(key)
|
|
75
|
-
if
|
|
76
|
+
if not value:
|
|
77
|
+
continue
|
|
78
|
+
if key == "cycles_mem" and mem_is_upper and _is_numeric(value) and float(value) == 0:
|
|
79
|
+
# uops.info convention: cycles_mem=0 with the upper-bound flag
|
|
80
|
+
# is a "not measured" marker, not a real zero-cycle latency.
|
|
81
|
+
continue
|
|
82
|
+
if value not in values:
|
|
76
83
|
values.append(value)
|
|
77
84
|
return values
|
|
78
85
|
|
|
@@ -82,7 +82,27 @@ else:
|
|
|
82
82
|
|
|
83
83
|
CATALOG_PATH = DATA_DIR / "catalog.msgpack"
|
|
84
84
|
SQLITE_PATH = DATA_DIR / "catalog.db"
|
|
85
|
-
|
|
85
|
+
INSTALLED_VERSION_STAMP = DATA_DIR / "installed_version"
|
|
86
|
+
SQLITE_SCHEMA_VERSION = "12"
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def read_installed_version_stamp() -> str | None:
|
|
90
|
+
"""Return the package version that last refreshed the data dir, or None."""
|
|
91
|
+
try:
|
|
92
|
+
return INSTALLED_VERSION_STAMP.read_text(encoding="utf-8").strip() or None
|
|
93
|
+
except OSError:
|
|
94
|
+
return None
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def write_installed_version_stamp(version: str) -> None:
|
|
98
|
+
"""Record the package version that just refreshed the data dir."""
|
|
99
|
+
try:
|
|
100
|
+
INSTALLED_VERSION_STAMP.parent.mkdir(parents=True, exist_ok=True)
|
|
101
|
+
INSTALLED_VERSION_STAMP.write_text(version.strip() + "\n", encoding="utf-8")
|
|
102
|
+
except OSError:
|
|
103
|
+
pass # best-effort — stamp persistence must not break commands
|
|
104
|
+
|
|
105
|
+
|
|
86
106
|
FTS_TOKEN_RE = re.compile(r"[A-Za-z0-9]+")
|
|
87
107
|
SQLITE_INSERT_BATCH_SIZE = 512
|
|
88
108
|
|