This is an archive of the discontinued LLVM Phabricator instance.

[compiler-rt][builtins] Do not use ldrexd or strexd on ARMv6
AcceptedPublic

Authored by benwolsieffer on Dec 7 2022, 2:53 PM.

Details

Reviewers
compnerd
MaskRay
Summary

The ldrexd and strexd instructions are not available on base ARMv6, and were
only added in ARMv6K (see [1]). This patch solves this problem once and for all
using the __ARM_FEATURE_LDREX macro (see [2]) defined in the ARM C Language
Extensions (ACLE). Although this macro is technically deprecated in the ACLE,
it allows compiler-rt to reliably detect whether ldrexd and strexd are supported
without complicated conditionals to detect different ARM architecture variants.

[1] https://developer.arm.com/documentation/dht0008/a/ch01s02s01
[2] https://arm-software.github.io/acle/main/acle.html#ldrexstrex

Diff Detail

Event Timeline

benwolsieffer created this revision.Dec 7 2022, 2:53 PM
benwolsieffer requested review of this revision.Dec 7 2022, 2:53 PM
Herald added a project: Restricted Project. · View Herald TranscriptDec 7 2022, 2:53 PM
Herald added a subscriber: Restricted Project. · View Herald Transcript

Might be useful to add a reference to https://developer.arm.com/documentation/dht0008/a/ch01s02s01 in the commit message.

I'm worried about the current condition though as what we really want is to ensure that the ARM architecture is 7 or newer and that not in the M profile. What do you think of using:

__ARM_ARCH > 7 || (__ARM_ARCH == 7 && __ARM_ARCH_PROFILE != 'M')

instead?

That's not quite right though, since that excludes ARMv6K and ARMv6Z (which is a superset of ARMv6K). The only ARMv6 variant that doesn't support these instructions is base ARMv6 (and technically ARMv6J, but LLVM doesn't appear to consider that as a separate target). __ARM_ARCH_6__ is defined only when targeting base ARMv6, not any of the other variants.

According to https://reviews.llvm.org/D95891, these instruction are not supported in ARMv8-M either, so we don't want to use __ARM_ARCH > 7.

benwolsieffer updated this revision to Diff 481373.EditedDec 8 2022, 11:17 AM
benwolsieffer edited the summary of this revision. (Show Details)

I updated the commit message to include the reference to the ARM documentation.

That's not quite right though, since that excludes ARMv6K and ARMv6Z (which is a superset of ARMv6K). The only ARMv6 variant that doesn't support these instructions is base ARMv6 (and technically ARMv6J, but LLVM doesn't appear to consider that as a separate target). __ARM_ARCH_6__ is defined only when targeting base ARMv6, not any of the other variants.

According to https://reviews.llvm.org/D95891, these instruction are not supported in ARMv8-M either, so we don't want to use __ARM_ARCH > 7.

Doesn't the current check not exclude those variants as well? __ARM_ARCH_6__ should be defined when targeting the ARMv6{K,Z} targets right? I think that this is complicated enough that we should define this centrally and use that to guard the operations.

No, __ARM_ARCH_6__ is only defined on base ARMv6. __ARM_ARCH_6K__ is defined instead on ARMv6K. I can't find this clearly documented anywhere, but I have confirmed this behavior through experimentation with GCC and by examination with clang (see implementation here)

On the other hand, there is the __ARM_FEATURE_LDREX macro, which provides the exact functionality we want here. The only problem is that it is deprecated in the ARM C Language Extensions specification, although it is still defined even in the latest versions of the ACLE. This macro was not used in https://reviews.llvm.org/D5490 in part because it was deprecated, but mostly because clang did not implement it at the time.

What do you think about using that macro instead, despite the deprecation?

No, __ARM_ARCH_6__ is only defined on base ARMv6. __ARM_ARCH_6K__ is defined instead on ARMv6K. I can't find this clearly documented anywhere, but I have confirmed this behavior through experimentation with GCC and by examination with clang (see implementation here)

On the other hand, there is the __ARM_FEATURE_LDREX macro, which provides the exact functionality we want here. The only problem is that it is deprecated in the ARM C Language Extensions specification, although it is still defined even in the latest versions of the ACLE. This macro was not used in https://reviews.llvm.org/D5490 in part because it was deprecated, but mostly because clang did not implement it at the time.

What do you think about using that macro instead, despite the deprecation?

I think that is a much clearer macro for this. While it is deprecated, this is an internal reference, so should we ever drop support for it, we should catch it pretty quickly I think. I think that going with that is reasonable. Thanks for the reference, and walking me through this.

benwolsieffer edited the summary of this revision. (Show Details)

I updated the patch to use __ARM_FEATURE_LDREX.

compnerd accepted this revision.Dec 11 2022, 5:07 PM

Thanks! This looks good. Personally, I'd use 0x8 instead of 8, which might make it more obvious that this is intentional (and that it is a bitmask).

This revision is now accepted and ready to land.Dec 11 2022, 5:07 PM

Rebase on main

Sorry I went silent for so long. I updated the patch to use 0x8. Also, I don't have commit access, so I need someone else to commit this.