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
tgross35 added a commit to tgross35/llvm-project that referenced this pull request Aug 6, 2026
These were missing `NO_EXEC_STACK_DIRECTIVE` to add `.note.GNU-stack`;
without it, a binary including any of these files will have the stack
marked executable. Add the directive here, matching other similar files.

Symtab diff before:

    $ clang compiler-rt/lib/builtins/arm/aeabi_uread4.S --target=arm-unknown-linux-gnueabi -c
    $ llvm-readelf aeabi_uread4.o -S
    There are 5 section headers, starting at offset 0xe4:

    Section Headers:
      [Nr] Name              Type            Address  Off    Size   ES Flg Lk Inf Al
      [ 0]                   NULL            00000000 000000 000000 00      0   0  0
      [ 1] .strtab           STRTAB          00000000 0000a8 000039 00      0   0  1
      [ 2] .text             PROGBITS        00000000 000034 000020 00  AX  0   0  4
      [ 3] .ARM.attributes   ARM_ATTRIBUTES  00000000 000054 000022 00      0   0  1
      [ 4] .symtab           SYMTAB          00000000 000078 000030 10      1   2  4

After:

    $ clang compiler-rt/lib/builtins/arm/aeabi_uread4.S --target=arm-unknown-linux-gnueabi -c
    $ llvm-readelf aeabi_uread4.o -S
    There are 6 section headers, starting at offset 0xf4:

    Section Headers:
      [Nr] Name              Type            Address  Off    Size   ES Flg Lk Inf Al
      [ 0]                   NULL            00000000 000000 000000 00      0   0  0
      [ 1] .strtab           STRTAB          00000000 0000a8 000049 00      0   0  1
      [ 2] .text             PROGBITS        00000000 000034 000020 00  AX  0   0  4
      [ 3] .note.GNU-stack   PROGBITS        00000000 000054 000000 00      0   0  1
      [ 4] .ARM.attributes   ARM_ATTRIBUTES  00000000 000054 000022 00      0   0  1
      [ 5] .symtab           SYMTAB          00000000 000078 000030 10      1   2  4

Fixes: 39413af ("[Compiler-rt] Implement AEABI Unaligned Read/Write
       Helpers in compiler-rt (llvm#167913)")
statham-arm pushed a commit that referenced this pull request Aug 6, 2026
…214465)

These were missing `NO_EXEC_STACK_DIRECTIVE` to add `.note.GNU-stack`;
without it, a binary including any of these files will have the stack
marked executable. Add the directive here, matching other similar files.

Symtab diff before:

$ clang compiler-rt/lib/builtins/arm/aeabi_uread4.S
--target=arm-unknown-linux-gnueabi -c
    $ llvm-readelf aeabi_uread4.o -S
    There are 5 section headers, starting at offset 0xe4:

    Section Headers:
[Nr] Name Type Address Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .strtab STRTAB 00000000 0000a8 000039 00 0 0 1
[ 2] .text PROGBITS 00000000 000034 000020 00 AX 0 0 4
[ 3] .ARM.attributes ARM_ATTRIBUTES 00000000 000054 000022 00 0 0 1
[ 4] .symtab SYMTAB 00000000 000078 000030 10 1 2 4

After:

$ clang compiler-rt/lib/builtins/arm/aeabi_uread4.S
--target=arm-unknown-linux-gnueabi -c
    $ llvm-readelf aeabi_uread4.o -S
    There are 6 section headers, starting at offset 0xf4:

    Section Headers:
[Nr] Name Type Address Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .strtab STRTAB 00000000 0000a8 000049 00 0 0 1
[ 2] .text PROGBITS 00000000 000034 000020 00 AX 0 0 4
[ 3] .note.GNU-stack PROGBITS 00000000 000054 000000 00 0 0 1
[ 4] .ARM.attributes ARM_ATTRIBUTES 00000000 000054 000022 00 0 0 1
[ 5] .symtab SYMTAB 00000000 000078 000030 10 1 2 4

Fixes: 39413af ("[Compiler-rt] Implement AEABI Unaligned Read/Write
       Helpers in compiler-rt (#167913)")
dyung pushed a commit to llvmbot/llvm-project that referenced this pull request Aug 7, 2026
…lvm#214465)

These were missing `NO_EXEC_STACK_DIRECTIVE` to add `.note.GNU-stack`;
without it, a binary including any of these files will have the stack
marked executable. Add the directive here, matching other similar files.

Symtab diff before:

$ clang compiler-rt/lib/builtins/arm/aeabi_uread4.S
--target=arm-unknown-linux-gnueabi -c
    $ llvm-readelf aeabi_uread4.o -S
    There are 5 section headers, starting at offset 0xe4:

    Section Headers:
[Nr] Name Type Address Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .strtab STRTAB 00000000 0000a8 000039 00 0 0 1
[ 2] .text PROGBITS 00000000 000034 000020 00 AX 0 0 4
[ 3] .ARM.attributes ARM_ATTRIBUTES 00000000 000054 000022 00 0 0 1
[ 4] .symtab SYMTAB 00000000 000078 000030 10 1 2 4

After:

$ clang compiler-rt/lib/builtins/arm/aeabi_uread4.S
--target=arm-unknown-linux-gnueabi -c
    $ llvm-readelf aeabi_uread4.o -S
    There are 6 section headers, starting at offset 0xf4:

    Section Headers:
[Nr] Name Type Address Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .strtab STRTAB 00000000 0000a8 000049 00 0 0 1
[ 2] .text PROGBITS 00000000 000034 000020 00 AX 0 0 4
[ 3] .note.GNU-stack PROGBITS 00000000 000054 000000 00 0 0 1
[ 4] .ARM.attributes ARM_ATTRIBUTES 00000000 000054 000022 00 0 0 1
[ 5] .symtab SYMTAB 00000000 000078 000030 10 1 2 4

Fixes: 39413af ("[Compiler-rt] Implement AEABI Unaligned Read/Write
       Helpers in compiler-rt (llvm#167913)")
(cherry picked from commit 849c51e)
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