blob: cf71d6287760ca1a826bd0964a2f22e231a8f0b8 [file] [log] [blame]
// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py
// RUN: %clang_cc1 %s -O0 -emit-llvm -triple x86_64-unknown-unknown -target-feature +avx512fp16 -o - | FileCheck %s --check-prefixes=AVX
// RUN: %clang_cc1 %s -O0 -emit-llvm -triple x86_64-unknown-unknown -o - | FileCheck %s --check-prefixes=X86
// AVX-LABEL: @add_half_rr(
// AVX-NEXT: entry:
// AVX-NEXT: [[RETVAL:%.*]] = alloca { half, half }, align 2
// AVX-NEXT: [[A_ADDR:%.*]] = alloca half, align 2
// AVX-NEXT: [[B_ADDR:%.*]] = alloca half, align 2
// AVX-NEXT: store half [[A:%.*]], ptr [[A_ADDR]], align 2
// AVX-NEXT: store half [[B:%.*]], ptr [[B_ADDR]], align 2
// AVX-NEXT: [[TMP0:%.*]] = load half, ptr [[A_ADDR]], align 2
// AVX-NEXT: [[TMP1:%.*]] = load half, ptr [[B_ADDR]], align 2
// AVX-NEXT: [[ADD:%.*]] = fadd half [[TMP0]], [[TMP1]]
// AVX-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 0
// AVX-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 1
// AVX-NEXT: store half [[ADD]], ptr [[RETVAL_REALP]], align 2
// AVX-NEXT: store half 0xH0000, ptr [[RETVAL_IMAGP]], align 2
// AVX-NEXT: [[TMP2:%.*]] = load <2 x half>, ptr [[RETVAL]], align 2
// AVX-NEXT: ret <2 x half> [[TMP2]]
//
// X86-LABEL: @add_half_rr(
// X86-NEXT: entry:
// X86-NEXT: [[RETVAL:%.*]] = alloca { half, half }, align 2
// X86-NEXT: [[A_ADDR:%.*]] = alloca half, align 2
// X86-NEXT: [[B_ADDR:%.*]] = alloca half, align 2
// X86-NEXT: store half [[A:%.*]], ptr [[A_ADDR]], align 2
// X86-NEXT: store half [[B:%.*]], ptr [[B_ADDR]], align 2
// X86-NEXT: [[TMP0:%.*]] = load half, ptr [[A_ADDR]], align 2
// X86-NEXT: [[EXT:%.*]] = fpext half [[TMP0]] to float
// X86-NEXT: [[TMP1:%.*]] = load half, ptr [[B_ADDR]], align 2
// X86-NEXT: [[EXT1:%.*]] = fpext half [[TMP1]] to float
// X86-NEXT: [[ADD:%.*]] = fadd float [[EXT]], [[EXT1]]
// X86-NEXT: [[UNPROMOTION:%.*]] = fptrunc float [[ADD]] to half
// X86-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 0
// X86-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 1
// X86-NEXT: store half [[UNPROMOTION]], ptr [[RETVAL_REALP]], align 2
// X86-NEXT: store half 0xH0000, ptr [[RETVAL_IMAGP]], align 2
// X86-NEXT: [[TMP2:%.*]] = load <2 x half>, ptr [[RETVAL]], align 2
// X86-NEXT: ret <2 x half> [[TMP2]]
//
_Float16 _Complex add_half_rr(_Float16 a, _Float16 b) {
return a + b;
}
// AVX-LABEL: @add_half_cr(
// AVX-NEXT: entry:
// AVX-NEXT: [[RETVAL:%.*]] = alloca { half, half }, align 2
// AVX-NEXT: [[A:%.*]] = alloca { half, half }, align 2
// AVX-NEXT: [[B_ADDR:%.*]] = alloca half, align 2
// AVX-NEXT: store <2 x half> [[A_COERCE:%.*]], ptr [[A]], align 2
// AVX-NEXT: store half [[B:%.*]], ptr [[B_ADDR]], align 2
// AVX-NEXT: [[A_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[A]], i32 0, i32 0
// AVX-NEXT: [[A_REAL:%.*]] = load half, ptr [[A_REALP]], align 2
// AVX-NEXT: [[A_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[A]], i32 0, i32 1
// AVX-NEXT: [[A_IMAG:%.*]] = load half, ptr [[A_IMAGP]], align 2
// AVX-NEXT: [[TMP0:%.*]] = load half, ptr [[B_ADDR]], align 2
// AVX-NEXT: [[ADD_R:%.*]] = fadd half [[A_REAL]], [[TMP0]]
// AVX-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 0
// AVX-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 1
// AVX-NEXT: store half [[ADD_R]], ptr [[RETVAL_REALP]], align 2
// AVX-NEXT: store half [[A_IMAG]], ptr [[RETVAL_IMAGP]], align 2
// AVX-NEXT: [[TMP1:%.*]] = load <2 x half>, ptr [[RETVAL]], align 2
// AVX-NEXT: ret <2 x half> [[TMP1]]
//
// X86-LABEL: @add_half_cr(
// X86-NEXT: entry:
// X86-NEXT: [[RETVAL:%.*]] = alloca { half, half }, align 2
// X86-NEXT: [[A:%.*]] = alloca { half, half }, align 2
// X86-NEXT: [[B_ADDR:%.*]] = alloca half, align 2
// X86-NEXT: store <2 x half> [[A_COERCE:%.*]], ptr [[A]], align 2
// X86-NEXT: store half [[B:%.*]], ptr [[B_ADDR]], align 2
// X86-NEXT: [[A_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[A]], i32 0, i32 0
// X86-NEXT: [[A_REAL:%.*]] = load half, ptr [[A_REALP]], align 2
// X86-NEXT: [[A_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[A]], i32 0, i32 1
// X86-NEXT: [[A_IMAG:%.*]] = load half, ptr [[A_IMAGP]], align 2
// X86-NEXT: [[EXT:%.*]] = fpext half [[A_REAL]] to float
// X86-NEXT: [[EXT1:%.*]] = fpext half [[A_IMAG]] to float
// X86-NEXT: [[TMP0:%.*]] = load half, ptr [[B_ADDR]], align 2
// X86-NEXT: [[EXT2:%.*]] = fpext half [[TMP0]] to float
// X86-NEXT: [[ADD_R:%.*]] = fadd float [[EXT]], [[EXT2]]
// X86-NEXT: [[UNPROMOTION:%.*]] = fptrunc float [[ADD_R]] to half
// X86-NEXT: [[UNPROMOTION3:%.*]] = fptrunc float [[EXT1]] to half
// X86-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 0
// X86-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 1
// X86-NEXT: store half [[UNPROMOTION]], ptr [[RETVAL_REALP]], align 2
// X86-NEXT: store half [[UNPROMOTION3]], ptr [[RETVAL_IMAGP]], align 2
// X86-NEXT: [[TMP1:%.*]] = load <2 x half>, ptr [[RETVAL]], align 2
// X86-NEXT: ret <2 x half> [[TMP1]]
//
_Float16 _Complex add_half_cr(_Float16 _Complex a, _Float16 b) {
return a + b;
}
// AVX-LABEL: @add_half_rc(
// AVX-NEXT: entry:
// AVX-NEXT: [[RETVAL:%.*]] = alloca { half, half }, align 2
// AVX-NEXT: [[B:%.*]] = alloca { half, half }, align 2
// AVX-NEXT: [[A_ADDR:%.*]] = alloca half, align 2
// AVX-NEXT: store <2 x half> [[B_COERCE:%.*]], ptr [[B]], align 2
// AVX-NEXT: store half [[A:%.*]], ptr [[A_ADDR]], align 2
// AVX-NEXT: [[TMP0:%.*]] = load half, ptr [[A_ADDR]], align 2
// AVX-NEXT: [[B_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[B]], i32 0, i32 0
// AVX-NEXT: [[B_REAL:%.*]] = load half, ptr [[B_REALP]], align 2
// AVX-NEXT: [[B_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[B]], i32 0, i32 1
// AVX-NEXT: [[B_IMAG:%.*]] = load half, ptr [[B_IMAGP]], align 2
// AVX-NEXT: [[ADD_R:%.*]] = fadd half [[TMP0]], [[B_REAL]]
// AVX-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 0
// AVX-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 1
// AVX-NEXT: store half [[ADD_R]], ptr [[RETVAL_REALP]], align 2
// AVX-NEXT: store half [[B_IMAG]], ptr [[RETVAL_IMAGP]], align 2
// AVX-NEXT: [[TMP1:%.*]] = load <2 x half>, ptr [[RETVAL]], align 2
// AVX-NEXT: ret <2 x half> [[TMP1]]
//
// X86-LABEL: @add_half_rc(
// X86-NEXT: entry:
// X86-NEXT: [[RETVAL:%.*]] = alloca { half, half }, align 2
// X86-NEXT: [[B:%.*]] = alloca { half, half }, align 2
// X86-NEXT: [[A_ADDR:%.*]] = alloca half, align 2
// X86-NEXT: store <2 x half> [[B_COERCE:%.*]], ptr [[B]], align 2
// X86-NEXT: store half [[A:%.*]], ptr [[A_ADDR]], align 2
// X86-NEXT: [[TMP0:%.*]] = load half, ptr [[A_ADDR]], align 2
// X86-NEXT: [[EXT:%.*]] = fpext half [[TMP0]] to float
// X86-NEXT: [[B_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[B]], i32 0, i32 0
// X86-NEXT: [[B_REAL:%.*]] = load half, ptr [[B_REALP]], align 2
// X86-NEXT: [[B_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[B]], i32 0, i32 1
// X86-NEXT: [[B_IMAG:%.*]] = load half, ptr [[B_IMAGP]], align 2
// X86-NEXT: [[EXT1:%.*]] = fpext half [[B_REAL]] to float
// X86-NEXT: [[EXT2:%.*]] = fpext half [[B_IMAG]] to float
// X86-NEXT: [[ADD_R:%.*]] = fadd float [[EXT]], [[EXT1]]
// X86-NEXT: [[UNPROMOTION:%.*]] = fptrunc float [[ADD_R]] to half
// X86-NEXT: [[UNPROMOTION3:%.*]] = fptrunc float [[EXT2]] to half
// X86-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 0
// X86-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 1
// X86-NEXT: store half [[UNPROMOTION]], ptr [[RETVAL_REALP]], align 2
// X86-NEXT: store half [[UNPROMOTION3]], ptr [[RETVAL_IMAGP]], align 2
// X86-NEXT: [[TMP1:%.*]] = load <2 x half>, ptr [[RETVAL]], align 2
// X86-NEXT: ret <2 x half> [[TMP1]]
//
_Float16 _Complex add_half_rc(_Float16 a, _Float16 _Complex b) {
return a + b;
}
// AVX-LABEL: @add_half_cc(
// AVX-NEXT: entry:
// AVX-NEXT: [[RETVAL:%.*]] = alloca { half, half }, align 2
// AVX-NEXT: [[A:%.*]] = alloca { half, half }, align 2
// AVX-NEXT: [[B:%.*]] = alloca { half, half }, align 2
// AVX-NEXT: store <2 x half> [[A_COERCE:%.*]], ptr [[A]], align 2
// AVX-NEXT: store <2 x half> [[B_COERCE:%.*]], ptr [[B]], align 2
// AVX-NEXT: [[A_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[A]], i32 0, i32 0
// AVX-NEXT: [[A_REAL:%.*]] = load half, ptr [[A_REALP]], align 2
// AVX-NEXT: [[A_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[A]], i32 0, i32 1
// AVX-NEXT: [[A_IMAG:%.*]] = load half, ptr [[A_IMAGP]], align 2
// AVX-NEXT: [[B_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[B]], i32 0, i32 0
// AVX-NEXT: [[B_REAL:%.*]] = load half, ptr [[B_REALP]], align 2
// AVX-NEXT: [[B_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[B]], i32 0, i32 1
// AVX-NEXT: [[B_IMAG:%.*]] = load half, ptr [[B_IMAGP]], align 2
// AVX-NEXT: [[ADD_R:%.*]] = fadd half [[A_REAL]], [[B_REAL]]
// AVX-NEXT: [[ADD_I:%.*]] = fadd half [[A_IMAG]], [[B_IMAG]]
// AVX-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 0
// AVX-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 1
// AVX-NEXT: store half [[ADD_R]], ptr [[RETVAL_REALP]], align 2
// AVX-NEXT: store half [[ADD_I]], ptr [[RETVAL_IMAGP]], align 2
// AVX-NEXT: [[TMP0:%.*]] = load <2 x half>, ptr [[RETVAL]], align 2
// AVX-NEXT: ret <2 x half> [[TMP0]]
//
// X86-LABEL: @add_half_cc(
// X86-NEXT: entry:
// X86-NEXT: [[RETVAL:%.*]] = alloca { half, half }, align 2
// X86-NEXT: [[A:%.*]] = alloca { half, half }, align 2
// X86-NEXT: [[B:%.*]] = alloca { half, half }, align 2
// X86-NEXT: store <2 x half> [[A_COERCE:%.*]], ptr [[A]], align 2
// X86-NEXT: store <2 x half> [[B_COERCE:%.*]], ptr [[B]], align 2
// X86-NEXT: [[A_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[A]], i32 0, i32 0
// X86-NEXT: [[A_REAL:%.*]] = load half, ptr [[A_REALP]], align 2
// X86-NEXT: [[A_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[A]], i32 0, i32 1
// X86-NEXT: [[A_IMAG:%.*]] = load half, ptr [[A_IMAGP]], align 2
// X86-NEXT: [[EXT:%.*]] = fpext half [[A_REAL]] to float
// X86-NEXT: [[EXT1:%.*]] = fpext half [[A_IMAG]] to float
// X86-NEXT: [[B_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[B]], i32 0, i32 0
// X86-NEXT: [[B_REAL:%.*]] = load half, ptr [[B_REALP]], align 2
// X86-NEXT: [[B_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[B]], i32 0, i32 1
// X86-NEXT: [[B_IMAG:%.*]] = load half, ptr [[B_IMAGP]], align 2
// X86-NEXT: [[EXT2:%.*]] = fpext half [[B_REAL]] to float
// X86-NEXT: [[EXT3:%.*]] = fpext half [[B_IMAG]] to float
// X86-NEXT: [[ADD_R:%.*]] = fadd float [[EXT]], [[EXT2]]
// X86-NEXT: [[ADD_I:%.*]] = fadd float [[EXT1]], [[EXT3]]
// X86-NEXT: [[UNPROMOTION:%.*]] = fptrunc float [[ADD_R]] to half
// X86-NEXT: [[UNPROMOTION4:%.*]] = fptrunc float [[ADD_I]] to half
// X86-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 0
// X86-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 1
// X86-NEXT: store half [[UNPROMOTION]], ptr [[RETVAL_REALP]], align 2
// X86-NEXT: store half [[UNPROMOTION4]], ptr [[RETVAL_IMAGP]], align 2
// X86-NEXT: [[TMP0:%.*]] = load <2 x half>, ptr [[RETVAL]], align 2
// X86-NEXT: ret <2 x half> [[TMP0]]
//
_Float16 _Complex add_half_cc(_Float16 _Complex a, _Float16 _Complex b) {
return a + b;
}
// AVX-LABEL: @add2_haff_rrr(
// AVX-NEXT: entry:
// AVX-NEXT: [[RETVAL:%.*]] = alloca { half, half }, align 2
// AVX-NEXT: [[A_ADDR:%.*]] = alloca half, align 2
// AVX-NEXT: [[B_ADDR:%.*]] = alloca half, align 2
// AVX-NEXT: [[C_ADDR:%.*]] = alloca half, align 2
// AVX-NEXT: store half [[A:%.*]], ptr [[A_ADDR]], align 2
// AVX-NEXT: store half [[B:%.*]], ptr [[B_ADDR]], align 2
// AVX-NEXT: store half [[C:%.*]], ptr [[C_ADDR]], align 2
// AVX-NEXT: [[TMP0:%.*]] = load half, ptr [[A_ADDR]], align 2
// AVX-NEXT: [[TMP1:%.*]] = load half, ptr [[B_ADDR]], align 2
// AVX-NEXT: [[ADD:%.*]] = fadd half [[TMP0]], [[TMP1]]
// AVX-NEXT: [[TMP2:%.*]] = load half, ptr [[C_ADDR]], align 2
// AVX-NEXT: [[ADD1:%.*]] = fadd half [[ADD]], [[TMP2]]
// AVX-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 0
// AVX-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 1
// AVX-NEXT: store half [[ADD1]], ptr [[RETVAL_REALP]], align 2
// AVX-NEXT: store half 0xH0000, ptr [[RETVAL_IMAGP]], align 2
// AVX-NEXT: [[TMP3:%.*]] = load <2 x half>, ptr [[RETVAL]], align 2
// AVX-NEXT: ret <2 x half> [[TMP3]]
//
// X86-LABEL: @add2_haff_rrr(
// X86-NEXT: entry:
// X86-NEXT: [[RETVAL:%.*]] = alloca { half, half }, align 2
// X86-NEXT: [[A_ADDR:%.*]] = alloca half, align 2
// X86-NEXT: [[B_ADDR:%.*]] = alloca half, align 2
// X86-NEXT: [[C_ADDR:%.*]] = alloca half, align 2
// X86-NEXT: store half [[A:%.*]], ptr [[A_ADDR]], align 2
// X86-NEXT: store half [[B:%.*]], ptr [[B_ADDR]], align 2
// X86-NEXT: store half [[C:%.*]], ptr [[C_ADDR]], align 2
// X86-NEXT: [[TMP0:%.*]] = load half, ptr [[A_ADDR]], align 2
// X86-NEXT: [[EXT:%.*]] = fpext half [[TMP0]] to float
// X86-NEXT: [[TMP1:%.*]] = load half, ptr [[B_ADDR]], align 2
// X86-NEXT: [[EXT1:%.*]] = fpext half [[TMP1]] to float
// X86-NEXT: [[ADD:%.*]] = fadd float [[EXT]], [[EXT1]]
// X86-NEXT: [[TMP2:%.*]] = load half, ptr [[C_ADDR]], align 2
// X86-NEXT: [[EXT2:%.*]] = fpext half [[TMP2]] to float
// X86-NEXT: [[ADD3:%.*]] = fadd float [[ADD]], [[EXT2]]
// X86-NEXT: [[UNPROMOTION:%.*]] = fptrunc float [[ADD3]] to half
// X86-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 0
// X86-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 1
// X86-NEXT: store half [[UNPROMOTION]], ptr [[RETVAL_REALP]], align 2
// X86-NEXT: store half 0xH0000, ptr [[RETVAL_IMAGP]], align 2
// X86-NEXT: [[TMP3:%.*]] = load <2 x half>, ptr [[RETVAL]], align 2
// X86-NEXT: ret <2 x half> [[TMP3]]
//
_Float16 _Complex add2_haff_rrr(_Float16 a, _Float16 b, _Float16 c) {
return a + b + c;
}
// AVX-LABEL: @add2_haff_rcr(
// AVX-NEXT: entry:
// AVX-NEXT: [[RETVAL:%.*]] = alloca { half, half }, align 2
// AVX-NEXT: [[B:%.*]] = alloca { half, half }, align 2
// AVX-NEXT: [[A_ADDR:%.*]] = alloca half, align 2
// AVX-NEXT: [[C_ADDR:%.*]] = alloca half, align 2
// AVX-NEXT: store <2 x half> [[B_COERCE:%.*]], ptr [[B]], align 2
// AVX-NEXT: store half [[A:%.*]], ptr [[A_ADDR]], align 2
// AVX-NEXT: store half [[C:%.*]], ptr [[C_ADDR]], align 2
// AVX-NEXT: [[TMP0:%.*]] = load half, ptr [[A_ADDR]], align 2
// AVX-NEXT: [[B_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[B]], i32 0, i32 0
// AVX-NEXT: [[B_REAL:%.*]] = load half, ptr [[B_REALP]], align 2
// AVX-NEXT: [[B_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[B]], i32 0, i32 1
// AVX-NEXT: [[B_IMAG:%.*]] = load half, ptr [[B_IMAGP]], align 2
// AVX-NEXT: [[ADD_R:%.*]] = fadd half [[TMP0]], [[B_REAL]]
// AVX-NEXT: [[TMP1:%.*]] = load half, ptr [[C_ADDR]], align 2
// AVX-NEXT: [[ADD_R1:%.*]] = fadd half [[ADD_R]], [[TMP1]]
// AVX-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 0
// AVX-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 1
// AVX-NEXT: store half [[ADD_R1]], ptr [[RETVAL_REALP]], align 2
// AVX-NEXT: store half [[B_IMAG]], ptr [[RETVAL_IMAGP]], align 2
// AVX-NEXT: [[TMP2:%.*]] = load <2 x half>, ptr [[RETVAL]], align 2
// AVX-NEXT: ret <2 x half> [[TMP2]]
//
// X86-LABEL: @add2_haff_rcr(
// X86-NEXT: entry:
// X86-NEXT: [[RETVAL:%.*]] = alloca { half, half }, align 2
// X86-NEXT: [[B:%.*]] = alloca { half, half }, align 2
// X86-NEXT: [[A_ADDR:%.*]] = alloca half, align 2
// X86-NEXT: [[C_ADDR:%.*]] = alloca half, align 2
// X86-NEXT: store <2 x half> [[B_COERCE:%.*]], ptr [[B]], align 2
// X86-NEXT: store half [[A:%.*]], ptr [[A_ADDR]], align 2
// X86-NEXT: store half [[C:%.*]], ptr [[C_ADDR]], align 2
// X86-NEXT: [[TMP0:%.*]] = load half, ptr [[A_ADDR]], align 2
// X86-NEXT: [[EXT:%.*]] = fpext half [[TMP0]] to float
// X86-NEXT: [[B_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[B]], i32 0, i32 0
// X86-NEXT: [[B_REAL:%.*]] = load half, ptr [[B_REALP]], align 2
// X86-NEXT: [[B_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[B]], i32 0, i32 1
// X86-NEXT: [[B_IMAG:%.*]] = load half, ptr [[B_IMAGP]], align 2
// X86-NEXT: [[EXT1:%.*]] = fpext half [[B_REAL]] to float
// X86-NEXT: [[EXT2:%.*]] = fpext half [[B_IMAG]] to float
// X86-NEXT: [[ADD_R:%.*]] = fadd float [[EXT]], [[EXT1]]
// X86-NEXT: [[TMP1:%.*]] = load half, ptr [[C_ADDR]], align 2
// X86-NEXT: [[EXT3:%.*]] = fpext half [[TMP1]] to float
// X86-NEXT: [[ADD_R4:%.*]] = fadd float [[ADD_R]], [[EXT3]]
// X86-NEXT: [[UNPROMOTION:%.*]] = fptrunc float [[ADD_R4]] to half
// X86-NEXT: [[UNPROMOTION5:%.*]] = fptrunc float [[EXT2]] to half
// X86-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 0
// X86-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 1
// X86-NEXT: store half [[UNPROMOTION]], ptr [[RETVAL_REALP]], align 2
// X86-NEXT: store half [[UNPROMOTION5]], ptr [[RETVAL_IMAGP]], align 2
// X86-NEXT: [[TMP2:%.*]] = load <2 x half>, ptr [[RETVAL]], align 2
// X86-NEXT: ret <2 x half> [[TMP2]]
//
_Float16 _Complex add2_haff_rcr(_Float16 a, _Float16 _Complex b, _Float16 c) {
return a + b + c;
}
// AVX-LABEL: @add2_haff_rcc(
// AVX-NEXT: entry:
// AVX-NEXT: [[RETVAL:%.*]] = alloca { half, half }, align 2
// AVX-NEXT: [[B:%.*]] = alloca { half, half }, align 2
// AVX-NEXT: [[C:%.*]] = alloca { half, half }, align 2
// AVX-NEXT: [[A_ADDR:%.*]] = alloca half, align 2
// AVX-NEXT: store <2 x half> [[B_COERCE:%.*]], ptr [[B]], align 2
// AVX-NEXT: store <2 x half> [[C_COERCE:%.*]], ptr [[C]], align 2
// AVX-NEXT: store half [[A:%.*]], ptr [[A_ADDR]], align 2
// AVX-NEXT: [[TMP0:%.*]] = load half, ptr [[A_ADDR]], align 2
// AVX-NEXT: [[B_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[B]], i32 0, i32 0
// AVX-NEXT: [[B_REAL:%.*]] = load half, ptr [[B_REALP]], align 2
// AVX-NEXT: [[B_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[B]], i32 0, i32 1
// AVX-NEXT: [[B_IMAG:%.*]] = load half, ptr [[B_IMAGP]], align 2
// AVX-NEXT: [[ADD_R:%.*]] = fadd half [[TMP0]], [[B_REAL]]
// AVX-NEXT: [[C_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[C]], i32 0, i32 0
// AVX-NEXT: [[C_REAL:%.*]] = load half, ptr [[C_REALP]], align 2
// AVX-NEXT: [[C_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[C]], i32 0, i32 1
// AVX-NEXT: [[C_IMAG:%.*]] = load half, ptr [[C_IMAGP]], align 2
// AVX-NEXT: [[ADD_R1:%.*]] = fadd half [[ADD_R]], [[C_REAL]]
// AVX-NEXT: [[ADD_I:%.*]] = fadd half [[B_IMAG]], [[C_IMAG]]
// AVX-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 0
// AVX-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 1
// AVX-NEXT: store half [[ADD_R1]], ptr [[RETVAL_REALP]], align 2
// AVX-NEXT: store half [[ADD_I]], ptr [[RETVAL_IMAGP]], align 2
// AVX-NEXT: [[TMP1:%.*]] = load <2 x half>, ptr [[RETVAL]], align 2
// AVX-NEXT: ret <2 x half> [[TMP1]]
//
// X86-LABEL: @add2_haff_rcc(
// X86-NEXT: entry:
// X86-NEXT: [[RETVAL:%.*]] = alloca { half, half }, align 2
// X86-NEXT: [[B:%.*]] = alloca { half, half }, align 2
// X86-NEXT: [[C:%.*]] = alloca { half, half }, align 2
// X86-NEXT: [[A_ADDR:%.*]] = alloca half, align 2
// X86-NEXT: store <2 x half> [[B_COERCE:%.*]], ptr [[B]], align 2
// X86-NEXT: store <2 x half> [[C_COERCE:%.*]], ptr [[C]], align 2
// X86-NEXT: store half [[A:%.*]], ptr [[A_ADDR]], align 2
// X86-NEXT: [[TMP0:%.*]] = load half, ptr [[A_ADDR]], align 2
// X86-NEXT: [[EXT:%.*]] = fpext half [[TMP0]] to float
// X86-NEXT: [[B_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[B]], i32 0, i32 0
// X86-NEXT: [[B_REAL:%.*]] = load half, ptr [[B_REALP]], align 2
// X86-NEXT: [[B_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[B]], i32 0, i32 1
// X86-NEXT: [[B_IMAG:%.*]] = load half, ptr [[B_IMAGP]], align 2
// X86-NEXT: [[EXT1:%.*]] = fpext half [[B_REAL]] to float
// X86-NEXT: [[EXT2:%.*]] = fpext half [[B_IMAG]] to float
// X86-NEXT: [[ADD_R:%.*]] = fadd float [[EXT]], [[EXT1]]
// X86-NEXT: [[C_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[C]], i32 0, i32 0
// X86-NEXT: [[C_REAL:%.*]] = load half, ptr [[C_REALP]], align 2
// X86-NEXT: [[C_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[C]], i32 0, i32 1
// X86-NEXT: [[C_IMAG:%.*]] = load half, ptr [[C_IMAGP]], align 2
// X86-NEXT: [[EXT3:%.*]] = fpext half [[C_REAL]] to float
// X86-NEXT: [[EXT4:%.*]] = fpext half [[C_IMAG]] to float
// X86-NEXT: [[ADD_R5:%.*]] = fadd float [[ADD_R]], [[EXT3]]
// X86-NEXT: [[ADD_I:%.*]] = fadd float [[EXT2]], [[EXT4]]
// X86-NEXT: [[UNPROMOTION:%.*]] = fptrunc float [[ADD_R5]] to half
// X86-NEXT: [[UNPROMOTION6:%.*]] = fptrunc float [[ADD_I]] to half
// X86-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 0
// X86-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 1
// X86-NEXT: store half [[UNPROMOTION]], ptr [[RETVAL_REALP]], align 2
// X86-NEXT: store half [[UNPROMOTION6]], ptr [[RETVAL_IMAGP]], align 2
// X86-NEXT: [[TMP1:%.*]] = load <2 x half>, ptr [[RETVAL]], align 2
// X86-NEXT: ret <2 x half> [[TMP1]]
//
_Float16 _Complex add2_haff_rcc(_Float16 a, _Float16 _Complex b, _Float16 _Complex c) {
return a + b + c;
}
// AVX-LABEL: @add2_haff_crr(
// AVX-NEXT: entry:
// AVX-NEXT: [[RETVAL:%.*]] = alloca { half, half }, align 2
// AVX-NEXT: [[A:%.*]] = alloca { half, half }, align 2
// AVX-NEXT: [[B_ADDR:%.*]] = alloca half, align 2
// AVX-NEXT: [[C_ADDR:%.*]] = alloca half, align 2
// AVX-NEXT: store <2 x half> [[A_COERCE:%.*]], ptr [[A]], align 2
// AVX-NEXT: store half [[B:%.*]], ptr [[B_ADDR]], align 2
// AVX-NEXT: store half [[C:%.*]], ptr [[C_ADDR]], align 2
// AVX-NEXT: [[A_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[A]], i32 0, i32 0
// AVX-NEXT: [[A_REAL:%.*]] = load half, ptr [[A_REALP]], align 2
// AVX-NEXT: [[A_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[A]], i32 0, i32 1
// AVX-NEXT: [[A_IMAG:%.*]] = load half, ptr [[A_IMAGP]], align 2
// AVX-NEXT: [[TMP0:%.*]] = load half, ptr [[B_ADDR]], align 2
// AVX-NEXT: [[ADD_R:%.*]] = fadd half [[A_REAL]], [[TMP0]]
// AVX-NEXT: [[TMP1:%.*]] = load half, ptr [[C_ADDR]], align 2
// AVX-NEXT: [[ADD_R1:%.*]] = fadd half [[ADD_R]], [[TMP1]]
// AVX-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 0
// AVX-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 1
// AVX-NEXT: store half [[ADD_R1]], ptr [[RETVAL_REALP]], align 2
// AVX-NEXT: store half [[A_IMAG]], ptr [[RETVAL_IMAGP]], align 2
// AVX-NEXT: [[TMP2:%.*]] = load <2 x half>, ptr [[RETVAL]], align 2
// AVX-NEXT: ret <2 x half> [[TMP2]]
//
// X86-LABEL: @add2_haff_crr(
// X86-NEXT: entry:
// X86-NEXT: [[RETVAL:%.*]] = alloca { half, half }, align 2
// X86-NEXT: [[A:%.*]] = alloca { half, half }, align 2
// X86-NEXT: [[B_ADDR:%.*]] = alloca half, align 2
// X86-NEXT: [[C_ADDR:%.*]] = alloca half, align 2
// X86-NEXT: store <2 x half> [[A_COERCE:%.*]], ptr [[A]], align 2
// X86-NEXT: store half [[B:%.*]], ptr [[B_ADDR]], align 2
// X86-NEXT: store half [[C:%.*]], ptr [[C_ADDR]], align 2
// X86-NEXT: [[A_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[A]], i32 0, i32 0
// X86-NEXT: [[A_REAL:%.*]] = load half, ptr [[A_REALP]], align 2
// X86-NEXT: [[A_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[A]], i32 0, i32 1
// X86-NEXT: [[A_IMAG:%.*]] = load half, ptr [[A_IMAGP]], align 2
// X86-NEXT: [[EXT:%.*]] = fpext half [[A_REAL]] to float
// X86-NEXT: [[EXT1:%.*]] = fpext half [[A_IMAG]] to float
// X86-NEXT: [[TMP0:%.*]] = load half, ptr [[B_ADDR]], align 2
// X86-NEXT: [[EXT2:%.*]] = fpext half [[TMP0]] to float
// X86-NEXT: [[ADD_R:%.*]] = fadd float [[EXT]], [[EXT2]]
// X86-NEXT: [[TMP1:%.*]] = load half, ptr [[C_ADDR]], align 2
// X86-NEXT: [[EXT3:%.*]] = fpext half [[TMP1]] to float
// X86-NEXT: [[ADD_R4:%.*]] = fadd float [[ADD_R]], [[EXT3]]
// X86-NEXT: [[UNPROMOTION:%.*]] = fptrunc float [[ADD_R4]] to half
// X86-NEXT: [[UNPROMOTION5:%.*]] = fptrunc float [[EXT1]] to half
// X86-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 0
// X86-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 1
// X86-NEXT: store half [[UNPROMOTION]], ptr [[RETVAL_REALP]], align 2
// X86-NEXT: store half [[UNPROMOTION5]], ptr [[RETVAL_IMAGP]], align 2
// X86-NEXT: [[TMP2:%.*]] = load <2 x half>, ptr [[RETVAL]], align 2
// X86-NEXT: ret <2 x half> [[TMP2]]
//
_Float16 _Complex add2_haff_crr(_Float16 _Complex a, _Float16 b, _Float16 c) {
return a + b + c;
}
// AVX-LABEL: @add2_haff_ccr(
// AVX-NEXT: entry:
// AVX-NEXT: [[RETVAL:%.*]] = alloca { half, half }, align 2
// AVX-NEXT: [[A:%.*]] = alloca { half, half }, align 2
// AVX-NEXT: [[B:%.*]] = alloca { half, half }, align 2
// AVX-NEXT: [[C_ADDR:%.*]] = alloca half, align 2
// AVX-NEXT: store <2 x half> [[A_COERCE:%.*]], ptr [[A]], align 2
// AVX-NEXT: store <2 x half> [[B_COERCE:%.*]], ptr [[B]], align 2
// AVX-NEXT: store half [[C:%.*]], ptr [[C_ADDR]], align 2
// AVX-NEXT: [[A_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[A]], i32 0, i32 0
// AVX-NEXT: [[A_REAL:%.*]] = load half, ptr [[A_REALP]], align 2
// AVX-NEXT: [[A_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[A]], i32 0, i32 1
// AVX-NEXT: [[A_IMAG:%.*]] = load half, ptr [[A_IMAGP]], align 2
// AVX-NEXT: [[B_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[B]], i32 0, i32 0
// AVX-NEXT: [[B_REAL:%.*]] = load half, ptr [[B_REALP]], align 2
// AVX-NEXT: [[B_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[B]], i32 0, i32 1
// AVX-NEXT: [[B_IMAG:%.*]] = load half, ptr [[B_IMAGP]], align 2
// AVX-NEXT: [[ADD_R:%.*]] = fadd half [[A_REAL]], [[B_REAL]]
// AVX-NEXT: [[ADD_I:%.*]] = fadd half [[A_IMAG]], [[B_IMAG]]
// AVX-NEXT: [[TMP0:%.*]] = load half, ptr [[C_ADDR]], align 2
// AVX-NEXT: [[ADD_R1:%.*]] = fadd half [[ADD_R]], [[TMP0]]
// AVX-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 0
// AVX-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 1
// AVX-NEXT: store half [[ADD_R1]], ptr [[RETVAL_REALP]], align 2
// AVX-NEXT: store half [[ADD_I]], ptr [[RETVAL_IMAGP]], align 2
// AVX-NEXT: [[TMP1:%.*]] = load <2 x half>, ptr [[RETVAL]], align 2
// AVX-NEXT: ret <2 x half> [[TMP1]]
//
// X86-LABEL: @add2_haff_ccr(
// X86-NEXT: entry:
// X86-NEXT: [[RETVAL:%.*]] = alloca { half, half }, align 2
// X86-NEXT: [[A:%.*]] = alloca { half, half }, align 2
// X86-NEXT: [[B:%.*]] = alloca { half, half }, align 2
// X86-NEXT: [[C_ADDR:%.*]] = alloca half, align 2
// X86-NEXT: store <2 x half> [[A_COERCE:%.*]], ptr [[A]], align 2
// X86-NEXT: store <2 x half> [[B_COERCE:%.*]], ptr [[B]], align 2
// X86-NEXT: store half [[C:%.*]], ptr [[C_ADDR]], align 2
// X86-NEXT: [[A_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[A]], i32 0, i32 0
// X86-NEXT: [[A_REAL:%.*]] = load half, ptr [[A_REALP]], align 2
// X86-NEXT: [[A_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[A]], i32 0, i32 1
// X86-NEXT: [[A_IMAG:%.*]] = load half, ptr [[A_IMAGP]], align 2
// X86-NEXT: [[EXT:%.*]] = fpext half [[A_REAL]] to float
// X86-NEXT: [[EXT1:%.*]] = fpext half [[A_IMAG]] to float
// X86-NEXT: [[B_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[B]], i32 0, i32 0
// X86-NEXT: [[B_REAL:%.*]] = load half, ptr [[B_REALP]], align 2
// X86-NEXT: [[B_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[B]], i32 0, i32 1
// X86-NEXT: [[B_IMAG:%.*]] = load half, ptr [[B_IMAGP]], align 2
// X86-NEXT: [[EXT2:%.*]] = fpext half [[B_REAL]] to float
// X86-NEXT: [[EXT3:%.*]] = fpext half [[B_IMAG]] to float
// X86-NEXT: [[ADD_R:%.*]] = fadd float [[EXT]], [[EXT2]]
// X86-NEXT: [[ADD_I:%.*]] = fadd float [[EXT1]], [[EXT3]]
// X86-NEXT: [[TMP0:%.*]] = load half, ptr [[C_ADDR]], align 2
// X86-NEXT: [[EXT4:%.*]] = fpext half [[TMP0]] to float
// X86-NEXT: [[ADD_R5:%.*]] = fadd float [[ADD_R]], [[EXT4]]
// X86-NEXT: [[UNPROMOTION:%.*]] = fptrunc float [[ADD_R5]] to half
// X86-NEXT: [[UNPROMOTION6:%.*]] = fptrunc float [[ADD_I]] to half
// X86-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 0
// X86-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 1
// X86-NEXT: store half [[UNPROMOTION]], ptr [[RETVAL_REALP]], align 2
// X86-NEXT: store half [[UNPROMOTION6]], ptr [[RETVAL_IMAGP]], align 2
// X86-NEXT: [[TMP1:%.*]] = load <2 x half>, ptr [[RETVAL]], align 2
// X86-NEXT: ret <2 x half> [[TMP1]]
//
_Float16 _Complex add2_haff_ccr(_Float16 _Complex a, _Float16 _Complex b, _Float16 c) {
return a + b + c;
}
// AVX-LABEL: @add2_haff_crc(
// AVX-NEXT: entry:
// AVX-NEXT: [[RETVAL:%.*]] = alloca { half, half }, align 2
// AVX-NEXT: [[A:%.*]] = alloca { half, half }, align 2
// AVX-NEXT: [[C:%.*]] = alloca { half, half }, align 2
// AVX-NEXT: [[B_ADDR:%.*]] = alloca half, align 2
// AVX-NEXT: store <2 x half> [[A_COERCE:%.*]], ptr [[A]], align 2
// AVX-NEXT: store <2 x half> [[C_COERCE:%.*]], ptr [[C]], align 2
// AVX-NEXT: store half [[B:%.*]], ptr [[B_ADDR]], align 2
// AVX-NEXT: [[A_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[A]], i32 0, i32 0
// AVX-NEXT: [[A_REAL:%.*]] = load half, ptr [[A_REALP]], align 2
// AVX-NEXT: [[A_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[A]], i32 0, i32 1
// AVX-NEXT: [[A_IMAG:%.*]] = load half, ptr [[A_IMAGP]], align 2
// AVX-NEXT: [[TMP0:%.*]] = load half, ptr [[B_ADDR]], align 2
// AVX-NEXT: [[ADD_R:%.*]] = fadd half [[A_REAL]], [[TMP0]]
// AVX-NEXT: [[C_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[C]], i32 0, i32 0
// AVX-NEXT: [[C_REAL:%.*]] = load half, ptr [[C_REALP]], align 2
// AVX-NEXT: [[C_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[C]], i32 0, i32 1
// AVX-NEXT: [[C_IMAG:%.*]] = load half, ptr [[C_IMAGP]], align 2
// AVX-NEXT: [[ADD_R1:%.*]] = fadd half [[ADD_R]], [[C_REAL]]
// AVX-NEXT: [[ADD_I:%.*]] = fadd half [[A_IMAG]], [[C_IMAG]]
// AVX-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 0
// AVX-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 1
// AVX-NEXT: store half [[ADD_R1]], ptr [[RETVAL_REALP]], align 2
// AVX-NEXT: store half [[ADD_I]], ptr [[RETVAL_IMAGP]], align 2
// AVX-NEXT: [[TMP1:%.*]] = load <2 x half>, ptr [[RETVAL]], align 2
// AVX-NEXT: ret <2 x half> [[TMP1]]
//
// X86-LABEL: @add2_haff_crc(
// X86-NEXT: entry:
// X86-NEXT: [[RETVAL:%.*]] = alloca { half, half }, align 2
// X86-NEXT: [[A:%.*]] = alloca { half, half }, align 2
// X86-NEXT: [[C:%.*]] = alloca { half, half }, align 2
// X86-NEXT: [[B_ADDR:%.*]] = alloca half, align 2
// X86-NEXT: store <2 x half> [[A_COERCE:%.*]], ptr [[A]], align 2
// X86-NEXT: store <2 x half> [[C_COERCE:%.*]], ptr [[C]], align 2
// X86-NEXT: store half [[B:%.*]], ptr [[B_ADDR]], align 2
// X86-NEXT: [[A_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[A]], i32 0, i32 0
// X86-NEXT: [[A_REAL:%.*]] = load half, ptr [[A_REALP]], align 2
// X86-NEXT: [[A_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[A]], i32 0, i32 1
// X86-NEXT: [[A_IMAG:%.*]] = load half, ptr [[A_IMAGP]], align 2
// X86-NEXT: [[EXT:%.*]] = fpext half [[A_REAL]] to float
// X86-NEXT: [[EXT1:%.*]] = fpext half [[A_IMAG]] to float
// X86-NEXT: [[TMP0:%.*]] = load half, ptr [[B_ADDR]], align 2
// X86-NEXT: [[EXT2:%.*]] = fpext half [[TMP0]] to float
// X86-NEXT: [[ADD_R:%.*]] = fadd float [[EXT]], [[EXT2]]
// X86-NEXT: [[C_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[C]], i32 0, i32 0
// X86-NEXT: [[C_REAL:%.*]] = load half, ptr [[C_REALP]], align 2
// X86-NEXT: [[C_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[C]], i32 0, i32 1
// X86-NEXT: [[C_IMAG:%.*]] = load half, ptr [[C_IMAGP]], align 2
// X86-NEXT: [[EXT3:%.*]] = fpext half [[C_REAL]] to float
// X86-NEXT: [[EXT4:%.*]] = fpext half [[C_IMAG]] to float
// X86-NEXT: [[ADD_R5:%.*]] = fadd float [[ADD_R]], [[EXT3]]
// X86-NEXT: [[ADD_I:%.*]] = fadd float [[EXT1]], [[EXT4]]
// X86-NEXT: [[UNPROMOTION:%.*]] = fptrunc float [[ADD_R5]] to half
// X86-NEXT: [[UNPROMOTION6:%.*]] = fptrunc float [[ADD_I]] to half
// X86-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 0
// X86-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 1
// X86-NEXT: store half [[UNPROMOTION]], ptr [[RETVAL_REALP]], align 2
// X86-NEXT: store half [[UNPROMOTION6]], ptr [[RETVAL_IMAGP]], align 2
// X86-NEXT: [[TMP1:%.*]] = load <2 x half>, ptr [[RETVAL]], align 2
// X86-NEXT: ret <2 x half> [[TMP1]]
//
_Float16 _Complex add2_haff_crc(_Float16 _Complex a, _Float16 b, _Float16 _Complex c) {
return a + b + c;
}
// AVX-LABEL: @add2_haff_ccc(
// AVX-NEXT: entry:
// AVX-NEXT: [[RETVAL:%.*]] = alloca { half, half }, align 2
// AVX-NEXT: [[A:%.*]] = alloca { half, half }, align 2
// AVX-NEXT: [[B:%.*]] = alloca { half, half }, align 2
// AVX-NEXT: [[C:%.*]] = alloca { half, half }, align 2
// AVX-NEXT: store <2 x half> [[A_COERCE:%.*]], ptr [[A]], align 2
// AVX-NEXT: store <2 x half> [[B_COERCE:%.*]], ptr [[B]], align 2
// AVX-NEXT: store <2 x half> [[C_COERCE:%.*]], ptr [[C]], align 2
// AVX-NEXT: [[A_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[A]], i32 0, i32 0
// AVX-NEXT: [[A_REAL:%.*]] = load half, ptr [[A_REALP]], align 2
// AVX-NEXT: [[A_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[A]], i32 0, i32 1
// AVX-NEXT: [[A_IMAG:%.*]] = load half, ptr [[A_IMAGP]], align 2
// AVX-NEXT: [[B_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[B]], i32 0, i32 0
// AVX-NEXT: [[B_REAL:%.*]] = load half, ptr [[B_REALP]], align 2
// AVX-NEXT: [[B_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[B]], i32 0, i32 1
// AVX-NEXT: [[B_IMAG:%.*]] = load half, ptr [[B_IMAGP]], align 2
// AVX-NEXT: [[ADD_R:%.*]] = fadd half [[A_REAL]], [[B_REAL]]
// AVX-NEXT: [[ADD_I:%.*]] = fadd half [[A_IMAG]], [[B_IMAG]]
// AVX-NEXT: [[C_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[C]], i32 0, i32 0
// AVX-NEXT: [[C_REAL:%.*]] = load half, ptr [[C_REALP]], align 2
// AVX-NEXT: [[C_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[C]], i32 0, i32 1
// AVX-NEXT: [[C_IMAG:%.*]] = load half, ptr [[C_IMAGP]], align 2
// AVX-NEXT: [[ADD_R1:%.*]] = fadd half [[ADD_R]], [[C_REAL]]
// AVX-NEXT: [[ADD_I2:%.*]] = fadd half [[ADD_I]], [[C_IMAG]]
// AVX-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 0
// AVX-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 1
// AVX-NEXT: store half [[ADD_R1]], ptr [[RETVAL_REALP]], align 2
// AVX-NEXT: store half [[ADD_I2]], ptr [[RETVAL_IMAGP]], align 2
// AVX-NEXT: [[TMP0:%.*]] = load <2 x half>, ptr [[RETVAL]], align 2
// AVX-NEXT: ret <2 x half> [[TMP0]]
//
// X86-LABEL: @add2_haff_ccc(
// X86-NEXT: entry:
// X86-NEXT: [[RETVAL:%.*]] = alloca { half, half }, align 2
// X86-NEXT: [[A:%.*]] = alloca { half, half }, align 2
// X86-NEXT: [[B:%.*]] = alloca { half, half }, align 2
// X86-NEXT: [[C:%.*]] = alloca { half, half }, align 2
// X86-NEXT: store <2 x half> [[A_COERCE:%.*]], ptr [[A]], align 2
// X86-NEXT: store <2 x half> [[B_COERCE:%.*]], ptr [[B]], align 2
// X86-NEXT: store <2 x half> [[C_COERCE:%.*]], ptr [[C]], align 2
// X86-NEXT: [[A_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[A]], i32 0, i32 0
// X86-NEXT: [[A_REAL:%.*]] = load half, ptr [[A_REALP]], align 2
// X86-NEXT: [[A_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[A]], i32 0, i32 1
// X86-NEXT: [[A_IMAG:%.*]] = load half, ptr [[A_IMAGP]], align 2
// X86-NEXT: [[EXT:%.*]] = fpext half [[A_REAL]] to float
// X86-NEXT: [[EXT1:%.*]] = fpext half [[A_IMAG]] to float
// X86-NEXT: [[B_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[B]], i32 0, i32 0
// X86-NEXT: [[B_REAL:%.*]] = load half, ptr [[B_REALP]], align 2
// X86-NEXT: [[B_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[B]], i32 0, i32 1
// X86-NEXT: [[B_IMAG:%.*]] = load half, ptr [[B_IMAGP]], align 2
// X86-NEXT: [[EXT2:%.*]] = fpext half [[B_REAL]] to float
// X86-NEXT: [[EXT3:%.*]] = fpext half [[B_IMAG]] to float
// X86-NEXT: [[ADD_R:%.*]] = fadd float [[EXT]], [[EXT2]]
// X86-NEXT: [[ADD_I:%.*]] = fadd float [[EXT1]], [[EXT3]]
// X86-NEXT: [[C_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[C]], i32 0, i32 0
// X86-NEXT: [[C_REAL:%.*]] = load half, ptr [[C_REALP]], align 2
// X86-NEXT: [[C_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[C]], i32 0, i32 1
// X86-NEXT: [[C_IMAG:%.*]] = load half, ptr [[C_IMAGP]], align 2
// X86-NEXT: [[EXT4:%.*]] = fpext half [[C_REAL]] to float
// X86-NEXT: [[EXT5:%.*]] = fpext half [[C_IMAG]] to float
// X86-NEXT: [[ADD_R6:%.*]] = fadd float [[ADD_R]], [[EXT4]]
// X86-NEXT: [[ADD_I7:%.*]] = fadd float [[ADD_I]], [[EXT5]]
// X86-NEXT: [[UNPROMOTION:%.*]] = fptrunc float [[ADD_R6]] to half
// X86-NEXT: [[UNPROMOTION8:%.*]] = fptrunc float [[ADD_I7]] to half
// X86-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 0
// X86-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 1
// X86-NEXT: store half [[UNPROMOTION]], ptr [[RETVAL_REALP]], align 2
// X86-NEXT: store half [[UNPROMOTION8]], ptr [[RETVAL_IMAGP]], align 2
// X86-NEXT: [[TMP0:%.*]] = load <2 x half>, ptr [[RETVAL]], align 2
// X86-NEXT: ret <2 x half> [[TMP0]]
//
_Float16 _Complex add2_haff_ccc(_Float16 _Complex a, _Float16 _Complex b, _Float16 _Complex c) {
return a + b + c;
}
// AVX-LABEL: @sub_half_rr(
// AVX-NEXT: entry:
// AVX-NEXT: [[RETVAL:%.*]] = alloca { half, half }, align 2
// AVX-NEXT: [[A_ADDR:%.*]] = alloca half, align 2
// AVX-NEXT: [[B_ADDR:%.*]] = alloca half, align 2
// AVX-NEXT: store half [[A:%.*]], ptr [[A_ADDR]], align 2
// AVX-NEXT: store half [[B:%.*]], ptr [[B_ADDR]], align 2
// AVX-NEXT: [[TMP0:%.*]] = load half, ptr [[A_ADDR]], align 2
// AVX-NEXT: [[TMP1:%.*]] = load half, ptr [[B_ADDR]], align 2
// AVX-NEXT: [[SUB:%.*]] = fsub half [[TMP0]], [[TMP1]]
// AVX-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 0
// AVX-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 1
// AVX-NEXT: store half [[SUB]], ptr [[RETVAL_REALP]], align 2
// AVX-NEXT: store half 0xH0000, ptr [[RETVAL_IMAGP]], align 2
// AVX-NEXT: [[TMP2:%.*]] = load <2 x half>, ptr [[RETVAL]], align 2
// AVX-NEXT: ret <2 x half> [[TMP2]]
//
// X86-LABEL: @sub_half_rr(
// X86-NEXT: entry:
// X86-NEXT: [[RETVAL:%.*]] = alloca { half, half }, align 2
// X86-NEXT: [[A_ADDR:%.*]] = alloca half, align 2
// X86-NEXT: [[B_ADDR:%.*]] = alloca half, align 2
// X86-NEXT: store half [[A:%.*]], ptr [[A_ADDR]], align 2
// X86-NEXT: store half [[B:%.*]], ptr [[B_ADDR]], align 2
// X86-NEXT: [[TMP0:%.*]] = load half, ptr [[A_ADDR]], align 2
// X86-NEXT: [[EXT:%.*]] = fpext half [[TMP0]] to float
// X86-NEXT: [[TMP1:%.*]] = load half, ptr [[B_ADDR]], align 2
// X86-NEXT: [[EXT1:%.*]] = fpext half [[TMP1]] to float
// X86-NEXT: [[SUB:%.*]] = fsub float [[EXT]], [[EXT1]]
// X86-NEXT: [[UNPROMOTION:%.*]] = fptrunc float [[SUB]] to half
// X86-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 0
// X86-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 1
// X86-NEXT: store half [[UNPROMOTION]], ptr [[RETVAL_REALP]], align 2
// X86-NEXT: store half 0xH0000, ptr [[RETVAL_IMAGP]], align 2
// X86-NEXT: [[TMP2:%.*]] = load <2 x half>, ptr [[RETVAL]], align 2
// X86-NEXT: ret <2 x half> [[TMP2]]
//
_Float16 _Complex sub_half_rr(_Float16 a, _Float16 b) {
return a - b;
}
// AVX-LABEL: @sub_half_cr(
// AVX-NEXT: entry:
// AVX-NEXT: [[RETVAL:%.*]] = alloca { half, half }, align 2
// AVX-NEXT: [[A:%.*]] = alloca { half, half }, align 2
// AVX-NEXT: [[B_ADDR:%.*]] = alloca half, align 2
// AVX-NEXT: store <2 x half> [[A_COERCE:%.*]], ptr [[A]], align 2
// AVX-NEXT: store half [[B:%.*]], ptr [[B_ADDR]], align 2
// AVX-NEXT: [[A_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[A]], i32 0, i32 0
// AVX-NEXT: [[A_REAL:%.*]] = load half, ptr [[A_REALP]], align 2
// AVX-NEXT: [[A_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[A]], i32 0, i32 1
// AVX-NEXT: [[A_IMAG:%.*]] = load half, ptr [[A_IMAGP]], align 2
// AVX-NEXT: [[TMP0:%.*]] = load half, ptr [[B_ADDR]], align 2
// AVX-NEXT: [[SUB_R:%.*]] = fsub half [[A_REAL]], [[TMP0]]
// AVX-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 0
// AVX-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 1
// AVX-NEXT: store half [[SUB_R]], ptr [[RETVAL_REALP]], align 2
// AVX-NEXT: store half [[A_IMAG]], ptr [[RETVAL_IMAGP]], align 2
// AVX-NEXT: [[TMP1:%.*]] = load <2 x half>, ptr [[RETVAL]], align 2
// AVX-NEXT: ret <2 x half> [[TMP1]]
//
// X86-LABEL: @sub_half_cr(
// X86-NEXT: entry:
// X86-NEXT: [[RETVAL:%.*]] = alloca { half, half }, align 2
// X86-NEXT: [[A:%.*]] = alloca { half, half }, align 2
// X86-NEXT: [[B_ADDR:%.*]] = alloca half, align 2
// X86-NEXT: store <2 x half> [[A_COERCE:%.*]], ptr [[A]], align 2
// X86-NEXT: store half [[B:%.*]], ptr [[B_ADDR]], align 2
// X86-NEXT: [[A_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[A]], i32 0, i32 0
// X86-NEXT: [[A_REAL:%.*]] = load half, ptr [[A_REALP]], align 2
// X86-NEXT: [[A_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[A]], i32 0, i32 1
// X86-NEXT: [[A_IMAG:%.*]] = load half, ptr [[A_IMAGP]], align 2
// X86-NEXT: [[EXT:%.*]] = fpext half [[A_REAL]] to float
// X86-NEXT: [[EXT1:%.*]] = fpext half [[A_IMAG]] to float
// X86-NEXT: [[TMP0:%.*]] = load half, ptr [[B_ADDR]], align 2
// X86-NEXT: [[EXT2:%.*]] = fpext half [[TMP0]] to float
// X86-NEXT: [[SUB_R:%.*]] = fsub float [[EXT]], [[EXT2]]
// X86-NEXT: [[UNPROMOTION:%.*]] = fptrunc float [[SUB_R]] to half
// X86-NEXT: [[UNPROMOTION3:%.*]] = fptrunc float [[EXT1]] to half
// X86-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 0
// X86-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 1
// X86-NEXT: store half [[UNPROMOTION]], ptr [[RETVAL_REALP]], align 2
// X86-NEXT: store half [[UNPROMOTION3]], ptr [[RETVAL_IMAGP]], align 2
// X86-NEXT: [[TMP1:%.*]] = load <2 x half>, ptr [[RETVAL]], align 2
// X86-NEXT: ret <2 x half> [[TMP1]]
//
_Float16 _Complex sub_half_cr(_Float16 _Complex a, _Float16 b) {
return a - b;
}
// AVX-LABEL: @sub_half_rc(
// AVX-NEXT: entry:
// AVX-NEXT: [[RETVAL:%.*]] = alloca { half, half }, align 2
// AVX-NEXT: [[B:%.*]] = alloca { half, half }, align 2
// AVX-NEXT: [[A_ADDR:%.*]] = alloca half, align 2
// AVX-NEXT: store <2 x half> [[B_COERCE:%.*]], ptr [[B]], align 2
// AVX-NEXT: store half [[A:%.*]], ptr [[A_ADDR]], align 2
// AVX-NEXT: [[TMP0:%.*]] = load half, ptr [[A_ADDR]], align 2
// AVX-NEXT: [[B_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[B]], i32 0, i32 0
// AVX-NEXT: [[B_REAL:%.*]] = load half, ptr [[B_REALP]], align 2
// AVX-NEXT: [[B_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[B]], i32 0, i32 1
// AVX-NEXT: [[B_IMAG:%.*]] = load half, ptr [[B_IMAGP]], align 2
// AVX-NEXT: [[SUB_R:%.*]] = fsub half [[TMP0]], [[B_REAL]]
// AVX-NEXT: [[SUB_I:%.*]] = fneg half [[B_IMAG]]
// AVX-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 0
// AVX-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 1
// AVX-NEXT: store half [[SUB_R]], ptr [[RETVAL_REALP]], align 2
// AVX-NEXT: store half [[SUB_I]], ptr [[RETVAL_IMAGP]], align 2
// AVX-NEXT: [[TMP1:%.*]] = load <2 x half>, ptr [[RETVAL]], align 2
// AVX-NEXT: ret <2 x half> [[TMP1]]
//
// X86-LABEL: @sub_half_rc(
// X86-NEXT: entry:
// X86-NEXT: [[RETVAL:%.*]] = alloca { half, half }, align 2
// X86-NEXT: [[B:%.*]] = alloca { half, half }, align 2
// X86-NEXT: [[A_ADDR:%.*]] = alloca half, align 2
// X86-NEXT: store <2 x half> [[B_COERCE:%.*]], ptr [[B]], align 2
// X86-NEXT: store half [[A:%.*]], ptr [[A_ADDR]], align 2
// X86-NEXT: [[TMP0:%.*]] = load half, ptr [[A_ADDR]], align 2
// X86-NEXT: [[EXT:%.*]] = fpext half [[TMP0]] to float
// X86-NEXT: [[B_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[B]], i32 0, i32 0
// X86-NEXT: [[B_REAL:%.*]] = load half, ptr [[B_REALP]], align 2
// X86-NEXT: [[B_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[B]], i32 0, i32 1
// X86-NEXT: [[B_IMAG:%.*]] = load half, ptr [[B_IMAGP]], align 2
// X86-NEXT: [[EXT1:%.*]] = fpext half [[B_REAL]] to float
// X86-NEXT: [[EXT2:%.*]] = fpext half [[B_IMAG]] to float
// X86-NEXT: [[SUB_R:%.*]] = fsub float [[EXT]], [[EXT1]]
// X86-NEXT: [[SUB_I:%.*]] = fneg float [[EXT2]]
// X86-NEXT: [[UNPROMOTION:%.*]] = fptrunc float [[SUB_R]] to half
// X86-NEXT: [[UNPROMOTION3:%.*]] = fptrunc float [[SUB_I]] to half
// X86-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 0
// X86-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 1
// X86-NEXT: store half [[UNPROMOTION]], ptr [[RETVAL_REALP]], align 2
// X86-NEXT: store half [[UNPROMOTION3]], ptr [[RETVAL_IMAGP]], align 2
// X86-NEXT: [[TMP1:%.*]] = load <2 x half>, ptr [[RETVAL]], align 2
// X86-NEXT: ret <2 x half> [[TMP1]]
//
_Float16 _Complex sub_half_rc(_Float16 a, _Float16 _Complex b) {
return a - b;
}
// AVX-LABEL: @sub_half_cc(
// AVX-NEXT: entry:
// AVX-NEXT: [[RETVAL:%.*]] = alloca { half, half }, align 2
// AVX-NEXT: [[A:%.*]] = alloca { half, half }, align 2
// AVX-NEXT: [[B:%.*]] = alloca { half, half }, align 2
// AVX-NEXT: store <2 x half> [[A_COERCE:%.*]], ptr [[A]], align 2
// AVX-NEXT: store <2 x half> [[B_COERCE:%.*]], ptr [[B]], align 2
// AVX-NEXT: [[A_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[A]], i32 0, i32 0
// AVX-NEXT: [[A_REAL:%.*]] = load half, ptr [[A_REALP]], align 2
// AVX-NEXT: [[A_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[A]], i32 0, i32 1
// AVX-NEXT: [[A_IMAG:%.*]] = load half, ptr [[A_IMAGP]], align 2
// AVX-NEXT: [[B_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[B]], i32 0, i32 0
// AVX-NEXT: [[B_REAL:%.*]] = load half, ptr [[B_REALP]], align 2
// AVX-NEXT: [[B_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[B]], i32 0, i32 1
// AVX-NEXT: [[B_IMAG:%.*]] = load half, ptr [[B_IMAGP]], align 2
// AVX-NEXT: [[SUB_R:%.*]] = fsub half [[A_REAL]], [[B_REAL]]
// AVX-NEXT: [[SUB_I:%.*]] = fsub half [[A_IMAG]], [[B_IMAG]]
// AVX-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 0
// AVX-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 1
// AVX-NEXT: store half [[SUB_R]], ptr [[RETVAL_REALP]], align 2
// AVX-NEXT: store half [[SUB_I]], ptr [[RETVAL_IMAGP]], align 2
// AVX-NEXT: [[TMP0:%.*]] = load <2 x half>, ptr [[RETVAL]], align 2
// AVX-NEXT: ret <2 x half> [[TMP0]]
//
// X86-LABEL: @sub_half_cc(
// X86-NEXT: entry:
// X86-NEXT: [[RETVAL:%.*]] = alloca { half, half }, align 2
// X86-NEXT: [[A:%.*]] = alloca { half, half }, align 2
// X86-NEXT: [[B:%.*]] = alloca { half, half }, align 2
// X86-NEXT: store <2 x half> [[A_COERCE:%.*]], ptr [[A]], align 2
// X86-NEXT: store <2 x half> [[B_COERCE:%.*]], ptr [[B]], align 2
// X86-NEXT: [[A_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[A]], i32 0, i32 0
// X86-NEXT: [[A_REAL:%.*]] = load half, ptr [[A_REALP]], align 2
// X86-NEXT: [[A_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[A]], i32 0, i32 1
// X86-NEXT: [[A_IMAG:%.*]] = load half, ptr [[A_IMAGP]], align 2
// X86-NEXT: [[EXT:%.*]] = fpext half [[A_REAL]] to float
// X86-NEXT: [[EXT1:%.*]] = fpext half [[A_IMAG]] to float
// X86-NEXT: [[B_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[B]], i32 0, i32 0
// X86-NEXT: [[B_REAL:%.*]] = load half, ptr [[B_REALP]], align 2
// X86-NEXT: [[B_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[B]], i32 0, i32 1
// X86-NEXT: [[B_IMAG:%.*]] = load half, ptr [[B_IMAGP]], align 2
// X86-NEXT: [[EXT2:%.*]] = fpext half [[B_REAL]] to float
// X86-NEXT: [[EXT3:%.*]] = fpext half [[B_IMAG]] to float
// X86-NEXT: [[SUB_R:%.*]] = fsub float [[EXT]], [[EXT2]]
// X86-NEXT: [[SUB_I:%.*]] = fsub float [[EXT1]], [[EXT3]]
// X86-NEXT: [[UNPROMOTION:%.*]] = fptrunc float [[SUB_R]] to half
// X86-NEXT: [[UNPROMOTION4:%.*]] = fptrunc float [[SUB_I]] to half
// X86-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 0
// X86-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 1
// X86-NEXT: store half [[UNPROMOTION]], ptr [[RETVAL_REALP]], align 2
// X86-NEXT: store half [[UNPROMOTION4]], ptr [[RETVAL_IMAGP]], align 2
// X86-NEXT: [[TMP0:%.*]] = load <2 x half>, ptr [[RETVAL]], align 2
// X86-NEXT: ret <2 x half> [[TMP0]]
//
_Float16 _Complex sub_half_cc(_Float16 _Complex a, _Float16 _Complex b) {
return a - b;
}
// AVX-LABEL: @mul_half_rr(
// AVX-NEXT: entry:
// AVX-NEXT: [[RETVAL:%.*]] = alloca { half, half }, align 2
// AVX-NEXT: [[A_ADDR:%.*]] = alloca half, align 2
// AVX-NEXT: [[B_ADDR:%.*]] = alloca half, align 2
// AVX-NEXT: store half [[A:%.*]], ptr [[A_ADDR]], align 2
// AVX-NEXT: store half [[B:%.*]], ptr [[B_ADDR]], align 2
// AVX-NEXT: [[TMP0:%.*]] = load half, ptr [[A_ADDR]], align 2
// AVX-NEXT: [[TMP1:%.*]] = load half, ptr [[B_ADDR]], align 2
// AVX-NEXT: [[MUL:%.*]] = fmul half [[TMP0]], [[TMP1]]
// AVX-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 0
// AVX-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 1
// AVX-NEXT: store half [[MUL]], ptr [[RETVAL_REALP]], align 2
// AVX-NEXT: store half 0xH0000, ptr [[RETVAL_IMAGP]], align 2
// AVX-NEXT: [[TMP2:%.*]] = load <2 x half>, ptr [[RETVAL]], align 2
// AVX-NEXT: ret <2 x half> [[TMP2]]
//
// X86-LABEL: @mul_half_rr(
// X86-NEXT: entry:
// X86-NEXT: [[RETVAL:%.*]] = alloca { half, half }, align 2
// X86-NEXT: [[A_ADDR:%.*]] = alloca half, align 2
// X86-NEXT: [[B_ADDR:%.*]] = alloca half, align 2
// X86-NEXT: store half [[A:%.*]], ptr [[A_ADDR]], align 2
// X86-NEXT: store half [[B:%.*]], ptr [[B_ADDR]], align 2
// X86-NEXT: [[TMP0:%.*]] = load half, ptr [[A_ADDR]], align 2
// X86-NEXT: [[EXT:%.*]] = fpext half [[TMP0]] to float
// X86-NEXT: [[TMP1:%.*]] = load half, ptr [[B_ADDR]], align 2
// X86-NEXT: [[EXT1:%.*]] = fpext half [[TMP1]] to float
// X86-NEXT: [[MUL:%.*]] = fmul float [[EXT]], [[EXT1]]
// X86-NEXT: [[UNPROMOTION:%.*]] = fptrunc float [[MUL]] to half
// X86-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 0
// X86-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 1
// X86-NEXT: store half [[UNPROMOTION]], ptr [[RETVAL_REALP]], align 2
// X86-NEXT: store half 0xH0000, ptr [[RETVAL_IMAGP]], align 2
// X86-NEXT: [[TMP2:%.*]] = load <2 x half>, ptr [[RETVAL]], align 2
// X86-NEXT: ret <2 x half> [[TMP2]]
//
_Float16 _Complex mul_half_rr(_Float16 a, _Float16 b) {
return a * b;
}
// AVX-LABEL: @mul_half_cr(
// AVX-NEXT: entry:
// AVX-NEXT: [[RETVAL:%.*]] = alloca { half, half }, align 2
// AVX-NEXT: [[A:%.*]] = alloca { half, half }, align 2
// AVX-NEXT: [[B_ADDR:%.*]] = alloca half, align 2
// AVX-NEXT: store <2 x half> [[A_COERCE:%.*]], ptr [[A]], align 2
// AVX-NEXT: store half [[B:%.*]], ptr [[B_ADDR]], align 2
// AVX-NEXT: [[A_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[A]], i32 0, i32 0
// AVX-NEXT: [[A_REAL:%.*]] = load half, ptr [[A_REALP]], align 2
// AVX-NEXT: [[A_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[A]], i32 0, i32 1
// AVX-NEXT: [[A_IMAG:%.*]] = load half, ptr [[A_IMAGP]], align 2
// AVX-NEXT: [[TMP0:%.*]] = load half, ptr [[B_ADDR]], align 2
// AVX-NEXT: [[MUL_RL:%.*]] = fmul half [[A_REAL]], [[TMP0]]
// AVX-NEXT: [[MUL_IL:%.*]] = fmul half [[A_IMAG]], [[TMP0]]
// AVX-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 0
// AVX-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 1
// AVX-NEXT: store half [[MUL_RL]], ptr [[RETVAL_REALP]], align 2
// AVX-NEXT: store half [[MUL_IL]], ptr [[RETVAL_IMAGP]], align 2
// AVX-NEXT: [[TMP1:%.*]] = load <2 x half>, ptr [[RETVAL]], align 2
// AVX-NEXT: ret <2 x half> [[TMP1]]
//
// X86-LABEL: @mul_half_cr(
// X86-NEXT: entry:
// X86-NEXT: [[RETVAL:%.*]] = alloca { half, half }, align 2
// X86-NEXT: [[A:%.*]] = alloca { half, half }, align 2
// X86-NEXT: [[B_ADDR:%.*]] = alloca half, align 2
// X86-NEXT: store <2 x half> [[A_COERCE:%.*]], ptr [[A]], align 2
// X86-NEXT: store half [[B:%.*]], ptr [[B_ADDR]], align 2
// X86-NEXT: [[A_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[A]], i32 0, i32 0
// X86-NEXT: [[A_REAL:%.*]] = load half, ptr [[A_REALP]], align 2
// X86-NEXT: [[A_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[A]], i32 0, i32 1
// X86-NEXT: [[A_IMAG:%.*]] = load half, ptr [[A_IMAGP]], align 2
// X86-NEXT: [[EXT:%.*]] = fpext half [[A_REAL]] to float
// X86-NEXT: [[EXT1:%.*]] = fpext half [[A_IMAG]] to float
// X86-NEXT: [[TMP0:%.*]] = load half, ptr [[B_ADDR]], align 2
// X86-NEXT: [[EXT2:%.*]] = fpext half [[TMP0]] to float
// X86-NEXT: [[MUL_RL:%.*]] = fmul float [[EXT]], [[EXT2]]
// X86-NEXT: [[MUL_IL:%.*]] = fmul float [[EXT1]], [[EXT2]]
// X86-NEXT: [[UNPROMOTION:%.*]] = fptrunc float [[MUL_RL]] to half
// X86-NEXT: [[UNPROMOTION3:%.*]] = fptrunc float [[MUL_IL]] to half
// X86-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 0
// X86-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 1
// X86-NEXT: store half [[UNPROMOTION]], ptr [[RETVAL_REALP]], align 2
// X86-NEXT: store half [[UNPROMOTION3]], ptr [[RETVAL_IMAGP]], align 2
// X86-NEXT: [[TMP1:%.*]] = load <2 x half>, ptr [[RETVAL]], align 2
// X86-NEXT: ret <2 x half> [[TMP1]]
//
_Float16 _Complex mul_half_cr(_Float16 _Complex a, _Float16 b) {
return a * b;
}
// AVX-LABEL: @mul_half_rc(
// AVX-NEXT: entry:
// AVX-NEXT: [[RETVAL:%.*]] = alloca { half, half }, align 2
// AVX-NEXT: [[B:%.*]] = alloca { half, half }, align 2
// AVX-NEXT: [[A_ADDR:%.*]] = alloca half, align 2
// AVX-NEXT: store <2 x half> [[B_COERCE:%.*]], ptr [[B]], align 2
// AVX-NEXT: store half [[A:%.*]], ptr [[A_ADDR]], align 2
// AVX-NEXT: [[TMP0:%.*]] = load half, ptr [[A_ADDR]], align 2
// AVX-NEXT: [[B_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[B]], i32 0, i32 0
// AVX-NEXT: [[B_REAL:%.*]] = load half, ptr [[B_REALP]], align 2
// AVX-NEXT: [[B_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[B]], i32 0, i32 1
// AVX-NEXT: [[B_IMAG:%.*]] = load half, ptr [[B_IMAGP]], align 2
// AVX-NEXT: [[MUL_RL:%.*]] = fmul half [[TMP0]], [[B_REAL]]
// AVX-NEXT: [[MUL_IR:%.*]] = fmul half [[TMP0]], [[B_IMAG]]
// AVX-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 0
// AVX-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 1
// AVX-NEXT: store half [[MUL_RL]], ptr [[RETVAL_REALP]], align 2
// AVX-NEXT: store half [[MUL_IR]], ptr [[RETVAL_IMAGP]], align 2
// AVX-NEXT: [[TMP1:%.*]] = load <2 x half>, ptr [[RETVAL]], align 2
// AVX-NEXT: ret <2 x half> [[TMP1]]
//
// X86-LABEL: @mul_half_rc(
// X86-NEXT: entry:
// X86-NEXT: [[RETVAL:%.*]] = alloca { half, half }, align 2
// X86-NEXT: [[B:%.*]] = alloca { half, half }, align 2
// X86-NEXT: [[A_ADDR:%.*]] = alloca half, align 2
// X86-NEXT: store <2 x half> [[B_COERCE:%.*]], ptr [[B]], align 2
// X86-NEXT: store half [[A:%.*]], ptr [[A_ADDR]], align 2
// X86-NEXT: [[TMP0:%.*]] = load half, ptr [[A_ADDR]], align 2
// X86-NEXT: [[EXT:%.*]] = fpext half [[TMP0]] to float
// X86-NEXT: [[B_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[B]], i32 0, i32 0
// X86-NEXT: [[B_REAL:%.*]] = load half, ptr [[B_REALP]], align 2
// X86-NEXT: [[B_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[B]], i32 0, i32 1
// X86-NEXT: [[B_IMAG:%.*]] = load half, ptr [[B_IMAGP]], align 2
// X86-NEXT: [[EXT1:%.*]] = fpext half [[B_REAL]] to float
// X86-NEXT: [[EXT2:%.*]] = fpext half [[B_IMAG]] to float
// X86-NEXT: [[MUL_RL:%.*]] = fmul float [[EXT]], [[EXT1]]
// X86-NEXT: [[MUL_IR:%.*]] = fmul float [[EXT]], [[EXT2]]
// X86-NEXT: [[UNPROMOTION:%.*]] = fptrunc float [[MUL_RL]] to half
// X86-NEXT: [[UNPROMOTION3:%.*]] = fptrunc float [[MUL_IR]] to half
// X86-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 0
// X86-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 1
// X86-NEXT: store half [[UNPROMOTION]], ptr [[RETVAL_REALP]], align 2
// X86-NEXT: store half [[UNPROMOTION3]], ptr [[RETVAL_IMAGP]], align 2
// X86-NEXT: [[TMP1:%.*]] = load <2 x half>, ptr [[RETVAL]], align 2
// X86-NEXT: ret <2 x half> [[TMP1]]
//
_Float16 _Complex mul_half_rc(_Float16 a, _Float16 _Complex b) {
return a * b;
}
// AVX-LABEL: @mul_half_cc(
// AVX-NEXT: entry:
// AVX-NEXT: [[RETVAL:%.*]] = alloca { half, half }, align 2
// AVX-NEXT: [[A:%.*]] = alloca { half, half }, align 2
// AVX-NEXT: [[B:%.*]] = alloca { half, half }, align 2
// AVX-NEXT: [[COERCE:%.*]] = alloca { half, half }, align 2
// AVX-NEXT: store <2 x half> [[A_COERCE:%.*]], ptr [[A]], align 2
// AVX-NEXT: store <2 x half> [[B_COERCE:%.*]], ptr [[B]], align 2
// AVX-NEXT: [[A_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[A]], i32 0, i32 0
// AVX-NEXT: [[A_REAL:%.*]] = load half, ptr [[A_REALP]], align 2
// AVX-NEXT: [[A_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[A]], i32 0, i32 1
// AVX-NEXT: [[A_IMAG:%.*]] = load half, ptr [[A_IMAGP]], align 2
// AVX-NEXT: [[B_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[B]], i32 0, i32 0
// AVX-NEXT: [[B_REAL:%.*]] = load half, ptr [[B_REALP]], align 2
// AVX-NEXT: [[B_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[B]], i32 0, i32 1
// AVX-NEXT: [[B_IMAG:%.*]] = load half, ptr [[B_IMAGP]], align 2
// AVX-NEXT: [[MUL_AC:%.*]] = fmul half [[A_REAL]], [[B_REAL]]
// AVX-NEXT: [[MUL_BD:%.*]] = fmul half [[A_IMAG]], [[B_IMAG]]
// AVX-NEXT: [[MUL_AD:%.*]] = fmul half [[A_REAL]], [[B_IMAG]]
// AVX-NEXT: [[MUL_BC:%.*]] = fmul half [[A_IMAG]], [[B_REAL]]
// AVX-NEXT: [[MUL_R:%.*]] = fsub half [[MUL_AC]], [[MUL_BD]]
// AVX-NEXT: [[MUL_I:%.*]] = fadd half [[MUL_AD]], [[MUL_BC]]
// AVX-NEXT: [[ISNAN_CMP:%.*]] = fcmp uno half [[MUL_R]], [[MUL_R]]
// AVX-NEXT: br i1 [[ISNAN_CMP]], label [[COMPLEX_MUL_IMAG_NAN:%.*]], label [[COMPLEX_MUL_CONT:%.*]], !prof [[PROF2:![0-9]+]]
// AVX: complex_mul_imag_nan:
// AVX-NEXT: [[ISNAN_CMP1:%.*]] = fcmp uno half [[MUL_I]], [[MUL_I]]
// AVX-NEXT: br i1 [[ISNAN_CMP1]], label [[COMPLEX_MUL_LIBCALL:%.*]], label [[COMPLEX_MUL_CONT]], !prof [[PROF2]]
// AVX: complex_mul_libcall:
// AVX-NEXT: [[CALL:%.*]] = call <2 x half> @__mulhc3(half noundef [[A_REAL]], half noundef [[A_IMAG]], half noundef [[B_REAL]], half noundef [[B_IMAG]]) #[[ATTR1:[0-9]+]]
// AVX-NEXT: store <2 x half> [[CALL]], ptr [[COERCE]], align 2
// AVX-NEXT: [[COERCE_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[COERCE]], i32 0, i32 0
// AVX-NEXT: [[COERCE_REAL:%.*]] = load half, ptr [[COERCE_REALP]], align 2
// AVX-NEXT: [[COERCE_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[COERCE]], i32 0, i32 1
// AVX-NEXT: [[COERCE_IMAG:%.*]] = load half, ptr [[COERCE_IMAGP]], align 2
// AVX-NEXT: br label [[COMPLEX_MUL_CONT]]
// AVX: complex_mul_cont:
// AVX-NEXT: [[REAL_MUL_PHI:%.*]] = phi half [ [[MUL_R]], [[ENTRY:%.*]] ], [ [[MUL_R]], [[COMPLEX_MUL_IMAG_NAN]] ], [ [[COERCE_REAL]], [[COMPLEX_MUL_LIBCALL]] ]
// AVX-NEXT: [[IMAG_MUL_PHI:%.*]] = phi half [ [[MUL_I]], [[ENTRY]] ], [ [[MUL_I]], [[COMPLEX_MUL_IMAG_NAN]] ], [ [[COERCE_IMAG]], [[COMPLEX_MUL_LIBCALL]] ]
// AVX-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 0
// AVX-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 1
// AVX-NEXT: store half [[REAL_MUL_PHI]], ptr [[RETVAL_REALP]], align 2
// AVX-NEXT: store half [[IMAG_MUL_PHI]], ptr [[RETVAL_IMAGP]], align 2
// AVX-NEXT: [[TMP0:%.*]] = load <2 x half>, ptr [[RETVAL]], align 2
// AVX-NEXT: ret <2 x half> [[TMP0]]
//
// X86-LABEL: @mul_half_cc(
// X86-NEXT: entry:
// X86-NEXT: [[RETVAL:%.*]] = alloca { half, half }, align 2
// X86-NEXT: [[A:%.*]] = alloca { half, half }, align 2
// X86-NEXT: [[B:%.*]] = alloca { half, half }, align 2
// X86-NEXT: [[COERCE:%.*]] = alloca { float, float }, align 4
// X86-NEXT: store <2 x half> [[A_COERCE:%.*]], ptr [[A]], align 2
// X86-NEXT: store <2 x half> [[B_COERCE:%.*]], ptr [[B]], align 2
// X86-NEXT: [[A_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[A]], i32 0, i32 0
// X86-NEXT: [[A_REAL:%.*]] = load half, ptr [[A_REALP]], align 2
// X86-NEXT: [[A_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[A]], i32 0, i32 1
// X86-NEXT: [[A_IMAG:%.*]] = load half, ptr [[A_IMAGP]], align 2
// X86-NEXT: [[EXT:%.*]] = fpext half [[A_REAL]] to float
// X86-NEXT: [[EXT1:%.*]] = fpext half [[A_IMAG]] to float
// X86-NEXT: [[B_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[B]], i32 0, i32 0
// X86-NEXT: [[B_REAL:%.*]] = load half, ptr [[B_REALP]], align 2
// X86-NEXT: [[B_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[B]], i32 0, i32 1
// X86-NEXT: [[B_IMAG:%.*]] = load half, ptr [[B_IMAGP]], align 2
// X86-NEXT: [[EXT2:%.*]] = fpext half [[B_REAL]] to float
// X86-NEXT: [[EXT3:%.*]] = fpext half [[B_IMAG]] to float
// X86-NEXT: [[MUL_AC:%.*]] = fmul float [[EXT]], [[EXT2]]
// X86-NEXT: [[MUL_BD:%.*]] = fmul float [[EXT1]], [[EXT3]]
// X86-NEXT: [[MUL_AD:%.*]] = fmul float [[EXT]], [[EXT3]]
// X86-NEXT: [[MUL_BC:%.*]] = fmul float [[EXT1]], [[EXT2]]
// X86-NEXT: [[MUL_R:%.*]] = fsub float [[MUL_AC]], [[MUL_BD]]
// X86-NEXT: [[MUL_I:%.*]] = fadd float [[MUL_AD]], [[MUL_BC]]
// X86-NEXT: [[ISNAN_CMP:%.*]] = fcmp uno float [[MUL_R]], [[MUL_R]]
// X86-NEXT: br i1 [[ISNAN_CMP]], label [[COMPLEX_MUL_IMAG_NAN:%.*]], label [[COMPLEX_MUL_CONT:%.*]], !prof [[PROF2:![0-9]+]]
// X86: complex_mul_imag_nan:
// X86-NEXT: [[ISNAN_CMP4:%.*]] = fcmp uno float [[MUL_I]], [[MUL_I]]
// X86-NEXT: br i1 [[ISNAN_CMP4]], label [[COMPLEX_MUL_LIBCALL:%.*]], label [[COMPLEX_MUL_CONT]], !prof [[PROF2]]
// X86: complex_mul_libcall:
// X86-NEXT: [[CALL:%.*]] = call <2 x float> @__mulsc3(float noundef [[EXT]], float noundef [[EXT1]], float noundef [[EXT2]], float noundef [[EXT3]]) #[[ATTR2:[0-9]+]]
// X86-NEXT: store <2 x float> [[CALL]], ptr [[COERCE]], align 4
// X86-NEXT: [[COERCE_REALP:%.*]] = getelementptr inbounds { float, float }, ptr [[COERCE]], i32 0, i32 0
// X86-NEXT: [[COERCE_REAL:%.*]] = load float, ptr [[COERCE_REALP]], align 4
// X86-NEXT: [[COERCE_IMAGP:%.*]] = getelementptr inbounds { float, float }, ptr [[COERCE]], i32 0, i32 1
// X86-NEXT: [[COERCE_IMAG:%.*]] = load float, ptr [[COERCE_IMAGP]], align 4
// X86-NEXT: br label [[COMPLEX_MUL_CONT]]
// X86: complex_mul_cont:
// X86-NEXT: [[REAL_MUL_PHI:%.*]] = phi float [ [[MUL_R]], [[ENTRY:%.*]] ], [ [[MUL_R]], [[COMPLEX_MUL_IMAG_NAN]] ], [ [[COERCE_REAL]], [[COMPLEX_MUL_LIBCALL]] ]
// X86-NEXT: [[IMAG_MUL_PHI:%.*]] = phi float [ [[MUL_I]], [[ENTRY]] ], [ [[MUL_I]], [[COMPLEX_MUL_IMAG_NAN]] ], [ [[COERCE_IMAG]], [[COMPLEX_MUL_LIBCALL]] ]
// X86-NEXT: [[UNPROMOTION:%.*]] = fptrunc float [[REAL_MUL_PHI]] to half
// X86-NEXT: [[UNPROMOTION5:%.*]] = fptrunc float [[IMAG_MUL_PHI]] to half
// X86-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 0
// X86-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 1
// X86-NEXT: store half [[UNPROMOTION]], ptr [[RETVAL_REALP]], align 2
// X86-NEXT: store half [[UNPROMOTION5]], ptr [[RETVAL_IMAGP]], align 2
// X86-NEXT: [[TMP0:%.*]] = load <2 x half>, ptr [[RETVAL]], align 2
// X86-NEXT: ret <2 x half> [[TMP0]]
//
_Float16 _Complex mul_half_cc(_Float16 _Complex a, _Float16 _Complex b) {
return a * b;
}
// AVX-LABEL: @div_half_rr(
// AVX-NEXT: entry:
// AVX-NEXT: [[RETVAL:%.*]] = alloca { half, half }, align 2
// AVX-NEXT: [[A_ADDR:%.*]] = alloca half, align 2
// AVX-NEXT: [[B_ADDR:%.*]] = alloca half, align 2
// AVX-NEXT: store half [[A:%.*]], ptr [[A_ADDR]], align 2
// AVX-NEXT: store half [[B:%.*]], ptr [[B_ADDR]], align 2
// AVX-NEXT: [[TMP0:%.*]] = load half, ptr [[A_ADDR]], align 2
// AVX-NEXT: [[TMP1:%.*]] = load half, ptr [[B_ADDR]], align 2
// AVX-NEXT: [[DIV:%.*]] = fdiv half [[TMP0]], [[TMP1]]
// AVX-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 0
// AVX-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 1
// AVX-NEXT: store half [[DIV]], ptr [[RETVAL_REALP]], align 2
// AVX-NEXT: store half 0xH0000, ptr [[RETVAL_IMAGP]], align 2
// AVX-NEXT: [[TMP2:%.*]] = load <2 x half>, ptr [[RETVAL]], align 2
// AVX-NEXT: ret <2 x half> [[TMP2]]
//
// X86-LABEL: @div_half_rr(
// X86-NEXT: entry:
// X86-NEXT: [[RETVAL:%.*]] = alloca { half, half }, align 2
// X86-NEXT: [[A_ADDR:%.*]] = alloca half, align 2
// X86-NEXT: [[B_ADDR:%.*]] = alloca half, align 2
// X86-NEXT: store half [[A:%.*]], ptr [[A_ADDR]], align 2
// X86-NEXT: store half [[B:%.*]], ptr [[B_ADDR]], align 2
// X86-NEXT: [[TMP0:%.*]] = load half, ptr [[A_ADDR]], align 2
// X86-NEXT: [[EXT:%.*]] = fpext half [[TMP0]] to float
// X86-NEXT: [[TMP1:%.*]] = load half, ptr [[B_ADDR]], align 2
// X86-NEXT: [[EXT1:%.*]] = fpext half [[TMP1]] to float
// X86-NEXT: [[DIV:%.*]] = fdiv float [[EXT]], [[EXT1]]
// X86-NEXT: [[UNPROMOTION:%.*]] = fptrunc float [[DIV]] to half
// X86-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 0
// X86-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 1
// X86-NEXT: store half [[UNPROMOTION]], ptr [[RETVAL_REALP]], align 2
// X86-NEXT: store half 0xH0000, ptr [[RETVAL_IMAGP]], align 2
// X86-NEXT: [[TMP2:%.*]] = load <2 x half>, ptr [[RETVAL]], align 2
// X86-NEXT: ret <2 x half> [[TMP2]]
//
_Float16 _Complex div_half_rr(_Float16 a, _Float16 b) {
return a / b;
}
// AVX-LABEL: @div_half_cr(
// AVX-NEXT: entry:
// AVX-NEXT: [[RETVAL:%.*]] = alloca { half, half }, align 2
// AVX-NEXT: [[A:%.*]] = alloca { half, half }, align 2
// AVX-NEXT: [[B_ADDR:%.*]] = alloca half, align 2
// AVX-NEXT: store <2 x half> [[A_COERCE:%.*]], ptr [[A]], align 2
// AVX-NEXT: store half [[B:%.*]], ptr [[B_ADDR]], align 2
// AVX-NEXT: [[A_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[A]], i32 0, i32 0
// AVX-NEXT: [[A_REAL:%.*]] = load half, ptr [[A_REALP]], align 2
// AVX-NEXT: [[A_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[A]], i32 0, i32 1
// AVX-NEXT: [[A_IMAG:%.*]] = load half, ptr [[A_IMAGP]], align 2
// AVX-NEXT: [[TMP0:%.*]] = load half, ptr [[B_ADDR]], align 2
// AVX-NEXT: [[TMP1:%.*]] = fdiv half [[A_REAL]], [[TMP0]]
// AVX-NEXT: [[TMP2:%.*]] = fdiv half [[A_IMAG]], [[TMP0]]
// AVX-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 0
// AVX-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 1
// AVX-NEXT: store half [[TMP1]], ptr [[RETVAL_REALP]], align 2
// AVX-NEXT: store half [[TMP2]], ptr [[RETVAL_IMAGP]], align 2
// AVX-NEXT: [[TMP3:%.*]] = load <2 x half>, ptr [[RETVAL]], align 2
// AVX-NEXT: ret <2 x half> [[TMP3]]
//
// X86-LABEL: @div_half_cr(
// X86-NEXT: entry:
// X86-NEXT: [[RETVAL:%.*]] = alloca { half, half }, align 2
// X86-NEXT: [[A:%.*]] = alloca { half, half }, align 2
// X86-NEXT: [[B_ADDR:%.*]] = alloca half, align 2
// X86-NEXT: store <2 x half> [[A_COERCE:%.*]], ptr [[A]], align 2
// X86-NEXT: store half [[B:%.*]], ptr [[B_ADDR]], align 2
// X86-NEXT: [[A_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[A]], i32 0, i32 0
// X86-NEXT: [[A_REAL:%.*]] = load half, ptr [[A_REALP]], align 2
// X86-NEXT: [[A_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[A]], i32 0, i32 1
// X86-NEXT: [[A_IMAG:%.*]] = load half, ptr [[A_IMAGP]], align 2
// X86-NEXT: [[EXT:%.*]] = fpext half [[A_REAL]] to float
// X86-NEXT: [[EXT1:%.*]] = fpext half [[A_IMAG]] to float
// X86-NEXT: [[TMP0:%.*]] = load half, ptr [[B_ADDR]], align 2
// X86-NEXT: [[EXT2:%.*]] = fpext half [[TMP0]] to float
// X86-NEXT: [[TMP1:%.*]] = fdiv float [[EXT]], [[EXT2]]
// X86-NEXT: [[TMP2:%.*]] = fdiv float [[EXT1]], [[EXT2]]
// X86-NEXT: [[UNPROMOTION:%.*]] = fptrunc float [[TMP1]] to half
// X86-NEXT: [[UNPROMOTION3:%.*]] = fptrunc float [[TMP2]] to half
// X86-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 0
// X86-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 1
// X86-NEXT: store half [[UNPROMOTION]], ptr [[RETVAL_REALP]], align 2
// X86-NEXT: store half [[UNPROMOTION3]], ptr [[RETVAL_IMAGP]], align 2
// X86-NEXT: [[TMP3:%.*]] = load <2 x half>, ptr [[RETVAL]], align 2
// X86-NEXT: ret <2 x half> [[TMP3]]
//
_Float16 _Complex div_half_cr(_Float16 _Complex a, _Float16 b) {
return a / b;
}
// AVX-LABEL: @div_half_rc(
// AVX-NEXT: entry:
// AVX-NEXT: [[RETVAL:%.*]] = alloca { half, half }, align 2
// AVX-NEXT: [[B:%.*]] = alloca { half, half }, align 2
// AVX-NEXT: [[A_ADDR:%.*]] = alloca half, align 2
// AVX-NEXT: [[COERCE:%.*]] = alloca { half, half }, align 2
// AVX-NEXT: store <2 x half> [[B_COERCE:%.*]], ptr [[B]], align 2
// AVX-NEXT: store half [[A:%.*]], ptr [[A_ADDR]], align 2
// AVX-NEXT: [[TMP0:%.*]] = load half, ptr [[A_ADDR]], align 2
// AVX-NEXT: [[B_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[B]], i32 0, i32 0
// AVX-NEXT: [[B_REAL:%.*]] = load half, ptr [[B_REALP]], align 2
// AVX-NEXT: [[B_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[B]], i32 0, i32 1
// AVX-NEXT: [[B_IMAG:%.*]] = load half, ptr [[B_IMAGP]], align 2
// AVX-NEXT: [[CALL:%.*]] = call <2 x half> @__divhc3(half noundef [[TMP0]], half noundef 0xH0000, half noundef [[B_REAL]], half noundef [[B_IMAG]]) #[[ATTR1]]
// AVX-NEXT: store <2 x half> [[CALL]], ptr [[COERCE]], align 2
// AVX-NEXT: [[COERCE_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[COERCE]], i32 0, i32 0
// AVX-NEXT: [[COERCE_REAL:%.*]] = load half, ptr [[COERCE_REALP]], align 2
// AVX-NEXT: [[COERCE_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[COERCE]], i32 0, i32 1
// AVX-NEXT: [[COERCE_IMAG:%.*]] = load half, ptr [[COERCE_IMAGP]], align 2
// AVX-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 0
// AVX-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 1
// AVX-NEXT: store half [[COERCE_REAL]], ptr [[RETVAL_REALP]], align 2
// AVX-NEXT: store half [[COERCE_IMAG]], ptr [[RETVAL_IMAGP]], align 2
// AVX-NEXT: [[TMP1:%.*]] = load <2 x half>, ptr [[RETVAL]], align 2
// AVX-NEXT: ret <2 x half> [[TMP1]]
//
// X86-LABEL: @div_half_rc(
// X86-NEXT: entry:
// X86-NEXT: [[RETVAL:%.*]] = alloca { half, half }, align 2
// X86-NEXT: [[B:%.*]] = alloca { half, half }, align 2
// X86-NEXT: [[A_ADDR:%.*]] = alloca half, align 2
// X86-NEXT: [[COERCE:%.*]] = alloca { float, float }, align 4
// X86-NEXT: store <2 x half> [[B_COERCE:%.*]], ptr [[B]], align 2
// X86-NEXT: store half [[A:%.*]], ptr [[A_ADDR]], align 2
// X86-NEXT: [[TMP0:%.*]] = load half, ptr [[A_ADDR]], align 2
// X86-NEXT: [[EXT:%.*]] = fpext half [[TMP0]] to float
// X86-NEXT: [[B_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[B]], i32 0, i32 0
// X86-NEXT: [[B_REAL:%.*]] = load half, ptr [[B_REALP]], align 2
// X86-NEXT: [[B_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[B]], i32 0, i32 1
// X86-NEXT: [[B_IMAG:%.*]] = load half, ptr [[B_IMAGP]], align 2
// X86-NEXT: [[EXT1:%.*]] = fpext half [[B_REAL]] to float
// X86-NEXT: [[EXT2:%.*]] = fpext half [[B_IMAG]] to float
// X86-NEXT: [[CALL:%.*]] = call <2 x float> @__divsc3(float noundef [[EXT]], float noundef 0.000000e+00, float noundef [[EXT1]], float noundef [[EXT2]]) #[[ATTR2]]
// X86-NEXT: store <2 x float> [[CALL]], ptr [[COERCE]], align 4
// X86-NEXT: [[COERCE_REALP:%.*]] = getelementptr inbounds { float, float }, ptr [[COERCE]], i32 0, i32 0
// X86-NEXT: [[COERCE_REAL:%.*]] = load float, ptr [[COERCE_REALP]], align 4
// X86-NEXT: [[COERCE_IMAGP:%.*]] = getelementptr inbounds { float, float }, ptr [[COERCE]], i32 0, i32 1
// X86-NEXT: [[COERCE_IMAG:%.*]] = load float, ptr [[COERCE_IMAGP]], align 4
// X86-NEXT: [[UNPROMOTION:%.*]] = fptrunc float [[COERCE_REAL]] to half
// X86-NEXT: [[UNPROMOTION3:%.*]] = fptrunc float [[COERCE_IMAG]] to half
// X86-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 0
// X86-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 1
// X86-NEXT: store half [[UNPROMOTION]], ptr [[RETVAL_REALP]], align 2
// X86-NEXT: store half [[UNPROMOTION3]], ptr [[RETVAL_IMAGP]], align 2
// X86-NEXT: [[TMP1:%.*]] = load <2 x half>, ptr [[RETVAL]], align 2
// X86-NEXT: ret <2 x half> [[TMP1]]
//
_Float16 _Complex div_half_rc(_Float16 a, _Float16 _Complex b) {
return a / b;
}
// AVX-LABEL: @div_half_cc(
// AVX-NEXT: entry:
// AVX-NEXT: [[RETVAL:%.*]] = alloca { half, half }, align 2
// AVX-NEXT: [[A:%.*]] = alloca { half, half }, align 2
// AVX-NEXT: [[B:%.*]] = alloca { half, half }, align 2
// AVX-NEXT: [[COERCE:%.*]] = alloca { half, half }, align 2
// AVX-NEXT: store <2 x half> [[A_COERCE:%.*]], ptr [[A]], align 2
// AVX-NEXT: store <2 x half> [[B_COERCE:%.*]], ptr [[B]], align 2
// AVX-NEXT: [[A_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[A]], i32 0, i32 0
// AVX-NEXT: [[A_REAL:%.*]] = load half, ptr [[A_REALP]], align 2
// AVX-NEXT: [[A_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[A]], i32 0, i32 1
// AVX-NEXT: [[A_IMAG:%.*]] = load half, ptr [[A_IMAGP]], align 2
// AVX-NEXT: [[B_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[B]], i32 0, i32 0
// AVX-NEXT: [[B_REAL:%.*]] = load half, ptr [[B_REALP]], align 2
// AVX-NEXT: [[B_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[B]], i32 0, i32 1
// AVX-NEXT: [[B_IMAG:%.*]] = load half, ptr [[B_IMAGP]], align 2
// AVX-NEXT: [[CALL:%.*]] = call <2 x half> @__divhc3(half noundef [[A_REAL]], half noundef [[A_IMAG]], half noundef [[B_REAL]], half noundef [[B_IMAG]]) #[[ATTR1]]
// AVX-NEXT: store <2 x half> [[CALL]], ptr [[COERCE]], align 2
// AVX-NEXT: [[COERCE_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[COERCE]], i32 0, i32 0
// AVX-NEXT: [[COERCE_REAL:%.*]] = load half, ptr [[COERCE_REALP]], align 2
// AVX-NEXT: [[COERCE_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[COERCE]], i32 0, i32 1
// AVX-NEXT: [[COERCE_IMAG:%.*]] = load half, ptr [[COERCE_IMAGP]], align 2
// AVX-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 0
// AVX-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 1
// AVX-NEXT: store half [[COERCE_REAL]], ptr [[RETVAL_REALP]], align 2
// AVX-NEXT: store half [[COERCE_IMAG]], ptr [[RETVAL_IMAGP]], align 2
// AVX-NEXT: [[TMP0:%.*]] = load <2 x half>, ptr [[RETVAL]], align 2
// AVX-NEXT: ret <2 x half> [[TMP0]]
//
// X86-LABEL: @div_half_cc(
// X86-NEXT: entry:
// X86-NEXT: [[RETVAL:%.*]] = alloca { half, half }, align 2
// X86-NEXT: [[A:%.*]] = alloca { half, half }, align 2
// X86-NEXT: [[B:%.*]] = alloca { half, half }, align 2
// X86-NEXT: [[COERCE:%.*]] = alloca { float, float }, align 4
// X86-NEXT: store <2 x half> [[A_COERCE:%.*]], ptr [[A]], align 2
// X86-NEXT: store <2 x half> [[B_COERCE:%.*]], ptr [[B]], align 2
// X86-NEXT: [[A_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[A]], i32 0, i32 0
// X86-NEXT: [[A_REAL:%.*]] = load half, ptr [[A_REALP]], align 2
// X86-NEXT: [[A_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[A]], i32 0, i32 1
// X86-NEXT: [[A_IMAG:%.*]] = load half, ptr [[A_IMAGP]], align 2
// X86-NEXT: [[EXT:%.*]] = fpext half [[A_REAL]] to float
// X86-NEXT: [[EXT1:%.*]] = fpext half [[A_IMAG]] to float
// X86-NEXT: [[B_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[B]], i32 0, i32 0
// X86-NEXT: [[B_REAL:%.*]] = load half, ptr [[B_REALP]], align 2
// X86-NEXT: [[B_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[B]], i32 0, i32 1
// X86-NEXT: [[B_IMAG:%.*]] = load half, ptr [[B_IMAGP]], align 2
// X86-NEXT: [[EXT2:%.*]] = fpext half [[B_REAL]] to float
// X86-NEXT: [[EXT3:%.*]] = fpext half [[B_IMAG]] to float
// X86-NEXT: [[CALL:%.*]] = call <2 x float> @__divsc3(float noundef [[EXT]], float noundef [[EXT1]], float noundef [[EXT2]], float noundef [[EXT3]]) #[[ATTR2]]
// X86-NEXT: store <2 x float> [[CALL]], ptr [[COERCE]], align 4
// X86-NEXT: [[COERCE_REALP:%.*]] = getelementptr inbounds { float, float }, ptr [[COERCE]], i32 0, i32 0
// X86-NEXT: [[COERCE_REAL:%.*]] = load float, ptr [[COERCE_REALP]], align 4
// X86-NEXT: [[COERCE_IMAGP:%.*]] = getelementptr inbounds { float, float }, ptr [[COERCE]], i32 0, i32 1
// X86-NEXT: [[COERCE_IMAG:%.*]] = load float, ptr [[COERCE_IMAGP]], align 4
// X86-NEXT: [[UNPROMOTION:%.*]] = fptrunc float [[COERCE_REAL]] to half
// X86-NEXT: [[UNPROMOTION4:%.*]] = fptrunc float [[COERCE_IMAG]] to half
// X86-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 0
// X86-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 1
// X86-NEXT: store half [[UNPROMOTION]], ptr [[RETVAL_REALP]], align 2
// X86-NEXT: store half [[UNPROMOTION4]], ptr [[RETVAL_IMAGP]], align 2
// X86-NEXT: [[TMP0:%.*]] = load <2 x half>, ptr [[RETVAL]], align 2
// X86-NEXT: ret <2 x half> [[TMP0]]
//
_Float16 _Complex div_half_cc(_Float16 _Complex a, _Float16 _Complex b) {
return a / b;
}
// AVX-LABEL: @addcompound_half_rr(
// AVX-NEXT: entry:
// AVX-NEXT: [[RETVAL:%.*]] = alloca { half, half }, align 2
// AVX-NEXT: [[A_ADDR:%.*]] = alloca half, align 2
// AVX-NEXT: [[C_ADDR:%.*]] = alloca half, align 2
// AVX-NEXT: store half [[A:%.*]], ptr [[A_ADDR]], align 2
// AVX-NEXT: store half [[C:%.*]], ptr [[C_ADDR]], align 2
// AVX-NEXT: [[TMP0:%.*]] = load half, ptr [[A_ADDR]], align 2
// AVX-NEXT: [[TMP1:%.*]] = load half, ptr [[C_ADDR]], align 2
// AVX-NEXT: [[ADD:%.*]] = fadd half [[TMP1]], [[TMP0]]
// AVX-NEXT: store half [[ADD]], ptr [[C_ADDR]], align 2
// AVX-NEXT: [[TMP2:%.*]] = load half, ptr [[C_ADDR]], align 2
// AVX-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 0
// AVX-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 1
// AVX-NEXT: store half [[TMP2]], ptr [[RETVAL_REALP]], align 2
// AVX-NEXT: store half 0xH0000, ptr [[RETVAL_IMAGP]], align 2
// AVX-NEXT: [[TMP3:%.*]] = load <2 x half>, ptr [[RETVAL]], align 2
// AVX-NEXT: ret <2 x half> [[TMP3]]
//
// X86-LABEL: @addcompound_half_rr(
// X86-NEXT: entry:
// X86-NEXT: [[RETVAL:%.*]] = alloca { half, half }, align 2
// X86-NEXT: [[A_ADDR:%.*]] = alloca half, align 2
// X86-NEXT: [[C_ADDR:%.*]] = alloca half, align 2
// X86-NEXT: store half [[A:%.*]], ptr [[A_ADDR]], align 2
// X86-NEXT: store half [[C:%.*]], ptr [[C_ADDR]], align 2
// X86-NEXT: [[TMP0:%.*]] = load half, ptr [[A_ADDR]], align 2
// X86-NEXT: [[EXT:%.*]] = fpext half [[TMP0]] to float
// X86-NEXT: [[TMP1:%.*]] = load half, ptr [[C_ADDR]], align 2
// X86-NEXT: [[CONV:%.*]] = fpext half [[TMP1]] to float
// X86-NEXT: [[ADD:%.*]] = fadd float [[CONV]], [[EXT]]
// X86-NEXT: [[CONV1:%.*]] = fptrunc float [[ADD]] to half
// X86-NEXT: store half [[CONV1]], ptr [[C_ADDR]], align 2
// X86-NEXT: [[TMP2:%.*]] = load half, ptr [[C_ADDR]], align 2
// X86-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 0
// X86-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 1
// X86-NEXT: store half [[TMP2]], ptr [[RETVAL_REALP]], align 2
// X86-NEXT: store half 0xH0000, ptr [[RETVAL_IMAGP]], align 2
// X86-NEXT: [[TMP3:%.*]] = load <2 x half>, ptr [[RETVAL]], align 2
// X86-NEXT: ret <2 x half> [[TMP3]]
//
_Float16 _Complex addcompound_half_rr(_Float16 a, _Float16 c) {
c += a;
return c;
}
// AVX-LABEL: @addcompound_half_cr(
// AVX-NEXT: entry:
// AVX-NEXT: [[RETVAL:%.*]] = alloca { half, half }, align 2
// AVX-NEXT: [[A:%.*]] = alloca { half, half }, align 2
// AVX-NEXT: [[C_ADDR:%.*]] = alloca half, align 2
// AVX-NEXT: store <2 x half> [[A_COERCE:%.*]], ptr [[A]], align 2
// AVX-NEXT: store half [[C:%.*]], ptr [[C_ADDR]], align 2
// AVX-NEXT: [[A_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[A]], i32 0, i32 0
// AVX-NEXT: [[A_REAL:%.*]] = load half, ptr [[A_REALP]], align 2
// AVX-NEXT: [[A_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[A]], i32 0, i32 1
// AVX-NEXT: [[A_IMAG:%.*]] = load half, ptr [[A_IMAGP]], align 2
// AVX-NEXT: [[TMP0:%.*]] = load half, ptr [[C_ADDR]], align 2
// AVX-NEXT: [[ADD_R:%.*]] = fadd half [[TMP0]], [[A_REAL]]
// AVX-NEXT: store half [[ADD_R]], ptr [[C_ADDR]], align 2
// AVX-NEXT: [[TMP1:%.*]] = load half, ptr [[C_ADDR]], align 2
// AVX-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 0
// AVX-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 1
// AVX-NEXT: store half [[TMP1]], ptr [[RETVAL_REALP]], align 2
// AVX-NEXT: store half 0xH0000, ptr [[RETVAL_IMAGP]], align 2
// AVX-NEXT: [[TMP2:%.*]] = load <2 x half>, ptr [[RETVAL]], align 2
// AVX-NEXT: ret <2 x half> [[TMP2]]
//
// X86-LABEL: @addcompound_half_cr(
// X86-NEXT: entry:
// X86-NEXT: [[RETVAL:%.*]] = alloca { half, half }, align 2
// X86-NEXT: [[A:%.*]] = alloca { half, half }, align 2
// X86-NEXT: [[C_ADDR:%.*]] = alloca half, align 2
// X86-NEXT: store <2 x half> [[A_COERCE:%.*]], ptr [[A]], align 2
// X86-NEXT: store half [[C:%.*]], ptr [[C_ADDR]], align 2
// X86-NEXT: [[A_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[A]], i32 0, i32 0
// X86-NEXT: [[A_REAL:%.*]] = load half, ptr [[A_REALP]], align 2
// X86-NEXT: [[A_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[A]], i32 0, i32 1
// X86-NEXT: [[A_IMAG:%.*]] = load half, ptr [[A_IMAGP]], align 2
// X86-NEXT: [[EXT:%.*]] = fpext half [[A_REAL]] to float
// X86-NEXT: [[EXT1:%.*]] = fpext half [[A_IMAG]] to float
// X86-NEXT: [[TMP0:%.*]] = load half, ptr [[C_ADDR]], align 2
// X86-NEXT: [[CONV:%.*]] = fpext half [[TMP0]] to float
// X86-NEXT: [[ADD_R:%.*]] = fadd float [[CONV]], [[EXT]]
// X86-NEXT: [[CONV2:%.*]] = fptrunc float [[ADD_R]] to half
// X86-NEXT: store half [[CONV2]], ptr [[C_ADDR]], align 2
// X86-NEXT: [[TMP1:%.*]] = load half, ptr [[C_ADDR]], align 2
// X86-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 0
// X86-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 1
// X86-NEXT: store half [[TMP1]], ptr [[RETVAL_REALP]], align 2
// X86-NEXT: store half 0xH0000, ptr [[RETVAL_IMAGP]], align 2
// X86-NEXT: [[TMP2:%.*]] = load <2 x half>, ptr [[RETVAL]], align 2
// X86-NEXT: ret <2 x half> [[TMP2]]
//
_Float16 _Complex addcompound_half_cr(_Float16 _Complex a, _Float16 c) {
c += a;
return c;
}
// AVX-LABEL: @addcompound_half_rc(
// AVX-NEXT: entry:
// AVX-NEXT: [[RETVAL:%.*]] = alloca { half, half }, align 2
// AVX-NEXT: [[C:%.*]] = alloca { half, half }, align 2
// AVX-NEXT: [[A_ADDR:%.*]] = alloca half, align 2
// AVX-NEXT: store <2 x half> [[C_COERCE:%.*]], ptr [[C]], align 2
// AVX-NEXT: store half [[A:%.*]], ptr [[A_ADDR]], align 2
// AVX-NEXT: [[TMP0:%.*]] = load half, ptr [[A_ADDR]], align 2
// AVX-NEXT: [[C_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[C]], i32 0, i32 0
// AVX-NEXT: [[C_REAL:%.*]] = load half, ptr [[C_REALP]], align 2
// AVX-NEXT: [[C_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[C]], i32 0, i32 1
// AVX-NEXT: [[C_IMAG:%.*]] = load half, ptr [[C_IMAGP]], align 2
// AVX-NEXT: [[ADD_R:%.*]] = fadd half [[C_REAL]], [[TMP0]]
// AVX-NEXT: [[C_REALP1:%.*]] = getelementptr inbounds { half, half }, ptr [[C]], i32 0, i32 0
// AVX-NEXT: [[C_IMAGP2:%.*]] = getelementptr inbounds { half, half }, ptr [[C]], i32 0, i32 1
// AVX-NEXT: store half [[ADD_R]], ptr [[C_REALP1]], align 2
// AVX-NEXT: store half [[C_IMAG]], ptr [[C_IMAGP2]], align 2
// AVX-NEXT: [[C_REALP3:%.*]] = getelementptr inbounds { half, half }, ptr [[C]], i32 0, i32 0
// AVX-NEXT: [[C_REAL4:%.*]] = load half, ptr [[C_REALP3]], align 2
// AVX-NEXT: [[C_IMAGP5:%.*]] = getelementptr inbounds { half, half }, ptr [[C]], i32 0, i32 1
// AVX-NEXT: [[C_IMAG6:%.*]] = load half, ptr [[C_IMAGP5]], align 2
// AVX-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 0
// AVX-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 1
// AVX-NEXT: store half [[C_REAL4]], ptr [[RETVAL_REALP]], align 2
// AVX-NEXT: store half [[C_IMAG6]], ptr [[RETVAL_IMAGP]], align 2
// AVX-NEXT: [[TMP1:%.*]] = load <2 x half>, ptr [[RETVAL]], align 2
// AVX-NEXT: ret <2 x half> [[TMP1]]
//
// X86-LABEL: @addcompound_half_rc(
// X86-NEXT: entry:
// X86-NEXT: [[RETVAL:%.*]] = alloca { half, half }, align 2
// X86-NEXT: [[C:%.*]] = alloca { half, half }, align 2
// X86-NEXT: [[A_ADDR:%.*]] = alloca half, align 2
// X86-NEXT: store <2 x half> [[C_COERCE:%.*]], ptr [[C]], align 2
// X86-NEXT: store half [[A:%.*]], ptr [[A_ADDR]], align 2
// X86-NEXT: [[TMP0:%.*]] = load half, ptr [[A_ADDR]], align 2
// X86-NEXT: [[EXT:%.*]] = fpext half [[TMP0]] to float
// X86-NEXT: [[C_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[C]], i32 0, i32 0
// X86-NEXT: [[C_REAL:%.*]] = load half, ptr [[C_REALP]], align 2
// X86-NEXT: [[C_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[C]], i32 0, i32 1
// X86-NEXT: [[C_IMAG:%.*]] = load half, ptr [[C_IMAGP]], align 2
// X86-NEXT: [[CONV:%.*]] = fpext half [[C_REAL]] to float
// X86-NEXT: [[CONV1:%.*]] = fpext half [[C_IMAG]] to float
// X86-NEXT: [[ADD_R:%.*]] = fadd float [[CONV]], [[EXT]]
// X86-NEXT: [[CONV2:%.*]] = fptrunc float [[ADD_R]] to half
// X86-NEXT: [[CONV3:%.*]] = fptrunc float [[CONV1]] to half
// X86-NEXT: [[C_REALP4:%.*]] = getelementptr inbounds { half, half }, ptr [[C]], i32 0, i32 0
// X86-NEXT: [[C_IMAGP5:%.*]] = getelementptr inbounds { half, half }, ptr [[C]], i32 0, i32 1
// X86-NEXT: store half [[CONV2]], ptr [[C_REALP4]], align 2
// X86-NEXT: store half [[CONV3]], ptr [[C_IMAGP5]], align 2
// X86-NEXT: [[C_REALP6:%.*]] = getelementptr inbounds { half, half }, ptr [[C]], i32 0, i32 0
// X86-NEXT: [[C_REAL7:%.*]] = load half, ptr [[C_REALP6]], align 2
// X86-NEXT: [[C_IMAGP8:%.*]] = getelementptr inbounds { half, half }, ptr [[C]], i32 0, i32 1
// X86-NEXT: [[C_IMAG9:%.*]] = load half, ptr [[C_IMAGP8]], align 2
// X86-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 0
// X86-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 1
// X86-NEXT: store half [[C_REAL7]], ptr [[RETVAL_REALP]], align 2
// X86-NEXT: store half [[C_IMAG9]], ptr [[RETVAL_IMAGP]], align 2
// X86-NEXT: [[TMP1:%.*]] = load <2 x half>, ptr [[RETVAL]], align 2
// X86-NEXT: ret <2 x half> [[TMP1]]
//
_Float16 _Complex addcompound_half_rc(_Float16 a, _Float16 _Complex c) {
c += a;
return c;
}
// AVX-LABEL: @addcompound_half_cc(
// AVX-NEXT: entry:
// AVX-NEXT: [[RETVAL:%.*]] = alloca { half, half }, align 2
// AVX-NEXT: [[A:%.*]] = alloca { half, half }, align 2
// AVX-NEXT: [[C:%.*]] = alloca { half, half }, align 2
// AVX-NEXT: store <2 x half> [[A_COERCE:%.*]], ptr [[A]], align 2
// AVX-NEXT: store <2 x half> [[C_COERCE:%.*]], ptr [[C]], align 2
// AVX-NEXT: [[A_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[A]], i32 0, i32 0
// AVX-NEXT: [[A_REAL:%.*]] = load half, ptr [[A_REALP]], align 2
// AVX-NEXT: [[A_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[A]], i32 0, i32 1
// AVX-NEXT: [[A_IMAG:%.*]] = load half, ptr [[A_IMAGP]], align 2
// AVX-NEXT: [[C_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[C]], i32 0, i32 0
// AVX-NEXT: [[C_REAL:%.*]] = load half, ptr [[C_REALP]], align 2
// AVX-NEXT: [[C_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[C]], i32 0, i32 1
// AVX-NEXT: [[C_IMAG:%.*]] = load half, ptr [[C_IMAGP]], align 2
// AVX-NEXT: [[ADD_R:%.*]] = fadd half [[C_REAL]], [[A_REAL]]
// AVX-NEXT: [[ADD_I:%.*]] = fadd half [[C_IMAG]], [[A_IMAG]]
// AVX-NEXT: [[C_REALP1:%.*]] = getelementptr inbounds { half, half }, ptr [[C]], i32 0, i32 0
// AVX-NEXT: [[C_IMAGP2:%.*]] = getelementptr inbounds { half, half }, ptr [[C]], i32 0, i32 1
// AVX-NEXT: store half [[ADD_R]], ptr [[C_REALP1]], align 2
// AVX-NEXT: store half [[ADD_I]], ptr [[C_IMAGP2]], align 2
// AVX-NEXT: [[C_REALP3:%.*]] = getelementptr inbounds { half, half }, ptr [[C]], i32 0, i32 0
// AVX-NEXT: [[C_REAL4:%.*]] = load half, ptr [[C_REALP3]], align 2
// AVX-NEXT: [[C_IMAGP5:%.*]] = getelementptr inbounds { half, half }, ptr [[C]], i32 0, i32 1
// AVX-NEXT: [[C_IMAG6:%.*]] = load half, ptr [[C_IMAGP5]], align 2
// AVX-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 0
// AVX-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 1
// AVX-NEXT: store half [[C_REAL4]], ptr [[RETVAL_REALP]], align 2
// AVX-NEXT: store half [[C_IMAG6]], ptr [[RETVAL_IMAGP]], align 2
// AVX-NEXT: [[TMP0:%.*]] = load <2 x half>, ptr [[RETVAL]], align 2
// AVX-NEXT: ret <2 x half> [[TMP0]]
//
// X86-LABEL: @addcompound_half_cc(
// X86-NEXT: entry:
// X86-NEXT: [[RETVAL:%.*]] = alloca { half, half }, align 2
// X86-NEXT: [[A:%.*]] = alloca { half, half }, align 2
// X86-NEXT: [[C:%.*]] = alloca { half, half }, align 2
// X86-NEXT: store <2 x half> [[A_COERCE:%.*]], ptr [[A]], align 2
// X86-NEXT: store <2 x half> [[C_COERCE:%.*]], ptr [[C]], align 2
// X86-NEXT: [[A_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[A]], i32 0, i32 0
// X86-NEXT: [[A_REAL:%.*]] = load half, ptr [[A_REALP]], align 2
// X86-NEXT: [[A_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[A]], i32 0, i32 1
// X86-NEXT: [[A_IMAG:%.*]] = load half, ptr [[A_IMAGP]], align 2
// X86-NEXT: [[EXT:%.*]] = fpext half [[A_REAL]] to float
// X86-NEXT: [[EXT1:%.*]] = fpext half [[A_IMAG]] to float
// X86-NEXT: [[C_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[C]], i32 0, i32 0
// X86-NEXT: [[C_REAL:%.*]] = load half, ptr [[C_REALP]], align 2
// X86-NEXT: [[C_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[C]], i32 0, i32 1
// X86-NEXT: [[C_IMAG:%.*]] = load half, ptr [[C_IMAGP]], align 2
// X86-NEXT: [[CONV:%.*]] = fpext half [[C_REAL]] to float
// X86-NEXT: [[CONV2:%.*]] = fpext half [[C_IMAG]] to float
// X86-NEXT: [[ADD_R:%.*]] = fadd float [[CONV]], [[EXT]]
// X86-NEXT: [[ADD_I:%.*]] = fadd float [[CONV2]], [[EXT1]]
// X86-NEXT: [[CONV3:%.*]] = fptrunc float [[ADD_R]] to half
// X86-NEXT: [[CONV4:%.*]] = fptrunc float [[ADD_I]] to half
// X86-NEXT: [[C_REALP5:%.*]] = getelementptr inbounds { half, half }, ptr [[C]], i32 0, i32 0
// X86-NEXT: [[C_IMAGP6:%.*]] = getelementptr inbounds { half, half }, ptr [[C]], i32 0, i32 1
// X86-NEXT: store half [[CONV3]], ptr [[C_REALP5]], align 2
// X86-NEXT: store half [[CONV4]], ptr [[C_IMAGP6]], align 2
// X86-NEXT: [[C_REALP7:%.*]] = getelementptr inbounds { half, half }, ptr [[C]], i32 0, i32 0
// X86-NEXT: [[C_REAL8:%.*]] = load half, ptr [[C_REALP7]], align 2
// X86-NEXT: [[C_IMAGP9:%.*]] = getelementptr inbounds { half, half }, ptr [[C]], i32 0, i32 1
// X86-NEXT: [[C_IMAG10:%.*]] = load half, ptr [[C_IMAGP9]], align 2
// X86-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 0
// X86-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 1
// X86-NEXT: store half [[C_REAL8]], ptr [[RETVAL_REALP]], align 2
// X86-NEXT: store half [[C_IMAG10]], ptr [[RETVAL_IMAGP]], align 2
// X86-NEXT: [[TMP0:%.*]] = load <2 x half>, ptr [[RETVAL]], align 2
// X86-NEXT: ret <2 x half> [[TMP0]]
//
_Float16 _Complex addcompound_half_cc(_Float16 _Complex a, _Float16 _Complex c) {
c += a;
return c;
}
// AVX-LABEL: @MinusOp_r(
// AVX-NEXT: entry:
// AVX-NEXT: [[RETVAL:%.*]] = alloca { half, half }, align 2
// AVX-NEXT: [[A_ADDR:%.*]] = alloca half, align 2
// AVX-NEXT: store half [[A:%.*]], ptr [[A_ADDR]], align 2
// AVX-NEXT: [[TMP0:%.*]] = load half, ptr [[A_ADDR]], align 2
// AVX-NEXT: [[FNEG:%.*]] = fneg half [[TMP0]]
// AVX-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 0
// AVX-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 1
// AVX-NEXT: store half [[FNEG]], ptr [[RETVAL_REALP]], align 2
// AVX-NEXT: store half 0xH0000, ptr [[RETVAL_IMAGP]], align 2
// AVX-NEXT: [[TMP1:%.*]] = load <2 x half>, ptr [[RETVAL]], align 2
// AVX-NEXT: ret <2 x half> [[TMP1]]
//
// X86-LABEL: @MinusOp_r(
// X86-NEXT: entry:
// X86-NEXT: [[RETVAL:%.*]] = alloca { half, half }, align 2
// X86-NEXT: [[A_ADDR:%.*]] = alloca half, align 2
// X86-NEXT: store half [[A:%.*]], ptr [[A_ADDR]], align 2
// X86-NEXT: [[TMP0:%.*]] = load half, ptr [[A_ADDR]], align 2
// X86-NEXT: [[EXT:%.*]] = fpext half [[TMP0]] to float
// X86-NEXT: [[FNEG:%.*]] = fneg float [[EXT]]
// X86-NEXT: [[UNPROMOTION:%.*]] = fptrunc float [[FNEG]] to half
// X86-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 0
// X86-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 1
// X86-NEXT: store half [[UNPROMOTION]], ptr [[RETVAL_REALP]], align 2
// X86-NEXT: store half 0xH0000, ptr [[RETVAL_IMAGP]], align 2
// X86-NEXT: [[TMP1:%.*]] = load <2 x half>, ptr [[RETVAL]], align 2
// X86-NEXT: ret <2 x half> [[TMP1]]
//
_Float16 _Complex MinusOp_r(_Float16 a) {
return -a;
}
// AVX-LABEL: @MinusOp_c(
// AVX-NEXT: entry:
// AVX-NEXT: [[RETVAL:%.*]] = alloca { half, half }, align 2
// AVX-NEXT: [[A:%.*]] = alloca { half, half }, align 2
// AVX-NEXT: store <2 x half> [[A_COERCE:%.*]], ptr [[A]], align 2
// AVX-NEXT: [[A_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[A]], i32 0, i32 0
// AVX-NEXT: [[A_REAL:%.*]] = load half, ptr [[A_REALP]], align 2
// AVX-NEXT: [[A_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[A]], i32 0, i32 1
// AVX-NEXT: [[A_IMAG:%.*]] = load half, ptr [[A_IMAGP]], align 2
// AVX-NEXT: [[NEG_R:%.*]] = fneg half [[A_REAL]]
// AVX-NEXT: [[NEG_I:%.*]] = fneg half [[A_IMAG]]
// AVX-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 0
// AVX-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 1
// AVX-NEXT: store half [[NEG_R]], ptr [[RETVAL_REALP]], align 2
// AVX-NEXT: store half [[NEG_I]], ptr [[RETVAL_IMAGP]], align 2
// AVX-NEXT: [[TMP0:%.*]] = load <2 x half>, ptr [[RETVAL]], align 2
// AVX-NEXT: ret <2 x half> [[TMP0]]
//
// X86-LABEL: @MinusOp_c(
// X86-NEXT: entry:
// X86-NEXT: [[RETVAL:%.*]] = alloca { half, half }, align 2
// X86-NEXT: [[A:%.*]] = alloca { half, half }, align 2
// X86-NEXT: store <2 x half> [[A_COERCE:%.*]], ptr [[A]], align 2
// X86-NEXT: [[A_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[A]], i32 0, i32 0
// X86-NEXT: [[A_REAL:%.*]] = load half, ptr [[A_REALP]], align 2
// X86-NEXT: [[A_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[A]], i32 0, i32 1
// X86-NEXT: [[A_IMAG:%.*]] = load half, ptr [[A_IMAGP]], align 2
// X86-NEXT: [[EXT:%.*]] = fpext half [[A_REAL]] to float
// X86-NEXT: [[EXT1:%.*]] = fpext half [[A_IMAG]] to float
// X86-NEXT: [[NEG_R:%.*]] = fneg float [[EXT]]
// X86-NEXT: [[NEG_I:%.*]] = fneg float [[EXT1]]
// X86-NEXT: [[UNPROMOTION:%.*]] = fptrunc float [[NEG_R]] to half
// X86-NEXT: [[UNPROMOTION2:%.*]] = fptrunc float [[NEG_I]] to half
// X86-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 0
// X86-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 1
// X86-NEXT: store half [[UNPROMOTION]], ptr [[RETVAL_REALP]], align 2
// X86-NEXT: store half [[UNPROMOTION2]], ptr [[RETVAL_IMAGP]], align 2
// X86-NEXT: [[TMP0:%.*]] = load <2 x half>, ptr [[RETVAL]], align 2
// X86-NEXT: ret <2 x half> [[TMP0]]
//
_Float16 _Complex MinusOp_c(_Float16 _Complex a) {
return -a;
}
// AVX-LABEL: @PlusOp_r(
// AVX-NEXT: entry:
// AVX-NEXT: [[RETVAL:%.*]] = alloca { half, half }, align 2
// AVX-NEXT: [[A_ADDR:%.*]] = alloca half, align 2
// AVX-NEXT: store half [[A:%.*]], ptr [[A_ADDR]], align 2
// AVX-NEXT: [[TMP0:%.*]] = load half, ptr [[A_ADDR]], align 2
// AVX-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 0
// AVX-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 1
// AVX-NEXT: store half [[TMP0]], ptr [[RETVAL_REALP]], align 2
// AVX-NEXT: store half 0xH0000, ptr [[RETVAL_IMAGP]], align 2
// AVX-NEXT: [[TMP1:%.*]] = load <2 x half>, ptr [[RETVAL]], align 2
// AVX-NEXT: ret <2 x half> [[TMP1]]
//
// X86-LABEL: @PlusOp_r(
// X86-NEXT: entry:
// X86-NEXT: [[RETVAL:%.*]] = alloca { half, half }, align 2
// X86-NEXT: [[A_ADDR:%.*]] = alloca half, align 2
// X86-NEXT: store half [[A:%.*]], ptr [[A_ADDR]], align 2
// X86-NEXT: [[TMP0:%.*]] = load half, ptr [[A_ADDR]], align 2
// X86-NEXT: [[EXT:%.*]] = fpext half [[TMP0]] to float
// X86-NEXT: [[UNPROMOTION:%.*]] = fptrunc float [[EXT]] to half
// X86-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 0
// X86-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 1
// X86-NEXT: store half [[UNPROMOTION]], ptr [[RETVAL_REALP]], align 2
// X86-NEXT: store half 0xH0000, ptr [[RETVAL_IMAGP]], align 2
// X86-NEXT: [[TMP1:%.*]] = load <2 x half>, ptr [[RETVAL]], align 2
// X86-NEXT: ret <2 x half> [[TMP1]]
//
_Float16 _Complex PlusOp_r(_Float16 a) {
return +a;
}
// AVX-LABEL: @PlusOp_c(
// AVX-NEXT: entry:
// AVX-NEXT: [[RETVAL:%.*]] = alloca { half, half }, align 2
// AVX-NEXT: [[A:%.*]] = alloca { half, half }, align 2
// AVX-NEXT: store <2 x half> [[A_COERCE:%.*]], ptr [[A]], align 2
// AVX-NEXT: [[A_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[A]], i32 0, i32 0
// AVX-NEXT: [[A_REAL:%.*]] = load half, ptr [[A_REALP]], align 2
// AVX-NEXT: [[A_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[A]], i32 0, i32 1
// AVX-NEXT: [[A_IMAG:%.*]] = load half, ptr [[A_IMAGP]], align 2
// AVX-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 0
// AVX-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 1
// AVX-NEXT: store half [[A_REAL]], ptr [[RETVAL_REALP]], align 2
// AVX-NEXT: store half [[A_IMAG]], ptr [[RETVAL_IMAGP]], align 2
// AVX-NEXT: [[TMP0:%.*]] = load <2 x half>, ptr [[RETVAL]], align 2
// AVX-NEXT: ret <2 x half> [[TMP0]]
//
// X86-LABEL: @PlusOp_c(
// X86-NEXT: entry:
// X86-NEXT: [[RETVAL:%.*]] = alloca { half, half }, align 2
// X86-NEXT: [[A:%.*]] = alloca { half, half }, align 2
// X86-NEXT: store <2 x half> [[A_COERCE:%.*]], ptr [[A]], align 2
// X86-NEXT: [[A_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[A]], i32 0, i32 0
// X86-NEXT: [[A_REAL:%.*]] = load half, ptr [[A_REALP]], align 2
// X86-NEXT: [[A_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[A]], i32 0, i32 1
// X86-NEXT: [[A_IMAG:%.*]] = load half, ptr [[A_IMAGP]], align 2
// X86-NEXT: [[EXT:%.*]] = fpext half [[A_REAL]] to float
// X86-NEXT: [[EXT1:%.*]] = fpext half [[A_IMAG]] to float
// X86-NEXT: [[UNPROMOTION:%.*]] = fptrunc float [[EXT]] to half
// X86-NEXT: [[UNPROMOTION2:%.*]] = fptrunc float [[EXT1]] to half
// X86-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 0
// X86-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 1
// X86-NEXT: store half [[UNPROMOTION]], ptr [[RETVAL_REALP]], align 2
// X86-NEXT: store half [[UNPROMOTION2]], ptr [[RETVAL_IMAGP]], align 2
// X86-NEXT: [[TMP0:%.*]] = load <2 x half>, ptr [[RETVAL]], align 2
// X86-NEXT: ret <2 x half> [[TMP0]]
//
_Float16 _Complex PlusOp_c(_Float16 _Complex a) {
return +a;
}
// AVX-LABEL: @RealOp_r(
// AVX-NEXT: entry:
// AVX-NEXT: [[RETVAL:%.*]] = alloca { half, half }, align 2
// AVX-NEXT: [[A_ADDR:%.*]] = alloca half, align 2
// AVX-NEXT: store half [[A:%.*]], ptr [[A_ADDR]], align 2
// AVX-NEXT: [[TMP0:%.*]] = load half, ptr [[A_ADDR]], align 2
// AVX-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 0
// AVX-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 1
// AVX-NEXT: store half [[TMP0]], ptr [[RETVAL_REALP]], align 2
// AVX-NEXT: store half 0xH0000, ptr [[RETVAL_IMAGP]], align 2
// AVX-NEXT: [[TMP1:%.*]] = load <2 x half>, ptr [[RETVAL]], align 2
// AVX-NEXT: ret <2 x half> [[TMP1]]
//
// X86-LABEL: @RealOp_r(
// X86-NEXT: entry:
// X86-NEXT: [[RETVAL:%.*]] = alloca { half, half }, align 2
// X86-NEXT: [[A_ADDR:%.*]] = alloca half, align 2
// X86-NEXT: store half [[A:%.*]], ptr [[A_ADDR]], align 2
// X86-NEXT: [[TMP0:%.*]] = load half, ptr [[A_ADDR]], align 2
// X86-NEXT: [[EXT:%.*]] = fpext half [[TMP0]] to float
// X86-NEXT: [[UNPROMOTION:%.*]] = fptrunc float [[EXT]] to half
// X86-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 0
// X86-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 1
// X86-NEXT: store half [[UNPROMOTION]], ptr [[RETVAL_REALP]], align 2
// X86-NEXT: store half 0xH0000, ptr [[RETVAL_IMAGP]], align 2
// X86-NEXT: [[TMP1:%.*]] = load <2 x half>, ptr [[RETVAL]], align 2
// X86-NEXT: ret <2 x half> [[TMP1]]
//
_Float16 _Complex RealOp_r(_Float16 a) {
return +a;
}
// AVX-LABEL: @RealOp_c(
// AVX-NEXT: entry:
// AVX-NEXT: [[RETVAL:%.*]] = alloca { half, half }, align 2
// AVX-NEXT: [[A:%.*]] = alloca { half, half }, align 2
// AVX-NEXT: store <2 x half> [[A_COERCE:%.*]], ptr [[A]], align 2
// AVX-NEXT: [[A_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[A]], i32 0, i32 0
// AVX-NEXT: [[TMP0:%.*]] = load half, ptr [[A_REALP]], align 2
// AVX-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 0
// AVX-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 1
// AVX-NEXT: store half [[TMP0]], ptr [[RETVAL_REALP]], align 2
// AVX-NEXT: store half 0xH0000, ptr [[RETVAL_IMAGP]], align 2
// AVX-NEXT: [[TMP1:%.*]] = load <2 x half>, ptr [[RETVAL]], align 2
// AVX-NEXT: ret <2 x half> [[TMP1]]
//
// X86-LABEL: @RealOp_c(
// X86-NEXT: entry:
// X86-NEXT: [[RETVAL:%.*]] = alloca { half, half }, align 2
// X86-NEXT: [[A:%.*]] = alloca { half, half }, align 2
// X86-NEXT: store <2 x half> [[A_COERCE:%.*]], ptr [[A]], align 2
// X86-NEXT: [[A_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[A]], i32 0, i32 0
// X86-NEXT: [[A_REAL:%.*]] = load half, ptr [[A_REALP]], align 2
// X86-NEXT: [[EXT:%.*]] = fpext half [[A_REAL]] to float
// X86-NEXT: [[UNPROMOTION:%.*]] = fptrunc float [[EXT]] to half
// X86-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 0
// X86-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 1
// X86-NEXT: store half [[UNPROMOTION]], ptr [[RETVAL_REALP]], align 2
// X86-NEXT: store half 0xH0000, ptr [[RETVAL_IMAGP]], align 2
// X86-NEXT: [[TMP0:%.*]] = load <2 x half>, ptr [[RETVAL]], align 2
// X86-NEXT: ret <2 x half> [[TMP0]]
//
_Float16 _Complex RealOp_c(_Float16 _Complex a) {
return __real a;
}
// AVX-LABEL: @ImagOp_r(
// AVX-NEXT: entry:
// AVX-NEXT: [[RETVAL:%.*]] = alloca { half, half }, align 2
// AVX-NEXT: [[A_ADDR:%.*]] = alloca half, align 2
// AVX-NEXT: store half [[A:%.*]], ptr [[A_ADDR]], align 2
// AVX-NEXT: [[TMP0:%.*]] = load half, ptr [[A_ADDR]], align 2
// AVX-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 0
// AVX-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 1
// AVX-NEXT: store half 0xH0000, ptr [[RETVAL_REALP]], align 2
// AVX-NEXT: store half 0xH0000, ptr [[RETVAL_IMAGP]], align 2
// AVX-NEXT: [[TMP1:%.*]] = load <2 x half>, ptr [[RETVAL]], align 2
// AVX-NEXT: ret <2 x half> [[TMP1]]
//
// X86-LABEL: @ImagOp_r(
// X86-NEXT: entry:
// X86-NEXT: [[RETVAL:%.*]] = alloca { half, half }, align 2
// X86-NEXT: [[A_ADDR:%.*]] = alloca half, align 2
// X86-NEXT: store half [[A:%.*]], ptr [[A_ADDR]], align 2
// X86-NEXT: [[TMP0:%.*]] = load half, ptr [[A_ADDR]], align 2
// X86-NEXT: [[EXT:%.*]] = fpext half [[TMP0]] to float
// X86-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 0
// X86-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 1
// X86-NEXT: store half 0xH0000, ptr [[RETVAL_REALP]], align 2
// X86-NEXT: store half 0xH0000, ptr [[RETVAL_IMAGP]], align 2
// X86-NEXT: [[TMP1:%.*]] = load <2 x half>, ptr [[RETVAL]], align 2
// X86-NEXT: ret <2 x half> [[TMP1]]
//
_Float16 _Complex ImagOp_r(_Float16 a) {
return __imag a;
}
// AVX-LABEL: @ImagOp_c(
// AVX-NEXT: entry:
// AVX-NEXT: [[RETVAL:%.*]] = alloca { half, half }, align 2
// AVX-NEXT: [[A:%.*]] = alloca { half, half }, align 2
// AVX-NEXT: store <2 x half> [[A_COERCE:%.*]], ptr [[A]], align 2
// AVX-NEXT: [[A_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[A]], i32 0, i32 1
// AVX-NEXT: [[TMP0:%.*]] = load half, ptr [[A_IMAGP]], align 2
// AVX-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 0
// AVX-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 1
// AVX-NEXT: store half [[TMP0]], ptr [[RETVAL_REALP]], align 2
// AVX-NEXT: store half 0xH0000, ptr [[RETVAL_IMAGP]], align 2
// AVX-NEXT: [[TMP1:%.*]] = load <2 x half>, ptr [[RETVAL]], align 2
// AVX-NEXT: ret <2 x half> [[TMP1]]
//
// X86-LABEL: @ImagOp_c(
// X86-NEXT: entry:
// X86-NEXT: [[RETVAL:%.*]] = alloca { half, half }, align 2
// X86-NEXT: [[A:%.*]] = alloca { half, half }, align 2
// X86-NEXT: store <2 x half> [[A_COERCE:%.*]], ptr [[A]], align 2
// X86-NEXT: [[A_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[A]], i32 0, i32 1
// X86-NEXT: [[A_IMAG:%.*]] = load half, ptr [[A_IMAGP]], align 2
// X86-NEXT: [[EXT:%.*]] = fpext half [[A_IMAG]] to float
// X86-NEXT: [[UNPROMOTION:%.*]] = fptrunc float [[EXT]] to half
// X86-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 0
// X86-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 1
// X86-NEXT: store half [[UNPROMOTION]], ptr [[RETVAL_REALP]], align 2
// X86-NEXT: store half 0xH0000, ptr [[RETVAL_IMAGP]], align 2
// X86-NEXT: [[TMP0:%.*]] = load <2 x half>, ptr [[RETVAL]], align 2
// X86-NEXT: ret <2 x half> [[TMP0]]
//
_Float16 _Complex ImagOp_c(_Float16 _Complex a) {
return __imag a;
}
// AVX-LABEL: @MinusOp_c_c(
// AVX-NEXT: entry:
// AVX-NEXT: [[RETVAL:%.*]] = alloca { half, half }, align 2
// AVX-NEXT: [[A:%.*]] = alloca { half, half }, align 2
// AVX-NEXT: [[C:%.*]] = alloca { half, half }, align 2
// AVX-NEXT: store <2 x half> [[A_COERCE:%.*]], ptr [[A]], align 2
// AVX-NEXT: store <2 x half> [[C_COERCE:%.*]], ptr [[C]], align 2
// AVX-NEXT: [[A_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[A]], i32 0, i32 0
// AVX-NEXT: [[A_REAL:%.*]] = load half, ptr [[A_REALP]], align 2
// AVX-NEXT: [[A_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[A]], i32 0, i32 1
// AVX-NEXT: [[A_IMAG:%.*]] = load half, ptr [[A_IMAGP]], align 2
// AVX-NEXT: [[C_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[C]], i32 0, i32 0
// AVX-NEXT: [[C_REAL:%.*]] = load half, ptr [[C_REALP]], align 2
// AVX-NEXT: [[C_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[C]], i32 0, i32 1
// AVX-NEXT: [[C_IMAG:%.*]] = load half, ptr [[C_IMAGP]], align 2
// AVX-NEXT: [[NEG_R:%.*]] = fneg half [[C_REAL]]
// AVX-NEXT: [[NEG_I:%.*]] = fneg half [[C_IMAG]]
// AVX-NEXT: [[ADD_R:%.*]] = fadd half [[A_REAL]], [[NEG_R]]
// AVX-NEXT: [[ADD_I:%.*]] = fadd half [[A_IMAG]], [[NEG_I]]
// AVX-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 0
// AVX-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 1
// AVX-NEXT: store half [[ADD_R]], ptr [[RETVAL_REALP]], align 2
// AVX-NEXT: store half [[ADD_I]], ptr [[RETVAL_IMAGP]], align 2
// AVX-NEXT: [[TMP0:%.*]] = load <2 x half>, ptr [[RETVAL]], align 2
// AVX-NEXT: ret <2 x half> [[TMP0]]
//
// X86-LABEL: @MinusOp_c_c(
// X86-NEXT: entry:
// X86-NEXT: [[RETVAL:%.*]] = alloca { half, half }, align 2
// X86-NEXT: [[A:%.*]] = alloca { half, half }, align 2
// X86-NEXT: [[C:%.*]] = alloca { half, half }, align 2
// X86-NEXT: store <2 x half> [[A_COERCE:%.*]], ptr [[A]], align 2
// X86-NEXT: store <2 x half> [[C_COERCE:%.*]], ptr [[C]], align 2
// X86-NEXT: [[A_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[A]], i32 0, i32 0
// X86-NEXT: [[A_REAL:%.*]] = load half, ptr [[A_REALP]], align 2
// X86-NEXT: [[A_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[A]], i32 0, i32 1
// X86-NEXT: [[A_IMAG:%.*]] = load half, ptr [[A_IMAGP]], align 2
// X86-NEXT: [[EXT:%.*]] = fpext half [[A_REAL]] to float
// X86-NEXT: [[EXT1:%.*]] = fpext half [[A_IMAG]] to float
// X86-NEXT: [[C_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[C]], i32 0, i32 0
// X86-NEXT: [[C_REAL:%.*]] = load half, ptr [[C_REALP]], align 2
// X86-NEXT: [[C_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[C]], i32 0, i32 1
// X86-NEXT: [[C_IMAG:%.*]] = load half, ptr [[C_IMAGP]], align 2
// X86-NEXT: [[EXT2:%.*]] = fpext half [[C_REAL]] to float
// X86-NEXT: [[EXT3:%.*]] = fpext half [[C_IMAG]] to float
// X86-NEXT: [[NEG_R:%.*]] = fneg float [[EXT2]]
// X86-NEXT: [[NEG_I:%.*]] = fneg float [[EXT3]]
// X86-NEXT: [[ADD_R:%.*]] = fadd float [[EXT]], [[NEG_R]]
// X86-NEXT: [[ADD_I:%.*]] = fadd float [[EXT1]], [[NEG_I]]
// X86-NEXT: [[UNPROMOTION:%.*]] = fptrunc float [[ADD_R]] to half
// X86-NEXT: [[UNPROMOTION4:%.*]] = fptrunc float [[ADD_I]] to half
// X86-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 0
// X86-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 1
// X86-NEXT: store half [[UNPROMOTION]], ptr [[RETVAL_REALP]], align 2
// X86-NEXT: store half [[UNPROMOTION4]], ptr [[RETVAL_IMAGP]], align 2
// X86-NEXT: [[TMP0:%.*]] = load <2 x half>, ptr [[RETVAL]], align 2
// X86-NEXT: ret <2 x half> [[TMP0]]
//
_Float16 _Complex MinusOp_c_c(_Float16 _Complex a, _Float16 _Complex c) {
return a + -c;
}
// AVX-LABEL: @PlusOp_c_c(
// AVX-NEXT: entry:
// AVX-NEXT: [[RETVAL:%.*]] = alloca { half, half }, align 2
// AVX-NEXT: [[A:%.*]] = alloca { half, half }, align 2
// AVX-NEXT: [[C:%.*]] = alloca { half, half }, align 2
// AVX-NEXT: store <2 x half> [[A_COERCE:%.*]], ptr [[A]], align 2
// AVX-NEXT: store <2 x half> [[C_COERCE:%.*]], ptr [[C]], align 2
// AVX-NEXT: [[A_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[A]], i32 0, i32 0
// AVX-NEXT: [[A_REAL:%.*]] = load half, ptr [[A_REALP]], align 2
// AVX-NEXT: [[A_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[A]], i32 0, i32 1
// AVX-NEXT: [[A_IMAG:%.*]] = load half, ptr [[A_IMAGP]], align 2
// AVX-NEXT: [[C_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[C]], i32 0, i32 0
// AVX-NEXT: [[C_REAL:%.*]] = load half, ptr [[C_REALP]], align 2
// AVX-NEXT: [[C_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[C]], i32 0, i32 1
// AVX-NEXT: [[C_IMAG:%.*]] = load half, ptr [[C_IMAGP]], align 2
// AVX-NEXT: [[SUB_R:%.*]] = fsub half [[A_REAL]], [[C_REAL]]
// AVX-NEXT: [[SUB_I:%.*]] = fsub half [[A_IMAG]], [[C_IMAG]]
// AVX-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 0
// AVX-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 1
// AVX-NEXT: store half [[SUB_R]], ptr [[RETVAL_REALP]], align 2
// AVX-NEXT: store half [[SUB_I]], ptr [[RETVAL_IMAGP]], align 2
// AVX-NEXT: [[TMP0:%.*]] = load <2 x half>, ptr [[RETVAL]], align 2
// AVX-NEXT: ret <2 x half> [[TMP0]]
//
// X86-LABEL: @PlusOp_c_c(
// X86-NEXT: entry:
// X86-NEXT: [[RETVAL:%.*]] = alloca { half, half }, align 2
// X86-NEXT: [[A:%.*]] = alloca { half, half }, align 2
// X86-NEXT: [[C:%.*]] = alloca { half, half }, align 2
// X86-NEXT: store <2 x half> [[A_COERCE:%.*]], ptr [[A]], align 2
// X86-NEXT: store <2 x half> [[C_COERCE:%.*]], ptr [[C]], align 2
// X86-NEXT: [[A_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[A]], i32 0, i32 0
// X86-NEXT: [[A_REAL:%.*]] = load half, ptr [[A_REALP]], align 2
// X86-NEXT: [[A_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[A]], i32 0, i32 1
// X86-NEXT: [[A_IMAG:%.*]] = load half, ptr [[A_IMAGP]], align 2
// X86-NEXT: [[EXT:%.*]] = fpext half [[A_REAL]] to float
// X86-NEXT: [[EXT1:%.*]] = fpext half [[A_IMAG]] to float
// X86-NEXT: [[C_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[C]], i32 0, i32 0
// X86-NEXT: [[C_REAL:%.*]] = load half, ptr [[C_REALP]], align 2
// X86-NEXT: [[C_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[C]], i32 0, i32 1
// X86-NEXT: [[C_IMAG:%.*]] = load half, ptr [[C_IMAGP]], align 2
// X86-NEXT: [[EXT2:%.*]] = fpext half [[C_REAL]] to float
// X86-NEXT: [[EXT3:%.*]] = fpext half [[C_IMAG]] to float
// X86-NEXT: [[SUB_R:%.*]] = fsub float [[EXT]], [[EXT2]]
// X86-NEXT: [[SUB_I:%.*]] = fsub float [[EXT1]], [[EXT3]]
// X86-NEXT: [[UNPROMOTION:%.*]] = fptrunc float [[SUB_R]] to half
// X86-NEXT: [[UNPROMOTION4:%.*]] = fptrunc float [[SUB_I]] to half
// X86-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 0
// X86-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds { half, half }, ptr [[RETVAL]], i32 0, i32 1
// X86-NEXT: store half [[UNPROMOTION]], ptr [[RETVAL_REALP]], align 2
// X86-NEXT: store half [[UNPROMOTION4]], ptr [[RETVAL_IMAGP]], align 2
// X86-NEXT: [[TMP0:%.*]] = load <2 x half>, ptr [[RETVAL]], align 2
// X86-NEXT: ret <2 x half> [[TMP0]]
//
_Float16 _Complex PlusOp_c_c(_Float16 _Complex a, _Float16 _Complex c) {
return a - +c;
}