<table border="1" cellspacing="0" cellpadding="8">
    <tr>
        <th>Issue</th>
        <td>
            <a href=https://github.com/llvm/llvm-project/issues/124061>124061</a>
        </td>
    </tr>

    <tr>
        <th>Summary</th>
        <td>
            extractvalue with packed struct with vector off-by-one error
        </td>
    </tr>

    <tr>
      <th>Labels</th>
      <td>
            new issue
      </td>
    </tr>

    <tr>
      <th>Assignees</th>
      <td>
      </td>
    </tr>

    <tr>
      <th>Reporter</th>
      <td>
          Chobbes
      </td>
    </tr>
</table>

<pre>
    This bug was initially discovered in this [issue](https://github.com/vellvm/vellvm/issues/283)

We believe there is an off-by-one error with code generation for the
extractvalue instruction when a vector is contained within a packed
structure. We have two example programs, one which exhibits what we
believe to be a miscompilation that uses a `<{<3 x i8>, i8}>`
structure, and one where we have replaced the vector with an array
type instead, and miscompilation does not occur.

- [ptrtoint2.ll](https://github.com/vellvm/vellvm/blob/dev/qc-test-failures/ptrtoint-roundtrip/ptrtoint2.ll), which uses `<{<3 x i8>, i8}>`. This one we believe miscompiles.
- [ptrtoint7.ll](https://github.com/vellvm/vellvm/blob/dev/qc-test-failures/ptrtoint-roundtrip/ptrtoint7.ll), which uses `<{[3 x i8], i8}>`. This gives us the behavior we expect.

The program which we believe miscompiles is as follows:

```
define  i8 @main() {
    %v0 = alloca i32
    store i32 0, i32* %v0, align 1
    %v1 = ptrtoint i32* %v0 to i64
    %v2 = inttoptr i64 %v1 to <{<3 x i8>, i8}>*
 %v3 = load <{<3 x i8>, i8}>, <{<3 x i8>, i8}>* %v2, align 1
    %v4 = extractvalue <{<3 x i8>, i8}> %v3, 1
    ret i8 %v4
}
```

We expect this to return 0, because we are essentially bitcasting a
32-bit 0 value to this 32-bit packed structure, and fetching the last
byte of it (which should be 0). After compiling this on an intel mac,
and an intel linux machine we get a different return value instead
(e.g., 46 is returned instead of 0 on the mac).

If we replace the vector with an array:

```
define  i8 @main() {
    %v0 = alloca i32
    store i32 0, i32* %v0, align 1
    %v1 = ptrtoint i32* %v0 to i64
    %v2 = inttoptr i64 %v1 to <{[3 x i8], i8}>*
 %v3 = load <{[3 x i8], i8}>, <{[3 x i8], i8}>* %v2, align 1
    %v4 = extractvalue <{[3 x i8], i8}> %v3, 1
    ret i8 %v4
}
```

We get the expected value of 0 on all platforms we've tried.

We believe that this is caused by an off-by-one error somewhere in the
code generation for extractvalue. For instance, we tried generating
RISC-V assembly code to see what code was generated for both of these
programs. Both the vector and array versions compile to identical
assembly language *except* for the load of the return value.

The vector version:

```
        .text
        .attribute      4, 16
        .attribute      5, "rv64i2p1_m2p0_a2p1_c2p0_zmmul1p0"
        .file   "ptrtoint2.ll"
        .globl  main # -- Begin function main
        .p2align        1
        .type   main,@function
main: # @main
        .cfi_startproc
# %bb.0:
        addi    sp, sp, -16
        .cfi_def_cfa_offset 16
        li      a0, 0
        sb      a0, 15(sp)
        sb      a0, 14(sp)
        sb      a0, 13(sp)
        sb      a0, 12(sp)
        lbu     a0, 16(sp)
        addi    sp, sp, 16
        ret
.Lfunc_end0:
        .size   main, .Lfunc_end0-main
        .cfi_endproc
                                        # -- End function
        .section        ".note.GNU-stack","",@progbits
        .addrsig
```

The array version:

```
        .text
        .attribute      4, 16
        .attribute      5, "rv64i2p1_m2p0_a2p1_c2p0_zmmul1p0"
        .file   "ptrtoint7.ll"
        .globl  main # -- Begin function main
        .p2align        1
        .type   main,@function
main: # @main
        .cfi_startproc
# %bb.0:
        addi    sp, sp, -16
        .cfi_def_cfa_offset 16
        li      a0, 0
        sb      a0, 15(sp)
        sb      a0, 14(sp)
        sb      a0, 13(sp)
        sb      a0, 12(sp)
        lbu     a0, 15(sp)
        addi    sp, sp, 16
        ret
.Lfunc_end0:
        .size   main, .Lfunc_end0-main
        .cfi_endproc
                                        # -- End function
        .section        ".note.GNU-stack","",@progbits
        .addrsig
```

In the vector version the instruction `lbu a0, 16(sp)` should be `lbu
a0, 15(sp)`, as in the array version. A similar issue can be seen in
the ARM code that's generated as well. Presumably something similar
happens in x86 as well, but there are larger differences between the
assembly files generated between the two files as well.

This test was ran using the following machines
- Clang 13
```
Homebrew clang version 13.0.1
Target: x86_64-apple-darwin21.6.0
Thread model: posix
InstalledDir: /usr/local/opt/llvm@13/bin
```
- Clang 19
```
Homebrew clang version 19.1.7
Target: x86_64-apple-darwin21.6.0
Thread model: posix
InstalledDir: /usr/local/Cellar/llvm/19.1.7/bin
Configuration file: /usr/local/etc/clang/x86_64-apple-darwin21.cfg
```

We believe that the structure in both of the examples should be of the same size as the `i32` value because of the following statements from the LLVM Language Reference:
- "In general vector elements are laid out in memory in the same way as array types. Such an analogy works fine as long as the vector elements are byte sized"
- "Structures may optionally be 'packed' structures, which indicate that the alignment of the struct is one byte, and that there is no padding between the elements."

Notice the following
- It is true that, according to this [mail](https://lists.llvm.org/pipermail/llvm-dev/2011-December/046257.html), that "`extractvalue` does not work on vectors, [and one] needs to use `extractelement` for them". However, the example in that code was directly extracting the element from the vector inside the packed struct using a single `extractvalue` call. This example is different, and is similar to the first few instructions of the example in the [mail](https://lists.llvm.org/pipermail/llvm-dev/2011-December/046257.html): our example does not directly load value from the vector inside the packed struct, but other elements inside the packed struct.

</pre>
<img width="1" height="1" alt="" src="http://email.email.llvm.org/o/eJzsWVtv4zYW_jXMy4EFmbJl-yEPjlNvB5gWi7bbPgaUdGRzS5FakrLj_vrFISlfMs7MYIDuLhYdDBKHl8Nz-87Nwjm504iPbP7E5s8PYvB7Yx83e1NV6B4q05wef9lLB9Wwg6NwILX0Uih1gka62hzQYgNSg6dDbP4knRuQzZ8ZX-697x0r1oxvGd_upN8PVVabjvHtAZU63HwI9xzjW74sGF-xfM3y9W8IFSqJBwS_R4sgHQgNpm0n1WliNAJaaywcpd9DbRqEHWq0wkujoTWWbrF8ja_eitofhBoQpHbeDnU4ctyjBgEHrL2xRLw22gupsQkkJW32ov4dG5av47XBYga_IewFMXU0gK-i6xVCb83Ois4xvgHi7LiX9R7wdS8r6R0c98LDkbg5S2SgQhDQkR67XqrItqeDg0MHAliZs2LDFk-s2BTwCnLJiu_oAblki2f6XObXnNGW0E16nxR2TJxa7JWosSGNjPIGrQkNwlpxYvnan_qoHhTNSOkNc41BB9p4MHU92CxaaUJ27731RmrPM6W-wfyVMhXj2wYPjG__VU88Oj9phVSDDV4xkp9YM-jGW9lfLYY3-Yp4jloP6vsa5WUQnDvo6-JrZ6HRZW_lW_wX5Ft8Qb75U5KP-Lon304e0MHggvUr3IuDJPsj4GuPtU92_GV_9uL0zn2dBBQ6aI1S5hg0EK4TP_F_vm6wlRoB5BLYLO-E1IwvGV8BsZuvAQAYnx9yYMUzCKVMLUAWPG05bwjrBYc8yFNwxtfxQvBLJXcapld0poHOqK6bCwQzWc6uDvNwWGrvTe8tbSYa3sAXHIaTnOF0EYgoI5ov3tl8mWrk675ss_DSTQj7PL3IH62MZCz6YAmiRoZaPL8xVwy10RliJPeGbg1WRxNUWIvBBZAIi4DOoU5poJK-Fs5LvQPB8nXBJ5X0kENk1ZtILy3HYAqfBKwWfb0nEuSgSjhPcfLkEUwL0gPjy-iQbm8G1VDczBlfZbBuPVqIjhmvBzRTVJPao4JO1IxvWL6mV86rSurhlfb2MiJ_hx4ENLJt0aL2o-yXjEEhMV8zvsRslxHXs5JgEM-FDBjOEL85hCiO8e1VAteHlt5JYfj9KPx_CKb3otPnwPTunc2XqX4bmN6h981gIo8iK0dQYZN8afQPoRT0SvjW2M5RXcAXVBJYiU12p_YRCZZUohAQG6hOdyshZzqMmT_UZFRv3KuLrjWQwZaKH-280HVA5DFxcr6ldyxf__Th583kVxDOYVepU6y3vAGHGKubsEA1YrqGTXirMn5Pcvs9OuJnLJQyeKKdKygEjBIM4IDWSaNdgnZ4RzYUc2qhCM0jE0ro3SB2CIyv8bXG3pMHpNIvulR8-gbSVwkvPZ0evIs_lq8yj68-fRTeW1kNHlm-mgXPKO_szIOvcm4P5UzyfvrS8T5_EfSppk9_dN2gpn3OOE-3W6noIuP8tq4Z93fKVIrlKwoAwHgBkwk84U5qaAcd69kQG-LpngfvZ_lqOopw6jFdp5A4y8drLF-HxWIdyI4xJt6qW_nivLC-t6YOIbAg36-qLB-VtRJNI1m-cj3JHH9OzkohAg22L3UrXkzbOvRnhSm6JUIYSnp21XllOmd8ScRWn27N3t8q3t_it1uqGi575e3eHYlGpi2SI2QfSXsvqJuLGjIn_7jSMFydmbzRKOom6RO-8l8y-HeULC92C69i-otcJ9PGY_a3H_8xcV7Uv5P38E34yaPRCX3UkIwu2zTWyd2nIYywcYPF_y1oLP6Cxn8KGvO_oHELjQ_6OmkleISl69kCK3NVDfBJfCnzqyo2HqKE9lbXZazOXMrjt1jMYA1OdlIJC2FwArXQRM8hUo1LzfweYf3TDylL74VnfHGdmQVVHUpl8HeLbugEJVMqHnwowxNxlq_3ou9RBzZel-V4LfQEg09TGWoJlLA7tOcSukYHFfoj8RPLkHPKbkMPeeHk6lgYqMT9kb8xGlFPgs6H-sIKDYMb24XYh9JfqaB3oWffUGlATn9rv-9Nh5XFI9Rhf7TetMjyjMLBLySHJ8C_LsuXcjYRfa9w0gh7lJpPszLLAz-Wqv3ONKjobG-cfA2u4bxQCptnaWPQ2A7OMr6lolwxvjVUoGzDUGCWEyK3VfT-KxbPvK--kvdVNs0Wfz7vG1TkE4l9vk3vjiJsjG7lbhirTArZ96igrxnfBgkY395ntG7vwO7TghgvjST551WhOU7l3BXW0o4THQKFI3IxWmBlTj1OObasY6-bzl_cy3nhsUPtHbTWdGH348dff4CPYxH6Eybnj4FvQlnug06-rsaIgSpRibiRDZjBkwAddsaeRsQHRo_iRHxG9FOachn8PNSxY9RCmd0Jjsb-7iD0iMKBMtSJu-sQdfNgaKtJ_ibmz8Dkz6MeHXTiBKYnG8b2nkrrRRqC8sVF4-4yjpK6kbXwV3YJCZbePGs9XIM0ayMextZ_vBOnu9pATxlG727iwihBNub89Y_Gy9RIny0UpPkQXvF2GMPeBkRdGxtojuMINn_qhLw7yFPSeZeRi2fGkov2skcbTkfPn8QhHs-n08kz1thVSP6dz0o-X2R7342zuiAZMVzm1_0Wedp5jkq2o34wWirolM2f0gyXzZ9BIzZhHEMueaGUFEK0UrPTUYqD780RD8TP5hoG0aWuW7RGWqy9Oo2d4BhME92Lg4-zce1kE9V9M8NJcVgA_VLXHJ5lrQWlmRDBz-y4y6xl9APpziktWAmhldZ5aPF4nVfdG4SPaPnzLVqswQz2_O7ZhGdVhm4zxpCvVd-YRw0B4ILT945TNnxoHotmVazEAz5OF8WizMtpWT7sH5uyLPOy4OVyVhVFVTXY5FO-bJYrsVxOi-JBPvKcz_MpL_IZ57MyE_Nqyle8nIm8xlldsFmOpJazrh5CcfE45bO8nD4oUaFy4ZsizjWZJXzXwzmbPz_Yx6DJatg5NstvVf7gpVf4eDN2CWOvW1cKS0lhbwcbD4NVj5-ZuKeUFHjorfknkm4vXyolCQ6P_N8BAAD__ziwXZ8">