Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions examples/models/llama/export_llama_lib.py
Original file line number Diff line number Diff line change
Expand Up @@ -1805,9 +1805,7 @@ def _export_llama(llm_config: LlmConfig) -> LLMEdgeManager: # noqa: C901
verbose=llm_config.debug.verbose,
)
elif llm_config.backend.coreml.enabled and not (
llm_config.backend.vulkan.enabled
or llm_config.backend.mps.enabled
or llm_config.backend.qnn.enabled
llm_config.backend.vulkan.enabled or llm_config.backend.qnn.enabled
):
builder = _to_edge_and_lower_llama_coreml(
builder_exported,
Expand Down
31 changes: 31 additions & 0 deletions examples/models/llama/tests/test_export_llama_lib.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
# LICENSE file in the root directory of this source tree.

import unittest
from unittest.mock import patch

from executorch.devtools.backend_debug import get_delegation_info

Expand Down Expand Up @@ -41,6 +42,36 @@


class ExportLlamaLibTest(unittest.TestCase):
def _assert_export_reaches(self, target, **backends):
"""Run an export and assert which lowering it routes to."""
llm_config = LlmConfig()
llm_config.backend.coreml.enabled = True
for name, enabled in backends.items():
getattr(llm_config.backend, name).enabled = enabled
# Core ML and QNN reject dynamic shapes, and _validate_args runs before the lowering.
llm_config.model.enable_dynamic_shape = False

with patch(
f"executorch.examples.models.llama.export_llama_lib.{target}",
side_effect=RuntimeError("reached"),
) as lowering:
with self.assertRaises(RuntimeError):
_export_llama(llm_config)
lowering.assert_called_once()

def test_core_ml_alone_reaches_the_core_ml_lowering(self):
"""The guard used to read a backend config field that no longer existed, so this raised
AttributeError before reaching any lowering."""
self._assert_export_reaches("_to_edge_and_lower_llama_coreml")

def test_core_ml_with_qnn_reaches_the_combined_lowering(self):
"""The other case the removed read broke, and the one that pins the exclusion clause.

Core ML with QNN must fall through to the combined lowering, which still lowers Core ML but
keeps the QNN partitioner. Without this, deleting the whole clause passes.
"""
self._assert_export_reaches("_to_edge_and_lower_llama", qnn=True)

def test_has_expected_ops_and_op_counts(self):
"""
Checks the presence of unwanted expensive ops.
Expand Down
Loading