blob: f50bcbba7f8bfead7d861c73ebbf5f1c369e4a1b [file] [edit]
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir
// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t-cir.ll
// RUN: FileCheck --check-prefix=LLVM --input-file=%t-cir.ll %s
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll
// RUN: FileCheck --check-prefix=OGCG --input-file=%t.ll %s
// frexp: float, double, long double
float test_frexpf(float x) {
int exp;
return __builtin_frexpf(x, &exp);
}
// CIR-LABEL: cir.func {{.*}} @test_frexpf
// CIR: %{{.*}}, %{{.*}} = cir.frexp %{{.*}} : !cir.float -> !cir.float, !s32i
// CIR: cir.store
// CIR: cir.return
// LLVM-LABEL: define {{.*}} float @test_frexpf
// LLVM: %{{.*}} = call { float, i32 } @llvm.frexp.f32.i32(float %{{.*}})
// LLVM: %{{.*}} = extractvalue { float, i32 } %{{.*}}, 0
// LLVM: %{{.*}} = extractvalue { float, i32 } %{{.*}}, 1
// LLVM: ret float
// OGCG-LABEL: define {{.*}} float @test_frexpf
// OGCG: %{{.*}} = call { float, i32 } @llvm.frexp.f32.i32(float %{{.*}})
// OGCG: %{{.*}} = extractvalue { float, i32 } %{{.*}}, 1
// OGCG: %{{.*}} = extractvalue { float, i32 } %{{.*}}, 0
// OGCG: ret float
double test_frexp(double x) {
int exp;
return __builtin_frexp(x, &exp);
}
// CIR-LABEL: cir.func {{.*}} @test_frexp
// CIR: %{{.*}}, %{{.*}} = cir.frexp %{{.*}} : !cir.double -> !cir.double, !s32i
// CIR: cir.store
// CIR: cir.return
// LLVM-LABEL: define {{.*}} double @test_frexp
// LLVM: %{{.*}} = call { double, i32 } @llvm.frexp.f64.i32(double %{{.*}})
// LLVM: %{{.*}} = extractvalue { double, i32 } %{{.*}}, 0
// LLVM: %{{.*}} = extractvalue { double, i32 } %{{.*}}, 1
// LLVM: ret double
// OGCG-LABEL: define {{.*}} double @test_frexp
// OGCG: %{{.*}} = call { double, i32 } @llvm.frexp.f64.i32(double %{{.*}})
// OGCG: %{{.*}} = extractvalue { double, i32 } %{{.*}}, 1
// OGCG: %{{.*}} = extractvalue { double, i32 } %{{.*}}, 0
// OGCG: ret double
long double test_frexpl(long double x) {
int exp;
return __builtin_frexpl(x, &exp);
}
// CIR-LABEL: cir.func {{.*}} @test_frexpl
// CIR: %{{.*}}, %{{.*}} = cir.frexp %{{.*}} : !cir.long_double<!cir.f80> -> !cir.long_double<!cir.f80>, !s32i
// CIR: cir.store
// CIR: cir.return
// LLVM-LABEL: define {{.*}} x86_fp80 @test_frexpl
// LLVM: %{{.*}} = call { x86_fp80, i32 } @llvm.frexp.f80.i32(x86_fp80 %{{.*}})
// LLVM: %{{.*}} = extractvalue { x86_fp80, i32 } %{{.*}}, 0
// LLVM: %{{.*}} = extractvalue { x86_fp80, i32 } %{{.*}}, 1
// LLVM: ret x86_fp80
// OGCG-LABEL: define {{.*}} x86_fp80 @test_frexpl
// OGCG: %{{.*}} = call { x86_fp80, i32 } @llvm.frexp.f80.i32(x86_fp80 %{{.*}})
// OGCG: %{{.*}} = extractvalue { x86_fp80, i32 } %{{.*}}, 1
// OGCG: %{{.*}} = extractvalue { x86_fp80, i32 } %{{.*}}, 0
// OGCG: ret x86_fp80
__float128 test_frexpf128(__float128 x) {
int exp;
return __builtin_frexpf128(x, &exp);
}
// CIR-LABEL: cir.func {{.*}} @test_frexpf128
// CIR: %{{.*}}, %{{.*}} = cir.frexp %{{.*}} : !cir.f128 -> !cir.f128, !s32i
// CIR: cir.store
// CIR: cir.return
// LLVM-LABEL: define {{.*}} fp128 @test_frexpf128
// LLVM: %{{.*}} = call { fp128, i32 } @llvm.frexp.f128.i32(fp128 %{{.*}})
// LLVM: %{{.*}} = extractvalue { fp128, i32 } %{{.*}}, 0
// LLVM: %{{.*}} = extractvalue { fp128, i32 } %{{.*}}, 1
// LLVM: ret fp128
// OGCG-LABEL: define {{.*}} fp128 @test_frexpf128
// OGCG: %{{.*}} = call { fp128, i32 } @llvm.frexp.f128.i32(fp128 %{{.*}})
// OGCG: %{{.*}} = extractvalue { fp128, i32 } %{{.*}}, 1
// OGCG: %{{.*}} = extractvalue { fp128, i32 } %{{.*}}, 0
// OGCG: ret fp128
// modf: float, double, long double
float test_modff(float x) {
float ipart;
return __builtin_modff(x, &ipart);
}
// CIR-LABEL: cir.func {{.*}} @test_modff
// CIR: %{{.*}}, %{{.*}} = cir.modf %{{.*}} : !cir.float -> !cir.float, !cir.float
// CIR: cir.store
// CIR: cir.return
// LLVM-LABEL: define {{.*}} float @test_modff
// LLVM: %{{.*}} = call { float, float } @llvm.modf.f32(float %{{.*}})
// LLVM: %{{.*}} = extractvalue { float, float } %{{.*}}, 0
// LLVM: %{{.*}} = extractvalue { float, float } %{{.*}}, 1
// LLVM: ret float
// OGCG-LABEL: define {{.*}} float @test_modff
// OGCG: %{{.*}} = call { float, float } @llvm.modf.f32(float %{{.*}})
// OGCG: %{{.*}} = extractvalue { float, float } %{{.*}}, 0
// OGCG: %{{.*}} = extractvalue { float, float } %{{.*}}, 1
// OGCG: ret float
double test_modf(double x) {
double ipart;
return __builtin_modf(x, &ipart);
}
// CIR-LABEL: cir.func {{.*}} @test_modf
// CIR: %{{.*}}, %{{.*}} = cir.modf %{{.*}} : !cir.double -> !cir.double, !cir.double
// CIR: cir.store
// CIR: cir.return
// LLVM-LABEL: define {{.*}} double @test_modf
// LLVM: %{{.*}} = call { double, double } @llvm.modf.f64(double %{{.*}})
// LLVM: %{{.*}} = extractvalue { double, double } %{{.*}}, 0
// LLVM: %{{.*}} = extractvalue { double, double } %{{.*}}, 1
// LLVM: ret double
// OGCG-LABEL: define {{.*}} double @test_modf
// OGCG: %{{.*}} = call { double, double } @llvm.modf.f64(double %{{.*}})
// OGCG: %{{.*}} = extractvalue { double, double } %{{.*}}, 0
// OGCG: %{{.*}} = extractvalue { double, double } %{{.*}}, 1
// OGCG: ret double
long double test_modfl(long double x) {
long double ipart;
return __builtin_modfl(x, &ipart);
}
// CIR-LABEL: cir.func {{.*}} @test_modfl
// CIR: %{{.*}}, %{{.*}} = cir.modf %{{.*}} : !cir.long_double<!cir.f80> -> !cir.long_double<!cir.f80>, !cir.long_double<!cir.f80>
// CIR: cir.store
// CIR: cir.return
// LLVM-LABEL: define {{.*}} x86_fp80 @test_modfl
// LLVM: %{{.*}} = call { x86_fp80, x86_fp80 } @llvm.modf.f80(x86_fp80 %{{.*}})
// LLVM: %{{.*}} = extractvalue { x86_fp80, x86_fp80 } %{{.*}}, 0
// LLVM: %{{.*}} = extractvalue { x86_fp80, x86_fp80 } %{{.*}}, 1
// LLVM: ret x86_fp80
// OGCG-LABEL: define {{.*}} x86_fp80 @test_modfl
// OGCG: %{{.*}} = call { x86_fp80, x86_fp80 } @llvm.modf.f80(x86_fp80 %{{.*}})
// OGCG: %{{.*}} = extractvalue { x86_fp80, x86_fp80 } %{{.*}}, 0
// OGCG: %{{.*}} = extractvalue { x86_fp80, x86_fp80 } %{{.*}}, 1
// OGCG: ret x86_fp80
__float128 test_modff128(__float128 x) {
__float128 ipart;
return __builtin_modff128(x, &ipart);
}
// CIR-LABEL: cir.func {{.*}} @test_modff128
// CIR: cir.call @modff128
// CIR: cir.return
// LLVM-LABEL: define {{.*}} fp128 @test_modff128
// LLVM: call fp128 @modff128(fp128 {{.*}}, ptr {{.*}})
// LLVM: ret fp128
// OGCG-LABEL: define {{.*}} fp128 @test_modff128
// OGCG: call fp128 @modff128(fp128 {{.*}}, ptr {{.*}})
// OGCG: ret fp128
// powi: float, double, long double
float test_powif(float x, int y) {
return __builtin_powif(x, y);
}
// CIR-LABEL: cir.func {{.*}} @test_powif
// CIR: %{{.*}} = cir.call_llvm_intrinsic "powi" %{{.*}}, %{{.*}} : (!cir.float, !s32i) -> !cir.float
// CIR: cir.return
// LLVM-LABEL: define {{.*}} float @test_powif
// LLVM: call float @llvm.powi.f32.i32(float %{{.*}}, i32 %{{.*}})
// LLVM: ret float
// OGCG-LABEL: define {{.*}} float @test_powif
// OGCG: call float @llvm.powi.f32.i32(float %{{.*}}, i32 %{{.*}})
// OGCG: ret float
double test_powi(double x, int y) {
return __builtin_powi(x, y);
}
// CIR-LABEL: cir.func {{.*}} @test_powi
// CIR: %{{.*}} = cir.call_llvm_intrinsic "powi" %{{.*}}, %{{.*}} : (!cir.double, !s32i) -> !cir.double
// CIR: cir.return
// LLVM-LABEL: define {{.*}} double @test_powi
// LLVM: call double @llvm.powi.f64.i32(double %{{.*}}, i32 %{{.*}})
// LLVM: ret double
// OGCG-LABEL: define {{.*}} double @test_powi
// OGCG: call double @llvm.powi.f64.i32(double %{{.*}}, i32 %{{.*}})
// OGCG: ret double
long double test_powil(long double x, int y) {
return __builtin_powil(x, y);
}
// CIR-LABEL: cir.func {{.*}} @test_powil
// CIR: %{{.*}} = cir.call_llvm_intrinsic "powi" %{{.*}}, %{{.*}} : (!cir.long_double<!cir.f80>, !s32i) -> !cir.long_double<!cir.f80>
// CIR: cir.return
// LLVM-LABEL: define {{.*}} x86_fp80 @test_powil
// LLVM: call x86_fp80 @llvm.powi.f80.i32(x86_fp80 %{{.*}}, i32 %{{.*}})
// LLVM: ret x86_fp80
// OGCG-LABEL: define {{.*}} x86_fp80 @test_powil
// OGCG: call x86_fp80 @llvm.powi.f80.i32(x86_fp80 %{{.*}}, i32 %{{.*}})
// OGCG: ret x86_fp80
// FP comparison builtins: float
void test_floats(float x, float y, int *out) {
out[0] = __builtin_isgreater(x, y);
// CIR: cir.cmp gt %{{.*}}, %{{.*}} : !cir.float
// LLVM: fcmp ogt float
// OGCG: fcmp ogt float
out[1] = __builtin_isgreaterequal(x, y);
// CIR: cir.cmp ge %{{.*}}, %{{.*}} : !cir.float
// LLVM: fcmp oge float
// OGCG: fcmp oge float
out[2] = __builtin_isless(x, y);
// CIR: cir.cmp lt %{{.*}}, %{{.*}} : !cir.float
// LLVM: fcmp olt float
// OGCG: fcmp olt float
out[3] = __builtin_islessequal(x, y);
// CIR: cir.cmp le %{{.*}}, %{{.*}} : !cir.float
// LLVM: fcmp ole float
// OGCG: fcmp ole float
out[4] = __builtin_islessgreater(x, y);
// CIR: cir.cmp one %{{.*}}, %{{.*}} : !cir.float
// LLVM: fcmp one float
// OGCG: fcmp one float
out[5] = __builtin_isunordered(x, y);
// CIR: cir.cmp uno %{{.*}}, %{{.*}} : !cir.float
// LLVM: fcmp uno float
// OGCG: fcmp uno float
}
// FP comparison builtins: double
void test_doubles(double x, double y, int *out) {
out[0] = __builtin_isgreater(x, y);
// CIR: cir.cmp gt %{{.*}}, %{{.*}} : !cir.double
// LLVM: fcmp ogt double
// OGCG: fcmp ogt double
out[1] = __builtin_isgreaterequal(x, y);
// CIR: cir.cmp ge %{{.*}}, %{{.*}} : !cir.double
// LLVM: fcmp oge double
// OGCG: fcmp oge double
out[2] = __builtin_isless(x, y);
// CIR: cir.cmp lt %{{.*}}, %{{.*}} : !cir.double
// LLVM: fcmp olt double
// OGCG: fcmp olt double
out[3] = __builtin_islessequal(x, y);
// CIR: cir.cmp le %{{.*}}, %{{.*}} : !cir.double
// LLVM: fcmp ole double
// OGCG: fcmp ole double
out[4] = __builtin_islessgreater(x, y);
// CIR: cir.cmp one %{{.*}}, %{{.*}} : !cir.double
// LLVM: fcmp one double
// OGCG: fcmp one double
out[5] = __builtin_isunordered(x, y);
// CIR: cir.cmp uno %{{.*}}, %{{.*}} : !cir.double
// LLVM: fcmp uno double
// OGCG: fcmp uno double
}
// FP comparison builtins: mixed double + float (fpext)
void test_mixed(double x, float y, int *out) {
out[0] = __builtin_isgreater(x, y);
// CIR: cir.cast floating %{{.*}} : !cir.float -> !cir.double
// CIR: cir.cmp gt %{{.*}}, %{{.*}} : !cir.double
// LLVM: fpext float %{{.*}} to double
// LLVM: fcmp ogt double
// OGCG: fpext float %{{.*}} to double
// OGCG: fcmp ogt double
out[1] = __builtin_isgreaterequal(x, y);
// CIR: cir.cast floating %{{.*}} : !cir.float -> !cir.double
// CIR: cir.cmp ge %{{.*}}, %{{.*}} : !cir.double
// LLVM: fpext float %{{.*}} to double
// LLVM: fcmp oge double
// OGCG: fpext float %{{.*}} to double
// OGCG: fcmp oge double
out[2] = __builtin_isless(x, y);
// CIR: cir.cast floating %{{.*}} : !cir.float -> !cir.double
// CIR: cir.cmp lt %{{.*}}, %{{.*}} : !cir.double
// LLVM: fpext float %{{.*}} to double
// LLVM: fcmp olt double
// OGCG: fpext float %{{.*}} to double
// OGCG: fcmp olt double
out[3] = __builtin_islessequal(x, y);
// CIR: cir.cast floating %{{.*}} : !cir.float -> !cir.double
// CIR: cir.cmp le %{{.*}}, %{{.*}} : !cir.double
// LLVM: fpext float %{{.*}} to double
// LLVM: fcmp ole double
// OGCG: fpext float %{{.*}} to double
// OGCG: fcmp ole double
out[4] = __builtin_islessgreater(x, y);
// CIR: cir.cast floating %{{.*}} : !cir.float -> !cir.double
// CIR: cir.cmp one %{{.*}}, %{{.*}} : !cir.double
// LLVM: fpext float %{{.*}} to double
// LLVM: fcmp one double
// OGCG: fpext float %{{.*}} to double
// OGCG: fcmp one double
out[5] = __builtin_isunordered(x, y);
// CIR: cir.cast floating %{{.*}} : !cir.float -> !cir.double
// CIR: cir.cmp uno %{{.*}}, %{{.*}} : !cir.double
// LLVM: fpext float %{{.*}} to double
// LLVM: fcmp uno double
// OGCG: fpext float %{{.*}} to double
// OGCG: fcmp uno double
}
// FP comparison builtins: __fp16 (promoted to float)
int test_isgreater_half(__fp16 *a, __fp16 *b) {
return __builtin_isgreater(*a, *b);
}
// CIR-LABEL: cir.func {{.*}} @test_isgreater_half
// CIR: cir.cast floating %{{.*}} : !cir.f16 -> !cir.float
// CIR: cir.cast floating %{{.*}} : !cir.f16 -> !cir.float
// CIR: cir.cmp gt %{{.*}}, %{{.*}} : !cir.float
// LLVM-LABEL: define {{.*}} i32 @test_isgreater_half
// LLVM: fpext half %{{.*}} to float
// LLVM: fpext half %{{.*}} to float
// LLVM: fcmp ogt float
// LLVM: zext i1 %{{.*}} to i32
// LLVM: ret i32
// OGCG-LABEL: define {{.*}} i32 @test_isgreater_half
// OGCG: fpext half %{{.*}} to float
// OGCG: fpext half %{{.*}} to float
// OGCG: fcmp ogt float
// OGCG: zext i1 %{{.*}} to i32
// OGCG: ret i32