Sjoerd Meijer 3d9a0445cc Recommit #2 "[Driver] Default to -fno-common for all targets"
After a first attempt to fix the test-suite failures, my first recommit
caused the same failures again. I had updated CMakeList.txt files of
tests that needed -fcommon, but it turns out that there are also
Makefiles which are used by some bots, so I've updated these Makefiles
now too.

See the original commit message for more details on this change:
0a9fc9233e172601e26381810d093e02ef410f65
2020-03-09 19:57:03 +00:00

328 lines
11 KiB
C

// RUN: %clang_cc1 -Wno-return-type -Wno-unused-value -emit-llvm %s -w -o - | FileCheck %s
// CHECK: @i = {{(dso_local )?}}global [[INT:i[0-9]+]] 0
volatile int i, j, k;
volatile int ar[5];
volatile char c;
// CHECK: @ci = {{(dso_local )?}}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-LABEL: define {{.*}}void @test()
void test() {
// CHECK: load volatile [[INT]], [[INT]]* @i
i;
// CHECK-NEXT: load volatile [[INT]], [[INT]]* getelementptr inbounds ([[CINT]], [[CINT]]* @ci, i32 0, i32 0), align 4
// CHECK-NEXT: load volatile [[INT]], [[INT]]* getelementptr inbounds ([[CINT]], [[CINT]]* @ci, i32 0, i32 1), align 4
// CHECK-NEXT: sitofp [[INT]]
(float)(ci);
// CHECK-NEXT: load volatile [[INT]], [[INT]]* getelementptr inbounds ([[CINT]], [[CINT]]* @ci, i32 0, i32 0), align 4
// CHECK-NEXT: load volatile [[INT]], [[INT]]* getelementptr inbounds ([[CINT]], [[CINT]]* @ci, i32 0, i32 1), align 4
(void)ci;
// CHECK-NEXT: bitcast
// CHECK-NEXT: memcpy
(void)a;
// CHECK-NEXT: [[R:%.*]] = load volatile [[INT]], [[INT]]* getelementptr inbounds ([[CINT]], [[CINT]]* @ci, i32 0, i32 0), align 4
// CHECK-NEXT: [[I:%.*]] = load volatile [[INT]], [[INT]]* getelementptr inbounds ([[CINT]], [[CINT]]* @ci, i32 0, i32 1), align 4
// CHECK-NEXT: store volatile [[INT]] [[R]], [[INT]]* getelementptr inbounds ([[CINT]], [[CINT]]* @ci, i32 0, i32 0), align 4
// CHECK-NEXT: store volatile [[INT]] [[I]], [[INT]]* getelementptr inbounds ([[CINT]], [[CINT]]* @ci, i32 0, i32 1), align 4
(void)(ci=ci);
// CHECK-NEXT: [[T:%.*]] = load volatile [[INT]], [[INT]]* @j
// CHECK-NEXT: store volatile [[INT]] [[T]], [[INT]]* @i
(void)(i=j);
// CHECK-NEXT: [[R1:%.*]] = load volatile [[INT]], [[INT]]* getelementptr inbounds ([[CINT]], [[CINT]]* @ci, i32 0, i32 0), align 4
// CHECK-NEXT: [[I1:%.*]] = load volatile [[INT]], [[INT]]* getelementptr inbounds ([[CINT]], [[CINT]]* @ci, i32 0, i32 1), align 4
// CHECK-NEXT: [[R2:%.*]] = load volatile [[INT]], [[INT]]* getelementptr inbounds ([[CINT]], [[CINT]]* @ci, i32 0, i32 0), align 4
// CHECK-NEXT: [[I2:%.*]] = load volatile [[INT]], [[INT]]* getelementptr inbounds ([[CINT]], [[CINT]]* @ci, i32 0, i32 1), align 4
// 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]], [[CINT]]* @ci, i32 0, i32 0), align 4
// CHECK-NEXT: store volatile [[INT]] [[I]], [[INT]]* getelementptr inbounds ([[CINT]], [[CINT]]* @ci, i32 0, i32 1), align 4
ci+=ci;
// CHECK-NEXT: [[R1:%.*]] = load volatile [[INT]], [[INT]]* getelementptr inbounds ([[CINT]], [[CINT]]* @ci, i32 0, i32 0), align 4
// CHECK-NEXT: [[I1:%.*]] = load volatile [[INT]], [[INT]]* getelementptr inbounds ([[CINT]], [[CINT]]* @ci, i32 0, i32 1), align 4
// CHECK-NEXT: [[R2:%.*]] = load volatile [[INT]], [[INT]]* getelementptr inbounds ([[CINT]], [[CINT]]* @ci, i32 0, i32 0), align 4
// CHECK-NEXT: [[I2:%.*]] = load volatile [[INT]], [[INT]]* getelementptr inbounds ([[CINT]], [[CINT]]* @ci, i32 0, i32 1), align 4
// CHECK-NEXT: [[R:%.*]] = add [[INT]] [[R2]], [[R1]]
// CHECK-NEXT: [[I:%.*]] = add [[INT]] [[I2]], [[I1]]
// CHECK-NEXT: store volatile [[INT]] [[R]], [[INT]]* getelementptr inbounds ([[CINT]], [[CINT]]* @ci, i32 0, i32 0), align 4
// CHECK-NEXT: store volatile [[INT]] [[I]], [[INT]]* getelementptr inbounds ([[CINT]], [[CINT]]* @ci, i32 0, i32 1), align 4
// CHECK-NEXT: [[R2:%.*]] = load volatile [[INT]], [[INT]]* getelementptr inbounds ([[CINT]], [[CINT]]* @ci, i32 0, i32 0), align 4
// CHECK-NEXT: [[I2:%.*]] = load volatile [[INT]], [[INT]]* getelementptr inbounds ([[CINT]], [[CINT]]* @ci, i32 0, i32 1), align 4
// 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]], [[INT]]* getelementptr inbounds ([[CINT]], [[CINT]]* @ci, i32 0, i32 1)
// CHECK-NEXT: store volatile [[INT]] [[T]], [[INT]]* getelementptr inbounds ([[CINT]], [[CINT]]* @ci, i32 0, i32 1)
// CHECK-NEXT: store volatile [[INT]] [[T]], [[INT]]* getelementptr inbounds ([[CINT]], [[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-LABEL: 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;
}
// CHECK: define {{.*}} @test2()
int test2() {
// CHECK: load volatile i32, i32*
// CHECK-NEXT: load volatile i32, i32*
// CHECK-NEXT: load volatile i32, i32*
// CHECK-NEXT: add i32
// CHECK-NEXT: add i32
// CHECK-NEXT: store volatile i32
// CHECK-NEXT: ret i32
return i += ci;
}