<html>
    <head>
      <base href="http://llvm.org/bugs/" />
    </head>
    <body><table border="1" cellspacing="0" cellpadding="8">
        <tr>
          <th>Bug ID</th>
          <td><a class="bz_bug_link 
          bz_status_NEW "
   title="NEW --- - ARM struct byval size > 64 triggers failure"
   href="http://llvm.org/bugs/show_bug.cgi?id=16368">16368</a>
          </td>
        </tr>

        <tr>
          <th>Summary</th>
          <td>ARM struct byval size > 64 triggers failure
          </td>
        </tr>

        <tr>
          <th>Product</th>
          <td>libraries
          </td>
        </tr>

        <tr>
          <th>Version</th>
          <td>trunk
          </td>
        </tr>

        <tr>
          <th>Hardware</th>
          <td>Other
          </td>
        </tr>

        <tr>
          <th>OS</th>
          <td>Linux
          </td>
        </tr>

        <tr>
          <th>Status</th>
          <td>NEW
          </td>
        </tr>

        <tr>
          <th>Severity</th>
          <td>normal
          </td>
        </tr>

        <tr>
          <th>Priority</th>
          <td>P
          </td>
        </tr>

        <tr>
          <th>Component</th>
          <td>Backend: ARM
          </td>
        </tr>

        <tr>
          <th>Assignee</th>
          <td>unassignedbugs@nondot.org
          </td>
        </tr>

        <tr>
          <th>Reporter</th>
          <td>viswabramana.rajesh@gmail.com
          </td>
        </tr>

        <tr>
          <th>CC</th>
          <td>llvmbugs@cs.uiuc.edu
          </td>
        </tr>

        <tr>
          <th>Classification</th>
          <td>Unclassified
          </td>
        </tr></table>
      <p>
        <div>
        <pre>Handling of pass byval of struct size >64 bytes case is going wrong for arm
targets.

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++)             //filling a114 with some values for mark
    for(i=0; i<sizeof(struct S114); i++)
      memset(&a114[j].a[i],(0x11+i+j*30), sizeof(int)); 

  check114 (a114[1], &a114[0]);         
}

Output:
# ./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
     sp             0xbefff808 0xbefff808

@if condition :

   0x83b4 <check114+28>: ldr r1, [r11, #76] ; 0x4c  <- wrong value copied
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

>From ARM Lowering part

ARMTargetLowering::computeRegArea(..) {
  ...
  VARegSize = NumGPRs * 4;
  VARegSaveSize = (VARegSize + Align - 1) & ~(Align - 1);//-> 8 byte alignment
done here
}

For above test code case,
NumGPRs = 3 registers (used to hold struct byval) = 3*4
VARegSaveSize  = 16 (after considering 8 byte alignment )
So, 4 bytes offset added due to alignment.

Which results,
     sub sp, sp, #16

- Offset(#76) for the instruction, "ldr r1, [r11, #76] ; 0x4c"  when
calculated, 4 bytes alignment is considered.
- Prologue stackpointer calculation 8 byte alignment is considered.

Due to this alignment mismatch, when try to access second or rest of arguments
after struct byval goes wrong.


- Issue occurs for only if odd number of registers used for struct byval.
- If even number of registers used for byval, issue doesnt occur(since it will
be naturally aligned by 8 byte boundary when copied to stack).

Ex: Update of above test case with int,
struct S114 check114 (int a, struct S114 arg0, struct S114* arg1) { //
accessing arg1 is fine in this case
.....
} //works fine.</pre>
        </div>
      </p>
      <hr>
      <span>You are receiving this mail because:</span>
      
      <ul>
          <li>You are on the CC list for the bug.</li>
      </ul>
    </body>
</html>