/**
- * Prevent returning a fractional part of 1.0 for very small negative values of
- * 'a' by clamping against 0.99999(9).
+ * Prevent returning 1.0 for very small negative values of 'a' by clamping
+ * against 0.99999(9). (Will also return that value for NaNs.)
*/
static inline LLVMValueRef
clamp_fract(struct lp_build_context *bld, LLVMValueRef fract)
/* this is the largest number smaller than 1.0 representable as float */
max = lp_build_const_vec(bld->gallivm, bld->type,
1.0 - 1.0/(1LL << (lp_mantissa(bld->type) + 1)));
- return lp_build_min(bld, fract, max);
+ return lp_build_min_ext(bld, fract, max,
+ GALLIVM_NAN_RETURN_OTHER_SECOND_NONNAN);
}
/**
* Same as lp_build_fract, but guarantees that the result is always smaller
- * than one.
+ * than one. Will also return the smaller-than-one value for infs, NaNs.
*/
LLVMValueRef
lp_build_fract_safe(struct lp_build_context *bld,
mask = lp_build_compare(int_coord_bld->gallivm, int_coord_bld->type,
PIPE_FUNC_LESS, *coord0_i, int_coord_bld->zero);
*coord0_i = lp_build_select(int_coord_bld, mask, length_minus_one, *coord0_i);
+ /*
+ * We should never get values too large - except if coord was nan or inf,
+ * in which case things go terribly wrong...
+ * Alternatively, could use fract_safe above...
+ */
+ *coord0_i = lp_build_min(int_coord_bld, *coord0_i, length_minus_one);
}
*coord1 = lp_build_add(coord_bld, coord, half);
coord = lp_build_sub(coord_bld, coord, half);
*weight = lp_build_fract(coord_bld, coord);
+ /*
+ * It is important for this comparison to be unordered
+ * (or need fract_safe above).
+ */
mask = lp_build_compare(coord_bld->gallivm, coord_bld->type,
PIPE_FUNC_LESS, coord, coord_bld->zero);
*coord0 = lp_build_select(coord_bld, mask, length_minus_one, coord);
coord = lp_build_sub(coord_bld, coord, half);
}
/* clamp to [0, length - 1] */
- coord = lp_build_min(coord_bld, coord, length_minus_one);
+ coord = lp_build_min_ext(coord_bld, coord, length_minus_one,
+ GALLIVM_NAN_RETURN_OTHER_SECOND_NONNAN);
coord = lp_build_max(coord_bld, coord, coord_bld->zero);
*coord1 = lp_build_add(coord_bld, coord, coord_bld->one);
/* convert to int, compute lerp weight */
LLVMValueRef fract, flr, isOdd;
lp_build_ifloor_fract(coord_bld, coord, &flr, &fract);
+ /* kill off NaNs */
+ /* XXX: not safe without arch rounding, fract can be anything. */
+ fract = lp_build_max_ext(coord_bld, fract, coord_bld->zero,
+ GALLIVM_NAN_RETURN_OTHER_SECOND_NONNAN);
/* isOdd = flr & 1 */
isOdd = LLVMBuildAnd(bld->gallivm->builder, flr, int_coord_bld->one, "");
/* make coord positive or negative depending on isOdd */
+ /* XXX slight overkill masking out sign bit is unnecessary */
coord = lp_build_set_sign(coord_bld, fract, isOdd);
/* convert isOdd to float */
* we avoided the 0.5/length division before the repeat wrap,
* now need to fix up edge cases with selects
*/
+ /*
+ * Note we do a float (unordered) compare so we can eliminate NaNs.
+ * (Otherwise would need fract_safe above).
+ */
+ mask = lp_build_compare(coord_bld->gallivm, coord_bld->type,
+ PIPE_FUNC_LESS, coord_f, coord_bld->zero);
+
/* convert to int, compute lerp weight */
lp_build_ifloor_fract(coord_bld, coord_f, coord0_i, weight_f);
- mask = lp_build_compare(int_coord_bld->gallivm, int_coord_bld->type,
- PIPE_FUNC_LESS, *coord0_i, int_coord_bld->zero);
*coord0_i = lp_build_select(int_coord_bld, mask, length_minus_one, *coord0_i);
}
}
/* clamp to length max */
- coord = lp_build_min(coord_bld, coord, length_f);
+ coord = lp_build_min_ext(coord_bld, coord, length_f,
+ GALLIVM_NAN_RETURN_OTHER_SECOND_NONNAN);
/* subtract 0.5 */
coord = lp_build_sub(coord_bld, coord, half);
/* clamp to [0, length - 0.5] */
coord = lp_build_add(coord_bld, coord, offset);
}
/* was: clamp to [-0.5, length + 0.5], then sub 0.5 */
- /* can skip clamp (though might not work for very large coord values */
+ /* can skip clamp (though might not work for very large coord values) */
coord = lp_build_sub(coord_bld, coord, half);
/* convert to int, compute lerp weight */
lp_build_ifloor_fract(coord_bld, coord, &coord0, &weight);
coord = lp_build_abs(coord_bld, coord);
/* clamp to length max */
- coord = lp_build_min(coord_bld, coord, length_f);
+ coord = lp_build_min_ext(coord_bld, coord, length_f,
+ GALLIVM_NAN_RETURN_OTHER_SECOND_NONNAN);
/* subtract 0.5 */
coord = lp_build_sub(coord_bld, coord, half);
/* clamp to [0, length - 0.5] */
/* itrunc == ifloor here */
icoord = lp_build_itrunc(coord_bld, coord);
-
- /* clamp to [0, length - 1] */
- icoord = lp_build_min(int_coord_bld, icoord, length_minus_one);
+ /*
+ * Use unsigned min due to possible undef values (NaNs, overflow)
+ */
+ {
+ struct lp_build_context abs_coord_bld = *int_coord_bld;
+ abs_coord_bld.type.sign = FALSE;
+ /* clamp to [0, length - 1] */
+ icoord = lp_build_min(&abs_coord_bld, icoord, length_minus_one);
+ }
break;
case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER: