// RUN: %clang_cc1 -no-enable-noundef-analysis %s -cl-std=CL2.0 -include opencl-c.h -triple amdgcn -emit-llvm -o - | FileCheck %s
// RUN: %clang_cc1 -no-enable-noundef-analysis %s -O0 -cl-std=CL2.0 -include opencl-c.h -triple amdgcn -emit-llvm -o - | FileCheck --check-prefix=NOOPT %s
// RUN: %clang_cc1 -no-enable-noundef-analysis %s -cl-std=CL2.0 -include opencl-c.h -triple amdgcn---opencl -emit-llvm -o - | FileCheck %s
// RUN: %clang_cc1 -no-enable-noundef-analysis %s -cl-std=CL2.0 -include opencl-c.h -triple amdgcn -fcommon -emit-llvm -o - | FileCheck %s --check-prefix=COMMON

typedef struct {
  private char *p1;
  local char *p2;
  constant char *p3;
  global char *p4;
  generic char *p5;
} StructTy1;

typedef struct {
  constant char *p3;
  global char *p4;
  generic char *p5;
} StructTy2;

// Test 0 as initializer.

// CHECK: @private_p ={{.*}} local_unnamed_addr addrspace(1) global ptr addrspace(5) addrspacecast (ptr null to ptr addrspace(5)), align 4
private char *private_p = 0;

// CHECK: @local_p ={{.*}} local_unnamed_addr addrspace(1) global ptr addrspace(3) addrspacecast (ptr null to ptr addrspace(3)), align 4
local char *local_p = 0;

// CHECK: @global_p ={{.*}} local_unnamed_addr addrspace(1) global ptr addrspace(1) null, align 8
global char *global_p = 0;

// CHECK: @constant_p ={{.*}} local_unnamed_addr addrspace(1) global ptr addrspace(4) null, align 8
constant char *constant_p = 0;

// CHECK: @generic_p ={{.*}} local_unnamed_addr addrspace(1) global ptr null, align 8
generic char *generic_p = 0;

// Test NULL as initializer.

// CHECK: @private_p_NULL ={{.*}} local_unnamed_addr addrspace(1) global ptr addrspace(5) addrspacecast (ptr null to ptr addrspace(5)), align 4
private char *private_p_NULL = NULL;

// CHECK: @local_p_NULL ={{.*}} local_unnamed_addr addrspace(1) global ptr addrspace(3) addrspacecast (ptr null to ptr addrspace(3)), align 4
local char *local_p_NULL = NULL;

// CHECK: @global_p_NULL ={{.*}} local_unnamed_addr addrspace(1) global ptr addrspace(1) null, align 8
global char *global_p_NULL = NULL;

// CHECK: @constant_p_NULL ={{.*}} local_unnamed_addr addrspace(1) global ptr addrspace(4) null, align 8
constant char *constant_p_NULL = NULL;

// CHECK: @generic_p_NULL ={{.*}} local_unnamed_addr addrspace(1) global ptr null, align 8
generic char *generic_p_NULL = NULL;

// Test constant folding of null pointer.
// A null pointer should be folded to a null pointer in the target address space.

// CHECK: @fold_generic ={{.*}} local_unnamed_addr addrspace(1) global ptr null, align 8
generic int *fold_generic = (global int*)(generic float*)(private char*)0;

// CHECK: @fold_priv ={{.*}} local_unnamed_addr addrspace(1) global ptr addrspace(5) addrspacecast (ptr addrspace(1) null to ptr addrspace(5)), align 4
private short *fold_priv = (private short*)(generic int*)(global void*)0;

// CHECK: @fold_priv_arith ={{.*}} local_unnamed_addr addrspace(1) global ptr addrspace(5) inttoptr (i32 9 to ptr addrspace(5)), align 4
private char *fold_priv_arith = (private char*)0 + 10;

// CHECK: @fold_local_arith ={{.*}} local_unnamed_addr addrspace(1) global ptr addrspace(3) inttoptr (i32 9 to ptr addrspace(3)), align 4
local char *fold_local_arith = (local char*)0 + 10;

// CHECK: @fold_int ={{.*}} local_unnamed_addr addrspace(1) global i32 13, align 4
int fold_int = (int)(private void*)(generic char*)(global int*)0 + 14;

// CHECK: @fold_int2 ={{.*}} local_unnamed_addr addrspace(1) global i32 12, align 4
int fold_int2 = (int) ((private void*)0 + 13);

// CHECK: @fold_int3 ={{.*}} local_unnamed_addr addrspace(1) global i32 -1, align 4
int fold_int3 = (int) ((private int*)0);

// CHECK: @fold_int4 ={{.*}} local_unnamed_addr addrspace(1) global i32 7, align 4
int fold_int4 = (int) &((private int*)0)[2];

// CHECK: @fold_int5 ={{.*}} local_unnamed_addr addrspace(1) global i32 3, align 4
int fold_int5 = (int) &((private StructTy1*)0)->p2;


// CHECK: @fold_int_local ={{.*}} local_unnamed_addr addrspace(1) global i32 13, align 4
int fold_int_local = (int)(local void*)(generic char*)(global int*)0 + 14;

// CHECK: @fold_int2_local ={{.*}} local_unnamed_addr addrspace(1) global i32 12, align 4
int fold_int2_local = (int) ((local void*)0 + 13);

// CHECK: @fold_int3_local ={{.*}} local_unnamed_addr addrspace(1) global i32 -1, align 4
int fold_int3_local = (int) ((local int*)0);

// CHECK: @fold_int4_local ={{.*}} local_unnamed_addr addrspace(1) global i32 7, align 4
int fold_int4_local = (int) &((local int*)0)[2];

// CHECK: @fold_int5_local ={{.*}} local_unnamed_addr addrspace(1) global i32 3, align 4
int fold_int5_local = (int) &((local StructTy1*)0)->p2;


// Test static variable initialization.

// NOOPT: @test_static_var_private.sp1 = internal addrspace(1) global ptr addrspace(5) addrspacecast (ptr null to ptr addrspace(5)), align 4
// NOOPT: @test_static_var_private.sp2 = internal addrspace(1) global ptr addrspace(5) addrspacecast (ptr null to ptr addrspace(5)), align 4
// NOOPT: @test_static_var_private.sp3 = internal addrspace(1) global ptr addrspace(5) addrspacecast (ptr null to ptr addrspace(5)), align 4
// NOOPT: @test_static_var_private.sp4 = internal addrspace(1) global ptr addrspace(5) null, align 4
// NOOPT: @test_static_var_private.sp5 = internal addrspace(1) global ptr addrspace(5) addrspacecast (ptr null to ptr addrspace(5)), align 4
// NOOPT: @test_static_var_private.SS1 = internal addrspace(1) global %struct.StructTy1 { ptr addrspace(5) addrspacecast (ptr null to ptr addrspace(5)), ptr addrspace(3) addrspacecast (ptr null to ptr addrspace(3)), ptr addrspace(4) null, ptr addrspace(1) null, ptr null }, align 8
// NOOPT: @test_static_var_private.SS2 = internal addrspace(1) global %struct.StructTy2 zeroinitializer, align 8

void test_static_var_private(void) {
  static private char *sp1 = 0;
  static private char *sp2 = NULL;
  static private char *sp3;
  static private char *sp4 = (private char*)((void)0, 0);
  const int x = 0;
  static private char *sp5 = (private char*)x;
  static StructTy1 SS1;
  static StructTy2 SS2;
}

// NOOPT: @test_static_var_local.sp1 = internal addrspace(1) global ptr addrspace(3) addrspacecast (ptr null to ptr addrspace(3)), align 4
// NOOPT: @test_static_var_local.sp2 = internal addrspace(1) global ptr addrspace(3) addrspacecast (ptr null to ptr addrspace(3)), align 4
// NOOPT: @test_static_var_local.sp3 = internal addrspace(1) global ptr addrspace(3) addrspacecast (ptr null to ptr addrspace(3)), align 4
// NOOPT: @test_static_var_local.sp4 = internal addrspace(1) global ptr addrspace(3) null, align 4
// NOOPT: @test_static_var_local.sp5 = internal addrspace(1) global ptr addrspace(3) addrspacecast (ptr null to ptr addrspace(3)), align 4
// NOOPT: @test_static_var_local.SS1 = internal addrspace(1) global %struct.StructTy1 { ptr addrspace(5) addrspacecast (ptr null to ptr addrspace(5)), ptr addrspace(3) addrspacecast (ptr null to ptr addrspace(3)), ptr addrspace(4) null, ptr addrspace(1) null, ptr null }, align 8
// NOOPT: @test_static_var_local.SS2 = internal addrspace(1) global %struct.StructTy2 zeroinitializer, align 8
void test_static_var_local(void) {
  static local char *sp1 = 0;
  static local char *sp2 = NULL;
  static local char *sp3;
  static local char *sp4 = (local char*)((void)0, 0);
  const int x = 0;
  static local char *sp5 = (local char*)x;
  static StructTy1 SS1;
  static StructTy2 SS2;
}

// Test function-scope variable initialization.
// NOOPT-LABEL: @test_func_scope_var_private(
// NOOPT: store ptr addrspace(5) addrspacecast (ptr null to ptr addrspace(5)), ptr addrspace(5) %sp1, align 4
// NOOPT: store ptr addrspace(5) addrspacecast (ptr null to ptr addrspace(5)), ptr addrspace(5) %sp2, align 4
// NOOPT: store ptr addrspace(5) null, ptr addrspace(5) %sp3, align 4
// NOOPT: store ptr addrspace(5) addrspacecast (ptr null to ptr addrspace(5)), ptr addrspace(5) %sp4, align 4
// NOOPT: call void @llvm.memcpy.p5.p4.i64(ptr addrspace(5) align 8 %SS1, ptr addrspace(4) align 8 @__const.test_func_scope_var_private.SS1, i64 32, i1 false)
// NOOPT: call void @llvm.memset.p5.i64(ptr addrspace(5) align 8 %SS2, i8 0, i64 24, i1 false)
void test_func_scope_var_private(void) {
  private char *sp1 = 0;
  private char *sp2 = NULL;
  private char *sp3 = (private char*)((void)0, 0);
  const int x = 0;
  private char *sp4 = (private char*)x;
  StructTy1 SS1 = {0, 0, 0, 0, 0};
  StructTy2 SS2 = {0, 0, 0};
}

// Test function-scope variable initialization.
// NOOPT-LABEL: @test_func_scope_var_local(
// NOOPT: store ptr addrspace(3) addrspacecast (ptr null to ptr addrspace(3)), ptr addrspace(5) %sp1, align 4
// NOOPT: store ptr addrspace(3) addrspacecast (ptr null to ptr addrspace(3)), ptr addrspace(5) %sp2, align 4
// NOOPT: store ptr addrspace(3) null, ptr addrspace(5) %sp3, align 4
// NOOPT: store ptr addrspace(3) addrspacecast (ptr null to ptr addrspace(3)), ptr addrspace(5) %sp4, align 4
// NOOPT: call void @llvm.memcpy.p5.p4.i64(ptr addrspace(5) align 8 %SS1, ptr addrspace(4) align 8 @__const.test_func_scope_var_local.SS1, i64 32, i1 false)
// NOOPT: call void @llvm.memset.p5.i64(ptr addrspace(5) align 8 %SS2, i8 0, i64 24, i1 false)
void test_func_scope_var_local(void) {
  local char *sp1 = 0;
  local char *sp2 = NULL;
  local char *sp3 = (local char*)((void)0, 0);
  const int x = 0;
  local char *sp4 = (local char*)x;
  StructTy1 SS1 = {0, 0, 0, 0, 0};
  StructTy2 SS2 = {0, 0, 0};
}


// Test default initialization of pointers.

// Tentative definition of global variables with non-zero initializer
// cannot have common linkage since common linkage requires zero initialization
// and does not have explicit section.

// CHECK: @p1 ={{.*}} local_unnamed_addr addrspace(1) global ptr addrspace(5) addrspacecast (ptr null to ptr addrspace(5)), align 4
// COMMON: @p1 = weak local_unnamed_addr addrspace(1) global ptr addrspace(5) addrspacecast (ptr null to ptr addrspace(5)), align 4
private char *p1;

// CHECK: @p2 ={{.*}} local_unnamed_addr addrspace(1) global ptr addrspace(3) addrspacecast (ptr null to ptr addrspace(3)), align 4
// COMMON: @p2 = weak local_unnamed_addr addrspace(1) global ptr addrspace(3) addrspacecast (ptr null to ptr addrspace(3)), align 4
local char *p2;

// CHECK: @p3 ={{.*}} local_unnamed_addr addrspace(1) global ptr addrspace(4) null, align 8
// COMMON: @p3 = common local_unnamed_addr addrspace(1) global ptr addrspace(4) null, align 8
constant char *p3;

// CHECK: @p4 ={{.*}} local_unnamed_addr addrspace(1) global ptr addrspace(1) null, align 8
// COMMON: @p4 = common local_unnamed_addr addrspace(1) global ptr addrspace(1) null, align 8
global char *p4;

// CHECK: @p5 ={{.*}} local_unnamed_addr addrspace(1) global ptr null, align 8
// COMMON: @p5 = common local_unnamed_addr addrspace(1) global ptr null, align 8
generic char *p5;

// Test default initialization of structure.

// CHECK: @S1 ={{.*}} local_unnamed_addr addrspace(1) global %struct.StructTy1 { ptr addrspace(5) addrspacecast (ptr null to ptr addrspace(5)), ptr addrspace(3) addrspacecast (ptr null to ptr addrspace(3)), ptr addrspace(4) null, ptr addrspace(1) null, ptr null }, align 8
StructTy1 S1;

// CHECK: @S2 ={{.*}} local_unnamed_addr addrspace(1) global %struct.StructTy2 zeroinitializer, align 8
StructTy2 S2;

// Test default initialization of array.
// CHECK: @A1 ={{.*}} local_unnamed_addr addrspace(1) global [2 x %struct.StructTy1] [%struct.StructTy1 { ptr addrspace(5) addrspacecast (ptr null to ptr addrspace(5)), ptr addrspace(3) addrspacecast (ptr null to ptr addrspace(3)), ptr addrspace(4) null, ptr addrspace(1) null, ptr null }, %struct.StructTy1 { ptr addrspace(5) addrspacecast (ptr null to ptr addrspace(5)), ptr addrspace(3) addrspacecast (ptr null to ptr addrspace(3)), ptr addrspace(4) null, ptr addrspace(1) null, ptr null }], align 8
StructTy1 A1[2];

// CHECK: @A2 ={{.*}} local_unnamed_addr addrspace(1) global [2 x %struct.StructTy2] zeroinitializer, align 8
StructTy2 A2[2];

// Test comparison with 0.

// CHECK-LABEL: cmp_private
// CHECK: icmp eq ptr addrspace(5) %p, addrspacecast (ptr null to ptr addrspace(5))
void cmp_private(private char* p) {
  if (p != 0)
    *p = 0;
}

// CHECK-LABEL: cmp_local
// CHECK: icmp eq ptr addrspace(3) %p, addrspacecast (ptr null to ptr addrspace(3))
void cmp_local(local char* p) {
  if (p != 0)
    *p = 0;
}

// CHECK-LABEL: cmp_global
// CHECK: icmp eq ptr addrspace(1) %p, null
void cmp_global(global char* p) {
  if (p != 0)
    *p = 0;
}

// CHECK-LABEL: cmp_constant
// CHECK: icmp eq ptr addrspace(4) %p, null
char cmp_constant(constant char* p) {
  if (p != 0)
    return *p;
  else
    return 0;
}

// CHECK-LABEL: cmp_generic
// CHECK: icmp eq ptr %p, null
void cmp_generic(generic char* p) {
  if (p != 0)
    *p = 0;
}

// Test comparison with NULL.

// CHECK-LABEL: cmp_NULL_private
// CHECK: icmp eq ptr addrspace(5) %p, addrspacecast (ptr null to ptr addrspace(5))
void cmp_NULL_private(private char* p) {
  if (p != NULL)
    *p = 0;
}

// CHECK-LABEL: cmp_NULL_local
// CHECK: icmp eq ptr addrspace(3) %p, addrspacecast (ptr null to ptr addrspace(3))
void cmp_NULL_local(local char* p) {
  if (p != NULL)
    *p = 0;
}

// CHECK-LABEL: cmp_NULL_global
// CHECK: icmp eq ptr addrspace(1) %p, null
void cmp_NULL_global(global char* p) {
  if (p != NULL)
    *p = 0;
}

// CHECK-LABEL: cmp_NULL_constant
// CHECK: icmp eq ptr addrspace(4) %p, null
char cmp_NULL_constant(constant char* p) {
  if (p != NULL)
    return *p;
  else
    return 0;
}

// CHECK-LABEL: cmp_NULL_generic
// CHECK: icmp eq ptr %p, null
void cmp_NULL_generic(generic char* p) {
  if (p != NULL)
    *p = 0;
}

// Test storage 0 as null pointer.
// CHECK-LABEL: test_storage_null_pointer
// CHECK: store ptr addrspace(5) addrspacecast (ptr null to ptr addrspace(5)), ptr %arg_private
// CHECK: store ptr addrspace(3) addrspacecast (ptr null to ptr addrspace(3)), ptr %arg_local
// CHECK: store ptr addrspace(1) null, ptr %arg_global
// CHECK: store ptr addrspace(4) null, ptr %arg_constant
// CHECK: store ptr null, ptr %arg_generic
void test_storage_null_pointer(private char** arg_private,
                               local char** arg_local,
                               global char** arg_global,
                               constant char** arg_constant,
                               generic char** arg_generic) {
   *arg_private = 0;
   *arg_local = 0;
   *arg_global = 0;
   *arg_constant = 0;
   *arg_generic = 0;
}

// Test storage NULL as null pointer.
// CHECK-LABEL: test_storage_null_pointer_NULL
// CHECK: store ptr addrspace(5) addrspacecast (ptr null to ptr addrspace(5)), ptr %arg_private
// CHECK: store ptr addrspace(3) addrspacecast (ptr null to ptr addrspace(3)), ptr %arg_local
// CHECK: store ptr addrspace(1) null, ptr %arg_global
// CHECK: store ptr addrspace(4) null, ptr %arg_constant
// CHECK: store ptr null, ptr %arg_generic
void test_storage_null_pointer_NULL(private char** arg_private,
                                    local char** arg_local,
                                    global char** arg_global,
                                    constant char** arg_constant,
                                    generic char** arg_generic) {
   *arg_private = NULL;
   *arg_local = NULL;
   *arg_global = NULL;
   *arg_constant = NULL;
   *arg_generic = NULL;
}

// Test pass null pointer to function as argument.
void test_pass_null_pointer_arg_calee(private char* arg_private,
                                      local char* arg_local,
                                      global char* arg_global,
                                      constant char* arg_constant,
                                      generic char* arg_generic);

// CHECK-LABEL: test_pass_null_pointer_arg
// CHECK: call void @test_pass_null_pointer_arg_calee(ptr addrspace(5) addrspacecast (ptr null to ptr addrspace(5)), ptr addrspace(3) addrspacecast (ptr null to ptr addrspace(3)), ptr addrspace(1) null, ptr addrspace(4) null, ptr null)
// CHECK: call void @test_pass_null_pointer_arg_calee(ptr addrspace(5) addrspacecast (ptr null to ptr addrspace(5)), ptr addrspace(3) addrspacecast (ptr null to ptr addrspace(3)), ptr addrspace(1) null, ptr addrspace(4) null, ptr null)
void test_pass_null_pointer_arg(void) {
  test_pass_null_pointer_arg_calee(0, 0, 0, 0, 0);
  test_pass_null_pointer_arg_calee(NULL, NULL, NULL, NULL, NULL);
}

// Test cast null pointer to size_t.
void test_cast_null_pointer_to_sizet_calee(size_t arg_private,
                                           size_t arg_local,
                                           size_t arg_global,
                                           size_t arg_constant,
                                           size_t arg_generic);

// CHECK-LABEL: test_cast_null_pointer_to_sizet
// CHECK: call void @test_cast_null_pointer_to_sizet_calee(i64 ptrtoint (ptr addrspace(5) addrspacecast (ptr null to ptr addrspace(5)) to i64), i64 ptrtoint (ptr addrspace(3) addrspacecast (ptr null to ptr addrspace(3)) to i64), i64 0, i64 0, i64 0)
// CHECK: call void @test_cast_null_pointer_to_sizet_calee(i64 ptrtoint (ptr addrspace(5) addrspacecast (ptr null to ptr addrspace(5)) to i64), i64 ptrtoint (ptr addrspace(3) addrspacecast (ptr null to ptr addrspace(3)) to i64), i64 0, i64 0, i64 0)
void test_cast_null_pointer_to_sizet(void) {
  test_cast_null_pointer_to_sizet_calee((size_t)((private char*)0),
                                        (size_t)((local char*)0),
                                        (size_t)((global char*)0),
                                        (size_t)((constant char*)0),
                                        (size_t)((generic char*)0));
  test_cast_null_pointer_to_sizet_calee((size_t)((private char*)NULL),
                                        (size_t)((local char*)NULL),
                                        (size_t)((global char*)NULL),
                                        (size_t)((constant char*)0), // NULL cannot be casted to constant pointer since it is defined as a generic pointer
                                        (size_t)((generic char*)NULL));
}

// Test comparison between null pointers.
#define TEST_EQ00(addr1, addr2) int test_eq00_##addr1##_##addr2(void) { return (addr1 char*)0 == (addr2 char*)0; }
#define TEST_EQ0N(addr1, addr2) int test_eq0N_##addr1##_##addr2(void) { return (addr1 char*)0 == (addr2 char*)NULL; }
#define TEST_EQN0(addr1, addr2) int test_eqN0_##addr1##_##addr2(void) { return (addr1 char*)NULL == (addr2 char*)0; }
#define TEST_EQNN(addr1, addr2) int test_eqNN_##addr1##_##addr2(void) { return (addr1 char*)0 == (addr2 char*)NULL; }
#define TEST_NE00(addr1, addr2) int test_ne00_##addr1##_##addr2(void) { return (addr1 char*)0 != (addr2 char*)0; }
#define TEST_NE0N(addr1, addr2) int test_ne0N_##addr1##_##addr2(void) { return (addr1 char*)0 != (addr2 char*)NULL; }
#define TEST_NEN0(addr1, addr2) int test_neN0_##addr1##_##addr2(void) { return (addr1 char*)NULL != (addr2 char*)0; }
#define TEST_NENN(addr1, addr2) int test_neNN_##addr1##_##addr2(void) { return (addr1 char*)0 != (addr2 char*)NULL; }
#define TEST(addr1, addr2) \
        TEST_EQ00(addr1, addr2) \
        TEST_EQ0N(addr1, addr2) \
        TEST_EQN0(addr1, addr2) \
        TEST_EQNN(addr1, addr2) \
        TEST_NE00(addr1, addr2) \
        TEST_NE0N(addr1, addr2) \
        TEST_NEN0(addr1, addr2) \
        TEST_NENN(addr1, addr2)

// CHECK-LABEL: test_eq00_generic_private
// CHECK: ret i32 1
// CHECK-LABEL: test_eq0N_generic_private
// CHECK: ret i32 1
// CHECK-LABEL: test_eqN0_generic_private
// CHECK: ret i32 1
// CHECK-LABEL: test_eqNN_generic_private
// CHECK: ret i32 1
// CHECK-LABEL: test_ne00_generic_private
// CHECK: ret i32 0
// CHECK-LABEL: test_ne0N_generic_private
// CHECK: ret i32 0
// CHECK-LABEL: test_neN0_generic_private
// CHECK: ret i32 0
// CHECK-LABEL: test_neNN_generic_private
// CHECK: ret i32 0
TEST(generic, private)

// CHECK-LABEL: test_eq00_generic_local
// CHECK: ret i32 1
// CHECK-LABEL: test_eq0N_generic_local
// CHECK: ret i32 1
// CHECK-LABEL: test_eqN0_generic_local
// CHECK: ret i32 1
// CHECK-LABEL: test_eqNN_generic_local
// CHECK: ret i32 1
// CHECK-LABEL: test_ne00_generic_local
// CHECK: ret i32 0
// CHECK-LABEL: test_ne0N_generic_local
// CHECK: ret i32 0
// CHECK-LABEL: test_neN0_generic_local
// CHECK: ret i32 0
// CHECK-LABEL: test_neNN_generic_local
// CHECK: ret i32 0
TEST(generic, local)

// CHECK-LABEL: test_eq00_generic_global
// CHECK: ret i32 1
// CHECK-LABEL: test_eq0N_generic_global
// CHECK: ret i32 1
// CHECK-LABEL: test_eqN0_generic_global
// CHECK: ret i32 1
// CHECK-LABEL: test_eqNN_generic_global
// CHECK: ret i32 1
// CHECK-LABEL: test_ne00_generic_global
// CHECK: ret i32 0
// CHECK-LABEL: test_ne0N_generic_global
// CHECK: ret i32 0
// CHECK-LABEL: test_neN0_generic_global
// CHECK: ret i32 0
// CHECK-LABEL: test_neNN_generic_global
// CHECK: ret i32 0
TEST(generic, global)

// CHECK-LABEL: test_eq00_generic_generic
// CHECK: ret i32 1
// CHECK-LABEL: test_eq0N_generic_generic
// CHECK: ret i32 1
// CHECK-LABEL: test_eqN0_generic_generic
// CHECK: ret i32 1
// CHECK-LABEL: test_eqNN_generic_generic
// CHECK: ret i32 1
// CHECK-LABEL: test_ne00_generic_generic
// CHECK: ret i32 0
// CHECK-LABEL: test_ne0N_generic_generic
// CHECK: ret i32 0
// CHECK-LABEL: test_neN0_generic_generic
// CHECK: ret i32 0
// CHECK-LABEL: test_neNN_generic_generic
// CHECK: ret i32 0
TEST(generic, generic)

// CHECK-LABEL: test_eq00_constant_constant
// CHECK: ret i32 1
TEST_EQ00(constant, constant)

// Test cast to bool.

// CHECK-LABEL: cast_bool_private
// CHECK: icmp eq ptr addrspace(5) %p, addrspacecast (ptr null to ptr addrspace(5))
void cast_bool_private(private char* p) {
  if (p)
    *p = 0;
}

// CHECK-LABEL: cast_bool_local
// CHECK: icmp eq ptr addrspace(3) %p, addrspacecast (ptr null to ptr addrspace(3))
void cast_bool_local(local char* p) {
  if (p)
    *p = 0;
}

// CHECK-LABEL: cast_bool_global
// CHECK: icmp eq ptr addrspace(1) %p, null
void cast_bool_global(global char* p) {
  if (p)
    *p = 0;
}

// CHECK-LABEL: cast_bool_constant
// CHECK: icmp eq ptr addrspace(4) %p, null
char cast_bool_constant(constant char* p) {
  if (p)
    return *p;
  else
    return 0;
}

// CHECK-LABEL: cast_bool_generic
// CHECK: icmp eq ptr %p, null
void cast_bool_generic(generic char* p) {
  if (p)
    *p = 0;
}

// Test initialize a struct using memset.
// For large structures which is mostly zero, clang generats llvm.memset for
// the zero part and store for non-zero members.
typedef struct {
  long a, b, c, d;
  private char *p;
} StructTy3;

// CHECK-LABEL: test_memset_private
// CHECK: call void @llvm.memset.p5.i64(ptr addrspace(5) noundef align 8 {{.*}}, i8 0, i64 32, i1 false)
// CHECK: [[GEP:%.*]] = getelementptr inbounds nuw i8, ptr addrspace(5) %ptr, i32 32
// CHECK: store ptr addrspace(5) addrspacecast (ptr null to ptr addrspace(5)), ptr addrspace(5) [[GEP]]
// CHECK: [[GEP1:%.*]] = getelementptr inbounds nuw i8, ptr addrspace(5) {{.*}}, i32 36
// CHECK: store i32 0, ptr addrspace(5) [[GEP1]], align 4
void test_memset_private(private StructTy3 *ptr) {
  StructTy3 S3 = {0, 0, 0, 0, 0};
  *ptr = S3;
}

// Test casting literal 0 to pointer.
// A 0 literal casted to pointer should become a null pointer.

// CHECK-LABEL: test_cast_0_to_local_ptr
// CHECK: ret ptr addrspace(3) addrspacecast (ptr null to ptr addrspace(3))
local int* test_cast_0_to_local_ptr(void) {
  return (local int*)0;
}

// CHECK-LABEL: test_cast_0_to_private_ptr
// CHECK: ret ptr addrspace(5) addrspacecast (ptr null to ptr addrspace(5))
private int* test_cast_0_to_private_ptr(void) {
  return (private int*)0;
}

// Test casting non-literal integer with 0 value to pointer.
// A non-literal integer expression with 0 value is casted to a pointer with
// zero value.

// CHECK-LABEL: test_cast_int_to_ptr1_private
// CHECK: ret ptr addrspace(5) null
private int* test_cast_int_to_ptr1_private(void) {
  return (private int*)((void)0, 0);
}

// CHECK-LABEL: test_cast_int_to_ptr1_local
 // CHECK: ret ptr addrspace(3) null
local int* test_cast_int_to_ptr1_local(void) {
  return (local int*)((void)0, 0);
}

// CHECK-LABEL: test_cast_int_to_ptr2
// CHECK: ret ptr addrspace(5) null
private int* test_cast_int_to_ptr2(void) {
  int x = 0;
  return (private int*)x;
}

// Test logical operations.
// CHECK-LABEL: test_not_nullptr
// CHECK: ret i32 1
int test_not_nullptr(void) {
  return !(private char*)NULL;
}

// CHECK-LABEL: test_and_nullptr
// CHECK: ret i32 0
int test_and_nullptr(int a) {
  return a && ((private char*)NULL);
}

// CHECK-LABEL: test_not_private_ptr
// CHECK: %[[lnot:.*]] = icmp eq ptr addrspace(5) %p, addrspacecast (ptr null to ptr addrspace(5))
// CHECK: %[[lnot_ext:.*]] = zext i1 %[[lnot]] to i32
// CHECK: ret i32 %[[lnot_ext]]
int test_not_private_ptr(private char* p) {
  return !p;
}

// CHECK-LABEL: test_not_local_ptr
// CHECK: %[[lnot:.*]] = icmp eq ptr addrspace(3) %p, addrspacecast (ptr null to ptr addrspace(3))
// CHECK: %[[lnot_ext:.*]] = zext i1 %[[lnot]] to i32
// CHECK: ret i32 %[[lnot_ext]]
int test_not_local_ptr(local char* p) {
  return !p;
}


// CHECK-LABEL: test_and_ptr
// CHECK: %[[tobool:.*]] = icmp ne ptr addrspace(5) %p1, addrspacecast (ptr null to ptr addrspace(5))
// CHECK: %[[tobool1:.*]] = icmp ne ptr addrspace(3) %p2, addrspacecast (ptr null to ptr addrspace(3))
// CHECK: %[[res:.*]] = select i1 %[[tobool]], i1 %[[tobool1]], i1 false
// CHECK: %[[land_ext:.*]] = zext i1 %[[res]] to i32
// CHECK: ret i32 %[[land_ext]]
int test_and_ptr(private char* p1, local char* p2) {
  return p1 && p2;
}

// Test folding of null pointer in function scope.
// NOOPT-LABEL: test_fold_private
// NOOPT: call void @test_fold_callee
// NOOPT: store ptr addrspace(1) null, ptr addrspace(5) %glob, align 8
// NOOPT: %{{.*}} = sub i64 %{{.*}}, 0
// NOOPT: call void @test_fold_callee
// NOOPT: %[[SEXT:.*]] = sext i32 ptrtoint (ptr addrspace(5) addrspacecast (ptr null to ptr addrspace(5)) to i32) to i64
// NOOPT: %{{.*}} = add nsw i64 %1, %[[SEXT]]
// NOOPT: %{{.*}} = sub nsw i64 %{{.*}}, 1
void test_fold_callee(void);
void test_fold_private(void) {
  global int* glob = (test_fold_callee(), (global int*)(generic char*)0);
  long x = glob - (global int*)(generic char*)0;
  x = x + (int)(test_fold_callee(), (private int*)(generic char*)(global short*)0);
  x = x - (int)((private int*)0 == (private int*)(generic char*)0);
}

// NOOPT-LABEL: test_fold_local
// NOOPT: call void @test_fold_callee
// NOOPT: store ptr addrspace(1) null, ptr addrspace(5) %glob, align 8
// NOOPT: %{{.*}} = sub i64 %{{.*}}, 0
// NOOPT: call void @test_fold_callee
// NOOPT: %[[SEXT:.*]] = sext i32 ptrtoint (ptr addrspace(3) addrspacecast (ptr null to ptr addrspace(3)) to i32) to i64
// NOOPT: %{{.*}} = add nsw i64 %{{.*}}, %[[SEXT]]
// NOOPT: %{{.*}} = sub nsw i64 %{{.*}}, 1
void test_fold_local(void) {
  global int* glob = (test_fold_callee(), (global int*)(generic char*)0);
  long x = glob - (global int*)(generic char*)0;
  x = x + (int)(test_fold_callee(), (local int*)(generic char*)(global short*)0);
  x = x - (int)((local int*)0 == (local int*)(generic char*)0);
}
