Hi
Potential GCC bug? - please advise if this is a known issue, if not please inform how to raise an issue on the Gnu toolchain for Morello.
Issue: When defining register variables in a template function, the compiler ignores the directives. Does not happen if not using templates.
Found on: ARM GNU Toolchain for Morello release. Applies to Linux hybrid-cap or Linux pure-cap.- Note: This behaviour does not apply when using clang.
Example Code Snippet
Note: This is based on Arm Morello compartment demo.Intent is to call into a function following C calling convention, with C0...C6 set to passed in arguments:
#include <stdint.h> extern uintcap_t AsUintcap(uint32_t); template <typename Fn> inline void TestCall(uint32_t id, uintcap_t arg0, uintcap_t arg1, uintcap_t arg2, uintcap_t arg3, uintcap_t arg4, uintcap_t arg5, Fn arg6) { register uintcap_t c0 asm("c0") = AsUintcap(id); register uintcap_t c1 asm("c1") = arg0; register uintcap_t c2 asm("c2") = arg1; register uintcap_t c3 asm("c3") = arg2; register uintcap_t c4 asm("c4") = arg3; register uintcap_t c5 asm("c5") = arg4; register uintcap_t c6 asm("c6") = arg5; asm __volatile__("blr %[fn]\n" : : [fn] "C"(arg6), "C"(c0), "C"(c1), "C"(c2), "C"(c3), "C"(c4), "C"(c5), "C"(c6) ); } void DoTestCall(uint32_t id, uintcap_t arg0, uintcap_t arg1, uintcap_t arg2, uintcap_t arg3, uintcap_t arg4, uintcap_t arg5, void *__capability arg6) { TestCall(id, arg0, arg1, arg2, arg3, arg4, arg5, arg6); }
Compile with g++ -march=morello -save-temps -Wall -Wextra -O3 -std=gnu++14 -c test.cpp (Note: different optimisation levels give same failure behaviour).
Resulting generated assembler (tidied - comment added is mine):
stp x29, x30, [sp, -128]! mov x29, sp str c7, [sp, 16] stp c6, c5, [sp, 32] str c2, [sp, 96] str c1, [sp, 112] stp c4, c3, [sp, 64] bl _Z9AsUintcapj ldr c14, [sp, 112] ldp c2, c6, [sp, 16] ldp c8, c4, [sp, 48] ldp c10, c12, [sp, 80] // Args passed as c0, c14, c4, c6, c8, c10, c12 // c2 corrupted; being used for branch address blr c2 ldp x29, x30, [sp], 128 ret
Compare result if not using a template function (modify example code by removing template statement and add using Fn=void *__capability;):
stp x29, x30, [sp, -128]! mov x29, sp str c7, [sp, 16] stp c6, c5, [sp, 32] stp c4, c3, [sp, 64] stp c2, c1, [sp, 96] bl _Z9AsUintcapj ldr c8, [sp, 16] ldp c6, c5, [sp, 32] ldp c4, c3, [sp, 64] ldp c2, c1, [sp, 96] // c0..c6 set correctly as defined arguments. // c8 is used for address; no corruption of registers we are using blr c8 ldp x29, x30, [sp], 128 ret
ThanksPete
Hi Pete,
Hybrid compilation is currently only supported from C code in GCC. See the "Known Limitations and Issues" section of the release notes at https://developer.arm.com/downloads/-/arm-gnu-toolchain-for-morello-downloads.
You mentioned that you saw a similar issue when compiling for purecap. Can you expand on the problem you're seeing there?
For future reference, the best place to report bugs in the GNU binary toolchain releases is https://bugs.linaro.org/
Alex
Nevermind, on further investigation I can reproduce the issue in the purecap case. Thanks for reporting this.
Hi Alex, I was literally just about to post an update when saw your reply!Yes on purecap it does occur, although for me with no optimisation level i.e -O0 flag. Also on purecap, uintcap_t is not defined therefore I am using uintptr_t on purecap, i.e I have in the code using uintcap_t = uintpr_t; .
Thank you for the link to linaro bugs, will report there in future.
By the way, considering C++ is not supported in gcc on hybrid I have to say it works incredibly well! - for example, it successfully built Arm's morello compartments example (albeit with workarounds for a couple of known issues).