⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 slang_assemble.c

📁 mesa-6.5-minigui源码
💻 C
📖 第 1 页 / 共 3 页
字号:
/*
 * Mesa 3-D graphics library
 * Version:  6.5
 *
 * Copyright (C) 2005-2006  Brian Paul   All Rights Reserved.
 *
 * 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 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
 * BRIAN PAUL 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.
 */

/**
 * \file slang_assemble.c
 * slang intermediate code assembler
 * \author Michal Krol
 */

#include "imports.h"
#include "slang_assemble.h"
#include "slang_compile.h"
#include "slang_storage.h"

/* slang_assembly */

static GLboolean slang_assembly_construct (slang_assembly *assem)
{
	assem->type = slang_asm_none;
	return GL_TRUE;
}

static GLvoid slang_assembly_destruct (slang_assembly *assem)
{
}

/* slang_assembly_file */

GLboolean slang_assembly_file_construct (slang_assembly_file *file)
{
	file->code = NULL;
	file->count = 0;
	file->capacity = 0;
	return GL_TRUE;
}

GLvoid slang_assembly_file_destruct (slang_assembly_file *file)
{
	GLuint i;

	for (i = 0; i < file->count; i++)
		slang_assembly_destruct (&file->code[i]);
	slang_alloc_free (file->code);
}

static GLboolean push_new (slang_assembly_file *file)
{
	if (file->count == file->capacity)
	{
		GLuint n;

		if (file->capacity == 0)
			n = 256;
		else
			n = file->capacity * 2;
		file->code = (slang_assembly *) slang_alloc_realloc (file->code,
			file->capacity * sizeof (slang_assembly), n * sizeof (slang_assembly));
		if (file->code == NULL)
			return GL_FALSE;
		file->capacity = n;
	}
	if (!slang_assembly_construct (&file->code[file->count]))
		return GL_FALSE;
	file->count++;
	return GL_TRUE;
}

static GLboolean push_gen (slang_assembly_file *file, slang_assembly_type type, GLfloat literal,
	GLuint label, GLuint size)
{
	slang_assembly *assem;

	if (!push_new (file))
		return GL_FALSE;
	assem = &file->code[file->count - 1];
	assem->type = type;
	assem->literal = literal;
	assem->param[0] = label;
	assem->param[1] = size;
	return GL_TRUE;
}

GLboolean slang_assembly_file_push (slang_assembly_file *file, slang_assembly_type type)
{
	return push_gen (file, type, (GLfloat) 0, 0, 0);
}

GLboolean slang_assembly_file_push_label (slang_assembly_file *file, slang_assembly_type type,
	GLuint label)
{
	return push_gen (file, type, (GLfloat) 0, label, 0);
}

GLboolean slang_assembly_file_push_label2 (slang_assembly_file *file, slang_assembly_type type,
	GLuint label1, GLuint label2)
{
	return push_gen (file, type, (GLfloat) 0, label1, label2);
}

GLboolean slang_assembly_file_push_literal (slang_assembly_file *file, slang_assembly_type type,
	GLfloat literal)
{
	return push_gen (file, type, literal, 0, 0);
}

#define PUSH slang_assembly_file_push
#define PLAB slang_assembly_file_push_label
#define PLAB2 slang_assembly_file_push_label2
#define PLIT slang_assembly_file_push_literal

/* slang_assembly_file_restore_point */

GLboolean slang_assembly_file_restore_point_save (slang_assembly_file *file,
	slang_assembly_file_restore_point *point)
{
	point->count = file->count;
	return GL_TRUE;
}

GLboolean slang_assembly_file_restore_point_load (slang_assembly_file *file,
	slang_assembly_file_restore_point *point)
{
	GLuint i;

	for (i = point->count; i < file->count; i++)
		slang_assembly_destruct (&file->code[i]);
	file->count = point->count;
	return GL_TRUE;
}

/* utility functions */

static GLboolean sizeof_variable (slang_assemble_ctx *A, slang_type_specifier *spec,
	slang_type_qualifier qual, GLuint array_len, GLuint *size)
{
	slang_storage_aggregate agg;

	/* calculate the size of the variable's aggregate */
	if (!slang_storage_aggregate_construct (&agg))
		return GL_FALSE;
	if (!_slang_aggregate_variable (&agg, spec, array_len, A->space.funcs, A->space.structs,
			A->space.vars, A->mach, A->file, A->atoms))
	{
		slang_storage_aggregate_destruct (&agg);
		return GL_FALSE;
	}
	*size += _slang_sizeof_aggregate (&agg);
	slang_storage_aggregate_destruct (&agg);

	/* for reference variables consider the additional address overhead */
	if (qual == slang_qual_out || qual == slang_qual_inout)
		*size += 4;

	return GL_TRUE;
}

static GLboolean sizeof_variable2 (slang_assemble_ctx *A, slang_variable *var, GLuint *size)
{
	var->address = *size;
	if (var->type.qualifier == slang_qual_out || var->type.qualifier == slang_qual_inout)
		var->address += 4;
	return sizeof_variable (A, &var->type.specifier, var->type.qualifier, var->array_len, size);
}

static GLboolean sizeof_variables (slang_assemble_ctx *A, slang_variable_scope *vars, GLuint start,
	GLuint stop, GLuint *size)
{
	GLuint i;

	for (i = start; i < stop; i++)
		if (!sizeof_variable2 (A, &vars->variables[i], size))
			return GL_FALSE;
	return GL_TRUE;
}

static GLboolean collect_locals (slang_assemble_ctx *A, slang_operation *op, GLuint *size)
{
	GLuint i;

	if (!sizeof_variables (A, op->locals, 0, op->locals->num_variables, size))
		return GL_FALSE;
	for (i = 0; i < op->num_children; i++)
		if (!collect_locals (A, &op->children[i], size))
			return GL_FALSE;
	return GL_TRUE;
}

/* _slang_locate_function() */

slang_function *_slang_locate_function (slang_function_scope *funcs, slang_atom a_name,
	slang_operation *params, GLuint num_params, slang_assembly_name_space *space,
	slang_atom_pool *atoms)
{
	GLuint i;

	for (i = 0; i < funcs->num_functions; i++)
	{
		GLuint j;
		slang_function *f = &funcs->functions[i];

		if (a_name != f->header.a_name)
			continue;
		if (f->param_count != num_params)
			continue;
		for (j = 0; j < num_params; j++)
		{
			slang_assembly_typeinfo ti;

			if (!slang_assembly_typeinfo_construct (&ti))
				return NULL;
			if (!_slang_typeof_operation_ (&params[j], space, &ti, atoms))
			{
				slang_assembly_typeinfo_destruct (&ti);
				return NULL;
			}
			if (!slang_type_specifier_equal (&ti.spec, &f->parameters->variables[j].type.specifier))
			{
				slang_assembly_typeinfo_destruct (&ti);
				break;
			}
			slang_assembly_typeinfo_destruct (&ti);

			/* "out" and "inout" formal parameter requires the actual parameter to be l-value */
			if (!ti.can_be_referenced &&
					(f->parameters->variables[j].type.qualifier == slang_qual_out ||
					f->parameters->variables[j].type.qualifier == slang_qual_inout))
				break;
		}
		if (j == num_params)
			return f;
	}
	if (funcs->outer_scope != NULL)
		return _slang_locate_function (funcs->outer_scope, a_name, params, num_params, space, atoms);
	return NULL;
}

/* _slang_assemble_function() */

GLboolean _slang_assemble_function (slang_assemble_ctx *A, slang_function *fun)
{
	GLuint param_size, local_size;
	GLuint skip, cleanup;

	fun->address = A->file->count;

	if (fun->body == NULL)
	{
		/* jump to the actual function body - we do not know it, so add the instruction
		 * to fixup table */
		fun->fixups.table = (GLuint *) slang_alloc_realloc (fun->fixups.table,
			fun->fixups.count * sizeof (GLuint), (fun->fixups.count + 1) * sizeof (GLuint));
		if (fun->fixups.table == NULL)
			return GL_FALSE;
		fun->fixups.table[fun->fixups.count] = fun->address;
		fun->fixups.count++;
		if (!PUSH (A->file, slang_asm_jump))
			return GL_FALSE;
		return GL_TRUE;
	}
	else
	{
		GLuint i;

		/* resolve all fixup table entries and delete it */
		for (i = 0; i < fun->fixups.count; i++)
			A->file->code[fun->fixups.table[i]].param[0] = fun->address;
		slang_fixup_table_free (&fun->fixups);
	}

	/* At this point traverse function formal parameters and code to calculate
	 * total memory size to be allocated on the stack.
	 * During this process the variables will be assigned local addresses to
	 * reference them in the code.
	 * No storage optimizations are performed so exclusive scopes are not detected and shared. */

	/* calculate return value size */
	param_size = 0;
	if (fun->header.type.specifier.type != slang_spec_void)
		if (!sizeof_variable (A, &fun->header.type.specifier, slang_qual_none, 0, &param_size))
			return GL_FALSE;
	A->local.ret_size = param_size;

	/* calculate formal parameter list size */
	if (!sizeof_variables (A, fun->parameters, 0, fun->param_count, &param_size))
		return GL_FALSE;

	/* calculate local variables size - take into account the four-byte return address and
	 * temporaries for various tasks (4 for addr and 16 for swizzle temporaries).
	 * these include variables from the formal parameter scope and from the code */
	A->local.addr_tmp = param_size + 4;
	A->local.swizzle_tmp = param_size + 4 + 4;
	local_size = param_size + 4 + 4 + 16;
	if (!sizeof_variables (A, fun->parameters, fun->param_count, fun->parameters->num_variables,
			&local_size))
		return GL_FALSE;
	if (!collect_locals (A, fun->body, &local_size))
		return GL_FALSE;

	/* allocate local variable storage */
	if (!PLAB (A->file, slang_asm_local_alloc, local_size - param_size - 4))
		return GL_FALSE;

	/* mark a new frame for function variable storage */
	if (!PLAB (A->file, slang_asm_enter, local_size))
		return GL_FALSE;

	/* jump directly to the actual code */
	skip = A->file->count;
	if (!push_new (A->file))
		return GL_FALSE;
	A->file->code[skip].type = slang_asm_jump;

	/* all "return" statements will be directed here */
	A->flow.function_end = A->file->count;
	cleanup = A->file->count;
	if (!push_new (A->file))
		return GL_FALSE;
	A->file->code[cleanup].type = slang_asm_jump;

	/* execute the function body */
	A->file->code[skip].param[0] = A->file->count;
	if (!_slang_assemble_operation (A, fun->body, /*slang_ref_freelance*/slang_ref_forbid))
		return GL_FALSE;

	/* this is the end of the function - restore the old function frame */
	A->file->code[cleanup].param[0] = A->file->count;
	if (!PUSH (A->file, slang_asm_leave))
		return GL_FALSE;

	/* free local variable storage */
	if (!PLAB (A->file, slang_asm_local_free, local_size - param_size - 4))
		return GL_FALSE;

	/* return from the function */
	if (!PUSH (A->file, slang_asm_return))
		return GL_FALSE;

	return GL_TRUE;
}

GLboolean _slang_cleanup_stack (slang_assemble_ctx *A, slang_operation *op)
{
	slang_assembly_typeinfo ti;
	GLuint size = 0;

	/* get type info of the operation and calculate its size */
	if (!slang_assembly_typeinfo_construct (&ti))
		return GL_FALSE;
	if (!_slang_typeof_operation (A, op, &ti))
	{
		slang_assembly_typeinfo_destruct (&ti);
		return GL_FALSE;
	}
	if (ti.spec.type != slang_spec_void) {
		if (A->ref == slang_ref_force) {
			size = 4;
		}
		else if (!sizeof_variable (A, &ti.spec, slang_qual_none, 0, &size))
		{
			slang_assembly_typeinfo_destruct (&ti);
			return GL_FALSE;
		}
	}
	slang_assembly_typeinfo_destruct (&ti);

	/* if nonzero, free it from the stack */
	if (size != 0)
	{
		if (!PLAB (A->file, slang_asm_local_free, size))
			return GL_FALSE;
	}

	return GL_TRUE;
}

/* _slang_assemble_operation() */

static GLboolean dereference_aggregate (slang_assemble_ctx *A, const slang_storage_aggregate *agg,
	GLuint *size, slang_swizzle *swz, GLboolean is_swizzled)
{
	GLuint i;

	for (i = agg->count; i > 0; i--)
	{
		const slang_storage_array *arr = &agg->arrays[i - 1];
		GLuint j;

		for (j = arr->length; j > 0; j--)
		{
			if (arr->type == slang_stor_aggregate)
			{
				if (!dereference_aggregate (A, arr->aggregate, size, swz, is_swizzled))
					return GL_FALSE;
			}
			else
			{
				GLuint src_offset;
				slang_assembly_type ty;

				*size -= 4;

				/* calculate the offset within source variable to read */
				if (is_swizzled)
				{
					/* swizzle the index to get the actual offset */
					src_offset = swz->swizzle[*size / 4] * 4;
				}
				else
				{
					/* no swizzling - read sequentially */
					src_offset = *size;
				}

				/* dereference data slot of a basic type */
				if (!PLAB2 (A->file, slang_asm_local_addr, A->local.addr_tmp, 4))
					return GL_FALSE;
				if (!PUSH (A->file, slang_asm_addr_deref))
					return GL_FALSE;
				if (!PLAB (A->file, slang_asm_addr_push, src_offset))
					return GL_FALSE;
				if (!PUSH (A->file, slang_asm_addr_add))
					return GL_FALSE;

				switch (arr->type)
				{
				case slang_stor_bool:
					ty = slang_asm_bool_deref;
					break;
				case slang_stor_int:
					ty = slang_asm_int_deref;
					break;
				case slang_stor_float:
					ty = slang_asm_float_deref;
					break;
				default:
					_mesa_problem(NULL, "Unexpected arr->type in dereference_aggregate");
					ty = slang_asm_none;
				}
				if (!PUSH (A->file, ty))
					return GL_FALSE;
			}
		}
	}

	return GL_TRUE;
}

GLboolean _slang_dereference (slang_assemble_ctx *A, slang_operation *op)
{
	slang_assembly_typeinfo ti;
	GLboolean result = GL_FALSE;
	slang_storage_aggregate agg;
	GLuint size;

	/* get type information of the given operation */
	if (!slang_assembly_typeinfo_construct (&ti))
		return GL_FALSE;
	if (!_slang_typeof_operation (A, op, &ti))
		goto end1;

	/* construct aggregate from the type info */
	if (!slang_storage_aggregate_construct (&agg))
		goto end1;
	if (!_slang_aggregate_variable (&agg, &ti.spec, ti.array_len, A->space.funcs, A->space.structs,
			A->space.vars, A->mach, A->file, A->atoms))
		goto end;

	/* dereference the resulting aggregate */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -