// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --check-globals all --version 6
// RUN: %clang_cc1 -triple wasm64-- -fnative-half-arguments-and-returns -emit-llvm -O1 -disable-llvm-passes -o - %s | FileCheck %s

__fp16 g = 2.0f;

//.
// CHECK: @g = global i16 16384, align 2
//.
// CHECK-LABEL: define float @test_memory_fp16_to_float(
// CHECK-SAME: ptr noundef [[PTR:%.*]]) #[[ATTR0:[0-9]+]] {
// CHECK-NEXT:  [[ENTRY:.*:]]
// CHECK-NEXT:    [[PTR_ADDR:%.*]] = alloca ptr, align 8
// CHECK-NEXT:    store ptr [[PTR]], ptr [[PTR_ADDR]], align 8, !tbaa [[__FP16PTR_TBAA5:![0-9]+]]
// CHECK-NEXT:    [[TMP0:%.*]] = load ptr, ptr [[PTR_ADDR]], align 8, !tbaa [[__FP16PTR_TBAA5]]
// CHECK-NEXT:    [[TMP1:%.*]] = load i16, ptr [[TMP0]], align 2, !tbaa [[__FP16_TBAA8:![0-9]+]]
// CHECK-NEXT:    [[TMP2:%.*]] = bitcast i16 [[TMP1]] to half
// CHECK-NEXT:    [[CONV:%.*]] = fpext half [[TMP2]] to float
// CHECK-NEXT:    ret float [[CONV]]
//
float test_memory_fp16_to_float(__fp16 *ptr) {
    return *ptr;
}

// CHECK-LABEL: define void @test_memory_float_from_fp16(
// CHECK-SAME: ptr noundef [[PTR:%.*]], float noundef [[VAL:%.*]]) #[[ATTR0]] {
// CHECK-NEXT:  [[ENTRY:.*:]]
// CHECK-NEXT:    [[PTR_ADDR:%.*]] = alloca ptr, align 8
// CHECK-NEXT:    [[VAL_ADDR:%.*]] = alloca float, align 4
// CHECK-NEXT:    store ptr [[PTR]], ptr [[PTR_ADDR]], align 8, !tbaa [[__FP16PTR_TBAA5]]
// CHECK-NEXT:    store float [[VAL]], ptr [[VAL_ADDR]], align 4, !tbaa [[FLOAT_TBAA10:![0-9]+]]
// CHECK-NEXT:    [[TMP0:%.*]] = load float, ptr [[VAL_ADDR]], align 4, !tbaa [[FLOAT_TBAA10]]
// CHECK-NEXT:    [[CONV:%.*]] = fptrunc float [[TMP0]] to half
// CHECK-NEXT:    [[TMP1:%.*]] = bitcast half [[CONV]] to i16
// CHECK-NEXT:    [[TMP2:%.*]] = load ptr, ptr [[PTR_ADDR]], align 8, !tbaa [[__FP16PTR_TBAA5]]
// CHECK-NEXT:    store i16 [[TMP1]], ptr [[TMP2]], align 2, !tbaa [[__FP16_TBAA8]]
// CHECK-NEXT:    ret void
//
void test_memory_float_from_fp16(__fp16* ptr, float val) {
    *ptr = val;
}

// CHECK-LABEL: define float @test_memory_fp16_preinc(
// CHECK-SAME: ptr noundef [[PTR:%.*]]) #[[ATTR0]] {
// CHECK-NEXT:  [[ENTRY:.*:]]
// CHECK-NEXT:    [[PTR_ADDR:%.*]] = alloca ptr, align 8
// CHECK-NEXT:    store ptr [[PTR]], ptr [[PTR_ADDR]], align 8, !tbaa [[__FP16PTR_TBAA5]]
// CHECK-NEXT:    [[TMP0:%.*]] = load ptr, ptr [[PTR_ADDR]], align 8, !tbaa [[__FP16PTR_TBAA5]]
// CHECK-NEXT:    [[TMP1:%.*]] = load i16, ptr [[TMP0]], align 2, !tbaa [[__FP16_TBAA8]]
// CHECK-NEXT:    [[TMP2:%.*]] = bitcast i16 [[TMP1]] to half
// CHECK-NEXT:    [[INCDEC_CONV:%.*]] = fpext half [[TMP2]] to float
// CHECK-NEXT:    [[INC:%.*]] = fadd float [[INCDEC_CONV]], 1.000000e+00
// CHECK-NEXT:    [[INCDEC_CONV1:%.*]] = fptrunc float [[INC]] to half
// CHECK-NEXT:    [[TMP3:%.*]] = bitcast half [[INCDEC_CONV1]] to i16
// CHECK-NEXT:    store i16 [[TMP3]], ptr [[TMP0]], align 2, !tbaa [[__FP16_TBAA8]]
// CHECK-NEXT:    [[TMP4:%.*]] = bitcast i16 [[TMP3]] to half
// CHECK-NEXT:    [[CONV:%.*]] = fpext half [[TMP4]] to float
// CHECK-NEXT:    ret float [[CONV]]
//
float test_memory_fp16_preinc(__fp16 *ptr) {
  return ++(*ptr);
}

// CHECK-LABEL: define float @test_memory_fp16_postinc(
// CHECK-SAME: ptr noundef [[PTR:%.*]]) #[[ATTR0]] {
// CHECK-NEXT:  [[ENTRY:.*:]]
// CHECK-NEXT:    [[PTR_ADDR:%.*]] = alloca ptr, align 8
// CHECK-NEXT:    store ptr [[PTR]], ptr [[PTR_ADDR]], align 8, !tbaa [[__FP16PTR_TBAA5]]
// CHECK-NEXT:    [[TMP0:%.*]] = load ptr, ptr [[PTR_ADDR]], align 8, !tbaa [[__FP16PTR_TBAA5]]
// CHECK-NEXT:    [[TMP1:%.*]] = load i16, ptr [[TMP0]], align 2, !tbaa [[__FP16_TBAA8]]
// CHECK-NEXT:    [[TMP2:%.*]] = bitcast i16 [[TMP1]] to half
// CHECK-NEXT:    [[INCDEC_CONV:%.*]] = fpext half [[TMP2]] to float
// CHECK-NEXT:    [[INC:%.*]] = fadd float [[INCDEC_CONV]], 1.000000e+00
// CHECK-NEXT:    [[INCDEC_CONV1:%.*]] = fptrunc float [[INC]] to half
// CHECK-NEXT:    [[TMP3:%.*]] = bitcast half [[INCDEC_CONV1]] to i16
// CHECK-NEXT:    store i16 [[TMP3]], ptr [[TMP0]], align 2, !tbaa [[__FP16_TBAA8]]
// CHECK-NEXT:    [[TMP4:%.*]] = bitcast i16 [[TMP1]] to half
// CHECK-NEXT:    [[CONV:%.*]] = fpext half [[TMP4]] to float
// CHECK-NEXT:    ret float [[CONV]]
//
float test_memory_fp16_postinc(__fp16 *ptr) {
  return (*ptr)++;
}

// CHECK-LABEL: define float @test_memory_fp16_predec(
// CHECK-SAME: ptr noundef [[PTR:%.*]]) #[[ATTR0]] {
// CHECK-NEXT:  [[ENTRY:.*:]]
// CHECK-NEXT:    [[PTR_ADDR:%.*]] = alloca ptr, align 8
// CHECK-NEXT:    store ptr [[PTR]], ptr [[PTR_ADDR]], align 8, !tbaa [[__FP16PTR_TBAA5]]
// CHECK-NEXT:    [[TMP0:%.*]] = load ptr, ptr [[PTR_ADDR]], align 8, !tbaa [[__FP16PTR_TBAA5]]
// CHECK-NEXT:    [[TMP1:%.*]] = load i16, ptr [[TMP0]], align 2, !tbaa [[__FP16_TBAA8]]
// CHECK-NEXT:    [[TMP2:%.*]] = bitcast i16 [[TMP1]] to half
// CHECK-NEXT:    [[INCDEC_CONV:%.*]] = fpext half [[TMP2]] to float
// CHECK-NEXT:    [[DEC:%.*]] = fadd float [[INCDEC_CONV]], -1.000000e+00
// CHECK-NEXT:    [[INCDEC_CONV1:%.*]] = fptrunc float [[DEC]] to half
// CHECK-NEXT:    [[TMP3:%.*]] = bitcast half [[INCDEC_CONV1]] to i16
// CHECK-NEXT:    store i16 [[TMP3]], ptr [[TMP0]], align 2, !tbaa [[__FP16_TBAA8]]
// CHECK-NEXT:    [[TMP4:%.*]] = bitcast i16 [[TMP3]] to half
// CHECK-NEXT:    [[CONV:%.*]] = fpext half [[TMP4]] to float
// CHECK-NEXT:    ret float [[CONV]]
//
float test_memory_fp16_predec(__fp16 *ptr) {
  return --(*ptr);
}

// CHECK-LABEL: define float @test_memory_fp16_postdec(
// CHECK-SAME: ptr noundef [[PTR:%.*]]) #[[ATTR0]] {
// CHECK-NEXT:  [[ENTRY:.*:]]
// CHECK-NEXT:    [[PTR_ADDR:%.*]] = alloca ptr, align 8
// CHECK-NEXT:    store ptr [[PTR]], ptr [[PTR_ADDR]], align 8, !tbaa [[__FP16PTR_TBAA5]]
// CHECK-NEXT:    [[TMP0:%.*]] = load ptr, ptr [[PTR_ADDR]], align 8, !tbaa [[__FP16PTR_TBAA5]]
// CHECK-NEXT:    [[TMP1:%.*]] = load i16, ptr [[TMP0]], align 2, !tbaa [[__FP16_TBAA8]]
// CHECK-NEXT:    [[TMP2:%.*]] = bitcast i16 [[TMP1]] to half
// CHECK-NEXT:    [[INCDEC_CONV:%.*]] = fpext half [[TMP2]] to float
// CHECK-NEXT:    [[DEC:%.*]] = fadd float [[INCDEC_CONV]], -1.000000e+00
// CHECK-NEXT:    [[INCDEC_CONV1:%.*]] = fptrunc float [[DEC]] to half
// CHECK-NEXT:    [[TMP3:%.*]] = bitcast half [[INCDEC_CONV1]] to i16
// CHECK-NEXT:    store i16 [[TMP3]], ptr [[TMP0]], align 2, !tbaa [[__FP16_TBAA8]]
// CHECK-NEXT:    [[TMP4:%.*]] = bitcast i16 [[TMP1]] to half
// CHECK-NEXT:    [[CONV:%.*]] = fpext half [[TMP4]] to float
// CHECK-NEXT:    ret float [[CONV]]
//
float test_memory_fp16_postdec(__fp16 *ptr) {
  return (*ptr)--;
}

// CHECK-LABEL: define i16 @test_arg_return(
// CHECK-SAME: i16 noundef [[X:%.*]]) #[[ATTR0]] {
// CHECK-NEXT:  [[ENTRY:.*:]]
// CHECK-NEXT:    [[X_ADDR:%.*]] = alloca i16, align 2
// CHECK-NEXT:    store i16 [[X]], ptr [[X_ADDR]], align 2, !tbaa [[__FP16_TBAA8]]
// CHECK-NEXT:    [[TMP0:%.*]] = load i16, ptr [[X_ADDR]], align 2, !tbaa [[__FP16_TBAA8]]
// CHECK-NEXT:    [[TMP1:%.*]] = bitcast i16 [[TMP0]] to half
// CHECK-NEXT:    [[CONV:%.*]] = fpext half [[TMP1]] to float
// CHECK-NEXT:    [[TMP2:%.*]] = load i16, ptr [[X_ADDR]], align 2, !tbaa [[__FP16_TBAA8]]
// CHECK-NEXT:    [[TMP3:%.*]] = bitcast i16 [[TMP2]] to half
// CHECK-NEXT:    [[CONV1:%.*]] = fpext half [[TMP3]] to float
// CHECK-NEXT:    [[ADD:%.*]] = fadd float [[CONV]], [[CONV1]]
// CHECK-NEXT:    [[CONV2:%.*]] = fptrunc float [[ADD]] to half
// CHECK-NEXT:    [[TMP4:%.*]] = bitcast half [[CONV2]] to i16
// CHECK-NEXT:    ret i16 [[TMP4]]
//
__fp16 test_arg_return(__fp16 x) {
    return x + x;
}
//.
// CHECK: attributes #[[ATTR0]] = { nounwind "no-trapping-math"="true" "stack-protector-buffer-size"="8" }
//.
// CHECK: [[META0:![0-9]+]] = !{!"{{.*}}clang version {{.*}}"}
// CHECK: [[META1:![0-9]+]] = !{[[META2:![0-9]+]], [[META2]], i64 0}
// CHECK: [[META2]] = !{!"int", [[META3:![0-9]+]], i64 0}
// CHECK: [[META3]] = !{!"omnipotent char", [[META4:![0-9]+]], i64 0}
// CHECK: [[META4]] = !{!"Simple C/C++ TBAA"}
// CHECK: [[__FP16PTR_TBAA5]] = !{[[META6:![0-9]+]], [[META6]], i64 0}
// CHECK: [[META6]] = !{!"p1 __fp16", [[META7:![0-9]+]], i64 0}
// CHECK: [[META7]] = !{!"any pointer", [[META3]], i64 0}
// CHECK: [[__FP16_TBAA8]] = !{[[META9:![0-9]+]], [[META9]], i64 0}
// CHECK: [[META9]] = !{!"__fp16", [[META3]], i64 0}
// CHECK: [[FLOAT_TBAA10]] = !{[[META11:![0-9]+]], [[META11]], i64 0}
// CHECK: [[META11]] = !{!"float", [[META3]], i64 0}
//.
