Path: blob/21.2-virgl/src/gallium/auxiliary/gallivm/lp_bld_format_float.c
4565 views
/**************************************************************************1*2* Copyright 2013 VMware, Inc.3* All Rights Reserved.4*5* Permission is hereby granted, free of charge, to any person obtaining a6* copy of this software and associated documentation files (the7* "Software"), to deal in the Software without restriction, including8* without limitation the rights to use, copy, modify, merge, publish,9* distribute, sub license, and/or sell copies of the Software, and to10* permit persons to whom the Software is furnished to do so, subject to11* the following conditions:12*13* The above copyright notice and this permission notice (including the14* next paragraph) shall be included in all copies or substantial portions15* of the Software.16*17* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS18* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF19* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.20* IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR21* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,22* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE23* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.24*25**************************************************************************/262728/**29* @file30* Format conversion code for "special" float formats.31*32* @author Roland Scheidegger <[email protected]>33*/343536#include "util/u_debug.h"3738#include "lp_bld_type.h"39#include "lp_bld_const.h"40#include "lp_bld_arit.h"41#include "lp_bld_bitarit.h"42#include "lp_bld_logic.h"43#include "lp_bld_format.h"444546/**47* Convert float32 to a float-like value with less exponent and mantissa48* bits. The mantissa is still biased, and the mantissa still has an implied 1,49* and there may be a sign bit.50*51* @param src (vector) float value to convert52* @param mantissa_bits the number of mantissa bits53* @param exponent_bits the number of exponent bits54* @param mantissa_start the start position of the small float in result value55* @param has_sign if the small float has a sign bit56*57* This implements round-towards-zero (trunc) hence too large numbers get58* converted to largest representable number, not infinity.59* Small numbers may get converted to denorms, depending on normal60* float denorm handling of the cpu.61* Note that compared to the references, below, we skip any rounding bias62* since we do rounding towards zero - OpenGL allows rounding towards zero63* (though not preferred) and DX10 even seems to require it.64* Note that this will pack mantissa, exponent and sign bit (if any) together,65* and shift the result to mantissa_start.66*67* ref http://fgiesen.wordpress.com/2012/03/28/half-to-float-done-quic/68* ref https://gist.github.com/rygorous/215666869*/70LLVMValueRef71lp_build_float_to_smallfloat(struct gallivm_state *gallivm,72struct lp_type i32_type,73LLVMValueRef src,74unsigned mantissa_bits,75unsigned exponent_bits,76unsigned mantissa_start,77boolean has_sign)78{79LLVMBuilderRef builder = gallivm->builder;80LLVMValueRef i32_floatexpmask, i32_smallexpmask, magic, normal;81LLVMValueRef rescale_src, i32_roundmask, small_max;82LLVMValueRef i32_qnanbit, shift, res;83LLVMValueRef is_nan_or_inf, nan_or_inf, mask, i32_src;84struct lp_type f32_type = lp_type_float_vec(32, 32 * i32_type.length);85struct lp_build_context f32_bld, i32_bld;86LLVMValueRef zero = lp_build_const_vec(gallivm, f32_type, 0.0f);87unsigned exponent_start = mantissa_start + mantissa_bits;88boolean always_preserve_nans = true;89boolean maybe_correct_denorm_rounding = true;9091lp_build_context_init(&f32_bld, gallivm, f32_type);92lp_build_context_init(&i32_bld, gallivm, i32_type);9394i32_smallexpmask = lp_build_const_int_vec(gallivm, i32_type,95((1 << exponent_bits) - 1) << 23);96i32_floatexpmask = lp_build_const_int_vec(gallivm, i32_type, 0xff << 23);9798i32_src = LLVMBuildBitCast(builder, src, i32_bld.vec_type, "");99100if (has_sign) {101rescale_src = src;102}103else {104/* clamp to pos range (can still have sign bit if NaN or negative zero) */105rescale_src = lp_build_max(&f32_bld, zero, src);106}107rescale_src = LLVMBuildBitCast(builder, rescale_src, i32_bld.vec_type, "");108109/* "ordinary" number */110/*111* get rid of excess mantissa bits and sign bit112* This is only really needed for correct rounding of denorms I think113* but only if we use the preserve NaN path does using114* src_abs instead save us any instruction.115*/116if (maybe_correct_denorm_rounding || !always_preserve_nans) {117i32_roundmask = lp_build_const_int_vec(gallivm, i32_type,118~((1 << (23 - mantissa_bits)) - 1) &1190x7fffffff);120rescale_src = LLVMBuildBitCast(builder, rescale_src, i32_bld.vec_type, "");121rescale_src = lp_build_and(&i32_bld, rescale_src, i32_roundmask);122rescale_src = LLVMBuildBitCast(builder, rescale_src, f32_bld.vec_type, "");123}124else {125rescale_src = lp_build_abs(&f32_bld, src);126}127128/* bias exponent (and denormalize if necessary) */129magic = lp_build_const_int_vec(gallivm, i32_type,130((1 << (exponent_bits - 1)) - 1) << 23);131magic = LLVMBuildBitCast(builder, magic, f32_bld.vec_type, "");132normal = lp_build_mul(&f32_bld, rescale_src, magic);133134/* clamp to max value - largest non-infinity number */135small_max = lp_build_const_int_vec(gallivm, i32_type,136(((1 << exponent_bits) - 2) << 23) |137(((1 << mantissa_bits) - 1) << (23 - mantissa_bits)));138small_max = LLVMBuildBitCast(builder, small_max, f32_bld.vec_type, "");139normal = lp_build_min(&f32_bld, normal, small_max);140normal = LLVMBuildBitCast(builder, normal, i32_bld.vec_type, "");141142/*143* handle nan/inf cases144* a little bit tricky since -Inf -> 0, +Inf -> +Inf, +-Nan -> +Nan145* (for no sign) else ->Inf -> ->Inf too.146* could use explicit "unordered" comparison checking for NaNs147* which might save us from calculating src_abs too.148* (Cannot actually save the comparison since we need to distinguish149* Inf and NaN cases anyway, but it would be better for AVX.)150*/151if (always_preserve_nans) {152LLVMValueRef infcheck_src, is_inf, is_nan;153LLVMValueRef src_abs = lp_build_abs(&f32_bld, src);154src_abs = LLVMBuildBitCast(builder, src_abs, i32_bld.vec_type, "");155156if (has_sign) {157infcheck_src = src_abs;158}159else {160infcheck_src = i32_src;161}162is_nan = lp_build_compare(gallivm, i32_type, PIPE_FUNC_GREATER,163src_abs, i32_floatexpmask);164is_inf = lp_build_compare(gallivm, i32_type, PIPE_FUNC_EQUAL,165infcheck_src, i32_floatexpmask);166is_nan_or_inf = lp_build_or(&i32_bld, is_nan, is_inf);167/* could also set more mantissa bits but need at least the highest mantissa bit */168i32_qnanbit = lp_build_const_vec(gallivm, i32_type, 1 << 22);169/* combine maxexp with qnanbit */170nan_or_inf = lp_build_or(&i32_bld, i32_smallexpmask,171lp_build_and(&i32_bld, is_nan, i32_qnanbit));172}173else {174/*175* A couple simplifications, with mostly 2 drawbacks (so disabled):176* - it will promote some SNaNs (those which only had bits set177* in the mantissa part which got chopped off) to +-Infinity.178* (Those bits get chopped off anyway later so can as well use179* rescale_src instead of src_abs here saving the calculation of that.)180* - for no sign case, it relies on the max() being used for rescale_src181* to give back the NaN (which is NOT ieee754r behavior, but should work182* with sse2 on a full moon (rather if I got the operand order right) -183* we _don't_ have well-defined behavior specified with min/max wrt NaNs,184* however, and if it gets converted to cmp/select it may not work (we185* don't really have specified behavior for cmp wrt NaNs neither).186*/187rescale_src = LLVMBuildBitCast(builder, rescale_src, i32_bld.vec_type, "");188is_nan_or_inf = lp_build_compare(gallivm, i32_type, PIPE_FUNC_GEQUAL,189rescale_src, i32_floatexpmask);190/* note this will introduce excess exponent bits */191nan_or_inf = rescale_src;192}193res = lp_build_select(&i32_bld, is_nan_or_inf, nan_or_inf, normal);194195if (mantissa_start > 0 || !always_preserve_nans) {196/* mask off excess bits */197unsigned maskbits = (1 << (mantissa_bits + exponent_bits)) - 1;198mask = lp_build_const_int_vec(gallivm, i32_type,199maskbits << (23 - mantissa_bits));200res = lp_build_and(&i32_bld, res, mask);201}202203/* add back sign bit at right position */204if (has_sign) {205LLVMValueRef sign;206struct lp_type u32_type = lp_type_uint_vec(32, 32 * i32_type.length);207struct lp_build_context u32_bld;208lp_build_context_init(&u32_bld, gallivm, u32_type);209210mask = lp_build_const_int_vec(gallivm, i32_type, 0x80000000);211shift = lp_build_const_int_vec(gallivm, i32_type, 8 - exponent_bits);212sign = lp_build_and(&i32_bld, mask, i32_src);213sign = lp_build_shr(&u32_bld, sign, shift);214res = lp_build_or(&i32_bld, sign, res);215}216217/* shift to final position */218if (exponent_start < 23) {219shift = lp_build_const_int_vec(gallivm, i32_type, 23 - exponent_start);220res = lp_build_shr(&i32_bld, res, shift);221}222else {223shift = lp_build_const_int_vec(gallivm, i32_type, exponent_start - 23);224res = lp_build_shl(&i32_bld, res, shift);225}226return res;227}228229230/**231* Convert rgba float SoA values to packed r11g11b10 values.232*233* @param src SoA float (vector) values to convert.234*/235LLVMValueRef236lp_build_float_to_r11g11b10(struct gallivm_state *gallivm,237const LLVMValueRef *src)238{239LLVMValueRef dst, rcomp, bcomp, gcomp;240struct lp_build_context i32_bld;241LLVMTypeRef src_type = LLVMTypeOf(*src);242unsigned src_length = LLVMGetTypeKind(src_type) == LLVMVectorTypeKind ?243LLVMGetVectorSize(src_type) : 1;244struct lp_type i32_type = lp_type_int_vec(32, 32 * src_length);245246lp_build_context_init(&i32_bld, gallivm, i32_type);247248/* "rescale" and put in right position */249rcomp = lp_build_float_to_smallfloat(gallivm, i32_type, src[0], 6, 5, 0, false);250gcomp = lp_build_float_to_smallfloat(gallivm, i32_type, src[1], 6, 5, 11, false);251bcomp = lp_build_float_to_smallfloat(gallivm, i32_type, src[2], 5, 5, 22, false);252253/* combine the values */254dst = lp_build_or(&i32_bld, rcomp, gcomp);255return lp_build_or(&i32_bld, dst, bcomp);256}257258259/**260* Convert a float-like value with less exponent and mantissa261* bits than a normal float32 to a float32. The mantissa of262* the source value is assumed to have an implied 1, and the exponent263* is biased. There may be a sign bit.264* The source value to extract must be in a 32bit int (bits not part of265* the value to convert will be masked off).266* This works for things like 11-bit floats or half-floats,267* mantissa, exponent (and sign if present) must be packed268* the same as they are in a ordinary float.269*270* @param src (vector) value to convert271* @param mantissa_bits the number of mantissa bits272* @param exponent_bits the number of exponent bits273* @param mantissa_start the bit start position of the packed component274* @param has_sign if the small float has a sign bit275*276* ref http://fgiesen.wordpress.com/2012/03/28/half-to-float-done-quic/277* ref https://gist.github.com/rygorous/2156668278*/279LLVMValueRef280lp_build_smallfloat_to_float(struct gallivm_state *gallivm,281struct lp_type f32_type,282LLVMValueRef src,283unsigned mantissa_bits,284unsigned exponent_bits,285unsigned mantissa_start,286boolean has_sign)287{288LLVMBuilderRef builder = gallivm->builder;289LLVMValueRef smallexpmask, i32_floatexpmask, magic;290LLVMValueRef wasinfnan, tmp, res, shift, maskabs, srcabs, sign;291unsigned exponent_start = mantissa_start + mantissa_bits;292struct lp_type i32_type = lp_type_int_vec(32, 32 * f32_type.length);293struct lp_build_context f32_bld, i32_bld;294295lp_build_context_init(&f32_bld, gallivm, f32_type);296lp_build_context_init(&i32_bld, gallivm, i32_type);297298/* extract the component to "float position" */299if (exponent_start < 23) {300shift = lp_build_const_int_vec(gallivm, i32_type, 23 - exponent_start);301src = lp_build_shl(&i32_bld, src, shift);302}303else {304shift = lp_build_const_int_vec(gallivm, i32_type, exponent_start - 23);305src = lp_build_shr(&i32_bld, src, shift);306}307maskabs = lp_build_const_int_vec(gallivm, i32_type,308((1 << (mantissa_bits + exponent_bits)) - 1)309<< (23 - mantissa_bits));310srcabs = lp_build_and(&i32_bld, src, maskabs);311312/* now do the actual scaling */313smallexpmask = lp_build_const_int_vec(gallivm, i32_type,314((1 << exponent_bits) - 1) << 23);315i32_floatexpmask = lp_build_const_int_vec(gallivm, i32_type, 0xff << 23);316317if (0) {318/*319* Note that this code path, while simpler, will convert small320* float denorms to floats according to current cpu denorm mode, if321* denorms are disabled it will flush them to zero!322* If cpu denorms are enabled, it should be faster though as long as323* there's no denorms in the inputs, but if there are actually denorms324* it's likely to be an order of magnitude slower (on x86 cpus).325*/326327srcabs = LLVMBuildBitCast(builder, srcabs, f32_bld.vec_type, "");328329/*330* magic number has exponent new exp bias + (new exp bias - old exp bias),331* mantissa is 0.332*/333magic = lp_build_const_int_vec(gallivm, i32_type,334(255 - (1 << (exponent_bits - 1))) << 23);335magic = LLVMBuildBitCast(builder, magic, f32_bld.vec_type, "");336337/* adjust exponent and fix denorms */338res = lp_build_mul(&f32_bld, srcabs, magic);339340/*341* if exp was max (== NaN or Inf) set new exp to max (keep mantissa),342* so a simple "or" will do (because exp adjust will leave mantissa intact)343*/344/* use float compare (better for AVX 8-wide / no AVX2 but else should use int) */345smallexpmask = LLVMBuildBitCast(builder, smallexpmask, f32_bld.vec_type, "");346wasinfnan = lp_build_compare(gallivm, f32_type, PIPE_FUNC_GEQUAL, srcabs, smallexpmask);347res = LLVMBuildBitCast(builder, res, i32_bld.vec_type, "");348tmp = lp_build_and(&i32_bld, i32_floatexpmask, wasinfnan);349res = lp_build_or(&i32_bld, tmp, res);350}351352else {353LLVMValueRef exp_one, isdenorm, denorm, normal, exp_adj;354355/* denorm (or zero) if exponent is zero */356exp_one = lp_build_const_int_vec(gallivm, i32_type, 1 << 23);357isdenorm = lp_build_cmp(&i32_bld, PIPE_FUNC_LESS, srcabs, exp_one);358359/* inf or nan if exponent is max */360wasinfnan = lp_build_cmp(&i32_bld, PIPE_FUNC_GEQUAL, srcabs, smallexpmask);361362/* for denormal (or zero), add (== or) magic exp to mantissa (== srcabs) (as int)363* then subtract it (as float).364* Another option would be to just do inttofp then do a rescale mul.365*/366magic = lp_build_const_int_vec(gallivm, i32_type,367(127 - ((1 << (exponent_bits - 1)) - 2)) << 23);368denorm = lp_build_or(&i32_bld, srcabs, magic);369denorm = LLVMBuildBitCast(builder, denorm, f32_bld.vec_type, "");370denorm = lp_build_sub(&f32_bld, denorm,371LLVMBuildBitCast(builder, magic, f32_bld.vec_type, ""));372denorm = LLVMBuildBitCast(builder, denorm, i32_bld.vec_type, "");373374/* for normals, Infs, Nans fix up exponent */375exp_adj = lp_build_const_int_vec(gallivm, i32_type,376(127 - ((1 << (exponent_bits - 1)) - 1)) << 23);377normal = lp_build_add(&i32_bld, srcabs, exp_adj);378tmp = lp_build_and(&i32_bld, wasinfnan, i32_floatexpmask);379normal = lp_build_or(&i32_bld, tmp, normal);380381res = lp_build_select(&i32_bld, isdenorm, denorm, normal);382}383384if (has_sign) {385LLVMValueRef signmask = lp_build_const_int_vec(gallivm, i32_type, 0x80000000);386shift = lp_build_const_int_vec(gallivm, i32_type, 8 - exponent_bits);387sign = lp_build_shl(&i32_bld, src, shift);388sign = lp_build_and(&i32_bld, signmask, sign);389res = lp_build_or(&i32_bld, res, sign);390}391392return LLVMBuildBitCast(builder, res, f32_bld.vec_type, "");393}394395396/**397* Convert packed float format (r11g11b10) value(s) to rgba float SoA values.398*399* @param src packed AoS r11g11b10 values (as (vector) int32)400* @param dst pointer to the SoA result values401*/402void403lp_build_r11g11b10_to_float(struct gallivm_state *gallivm,404LLVMValueRef src,405LLVMValueRef *dst)406{407LLVMTypeRef src_type = LLVMTypeOf(src);408unsigned src_length = LLVMGetTypeKind(src_type) == LLVMVectorTypeKind ?409LLVMGetVectorSize(src_type) : 1;410struct lp_type f32_type = lp_type_float_vec(32, 32 * src_length);411412dst[0] = lp_build_smallfloat_to_float(gallivm, f32_type, src, 6, 5, 0, false);413dst[1] = lp_build_smallfloat_to_float(gallivm, f32_type, src, 6, 5, 11, false);414dst[2] = lp_build_smallfloat_to_float(gallivm, f32_type, src, 5, 5, 22, false);415416/* Just set alpha to one */417dst[3] = lp_build_one(gallivm, f32_type);418}419420421static LLVMValueRef422lp_build_rgb9_to_float_helper(struct gallivm_state *gallivm,423struct lp_type f32_type,424LLVMValueRef src,425LLVMValueRef scale,426unsigned mantissa_start)427{428LLVMValueRef shift, mask;429430struct lp_type i32_type = lp_type_int_vec(32, 32 * f32_type.length);431struct lp_build_context i32_bld, f32_bld;432433lp_build_context_init(&i32_bld, gallivm, i32_type);434lp_build_context_init(&f32_bld, gallivm, f32_type);435436/*437* This is much easier as other weirdo float formats, since438* there's no sign, no Inf/NaN, and there's nothing special439* required for normals/denormals neither (as without the implied one440* for the mantissa for other formats, everything looks like a denormal).441* So just do (float)comp_bits * scale442*/443shift = lp_build_const_int_vec(gallivm, i32_type, mantissa_start);444mask = lp_build_const_int_vec(gallivm, i32_type, 0x1ff);445src = lp_build_shr(&i32_bld, src, shift);446src = lp_build_and(&i32_bld, src, mask);447src = lp_build_int_to_float(&f32_bld, src);448return lp_build_mul(&f32_bld, src, scale);449}450451452/**453* Convert shared exponent format (rgb9e5) value(s) to rgba float SoA values.454*455* @param src packed AoS rgb9e5 values (as (vector) int32)456* @param dst pointer to the SoA result values457*/458void459lp_build_rgb9e5_to_float(struct gallivm_state *gallivm,460LLVMValueRef src,461LLVMValueRef *dst)462{463LLVMBuilderRef builder = gallivm->builder;464LLVMTypeRef src_type = LLVMTypeOf(src);465LLVMValueRef shift, scale, bias, exp;466unsigned src_length = LLVMGetTypeKind(src_type) == LLVMVectorTypeKind ?467LLVMGetVectorSize(src_type) : 1;468struct lp_type i32_type = lp_type_int_vec(32, 32 * src_length);469struct lp_type u32_type = lp_type_uint_vec(32, 32 * src_length);470struct lp_type f32_type = lp_type_float_vec(32, 32 * src_length);471struct lp_build_context i32_bld, u32_bld, f32_bld;472473lp_build_context_init(&i32_bld, gallivm, i32_type);474lp_build_context_init(&u32_bld, gallivm, u32_type);475lp_build_context_init(&f32_bld, gallivm, f32_type);476477/* extract exponent */478shift = lp_build_const_int_vec(gallivm, i32_type, 27);479/* this shift needs to be unsigned otherwise need mask */480exp = lp_build_shr(&u32_bld, src, shift);481482/*483* scale factor is 2 ^ (exp - bias)484* (and additionally corrected here for the mantissa bits)485* not using shift because486* a) don't have vector shift in a lot of cases487* b) shift direction changes hence need 2 shifts + conditional488* (or rotate instruction which is even more rare (for instance XOP))489* so use whacky float 2 ^ function instead manipulating exponent490* (saves us the float conversion at the end too)491*/492bias = lp_build_const_int_vec(gallivm, i32_type, 127 - (15 + 9));493scale = lp_build_add(&i32_bld, exp, bias);494shift = lp_build_const_int_vec(gallivm, i32_type, 23);495scale = lp_build_shl(&i32_bld, scale, shift);496scale = LLVMBuildBitCast(builder, scale, f32_bld.vec_type, "");497498dst[0] = lp_build_rgb9_to_float_helper(gallivm, f32_type, src, scale, 0);499dst[1] = lp_build_rgb9_to_float_helper(gallivm, f32_type, src, scale, 9);500dst[2] = lp_build_rgb9_to_float_helper(gallivm, f32_type, src, scale, 18);501502/* Just set alpha to one */503dst[3] = f32_bld.one;504}505506507