volatile-1.cpp revision 2a41637a995affa1563f4d82a8b026e326a2faa0
1// RUN: %clang_cc1 -Wno-unused-value -emit-llvm %s -o - | FileCheck %s 2 3// CHECK: @i = global [[INT:i[0-9]+]] 0 4volatile int i, j, k; 5volatile int ar[5]; 6volatile char c; 7// CHECK: @ci = global [[CINT:%.*]] zeroinitializer 8volatile _Complex int ci; 9volatile struct S { 10#ifdef __cplusplus 11 void operator =(volatile struct S&o) volatile; 12#endif 13 int i; 14} a, b; 15 16//void operator =(volatile struct S&o1, volatile struct S&o2) volatile; 17int printf(const char *, ...); 18 19 20// CHECK: define void @{{.*}}test 21void test() { 22 23 asm("nop"); // CHECK: call void asm 24 25 // should not load 26 i; 27 28 (float)(ci); 29 // CHECK-NEXT: volatile load [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0) 30 // CHECK-NEXT: volatile load [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1) 31 // CHECK-NEXT: sitofp [[INT]] 32 33 // These are not uses in C++: 34 // [expr.static.cast]p6: 35 // The lvalue-to-rvalue . . . conversions are not applied to the expression. 36 (void)ci; 37 (void)a; 38 39 (void)(ci=ci); 40 // CHECK-NEXT: [[R:%.*]] = volatile load [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0) 41 // CHECK-NEXT: [[I:%.*]] = volatile load [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1) 42 // CHECK-NEXT: volatile store [[INT]] [[R]], [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0) 43 // CHECK-NEXT: volatile store [[INT]] [[I]], [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1) 44 45 (void)(i=j); 46 // CHECK-NEXT: [[T:%.*]] = volatile load [[INT]]* @j 47 // CHECK-NEXT: volatile store [[INT]] [[T]], [[INT]]* @i 48 49 ci+=ci; 50 // CHECK-NEXT: [[R1:%.*]] = volatile load [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0) 51 // CHECK-NEXT: [[I1:%.*]] = volatile load [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1) 52 // CHECK-NEXT: [[R2:%.*]] = volatile load [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0) 53 // CHECK-NEXT: [[I2:%.*]] = volatile load [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1) 54 // Not sure why they're ordered this way. 55 // CHECK-NEXT: [[R:%.*]] = add [[INT]] [[R2]], [[R1]] 56 // CHECK-NEXT: [[I:%.*]] = add [[INT]] [[I2]], [[I1]] 57 // CHECK-NEXT: volatile store [[INT]] [[R]], [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0) 58 // CHECK-NEXT: volatile store [[INT]] [[I]], [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1) 59 60 // Note that C++ requires an extra volatile load over C from the LHS of the '+'. 61 (ci += ci) + ci; 62 // CHECK-NEXT: [[R1:%.*]] = volatile load [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0) 63 // CHECK-NEXT: [[I1:%.*]] = volatile load [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1) 64 // CHECK-NEXT: [[R2:%.*]] = volatile load [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0) 65 // CHECK-NEXT: [[I2:%.*]] = volatile load [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1) 66 // CHECK-NEXT: [[R:%.*]] = add [[INT]] [[R2]], [[R1]] 67 // CHECK-NEXT: [[I:%.*]] = add [[INT]] [[I2]], [[I1]] 68 // CHECK-NEXT: volatile store [[INT]] [[R]], [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0) 69 // CHECK-NEXT: volatile store [[INT]] [[I]], [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1) 70 // CHECK-NEXT: [[R1:%.*]] = volatile load [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0) 71 // CHECK-NEXT: [[I1:%.*]] = volatile load [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1) 72 // CHECK-NEXT: [[R2:%.*]] = volatile load [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0) 73 // CHECK-NEXT: [[I2:%.*]] = volatile load [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1) 74 // These additions can be elided. 75 // CHECK-NEXT: add [[INT]] [[R1]], [[R2]] 76 // CHECK-NEXT: add [[INT]] [[I1]], [[I2]] 77 78 asm("nop"); // CHECK-NEXT: call void asm 79 80 // Extra volatile load in C++. 81 (i += j) + k; 82 // CHECK-NEXT: volatile load 83 // CHECK-NEXT: volatile load 84 // CHECK-NEXT: add nsw [[INT]] 85 // CHECK-NEXT: volatile store 86 // CHECK-NEXT: volatile load 87 // CHECK-NEXT: volatile load 88 // CHECK-NEXT: add nsw [[INT]] 89 90 asm("nop"); // CHECK-NEXT: call void asm 91 92 // Extra volatile load in C++. 93 (i += j) + 1; 94 // CHECK-NEXT: volatile load 95 // CHECK-NEXT: volatile load 96 // CHECK-NEXT: add nsw [[INT]] 97 // CHECK-NEXT: volatile store 98 // CHECK-NEXT: volatile load 99 // CHECK-NEXT: add nsw [[INT]] 100 101 asm("nop"); // CHECK-NEXT: call void asm 102 103 ci+ci; 104 // CHECK-NEXT: volatile load 105 // CHECK-NEXT: volatile load 106 // CHECK-NEXT: volatile load 107 // CHECK-NEXT: volatile load 108 // CHECK-NEXT: add [[INT]] 109 // CHECK-NEXT: add [[INT]] 110 111 __real i; 112 113 +ci; 114 // CHECK-NEXT: volatile load 115 // CHECK-NEXT: volatile load 116 117 asm("nop"); // CHECK-NEXT: call void asm 118 119 (void)(i=i); 120 // CHECK-NEXT: volatile load 121 // CHECK-NEXT: volatile store 122 123 (float)(i=i); 124 // CHECK-NEXT: volatile load 125 // CHECK-NEXT: volatile store 126 // CHECK-NEXT: volatile load 127 // CHECK-NEXT: sitofp 128 129 (void)i; 130 131 i=i; 132 // CHECK-NEXT: volatile load 133 // CHECK-NEXT: volatile store 134 135 // Extra volatile load in C++. 136 i=i=i; 137 // CHECK-NEXT: volatile load 138 // CHECK-NEXT: volatile store 139 // CHECK-NEXT: volatile load 140 // CHECK-NEXT: volatile store 141 142 (void)__builtin_choose_expr(0, i=i, j=j); 143 // CHECK-NEXT: volatile load 144 // CHECK-NEXT: volatile store 145 146 // FIXME: the phi-equivalent is unnecessary 147 k ? (i=i) : (j=j); 148 // CHECK-NEXT: volatile load 149 // CHECK-NEXT: icmp 150 // CHECK-NEXT: br i1 151 // CHECK: volatile load 152 // CHECK-NEXT: volatile store 153 // CHECK-NEXT: store [[INT]]* @i 154 // CHECK-NEXT: br label 155 // CHECK: volatile load 156 // CHECK-NEXT: volatile store 157 // CHECK-NEXT: store [[INT]]* @j 158 // CHECK-NEXT: br label 159 // CHECK: load [[INT]]** 160 161 (void)(i,(i=i)); 162 // CHECK-NEXT: volatile load 163 // CHECK-NEXT: volatile store 164 165 i=i,k; 166 // CHECK-NEXT: volatile load [[INT]]* @i 167 // CHECK-NEXT: volatile store {{.*}}, [[INT]]* @i 168 169 (i=j,k=j); 170 // CHECK-NEXT: volatile load [[INT]]* @j 171 // CHECK-NEXT: volatile store {{.*}}, [[INT]]* @i 172 // CHECK-NEXT: volatile load [[INT]]* @j 173 // CHECK-NEXT: volatile store {{.*}}, [[INT]]* @k 174 175 (i=j,k); 176 // CHECK-NEXT: volatile load [[INT]]* @j 177 // CHECK-NEXT: volatile store {{.*}}, [[INT]]* @i 178 179 (i,j); 180 181 // Extra load in C++. 182 i=c=k; 183 // CHECK-NEXT: volatile load 184 // CHECK-NEXT: trunc 185 // CHECK-NEXT: volatile store 186 // CHECK-NEXT: volatile load 187 // CHECK-NEXT: sext 188 // CHECK-NEXT: volatile store 189 190 i+=k; 191 // CHECK-NEXT: volatile load 192 // CHECK-NEXT: volatile load 193 // CHECK-NEXT: add nsw [[INT]] 194 // CHECK-NEXT: volatile store 195 196 ci; 197 198 asm("nop"); // CHECK-NEXT: call void asm 199 200 (int)ci; 201 // CHECK-NEXT: volatile load {{.*}} @ci, i32 0, i32 0 202 // CHECK-NEXT: volatile load {{.*}} @ci, i32 0, i32 1 203 204 (bool)ci; 205 // CHECK-NEXT: volatile load {{.*}} @ci, i32 0, i32 0 206 // CHECK-NEXT: volatile load {{.*}} @ci, i32 0, i32 1 207 // CHECK-NEXT: icmp ne 208 // CHECK-NEXT: icmp ne 209 // CHECK-NEXT: or i1 210 211 ci=ci; 212 // CHECK-NEXT: volatile load 213 // CHECK-NEXT: volatile load 214 // CHECK-NEXT: volatile store 215 // CHECK-NEXT: volatile store 216 217 asm("nop"); // CHECK-NEXT: call void asm 218 219 // Extra load in C++. 220 ci=ci=ci; 221 // CHECK-NEXT: volatile load 222 // CHECK-NEXT: volatile load 223 // CHECK-NEXT: volatile store 224 // CHECK-NEXT: volatile store 225 // CHECK-NEXT: volatile load 226 // CHECK-NEXT: volatile load 227 // CHECK-NEXT: volatile store 228 // CHECK-NEXT: volatile store 229 230 __imag ci = __imag ci = __imag ci; 231 // CHECK-NEXT: [[T:%.*]] = volatile load [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1) 232 // CHECK-NEXT: volatile store [[INT]] [[T]], [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1) 233 // CHECK-NEXT: [[T:%.*]] = volatile load [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1) 234 // CHECK-NEXT: volatile store [[INT]] [[T]], [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1) 235 236 __real (i = j); 237 // CHECK-NEXT: volatile load 238 // CHECK-NEXT: volatile store 239 240 __imag i; 241 242 // ============================================================ 243 // FIXME: Test cases we get wrong. 244 245 // A use. We load all of a into a copy of a, then load i. gcc forgets to do 246 // the assignment. 247 // (a = a).i; 248 249 // ============================================================ 250 // Test cases where we intentionally differ from gcc, due to suspected bugs in 251 // gcc. 252 253 // Not a use. gcc forgets to do the assignment. 254 // CHECK-NEXT: call 255 ((a=a),a); 256 257 // Not a use. gcc gets this wrong, it doesn't emit the copy! 258 // CHECK-NEXT: call 259 (void)(a=a); 260 261 // Not a use. gcc got this wrong in 4.2 and omitted the side effects 262 // entirely, but it is fixed in 4.4.0. 263 __imag (i = j); 264 // CHECK-NEXT: volatile load 265 // CHECK-NEXT: volatile store 266 267 // C++ does an extra load here. Note that we have to do full loads. 268 (float)(ci=ci); 269 // CHECK-NEXT: volatile load 270 // CHECK-NEXT: volatile load 271 // CHECK-NEXT: volatile store 272 // CHECK-NEXT: volatile store 273 // CHECK-NEXT: volatile load 274 // CHECK-NEXT: volatile load 275 // CHECK-NEXT: sitofp 276 277 // Not a use, bug? gcc treats this as not a use, that's probably a 278 // bug due to tree folding ignoring volatile. 279 (int)(ci=ci); 280 // CHECK-NEXT: volatile load 281 // CHECK-NEXT: volatile load 282 // CHECK-NEXT: volatile store 283 // CHECK-NEXT: volatile store 284 // CHECK-NEXT: volatile load 285 // CHECK-NEXT: volatile load 286 287 // A use. 288 (float)(i=i); 289 // CHECK-NEXT: volatile load 290 // CHECK-NEXT: volatile store 291 // CHECK-NEXT: volatile load 292 // CHECK-NEXT: sitofp 293 294 // A use. gcc treats this as not a use, that's probably a bug due to tree 295 // folding ignoring volatile. 296 (int)(i=i); 297 // CHECK-NEXT: volatile load 298 // CHECK-NEXT: volatile store 299 // CHECK-NEXT: volatile load 300 301 // A use. 302 -(i=j); 303 // CHECK-NEXT: volatile load 304 // CHECK-NEXT: volatile store 305 // CHECK-NEXT: volatile load 306 // CHECK-NEXT: sub 307 308 // A use. gcc treats this a not a use, that's probably a bug due to tree 309 // folding ignoring volatile. 310 +(i=k); 311 // CHECK-NEXT: volatile load 312 // CHECK-NEXT: volatile store 313 // CHECK-NEXT: volatile load 314 315 // A use. gcc treats this a not a use, that's probably a bug due to tree 316 // folding ignoring volatile. 317 __real (ci=ci); 318 // CHECK-NEXT: volatile load 319 // CHECK-NEXT: volatile load 320 // CHECK-NEXT: volatile store 321 // CHECK-NEXT: volatile store 322 323 // A use. 324 i + 0; 325 // CHECK-NEXT: volatile load 326 // CHECK-NEXT: add 327 328 // A use. 329 (i=j) + i; 330 // CHECK-NEXT: volatile load 331 // CHECK-NEXT: volatile store 332 // CHECK-NEXT: volatile load 333 // CHECK-NEXT: volatile load 334 // CHECK-NEXT: add 335 336 // A use. gcc treats this as not a use, that's probably a bug due to tree 337 // folding ignoring volatile. 338 (i=j) + 0; 339 // CHECK-NEXT: volatile load 340 // CHECK-NEXT: volatile store 341 // CHECK-NEXT: volatile load 342 // CHECK-NEXT: add 343 344 (i,j)=k; 345 // CHECK-NEXT: volatile load [[INT]]* @k 346 // CHECK-NEXT: volatile store {{.*}}, [[INT]]* @j 347 348 (j=k,i)=i; 349 // CHECK-NEXT: volatile load [[INT]]* @k 350 // CHECK-NEXT: volatile store {{.*}}, [[INT]]* @j 351 // CHECK-NEXT: volatile load [[INT]]* @i 352 // CHECK-NEXT: volatile store {{.*}}, [[INT]]* @i 353 354 // CHECK-NEXT: ret void 355} 356