ARM arch in Build system help

I'm still working on a rust-lang toolchain for OpenWrt, and someone testing ran into issues with the FPU for arm_cortex-a7+neon-vfpv4.

Currently, I am defining arm arch in rust as arm_openwrt_linux_muslgnueabi, basically arm_unknown_linux_musleabi (which LLVMs to arm-unknown-linux-gnueabi)

So, few questions. How can I check for armv7 vs arm? And, what triple should it be? Armv7 Soft-float or Armv7 Hardfloat? How many arm targets should I be differentiating?

Ah, this appears to be OpenWrt not splitting the values out in ./include/target.mk perhaps?

RUSTC_TARGET_ARCH:=$(REAL_GNU_TARGET_NAME) is how I call my toolchain triples. It's passing arm-openwrt-linux-muslgnueabi as $(REAL_GNU_TARGET_NAME)

bump. I need to figure this out, or cut arm support for rust-lang until it gets figured out :frowning:

why not simply using $ARCH ?
I get a similar problem with GO, but do not remember how I fixed it...
I will try to find out in my notes

$ARCH returns arm. I was using $(REAL_GNU_TARGET_NAME) to set the toolchain triple. ./include/target.mk doesn't split out by ARCH, but by FEATURES it looks like.

If you faced this in go-lang, I'll just check there to see what I can find. For now, I think I'm just going to force arm-openwrt-linux-musblgnuabi to be hf with neon support.

$(REAL_GNU_TARGET_NAME) should return arm, armv7, armv8, etc, but it doesn't.

This is what I've ended up with, which seems to work for sorting (the triples are still wrong, I think, but.)

IS_ARMV7:=$(if $CPU_TYPE, $(filter $CPU_TYPE, cortext-a5 cortex-a7 \
            cortex-a8 cortex-a9 cortex-a12 cortex-a15 cortex-a17),NULL)
IS_ARMV8:=$(if $CPU_TYPE, $(filter $CPU_TYPE, cortex-a32 cortex-a34 \
            cortex-a35 cortex-a53 cortex-a55 cortex-a57 cortex-a72 \
            cortex-a73 cortex-a75 cortex-a76 cortex-a77 cortex-a78 \
            cortex-a510 cortex-a710),NULL)

ifneq ( $IS_ARMV7, )
RUSTC_TARGET_ARCH:=armv7-openwrt-linux-muslgnuabihf
endif
ifneq ( $IS_ARMV8, )
RUSTC_TARGET_ARCH:=armv7-openwrt-linux-muslgnuabihf
endif

soft vs. hard float is decided based on CPU_SUBTYPE, and there are plenty of options....
ARMv8 is basically aarch64, so no need to handle those for arm (ie. 32-bit) builds. From what I could tell, aarch64 was fine already.

aarch64 seems fine. It's just that arm vs armv7/armv8 thing

I think I figured out I can just set the arm define as the armv7 spec and be done with it. Leaves it hacky and will require manual changes down the line :frowning: but, sometimes it's what you gotta do

Not quite, as there are also ARMv6 targets in the tree, namely oxnas, mxs and at91...

I am defining the toolchain, so I can also set the flags.
Will +strict-align,+v6,+vfp2,-d32 flags work for ALL arm targets in the build system?

The armv7-muslgnuabihf has +v7,+vfp3,-d32,+thumb2,-neon

armv6_unknown_freebsd.rs       armv6_unknown_netbsd_eabihf.rs

to use as models for the equiv openwrt version.

This is what I have to work with on arm arch. Ignore the arm_openwrt_ ones, as they are my remnants

arm_base.rs                       armebv7r_none_eabihf.rs              armv7_linux_androideabi.rs         armv7a_none_eabi.rs
arm_linux_androideabi.rs          armv4t_unknown_linux_gnueabi.rs      armv7_unknown_freebsd.rs           armv7a_none_eabihf.rs
arm_openwrt_linux_muslgnueabi.rs  armv5te_unknown_linux_gnueabi.rs     armv7_unknown_linux_gnueabi.rs     armv7r_none_eabi.rs
arm_unknown_linux_gnueabi.rs      armv5te_unknown_linux_musleabi.rs    armv7_unknown_linux_gnueabihf.rs   armv7r_none_eabihf.rs
arm_unknown_linux_gnueabihf.rs    armv5te_unknown_linux_uclibceabi.rs  armv7_unknown_linux_musleabi.rs    armv7s_apple_ios.rs
arm_unknown_linux_musleabi.rs     armv6_unknown_freebsd.rs             armv7_unknown_linux_musleabihf.rs
arm_unknown_linux_musleabihf.rs   armv6_unknown_netbsd_eabihf.rs       armv7_unknown_netbsd_eabihf.rs
armebv7r_none_eabi.rs             armv7_apple_ios.rs                   armv7_wrs_vxworks_eabihf.rs

I was talking about the regular GNU GCC toolchain in OpenWrt and these options need to match the options used for LLVM/Rust otherwise linking will fail (as seen).
There isn't a single answer for all 32-bit ARM targets, we got different ARM cores (FA526, xscale ie. ARMv5, ARM10MPcore and ARM11 which are ARMv6, all the 32-bit members of the Cortex-A family which are all ARMv7-A) combined with different incompatible FPUs (VFPv2, VFPv3, VFPv4, the latter two also in 16-bit float instead of 32-bit float variants, NEON, ...) and also soft-float targets without any FPU at all.
You will have to form the target triplet based on CPU_TYPE and CPU_SUBTYPE I'm afraid.

1 Like

Oh this will be ugly.

According to https://downloads.openwrt.org/snapshots/packages/ and https://en.wikipedia.org/wiki/List_of_ARM_microarchitectures the list of needed 32-bit ARM targets looks like this:

soft-float:
fa526 (ARMv4)
xscale (ARMv5TE)
arm926ej-s (ARMv5TEJ)
mpcore (ARMv6K)
cortex-a7 (ARMv7-A)
cortex-a9 (ARMv7-A)

hard-float combinations used:
arm1176jzf-s_vfp (ARMv6Z with VFPv2)
cortex-a5_vfpv4 (ARMv7-A with VFPv4)
cortex-a7_neon-vfpv4 (ARMv7-A with VFPv4 and NEONv2)
cortex-a8_vfpv3 (ARMv7-A with VFPv3)
cortex-a9_neon (ARMv7-A with VFPv3 and NEONv1)
cortex-a9_vfpv3 (ARMv7-A with VFPv3)
cortex-a9_vfpv3-d16 (ARMv7-A with 16-bit VFPv3)
cortex-a15_neon-vfpv4 (ARMv7-A with VFPv4)

float unit types:
vfp (aka. vfpv2, only on ARMv6)
vfpv3 (only on ARMv7-A)
vfpv3-d16 (only on ARMv7-A)
vfpv4 (only on ARMv7-A)

vector unit types:
neon (aka. neon-vfpv3)
neon-vfpv4
2 Likes

This was the best I was able to come up with for now. It's completely hacky, but unless someone wants to change how the build system reports the target triple, it's the best I can do.

ifeq ( $(ARCH), "arm" )

IS_ARMV6:=$(if $CPU_TYPE, $(filter $CPU_TYPE, arm1176jzf-s_vfp))
IS_ARMV7:=$(if $CPU_TYPE, $(filter $CPU_TYPE, cortext-a5 cortex-a7 \
            cortex-a8 cortex-a9 cortex-a15),NULL)

# TODO: ARMv6 still needs proper toolchain support
ifneq ( $IS_ARMV6, )
    ifneq ( , $(findstring fpu, $(FEATURES)) )
        RUSTC_TARGET_ARCH:=arm-openwrt-linux-muslabihf
    else
        RUSTC_TARGET_ARCH:=arm-openwrt-linux-muslabi
    endif
endif

# This should cover ARMv7 Architectures
ifneq ( $IS_ARMV7, )
        ifneq ( , $(findstring fpu, $(FEATURES)) )
            RUSTC_TARGET_ARCH:=armv7-openwrt-linux-muslabihf
        else
            RUSTC_TARGET_ARCH:=armv7-openwrt-linux-muslabi
        endif
    endif
endif

There is not really any better way to do this and it's a good start to get where we need to get.
I don't see arm1176jzf-s_vfp being covered correctly, it's ARMv6Z with VFPv2, ie. hard-float (it's used for bcm2708 ie. RaspberryPi 1).

While they are all slightly outdated, of course, it'd also still be nice to see older pre-ARMv7 cores we still got in the tree covered.
I'm also not sure if everything from ARMv4 to ARMv6 is ok with the generic arm Rust arch, maybe better have them spelled out as well...

I'll check out that target and see what it returns! Thanks for the heads up!

Ok @daniel, I need your help! :smiley:

ARMv6 has 2 defines in rust, but neither seem correct for what OpenWrt needs. Here are the defines for the 2 ARMv6 and the arm-muslgnuabihf to give a HF base. You can see it's pretty basic on how it's setup, but I have no idea on the ARMv6 (v7 is pretty well defined in the toolchain already for me to borrow)

armv6_unknown_freebsd

use crate::spec::{Target, TargetOptions};

pub fn target() -> Target {
    Target {
        llvm_target: "armv6-unknown-freebsd-gnueabihf".to_string(),
        pointer_width: 32,
        data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
        arch: "arm".to_string(),
        options: TargetOptions {
            abi: "eabihf".to_string(),
            // FIXME: change env to "gnu" when cfg_target_abi becomes stable
            env: "gnueabihf".to_string(),
            features: "+v6,+vfp2,-d32".to_string(),
            max_atomic_width: Some(64),
            mcount: "\u{1}__gnu_mcount_nc".to_string(),
            ..super::freebsd_base::opts()
        },
    }

armv6_unknown_netbsd_eabihf

use crate::spec::{Target, TargetOptions};

pub fn target() -> Target {
    Target {
        llvm_target: "armv6-unknown-netbsdelf-eabihf".to_string(),
        pointer_width: 32,
        data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
        arch: "arm".to_string(),
        options: TargetOptions {
            abi: "eabihf".to_string(),
            // FIXME: remove env when cfg_target_abi becomes stable
            env: "eabihf".to_string(),
            features: "+v6,+vfp2,-d32".to_string(),
            max_atomic_width: Some(64),
            mcount: "__mcount".to_string(),
            ..super::netbsd_base::opts()
        },
    }
}

arm_unknown_linux_musleabihf

use crate::spec::{Target, TargetOptions};

pub fn target() -> Target {
    Target {
        // It's important we use "gnueabihf" and not "musleabihf" here. LLVM
        // uses it to determine the calling convention and float ABI, and it
        // doesn't support the "musleabihf" value.
        llvm_target: "arm-unknown-linux-gnueabihf".to_string(),
        pointer_width: 32,
        data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
        arch: "arm".to_string(),
        options: TargetOptions {
            abi: "eabihf".to_string(),
            // Most of these settings are copied from the arm_unknown_linux_gnueabihf
            // target.
            features: "+strict-align,+v6,+vfp2,-d32".to_string(),
            max_atomic_width: Some(64),
            mcount: "\u{1}mcount".to_string(),
            ..super::linux_musl_base::opts()
        },
    }
}

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.