llvm / llvm-project

The LLVM Project is a collection of modular and reusable compiler and toolchain technologies.
http://llvm.org
Other
28.07k stars 11.59k forks source link

[LLC]Why are general-purpose registers and floating-point registers stored on both sides of fp in the Aarch64 architecture #104050

Open Wang-Zhongqi opened 1 month ago

Wang-Zhongqi commented 1 month ago

Hello everyone, I have a question. Why are the callee saved general-purpose registers and callee saved floating-point registers stored on both sides of fp and lr respectively in the aarch64 architecture c callconv? This may be the case in the stack: -- stack -- | saved x28 | | saved x27 | | saved lr | | saved fp | <- new fp | saved d9 | | saved d8 |

When I did not use the called saved floating-point register, I used LLVMBuildAlloc to generate a structure and obtained the space below fp. During the backtrace process, I used * (fp-8) to obtain the value I needed. The stack frame structure is as follows: | saved x28 | | saved x27 | | saved lr | | saved fp | <- new fp | frame_type | <- value | context ptr |

However, when using the callee saved floating-point register, the stack frame structure changed, making it impossible for me to obtain values through the original method. The specific stack frame structure may be as follows: | saved x28 | | saved x27 | | saved lr | | saved fp | <- new fp | saved d9 | <- inserted in the middle | saved d8 | | frame_type | <- value | context ptr |

If I want to save some values adjacent to fp for retrieval during backtrace, how can I implement it through llvm17 c-API? I have considered preserving registers to avoid using d8-d31, but I only found+reserve-x0 in -- attr, which only provides the option to preserve general-purpose registers.

llvmbot commented 1 month ago

@llvm/issue-subscribers-backend-aarch64

Author: None (Wang-Zhongqi)

Hello everyone, I have a question. Why are the callee saved general-purpose registers and callee saved floating-point registers stored on both sides of fp and lr respectively in the aarch64 architecture c callconv? This may be the case in the stack: -- stack -- | saved x28 | | saved x27 | | saved lr | | saved fp | <- new fp | saved d9 | | saved d8 | When I did not use the called saved floating-point register, I used LLVMBuildAlloc to generate a structure and obtained the space below fp. During the backtrace process, I used * (fp-8) to obtain the value I needed. The stack frame structure is as follows: | saved x28 | | saved x27 | | saved lr | | saved fp | <- new fp | frame_type | <- value | context ptr | However, when using the callee saved floating-point register, the stack frame structure changed, making it impossible for me to obtain values through the original method. The specific stack frame structure may be as follows: | saved x28 | | saved x27 | | saved lr | | saved fp | <- new fp | saved d9 | <- inserted in the middle | saved d8 | | frame_type | <- value | context ptr | If I want to save some values adjacent to fp for retrieval during backtrace, how can I implement it through llvm17 c-API? I have considered preserving registers to avoid using d8-d31, but I only found+reserve-x0 in -- attr, which only provides the option to preserve general-purpose registers.
pinskia commented 1 month ago

Note the aarch64 ABIs have no defined order or really location for callee-saved registers. The only way to get back this information is to use the unwinding notes.

Wang-Zhongqi commented 1 month ago

It seems that unwind notes can only retrieve register information stored on the stack and cannot generate the stack frame layout I need. So it may not be possible to generate the stack frame layout I need through the LLVM C API, so I may consider modifying the LLVM source code and adding a callconv on the Aarch64 backend to specify the order in which the callee saved register is saved, thereby controlling the stack frame layout.