llvmorg-github-actions[bot] wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang-codegen

Author: yonghong-song

<details>
<summary>Changes</summary>

A member access is relocated with CO-RE either inside 
`__builtin_preserve_access_index()` or through the preserve_access_index 
attribute on the record. For an array member with more than one subscript, the 
builtin works, but the attribute does not. With
```
  #define __pai __attribute__((preserve_access_index))
  struct S { long x; int y; } __pai;
  union V { long l; struct S m[2][3]; } __pai;
  struct T {
    struct S a[2][3];
    union V g[3][2];
    struct S (*q)[3];
    struct S *p[3];
    struct S v[2][3][4];
  } __pai;
```
the relocations for `t-&gt;a[1][2].y` are:
  -`__builtin_preserve_access_index(t-&gt;a[1][2].y)`: one relocation, `struct 
T::a[1][2].y`.
  - `t-&gt;a[1][2].y` with only the attribute: `struct T::a[1]` and `struct 
S::y`. The offset of `[2]` is fixed at 32 bytes at compile time, which is wrong 
if the size of `struct S` changes.

This patch closes this gap.

With only the attribute:
  - `emitArraySubscriptGEP()` emits a constant subscript as 
`llvm.preserve.array.access.index`, instead of a plain GEP, only if 
`IsPreserveAIArrayBase()` finds that the base of the subscript comes from a 
record with the attribute.
  - `IsPreserveAIArrayBase()` stripped implicit casts from the base and 
accepted only a member of such a record, e.g., `t-&gt;a in t-&gt;a[1]`, or a 
pointer to such a record.
  - In `t-&gt;a[1][2]`, the base of `[2]` is the subscript `t-&gt;a[1]`, so 
`[2]` became a plain GEP.
  - The BPF backend follows only GEPs with all-zero indices, so that GEP ended 
the CO-RE access chain. The rest of the access started a new chain, and the 
offset of `[2]` was not relocated.
  - Parentheses had the same effect, e.g., in `(t-&gt;a)[2]`, stripping stopped 
at the `ParenExpr`.

Now `IsPreserveAIArrayBase()`:
  - For the second and later subscripts, the base is another 
`ArraySubscriptExpr`, e.g., `t-&gt;a[1]` for `[2]` in `t-&gt;a[1][2]`. It 
replaces the `ArraySubscriptExpr` with its base, repeatedly, until the base is 
no longer a subscript, e.g., the `MemberExpr t-&gt;a` for `[2]`, and checks 
that as before.
  - Uses `IgnoreParenImpCasts()` instead of `IgnoreImpCasts()`, so a 
`ParenExpr` is skipped like an `ImplicitCastExpr`.
  - Still stops at an explicit cast or any other operator.

The relocations with only the attribute are:
```
  - t-&gt;a[1][2].y before: struct T::a[1], struct S::y, [2] fixed at 32 bytes 
after:  struct T::a[1][2].y

  - t-&gt;g[2][1].m[1][2].y, struct -&gt; 2-D array -&gt; union -&gt; 2-D array 
-&gt; struct before: struct T::g[2], union V::m[1], struct S::y, g's [1] and 
m's [2] fixed after:  struct T::g[2][1].m[1][2].y

  - t-&gt;q[1][2].y, a pointer to an array before: struct T::q, struct S::[3], 
struct S::y, [2] fixed at 32 bytes after:  struct T::q, struct S::[5].y

  - t-&gt;p[1][2].y, an array of pointers before: struct T::p[1], struct S::y, 
[2] fixed at 32 bytes after:  struct T::p[1], struct S::[2].y

  - (t-&gt;a[1])[2].y before: struct T::a[1], struct S::y, [2] fixed at 32 
bytes after:  struct T::a[1][2].y, the same as without parentheses

  - t-&gt;v[n][2][3].y, a 3-D array with a variable n before: struct T::v, 
struct S::y, [2][3] fixed at 176 bytes after:  struct T::v, struct S::[11].y 
[n] is not relocated in either case, since a variable subscript cannot be 
preserved, but [2] and [3] after it now are, folded into one index, 2 * 4 + 3 = 
11.
```
In each case, "after" is the same as with
`__builtin_preserve_access_index()`. A pointer load still ends the chain, as in 
the `t-&gt;q` and `t-&gt;p` examples, but the access after the load is now 
relocated as a whole.

---

Patch is 41.99 KiB, truncated to 20.00 KiB below, full version: 
https://github.com/llvm/llvm-project/pull/237589.diff


3 Files Affected:

- (modified) clang/lib/CodeGen/CGExpr.cpp (+5-1) 
- (added) clang/test/CodeGen/bpf-attr-preserve-access-index-9.c (+195) 
- (added) llvm/test/CodeGen/BPF/CORE/offset-reloc-subarray-record.ll (+469) 


``````````diff
diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index 98133ecf1b48fc..ae5f4e723f5129 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -4902,7 +4902,11 @@ static bool IsPreserveAIArrayBase(CodeGenFunction &CGF, 
const Expr *ArrayBase) {
   //    p[1].a
   // p[1] will generate a DeclRefExpr and p[1].a is a MemberExpr.
   // p->b[5] is a MemberExpr example.
-  const Expr *E = ArrayBase->IgnoreImpCasts();
+  const Expr *E = ArrayBase->IgnoreParenImpCasts();
+  // In p->b[1][2], the base of [2] is the subscript p->b[1]. Step through
+  // subscripts to the member p->b.
+  while (const auto *ASE = dyn_cast<ArraySubscriptExpr>(E))
+    E = ASE->getBase()->IgnoreParenImpCasts();
   if (const auto *ME = dyn_cast<MemberExpr>(E))
     return ME->getMemberDecl()->hasAttr<BPFPreserveAccessIndexAttr>();
 
diff --git a/clang/test/CodeGen/bpf-attr-preserve-access-index-9.c 
b/clang/test/CodeGen/bpf-attr-preserve-access-index-9.c
new file mode 100644
index 00000000000000..dd9b1ea7911022
--- /dev/null
+++ b/clang/test/CodeGen/bpf-attr-preserve-access-index-9.c
@@ -0,0 +1,195 @@
+// REQUIRES: bpf-registered-target
+// RUN: %clang_cc1 -triple bpf -emit-llvm -debug-info-kind=limited 
-disable-llvm-passes %s -o - | FileCheck %s
+
+#define __reloc__ __attribute__((preserve_access_index))
+
+// Every subscript of a multi-dimensional array member is preserved, so the
+// record behind the array stays in the same access chain.
+struct s1 {
+  long a;
+  int b;
+} __reloc__;
+typedef const struct s1 __s1;
+typedef struct s1 arr2_t[2][3];
+typedef struct s1 row_t[3];
+
+union u1 {
+  int c;
+  __s1 d;
+} __reloc__;
+
+struct s2 {
+  int e;
+  struct s1 f[2][3];
+  volatile union u1 g[2][3];
+  struct s1 (*h)[3];
+  struct s1 *i[3];
+  const arr2_t j;
+  row_t k[2];
+  struct s1 l[2][3][4];
+} __reloc__;
+typedef struct s2 __s2;
+
+union u2 {
+  int l;
+  __s1 m[2][3];
+} __reloc__;
+typedef union u2 u2row_t[2];
+
+struct s3 {
+  int n;
+  const u2row_t o[3];
+} __reloc__;
+
+int test1(__s2 *arg) { return arg->f[1][2].b; }
+
+// CHECK-LABEL: @test1
+// CHECK-NOT:   getelementptr
+// CHECK:       call ptr @llvm.preserve.struct.access.index.p0.p0(ptr 
elementtype(%struct.s2) %{{[0-9a-z]+}}, i32 1, i32 1)
+// CHECK-NOT:   getelementptr
+// CHECK:       call ptr @llvm.preserve.array.access.index.p0.p0(ptr 
elementtype([2 x [3 x %struct.s1]]) %{{[0-9a-z]+}}, i32 1, i32 1)
+// CHECK-NOT:   getelementptr
+// CHECK:       call ptr @llvm.preserve.array.access.index.p0.p0(ptr 
elementtype([3 x %struct.s1]) %{{[0-9a-z]+}}, i32 1, i32 2)
+// CHECK-NOT:   getelementptr
+// CHECK:       call ptr @llvm.preserve.struct.access.index.p0.p0(ptr 
elementtype(%struct.s1) %{{[0-9a-z]+}}, i32 1, i32 1)
+
+int test2(__s2 *arg) { return arg->g[1][2].d.b; }
+
+// CHECK-LABEL: @test2
+// CHECK-NOT:   getelementptr
+// CHECK:       call ptr @llvm.preserve.struct.access.index.p0.p0(ptr 
elementtype(%struct.s2) %{{[0-9a-z]+}}, i32 2, i32 2)
+// CHECK-NOT:   getelementptr
+// CHECK:       call ptr @llvm.preserve.array.access.index.p0.p0(ptr 
elementtype([2 x [3 x %union.u1]]) %{{[0-9a-z]+}}, i32 1, i32 1)
+// CHECK-NOT:   getelementptr
+// CHECK:       call ptr @llvm.preserve.array.access.index.p0.p0(ptr 
elementtype([3 x %union.u1]) %{{[0-9a-z]+}}, i32 1, i32 2)
+// CHECK-NOT:   getelementptr
+// CHECK:       call ptr @llvm.preserve.union.access.index.p0.p0(ptr 
%{{[0-9a-z]+}}, i32 1)
+// CHECK-NOT:   getelementptr
+// CHECK:       call ptr @llvm.preserve.struct.access.index.p0.p0(ptr 
elementtype(%struct.s1) %{{[0-9a-z]+}}, i32 1, i32 1)
+
+int test3(union u2 *arg) { return arg->m[1][2].b; }
+
+// CHECK-LABEL: @test3
+// CHECK-NOT:   getelementptr
+// CHECK:       call ptr @llvm.preserve.union.access.index.p0.p0(ptr 
%{{[0-9a-z]+}}, i32 1)
+// CHECK-NOT:   getelementptr
+// CHECK:       call ptr @llvm.preserve.array.access.index.p0.p0(ptr 
elementtype([2 x [3 x %struct.s1]]) %{{[0-9a-z]+}}, i32 1, i32 1)
+// CHECK-NOT:   getelementptr
+// CHECK:       call ptr @llvm.preserve.array.access.index.p0.p0(ptr 
elementtype([3 x %struct.s1]) %{{[0-9a-z]+}}, i32 1, i32 2)
+// CHECK-NOT:   getelementptr
+// CHECK:       call ptr @llvm.preserve.struct.access.index.p0.p0(ptr 
elementtype(%struct.s1) %{{[0-9a-z]+}}, i32 1, i32 1)
+
+int test4(__s2 *arg) { return arg->h[1][2].b; }
+
+// CHECK-LABEL: @test4
+// CHECK-NOT:   getelementptr
+// CHECK:       call ptr @llvm.preserve.struct.access.index.p0.p0(ptr 
elementtype(%struct.s2) %{{[0-9a-z]+}}, i32 3, i32 3)
+// CHECK-NOT:   getelementptr
+// CHECK:       call ptr @llvm.preserve.array.access.index.p0.p0(ptr 
elementtype([3 x %struct.s1]) %{{[0-9a-z]+}}, i32 0, i32 1)
+// CHECK-NOT:   getelementptr
+// CHECK:       call ptr @llvm.preserve.array.access.index.p0.p0(ptr 
elementtype([3 x %struct.s1]) %{{[0-9a-z]+}}, i32 1, i32 2)
+// CHECK-NOT:   getelementptr
+// CHECK:       call ptr @llvm.preserve.struct.access.index.p0.p0(ptr 
elementtype(%struct.s1) %{{[0-9a-z]+}}, i32 1, i32 1)
+
+int test5(__s2 *arg) { return arg->i[1][2].b; }
+
+// CHECK-LABEL: @test5
+// CHECK-NOT:   getelementptr
+// CHECK:       call ptr @llvm.preserve.struct.access.index.p0.p0(ptr 
elementtype(%struct.s2) %{{[0-9a-z]+}}, i32 4, i32 4)
+// CHECK-NOT:   getelementptr
+// CHECK:       call ptr @llvm.preserve.array.access.index.p0.p0(ptr 
elementtype([3 x ptr]) %{{[0-9a-z]+}}, i32 1, i32 1)
+// CHECK-NOT:   getelementptr
+// CHECK:       call ptr @llvm.preserve.array.access.index.p0.p0(ptr 
elementtype(%struct.s1) %{{[0-9a-z]+}}, i32 0, i32 2)
+// CHECK-NOT:   getelementptr
+// CHECK:       call ptr @llvm.preserve.struct.access.index.p0.p0(ptr 
elementtype(%struct.s1) %{{[0-9a-z]+}}, i32 1, i32 1)
+
+int test6(__s2 *arg) { return arg->j[1][2].b; }
+
+// CHECK-LABEL: @test6
+// CHECK-NOT:   getelementptr
+// CHECK:       call ptr @llvm.preserve.struct.access.index.p0.p0(ptr 
elementtype(%struct.s2) %{{[0-9a-z]+}}, i32 5, i32 5)
+// CHECK-NOT:   getelementptr
+// CHECK:       call ptr @llvm.preserve.array.access.index.p0.p0(ptr 
elementtype([2 x [3 x %struct.s1]]) %{{[0-9a-z]+}}, i32 1, i32 1)
+// CHECK-NOT:   getelementptr
+// CHECK:       call ptr @llvm.preserve.array.access.index.p0.p0(ptr 
elementtype([3 x %struct.s1]) %{{[0-9a-z]+}}, i32 1, i32 2)
+// CHECK-NOT:   getelementptr
+// CHECK:       call ptr @llvm.preserve.struct.access.index.p0.p0(ptr 
elementtype(%struct.s1) %{{[0-9a-z]+}}, i32 1, i32 1)
+
+int test7(__s2 *arg) { return arg->k[1][2].b; }
+
+// CHECK-LABEL: @test7
+// CHECK-NOT:   getelementptr
+// CHECK:       call ptr @llvm.preserve.struct.access.index.p0.p0(ptr 
elementtype(%struct.s2) %{{[0-9a-z]+}}, i32 6, i32 6)
+// CHECK-NOT:   getelementptr
+// CHECK:       call ptr @llvm.preserve.array.access.index.p0.p0(ptr 
elementtype([2 x [3 x %struct.s1]]) %{{[0-9a-z]+}}, i32 1, i32 1)
+// CHECK-NOT:   getelementptr
+// CHECK:       call ptr @llvm.preserve.array.access.index.p0.p0(ptr 
elementtype([3 x %struct.s1]) %{{[0-9a-z]+}}, i32 1, i32 2)
+// CHECK-NOT:   getelementptr
+// CHECK:       call ptr @llvm.preserve.struct.access.index.p0.p0(ptr 
elementtype(%struct.s1) %{{[0-9a-z]+}}, i32 1, i32 1)
+
+// struct -> array -> union -> array -> struct
+int test8(struct s3 *arg) { return arg->o[2][1].m[1][2].b; }
+
+// CHECK-LABEL: @test8
+// CHECK-NOT:   getelementptr
+// CHECK:       call ptr @llvm.preserve.struct.access.index.p0.p0(ptr 
elementtype(%struct.s3) %{{[0-9a-z]+}}, i32 1, i32 1)
+// CHECK-NOT:   getelementptr
+// CHECK:       call ptr @llvm.preserve.array.access.index.p0.p0(ptr 
elementtype([3 x [2 x %union.u2]]) %{{[0-9a-z]+}}, i32 1, i32 2)
+// CHECK-NOT:   getelementptr
+// CHECK:       call ptr @llvm.preserve.array.access.index.p0.p0(ptr 
elementtype([2 x %union.u2]) %{{[0-9a-z]+}}, i32 1, i32 1)
+// CHECK-NOT:   getelementptr
+// CHECK:       call ptr @llvm.preserve.union.access.index.p0.p0(ptr 
%{{[0-9a-z]+}}, i32 1)
+// CHECK-NOT:   getelementptr
+// CHECK:       call ptr @llvm.preserve.array.access.index.p0.p0(ptr 
elementtype([2 x [3 x %struct.s1]]) %{{[0-9a-z]+}}, i32 1, i32 1)
+// CHECK-NOT:   getelementptr
+// CHECK:       call ptr @llvm.preserve.array.access.index.p0.p0(ptr 
elementtype([3 x %struct.s1]) %{{[0-9a-z]+}}, i32 1, i32 2)
+// CHECK-NOT:   getelementptr
+// CHECK:       call ptr @llvm.preserve.struct.access.index.p0.p0(ptr 
elementtype(%struct.s1) %{{[0-9a-z]+}}, i32 1, i32 1)
+
+// A variable index cannot be preserved, but later constant subscripts can.
+int test9(__s2 *arg, int n) { return arg->f[n][2].b; }
+
+// CHECK-LABEL: @test9
+// CHECK:       call ptr @llvm.preserve.struct.access.index.p0.p0(ptr 
elementtype(%struct.s2) %{{[0-9a-z]+}}, i32 1, i32 1)
+// CHECK:       getelementptr inbounds [2 x [3 x %struct.s1]], ptr 
%{{[0-9a-z]+}}, i64 0, i64 %{{[0-9a-z]+}}
+// CHECK:       call ptr @llvm.preserve.array.access.index.p0.p0(ptr 
elementtype([3 x %struct.s1]) %{{[0-9a-z]+}}, i32 1, i32 2)
+// CHECK:       call ptr @llvm.preserve.struct.access.index.p0.p0(ptr 
elementtype(%struct.s1) %{{[0-9a-z]+}}, i32 1, i32 1)
+
+// Parentheses do not change the access chain.
+int test10(__s2 *arg) { return (arg->f[1])[2].b; }
+
+// CHECK-LABEL: @test10
+// CHECK-NOT:   getelementptr
+// CHECK:       call ptr @llvm.preserve.struct.access.index.p0.p0(ptr 
elementtype(%struct.s2) %{{[0-9a-z]+}}, i32 1, i32 1)
+// CHECK-NOT:   getelementptr
+// CHECK:       call ptr @llvm.preserve.array.access.index.p0.p0(ptr 
elementtype([2 x [3 x %struct.s1]]) %{{[0-9a-z]+}}, i32 1, i32 1)
+// CHECK-NOT:   getelementptr
+// CHECK:       call ptr @llvm.preserve.array.access.index.p0.p0(ptr 
elementtype([3 x %struct.s1]) %{{[0-9a-z]+}}, i32 1, i32 2)
+// CHECK-NOT:   getelementptr
+// CHECK:       call ptr @llvm.preserve.struct.access.index.p0.p0(ptr 
elementtype(%struct.s1) %{{[0-9a-z]+}}, i32 1, i32 1)
+
+int test11(__s2 *arg) { return (arg->f)[1][2].b; }
+
+// CHECK-LABEL: @test11
+// CHECK-NOT:   getelementptr
+// CHECK:       call ptr @llvm.preserve.struct.access.index.p0.p0(ptr 
elementtype(%struct.s2) %{{[0-9a-z]+}}, i32 1, i32 1)
+// CHECK-NOT:   getelementptr
+// CHECK:       call ptr @llvm.preserve.array.access.index.p0.p0(ptr 
elementtype([2 x [3 x %struct.s1]]) %{{[0-9a-z]+}}, i32 1, i32 1)
+// CHECK-NOT:   getelementptr
+// CHECK:       call ptr @llvm.preserve.array.access.index.p0.p0(ptr 
elementtype([3 x %struct.s1]) %{{[0-9a-z]+}}, i32 1, i32 2)
+// CHECK-NOT:   getelementptr
+// CHECK:       call ptr @llvm.preserve.struct.access.index.p0.p0(ptr 
elementtype(%struct.s1) %{{[0-9a-z]+}}, i32 1, i32 1)
+
+// A variable index in a 3-D array member: the constant subscripts after it are
+// still preserved.
+int test12(__s2 *arg, int n) { return arg->l[n][2][3].b; }
+
+// CHECK-LABEL: @test12
+// CHECK:       call ptr @llvm.preserve.struct.access.index.p0.p0(ptr 
elementtype(%struct.s2) %{{[0-9a-z]+}}, i32 7, i32 7)
+// CHECK:       getelementptr inbounds [2 x [3 x [4 x %struct.s1]]], ptr 
%{{[0-9a-z]+}}, i64 0, i64 %{{[0-9a-z]+}}
+// CHECK-NOT:   getelementptr
+// CHECK:       call ptr @llvm.preserve.array.access.index.p0.p0(ptr 
elementtype([3 x [4 x %struct.s1]]) %{{[0-9a-z]+}}, i32 1, i32 2)
+// CHECK-NOT:   getelementptr
+// CHECK:       call ptr @llvm.preserve.array.access.index.p0.p0(ptr 
elementtype([4 x %struct.s1]) %{{[0-9a-z]+}}, i32 1, i32 3)
+// CHECK-NOT:   getelementptr
+// CHECK:       call ptr @llvm.preserve.struct.access.index.p0.p0(ptr 
elementtype(%struct.s1) %{{[0-9a-z]+}}, i32 1, i32 1)
diff --git a/llvm/test/CodeGen/BPF/CORE/offset-reloc-subarray-record.ll 
b/llvm/test/CodeGen/BPF/CORE/offset-reloc-subarray-record.ll
new file mode 100644
index 00000000000000..2e25097ff79199
--- /dev/null
+++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-subarray-record.ll
@@ -0,0 +1,469 @@
+; RUN: opt -O2 %s | llc -filetype=obj -o - | \
+; RUN:   llvm-objdump --no-addresses --no-show-raw-insn --no-print-imm-hex -dr 
- | \
+; RUN:   FileCheck %s --implicit-check-not=CO-RE
+
+; A record inside a multi-dimensional array member stays in the access chain,
+; so each access needs one relocation rooted at the outer record. This holds
+; through qualifiers, typedefs, array element typedefs and nested arrays.
+;
+; Source:
+;   #define __pai __attribute__((preserve_access_index))
+;   struct S { long x; int y; } __pai;
+;   typedef const volatile struct S cvS;
+;   typedef struct { long x; int y; } __pai Anon;
+;   typedef struct S Arr2[2][3];
+;   typedef struct S Row[3];
+;   union U { int i; const struct S s; } __pai;
+;   union V { long l; const struct S m[2][3]; } __pai;
+;   typedef union V Vrow[2];
+;   struct T { int pad; struct S a[2][3]; volatile union U b[2][3]; cvS 
c[2][3]; Anon d[2][3]; const Arr2 e; Row f[2]; const Vrow g[3]; struct S 
h[2][3][4]; } __pai;
+;   typedef const struct T cT;
+;   int rec(cT *t) { return t->a[1][2].y; }
+;   int un(cT *t) { return t->b[1][2].s.y; }
+;   int cv(cT *t) { return t->c[1][2].y; }
+;   int anon(cT *t) { return t->d[1][2].y; }
+;   int arr2(cT *t) { return t->e[1][2].y; }
+;   int row(cT *t) { return t->f[1][2].y; }
+;   int nest(cT *t) { return t->g[2][1].m[1][2].y; }
+;   unsigned nest_sz(cT *t) { return 
__builtin_preserve_field_info(t->g[2][1].m[1], 1); }
+;   int var(cT *t, int n) { return t->a[n][2].y; }
+;   int var3(cT *t, int n) { return t->h[n][2][3].y; }
+; Compilation flag:
+;   clang -target bpf -O2 -g -S -emit-llvm -Xclang -disable-llvm-passes test.c
+
+; CHECK-LABEL: <rec>:
+; CHECK:       w0 = *(u32 *)(r1 + 96)
+; CHECK-NEXT:  CO-RE <byte_off> [{{[0-9]+}}] typedef cT::a[1][2].y (0:1:1:2:1)
+; CHECK-LABEL: <un>:
+; CHECK:       w0 = *(u32 *)(r1 + 192)
+; CHECK-NEXT:  CO-RE <byte_off> [{{[0-9]+}}] typedef cT::b[1][2].s.y 
(0:2:1:2:1:1)
+; CHECK-LABEL: <cv>:
+; CHECK:       w0 = *(u32 *)(r1 + 288)
+; CHECK-NEXT:  CO-RE <byte_off> [{{[0-9]+}}] typedef cT::c[1][2].y (0:3:1:2:1)
+; CHECK-LABEL: <anon>:
+; CHECK:       w0 = *(u32 *)(r1 + 384)
+; CHECK-NEXT:  CO-RE <byte_off> [{{[0-9]+}}] typedef cT::d[1][2].y (0:4:1:2:1)
+; CHECK-LABEL: <arr2>:
+; CHECK:       w0 = *(u32 *)(r1 + 480)
+; CHECK-NEXT:  CO-RE <byte_off> [{{[0-9]+}}] typedef cT::e[1][2].y (0:5:1:2:1)
+; CHECK-LABEL: <row>:
+; CHECK:       w0 = *(u32 *)(r1 + 576)
+; CHECK-NEXT:  CO-RE <byte_off> [{{[0-9]+}}] typedef cT::f[1][2].y (0:6:1:2:1)
+; CHECK-LABEL: <nest>:
+; CHECK:       w0 = *(u32 *)(r1 + 1152)
+; CHECK-NEXT:  CO-RE <byte_off> [{{[0-9]+}}] typedef cT::g[2][1].m[1][2].y 
(0:7:2:1:1:1:2:1)
+; CHECK-LABEL: <nest_sz>:
+; CHECK:       r0 = 48
+; CHECK-NEXT:  CO-RE <byte_sz> [{{[0-9]+}}] typedef cT::g[2][1].m[1] 
(0:7:2:1:1:1)
+; The variable subscript [n] is not relocated, but the constant [2] after it
+; is part of the relocation rooted at struct S.
+; CHECK-LABEL: <var>:
+; CHECK:       r{{[0-9]+}} = 8
+; CHECK-NEXT:  CO-RE <byte_off> [{{[0-9]+}}] typedef cT::a (0:1)
+; CHECK:       w0 = *(u32 *)(r1 + 40)
+; CHECK-NEXT:  CO-RE <byte_off> [{{[0-9]+}}] struct S::[2].y (2:1)
+; In a 3-D array, both constant subscripts after [n] are folded into one
+; index, 2 * 4 + 3 = 11.
+; CHECK-LABEL: <var3>:
+; CHECK:       r{{[0-9]+}} = 1160
+; CHECK-NEXT:  CO-RE <byte_off> [{{[0-9]+}}] typedef cT::h (0:8)
+; CHECK:       w0 = *(u32 *)(r1 + 184)
+; CHECK-NEXT:  CO-RE <byte_off> [{{[0-9]+}}] struct S::[11].y (11:1)
+
+source_filename = "test.c"
+target triple = "bpf"
+
+%struct.T = type { i32, [2 x [3 x %struct.S]], [2 x [3 x %union.U]], [2 x [3 x 
%struct.S]], [2 x [3 x %struct.Anon]], [2 x [3 x %struct.S]], [2 x [3 x 
%struct.S]], [3 x [2 x %union.V]], [2 x [3 x [4 x %struct.S]]] }
+%union.U = type { %struct.S }
+%struct.S = type { i64, i32 }
+%struct.Anon = type { i64, i32 }
+%union.V = type { [2 x [3 x %struct.S]] }
+
+; Function Attrs: nounwind
+define dso_local i32 @rec(ptr noundef %0) #0 !dbg !93 {
+  %2 = alloca ptr, align 8
+  store ptr %0, ptr %2, align 8, !tbaa !99
+    #dbg_declare(ptr %2, !98, !DIExpression(), !102)
+  %3 = load ptr, ptr %2, align 8, !dbg !103, !tbaa !99
+  %4 = call ptr @llvm.preserve.struct.access.index.p0.p0(ptr 
elementtype(%struct.T) %3, i32 1, i32 1), !dbg !104, 
!llvm.preserve.access.index !3
+  %5 = call ptr @llvm.preserve.array.access.index.p0.p0(ptr elementtype([2 x 
[3 x %struct.S]]) %4, i32 1, i32 1), !dbg !103, !llvm.preserve.access.index !62
+  %6 = call ptr @llvm.preserve.array.access.index.p0.p0(ptr elementtype([3 x 
%struct.S]) %5, i32 1, i32 2), !dbg !103, !llvm.preserve.access.index !63
+  %7 = call ptr @llvm.preserve.struct.access.index.p0.p0(ptr 
elementtype(%struct.S) %6, i32 1, i32 1), !dbg !105, 
!llvm.preserve.access.index !26
+  %8 = load i32, ptr %7, align 8, !dbg !106, !tbaa !107
+  ret i32 %8, !dbg !110
+}
+
+; Function Attrs: nocallback nofree nosync nounwind willreturn memory(none)
+declare ptr @llvm.preserve.struct.access.index.p0.p0(ptr, i32 immarg, i32 
immarg) #1
+
+; Function Attrs: nocallback nofree nosync nounwind willreturn memory(none)
+declare ptr @llvm.preserve.array.access.index.p0.p0(ptr, i32 immarg, i32 
immarg) #1
+
+; Function Attrs: nounwind
+define dso_local i32 @un(ptr noundef %0) #0 !dbg !111 {
+  %2 = alloca ptr, align 8
+  store ptr %0, ptr %2, align 8, !tbaa !99
+    #dbg_declare(ptr %2, !113, !DIExpression(), !114)
+  %3 = load ptr, ptr %2, align 8, !dbg !115, !tbaa !99
+  %4 = call ptr @llvm.preserve.struct.access.index.p0.p0(ptr 
elementtype(%struct.T) %3, i32 2, i32 2), !dbg !116, 
!llvm.preserve.access.index !3
+  %5 = call ptr @llvm.preserve.array.access.index.p0.p0(ptr elementtype([2 x 
[3 x %union.U]]) %4, i32 1, i32 1), !dbg !115, !llvm.preserve.access.index !64
+  %6 = call ptr @llvm.preserve.array.access.index.p0.p0(ptr elementtype([3 x 
%union.U]) %5, i32 1, i32 2), !dbg !115, !llvm.preserve.access.index !66
+  %7 = call ptr @llvm.preserve.union.access.index.p0.p0(ptr %6, i32 1), !dbg 
!117, !llvm.preserve.access.index !118
+  %8 = call ptr @llvm.preserve.struct.access.index.p0.p0(ptr 
elementtype(%struct.S) %7, i32 1, i32 1), !dbg !119, 
!llvm.preserve.access.index !26
+  %9 = load volatile i32, ptr %8, align 8, !dbg !120, !tbaa !121
+  ret i32 %9, !dbg !122
+}
+
+; Function Attrs: nocallback nofree nosync nounwind willreturn memory(none)
+declare ptr @llvm.preserve.union.access.index.p0.p0(ptr, i32 immarg) #1
+
+; Function Attrs: nounwind
+define dso_local i32 @cv(ptr noundef %0) #0 !dbg !123 {
+  %2 = alloca ptr, align 8
+  store ptr %0, ptr %2, align 8, !tbaa !99
+    #dbg_declare(ptr %2, !125, !DIExpression(), !126)
+  %3 = load ptr, ptr %2, align 8, !dbg !127, !tbaa !99
+  %4 = call ptr @llvm.preserve.struct.access.index.p0.p0(ptr 
elementtype(%struct.T) %3, i32 3, i32 3), !dbg !128, 
!llvm.preserve.access.index !3
+  %5 = call ptr @llvm.preserve.array.access.index.p0.p0(ptr elementtype([2 x 
[3 x %struct.S]]) %4, i32 1, i32 1), !dbg !127, !llvm.preserve.access.index !28
+  %6 = call ptr @llvm.preserve.array.access.index.p0.p0(ptr elementtype([3 x 
%struct.S]) %5, i32 1, i32 2), !dbg !127, !llvm.preserve.access.index !69
+  %7 = call ptr @llvm.preserve.struct.access.index.p0.p0(ptr 
elementtype(%struct.S) %6, i32 1, i32 1), !dbg !129, 
!llvm.preserve.access.index !29
+  %8 = load volatile i32, ptr %7, align 8, !dbg !130, !tbaa !107
+  ret i32 %8, !dbg !131
+}
+
+; Function Attrs: nounwind
+define dso_local i32 @anon(ptr noundef %0) #0 !dbg !132 {
+  %2 = alloca ptr, align 8
+  store ptr %0, ptr %2, align 8, !tbaa !99
+    #dbg_declare(ptr %2, !134, !DIExpression(), !135)
+  %3 = load ptr, ptr %2, align 8, !dbg !136, !tbaa !99
+  %4 = call ptr @llvm.preserve.struct.access.index.p0.p0(ptr 
elementtype(%struct.T) %3, i32 4, i32 4), !dbg !137, 
!llvm.preserve.access.index !3
+  %5 = call ptr @llvm.preserve.array.access.index.p0.p0(ptr elementtype([2 x 
[3 x %struct.Anon]]) %4, i32 1, i32 1), !dbg !136, !llvm.preserve.access.index 
!70
+  %6 = call ptr @llvm.preserve.array.access.index.p0.p0(ptr elementtype([3 x 
%struct.Anon]) %5, i32 1, i32 2), !dbg !136, !llvm.preserve.access.index !71
+  %7 = call ptr @llvm.preserve.struct.access.index.p0.p0(ptr 
elementtype(%struct.Anon) %6, i32 1, i32 1), !dbg !138, 
!llvm.preserve.access.index !73
+  %8 = load i32, ptr %7, align 8, !dbg !139, !tbaa !140
+  ret i32 %8, !dbg !142
+}
+
+; Function Attrs: nounwind
+define dso_local i32 @arr2(ptr noundef %0) #0 !dbg !143 {
+  %2 = alloca ptr, align 8
+  store ptr %0, ptr %2, align 8, !tbaa !99
+    #dbg_declare(ptr %2, !145, !DIExpression(), !146)
+  %3 = load ptr, ptr %2, align 8, !dbg !147, !tbaa !99
+  %4 = call ptr @llvm.preserve.struct.access.index.p0.p0(ptr 
elementtype(%struct.T) %3, i32 5, i32 5), !dbg !148, 
!llvm.preserve.access.index !3
+  %5...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/237589
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to