Skip to content

Commit 4754814

Browse files
committed
fix unnamed fiefield issue and add tests for __builtin_preserve_access_index intrinsic
The original commit is r366076. It is temporarily reverted (r366155) due to test failure. This resubmit makes test more robust by accepting regex instead of hardcoded names/references in several places. This is a followup patch for https://reviews.llvm.org/D61809. Handle unnamed bitfield properly and add more test cases. Fixed the unnamed bitfield issue. The unnamed bitfield is ignored by debug info, so we need to ignore such a struct/union member when we try to get the member index in the debug info. D61809 contains two test cases but not enough as it does not checking generated IRs in the fine grain level, and also it does not have semantics checking tests. This patch added unit tests for both code gen and semantics checking for the new intrinsic. Signed-off-by: Yonghong Song <yhs@fb.com> llvm-svn: 366231
1 parent c65a9db commit 4754814

File tree

4 files changed

+212
-2
lines changed

4 files changed

+212
-2
lines changed

clang/lib/CodeGen/CGExpr.cpp

+19-2
Original file line numberDiff line numberDiff line change
@@ -3892,6 +3892,23 @@ LValue CodeGenFunction::EmitLValueForLambdaField(const FieldDecl *Field) {
38923892
return EmitLValueForField(LambdaLV, Field);
38933893
}
38943894

3895+
/// Get the field index in the debug info. The debug info structure/union
3896+
/// will ignore the unnamed bitfields.
3897+
unsigned CodeGenFunction::getDebugInfoFIndex(const RecordDecl *Rec,
3898+
unsigned FieldIndex) {
3899+
unsigned I = 0, Skipped = 0;
3900+
3901+
for (auto F : Rec->getDefinition()->fields()) {
3902+
if (I == FieldIndex)
3903+
break;
3904+
if (F->isUnnamedBitfield())
3905+
Skipped++;
3906+
I++;
3907+
}
3908+
3909+
return FieldIndex - Skipped;
3910+
}
3911+
38953912
/// Get the address of a zero-sized field within a record. The resulting
38963913
/// address doesn't necessarily have the right type.
38973914
static Address emitAddrOfZeroSizeField(CodeGenFunction &CGF, Address Base,
@@ -3931,7 +3948,7 @@ static Address emitPreserveStructAccess(CodeGenFunction &CGF, Address base,
39313948
CGF.CGM.getTypes().getCGRecordLayout(rec).getLLVMFieldNo(field);
39323949

39333950
return CGF.Builder.CreatePreserveStructAccessIndex(
3934-
base, idx, field->getFieldIndex(), DbgInfo);
3951+
base, idx, CGF.getDebugInfoFIndex(rec, field->getFieldIndex()), DbgInfo);
39353952
}
39363953

39373954
static bool hasAnyVptr(const QualType Type, const ASTContext &Context) {
@@ -4048,7 +4065,7 @@ LValue CodeGenFunction::EmitLValueForField(LValue base,
40484065
getContext().getRecordType(rec), rec->getLocation());
40494066
addr = Address(
40504067
Builder.CreatePreserveUnionAccessIndex(
4051-
addr.getPointer(), field->getFieldIndex(), DbgInfo),
4068+
addr.getPointer(), getDebugInfoFIndex(rec, field->getFieldIndex()), DbgInfo),
40524069
addr.getAlignment());
40534070
}
40544071
} else {

clang/lib/CodeGen/CodeGenFunction.h

+3
Original file line numberDiff line numberDiff line change
@@ -2652,6 +2652,9 @@ class CodeGenFunction : public CodeGenTypeCache {
26522652
/// Converts Location to a DebugLoc, if debug information is enabled.
26532653
llvm::DebugLoc SourceLocToDebugLoc(SourceLocation Location);
26542654

2655+
/// Get the record field index as represented in debug info.
2656+
unsigned getDebugInfoFIndex(const RecordDecl *Rec, unsigned FieldIndex);
2657+
26552658

26562659
//===--------------------------------------------------------------------===//
26572660
// Declaration Emission
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
// RUN: %clang -target x86_64 -emit-llvm -S -g %s -o - | FileCheck %s
2+
3+
#define _(x) (__builtin_preserve_access_index(x))
4+
5+
const void *unit1(const void *arg) {
6+
return _(arg);
7+
}
8+
// CHECK: define dso_local i8* @unit1
9+
// CHECK-NOT: llvm.preserve.array.access.index
10+
// CHECK-NOT: llvm.preserve.struct.access.index
11+
// CHECK-NOT: llvm.preserve.union.access.index
12+
13+
const void *unit2(void) {
14+
return _((const void *)0xffffffffFFFF0000ULL);
15+
}
16+
// CHECK: define dso_local i8* @unit2
17+
// CHECK-NOT: llvm.preserve.array.access.index
18+
// CHECK-NOT: llvm.preserve.struct.access.index
19+
// CHECK-NOT: llvm.preserve.union.access.index
20+
21+
const void *unit3(const int *arg) {
22+
return _(arg + 1);
23+
}
24+
// CHECK: define dso_local i8* @unit3
25+
// CHECK-NOT: llvm.preserve.array.access.index
26+
// CHECK-NOT: llvm.preserve.struct.access.index
27+
// CHECK-NOT: llvm.preserve.union.access.index
28+
29+
const void *unit4(const int *arg) {
30+
return _(&arg[1]);
31+
}
32+
// CHECK: define dso_local i8* @unit4
33+
// CHECK-NOT: getelementptr
34+
// CHECK: call i32* @llvm.preserve.array.access.index.p0i32.p0i32(i32* %{{[0-9a-z]+}}, i32 0, i32 1)
35+
36+
const void *unit5(const int *arg[5]) {
37+
return _(&arg[1][2]);
38+
}
39+
// CHECK: define dso_local i8* @unit5
40+
// CHECK-NOT: getelementptr
41+
// CHECK: call i32** @llvm.preserve.array.access.index.p0p0i32.p0p0i32(i32** %{{[0-9a-z]+}}, i32 0, i32 1)
42+
// CHECK-NOT: getelementptr
43+
// CHECK: call i32* @llvm.preserve.array.access.index.p0i32.p0i32(i32* %{{[0-9a-z]+}}, i32 0, i32 2)
44+
45+
struct s1 {
46+
char a;
47+
int b;
48+
};
49+
50+
struct s2 {
51+
char a1:1;
52+
char a2:1;
53+
int b;
54+
};
55+
56+
struct s3 {
57+
char a1:1;
58+
char a2:1;
59+
char :6;
60+
int b;
61+
};
62+
63+
const void *unit6(struct s1 *arg) {
64+
return _(&arg->a);
65+
}
66+
// CHECK: define dso_local i8* @unit6
67+
// CHECK-NOT: getelementptr
68+
// CHECK: call i8* @llvm.preserve.struct.access.index.p0i8.p0s_struct.s1s(%struct.s1* %{{[0-9a-z]+}}, i32 0, i32 0), !dbg !{{[0-9]+}}, !llvm.preserve.access.index ![[STRUCT_S1:[0-9]+]]
69+
70+
const void *unit7(struct s1 *arg) {
71+
return _(&arg->b);
72+
}
73+
// CHECK: define dso_local i8* @unit7
74+
// CHECK-NOT: getelementptr
75+
// CHECK: call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.s1s(%struct.s1* %{{[0-9a-z]+}}, i32 1, i32 1), !dbg !{{[0-9]+}}, !llvm.preserve.access.index ![[STRUCT_S1]]
76+
77+
const void *unit8(struct s2 *arg) {
78+
return _(&arg->b);
79+
}
80+
// CHECK: define dso_local i8* @unit8
81+
// CHECK-NOT: getelementptr
82+
// CHECK: call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.s2s(%struct.s2* %{{[0-9a-z]+}}, i32 1, i32 2), !dbg !{{[0-9]+}}, !llvm.preserve.access.index ![[STRUCT_S2:[0-9]+]]
83+
84+
const void *unit9(struct s3 *arg) {
85+
return _(&arg->b);
86+
}
87+
// CHECK: define dso_local i8* @unit9
88+
// CHECK-NOT: getelementptr
89+
// CHECK: call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.s3s(%struct.s3* %{{[0-9a-z]+}}, i32 1, i32 2), !dbg !{{[0-9]+}}, !llvm.preserve.access.index ![[STRUCT_S3:[0-9]+]]
90+
91+
union u1 {
92+
char a;
93+
int b;
94+
};
95+
96+
union u2 {
97+
char a;
98+
int :32;
99+
int b;
100+
};
101+
102+
const void *unit10(union u1 *arg) {
103+
return _(&arg->a);
104+
}
105+
// CHECK: define dso_local i8* @unit10
106+
// CHECK-NOT: getelementptr
107+
// CHECK: call %union.u1* @llvm.preserve.union.access.index.p0s_union.u1s.p0s_union.u1s(%union.u1* %{{[0-9a-z]+}}, i32 0), !dbg !{{[0-9]+}}, !llvm.preserve.access.index ![[UNION_U1:[0-9]+]]
108+
109+
const void *unit11(union u1 *arg) {
110+
return _(&arg->b);
111+
}
112+
// CHECK: define dso_local i8* @unit11
113+
// CHECK-NOT: getelementptr
114+
// CHECK: call %union.u1* @llvm.preserve.union.access.index.p0s_union.u1s.p0s_union.u1s(%union.u1* %{{[0-9a-z]+}}, i32 1), !dbg !{{[0-9]+}}, !llvm.preserve.access.index ![[UNION_U1]]
115+
116+
const void *unit12(union u2 *arg) {
117+
return _(&arg->b);
118+
}
119+
// CHECK: define dso_local i8* @unit12
120+
// CHECK-NOT: getelementptr
121+
// CHECK: call %union.u2* @llvm.preserve.union.access.index.p0s_union.u2s.p0s_union.u2s(%union.u2* %{{[0-9a-z]+}}, i32 1), !dbg !{{[0-9]+}}, !llvm.preserve.access.index ![[UNION_U2:[0-9]+]]
122+
123+
struct s4 {
124+
char d;
125+
union u {
126+
int b[4];
127+
char a;
128+
} c;
129+
};
130+
131+
union u3 {
132+
struct s {
133+
int b[4];
134+
} c;
135+
char a;
136+
};
137+
138+
const void *unit13(struct s4 *arg) {
139+
return _(&arg->c.b[2]);
140+
}
141+
// CHECK: define dso_local i8* @unit13
142+
// CHECK: call %union.u* @llvm.preserve.struct.access.index.p0s_union.us.p0s_struct.s4s(%struct.s4* %{{[0-9a-z]+}}, i32 1, i32 1), !dbg !{{[0-9]+}}, !llvm.preserve.access.index ![[STRUCT_S4:[0-9]+]]
143+
// CHECK: call %union.u* @llvm.preserve.union.access.index.p0s_union.us.p0s_union.us(%union.u* %{{[0-9a-z]+}}, i32 0), !dbg !{{[0-9]+}}, !llvm.preserve.access.index ![[UNION_I_U:[0-9]+]]
144+
// CHECK: call i32* @llvm.preserve.array.access.index.p0i32.p0a4i32([4 x i32]* %{{[0-9a-z]+}}, i32 1, i32 2)
145+
146+
const void *unit14(union u3 *arg) {
147+
return _(&arg->c.b[2]);
148+
}
149+
// CHECK: define dso_local i8* @unit14
150+
// CHECK: call %union.u3* @llvm.preserve.union.access.index.p0s_union.u3s.p0s_union.u3s(%union.u3* %{{[0-9a-z]+}}, i32 0), !dbg !{{[0-9]+}}, !llvm.preserve.access.index ![[UNION_U3:[0-9]+]]
151+
// CHECK: call [4 x i32]* @llvm.preserve.struct.access.index.p0a4i32.p0s_struct.ss(%struct.s* %{{[0-9a-z]+}}, i32 0, i32 0), !dbg !{{[0-9]+}}, !llvm.preserve.access.index ![[STRUCT_I_S:[0-9]+]]
152+
// CHECK: call i32* @llvm.preserve.array.access.index.p0i32.p0a4i32([4 x i32]* %{{[0-9a-z]+}}, i32 1, i32 2)
153+
154+
const void *unit15(struct s4 *arg) {
155+
return _(&arg[2].c.a);
156+
}
157+
// CHECK: define dso_local i8* @unit15
158+
// CHECK: call %struct.s4* @llvm.preserve.array.access.index.p0s_struct.s4s.p0s_struct.s4s(%struct.s4* %{{[0-9a-z]+}}, i32 0, i32 2)
159+
// CHECK: call %union.u* @llvm.preserve.struct.access.index.p0s_union.us.p0s_struct.s4s(%struct.s4* %{{[0-9a-z]+}}, i32 1, i32 1), !dbg !{{[0-9]+}}, !llvm.preserve.access.index ![[STRUCT_S4]]
160+
// CHECK: call %union.u* @llvm.preserve.union.access.index.p0s_union.us.p0s_union.us(%union.u* %{{[0-9a-z]+}}, i32 1), !dbg !{{[0-9]+}}, !llvm.preserve.access.index ![[UNION_I_U]]
161+
162+
const void *unit16(union u3 *arg) {
163+
return _(&arg[2].a);
164+
}
165+
// CHECK: define dso_local i8* @unit16
166+
// CHECK: call %union.u3* @llvm.preserve.array.access.index.p0s_union.u3s.p0s_union.u3s(%union.u3* %{{[0-9a-z]+}}, i32 0, i32 2)
167+
// CHECK: call %union.u3* @llvm.preserve.union.access.index.p0s_union.u3s.p0s_union.u3s(%union.u3* %{{[0-9a-z]+}}, i32 1), !dbg !{{[0-9]+}}, !llvm.preserve.access.index ![[UNION_U3]]
168+
169+
// CHECK: ![[STRUCT_S1]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "s1"
170+
// CHECK: ![[STRUCT_S2]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "s2"
171+
// CHECK: ![[STRUCT_S3]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "s3"
172+
// CHECK: ![[UNION_U1]] = distinct !DICompositeType(tag: DW_TAG_union_type, name: "u1"
173+
// CHECK: ![[UNION_U2]] = distinct !DICompositeType(tag: DW_TAG_union_type, name: "u2"
174+
// CHECK: ![[STRUCT_S4]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "s4"
175+
// CHECK: ![[UNION_I_U]] = distinct !DICompositeType(tag: DW_TAG_union_type, name: "u"
176+
// CHECK: ![[UNION_U3]] = distinct !DICompositeType(tag: DW_TAG_union_type, name: "u3"
177+
// CHECK: ![[STRUCT_I_S]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "s"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// RUN: %clang_cc1 -x c -triple x86_64-pc-linux-gnu -dwarf-version=4 -fsyntax-only -verify %s
2+
3+
const void *invalid1(const int *arg) {
4+
return __builtin_preserve_access_index(&arg[1], 1); // expected-error {{too many arguments to function call, expected 1, have 2}}
5+
}
6+
7+
void *invalid2(const int *arg) {
8+
return __builtin_preserve_access_index(&arg[1]); // expected-warning {{returning 'const void *' from a function with result type 'void *' discards qualifiers}}
9+
}
10+
11+
const void *invalid3(const int *arg) {
12+
return __builtin_preserve_access_index(1); // expected-warning {{incompatible integer to pointer conversion passing 'int' to parameter of type 'const void *'}}
13+
}

0 commit comments

Comments
 (0)