1 | // RUN: %clang_cc1 -triple x86_64-linux-gnu -ffine-grained-bitfield-accesses \ |
2 | // RUN: -emit-llvm -o - %s | FileCheck %s |
3 | // RUN: %clang_cc1 -triple x86_64-linux-gnu -ffine-grained-bitfield-accesses \ |
4 | // RUN: -emit-llvm -fsanitize=address -o - %s | FileCheck %s --check-prefix=SANITIZE |
5 | // Check -fsplit-bitfields will be ignored since sanitizer is enabled. |
6 | |
7 | struct S1 { |
8 | unsigned f1:2; |
9 | unsigned f2:6; |
10 | unsigned f3:8; |
11 | unsigned f4:4; |
12 | unsigned f5:8; |
13 | }; |
14 | |
15 | S1 a1; |
16 | unsigned read8_1() { |
17 | // CHECK-LABEL: @_Z7read8_1v |
18 | // CHECK: %bf.load = load i8, i8* getelementptr inbounds (%struct.S1, %struct.S1* @a1, i32 0, i32 1), align 1 |
19 | // CHECK-NEXT: %bf.cast = zext i8 %bf.load to i32 |
20 | // CHECK-NEXT: ret i32 %bf.cast |
21 | // SANITIZE-LABEL: @_Z7read8_1v |
22 | // SANITIZE: %bf.load = load i32, i32* getelementptr inbounds {{.*}}, align 4 |
23 | // SANITIZE: %bf.lshr = lshr i32 %bf.load, 8 |
24 | // SANITIZE: %bf.clear = and i32 %bf.lshr, 255 |
25 | // SANITIZE: ret i32 %bf.clear |
26 | return a1.f3; |
27 | } |
28 | void write8_1() { |
29 | // CHECK-LABEL: @_Z8write8_1v |
30 | // CHECK: store i8 3, i8* getelementptr inbounds (%struct.S1, %struct.S1* @a1, i32 0, i32 1), align 1 |
31 | // CHECK-NEXT: ret void |
32 | // SANITIZE-LABEL: @_Z8write8_1v |
33 | // SANITIZE: %bf.load = load i32, i32* getelementptr inbounds {{.*}}, align 4 |
34 | // SANITIZE-NEXT: %bf.clear = and i32 %bf.load, -65281 |
35 | // SANITIZE-NEXT: %bf.set = or i32 %bf.clear, 768 |
36 | // SANITIZE-NEXT: store i32 %bf.set, i32* getelementptr inbounds {{.*}}, align 4 |
37 | // SANITIZE-NEXT: ret void |
38 | a1.f3 = 3; |
39 | } |
40 | |
41 | unsigned read8_2() { |
42 | // CHECK-LABEL: @_Z7read8_2v |
43 | // CHECK: %bf.load = load i16, i16* getelementptr inbounds (%struct.S1, %struct.S1* @a1, i32 0, i32 2), align 2 |
44 | // CHECK-NEXT: %bf.lshr = lshr i16 %bf.load, 4 |
45 | // CHECK-NEXT: %bf.clear = and i16 %bf.lshr, 255 |
46 | // CHECK-NEXT: %bf.cast = zext i16 %bf.clear to i32 |
47 | // CHECK-NEXT: ret i32 %bf.cast |
48 | // SANITIZE-LABEL: @_Z7read8_2v |
49 | // SANITIZE: %bf.load = load i32, i32* getelementptr inbounds {{.*}}, align 4 |
50 | // SANITIZE-NEXT: %bf.lshr = lshr i32 %bf.load, 20 |
51 | // SANITIZE-NEXT: %bf.clear = and i32 %bf.lshr, 255 |
52 | // SANITIZE-NEXT: ret i32 %bf.clear |
53 | return a1.f5; |
54 | } |
55 | void write8_2() { |
56 | // CHECK-LABEL: @_Z8write8_2v |
57 | // CHECK: %bf.load = load i16, i16* getelementptr inbounds (%struct.S1, %struct.S1* @a1, i32 0, i32 2), align 2 |
58 | // CHECK-NEXT: %bf.clear = and i16 %bf.load, -4081 |
59 | // CHECK-NEXT: %bf.set = or i16 %bf.clear, 48 |
60 | // CHECK-NEXT: store i16 %bf.set, i16* getelementptr inbounds (%struct.S1, %struct.S1* @a1, i32 0, i32 2), align 2 |
61 | // CHECK-NEXT: ret void |
62 | // SANITIZE-LABEL: @_Z8write8_2v |
63 | // SANITIZE: %bf.load = load i32, i32* getelementptr inbounds {{.*}}, align 4 |
64 | // SANITIZE-NEXT: %bf.clear = and i32 %bf.load, -267386881 |
65 | // SANITIZE-NEXT: %bf.set = or i32 %bf.clear, 3145728 |
66 | // SANITIZE-NEXT: store i32 %bf.set, i32* getelementptr inbounds {{.*}}, align 4 |
67 | // SANITIZE-NEXT: ret void |
68 | a1.f5 = 3; |
69 | } |
70 | |
71 | struct S2 { |
72 | unsigned long f1:16; |
73 | unsigned long f2:16; |
74 | unsigned long f3:6; |
75 | }; |
76 | |
77 | S2 a2; |
78 | unsigned read16_1() { |
79 | // CHECK-LABEL: @_Z8read16_1v |
80 | // CHECK: %bf.load = load i16, i16* getelementptr inbounds (%struct.S2, %struct.S2* @a2, i32 0, i32 0), align 8 |
81 | // CHECK-NEXT: %bf.cast = zext i16 %bf.load to i64 |
82 | // CHECK-NEXT: %conv = trunc i64 %bf.cast to i32 |
83 | // CHECK-NEXT: ret i32 %conv |
84 | // SANITIZE-LABEL: @_Z8read16_1v |
85 | // SANITIZE: %bf.load = load i64, i64* bitcast {{.*}}, align 8 |
86 | // SANITIZE-NEXT: %bf.clear = and i64 %bf.load, 65535 |
87 | // SANITIZE-NEXT: %conv = trunc i64 %bf.clear to i32 |
88 | // SANITIZE-NEXT: ret i32 %conv |
89 | return a2.f1; |
90 | } |
91 | unsigned read16_2() { |
92 | // CHECK-LABEL: @_Z8read16_2v |
93 | // CHECK: %bf.load = load i16, i16* getelementptr inbounds (%struct.S2, %struct.S2* @a2, i32 0, i32 1), align 2 |
94 | // CHECK-NEXT: %bf.cast = zext i16 %bf.load to i64 |
95 | // CHECK-NEXT: %conv = trunc i64 %bf.cast to i32 |
96 | // CHECK-NEXT: ret i32 %conv |
97 | // SANITIZE-LABEL: @_Z8read16_2v |
98 | // SANITIZE: %bf.load = load i64, i64* bitcast {{.*}}, align 8 |
99 | // SANITIZE-NEXT: %bf.lshr = lshr i64 %bf.load, 16 |
100 | // SANITIZE-NEXT: %bf.clear = and i64 %bf.lshr, 65535 |
101 | // SANITIZE-NEXT: %conv = trunc i64 %bf.clear to i32 |
102 | // SANITIZE-NEXT: ret i32 %conv |
103 | return a2.f2; |
104 | } |
105 | |
106 | void write16_1() { |
107 | // CHECK-LABEL: @_Z9write16_1v |
108 | // CHECK: store i16 5, i16* getelementptr inbounds (%struct.S2, %struct.S2* @a2, i32 0, i32 0), align 8 |
109 | // CHECK-NEXT: ret void |
110 | // SANITIZE-LABEL: @_Z9write16_1v |
111 | // SANITIZE: %bf.load = load i64, i64* bitcast {{.*}}, align 8 |
112 | // SANITIZE-NEXT: %bf.clear = and i64 %bf.load, -65536 |
113 | // SANITIZE-NEXT: %bf.set = or i64 %bf.clear, 5 |
114 | // SANITIZE-NEXT: store i64 %bf.set, i64* bitcast {{.*}}, align 8 |
115 | // SANITIZE-NEXT: ret void |
116 | a2.f1 = 5; |
117 | } |
118 | void write16_2() { |
119 | // CHECK-LABEL: @_Z9write16_2v |
120 | // CHECK: store i16 5, i16* getelementptr inbounds (%struct.S2, %struct.S2* @a2, i32 0, i32 1), align 2 |
121 | // CHECK-NEXT: ret void |
122 | // SANITIZE-LABEL: @_Z9write16_2v |
123 | // SANITIZE: %bf.load = load i64, i64* bitcast {{.*}}, align 8 |
124 | // SANITIZE-NEXT: %bf.clear = and i64 %bf.load, -4294901761 |
125 | // SANITIZE-NEXT: %bf.set = or i64 %bf.clear, 327680 |
126 | // SANITIZE-NEXT: store i64 %bf.set, i64* bitcast {{.*}}, align 8 |
127 | // SANITIZE-NEXT: ret void |
128 | a2.f2 = 5; |
129 | } |
130 | |
131 | struct S3 { |
132 | unsigned long f1:14; |
133 | unsigned long f2:18; |
134 | unsigned long f3:32; |
135 | }; |
136 | |
137 | S3 a3; |
138 | unsigned read32_1() { |
139 | // CHECK-LABEL: @_Z8read32_1v |
140 | // CHECK: %bf.load = load i32, i32* getelementptr inbounds (%struct.S3, %struct.S3* @a3, i32 0, i32 1), align 4 |
141 | // CHECK-NEXT: %bf.cast = zext i32 %bf.load to i64 |
142 | // CHECK-NEXT: %conv = trunc i64 %bf.cast to i32 |
143 | // CHECK-NEXT: ret i32 %conv |
144 | // SANITIZE-LABEL: @_Z8read32_1v |
145 | // SANITIZE: %bf.load = load i64, i64* getelementptr inbounds {{.*}}, align 8 |
146 | // SANITIZE-NEXT: %bf.lshr = lshr i64 %bf.load, 32 |
147 | // SANITIZE-NEXT: %conv = trunc i64 %bf.lshr to i32 |
148 | // SANITIZE-NEXT: ret i32 %conv |
149 | return a3.f3; |
150 | } |
151 | void write32_1() { |
152 | // CHECK-LABEL: @_Z9write32_1v |
153 | // CHECK: store i32 5, i32* getelementptr inbounds (%struct.S3, %struct.S3* @a3, i32 0, i32 1), align 4 |
154 | // CHECK-NEXT: ret void |
155 | // SANITIZE-LABEL: @_Z9write32_1v |
156 | // SANITIZE: %bf.load = load i64, i64* getelementptr inbounds {{.*}}, align 8 |
157 | // SANITIZE-NEXT: %bf.clear = and i64 %bf.load, 4294967295 |
158 | // SANITIZE-NEXT: %bf.set = or i64 %bf.clear, 21474836480 |
159 | // SANITIZE-NEXT: store i64 %bf.set, i64* getelementptr inbounds {{.*}}, align 8 |
160 | // SANITIZE-NEXT: ret void |
161 | a3.f3 = 5; |
162 | } |
163 | |