[LLVMdev] ARM struct byval size > 64 triggers failure

Manman Ren mren at apple.com
Tue Jun 18 11:37:08 PDT 2013


Hi Rajesh,

The callee code looks okay to me
> Assembly for check114 
> ---------------------------------------------------------------
>         sub     sp, sp, #16
>         push    {r11, lr}
>         mov     r11, sp
>         sub     sp, sp, #8
>         str     r3, [r11, #20]
>         str     r2, [r11, #16]
>         str     r1, [r11, #12]
>         ldr     r1, [r11, #76]
VARegSaveSize is 16 because we store the first 16 bytes of struct byval in r0 to r3.
Align in computeRegArea is 8 since ABI says the stack pointer needs to be 8 byte aligned at function entry point.
But the second argument does not have to be 8 byte aligned, in fact it is 4 byte aligned for i32.

r11, #76 is equivalent to sp_at_entry + 52 since r11 = spat_entry - 16 - 8, which is 4-byte aligned after
storing the leftover (67-16=51) bytes of struct byval.

Can you also paste the assembly for the caller side and check whether the second argument is stored
at sp_at_entry+52?

As Renato suggested, please file a bug report.

Thanks,
Manman


On Jun 18, 2013, at 4:26 AM, Rajesh Viswabramana <rajesh.vis at samsung.com> wrote:

> Hi,
>  
> Handling of pass by val of struct size >64 bytes case is seems wrong for arm targets.
>  
> Summary:
> Incase of struct pass by value for size > 64 along with other function params, failure seen in some corner cases. Access to function params result in wrong stack location access. 
> Stack pointer adjustment done by prologue emitter and offset used to access function params have different logics for calculaton.
>  
> Test code
> ---------------------------------------------------------------
> #include <stdio.h>
> struct S114 {
>   char a[67];
> }a114[5];
> struct S114 check114 (struct S114 arg0, struct S114* arg1) { 
>   if(&a114[0] != arg1)                         // arg1 value is wrong
>     printf( "values %p, %p\n", &a114[0], arg1);
> }
> int main () {
>   int i= 0, j = 0;
>   for (;j<2; j++)                                    // just filling a114 with some values for identification
>     for(i=0; i<sizeof(struct S114); i++)
>       memset(&a114[j].a[i],(0x11+i+j*30), sizeof(int)); 
>   check114 (a114[1], &a114[0]);         //=> a114[0]  is accessed from wrong location inside check114 function
> }
> ---------------------------------------------------------------
> clang -v
> clang version 3.3 (tags/RELEASE_33/final)
> Target: i386-pc-linux-gnu
> Thread model: posix
>  
> Output on arm :
> # ./check114.exe 
> values 0x10861, 0x4071706f
> which is wrong.
>  
> Assembly for check114 
> ---------------------------------------------------------------
>         sub     sp, sp, #16
>         push    {r11, lr}
>         mov     r11, sp
>         sub     sp, sp, #8
>         str     r3, [r11, #20]
>         str     r2, [r11, #16]
>         str     r1, [r11, #12]
>         ldr     r1, [r11, #76]
>         str     r1, [sp, #4]
>         .loc    1 7 0 prologue_end
>         ldr     r2, .LCPI0_0
>         cmp     r2, r1
>         beq     .LBB0_2
>         b       .LBB0_1
> ---------------------------------------------------------------
>  
> From reg, stack dump:
> ------------------------------------------------------------------------------------------------------------------------------
> @entry of check114
>   => 0x8398 <check114>: sub sp, sp, #16
>         0x839c <check114+4>: push {r11, lr}
>   sp             0xbefff808 0xbefff808
> @if condition
>        0x83b4 <check114+28>: ldr r1, [r11, #76] ; 0x4c         <--- wrong value copied to r1, offset #76 should be #80
>        0x83b8 <check114+32>: str r1, [sp, #4]
>        0x83bc <check114+36>: ldr r2, [pc, #44] ; 0x83f0 <check114+88>
>  => 0x83c0 <check114+40>: cmp r2, r1
>   
>   r11            0xbefff7f0 -1090521104
>   sp             0xbefff7e8 0xbefff7e8
>   Stack dump:
>   0xbefff7e4: 0x4001ed08 0x40024f90 0x4071706f 0xbefff8a0
>   0xbefff7f4: 0x0000869c 0x00000000 0x3231302f 0x36353433
>   0xbefff804: 0x3a393837 0x3e3d3c3b 0x4241403f 0x46454443
>   0xbefff814: 0x4a494847 0x4e4d4c4b 0x5251504f 0x56555453
>   0xbefff824: 0x5a595857 0x5e5d5c5b 0x6261605f 0x66656463
>   0xbefff834: 0x6a696867 0x6e6d6c6b 0x4071706f 0x00010861                 //[R11+4c] -> [0xbefff7f0+4c] -> [0xbefff83c] -> 0x4071706f
> Correct value is at location {[R11+4c]+4} --> 0x00010861, 4 bytes offset going wrong.
> ------------------------------------------------------------------------------------------------------------------------------
> When i checked from the ARM Lowering part for generation of
>   sub sp, sp, #16
> Emitted by,
>   if (VARegSaveSize)
>     emitSPUpdate(isARM, MBB, MBBI, dl, TII, -VARegSaveSize,        // --> VARegSaveSize is calculated in computeRegArea
>                  MachineInstr::FrameSetup)
> 
> ARMTargetLowering::computeRegArea(..) {
>   ...
>   VARegSize = NumGPRs * 4;
>   VARegSaveSize = (VARegSize + Align - 1) & ~(Align - 1);                 // --> 8 byte alignment done here
> }
> Stack pointer decremented to NumGPRs*4 + alignment
> NumGPRs = 3 registers
> VARegSaveSize  = 16 (after considering 8 byte alignment )
> 
> When the offset(#76) for the instruction, "ldr r1, [r11, #76] ; 0x4c"  is calculated, 4 bytes alignment is considered.
> In prologue stackpointer calculation 8 byte alignment is considered.
> Due to this mimatch of alignment, If try to access any parameter after byval which results wrong value.
>  
> Issue(or offset of 4 bytes) wont occur if even number of register used for byval spilling.
> ex: 
> struct S114 check114 (int a, struct S114 arg0, struct S114* arg1) { // accessing arg1 is fine in this case
> .....
> }
>  
> Could someone comment on below queries about fixing the problem,
> 1) Is this 8 byte alignment mandatory ?  Is this due to " ARM AAPCS 5.2.1.2 Stack constraints at a public interface" ? Can this be removed?
> 2) We will leave alignment as it is but in prologue we will adjust SP once again, this is little meaningless.
> 3) While accessing arg1 we will consider alignment and add extra offset -> looks better.
>  Offset to access arg1 is calculated by selection DAG that will be target independent. But Alignment adjustment should be done by target lowering. Any suggestions on how to fix this ?
>  
> Regards,
> Rajesh
>  
> <201306181656803_BEI0XT4N.gif>
> _______________________________________________
> LLVM Developers mailing list
> LLVMdev at cs.uiuc.edu         http://llvm.cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20130618/947a601e/attachment.html>


More information about the llvm-dev mailing list