<commit_before>/*
 * Copyright 2011 Advanced Micro Devices, Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice (including the next
 * paragraph) shall be included in all copies or substantial portions of the
 * Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 * Authors: <NAME> <<EMAIL>>
 *
 */
#include "radeon_llvm.h"

#include "gallivm/lp_bld_const.h"
#include "gallivm/lp_bld_gather.h"
#include "gallivm/lp_bld_flow.h"
#include "gallivm/lp_bld_init.h"
#include "gallivm/lp_bld_intr.h"
#include "gallivm/lp_bld_misc.h"
#include "gallivm/lp_bld_swizzle.h"
#include "tgsi/tgsi_info.h"
#include "tgsi/tgsi_parse.h"
#include "util/u_math.h"
#include "util/u_memory.h"
#include "util/u_debug.h"

#include <llvm-c/Core.h>
#include <llvm-c/Transforms/Scalar.h>

LLVMTypeRef tgsi2llvmtype(struct lp_build_tgsi_context *bld_base,
			  enum tgsi_opcode_type type)
{
	LLVMContextRef ctx = bld_base->base.gallivm->context;

	switch (type) {
	case TGSI_TYPE_UNSIGNED:
	case TGSI_TYPE_SIGNED:
		return LLVMInt32TypeInContext(ctx);
	case TGSI_TYPE_DOUBLE:
		return LLVMDoubleTypeInContext(ctx);
	case TGSI_TYPE_UNTYPED:
	case TGSI_TYPE_FLOAT:
		return LLVMFloatTypeInContext(ctx);
	default: break;
	}
	return 0;
}

LLVMValueRef bitcast(struct lp_build_tgsi_context *bld_base,
		     enum tgsi_opcode_type type, LLVMValueRef value)
{
	LLVMBuilderRef builder = bld_base->base.gallivm->builder;
	LLVMTypeRef dst_type = tgsi2llvmtype(bld_base, type);

	if (dst_type)
		return LLVMBuildBitCast(builder, value, dst_type, "");
	else
		return value;
}

static struct radeon_llvm_loop *get_current_loop(struct radeon_llvm_context *ctx)
{
	return ctx->loop_depth > 0 ? ctx->loop + (ctx->loop_depth - 1) : NULL;
}

static struct radeon_llvm_branch *get_current_branch(struct radeon_llvm_context *ctx)
{
	return ctx->branch_depth > 0 ?
			ctx->branch + (ctx->branch_depth - 1) : NULL;
}

unsigned radeon_llvm_reg_index_soa(unsigned index, unsigned chan)
{
	return (index * 4) + chan;
}

static LLVMValueRef emit_swizzle(struct lp_build_tgsi_context *bld_base,
				 LLVMValueRef value,
				 unsigned swizzle_x,
				 unsigned swizzle_y,
				 unsigned swizzle_z,
				 unsigned swizzle_w)
{
	LLVMValueRef swizzles[4];
	LLVMTypeRef i32t =
		LLVMInt32TypeInContext(bld_base->base.gallivm->context);

	swizzles[0] = LLVMConstInt(i32t, swizzle_x, 0);
	swizzles[1] = LLVMConstInt(i32t, swizzle_y, 0);
	swizzles[2] = LLVMConstInt(i32t, swizzle_z, 0);
	swizzles[3] = LLVMConstInt(i32t, swizzle_w, 0);

	return LLVMBuildShuffleVector(bld_base->base.gallivm->builder,
				      value,
				      LLVMGetUndef(LLVMTypeOf(value)),
				      LLVMConstVector(swizzles, 4), "");
}

static struct tgsi_declaration_range
get_array_range(struct lp_build_tgsi_context *bld_base,
		unsigned File, unsigned reg_index,
		const struct tgsi_ind_register *reg)
{
	struct radeon_llvm_context *ctx = radeon_llvm_context(bld_base);

	if (!reg) {
		unsigned i;
		unsigned num_arrays = bld_base->info->array_max[TGSI_FILE_TEMPORARY];
		for (i = 0; i < num_arrays; i++) {
			const struct tgsi_declaration_range *range =
						&ctx->arrays[i].range;

			if (reg_index >= range->First && reg_index <= range->Last) {
				return ctx->arrays[i].range;
			}
		}
	}

	if (File != TGSI_FILE_TEMPORARY || !reg || reg->ArrayID == 0 ||
	    reg->ArrayID > bld_base->info->array_max[TGSI_FILE_TEMPORARY]) {
		struct tgsi_declaration_range range;
		range.First = 0;
		range.Last = bld_base->info->file_max[File];
		return range;
	}

	return ctx->arrays[reg->ArrayID - 1].range;
}

static LLVMValueRef get_alloca_for_array(struct lp_build_tgsi_context *bld_base,
					 unsigned file,
					 unsigned index)
{
	unsigned i;
	unsigned num_arrays;
	struct radeon_llvm_context *ctx = radeon_llvm_context(bld_base);

	if (file != TGSI_FILE_TEMPORARY)
		return NULL;

	num_arrays = bld_base->info->array_max[TGSI_FILE_TEMPORARY];
	for (i = 0; i < num_arrays; i++) {
		const struct tgsi_declaration_range *range =
						&ctx->arrays[i].range;

		if (index >= range->First && index <= range->Last) {
			return ctx->arrays[i].alloca;
		}
	}
	return NULL;
}

static LLVMValueRef
emit_array_index(struct lp_build_tgsi_soa_context *bld,
		 const struct tgsi_ind_register *reg,
		 unsigned offset)
{
	struct gallivm_state *gallivm = bld->bld_base.base.gallivm;

	if (!reg) {
		return lp_build_const_int32(gallivm, offset);
	}
	LLVMValueRef addr = LLVMBuildLoad(gallivm->builder, bld->addr[reg->Index][reg->Swizzle], "");
	return LLVMBuildAdd(gallivm->builder, addr, lp_build_const_int32(gallivm, offset), "");
}

LLVMValueRef
radeon_llvm_emit_fetch_64bit(struct lp_build_tgsi_context *bld_base,
			     enum tgsi_opcode_type type,
			     LLVMValueRef ptr,
			     LLVMValueRef ptr2)
{
	LLVMBuilderRef builder = bld_base->base.gallivm->builder;
	LLVMValueRef result;

	result = LLVMGetUndef(LLVMVectorType(LLVMIntTypeInContext(bld_base->base.gallivm->context, 32), bld_base->base.type.length * 2));

	result = LLVMBuildInsertElement(builder,
					result,
					bitcast(bld_base, TGSI_TYPE_UNSIGNED, ptr),
					bld_base->int_bld.zero, "");
	result = LLVMBuildInsertElement(builder,
					result,
					bitcast(bld_base, TGSI_TYPE_UNSIGNED, ptr2),
					bld_base->int_bld.one, "");
	return bitcast(bld_base, type, result);
}

static LLVMValueRef
emit_array_fetch(struct lp_build_tgsi_context *bld_base,
		 unsigned File, enum tgsi_opcode_type type,
		 struct tgsi_declaration_range range,
		 unsigned swizzle)
{
	struct lp_build_tgsi_soa_context *bld = lp_soa_context(bld_base);
	struct gallivm_state *gallivm = bld->bld_base.base.gallivm;
	LLVMBuilderRef builder = bld_base->base.gallivm->builder;

	unsigned i, size = range.Last - range.First + 1;
	LLVMTypeRef vec = LLVMVectorType(tgsi2llvmtype(bld_base, type), size);
	LLVMValueRef result = LLVMGetUndef(vec);

	struct tgsi_full_src_register tmp_reg = {};
	tmp_reg.Register.File = File;

	for (i = 0; i < size; ++i) {
		tmp_reg.Register.Index = i + range.First;
		LLVMValueRef temp = radeon_llvm_emit_fetch(bld_base, &tmp_reg, type, swizzle);
		result = LLVMBuildInsertElement(builder, result, temp,
			lp_build_const_int32(gallivm, i), "array_vector");
	}
	return result;
}

static LLVMValueRef
load_value_from_array(struct lp_build_tgsi_context *bld_base,
		      unsigned file,
		      enum tgsi_opcode_type type,
		      unsigned swizzle,
		      unsigned reg_index,
		      const struct tgsi_ind_register *reg_indirect)
{
	struct lp_build_tgsi_soa_context *bld = lp_soa_context(bld_base);
	struct gallivm_state *gallivm = bld_base->base.gallivm;
	LLVMBuilderRef builder = gallivm->builder;
	struct tgsi_declaration_range range = get_array_range(bld_base, file, reg_index, reg_indirect);
	LLVMValueRef index = emit_array_index(bld, reg_indirect, reg_index - range.First);
	LLVMValueRef array = get_alloca_for_array(bld_base, file, reg_index);
	LLVMValueRef ptr, val, indices[2];

	if (!array) {
		/* Handle the case where the array is stored as a vector. */
		return LLVMBuildExtractElement(builder,
				emit_array_fetch(bld_base, file, type, range, swizzle),
				index, "");
	}

	index = LLVMBuildMul(builder, index, lp_build_const_int32(gallivm, TGSI_NUM_CHANNELS), "");
	index = LLVMBuildAdd(builder, index, lp_build_const_int32(gallivm, swizzle), "");
	indices[0] = bld_base->uint_bld.zero;
	indices[1] = index;
	ptr = LLVMBuildGEP(builder, array, indices, 2, "");
	val = LLVMBuildLoad(builder, ptr, "");
	if (tgsi_type_is_64bit(type)) {
		LLVMValueRef ptr_hi, val_hi;
		indices[0] = lp_build_const_int32(gallivm, 1);
		ptr_hi = LLVMBuildGEP(builder, ptr, indices, 1, "");
		val_hi = LLVMBuildLoad(builder, ptr_hi, "");
		val = radeon_llvm_emit_fetch_64bit(bld_base, type, val, val_hi);

	}
	return val;
}

static LLVMValueRef
store_value_to_array(struct lp_build_tgsi_context *bld_base,
		     LLVMValueRef value,
		     unsigned file,
		     unsigned chan_index,
		     unsigned reg_index,
		     const struct tgsi_ind_register *reg_indirect)
{
	struct lp_build_tgsi_soa_context *bld = lp_soa_context(bld_base);
	struct gallivm_state *gallivm = bld_base->base.gallivm;
	LLVMBuilderRef builder = gallivm->builder;
	struct tgsi_declaration_range range = get_array_range(bld_base, file, reg_index, reg_indirect);
	LLVMValueRef index = emit_array_index(bld, reg_indirect, reg_index - range.First);
	LLVMValueRef array = get_alloca_for_array(bld_base, file, reg_index);

	if (array) {
		LLVMValueRef indices[2];
		index = LLVMBuildMul(builder, index, lp_build_const_int32(gallivm, TGSI_NUM_CHANNELS), "");
		index = LLVMBuildAdd(builder, index, lp_build_const_int32(gallivm, chan_index), "");
		indices[0] = bld_base->uint_bld.zero;
		indices[1] = index;
		LLVMValueRef pointer = LLVMBuildGEP(builder, array, indices, 2, "");
		LLVMBuildStore(builder, value, pointer);
		return NULL;
	} else {
		return LLVMBuildInsertElement(builder,
				emit_array_fetch(bld_base, file, TGSI_TYPE_FLOAT, range, chan_index),
				value, index, "");
	}
}

LLVMValueRef radeon_llvm_emit_fetch(struct lp_build_tgsi_context *bld_base,
				    const struct tgsi_full_src_register *reg,
				    enum tgsi_opcode_type type,
				    unsigned swizzle)
{
	struct radeon_llvm_context *ctx = radeon_llvm_context(bld_base);
	struct lp_build_tgsi_soa_context *bld = lp_soa_context(bld_base);
	LLVMBuilderRef builder = bld_base->base.gallivm->builder;
	LLVMValueRef result = NULL, ptr, ptr2;

	if (swizzle == ~0) {
		LLVMValueRef values[TGSI_NUM_CHANNELS];
		unsigned chan;
		for (chan = 0; chan < TGSI_NUM_CHANNELS; chan++) {
			values[chan] = radeon_llvm_emit_fetch(bld_base, reg, type, chan);
		}
		return lp_build_gather_values(bld_base->base.gallivm, values,
					      TGSI_NUM_CHANNELS);
	}

	if (reg->Register.Indirect) {
		LLVMValueRef load = load_value_from_array(bld_base, reg->Register.File, type,
				swizzle, reg->Register.Index, &reg->Indirect);
		return bitcast(bld_base, type, load);
	}

	switch(reg->Register.File) {
	case TGSI_FILE_IMMEDIATE: {
		LLVMTypeRef ctype = tgsi2llvmtype(bld_base, type);
		if (tgsi_type_is_64bit(type)) {
			result = LLVMGetUndef(LLVMVectorType(LLVMIntTypeInContext(bld_base->base.gallivm->context, 32), bld_base->base.type.length * 2));
			result = LLVMConstInsertElement(result,
							bld->immediates[reg->Register.Index][swizzle],
							bld_base->int_bld.zero);
			result = LLVMConstInsertElement(result,
							bld->immediates[reg->Register.Index][swizzle + 1],
							bld_base->int_bld.one);
			return LLVMConstBitCast(result, ctype);
		} else {
			return LLVMConstBitCast(bld->immediates[reg->Register.Index][swizzle], ctype);
		}
	}

	case TGSI_FILE_INPUT:
		result = ctx->inputs[radeon_llvm_reg_index_soa(reg->Register.Index, swizzle)];
		if (tgsi_type_is_64bit(type)) {
			ptr = result;
			ptr2 = ctx->inputs[radeon_llvm_reg_index_soa(reg->Register.Index, swizzle + 1)];
			return radeon_llvm_emit_fetch_64bit(bld_base, type, ptr, ptr2);
		}
		break;

	case TGSI_FILE_TEMPORARY:
		if (reg->Register.Index >= ctx->temps_count)
			return LLVMGetUndef(tgsi2llvmtype(bld_base, type));
		ptr = ctx->temps[reg->Register.Index * TGSI_NUM_CHANNELS + swizzle];
		if (tgsi_type_is_64bit(type)) {
			ptr2 = ctx->temps[reg->Register.Index * TGSI_NUM_CHANNELS + swizzle + 1];
			return radeon_llvm_emit_fetch_64bit(bld_base, type,
						 LLVMBuildLoad(builder, ptr, ""),
						 LLVMBuildLoad(builder, ptr2, ""));
		}
		LLVMValueRef array = get_alloca_for_array(bld_base, reg->Register.File, reg->Register.Index);
		if (array) {
			return bitcast(bld_base, type, load_value_from_array(bld_base, reg->Register.File, type,
					swizzle, reg->Register.Index, NULL));
		}
		result = LLVMBuildLoad(builder, ptr, "");
		break;

	case TGSI_FILE_OUTPUT:
		ptr = lp_get_output_ptr(bld, reg->Register.Index, swizzle);
		if (tgsi_type_is_64bit(type)) {
			ptr2 = lp_get_output_ptr(bld, reg->Register.Index, swizzle + 1);
			return radeon_llvm_emit_fetch_64bit(bld_base, type,
						 LLVMBuildLoad(builder, ptr, ""),
						 LLVMBuildLoad(builder, ptr2, ""));
		}
		result = LLVMBuildLoad(builder, ptr, "");
		break;

	default:
		return LLVMGetUndef(tgsi2llvmtype(bld_base, type));<commit_msg>gallium/radeon: simplify radeon_llvm_emit_fetch for direct array addressing<commit_after>/*
 * Copyright 2011 Advanced Micro Devices, Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice (including the next
 * paragraph) shall be included in all copies or substantial portions of the
 * Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 * Authors: <NAME> <<EMAIL>>
 *
 */
#include "radeon_llvm.h"

#include "gallivm/lp_bld_const.h"
#include "gallivm/lp_bld_gather.h"
#include "gallivm/lp_bld_flow.h"
#include "gallivm/lp_bld_init.h"
#include "gallivm/lp_bld_intr.h"
#include "gallivm/lp_bld_misc.h"
#include "gallivm/lp_bld_swizzle.h"
#include "tgsi/tgsi_info.h"
#include "tgsi/tgsi_parse.h"
#include "util/u_math.h"
#include "util/u_memory.h"
#include "util/u_debug.h"

#include <llvm-c/Core.h>
#include <llvm-c/Transforms/Scalar.h>

LLVMTypeRef tgsi2llvmtype(struct lp_build_tgsi_context *bld_base,
			  enum tgsi_opcode_type type)
{
	LLVMContextRef ctx = bld_base->base.gallivm->context;

	switch (type) {
	case TGSI_TYPE_UNSIGNED:
	case TGSI_TYPE_SIGNED:
		return LLVMInt32TypeInContext(ctx);
	case TGSI_TYPE_DOUBLE:
		return LLVMDoubleTypeInContext(ctx);
	case TGSI_TYPE_UNTYPED:
	case TGSI_TYPE_FLOAT:
		return LLVMFloatTypeInContext(ctx);
	default: break;
	}
	return 0;
}

LLVMValueRef bitcast(struct lp_build_tgsi_context *bld_base,
		     enum tgsi_opcode_type type, LLVMValueRef value)
{
	LLVMBuilderRef builder = bld_base->base.gallivm->builder;
	LLVMTypeRef dst_type = tgsi2llvmtype(bld_base, type);

	if (dst_type)
		return LLVMBuildBitCast(builder, value, dst_type, "");
	else
		return value;
}

static struct radeon_llvm_loop *get_current_loop(struct radeon_llvm_context *ctx)
{
	return ctx->loop_depth > 0 ? ctx->loop + (ctx->loop_depth - 1) : NULL;
}

static struct radeon_llvm_branch *get_current_branch(struct radeon_llvm_context *ctx)
{
	return ctx->branch_depth > 0 ?
			ctx->branch + (ctx->branch_depth - 1) : NULL;
}

unsigned radeon_llvm_reg_index_soa(unsigned index, unsigned chan)
{
	return (index * 4) + chan;
}

static LLVMValueRef emit_swizzle(struct lp_build_tgsi_context *bld_base,
				 LLVMValueRef value,
				 unsigned swizzle_x,
				 unsigned swizzle_y,
				 unsigned swizzle_z,
				 unsigned swizzle_w)
{
	LLVMValueRef swizzles[4];
	LLVMTypeRef i32t =
		LLVMInt32TypeInContext(bld_base->base.gallivm->context);

	swizzles[0] = LLVMConstInt(i32t, swizzle_x, 0);
	swizzles[1] = LLVMConstInt(i32t, swizzle_y, 0);
	swizzles[2] = LLVMConstInt(i32t, swizzle_z, 0);
	swizzles[3] = LLVMConstInt(i32t, swizzle_w, 0);

	return LLVMBuildShuffleVector(bld_base->base.gallivm->builder,
				      value,
				      LLVMGetUndef(LLVMTypeOf(value)),
				      LLVMConstVector(swizzles, 4), "");
}

static struct tgsi_declaration_range
get_array_range(struct lp_build_tgsi_context *bld_base,
		unsigned File, unsigned reg_index,
		const struct tgsi_ind_register *reg)
{
	struct radeon_llvm_context *ctx = radeon_llvm_context(bld_base);

	if (!reg) {
		unsigned i;
		unsigned num_arrays = bld_base->info->array_max[TGSI_FILE_TEMPORARY];
		for (i = 0; i < num_arrays; i++) {
			const struct tgsi_declaration_range *range =
						&ctx->arrays[i].range;

			if (reg_index >= range->First && reg_index <= range->Last) {
				return ctx->arrays[i].range;
			}
		}
	}

	if (File != TGSI_FILE_TEMPORARY || !reg || reg->ArrayID == 0 ||
	    reg->ArrayID > bld_base->info->array_max[TGSI_FILE_TEMPORARY]) {
		struct tgsi_declaration_range range;
		range.First = 0;
		range.Last = bld_base->info->file_max[File];
		return range;
	}

	return ctx->arrays[reg->ArrayID - 1].range;
}

static LLVMValueRef get_alloca_for_array(struct lp_build_tgsi_context *bld_base,
					 unsigned file,
					 unsigned index)
{
	unsigned i;
	unsigned num_arrays;
	struct radeon_llvm_context *ctx = radeon_llvm_context(bld_base);

	if (file != TGSI_FILE_TEMPORARY)
		return NULL;

	num_arrays = bld_base->info->array_max[TGSI_FILE_TEMPORARY];
	for (i = 0; i < num_arrays; i++) {
		const struct tgsi_declaration_range *range =
						&ctx->arrays[i].range;

		if (index >= range->First && index <= range->Last) {
			return ctx->arrays[i].alloca;
		}
	}
	return NULL;
}

static LLVMValueRef
emit_array_index(struct lp_build_tgsi_soa_context *bld,
		 const struct tgsi_ind_register *reg,
		 unsigned offset)
{
	struct gallivm_state *gallivm = bld->bld_base.base.gallivm;

	if (!reg) {
		return lp_build_const_int32(gallivm, offset);
	}
	LLVMValueRef addr = LLVMBuildLoad(gallivm->builder, bld->addr[reg->Index][reg->Swizzle], "");
	return LLVMBuildAdd(gallivm->builder, addr, lp_build_const_int32(gallivm, offset), "");
}

LLVMValueRef
radeon_llvm_emit_fetch_64bit(struct lp_build_tgsi_context *bld_base,
			     enum tgsi_opcode_type type,
			     LLVMValueRef ptr,
			     LLVMValueRef ptr2)
{
	LLVMBuilderRef builder = bld_base->base.gallivm->builder;
	LLVMValueRef result;

	result = LLVMGetUndef(LLVMVectorType(LLVMIntTypeInContext(bld_base->base.gallivm->context, 32), bld_base->base.type.length * 2));

	result = LLVMBuildInsertElement(builder,
					result,
					bitcast(bld_base, TGSI_TYPE_UNSIGNED, ptr),
					bld_base->int_bld.zero, "");
	result = LLVMBuildInsertElement(builder,
					result,
					bitcast(bld_base, TGSI_TYPE_UNSIGNED, ptr2),
					bld_base->int_bld.one, "");
	return bitcast(bld_base, type, result);
}

static LLVMValueRef
emit_array_fetch(struct lp_build_tgsi_context *bld_base,
		 unsigned File, enum tgsi_opcode_type type,
		 struct tgsi_declaration_range range,
		 unsigned swizzle)
{
	struct lp_build_tgsi_soa_context *bld = lp_soa_context(bld_base);
	struct gallivm_state *gallivm = bld->bld_base.base.gallivm;
	LLVMBuilderRef builder = bld_base->base.gallivm->builder;

	unsigned i, size = range.Last - range.First + 1;
	LLVMTypeRef vec = LLVMVectorType(tgsi2llvmtype(bld_base, type), size);
	LLVMValueRef result = LLVMGetUndef(vec);

	struct tgsi_full_src_register tmp_reg = {};
	tmp_reg.Register.File = File;

	for (i = 0; i < size; ++i) {
		tmp_reg.Register.Index = i + range.First;
		LLVMValueRef temp = radeon_llvm_emit_fetch(bld_base, &tmp_reg, type, swizzle);
		result = LLVMBuildInsertElement(builder, result, temp,
			lp_build_const_int32(gallivm, i), "array_vector");
	}
	return result;
}

static LLVMValueRef
load_value_from_array(struct lp_build_tgsi_context *bld_base,
		      unsigned file,
		      enum tgsi_opcode_type type,
		      unsigned swizzle,
		      unsigned reg_index,
		      const struct tgsi_ind_register *reg_indirect)
{
	struct lp_build_tgsi_soa_context *bld = lp_soa_context(bld_base);
	struct gallivm_state *gallivm = bld_base->base.gallivm;
	LLVMBuilderRef builder = gallivm->builder;
	struct tgsi_declaration_range range = get_array_range(bld_base, file, reg_index, reg_indirect);
	LLVMValueRef index = emit_array_index(bld, reg_indirect, reg_index - range.First);
	LLVMValueRef array = get_alloca_for_array(bld_base, file, reg_index);
	LLVMValueRef ptr, val, indices[2];

	if (!array) {
		/* Handle the case where the array is stored as a vector. */
		return LLVMBuildExtractElement(builder,
				emit_array_fetch(bld_base, file, type, range, swizzle),
				index, "");
	}

	index = LLVMBuildMul(builder, index, lp_build_const_int32(gallivm, TGSI_NUM_CHANNELS), "");
	index = LLVMBuildAdd(builder, index, lp_build_const_int32(gallivm, swizzle), "");
	indices[0] = bld_base->uint_bld.zero;
	indices[1] = index;
	ptr = LLVMBuildGEP(builder, array, indices, 2, "");
	val = LLVMBuildLoad(builder, ptr, "");
	if (tgsi_type_is_64bit(type)) {
		LLVMValueRef ptr_hi, val_hi;
		indices[0] = lp_build_const_int32(gallivm, 1);
		ptr_hi = LLVMBuildGEP(builder, ptr, indices, 1, "");
		val_hi = LLVMBuildLoad(builder, ptr_hi, "");
		val = radeon_llvm_emit_fetch_64bit(bld_base, type, val, val_hi);

	}
	return val;
}

static LLVMValueRef
store_value_to_array(struct lp_build_tgsi_context *bld_base,
		     LLVMValueRef value,
		     unsigned file,
		     unsigned chan_index,
		     unsigned reg_index,
		     const struct tgsi_ind_register *reg_indirect)
{
	struct lp_build_tgsi_soa_context *bld = lp_soa_context(bld_base);
	struct gallivm_state *gallivm = bld_base->base.gallivm;
	LLVMBuilderRef builder = gallivm->builder;
	struct tgsi_declaration_range range = get_array_range(bld_base, file, reg_index, reg_indirect);
	LLVMValueRef index = emit_array_index(bld, reg_indirect, reg_index - range.First);
	LLVMValueRef array = get_alloca_for_array(bld_base, file, reg_index);

	if (array) {
		LLVMValueRef indices[2];
		index = LLVMBuildMul(builder, index, lp_build_const_int32(gallivm, TGSI_NUM_CHANNELS), "");
		index = LLVMBuildAdd(builder, index, lp_build_const_int32(gallivm, chan_index), "");
		indices[0] = bld_base->uint_bld.zero;
		indices[1] = index;
		LLVMValueRef pointer = LLVMBuildGEP(builder, array, indices, 2, "");
		LLVMBuildStore(builder, value, pointer);
		return NULL;
	} else {
		return LLVMBuildInsertElement(builder,
				emit_array_fetch(bld_base, file, TGSI_TYPE_FLOAT, range, chan_index),
				value, index, "");
	}
}

LLVMValueRef radeon_llvm_emit_fetch(struct lp_build_tgsi_context *bld_base,
				    const struct tgsi_full_src_register *reg,
				    enum tgsi_opcode_type type,
				    unsigned swizzle)
{
	struct radeon_llvm_context *ctx = radeon_llvm_context(bld_base);
	struct lp_build_tgsi_soa_context *bld = lp_soa_context(bld_base);
	LLVMBuilderRef builder = bld_base->base.gallivm->builder;
	LLVMValueRef result = NULL, ptr, ptr2;

	if (swizzle == ~0) {
		LLVMValueRef values[TGSI_NUM_CHANNELS];
		unsigned chan;
		for (chan = 0; chan < TGSI_NUM_CHANNELS; chan++) {
			values[chan] = radeon_llvm_emit_fetch(bld_base, reg, type, chan);
		}
		return lp_build_gather_values(bld_base->base.gallivm, values,
					      TGSI_NUM_CHANNELS);
	}

	if (reg->Register.Indirect) {
		LLVMValueRef load = load_value_from_array(bld_base, reg->Register.File, type,
				swizzle, reg->Register.Index, &reg->Indirect);
		return bitcast(bld_base, type, load);
	}

	switch(reg->Register.File) {
	case TGSI_FILE_IMMEDIATE: {
		LLVMTypeRef ctype = tgsi2llvmtype(bld_base, type);
		if (tgsi_type_is_64bit(type)) {
			result = LLVMGetUndef(LLVMVectorType(LLVMIntTypeInContext(bld_base->base.gallivm->context, 32), bld_base->base.type.length * 2));
			result = LLVMConstInsertElement(result,
							bld->immediates[reg->Register.Index][swizzle],
							bld_base->int_bld.zero);
			result = LLVMConstInsertElement(result,
							bld->immediates[reg->Register.Index][swizzle + 1],
							bld_base->int_bld.one);
			return LLVMConstBitCast(result, ctype);
		} else {
			return LLVMConstBitCast(bld->immediates[reg->Register.Index][swizzle], ctype);
		}
	}

	case TGSI_FILE_INPUT:
		result = ctx->inputs[radeon_llvm_reg_index_soa(reg->Register.Index, swizzle)];
		if (tgsi_type_is_64bit(type)) {
			ptr = result;
			ptr2 = ctx->inputs[radeon_llvm_reg_index_soa(reg->Register.Index, swizzle + 1)];
			return radeon_llvm_emit_fetch_64bit(bld_base, type, ptr, ptr2);
		}
		break;

	case TGSI_FILE_TEMPORARY:
		if (reg->Register.Index >= ctx->temps_count)
			return LLVMGetUndef(tgsi2llvmtype(bld_base, type));
		ptr = ctx->temps[reg->Register.Index * TGSI_NUM_CHANNELS + swizzle];
		if (tgsi_type_is_64bit(type)) {
			ptr2 = ctx->temps[reg->Register.Index * TGSI_NUM_CHANNELS + swizzle + 1];
			return radeon_llvm_emit_fetch_64bit(bld_base, type,
						 LLVMBuildLoad(builder, ptr, ""),
						 LLVMBuildLoad(builder, ptr2, ""));
		}
		result = LLVMBuildLoad(builder, ptr, "");
		break;

	case TGSI_FILE_OUTPUT:
		ptr = lp_get_output_ptr(bld, reg->Register.Index, swizzle);
		if (tgsi_type_is_64bit(type)) {
			ptr2 = lp_get_output_ptr(bld, reg->Register.Index, swizzle + 1);
			return radeon_llvm_emit_fetch_64bit(bld_base, type,
						 LLVMBuildLoad(builder, ptr, ""),
						 LLVMBuildLoad(builder, ptr2, ""));
		}
		result = LLVMBuildLoad(builder, ptr, "");
		break;

	default:
		return LLVMGetUndef(tgsi2llvmtype(bld_base, type));
{'fraction_non_alphanumeric': 0.11055042310379629, 'fraction_numerical': 0.008927878270320627, 'mean_word_length': 5.006761482863138, 'pattern_counts': {'":': 0, '<': 25, '<?xml version=': 0, '>': 203, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2397471', 'n_tokens_mistral': 10655, 'n_tokens_neox': 9694, 'n_words': 1937}