summaryrefslogtreecommitdiffstats
path: root/llvm/test
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/test')
-rw-r--r--llvm/test/CodeGen/BPF/CORE/intrinsic-array.ll5
-rw-r--r--llvm/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-byte-size-1.ll148
-rw-r--r--llvm/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-byte-size-2.ll138
-rw-r--r--llvm/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-byte-size-3.ll130
-rw-r--r--llvm/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-existence-1.ll162
-rw-r--r--llvm/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-existence-2.ll121
-rw-r--r--llvm/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-existence-3.ll129
-rw-r--r--llvm/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-lshift-1.ll153
-rw-r--r--llvm/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-lshift-2.ll122
-rw-r--r--llvm/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-rshift-1.ll148
-rw-r--r--llvm/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-rshift-2.ll121
-rw-r--r--llvm/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-rshift-3.ll131
-rw-r--r--llvm/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-signedness-1.ll162
-rw-r--r--llvm/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-signedness-2.ll151
-rw-r--r--llvm/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-signedness-3.ll149
-rw-r--r--llvm/test/CodeGen/BPF/CORE/intrinsic-struct.ll5
-rw-r--r--llvm/test/CodeGen/BPF/CORE/intrinsic-union.ll5
-rw-r--r--llvm/test/CodeGen/BPF/CORE/offset-reloc-access-str.ll6
-rw-r--r--llvm/test/CodeGen/BPF/CORE/offset-reloc-basic.ll9
-rw-r--r--llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-array-1.ll6
-rw-r--r--llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-array-2.ll6
-rw-r--r--llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-struct-1.ll6
-rw-r--r--llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-struct-2.ll6
-rw-r--r--llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-struct-3.ll6
-rw-r--r--llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-union-1.ll6
-rw-r--r--llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-union-2.ll6
-rw-r--r--llvm/test/CodeGen/BPF/CORE/offset-reloc-end-load.ll5
-rw-r--r--llvm/test/CodeGen/BPF/CORE/offset-reloc-end-ret.ll5
-rw-r--r--llvm/test/CodeGen/BPF/CORE/offset-reloc-fieldinfo-1.ll189
-rw-r--r--llvm/test/CodeGen/BPF/CORE/offset-reloc-fieldinfo-2.ll246
-rw-r--r--llvm/test/CodeGen/BPF/CORE/offset-reloc-global-1.ll5
-rw-r--r--llvm/test/CodeGen/BPF/CORE/offset-reloc-global-2.ll5
-rw-r--r--llvm/test/CodeGen/BPF/CORE/offset-reloc-global-3.ll5
-rw-r--r--llvm/test/CodeGen/BPF/CORE/offset-reloc-ignore.ll2
-rw-r--r--llvm/test/CodeGen/BPF/CORE/offset-reloc-middle-chain.ll7
-rw-r--r--llvm/test/CodeGen/BPF/CORE/offset-reloc-multi-array-1.ll5
-rw-r--r--llvm/test/CodeGen/BPF/CORE/offset-reloc-multi-array-2.ll5
-rw-r--r--llvm/test/CodeGen/BPF/CORE/offset-reloc-multilevel.ll9
-rw-r--r--llvm/test/CodeGen/BPF/CORE/offset-reloc-pointer-1.ll5
-rw-r--r--llvm/test/CodeGen/BPF/CORE/offset-reloc-pointer-2.ll5
-rw-r--r--llvm/test/CodeGen/BPF/CORE/offset-reloc-struct-anonymous.ll9
-rw-r--r--llvm/test/CodeGen/BPF/CORE/offset-reloc-struct-array.ll9
-rw-r--r--llvm/test/CodeGen/BPF/CORE/offset-reloc-typedef-array.ll5
-rw-r--r--llvm/test/CodeGen/BPF/CORE/offset-reloc-typedef-struct.ll5
-rw-r--r--llvm/test/CodeGen/BPF/CORE/offset-reloc-typedef-union.ll5
-rw-r--r--llvm/test/CodeGen/BPF/CORE/offset-reloc-typedef.ll5
-rw-r--r--llvm/test/CodeGen/BPF/CORE/offset-reloc-union.ll9
47 files changed, 2511 insertions, 71 deletions
diff --git a/llvm/test/CodeGen/BPF/CORE/intrinsic-array.ll b/llvm/test/CodeGen/BPF/CORE/intrinsic-array.ll
index fe2c1968fd9..cf5511e7414 100644
--- a/llvm/test/CodeGen/BPF/CORE/intrinsic-array.ll
+++ b/llvm/test/CodeGen/BPF/CORE/intrinsic-array.ll
@@ -28,12 +28,13 @@ entry:
; CHECK: exit
;
; CHECK: .section .BTF.ext,"",@progbits
-; CHECK: .long 12 # OffsetReloc
-; CHECK-NEXT: .long 20 # Offset reloc section string offset=20
+; CHECK: .long 16 # FieldReloc
+; CHECK-NEXT: .long 20 # Field reloc section string offset=20
; CHECK-NEXT: .long 1
; CHECK-NEXT: .long [[RELOC]]
; CHECK-NEXT: .long 2
; CHECK-NEXT: .long 26
+; CHECK-NEXT: .long 0
declare dso_local i32 @get_value(i8*) local_unnamed_addr #1
diff --git a/llvm/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-byte-size-1.ll b/llvm/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-byte-size-1.ll
new file mode 100644
index 00000000000..d8be7b85a9d
--- /dev/null
+++ b/llvm/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-byte-size-1.ll
@@ -0,0 +1,148 @@
+; RUN: llc -march=bpfel -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
+; RUN: llc -march=bpfeb -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
+; Source code:
+; typedef struct s1 { int a1:7; int a2:4; int a3:5; int a4:16;} __s1;
+; union u1 { int b1; __s1 b2; };
+; enum { FIELD_BYTE_SIZE = 1, };
+; int test(union u1 *arg) {
+; unsigned r1 = __builtin_preserve_field_info(arg->b2.a1, FIELD_BYTE_SIZE);
+; unsigned r2 = __builtin_preserve_field_info(arg->b2.a2, FIELD_BYTE_SIZE);
+; unsigned r3 = __builtin_preserve_field_info(arg->b2.a3, FIELD_BYTE_SIZE);
+; unsigned r4 = __builtin_preserve_field_info(arg->b2.a4, FIELD_BYTE_SIZE);
+; /* r1: 4, r2: 4, r3: 4, r4: 4 */
+; return r1 + r2 + r3 + r4;
+; }
+; Compilation flag:
+; clang -target bpf -O2 -g -S -emit-llvm test.c
+
+%union.u1 = type { i32 }
+%struct.s1 = type { i32 }
+
+; Function Attrs: nounwind readnone
+define dso_local i32 @test(%union.u1* %arg) local_unnamed_addr #0 !dbg !11 {
+entry:
+ call void @llvm.dbg.value(metadata %union.u1* %arg, metadata !28, metadata !DIExpression()), !dbg !33
+ %0 = tail call %union.u1* @llvm.preserve.union.access.index.p0s_union.u1s.p0s_union.u1s(%union.u1* %arg, i32 1), !dbg !34, !llvm.preserve.access.index !16
+ %b2 = bitcast %union.u1* %0 to %struct.s1*, !dbg !34
+ %1 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.s1s(%struct.s1* %b2, i32 0, i32 0), !dbg !35, !llvm.preserve.access.index !21
+ %2 = tail call i32 @llvm.bpf.preserve.field.info.p0i32(i32* %1, i64 1), !dbg !36
+ call void @llvm.dbg.value(metadata i32 %2, metadata !29, metadata !DIExpression()), !dbg !33
+ %3 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.s1s(%struct.s1* %b2, i32 0, i32 1), !dbg !37, !llvm.preserve.access.index !21
+ %4 = tail call i32 @llvm.bpf.preserve.field.info.p0i32(i32* %3, i64 1), !dbg !38
+ call void @llvm.dbg.value(metadata i32 %4, metadata !30, metadata !DIExpression()), !dbg !33
+ %5 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.s1s(%struct.s1* %b2, i32 0, i32 2), !dbg !39, !llvm.preserve.access.index !21
+ %6 = tail call i32 @llvm.bpf.preserve.field.info.p0i32(i32* %5, i64 1), !dbg !40
+ call void @llvm.dbg.value(metadata i32 %6, metadata !31, metadata !DIExpression()), !dbg !33
+ %7 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.s1s(%struct.s1* %b2, i32 0, i32 3), !dbg !41, !llvm.preserve.access.index !21
+ %8 = tail call i32 @llvm.bpf.preserve.field.info.p0i32(i32* %7, i64 1), !dbg !42
+ call void @llvm.dbg.value(metadata i32 %8, metadata !32, metadata !DIExpression()), !dbg !33
+ %add = add i32 %4, %2, !dbg !43
+ %add4 = add i32 %add, %6, !dbg !44
+ %add5 = add i32 %add4, %8, !dbg !45
+ ret i32 %add5, !dbg !46
+}
+
+; CHECK: r1 = 4
+; CHECK: r0 = 4
+; CHECK: r0 += r1
+; CHECK: r1 = 4
+; CHECK: r0 += r1
+; CHECK: r1 = 4
+; CHECK: r0 += r1
+; CHECK: exit
+
+; CHECK: .long 1 # BTF_KIND_UNION(id = 2)
+; CHECK: .ascii "u1" # string offset=1
+; CHECK: .ascii ".text" # string offset=43
+; CHECK: .ascii "0:1:0" # string offset=49
+; CHECK: .ascii "0:1:1" # string offset=92
+; CHECK: .ascii "0:1:2" # string offset=98
+; CHECK: .ascii "0:1:3" # string offset=104
+
+; CHECK: .long 16 # FieldReloc
+; CHECK-NEXT: .long 43 # Field reloc section string offset=43
+; CHECK-NEXT: .long 4
+; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
+; CHECK-NEXT: .long 2
+; CHECK-NEXT: .long 49
+; CHECK-NEXT: .long 1
+; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
+; CHECK-NEXT: .long 2
+; CHECK-NEXT: .long 92
+; CHECK-NEXT: .long 1
+; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
+; CHECK-NEXT: .long 2
+; CHECK-NEXT: .long 98
+; CHECK-NEXT: .long 1
+; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
+; CHECK-NEXT: .long 2
+; CHECK-NEXT: .long 104
+; CHECK-NEXT: .long 1
+
+; Function Attrs: nounwind readnone
+declare %union.u1* @llvm.preserve.union.access.index.p0s_union.u1s.p0s_union.u1s(%union.u1*, i32) #1
+
+; Function Attrs: nounwind readnone
+declare i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.s1s(%struct.s1*, i32, i32) #1
+
+; Function Attrs: nounwind readnone
+declare i32 @llvm.bpf.preserve.field.info.p0i32(i32*, i64) #1
+
+; Function Attrs: nounwind readnone speculatable willreturn
+declare void @llvm.dbg.value(metadata, metadata, metadata) #2
+
+attributes #0 = { nounwind readnone "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { nounwind readnone }
+attributes #2 = { nounwind readnone speculatable willreturn }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!7, !8, !9}
+!llvm.ident = !{!10}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (https://github.com/llvm/llvm-project.git 4a60741b74384f14b21fdc0131ede326438840ab)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None)
+!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/core")
+!2 = !{!3}
+!3 = !DICompositeType(tag: DW_TAG_enumeration_type, file: !1, line: 3, baseType: !4, size: 32, elements: !5)
+!4 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned)
+!5 = !{!6}
+!6 = !DIEnumerator(name: "FIELD_BYTE_SIZE", value: 1, isUnsigned: true)
+!7 = !{i32 2, !"Dwarf Version", i32 4}
+!8 = !{i32 2, !"Debug Info Version", i32 3}
+!9 = !{i32 1, !"wchar_size", i32 4}
+!10 = !{!"clang version 10.0.0 (https://github.com/llvm/llvm-project.git 4a60741b74384f14b21fdc0131ede326438840ab)"}
+!11 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 4, type: !12, scopeLine: 4, flags: DIFlagPrototyped, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !27)
+!12 = !DISubroutineType(types: !13)
+!13 = !{!14, !15}
+!14 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!15 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !16, size: 64)
+!16 = distinct !DICompositeType(tag: DW_TAG_union_type, name: "u1", file: !1, line: 2, size: 32, elements: !17)
+!17 = !{!18, !19}
+!18 = !DIDerivedType(tag: DW_TAG_member, name: "b1", scope: !16, file: !1, line: 2, baseType: !14, size: 32)
+!19 = !DIDerivedType(tag: DW_TAG_member, name: "b2", scope: !16, file: !1, line: 2, baseType: !20, size: 32)
+!20 = !DIDerivedType(tag: DW_TAG_typedef, name: "__s1", file: !1, line: 1, baseType: !21)
+!21 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "s1", file: !1, line: 1, size: 32, elements: !22)
+!22 = !{!23, !24, !25, !26}
+!23 = !DIDerivedType(tag: DW_TAG_member, name: "a1", scope: !21, file: !1, line: 1, baseType: !14, size: 7, flags: DIFlagBitField, extraData: i64 0)
+!24 = !DIDerivedType(tag: DW_TAG_member, name: "a2", scope: !21, file: !1, line: 1, baseType: !14, size: 4, offset: 7, flags: DIFlagBitField, extraData: i64 0)
+!25 = !DIDerivedType(tag: DW_TAG_member, name: "a3", scope: !21, file: !1, line: 1, baseType: !14, size: 5, offset: 11, flags: DIFlagBitField, extraData: i64 0)
+!26 = !DIDerivedType(tag: DW_TAG_member, name: "a4", scope: !21, file: !1, line: 1, baseType: !14, size: 16, offset: 16, flags: DIFlagBitField, extraData: i64 0)
+!27 = !{!28, !29, !30, !31, !32}
+!28 = !DILocalVariable(name: "arg", arg: 1, scope: !11, file: !1, line: 4, type: !15)
+!29 = !DILocalVariable(name: "r1", scope: !11, file: !1, line: 5, type: !4)
+!30 = !DILocalVariable(name: "r2", scope: !11, file: !1, line: 6, type: !4)
+!31 = !DILocalVariable(name: "r3", scope: !11, file: !1, line: 7, type: !4)
+!32 = !DILocalVariable(name: "r4", scope: !11, file: !1, line: 8, type: !4)
+!33 = !DILocation(line: 0, scope: !11)
+!34 = !DILocation(line: 5, column: 52, scope: !11)
+!35 = !DILocation(line: 5, column: 55, scope: !11)
+!36 = !DILocation(line: 5, column: 17, scope: !11)
+!37 = !DILocation(line: 6, column: 55, scope: !11)
+!38 = !DILocation(line: 6, column: 17, scope: !11)
+!39 = !DILocation(line: 7, column: 55, scope: !11)
+!40 = !DILocation(line: 7, column: 17, scope: !11)
+!41 = !DILocation(line: 8, column: 55, scope: !11)
+!42 = !DILocation(line: 8, column: 17, scope: !11)
+!43 = !DILocation(line: 10, column: 13, scope: !11)
+!44 = !DILocation(line: 10, column: 18, scope: !11)
+!45 = !DILocation(line: 10, column: 23, scope: !11)
+!46 = !DILocation(line: 10, column: 3, scope: !11)
diff --git a/llvm/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-byte-size-2.ll b/llvm/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-byte-size-2.ll
new file mode 100644
index 00000000000..291d79f6514
--- /dev/null
+++ b/llvm/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-byte-size-2.ll
@@ -0,0 +1,138 @@
+; RUN: llc -march=bpfel -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
+; RUN: llc -march=bpfeb -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
+; Source code:
+; typedef struct s1 { int a1; char a2; } __s1;
+; union u1 { int b1; __s1 b2; };
+; enum { FIELD_BYTE_SIZE = 1, };
+; int test(union u1 *arg) {
+; unsigned r1 = __builtin_preserve_field_info(arg->b2, FIELD_BYTE_SIZE);
+; unsigned r2 = __builtin_preserve_field_info(arg->b2.a1, FIELD_BYTE_SIZE);
+; unsigned r3 = __builtin_preserve_field_info(arg->b2.a2, FIELD_BYTE_SIZE);
+; /* r1: 8, r2: 4, r3: 1 */
+; return r1 + r2 + r3;
+; }
+; Compilation flag:
+; clang -target bpf -O2 -g -S -emit-llvm test.c
+
+%union.u1 = type { %struct.s1 }
+%struct.s1 = type { i32, i8 }
+
+; Function Attrs: nounwind readnone
+define dso_local i32 @test(%union.u1* %arg) local_unnamed_addr #0 !dbg !11 {
+entry:
+ call void @llvm.dbg.value(metadata %union.u1* %arg, metadata !27, metadata !DIExpression()), !dbg !31
+ %0 = tail call %union.u1* @llvm.preserve.union.access.index.p0s_union.u1s.p0s_union.u1s(%union.u1* %arg, i32 1), !dbg !32, !llvm.preserve.access.index !16
+ %b2 = getelementptr inbounds %union.u1, %union.u1* %0, i64 0, i32 0, !dbg !32
+ %1 = tail call i32 @llvm.bpf.preserve.field.info.p0s_struct.s1s(%struct.s1* %b2, i64 1), !dbg !33
+ call void @llvm.dbg.value(metadata i32 %1, metadata !28, metadata !DIExpression()), !dbg !31
+ %2 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.s1s(%struct.s1* %b2, i32 0, i32 0), !dbg !34, !llvm.preserve.access.index !21
+ %3 = tail call i32 @llvm.bpf.preserve.field.info.p0i32(i32* %2, i64 1), !dbg !35
+ call void @llvm.dbg.value(metadata i32 %3, metadata !29, metadata !DIExpression()), !dbg !31
+ %4 = tail call i8* @llvm.preserve.struct.access.index.p0i8.p0s_struct.s1s(%struct.s1* %b2, i32 1, i32 1), !dbg !36, !llvm.preserve.access.index !21
+ %5 = tail call i32 @llvm.bpf.preserve.field.info.p0i8(i8* %4, i64 1), !dbg !37
+ call void @llvm.dbg.value(metadata i32 %5, metadata !30, metadata !DIExpression()), !dbg !31
+ %add = add i32 %3, %1, !dbg !38
+ %add3 = add i32 %add, %5, !dbg !39
+ ret i32 %add3, !dbg !40
+}
+
+; CHECK: r1 = 8
+; CHECK: r0 = 4
+; CHECK: r0 += r1
+; CHECK: r1 = 1
+; CHECK: r0 += r1
+; CHECK: exit
+
+; CHECK: .long 1 # BTF_KIND_UNION(id = 2)
+; CHECK: .ascii "u1" # string offset=1
+; CHECK: .ascii ".text" # string offset=42
+; CHECK: .ascii "0:1" # string offset=48
+; CHECK: .ascii "0:1:0" # string offset=89
+; CHECK: .ascii "0:1:1" # string offset=95
+
+; CHECK: .long 16 # FieldReloc
+; CHECK-NEXT: .long 42 # Field reloc section string offset=42
+; CHECK-NEXT: .long 3
+; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
+; CHECK-NEXT: .long 2
+; CHECK-NEXT: .long 48
+; CHECK-NEXT: .long 1
+; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
+; CHECK-NEXT: .long 2
+; CHECK-NEXT: .long 89
+; CHECK-NEXT: .long 1
+; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
+; CHECK-NEXT: .long 2
+; CHECK-NEXT: .long 95
+; CHECK-NEXT: .long 1
+
+; Function Attrs: nounwind readnone
+declare %union.u1* @llvm.preserve.union.access.index.p0s_union.u1s.p0s_union.u1s(%union.u1*, i32) #1
+
+; Function Attrs: nounwind readnone
+declare i32 @llvm.bpf.preserve.field.info.p0s_struct.s1s(%struct.s1*, i64) #1
+
+; Function Attrs: nounwind readnone
+declare i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.s1s(%struct.s1*, i32, i32) #1
+
+; Function Attrs: nounwind readnone
+declare i32 @llvm.bpf.preserve.field.info.p0i32(i32*, i64) #1
+
+; Function Attrs: nounwind readnone
+declare i8* @llvm.preserve.struct.access.index.p0i8.p0s_struct.s1s(%struct.s1*, i32, i32) #1
+
+; Function Attrs: nounwind readnone
+declare i32 @llvm.bpf.preserve.field.info.p0i8(i8*, i64) #1
+
+; Function Attrs: nounwind readnone speculatable willreturn
+declare void @llvm.dbg.value(metadata, metadata, metadata) #2
+
+attributes #0 = { nounwind readnone "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { nounwind readnone }
+attributes #2 = { nounwind readnone speculatable willreturn }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!7, !8, !9}
+!llvm.ident = !{!10}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (https://github.com/llvm/llvm-project.git 4a60741b74384f14b21fdc0131ede326438840ab)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None)
+!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/core")
+!2 = !{!3}
+!3 = !DICompositeType(tag: DW_TAG_enumeration_type, file: !1, line: 3, baseType: !4, size: 32, elements: !5)
+!4 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned)
+!5 = !{!6}
+!6 = !DIEnumerator(name: "FIELD_BYTE_SIZE", value: 1, isUnsigned: true)
+!7 = !{i32 2, !"Dwarf Version", i32 4}
+!8 = !{i32 2, !"Debug Info Version", i32 3}
+!9 = !{i32 1, !"wchar_size", i32 4}
+!10 = !{!"clang version 10.0.0 (https://github.com/llvm/llvm-project.git 4a60741b74384f14b21fdc0131ede326438840ab)"}
+!11 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 4, type: !12, scopeLine: 4, flags: DIFlagPrototyped, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !26)
+!12 = !DISubroutineType(types: !13)
+!13 = !{!14, !15}
+!14 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!15 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !16, size: 64)
+!16 = distinct !DICompositeType(tag: DW_TAG_union_type, name: "u1", file: !1, line: 2, size: 64, elements: !17)
+!17 = !{!18, !19}
+!18 = !DIDerivedType(tag: DW_TAG_member, name: "b1", scope: !16, file: !1, line: 2, baseType: !14, size: 32)
+!19 = !DIDerivedType(tag: DW_TAG_member, name: "b2", scope: !16, file: !1, line: 2, baseType: !20, size: 64)
+!20 = !DIDerivedType(tag: DW_TAG_typedef, name: "__s1", file: !1, line: 1, baseType: !21)
+!21 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "s1", file: !1, line: 1, size: 64, elements: !22)
+!22 = !{!23, !24}
+!23 = !DIDerivedType(tag: DW_TAG_member, name: "a1", scope: !21, file: !1, line: 1, baseType: !14, size: 32)
+!24 = !DIDerivedType(tag: DW_TAG_member, name: "a2", scope: !21, file: !1, line: 1, baseType: !25, size: 8, offset: 32)
+!25 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char)
+!26 = !{!27, !28, !29, !30}
+!27 = !DILocalVariable(name: "arg", arg: 1, scope: !11, file: !1, line: 4, type: !15)
+!28 = !DILocalVariable(name: "r1", scope: !11, file: !1, line: 5, type: !4)
+!29 = !DILocalVariable(name: "r2", scope: !11, file: !1, line: 6, type: !4)
+!30 = !DILocalVariable(name: "r3", scope: !11, file: !1, line: 7, type: !4)
+!31 = !DILocation(line: 0, scope: !11)
+!32 = !DILocation(line: 5, column: 52, scope: !11)
+!33 = !DILocation(line: 5, column: 17, scope: !11)
+!34 = !DILocation(line: 6, column: 55, scope: !11)
+!35 = !DILocation(line: 6, column: 17, scope: !11)
+!36 = !DILocation(line: 7, column: 55, scope: !11)
+!37 = !DILocation(line: 7, column: 17, scope: !11)
+!38 = !DILocation(line: 9, column: 13, scope: !11)
+!39 = !DILocation(line: 9, column: 18, scope: !11)
+!40 = !DILocation(line: 9, column: 3, scope: !11)
diff --git a/llvm/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-byte-size-3.ll b/llvm/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-byte-size-3.ll
new file mode 100644
index 00000000000..fd517bf7357
--- /dev/null
+++ b/llvm/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-byte-size-3.ll
@@ -0,0 +1,130 @@
+; RUN: llc -march=bpfel -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
+; RUN: llc -march=bpfeb -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
+; Source code:
+; typedef struct s1 { int a1[10][10]; } __s1;
+; union u1 { int b1; __s1 b2; };
+; enum { FIELD_BYTE_SIZE = 1, };
+; int test(union u1 *arg) {
+; unsigned r1 = __builtin_preserve_field_info(arg->b2.a1[5], FIELD_BYTE_SIZE);
+; unsigned r2 = __builtin_preserve_field_info(arg->b2.a1[5][5], FIELD_BYTE_SIZE);
+; /* r1: 40, r2: 4 */
+; return r1 + r2;
+; }
+; Compilation flag:
+; clang -target bpf -O2 -g -S -emit-llvm test.c
+
+%union.u1 = type { %struct.s1 }
+%struct.s1 = type { [10 x [10 x i32]] }
+
+; Function Attrs: nounwind readnone
+define dso_local i32 @test(%union.u1* %arg) local_unnamed_addr #0 !dbg !18 {
+entry:
+ call void @llvm.dbg.value(metadata %union.u1* %arg, metadata !31, metadata !DIExpression()), !dbg !34
+ %0 = tail call %union.u1* @llvm.preserve.union.access.index.p0s_union.u1s.p0s_union.u1s(%union.u1* %arg, i32 1), !dbg !35, !llvm.preserve.access.index !22
+ %b2 = getelementptr inbounds %union.u1, %union.u1* %0, i64 0, i32 0, !dbg !35
+ %1 = tail call [10 x [10 x i32]]* @llvm.preserve.struct.access.index.p0a10a10i32.p0s_struct.s1s(%struct.s1* %b2, i32 0, i32 0), !dbg !36, !llvm.preserve.access.index !27
+ %2 = tail call [10 x i32]* @llvm.preserve.array.access.index.p0a10i32.p0a10a10i32([10 x [10 x i32]]* %1, i32 1, i32 5), !dbg !37, !llvm.preserve.access.index !8
+ %3 = tail call i32 @llvm.bpf.preserve.field.info.p0a10i32([10 x i32]* %2, i64 1), !dbg !38
+ call void @llvm.dbg.value(metadata i32 %3, metadata !32, metadata !DIExpression()), !dbg !34
+ %4 = tail call i32* @llvm.preserve.array.access.index.p0i32.p0a10i32([10 x i32]* %2, i32 1, i32 5), !dbg !39, !llvm.preserve.access.index !12
+ %5 = tail call i32 @llvm.bpf.preserve.field.info.p0i32(i32* %4, i64 1), !dbg !40
+ call void @llvm.dbg.value(metadata i32 %5, metadata !33, metadata !DIExpression()), !dbg !34
+ %add = add i32 %5, %3, !dbg !41
+ ret i32 %add, !dbg !42
+}
+
+; CHECK: r1 = 40
+; CHECK: r0 = 4
+; CHECK: r0 += r1
+; CHECK: exit
+
+; CHECK: .long 1 # BTF_KIND_UNION(id = 2)
+; CHECK: .ascii "u1" # string offset=1
+; CHECK: .ascii ".text" # string offset=54
+; CHECK: .ascii "0:1:0:5" # string offset=60
+; CHECK: .ascii "0:1:0:5:5" # string offset=105
+
+; CHECK: .long 16 # FieldReloc
+; CHECK-NEXT: .long 54 # Field reloc section string offset=54
+; CHECK-NEXT: .long 2
+; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
+; CHECK-NEXT: .long 2
+; CHECK-NEXT: .long 60
+; CHECK-NEXT: .long 1
+; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
+; CHECK-NEXT: .long 2
+; CHECK-NEXT: .long 105
+; CHECK-NEXT: .long 1
+
+; Function Attrs: nounwind readnone
+declare %union.u1* @llvm.preserve.union.access.index.p0s_union.u1s.p0s_union.u1s(%union.u1*, i32) #1
+
+; Function Attrs: nounwind readnone
+declare [10 x [10 x i32]]* @llvm.preserve.struct.access.index.p0a10a10i32.p0s_struct.s1s(%struct.s1*, i32, i32) #1
+
+; Function Attrs: nounwind readnone
+declare [10 x i32]* @llvm.preserve.array.access.index.p0a10i32.p0a10a10i32([10 x [10 x i32]]*, i32, i32) #1
+
+; Function Attrs: nounwind readnone
+declare i32 @llvm.bpf.preserve.field.info.p0a10i32([10 x i32]*, i64) #1
+
+; Function Attrs: nounwind readnone
+declare i32* @llvm.preserve.array.access.index.p0i32.p0a10i32([10 x i32]*, i32, i32) #1
+
+; Function Attrs: nounwind readnone
+declare i32 @llvm.bpf.preserve.field.info.p0i32(i32*, i64) #1
+
+; Function Attrs: nounwind readnone speculatable willreturn
+declare void @llvm.dbg.value(metadata, metadata, metadata) #2
+
+attributes #0 = { nounwind readnone "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { nounwind readnone }
+attributes #2 = { nounwind readnone speculatable willreturn }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!14, !15, !16}
+!llvm.ident = !{!17}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (https://github.com/llvm/llvm-project.git c1e02f16f1105ffaf1c35ee8bc38b7d6db5c6ea9)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !7, nameTableKind: None)
+!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/core")
+!2 = !{!3}
+!3 = !DICompositeType(tag: DW_TAG_enumeration_type, file: !1, line: 3, baseType: !4, size: 32, elements: !5)
+!4 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned)
+!5 = !{!6}
+!6 = !DIEnumerator(name: "FIELD_BYTE_SIZE", value: 1, isUnsigned: true)
+!7 = !{!8, !12}
+!8 = !DICompositeType(tag: DW_TAG_array_type, baseType: !9, size: 3200, elements: !10)
+!9 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!10 = !{!11, !11}
+!11 = !DISubrange(count: 10)
+!12 = !DICompositeType(tag: DW_TAG_array_type, baseType: !9, size: 320, elements: !13)
+!13 = !{!11}
+!14 = !{i32 2, !"Dwarf Version", i32 4}
+!15 = !{i32 2, !"Debug Info Version", i32 3}
+!16 = !{i32 1, !"wchar_size", i32 4}
+!17 = !{!"clang version 10.0.0 (https://github.com/llvm/llvm-project.git c1e02f16f1105ffaf1c35ee8bc38b7d6db5c6ea9)"}
+!18 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 4, type: !19, scopeLine: 4, flags: DIFlagPrototyped, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !30)
+!19 = !DISubroutineType(types: !20)
+!20 = !{!9, !21}
+!21 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !22, size: 64)
+!22 = distinct !DICompositeType(tag: DW_TAG_union_type, name: "u1", file: !1, line: 2, size: 3200, elements: !23)
+!23 = !{!24, !25}
+!24 = !DIDerivedType(tag: DW_TAG_member, name: "b1", scope: !22, file: !1, line: 2, baseType: !9, size: 32)
+!25 = !DIDerivedType(tag: DW_TAG_member, name: "b2", scope: !22, file: !1, line: 2, baseType: !26, size: 3200)
+!26 = !DIDerivedType(tag: DW_TAG_typedef, name: "__s1", file: !1, line: 1, baseType: !27)
+!27 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "s1", file: !1, line: 1, size: 3200, elements: !28)
+!28 = !{!29}
+!29 = !DIDerivedType(tag: DW_TAG_member, name: "a1", scope: !27, file: !1, line: 1, baseType: !8, size: 3200)
+!30 = !{!31, !32, !33}
+!31 = !DILocalVariable(name: "arg", arg: 1, scope: !18, file: !1, line: 4, type: !21)
+!32 = !DILocalVariable(name: "r1", scope: !18, file: !1, line: 5, type: !4)
+!33 = !DILocalVariable(name: "r2", scope: !18, file: !1, line: 6, type: !4)
+!34 = !DILocation(line: 0, scope: !18)
+!35 = !DILocation(line: 5, column: 52, scope: !18)
+!36 = !DILocation(line: 5, column: 55, scope: !18)
+!37 = !DILocation(line: 5, column: 47, scope: !18)
+!38 = !DILocation(line: 5, column: 17, scope: !18)
+!39 = !DILocation(line: 6, column: 47, scope: !18)
+!40 = !DILocation(line: 6, column: 17, scope: !18)
+!41 = !DILocation(line: 8, column: 13, scope: !18)
+!42 = !DILocation(line: 8, column: 3, scope: !18)
diff --git a/llvm/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-existence-1.ll b/llvm/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-existence-1.ll
new file mode 100644
index 00000000000..f140dcbc127
--- /dev/null
+++ b/llvm/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-existence-1.ll
@@ -0,0 +1,162 @@
+; RUN: llc -march=bpfel -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
+; RUN: llc -march=bpfeb -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
+; Source code:
+; typedef unsigned __uint;
+; struct s1 { int a1; __uint a2:9; __uint a3:4; };
+; union u1 { int b1; __uint b2:9; __uint b3:4; };
+; enum { FIELD_EXISTENCE = 2, };
+; int test(struct s1 *arg1, union u1 *arg2) {
+; unsigned r1 = __builtin_preserve_field_info(arg1->a1, FIELD_EXISTENCE);
+; unsigned r2 = __builtin_preserve_field_info(arg1->a3, FIELD_EXISTENCE);
+; unsigned r3 = __builtin_preserve_field_info(arg2->b1, FIELD_EXISTENCE);
+; unsigned r4 = __builtin_preserve_field_info(arg2->b3, FIELD_EXISTENCE);
+; return r1 + r2 + r3 + r4;
+; }
+; Compilation flag:
+; clang -target bpf -O2 -g -S -emit-llvm test.c
+
+%struct.s1 = type { i32, i16 }
+%union.u1 = type { i32 }
+
+; Function Attrs: nounwind readnone
+define dso_local i32 @test(%struct.s1* %arg1, %union.u1* %arg2) local_unnamed_addr #0 !dbg !11 {
+entry:
+ call void @llvm.dbg.value(metadata %struct.s1* %arg1, metadata !29, metadata !DIExpression()), !dbg !35
+ call void @llvm.dbg.value(metadata %union.u1* %arg2, metadata !30, metadata !DIExpression()), !dbg !35
+ %0 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.s1s(%struct.s1* %arg1, i32 0, i32 0), !dbg !36, !llvm.preserve.access.index !16
+ %1 = tail call i32 @llvm.bpf.preserve.field.info.p0i32(i32* %0, i64 2), !dbg !37
+ call void @llvm.dbg.value(metadata i32 %1, metadata !31, metadata !DIExpression()), !dbg !35
+ %2 = tail call i16* @llvm.preserve.struct.access.index.p0i16.p0s_struct.s1s(%struct.s1* %arg1, i32 1, i32 2), !dbg !38, !llvm.preserve.access.index !16
+ %3 = tail call i32 @llvm.bpf.preserve.field.info.p0i16(i16* %2, i64 2), !dbg !39
+ call void @llvm.dbg.value(metadata i32 %3, metadata !32, metadata !DIExpression()), !dbg !35
+ %4 = tail call %union.u1* @llvm.preserve.union.access.index.p0s_union.u1s.p0s_union.u1s(%union.u1* %arg2, i32 0), !dbg !40, !llvm.preserve.access.index !23
+ %b1 = getelementptr inbounds %union.u1, %union.u1* %4, i64 0, i32 0, !dbg !40
+ %5 = tail call i32 @llvm.bpf.preserve.field.info.p0i32(i32* %b1, i64 2), !dbg !41
+ call void @llvm.dbg.value(metadata i32 %5, metadata !33, metadata !DIExpression()), !dbg !35
+ %6 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_union.u1s(%union.u1* %arg2, i32 0, i32 2), !dbg !42, !llvm.preserve.access.index !23
+ %7 = bitcast i32* %6 to i8*, !dbg !42
+ %8 = tail call i32 @llvm.bpf.preserve.field.info.p0i8(i8* %7, i64 2), !dbg !43
+ call void @llvm.dbg.value(metadata i32 %8, metadata !34, metadata !DIExpression()), !dbg !35
+ %add = add i32 %3, %1, !dbg !44
+ %add1 = add i32 %add, %5, !dbg !45
+ %add2 = add i32 %add1, %8, !dbg !46
+ ret i32 %add2, !dbg !47
+}
+
+; CHECK: r1 = 1
+; CHECK: r0 = 1
+; CHECK: r0 += r1
+; CHECK: r1 = 1
+; CHECK: r0 += r1
+; CHECK: r1 = 1
+; CHECK: r0 += r1
+; CHECK: exit
+
+; CHECK: .long 1 # BTF_KIND_STRUCT(id = 2)
+; CHECK: .long 37 # BTF_KIND_UNION(id = 7)
+; CHECK: .ascii "s1" # string offset=1
+; CHECK: .ascii "u1" # string offset=37
+; CHECK: .ascii ".text" # string offset=64
+; CHECK: .ascii "0:0" # string offset=70
+; CHECK: .ascii "0:2" # string offset=111
+
+; CHECK: .long 16 # FieldReloc
+; CHECK-NEXT: .long 64 # Field reloc section string offset=64
+; CHECK-NEXT: .long 4
+; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
+; CHECK-NEXT: .long 2
+; CHECK-NEXT: .long 70
+; CHECK-NEXT: .long 2
+; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
+; CHECK-NEXT: .long 2
+; CHECK-NEXT: .long 111
+; CHECK-NEXT: .long 2
+; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
+; CHECK-NEXT: .long 7
+; CHECK-NEXT: .long 70
+; CHECK-NEXT: .long 2
+; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
+; CHECK-NEXT: .long 7
+; CHECK-NEXT: .long 111
+; CHECK-NEXT: .long 2
+
+; Function Attrs: nounwind readnone
+declare i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.s1s(%struct.s1*, i32, i32) #1
+
+; Function Attrs: nounwind readnone
+declare i32 @llvm.bpf.preserve.field.info.p0i32(i32*, i64) #1
+
+; Function Attrs: nounwind readnone
+declare i16* @llvm.preserve.struct.access.index.p0i16.p0s_struct.s1s(%struct.s1*, i32, i32) #1
+
+; Function Attrs: nounwind readnone
+declare i32 @llvm.bpf.preserve.field.info.p0i16(i16*, i64) #1
+
+; Function Attrs: nounwind readnone
+declare %union.u1* @llvm.preserve.union.access.index.p0s_union.u1s.p0s_union.u1s(%union.u1*, i32) #1
+
+; Function Attrs: nounwind readnone
+declare i32* @llvm.preserve.struct.access.index.p0i32.p0s_union.u1s(%union.u1*, i32, i32) #1
+
+; Function Attrs: nounwind readnone
+declare i32 @llvm.bpf.preserve.field.info.p0i8(i8*, i64) #1
+
+; Function Attrs: nounwind readnone speculatable willreturn
+declare void @llvm.dbg.value(metadata, metadata, metadata) #2
+
+attributes #0 = { nounwind readnone "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { nounwind readnone }
+attributes #2 = { nounwind readnone speculatable willreturn }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!7, !8, !9}
+!llvm.ident = !{!10}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (https://github.com/llvm/llvm-project.git 4a60741b74384f14b21fdc0131ede326438840ab)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None)
+!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/core")
+!2 = !{!3}
+!3 = !DICompositeType(tag: DW_TAG_enumeration_type, file: !1, line: 4, baseType: !4, size: 32, elements: !5)
+!4 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned)
+!5 = !{!6}
+!6 = !DIEnumerator(name: "FIELD_EXISTENCE", value: 2, isUnsigned: true)
+!7 = !{i32 2, !"Dwarf Version", i32 4}
+!8 = !{i32 2, !"Debug Info Version", i32 3}
+!9 = !{i32 1, !"wchar_size", i32 4}
+!10 = !{!"clang version 10.0.0 (https://github.com/llvm/llvm-project.git 4a60741b74384f14b21fdc0131ede326438840ab)"}
+!11 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 5, type: !12, scopeLine: 5, flags: DIFlagPrototyped, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !28)
+!12 = !DISubroutineType(types: !13)
+!13 = !{!14, !15, !22}
+!14 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!15 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !16, size: 64)
+!16 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "s1", file: !1, line: 2, size: 64, elements: !17)
+!17 = !{!18, !19, !21}
+!18 = !DIDerivedType(tag: DW_TAG_member, name: "a1", scope: !16, file: !1, line: 2, baseType: !14, size: 32)
+!19 = !DIDerivedType(tag: DW_TAG_member, name: "a2", scope: !16, file: !1, line: 2, baseType: !20, size: 9, offset: 32, flags: DIFlagBitField, extraData: i64 32)
+!20 = !DIDerivedType(tag: DW_TAG_typedef, name: "__uint", file: !1, line: 1, baseType: !4)
+!21 = !DIDerivedType(tag: DW_TAG_member, name: "a3", scope: !16, file: !1, line: 2, baseType: !20, size: 4, offset: 41, flags: DIFlagBitField, extraData: i64 32)
+!22 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !23, size: 64)
+!23 = distinct !DICompositeType(tag: DW_TAG_union_type, name: "u1", file: !1, line: 3, size: 32, elements: !24)
+!24 = !{!25, !26, !27}
+!25 = !DIDerivedType(tag: DW_TAG_member, name: "b1", scope: !23, file: !1, line: 3, baseType: !14, size: 32)
+!26 = !DIDerivedType(tag: DW_TAG_member, name: "b2", scope: !23, file: !1, line: 3, baseType: !20, size: 9, flags: DIFlagBitField, extraData: i64 0)
+!27 = !DIDerivedType(tag: DW_TAG_member, name: "b3", scope: !23, file: !1, line: 3, baseType: !20, size: 4, flags: DIFlagBitField, extraData: i64 0)
+!28 = !{!29, !30, !31, !32, !33, !34}
+!29 = !DILocalVariable(name: "arg1", arg: 1, scope: !11, file: !1, line: 5, type: !15)
+!30 = !DILocalVariable(name: "arg2", arg: 2, scope: !11, file: !1, line: 5, type: !22)
+!31 = !DILocalVariable(name: "r1", scope: !11, file: !1, line: 6, type: !4)
+!32 = !DILocalVariable(name: "r2", scope: !11, file: !1, line: 7, type: !4)
+!33 = !DILocalVariable(name: "r3", scope: !11, file: !1, line: 8, type: !4)
+!34 = !DILocalVariable(name: "r4", scope: !11, file: !1, line: 9, type: !4)
+!35 = !DILocation(line: 0, scope: !11)
+!36 = !DILocation(line: 6, column: 53, scope: !11)
+!37 = !DILocation(line: 6, column: 17, scope: !11)
+!38 = !DILocation(line: 7, column: 53, scope: !11)
+!39 = !DILocation(line: 7, column: 17, scope: !11)
+!40 = !DILocation(line: 8, column: 53, scope: !11)
+!41 = !DILocation(line: 8, column: 17, scope: !11)
+!42 = !DILocation(line: 9, column: 53, scope: !11)
+!43 = !DILocation(line: 9, column: 17, scope: !11)
+!44 = !DILocation(line: 10, column: 13, scope: !11)
+!45 = !DILocation(line: 10, column: 18, scope: !11)
+!46 = !DILocation(line: 10, column: 23, scope: !11)
+!47 = !DILocation(line: 10, column: 3, scope: !11)
diff --git a/llvm/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-existence-2.ll b/llvm/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-existence-2.ll
new file mode 100644
index 00000000000..186af8648b2
--- /dev/null
+++ b/llvm/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-existence-2.ll
@@ -0,0 +1,121 @@
+; RUN: llc -march=bpfel -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
+; RUN: llc -march=bpfeb -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
+; Source code:
+; typedef unsigned __uint;
+; struct s1 { int a1; __uint a2:9; __uint a3:4; };
+; union u1 { int b1; struct s1 b2; };
+; enum { FIELD_EXISTENCE = 2, };
+; int test(union u1 *arg) {
+; unsigned r1 = __builtin_preserve_field_info(arg->b2.a1, FIELD_EXISTENCE);
+; unsigned r2 = __builtin_preserve_field_info(arg->b2.a3, FIELD_EXISTENCE);
+; return r1 + r2;
+; }
+; Compilation flag:
+; clang -target bpf -O2 -g -S -emit-llvm test.c
+
+%union.u1 = type { %struct.s1 }
+%struct.s1 = type { i32, i16 }
+
+; Function Attrs: nounwind readnone
+define dso_local i32 @test(%union.u1* %arg) local_unnamed_addr #0 !dbg !11 {
+entry:
+ call void @llvm.dbg.value(metadata %union.u1* %arg, metadata !27, metadata !DIExpression()), !dbg !30
+ %0 = tail call %union.u1* @llvm.preserve.union.access.index.p0s_union.u1s.p0s_union.u1s(%union.u1* %arg, i32 1), !dbg !31, !llvm.preserve.access.index !16
+ %b2 = getelementptr inbounds %union.u1, %union.u1* %0, i64 0, i32 0, !dbg !31
+ %1 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.s1s(%struct.s1* %b2, i32 0, i32 0), !dbg !32, !llvm.preserve.access.index !20
+ %2 = tail call i32 @llvm.bpf.preserve.field.info.p0i32(i32* %1, i64 2), !dbg !33
+ call void @llvm.dbg.value(metadata i32 %2, metadata !28, metadata !DIExpression()), !dbg !30
+ %3 = tail call i16* @llvm.preserve.struct.access.index.p0i16.p0s_struct.s1s(%struct.s1* %b2, i32 1, i32 2), !dbg !34, !llvm.preserve.access.index !20
+ %4 = tail call i32 @llvm.bpf.preserve.field.info.p0i16(i16* %3, i64 2), !dbg !35
+ call void @llvm.dbg.value(metadata i32 %4, metadata !29, metadata !DIExpression()), !dbg !30
+ %add = add i32 %4, %2, !dbg !36
+ ret i32 %add, !dbg !37
+}
+
+; CHECK: r1 = 1
+; CHECK: r0 = 1
+; CHECK: r0 += r1
+; CHECK: exit
+
+; CHECK: .long 1 # BTF_KIND_UNION(id = 2)
+; CHECK: .ascii "u1" # string offset=1
+; CHECK: .ascii ".text" # string offset=55
+; CHECK: .ascii "0:1:0" # string offset=61
+; CHECK: .ascii "0:1:2" # string offset=104
+
+; CHECK: .long 16 # FieldReloc
+; CHECK-NEXT: .long 55 # Field reloc section string offset=55
+; CHECK-NEXT: .long 2
+; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
+; CHECK-NEXT: .long 2
+; CHECK-NEXT: .long 61
+; CHECK-NEXT: .long 2
+; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
+; CHECK-NEXT: .long 2
+; CHECK-NEXT: .long 104
+; CHECK-NEXT: .long 2
+
+; Function Attrs: nounwind readnone
+declare %union.u1* @llvm.preserve.union.access.index.p0s_union.u1s.p0s_union.u1s(%union.u1*, i32) #1
+
+; Function Attrs: nounwind readnone
+declare i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.s1s(%struct.s1*, i32, i32) #1
+
+; Function Attrs: nounwind readnone
+declare i32 @llvm.bpf.preserve.field.info.p0i32(i32*, i64) #1
+
+; Function Attrs: nounwind readnone
+declare i16* @llvm.preserve.struct.access.index.p0i16.p0s_struct.s1s(%struct.s1*, i32, i32) #1
+
+; Function Attrs: nounwind readnone
+declare i32 @llvm.bpf.preserve.field.info.p0i16(i16*, i64) #1
+
+; Function Attrs: nounwind readnone speculatable willreturn
+declare void @llvm.dbg.value(metadata, metadata, metadata) #2
+
+attributes #0 = { nounwind readnone "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { nounwind readnone }
+attributes #2 = { nounwind readnone speculatable willreturn }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!7, !8, !9}
+!llvm.ident = !{!10}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (https://github.com/llvm/llvm-project.git 4a60741b74384f14b21fdc0131ede326438840ab)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None)
+!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/core")
+!2 = !{!3}
+!3 = !DICompositeType(tag: DW_TAG_enumeration_type, file: !1, line: 4, baseType: !4, size: 32, elements: !5)
+!4 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned)
+!5 = !{!6}
+!6 = !DIEnumerator(name: "FIELD_EXISTENCE", value: 2, isUnsigned: true)
+!7 = !{i32 2, !"Dwarf Version", i32 4}
+!8 = !{i32 2, !"Debug Info Version", i32 3}
+!9 = !{i32 1, !"wchar_size", i32 4}
+!10 = !{!"clang version 10.0.0 (https://github.com/llvm/llvm-project.git 4a60741b74384f14b21fdc0131ede326438840ab)"}
+!11 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 5, type: !12, scopeLine: 5, flags: DIFlagPrototyped, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !26)
+!12 = !DISubroutineType(types: !13)
+!13 = !{!14, !15}
+!14 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!15 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !16, size: 64)
+!16 = distinct !DICompositeType(tag: DW_TAG_union_type, name: "u1", file: !1, line: 3, size: 64, elements: !17)
+!17 = !{!18, !19}
+!18 = !DIDerivedType(tag: DW_TAG_member, name: "b1", scope: !16, file: !1, line: 3, baseType: !14, size: 32)
+!19 = !DIDerivedType(tag: DW_TAG_member, name: "b2", scope: !16, file: !1, line: 3, baseType: !20, size: 64)
+!20 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "s1", file: !1, line: 2, size: 64, elements: !21)
+!21 = !{!22, !23, !25}
+!22 = !DIDerivedType(tag: DW_TAG_member, name: "a1", scope: !20, file: !1, line: 2, baseType: !14, size: 32)
+!23 = !DIDerivedType(tag: DW_TAG_member, name: "a2", scope: !20, file: !1, line: 2, baseType: !24, size: 9, offset: 32, flags: DIFlagBitField, extraData: i64 32)
+!24 = !DIDerivedType(tag: DW_TAG_typedef, name: "__uint", file: !1, line: 1, baseType: !4)
+!25 = !DIDerivedType(tag: DW_TAG_member, name: "a3", scope: !20, file: !1, line: 2, baseType: !24, size: 4, offset: 41, flags: DIFlagBitField, extraData: i64 32)
+!26 = !{!27, !28, !29}
+!27 = !DILocalVariable(name: "arg", arg: 1, scope: !11, file: !1, line: 5, type: !15)
+!28 = !DILocalVariable(name: "r1", scope: !11, file: !1, line: 6, type: !4)
+!29 = !DILocalVariable(name: "r2", scope: !11, file: !1, line: 7, type: !4)
+!30 = !DILocation(line: 0, scope: !11)
+!31 = !DILocation(line: 6, column: 52, scope: !11)
+!32 = !DILocation(line: 6, column: 55, scope: !11)
+!33 = !DILocation(line: 6, column: 17, scope: !11)
+!34 = !DILocation(line: 7, column: 55, scope: !11)
+!35 = !DILocation(line: 7, column: 17, scope: !11)
+!36 = !DILocation(line: 8, column: 13, scope: !11)
+!37 = !DILocation(line: 8, column: 3, scope: !11)
diff --git a/llvm/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-existence-3.ll b/llvm/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-existence-3.ll
new file mode 100644
index 00000000000..4c0a93a5638
--- /dev/null
+++ b/llvm/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-existence-3.ll
@@ -0,0 +1,129 @@
+; RUN: llc -march=bpfel -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
+; RUN: llc -march=bpfeb -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
+; Source code:
+; typedef struct s1 { int a1[10][10]; } __s1;
+; union u1 { int b1; __s1 b2; };
+; enum { FIELD_EXISTENCE = 2, };
+; int test(union u1 *arg) {
+; unsigned r1 = __builtin_preserve_field_info(arg->b2.a1[5], FIELD_EXISTENCE);
+; unsigned r2 = __builtin_preserve_field_info(arg->b2.a1[5][5], FIELD_EXISTENCE);
+; return r1 + r2;
+; }
+; Compilation flag:
+; clang -target bpf -O2 -g -S -emit-llvm test.c
+
+%union.u1 = type { %struct.s1 }
+%struct.s1 = type { [10 x [10 x i32]] }
+
+; Function Attrs: nounwind readnone
+define dso_local i32 @test(%union.u1* %arg) local_unnamed_addr #0 !dbg !18 {
+entry:
+ call void @llvm.dbg.value(metadata %union.u1* %arg, metadata !31, metadata !DIExpression()), !dbg !34
+ %0 = tail call %union.u1* @llvm.preserve.union.access.index.p0s_union.u1s.p0s_union.u1s(%union.u1* %arg, i32 1), !dbg !35, !llvm.preserve.access.index !22
+ %b2 = getelementptr inbounds %union.u1, %union.u1* %0, i64 0, i32 0, !dbg !35
+ %1 = tail call [10 x [10 x i32]]* @llvm.preserve.struct.access.index.p0a10a10i32.p0s_struct.s1s(%struct.s1* %b2, i32 0, i32 0), !dbg !36, !llvm.preserve.access.index !27
+ %2 = tail call [10 x i32]* @llvm.preserve.array.access.index.p0a10i32.p0a10a10i32([10 x [10 x i32]]* %1, i32 1, i32 5), !dbg !37, !llvm.preserve.access.index !8
+ %3 = tail call i32 @llvm.bpf.preserve.field.info.p0a10i32([10 x i32]* %2, i64 2), !dbg !38
+ call void @llvm.dbg.value(metadata i32 %3, metadata !32, metadata !DIExpression()), !dbg !34
+ %4 = tail call i32* @llvm.preserve.array.access.index.p0i32.p0a10i32([10 x i32]* %2, i32 1, i32 5), !dbg !39, !llvm.preserve.access.index !12
+ %5 = tail call i32 @llvm.bpf.preserve.field.info.p0i32(i32* %4, i64 2), !dbg !40
+ call void @llvm.dbg.value(metadata i32 %5, metadata !33, metadata !DIExpression()), !dbg !34
+ %add = add i32 %5, %3, !dbg !41
+ ret i32 %add, !dbg !42
+}
+
+; CHECK: r1 = 1
+; CHECK: r0 = 1
+; CHECK: r0 += r1
+; CHECK: exit
+
+; CHECK: .long 1 # BTF_KIND_UNION(id = 2)
+; CHECK: .ascii "u1" # string offset=1
+; CHECK: .ascii ".text" # string offset=54
+; CHECK: .ascii "0:1:0:5" # string offset=60
+; CHECK: .ascii "0:1:0:5:5" # string offset=105
+
+; CHECK: .long 16 # FieldReloc
+; CHECK-NEXT: .long 54 # Field reloc section string offset=54
+; CHECK-NEXT: .long 2
+; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
+; CHECK-NEXT: .long 2
+; CHECK-NEXT: .long 60
+; CHECK-NEXT: .long 2
+; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
+; CHECK-NEXT: .long 2
+; CHECK-NEXT: .long 105
+; CHECK-NEXT: .long 2
+
+; Function Attrs: nounwind readnone
+declare %union.u1* @llvm.preserve.union.access.index.p0s_union.u1s.p0s_union.u1s(%union.u1*, i32) #1
+
+; Function Attrs: nounwind readnone
+declare [10 x [10 x i32]]* @llvm.preserve.struct.access.index.p0a10a10i32.p0s_struct.s1s(%struct.s1*, i32, i32) #1
+
+; Function Attrs: nounwind readnone
+declare [10 x i32]* @llvm.preserve.array.access.index.p0a10i32.p0a10a10i32([10 x [10 x i32]]*, i32, i32) #1
+
+; Function Attrs: nounwind readnone
+declare i32 @llvm.bpf.preserve.field.info.p0a10i32([10 x i32]*, i64) #1
+
+; Function Attrs: nounwind readnone
+declare i32* @llvm.preserve.array.access.index.p0i32.p0a10i32([10 x i32]*, i32, i32) #1
+
+; Function Attrs: nounwind readnone
+declare i32 @llvm.bpf.preserve.field.info.p0i32(i32*, i64) #1
+
+; Function Attrs: nounwind readnone speculatable willreturn
+declare void @llvm.dbg.value(metadata, metadata, metadata) #2
+
+attributes #0 = { nounwind readnone "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { nounwind readnone }
+attributes #2 = { nounwind readnone speculatable willreturn }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!14, !15, !16}
+!llvm.ident = !{!17}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (https://github.com/llvm/llvm-project.git c1e02f16f1105ffaf1c35ee8bc38b7d6db5c6ea9)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !7, nameTableKind: None)
+!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/core")
+!2 = !{!3}
+!3 = !DICompositeType(tag: DW_TAG_enumeration_type, file: !1, line: 3, baseType: !4, size: 32, elements: !5)
+!4 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned)
+!5 = !{!6}
+!6 = !DIEnumerator(name: "FIELD_EXISTENCE", value: 2, isUnsigned: true)
+!7 = !{!8, !12}
+!8 = !DICompositeType(tag: DW_TAG_array_type, baseType: !9, size: 3200, elements: !10)
+!9 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!10 = !{!11, !11}
+!11 = !DISubrange(count: 10)
+!12 = !DICompositeType(tag: DW_TAG_array_type, baseType: !9, size: 320, elements: !13)
+!13 = !{!11}
+!14 = !{i32 2, !"Dwarf Version", i32 4}
+!15 = !{i32 2, !"Debug Info Version", i32 3}
+!16 = !{i32 1, !"wchar_size", i32 4}
+!17 = !{!"clang version 10.0.0 (https://github.com/llvm/llvm-project.git c1e02f16f1105ffaf1c35ee8bc38b7d6db5c6ea9)"}
+!18 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 4, type: !19, scopeLine: 4, flags: DIFlagPrototyped, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !30)
+!19 = !DISubroutineType(types: !20)
+!20 = !{!9, !21}
+!21 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !22, size: 64)
+!22 = distinct !DICompositeType(tag: DW_TAG_union_type, name: "u1", file: !1, line: 2, size: 3200, elements: !23)
+!23 = !{!24, !25}
+!24 = !DIDerivedType(tag: DW_TAG_member, name: "b1", scope: !22, file: !1, line: 2, baseType: !9, size: 32)
+!25 = !DIDerivedType(tag: DW_TAG_member, name: "b2", scope: !22, file: !1, line: 2, baseType: !26, size: 3200)
+!26 = !DIDerivedType(tag: DW_TAG_typedef, name: "__s1", file: !1, line: 1, baseType: !27)
+!27 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "s1", file: !1, line: 1, size: 3200, elements: !28)
+!28 = !{!29}
+!29 = !DIDerivedType(tag: DW_TAG_member, name: "a1", scope: !27, file: !1, line: 1, baseType: !8, size: 3200)
+!30 = !{!31, !32, !33}
+!31 = !DILocalVariable(name: "arg", arg: 1, scope: !18, file: !1, line: 4, type: !21)
+!32 = !DILocalVariable(name: "r1", scope: !18, file: !1, line: 5, type: !4)
+!33 = !DILocalVariable(name: "r2", scope: !18, file: !1, line: 6, type: !4)
+!34 = !DILocation(line: 0, scope: !18)
+!35 = !DILocation(line: 5, column: 52, scope: !18)
+!36 = !DILocation(line: 5, column: 55, scope: !18)
+!37 = !DILocation(line: 5, column: 47, scope: !18)
+!38 = !DILocation(line: 5, column: 17, scope: !18)
+!39 = !DILocation(line: 6, column: 47, scope: !18)
+!40 = !DILocation(line: 6, column: 17, scope: !18)
+!41 = !DILocation(line: 7, column: 13, scope: !18)
+!42 = !DILocation(line: 7, column: 3, scope: !18)
diff --git a/llvm/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-lshift-1.ll b/llvm/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-lshift-1.ll
new file mode 100644
index 00000000000..ce4074cd558
--- /dev/null
+++ b/llvm/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-lshift-1.ll
@@ -0,0 +1,153 @@
+; RUN: llc -march=bpfel -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK,CHECK-EL %s
+; RUN: llc -march=bpfeb -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK,CHECK-EB %s
+; Source code:
+; typedef struct s1 { int a1:7; int a2:4; int a3:5; int a4:16;} __s1;
+; union u1 { int b1; __s1 b2; };
+; enum { FIELD_LSHIFT_U64 = 4, };
+; int test(union u1 *arg) {
+; unsigned r1 = __builtin_preserve_field_info(arg->b2.a1, FIELD_LSHIFT_U64);
+; unsigned r2 = __builtin_preserve_field_info(arg->b2.a2, FIELD_LSHIFT_U64);
+; unsigned r3 = __builtin_preserve_field_info(arg->b2.a3, FIELD_LSHIFT_U64);
+; unsigned r4 = __builtin_preserve_field_info(arg->b2.a4, FIELD_LSHIFT_U64);
+; /* big endian: r1: 32, r2: 39, r3: 43, r4: 48 */
+; /* little endian: r1: 57, r2: 53, r3: 48, r4: 32 */
+; return r1 + r2 + r3 + r4;
+; }
+; Compilation flag:
+; clang -target bpf -O2 -g -S -emit-llvm test.c
+
+%union.u1 = type { i32 }
+%struct.s1 = type { i32 }
+
+; Function Attrs: nounwind readnone
+define dso_local i32 @test(%union.u1* %arg) local_unnamed_addr #0 !dbg !11 {
+entry:
+ call void @llvm.dbg.value(metadata %union.u1* %arg, metadata !28, metadata !DIExpression()), !dbg !33
+ %0 = tail call %union.u1* @llvm.preserve.union.access.index.p0s_union.u1s.p0s_union.u1s(%union.u1* %arg, i32 1), !dbg !34, !llvm.preserve.access.index !16
+ %b2 = bitcast %union.u1* %0 to %struct.s1*, !dbg !34
+ %1 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.s1s(%struct.s1* %b2, i32 0, i32 0), !dbg !35, !llvm.preserve.access.index !21
+ %2 = tail call i32 @llvm.bpf.preserve.field.info.p0i32(i32* %1, i64 4), !dbg !36
+ call void @llvm.dbg.value(metadata i32 %2, metadata !29, metadata !DIExpression()), !dbg !33
+ %3 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.s1s(%struct.s1* %b2, i32 0, i32 1), !dbg !37, !llvm.preserve.access.index !21
+ %4 = tail call i32 @llvm.bpf.preserve.field.info.p0i32(i32* %3, i64 4), !dbg !38
+ call void @llvm.dbg.value(metadata i32 %4, metadata !30, metadata !DIExpression()), !dbg !33
+ %5 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.s1s(%struct.s1* %b2, i32 0, i32 2), !dbg !39, !llvm.preserve.access.index !21
+ %6 = tail call i32 @llvm.bpf.preserve.field.info.p0i32(i32* %5, i64 4), !dbg !40
+ call void @llvm.dbg.value(metadata i32 %6, metadata !31, metadata !DIExpression()), !dbg !33
+ %7 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.s1s(%struct.s1* %b2, i32 0, i32 3), !dbg !41, !llvm.preserve.access.index !21
+ %8 = tail call i32 @llvm.bpf.preserve.field.info.p0i32(i32* %7, i64 4), !dbg !42
+ call void @llvm.dbg.value(metadata i32 %8, metadata !32, metadata !DIExpression()), !dbg !33
+ %add = add i32 %4, %2, !dbg !43
+ %add4 = add i32 %add, %6, !dbg !44
+ %add5 = add i32 %add4, %8, !dbg !45
+ ret i32 %add5, !dbg !46
+}
+
+; CHECK-EL: r1 = 57
+; CHECK-EL: r0 = 53
+; CHECK-EB: r1 = 32
+; CHECK-EB: r0 = 39
+; CHECK: r0 += r1
+; CHECK-EL: r1 = 48
+; CHECK-EB: r1 = 43
+; CHECK: r0 += r1
+; CHECK-EL: r1 = 32
+; CHECK-EB: r1 = 48
+; CHECK: r0 += r1
+; CHECK: exit
+
+; CHECK: .long 1 # BTF_KIND_UNION(id = 2)
+; CHECK: .ascii "u1" # string offset=1
+; CHECK: .ascii ".text" # string offset=43
+; CHECK: .ascii "0:1:0" # string offset=49
+; CHECK: .ascii "0:1:1" # string offset=92
+; CHECK: .ascii "0:1:2" # string offset=98
+; CHECK: .ascii "0:1:3" # string offset=104
+
+; CHECK: .long 16 # FieldReloc
+; CHECK-NEXT: .long 43 # Field reloc section string offset=43
+; CHECK-NEXT: .long 4
+; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
+; CHECK-NEXT: .long 2
+; CHECK-NEXT: .long 49
+; CHECK-NEXT: .long 4
+; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
+; CHECK-NEXT: .long 2
+; CHECK-NEXT: .long 92
+; CHECK-NEXT: .long 4
+; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
+; CHECK-NEXT: .long 2
+; CHECK-NEXT: .long 98
+; CHECK-NEXT: .long 4
+; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
+; CHECK-NEXT: .long 2
+; CHECK-NEXT: .long 104
+; CHECK-NEXT: .long 4
+
+; Function Attrs: nounwind readnone
+declare %union.u1* @llvm.preserve.union.access.index.p0s_union.u1s.p0s_union.u1s(%union.u1*, i32) #1
+
+; Function Attrs: nounwind readnone
+declare i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.s1s(%struct.s1*, i32, i32) #1
+
+; Function Attrs: nounwind readnone
+declare i32 @llvm.bpf.preserve.field.info.p0i32(i32*, i64) #1
+
+; Function Attrs: nounwind readnone speculatable willreturn
+declare void @llvm.dbg.value(metadata, metadata, metadata) #2
+
+attributes #0 = { nounwind readnone "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { nounwind readnone }
+attributes #2 = { nounwind readnone speculatable willreturn }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!7, !8, !9}
+!llvm.ident = !{!10}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (https://github.com/llvm/llvm-project.git 5635073377f153f7f2ff9b34c77af3c79885ff4a)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None)
+!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/core")
+!2 = !{!3}
+!3 = !DICompositeType(tag: DW_TAG_enumeration_type, file: !1, line: 3, baseType: !4, size: 32, elements: !5)
+!4 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned)
+!5 = !{!6}
+!6 = !DIEnumerator(name: "FIELD_LSHIFT_U64", value: 4, isUnsigned: true)
+!7 = !{i32 2, !"Dwarf Version", i32 4}
+!8 = !{i32 2, !"Debug Info Version", i32 3}
+!9 = !{i32 1, !"wchar_size", i32 4}
+!10 = !{!"clang version 10.0.0 (https://github.com/llvm/llvm-project.git 5635073377f153f7f2ff9b34c77af3c79885ff4a)"}
+!11 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 4, type: !12, scopeLine: 4, flags: DIFlagPrototyped, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !27)
+!12 = !DISubroutineType(types: !13)
+!13 = !{!14, !15}
+!14 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!15 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !16, size: 64)
+!16 = distinct !DICompositeType(tag: DW_TAG_union_type, name: "u1", file: !1, line: 2, size: 32, elements: !17)
+!17 = !{!18, !19}
+!18 = !DIDerivedType(tag: DW_TAG_member, name: "b1", scope: !16, file: !1, line: 2, baseType: !14, size: 32)
+!19 = !DIDerivedType(tag: DW_TAG_member, name: "b2", scope: !16, file: !1, line: 2, baseType: !20, size: 32)
+!20 = !DIDerivedType(tag: DW_TAG_typedef, name: "__s1", file: !1, line: 1, baseType: !21)
+!21 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "s1", file: !1, line: 1, size: 32, elements: !22)
+!22 = !{!23, !24, !25, !26}
+!23 = !DIDerivedType(tag: DW_TAG_member, name: "a1", scope: !21, file: !1, line: 1, baseType: !14, size: 7, flags: DIFlagBitField, extraData: i64 0)
+!24 = !DIDerivedType(tag: DW_TAG_member, name: "a2", scope: !21, file: !1, line: 1, baseType: !14, size: 4, offset: 7, flags: DIFlagBitField, extraData: i64 0)
+!25 = !DIDerivedType(tag: DW_TAG_member, name: "a3", scope: !21, file: !1, line: 1, baseType: !14, size: 5, offset: 11, flags: DIFlagBitField, extraData: i64 0)
+!26 = !DIDerivedType(tag: DW_TAG_member, name: "a4", scope: !21, file: !1, line: 1, baseType: !14, size: 16, offset: 16, flags: DIFlagBitField, extraData: i64 0)
+!27 = !{!28, !29, !30, !31, !32}
+!28 = !DILocalVariable(name: "arg", arg: 1, scope: !11, file: !1, line: 4, type: !15)
+!29 = !DILocalVariable(name: "r1", scope: !11, file: !1, line: 5, type: !4)
+!30 = !DILocalVariable(name: "r2", scope: !11, file: !1, line: 6, type: !4)
+!31 = !DILocalVariable(name: "r3", scope: !11, file: !1, line: 7, type: !4)
+!32 = !DILocalVariable(name: "r4", scope: !11, file: !1, line: 8, type: !4)
+!33 = !DILocation(line: 0, scope: !11)
+!34 = !DILocation(line: 5, column: 52, scope: !11)
+!35 = !DILocation(line: 5, column: 55, scope: !11)
+!36 = !DILocation(line: 5, column: 17, scope: !11)
+!37 = !DILocation(line: 6, column: 55, scope: !11)
+!38 = !DILocation(line: 6, column: 17, scope: !11)
+!39 = !DILocation(line: 7, column: 55, scope: !11)
+!40 = !DILocation(line: 7, column: 17, scope: !11)
+!41 = !DILocation(line: 8, column: 55, scope: !11)
+!42 = !DILocation(line: 8, column: 17, scope: !11)
+!43 = !DILocation(line: 11, column: 13, scope: !11)
+!44 = !DILocation(line: 11, column: 18, scope: !11)
+!45 = !DILocation(line: 11, column: 23, scope: !11)
+!46 = !DILocation(line: 11, column: 3, scope: !11)
diff --git a/llvm/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-lshift-2.ll b/llvm/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-lshift-2.ll
new file mode 100644
index 00000000000..83d1b3e1b00
--- /dev/null
+++ b/llvm/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-lshift-2.ll
@@ -0,0 +1,122 @@
+; RUN: llc -march=bpfel -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
+; RUN: llc -march=bpfeb -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
+; Source code:
+; typedef struct s1 { int a1; short a2; } __s1;
+; union u1 { int b1; __s1 b2; };
+; enum { FIELD_LSHIFT_U64 = 4, };
+; int test(union u1 *arg) {
+; unsigned r1 = __builtin_preserve_field_info(arg->b2.a1, FIELD_LSHIFT_U64);
+; unsigned r2 = __builtin_preserve_field_info(arg->b2.a2, FIELD_LSHIFT_U64);
+; /* big endian: r1: 32, r2: 48 */
+; /* little endian: r1: 32, r2: 48 */
+; return r1 + r2;
+; }
+; Compilation flag:
+; clang -target bpf -O2 -g -S -emit-llvm test.c
+
+%union.u1 = type { %struct.s1 }
+%struct.s1 = type { i32, i16 }
+
+; Function Attrs: nounwind readnone
+define dso_local i32 @test(%union.u1* %arg) local_unnamed_addr #0 !dbg !11 {
+entry:
+ call void @llvm.dbg.value(metadata %union.u1* %arg, metadata !27, metadata !DIExpression()), !dbg !30
+ %0 = tail call %union.u1* @llvm.preserve.union.access.index.p0s_union.u1s.p0s_union.u1s(%union.u1* %arg, i32 1), !dbg !31, !llvm.preserve.access.index !16
+ %b2 = getelementptr %union.u1, %union.u1* %0, i64 0, i32 0, !dbg !31
+ %1 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.s1s(%struct.s1* %b2, i32 0, i32 0), !dbg !32, !llvm.preserve.access.index !21
+ %2 = tail call i32 @llvm.bpf.preserve.field.info.p0i32(i32* %1, i64 4), !dbg !33
+ call void @llvm.dbg.value(metadata i32 %2, metadata !28, metadata !DIExpression()), !dbg !30
+ %3 = tail call i16* @llvm.preserve.struct.access.index.p0i16.p0s_struct.s1s(%struct.s1* %b2, i32 1, i32 1), !dbg !34, !llvm.preserve.access.index !21
+ %4 = tail call i32 @llvm.bpf.preserve.field.info.p0i16(i16* %3, i64 4), !dbg !35
+ call void @llvm.dbg.value(metadata i32 %4, metadata !29, metadata !DIExpression()), !dbg !30
+ %add = add i32 %4, %2, !dbg !36
+ ret i32 %add, !dbg !37
+}
+
+; CHECK: r1 = 32
+; CHECK: r0 = 48
+; CHECK: r0 += r1
+; CHECK: exit
+
+; CHECK: .long 1 # BTF_KIND_UNION(id = 2)
+; CHECK: .ascii "u1" # string offset=1
+; CHECK: .ascii ".text" # string offset=43
+; CHECK: .ascii "0:1:0" # string offset=49
+; CHECK: .ascii "0:1:1" # string offset=92
+
+; CHECK: .long 16 # FieldReloc
+; CHECK-NEXT: .long 43 # Field reloc section string offset=43
+; CHECK-NEXT: .long 2
+; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
+; CHECK-NEXT: .long 2
+; CHECK-NEXT: .long 49
+; CHECK-NEXT: .long 4
+; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
+; CHECK-NEXT: .long 2
+; CHECK-NEXT: .long 92
+; CHECK-NEXT: .long 4
+
+; Function Attrs: nounwind readnone
+declare %union.u1* @llvm.preserve.union.access.index.p0s_union.u1s.p0s_union.u1s(%union.u1*, i32) #1
+
+; Function Attrs: nounwind readnone
+declare i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.s1s(%struct.s1*, i32, i32) #1
+
+; Function Attrs: nounwind readnone
+declare i32 @llvm.bpf.preserve.field.info.p0i32(i32*, i64) #1
+
+; Function Attrs: nounwind readnone
+declare i16* @llvm.preserve.struct.access.index.p0i16.p0s_struct.s1s(%struct.s1*, i32, i32) #1
+
+; Function Attrs: nounwind readnone
+declare i32 @llvm.bpf.preserve.field.info.p0i16(i16*, i64) #1
+
+; Function Attrs: nounwind readnone speculatable willreturn
+declare void @llvm.dbg.value(metadata, metadata, metadata) #2
+
+attributes #0 = { nounwind readnone "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { nounwind readnone }
+attributes #2 = { nounwind readnone speculatable willreturn }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!7, !8, !9}
+!llvm.ident = !{!10}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (https://github.com/llvm/llvm-project.git 5635073377f153f7f2ff9b34c77af3c79885ff4a)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None)
+!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/core")
+!2 = !{!3}
+!3 = !DICompositeType(tag: DW_TAG_enumeration_type, file: !1, line: 3, baseType: !4, size: 32, elements: !5)
+!4 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned)
+!5 = !{!6}
+!6 = !DIEnumerator(name: "FIELD_LSHIFT_U64", value: 4, isUnsigned: true)
+!7 = !{i32 2, !"Dwarf Version", i32 4}
+!8 = !{i32 2, !"Debug Info Version", i32 3}
+!9 = !{i32 1, !"wchar_size", i32 4}
+!10 = !{!"clang version 10.0.0 (https://github.com/llvm/llvm-project.git 5635073377f153f7f2ff9b34c77af3c79885ff4a)"}
+!11 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 4, type: !12, scopeLine: 4, flags: DIFlagPrototyped, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !26)
+!12 = !DISubroutineType(types: !13)
+!13 = !{!14, !15}
+!14 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!15 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !16, size: 64)
+!16 = distinct !DICompositeType(tag: DW_TAG_union_type, name: "u1", file: !1, line: 2, size: 64, elements: !17)
+!17 = !{!18, !19}
+!18 = !DIDerivedType(tag: DW_TAG_member, name: "b1", scope: !16, file: !1, line: 2, baseType: !14, size: 32)
+!19 = !DIDerivedType(tag: DW_TAG_member, name: "b2", scope: !16, file: !1, line: 2, baseType: !20, size: 64)
+!20 = !DIDerivedType(tag: DW_TAG_typedef, name: "__s1", file: !1, line: 1, baseType: !21)
+!21 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "s1", file: !1, line: 1, size: 64, elements: !22)
+!22 = !{!23, !24}
+!23 = !DIDerivedType(tag: DW_TAG_member, name: "a1", scope: !21, file: !1, line: 1, baseType: !14, size: 32)
+!24 = !DIDerivedType(tag: DW_TAG_member, name: "a2", scope: !21, file: !1, line: 1, baseType: !25, size: 16, offset: 32)
+!25 = !DIBasicType(name: "short", size: 16, encoding: DW_ATE_signed)
+!26 = !{!27, !28, !29}
+!27 = !DILocalVariable(name: "arg", arg: 1, scope: !11, file: !1, line: 4, type: !15)
+!28 = !DILocalVariable(name: "r1", scope: !11, file: !1, line: 5, type: !4)
+!29 = !DILocalVariable(name: "r2", scope: !11, file: !1, line: 6, type: !4)
+!30 = !DILocation(line: 0, scope: !11)
+!31 = !DILocation(line: 5, column: 52, scope: !11)
+!32 = !DILocation(line: 5, column: 55, scope: !11)
+!33 = !DILocation(line: 5, column: 17, scope: !11)
+!34 = !DILocation(line: 6, column: 55, scope: !11)
+!35 = !DILocation(line: 6, column: 17, scope: !11)
+!36 = !DILocation(line: 9, column: 13, scope: !11)
+!37 = !DILocation(line: 9, column: 3, scope: !11)
diff --git a/llvm/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-rshift-1.ll b/llvm/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-rshift-1.ll
new file mode 100644
index 00000000000..70791d39cf7
--- /dev/null
+++ b/llvm/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-rshift-1.ll
@@ -0,0 +1,148 @@
+; RUN: llc -march=bpfel -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
+; RUN: llc -march=bpfeb -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
+; Source code:
+; typedef struct s1 { int a1:7; int a2:4; int a3:5; int a4:16;} __s1;
+; union u1 { int b1; __s1 b2; };
+; enum { FIELD_RSHIFT_U64 = 5, };
+; int test(union u1 *arg) {
+; unsigned r1 = __builtin_preserve_field_info(arg->b2.a1, FIELD_RSHIFT_U64);
+; unsigned r2 = __builtin_preserve_field_info(arg->b2.a2, FIELD_RSHIFT_U64);
+; unsigned r3 = __builtin_preserve_field_info(arg->b2.a3, FIELD_RSHIFT_U64);
+; unsigned r4 = __builtin_preserve_field_info(arg->b2.a4, FIELD_RSHIFT_U64);
+; /* r1: 57, r2: 60, r3: 59, r4: 48 */
+; return r1 + r2 + r3 + r4;
+; }
+; Compilation flag:
+; clang -target bpf -O2 -g -S -emit-llvm test.c
+
+%union.u1 = type { i32 }
+%struct.s1 = type { i32 }
+
+; Function Attrs: nounwind readnone
+define dso_local i32 @test(%union.u1* %arg) local_unnamed_addr #0 !dbg !11 {
+entry:
+ call void @llvm.dbg.value(metadata %union.u1* %arg, metadata !28, metadata !DIExpression()), !dbg !33
+ %0 = tail call %union.u1* @llvm.preserve.union.access.index.p0s_union.u1s.p0s_union.u1s(%union.u1* %arg, i32 1), !dbg !34, !llvm.preserve.access.index !16
+ %b2 = bitcast %union.u1* %0 to %struct.s1*, !dbg !34
+ %1 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.s1s(%struct.s1* %b2, i32 0, i32 0), !dbg !35, !llvm.preserve.access.index !21
+ %2 = tail call i32 @llvm.bpf.preserve.field.info.p0i32(i32* %1, i64 5), !dbg !36
+ call void @llvm.dbg.value(metadata i32 %2, metadata !29, metadata !DIExpression()), !dbg !33
+ %3 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.s1s(%struct.s1* %b2, i32 0, i32 1), !dbg !37, !llvm.preserve.access.index !21
+ %4 = tail call i32 @llvm.bpf.preserve.field.info.p0i32(i32* %3, i64 5), !dbg !38
+ call void @llvm.dbg.value(metadata i32 %4, metadata !30, metadata !DIExpression()), !dbg !33
+ %5 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.s1s(%struct.s1* %b2, i32 0, i32 2), !dbg !39, !llvm.preserve.access.index !21
+ %6 = tail call i32 @llvm.bpf.preserve.field.info.p0i32(i32* %5, i64 5), !dbg !40
+ call void @llvm.dbg.value(metadata i32 %6, metadata !31, metadata !DIExpression()), !dbg !33
+ %7 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.s1s(%struct.s1* %b2, i32 0, i32 3), !dbg !41, !llvm.preserve.access.index !21
+ %8 = tail call i32 @llvm.bpf.preserve.field.info.p0i32(i32* %7, i64 5), !dbg !42
+ call void @llvm.dbg.value(metadata i32 %8, metadata !32, metadata !DIExpression()), !dbg !33
+ %add = add i32 %4, %2, !dbg !43
+ %add4 = add i32 %add, %6, !dbg !44
+ %add5 = add i32 %add4, %8, !dbg !45
+ ret i32 %add5, !dbg !46
+}
+
+; CHECK: r1 = 57
+; CHECK: r0 = 60
+; CHECK: r0 += r1
+; CHECK: r1 = 59
+; CHECK: r0 += r1
+; CHECK: r1 = 48
+; CHECK: r0 += r1
+; CHECK: exit
+
+; CHECK: .long 1 # BTF_KIND_UNION(id = 2)
+; CHECK: .ascii "u1" # string offset=1
+; CHECK: .ascii ".text" # string offset=43
+; CHECK: .ascii "0:1:0" # string offset=49
+; CHECK: .ascii "0:1:1" # string offset=92
+; CHECK: .ascii "0:1:2" # string offset=98
+; CHECK: .ascii "0:1:3" # string offset=104
+
+; CHECK: .long 16 # FieldReloc
+; CHECK-NEXT: .long 43 # Field reloc section string offset=43
+; CHECK-NEXT: .long 4
+; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
+; CHECK-NEXT: .long 2
+; CHECK-NEXT: .long 49
+; CHECK-NEXT: .long 5
+; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
+; CHECK-NEXT: .long 2
+; CHECK-NEXT: .long 92
+; CHECK-NEXT: .long 5
+; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
+; CHECK-NEXT: .long 2
+; CHECK-NEXT: .long 98
+; CHECK-NEXT: .long 5
+; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
+; CHECK-NEXT: .long 2
+; CHECK-NEXT: .long 104
+; CHECK-NEXT: .long 5
+
+; Function Attrs: nounwind readnone
+declare %union.u1* @llvm.preserve.union.access.index.p0s_union.u1s.p0s_union.u1s(%union.u1*, i32) #1
+
+; Function Attrs: nounwind readnone
+declare i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.s1s(%struct.s1*, i32, i32) #1
+
+; Function Attrs: nounwind readnone
+declare i32 @llvm.bpf.preserve.field.info.p0i32(i32*, i64) #1
+
+; Function Attrs: nounwind readnone speculatable willreturn
+declare void @llvm.dbg.value(metadata, metadata, metadata) #2
+
+attributes #0 = { nounwind readnone "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { nounwind readnone }
+attributes #2 = { nounwind readnone speculatable willreturn }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!7, !8, !9}
+!llvm.ident = !{!10}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (https://github.com/llvm/llvm-project.git 4a60741b74384f14b21fdc0131ede326438840ab)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None)
+!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/core")
+!2 = !{!3}
+!3 = !DICompositeType(tag: DW_TAG_enumeration_type, file: !1, line: 3, baseType: !4, size: 32, elements: !5)
+!4 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned)
+!5 = !{!6}
+!6 = !DIEnumerator(name: "FIELD_RSHIFT_U64", value: 5, isUnsigned: true)
+!7 = !{i32 2, !"Dwarf Version", i32 4}
+!8 = !{i32 2, !"Debug Info Version", i32 3}
+!9 = !{i32 1, !"wchar_size", i32 4}
+!10 = !{!"clang version 10.0.0 (https://github.com/llvm/llvm-project.git 4a60741b74384f14b21fdc0131ede326438840ab)"}
+!11 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 4, type: !12, scopeLine: 4, flags: DIFlagPrototyped, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !27)
+!12 = !DISubroutineType(types: !13)
+!13 = !{!14, !15}
+!14 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!15 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !16, size: 64)
+!16 = distinct !DICompositeType(tag: DW_TAG_union_type, name: "u1", file: !1, line: 2, size: 32, elements: !17)
+!17 = !{!18, !19}
+!18 = !DIDerivedType(tag: DW_TAG_member, name: "b1", scope: !16, file: !1, line: 2, baseType: !14, size: 32)
+!19 = !DIDerivedType(tag: DW_TAG_member, name: "b2", scope: !16, file: !1, line: 2, baseType: !20, size: 32)
+!20 = !DIDerivedType(tag: DW_TAG_typedef, name: "__s1", file: !1, line: 1, baseType: !21)
+!21 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "s1", file: !1, line: 1, size: 32, elements: !22)
+!22 = !{!23, !24, !25, !26}
+!23 = !DIDerivedType(tag: DW_TAG_member, name: "a1", scope: !21, file: !1, line: 1, baseType: !14, size: 7, flags: DIFlagBitField, extraData: i64 0)
+!24 = !DIDerivedType(tag: DW_TAG_member, name: "a2", scope: !21, file: !1, line: 1, baseType: !14, size: 4, offset: 7, flags: DIFlagBitField, extraData: i64 0)
+!25 = !DIDerivedType(tag: DW_TAG_member, name: "a3", scope: !21, file: !1, line: 1, baseType: !14, size: 5, offset: 11, flags: DIFlagBitField, extraData: i64 0)
+!26 = !DIDerivedType(tag: DW_TAG_member, name: "a4", scope: !21, file: !1, line: 1, baseType: !14, size: 16, offset: 16, flags: DIFlagBitField, extraData: i64 0)
+!27 = !{!28, !29, !30, !31, !32}
+!28 = !DILocalVariable(name: "arg", arg: 1, scope: !11, file: !1, line: 4, type: !15)
+!29 = !DILocalVariable(name: "r1", scope: !11, file: !1, line: 5, type: !4)
+!30 = !DILocalVariable(name: "r2", scope: !11, file: !1, line: 6, type: !4)
+!31 = !DILocalVariable(name: "r3", scope: !11, file: !1, line: 7, type: !4)
+!32 = !DILocalVariable(name: "r4", scope: !11, file: !1, line: 8, type: !4)
+!33 = !DILocation(line: 0, scope: !11)
+!34 = !DILocation(line: 5, column: 52, scope: !11)
+!35 = !DILocation(line: 5, column: 55, scope: !11)
+!36 = !DILocation(line: 5, column: 17, scope: !11)
+!37 = !DILocation(line: 6, column: 55, scope: !11)
+!38 = !DILocation(line: 6, column: 17, scope: !11)
+!39 = !DILocation(line: 7, column: 55, scope: !11)
+!40 = !DILocation(line: 7, column: 17, scope: !11)
+!41 = !DILocation(line: 8, column: 55, scope: !11)
+!42 = !DILocation(line: 8, column: 17, scope: !11)
+!43 = !DILocation(line: 10, column: 13, scope: !11)
+!44 = !DILocation(line: 10, column: 18, scope: !11)
+!45 = !DILocation(line: 10, column: 23, scope: !11)
+!46 = !DILocation(line: 10, column: 3, scope: !11)
diff --git a/llvm/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-rshift-2.ll b/llvm/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-rshift-2.ll
new file mode 100644
index 00000000000..657b19c872b
--- /dev/null
+++ b/llvm/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-rshift-2.ll
@@ -0,0 +1,121 @@
+; RUN: llc -march=bpfel -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
+; RUN: llc -march=bpfeb -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
+; Source code:
+; typedef struct s1 { int a1; char a2; } __s1;
+; union u1 { int b1; __s1 b2; };
+; enum { FIELD_RSHIFT_U64 = 5, };
+; int test(union u1 *arg) {
+; unsigned r1 = __builtin_preserve_field_info(arg->b2.a1, FIELD_RSHIFT_U64);
+; unsigned r2 = __builtin_preserve_field_info(arg->b2.a2, FIELD_RSHIFT_U64);
+; /* r1: 32, r2: 56 */
+; return r1 + r2;
+; }
+; Compilation flag:
+; clang -target bpf -O2 -g -S -emit-llvm test.c
+
+%union.u1 = type { %struct.s1 }
+%struct.s1 = type { i32, i8 }
+
+; Function Attrs: nounwind readnone
+define dso_local i32 @test(%union.u1* %arg) local_unnamed_addr #0 !dbg !11 {
+entry:
+ call void @llvm.dbg.value(metadata %union.u1* %arg, metadata !27, metadata !DIExpression()), !dbg !30
+ %0 = tail call %union.u1* @llvm.preserve.union.access.index.p0s_union.u1s.p0s_union.u1s(%union.u1* %arg, i32 1), !dbg !31, !llvm.preserve.access.index !16
+ %b2 = getelementptr inbounds %union.u1, %union.u1* %0, i64 0, i32 0, !dbg !31
+ %1 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.s1s(%struct.s1* %b2, i32 0, i32 0), !dbg !32, !llvm.preserve.access.index !21
+ %2 = tail call i32 @llvm.bpf.preserve.field.info.p0i32(i32* %1, i64 5), !dbg !33
+ call void @llvm.dbg.value(metadata i32 %2, metadata !28, metadata !DIExpression()), !dbg !30
+ %3 = tail call i8* @llvm.preserve.struct.access.index.p0i8.p0s_struct.s1s(%struct.s1* %b2, i32 1, i32 1), !dbg !34, !llvm.preserve.access.index !21
+ %4 = tail call i32 @llvm.bpf.preserve.field.info.p0i8(i8* %3, i64 5), !dbg !35
+ call void @llvm.dbg.value(metadata i32 %4, metadata !29, metadata !DIExpression()), !dbg !30
+ %add = add i32 %4, %2, !dbg !36
+ ret i32 %add, !dbg !37
+}
+
+; CHECK: r1 = 32
+; CHECK: r0 = 56
+; CHECK: r0 += r1
+; CHECK: exit
+
+; CHECK: .long 1 # BTF_KIND_UNION(id = 2)
+; CHECK: .ascii "u1" # string offset=1
+; CHECK: .ascii ".text" # string offset=42
+; CHECK: .ascii "0:1:0" # string offset=48
+; CHECK: .ascii "0:1:1" # string offset=91
+
+; CHECK: .long 16 # FieldReloc
+; CHECK-NEXT: .long 42 # Field reloc section string offset=42
+; CHECK-NEXT: .long 2
+; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
+; CHECK-NEXT: .long 2
+; CHECK-NEXT: .long 48
+; CHECK-NEXT: .long 5
+; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
+; CHECK-NEXT: .long 2
+; CHECK-NEXT: .long 91
+; CHECK-NEXT: .long 5
+
+; Function Attrs: nounwind readnone
+declare %union.u1* @llvm.preserve.union.access.index.p0s_union.u1s.p0s_union.u1s(%union.u1*, i32) #1
+
+; Function Attrs: nounwind readnone
+declare i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.s1s(%struct.s1*, i32, i32) #1
+
+; Function Attrs: nounwind readnone
+declare i32 @llvm.bpf.preserve.field.info.p0i32(i32*, i64) #1
+
+; Function Attrs: nounwind readnone
+declare i8* @llvm.preserve.struct.access.index.p0i8.p0s_struct.s1s(%struct.s1*, i32, i32) #1
+
+; Function Attrs: nounwind readnone
+declare i32 @llvm.bpf.preserve.field.info.p0i8(i8*, i64) #1
+
+; Function Attrs: nounwind readnone speculatable willreturn
+declare void @llvm.dbg.value(metadata, metadata, metadata) #2
+
+attributes #0 = { nounwind readnone "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { nounwind readnone }
+attributes #2 = { nounwind readnone speculatable willreturn }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!7, !8, !9}
+!llvm.ident = !{!10}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (https://github.com/llvm/llvm-project.git 4a60741b74384f14b21fdc0131ede326438840ab)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None)
+!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/core")
+!2 = !{!3}
+!3 = !DICompositeType(tag: DW_TAG_enumeration_type, file: !1, line: 3, baseType: !4, size: 32, elements: !5)
+!4 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned)
+!5 = !{!6}
+!6 = !DIEnumerator(name: "FIELD_RSHIFT_U64", value: 5, isUnsigned: true)
+!7 = !{i32 2, !"Dwarf Version", i32 4}
+!8 = !{i32 2, !"Debug Info Version", i32 3}
+!9 = !{i32 1, !"wchar_size", i32 4}
+!10 = !{!"clang version 10.0.0 (https://github.com/llvm/llvm-project.git 4a60741b74384f14b21fdc0131ede326438840ab)"}
+!11 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 4, type: !12, scopeLine: 4, flags: DIFlagPrototyped, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !26)
+!12 = !DISubroutineType(types: !13)
+!13 = !{!14, !15}
+!14 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!15 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !16, size: 64)
+!16 = distinct !DICompositeType(tag: DW_TAG_union_type, name: "u1", file: !1, line: 2, size: 64, elements: !17)
+!17 = !{!18, !19}
+!18 = !DIDerivedType(tag: DW_TAG_member, name: "b1", scope: !16, file: !1, line: 2, baseType: !14, size: 32)
+!19 = !DIDerivedType(tag: DW_TAG_member, name: "b2", scope: !16, file: !1, line: 2, baseType: !20, size: 64)
+!20 = !DIDerivedType(tag: DW_TAG_typedef, name: "__s1", file: !1, line: 1, baseType: !21)
+!21 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "s1", file: !1, line: 1, size: 64, elements: !22)
+!22 = !{!23, !24}
+!23 = !DIDerivedType(tag: DW_TAG_member, name: "a1", scope: !21, file: !1, line: 1, baseType: !14, size: 32)
+!24 = !DIDerivedType(tag: DW_TAG_member, name: "a2", scope: !21, file: !1, line: 1, baseType: !25, size: 8, offset: 32)
+!25 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char)
+!26 = !{!27, !28, !29}
+!27 = !DILocalVariable(name: "arg", arg: 1, scope: !11, file: !1, line: 4, type: !15)
+!28 = !DILocalVariable(name: "r1", scope: !11, file: !1, line: 5, type: !4)
+!29 = !DILocalVariable(name: "r2", scope: !11, file: !1, line: 6, type: !4)
+!30 = !DILocation(line: 0, scope: !11)
+!31 = !DILocation(line: 5, column: 52, scope: !11)
+!32 = !DILocation(line: 5, column: 55, scope: !11)
+!33 = !DILocation(line: 5, column: 17, scope: !11)
+!34 = !DILocation(line: 6, column: 55, scope: !11)
+!35 = !DILocation(line: 6, column: 17, scope: !11)
+!36 = !DILocation(line: 8, column: 13, scope: !11)
+!37 = !DILocation(line: 8, column: 3, scope: !11)
diff --git a/llvm/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-rshift-3.ll b/llvm/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-rshift-3.ll
new file mode 100644
index 00000000000..2f9cf2fa843
--- /dev/null
+++ b/llvm/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-rshift-3.ll
@@ -0,0 +1,131 @@
+; RUN: llc -march=bpfel -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
+; RUN: llc -march=bpfeb -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
+; Source code:
+; typedef struct s1 { char a1 [5][5]; } __s1;
+; union u1 { int b1; __s1 b2; };
+; enum { FIELD_RSHIFT_U64 = 5, };
+; int test(union u1 *arg) {
+; unsigned r1 = __builtin_preserve_field_info(arg->b2.a1[3], FIELD_RSHIFT_U64);
+; unsigned r2 = __builtin_preserve_field_info(arg->b2.a1[3][3], FIELD_RSHIFT_U64);
+; /* r1 : 24, r2 : 56 */
+; return r1 + r2;
+; }
+; Compilation flag:
+; clang -target bpf -O2 -g -S -emit-llvm test.c
+
+%union.u1 = type { i32, [24 x i8] }
+%struct.s1 = type { [5 x [5 x i8]] }
+
+; Function Attrs: nounwind readnone
+define dso_local i32 @test(%union.u1* %arg) local_unnamed_addr #0 !dbg !18 {
+entry:
+ call void @llvm.dbg.value(metadata %union.u1* %arg, metadata !32, metadata !DIExpression()), !dbg !35
+ %0 = tail call %union.u1* @llvm.preserve.union.access.index.p0s_union.u1s.p0s_union.u1s(%union.u1* %arg, i32 1), !dbg !36, !llvm.preserve.access.index !23
+ %b2 = bitcast %union.u1* %0 to %struct.s1*, !dbg !36
+ %1 = tail call [5 x [5 x i8]]* @llvm.preserve.struct.access.index.p0a5a5i8.p0s_struct.s1s(%struct.s1* %b2, i32 0, i32 0), !dbg !37, !llvm.preserve.access.index !28
+ %2 = tail call [5 x i8]* @llvm.preserve.array.access.index.p0a5i8.p0a5a5i8([5 x [5 x i8]]* %1, i32 1, i32 3), !dbg !38, !llvm.preserve.access.index !8
+ %3 = tail call i32 @llvm.bpf.preserve.field.info.p0a5i8([5 x i8]* %2, i64 5), !dbg !39
+ call void @llvm.dbg.value(metadata i32 %3, metadata !33, metadata !DIExpression()), !dbg !35
+ %4 = tail call i8* @llvm.preserve.array.access.index.p0i8.p0a5i8([5 x i8]* %2, i32 1, i32 3), !dbg !40, !llvm.preserve.access.index !12
+ %5 = tail call i32 @llvm.bpf.preserve.field.info.p0i8(i8* %4, i64 5), !dbg !41
+ call void @llvm.dbg.value(metadata i32 %5, metadata !34, metadata !DIExpression()), !dbg !35
+ %add = add i32 %5, %3, !dbg !42
+ ret i32 %add, !dbg !43
+}
+
+; CHECK: r1 = 24
+; CHECK: r0 = 56
+; CHECK: r0 += r1
+; CHECK: exit
+
+; CHECK: .long 1 # BTF_KIND_UNION(id = 2)
+; CHECK: .ascii "u1" # string offset=1
+; CHECK: .ascii ".text" # string offset=59
+; CHECK: .ascii "0:1:0:3" # string offset=65
+; CHECK: .ascii "0:1:0:3:3" # string offset=110
+
+; CHECK: .long 16 # FieldReloc
+; CHECK-NEXT: .long 59 # Field reloc section string offset=59
+; CHECK-NEXT: .long 2
+; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
+; CHECK-NEXT: .long 2
+; CHECK-NEXT: .long 65
+; CHECK-NEXT: .long 5
+; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
+; CHECK-NEXT: .long 2
+; CHECK-NEXT: .long 110
+; CHECK-NEXT: .long 5
+
+; Function Attrs: nounwind readnone
+declare %union.u1* @llvm.preserve.union.access.index.p0s_union.u1s.p0s_union.u1s(%union.u1*, i32) #1
+
+; Function Attrs: nounwind readnone
+declare [5 x [5 x i8]]* @llvm.preserve.struct.access.index.p0a5a5i8.p0s_struct.s1s(%struct.s1*, i32, i32) #1
+
+; Function Attrs: nounwind readnone
+declare [5 x i8]* @llvm.preserve.array.access.index.p0a5i8.p0a5a5i8([5 x [5 x i8]]*, i32, i32) #1
+
+; Function Attrs: nounwind readnone
+declare i32 @llvm.bpf.preserve.field.info.p0a5i8([5 x i8]*, i64) #1
+
+; Function Attrs: nounwind readnone
+declare i8* @llvm.preserve.array.access.index.p0i8.p0a5i8([5 x i8]*, i32, i32) #1
+
+; Function Attrs: nounwind readnone
+declare i32 @llvm.bpf.preserve.field.info.p0i8(i8*, i64) #1
+
+; Function Attrs: nounwind readnone speculatable willreturn
+declare void @llvm.dbg.value(metadata, metadata, metadata) #2
+
+attributes #0 = { nounwind readnone "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { nounwind readnone }
+attributes #2 = { nounwind readnone speculatable willreturn }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!14, !15, !16}
+!llvm.ident = !{!17}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (https://github.com/llvm/llvm-project.git c1e02f16f1105ffaf1c35ee8bc38b7d6db5c6ea9)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !7, nameTableKind: None)
+!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/core")
+!2 = !{!3}
+!3 = !DICompositeType(tag: DW_TAG_enumeration_type, file: !1, line: 3, baseType: !4, size: 32, elements: !5)
+!4 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned)
+!5 = !{!6}
+!6 = !DIEnumerator(name: "FIELD_RSHIFT_U64", value: 5, isUnsigned: true)
+!7 = !{!8, !12}
+!8 = !DICompositeType(tag: DW_TAG_array_type, baseType: !9, size: 200, elements: !10)
+!9 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char)
+!10 = !{!11, !11}
+!11 = !DISubrange(count: 5)
+!12 = !DICompositeType(tag: DW_TAG_array_type, baseType: !9, size: 40, elements: !13)
+!13 = !{!11}
+!14 = !{i32 2, !"Dwarf Version", i32 4}
+!15 = !{i32 2, !"Debug Info Version", i32 3}
+!16 = !{i32 1, !"wchar_size", i32 4}
+!17 = !{!"clang version 10.0.0 (https://github.com/llvm/llvm-project.git c1e02f16f1105ffaf1c35ee8bc38b7d6db5c6ea9)"}
+!18 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 4, type: !19, scopeLine: 4, flags: DIFlagPrototyped, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !31)
+!19 = !DISubroutineType(types: !20)
+!20 = !{!21, !22}
+!21 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!22 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !23, size: 64)
+!23 = distinct !DICompositeType(tag: DW_TAG_union_type, name: "u1", file: !1, line: 2, size: 224, elements: !24)
+!24 = !{!25, !26}
+!25 = !DIDerivedType(tag: DW_TAG_member, name: "b1", scope: !23, file: !1, line: 2, baseType: !21, size: 32)
+!26 = !DIDerivedType(tag: DW_TAG_member, name: "b2", scope: !23, file: !1, line: 2, baseType: !27, size: 200)
+!27 = !DIDerivedType(tag: DW_TAG_typedef, name: "__s1", file: !1, line: 1, baseType: !28)
+!28 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "s1", file: !1, line: 1, size: 200, elements: !29)
+!29 = !{!30}
+!30 = !DIDerivedType(tag: DW_TAG_member, name: "a1", scope: !28, file: !1, line: 1, baseType: !8, size: 200)
+!31 = !{!32, !33, !34}
+!32 = !DILocalVariable(name: "arg", arg: 1, scope: !18, file: !1, line: 4, type: !22)
+!33 = !DILocalVariable(name: "r1", scope: !18, file: !1, line: 5, type: !4)
+!34 = !DILocalVariable(name: "r2", scope: !18, file: !1, line: 6, type: !4)
+!35 = !DILocation(line: 0, scope: !18)
+!36 = !DILocation(line: 5, column: 52, scope: !18)
+!37 = !DILocation(line: 5, column: 55, scope: !18)
+!38 = !DILocation(line: 5, column: 47, scope: !18)
+!39 = !DILocation(line: 5, column: 17, scope: !18)
+!40 = !DILocation(line: 6, column: 47, scope: !18)
+!41 = !DILocation(line: 6, column: 17, scope: !18)
+!42 = !DILocation(line: 8, column: 13, scope: !18)
+!43 = !DILocation(line: 8, column: 3, scope: !18)
diff --git a/llvm/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-signedness-1.ll b/llvm/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-signedness-1.ll
new file mode 100644
index 00000000000..f5605cb9b62
--- /dev/null
+++ b/llvm/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-signedness-1.ll
@@ -0,0 +1,162 @@
+; RUN: llc -march=bpfel -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
+; RUN: llc -march=bpfeb -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
+; Source code:
+; typedef unsigned __uint;
+; struct s1 { int a1; __uint a2:9; __uint a3:4; };
+; union u1 { int b1; __uint b2:9; __uint b3:4; };
+; enum { FIELD_SIGNEDNESS = 3, };
+; int test(struct s1 *arg1, union u1 *arg2) {
+; unsigned r1 = __builtin_preserve_field_info(arg1->a1, FIELD_SIGNEDNESS);
+; unsigned r2 = __builtin_preserve_field_info(arg1->a3, FIELD_SIGNEDNESS);
+; unsigned r3 = __builtin_preserve_field_info(arg2->b1, FIELD_SIGNEDNESS);
+; unsigned r4 = __builtin_preserve_field_info(arg2->b3, FIELD_SIGNEDNESS);
+; return r1 + r2 + r3 + r4;
+; }
+; Compilation flag:
+; clang -target bpf -O2 -g -S -emit-llvm test.c
+
+%struct.s1 = type { i32, i16 }
+%union.u1 = type { i32 }
+
+; Function Attrs: nounwind readnone
+define dso_local i32 @test(%struct.s1* %arg1, %union.u1* %arg2) local_unnamed_addr #0 !dbg !11 {
+entry:
+ call void @llvm.dbg.value(metadata %struct.s1* %arg1, metadata !29, metadata !DIExpression()), !dbg !35
+ call void @llvm.dbg.value(metadata %union.u1* %arg2, metadata !30, metadata !DIExpression()), !dbg !35
+ %0 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.s1s(%struct.s1* %arg1, i32 0, i32 0), !dbg !36, !llvm.preserve.access.index !16
+ %1 = tail call i32 @llvm.bpf.preserve.field.info.p0i32(i32* %0, i64 3), !dbg !37
+ call void @llvm.dbg.value(metadata i32 %1, metadata !31, metadata !DIExpression()), !dbg !35
+ %2 = tail call i16* @llvm.preserve.struct.access.index.p0i16.p0s_struct.s1s(%struct.s1* %arg1, i32 1, i32 2), !dbg !38, !llvm.preserve.access.index !16
+ %3 = tail call i32 @llvm.bpf.preserve.field.info.p0i16(i16* %2, i64 3), !dbg !39
+ call void @llvm.dbg.value(metadata i32 %3, metadata !32, metadata !DIExpression()), !dbg !35
+ %4 = tail call %union.u1* @llvm.preserve.union.access.index.p0s_union.u1s.p0s_union.u1s(%union.u1* %arg2, i32 0), !dbg !40, !llvm.preserve.access.index !23
+ %b1 = getelementptr inbounds %union.u1, %union.u1* %4, i64 0, i32 0, !dbg !40
+ %5 = tail call i32 @llvm.bpf.preserve.field.info.p0i32(i32* %b1, i64 3), !dbg !41
+ call void @llvm.dbg.value(metadata i32 %5, metadata !33, metadata !DIExpression()), !dbg !35
+ %6 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_union.u1s(%union.u1* %arg2, i32 0, i32 2), !dbg !42, !llvm.preserve.access.index !23
+ %7 = bitcast i32* %6 to i8*, !dbg !42
+ %8 = tail call i32 @llvm.bpf.preserve.field.info.p0i8(i8* %7, i64 3), !dbg !43
+ call void @llvm.dbg.value(metadata i32 %8, metadata !34, metadata !DIExpression()), !dbg !35
+ %add = add i32 %3, %1, !dbg !44
+ %add1 = add i32 %add, %5, !dbg !45
+ %add2 = add i32 %add1, %8, !dbg !46
+ ret i32 %add2, !dbg !47
+}
+
+; CHECK: r1 = 1
+; CHECK: r0 = 0
+; CHECK: r0 += r1
+; CHECK: r1 = 1
+; CHECK: r0 += r1
+; CHECK: r1 = 0
+; CHECK: r0 += r1
+; CHECK: exit
+
+; CHECK: .long 1 # BTF_KIND_STRUCT(id = 2)
+; CHECK: .long 37 # BTF_KIND_UNION(id = 7)
+; CHECK: .ascii "s1" # string offset=1
+; CHECK: .ascii "u1" # string offset=37
+; CHECK: .ascii ".text" # string offset=64
+; CHECK: .ascii "0:0" # string offset=70
+; CHECK: .ascii "0:2" # string offset=111
+
+; CHECK: .long 16 # FieldReloc
+; CHECK-NEXT: .long 64 # Field reloc section string offset=64
+; CHECK-NEXT: .long 4
+; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
+; CHECK-NEXT: .long 2
+; CHECK-NEXT: .long 70
+; CHECK-NEXT: .long 3
+; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
+; CHECK-NEXT: .long 2
+; CHECK-NEXT: .long 111
+; CHECK-NEXT: .long 3
+; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
+; CHECK-NEXT: .long 7
+; CHECK-NEXT: .long 70
+; CHECK-NEXT: .long 3
+; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
+; CHECK-NEXT: .long 7
+; CHECK-NEXT: .long 111
+; CHECK-NEXT: .long 3
+
+; Function Attrs: nounwind readnone
+declare i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.s1s(%struct.s1*, i32, i32) #1
+
+; Function Attrs: nounwind readnone
+declare i32 @llvm.bpf.preserve.field.info.p0i32(i32*, i64) #1
+
+; Function Attrs: nounwind readnone
+declare i16* @llvm.preserve.struct.access.index.p0i16.p0s_struct.s1s(%struct.s1*, i32, i32) #1
+
+; Function Attrs: nounwind readnone
+declare i32 @llvm.bpf.preserve.field.info.p0i16(i16*, i64) #1
+
+; Function Attrs: nounwind readnone
+declare %union.u1* @llvm.preserve.union.access.index.p0s_union.u1s.p0s_union.u1s(%union.u1*, i32) #1
+
+; Function Attrs: nounwind readnone
+declare i32* @llvm.preserve.struct.access.index.p0i32.p0s_union.u1s(%union.u1*, i32, i32) #1
+
+; Function Attrs: nounwind readnone
+declare i32 @llvm.bpf.preserve.field.info.p0i8(i8*, i64) #1
+
+; Function Attrs: nounwind readnone speculatable willreturn
+declare void @llvm.dbg.value(metadata, metadata, metadata) #2
+
+attributes #0 = { nounwind readnone "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { nounwind readnone }
+attributes #2 = { nounwind readnone speculatable willreturn }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!7, !8, !9}
+!llvm.ident = !{!10}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (https://github.com/llvm/llvm-project.git 4a60741b74384f14b21fdc0131ede326438840ab)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None)
+!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/core")
+!2 = !{!3}
+!3 = !DICompositeType(tag: DW_TAG_enumeration_type, file: !1, line: 4, baseType: !4, size: 32, elements: !5)
+!4 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned)
+!5 = !{!6}
+!6 = !DIEnumerator(name: "FIELD_SIGNEDNESS", value: 3, isUnsigned: true)
+!7 = !{i32 2, !"Dwarf Version", i32 4}
+!8 = !{i32 2, !"Debug Info Version", i32 3}
+!9 = !{i32 1, !"wchar_size", i32 4}
+!10 = !{!"clang version 10.0.0 (https://github.com/llvm/llvm-project.git 4a60741b74384f14b21fdc0131ede326438840ab)"}
+!11 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 5, type: !12, scopeLine: 5, flags: DIFlagPrototyped, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !28)
+!12 = !DISubroutineType(types: !13)
+!13 = !{!14, !15, !22}
+!14 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!15 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !16, size: 64)
+!16 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "s1", file: !1, line: 2, size: 64, elements: !17)
+!17 = !{!18, !19, !21}
+!18 = !DIDerivedType(tag: DW_TAG_member, name: "a1", scope: !16, file: !1, line: 2, baseType: !14, size: 32)
+!19 = !DIDerivedType(tag: DW_TAG_member, name: "a2", scope: !16, file: !1, line: 2, baseType: !20, size: 9, offset: 32, flags: DIFlagBitField, extraData: i64 32)
+!20 = !DIDerivedType(tag: DW_TAG_typedef, name: "__uint", file: !1, line: 1, baseType: !4)
+!21 = !DIDerivedType(tag: DW_TAG_member, name: "a3", scope: !16, file: !1, line: 2, baseType: !20, size: 4, offset: 41, flags: DIFlagBitField, extraData: i64 32)
+!22 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !23, size: 64)
+!23 = distinct !DICompositeType(tag: DW_TAG_union_type, name: "u1", file: !1, line: 3, size: 32, elements: !24)
+!24 = !{!25, !26, !27}
+!25 = !DIDerivedType(tag: DW_TAG_member, name: "b1", scope: !23, file: !1, line: 3, baseType: !14, size: 32)
+!26 = !DIDerivedType(tag: DW_TAG_member, name: "b2", scope: !23, file: !1, line: 3, baseType: !20, size: 9, flags: DIFlagBitField, extraData: i64 0)
+!27 = !DIDerivedType(tag: DW_TAG_member, name: "b3", scope: !23, file: !1, line: 3, baseType: !20, size: 4, flags: DIFlagBitField, extraData: i64 0)
+!28 = !{!29, !30, !31, !32, !33, !34}
+!29 = !DILocalVariable(name: "arg1", arg: 1, scope: !11, file: !1, line: 5, type: !15)
+!30 = !DILocalVariable(name: "arg2", arg: 2, scope: !11, file: !1, line: 5, type: !22)
+!31 = !DILocalVariable(name: "r1", scope: !11, file: !1, line: 6, type: !4)
+!32 = !DILocalVariable(name: "r2", scope: !11, file: !1, line: 7, type: !4)
+!33 = !DILocalVariable(name: "r3", scope: !11, file: !1, line: 8, type: !4)
+!34 = !DILocalVariable(name: "r4", scope: !11, file: !1, line: 9, type: !4)
+!35 = !DILocation(line: 0, scope: !11)
+!36 = !DILocation(line: 6, column: 53, scope: !11)
+!37 = !DILocation(line: 6, column: 17, scope: !11)
+!38 = !DILocation(line: 7, column: 53, scope: !11)
+!39 = !DILocation(line: 7, column: 17, scope: !11)
+!40 = !DILocation(line: 8, column: 53, scope: !11)
+!41 = !DILocation(line: 8, column: 17, scope: !11)
+!42 = !DILocation(line: 9, column: 53, scope: !11)
+!43 = !DILocation(line: 9, column: 17, scope: !11)
+!44 = !DILocation(line: 10, column: 13, scope: !11)
+!45 = !DILocation(line: 10, column: 18, scope: !11)
+!46 = !DILocation(line: 10, column: 23, scope: !11)
+!47 = !DILocation(line: 10, column: 3, scope: !11)
diff --git a/llvm/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-signedness-2.ll b/llvm/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-signedness-2.ll
new file mode 100644
index 00000000000..cec9790f577
--- /dev/null
+++ b/llvm/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-signedness-2.ll
@@ -0,0 +1,151 @@
+; RUN: llc -march=bpfel -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
+; RUN: llc -march=bpfeb -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
+; Source code:
+; enum A { AA = -1, AB = 0, }; /* signed */
+; enum B { BA = 0, BB = 1, }; /* unsigned */
+; typedef enum A __A;
+; typedef enum B __B;
+; typedef int __int; /* signed */
+; struct s1 { __A a1; __B a2:9; __int a3:4; };
+; union u1 { int b1; struct s1 b2; };
+; enum { FIELD_SIGNEDNESS = 3, };
+; int test(union u1 *arg) {
+; unsigned r1 = __builtin_preserve_field_info(arg->b2.a1, FIELD_SIGNEDNESS);
+; unsigned r2 = __builtin_preserve_field_info(arg->b2.a2, FIELD_SIGNEDNESS);
+; unsigned r3 = __builtin_preserve_field_info(arg->b2.a3, FIELD_SIGNEDNESS);
+; return r1 + r2 + r3;
+; }
+; Compilation flag:
+; clang -target bpf -O2 -g -S -emit-llvm test.c
+
+%union.u1 = type { %struct.s1 }
+%struct.s1 = type { i32, i16 }
+
+; Function Attrs: nounwind readnone
+define dso_local i32 @test(%union.u1* %arg) local_unnamed_addr #0 !dbg !20 {
+entry:
+ call void @llvm.dbg.value(metadata %union.u1* %arg, metadata !37, metadata !DIExpression()), !dbg !41
+ %0 = tail call %union.u1* @llvm.preserve.union.access.index.p0s_union.u1s.p0s_union.u1s(%union.u1* %arg, i32 1), !dbg !42, !llvm.preserve.access.index !24
+ %b2 = getelementptr inbounds %union.u1, %union.u1* %0, i64 0, i32 0, !dbg !42
+ %1 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.s1s(%struct.s1* %b2, i32 0, i32 0), !dbg !43, !llvm.preserve.access.index !28
+ %2 = tail call i32 @llvm.bpf.preserve.field.info.p0i32(i32* %1, i64 3), !dbg !44
+ call void @llvm.dbg.value(metadata i32 %2, metadata !38, metadata !DIExpression()), !dbg !41
+ %3 = tail call i16* @llvm.preserve.struct.access.index.p0i16.p0s_struct.s1s(%struct.s1* %b2, i32 1, i32 1), !dbg !45, !llvm.preserve.access.index !28
+ %4 = tail call i32 @llvm.bpf.preserve.field.info.p0i16(i16* %3, i64 3), !dbg !46
+ call void @llvm.dbg.value(metadata i32 %4, metadata !39, metadata !DIExpression()), !dbg !41
+ %5 = tail call i16* @llvm.preserve.struct.access.index.p0i16.p0s_struct.s1s(%struct.s1* %b2, i32 1, i32 2), !dbg !47, !llvm.preserve.access.index !28
+ %6 = tail call i32 @llvm.bpf.preserve.field.info.p0i16(i16* %5, i64 3), !dbg !48
+ call void @llvm.dbg.value(metadata i32 %6, metadata !40, metadata !DIExpression()), !dbg !41
+ %add = add i32 %4, %2, !dbg !49
+ %add3 = add i32 %add, %6, !dbg !50
+ ret i32 %add3, !dbg !51
+}
+
+; CHECK: r1 = 1
+; CHECK: r0 = 0
+; CHECK: r0 += r1
+; CHECK: r1 = 1
+; CHECK: r0 += r1
+; CHECK: exit
+
+; CHECK: .long 1 # BTF_KIND_UNION(id = 2)
+; CHECK: .ascii "u1" # string offset=1
+; CHECK: .ascii ".text" # string offset=65
+; CHECK: .ascii "0:1:0" # string offset=71
+; CHECK: .ascii "0:1:1" # string offset=114
+; CHECK: .ascii "0:1:2" # string offset=120
+
+; CHECK: .long 16 # FieldReloc
+; CHECK-NEXT: .long 65 # Field reloc section string offset=65
+; CHECK-NEXT: .long 3
+; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
+; CHECK-NEXT: .long 2
+; CHECK-NEXT: .long 71
+; CHECK-NEXT: .long 3
+; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
+; CHECK-NEXT: .long 2
+; CHECK-NEXT: .long 114
+; CHECK-NEXT: .long 3
+; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
+; CHECK-NEXT: .long 2
+; CHECK-NEXT: .long 120
+; CHECK-NEXT: .long 3
+
+; Function Attrs: nounwind readnone
+declare %union.u1* @llvm.preserve.union.access.index.p0s_union.u1s.p0s_union.u1s(%union.u1*, i32) #1
+
+; Function Attrs: nounwind readnone
+declare i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.s1s(%struct.s1*, i32, i32) #1
+
+; Function Attrs: nounwind readnone
+declare i32 @llvm.bpf.preserve.field.info.p0i32(i32*, i64) #1
+
+; Function Attrs: nounwind readnone
+declare i16* @llvm.preserve.struct.access.index.p0i16.p0s_struct.s1s(%struct.s1*, i32, i32) #1
+
+; Function Attrs: nounwind readnone
+declare i32 @llvm.bpf.preserve.field.info.p0i16(i16*, i64) #1
+
+; Function Attrs: nounwind readnone speculatable willreturn
+declare void @llvm.dbg.value(metadata, metadata, metadata) #2
+
+attributes #0 = { nounwind readnone "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { nounwind readnone }
+attributes #2 = { nounwind readnone speculatable willreturn }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!16, !17, !18}
+!llvm.ident = !{!19}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (https://github.com/llvm/llvm-project.git 4a60741b74384f14b21fdc0131ede326438840ab)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None)
+!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/core")
+!2 = !{!3, !8, !13}
+!3 = !DICompositeType(tag: DW_TAG_enumeration_type, name: "A", file: !1, line: 1, baseType: !4, size: 32, elements: !5)
+!4 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!5 = !{!6, !7}
+!6 = !DIEnumerator(name: "AA", value: -1)
+!7 = !DIEnumerator(name: "AB", value: 0)
+!8 = !DICompositeType(tag: DW_TAG_enumeration_type, name: "B", file: !1, line: 2, baseType: !9, size: 32, elements: !10)
+!9 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned)
+!10 = !{!11, !12}
+!11 = !DIEnumerator(name: "BA", value: 0, isUnsigned: true)
+!12 = !DIEnumerator(name: "BB", value: 1, isUnsigned: true)
+!13 = !DICompositeType(tag: DW_TAG_enumeration_type, file: !1, line: 8, baseType: !9, size: 32, elements: !14)
+!14 = !{!15}
+!15 = !DIEnumerator(name: "FIELD_SIGNEDNESS", value: 3, isUnsigned: true)
+!16 = !{i32 2, !"Dwarf Version", i32 4}
+!17 = !{i32 2, !"Debug Info Version", i32 3}
+!18 = !{i32 1, !"wchar_size", i32 4}
+!19 = !{!"clang version 10.0.0 (https://github.com/llvm/llvm-project.git 4a60741b74384f14b21fdc0131ede326438840ab)"}
+!20 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 9, type: !21, scopeLine: 9, flags: DIFlagPrototyped, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !36)
+!21 = !DISubroutineType(types: !22)
+!22 = !{!4, !23}
+!23 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !24, size: 64)
+!24 = distinct !DICompositeType(tag: DW_TAG_union_type, name: "u1", file: !1, line: 7, size: 64, elements: !25)
+!25 = !{!26, !27}
+!26 = !DIDerivedType(tag: DW_TAG_member, name: "b1", scope: !24, file: !1, line: 7, baseType: !4, size: 32)
+!27 = !DIDerivedType(tag: DW_TAG_member, name: "b2", scope: !24, file: !1, line: 7, baseType: !28, size: 64)
+!28 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "s1", file: !1, line: 6, size: 64, elements: !29)
+!29 = !{!30, !32, !34}
+!30 = !DIDerivedType(tag: DW_TAG_member, name: "a1", scope: !28, file: !1, line: 6, baseType: !31, size: 32)
+!31 = !DIDerivedType(tag: DW_TAG_typedef, name: "__A", file: !1, line: 3, baseType: !3)
+!32 = !DIDerivedType(tag: DW_TAG_member, name: "a2", scope: !28, file: !1, line: 6, baseType: !33, size: 9, offset: 32, flags: DIFlagBitField, extraData: i64 32)
+!33 = !DIDerivedType(tag: DW_TAG_typedef, name: "__B", file: !1, line: 4, baseType: !8)
+!34 = !DIDerivedType(tag: DW_TAG_member, name: "a3", scope: !28, file: !1, line: 6, baseType: !35, size: 4, offset: 41, flags: DIFlagBitField, extraData: i64 32)
+!35 = !DIDerivedType(tag: DW_TAG_typedef, name: "__int", file: !1, line: 5, baseType: !4)
+!36 = !{!37, !38, !39, !40}
+!37 = !DILocalVariable(name: "arg", arg: 1, scope: !20, file: !1, line: 9, type: !23)
+!38 = !DILocalVariable(name: "r1", scope: !20, file: !1, line: 10, type: !9)
+!39 = !DILocalVariable(name: "r2", scope: !20, file: !1, line: 11, type: !9)
+!40 = !DILocalVariable(name: "r3", scope: !20, file: !1, line: 12, type: !9)
+!41 = !DILocation(line: 0, scope: !20)
+!42 = !DILocation(line: 10, column: 52, scope: !20)
+!43 = !DILocation(line: 10, column: 55, scope: !20)
+!44 = !DILocation(line: 10, column: 17, scope: !20)
+!45 = !DILocation(line: 11, column: 55, scope: !20)
+!46 = !DILocation(line: 11, column: 17, scope: !20)
+!47 = !DILocation(line: 12, column: 55, scope: !20)
+!48 = !DILocation(line: 12, column: 17, scope: !20)
+!49 = !DILocation(line: 13, column: 13, scope: !20)
+!50 = !DILocation(line: 13, column: 18, scope: !20)
+!51 = !DILocation(line: 13, column: 3, scope: !20)
diff --git a/llvm/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-signedness-3.ll b/llvm/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-signedness-3.ll
new file mode 100644
index 00000000000..619ca8af9ee
--- /dev/null
+++ b/llvm/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-signedness-3.ll
@@ -0,0 +1,149 @@
+; RUN: llc -march=bpfel -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
+; RUN: llc -march=bpfeb -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
+; Source code:
+; enum A { AA = -1, AB = 0, };
+; enum B { BA = 0, BB = 1, };
+; typedef enum A __A;
+; typedef enum B __B;
+; typedef struct s1 { __A a1[10]; __B a2[10][10]; } __s1;
+; union u1 { int b1; __s1 b2; };
+; enum { FIELD_SIGNEDNESS = 3, };
+; int test(union u1 *arg) {
+; unsigned r1 = __builtin_preserve_field_info(arg->b2.a1[5], FIELD_SIGNEDNESS);
+; unsigned r2 = __builtin_preserve_field_info(arg->b2.a2[5][5], FIELD_SIGNEDNESS);
+; /* r1 : 1, r2 : 0 */
+; return r1 + r2;
+; }
+; Compilation flag:
+; clang -target bpf -O2 -g -S -emit-llvm test.c
+
+%union.u1 = type { %struct.s1 }
+%struct.s1 = type { [10 x i32], [10 x [10 x i32]] }
+
+; Function Attrs: nounwind readnone
+define dso_local i32 @test(%union.u1* %arg) local_unnamed_addr #0 !dbg !29 {
+entry:
+ call void @llvm.dbg.value(metadata %union.u1* %arg, metadata !43, metadata !DIExpression()), !dbg !46
+ %0 = tail call %union.u1* @llvm.preserve.union.access.index.p0s_union.u1s.p0s_union.u1s(%union.u1* %arg, i32 1), !dbg !47, !llvm.preserve.access.index !33
+ %b2 = getelementptr inbounds %union.u1, %union.u1* %0, i64 0, i32 0, !dbg !47
+ %1 = tail call [10 x i32]* @llvm.preserve.struct.access.index.p0a10i32.p0s_struct.s1s(%struct.s1* %b2, i32 0, i32 0), !dbg !48, !llvm.preserve.access.index !38
+ %2 = tail call i32* @llvm.preserve.array.access.index.p0i32.p0a10i32([10 x i32]* %1, i32 1, i32 5), !dbg !49, !llvm.preserve.access.index !17
+ %3 = tail call i32 @llvm.bpf.preserve.field.info.p0i32(i32* %2, i64 3), !dbg !50
+ call void @llvm.dbg.value(metadata i32 %3, metadata !44, metadata !DIExpression()), !dbg !46
+ %4 = tail call [10 x [10 x i32]]* @llvm.preserve.struct.access.index.p0a10a10i32.p0s_struct.s1s(%struct.s1* %b2, i32 1, i32 1), !dbg !51, !llvm.preserve.access.index !38
+ %5 = tail call [10 x i32]* @llvm.preserve.array.access.index.p0a10i32.p0a10a10i32([10 x [10 x i32]]* %4, i32 1, i32 5), !dbg !52, !llvm.preserve.access.index !21
+ %6 = tail call i32* @llvm.preserve.array.access.index.p0i32.p0a10i32([10 x i32]* %5, i32 1, i32 5), !dbg !52, !llvm.preserve.access.index !24
+ %7 = tail call i32 @llvm.bpf.preserve.field.info.p0i32(i32* %6, i64 3), !dbg !53
+ call void @llvm.dbg.value(metadata i32 %7, metadata !45, metadata !DIExpression()), !dbg !46
+ %add = add i32 %7, %3, !dbg !54
+ ret i32 %add, !dbg !55
+}
+
+; CHECK: r1 = 1
+; CHECK: r0 = 0
+; CHECK: r0 += r1
+; CHECK: exit
+
+; CHECK: .long 1 # BTF_KIND_UNION(id = 2)
+; CHECK: .ascii "u1" # string offset=1
+; CHECK: .ascii ".text" # string offset=81
+; CHECK: .ascii "0:1:0:5" # string offset=87
+; CHECK: .ascii "0:1:1:5:5" # string offset=132
+
+; CHECK: .long 16 # FieldReloc
+; CHECK-NEXT: .long 81 # Field reloc section string offset=81
+; CHECK-NEXT: .long 2
+; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
+; CHECK-NEXT: .long 2
+; CHECK-NEXT: .long 87
+; CHECK-NEXT: .long 3
+; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
+; CHECK-NEXT: .long 2
+; CHECK-NEXT: .long 132
+; CHECK-NEXT: .long 3
+
+; Function Attrs: nounwind readnone
+declare %union.u1* @llvm.preserve.union.access.index.p0s_union.u1s.p0s_union.u1s(%union.u1*, i32) #1
+
+; Function Attrs: nounwind readnone
+declare [10 x i32]* @llvm.preserve.struct.access.index.p0a10i32.p0s_struct.s1s(%struct.s1*, i32, i32) #1
+
+; Function Attrs: nounwind readnone
+declare i32* @llvm.preserve.array.access.index.p0i32.p0a10i32([10 x i32]*, i32, i32) #1
+
+; Function Attrs: nounwind readnone
+declare i32 @llvm.bpf.preserve.field.info.p0i32(i32*, i64) #1
+
+; Function Attrs: nounwind readnone
+declare [10 x [10 x i32]]* @llvm.preserve.struct.access.index.p0a10a10i32.p0s_struct.s1s(%struct.s1*, i32, i32) #1
+
+; Function Attrs: nounwind readnone
+declare [10 x i32]* @llvm.preserve.array.access.index.p0a10i32.p0a10a10i32([10 x [10 x i32]]*, i32, i32) #1
+
+; Function Attrs: nounwind readnone speculatable willreturn
+declare void @llvm.dbg.value(metadata, metadata, metadata) #2
+
+attributes #0 = { nounwind readnone "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { nounwind readnone }
+attributes #2 = { nounwind readnone speculatable willreturn }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!25, !26, !27}
+!llvm.ident = !{!28}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (https://github.com/llvm/llvm-project.git c1e02f16f1105ffaf1c35ee8bc38b7d6db5c6ea9)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !16, nameTableKind: None)
+!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/core")
+!2 = !{!3, !8, !13}
+!3 = !DICompositeType(tag: DW_TAG_enumeration_type, name: "A", file: !1, line: 1, baseType: !4, size: 32, elements: !5)
+!4 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!5 = !{!6, !7}
+!6 = !DIEnumerator(name: "AA", value: -1)
+!7 = !DIEnumerator(name: "AB", value: 0)
+!8 = !DICompositeType(tag: DW_TAG_enumeration_type, name: "B", file: !1, line: 2, baseType: !9, size: 32, elements: !10)
+!9 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned)
+!10 = !{!11, !12}
+!11 = !DIEnumerator(name: "BA", value: 0, isUnsigned: true)
+!12 = !DIEnumerator(name: "BB", value: 1, isUnsigned: true)
+!13 = !DICompositeType(tag: DW_TAG_enumeration_type, file: !1, line: 7, baseType: !9, size: 32, elements: !14)
+!14 = !{!15}
+!15 = !DIEnumerator(name: "FIELD_SIGNEDNESS", value: 3, isUnsigned: true)
+!16 = !{!17, !21, !24}
+!17 = !DICompositeType(tag: DW_TAG_array_type, baseType: !18, size: 320, elements: !19)
+!18 = !DIDerivedType(tag: DW_TAG_typedef, name: "__A", file: !1, line: 3, baseType: !3)
+!19 = !{!20}
+!20 = !DISubrange(count: 10)
+!21 = !DICompositeType(tag: DW_TAG_array_type, baseType: !22, size: 3200, elements: !23)
+!22 = !DIDerivedType(tag: DW_TAG_typedef, name: "__B", file: !1, line: 4, baseType: !8)
+!23 = !{!20, !20}
+!24 = !DICompositeType(tag: DW_TAG_array_type, baseType: !22, size: 320, elements: !19)
+!25 = !{i32 2, !"Dwarf Version", i32 4}
+!26 = !{i32 2, !"Debug Info Version", i32 3}
+!27 = !{i32 1, !"wchar_size", i32 4}
+!28 = !{!"clang version 10.0.0 (https://github.com/llvm/llvm-project.git c1e02f16f1105ffaf1c35ee8bc38b7d6db5c6ea9)"}
+!29 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 8, type: !30, scopeLine: 8, flags: DIFlagPrototyped, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !42)
+!30 = !DISubroutineType(types: !31)
+!31 = !{!4, !32}
+!32 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !33, size: 64)
+!33 = distinct !DICompositeType(tag: DW_TAG_union_type, name: "u1", file: !1, line: 6, size: 3520, elements: !34)
+!34 = !{!35, !36}
+!35 = !DIDerivedType(tag: DW_TAG_member, name: "b1", scope: !33, file: !1, line: 6, baseType: !4, size: 32)
+!36 = !DIDerivedType(tag: DW_TAG_member, name: "b2", scope: !33, file: !1, line: 6, baseType: !37, size: 3520)
+!37 = !DIDerivedType(tag: DW_TAG_typedef, name: "__s1", file: !1, line: 5, baseType: !38)
+!38 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "s1", file: !1, line: 5, size: 3520, elements: !39)
+!39 = !{!40, !41}
+!40 = !DIDerivedType(tag: DW_TAG_member, name: "a1", scope: !38, file: !1, line: 5, baseType: !17, size: 320)
+!41 = !DIDerivedType(tag: DW_TAG_member, name: "a2", scope: !38, file: !1, line: 5, baseType: !21, size: 3200, offset: 320)
+!42 = !{!43, !44, !45}
+!43 = !DILocalVariable(name: "arg", arg: 1, scope: !29, file: !1, line: 8, type: !32)
+!44 = !DILocalVariable(name: "r1", scope: !29, file: !1, line: 9, type: !9)
+!45 = !DILocalVariable(name: "r2", scope: !29, file: !1, line: 10, type: !9)
+!46 = !DILocation(line: 0, scope: !29)
+!47 = !DILocation(line: 9, column: 52, scope: !29)
+!48 = !DILocation(line: 9, column: 55, scope: !29)
+!49 = !DILocation(line: 9, column: 47, scope: !29)
+!50 = !DILocation(line: 9, column: 17, scope: !29)
+!51 = !DILocation(line: 10, column: 55, scope: !29)
+!52 = !DILocation(line: 10, column: 47, scope: !29)
+!53 = !DILocation(line: 10, column: 17, scope: !29)
+!54 = !DILocation(line: 12, column: 13, scope: !29)
+!55 = !DILocation(line: 12, column: 3, scope: !29)
diff --git a/llvm/test/CodeGen/BPF/CORE/intrinsic-struct.ll b/llvm/test/CodeGen/BPF/CORE/intrinsic-struct.ll
index c07c16f5228..1c0189b0f09 100644
--- a/llvm/test/CodeGen/BPF/CORE/intrinsic-struct.ll
+++ b/llvm/test/CodeGen/BPF/CORE/intrinsic-struct.ll
@@ -28,12 +28,13 @@ entry:
; CHECK: exit
;
; CHECK: .section .BTF.ext,"",@progbits
-; CHECK: .long 12 # OffsetReloc
-; CHECK-NEXT: .long 20 # Offset reloc section string offset=20
+; CHECK: .long 16 # FieldReloc
+; CHECK-NEXT: .long 20 # Field reloc section string offset=20
; CHECK-NEXT: .long 1
; CHECK-NEXT: .long [[RELOC]]
; CHECK-NEXT: .long 2
; CHECK-NEXT: .long 26
+; CHECK-NEXT: .long 0
declare dso_local i32 @get_value(i8*) local_unnamed_addr #1
diff --git a/llvm/test/CodeGen/BPF/CORE/intrinsic-union.ll b/llvm/test/CodeGen/BPF/CORE/intrinsic-union.ll
index 19b459533be..48cfa4536f5 100644
--- a/llvm/test/CodeGen/BPF/CORE/intrinsic-union.ll
+++ b/llvm/test/CodeGen/BPF/CORE/intrinsic-union.ll
@@ -27,12 +27,13 @@ entry:
; CHECK: exit
; CHECK: .section .BTF.ext,"",@progbits
-; CHECK: .long 12 # OffsetReloc
-; CHECK-NEXT: .long 20 # Offset reloc section string offset=20
+; CHECK: .long 16 # FieldReloc
+; CHECK-NEXT: .long 20 # Field reloc section string offset=20
; CHECK-NEXT: .long 1
; CHECK-NEXT: .long [[RELOC]]
; CHECK-NEXT: .long 2
; CHECK-NEXT: .long 26
+; CHECK-NEXT: .long 0
declare dso_local i32 @get_value(i8*) local_unnamed_addr #1
diff --git a/llvm/test/CodeGen/BPF/CORE/offset-reloc-access-str.ll b/llvm/test/CodeGen/BPF/CORE/offset-reloc-access-str.ll
index 5625bf99fa4..c2e3296067c 100644
--- a/llvm/test/CodeGen/BPF/CORE/offset-reloc-access-str.ll
+++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-access-str.ll
@@ -33,15 +33,17 @@ entry:
; CHECK: .ascii "0:1" # string offset=[[ACCESS_STR:[0-9]+]]
; CHECK-NEXT: .byte 0
; CHECK: .section .BTF.ext,"",@progbits
-; CHECK: .long 12 # OffsetReloc
-; CHECK-NEXT: .long [[SEC_INDEX]] # Offset reloc section string offset=[[SEC_INDEX]]
+; CHECK: .long 16 # FieldReloc
+; CHECK-NEXT: .long [[SEC_INDEX]] # Field reloc section string offset=[[SEC_INDEX]]
; CHECK-NEXT: .long 2
; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
; CHECK-NEXT: .long {{[0-9]+}}
; CHECK-NEXT: .long [[ACCESS_STR]]
+; CHECK-NEXT: .long 0
; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
; CHECK-NEXT: .long {{[0-9]+}}
; CHECK-NEXT: .long [[ACCESS_STR]]
+; CHECK-NEXT: .long 0
declare dso_local i32 @get_value(i8*, i8*) local_unnamed_addr #1
diff --git a/llvm/test/CodeGen/BPF/CORE/offset-reloc-basic.ll b/llvm/test/CodeGen/BPF/CORE/offset-reloc-basic.ll
index a6fb3a34dde..6c4bbf14ce7 100644
--- a/llvm/test/CodeGen/BPF/CORE/offset-reloc-basic.ll
+++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-basic.ll
@@ -109,17 +109,18 @@ define dso_local i32 @bpf_prog(%struct.sk_buff*) local_unnamed_addr #0 !dbg !15
; CHECK-NEXT: .long 20
; CHECK-NEXT: .long 124
; CHECK-NEXT: .long 144
-; CHECK-NEXT: .long 24
-; CHECK-NEXT: .long 168
+; CHECK-NEXT: .long 28
+; CHECK-NEXT: .long 172
; CHECK-NEXT: .long 0
; CHECK-NEXT: .long 8 # FuncInfo
-; CHECK: .long 12 # OffsetReloc
-; CHECK-NEXT: .long 43 # Offset reloc section string offset=43
+; CHECK: .long 16 # FieldReloc
+; CHECK-NEXT: .long 43 # Field reloc section string offset=43
; CHECK-NEXT: .long 1
; CHECK-NEXT: .long .Ltmp2
; CHECK-NEXT: .long 2
; CHECK-NEXT: .long 86
+; CHECK-NEXT: .long 0
; Function Attrs: argmemonly nounwind
declare void @llvm.lifetime.start.p0i8(i64 immarg, i8* nocapture) #1
diff --git a/llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-array-1.ll b/llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-array-1.ll
index 9e291cd220e..ceda85b0e6e 100644
--- a/llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-array-1.ll
+++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-array-1.ll
@@ -45,15 +45,17 @@ entry:
; CHECK: .ascii "0:1:0" # string offset=52
; CHECK: .ascii "2:1" # string offset=107
-; CHECK: .long 12 # OffsetReloc
-; CHECK-NEXT: .long 46 # Offset reloc section string offset=46
+; CHECK: .long 16 # FieldReloc
+; CHECK-NEXT: .long 46 # Field reloc section string offset=46
; CHECK-NEXT: .long 2
; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
; CHECK-NEXT: .long [[TID1]]
; CHECK-NEXT: .long 52
+; CHECK-NEXT: .long 0
; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
; CHECK-NEXT: .long [[TID2]]
; CHECK-NEXT: .long 107
+; CHECK-NEXT: .long 0
declare dso_local i32 @get_value(i32*) local_unnamed_addr #1
diff --git a/llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-array-2.ll b/llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-array-2.ll
index 7903179dbdb..19a8aa3701e 100644
--- a/llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-array-2.ll
+++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-array-2.ll
@@ -47,15 +47,17 @@ entry:
; CHECK: .ascii "v1" # string offset=100
; CHECK: .ascii "11:1" # string offset=107
-; CHECK: .long 12 # OffsetReloc
-; CHECK-NEXT: .long 46 # Offset reloc section string offset=46
+; CHECK: .long 16 # FieldReloc
+; CHECK-NEXT: .long 46 # Field reloc section string offset=46
; CHECK-NEXT: .long 2
; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
; CHECK-NEXT: .long [[TID1]]
; CHECK-NEXT: .long 52
+; CHECK-NEXT: .long 0
; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
; CHECK-NEXT: .long [[TID2]]
; CHECK-NEXT: .long 107
+; CHECK-NEXT: .long 0
declare dso_local i32 @get_value(i32*) local_unnamed_addr #1
diff --git a/llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-struct-1.ll b/llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-struct-1.ll
index a97c6a039f5..9ec78ddab72 100644
--- a/llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-struct-1.ll
+++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-struct-1.ll
@@ -46,15 +46,17 @@ entry:
; CHECK: .ascii "v1" # string offset=81
; CHECK-NEXT: .byte 0
-; CHECK: .long 12 # OffsetReloc
-; CHECK-NEXT: .long [[SEC_STR]] # Offset reloc section string offset=[[SEC_STR]]
+; CHECK: .long 16 # FieldReloc
+; CHECK-NEXT: .long [[SEC_STR]] # Field reloc section string offset=[[SEC_STR]]
; CHECK-NEXT: .long 2
; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
; CHECK-NEXT: .long [[V3_TID]]
; CHECK-NEXT: .long [[ACCESS_STR]]
+; CHECK-NEXT: .long 0
; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
; CHECK-NEXT: .long [[V1_TID]]
; CHECK-NEXT: .long [[ACCESS_STR]]
+; CHECK-NEXT: .long 0
declare dso_local i32 @get_value(i32*) local_unnamed_addr #1
diff --git a/llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-struct-2.ll b/llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-struct-2.ll
index f65b3f3fd69..ee2b6173307 100644
--- a/llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-struct-2.ll
+++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-struct-2.ll
@@ -46,15 +46,17 @@ entry:
; CHECK: .ascii "v1" # string offset=91
-; CHECK: .long 12 # OffsetReloc
-; CHECK-NEXT: .long 39 # Offset reloc section string offset=39
+; CHECK: .long 16 # FieldReloc
+; CHECK-NEXT: .long 39 # Field reloc section string offset=39
; CHECK-NEXT: .long 2
; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
; CHECK-NEXT: .long [[TID1]]
; CHECK-NEXT: .long 45
+; CHECK-NEXT: .long 0
; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
; CHECK-NEXT: .long [[TID2]]
; CHECK-NEXT: .long 45
+; CHECK-NEXT: .long 0
declare dso_local i32 @get_value(i32*) local_unnamed_addr #1
diff --git a/llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-struct-3.ll b/llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-struct-3.ll
index ed78b84eedf..7b51029f1a0 100644
--- a/llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-struct-3.ll
+++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-struct-3.ll
@@ -45,15 +45,17 @@ entry:
; CHECK: .ascii "v1" # string offset=111
; CHECK: .ascii "0:1" # string offset=118
-; CHECK: .long 12 # OffsetReloc
-; CHECK-NEXT: .long 57 # Offset reloc section string offset=57
+; CHECK: .long 16 # FieldReloc
+; CHECK-NEXT: .long 57 # Field reloc section string offset=57
; CHECK-NEXT: .long 2
; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
; CHECK-NEXT: .long [[TID1]]
; CHECK-NEXT: .long 63
+; CHECK-NEXT: .long 0
; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
; CHECK-NEXT: .long [[TID2]]
; CHECK-NEXT: .long 118
+; CHECK-NEXT: .long 0
declare dso_local i32 @get_value(i32*) local_unnamed_addr #1
diff --git a/llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-union-1.ll b/llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-union-1.ll
index 1e8f99cc6ae..8a6f9089fb3 100644
--- a/llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-union-1.ll
+++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-union-1.ll
@@ -46,15 +46,17 @@ entry:
; CHECK: .ascii "0:1" # string offset=45
; CHECK: .ascii "v1" # string offset=91
-; CHECK: .long 12 # OffsetReloc
-; CHECK-NEXT: .long 39 # Offset reloc section string offset=39
+; CHECK: .long 16 # FieldReloc
+; CHECK-NEXT: .long 39 # Field reloc section string offset=39
; CHECK-NEXT: .long 2
; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
; CHECK-NEXT: .long [[TID1]]
; CHECK-NEXT: .long 45
+; CHECK-NEXT: .long 0
; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
; CHECK-NEXT: .long [[TID2]]
; CHECK-NEXT: .long 45
+; CHECK-NEXT: .long 0
declare dso_local i32 @get_value(i32*) local_unnamed_addr #1
diff --git a/llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-union-2.ll b/llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-union-2.ll
index 320b0a9383b..fd4734bd675 100644
--- a/llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-union-2.ll
+++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-union-2.ll
@@ -47,15 +47,17 @@ entry:
; CHECK: .ascii "v1" # string offset=111
; CHECK: .ascii "0:1" # string offset=118
-; CHECK: .long 12 # OffsetReloc
-; CHECK-NEXT: .long 57 # Offset reloc section string offset=57
+; CHECK: .long 16 # FieldReloc
+; CHECK-NEXT: .long 57 # Field reloc section string offset=57
; CHECK-NEXT: .long 2
; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
; CHECK-NEXT: .long [[TID1]]
; CHECK-NEXT: .long 63
+; CHECK-NEXT: .long 0
; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
; CHECK-NEXT: .long [[TID2]]
; CHECK-NEXT: .long 118
+; CHECK-NEXT: .long 0
declare dso_local i32 @get_value(i32*) local_unnamed_addr #1
diff --git a/llvm/test/CodeGen/BPF/CORE/offset-reloc-end-load.ll b/llvm/test/CodeGen/BPF/CORE/offset-reloc-end-load.ll
index 35415f6d9d3..f175425a0a2 100644
--- a/llvm/test/CodeGen/BPF/CORE/offset-reloc-end-load.ll
+++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-end-load.ll
@@ -30,12 +30,13 @@ entry:
; CHECK: .ascii ".text" # string offset=20
; CHECK: .ascii "0:1" # string offset=26
;
-; CHECK: .long 12 # OffsetReloc
-; CHECK-NEXT: .long 20 # Offset reloc section string offset=20
+; CHECK: .long 16 # FieldReloc
+; CHECK-NEXT: .long 20 # Field reloc section string offset=20
; CHECK-NEXT: .long 1
; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
; CHECK-NEXT: .long 2
; CHECK-NEXT: .long 26
+; CHECK-NEXT: .long 0
; Function Attrs: nounwind readnone
declare i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.ss(%struct.s*, i32, i32) #1
diff --git a/llvm/test/CodeGen/BPF/CORE/offset-reloc-end-ret.ll b/llvm/test/CodeGen/BPF/CORE/offset-reloc-end-ret.ll
index 52a630027e9..f15c9a3dd2b 100644
--- a/llvm/test/CodeGen/BPF/CORE/offset-reloc-end-ret.ll
+++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-end-ret.ll
@@ -30,12 +30,13 @@ entry:
; CHECK: .ascii ".text" # string offset=20
; CHECK: .ascii "0:1" # string offset=63
;
-; CHECK: .long 12 # OffsetReloc
-; CHECK-NEXT: .long 20 # Offset reloc section string offset=20
+; CHECK: .long 16 # FieldReloc
+; CHECK-NEXT: .long 20 # Field reloc section string offset=20
; CHECK-NEXT: .long 1
; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
; CHECK-NEXT: .long 2
; CHECK-NEXT: .long 63
+; CHECK-NEXT: .long 0
; Function Attrs: nounwind readnone
declare i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.ss(%struct.s*, i32, i32) #1
diff --git a/llvm/test/CodeGen/BPF/CORE/offset-reloc-fieldinfo-1.ll b/llvm/test/CodeGen/BPF/CORE/offset-reloc-fieldinfo-1.ll
new file mode 100644
index 00000000000..49982a53959
--- /dev/null
+++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-fieldinfo-1.ll
@@ -0,0 +1,189 @@
+; RUN: llc -march=bpfel -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
+; Source code:
+; struct s {
+; int a;
+; int b1:9;
+; int b2:4;
+; };
+; enum {
+; FIELD_BYTE_OFFSET = 0,
+; FIELD_BYTE_SIZE,
+; FIELD_EXISTENCE,
+; FIELD_SIGNEDNESS,
+; FIELD_LSHIFT_U64,
+; FIELD_RSHIFT_U64,
+; };
+; void bpf_probe_read(void *, unsigned, const void *);
+; int field_read(struct s *arg) {
+; unsigned long long ull;
+; unsigned offset = __builtin_preserve_field_info(arg->b2, FIELD_BYTE_OFFSET);
+; unsigned size = __builtin_preserve_field_info(arg->b2, FIELD_BYTE_SIZE);
+; unsigned lshift;
+;
+; bpf_probe_read(&ull, size, (const void *)arg + offset);
+; lshift = __builtin_preserve_field_info(arg->b2, FIELD_LSHIFT_U64);
+; #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+; lshift = lshift + (size << 3) - 64;
+; #endif
+; ull <<= lshift;
+; if (__builtin_preserve_field_info(arg->b2, FIELD_SIGNEDNESS))
+; return (long long)ull >> __builtin_preserve_field_info(arg->b2, FIELD_RSHIFT_U64);
+; return ull >> __builtin_preserve_field_info(arg->b2, FIELD_RSHIFT_U64);
+; }
+; Compilation flag:
+; clang -target bpfel -O2 -g -S -emit-llvm test.c
+
+%struct.s = type { i32, i16 }
+
+; Function Attrs: nounwind
+define dso_local i32 @field_read(%struct.s* %arg) local_unnamed_addr #0 !dbg !20 {
+entry:
+ %ull = alloca i64, align 8
+ call void @llvm.dbg.value(metadata %struct.s* %arg, metadata !31, metadata !DIExpression()), !dbg !37
+ %0 = bitcast i64* %ull to i8*, !dbg !38
+ call void @llvm.lifetime.start.p0i8(i64 8, i8* nonnull %0) #5, !dbg !38
+ %1 = tail call i16* @llvm.preserve.struct.access.index.p0i16.p0s_struct.ss(%struct.s* %arg, i32 1, i32 2), !dbg !39, !llvm.preserve.access.index !25
+ %2 = tail call i32 @llvm.bpf.preserve.field.info.p0i16(i16* %1, i64 0), !dbg !40
+ call void @llvm.dbg.value(metadata i32 %2, metadata !34, metadata !DIExpression()), !dbg !37
+ %3 = tail call i32 @llvm.bpf.preserve.field.info.p0i16(i16* %1, i64 1), !dbg !41
+ call void @llvm.dbg.value(metadata i32 %3, metadata !35, metadata !DIExpression()), !dbg !37
+ %4 = bitcast %struct.s* %arg to i8*, !dbg !42
+ %idx.ext = zext i32 %2 to i64, !dbg !43
+ %add.ptr = getelementptr i8, i8* %4, i64 %idx.ext, !dbg !43
+ call void @bpf_probe_read(i8* nonnull %0, i32 %3, i8* %add.ptr) #5, !dbg !44
+ %5 = call i32 @llvm.bpf.preserve.field.info.p0i16(i16* %1, i64 4), !dbg !45
+ call void @llvm.dbg.value(metadata i32 %5, metadata !36, metadata !DIExpression()), !dbg !37
+ %6 = load i64, i64* %ull, align 8, !dbg !46, !tbaa !47
+ call void @llvm.dbg.value(metadata i64 %6, metadata !32, metadata !DIExpression()), !dbg !37
+ %sh_prom = zext i32 %5 to i64, !dbg !46
+ %shl = shl i64 %6, %sh_prom, !dbg !46
+ call void @llvm.dbg.value(metadata i64 %shl, metadata !32, metadata !DIExpression()), !dbg !37
+ %7 = call i32 @llvm.bpf.preserve.field.info.p0i16(i16* %1, i64 3), !dbg !51
+ %tobool = icmp eq i32 %7, 0, !dbg !51
+ %8 = call i32 @llvm.bpf.preserve.field.info.p0i16(i16* %1, i64 5), !dbg !37
+ %sh_prom1 = zext i32 %8 to i64, !dbg !37
+ %shr = ashr i64 %shl, %sh_prom1, !dbg !53
+ %shr3 = lshr i64 %shl, %sh_prom1, !dbg !53
+ %retval.0.in = select i1 %tobool, i64 %shr3, i64 %shr, !dbg !53
+ %retval.0 = trunc i64 %retval.0.in to i32, !dbg !37
+ call void @llvm.lifetime.end.p0i8(i64 8, i8* nonnull %0) #5, !dbg !54
+ ret i32 %retval.0, !dbg !54
+}
+
+; CHECK: r{{[0-9]+}} = 4
+; CHECK: r{{[0-9]+}} = 4
+; CHECK: r{{[0-9]+}} = 51
+; CHECK: r{{[0-9]+}} = 60
+; CHECK: r{{[0-9]+}} = 1
+
+; CHECK: .byte 115 # string offset=1
+; CHECK: .ascii ".text" # string offset=30
+; CHECK: .ascii "0:2" # string offset=73
+
+; CHECK: .long 16 # FieldReloc
+; CHECK-NEXT: .long 30 # Field reloc section string offset=30
+; CHECK-NEXT: .long 5
+; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
+; CHECK-NEXT: .long 2
+; CHECK-NEXT: .long 73
+; CHECK-NEXT: .long 0
+; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
+; CHECK-NEXT: .long 2
+; CHECK-NEXT: .long 73
+; CHECK-NEXT: .long 1
+; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
+; CHECK-NEXT: .long 2
+; CHECK-NEXT: .long 73
+; CHECK-NEXT: .long 4
+; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
+; CHECK-NEXT: .long 2
+; CHECK-NEXT: .long 73
+; CHECK-NEXT: .long 5
+; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
+; CHECK-NEXT: .long 2
+; CHECK-NEXT: .long 73
+; CHECK-NEXT: .long 3
+
+; Function Attrs: argmemonly nounwind willreturn
+declare void @llvm.lifetime.start.p0i8(i64, i8* nocapture) #1
+
+; Function Attrs: nounwind readnone
+declare i16* @llvm.preserve.struct.access.index.p0i16.p0s_struct.ss(%struct.s*, i32, i32) #2
+
+; Function Attrs: nounwind readnone
+declare i32 @llvm.bpf.preserve.field.info.p0i16(i16*, i64) #2
+
+declare dso_local void @bpf_probe_read(i8*, i32, i8*) local_unnamed_addr #3
+
+; Function Attrs: argmemonly nounwind willreturn
+declare void @llvm.lifetime.end.p0i8(i64, i8* nocapture) #1
+
+; Function Attrs: nounwind readnone speculatable willreturn
+declare void @llvm.dbg.value(metadata, metadata, metadata) #4
+
+attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { argmemonly nounwind willreturn }
+attributes #2 = { nounwind readnone }
+attributes #3 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #4 = { nounwind readnone speculatable willreturn }
+attributes #5 = { nounwind }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!16, !17, !18}
+!llvm.ident = !{!19}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (https://github.com/llvm/llvm-project.git 923aa0ce806f7739b754167239fee2c9a15e2f31)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !12, nameTableKind: None)
+!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/core")
+!2 = !{!3}
+!3 = !DICompositeType(tag: DW_TAG_enumeration_type, file: !1, line: 6, baseType: !4, size: 32, elements: !5)
+!4 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned)
+!5 = !{!6, !7, !8, !9, !10, !11}
+!6 = !DIEnumerator(name: "FIELD_BYTE_OFFSET", value: 0, isUnsigned: true)
+!7 = !DIEnumerator(name: "FIELD_BYTE_SIZE", value: 1, isUnsigned: true)
+!8 = !DIEnumerator(name: "FIELD_EXISTENCE", value: 2, isUnsigned: true)
+!9 = !DIEnumerator(name: "FIELD_SIGNEDNESS", value: 3, isUnsigned: true)
+!10 = !DIEnumerator(name: "FIELD_LSHIFT_U64", value: 4, isUnsigned: true)
+!11 = !DIEnumerator(name: "FIELD_RSHIFT_U64", value: 5, isUnsigned: true)
+!12 = !{!13, !15}
+!13 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !14, size: 64)
+!14 = !DIDerivedType(tag: DW_TAG_const_type, baseType: null)
+!15 = !DIBasicType(name: "long long int", size: 64, encoding: DW_ATE_signed)
+!16 = !{i32 2, !"Dwarf Version", i32 4}
+!17 = !{i32 2, !"Debug Info Version", i32 3}
+!18 = !{i32 1, !"wchar_size", i32 4}
+!19 = !{!"clang version 10.0.0 (https://github.com/llvm/llvm-project.git 923aa0ce806f7739b754167239fee2c9a15e2f31)"}
+!20 = distinct !DISubprogram(name: "field_read", scope: !1, file: !1, line: 15, type: !21, scopeLine: 15, flags: DIFlagPrototyped, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !30)
+!21 = !DISubroutineType(types: !22)
+!22 = !{!23, !24}
+!23 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!24 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !25, size: 64)
+!25 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "s", file: !1, line: 1, size: 64, elements: !26)
+!26 = !{!27, !28, !29}
+!27 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !25, file: !1, line: 2, baseType: !23, size: 32)
+!28 = !DIDerivedType(tag: DW_TAG_member, name: "b1", scope: !25, file: !1, line: 3, baseType: !23, size: 9, offset: 32, flags: DIFlagBitField, extraData: i64 32)
+!29 = !DIDerivedType(tag: DW_TAG_member, name: "b2", scope: !25, file: !1, line: 4, baseType: !23, size: 4, offset: 41, flags: DIFlagBitField, extraData: i64 32)
+!30 = !{!31, !32, !34, !35, !36}
+!31 = !DILocalVariable(name: "arg", arg: 1, scope: !20, file: !1, line: 15, type: !24)
+!32 = !DILocalVariable(name: "ull", scope: !20, file: !1, line: 16, type: !33)
+!33 = !DIBasicType(name: "long long unsigned int", size: 64, encoding: DW_ATE_unsigned)
+!34 = !DILocalVariable(name: "offset", scope: !20, file: !1, line: 17, type: !4)
+!35 = !DILocalVariable(name: "size", scope: !20, file: !1, line: 18, type: !4)
+!36 = !DILocalVariable(name: "lshift", scope: !20, file: !1, line: 19, type: !4)
+!37 = !DILocation(line: 0, scope: !20)
+!38 = !DILocation(line: 16, column: 3, scope: !20)
+!39 = !DILocation(line: 17, column: 56, scope: !20)
+!40 = !DILocation(line: 17, column: 21, scope: !20)
+!41 = !DILocation(line: 18, column: 19, scope: !20)
+!42 = !DILocation(line: 21, column: 30, scope: !20)
+!43 = !DILocation(line: 21, column: 48, scope: !20)
+!44 = !DILocation(line: 21, column: 3, scope: !20)
+!45 = !DILocation(line: 22, column: 12, scope: !20)
+!46 = !DILocation(line: 26, column: 7, scope: !20)
+!47 = !{!48, !48, i64 0}
+!48 = !{!"long long", !49, i64 0}
+!49 = !{!"omnipotent char", !50, i64 0}
+!50 = !{!"Simple C/C++ TBAA"}
+!51 = !DILocation(line: 27, column: 7, scope: !52)
+!52 = distinct !DILexicalBlock(scope: !20, file: !1, line: 27, column: 7)
+!53 = !DILocation(line: 27, column: 7, scope: !20)
+!54 = !DILocation(line: 30, column: 1, scope: !20)
diff --git a/llvm/test/CodeGen/BPF/CORE/offset-reloc-fieldinfo-2.ll b/llvm/test/CodeGen/BPF/CORE/offset-reloc-fieldinfo-2.ll
new file mode 100644
index 00000000000..96680c91e72
--- /dev/null
+++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-fieldinfo-2.ll
@@ -0,0 +1,246 @@
+; RUN: llc -march=bpfel -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK,CHECK-EL %s
+; RUN: llc -march=bpfeb -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK,CHECK-EB %s
+; Source code:
+; struct s {
+; int a;
+; int b1:9;
+; int b2:4;
+; };
+; enum {
+; FIELD_BYTE_OFFSET = 0,
+; FIELD_BYTE_SIZE,
+; FIELD_EXISTENCE,
+; FIELD_SIGNEDNESS,
+; FIELD_LSHIFT_U64,
+; FIELD_RSHIFT_U64,
+; };
+; int field_read(struct s *arg) {
+; unsigned long long ull;
+; unsigned offset = __builtin_preserve_field_info(arg->b2, FIELD_BYTE_OFFSET);
+; unsigned size = __builtin_preserve_field_info(arg->b2, FIELD_BYTE_SIZE);
+; switch(size) {
+; case 1:
+; ull = *(unsigned char *)((void *)arg + offset); break;
+; case 2:
+; ull = *(unsigned short *)((void *)arg + offset); break;
+; case 4:
+; ull = *(unsigned int *)((void *)arg + offset); break;
+; case 8:
+; ull = *(unsigned long long *)((void *)arg + offset); break;
+; }
+; ull <<= __builtin_preserve_field_info(arg->b2, FIELD_LSHIFT_U64);
+; if (__builtin_preserve_field_info(arg->b2, FIELD_SIGNEDNESS))
+; return ((long long)ull) >>__builtin_preserve_field_info(arg->b2, FIELD_RSHIFT_U64);
+; return ull >> __builtin_preserve_field_info(arg->b2, FIELD_RSHIFT_U64);
+; }
+; Compilation flag:
+; clang -target bpf -O2 -g -S -emit-llvm test.c
+
+%struct.s = type { i32, i16 }
+
+; Function Attrs: nounwind readonly
+define dso_local i32 @field_read(%struct.s* %arg) local_unnamed_addr #0 !dbg !26 {
+entry:
+ call void @llvm.dbg.value(metadata %struct.s* %arg, metadata !37, metadata !DIExpression()), !dbg !41
+ %0 = tail call i16* @llvm.preserve.struct.access.index.p0i16.p0s_struct.ss(%struct.s* %arg, i32 1, i32 2), !dbg !42, !llvm.preserve.access.index !31
+ %1 = tail call i32 @llvm.bpf.preserve.field.info.p0i16(i16* %0, i64 0), !dbg !43
+ call void @llvm.dbg.value(metadata i32 %1, metadata !39, metadata !DIExpression()), !dbg !41
+ %2 = tail call i32 @llvm.bpf.preserve.field.info.p0i16(i16* %0, i64 1), !dbg !44
+ call void @llvm.dbg.value(metadata i32 %2, metadata !40, metadata !DIExpression()), !dbg !41
+ switch i32 %2, label %sw.epilog [
+ i32 1, label %sw.bb
+ i32 2, label %sw.bb1
+ i32 4, label %sw.bb5
+ i32 8, label %sw.bb9
+ ], !dbg !45
+
+sw.bb: ; preds = %entry
+ %3 = bitcast %struct.s* %arg to i8*, !dbg !46
+ %idx.ext = zext i32 %1 to i64, !dbg !48
+ %add.ptr = getelementptr i8, i8* %3, i64 %idx.ext, !dbg !48
+ %4 = load i8, i8* %add.ptr, align 1, !dbg !49, !tbaa !50
+ %conv = zext i8 %4 to i64, !dbg !49
+ call void @llvm.dbg.value(metadata i64 %conv, metadata !38, metadata !DIExpression()), !dbg !41
+ br label %sw.epilog, !dbg !53
+
+sw.bb1: ; preds = %entry
+ %5 = bitcast %struct.s* %arg to i8*, !dbg !54
+ %idx.ext2 = zext i32 %1 to i64, !dbg !55
+ %add.ptr3 = getelementptr i8, i8* %5, i64 %idx.ext2, !dbg !55
+ %6 = bitcast i8* %add.ptr3 to i16*, !dbg !56
+ %7 = load i16, i16* %6, align 2, !dbg !57, !tbaa !58
+ %conv4 = zext i16 %7 to i64, !dbg !57
+ call void @llvm.dbg.value(metadata i64 %conv4, metadata !38, metadata !DIExpression()), !dbg !41
+ br label %sw.epilog, !dbg !60
+
+sw.bb5: ; preds = %entry
+ %8 = bitcast %struct.s* %arg to i8*, !dbg !61
+ %idx.ext6 = zext i32 %1 to i64, !dbg !62
+ %add.ptr7 = getelementptr i8, i8* %8, i64 %idx.ext6, !dbg !62
+ %9 = bitcast i8* %add.ptr7 to i32*, !dbg !63
+ %10 = load i32, i32* %9, align 4, !dbg !64, !tbaa !65
+ %conv8 = zext i32 %10 to i64, !dbg !64
+ call void @llvm.dbg.value(metadata i64 %conv8, metadata !38, metadata !DIExpression()), !dbg !41
+ br label %sw.epilog, !dbg !67
+
+sw.bb9: ; preds = %entry
+ %11 = bitcast %struct.s* %arg to i8*, !dbg !68
+ %idx.ext10 = zext i32 %1 to i64, !dbg !69
+ %add.ptr11 = getelementptr i8, i8* %11, i64 %idx.ext10, !dbg !69
+ %12 = bitcast i8* %add.ptr11 to i64*, !dbg !70
+ %13 = load i64, i64* %12, align 8, !dbg !71, !tbaa !72
+ call void @llvm.dbg.value(metadata i64 %13, metadata !38, metadata !DIExpression()), !dbg !41
+ br label %sw.epilog, !dbg !74
+
+sw.epilog: ; preds = %entry, %sw.bb9, %sw.bb5, %sw.bb1, %sw.bb
+ %ull.0 = phi i64 [ undef, %entry ], [ %13, %sw.bb9 ], [ %conv8, %sw.bb5 ], [ %conv4, %sw.bb1 ], [ %conv, %sw.bb ]
+ call void @llvm.dbg.value(metadata i64 %ull.0, metadata !38, metadata !DIExpression()), !dbg !41
+ %14 = tail call i32 @llvm.bpf.preserve.field.info.p0i16(i16* %0, i64 4), !dbg !75
+ %sh_prom = zext i32 %14 to i64, !dbg !76
+ %shl = shl i64 %ull.0, %sh_prom, !dbg !76
+ call void @llvm.dbg.value(metadata i64 %shl, metadata !38, metadata !DIExpression()), !dbg !41
+ %15 = tail call i32 @llvm.bpf.preserve.field.info.p0i16(i16* %0, i64 3), !dbg !77
+ %tobool = icmp eq i32 %15, 0, !dbg !77
+ %16 = tail call i32 @llvm.bpf.preserve.field.info.p0i16(i16* %0, i64 5), !dbg !41
+ %sh_prom12 = zext i32 %16 to i64, !dbg !41
+ %shr = ashr i64 %shl, %sh_prom12, !dbg !79
+ %shr15 = lshr i64 %shl, %sh_prom12, !dbg !79
+ %retval.0.in = select i1 %tobool, i64 %shr15, i64 %shr, !dbg !79
+ %retval.0 = trunc i64 %retval.0.in to i32, !dbg !41
+ ret i32 %retval.0, !dbg !80
+}
+
+; CHECK: r{{[0-9]+}} = 4
+; CHECK: r{{[0-9]+}} = 4
+; CHECK-EL: r{{[0-9]+}} = 51
+; CHECK-EB: r{{[0-9]+}} = 41
+; CHECK: r{{[0-9]+}} = 60
+; CHECK: r{{[0-9]+}} = 1
+
+; CHECK: .long 1 # BTF_KIND_STRUCT(id = 2)
+; CHECK: .byte 115 # string offset=1
+; CHECK: .ascii ".text" # string offset=30
+; CHECK: .ascii "0:2" # string offset=36
+
+; CHECK: .long 16 # FieldReloc
+; CHECK-NEXT: .long 30 # Field reloc section string offset=30
+; CHECK-NEXT: .long 5
+; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
+; CHECK-NEXT: .long 2
+; CHECK-NEXT: .long 36
+; CHECK-NEXT: .long 0
+; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
+; CHECK-NEXT: .long 2
+; CHECK-NEXT: .long 36
+; CHECK-NEXT: .long 1
+; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
+; CHECK-NEXT: .long 2
+; CHECK-NEXT: .long 36
+; CHECK-NEXT: .long 4
+; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
+; CHECK-NEXT: .long 2
+; CHECK-NEXT: .long 36
+; CHECK-NEXT: .long 5
+; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
+; CHECK-NEXT: .long 2
+; CHECK-NEXT: .long 36
+; CHECK-NEXT: .long 3
+
+; Function Attrs: nounwind readnone
+declare i16* @llvm.preserve.struct.access.index.p0i16.p0s_struct.ss(%struct.s*, i32, i32) #1
+
+; Function Attrs: nounwind readnone
+declare i32 @llvm.bpf.preserve.field.info.p0i16(i16*, i64) #1
+
+; Function Attrs: nounwind readnone speculatable willreturn
+declare void @llvm.dbg.value(metadata, metadata, metadata) #2
+
+attributes #0 = { nounwind readonly "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { nounwind readnone }
+attributes #2 = { nounwind readnone speculatable willreturn }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!22, !23, !24}
+!llvm.ident = !{!25}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (https://github.com/llvm/llvm-project.git 923aa0ce806f7739b754167239fee2c9a15e2f31)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !12, nameTableKind: None)
+!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/core")
+!2 = !{!3}
+!3 = !DICompositeType(tag: DW_TAG_enumeration_type, file: !1, line: 6, baseType: !4, size: 32, elements: !5)
+!4 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned)
+!5 = !{!6, !7, !8, !9, !10, !11}
+!6 = !DIEnumerator(name: "FIELD_BYTE_OFFSET", value: 0, isUnsigned: true)
+!7 = !DIEnumerator(name: "FIELD_BYTE_SIZE", value: 1, isUnsigned: true)
+!8 = !DIEnumerator(name: "FIELD_EXISTENCE", value: 2, isUnsigned: true)
+!9 = !DIEnumerator(name: "FIELD_SIGNEDNESS", value: 3, isUnsigned: true)
+!10 = !DIEnumerator(name: "FIELD_LSHIFT_U64", value: 4, isUnsigned: true)
+!11 = !DIEnumerator(name: "FIELD_RSHIFT_U64", value: 5, isUnsigned: true)
+!12 = !{!13, !15, !16, !18, !19, !21}
+!13 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !14, size: 64)
+!14 = !DIBasicType(name: "unsigned char", size: 8, encoding: DW_ATE_unsigned_char)
+!15 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 64)
+!16 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !17, size: 64)
+!17 = !DIBasicType(name: "unsigned short", size: 16, encoding: DW_ATE_unsigned)
+!18 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !4, size: 64)
+!19 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !20, size: 64)
+!20 = !DIBasicType(name: "long long unsigned int", size: 64, encoding: DW_ATE_unsigned)
+!21 = !DIBasicType(name: "long long int", size: 64, encoding: DW_ATE_signed)
+!22 = !{i32 2, !"Dwarf Version", i32 4}
+!23 = !{i32 2, !"Debug Info Version", i32 3}
+!24 = !{i32 1, !"wchar_size", i32 4}
+!25 = !{!"clang version 10.0.0 (https://github.com/llvm/llvm-project.git 923aa0ce806f7739b754167239fee2c9a15e2f31)"}
+!26 = distinct !DISubprogram(name: "field_read", scope: !1, file: !1, line: 14, type: !27, scopeLine: 14, flags: DIFlagPrototyped, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !36)
+!27 = !DISubroutineType(types: !28)
+!28 = !{!29, !30}
+!29 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!30 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !31, size: 64)
+!31 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "s", file: !1, line: 1, size: 64, elements: !32)
+!32 = !{!33, !34, !35}
+!33 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !31, file: !1, line: 2, baseType: !29, size: 32)
+!34 = !DIDerivedType(tag: DW_TAG_member, name: "b1", scope: !31, file: !1, line: 3, baseType: !29, size: 9, offset: 32, flags: DIFlagBitField, extraData: i64 32)
+!35 = !DIDerivedType(tag: DW_TAG_member, name: "b2", scope: !31, file: !1, line: 4, baseType: !29, size: 4, offset: 41, flags: DIFlagBitField, extraData: i64 32)
+!36 = !{!37, !38, !39, !40}
+!37 = !DILocalVariable(name: "arg", arg: 1, scope: !26, file: !1, line: 14, type: !30)
+!38 = !DILocalVariable(name: "ull", scope: !26, file: !1, line: 15, type: !20)
+!39 = !DILocalVariable(name: "offset", scope: !26, file: !1, line: 16, type: !4)
+!40 = !DILocalVariable(name: "size", scope: !26, file: !1, line: 17, type: !4)
+!41 = !DILocation(line: 0, scope: !26)
+!42 = !DILocation(line: 16, column: 56, scope: !26)
+!43 = !DILocation(line: 16, column: 21, scope: !26)
+!44 = !DILocation(line: 17, column: 19, scope: !26)
+!45 = !DILocation(line: 18, column: 3, scope: !26)
+!46 = !DILocation(line: 20, column: 30, scope: !47)
+!47 = distinct !DILexicalBlock(scope: !26, file: !1, line: 18, column: 16)
+!48 = !DILocation(line: 20, column: 42, scope: !47)
+!49 = !DILocation(line: 20, column: 11, scope: !47)
+!50 = !{!51, !51, i64 0}
+!51 = !{!"omnipotent char", !52, i64 0}
+!52 = !{!"Simple C/C++ TBAA"}
+!53 = !DILocation(line: 20, column: 53, scope: !47)
+!54 = !DILocation(line: 22, column: 31, scope: !47)
+!55 = !DILocation(line: 22, column: 43, scope: !47)
+!56 = !DILocation(line: 22, column: 12, scope: !47)
+!57 = !DILocation(line: 22, column: 11, scope: !47)
+!58 = !{!59, !59, i64 0}
+!59 = !{!"short", !51, i64 0}
+!60 = !DILocation(line: 22, column: 54, scope: !47)
+!61 = !DILocation(line: 24, column: 29, scope: !47)
+!62 = !DILocation(line: 24, column: 41, scope: !47)
+!63 = !DILocation(line: 24, column: 12, scope: !47)
+!64 = !DILocation(line: 24, column: 11, scope: !47)
+!65 = !{!66, !66, i64 0}
+!66 = !{!"int", !51, i64 0}
+!67 = !DILocation(line: 24, column: 52, scope: !47)
+!68 = !DILocation(line: 26, column: 35, scope: !47)
+!69 = !DILocation(line: 26, column: 47, scope: !47)
+!70 = !DILocation(line: 26, column: 12, scope: !47)
+!71 = !DILocation(line: 26, column: 11, scope: !47)
+!72 = !{!73, !73, i64 0}
+!73 = !{!"long long", !51, i64 0}
+!74 = !DILocation(line: 26, column: 58, scope: !47)
+!75 = !DILocation(line: 28, column: 11, scope: !26)
+!76 = !DILocation(line: 28, column: 7, scope: !26)
+!77 = !DILocation(line: 29, column: 7, scope: !78)
+!78 = distinct !DILexicalBlock(scope: !26, file: !1, line: 29, column: 7)
+!79 = !DILocation(line: 29, column: 7, scope: !26)
+!80 = !DILocation(line: 32, column: 1, scope: !26)
diff --git a/llvm/test/CodeGen/BPF/CORE/offset-reloc-global-1.ll b/llvm/test/CodeGen/BPF/CORE/offset-reloc-global-1.ll
index 296e2d434a2..e83b3294090 100644
--- a/llvm/test/CodeGen/BPF/CORE/offset-reloc-global-1.ll
+++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-global-1.ll
@@ -34,12 +34,13 @@ entry:
; CHECK: .ascii "v3" # string offset=16
; CHECK: .ascii "0:1" # string offset=23
-; CHECK: .long 12 # OffsetReloc
-; CHECK-NEXT: .long 10 # Offset reloc section string offset=10
+; CHECK: .long 16 # FieldReloc
+; CHECK-NEXT: .long 10 # Field reloc section string offset=10
; CHECK-NEXT: .long 1
; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
; CHECK-NEXT: .long [[TID1]]
; CHECK-NEXT: .long 23
+; CHECK-NEXT: .long 0
declare dso_local i32 @get_value(i32*) local_unnamed_addr #1
diff --git a/llvm/test/CodeGen/BPF/CORE/offset-reloc-global-2.ll b/llvm/test/CodeGen/BPF/CORE/offset-reloc-global-2.ll
index 721081e29d2..66e8e66d083 100644
--- a/llvm/test/CodeGen/BPF/CORE/offset-reloc-global-2.ll
+++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-global-2.ll
@@ -36,12 +36,13 @@ entry:
; CHECK: .ascii "v3" # string offset=16
; CHECK: .ascii "7:1" # string offset=23
-; CHECK: .long 12 # OffsetReloc
-; CHECK-NEXT: .long 10 # Offset reloc section string offset=10
+; CHECK: .long 16 # FieldReloc
+; CHECK-NEXT: .long 10 # Field reloc section string offset=10
; CHECK-NEXT: .long 1
; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
; CHECK-NEXT: .long [[TID1]]
; CHECK-NEXT: .long 23
+; CHECK-NEXT: .long 0
declare dso_local i32 @get_value(i32*) local_unnamed_addr #1
diff --git a/llvm/test/CodeGen/BPF/CORE/offset-reloc-global-3.ll b/llvm/test/CodeGen/BPF/CORE/offset-reloc-global-3.ll
index 394d04f9f81..13c70fd4055 100644
--- a/llvm/test/CodeGen/BPF/CORE/offset-reloc-global-3.ll
+++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-global-3.ll
@@ -34,12 +34,13 @@ entry:
; CHECK: .ascii "v3" # string offset=16
; CHECK: .ascii "0:1" # string offset=23
-; CHECK: .long 12 # OffsetReloc
-; CHECK-NEXT: .long 10 # Offset reloc section string offset=10
+; CHECK: .long 16 # FieldReloc
+; CHECK-NEXT: .long 10 # Field reloc section string offset=10
; CHECK-NEXT: .long 1
; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
; CHECK-NEXT: .long [[TID1]]
; CHECK-NEXT: .long 23
+; CHECK-NEXT: .long 0
declare dso_local i32 @get_value(i32*) local_unnamed_addr #1
diff --git a/llvm/test/CodeGen/BPF/CORE/offset-reloc-ignore.ll b/llvm/test/CodeGen/BPF/CORE/offset-reloc-ignore.ll
index 2d14e7157b4..4646377cfbf 100644
--- a/llvm/test/CodeGen/BPF/CORE/offset-reloc-ignore.ll
+++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-ignore.ll
@@ -21,7 +21,7 @@ entry:
; CHECK: r1 += 16
; CHECK: call get_value
; CHECK: .section .BTF.ext,"",@progbits
-; CHECK-NOT: .long 12 # OffsetReloc
+; CHECK-NOT: .long 16 # FieldReloc
declare dso_local i32 @get_value(i32*) local_unnamed_addr #1
diff --git a/llvm/test/CodeGen/BPF/CORE/offset-reloc-middle-chain.ll b/llvm/test/CodeGen/BPF/CORE/offset-reloc-middle-chain.ll
index 0f75cd81242..14e58d7c97a 100644
--- a/llvm/test/CodeGen/BPF/CORE/offset-reloc-middle-chain.ll
+++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-middle-chain.ll
@@ -50,18 +50,21 @@ entry:
; CHECK: .ascii "0:0:0" # string offset=76
; CHECK: .ascii "0:0:0:0" # string offset=82
-; CHECK: .long 12 # OffsetReloc
-; CHECK-NEXT: .long 29 # Offset reloc section string offset=29
+; CHECK: .long 16 # FieldReloc
+; CHECK-NEXT: .long 29 # Field reloc section string offset=29
; CHECK-NEXT: .long 3
; CHECK_NEXT: .long .Ltmp{{[0-9]+}}
; CHECK_NEXT: .long 2
; CHECK_NEXT: .long 72
+; CHECK_NEXT: .long 0
; CHECK_NEXT: .long .Ltmp{{[0-9]+}}
; CHECK_NEXT: .long 2
; CHECK_NEXT: .long 76
+; CHECK_NEXT: .long 0
; CHECK_NEXT: .long .Ltmp{{[0-9]+}}
; CHECK_NEXT: .long 2
; CHECK_NEXT: .long 82
+; CHECK_NEXT: .long 0
; Function Attrs: nounwind readnone
declare %struct.s1* @llvm.preserve.struct.access.index.p0s_struct.s1s.p0s_struct.r1s(%struct.r1*, i32, i32) #1
diff --git a/llvm/test/CodeGen/BPF/CORE/offset-reloc-multi-array-1.ll b/llvm/test/CodeGen/BPF/CORE/offset-reloc-multi-array-1.ll
index 7f79196f9eb..61ff0f69f39 100644
--- a/llvm/test/CodeGen/BPF/CORE/offset-reloc-multi-array-1.ll
+++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-multi-array-1.ll
@@ -35,12 +35,13 @@ entry:
; CHECK: .ascii ".text" # string offset=52
; CHECK: .ascii "1:1:2:3" # string offset=58
-; CHECK: .long 12 # OffsetReloc
-; CHECK-NEXT: .long 52 # Offset reloc section string offset=52
+; CHECK: .long 16 # FieldReloc
+; CHECK-NEXT: .long 52 # Field reloc section string offset=52
; CHECK-NEXT: .long 1
; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
; CHECK-NEXT: .long [[TID1]]
; CHECK-NEXT: .long 58
+; CHECK-NEXT: .long 0
declare dso_local i32 @get_value(i32*) local_unnamed_addr #1
diff --git a/llvm/test/CodeGen/BPF/CORE/offset-reloc-multi-array-2.ll b/llvm/test/CodeGen/BPF/CORE/offset-reloc-multi-array-2.ll
index a9c29aa6b7c..612c3d2af27 100644
--- a/llvm/test/CodeGen/BPF/CORE/offset-reloc-multi-array-2.ll
+++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-multi-array-2.ll
@@ -36,12 +36,13 @@ entry:
; CHECK: .ascii ".text" # string offset=52
; CHECK: .ascii "1:1:2:3:2" # string offset=58
-; CHECK: .long 12 # OffsetReloc
-; CHECK-NEXT: .long 52 # Offset reloc section string offset=52
+; CHECK: .long 16 # FieldReloc
+; CHECK-NEXT: .long 52 # Field reloc section string offset=52
; CHECK-NEXT: .long 1
; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
; CHECK-NEXT: .long [[TID1]]
; CHECK-NEXT: .long 58
+; CHECK-NEXT: .long 0
declare dso_local i32 @get_value(i32*) local_unnamed_addr #1
diff --git a/llvm/test/CodeGen/BPF/CORE/offset-reloc-multilevel.ll b/llvm/test/CodeGen/BPF/CORE/offset-reloc-multilevel.ll
index 779b395299d..120b85d8687 100644
--- a/llvm/test/CodeGen/BPF/CORE/offset-reloc-multilevel.ll
+++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-multilevel.ll
@@ -117,17 +117,18 @@ define dso_local i32 @bpf_prog(%struct.sk_buff*) local_unnamed_addr #0 !dbg !15
; CHECK-NEXT: .long 20
; CHECK-NEXT: .long 76
; CHECK-NEXT: .long 96
-; CHECK-NEXT: .long 24
-; CHECK-NEXT: .long 120
+; CHECK-NEXT: .long 28
+; CHECK-NEXT: .long 124
; CHECK-NEXT: .long 0
; CHECK-NEXT: .long 8 # FuncInfo
-; CHECK: .long 12 # OffsetReloc
-; CHECK-NEXT: .long 57 # Offset reloc section string offset=57
+; CHECK: .long 16 # FieldReloc
+; CHECK-NEXT: .long 57 # Field reloc section string offset=57
; CHECK-NEXT: .long 1
; CHECK-NEXT: .long .Ltmp2
; CHECK-NEXT: .long 2
; CHECK-NEXT: .long 100
+; CHECK-NEXT: .long 0
; Function Attrs: argmemonly nounwind
declare void @llvm.lifetime.start.p0i8(i64 immarg, i8* nocapture) #1
diff --git a/llvm/test/CodeGen/BPF/CORE/offset-reloc-pointer-1.ll b/llvm/test/CodeGen/BPF/CORE/offset-reloc-pointer-1.ll
index e85b3934e5a..4d8875c3341 100644
--- a/llvm/test/CodeGen/BPF/CORE/offset-reloc-pointer-1.ll
+++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-pointer-1.ll
@@ -32,12 +32,13 @@ entry:
; CHECK: .ascii ".text" # string offset=26
; CHECK: .byte 49 # string offset=32
-; CHECK: .long 12 # OffsetReloc
-; CHECK-NEXT: .long 26 # Offset reloc section string offset=26
+; CHECK: .long 16 # FieldReloc
+; CHECK-NEXT: .long 26 # Field reloc section string offset=26
; CHECK-NEXT: .long 1
; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
; CHECK-NEXT: .long [[TID1]]
; CHECK-NEXT: .long 32
+; CHECK-NEXT: .long 0
declare dso_local i32 @get_value(i32*) local_unnamed_addr #1
diff --git a/llvm/test/CodeGen/BPF/CORE/offset-reloc-pointer-2.ll b/llvm/test/CodeGen/BPF/CORE/offset-reloc-pointer-2.ll
index 1c54935902d..35279023aa3 100644
--- a/llvm/test/CodeGen/BPF/CORE/offset-reloc-pointer-2.ll
+++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-pointer-2.ll
@@ -31,12 +31,13 @@ entry:
; CHECK: .ascii ".text" # string offset=26
; CHECK: .ascii "1:1" # string offset=32
-; CHECK: .long 12 # OffsetReloc
-; CHECK-NEXT: .long 26 # Offset reloc section string offset=26
+; CHECK: .long 16 # FieldReloc
+; CHECK-NEXT: .long 26 # Field reloc section string offset=26
; CHECK-NEXT: .long 1
; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
; CHECK-NEXT: .long [[TID1]]
; CHECK-NEXT: .long 32
+; CHECK-NEXT: .long 0
declare dso_local i32 @get_value(i32*) local_unnamed_addr #1
diff --git a/llvm/test/CodeGen/BPF/CORE/offset-reloc-struct-anonymous.ll b/llvm/test/CodeGen/BPF/CORE/offset-reloc-struct-anonymous.ll
index 08a204f7789..f77152b448b 100644
--- a/llvm/test/CodeGen/BPF/CORE/offset-reloc-struct-anonymous.ll
+++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-struct-anonymous.ll
@@ -127,17 +127,18 @@ define dso_local i32 @bpf_prog(%struct.sk_buff*) local_unnamed_addr #0 !dbg !15
; CHECK-NEXT: .long 20
; CHECK-NEXT: .long 76
; CHECK-NEXT: .long 96
-; CHECK-NEXT: .long 24
-; CHECK-NEXT: .long 120
+; CHECK-NEXT: .long 28
+; CHECK-NEXT: .long 124
; CHECK-NEXT: .long 0
; CHECK-NEXT: .long 8 # FuncInfo
-; CHECK: .long 12 # OffsetReloc
-; CHECK-NEXT: .long 66 # Offset reloc section string offset=66
+; CHECK: .long 16 # FieldReloc
+; CHECK-NEXT: .long 66 # Field reloc section string offset=66
; CHECK-NEXT: .long 1
; CHECK-NEXT: .long .Ltmp2
; CHECK-NEXT: .long 2
; CHECK-NEXT: .long 109
+; CHECK-NEXT: .long 0
; Function Attrs: argmemonly nounwind
declare void @llvm.lifetime.start.p0i8(i64 immarg, i8* nocapture) #1
diff --git a/llvm/test/CodeGen/BPF/CORE/offset-reloc-struct-array.ll b/llvm/test/CodeGen/BPF/CORE/offset-reloc-struct-array.ll
index b18a4ab37f4..a56b8fd8409 100644
--- a/llvm/test/CodeGen/BPF/CORE/offset-reloc-struct-array.ll
+++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-struct-array.ll
@@ -130,17 +130,18 @@ define dso_local i32 @bpf_prog(%struct.sk_buff*) local_unnamed_addr #0 !dbg !15
; CHECK-NEXT: .long 20
; CHECK-NEXT: .long 76
; CHECK-NEXT: .long 96
-; CHECK-NEXT: .long 24
-; CHECK-NEXT: .long 120
+; CHECK-NEXT: .long 28
+; CHECK-NEXT: .long 124
; CHECK-NEXT: .long 0
; CHECK-NEXT: .long 8 # FuncInfo
-; CHECK: .long 12 # OffsetReloc
-; CHECK-NEXT: .long 77 # Offset reloc section string offset=77
+; CHECK: .long 16 # FieldReloc
+; CHECK-NEXT: .long 77 # Field reloc section string offset=77
; CHECK-NEXT: .long 1
; CHECK-NEXT: .long .Ltmp2
; CHECK-NEXT: .long 2
; CHECK-NEXT: .long 120
+; CHECK-NEXT: .long 0
; Function Attrs: argmemonly nounwind
declare void @llvm.lifetime.start.p0i8(i64 immarg, i8* nocapture) #1
diff --git a/llvm/test/CodeGen/BPF/CORE/offset-reloc-typedef-array.ll b/llvm/test/CodeGen/BPF/CORE/offset-reloc-typedef-array.ll
index d63bc070c9d..4659d1ba213 100644
--- a/llvm/test/CodeGen/BPF/CORE/offset-reloc-typedef-array.ll
+++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-typedef-array.ll
@@ -38,12 +38,13 @@ entry:
; CHECK-NEXT: .byte 0
; CHECK: .ascii "0:0:1" # string offset=[[ACCESS_STR:[0-9]+]]
; CHECK-NEXT: .byte 0
-; CHECK: .long 12 # OffsetReloc
-; CHECK-NEXT: .long [[SEC_INDEX]] # Offset reloc section string offset=[[SEC_INDEX]]
+; CHECK: .long 16 # FieldReloc
+; CHECK-NEXT: .long [[SEC_INDEX]] # Field reloc section string offset=[[SEC_INDEX]]
; CHECK-NEXT: .long 1
; CHECK-NEXT: .long [[RELOC]]
; CHECK-NEXT: .long [[TYPE_ID]]
; CHECK-NEXT: .long [[ACCESS_STR]]
+; CHECK-NEXT: .long 0
declare dso_local i32 @get_value(i8*) local_unnamed_addr #1
diff --git a/llvm/test/CodeGen/BPF/CORE/offset-reloc-typedef-struct.ll b/llvm/test/CodeGen/BPF/CORE/offset-reloc-typedef-struct.ll
index a0d7532bf48..4bf6cffb108 100644
--- a/llvm/test/CodeGen/BPF/CORE/offset-reloc-typedef-struct.ll
+++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-typedef-struct.ll
@@ -37,12 +37,13 @@ entry:
; CHECK-NEXT: .byte 0
; CHECK: .ascii "0:1" # string offset=[[ACCESS_STR:[0-9]+]]
; CHECK-NEXT: .byte 0
-; CHECK: .long 12 # OffsetReloc
-; CHECK-NEXT: .long [[SEC_STR]] # Offset reloc section string offset={{[0-9]+}}
+; CHECK: .long 16 # FieldReloc
+; CHECK-NEXT: .long [[SEC_STR]] # Field reloc section string offset={{[0-9]+}}
; CHECK-NEXT: .long 1
; CHECK-NEXT: .long [[RELOC]]
; CHECK-NEXT: .long [[TYPE_ID]]
; CHECK-NEXT: .long [[ACCESS_STR]]
+; CHECK-NEXT: .long 0
declare dso_local i32 @get_value(i8*) local_unnamed_addr #1
diff --git a/llvm/test/CodeGen/BPF/CORE/offset-reloc-typedef-union.ll b/llvm/test/CodeGen/BPF/CORE/offset-reloc-typedef-union.ll
index caefc2b4bc6..707a45802ae 100644
--- a/llvm/test/CodeGen/BPF/CORE/offset-reloc-typedef-union.ll
+++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-typedef-union.ll
@@ -37,12 +37,13 @@ entry:
; CHECK-NEXT: .byte 0
; CHECK: .ascii "0:1" # string offset=[[ACCESS_STR:[0-9]+]]
; CHECK-NEXT: .byte 0
-; CHECK: .long 12 # OffsetReloc
-; CHECK-NEXT: .long [[SEC_INDEX]] # Offset reloc section string offset=[[SEC_INDEX]]
+; CHECK: .long 16 # FieldReloc
+; CHECK-NEXT: .long [[SEC_INDEX]] # Field reloc section string offset=[[SEC_INDEX]]
; CHECK-NEXT: .long 1
; CHECK-NEXT: .long [[RELOC]]
; CHECK-NEXT: .long [[TYPE_ID]]
; CHECK-NEXT: .long [[ACCESS_STR]]
+; CHECK-NEXT: .long 0
declare dso_local i32 @get_value(i8*) local_unnamed_addr #1
diff --git a/llvm/test/CodeGen/BPF/CORE/offset-reloc-typedef.ll b/llvm/test/CodeGen/BPF/CORE/offset-reloc-typedef.ll
index 82816944072..b6a08549a50 100644
--- a/llvm/test/CodeGen/BPF/CORE/offset-reloc-typedef.ll
+++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-typedef.ll
@@ -45,12 +45,13 @@ entry:
; CHECK-NEXT: .byte 0
; CHECK: .ascii "1:1:1" # string offset=[[ACCESS_STR:[0-9]+]]
; CHECK-NEXT: .byte 0
-; CHECK: .long 12 # OffsetReloc
-; CHECK-NEXT: .long [[SEC_STR:[0-9]+]] # Offset reloc section string offset=[[SEC_STR:[0-9]+]]
+; CHECK: .long 16 # FieldReloc
+; CHECK-NEXT: .long [[SEC_STR:[0-9]+]] # Field reloc section string offset=[[SEC_STR:[0-9]+]]
; CHECK-NEXT: .long 1
; CHECK-NEXT: .long [[RELOC:.Ltmp[0-9]+]]
; CHECK-NEXT: .long [[TYPE_ID:[0-9]+]]
; CHECK-NEXT: .long [[ACCESS_STR:[0-9]+]]
+; CHECK-NEXT: .long 0
declare dso_local i32 @get_value(i8*) local_unnamed_addr #1
diff --git a/llvm/test/CodeGen/BPF/CORE/offset-reloc-union.ll b/llvm/test/CodeGen/BPF/CORE/offset-reloc-union.ll
index eefa1ebda73..cb60c81d58a 100644
--- a/llvm/test/CodeGen/BPF/CORE/offset-reloc-union.ll
+++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-union.ll
@@ -133,17 +133,18 @@ define dso_local i32 @bpf_prog(%union.sk_buff*) local_unnamed_addr #0 !dbg !15 {
; CHECK-NEXT: .long 20
; CHECK-NEXT: .long 76
; CHECK-NEXT: .long 96
-; CHECK-NEXT: .long 24
-; CHECK-NEXT: .long 120
+; CHECK-NEXT: .long 28
+; CHECK-NEXT: .long 124
; CHECK-NEXT: .long 0
; CHECK-NEXT: .long 8 # FuncInfo
-; CHECK: .long 12 # OffsetReloc
-; CHECK-NEXT: .long 54 # Offset reloc section string offset=54
+; CHECK: .long 16 # FieldReloc
+; CHECK-NEXT: .long 54 # Field reloc section string offset=54
; CHECK-NEXT: .long 1
; CHECK-NEXT: .long .Ltmp2
; CHECK-NEXT: .long 2
; CHECK-NEXT: .long 97
+; CHECK-NEXT: .long 0
; Function Attrs: argmemonly nounwind
declare void @llvm.lifetime.start.p0i8(i64 immarg, i8* nocapture) #1
OpenPOWER on IntegriCloud