}
static boolean
-sse41_rounding_available(const struct lp_type type)
+arch_rounding_available(const struct lp_type type)
{
if ((util_cpu_caps.has_sse4_1 &&
(type.length == 1 || type.width*type.length == 128)) ||
(util_cpu_caps.has_avx && type.width*type.length == 256))
return TRUE;
+ else if ((util_cpu_caps.has_altivec &&
+ (type.width == 32 && type.length == 4)))
+ return TRUE;
return FALSE;
}
-enum lp_build_round_sse41_mode
+enum lp_build_round_mode
{
- LP_BUILD_ROUND_SSE41_NEAREST = 0,
- LP_BUILD_ROUND_SSE41_FLOOR = 1,
- LP_BUILD_ROUND_SSE41_CEIL = 2,
- LP_BUILD_ROUND_SSE41_TRUNCATE = 3
+ LP_BUILD_ROUND_NEAREST = 0,
+ LP_BUILD_ROUND_FLOOR = 1,
+ LP_BUILD_ROUND_CEIL = 2,
+ LP_BUILD_ROUND_TRUNCATE = 3
};
-
/**
* Helper for SSE4.1's ROUNDxx instructions.
*
static INLINE LLVMValueRef
lp_build_round_sse41(struct lp_build_context *bld,
LLVMValueRef a,
- enum lp_build_round_sse41_mode mode)
+ enum lp_build_round_mode mode)
{
LLVMBuilderRef builder = bld->gallivm->builder;
const struct lp_type type = bld->type;
}
+/*
+ */
+static INLINE LLVMValueRef
+lp_build_round_altivec(struct lp_build_context *bld,
+ LLVMValueRef a,
+ enum lp_build_round_mode mode)
+{
+ LLVMBuilderRef builder = bld->gallivm->builder;
+ const struct lp_type type = bld->type;
+ const char *intrinsic = NULL;
+
+ assert(type.floating);
+
+ assert(lp_check_value(type, a));
+ assert(util_cpu_caps.has_altivec);
+
+ switch (mode) {
+ case LP_BUILD_ROUND_NEAREST:
+ intrinsic = "llvm.ppc.altivec.vrfin";
+ break;
+ case LP_BUILD_ROUND_FLOOR:
+ intrinsic = "llvm.ppc.altivec.vrfim";
+ break;
+ case LP_BUILD_ROUND_CEIL:
+ intrinsic = "llvm.ppc.altivec.vrfip";
+ break;
+ case LP_BUILD_ROUND_TRUNCATE:
+ intrinsic = "llvm.ppc.altivec.vrfiz";
+ break;
+ }
+
+ return lp_build_intrinsic_unary(builder, intrinsic, bld->vec_type, a);
+}
+
+static INLINE LLVMValueRef
+lp_build_round_arch(struct lp_build_context *bld,
+ LLVMValueRef a,
+ enum lp_build_round_mode mode)
+{
+ if (util_cpu_caps.has_sse4_1)
+ return lp_build_round_sse41(bld, a, mode);
+ else /* (util_cpu_caps.has_altivec) */
+ return lp_build_round_altivec(bld, a, mode);
+}
+
/**
* Return the integer part of a float (vector) value (== round toward zero).
* The returned value is a float (vector).
assert(type.floating);
assert(lp_check_value(type, a));
- if (sse41_rounding_available(type)) {
- return lp_build_round_sse41(bld, a, LP_BUILD_ROUND_SSE41_TRUNCATE);
+ if (arch_rounding_available(type)) {
+ return lp_build_round_arch(bld, a, LP_BUILD_ROUND_TRUNCATE);
}
else {
LLVMTypeRef vec_type = lp_build_vec_type(bld->gallivm, type);
assert(type.floating);
assert(lp_check_value(type, a));
- if (sse41_rounding_available(type)) {
- return lp_build_round_sse41(bld, a, LP_BUILD_ROUND_SSE41_NEAREST);
+ if (arch_rounding_available(type)) {
+ return lp_build_round_arch(bld, a, LP_BUILD_ROUND_NEAREST);
}
else {
LLVMTypeRef vec_type = lp_build_vec_type(bld->gallivm, type);
assert(type.floating);
assert(lp_check_value(type, a));
- if (sse41_rounding_available(type)) {
- return lp_build_round_sse41(bld, a, LP_BUILD_ROUND_SSE41_FLOOR);
+ if (arch_rounding_available(type)) {
+ return lp_build_round_arch(bld, a, LP_BUILD_ROUND_FLOOR);
}
else {
LLVMTypeRef vec_type = lp_build_vec_type(bld->gallivm, type);
assert(type.floating);
assert(lp_check_value(type, a));
- if (sse41_rounding_available(type)) {
- return lp_build_round_sse41(bld, a, LP_BUILD_ROUND_SSE41_CEIL);
+ if (arch_rounding_available(type)) {
+ return lp_build_round_arch(bld, a, LP_BUILD_ROUND_CEIL);
}
else {
LLVMTypeRef vec_type = lp_build_vec_type(bld->gallivm, type);
(util_cpu_caps.has_avx && type.width == 32 && type.length == 8)) {
return lp_build_iround_nearest_sse2(bld, a);
}
- if (sse41_rounding_available(type)) {
- res = lp_build_round_sse41(bld, a, LP_BUILD_ROUND_SSE41_NEAREST);
+ if (arch_rounding_available(type)) {
+ res = lp_build_round_arch(bld, a, LP_BUILD_ROUND_NEAREST);
}
else {
LLVMValueRef half;
res = a;
if (type.sign) {
- if (sse41_rounding_available(type)) {
- res = lp_build_round_sse41(bld, a, LP_BUILD_ROUND_SSE41_FLOOR);
+ if (arch_rounding_available(type)) {
+ res = lp_build_round_arch(bld, a, LP_BUILD_ROUND_FLOOR);
}
else {
/* Take the sign bit and add it to 1 constant */
assert(type.floating);
assert(lp_check_value(type, a));
- if (sse41_rounding_available(type)) {
- res = lp_build_round_sse41(bld, a, LP_BUILD_ROUND_SSE41_CEIL);
+ if (arch_rounding_available(type)) {
+ res = lp_build_round_arch(bld, a, LP_BUILD_ROUND_CEIL);
}
else {
LLVMTypeRef vec_type = bld->vec_type;
assert(type.floating);
assert(lp_check_value(type, a));
- if (sse41_rounding_available(type)) {
+ if (arch_rounding_available(type)) {
/*
* floor() is easier.
*/