summaryrefslogtreecommitdiff
path: root/clang/test/CodeGen/volatile-1.c
diff options
context:
space:
mode:
Diffstat (limited to 'clang/test/CodeGen/volatile-1.c')
-rw-r--r--clang/test/CodeGen/volatile-1.c315
1 files changed, 315 insertions, 0 deletions
diff --git a/clang/test/CodeGen/volatile-1.c b/clang/test/CodeGen/volatile-1.c
new file mode 100644
index 0000000..6551159
--- /dev/null
+++ b/clang/test/CodeGen/volatile-1.c
@@ -0,0 +1,315 @@
+// RUN: %clang_cc1 -Wno-return-type -Wno-unused-value -emit-llvm %s -o - | FileCheck %s
+
+// CHECK: @i = common global [[INT:i[0-9]+]] 0
+volatile int i, j, k;
+volatile int ar[5];
+volatile char c;
+// CHECK: @ci = common global [[CINT:.*]] zeroinitializer
+volatile _Complex int ci;
+volatile struct S {
+#ifdef __cplusplus
+ void operator =(volatile struct S&o) volatile;
+#endif
+ int i;
+} a, b;
+
+//void operator =(volatile struct S&o1, volatile struct S&o2) volatile;
+int printf(const char *, ...);
+
+
+// Note that these test results are very much specific to C!
+// Assignments in C++ yield l-values, not r-values, and the situations
+// that do implicit lvalue-to-rvalue conversion are substantially
+// reduced.
+
+// CHECK: define void @test()
+void test() {
+ // CHECK: load volatile [[INT]]* @i
+ i;
+ // CHECK-NEXT: load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0)
+ // CHECK-NEXT: load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1)
+ // CHECK-NEXT: sitofp [[INT]]
+ (float)(ci);
+ // CHECK-NEXT: load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0)
+ // CHECK-NEXT: load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1)
+ (void)ci;
+ // CHECK-NEXT: bitcast
+ // CHECK-NEXT: memcpy
+ (void)a;
+ // CHECK-NEXT: [[R:%.*]] = load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0)
+ // CHECK-NEXT: [[I:%.*]] = load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1)
+ // CHECK-NEXT: store volatile [[INT]] [[R]], [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0)
+ // CHECK-NEXT: store volatile [[INT]] [[I]], [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1)
+ (void)(ci=ci);
+ // CHECK-NEXT: [[T:%.*]] = load volatile [[INT]]* @j
+ // CHECK-NEXT: store volatile [[INT]] [[T]], [[INT]]* @i
+ (void)(i=j);
+ // CHECK-NEXT: [[R1:%.*]] = load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0)
+ // CHECK-NEXT: [[I1:%.*]] = load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1)
+ // CHECK-NEXT: [[R2:%.*]] = load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0)
+ // CHECK-NEXT: [[I2:%.*]] = load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1)
+ // Not sure why they're ordered this way.
+ // CHECK-NEXT: [[R:%.*]] = add [[INT]] [[R2]], [[R1]]
+ // CHECK-NEXT: [[I:%.*]] = add [[INT]] [[I2]], [[I1]]
+ // CHECK-NEXT: store volatile [[INT]] [[R]], [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0)
+ // CHECK-NEXT: store volatile [[INT]] [[I]], [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1)
+ ci+=ci;
+
+ // CHECK-NEXT: [[R1:%.*]] = load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0)
+ // CHECK-NEXT: [[I1:%.*]] = load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1)
+ // CHECK-NEXT: [[R2:%.*]] = load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0)
+ // CHECK-NEXT: [[I2:%.*]] = load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1)
+ // CHECK-NEXT: [[R:%.*]] = add [[INT]] [[R2]], [[R1]]
+ // CHECK-NEXT: [[I:%.*]] = add [[INT]] [[I2]], [[I1]]
+ // CHECK-NEXT: store volatile [[INT]] [[R]], [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0)
+ // CHECK-NEXT: store volatile [[INT]] [[I]], [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1)
+ // CHECK-NEXT: [[R2:%.*]] = load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0)
+ // CHECK-NEXT: [[I2:%.*]] = load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1)
+ // These additions can be elided
+ // CHECK-NEXT: add [[INT]] [[R]], [[R2]]
+ // CHECK-NEXT: add [[INT]] [[I]], [[I2]]
+ (ci += ci) + ci;
+ // CHECK-NEXT: call void asm
+ asm("nop");
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: add nsw [[INT]]
+ // CHECK-NEXT: store volatile
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: add nsw [[INT]]
+ (i += j) + k;
+ // CHECK-NEXT: call void asm
+ asm("nop");
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: add nsw [[INT]]
+ // CHECK-NEXT: store volatile
+ // CHECK-NEXT: add nsw [[INT]]
+ (i += j) + 1;
+ // CHECK-NEXT: call void asm
+ asm("nop");
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: add [[INT]]
+ // CHECK-NEXT: add [[INT]]
+ ci+ci;
+
+ // CHECK-NEXT: load volatile
+ __real i;
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: load volatile
+ +ci;
+ // CHECK-NEXT: call void asm
+ asm("nop");
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: store volatile
+ (void)(i=i);
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: store volatile
+ // CHECK-NEXT: sitofp
+ (float)(i=i);
+ // CHECK-NEXT: load volatile
+ (void)i;
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: store volatile
+ i=i;
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: store volatile
+ // CHECK-NEXT: store volatile
+ i=i=i;
+#ifndef __cplusplus
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: store volatile
+ (void)__builtin_choose_expr(0, i=i, j=j);
+#endif
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: icmp
+ // CHECK-NEXT: br i1
+ // CHECK: load volatile
+ // CHECK-NEXT: store volatile
+ // CHECK-NEXT: br label
+ // CHECK: load volatile
+ // CHECK-NEXT: store volatile
+ // CHECK-NEXT: br label
+ k ? (i=i) : (j=j);
+ // CHECK: phi
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: store volatile
+ (void)(i,(i=i));
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: store volatile
+ // CHECK-NEXT: load volatile
+ i=i,i;
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: store volatile
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: store volatile
+ (i=j,k=j);
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: store volatile
+ // CHECK-NEXT: load volatile
+ (i=j,k);
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: load volatile
+ (i,j);
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: trunc
+ // CHECK-NEXT: store volatile
+ // CHECK-NEXT: sext
+ // CHECK-NEXT: store volatile
+ i=c=k;
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: add nsw [[INT]]
+ // CHECK-NEXT: store volatile
+ i+=k;
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: load volatile
+ ci;
+#ifndef __cplusplus
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: load volatile
+ (int)ci;
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: icmp ne
+ // CHECK-NEXT: icmp ne
+ // CHECK-NEXT: or i1
+ (_Bool)ci;
+#endif
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: store volatile
+ // CHECK-NEXT: store volatile
+ ci=ci;
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: store volatile
+ // CHECK-NEXT: store volatile
+ // CHECK-NEXT: store volatile
+ // CHECK-NEXT: store volatile
+ ci=ci=ci;
+ // CHECK-NEXT: [[T:%.*]] = load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1)
+ // CHECK-NEXT: store volatile [[INT]] [[T]], [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1)
+ // CHECK-NEXT: store volatile [[INT]] [[T]], [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1)
+ __imag ci = __imag ci = __imag ci;
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: store volatile
+ __real (i = j);
+ // CHECK-NEXT: load volatile
+ __imag i;
+
+ // ============================================================
+ // FIXME: Test cases we get wrong.
+
+ // A use. We load all of a into a copy of a, then load i. gcc forgets to do
+ // the assignment.
+ // (a = a).i;
+
+ // ============================================================
+ // Test cases where we intentionally differ from gcc, due to suspected bugs in
+ // gcc.
+
+ // Not a use. gcc forgets to do the assignment.
+ // CHECK-NEXT: call void @llvm.memcpy{{.*}}, i1 true
+ // CHECK-NEXT: bitcast
+ // CHECK-NEXT: call void @llvm.memcpy{{.*}}, i1 true
+ ((a=a),a);
+
+ // Not a use. gcc gets this wrong, it doesn't emit the copy!
+ // (void)(a=a);
+
+ // Not a use. gcc got this wrong in 4.2 and omitted the side effects
+ // entirely, but it is fixed in 4.4.0.
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: store volatile
+ __imag (i = j);
+
+#ifndef __cplusplus
+ // A use of the real part
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: store volatile
+ // CHECK-NEXT: store volatile
+ // CHECK-NEXT: sitofp
+ (float)(ci=ci);
+ // Not a use, bug? gcc treats this as not a use, that's probably a bug due to
+ // tree folding ignoring volatile.
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: store volatile
+ // CHECK-NEXT: store volatile
+ (int)(ci=ci);
+#endif
+
+ // A use.
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: store volatile
+ // CHECK-NEXT: sitofp
+ (float)(i=i);
+ // A use. gcc treats this as not a use, that's probably a bug due to tree
+ // folding ignoring volatile.
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: store volatile
+ (int)(i=i);
+
+ // A use.
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: store volatile
+ // CHECK-NEXT: sub
+ -(i=j);
+ // A use. gcc treats this a not a use, that's probably a bug due to tree
+ // folding ignoring volatile.
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: store volatile
+ +(i=k);
+
+ // A use. gcc treats this a not a use, that's probably a bug due to tree
+ // folding ignoring volatile.
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: store volatile
+ // CHECK-NEXT: store volatile
+ __real (ci=ci);
+
+ // A use.
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: add
+ i + 0;
+ // A use.
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: store volatile
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: add
+ (i=j) + i;
+ // A use. gcc treats this as not a use, that's probably a bug due to tree
+ // folding ignoring volatile.
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: store volatile
+ // CHECK-NEXT: add
+ (i=j) + 0;
+
+#ifdef __cplusplus
+ (i,j)=k;
+ (j=k,i)=i;
+ struct { int x; } s, s1;
+ printf("s is at %p\n", &s);
+ printf("s is at %p\n", &(s = s1));
+ printf("s.x is at %p\n", &((s = s1).x));
+#endif
+}
+
+extern volatile enum X x;
+// CHECK: define void @test1()
+void test1() {
+ extern void test1_helper(void);
+ test1_helper();
+ // CHECK: call void @test1_helper()
+ // CHECK-NEXT: ret void
+ x;
+ (void) x;
+ return x;
+}