367 lines · cpp
1// RUN: %clang_cc1 -Wno-unused-value -triple %itanium_abi_triple -emit-llvm %s -std=c++98 -o - | FileCheck %s2// RUN: %clang_cc1 -Wno-unused-value -triple %itanium_abi_triple -emit-llvm %s -std=c++11 -o - | FileCheck -check-prefix=CHECK -check-prefix=CHECK11 %s3 4// CHECK: @i = {{(dso_local )?}}global [[INT:i[0-9]+]] 05volatile int i, j, k;6volatile int ar[5];7volatile char c;8// CHECK: @ci = {{(dso_local )?}}global [[CINT:.*]] zeroinitializer9volatile _Complex int ci;10volatile struct S {11#ifdef __cplusplus12 void operator =(volatile struct S&o) volatile;13#endif14 int i;15} a, b;16 17//void operator =(volatile struct S&o1, volatile struct S&o2) volatile;18int printf(const char *, ...);19 20 21// CHECK: define {{.*}}void @{{.*}}test22void test() {23 24 asm("nop"); // CHECK: call void asm25 26 // should not load in C++9827 i;28 // CHECK11-NEXT: load volatile [[INT]], ptr @i29 30 (float)(ci);31 // CHECK-NEXT: load volatile [[INT]], ptr @ci32 // CHECK-NEXT: load volatile [[INT]], ptr getelementptr inbounds nuw ([[CINT]], ptr @ci, i32 0, i32 1)33 // CHECK-NEXT: sitofp [[INT]]34 35 // These are not uses in C++98:36 // [expr.static.cast]p6:37 // The lvalue-to-rvalue . . . conversions are not applied to the expression.38 (void)ci;39 // CHECK11-NEXT: load volatile [[INT]], ptr @ci40 // CHECK11-NEXT: load volatile [[INT]], ptr getelementptr inbounds nuw ([[CINT]], ptr @ci, i32 0, i32 1)41 42 (void)a;43 44 (void)(ci=ci);45 // CHECK-NEXT: [[R:%.*]] = load volatile [[INT]], ptr @ci46 // CHECK-NEXT: [[I:%.*]] = load volatile [[INT]], ptr getelementptr inbounds nuw ([[CINT]], ptr @ci, i32 0, i32 1)47 // CHECK-NEXT: store volatile [[INT]] [[R]], ptr @ci48 // CHECK-NEXT: store volatile [[INT]] [[I]], ptr getelementptr inbounds nuw ([[CINT]], ptr @ci, i32 0, i32 1)49 50 (void)(i=j);51 // CHECK-NEXT: [[T:%.*]] = load volatile [[INT]], ptr @j52 // CHECK-NEXT: store volatile [[INT]] [[T]], ptr @i53 54 ci+=ci;55 // CHECK-NEXT: [[R1:%.*]] = load volatile [[INT]], ptr @ci56 // CHECK-NEXT: [[I1:%.*]] = load volatile [[INT]], ptr getelementptr inbounds nuw ([[CINT]], ptr @ci, i32 0, i32 1)57 // CHECK-NEXT: [[R2:%.*]] = load volatile [[INT]], ptr @ci58 // CHECK-NEXT: [[I2:%.*]] = load volatile [[INT]], ptr getelementptr inbounds nuw ([[CINT]], ptr @ci, i32 0, i32 1)59 // Not sure why they're ordered this way.60 // CHECK-NEXT: [[R:%.*]] = add [[INT]] [[R2]], [[R1]]61 // CHECK-NEXT: [[I:%.*]] = add [[INT]] [[I2]], [[I1]]62 // CHECK-NEXT: store volatile [[INT]] [[R]], ptr @ci63 // CHECK-NEXT: store volatile [[INT]] [[I]], ptr getelementptr inbounds nuw ([[CINT]], ptr @ci, i32 0, i32 1)64 65 // Note that C++ requires an extra load volatile over C from the LHS of the '+'.66 (ci += ci) + ci;67 // CHECK-NEXT: [[R1:%.*]] = load volatile [[INT]], ptr @ci68 // CHECK-NEXT: [[I1:%.*]] = load volatile [[INT]], ptr getelementptr inbounds nuw ([[CINT]], ptr @ci, i32 0, i32 1)69 // CHECK-NEXT: [[R2:%.*]] = load volatile [[INT]], ptr @ci70 // CHECK-NEXT: [[I2:%.*]] = load volatile [[INT]], ptr getelementptr inbounds nuw ([[CINT]], ptr @ci, i32 0, i32 1)71 // CHECK-NEXT: [[R:%.*]] = add [[INT]] [[R2]], [[R1]]72 // CHECK-NEXT: [[I:%.*]] = add [[INT]] [[I2]], [[I1]]73 // CHECK-NEXT: store volatile [[INT]] [[R]], ptr @ci74 // CHECK-NEXT: store volatile [[INT]] [[I]], ptr getelementptr inbounds nuw ([[CINT]], ptr @ci, i32 0, i32 1)75 // CHECK-NEXT: [[R1:%.*]] = load volatile [[INT]], ptr @ci76 // CHECK-NEXT: [[I1:%.*]] = load volatile [[INT]], ptr getelementptr inbounds nuw ([[CINT]], ptr @ci, i32 0, i32 1)77 // CHECK-NEXT: [[R2:%.*]] = load volatile [[INT]], ptr @ci78 // CHECK-NEXT: [[I2:%.*]] = load volatile [[INT]], ptr getelementptr inbounds nuw ([[CINT]], ptr @ci, i32 0, i32 1)79 // These additions can be elided.80 // CHECK-NEXT: add [[INT]] [[R1]], [[R2]]81 // CHECK-NEXT: add [[INT]] [[I1]], [[I2]]82 83 asm("nop"); // CHECK-NEXT: call void asm84 85 // Extra load volatile in C++.86 (i += j) + k;87 // CHECK-NEXT: load volatile88 // CHECK-NEXT: load volatile89 // CHECK-NEXT: add nsw [[INT]]90 // CHECK-NEXT: store volatile91 // CHECK-NEXT: load volatile92 // CHECK-NEXT: load volatile93 // CHECK-NEXT: add nsw [[INT]]94 95 asm("nop"); // CHECK-NEXT: call void asm96 97 // Extra load volatile in C++.98 (i += j) + 1;99 // CHECK-NEXT: load volatile100 // CHECK-NEXT: load volatile101 // CHECK-NEXT: add nsw [[INT]]102 // CHECK-NEXT: store volatile103 // CHECK-NEXT: load volatile104 // CHECK-NEXT: add nsw [[INT]]105 106 asm("nop"); // CHECK-NEXT: call void asm107 108 ci+ci;109 // CHECK-NEXT: load volatile110 // CHECK-NEXT: load volatile111 // CHECK-NEXT: load volatile112 // CHECK-NEXT: load volatile113 // CHECK-NEXT: add [[INT]]114 // CHECK-NEXT: add [[INT]]115 116 __real i;117 118 +ci;119 // CHECK-NEXT: load volatile120 // CHECK-NEXT: load volatile121 122 asm("nop"); // CHECK-NEXT: call void asm123 124 (void)(i=i);125 // CHECK-NEXT: load volatile126 // CHECK-NEXT: store volatile127 128 (float)(i=i);129 // CHECK-NEXT: load volatile130 // CHECK-NEXT: store volatile131 // CHECK-NEXT: load volatile132 // CHECK-NEXT: sitofp133 134 (void)i; // This is now a load in C++11135 // CHECK11-NEXT: load volatile136 137 i=i;138 // CHECK-NEXT: load volatile139 // CHECK-NEXT: store volatile140 141 // Extra load volatile in C++.142 i=i=i;143 // CHECK-NEXT: load volatile144 // CHECK-NEXT: store volatile145 // CHECK-NEXT: load volatile146 // CHECK-NEXT: store volatile147 148 (void)__builtin_choose_expr(0, i=i, j=j);149 // CHECK-NEXT: load volatile150 // CHECK-NEXT: store volatile151 152 k ? (i=i) : (j=j);153 // CHECK-NEXT: load volatile154 // CHECK-NEXT: icmp155 // CHECK-NEXT: br i1156 // CHECK: load volatile157 // CHECK-NEXT: store volatile158 // CHECK-NEXT: br label159 // CHECK: load volatile160 // CHECK-NEXT: store volatile161 // CHECK-NEXT: br label162 // CHECK: phi163 164 (void)(i,(i=i)); // first i is also a load in C++11165 // CHECK11-NEXT: load volatile166 // CHECK-NEXT: load volatile167 // CHECK-NEXT: store volatile168 169 i=i,k; // k is also a load in C++11170 // CHECK-NEXT: load volatile [[INT]], ptr @i171 // CHECK-NEXT: store volatile {{.*}}, ptr @i172 // CHECK11-NEXT: load volatile [[INT]], ptr @k173 174 (i=j,k=j);175 // CHECK-NEXT: load volatile [[INT]], ptr @j176 // CHECK-NEXT: store volatile {{.*}}, ptr @i177 // CHECK-NEXT: load volatile [[INT]], ptr @j178 // CHECK-NEXT: store volatile {{.*}}, ptr @k179 180 (i=j,k); // k is also a load in C++11181 // CHECK-NEXT: load volatile [[INT]], ptr @j182 // CHECK-NEXT: store volatile {{.*}}, ptr @i183 // CHECK11-NEXT: load volatile [[INT]], ptr @k184 185 (i,j); // i and j both are loads in C++11186 // CHECK11-NEXT: load volatile [[INT]], ptr @i187 // CHECK11-NEXT: load volatile [[INT]], ptr @j188 189 // Extra load in C++.190 i=c=k;191 // CHECK-NEXT: load volatile192 // CHECK-NEXT: trunc193 // CHECK-NEXT: store volatile194 // CHECK-NEXT: load volatile195 // CHECK-NEXT: sext196 // CHECK-NEXT: store volatile197 198 i+=k;199 // CHECK-NEXT: load volatile200 // CHECK-NEXT: load volatile201 // CHECK-NEXT: add nsw [[INT]]202 // CHECK-NEXT: store volatile203 204 ci; // ci is a load in C++11205 // CHECK11-NEXT: load volatile {{.*}} @ci206 // CHECK11-NEXT: load volatile {{.*}} @ci, i32 0, i32 1207 208 asm("nop"); // CHECK-NEXT: call void asm209 210 (int)ci;211 // CHECK-NEXT: load volatile {{.*}} @ci212 // CHECK-NEXT: load volatile {{.*}} @ci, i32 0, i32 1213 214 (bool)ci;215 // CHECK-NEXT: load volatile {{.*}} @ci216 // CHECK-NEXT: load volatile {{.*}} @ci, i32 0, i32 1217 // CHECK-NEXT: icmp ne218 // CHECK-NEXT: icmp ne219 // CHECK-NEXT: or i1220 221 ci=ci;222 // CHECK-NEXT: load volatile223 // CHECK-NEXT: load volatile224 // CHECK-NEXT: store volatile225 // CHECK-NEXT: store volatile226 227 asm("nop"); // CHECK-NEXT: call void asm228 229 // Extra load in C++.230 ci=ci=ci;231 // CHECK-NEXT: load volatile232 // CHECK-NEXT: load volatile233 // CHECK-NEXT: store volatile234 // CHECK-NEXT: store volatile235 // CHECK-NEXT: load volatile236 // CHECK-NEXT: load volatile237 // CHECK-NEXT: store volatile238 // CHECK-NEXT: store volatile239 240 __imag ci = __imag ci = __imag ci;241 // CHECK-NEXT: [[T:%.*]] = load volatile [[INT]], ptr getelementptr inbounds nuw ([[CINT]], ptr @ci, i32 0, i32 1)242 // CHECK-NEXT: store volatile [[INT]] [[T]], ptr getelementptr inbounds nuw ([[CINT]], ptr @ci, i32 0, i32 1)243 // CHECK-NEXT: [[T:%.*]] = load volatile [[INT]], ptr getelementptr inbounds nuw ([[CINT]], ptr @ci, i32 0, i32 1)244 // CHECK-NEXT: store volatile [[INT]] [[T]], ptr getelementptr inbounds nuw ([[CINT]], ptr @ci, i32 0, i32 1)245 246 __real (i = j);247 // CHECK-NEXT: load volatile248 // CHECK-NEXT: store volatile249 250 __imag i;251 252 // ============================================================253 // FIXME: Test cases we get wrong.254 255 // A use. We load all of a into a copy of a, then load i. gcc forgets to do256 // the assignment.257 // (a = a).i;258 259 // ============================================================260 // Test cases where we intentionally differ from gcc, due to suspected bugs in261 // gcc.262 263 // Not a use. gcc forgets to do the assignment.264 // CHECK-NEXT: call {{.*}}void265 ((a=a),a);266 267 // Not a use. gcc gets this wrong, it doesn't emit the copy! 268 // CHECK-NEXT: call {{.*}}void269 (void)(a=a);270 271 // Not a use. gcc got this wrong in 4.2 and omitted the side effects272 // entirely, but it is fixed in 4.4.0.273 __imag (i = j);274 // CHECK-NEXT: load volatile275 // CHECK-NEXT: store volatile276 277 // C++ does an extra load here. Note that we have to do full loads.278 (float)(ci=ci);279 // CHECK-NEXT: load volatile280 // CHECK-NEXT: load volatile281 // CHECK-NEXT: store volatile282 // CHECK-NEXT: store volatile283 // CHECK-NEXT: load volatile284 // CHECK-NEXT: load volatile285 // CHECK-NEXT: sitofp286 287 // Not a use, bug? gcc treats this as not a use, that's probably a288 // bug due to tree folding ignoring volatile.289 (int)(ci=ci);290 // CHECK-NEXT: load volatile291 // CHECK-NEXT: load volatile292 // CHECK-NEXT: store volatile293 // CHECK-NEXT: store volatile294 // CHECK-NEXT: load volatile295 // CHECK-NEXT: load volatile296 297 // A use.298 (float)(i=i);299 // CHECK-NEXT: load volatile300 // CHECK-NEXT: store volatile301 // CHECK-NEXT: load volatile302 // CHECK-NEXT: sitofp303 304 // A use. gcc treats this as not a use, that's probably a bug due to tree305 // folding ignoring volatile.306 (int)(i=i);307 // CHECK-NEXT: load volatile308 // CHECK-NEXT: store volatile309 // CHECK-NEXT: load volatile310 311 // A use.312 -(i=j);313 // CHECK-NEXT: load volatile314 // CHECK-NEXT: store volatile315 // CHECK-NEXT: load volatile316 // CHECK-NEXT: sub317 318 // A use. gcc treats this a not a use, that's probably a bug due to tree319 // folding ignoring volatile.320 +(i=k);321 // CHECK-NEXT: load volatile322 // CHECK-NEXT: store volatile323 // CHECK-NEXT: load volatile324 325 // A use. gcc treats this a not a use, that's probably a bug due to tree326 // folding ignoring volatile.327 __real (ci=ci);328 // CHECK-NEXT: load volatile329 // CHECK-NEXT: load volatile330 // CHECK-NEXT: store volatile331 // CHECK-NEXT: store volatile332 333 // A use.334 i + 0;335 // CHECK-NEXT: load volatile336 // CHECK-NEXT: add337 338 // A use.339 (i=j) + i;340 // CHECK-NEXT: load volatile341 // CHECK-NEXT: store volatile342 // CHECK-NEXT: load volatile343 // CHECK-NEXT: load volatile344 // CHECK-NEXT: add345 346 // A use. gcc treats this as not a use, that's probably a bug due to tree347 // folding ignoring volatile.348 (i=j) + 0;349 // CHECK-NEXT: load volatile350 // CHECK-NEXT: store volatile351 // CHECK-NEXT: load volatile352 // CHECK-NEXT: add353 354 (i,j)=k; // i is also a load in C++11355 // CHECK-NEXT: load volatile [[INT]], ptr @k356 // CHECK11-NEXT: load volatile [[INT]], ptr @i357 // CHECK-NEXT: store volatile {{.*}}, ptr @j358 359 (j=k,i)=i;360 // CHECK-NEXT: load volatile [[INT]], ptr @i361 // CHECK-NEXT: load volatile [[INT]], ptr @k362 // CHECK-NEXT: store volatile {{.*}}, ptr @j363 // CHECK-NEXT: store volatile {{.*}}, ptr @i364 365 // CHECK-NEXT: ret void366}367