diff mbox series

[1/3] rust-target-config: armv8a AArch32 Thumb build fixes

Message ID 20260701-tune-a32-v1-1-a43f28b1d7a4@gmail.com
State New
Headers show
Series tune-cortexa32: AArch32 Thumb-2/crypto fixes, plus a QEMU machine | expand

Commit Message

Alex Kiernan July 1, 2026, 11:58 a.m. UTC
From: Alex Kiernan <alexk@a-squared-projects.uk>

llvm_features_from_tune() calls target_is_armv7() to gate both the +v7
LLVM feature and the +thumb2 feature. target_is_armv7() (in
rust-common.bbclass) only recognises armv7a/armv7r/armv7m/armv7ve -- it
returns False for armv8a.  As a result an ARMv8-A AArch32 Thumb build
gets "+neon,+thumb-mode" in the target JSON but neither "+v8" nor
"+thumb2".

LLVM's ParseARMTriple() returns "" for "arm-..." triples
(ARM::parseArch("arm") = INVALID), leaving HasV4TOps unset in the
MCSubtargetInfo used for module-level inline asm parsing.  The ARM ASM
parser's hasThumb() then returns false and ".thumb" directives in
compiler_builtins naked-function trampolines (__aeabi_uldivmod etc.)
are rejected.

This produces two failures when building libstd-rs / compiler_builtins:

  1. core: "LLVM ERROR: Cannot select: br" in core::fmt::num -- LLVM ARM
     ISel patterns for Thumb-2 unconditional branches (t2B) are gated on
     HasV8Ops as well as IsThumb2; without +v8 the pattern never fires.

  2. compiler_builtins: "target does not support Thumb mode" on .thumb
     directives in naked-function trampolines (__aeabi_uldivmod etc.) --
     two separate paths both require +thumb2: HasV4TOps in the
     MCSubtargetInfo (set transitively via ParseARMTriple) and
     FeatureThumb2 in the code-gen ARMSubtarget.

The natural fix would be to change RUST_TARGET_SYS to "armv8a-...", but
"armv8a" is not a recognised Rust target architecture so the triple is
not valid there.  Instead rust_sys_to_llvm_target() rewrites only the
JSON llvm-target field, leaving RUST_TARGET_SYS and rust-common.bbclass
unchanged.

- Add +v8 to llvm_features_from_tune for armv8a AArch32.

- Add +thumb2 to llvm_features_from_tune for armv8a AArch32 Thumb.

- Extend rust_sys_to_llvm_target() to accept the datastore and rewrite
  the "arm-..." triple to "armv8a-..." for armv8a AArch32 targets, so
  the JSON llvm-target field uses "armv8a-..." while RUST_TARGET_SYS
  keeps "arm-...".  ParseARMTriple then adds "+armv8-a" to the
  MCSubtargetInfo, transitively setting HasV4TOps and making hasThumb()
  return true.

The TARGET_ARCH == 'arm' guard is required because AArch64 tunes also
carry armv8a in TUNE_FEATURES (via arch-armv8a.inc) but must not be
affected.

AI-Generated: Claude Code (Claude Opus 4.8)
Signed-off-by: Alex Kiernan <alex.kiernan@gmail.com>
Signed-off-by: Alex Kiernan <alexk@a-squared-projects.uk>
---
 meta/classes-recipe/rust-target-config.bbclass | 21 ++++++++++++++++++---
 1 file changed, 18 insertions(+), 3 deletions(-)
diff mbox series

Patch

diff --git a/meta/classes-recipe/rust-target-config.bbclass b/meta/classes-recipe/rust-target-config.bbclass
index 941fe1958361..6acbe5e68834 100644
--- a/meta/classes-recipe/rust-target-config.bbclass
+++ b/meta/classes-recipe/rust-target-config.bbclass
@@ -19,6 +19,8 @@  def llvm_features_from_tune(d):
     mach_overrides = d.getVar('MACHINEOVERRIDES')
     mach_overrides = frozenset(mach_overrides.split(':'))
 
+    target_arch = d.getVar('TARGET_ARCH')
+
     if 'vfpv4' in feat:
         f.append("+vfp4")
     elif 'vfpv4d16' in feat:
@@ -46,6 +48,9 @@  def llvm_features_from_tune(d):
     if target_is_armv7(d):
         f.append('+v7')
 
+    if 'armv8a' in feat and target_arch == 'arm':
+        f.append('+v8')
+
     if ('armv6' in mach_overrides) or ('armv6' in feat):
         f.append("+v6")
     if 'armv5te' in feat:
@@ -63,7 +68,8 @@  def llvm_features_from_tune(d):
 
     if 'thumb' in feat:
         if d.getVar('ARM_THUMB_OPT') == "thumb":
-            if target_is_armv7(d):
+            if target_is_armv7(d) or \
+                    ('armv8a' in feat and target_arch == 'arm'):
                 f.append('+thumb2')
             f.append("+thumb-mode")
 
@@ -302,7 +308,16 @@  def arch_to_rust_target_arch(arch):
         return arch
 
 # Convert a rust target string to a llvm-compatible triplet
-def rust_sys_to_llvm_target(sys):
+def rust_sys_to_llvm_target(sys, d):
+    # For AArch32 ARMv8-A, RUST_TARGET_SYS stays "arm-..." because "armv8a" is not a
+    # valid Rust target architecture. Rewrite llvm-target to "armv8a-..." here so
+    # ParseARMTriple adds "+armv8-a" and transitively sets HasV4TOps in the
+    # MCSubtargetInfo used for module-level inline asm parsing, making hasThumb()
+    # return true for .thumb directives.
+    if sys.startswith('arm-') and \
+            'armv8a' in (d.getVar('TUNE_FEATURES') or '').split() and \
+            d.getVar('TARGET_ARCH') == 'arm':
+        return 'armv8a-' + sys[4:]
     return sys
 
 # generates our target CPU value
@@ -382,7 +397,7 @@  def rust_gen_target(d, thing, wd, arch):
 
     # build tspec
     tspec = {}
-    tspec['llvm-target'] = rust_sys_to_llvm_target(rustsys)
+    tspec['llvm-target'] = rust_sys_to_llvm_target(rustsys, d)
     tspec['data-layout'] = d.getVarFlag('DATA_LAYOUT', arch_abi)
     if tspec['data-layout'] is None:
         bb.fatal("No rust target defined for %s" % arch_abi)