llvm/clang/test/CodeGen/X86/Float16-arithmetic.c

// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py
// RUN: %clang_cc1 -triple x86_64-unknown-unknown -emit-llvm -o - %s | FileCheck %s

// CHECK-LABEL: @add1(
// CHECK-NEXT:  entry:
// CHECK-NEXT:    [[A_ADDR:%.*]] = alloca half, align 2
// CHECK-NEXT:    [[B_ADDR:%.*]] = alloca half, align 2
// CHECK-NEXT:    store half [[A:%.*]], ptr [[A_ADDR]], align 2
// CHECK-NEXT:    store half [[B:%.*]], ptr [[B_ADDR]], align 2
// CHECK-NEXT:    [[TMP0:%.*]] = load half, ptr [[A_ADDR]], align 2
// CHECK-NEXT:    [[EXT:%.*]] = fpext half [[TMP0]] to float
// CHECK-NEXT:    [[TMP1:%.*]] = load half, ptr [[B_ADDR]], align 2
// CHECK-NEXT:    [[EXT1:%.*]] = fpext half [[TMP1]] to float
// CHECK-NEXT:    [[ADD:%.*]] = fadd float [[EXT]], [[EXT1]]
// CHECK-NEXT:    [[UNPROMOTION:%.*]] = fptrunc float [[ADD]] to half
// CHECK-NEXT:    ret half [[UNPROMOTION]]
//
_Float16 add1(_Float16 a, _Float16 b) {
  return a + b;
}

// CHECK-LABEL: @add2(
// CHECK-NEXT:  entry:
// CHECK-NEXT:    [[A_ADDR:%.*]] = alloca half, align 2
// CHECK-NEXT:    [[B_ADDR:%.*]] = alloca half, align 2
// CHECK-NEXT:    [[C_ADDR:%.*]] = alloca half, align 2
// CHECK-NEXT:    store half [[A:%.*]], ptr [[A_ADDR]], align 2
// CHECK-NEXT:    store half [[B:%.*]], ptr [[B_ADDR]], align 2
// CHECK-NEXT:    store half [[C:%.*]], ptr [[C_ADDR]], align 2
// CHECK-NEXT:    [[TMP0:%.*]] = load half, ptr [[A_ADDR]], align 2
// CHECK-NEXT:    [[EXT:%.*]] = fpext half [[TMP0]] to float
// CHECK-NEXT:    [[TMP1:%.*]] = load half, ptr [[B_ADDR]], align 2
// CHECK-NEXT:    [[EXT1:%.*]] = fpext half [[TMP1]] to float
// CHECK-NEXT:    [[ADD:%.*]] = fadd float [[EXT]], [[EXT1]]
// CHECK-NEXT:    [[TMP2:%.*]] = load half, ptr [[C_ADDR]], align 2
// CHECK-NEXT:    [[EXT2:%.*]] = fpext half [[TMP2]] to float
// CHECK-NEXT:    [[ADD3:%.*]] = fadd float [[ADD]], [[EXT2]]
// CHECK-NEXT:    [[UNPROMOTION:%.*]] = fptrunc float [[ADD3]] to half
// CHECK-NEXT:    ret half [[UNPROMOTION]]
//
_Float16 add2(_Float16 a, _Float16 b, _Float16 c) {
  return a + b + c;
}

// CHECK-LABEL: @div(
// CHECK-NEXT:  entry:
// CHECK-NEXT:    [[A_ADDR:%.*]] = alloca half, align 2
// CHECK-NEXT:    [[B_ADDR:%.*]] = alloca half, align 2
// CHECK-NEXT:    store half [[A:%.*]], ptr [[A_ADDR]], align 2
// CHECK-NEXT:    store half [[B:%.*]], ptr [[B_ADDR]], align 2
// CHECK-NEXT:    [[TMP0:%.*]] = load half, ptr [[A_ADDR]], align 2
// CHECK-NEXT:    [[EXT:%.*]] = fpext half [[TMP0]] to float
// CHECK-NEXT:    [[TMP1:%.*]] = load half, ptr [[B_ADDR]], align 2
// CHECK-NEXT:    [[EXT1:%.*]] = fpext half [[TMP1]] to float
// CHECK-NEXT:    [[DIV:%.*]] = fdiv float [[EXT]], [[EXT1]]
// CHECK-NEXT:    [[UNPROMOTION:%.*]] = fptrunc float [[DIV]] to half
// CHECK-NEXT:    ret half [[UNPROMOTION]]
//
_Float16 div(_Float16 a, _Float16 b) {
  return a / b;
}

// CHECK-LABEL: @mul(
// CHECK-NEXT:  entry:
// CHECK-NEXT:    [[A_ADDR:%.*]] = alloca half, align 2
// CHECK-NEXT:    [[B_ADDR:%.*]] = alloca half, align 2
// CHECK-NEXT:    store half [[A:%.*]], ptr [[A_ADDR]], align 2
// CHECK-NEXT:    store half [[B:%.*]], ptr [[B_ADDR]], align 2
// CHECK-NEXT:    [[TMP0:%.*]] = load half, ptr [[A_ADDR]], align 2
// CHECK-NEXT:    [[EXT:%.*]] = fpext half [[TMP0]] to float
// CHECK-NEXT:    [[TMP1:%.*]] = load half, ptr [[B_ADDR]], align 2
// CHECK-NEXT:    [[EXT1:%.*]] = fpext half [[TMP1]] to float
// CHECK-NEXT:    [[MUL:%.*]] = fmul float [[EXT]], [[EXT1]]
// CHECK-NEXT:    [[UNPROMOTION:%.*]] = fptrunc float [[MUL]] to half
// CHECK-NEXT:    ret half [[UNPROMOTION]]
//
_Float16 mul(_Float16 a, _Float16 b) {
  return a * b;
}

// CHECK-LABEL: @add_and_mul1(
// CHECK-NEXT:  entry:
// CHECK-NEXT:    [[A_ADDR:%.*]] = alloca half, align 2
// CHECK-NEXT:    [[B_ADDR:%.*]] = alloca half, align 2
// CHECK-NEXT:    [[C_ADDR:%.*]] = alloca half, align 2
// CHECK-NEXT:    [[D_ADDR:%.*]] = alloca half, align 2
// CHECK-NEXT:    store half [[A:%.*]], ptr [[A_ADDR]], align 2
// CHECK-NEXT:    store half [[B:%.*]], ptr [[B_ADDR]], align 2
// CHECK-NEXT:    store half [[C:%.*]], ptr [[C_ADDR]], align 2
// CHECK-NEXT:    store half [[D:%.*]], ptr [[D_ADDR]], align 2
// CHECK-NEXT:    [[TMP0:%.*]] = load half, ptr [[A_ADDR]], align 2
// CHECK-NEXT:    [[EXT:%.*]] = fpext half [[TMP0]] to float
// CHECK-NEXT:    [[TMP1:%.*]] = load half, ptr [[B_ADDR]], align 2
// CHECK-NEXT:    [[EXT1:%.*]] = fpext half [[TMP1]] to float
// CHECK-NEXT:    [[MUL:%.*]] = fmul float [[EXT]], [[EXT1]]
// CHECK-NEXT:    [[TMP2:%.*]] = load half, ptr [[C_ADDR]], align 2
// CHECK-NEXT:    [[EXT2:%.*]] = fpext half [[TMP2]] to float
// CHECK-NEXT:    [[TMP3:%.*]] = load half, ptr [[D_ADDR]], align 2
// CHECK-NEXT:    [[EXT3:%.*]] = fpext half [[TMP3]] to float
// CHECK-NEXT:    [[MUL4:%.*]] = fmul float [[EXT2]], [[EXT3]]
// CHECK-NEXT:    [[ADD:%.*]] = fadd float [[MUL]], [[MUL4]]
// CHECK-NEXT:    [[UNPROMOTION:%.*]] = fptrunc float [[ADD]] to half
// CHECK-NEXT:    ret half [[UNPROMOTION]]
//
_Float16 add_and_mul1(_Float16 a, _Float16 b, _Float16 c, _Float16 d) {
  return a * b + c * d;
}

// CHECK-LABEL: @add_and_mul2(
// CHECK-NEXT:  entry:
// CHECK-NEXT:    [[A_ADDR:%.*]] = alloca half, align 2
// CHECK-NEXT:    [[B_ADDR:%.*]] = alloca half, align 2
// CHECK-NEXT:    [[C_ADDR:%.*]] = alloca half, align 2
// CHECK-NEXT:    store half [[A:%.*]], ptr [[A_ADDR]], align 2
// CHECK-NEXT:    store half [[B:%.*]], ptr [[B_ADDR]], align 2
// CHECK-NEXT:    store half [[C:%.*]], ptr [[C_ADDR]], align 2
// CHECK-NEXT:    [[TMP0:%.*]] = load half, ptr [[A_ADDR]], align 2
// CHECK-NEXT:    [[EXT:%.*]] = fpext half [[TMP0]] to float
// CHECK-NEXT:    [[TMP1:%.*]] = load half, ptr [[B_ADDR]], align 2
// CHECK-NEXT:    [[EXT1:%.*]] = fpext half [[TMP1]] to float
// CHECK-NEXT:    [[MUL:%.*]] = fmul float 6.000000e+00, [[EXT1]]
// CHECK-NEXT:    [[SUB:%.*]] = fsub float [[EXT]], [[MUL]]
// CHECK-NEXT:    [[TMP2:%.*]] = load half, ptr [[C_ADDR]], align 2
// CHECK-NEXT:    [[EXT2:%.*]] = fpext half [[TMP2]] to float
// CHECK-NEXT:    [[ADD:%.*]] = fadd float [[SUB]], [[EXT2]]
// CHECK-NEXT:    [[UNPROMOTION:%.*]] = fptrunc float [[ADD]] to half
// CHECK-NEXT:    ret half [[UNPROMOTION]]
//
_Float16 add_and_mul2(_Float16 a, _Float16 b, _Float16 c) {
  return (a - 6 * b) + c;
}

// CHECK-LABEL: @addcompound(
// CHECK-NEXT:  entry:
// CHECK-NEXT:    [[A_ADDR:%.*]] = alloca half, align 2
// CHECK-NEXT:    [[C_ADDR:%.*]] = alloca half, align 2
// CHECK-NEXT:    store half [[A:%.*]], ptr [[A_ADDR]], align 2
// CHECK-NEXT:    store half [[C:%.*]], ptr [[C_ADDR]], align 2
// CHECK-NEXT:    [[TMP0:%.*]] = load half, ptr [[A_ADDR]], align 2
// CHECK-NEXT:    [[EXT:%.*]] = fpext half [[TMP0]] to float
// CHECK-NEXT:    [[TMP1:%.*]] = load half, ptr [[C_ADDR]], align 2
// CHECK-NEXT:    [[CONV:%.*]] = fpext half [[TMP1]] to float
// CHECK-NEXT:    [[ADD:%.*]] = fadd float [[CONV]], [[EXT]]
// CHECK-NEXT:    [[CONV1:%.*]] = fptrunc float [[ADD]] to half
// CHECK-NEXT:    store half [[CONV1]], ptr [[C_ADDR]], align 2
// CHECK-NEXT:    [[TMP2:%.*]] = load half, ptr [[C_ADDR]], align 2
// CHECK-NEXT:    ret half [[TMP2]]
//
_Float16 addcompound(_Float16 a, _Float16 c) {
  c += a;
  return c;
}

// CHECK-LABEL: @mulcompound_int_float16(
// CHECK-NEXT:  entry:
// CHECK-NEXT:    [[A_ADDR:%.*]] = alloca i32, align 4
// CHECK-NEXT:    [[C_ADDR:%.*]] = alloca half, align 2
// CHECK-NEXT:    store i32 [[A:%.*]], ptr [[A_ADDR]], align 4
// CHECK-NEXT:    store half [[C:%.*]], ptr [[C_ADDR]], align 2
// CHECK-NEXT:    [[TMP0:%.*]] = load half, ptr [[C_ADDR]], align 2
// CHECK-NEXT:    [[EXT:%.*]] = fpext half [[TMP0]] to float
// CHECK-NEXT:    [[TMP1:%.*]] = load i32, ptr [[A_ADDR]], align 4
// CHECK-NEXT:    [[CONV:%.*]] = sitofp i32 [[TMP1]] to float
// CHECK-NEXT:    [[MUL:%.*]] = fmul float [[CONV]], [[EXT]]
// CHECK-NEXT:    [[CONV1:%.*]] = fptosi float [[MUL]] to i32
// CHECK-NEXT:    store i32 [[CONV1]], ptr [[A_ADDR]], align 4
// CHECK-NEXT:    [[TMP2:%.*]] = load half, ptr [[C_ADDR]], align 2
// CHECK-NEXT:    ret half [[TMP2]]
//
_Float16 mulcompound_int_float16(int a, _Float16 c) {
  a *= c;
  return c;
}

// CHECK-LABEL: @mulcompound_float_float16c(
// CHECK-NEXT:  entry:
// CHECK-NEXT:    [[C:%.*]] = alloca { half, half }, align 2
// CHECK-NEXT:    [[A_ADDR:%.*]] = alloca float, align 4
// CHECK-NEXT:    store <2 x half> [[C_COERCE:%.*]], ptr [[C]], align 2
// CHECK-NEXT:    store float [[A:%.*]], ptr [[A_ADDR]], align 4
// CHECK-NEXT:    [[C_REALP:%.*]] = getelementptr inbounds nuw { half, half }, ptr [[C]], i32 0, i32 0
// CHECK-NEXT:    [[C_REAL:%.*]] = load half, ptr [[C_REALP]], align 2
// CHECK-NEXT:    [[C_IMAGP:%.*]] = getelementptr inbounds nuw { half, half }, ptr [[C]], i32 0, i32 1
// CHECK-NEXT:    [[C_IMAG:%.*]] = load half, ptr [[C_IMAGP]], align 2
// CHECK-NEXT:    [[CONV:%.*]] = fpext half [[C_REAL]] to float
// CHECK-NEXT:    [[CONV1:%.*]] = fpext half [[C_IMAG]] to float
// CHECK-NEXT:    [[TMP0:%.*]] = load float, ptr [[A_ADDR]], align 4
// CHECK-NEXT:    [[MUL_RL:%.*]] = fmul float [[TMP0]], [[CONV]]
// CHECK-NEXT:    [[MUL_IR:%.*]] = fmul float [[TMP0]], [[CONV1]]
// CHECK-NEXT:    store float [[MUL_RL]], ptr [[A_ADDR]], align 4
// CHECK-NEXT:    [[C_REALP2:%.*]] = getelementptr inbounds nuw { half, half }, ptr [[C]], i32 0, i32 0
// CHECK-NEXT:    [[C_REAL3:%.*]] = load half, ptr [[C_REALP2]], align 2
// CHECK-NEXT:    ret half [[C_REAL3]]
//
_Float16 mulcompound_float_float16c(float a, _Float16 _Complex c) {
  a *= c;
  return c;
}

// CHECK-LABEL: @RealOp(
// CHECK-NEXT:  entry:
// CHECK-NEXT:    [[A_ADDR:%.*]] = alloca half, align 2
// CHECK-NEXT:    store half [[A:%.*]], ptr [[A_ADDR]], align 2
// CHECK-NEXT:    [[TMP0:%.*]] = load half, ptr [[A_ADDR]], align 2
// CHECK-NEXT:    [[EXT:%.*]] = fpext half [[TMP0]] to float
// CHECK-NEXT:    [[UNPROMOTION:%.*]] = fptrunc float [[EXT]] to half
// CHECK-NEXT:    ret half [[UNPROMOTION]]
//
_Float16 RealOp(_Float16 a) {
  return __real a;
}

// CHECK-LABEL: @RealOp_c(
// CHECK-NEXT:  entry:
// CHECK-NEXT:    [[A:%.*]] = alloca { half, half }, align 2
// CHECK-NEXT:    store <2 x half> [[A_COERCE:%.*]], ptr [[A]], align 2
// CHECK-NEXT:    [[A_REALP:%.*]] = getelementptr inbounds nuw { half, half }, ptr [[A]], i32 0, i32 0
// CHECK-NEXT:    [[A_REAL:%.*]] = load half, ptr [[A_REALP]], align 2
// CHECK-NEXT:    [[EXT:%.*]] = fpext half [[A_REAL]] to float
// CHECK-NEXT:    [[UNPROMOTION:%.*]] = fptrunc float [[EXT]] to half
// CHECK-NEXT:    ret half [[UNPROMOTION]]
//
_Float16 RealOp_c(_Float16 _Complex a) {
  return __real a;
}

// CHECK-LABEL: @ImagOp(
// CHECK-NEXT:  entry:
// CHECK-NEXT:    [[A_ADDR:%.*]] = alloca half, align 2
// CHECK-NEXT:    store half [[A:%.*]], ptr [[A_ADDR]], align 2
// CHECK-NEXT:    [[TMP0:%.*]] = load half, ptr [[A_ADDR]], align 2
// CHECK-NEXT:    [[EXT:%.*]] = fpext half [[TMP0]] to float
// CHECK-NEXT:    ret half 0xH0000
//
_Float16 ImagOp(_Float16 a) {
  return __imag a;
}

// CHECK-LABEL: @ImagOp_c(
// CHECK-NEXT:  entry:
// CHECK-NEXT:    [[A:%.*]] = alloca { half, half }, align 2
// CHECK-NEXT:    store <2 x half> [[A_COERCE:%.*]], ptr [[A]], align 2
// CHECK-NEXT:    [[A_IMAGP:%.*]] = getelementptr inbounds nuw { half, half }, ptr [[A]], i32 0, i32 1
// CHECK-NEXT:    [[A_IMAG:%.*]] = load half, ptr [[A_IMAGP]], align 2
// CHECK-NEXT:    [[EXT:%.*]] = fpext half [[A_IMAG]] to float
// CHECK-NEXT:    [[UNPROMOTION:%.*]] = fptrunc float [[EXT]] to half
// CHECK-NEXT:    ret half [[UNPROMOTION]]
//
_Float16 ImagOp_c(_Float16 _Complex a) {
  return __imag a;
}

// CHECK-LABEL: @MinusOp_r(
// CHECK-NEXT:  entry:
// CHECK-NEXT:    [[A_ADDR:%.*]] = alloca half, align 2
// CHECK-NEXT:    store half [[A:%.*]], ptr [[A_ADDR]], align 2
// CHECK-NEXT:    [[TMP0:%.*]] = load half, ptr [[A_ADDR]], align 2
// CHECK-NEXT:    [[EXT:%.*]] = fpext half [[TMP0]] to float
// CHECK-NEXT:    [[FNEG:%.*]] = fneg float [[EXT]]
// CHECK-NEXT:    [[UNPROMOTION:%.*]] = fptrunc float [[FNEG]] to half
// CHECK-NEXT:    ret half [[UNPROMOTION]]
//
_Float16 MinusOp_r(_Float16 a) {
  return -a;
}

// CHECK-LABEL: @MinusOp_c(
// CHECK-NEXT:  entry:
// CHECK-NEXT:    [[A:%.*]] = alloca { half, half }, align 2
// CHECK-NEXT:    store <2 x half> [[A_COERCE:%.*]], ptr [[A]], align 2
// CHECK-NEXT:    [[A_REALP:%.*]] = getelementptr inbounds nuw { half, half }, ptr [[A]], i32 0, i32 0
// CHECK-NEXT:    [[A_REAL:%.*]] = load half, ptr [[A_REALP]], align 2
// CHECK-NEXT:    [[A_IMAGP:%.*]] = getelementptr inbounds nuw { half, half }, ptr [[A]], i32 0, i32 1
// CHECK-NEXT:    [[A_IMAG:%.*]] = load half, ptr [[A_IMAGP]], align 2
// CHECK-NEXT:    [[EXT:%.*]] = fpext half [[A_REAL]] to float
// CHECK-NEXT:    [[EXT1:%.*]] = fpext half [[A_IMAG]] to float
// CHECK-NEXT:    [[NEG_R:%.*]] = fneg float [[EXT]]
// CHECK-NEXT:    [[NEG_I:%.*]] = fneg float [[EXT1]]
// CHECK-NEXT:    [[UNPROMOTION:%.*]] = fptrunc float [[NEG_R]] to half
// CHECK-NEXT:    [[UNPROMOTION2:%.*]] = fptrunc float [[NEG_I]] to half
// CHECK-NEXT:    ret half [[UNPROMOTION]]
//
_Float16 MinusOp_c(_Float16 _Complex a) {
  return -a;
}

// CHECK-LABEL: @PlusOp_r(
// CHECK-NEXT:  entry:
// CHECK-NEXT:    [[A_ADDR:%.*]] = alloca half, align 2
// CHECK-NEXT:    store half [[A:%.*]], ptr [[A_ADDR]], align 2
// CHECK-NEXT:    [[TMP0:%.*]] = load half, ptr [[A_ADDR]], align 2
// CHECK-NEXT:    [[EXT:%.*]] = fpext half [[TMP0]] to float
// CHECK-NEXT:    [[UNPROMOTION:%.*]] = fptrunc float [[EXT]] to half
// CHECK-NEXT:    ret half [[UNPROMOTION]]
//
_Float16 PlusOp_r(_Float16 a) {
  return +a;
}

// CHECK-LABEL: @PlusOp_c(
// CHECK-NEXT:  entry:
// CHECK-NEXT:    [[A:%.*]] = alloca { half, half }, align 2
// CHECK-NEXT:    store <2 x half> [[A_COERCE:%.*]], ptr [[A]], align 2
// CHECK-NEXT:    [[A_REALP:%.*]] = getelementptr inbounds nuw { half, half }, ptr [[A]], i32 0, i32 0
// CHECK-NEXT:    [[A_REAL:%.*]] = load half, ptr [[A_REALP]], align 2
// CHECK-NEXT:    [[A_IMAGP:%.*]] = getelementptr inbounds nuw { half, half }, ptr [[A]], i32 0, i32 1
// CHECK-NEXT:    [[A_IMAG:%.*]] = load half, ptr [[A_IMAGP]], align 2
// CHECK-NEXT:    [[EXT:%.*]] = fpext half [[A_REAL]] to float
// CHECK-NEXT:    [[EXT1:%.*]] = fpext half [[A_IMAG]] to float
// CHECK-NEXT:    [[UNPROMOTION:%.*]] = fptrunc float [[EXT]] to half
// CHECK-NEXT:    [[UNPROMOTION2:%.*]] = fptrunc float [[EXT1]] to half
// CHECK-NEXT:    ret half [[UNPROMOTION]]
//
_Float16 PlusOp_c(_Float16 _Complex a) {
  return +a;
}

// CHECK-LABEL: @MinusOp_r_r(
// CHECK-NEXT:  entry:
// CHECK-NEXT:    [[A_ADDR:%.*]] = alloca half, align 2
// CHECK-NEXT:    [[C_ADDR:%.*]] = alloca half, align 2
// CHECK-NEXT:    store half [[A:%.*]], ptr [[A_ADDR]], align 2
// CHECK-NEXT:    store half [[C:%.*]], ptr [[C_ADDR]], align 2
// CHECK-NEXT:    [[TMP0:%.*]] = load half, ptr [[A_ADDR]], align 2
// CHECK-NEXT:    [[EXT:%.*]] = fpext half [[TMP0]] to float
// CHECK-NEXT:    [[TMP1:%.*]] = load half, ptr [[C_ADDR]], align 2
// CHECK-NEXT:    [[EXT1:%.*]] = fpext half [[TMP1]] to float
// CHECK-NEXT:    [[FNEG:%.*]] = fneg float [[EXT1]]
// CHECK-NEXT:    [[ADD:%.*]] = fadd float [[EXT]], [[FNEG]]
// CHECK-NEXT:    [[UNPROMOTION:%.*]] = fptrunc float [[ADD]] to half
// CHECK-NEXT:    ret half [[UNPROMOTION]]
//
_Float16 MinusOp_r_r(_Float16 a, _Float16 c) {
  return a + -c;
}

// CHECK-LABEL: @MinusOp_c_r(
// CHECK-NEXT:  entry:
// CHECK-NEXT:    [[A:%.*]] = alloca { half, half }, align 2
// CHECK-NEXT:    [[C_ADDR:%.*]] = alloca half, align 2
// CHECK-NEXT:    store <2 x half> [[A_COERCE:%.*]], ptr [[A]], align 2
// CHECK-NEXT:    store half [[C:%.*]], ptr [[C_ADDR]], align 2
// CHECK-NEXT:    [[A_REALP:%.*]] = getelementptr inbounds nuw { half, half }, ptr [[A]], i32 0, i32 0
// CHECK-NEXT:    [[A_REAL:%.*]] = load half, ptr [[A_REALP]], align 2
// CHECK-NEXT:    [[A_IMAGP:%.*]] = getelementptr inbounds nuw { half, half }, ptr [[A]], i32 0, i32 1
// CHECK-NEXT:    [[A_IMAG:%.*]] = load half, ptr [[A_IMAGP]], align 2
// CHECK-NEXT:    [[EXT:%.*]] = fpext half [[A_REAL]] to float
// CHECK-NEXT:    [[EXT1:%.*]] = fpext half [[A_IMAG]] to float
// CHECK-NEXT:    [[TMP0:%.*]] = load half, ptr [[C_ADDR]], align 2
// CHECK-NEXT:    [[EXT2:%.*]] = fpext half [[TMP0]] to float
// CHECK-NEXT:    [[FNEG:%.*]] = fneg float [[EXT2]]
// CHECK-NEXT:    [[ADD_R:%.*]] = fadd float [[EXT]], [[FNEG]]
// CHECK-NEXT:    [[UNPROMOTION:%.*]] = fptrunc float [[ADD_R]] to half
// CHECK-NEXT:    [[UNPROMOTION3:%.*]] = fptrunc float [[EXT1]] to half
// CHECK-NEXT:    ret half [[UNPROMOTION]]
//
_Float16 MinusOp_c_r(_Float16 _Complex a, _Float16 c) {
  return a + -c;
}

// CHECK-LABEL: @MinusOp_r_c(
// CHECK-NEXT:  entry:
// CHECK-NEXT:    [[C:%.*]] = alloca { half, half }, align 2
// CHECK-NEXT:    [[A_ADDR:%.*]] = alloca half, align 2
// CHECK-NEXT:    store <2 x half> [[C_COERCE:%.*]], ptr [[C]], align 2
// CHECK-NEXT:    store half [[A:%.*]], ptr [[A_ADDR]], align 2
// CHECK-NEXT:    [[TMP0:%.*]] = load half, ptr [[A_ADDR]], align 2
// CHECK-NEXT:    [[EXT:%.*]] = fpext half [[TMP0]] to float
// CHECK-NEXT:    [[C_REALP:%.*]] = getelementptr inbounds nuw { half, half }, ptr [[C]], i32 0, i32 0
// CHECK-NEXT:    [[C_REAL:%.*]] = load half, ptr [[C_REALP]], align 2
// CHECK-NEXT:    [[C_IMAGP:%.*]] = getelementptr inbounds nuw { half, half }, ptr [[C]], i32 0, i32 1
// CHECK-NEXT:    [[C_IMAG:%.*]] = load half, ptr [[C_IMAGP]], align 2
// CHECK-NEXT:    [[EXT1:%.*]] = fpext half [[C_REAL]] to float
// CHECK-NEXT:    [[EXT2:%.*]] = fpext half [[C_IMAG]] to float
// CHECK-NEXT:    [[NEG_R:%.*]] = fneg float [[EXT1]]
// CHECK-NEXT:    [[NEG_I:%.*]] = fneg float [[EXT2]]
// CHECK-NEXT:    [[ADD_R:%.*]] = fadd float [[EXT]], [[NEG_R]]
// CHECK-NEXT:    [[UNPROMOTION:%.*]] = fptrunc float [[ADD_R]] to half
// CHECK-NEXT:    [[UNPROMOTION3:%.*]] = fptrunc float [[NEG_I]] to half
// CHECK-NEXT:    ret half [[UNPROMOTION]]
//
_Float16 MinusOp_r_c(_Float16 a, _Float16 _Complex c) {
  return a + -c;
}

// CHECK-LABEL: @MinusOp_c_c(
// CHECK-NEXT:  entry:
// CHECK-NEXT:    [[A:%.*]] = alloca { half, half }, align 2
// CHECK-NEXT:    [[C:%.*]] = alloca { half, half }, align 2
// CHECK-NEXT:    store <2 x half> [[A_COERCE:%.*]], ptr [[A]], align 2
// CHECK-NEXT:    store <2 x half> [[C_COERCE:%.*]], ptr [[C]], align 2
// CHECK-NEXT:    [[A_REALP:%.*]] = getelementptr inbounds nuw { half, half }, ptr [[A]], i32 0, i32 0
// CHECK-NEXT:    [[A_REAL:%.*]] = load half, ptr [[A_REALP]], align 2
// CHECK-NEXT:    [[A_IMAGP:%.*]] = getelementptr inbounds nuw { half, half }, ptr [[A]], i32 0, i32 1
// CHECK-NEXT:    [[A_IMAG:%.*]] = load half, ptr [[A_IMAGP]], align 2
// CHECK-NEXT:    [[EXT:%.*]] = fpext half [[A_REAL]] to float
// CHECK-NEXT:    [[EXT1:%.*]] = fpext half [[A_IMAG]] to float
// CHECK-NEXT:    [[C_REALP:%.*]] = getelementptr inbounds nuw { half, half }, ptr [[C]], i32 0, i32 0
// CHECK-NEXT:    [[C_REAL:%.*]] = load half, ptr [[C_REALP]], align 2
// CHECK-NEXT:    [[C_IMAGP:%.*]] = getelementptr inbounds nuw { half, half }, ptr [[C]], i32 0, i32 1
// CHECK-NEXT:    [[C_IMAG:%.*]] = load half, ptr [[C_IMAGP]], align 2
// CHECK-NEXT:    [[EXT2:%.*]] = fpext half [[C_REAL]] to float
// CHECK-NEXT:    [[EXT3:%.*]] = fpext half [[C_IMAG]] to float
// CHECK-NEXT:    [[NEG_R:%.*]] = fneg float [[EXT2]]
// CHECK-NEXT:    [[NEG_I:%.*]] = fneg float [[EXT3]]
// CHECK-NEXT:    [[ADD_R:%.*]] = fadd float [[EXT]], [[NEG_R]]
// CHECK-NEXT:    [[ADD_I:%.*]] = fadd float [[EXT1]], [[NEG_I]]
// CHECK-NEXT:    [[UNPROMOTION:%.*]] = fptrunc float [[ADD_R]] to half
// CHECK-NEXT:    [[UNPROMOTION4:%.*]] = fptrunc float [[ADD_I]] to half
// CHECK-NEXT:    ret half [[UNPROMOTION]]
//
_Float16 MinusOp_c_c(_Float16 _Complex a, _Float16 _Complex c) {
    return a + -c;
}

// CHECK-LABEL: @PlusOp_r_r(
// CHECK-NEXT:  entry:
// CHECK-NEXT:    [[A_ADDR:%.*]] = alloca half, align 2
// CHECK-NEXT:    [[C_ADDR:%.*]] = alloca half, align 2
// CHECK-NEXT:    store half [[A:%.*]], ptr [[A_ADDR]], align 2
// CHECK-NEXT:    store half [[C:%.*]], ptr [[C_ADDR]], align 2
// CHECK-NEXT:    [[TMP0:%.*]] = load half, ptr [[A_ADDR]], align 2
// CHECK-NEXT:    [[EXT:%.*]] = fpext half [[TMP0]] to float
// CHECK-NEXT:    [[TMP1:%.*]] = load half, ptr [[C_ADDR]], align 2
// CHECK-NEXT:    [[EXT1:%.*]] = fpext half [[TMP1]] to float
// CHECK-NEXT:    [[SUB:%.*]] = fsub float [[EXT]], [[EXT1]]
// CHECK-NEXT:    [[UNPROMOTION:%.*]] = fptrunc float [[SUB]] to half
// CHECK-NEXT:    ret half [[UNPROMOTION]]
//
_Float16 PlusOp_r_r(_Float16 a, _Float16 c) {
  return a - +c;
}

// CHECK-LABEL: @PlusOp_c_r(
// CHECK-NEXT:  entry:
// CHECK-NEXT:    [[A:%.*]] = alloca { half, half }, align 2
// CHECK-NEXT:    [[C_ADDR:%.*]] = alloca half, align 2
// CHECK-NEXT:    store <2 x half> [[A_COERCE:%.*]], ptr [[A]], align 2
// CHECK-NEXT:    store half [[C:%.*]], ptr [[C_ADDR]], align 2
// CHECK-NEXT:    [[A_REALP:%.*]] = getelementptr inbounds nuw { half, half }, ptr [[A]], i32 0, i32 0
// CHECK-NEXT:    [[A_REAL:%.*]] = load half, ptr [[A_REALP]], align 2
// CHECK-NEXT:    [[A_IMAGP:%.*]] = getelementptr inbounds nuw { half, half }, ptr [[A]], i32 0, i32 1
// CHECK-NEXT:    [[A_IMAG:%.*]] = load half, ptr [[A_IMAGP]], align 2
// CHECK-NEXT:    [[EXT:%.*]] = fpext half [[A_REAL]] to float
// CHECK-NEXT:    [[EXT1:%.*]] = fpext half [[A_IMAG]] to float
// CHECK-NEXT:    [[TMP0:%.*]] = load half, ptr [[C_ADDR]], align 2
// CHECK-NEXT:    [[EXT2:%.*]] = fpext half [[TMP0]] to float
// CHECK-NEXT:    [[SUB_R:%.*]] = fsub float [[EXT]], [[EXT2]]
// CHECK-NEXT:    [[UNPROMOTION:%.*]] = fptrunc float [[SUB_R]] to half
// CHECK-NEXT:    [[UNPROMOTION3:%.*]] = fptrunc float [[EXT1]] to half
// CHECK-NEXT:    ret half [[UNPROMOTION]]
//
_Float16 PlusOp_c_r(_Float16 _Complex a, _Float16 c) {
  return a - +c;
}

// CHECK-LABEL: @PlusOp_r_c(
// CHECK-NEXT:  entry:
// CHECK-NEXT:    [[C:%.*]] = alloca { half, half }, align 2
// CHECK-NEXT:    [[A_ADDR:%.*]] = alloca half, align 2
// CHECK-NEXT:    store <2 x half> [[C_COERCE:%.*]], ptr [[C]], align 2
// CHECK-NEXT:    store half [[A:%.*]], ptr [[A_ADDR]], align 2
// CHECK-NEXT:    [[TMP0:%.*]] = load half, ptr [[A_ADDR]], align 2
// CHECK-NEXT:    [[EXT:%.*]] = fpext half [[TMP0]] to float
// CHECK-NEXT:    [[C_REALP:%.*]] = getelementptr inbounds nuw { half, half }, ptr [[C]], i32 0, i32 0
// CHECK-NEXT:    [[C_REAL:%.*]] = load half, ptr [[C_REALP]], align 2
// CHECK-NEXT:    [[C_IMAGP:%.*]] = getelementptr inbounds nuw { half, half }, ptr [[C]], i32 0, i32 1
// CHECK-NEXT:    [[C_IMAG:%.*]] = load half, ptr [[C_IMAGP]], align 2
// CHECK-NEXT:    [[EXT1:%.*]] = fpext half [[C_REAL]] to float
// CHECK-NEXT:    [[EXT2:%.*]] = fpext half [[C_IMAG]] to float
// CHECK-NEXT:    [[SUB_R:%.*]] = fsub float [[EXT]], [[EXT1]]
// CHECK-NEXT:    [[SUB_I:%.*]] = fneg float [[EXT2]]
// CHECK-NEXT:    [[UNPROMOTION:%.*]] = fptrunc float [[SUB_R]] to half
// CHECK-NEXT:    [[UNPROMOTION3:%.*]] = fptrunc float [[SUB_I]] to half
// CHECK-NEXT:    ret half [[UNPROMOTION]]
//
_Float16 PlusOp_r_c(_Float16 a, _Float16 _Complex c) {
  return a - +c;
}

// CHECK-LABEL: @PlusOp_c_c(
// CHECK-NEXT:  entry:
// CHECK-NEXT:    [[A:%.*]] = alloca { half, half }, align 2
// CHECK-NEXT:    [[C:%.*]] = alloca { half, half }, align 2
// CHECK-NEXT:    store <2 x half> [[A_COERCE:%.*]], ptr [[A]], align 2
// CHECK-NEXT:    store <2 x half> [[C_COERCE:%.*]], ptr [[C]], align 2
// CHECK-NEXT:    [[A_REALP:%.*]] = getelementptr inbounds nuw { half, half }, ptr [[A]], i32 0, i32 0
// CHECK-NEXT:    [[A_REAL:%.*]] = load half, ptr [[A_REALP]], align 2
// CHECK-NEXT:    [[A_IMAGP:%.*]] = getelementptr inbounds nuw { half, half }, ptr [[A]], i32 0, i32 1
// CHECK-NEXT:    [[A_IMAG:%.*]] = load half, ptr [[A_IMAGP]], align 2
// CHECK-NEXT:    [[EXT:%.*]] = fpext half [[A_REAL]] to float
// CHECK-NEXT:    [[EXT1:%.*]] = fpext half [[A_IMAG]] to float
// CHECK-NEXT:    [[C_REALP:%.*]] = getelementptr inbounds nuw { half, half }, ptr [[C]], i32 0, i32 0
// CHECK-NEXT:    [[C_REAL:%.*]] = load half, ptr [[C_REALP]], align 2
// CHECK-NEXT:    [[C_IMAGP:%.*]] = getelementptr inbounds nuw { half, half }, ptr [[C]], i32 0, i32 1
// CHECK-NEXT:    [[C_IMAG:%.*]] = load half, ptr [[C_IMAGP]], align 2
// CHECK-NEXT:    [[EXT2:%.*]] = fpext half [[C_REAL]] to float
// CHECK-NEXT:    [[EXT3:%.*]] = fpext half [[C_IMAG]] to float
// CHECK-NEXT:    [[SUB_R:%.*]] = fsub float [[EXT]], [[EXT2]]
// CHECK-NEXT:    [[SUB_I:%.*]] = fsub float [[EXT1]], [[EXT3]]
// CHECK-NEXT:    [[UNPROMOTION:%.*]] = fptrunc float [[SUB_R]] to half
// CHECK-NEXT:    [[UNPROMOTION4:%.*]] = fptrunc float [[SUB_I]] to half
// CHECK-NEXT:    ret half [[UNPROMOTION]]
//
_Float16 PlusOp_c_c(_Float16 _Complex a, _Float16 _Complex c) {
  return a - +c;
}