📄 slang_assemble.c
字号:
/*
* 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_ (¶ms[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, ¶m_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, ¶m_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 + -