// 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;
}