// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir
// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t-cir.ll
// RUN: FileCheck --check-prefix=LLVM --input-file=%t-cir.ll %s
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll
// RUN: FileCheck --check-prefix=OGCG --input-file=%t.ll %s

struct IncompleteS;
IncompleteS *p;

// CIR: cir.global external @p = #cir.ptr<null> : !cir.ptr<!rec_IncompleteS>
// LLVM: @p = global ptr null
// OGCG: @p = global ptr null, align 8

struct CompleteS {
  int a;
  char b;
};

CompleteS cs;

// CIR:       cir.global external @cs = #cir.zero : !rec_CompleteS
// LLVM-DAG:  @cs = global %struct.CompleteS zeroinitializer
// OGCG-DAG:  @cs = global %struct.CompleteS zeroinitializer, align 4

void f(void) {
  IncompleteS *p;
}

// CIR:      cir.func{{.*}} @_Z1fv()
// CIR-NEXT:   cir.alloca !cir.ptr<!rec_IncompleteS>, !cir.ptr<!cir.ptr<!rec_IncompleteS>>, ["p"]
// CIR-NEXT:   cir.return

// LLVM:      define{{.*}} void @_Z1fv()
// LLVM-NEXT:   %[[P:.*]] = alloca ptr, i64 1, align 8
// LLVM-NEXT:   ret void

// OGCG:      define{{.*}} void @_Z1fv()
// OGCG-NEXT: entry:
// OGCG-NEXT:   %[[P:.*]] = alloca ptr, align 8
// OGCG-NEXT:   ret void

char f2(CompleteS &s) {
  return s.b;
}

// CIR: cir.func{{.*}} @_Z2f2R9CompleteS(%[[ARG_S:.*]]: !cir.ptr<!rec_CompleteS>{{.*}})
// CIR:   %[[S_ADDR:.*]] = cir.alloca !cir.ptr<!rec_CompleteS>, !cir.ptr<!cir.ptr<!rec_CompleteS>>, ["s", init, const]
// CIR:   cir.store %[[ARG_S]], %[[S_ADDR]]
// CIR:   %[[S_REF:.*]] = cir.load{{.*}} %[[S_ADDR]]
// CIR:   %[[S_ADDR2:.*]] = cir.get_member %[[S_REF]][1] {name = "b"}
// CIR:   %[[S_B:.*]] = cir.load{{.*}} %[[S_ADDR2]]

// LLVM: define{{.*}} i8 @_Z2f2R9CompleteS(ptr %[[ARG_S:.*]])
// LLVM:   %[[S_ADDR:.*]] = alloca ptr
// LLVM:   store ptr %[[ARG_S]], ptr %[[S_ADDR]]
// LLVM:   %[[S_REF:.*]] = load ptr, ptr %[[S_ADDR]], align 8
// LLVM:   %[[S_ADDR2:.*]] = getelementptr %struct.CompleteS, ptr %[[S_REF]], i32 0, i32 1
// LLVM:   %[[S_B:.*]] = load i8, ptr %[[S_ADDR2]]

// OGCG: define{{.*}} i8 @_Z2f2R9CompleteS(ptr{{.*}} %[[ARG_S:.*]])
// OGCG: entry:
// OGCG:   %[[S_ADDR:.*]] = alloca ptr
// OGCG:   store ptr %[[ARG_S]], ptr %[[S_ADDR]]
// OGCG:   %[[S_REF:.*]] = load ptr, ptr %[[S_ADDR]]
// OGCG:   %[[S_ADDR2:.*]] = getelementptr inbounds nuw %struct.CompleteS, ptr %[[S_REF]], i32 0, i32 1
// OGCG:   %[[S_B:.*]] = load i8, ptr %[[S_ADDR2]]

struct Inner {
  int n;
};

struct Outer {
  Inner i;
};

void f3() {
  Outer o;
  o.i.n;
}

// CIR: cir.func{{.*}} @_Z2f3v()
// CIR:   %[[O:.*]] = cir.alloca !rec_Outer, !cir.ptr<!rec_Outer>, ["o"]
// CIR:   %[[O_I:.*]] = cir.get_member %[[O]][0] {name = "i"}
// CIR:   %[[O_I_N:.*]] = cir.get_member %[[O_I]][0] {name = "n"}

// LLVM: define{{.*}} void @_Z2f3v()
// LLVM:   %[[O:.*]] = alloca %struct.Outer, i64 1, align 4
// LLVM:   %[[O_I:.*]] = getelementptr %struct.Outer, ptr %[[O]], i32 0, i32 0
// LLVM:   %[[O_I_N:.*]] = getelementptr %struct.Inner, ptr %[[O_I]], i32 0, i32 0

// OGCG: define{{.*}} void @_Z2f3v()
// OGCG:   %[[O:.*]] = alloca %struct.Outer, align 4
// OGCG:   %[[O_I:.*]] = getelementptr inbounds nuw %struct.Outer, ptr %[[O]], i32 0, i32 0
// OGCG:   %[[O_I_N:.*]] = getelementptr inbounds nuw %struct.Inner, ptr %[[O_I]], i32 0, i32 0
