void lp_build_exp2_approx(struct lp_build_context *bld, LLVMValueRef x, LLVMValueRef *p_exp2_int_part, LLVMValueRef *p_frac_part, LLVMValueRef *p_exp2) { const struct lp_type type = bld->type; LLVMTypeRef vec_type = lp_build_vec_type(type); LLVMTypeRef int_vec_type = lp_build_int_vec_type(type); LLVMValueRef ipart = NULL; LLVMValueRef fpart = NULL; LLVMValueRef expipart = NULL; LLVMValueRef expfpart = NULL; LLVMValueRef res = NULL; if(p_exp2_int_part || p_frac_part || p_exp2) { /* TODO: optimize the constant case */ if(LLVMIsConstant(x)) debug_printf("%s: inefficient/imprecise constant arithmetic\n", __FUNCTION__); assert(type.floating && type.width == 32); x = lp_build_min(bld, x, lp_build_const_scalar(type, 129.0)); x = lp_build_max(bld, x, lp_build_const_scalar(type, -126.99999)); /* ipart = int(x - 0.5) */ ipart = LLVMBuildSub(bld->builder, x, lp_build_const_scalar(type, 0.5f), ""); ipart = LLVMBuildFPToSI(bld->builder, ipart, int_vec_type, ""); /* fpart = x - ipart */ fpart = LLVMBuildSIToFP(bld->builder, ipart, vec_type, ""); fpart = LLVMBuildSub(bld->builder, x, fpart, ""); } if(p_exp2_int_part || p_exp2) { /* expipart = (float) (1 << ipart) */ expipart = LLVMBuildAdd(bld->builder, ipart, lp_build_int_const_scalar(type, 127), ""); expipart = LLVMBuildShl(bld->builder, expipart, lp_build_int_const_scalar(type, 23), ""); expipart = LLVMBuildBitCast(bld->builder, expipart, vec_type, ""); } if(p_exp2) { expfpart = lp_build_polynomial(bld, fpart, lp_build_exp2_polynomial, Elements(lp_build_exp2_polynomial)); res = LLVMBuildMul(bld->builder, expipart, expfpart, ""); } if(p_exp2_int_part) *p_exp2_int_part = expipart; if(p_frac_part) *p_frac_part = fpart; if(p_exp2) *p_exp2 = res; }
static void emit_f2i(const struct lp_build_tgsi_action *action, struct lp_build_tgsi_context *bld_base, struct lp_build_emit_data *emit_data) { LLVMBuilderRef builder = bld_base->base.gallivm->builder; emit_data->output[emit_data->chan] = LLVMBuildFPToSI(builder, emit_data->args[0], bld_base->int_bld.elem_type, ""); }
static void number_conversion(compile_t* c, num_conv_t* from, num_conv_t* to, bool native128) { if(!native128 && ((from->is_float && (to->size > 64)) || (to->is_float && (from->size > 64))) ) { return; } reach_type_t* t = reach_type_name(c->reach, from->type_name); if(t == NULL) return; FIND_METHOD(to->fun_name); start_function(c, m, to->type, &from->type, 1); LLVMValueRef arg = LLVMGetParam(m->func, 0); LLVMValueRef result; if(from->is_float) { if(to->is_float) { if(from->size < to->size) result = LLVMBuildFPExt(c->builder, arg, to->type, ""); else if(from->size > to->size) result = LLVMBuildFPTrunc(c->builder, arg, to->type, ""); else result = arg; } else if(to->is_signed) { result = LLVMBuildFPToSI(c->builder, arg, to->type, ""); } else { result = LLVMBuildFPToUI(c->builder, arg, to->type, ""); } } else if(to->is_float) { if(from->is_signed) result = LLVMBuildSIToFP(c->builder, arg, to->type, ""); else result = LLVMBuildUIToFP(c->builder, arg, to->type, ""); } else if(from->size > to->size) { result = LLVMBuildTrunc(c->builder, arg, to->type, ""); } else if(from->size < to->size) { if(from->is_signed) result = LLVMBuildSExt(c->builder, arg, to->type, ""); else result = LLVMBuildZExt(c->builder, arg, to->type, ""); } else { result = arg; } LLVMBuildRet(c->builder, result); codegen_finishfun(c); BOX_FUNCTION(); }
static void emit_arl(const struct lp_build_tgsi_action *action, struct lp_build_tgsi_context *bld_base, struct lp_build_emit_data *emit_data) { LLVMBuilderRef builder = bld_base->base.gallivm->builder; LLVMValueRef floor_index = lp_build_emit_llvm_unary(bld_base, TGSI_OPCODE_FLR, emit_data->args[0]); emit_data->output[emit_data->chan] = LLVMBuildFPToSI(builder, floor_index, bld_base->base.int_elem_type , ""); }
/** * Convert to integer, through whichever rounding method that's fastest, * typically truncating toward zero. */ LLVMValueRef lp_build_itrunc(struct lp_build_context *bld, LLVMValueRef a) { const struct lp_type type = bld->type; LLVMTypeRef int_vec_type = lp_build_int_vec_type(type); assert(type.floating); assert(lp_check_value(type, a)); return LLVMBuildFPToSI(bld->builder, a, int_vec_type, ""); }
/** * Convert float[] to int[] with floor(). */ LLVMValueRef lp_build_ifloor(struct lp_build_context *bld, LLVMValueRef a) { const struct lp_type type = bld->type; LLVMTypeRef int_vec_type = lp_build_int_vec_type(type); LLVMValueRef res; assert(type.floating); assert(lp_check_value(type, a)); if(util_cpu_caps.has_sse4_1) { res = lp_build_round_sse41(bld, a, LP_BUILD_ROUND_SSE41_FLOOR); } else { /* Take the sign bit and add it to 1 constant */ LLVMTypeRef vec_type = lp_build_vec_type(type); unsigned mantissa = lp_mantissa(type); LLVMValueRef mask = lp_build_int_const_scalar(type, (unsigned long long)1 << (type.width - 1)); LLVMValueRef sign; LLVMValueRef offset; /* sign = a < 0 ? ~0 : 0 */ sign = LLVMBuildBitCast(bld->builder, a, int_vec_type, ""); sign = LLVMBuildAnd(bld->builder, sign, mask, ""); sign = LLVMBuildAShr(bld->builder, sign, lp_build_int_const_scalar(type, type.width - 1), ""); lp_build_name(sign, "floor.sign"); /* offset = -0.99999(9)f */ offset = lp_build_const_scalar(type, -(double)(((unsigned long long)1 << mantissa) - 1)/((unsigned long long)1 << mantissa)); offset = LLVMConstBitCast(offset, int_vec_type); /* offset = a < 0 ? -0.99999(9)f : 0.0f */ offset = LLVMBuildAnd(bld->builder, offset, sign, ""); offset = LLVMBuildBitCast(bld->builder, offset, vec_type, ""); lp_build_name(offset, "floor.offset"); res = LLVMBuildAdd(bld->builder, a, offset, ""); lp_build_name(res, "floor.res"); } res = LLVMBuildFPToSI(bld->builder, res, int_vec_type, ""); lp_build_name(res, "floor"); return res; }
LLVMValueRef lp_build_trunc(struct lp_build_context *bld, LLVMValueRef a) { const struct lp_type type = bld->type; assert(type.floating); assert(lp_check_value(type, a)); if(util_cpu_caps.has_sse4_1) return lp_build_round_sse41(bld, a, LP_BUILD_ROUND_SSE41_TRUNCATE); else { LLVMTypeRef vec_type = lp_build_vec_type(type); LLVMTypeRef int_vec_type = lp_build_int_vec_type(type); LLVMValueRef res; res = LLVMBuildFPToSI(bld->builder, a, int_vec_type, ""); res = LLVMBuildSIToFP(bld->builder, res, vec_type, ""); return res; } }
LLVMValueRef lp_build_iceil(struct lp_build_context *bld, LLVMValueRef a) { const struct lp_type type = bld->type; LLVMTypeRef int_vec_type = lp_build_int_vec_type(type); LLVMValueRef res; assert(type.floating); assert(lp_check_value(type, a)); if(util_cpu_caps.has_sse4_1) { res = lp_build_round_sse41(bld, a, LP_BUILD_ROUND_SSE41_CEIL); } else { assert(0); res = bld->undef; } res = LLVMBuildFPToSI(bld->builder, res, int_vec_type, ""); return res; }
LLVMValueRef lp_build_iround(struct lp_build_context *bld, LLVMValueRef a) { const struct lp_type type = bld->type; LLVMTypeRef int_vec_type = lp_build_int_vec_type(type); LLVMValueRef res; assert(type.floating); assert(lp_check_value(type, a)); if(util_cpu_caps.has_sse4_1) { res = lp_build_round_sse41(bld, a, LP_BUILD_ROUND_SSE41_NEAREST); } else { LLVMTypeRef vec_type = lp_build_vec_type(type); LLVMValueRef mask = lp_build_int_const_scalar(type, (unsigned long long)1 << (type.width - 1)); LLVMValueRef sign; LLVMValueRef half; /* get sign bit */ sign = LLVMBuildBitCast(bld->builder, a, int_vec_type, ""); sign = LLVMBuildAnd(bld->builder, sign, mask, ""); /* sign * 0.5 */ half = lp_build_const_scalar(type, 0.5); half = LLVMBuildBitCast(bld->builder, half, int_vec_type, ""); half = LLVMBuildOr(bld->builder, sign, half, ""); half = LLVMBuildBitCast(bld->builder, half, vec_type, ""); res = LLVMBuildAdd(bld->builder, a, half, ""); } res = LLVMBuildFPToSI(bld->builder, res, int_vec_type, ""); return res; }
/** * Special case for converting clamped IEEE-754 floats to unsigned norms. * * The mathematical voodoo below may seem excessive but it is actually * paramount we do it this way for several reasons. First, there is no single * precision FP to unsigned integer conversion Intel SSE instruction. Second, * secondly, even if there was, since the FP's mantissa takes only a fraction * of register bits the typically scale and cast approach would require double * precision for accurate results, and therefore half the throughput * * Although the result values can be scaled to an arbitrary bit width specified * by dst_width, the actual result type will have the same width. * * Ex: src = { float, float, float, float } * return { i32, i32, i32, i32 } where each value is in [0, 2^dst_width-1]. */ LLVMValueRef lp_build_clamped_float_to_unsigned_norm(struct gallivm_state *gallivm, struct lp_type src_type, unsigned dst_width, LLVMValueRef src) { LLVMBuilderRef builder = gallivm->builder; LLVMTypeRef int_vec_type = lp_build_int_vec_type(gallivm, src_type); LLVMValueRef res; unsigned mantissa; assert(src_type.floating); assert(dst_width <= src_type.width); src_type.sign = FALSE; mantissa = lp_mantissa(src_type); if (dst_width <= mantissa) { /* * Apply magic coefficients that will make the desired result to appear * in the lowest significant bits of the mantissa, with correct rounding. * * This only works if the destination width fits in the mantissa. */ unsigned long long ubound; unsigned long long mask; double scale; double bias; ubound = (1ULL << dst_width); mask = ubound - 1; scale = (double)mask/ubound; bias = (double)(1ULL << (mantissa - dst_width)); res = LLVMBuildFMul(builder, src, lp_build_const_vec(gallivm, src_type, scale), ""); res = LLVMBuildFAdd(builder, res, lp_build_const_vec(gallivm, src_type, bias), ""); res = LLVMBuildBitCast(builder, res, int_vec_type, ""); res = LLVMBuildAnd(builder, res, lp_build_const_int_vec(gallivm, src_type, mask), ""); } else if (dst_width == (mantissa + 1)) { /* * The destination width matches exactly what can be represented in * floating point (i.e., mantissa + 1 bits). So do a straight * multiplication followed by casting. No further rounding is necessary. */ double scale; scale = (double)((1ULL << dst_width) - 1); res = LLVMBuildFMul(builder, src, lp_build_const_vec(gallivm, src_type, scale), ""); res = LLVMBuildFPToSI(builder, res, int_vec_type, ""); } else { /* * The destination exceeds what can be represented in the floating point. * So multiply by the largest power two we get away with, and when * subtract the most significant bit to rescale to normalized values. * * The largest power of two factor we can get away is * (1 << (src_type.width - 1)), because we need to use signed . In theory it * should be (1 << (src_type.width - 2)), but IEEE 754 rules states * INT_MIN should be returned in FPToSI, which is the correct result for * values near 1.0! * * This means we get (src_type.width - 1) correct bits for values near 0.0, * and (mantissa + 1) correct bits for values near 1.0. Equally or more * important, we also get exact results for 0.0 and 1.0. */ unsigned n = MIN2(src_type.width - 1, dst_width); double scale = (double)(1ULL << n); unsigned lshift = dst_width - n; unsigned rshift = n; LLVMValueRef lshifted; LLVMValueRef rshifted; res = LLVMBuildFMul(builder, src, lp_build_const_vec(gallivm, src_type, scale), ""); res = LLVMBuildFPToSI(builder, res, int_vec_type, ""); /* * Align the most significant bit to its final place. * * This will cause 1.0 to overflow to 0, but the later adjustment will * get it right. */ if (lshift) { lshifted = LLVMBuildShl(builder, res, lp_build_const_int_vec(gallivm, src_type, lshift), ""); } else { lshifted = res; } /* * Align the most significant bit to the right. */ rshifted = LLVMBuildLShr(builder, res, lp_build_const_int_vec(gallivm, src_type, rshift), ""); /* * Subtract the MSB to the LSB, therefore re-scaling from * (1 << dst_width) to ((1 << dst_width) - 1). */ res = LLVMBuildSub(builder, lshifted, rshifted, ""); } return res; }
/** * Generic type conversion. * * TODO: Take a precision argument, or even better, add a new precision member * to the lp_type union. */ void lp_build_conv(LLVMBuilderRef builder, struct lp_type src_type, struct lp_type dst_type, const LLVMValueRef *src, unsigned num_srcs, LLVMValueRef *dst, unsigned num_dsts) { struct lp_type tmp_type; LLVMValueRef tmp[LP_MAX_VECTOR_LENGTH]; unsigned num_tmps; unsigned i; /* We must not loose or gain channels. Only precision */ assert(src_type.length * num_srcs == dst_type.length * num_dsts); assert(src_type.length <= LP_MAX_VECTOR_LENGTH); assert(dst_type.length <= LP_MAX_VECTOR_LENGTH); assert(num_srcs <= LP_MAX_VECTOR_LENGTH); assert(num_dsts <= LP_MAX_VECTOR_LENGTH); tmp_type = src_type; for(i = 0; i < num_srcs; ++i) { assert(lp_check_value(src_type, src[i])); tmp[i] = src[i]; } num_tmps = num_srcs; /* * Clamp if necessary */ if(memcmp(&src_type, &dst_type, sizeof src_type) != 0) { struct lp_build_context bld; double src_min = lp_const_min(src_type); double dst_min = lp_const_min(dst_type); double src_max = lp_const_max(src_type); double dst_max = lp_const_max(dst_type); LLVMValueRef thres; lp_build_context_init(&bld, builder, tmp_type); if(src_min < dst_min) { if(dst_min == 0.0) thres = bld.zero; else thres = lp_build_const_vec(src_type, dst_min); for(i = 0; i < num_tmps; ++i) tmp[i] = lp_build_max(&bld, tmp[i], thres); } if(src_max > dst_max) { if(dst_max == 1.0) thres = bld.one; else thres = lp_build_const_vec(src_type, dst_max); for(i = 0; i < num_tmps; ++i) tmp[i] = lp_build_min(&bld, tmp[i], thres); } } /* * Scale to the narrowest range */ if(dst_type.floating) { /* Nothing to do */ } else if(tmp_type.floating) { if(!dst_type.fixed && !dst_type.sign && dst_type.norm) { for(i = 0; i < num_tmps; ++i) { tmp[i] = lp_build_clamped_float_to_unsigned_norm(builder, tmp_type, dst_type.width, tmp[i]); } tmp_type.floating = FALSE; } else { double dst_scale = lp_const_scale(dst_type); LLVMTypeRef tmp_vec_type; if (dst_scale != 1.0) { LLVMValueRef scale = lp_build_const_vec(tmp_type, dst_scale); for(i = 0; i < num_tmps; ++i) tmp[i] = LLVMBuildFMul(builder, tmp[i], scale, ""); } /* Use an equally sized integer for intermediate computations */ tmp_type.floating = FALSE; tmp_vec_type = lp_build_vec_type(tmp_type); for(i = 0; i < num_tmps; ++i) { #if 0 if(dst_type.sign) tmp[i] = LLVMBuildFPToSI(builder, tmp[i], tmp_vec_type, ""); else tmp[i] = LLVMBuildFPToUI(builder, tmp[i], tmp_vec_type, ""); #else /* FIXME: there is no SSE counterpart for LLVMBuildFPToUI */ tmp[i] = LLVMBuildFPToSI(builder, tmp[i], tmp_vec_type, ""); #endif } } } else { unsigned src_shift = lp_const_shift(src_type); unsigned dst_shift = lp_const_shift(dst_type); /* FIXME: compensate different offsets too */ if(src_shift > dst_shift) { LLVMValueRef shift = lp_build_const_int_vec(tmp_type, src_shift - dst_shift); for(i = 0; i < num_tmps; ++i) if(src_type.sign) tmp[i] = LLVMBuildAShr(builder, tmp[i], shift, ""); else tmp[i] = LLVMBuildLShr(builder, tmp[i], shift, ""); } } /* * Truncate or expand bit width * * No data conversion should happen here, although the sign bits are * crucial to avoid bad clamping. */ { struct lp_type new_type; new_type = tmp_type; new_type.sign = dst_type.sign; new_type.width = dst_type.width; new_type.length = dst_type.length; lp_build_resize(builder, tmp_type, new_type, tmp, num_srcs, tmp, num_dsts); tmp_type = new_type; num_tmps = num_dsts; } /* * Scale to the widest range */ if(src_type.floating) { /* Nothing to do */ } else if(!src_type.floating && dst_type.floating) { if(!src_type.fixed && !src_type.sign && src_type.norm) { for(i = 0; i < num_tmps; ++i) { tmp[i] = lp_build_unsigned_norm_to_float(builder, src_type.width, dst_type, tmp[i]); } tmp_type.floating = TRUE; } else { double src_scale = lp_const_scale(src_type); LLVMTypeRef tmp_vec_type; /* Use an equally sized integer for intermediate computations */ tmp_type.floating = TRUE; tmp_type.sign = TRUE; tmp_vec_type = lp_build_vec_type(tmp_type); for(i = 0; i < num_tmps; ++i) { #if 0 if(dst_type.sign) tmp[i] = LLVMBuildSIToFP(builder, tmp[i], tmp_vec_type, ""); else tmp[i] = LLVMBuildUIToFP(builder, tmp[i], tmp_vec_type, ""); #else /* FIXME: there is no SSE counterpart for LLVMBuildUIToFP */ tmp[i] = LLVMBuildSIToFP(builder, tmp[i], tmp_vec_type, ""); #endif } if (src_scale != 1.0) { LLVMValueRef scale = lp_build_const_vec(tmp_type, 1.0/src_scale); for(i = 0; i < num_tmps; ++i) tmp[i] = LLVMBuildFMul(builder, tmp[i], scale, ""); } } } else { unsigned src_shift = lp_const_shift(src_type); unsigned dst_shift = lp_const_shift(dst_type); /* FIXME: compensate different offsets too */ if(src_shift < dst_shift) { LLVMValueRef shift = lp_build_const_int_vec(tmp_type, dst_shift - src_shift); for(i = 0; i < num_tmps; ++i) tmp[i] = LLVMBuildShl(builder, tmp[i], shift, ""); } } for(i = 0; i < num_dsts; ++i) { dst[i] = tmp[i]; assert(lp_check_value(dst_type, dst[i])); } }
/** * Sample the texture/mipmap using given image filter and mip filter. * data0_ptr and data1_ptr point to the two mipmap levels to sample * from. width0/1_vec, height0/1_vec, depth0/1_vec indicate their sizes. * If we're using nearest miplevel sampling the '1' values will be null/unused. */ static void lp_build_sample_mipmap(struct lp_build_sample_context *bld, unsigned img_filter, unsigned mip_filter, LLVMValueRef s, LLVMValueRef t, LLVMValueRef r, LLVMValueRef ilevel0, LLVMValueRef ilevel1, LLVMValueRef lod_fpart, LLVMValueRef colors_lo_var, LLVMValueRef colors_hi_var) { LLVMBuilderRef builder = bld->gallivm->builder; LLVMValueRef size0; LLVMValueRef size1; LLVMValueRef row_stride0_vec; LLVMValueRef row_stride1_vec; LLVMValueRef img_stride0_vec; LLVMValueRef img_stride1_vec; LLVMValueRef data_ptr0; LLVMValueRef data_ptr1; LLVMValueRef colors0_lo, colors0_hi; LLVMValueRef colors1_lo, colors1_hi; /* sample the first mipmap level */ lp_build_mipmap_level_sizes(bld, ilevel0, &size0, &row_stride0_vec, &img_stride0_vec); data_ptr0 = lp_build_get_mipmap_level(bld, ilevel0); if (img_filter == PIPE_TEX_FILTER_NEAREST) { lp_build_sample_image_nearest(bld, size0, row_stride0_vec, img_stride0_vec, data_ptr0, s, t, r, &colors0_lo, &colors0_hi); } else { assert(img_filter == PIPE_TEX_FILTER_LINEAR); lp_build_sample_image_linear(bld, size0, row_stride0_vec, img_stride0_vec, data_ptr0, s, t, r, &colors0_lo, &colors0_hi); } /* Store the first level's colors in the output variables */ LLVMBuildStore(builder, colors0_lo, colors_lo_var); LLVMBuildStore(builder, colors0_hi, colors_hi_var); if (mip_filter == PIPE_TEX_MIPFILTER_LINEAR) { LLVMValueRef h16_scale = lp_build_const_float(bld->gallivm, 256.0); LLVMTypeRef i32_type = LLVMIntTypeInContext(bld->gallivm->context, 32); struct lp_build_if_state if_ctx; LLVMValueRef need_lerp; lod_fpart = LLVMBuildFMul(builder, lod_fpart, h16_scale, ""); lod_fpart = LLVMBuildFPToSI(builder, lod_fpart, i32_type, "lod_fpart.fixed16"); /* need_lerp = lod_fpart > 0 */ need_lerp = LLVMBuildICmp(builder, LLVMIntSGT, lod_fpart, LLVMConstNull(i32_type), "need_lerp"); lp_build_if(&if_ctx, bld->gallivm, need_lerp); { struct lp_build_context h16_bld; lp_build_context_init(&h16_bld, bld->gallivm, lp_type_ufixed(16)); /* sample the second mipmap level */ lp_build_mipmap_level_sizes(bld, ilevel1, &size1, &row_stride1_vec, &img_stride1_vec); data_ptr1 = lp_build_get_mipmap_level(bld, ilevel1); if (img_filter == PIPE_TEX_FILTER_NEAREST) { lp_build_sample_image_nearest(bld, size1, row_stride1_vec, img_stride1_vec, data_ptr1, s, t, r, &colors1_lo, &colors1_hi); } else { lp_build_sample_image_linear(bld, size1, row_stride1_vec, img_stride1_vec, data_ptr1, s, t, r, &colors1_lo, &colors1_hi); } /* interpolate samples from the two mipmap levels */ lod_fpart = LLVMBuildTrunc(builder, lod_fpart, h16_bld.elem_type, ""); lod_fpart = lp_build_broadcast_scalar(&h16_bld, lod_fpart); #if HAVE_LLVM == 0x208 /* This is a work-around for a bug in LLVM 2.8. * Evidently, something goes wrong in the construction of the * lod_fpart short[8] vector. Adding this no-effect shuffle seems * to force the vector to be properly constructed. * Tested with mesa-demos/src/tests/mipmap_limits.c (press t, f). */ { LLVMValueRef shuffles[8], shuffle; int i; assert(h16_bld.type.length <= Elements(shuffles)); for (i = 0; i < h16_bld.type.length; i++) shuffles[i] = lp_build_const_int32(bld->gallivm, 2 * (i & 1)); shuffle = LLVMConstVector(shuffles, h16_bld.type.length); lod_fpart = LLVMBuildShuffleVector(builder, lod_fpart, lod_fpart, shuffle, ""); } #endif colors0_lo = lp_build_lerp(&h16_bld, lod_fpart, colors0_lo, colors1_lo); colors0_hi = lp_build_lerp(&h16_bld, lod_fpart, colors0_hi, colors1_hi); LLVMBuildStore(builder, colors0_lo, colors_lo_var); LLVMBuildStore(builder, colors0_hi, colors_hi_var); } lp_build_endif(&if_ctx); } }
/** * Sample a single texture image with nearest sampling. * If sampling a cube texture, r = cube face in [0,5]. * Return filtered color as two vectors of 16-bit fixed point values. */ static void lp_build_sample_image_nearest(struct lp_build_sample_context *bld, LLVMValueRef int_size, LLVMValueRef row_stride_vec, LLVMValueRef img_stride_vec, LLVMValueRef data_ptr, LLVMValueRef s, LLVMValueRef t, LLVMValueRef r, LLVMValueRef *colors_lo, LLVMValueRef *colors_hi) { const unsigned dims = bld->dims; LLVMBuilderRef builder = bld->gallivm->builder; struct lp_build_context i32, h16, u8n; LLVMTypeRef i32_vec_type, h16_vec_type, u8n_vec_type; LLVMValueRef i32_c8; LLVMValueRef width_vec, height_vec, depth_vec; LLVMValueRef s_ipart, t_ipart = NULL, r_ipart = NULL; LLVMValueRef x_stride; LLVMValueRef x_offset, offset; LLVMValueRef x_subcoord, y_subcoord, z_subcoord; lp_build_context_init(&i32, bld->gallivm, lp_type_int_vec(32)); lp_build_context_init(&h16, bld->gallivm, lp_type_ufixed(16)); lp_build_context_init(&u8n, bld->gallivm, lp_type_unorm(8)); i32_vec_type = lp_build_vec_type(bld->gallivm, i32.type); h16_vec_type = lp_build_vec_type(bld->gallivm, h16.type); u8n_vec_type = lp_build_vec_type(bld->gallivm, u8n.type); lp_build_extract_image_sizes(bld, bld->int_size_type, bld->int_coord_type, int_size, &width_vec, &height_vec, &depth_vec); if (bld->static_state->normalized_coords) { LLVMValueRef scaled_size; LLVMValueRef flt_size; /* scale size by 256 (8 fractional bits) */ scaled_size = lp_build_shl_imm(&bld->int_size_bld, int_size, 8); flt_size = lp_build_int_to_float(&bld->float_size_bld, scaled_size); lp_build_unnormalized_coords(bld, flt_size, &s, &t, &r); } else { /* scale coords by 256 (8 fractional bits) */ s = lp_build_mul_imm(&bld->coord_bld, s, 256); if (dims >= 2) t = lp_build_mul_imm(&bld->coord_bld, t, 256); if (dims >= 3) r = lp_build_mul_imm(&bld->coord_bld, r, 256); } /* convert float to int */ s = LLVMBuildFPToSI(builder, s, i32_vec_type, ""); if (dims >= 2) t = LLVMBuildFPToSI(builder, t, i32_vec_type, ""); if (dims >= 3) r = LLVMBuildFPToSI(builder, r, i32_vec_type, ""); /* compute floor (shift right 8) */ i32_c8 = lp_build_const_int_vec(bld->gallivm, i32.type, 8); s_ipart = LLVMBuildAShr(builder, s, i32_c8, ""); if (dims >= 2) t_ipart = LLVMBuildAShr(builder, t, i32_c8, ""); if (dims >= 3) r_ipart = LLVMBuildAShr(builder, r, i32_c8, ""); /* get pixel, row, image strides */ x_stride = lp_build_const_vec(bld->gallivm, bld->int_coord_bld.type, bld->format_desc->block.bits/8); /* Do texcoord wrapping, compute texel offset */ lp_build_sample_wrap_nearest_int(bld, bld->format_desc->block.width, s_ipart, width_vec, x_stride, bld->static_state->pot_width, bld->static_state->wrap_s, &x_offset, &x_subcoord); offset = x_offset; if (dims >= 2) { LLVMValueRef y_offset; lp_build_sample_wrap_nearest_int(bld, bld->format_desc->block.height, t_ipart, height_vec, row_stride_vec, bld->static_state->pot_height, bld->static_state->wrap_t, &y_offset, &y_subcoord); offset = lp_build_add(&bld->int_coord_bld, offset, y_offset); if (dims >= 3) { LLVMValueRef z_offset; lp_build_sample_wrap_nearest_int(bld, 1, /* block length (depth) */ r_ipart, depth_vec, img_stride_vec, bld->static_state->pot_height, bld->static_state->wrap_r, &z_offset, &z_subcoord); offset = lp_build_add(&bld->int_coord_bld, offset, z_offset); } else if (bld->static_state->target == PIPE_TEXTURE_CUBE) { LLVMValueRef z_offset; /* The r coord is the cube face in [0,5] */ z_offset = lp_build_mul(&bld->int_coord_bld, r, img_stride_vec); offset = lp_build_add(&bld->int_coord_bld, offset, z_offset); } } /* * Fetch the pixels as 4 x 32bit (rgba order might differ): * * rgba0 rgba1 rgba2 rgba3 * * bit cast them into 16 x u8 * * r0 g0 b0 a0 r1 g1 b1 a1 r2 g2 b2 a2 r3 g3 b3 a3 * * unpack them into two 8 x i16: * * r0 g0 b0 a0 r1 g1 b1 a1 * r2 g2 b2 a2 r3 g3 b3 a3 * * The higher 8 bits of the resulting elements will be zero. */ { LLVMValueRef rgba8; if (util_format_is_rgba8_variant(bld->format_desc)) { /* * Given the format is a rgba8, just read the pixels as is, * without any swizzling. Swizzling will be done later. */ rgba8 = lp_build_gather(bld->gallivm, bld->texel_type.length, bld->format_desc->block.bits, bld->texel_type.width, data_ptr, offset); rgba8 = LLVMBuildBitCast(builder, rgba8, u8n_vec_type, ""); } else { rgba8 = lp_build_fetch_rgba_aos(bld->gallivm, bld->format_desc, u8n.type, data_ptr, offset, x_subcoord, y_subcoord); } /* Expand one 4*rgba8 to two 2*rgba16 */ lp_build_unpack2(bld->gallivm, u8n.type, h16.type, rgba8, colors_lo, colors_hi); } }
/** * Generic type conversion. * * TODO: Take a precision argument, or even better, add a new precision member * to the lp_type union. */ void lp_build_conv(struct gallivm_state *gallivm, struct lp_type src_type, struct lp_type dst_type, const LLVMValueRef *src, unsigned num_srcs, LLVMValueRef *dst, unsigned num_dsts) { LLVMBuilderRef builder = gallivm->builder; struct lp_type tmp_type; LLVMValueRef tmp[LP_MAX_VECTOR_LENGTH]; unsigned num_tmps; unsigned i; /* We must not loose or gain channels. Only precision */ assert(src_type.length * num_srcs == dst_type.length * num_dsts); assert(src_type.length <= LP_MAX_VECTOR_LENGTH); assert(dst_type.length <= LP_MAX_VECTOR_LENGTH); assert(num_srcs <= LP_MAX_VECTOR_LENGTH); assert(num_dsts <= LP_MAX_VECTOR_LENGTH); tmp_type = src_type; for(i = 0; i < num_srcs; ++i) { assert(lp_check_value(src_type, src[i])); tmp[i] = src[i]; } num_tmps = num_srcs; /* Special case 4x4f --> 1x16ub */ if (src_type.floating == 1 && src_type.fixed == 0 && src_type.sign == 1 && src_type.norm == 0 && src_type.width == 32 && src_type.length == 4 && dst_type.floating == 0 && dst_type.fixed == 0 && dst_type.sign == 0 && dst_type.norm == 1 && dst_type.width == 8 && dst_type.length == 16 && 4 * num_dsts == num_srcs && util_cpu_caps.has_sse2) { struct lp_build_context bld; struct lp_type int16_type = dst_type; struct lp_type int32_type = dst_type; LLVMValueRef const_255f; unsigned i, j; lp_build_context_init(&bld, gallivm, src_type); int16_type.width *= 2; int16_type.length /= 2; int16_type.sign = 1; int32_type.width *= 4; int32_type.length /= 4; int32_type.sign = 1; const_255f = lp_build_const_vec(gallivm, src_type, 255.0f); for (i = 0; i < num_dsts; ++i, src += 4) { LLVMValueRef lo, hi; for (j = 0; j < 4; ++j) { tmp[j] = LLVMBuildFMul(builder, src[j], const_255f, ""); tmp[j] = lp_build_iround(&bld, tmp[j]); } /* relying on clamping behavior of sse2 intrinsics here */ lo = lp_build_pack2(gallivm, int32_type, int16_type, tmp[0], tmp[1]); hi = lp_build_pack2(gallivm, int32_type, int16_type, tmp[2], tmp[3]); dst[i] = lp_build_pack2(gallivm, int16_type, dst_type, lo, hi); } return; } /* Special case 2x8f --> 1x16ub */ else if (src_type.floating == 1 && src_type.fixed == 0 && src_type.sign == 1 && src_type.norm == 0 && src_type.width == 32 && src_type.length == 8 && dst_type.floating == 0 && dst_type.fixed == 0 && dst_type.sign == 0 && dst_type.norm == 1 && dst_type.width == 8 && dst_type.length == 16 && 2 * num_dsts == num_srcs && util_cpu_caps.has_avx) { struct lp_build_context bld; struct lp_type int16_type = dst_type; struct lp_type int32_type = dst_type; LLVMValueRef const_255f; unsigned i; lp_build_context_init(&bld, gallivm, src_type); int16_type.width *= 2; int16_type.length /= 2; int16_type.sign = 1; int32_type.width *= 4; int32_type.length /= 4; int32_type.sign = 1; const_255f = lp_build_const_vec(gallivm, src_type, 255.0f); for (i = 0; i < num_dsts; ++i, src += 2) { LLVMValueRef lo, hi, a, b; a = LLVMBuildFMul(builder, src[0], const_255f, ""); b = LLVMBuildFMul(builder, src[1], const_255f, ""); a = lp_build_iround(&bld, a); b = lp_build_iround(&bld, b); tmp[0] = lp_build_extract_range(gallivm, a, 0, 4); tmp[1] = lp_build_extract_range(gallivm, a, 4, 4); tmp[2] = lp_build_extract_range(gallivm, b, 0, 4); tmp[3] = lp_build_extract_range(gallivm, b, 4, 4); /* relying on clamping behavior of sse2 intrinsics here */ lo = lp_build_pack2(gallivm, int32_type, int16_type, tmp[0], tmp[1]); hi = lp_build_pack2(gallivm, int32_type, int16_type, tmp[2], tmp[3]); dst[i] = lp_build_pack2(gallivm, int16_type, dst_type, lo, hi); } return; } /* Pre convert half-floats to floats */ else if (src_type.floating && src_type.width == 16) { for(i = 0; i < num_tmps; ++i) tmp[i] = lp_build_half_to_float(gallivm, src_type, tmp[i]); tmp_type.width = 32; } /* * Clamp if necessary */ if(memcmp(&src_type, &dst_type, sizeof src_type) != 0) { struct lp_build_context bld; double src_min = lp_const_min(src_type); double dst_min = lp_const_min(dst_type); double src_max = lp_const_max(src_type); double dst_max = lp_const_max(dst_type); LLVMValueRef thres; lp_build_context_init(&bld, gallivm, tmp_type); if(src_min < dst_min) { if(dst_min == 0.0) thres = bld.zero; else thres = lp_build_const_vec(gallivm, src_type, dst_min); for(i = 0; i < num_tmps; ++i) tmp[i] = lp_build_max(&bld, tmp[i], thres); } if(src_max > dst_max) { if(dst_max == 1.0) thres = bld.one; else thres = lp_build_const_vec(gallivm, src_type, dst_max); for(i = 0; i < num_tmps; ++i) tmp[i] = lp_build_min(&bld, tmp[i], thres); } } /* * Scale to the narrowest range */ if(dst_type.floating) { /* Nothing to do */ } else if(tmp_type.floating) { if(!dst_type.fixed && !dst_type.sign && dst_type.norm) { for(i = 0; i < num_tmps; ++i) { tmp[i] = lp_build_clamped_float_to_unsigned_norm(gallivm, tmp_type, dst_type.width, tmp[i]); } tmp_type.floating = FALSE; } else { double dst_scale = lp_const_scale(dst_type); LLVMTypeRef tmp_vec_type; if (dst_scale != 1.0) { LLVMValueRef scale = lp_build_const_vec(gallivm, tmp_type, dst_scale); for(i = 0; i < num_tmps; ++i) tmp[i] = LLVMBuildFMul(builder, tmp[i], scale, ""); } /* Use an equally sized integer for intermediate computations */ tmp_type.floating = FALSE; tmp_vec_type = lp_build_vec_type(gallivm, tmp_type); for(i = 0; i < num_tmps; ++i) { #if 0 if(dst_type.sign) tmp[i] = LLVMBuildFPToSI(builder, tmp[i], tmp_vec_type, ""); else tmp[i] = LLVMBuildFPToUI(builder, tmp[i], tmp_vec_type, ""); #else /* FIXME: there is no SSE counterpart for LLVMBuildFPToUI */ tmp[i] = LLVMBuildFPToSI(builder, tmp[i], tmp_vec_type, ""); #endif } } } else { unsigned src_shift = lp_const_shift(src_type); unsigned dst_shift = lp_const_shift(dst_type); unsigned src_offset = lp_const_offset(src_type); unsigned dst_offset = lp_const_offset(dst_type); /* Compensate for different offsets */ if (dst_offset > src_offset && src_type.width > dst_type.width) { for (i = 0; i < num_tmps; ++i) { LLVMValueRef shifted; LLVMValueRef shift = lp_build_const_int_vec(gallivm, tmp_type, src_shift - 1); if(src_type.sign) shifted = LLVMBuildAShr(builder, tmp[i], shift, ""); else shifted = LLVMBuildLShr(builder, tmp[i], shift, ""); tmp[i] = LLVMBuildSub(builder, tmp[i], shifted, ""); } } if(src_shift > dst_shift) { LLVMValueRef shift = lp_build_const_int_vec(gallivm, tmp_type, src_shift - dst_shift); for(i = 0; i < num_tmps; ++i) if(src_type.sign) tmp[i] = LLVMBuildAShr(builder, tmp[i], shift, ""); else tmp[i] = LLVMBuildLShr(builder, tmp[i], shift, ""); } } /* * Truncate or expand bit width * * No data conversion should happen here, although the sign bits are * crucial to avoid bad clamping. */ { struct lp_type new_type; new_type = tmp_type; new_type.sign = dst_type.sign; new_type.width = dst_type.width; new_type.length = dst_type.length; lp_build_resize(gallivm, tmp_type, new_type, tmp, num_srcs, tmp, num_dsts); tmp_type = new_type; num_tmps = num_dsts; } /* * Scale to the widest range */ if(src_type.floating) { /* Nothing to do */ } else if(!src_type.floating && dst_type.floating) { if(!src_type.fixed && !src_type.sign && src_type.norm) { for(i = 0; i < num_tmps; ++i) { tmp[i] = lp_build_unsigned_norm_to_float(gallivm, src_type.width, dst_type, tmp[i]); } tmp_type.floating = TRUE; } else { double src_scale = lp_const_scale(src_type); LLVMTypeRef tmp_vec_type; /* Use an equally sized integer for intermediate computations */ tmp_type.floating = TRUE; tmp_type.sign = TRUE; tmp_vec_type = lp_build_vec_type(gallivm, tmp_type); for(i = 0; i < num_tmps; ++i) { #if 0 if(dst_type.sign) tmp[i] = LLVMBuildSIToFP(builder, tmp[i], tmp_vec_type, ""); else tmp[i] = LLVMBuildUIToFP(builder, tmp[i], tmp_vec_type, ""); #else /* FIXME: there is no SSE counterpart for LLVMBuildUIToFP */ tmp[i] = LLVMBuildSIToFP(builder, tmp[i], tmp_vec_type, ""); #endif } if (src_scale != 1.0) { LLVMValueRef scale = lp_build_const_vec(gallivm, tmp_type, 1.0/src_scale); for(i = 0; i < num_tmps; ++i) tmp[i] = LLVMBuildFMul(builder, tmp[i], scale, ""); } } } else { unsigned src_shift = lp_const_shift(src_type); unsigned dst_shift = lp_const_shift(dst_type); unsigned src_offset = lp_const_offset(src_type); unsigned dst_offset = lp_const_offset(dst_type); if (src_shift < dst_shift) { LLVMValueRef pre_shift[LP_MAX_VECTOR_LENGTH]; LLVMValueRef shift = lp_build_const_int_vec(gallivm, tmp_type, dst_shift - src_shift); for (i = 0; i < num_tmps; ++i) { pre_shift[i] = tmp[i]; tmp[i] = LLVMBuildShl(builder, tmp[i], shift, ""); } /* Compensate for different offsets */ if (dst_offset > src_offset) { for (i = 0; i < num_tmps; ++i) { tmp[i] = LLVMBuildSub(builder, tmp[i], pre_shift[i], ""); } } } } for(i = 0; i < num_dsts; ++i) { dst[i] = tmp[i]; assert(lp_check_value(dst_type, dst[i])); } }
/** * Sample a single texture image with (bi-)(tri-)linear sampling. * Return filtered color as two vectors of 16-bit fixed point values. */ static void lp_build_sample_image_linear(struct lp_build_sample_context *bld, LLVMValueRef int_size, LLVMValueRef row_stride_vec, LLVMValueRef img_stride_vec, LLVMValueRef data_ptr, LLVMValueRef s, LLVMValueRef t, LLVMValueRef r, LLVMValueRef *colors_lo, LLVMValueRef *colors_hi) { const unsigned dims = bld->dims; LLVMBuilderRef builder = bld->gallivm->builder; struct lp_build_context i32, h16, u8n; LLVMTypeRef i32_vec_type, h16_vec_type, u8n_vec_type; LLVMValueRef i32_c8, i32_c128, i32_c255; LLVMValueRef width_vec, height_vec, depth_vec; LLVMValueRef s_ipart, s_fpart, s_fpart_lo, s_fpart_hi; LLVMValueRef t_ipart = NULL, t_fpart = NULL, t_fpart_lo = NULL, t_fpart_hi = NULL; LLVMValueRef r_ipart = NULL, r_fpart = NULL, r_fpart_lo = NULL, r_fpart_hi = NULL; LLVMValueRef x_stride, y_stride, z_stride; LLVMValueRef x_offset0, x_offset1; LLVMValueRef y_offset0, y_offset1; LLVMValueRef z_offset0, z_offset1; LLVMValueRef offset[2][2][2]; /* [z][y][x] */ LLVMValueRef x_subcoord[2], y_subcoord[2], z_subcoord[2]; LLVMValueRef neighbors_lo[2][2][2]; /* [z][y][x] */ LLVMValueRef neighbors_hi[2][2][2]; /* [z][y][x] */ LLVMValueRef packed_lo, packed_hi; unsigned x, y, z; unsigned i, j, k; unsigned numj, numk; lp_build_context_init(&i32, bld->gallivm, lp_type_int_vec(32)); lp_build_context_init(&h16, bld->gallivm, lp_type_ufixed(16)); lp_build_context_init(&u8n, bld->gallivm, lp_type_unorm(8)); i32_vec_type = lp_build_vec_type(bld->gallivm, i32.type); h16_vec_type = lp_build_vec_type(bld->gallivm, h16.type); u8n_vec_type = lp_build_vec_type(bld->gallivm, u8n.type); lp_build_extract_image_sizes(bld, bld->int_size_type, bld->int_coord_type, int_size, &width_vec, &height_vec, &depth_vec); if (bld->static_state->normalized_coords) { LLVMValueRef scaled_size; LLVMValueRef flt_size; /* scale size by 256 (8 fractional bits) */ scaled_size = lp_build_shl_imm(&bld->int_size_bld, int_size, 8); flt_size = lp_build_int_to_float(&bld->float_size_bld, scaled_size); lp_build_unnormalized_coords(bld, flt_size, &s, &t, &r); } else { /* scale coords by 256 (8 fractional bits) */ s = lp_build_mul_imm(&bld->coord_bld, s, 256); if (dims >= 2) t = lp_build_mul_imm(&bld->coord_bld, t, 256); if (dims >= 3) r = lp_build_mul_imm(&bld->coord_bld, r, 256); } /* convert float to int */ s = LLVMBuildFPToSI(builder, s, i32_vec_type, ""); if (dims >= 2) t = LLVMBuildFPToSI(builder, t, i32_vec_type, ""); if (dims >= 3) r = LLVMBuildFPToSI(builder, r, i32_vec_type, ""); /* subtract 0.5 (add -128) */ i32_c128 = lp_build_const_int_vec(bld->gallivm, i32.type, -128); s = LLVMBuildAdd(builder, s, i32_c128, ""); if (dims >= 2) { t = LLVMBuildAdd(builder, t, i32_c128, ""); } if (dims >= 3) { r = LLVMBuildAdd(builder, r, i32_c128, ""); } /* compute floor (shift right 8) */ i32_c8 = lp_build_const_int_vec(bld->gallivm, i32.type, 8); s_ipart = LLVMBuildAShr(builder, s, i32_c8, ""); if (dims >= 2) t_ipart = LLVMBuildAShr(builder, t, i32_c8, ""); if (dims >= 3) r_ipart = LLVMBuildAShr(builder, r, i32_c8, ""); /* compute fractional part (AND with 0xff) */ i32_c255 = lp_build_const_int_vec(bld->gallivm, i32.type, 255); s_fpart = LLVMBuildAnd(builder, s, i32_c255, ""); if (dims >= 2) t_fpart = LLVMBuildAnd(builder, t, i32_c255, ""); if (dims >= 3) r_fpart = LLVMBuildAnd(builder, r, i32_c255, ""); /* get pixel, row and image strides */ x_stride = lp_build_const_vec(bld->gallivm, bld->int_coord_bld.type, bld->format_desc->block.bits/8); y_stride = row_stride_vec; z_stride = img_stride_vec; /* do texcoord wrapping and compute texel offsets */ lp_build_sample_wrap_linear_int(bld, bld->format_desc->block.width, s_ipart, width_vec, x_stride, bld->static_state->pot_width, bld->static_state->wrap_s, &x_offset0, &x_offset1, &x_subcoord[0], &x_subcoord[1]); for (z = 0; z < 2; z++) { for (y = 0; y < 2; y++) { offset[z][y][0] = x_offset0; offset[z][y][1] = x_offset1; } } if (dims >= 2) { lp_build_sample_wrap_linear_int(bld, bld->format_desc->block.height, t_ipart, height_vec, y_stride, bld->static_state->pot_height, bld->static_state->wrap_t, &y_offset0, &y_offset1, &y_subcoord[0], &y_subcoord[1]); for (z = 0; z < 2; z++) { for (x = 0; x < 2; x++) { offset[z][0][x] = lp_build_add(&bld->int_coord_bld, offset[z][0][x], y_offset0); offset[z][1][x] = lp_build_add(&bld->int_coord_bld, offset[z][1][x], y_offset1); } } } if (dims >= 3) { lp_build_sample_wrap_linear_int(bld, bld->format_desc->block.height, r_ipart, depth_vec, z_stride, bld->static_state->pot_depth, bld->static_state->wrap_r, &z_offset0, &z_offset1, &z_subcoord[0], &z_subcoord[1]); for (y = 0; y < 2; y++) { for (x = 0; x < 2; x++) { offset[0][y][x] = lp_build_add(&bld->int_coord_bld, offset[0][y][x], z_offset0); offset[1][y][x] = lp_build_add(&bld->int_coord_bld, offset[1][y][x], z_offset1); } } } else if (bld->static_state->target == PIPE_TEXTURE_CUBE) { LLVMValueRef z_offset; z_offset = lp_build_mul(&bld->int_coord_bld, r, img_stride_vec); for (y = 0; y < 2; y++) { for (x = 0; x < 2; x++) { /* The r coord is the cube face in [0,5] */ offset[0][y][x] = lp_build_add(&bld->int_coord_bld, offset[0][y][x], z_offset); } } } /* * Transform 4 x i32 in * * s_fpart = {s0, s1, s2, s3} * * into 8 x i16 * * s_fpart = {00, s0, 00, s1, 00, s2, 00, s3} * * into two 8 x i16 * * s_fpart_lo = {s0, s0, s0, s0, s1, s1, s1, s1} * s_fpart_hi = {s2, s2, s2, s2, s3, s3, s3, s3} * * and likewise for t_fpart. There is no risk of loosing precision here * since the fractional parts only use the lower 8bits. */ s_fpart = LLVMBuildBitCast(builder, s_fpart, h16_vec_type, ""); if (dims >= 2) t_fpart = LLVMBuildBitCast(builder, t_fpart, h16_vec_type, ""); if (dims >= 3) r_fpart = LLVMBuildBitCast(builder, r_fpart, h16_vec_type, ""); { LLVMTypeRef elem_type = LLVMInt32TypeInContext(bld->gallivm->context); LLVMValueRef shuffles_lo[LP_MAX_VECTOR_LENGTH]; LLVMValueRef shuffles_hi[LP_MAX_VECTOR_LENGTH]; LLVMValueRef shuffle_lo; LLVMValueRef shuffle_hi; for (j = 0; j < h16.type.length; j += 4) { #ifdef PIPE_ARCH_LITTLE_ENDIAN unsigned subindex = 0; #else unsigned subindex = 1; #endif LLVMValueRef index; index = LLVMConstInt(elem_type, j/2 + subindex, 0); for (i = 0; i < 4; ++i) shuffles_lo[j + i] = index; index = LLVMConstInt(elem_type, h16.type.length/2 + j/2 + subindex, 0); for (i = 0; i < 4; ++i) shuffles_hi[j + i] = index; } shuffle_lo = LLVMConstVector(shuffles_lo, h16.type.length); shuffle_hi = LLVMConstVector(shuffles_hi, h16.type.length); s_fpart_lo = LLVMBuildShuffleVector(builder, s_fpart, h16.undef, shuffle_lo, ""); s_fpart_hi = LLVMBuildShuffleVector(builder, s_fpart, h16.undef, shuffle_hi, ""); if (dims >= 2) { t_fpart_lo = LLVMBuildShuffleVector(builder, t_fpart, h16.undef, shuffle_lo, ""); t_fpart_hi = LLVMBuildShuffleVector(builder, t_fpart, h16.undef, shuffle_hi, ""); } if (dims >= 3) { r_fpart_lo = LLVMBuildShuffleVector(builder, r_fpart, h16.undef, shuffle_lo, ""); r_fpart_hi = LLVMBuildShuffleVector(builder, r_fpart, h16.undef, shuffle_hi, ""); } } /* * Fetch the pixels as 4 x 32bit (rgba order might differ): * * rgba0 rgba1 rgba2 rgba3 * * bit cast them into 16 x u8 * * r0 g0 b0 a0 r1 g1 b1 a1 r2 g2 b2 a2 r3 g3 b3 a3 * * unpack them into two 8 x i16: * * r0 g0 b0 a0 r1 g1 b1 a1 * r2 g2 b2 a2 r3 g3 b3 a3 * * The higher 8 bits of the resulting elements will be zero. */ numj = 1 + (dims >= 2); numk = 1 + (dims >= 3); for (k = 0; k < numk; k++) { for (j = 0; j < numj; j++) { for (i = 0; i < 2; i++) { LLVMValueRef rgba8; if (util_format_is_rgba8_variant(bld->format_desc)) { /* * Given the format is a rgba8, just read the pixels as is, * without any swizzling. Swizzling will be done later. */ rgba8 = lp_build_gather(bld->gallivm, bld->texel_type.length, bld->format_desc->block.bits, bld->texel_type.width, data_ptr, offset[k][j][i]); rgba8 = LLVMBuildBitCast(builder, rgba8, u8n_vec_type, ""); } else { rgba8 = lp_build_fetch_rgba_aos(bld->gallivm, bld->format_desc, u8n.type, data_ptr, offset[k][j][i], x_subcoord[i], y_subcoord[j]); } /* Expand one 4*rgba8 to two 2*rgba16 */ lp_build_unpack2(bld->gallivm, u8n.type, h16.type, rgba8, &neighbors_lo[k][j][i], &neighbors_hi[k][j][i]); } } } /* * Linear interpolation with 8.8 fixed point. */ if (dims == 1) { /* 1-D lerp */ packed_lo = lp_build_lerp(&h16, s_fpart_lo, neighbors_lo[0][0][0], neighbors_lo[0][0][1]); packed_hi = lp_build_lerp(&h16, s_fpart_hi, neighbors_hi[0][0][0], neighbors_hi[0][0][1]); } else { /* 2-D lerp */ packed_lo = lp_build_lerp_2d(&h16, s_fpart_lo, t_fpart_lo, neighbors_lo[0][0][0], neighbors_lo[0][0][1], neighbors_lo[0][1][0], neighbors_lo[0][1][1]); packed_hi = lp_build_lerp_2d(&h16, s_fpart_hi, t_fpart_hi, neighbors_hi[0][0][0], neighbors_hi[0][0][1], neighbors_hi[0][1][0], neighbors_hi[0][1][1]); if (dims >= 3) { LLVMValueRef packed_lo2, packed_hi2; /* lerp in the second z slice */ packed_lo2 = lp_build_lerp_2d(&h16, s_fpart_lo, t_fpart_lo, neighbors_lo[1][0][0], neighbors_lo[1][0][1], neighbors_lo[1][1][0], neighbors_lo[1][1][1]); packed_hi2 = lp_build_lerp_2d(&h16, s_fpart_hi, t_fpart_hi, neighbors_hi[1][0][0], neighbors_hi[1][0][1], neighbors_hi[1][1][0], neighbors_hi[1][1][1]); /* interp between two z slices */ packed_lo = lp_build_lerp(&h16, r_fpart_lo, packed_lo, packed_lo2); packed_hi = lp_build_lerp(&h16, r_fpart_hi, packed_hi, packed_hi2); } } *colors_lo = packed_lo; *colors_hi = packed_hi; }
/** * Pack a single pixel. * * @param rgba 4 float vector with the unpacked components. * * XXX: This is mostly for reference and testing -- operating a single pixel at * a time is rarely if ever needed. */ LLVMValueRef lp_build_pack_rgba_aos(struct gallivm_state *gallivm, const struct util_format_description *desc, LLVMValueRef rgba) { LLVMBuilderRef builder = gallivm->builder; LLVMTypeRef type; LLVMValueRef packed = NULL; LLVMValueRef swizzles[4]; LLVMValueRef shifted, casted, scaled, unswizzled; LLVMValueRef shifts[4]; LLVMValueRef scales[4]; boolean normalized; unsigned shift; unsigned i, j; assert(desc->layout == UTIL_FORMAT_LAYOUT_PLAIN); assert(desc->block.width == 1); assert(desc->block.height == 1); type = LLVMIntTypeInContext(gallivm->context, desc->block.bits); /* Unswizzle the color components into the source vector. */ for (i = 0; i < 4; ++i) { for (j = 0; j < 4; ++j) { if (desc->swizzle[j] == i) break; } if (j < 4) swizzles[i] = lp_build_const_int32(gallivm, j); else swizzles[i] = LLVMGetUndef(LLVMInt32TypeInContext(gallivm->context)); } unswizzled = LLVMBuildShuffleVector(builder, rgba, LLVMGetUndef(LLVMVectorType(LLVMFloatTypeInContext(gallivm->context), 4)), LLVMConstVector(swizzles, 4), ""); normalized = FALSE; shift = 0; for (i = 0; i < 4; ++i) { unsigned bits = desc->channel[i].size; if (desc->channel[i].type == UTIL_FORMAT_TYPE_VOID) { shifts[i] = LLVMGetUndef(LLVMInt32TypeInContext(gallivm->context)); scales[i] = LLVMGetUndef(LLVMFloatTypeInContext(gallivm->context)); } else { unsigned mask = (1 << bits) - 1; assert(desc->channel[i].type == UTIL_FORMAT_TYPE_UNSIGNED); assert(bits < 32); shifts[i] = lp_build_const_int32(gallivm, shift); if (desc->channel[i].normalized) { scales[i] = lp_build_const_float(gallivm, mask); normalized = TRUE; } else scales[i] = lp_build_const_float(gallivm, 1.0); } shift += bits; } if (normalized) scaled = LLVMBuildFMul(builder, unswizzled, LLVMConstVector(scales, 4), ""); else scaled = unswizzled; casted = LLVMBuildFPToSI(builder, scaled, LLVMVectorType(LLVMInt32TypeInContext(gallivm->context), 4), ""); shifted = LLVMBuildShl(builder, casted, LLVMConstVector(shifts, 4), ""); /* Bitwise or all components */ for (i = 0; i < 4; ++i) { if (desc->channel[i].type == UTIL_FORMAT_TYPE_UNSIGNED) { LLVMValueRef component = LLVMBuildExtractElement(builder, shifted, lp_build_const_int32(gallivm, i), ""); if (packed) packed = LLVMBuildOr(builder, packed, component, ""); else packed = component; } } if (!packed) packed = LLVMGetUndef(LLVMInt32TypeInContext(gallivm->context)); if (desc->block.bits < 32) packed = LLVMBuildTrunc(builder, packed, type, ""); return packed; }
struct cl2llvm_val_t *llvm_type_cast(struct cl2llvm_val_t * original_val, struct cl2llvmTypeWrap *totype_w_sign) { struct cl2llvm_val_t *llvm_val = cl2llvm_val_create(); int i; struct cl2llvmTypeWrap *elem_type; struct cl2llvm_val_t *cast_original_val; LLVMValueRef index; LLVMValueRef vector_addr; LLVMValueRef vector; LLVMValueRef const_elems[16]; LLVMTypeRef fromtype = cl2llvmTypeWrapGetLlvmType(original_val->type); LLVMTypeRef totype = cl2llvmTypeWrapGetLlvmType(totype_w_sign); int fromsign = cl2llvmTypeWrapGetSign(original_val->type); int tosign = cl2llvmTypeWrapGetSign(totype_w_sign); /*By default the return value is the same as the original_val*/ llvm_val->val = original_val->val; cl2llvmTypeWrapSetLlvmType(llvm_val->type, cl2llvmTypeWrapGetLlvmType(original_val->type)); cl2llvmTypeWrapSetSign(llvm_val->type, cl2llvmTypeWrapGetSign(original_val->type)); snprintf(temp_var_name, sizeof temp_var_name, "tmp_%d", temp_var_count++); /* Check that fromtype is not a vector, unless both types are identical. */ if (LLVMGetTypeKind(fromtype) == LLVMVectorTypeKind) { if ((LLVMGetVectorSize(fromtype) != LLVMGetVectorSize(totype) || LLVMGetElementType(fromtype) != LLVMGetElementType(totype)) || fromsign != tosign) { if (LLVMGetTypeKind(totype) == LLVMVectorTypeKind) cl2llvm_yyerror("Casts between vector types are forbidden"); cl2llvm_yyerror("A vector may not be cast to any other type."); } } /* If totype is a vector, create a vector whose components are equal to original_val */ if (LLVMGetTypeKind(totype) == LLVMVectorTypeKind && LLVMGetTypeKind(fromtype) != LLVMVectorTypeKind) { /*Go to entry block and declare vector*/ LLVMPositionBuilder(cl2llvm_builder, cl2llvm_current_function->entry_block, cl2llvm_current_function->branch_instr); snprintf(temp_var_name, sizeof temp_var_name, "tmp_%d", temp_var_count++); vector_addr = LLVMBuildAlloca(cl2llvm_builder, totype, temp_var_name); LLVMPositionBuilderAtEnd(cl2llvm_builder, current_basic_block); /* Load vector */ snprintf(temp_var_name, sizeof temp_var_name, "tmp_%d", temp_var_count++); vector = LLVMBuildLoad(cl2llvm_builder, vector_addr, temp_var_name); /* Create object to represent element type of totype */ elem_type = cl2llvmTypeWrapCreate(LLVMGetElementType(totype), tosign); /* If original_val is constant create a constant vector */ if (LLVMIsConstant(original_val->val)) { cast_original_val = llvm_type_cast(original_val, elem_type); for (i = 0; i < LLVMGetVectorSize(totype); i++) const_elems[i] = cast_original_val->val; vector = LLVMConstVector(const_elems, LLVMGetVectorSize(totype)); llvm_val->val = vector; cl2llvm_val_free(cast_original_val); } /* If original value is not constant insert elements */ else { for (i = 0; i < LLVMGetVectorSize(totype); i++) { index = LLVMConstInt(LLVMInt32Type(), i, 0); cast_original_val = llvm_type_cast(original_val, elem_type); snprintf(temp_var_name, sizeof temp_var_name, "tmp_%d", temp_var_count++); vector = LLVMBuildInsertElement(cl2llvm_builder, vector, cast_original_val->val, index, temp_var_name); cl2llvm_val_free(cast_original_val); } } cl2llvmTypeWrapFree(elem_type); llvm_val->val = vector; } if (fromtype == LLVMInt64Type()) { if (totype == LLVMDoubleType()) { if (fromsign) { llvm_val->val = LLVMBuildSIToFP(cl2llvm_builder, original_val->val, LLVMDoubleType(), temp_var_name); } else { llvm_val->val = LLVMBuildUIToFP(cl2llvm_builder, original_val->val, LLVMDoubleType(), temp_var_name); } cl2llvmTypeWrapSetSign(llvm_val->type, 1); } else if (totype == LLVMFloatType()) { if (fromsign) { llvm_val->val = LLVMBuildSIToFP(cl2llvm_builder, original_val->val, LLVMFloatType(), temp_var_name); } else { llvm_val->val = LLVMBuildUIToFP(cl2llvm_builder, original_val->val, LLVMFloatType(), temp_var_name); } cl2llvmTypeWrapSetSign(llvm_val->type, 1); } else if (totype == LLVMHalfType()) { if (fromsign) { llvm_val->val = LLVMBuildSIToFP(cl2llvm_builder, original_val->val, LLVMHalfType(), temp_var_name); } else { llvm_val->val = LLVMBuildUIToFP(cl2llvm_builder, original_val->val, LLVMHalfType(), temp_var_name); } cl2llvmTypeWrapSetSign(llvm_val->type, 1); } else if (totype == LLVMInt64Type()) { if (tosign) cl2llvmTypeWrapSetSign(llvm_val->type, 1); else cl2llvmTypeWrapSetSign(llvm_val->type, 0); temp_var_count--; } else if (totype == LLVMInt32Type()) { llvm_val->val = LLVMBuildTrunc(cl2llvm_builder, original_val->val, LLVMInt32Type(), temp_var_name); if(tosign) cl2llvmTypeWrapSetSign(llvm_val->type, 1); else cl2llvmTypeWrapSetSign(llvm_val->type, 0); } else if (totype == LLVMInt16Type()) { llvm_val->val = LLVMBuildTrunc(cl2llvm_builder, original_val->val, LLVMInt16Type(), temp_var_name); if(tosign) cl2llvmTypeWrapSetSign(llvm_val->type, 1); else cl2llvmTypeWrapSetSign(llvm_val->type, 0); } else if (totype == LLVMInt8Type()) { llvm_val->val = LLVMBuildTrunc(cl2llvm_builder, original_val->val, LLVMInt8Type(), temp_var_name); if(tosign) cl2llvmTypeWrapSetSign(llvm_val->type, 1); else cl2llvmTypeWrapSetSign(llvm_val->type, 0); } else if (totype == LLVMInt1Type()) { llvm_val->val = LLVMBuildTrunc(cl2llvm_builder, original_val->val, LLVMInt1Type(), temp_var_name); if(tosign) cl2llvmTypeWrapSetSign(llvm_val->type, 1); else cl2llvmTypeWrapSetSign(llvm_val->type, 0); } } else if (fromtype == LLVMInt32Type()) { if (totype == LLVMDoubleType()) { if (fromsign) { llvm_val->val = LLVMBuildSIToFP(cl2llvm_builder, original_val->val, LLVMDoubleType(), temp_var_name); } else { llvm_val->val = LLVMBuildUIToFP(cl2llvm_builder, original_val->val, LLVMDoubleType(), temp_var_name); } cl2llvmTypeWrapSetSign(llvm_val->type, 1); } else if (totype == LLVMFloatType()) { if (fromsign) { llvm_val->val = LLVMBuildSIToFP(cl2llvm_builder, original_val->val, LLVMFloatType(), temp_var_name); } else { llvm_val->val = LLVMBuildUIToFP(cl2llvm_builder, original_val->val, LLVMFloatType(), temp_var_name); } cl2llvmTypeWrapSetSign(llvm_val->type, 1); } else if (totype == LLVMHalfType()) { if (fromsign) { llvm_val->val = LLVMBuildSIToFP(cl2llvm_builder, original_val->val, LLVMHalfType(), temp_var_name); } else { llvm_val->val = LLVMBuildUIToFP(cl2llvm_builder, original_val->val, LLVMHalfType(), temp_var_name); } cl2llvmTypeWrapSetSign(llvm_val->type, 1); } else if (totype == LLVMInt64Type()) { if (fromsign) { llvm_val->val = LLVMBuildSExt(cl2llvm_builder, original_val->val, LLVMInt64Type(), temp_var_name); } else { llvm_val->val = LLVMBuildZExt(cl2llvm_builder, original_val->val, LLVMInt64Type(), temp_var_name); } if (tosign) cl2llvmTypeWrapSetSign(llvm_val->type, 1); else cl2llvmTypeWrapSetSign(llvm_val->type, 0); } else if (totype == LLVMInt32Type()) { if(tosign) cl2llvmTypeWrapSetSign(llvm_val->type, 1); else cl2llvmTypeWrapSetSign(llvm_val->type, 0); temp_var_count--; } else if (totype == LLVMInt16Type()) { llvm_val->val = LLVMBuildTrunc(cl2llvm_builder, original_val->val, LLVMInt16Type(), temp_var_name); if(tosign) cl2llvmTypeWrapSetSign(llvm_val->type, 1); else cl2llvmTypeWrapSetSign(llvm_val->type, 0); } else if (totype == LLVMInt8Type()) { llvm_val->val = LLVMBuildTrunc(cl2llvm_builder, original_val->val, LLVMInt8Type(), temp_var_name); if(tosign) cl2llvmTypeWrapSetSign(llvm_val->type, 1); else cl2llvmTypeWrapSetSign(llvm_val->type, 0); } else if (totype == LLVMInt1Type()) { llvm_val->val = LLVMBuildTrunc(cl2llvm_builder, original_val->val, LLVMInt1Type(), temp_var_name); if(tosign) cl2llvmTypeWrapSetSign(llvm_val->type, 1); else cl2llvmTypeWrapSetSign(llvm_val->type, 0); } } else if (fromtype == LLVMInt16Type()) { if (totype == LLVMDoubleType()) { if (fromsign) { llvm_val->val = LLVMBuildSIToFP(cl2llvm_builder, original_val->val, LLVMDoubleType(), temp_var_name); } else { llvm_val->val = LLVMBuildUIToFP(cl2llvm_builder, original_val->val, LLVMDoubleType(), temp_var_name); } cl2llvmTypeWrapSetSign(llvm_val->type, 1); } else if (totype == LLVMFloatType()) { if (fromsign) { llvm_val->val = LLVMBuildSIToFP(cl2llvm_builder, original_val->val, LLVMFloatType(), temp_var_name); } else { llvm_val->val = LLVMBuildUIToFP(cl2llvm_builder, original_val->val, LLVMFloatType(), temp_var_name); } cl2llvmTypeWrapSetSign(llvm_val->type, 1); } else if (totype == LLVMHalfType()) { if (fromsign) { llvm_val->val = LLVMBuildSIToFP(cl2llvm_builder, original_val->val, LLVMHalfType(), temp_var_name); } else { llvm_val->val = LLVMBuildUIToFP(cl2llvm_builder, original_val->val, LLVMHalfType(), temp_var_name); } cl2llvmTypeWrapSetSign(llvm_val->type, 1); } else if (totype == LLVMInt64Type()) { if (fromsign) { llvm_val->val = LLVMBuildSExt(cl2llvm_builder, original_val->val, LLVMInt64Type(), temp_var_name); } else { llvm_val->val = LLVMBuildZExt(cl2llvm_builder, original_val->val, LLVMInt64Type(), temp_var_name); } if (tosign) cl2llvmTypeWrapSetSign(llvm_val->type, 1); else cl2llvmTypeWrapSetSign(llvm_val->type, 0); } else if (totype == LLVMInt32Type()) { if (fromsign) { llvm_val->val = LLVMBuildSExt(cl2llvm_builder, original_val->val, LLVMInt32Type(), temp_var_name); } else { llvm_val->val = LLVMBuildZExt(cl2llvm_builder, original_val->val, LLVMInt32Type(), temp_var_name); } if(tosign) cl2llvmTypeWrapSetSign(llvm_val->type, 1); else cl2llvmTypeWrapSetSign(llvm_val->type, 0); } else if (totype == LLVMInt16Type()) { if(tosign) cl2llvmTypeWrapSetSign(llvm_val->type, 1); else cl2llvmTypeWrapSetSign(llvm_val->type, 0); temp_var_count--; } else if (totype == LLVMInt8Type()) { llvm_val->val = LLVMBuildTrunc(cl2llvm_builder, original_val->val, LLVMInt8Type(), temp_var_name); if(tosign) cl2llvmTypeWrapSetSign(llvm_val->type, 1); else cl2llvmTypeWrapSetSign(llvm_val->type, 0); } else if (totype == LLVMInt1Type()) { llvm_val->val = LLVMBuildTrunc(cl2llvm_builder, original_val->val, LLVMInt1Type(), temp_var_name); if(tosign) cl2llvmTypeWrapSetSign(llvm_val->type, 1); else cl2llvmTypeWrapSetSign(llvm_val->type, 0); } } else if (fromtype == LLVMInt8Type()) { if (totype == LLVMDoubleType()) { if (fromsign) { llvm_val->val = LLVMBuildSIToFP(cl2llvm_builder, original_val->val, LLVMDoubleType(), temp_var_name); } else { llvm_val->val = LLVMBuildUIToFP(cl2llvm_builder, original_val->val, LLVMDoubleType(), temp_var_name); } cl2llvmTypeWrapSetSign(llvm_val->type, 1); } else if (totype == LLVMFloatType()) { if (fromsign) { llvm_val->val = LLVMBuildSIToFP(cl2llvm_builder, original_val->val, LLVMFloatType(), temp_var_name); } else { llvm_val->val = LLVMBuildUIToFP(cl2llvm_builder, original_val->val, LLVMFloatType(), temp_var_name); } cl2llvmTypeWrapSetSign(llvm_val->type, 1); } else if (totype == LLVMHalfType()) { if (fromsign) { llvm_val->val = LLVMBuildSIToFP(cl2llvm_builder, original_val->val, LLVMHalfType(), temp_var_name); } else { llvm_val->val = LLVMBuildUIToFP(cl2llvm_builder, original_val->val, LLVMHalfType(), temp_var_name); } cl2llvmTypeWrapSetSign(llvm_val->type, 1); } else if (totype == LLVMInt64Type()) { if (fromsign) { llvm_val->val = LLVMBuildSExt(cl2llvm_builder, original_val->val, LLVMInt64Type(), temp_var_name); } else { llvm_val->val = LLVMBuildZExt(cl2llvm_builder, original_val->val, LLVMInt64Type(), temp_var_name); } if (tosign) cl2llvmTypeWrapSetSign(llvm_val->type, 1); else cl2llvmTypeWrapSetSign(llvm_val->type, 0); } else if (totype == LLVMInt32Type()) { if (fromsign) { llvm_val->val = LLVMBuildSExt(cl2llvm_builder, original_val->val, LLVMInt32Type(), temp_var_name); } else { llvm_val->val = LLVMBuildZExt(cl2llvm_builder, original_val->val, LLVMInt32Type(), temp_var_name); } if(tosign) cl2llvmTypeWrapSetSign(llvm_val->type, 1); else cl2llvmTypeWrapSetSign(llvm_val->type, 0); } else if (totype == LLVMInt16Type()) { if (fromsign) { llvm_val->val = LLVMBuildSExt(cl2llvm_builder, original_val->val, LLVMInt16Type(), temp_var_name); } else { llvm_val->val = LLVMBuildZExt(cl2llvm_builder, original_val->val, LLVMInt16Type(), temp_var_name); } if(tosign) cl2llvmTypeWrapSetSign(llvm_val->type, 1); else cl2llvmTypeWrapSetSign(llvm_val->type, 0); } else if (totype == LLVMInt8Type()) { if(tosign) cl2llvmTypeWrapSetSign(llvm_val->type, 1); else cl2llvmTypeWrapSetSign(llvm_val->type, 0); temp_var_count--; } else if (totype == LLVMInt1Type()) { llvm_val->val = LLVMBuildTrunc(cl2llvm_builder, original_val->val, LLVMInt1Type(), temp_var_name); if(tosign) cl2llvmTypeWrapSetSign(llvm_val->type, 1); else cl2llvmTypeWrapSetSign(llvm_val->type, 0); } } else if (fromtype == LLVMInt1Type()) { if (totype == LLVMDoubleType()) { if (fromsign) { llvm_val->val = LLVMBuildSIToFP(cl2llvm_builder, original_val->val, LLVMDoubleType(), temp_var_name); } else { llvm_val->val = LLVMBuildUIToFP(cl2llvm_builder, original_val->val, LLVMDoubleType(), temp_var_name); } cl2llvmTypeWrapSetSign(llvm_val->type, 1); } else if (totype == LLVMFloatType()) { if (fromsign) { llvm_val->val = LLVMBuildSIToFP(cl2llvm_builder, original_val->val, LLVMFloatType(), temp_var_name); } else { llvm_val->val = LLVMBuildUIToFP(cl2llvm_builder, original_val->val, LLVMFloatType(), temp_var_name); } cl2llvmTypeWrapSetSign(llvm_val->type, 1); } else if (totype == LLVMHalfType()) { if (fromsign) { llvm_val->val = LLVMBuildSIToFP(cl2llvm_builder, original_val->val, LLVMHalfType(), temp_var_name); } else { llvm_val->val = LLVMBuildUIToFP(cl2llvm_builder, original_val->val, LLVMHalfType(), temp_var_name); } cl2llvmTypeWrapSetSign(llvm_val->type, 1); } else if (totype == LLVMInt64Type()) { if (fromsign) { llvm_val->val = LLVMBuildSExt(cl2llvm_builder, original_val->val, LLVMInt64Type(), temp_var_name); } else { llvm_val->val = LLVMBuildZExt(cl2llvm_builder, original_val->val, LLVMInt64Type(), temp_var_name); } if (tosign) cl2llvmTypeWrapSetSign(llvm_val->type, 1); else cl2llvmTypeWrapSetSign(llvm_val->type, 0); } else if (totype == LLVMInt32Type()) { if (fromsign) { llvm_val->val = LLVMBuildSExt(cl2llvm_builder, original_val->val, LLVMInt32Type(), temp_var_name); } else { llvm_val->val = LLVMBuildZExt(cl2llvm_builder, original_val->val, LLVMInt32Type(), temp_var_name); } if(tosign) cl2llvmTypeWrapSetSign(llvm_val->type, 1); else cl2llvmTypeWrapSetSign(llvm_val->type, 0); } else if (totype == LLVMInt16Type()) { if (fromsign) { llvm_val->val = LLVMBuildSExt(cl2llvm_builder, original_val->val, LLVMInt16Type(), temp_var_name); } else { llvm_val->val = LLVMBuildZExt(cl2llvm_builder, original_val->val, LLVMInt16Type(), temp_var_name); } if(tosign) cl2llvmTypeWrapSetSign(llvm_val->type, 1); else cl2llvmTypeWrapSetSign(llvm_val->type, 0); } else if (totype == LLVMInt8Type()) { if (fromsign) { llvm_val->val = LLVMBuildSExt(cl2llvm_builder, original_val->val, LLVMInt8Type(), temp_var_name); } else { llvm_val->val = LLVMBuildZExt(cl2llvm_builder, original_val->val, LLVMInt8Type(), temp_var_name); } if(tosign) cl2llvmTypeWrapSetSign(llvm_val->type, 1); else cl2llvmTypeWrapSetSign(llvm_val->type, 0); } else if (totype == LLVMInt1Type()) { if(tosign) cl2llvmTypeWrapSetSign(llvm_val->type, 1); else cl2llvmTypeWrapSetSign(llvm_val->type, 0); temp_var_count--; } } /*We now know that from type must be a floating point.*/ /*Floating point to signed integer conversions*/ else if (tosign && LLVMGetTypeKind(totype) == 8) { if (totype == LLVMInt64Type()) { llvm_val->val = LLVMBuildFPToSI(cl2llvm_builder, original_val->val, LLVMInt64Type(), temp_var_name); } else if (totype == LLVMInt32Type()) { llvm_val->val = LLVMBuildFPToSI(cl2llvm_builder, original_val->val, LLVMInt32Type(), temp_var_name); } else if (totype == LLVMInt16Type()) { llvm_val->val = LLVMBuildFPToSI(cl2llvm_builder, original_val->val, LLVMInt16Type(), temp_var_name); } else if (totype == LLVMInt8Type()) { llvm_val->val = LLVMBuildFPToSI(cl2llvm_builder, original_val->val, LLVMInt8Type(), temp_var_name); } else if (totype == LLVMInt1Type()) { llvm_val->val = LLVMBuildFPToSI(cl2llvm_builder, original_val->val, LLVMInt1Type(), temp_var_name); } cl2llvmTypeWrapSetSign(llvm_val->type, 1); } /*Floating point to unsigned integer conversions*/ else if (!tosign) { if (totype == LLVMInt64Type()) { llvm_val->val = LLVMBuildFPToUI(cl2llvm_builder, original_val->val, LLVMInt64Type(), temp_var_name); } else if (totype == LLVMInt32Type()) { llvm_val->val = LLVMBuildFPToUI(cl2llvm_builder, original_val->val, LLVMInt32Type(), temp_var_name); } else if (totype == LLVMInt16Type()) { llvm_val->val = LLVMBuildFPToUI(cl2llvm_builder, original_val->val, LLVMInt16Type(), temp_var_name); } else if (totype == LLVMInt8Type()) { llvm_val->val = LLVMBuildFPToUI(cl2llvm_builder, original_val->val, LLVMInt8Type(), temp_var_name); } else if (totype == LLVMInt1Type()) { llvm_val->val = LLVMBuildFPToUI(cl2llvm_builder, original_val->val, LLVMInt1Type(), temp_var_name); } cl2llvmTypeWrapSetSign(llvm_val->type, 0); } else if (totype == LLVMDoubleType()) { llvm_val->val = LLVMBuildFPExt(cl2llvm_builder, original_val->val, LLVMDoubleType(), temp_var_name); cl2llvmTypeWrapSetSign(llvm_val->type, 1); } else if (totype == LLVMFloatType()) { if (fromtype == LLVMDoubleType()) { llvm_val->val = LLVMBuildFPTrunc(cl2llvm_builder, original_val->val, LLVMFloatType(), temp_var_name); } else if (fromtype == LLVMHalfType()) { llvm_val->val = LLVMBuildFPExt(cl2llvm_builder, original_val->val, LLVMFloatType(), temp_var_name); } cl2llvmTypeWrapSetSign(llvm_val->type, 1); } else if (totype == LLVMHalfType()) { llvm_val->val = LLVMBuildFPTrunc(cl2llvm_builder, original_val->val, LLVMHalfType(), temp_var_name); cl2llvmTypeWrapSetSign(llvm_val->type, 1); } cl2llvmTypeWrapSetLlvmType(llvm_val->type, totype); cl2llvmTypeWrapSetSign(llvm_val->type, tosign); return llvm_val; }