Skip to content

[Compiler-rt] Implement AEABI Unaligned Read/Write Helpers in compiler-rt#167913

Merged
simpal01 merged 4 commits into
llvm:mainfrom
simpal01:add-aeabi-unaligned-helpers
Feb 2, 2026
Merged

[Compiler-rt] Implement AEABI Unaligned Read/Write Helpers in compiler-rt#167913
simpal01 merged 4 commits into
llvm:mainfrom
simpal01:add-aeabi-unaligned-helpers

Conversation

@simpal01

@simpal01 simpal01 commented Nov 13, 2025

Copy link
Copy Markdown
Contributor

This patch adds implementations for the __aeabi_uread and __aeabi_uwrite helper functions to compiler-rt.

Without these helpers, LLVM would need to inline byte wise sequences , which can increases code size, especially at -Os/-Oz. Using the helper functions allows to retain correctness while avoiding the code-size growth.

GCC-based toolchains already provide these AEABI helpers, so supporting them in compiler-rt ensures parity and avoids accidental dependencies on libgcc when LLVM begins emitting these calls.

…r-rt

This patch adds implementations for the __aeabi_uread
and __aeabi_uwrite helper functions to compiler-rt..
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===-----------------------------------------------------------------------------===//

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

char v[4];
} v4;

int __aeabi_uread4(void *p) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was going to say that surely the read functions should take a const void *, but in RTABI, they don't! I suppose because nobody ever calls these functions from C, so the C prototype isn't really important, only the machine-level PCS that it translates into.

extern long long __aeabi_uread8(void *);
extern long long __aeabi_uwrite8(long long, void *);

#define lenof(x) (sizeof((x)) / sizeof(*(x)))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's 2025, so we can use _Countof for this! \o/

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

long long target8;
int target4;
const char source[] = "abcdefghijklmno";
static char dest1[lenof(source)], dest2[lenof(source)];

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why static?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using static is optional. It’s used here mainly to improve reproducibility — since it provides a stable address from which we can repeatably test unaligned writes.

@github-actions

github-actions Bot commented Nov 19, 2025

Copy link
Copy Markdown

✅ With the latest revision this PR passed the C/C++ code formatter.

@github-actions

github-actions Bot commented Nov 19, 2025

Copy link
Copy Markdown

🐧 Linux x64 Test Results

  • 6178 tests passed
  • 1394 tests skipped

✅ The build succeeded and all tests passed.

…compiler-rt

Apply clang-format to address style issues in the previous patch.

@efriedma-quic efriedma-quic left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LLVM currently doesn't generate calls to these functions. From what I recall, my team did some internal testing of these functions at one point, and we found it basically doesn't make sense to call the 4-byte versions; on cores that still care about misaligned accesses, calls are expensive, so the tradeoff isn't really worth it for normal code.

Do you have some plan to use these functions?


typedef struct {
char v[4];
} v4;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Technically, to avoid breaking TBAA rules, this needs to be __attribute__((__may_alias__)). Not sure if it's likely to matter in practice.

@simpal01

simpal01 commented Dec 2, 2025

Copy link
Copy Markdown
Contributor Author

LLVM currently doesn't generate calls to these functions. From what I recall, my team did some internal testing of these functions at one point, and we found it basically doesn't make sense to call the 4-byte versions; on cores that still care about misaligned accesses, calls are expensive, so the tradeoff isn't really worth it for normal code.

Do you have some plan to use these functions?

Yes, we are currently working on enabling LLVM to emit these functions. I don’t have the patch ready right now, but I’m working on it and will send it soon.

These helpers are not intended for performance-oriented code paths—indeed, the call overhead can make them unsuitable for that. These functions are planned to be emitted only for size-optimised code paths (-Os/-Oz) and also when -mno-unaligned-access (or equivalent) is used. Without these helpers, LLVM would need to inline byte wise sequences , which can increases code size, especially at -Os/-Oz. Using the helper functions allows to retain correctness while avoiding that code-size growth. We haven’t benchmarked this yet, but we do expect some code-size savings in real workloads.

Even though many modern Arm cores handle unaligned accesses natively, there are still deployments—particularly in embedded and legacy environments—where unaligned support is limited or intentionally disabled. The AEABI helpers can give a mechanism to handle these cases.

Another motivation is ABI and ecosystem consistency. GCC-based toolchains already provide these AEABI helpers, so supporting them in compiler-rt ensures parity and avoids accidental dependencies on libgcc when LLVM begins emitting these calls.

Happy to hear any thoughts or concerns. Feedback on additional use-cases or scenarios we should consider would be very welcome.

@efriedma-quic

Copy link
Copy Markdown
Contributor

Okay, that's fine.

I suspect the performance penalty is too large at -Os; maybe it's okay at -Oz.

@simpal01
simpal01 requested a review from smithp35 December 2, 2025 20:13
@simpal01

Copy link
Copy Markdown
Contributor Author

Okay, that's fine.

I suspect the performance penalty is too large at -Os; maybe it's okay at -Oz.

From initial measurements, both -Os and -Oz appear to have a comparable performance degradation. This is the patch for the corresponding codegen emission #172672. At the moment, this implementation emits AEABI calls for unaligned accesses when building with -Os or -Oz together with -mno-unaligned-access.

@efriedma-quic

Copy link
Copy Markdown
Contributor

I'll approve after the following:

  • Please verify the unittest is actually getting invoked (not sure if there's some CMake magic you need to do).
  • Please address my comment about may_alias.

@efriedma-quic

Copy link
Copy Markdown
Contributor

From initial measurements, both -Os and -Oz appear to have a comparable performance degradation

My point is that users using -Os may not find that degradation acceptable. But we can continue that discussion that on the codegen patch.

…ers in compiler-rt

Make the AEABI Unaligned Read/Write Helpers
implementation in assembly.
@simpal01

Copy link
Copy Markdown
Contributor Author
  • Please address my comment about may_alias.

Hi,
I have reimplemented all these __aeabi_uread* and __aeabi_uwrite* helpers in assembly, as these functions follow a custom PCS and are only allowed to clobber r0–r3, ip, lr, and CPSR as per the ARM ABI https://github.com/ARM-software/abi-aa/blob/main/rtabi32/rtabi32.rst#533unaligned-memory-access .

A C implementation cannot reliably guarantee this.

When you have a chance, please have another look at the implementation.

@simpal01

Copy link
Copy Markdown
Contributor Author
  • Please verify the unittest is actually getting invoked (not sure if there's some CMake magic you need to do).

I verified this — arm/aeabi_unaligned_access_test.c is in the passed tests list (see test output/logs).

********************
Passed Tests (120):
  Builtins :: TestCases/check-same-common-code.test
  Builtins-arm-generic :: absvdi2_test.c
  Builtins-arm-generic :: absvsi2_test.c
  Builtins-arm-generic :: absvti2_test.c
  Builtins-arm-generic :: addvdi3_test.c
  Builtins-arm-generic :: addvsi3_test.c
  Builtins-arm-generic :: addvti3_test.c
  Builtins-arm-generic :: arm/aeabi_cdcmpeq_test.c
  Builtins-arm-generic :: arm/aeabi_cdcmple_test.c
  Builtins-arm-generic :: arm/aeabi_cfcmpeq_test.c
  Builtins-arm-generic :: arm/aeabi_cfcmple_test.c
  Builtins-arm-generic :: arm/aeabi_drsub_test.c
  Builtins-arm-generic :: arm/aeabi_frsub_test.c
  Builtins-arm-generic :: arm/aeabi_idivmod_test.c
  Builtins-arm-generic :: arm/aeabi_uidivmod_test.c
  Builtins-arm-generic :: arm/aeabi_uldivmod_test.c
  Builtins-arm-generic :: arm/aeabi_unaligned_access_test.c
  Builtins-arm-generic :: ashldi3_test.c
  Builtins-arm-generic :: ashlti3_test.c
  Builtins-arm-generic :: ashrdi3_test.c
  Builtins-arm-generic :: ashrti3_test.c
  Builtins-arm-generic :: bswapdi2_test.c
  Builtins-arm-generic :: bswapsi2_test.c
  Builtins-arm-generic :: clzdi2_test.c
  Builtins-arm-generic :: clzsi2_test.c
  Builtins-arm-generic :: clzti2_test.c
  Builtins-arm-generic :: cmpdi2_test.c
  Builtins-arm-generic :: cmpti2_test.c
  Builtins-arm-generic :: comparedf2_test.c
  Builtins-arm-generic :: comparesf2_test.c
  Builtins-arm-generic :: compiler_rt_fmax_test.c
  Builtins-arm-generic :: compiler_rt_fmaxl_test.c
  Builtins-arm-generic :: compiler_rt_logb_test.c
  Builtins-arm-generic :: compiler_rt_logbf_test.c
  Builtins-arm-generic :: compiler_rt_logbl_test.c
  Builtins-arm-generic :: compiler_rt_scalbn_test.c
  Builtins-arm-generic :: compiler_rt_scalbnf_test.c
  Builtins-arm-generic :: compiler_rt_scalbnl_test.c
  Builtins-arm-generic :: ctzdi2_test.c
  Builtins-arm-generic :: ctzsi2_test.c
  Builtins-arm-generic :: ctzti2_test.c
  Builtins-arm-generic :: divdc3_test.c
  Builtins-arm-generic :: divdf3_test.c
  Builtins-arm-generic :: divdi3_test.c
  Builtins-arm-generic :: divmodsi4_test.c
  Builtins-arm-generic :: divmodti4_test.c
  Builtins-arm-generic :: divsc3_test.c
  Builtins-arm-generic :: divsf3_test.c
  Builtins-arm-generic :: divsi3_test.c
  Builtins-arm-generic :: divti3_test.c
  Builtins-arm-generic :: extendhfdf2_test.c
  Builtins-arm-generic :: extendhfsf2_test.c
  Builtins-arm-generic :: ffsdi2_test.c
  Builtins-arm-generic :: ffssi2_test.c
  Builtins-arm-generic :: ffsti2_test.c
  Builtins-arm-generic :: fixdfdi_test.c
  Builtins-arm-generic :: fixdfti_test.c
  Builtins-arm-generic :: fixsfdi_test.c
  Builtins-arm-generic :: fixsfti_test.c
  Builtins-arm-generic :: fixunsdfdi_test.c
  Builtins-arm-generic :: fixunsdfsi_test.c
  Builtins-arm-generic :: fixunsdfti_test.c
  Builtins-arm-generic :: fixunssfdi_test.c
  Builtins-arm-generic :: fixunssfsi_test.c
  Builtins-arm-generic :: fixunssfti_test.c
  Builtins-arm-generic :: floatdidf_test.c
  Builtins-arm-generic :: floatdisf_test.c
  Builtins-arm-generic :: floattidf_test.c
  Builtins-arm-generic :: floattisf_test.c
  Builtins-arm-generic :: floatundidf_test.c
  Builtins-arm-generic :: floatundisf_test.c
  Builtins-arm-generic :: floatuntidf_test.c
  Builtins-arm-generic :: floatuntisf_test.c
  Builtins-arm-generic :: lshrdi3_test.c
  Builtins-arm-generic :: lshrti3_test.c
  Builtins-arm-generic :: moddi3_test.c
  Builtins-arm-generic :: modsi3_test.c
  Builtins-arm-generic :: modti3_test.c
  Builtins-arm-generic :: muldc3_test.c
  Builtins-arm-generic :: muldi3_test.c
  Builtins-arm-generic :: mulodi4_test.c
  Builtins-arm-generic :: mulosi4_test.c
  Builtins-arm-generic :: muloti4_test.c
  Builtins-arm-generic :: mulsc3_test.c
  Builtins-arm-generic :: mulsf3_test.c
  Builtins-arm-generic :: multi3_test.c
  Builtins-arm-generic :: mulvdi3_test.c
  Builtins-arm-generic :: mulvsi3_test.c
  Builtins-arm-generic :: mulvti3_test.c
  Builtins-arm-generic :: negdi2_test.c
  Builtins-arm-generic :: negti2_test.c
  Builtins-arm-generic :: negvdi2_test.c
  Builtins-arm-generic :: negvsi2_test.c
  Builtins-arm-generic :: negvti2_test.c
  Builtins-arm-generic :: paritydi2_test.c
  Builtins-arm-generic :: paritysi2_test.c
  Builtins-arm-generic :: parityti2_test.c
  Builtins-arm-generic :: popcountdi2_test.c
  Builtins-arm-generic :: popcountsi2_test.c
  Builtins-arm-generic :: popcountti2_test.c
  Builtins-arm-generic :: powidf2_test.c
  Builtins-arm-generic :: powisf2_test.c
  Builtins-arm-generic :: subvdi3_test.c
  Builtins-arm-generic :: subvsi3_test.c
  Builtins-arm-generic :: subvti3_test.c
  Builtins-arm-generic :: trampoline_setup_test.c
  Builtins-arm-generic :: truncdfhf2_test.c
  Builtins-arm-generic :: truncdfsf2_test.c
  Builtins-arm-generic :: truncsfhf2_test.c
  Builtins-arm-generic :: ucmpdi2_test.c
  Builtins-arm-generic :: ucmpti2_test.c
  Builtins-arm-generic :: udivdi3_test.c
  Builtins-arm-generic :: udivmoddi4_test.c
  Builtins-arm-generic :: udivmodsi4_test.c
  Builtins-arm-generic :: udivmodti4_test.c
  Builtins-arm-generic :: udivsi3_test.c
  Builtins-arm-generic :: udivti3_test.c
  Builtins-arm-generic :: umoddi3_test.c
  Builtins-arm-generic :: umodsi3_test.c
  Builtins-arm-generic :: umodti3_test.c


Testing Time: 0.66s

Total Discovered Tests: 226
  Unsupported: 106 (46.90%)
  Passed     : 120 (53.10%)

2 warning(s) in tests
No xml results generated to modify.

@efriedma-quic

Copy link
Copy Markdown
Contributor

Is it not sufficient to build the C code with -mfpu=none or something like that? Maybe easier to just write it in assembly and not worry about it, though.

@davemgreen

Copy link
Copy Markdown
Contributor

Is it not sufficient to build the C code with -mfpu=none or something like that? Maybe easier to just write it in assembly and not worry about it, though.

Yeah - It would help make sure we don't do anything silly like use the stack.

@simpal01

simpal01 commented Jan 28, 2026

Copy link
Copy Markdown
Contributor Author

Is it not sufficient to build the C code with -mfpu=none or something like that?

Yeah. These functions are relatively simple, I prefer to keep them implemented in assembly.

@efriedma-quic efriedma-quic left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@simpal01

simpal01 commented Feb 2, 2026

Copy link
Copy Markdown
Contributor Author

Thank you @efriedma-quic

@simpal01
simpal01 merged commit 39413af into llvm:main Feb 2, 2026
11 checks passed
rishabhmadan19 pushed a commit to rishabhmadan19/llvm-project that referenced this pull request Feb 9, 2026
…r-rt (llvm#167913)

This patch adds implementations for the __aeabi_uread and __aeabi_uwrite
helper functions to compiler-rt.

Without these helpers, LLVM would need to inline byte wise sequences ,
which can increases code size, especially at -Os/-Oz. Using the helper
functions allows to retain correctness while avoiding the code-size
growth.

GCC-based toolchains already provide these AEABI helpers, so supporting
them in compiler-rt ensures parity and avoids accidental dependencies on
libgcc when LLVM begins emitting these calls.
simpal01 added a commit to arm/arm-toolchain that referenced this pull request Feb 24, 2026
… unaligned i32/i64 loads/stores to __aeabi_uread/uwrite{4,8} (#734)

Downstream issue:#727

This was committed upstream after the LLVM 22 branch was created. Mostly
upstream will not accept it into the 22 branch, as it is not considered
critical enough for backporting.

When targeting ARM (in particular architectures or variants that do not
allow unaligned memory accesses, e.g., with -mno-unaligned-access or
older cores like ARMv6-M) the backend currently handles unaligned loads
or stores by expanding them into sequences of byte/half-word
loads/stores.

This change proposes to detect unaligned loads/stores of size 4 bytes
(i32) or 8 bytes (i64) when alignment is insufficient, and instead emit
calls to the AEABI helper functions by llvm:

• __aeabi_uread4, __aeabi_uread8 for unaligned reads

• __aeabi_uwrite4, __aeabi_uwrite8 for unaligned writes

By lowering to these functions, code size can be reduced compared to
in-lined byte/half-word sequences providing they are invoked more than
once across a program. This also needs to add the implementations for
the __aeabi_uread and __aeabi_uwrite helper functions to compiler-rt.

List of upstream PRs:

- llvm/llvm-project#167913
- llvm/llvm-project#172672
@nikic nikic mentioned this pull request Jul 25, 2026
9 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants