llvm / llvm-project

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

[Clang] Clang vs. GCC Frame Pointer Differences #108019

Open guoxin049 opened 1 month ago

guoxin049 commented 1 month ago

We used Clang 15 to build our kernel and encountered a problem during the process. I'm not sure if this is a bug or an issue with our configuration.

When using CONFIG_THUMB2_KERNEL, the frame pointer (FP) is set to r7. However, after compiling with Clang 15 and setting the option '-mframe-chain=aapcs+leaf', the frame pointer changes to r11.

When the -mframe-chain=aapcs+leaf option is set, the createAAPCSFrameChain() function returns true, and the getFramePointerReg() function uses ARM::R11 as the frame pointer. However, when I compile with GCC using the options -mthumb -mabi=aapcs, it still uses r7 as the frame pointer.

llvmbot commented 1 month ago

@llvm/issue-subscribers-backend-arm

Author: gxlayer (guoxin049)

We used Clang 15 to build our kernel and encountered a problem during the process. I'm not sure if this is a bug or an issue with our configuration. - The kernel code is as follows: https://github.com/torvalds/linux/blob/2c85ebc57b3e1817b6ce1a6b703928e113a90442/arch/arm/kernel/unwind.c#L68-L77 ``` enum regs { #ifdef CONFIG_THUMB2_KERNEL FP = 7, #else FP = 11, #endif SP = 13, LR = 14, PC = 15 }; ``` When using CONFIG_THUMB2_KERNEL, the frame pointer (FP) is set to r7. However, after compiling with Clang 15 and setting the option '-mframe-chain=aapcs+leaf', the frame pointer changes to r11. - I noticed that this part of the llvm code caused https://github.com/llvm/llvm-project/blob/cb30169422446b79d99df12b4cf5ab3d9d46d54c/llvm/lib/Target/ARM/ARMSubtarget.h#L374-L379 When the `-mframe-chain=aapcs+leaf` option is set, the createAAPCSFrameChain() function returns true, and the getFramePointerReg() function uses ARM::R11 as the frame pointer. However, when I compile with GCC using the options `-mthumb -mabi=aapcs`, it still uses r7 as the frame pointer. - This is my demo to illustrate the difference: https://godbolt.org/z/GcMGhKvq1
efriedma-quic commented 1 month ago

-mframe-chain=aapcs+leaf means that all functions should using an AAPCS frame pointer... and the spec in question says the frame pointer register is r11. If you really want frame pointers in r7 for some reason, -mframe-chain=none -fno-omit-frame-pointer does that, I think.

I have no idea whether gcc has equivalent options.

guoxin049 commented 1 month ago

-mframe-chain=aapcs+leaf means that all functions should using an AAPCS frame pointer... and the spec in question says the frame pointer register is r11. If you really want frame pointers in r7 for some reason, -mframe-chain=none -fno-omit-frame-pointer does that, I think.

I have no idea whether gcc has equivalent options.

Thank you for your reply. I would like to know whether the frame pointer (FP) uses r11 or r7 when both -mframe-chain=aapcs+leaf and -mthumb options are used together. Could you clarify which register is selected for the frame pointer in this case? Thank you.

efriedma-quic commented 1 month ago

-mframe-chain=aapcs+leaf forces the frame pointer to r11 even in Thumb mode.

guoxin049 commented 1 month ago

@efriedma-quic https://github.com/llvm/llvm-project/blob/d4f6ad51603405ab4e998fa6416bfdff4b1f43d4/llvm/lib/Target/ARM/ARMFrameLowering.cpp#L2265-L2273

Thank you for your reply. But I'm running into a problem. I’m trying to understand the rationale behind the condition !(requiresAAPCSFrameRecord(MF) && hasFP(MF)) for setting the boolean CanEliminateFrame. Specifically, why do both conditions need to be true simultaneously?

Given that hasFP(MF) being true implies that requiresAAPCSFrameRecord(MF) would be redundant, can this logic be simplified to just bool CanEliminateFrame = !hasFP(MF)?

efriedma-quic commented 1 month ago

I think what happened there is that the patch that added the line (https://reviews.llvm.org/D125094; CC @pratlucas) was mostly concerned about the behavior with -mframe-chain=aapcs. So the behavior changed for that case, but not for the non-AAPCS frame chain case.

As a practical matter, it's very unlikely to make a significant difference: functions without a stack frame are generally tiny anyways.

guoxin049 commented 1 month ago

I think what happened there is that the patch that added the line (https://reviews.llvm.org/D125094; CC @pratlucas) was mostly concerned about the behavior with -mframe-chain=aapcs. So the behavior changed for that case, but not for the non-AAPCS frame chain case.

As a practical matter, it's very unlikely to make a significant difference: functions without a stack frame are generally tiny anyways.

Thank you for your reply. Does LLVM currently generate stack pointers for smaller leaf functions, or are they optimized out in certain cases? Has the community considered the possibility of always generating stack pointers for such functions? thank you

This is my demo to illustrate clang and gcc the difference: https://godbolt.org/z/Kf1e3crMc

dongjianqiang2 commented 1 month ago

I think what happened there is that the patch that added the line (https://reviews.llvm.org/D125094; CC @pratlucas) was mostly concerned about the behavior with -mframe-chain=aapcs. So the behavior changed for that case, but not for the non-AAPCS frame chain case.

As a practical matter, it's very unlikely to make a significant difference: functions without a stack frame are generally tiny anyways.

I think the problem @guoxin049 found is that using the -fno-omit-frame-pointer option does not generate fp for leaf functions (Dopra uses fp to backtrace), so the option -mframe-chain=aapcs+leaf is used. However, the -mframe-chain=aapcs+leaf option is changed from r7 to r11 in thumb mode, then the kernel has compatibility issues. May I ask if you have any suggestions?

efriedma-quic commented 1 month ago

-mno-omit-leaf-frame-pointer should be the option to do that, but it looks like that doesn't currently work on 32-bit Arm. Which I guess is a bug.