Skip to content

Add Apple arm64e_x1 target feature (FEAT_PAuth_LR and FEAT_CPA2) - #9653

Draft
jpoumailloux wants to merge 7 commits into
halide:mainfrom
jpoumailloux:arm64e-x1-support
Draft

jpoumailloux wants to merge 7 commits into
halide:mainfrom
jpoumailloux:arm64e-x1-support

Conversation

@jpoumailloux

Copy link
Copy Markdown

Adds the arm64e_x1 target feature (Target::ARM64eX1 / halide_target_feature_arm64e_x1) for Apple's arm64e.x1 Mach-O architecture slice (FEAT_PAuth_LR and Checked Pointer Arithmetic FEAT_CPA2, introduced in Xcode 27).

Related discussion: #9651
(Note: Stacked on #9652; marked as draft until #9652 lands so the diff isolates the arm64e_x1 commit.)

Details

  • Target & Python bindings:
    • Adds halide_target_feature_arm64e_x1 / Target::ARM64eX1 / hl.TargetFeature.ARM64eX1 ("arm64e_x1"), valid on arm-64-ios and arm-64-macos.
    • Detects __arm64e_x1__ / __ARM_FEATURE_PAUTH_LR under __arm64e__ in calculate_host_target().
    • Implies arm64e, armv87a, arm_fp16, and arm_dot_prod (matching LLVM's HasV8_7aOps baseline on Apple CPUs without enabling FEAT_MOPS), and adds ARM64eX1 to matching_features in get_runtime_compatible_target().
  • CPU, feature attributes, & Mach-O output:
    • Selects apple-m5 (currently the newest Apple CPU model in LLVM) in CodeGen_ARM::mcpu_target() on both ios and macos when arm64e_x1 is set, and appends +pauth-lr and +cpa in CodeGen_ARM::mattrs().
    • Adds "branch-protection-pauth-lr" on non-intrinsic functions when +pauth-lr is present so function prologues/epilogues emit pacibsppc / retabsppc.
    • Enables -aarch64-use-featcpa-codegen=true in CodeGen_LLVM::initialize_llvm() after target registration (with &llvm::nulls() so it remains non-fatal if a future LLVM version removes the flag) so pointer arithmetic lowers to addpt / subpt / maddpt.
    • Clears opportunistic non-musttail tail-call markers on indirect ptrauth CallInsts when arm64e_x1 is enabled, as LLVM's AArch64 AUTH_TCRETURN lowering does not yet support branch-protection-pauth-lr.
    • Updates compile_llvm_module_to_object() to stamp mach_header_64.cpusubtype = 0x8000000c (CPU_SUBTYPE_ARM64E_X1 | 0x80000000) on Darwin arm64e Mach-O object outputs compiled with +cpa.

Testing

  • Extended test/correctness/target.cpp, python_bindings/halide/test/correctness/target.py, test/correctness/cross_compilation.cpp, and test/correctness/arm64e_codegen.cpp (verifying apple-m5, pacibsppc, retabsppc, addpt, and Mach-O cpusubtype == 0x8000000c for both pipeline and standalone runtime objects).

Checklist

  • Tests added or updated (not required for docs, CI config, or typo fixes)
  • Documentation updated (if public API changed)
  • Python bindings updated (if public API changed)
  • Benchmarks are included here if the change is intended to affect performance.
  • Commits include AI attribution where applicable (see Code of Conduct)

Generated with Gemini 3

@codecov

codecov Bot commented Nov 3, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 82.52788% with 47 lines in your changes missing coverage. Please review.
✅ Project coverage is 73.10%. Comparing base (d20180d) to head (17c85e0).
⚠️ Report is 12 commits behind head on main.

Files with missing lines Patch % Lines
src/CodeGen_Internal.cpp 78.75% 5 Missing and 12 partials ⚠️
src/Target.cpp 80.76% 9 Missing and 6 partials ⚠️
src/CodeGen_LLVM.cpp 83.78% 2 Missing and 4 partials ⚠️
src/JITModule.cpp 64.28% 2 Missing and 3 partials ⚠️
src/LLVM_Output.cpp 85.00% 0 Missing and 3 partials ⚠️
src/Module.cpp 95.65% 0 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #9653      +/-   ##
==========================================
+ Coverage   72.93%   73.10%   +0.17%     
==========================================
  Files         264      266       +2     
  Lines       83060    83555     +495     
  Branches    20399    20541     +142     
==========================================
+ Hits        60577    61085     +508     
- Misses      16117    16123       +6     
+ Partials     6366     6347      -19     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Add the `arm64e` target feature (`Target::ARM64e` /
`halide_target_feature_arm64e`) for 64-bit Darwin ARM targets (`ios` and
`macos`), enabling Apple's Pointer Authentication (PAC) ABI:

- Target definition & validation:
  - Detect `__arm64e__` in `calculate_host_target()` on Apple platforms.
  - Validate that `arm64e` is only used with 64-bit ARM on `ios` or `macos`.
  - Imply `armv83a` and `arm_fp16` when `arm64e` is enabled, and treat
    `ARM64e` as an ABI-matching feature in `get_runtime_compatible_target()`.
  - Expose `TargetFeature.ARM64e` in Python bindings.
- Triple & CPU selection:
  - Emit the `AArch64SubArch_arm64e` sub-architecture in
    `get_triple_for_target()` for `ios` and `macos` instead of overriding the
    macOS arch name to `arm64`.
  - Default `mcpu_target()` to `apple-a12` on iOS when `arm64e` is enabled.
- LLVM PAC codegen & JIT support:
  - Add `ptrauth-returns`, `ptrauth-calls`, `ptrauth-auth-traps`,
    `ptrauth-indirect-gotos`, and `aarch64-jump-table-hardening` function
    attributes on non-intrinsic functions when `triple.isArm64e()`.
  - Sign non-callee function references via `llvm::ConstantPtrAuth` (`IA` key 0,
    discriminator 0, matching Darwin userspace `arm64e`) and attach `"ptrauth"`
    operand bundles to indirect call sites across AOT and JIT modules.
  - Sign JIT-resolved function addresses via `llvm::orc::ExecutorAddr::toPtr`
    when building on `ptrauth_calls` hosts.
- Add target, cross-compilation, Python binding, and Mach-O / assembly / IR
  codegen tests.

Co-authored-by: Gemini 3 <gemini-code-assist@google.com>
jpoumailloux and others added 2 commits November 3, 2026 17:17
- Map `arm64e` on 64-bit `ios` and `macos` to `arm-64-(ios|macos)-arm64e` in
  `HalideTargetHelpers.cmake` (both `_Halide_cmake_target` and native
  single-arch `arm64e` host builds in `_Halide_host_target`).
- Support `arm-64-(ios|macos|osx)-arm64e` in `_Halide_set_osx_arch`,
  `FEATURES[<triple>]`, `_Halide_validate_multitarget`, `_Halide_is_crosscompiling`,
  and multi-arch `add_halide_runtime` slice filtering, and pin host generator
  `OSX_ARCHITECTURES` to `Halide_HOST_TARGET` when building multi-arch or
  consuming an imported `Halide::Generator` with a different Darwin ABI slice.
- Emit fat `arm64 + arm64e` `iphoneos` slices in `apps/HelloiOS` (`ARCHS =
  "$(ARCHS_STANDARD) arm64e"`), and add macOS CI steps building and verifying
  both `HelloiOS` (`iphoneos` `arm64 + arm64e`) and `test/integration/xc`
  (`CMAKE_OSX_ARCHITECTURES="arm64;arm64e"`).
- Document `arm-64-(ios|macos)-arm64e` CMake triples and `HelloiOS` slices.

Co-authored-by: Gemini 3 <gemini-code-assist@google.com>
- Initialize all words of `runtime_features` to `~uint64_t{0}` in
  `compile_multitarget()` and add `Target::ARM64e` to `must_match_features` so
  high-word target features (>= 64) are preserved on the shared runtime and
  mixed-PAC-ABI multitarget builds fail cleanly.
- Extract `CodeGen_LLVM::apply_target_options()` and invoke it when
  `JITSharedRuntime::get()` creates a standalone runtime module without
  `for_module`, and assert matching host/target `arm64e` PAC ABI in both
  `get_jit_target_from_environment()` and `compile_module_impl()`.
- Reject `arm64e` combined with `simulator` in `Target::validate_features()`.
- Preserve ascending `armv8*` lower-bound semantics for non-`arm64e` targets in
  `Target::get_arm_v8_lower_bound()` while clamping `arm64e` to at least `83`,
  and strip implied `armv8a`..`armv83a` bits from `arm64e` GCD outputs in
  `Target::get_runtime_compatible_target()`.
- Add `arm64e` static library, `compile_multitarget`, `with_implied_features()`
  GCD, and `arm-64-ios-arm64e-simulator` tests.

Co-authored-by: Gemini 3 <gemini-code-assist@google.com>
jpoumailloux and others added 3 commits November 3, 2026 18:32
Preserving high-word (>= 64) common features on runtime_target in compile_multitarget() exposed that runtime_target left vector_bits == 0, tripping CodeGen_ARM's SVE2 vector_bits assertion when all subtargets share SVE2 (e.g. host-profile-* on SVE2 ARM64 Linux).

Propagate vector_bits when uniform across all subtargets, clear SVE/SVE2/AVX10_1 when runtime_target.vector_bits == 0 (mixed vector_bits across subtargets), and clear SME2 when intersecting subtarget features clears all SME_SVL* bits. Add cross-compilation regression tests in compile_to_multitarget.cpp.

Co-authored-by: Gemini 3 <gemini-code-assist@google.com>
Add the `arm64e_x1` target feature (`Target::ARM64eX1` /
`halide_target_feature_arm64e_x1`) for Apple's `arm64e.x1` ABI slice on 64-bit
Darwin ARM (`ios` and `macos`):

- Target definition, host detection, & validation:
  - Detect `__arm64e_x1__` or active `pauth-lr` return-address signing
    (`__ARM_FEATURE_PAUTH_LR` with `__ARM_FEATURE_PAC_DEFAULT & (1 << 3)`) under
    `__arm64e__` in `calculate_host_target()`, and enforce matching 3-level PAC
    ABI (`none` / `arm64e` / `arm64e_x1`) in JIT validation.
  - Validate that `arm64e_x1` is only used with 64-bit ARM on `ios` or `macos`
    and cannot be combined with `simulator`.
  - Imply `arm64e`, `armv87a`, `arm_fp16`, and `arm_dot_prod` (matching LLVM's
    `HasV8_7aOps` baseline on Apple CPUs without enabling `FEAT_MOPS`), treat
    `ARM64eX1` as an ABI-matching feature in `get_runtime_compatible_target()`
    and `compile_multitarget()`, and strip implied `arm64e` and `armv8a`..`armv87a`
    bits from `arm64e_x1` GCD outputs.
  - Expose `TargetFeature.ARM64eX1` in Python bindings.
- CPU, feature attributes, & FEAT_CPA codegen:
  - Select `apple-m5` (currently the newest Apple CPU model in LLVM) in
    `CodeGen_ARM::mcpu_target()` on `ios` and `macos` when `arm64e_x1` is
    enabled, and append `+pauth-lr` and `+cpa` in `mattrs()`.
  - Record an explicit `"halide_arm64e_x1"` module flag in
    `CodeGen_LLVM::apply_target_options()` (and preserve it in
    `clone_target_options()`), using it to emit `"branch-protection-pauth-lr"`
    on non-intrinsic functions (`pacibsppc` / `retabsppc`) and to patch Darwin
    Mach-O `mach_header_64.cpusubtype` to `0x8000000c`
    (`CPU_SUBTYPE_ARM64E_X1 | 0x80000000`).
  - Enable `aarch64-use-featcpa-codegen` after `Initialize*Target()` via
    `cl::getRegisteredOptions()` when unset (falling back to
    `cl::ParseCommandLineOptions(..., &llvm::nulls())` for LLVM 24+ TableGen
    `LibraryOptions`) and before `HL_LLVM_ARGS` so `+cpa` lowers pointer
    indexing to `addpt` / `subpt` / `maddpt`.
  - Clear opportunistic non-`musttail` tail-call markers on indirect ptrauth
    `CallInst`s when `arm64e_x1` is active, since LLVM's AArch64 `AUTH_TCRETURN`
    lowering does not yet support `branch-protection-pauth-lr`.
- CMake & tests:
  - Support `arm64e.x1` / `arm-64-(ios|macos|osx)-arm64e_x1` in
    `HalideTargetHelpers.cmake`, `HalideGeneratorHelpers.cmake`, and
    `doc/HalideCMakePackage.md`.
  - Extend target, cross-compilation, Python binding, static library, and
    multitarget codegen tests.

Co-authored-by: Gemini 3 <gemini-code-assist@google.com>
- Wrap the arm64e/arm64e.x1 if-condition in cmake/HalideTargetHelpers.cmake
  to satisfy the cmtk pre-commit formatter.
- Use cl::Option::addOccurrence() instead of downcasting cl::Option* via
  static_cast<cl::opt<bool> *> in CodeGen_LLVM::initialize_llvm() to satisfy
  clang-tidy (cppcoreguidelines-pro-type-static-cast-downcast) under -fno-rtti.

Co-authored-by: Gemini 3 <gemini-code-assist@google.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant