static int gf_ctime (char *s, size_t max, const time_t timev) { struct tm ltm; int failed; char buf[CTIME_BUFSZ + 1]; /* Some targets provide a localtime_r based on a draft of the POSIX standard where the return type is int rather than the standardized struct tm*. */ __builtin_choose_expr (__builtin_classify_type (localtime_r (&timev, <m)) == 5, failed = localtime_r (&timev, <m) == NULL, failed = localtime_r (&timev, <m) != 0); if (failed) goto blank; int n = snprintf (buf, sizeof (buf), "%3.3s %3.3s%3d %.2d:%.2d:%.2d %d", "SunMonTueWedThuFriSat" + ltm.tm_wday * 3, "JanFebMarAprMayJunJulAugSepOctNovDec" + ltm.tm_mon * 3, ltm.tm_mday, ltm.tm_hour, ltm.tm_min, ltm.tm_sec, 1900 + ltm.tm_year); if (n < 0) goto blank; if ((size_t) n <= max) { cf_strcpy (s, max, buf); return n; } blank: memset (s, ' ', max); return 0; }
static void test() { int a; float b; double d; func(a); func(b); func(d); a = func_choose(a); b = func_choose(b); d = func_choose(d); int c; struct xx { int a; } x, y; c = __builtin_choose_expr(a+3-7, b, x); // expected-error{{'__builtin_choose_expr' requires a constant expression}} c = __builtin_choose_expr(0, b, x); // expected-error{{incompatible type assigning 'struct xx', expected 'int'}} c = __builtin_choose_expr(5+3-7, b, x); y = __builtin_choose_expr(4+3-7, b, x); }
int main() { char c = 0; int i = 1; if (sizeof(__builtin_choose_expr(1, c, i)) != sizeof(char)) E(1); if (sizeof(__builtin_choose_expr(0, c, i)) != sizeof(int)) E(2); int* p = __builtin_choose_expr(1, &i, 2.0); double d = __builtin_choose_expr(0, &i, 2.0); //Don't evaluate the i++ c = __builtin_choose_expr(1, c, i++); if (i != 1) E(3) //Do evaluate the i++ c = __builtin_choose_expr(0, c, i++); if (i != 2) E(4) return __builtin_choose_expr(1, 0, 1); }
// rdar://6095061 int test8(void) { int i; __builtin_choose_expr (0, 42, i) = 10; return i; }
// 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 }
// PR4996 template<unsigned I> int f0() { return __builtin_choose_expr(I, 0, 1); }
// ChooseExpr template<class T> void test(int (&)[sizeof(__builtin_choose_expr(true, 1, 1), T())]) {} // expected-error {{cannot yet mangle}}