cb424d7448
verify-patch-sanity.py validates every active recipe .patch has internally- consistent hunk line counts — catching the 'malformed patch at line N' failure at commit/CI/preflight time instead of hours into a cook. This cycle hit that class three times (qtwaylandscanner, sddm, xwayland), each only discovered when cookbook tried to apply the patch. Running it across the repo found 29 latent malformed patches (validated against GNU patch: e.g. relibc/P3-sysv-ipc reproduces 'malformed patch at line 22'). They were harmless only because they sit in vendored recipes (baked, not re- applied) — but would fail on any version-bump re-derivation. --fix recounts the hunk headers (body untouched) and repaired all 29. Wired into build-preflight.sh (Phase 1.0D) and redbear-ci.yml, with a unit test (test-patch-sanity.sh). Skips archived/legacy trees and unvalidatable formats (empty placeholders, bare-@@ git hunks).
327 lines
10 KiB
C
327 lines
10 KiB
C
// XFAIL: target=aarch64-pc-windows-msvc
|
|
// 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(void) {
|
|
// CHECK: load volatile [[INT]], ptr @i
|
|
i;
|
|
// CHECK-NEXT: load volatile [[INT]], ptr @ci, align 4
|
|
// CHECK-NEXT: load volatile [[INT]], ptr getelementptr inbounds nuw ([[CINT]], ptr @ci, i32 0, i32 1), align 4
|
|
// CHECK-NEXT: sitofp [[INT]]
|
|
(float)(ci);
|
|
// CHECK-NEXT: load volatile [[INT]], ptr @ci, align 4
|
|
// CHECK-NEXT: load volatile [[INT]], ptr getelementptr inbounds nuw ([[CINT]], ptr @ci, i32 0, i32 1), align 4
|
|
(void)ci;
|
|
// CHECK-NEXT: memcpy
|
|
(void)a;
|
|
// CHECK-NEXT: [[R:%.*]] = load volatile [[INT]], ptr @ci, align 4
|
|
// CHECK-NEXT: [[I:%.*]] = load volatile [[INT]], ptr getelementptr inbounds nuw ([[CINT]], ptr @ci, i32 0, i32 1), align 4
|
|
// CHECK-NEXT: store volatile [[INT]] [[R]], ptr @ci, align 4
|
|
// CHECK-NEXT: store volatile [[INT]] [[I]], ptr getelementptr inbounds nuw ([[CINT]], ptr @ci, i32 0, i32 1), align 4
|
|
(void)(ci=ci);
|
|
// CHECK-NEXT: [[T:%.*]] = load volatile [[INT]], ptr @j
|
|
// CHECK-NEXT: store volatile [[INT]] [[T]], ptr @i
|
|
(void)(i=j);
|
|
// CHECK-NEXT: [[R1:%.*]] = load volatile [[INT]], ptr @ci, align 4
|
|
// CHECK-NEXT: [[I1:%.*]] = load volatile [[INT]], ptr getelementptr inbounds nuw ([[CINT]], ptr @ci, i32 0, i32 1), align 4
|
|
// CHECK-NEXT: [[R2:%.*]] = load volatile [[INT]], ptr @ci, align 4
|
|
// CHECK-NEXT: [[I2:%.*]] = load volatile [[INT]], ptr getelementptr inbounds nuw ([[CINT]], ptr @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]], ptr @ci, align 4
|
|
// CHECK-NEXT: store volatile [[INT]] [[I]], ptr getelementptr inbounds nuw ([[CINT]], ptr @ci, i32 0, i32 1), align 4
|
|
ci+=ci;
|
|
|
|
// CHECK-NEXT: [[R1:%.*]] = load volatile [[INT]], ptr @ci, align 4
|
|
// CHECK-NEXT: [[I1:%.*]] = load volatile [[INT]], ptr getelementptr inbounds nuw ([[CINT]], ptr @ci, i32 0, i32 1), align 4
|
|
// CHECK-NEXT: [[R2:%.*]] = load volatile [[INT]], ptr @ci, align 4
|
|
// CHECK-NEXT: [[I2:%.*]] = load volatile [[INT]], ptr getelementptr inbounds nuw ([[CINT]], ptr @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]], ptr @ci, align 4
|
|
// CHECK-NEXT: store volatile [[INT]] [[I]], ptr getelementptr inbounds nuw ([[CINT]], ptr @ci, i32 0, i32 1), align 4
|
|
// CHECK-NEXT: [[R2:%.*]] = load volatile [[INT]], ptr @ci, align 4
|
|
// CHECK-NEXT: [[I2:%.*]] = load volatile [[INT]], ptr getelementptr inbounds nuw ([[CINT]], ptr @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]], ptr getelementptr inbounds nuw ([[CINT]], ptr @ci, i32 0, i32 1)
|
|
// CHECK-NEXT: store volatile [[INT]] [[T]], ptr getelementptr inbounds nuw ([[CINT]], ptr @ci, i32 0, i32 1)
|
|
// CHECK-NEXT: store volatile [[INT]] [[T]], ptr getelementptr inbounds nuw ([[CINT]], ptr @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: 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(void) {
|
|
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(void) {
|
|
// CHECK: load volatile i32, ptr
|
|
// CHECK-NEXT: load volatile i32, ptr
|
|
// CHECK-NEXT: load volatile i32, ptr
|
|
// CHECK-NEXT: add i32
|
|
// CHECK-NEXT: add i32
|
|
// CHECK-NEXT: store volatile i32
|
|
// CHECK-NEXT: ret i32
|
|
return i += ci;
|
|
}
|