326 lines · c
1// RUN: %clang_cc1 -Wno-return-type -Wno-unused-value -emit-llvm %s -w -o - | FileCheck %s2 3// CHECK: @i = {{(dso_local )?}}global [[INT:i[0-9]+]] 04volatile int i, j, k;5volatile int ar[5];6volatile char c;7// CHECK: @ci = {{(dso_local )?}}global [[CINT:.*]] zeroinitializer8volatile _Complex int ci;9volatile struct S {10#ifdef __cplusplus11 void operator =(volatile struct S&o) volatile;12#endif13 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// Note that these test results are very much specific to C!21// Assignments in C++ yield l-values, not r-values, and the situations22// that do implicit lvalue-to-rvalue conversion are substantially23// reduced.24 25// CHECK-LABEL: define {{.*}}void @test()26void test(void) {27 // CHECK: load volatile [[INT]], ptr @i28 i;29 // CHECK-NEXT: load volatile [[INT]], ptr @ci, align [[ALIGN:[0-9]+]]30 // CHECK-NEXT: load volatile [[INT]], ptr getelementptr inbounds nuw ([[CINT]], ptr @ci, i32 0, i32 1), align [[ALIGN_GEP:[0-9]+]]31 // CHECK-NEXT: sitofp [[INT]]32 (float)(ci);33 // CHECK-NEXT: load volatile [[INT]], ptr @ci, align [[ALIGN]]34 // CHECK-NEXT: load volatile [[INT]], ptr getelementptr inbounds nuw ([[CINT]], ptr @ci, i32 0, i32 1), align [[ALIGN_GEP]]35 (void)ci;36 // CHECK-NEXT: memcpy37 (void)a;38 // CHECK-NEXT: [[R:%.*]] = load volatile [[INT]], ptr @ci, align [[ALIGN]]39 // CHECK-NEXT: [[I:%.*]] = load volatile [[INT]], ptr getelementptr inbounds nuw ([[CINT]], ptr @ci, i32 0, i32 1), align [[ALIGN_GEP]]40 // CHECK-NEXT: store volatile [[INT]] [[R]], ptr @ci, align [[ALIGN]]41 // CHECK-NEXT: store volatile [[INT]] [[I]], ptr getelementptr inbounds nuw ([[CINT]], ptr @ci, i32 0, i32 1), align [[ALIGN_GEP]]42 (void)(ci=ci);43 // CHECK-NEXT: [[T:%.*]] = load volatile [[INT]], ptr @j44 // CHECK-NEXT: store volatile [[INT]] [[T]], ptr @i45 (void)(i=j);46 // CHECK-NEXT: [[R1:%.*]] = load volatile [[INT]], ptr @ci, align [[ALIGN]]47 // CHECK-NEXT: [[I1:%.*]] = load volatile [[INT]], ptr getelementptr inbounds nuw ([[CINT]], ptr @ci, i32 0, i32 1), align [[ALIGN_GEP]]48 // CHECK-NEXT: [[R2:%.*]] = load volatile [[INT]], ptr @ci, align [[ALIGN]]49 // CHECK-NEXT: [[I2:%.*]] = load volatile [[INT]], ptr getelementptr inbounds nuw ([[CINT]], ptr @ci, i32 0, i32 1), align [[ALIGN_GEP]]50 // Not sure why they're ordered this way.51 // CHECK-NEXT: [[R:%.*]] = add [[INT]] [[R2]], [[R1]]52 // CHECK-NEXT: [[I:%.*]] = add [[INT]] [[I2]], [[I1]]53 // CHECK-NEXT: store volatile [[INT]] [[R]], ptr @ci, align [[ALIGN]]54 // CHECK-NEXT: store volatile [[INT]] [[I]], ptr getelementptr inbounds nuw ([[CINT]], ptr @ci, i32 0, i32 1), align [[ALIGN_GEP]]55 ci+=ci;56 57 // CHECK-NEXT: [[R1:%.*]] = load volatile [[INT]], ptr @ci, align [[ALIGN]]58 // CHECK-NEXT: [[I1:%.*]] = load volatile [[INT]], ptr getelementptr inbounds nuw ([[CINT]], ptr @ci, i32 0, i32 1), align [[ALIGN_GEP]]59 // CHECK-NEXT: [[R2:%.*]] = load volatile [[INT]], ptr @ci, align [[ALIGN]]60 // CHECK-NEXT: [[I2:%.*]] = load volatile [[INT]], ptr getelementptr inbounds nuw ([[CINT]], ptr @ci, i32 0, i32 1), align [[ALIGN_GEP]]61 // CHECK-NEXT: [[R:%.*]] = add [[INT]] [[R2]], [[R1]]62 // CHECK-NEXT: [[I:%.*]] = add [[INT]] [[I2]], [[I1]]63 // CHECK-NEXT: store volatile [[INT]] [[R]], ptr @ci, align [[ALIGN]]64 // CHECK-NEXT: store volatile [[INT]] [[I]], ptr getelementptr inbounds nuw ([[CINT]], ptr @ci, i32 0, i32 1), align [[ALIGN_GEP]]65 // CHECK-NEXT: [[R2:%.*]] = load volatile [[INT]], ptr @ci, align [[ALIGN]]66 // CHECK-NEXT: [[I2:%.*]] = load volatile [[INT]], ptr getelementptr inbounds nuw ([[CINT]], ptr @ci, i32 0, i32 1), align [[ALIGN_GEP]]67 // These additions can be elided68 // CHECK-NEXT: add [[INT]] [[R]], [[R2]]69 // CHECK-NEXT: add [[INT]] [[I]], [[I2]]70 (ci += ci) + ci;71 // CHECK-NEXT: call void asm72 asm("nop");73 // CHECK-NEXT: load volatile74 // CHECK-NEXT: load volatile75 // CHECK-NEXT: add nsw [[INT]]76 // CHECK-NEXT: store volatile77 // CHECK-NEXT: load volatile78 // CHECK-NEXT: add nsw [[INT]]79 (i += j) + k;80 // CHECK-NEXT: call void asm81 asm("nop");82 // CHECK-NEXT: load volatile83 // CHECK-NEXT: load volatile84 // CHECK-NEXT: add nsw [[INT]]85 // CHECK-NEXT: store volatile86 // CHECK-NEXT: add nsw [[INT]]87 (i += j) + 1;88 // CHECK-NEXT: call void asm89 asm("nop");90 // CHECK-NEXT: load volatile91 // CHECK-NEXT: load volatile92 // CHECK-NEXT: load volatile93 // CHECK-NEXT: load volatile94 // CHECK-NEXT: add [[INT]]95 // CHECK-NEXT: add [[INT]]96 ci+ci;97 98 // CHECK-NEXT: load volatile99 __real i;100 // CHECK-NEXT: load volatile101 // CHECK-NEXT: load volatile102 +ci;103 // CHECK-NEXT: call void asm104 asm("nop");105 // CHECK-NEXT: load volatile106 // CHECK-NEXT: store volatile107 (void)(i=i);108 // CHECK-NEXT: load volatile109 // CHECK-NEXT: store volatile110 // CHECK-NEXT: sitofp111 (float)(i=i);112 // CHECK-NEXT: load volatile113 (void)i;114 // CHECK-NEXT: load volatile115 // CHECK-NEXT: store volatile116 i=i;117 // CHECK-NEXT: load volatile118 // CHECK-NEXT: store volatile119 // CHECK-NEXT: store volatile120 i=i=i;121#ifndef __cplusplus122 // CHECK-NEXT: load volatile123 // CHECK-NEXT: store volatile124 (void)__builtin_choose_expr(0, i=i, j=j);125#endif126 // CHECK-NEXT: load volatile127 // CHECK-NEXT: icmp128 // CHECK-NEXT: br i1129 // CHECK: load volatile130 // CHECK-NEXT: store volatile131 // CHECK-NEXT: br label132 // CHECK: load volatile133 // CHECK-NEXT: store volatile134 // CHECK-NEXT: br label135 k ? (i=i) : (j=j);136 // CHECK: phi137 // CHECK-NEXT: load volatile138 // CHECK-NEXT: load volatile139 // CHECK-NEXT: store volatile140 (void)(i,(i=i));141 // CHECK-NEXT: load volatile142 // CHECK-NEXT: store volatile143 // CHECK-NEXT: load volatile144 i=i,i;145 // CHECK-NEXT: load volatile146 // CHECK-NEXT: store volatile147 // CHECK-NEXT: load volatile148 // CHECK-NEXT: store volatile149 (i=j,k=j);150 // CHECK-NEXT: load volatile151 // CHECK-NEXT: store volatile152 // CHECK-NEXT: load volatile153 (i=j,k);154 // CHECK-NEXT: load volatile155 // CHECK-NEXT: load volatile156 (i,j);157 // CHECK-NEXT: load volatile158 // CHECK-NEXT: trunc159 // CHECK-NEXT: store volatile160 // CHECK-NEXT: sext161 // CHECK-NEXT: store volatile162 i=c=k;163 // CHECK-NEXT: load volatile164 // CHECK-NEXT: load volatile165 // CHECK-NEXT: add nsw [[INT]]166 // CHECK-NEXT: store volatile167 i+=k;168 // CHECK-NEXT: load volatile169 // CHECK-NEXT: load volatile170 ci;171#ifndef __cplusplus172 // CHECK-NEXT: load volatile173 // CHECK-NEXT: load volatile174 (int)ci;175 // CHECK-NEXT: load volatile176 // CHECK-NEXT: load volatile177 // CHECK-NEXT: icmp ne178 // CHECK-NEXT: icmp ne179 // CHECK-NEXT: or i1180 (_Bool)ci;181#endif182 // CHECK-NEXT: load volatile183 // CHECK-NEXT: load volatile184 // CHECK-NEXT: store volatile185 // CHECK-NEXT: store volatile186 ci=ci;187 // CHECK-NEXT: load volatile188 // CHECK-NEXT: load volatile189 // CHECK-NEXT: store volatile190 // CHECK-NEXT: store volatile191 // CHECK-NEXT: store volatile192 // CHECK-NEXT: store volatile193 ci=ci=ci;194 // CHECK-NEXT: [[T:%.*]] = load volatile [[INT]], ptr getelementptr inbounds nuw ([[CINT]], ptr @ci, i32 0, i32 1)195 // CHECK-NEXT: store volatile [[INT]] [[T]], ptr getelementptr inbounds nuw ([[CINT]], ptr @ci, i32 0, i32 1)196 // CHECK-NEXT: store volatile [[INT]] [[T]], ptr getelementptr inbounds nuw ([[CINT]], ptr @ci, i32 0, i32 1)197 __imag ci = __imag ci = __imag ci;198 // CHECK-NEXT: load volatile199 // CHECK-NEXT: store volatile200 __real (i = j);201 // CHECK-NEXT: load volatile202 __imag i;203 204 // ============================================================205 // FIXME: Test cases we get wrong.206 207 // A use. We load all of a into a copy of a, then load i. gcc forgets to do208 // the assignment.209 // (a = a).i;210 211 // ============================================================212 // Test cases where we intentionally differ from gcc, due to suspected bugs in213 // gcc.214 215 // Not a use. gcc forgets to do the assignment.216 // CHECK-NEXT: call void @llvm.memcpy{{.*}}, i1 true217 // CHECK-NEXT: call void @llvm.memcpy{{.*}}, i1 true218 ((a=a),a);219 220 // Not a use. gcc gets this wrong, it doesn't emit the copy! 221 // (void)(a=a);222 223 // Not a use. gcc got this wrong in 4.2 and omitted the side effects224 // entirely, but it is fixed in 4.4.0.225 // CHECK-NEXT: load volatile226 // CHECK-NEXT: store volatile227 __imag (i = j);228 229#ifndef __cplusplus230 // A use of the real part231 // CHECK-NEXT: load volatile232 // CHECK-NEXT: load volatile233 // CHECK-NEXT: store volatile234 // CHECK-NEXT: store volatile235 // CHECK-NEXT: sitofp236 (float)(ci=ci);237 // Not a use, bug? gcc treats this as not a use, that's probably a bug due to238 // tree folding ignoring volatile.239 // CHECK-NEXT: load volatile240 // CHECK-NEXT: load volatile241 // CHECK-NEXT: store volatile242 // CHECK-NEXT: store volatile243 (int)(ci=ci);244#endif245 246 // A use.247 // CHECK-NEXT: load volatile248 // CHECK-NEXT: store volatile249 // CHECK-NEXT: sitofp250 (float)(i=i);251 // A use. gcc treats this as not a use, that's probably a bug due to tree252 // folding ignoring volatile.253 // CHECK-NEXT: load volatile254 // CHECK-NEXT: store volatile255 (int)(i=i);256 257 // A use.258 // CHECK-NEXT: load volatile259 // CHECK-NEXT: store volatile260 // CHECK-NEXT: sub261 -(i=j);262 // A use. gcc treats this a not a use, that's probably a bug due to tree263 // folding ignoring volatile.264 // CHECK-NEXT: load volatile265 // CHECK-NEXT: store volatile266 +(i=k);267 268 // A use. gcc treats this a not a use, that's probably a bug due to tree269 // folding ignoring volatile.270 // CHECK-NEXT: load volatile271 // CHECK-NEXT: load volatile272 // CHECK-NEXT: store volatile273 // CHECK-NEXT: store volatile274 __real (ci=ci);275 276 // A use.277 // CHECK-NEXT: load volatile278 // CHECK-NEXT: add279 i + 0;280 // A use.281 // CHECK-NEXT: load volatile282 // CHECK-NEXT: store volatile283 // CHECK-NEXT: load volatile284 // CHECK-NEXT: add285 (i=j) + i;286 // A use. gcc treats this as not a use, that's probably a bug due to tree287 // folding ignoring volatile.288 // CHECK-NEXT: load volatile289 // CHECK-NEXT: store volatile290 // CHECK-NEXT: add291 (i=j) + 0;292 293#ifdef __cplusplus294 (i,j)=k;295 (j=k,i)=i;296 struct { int x; } s, s1;297 printf("s is at %p\n", &s);298 printf("s is at %p\n", &(s = s1));299 printf("s.x is at %p\n", &((s = s1).x));300#endif301}302 303extern volatile enum X x;304// CHECK-LABEL: define {{.*}}void @test1()305void test1(void) {306 extern void test1_helper(void);307 test1_helper();308 // CHECK: call {{.*}}void @test1_helper()309 // CHECK-NEXT: ret void310 x;311 (void) x;312 return x;313}314 315// CHECK: define {{.*}} @test2()316int test2(void) {317 // CHECK: load volatile i32, ptr318 // CHECK-NEXT: load volatile i32, ptr319 // CHECK-NEXT: load volatile i32, ptr320 // CHECK-NEXT: add i32321 // CHECK-NEXT: add i32322 // CHECK-NEXT: store volatile i32323 // CHECK-NEXT: ret i32324 return i += ci;325}326