text: // 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-LABEL: define void @test()
  void test() {
    // CHECK: load volatile [[INT]]* @i
    i;
    // CHECK-NEXT: load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0), align 4
    // CHECK-NEXT: load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1), align 4
    // CHECK-NEXT: sitofp [[INT]]
    (float)(ci);
    // CHECK-NEXT: load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0), align 4
    // CHECK-NEXT: load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1), align 4
    (void)ci;
    // CHECK-NEXT: bitcast
    // CHECK-NEXT: memcpy
    (void)a;
    // CHECK-NEXT: [[R:%.*]] = load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0), align 4
    // CHECK-NEXT: [[I:%.*]] = load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1), align 4
    // CHECK-NEXT: store volatile [[INT]] [[R]], [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0), align 4
    // CHECK-NEXT: store volatile [[INT]] [[I]], [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1), align 4
    (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), align 4
    // CHECK-NEXT: [[I1:%.*]] = load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1), align 4
    // CHECK-NEXT: [[R2:%.*]] = load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0), align 4
    // CHECK-NEXT: [[I2:%.*]] = load volatile [[INT]]* getelementptr inbounds ([[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]]* @ci, i32 0, i32 0), align 4
    // CHECK-NEXT: store volatile [[INT]] [[I]], [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1), align 4
    ci+=ci;
  
    // CHECK-NEXT: [[R1:%.*]] = load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0), align 4
    // CHECK-NEXT: [[I1:%.*]] = load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1), align 4
    // CHECK-NEXT: [[R2:%.*]] = load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0), align 4
    // CHECK-NEXT: [[I2:%.*]] = load volatile [[INT]]* getelementptr inbounds ([[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]]* @ci, i32 0, i32 0), align 4
    // CHECK-NEXT: store volatile [[INT]] [[I]], [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1), align 4
    // CHECK-NEXT: [[R2:%.*]] = load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0), align 4
    // CHECK-NEXT: [[I2:%.*]] = load volatile [[INT]]* getelementptr inbounds ([[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]]* 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-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*
    // CHECK-NEXT: load volatile i32*
    // CHECK-NEXT: load volatile i32*
    // CHECK-NEXT: add i32
    // CHECK-NEXT: add i32
    // CHECK-NEXT: store volatile i32
    // CHECK-NEXT: ret i32
    return i += ci;
  }
  