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

    <tr>
        <th>Summary</th>
        <td>
            Clang: __builtin_offsetof ignores attribute preserve_access_index
        </td>
    </tr>

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

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

    <tr>
      <th>Reporter</th>
      <td>
          j-piecuch
      </td>
    </tr>
</table>

<pre>
    https://godbolt.org/z/WdWG548bK

Source:
```c
#include <stddef.h>

struct s {
    int bar;
    int foo;
} __attribute__((preserve_access_index));

#define normal_offsetof(type, member)                              \
  ({ \
    type *__base = NULL; \
    ((unsigned long)(&__base->member)); \
 })

#define core_offsetof(type, member) \
  ({ \
    type *__base = NULL; \
    ((unsigned long)__builtin_preserve_access_index(&__base->member)); \
  })

unsigned long using_builtin_offsetof(int *p) {
 return __builtin_offsetof(struct s, foo);
}

unsigned long using_normal_offsetof(int *p) {
    return normal_offsetof(struct s, foo);
}

unsigned long using_core_offsetof(int *p) {
    return core_offsetof(struct s, foo);
}
```

LLVM IR:
```llvm
@"llvm.s:0:4$0:1" = external global i64, !llvm.preserve.access.index !0 #0

define dso_local i64 @using_builtin_offsetof(ptr nocapture noundef readnone %0) local_unnamed_addr #1 !dbg !15 {
  call void @llvm.dbg.value(metadata ptr %0, metadata !20, metadata !DIExpression()), !dbg !21
  ret i64 4, !dbg !22
}

define dso_local i64 @using_normal_offsetof(ptr nocapture noundef readnone %0) local_unnamed_addr #2 !dbg !23 {
  call void @llvm.dbg.value(metadata ptr %0, metadata !25, metadata !DIExpression()), !dbg !29
  call void @llvm.dbg.value(metadata ptr null, metadata !26, metadata !DIExpression()), !dbg !30
  %2 = load i64, ptr @"llvm.s:0:4$0:1", align 8
  %3 = getelementptr i8, ptr null, i64 %2
 %4 = tail call ptr @llvm.bpf.passthrough.p0.p0(i32 0, ptr %3)
  %5 = ptrtoint ptr %4 to i64, !dbg !31
  ret i64 %5, !dbg !32
}

define dso_local i64 @using_core_offsetof(ptr nocapture noundef readnone %0) local_unnamed_addr #2 !dbg !33 {
  call void @llvm.dbg.value(metadata ptr %0, metadata !35, metadata !DIExpression()), !dbg !38
  call void @llvm.dbg.value(metadata ptr null, metadata !36, metadata !DIExpression()), !dbg !39
  %2 = load i64, ptr @"llvm.s:0:4$0:1", align 8
  %3 = getelementptr i8, ptr null, i64 %2
  %4 = tail call ptr @llvm.bpf.passthrough.p0.p0(i32 1, ptr %3)
  %5 = ptrtoint ptr %4 to i64, !dbg !40
  ret i64 %5, !dbg !41
}

declare ptr @llvm.bpf.passthrough.p0.p0(i32, ptr) #3

declare void @llvm.dbg.value(metadata, metadata, metadata) #4

attributes #0 = { "btf_ama" }
attributes #1 = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) "frame-pointer"="all" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="v2" }
attributes #2 = { nofree nosync nounwind memory(read, argmem: none, inaccessiblemem: none) "frame-pointer"="all" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="v2" }
attributes #3 = { nofree nosync nounwind memory(none) }
attributes #4 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
```

Expected behavior: LLVM IR for `using_builtin_offsetof` should be the same as for `using_normal_offsetof` and `using_core_offsetof` (i.e. it should cause the backend to generate relocations for the offset).

My suspicion is that [`IntExprEvaluator::VisitOffsetOfExpr()`](https://github.com/llvm/llvm-project/blob/b95913e8c3a3521b85d689a358e620d89a4e83de/clang/lib/AST/ExprConstant.cpp#L13426) is completely oblivious to the `preserve_access_index` attribute and happily evaluates the expression to a constant.
</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJzUWFFv47gR_jX0C2FDIiVHfvCDN46LRXM9oNfePRoUOZJ5R5ECSWU3--uLoSyv4zjJIpsCbWBENjWc-ebjN-RIIgTdWoA1KT-RcjsTQzw4v_5z3muQgzzMaqce14cY-0D4hrAdYbvWqdqZuHC-JWz3jbDdH-qPv5VFVf-dZFuSbcb_v7nBS8BZ4-AyGz_y-JtxbaUZFFDCb0NUCprFgfC7cx8h-kFGGii5-TSOUEqptpHWwhN-MdY4dxojN1u634sYva6HCPs9YRVhVe8hgH-AvZASQthrq-ArYSv8nKZO-BQ02gK1znfC7F3TBIiuIayKjz0Qdks76GrwhK3oq3-kvJ2AIoqbT-cjlKI3Sthmv69FQDa29B__vr8n_MJuzGCwacUUNc62CXlF2HKcOyf87oRpTOnMBbnZ4tjVHKXz8HqG_9Uk9vt60CZqu39hgX40xytJPolFh6Bte4p2ljEKiLBNn3I9qc1DHLyl-2szJnEiTyi9cwndbN-C8FxV1xFQOoF4PuPnEFyu-VvxL-1_KPpU9edg7u9__4V-_ufzrcGYh-44VGSEMfy9wI0nI3xTEFbgNSeMJX3B1wjeCkNb42phqF4WCIWwPM2blLQYlbRISsK7GSWMPwF0LAIV3N44ObqipMheFEsfPbVOij4OHjeIwSpoqAehrLNYB2WGLCZn-8Fa0YHaC6U8hs4RhKpbvOTlOdVSGEMfnFYYPCWh6nbxIMwAhFUdRKFEFBSjjyGwQI-DhOXs2cj2891X5CFoZ1MRpYoZSToiYPkU3UNMiRcXBuyqol7n7LlWf4oydo6HfyRl5XsoW70juh2MeRZ9-Y7ok3RxLy3HSjBOqEn-KdPXqwfNhNGtpdWZK55ctRDBQAc2oiNdTS4n-GmVWcmmM4WVRZoXhTYjHUcAKXrdN4tehBAP3g3tYdFniz7DrYYzmp3QspKT75wSVpbJZR99dLgpHY0KGt1ZkU90PNMvOriweY-EL7e7DxMw_0gB8_cImFcfJGD-LgGv_ocE_DMKzj9GwUX2toKL_AUFSyM8_CjiI950wDPOr3l6UwvnC_70e3JanDs9td8hHbmJk9Q5MlbHZi86kc7yKaen5vnJvBtC7L1rUVbUusZDaspBDj7gt_BoZSrIL9oq-kUbc-xYOuicfySswgodAbLGiw7mPS4LtpCM8C1hTKA4sEiZdfPoRd9r2847EQ8nk-iRh2QTopB_zXvvIsjo_Lwemgb8POhvcDKvjrZR-BbiXPbD6dYDeyVtdkr7lOnT_E5J4daTKsG3HXSEb-iY5i3Vdux5dI2VcHbr_4IB_sMMnJK67qg4c4SFXQv510s-Qw9yMCKK2sDrEnq1tb372oOMoGgNB_GgnUfuj_0ubZynZPlSV7nMaDi4weBcGg9Ag-iAivB02mVjtcyosOr7_aen1hJ73UovYEF1nNxLMYQxAhICVuGu1IIFLyJQD3iCRe3sGBntRn-ErRbnuf7ySMMQei21s1QHGg8iUlJ-Isvss414DNzh5iFiYoHwze866Phr8vVrg_ePB8QyI-WWsOriNYOOh6FeSNcRtktPBuMFVfcnyEjYrjauxsuqXOUcKskFL1leV6VaVivBywqWLFPVShRQcQWE7aQR-MC5Mxonbn77F2E7RHLrbIjCxoXse8L4fc4LbM5WmJd0XW_wVHmkrjb6QbshIGXIDFlm159YcV0mMaYVOmBFmUcKIycQ0nw4HZboUVA54ZipNVcrvhIzWOfLKiuKG5avZod13eQF4zdKlXkNAELKGuqmVMtGqWZVsJles4zxrMhYXpScrxY3tRQqXwEoAFnKhhQZdEKbRdrjnW9nOoQB1st8lRUzI2owIb0PYszCF5puYuWW25lfpxWohzbgGaFDDN-9RB0NrG8Tw3xz5ZmZ6ha37XDGzFXyZoM3l--c3hZDwhkI26U8_hMAAP__MBSuMw">