📄 slang_assemble.c
字号:
/*
* Mesa 3-D graphics library
* Version: 6.3
*
* Copyright (C) 2005 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_utility.h"
#include "slang_assemble.h"
#include "slang_compile.h"
#include "slang_storage.h"
#include "slang_assemble_constructor.h"
#include "slang_assemble_typeinfo.h"
#include "slang_assemble_conditional.h"
#include "slang_assemble_assignment.h"
/* slang_assembly */
static void slang_assembly_construct (slang_assembly *assem)
{
assem->type = slang_asm_none;
}
static void slang_assembly_destruct (slang_assembly *assem)
{
}
/* slang_assembly_file */
void slang_assembly_file_construct (slang_assembly_file *file)
{
file->code = NULL;
file->count = 0;
}
void slang_assembly_file_destruct (slang_assembly_file *file)
{
unsigned int i;
for (i = 0; i < file->count; i++)
slang_assembly_destruct (file->code + i);
slang_alloc_free (file->code);
}
static int slang_assembly_file_push_new (slang_assembly_file *file)
{
file->code = (slang_assembly *) slang_alloc_realloc (file->code, file->count * sizeof (
slang_assembly), (file->count + 1) * sizeof (slang_assembly));
if (file->code != NULL)
{
slang_assembly_construct (file->code + file->count);
file->count++;
return 1;
}
return 0;
}
static int slang_assembly_file_push_general (slang_assembly_file *file, slang_assembly_type type,
GLfloat literal, GLuint label, GLuint size)
{
slang_assembly *assem;
if (!slang_assembly_file_push_new (file))
return 0;
assem = file->code + file->count - 1;
assem->type = type;
assem->literal = literal;
assem->param[0] = label;
assem->param[1] = size;
return 1;
}
int slang_assembly_file_push (slang_assembly_file *file, slang_assembly_type type)
{
return slang_assembly_file_push_general (file, type, (GLfloat) 0, 0, 0);
}
int slang_assembly_file_push_label (slang_assembly_file *file, slang_assembly_type type,
GLuint label)
{
return slang_assembly_file_push_general (file, type, (GLfloat) 0, label, 0);
}
int slang_assembly_file_push_label2 (slang_assembly_file *file, slang_assembly_type type,
GLuint label1, GLuint label2)
{
return slang_assembly_file_push_general (file, type, (GLfloat) 0, label1, label2);
}
int slang_assembly_file_push_literal (slang_assembly_file *file, slang_assembly_type type,
GLfloat literal)
{
return slang_assembly_file_push_general (file, type, literal, 0, 0);
}
/* utility functions */
static int sizeof_variable (slang_type_specifier *spec, slang_type_qualifier qual,
slang_operation *array_size, slang_assembly_name_space *space, unsigned int *size)
{
slang_storage_aggregate agg;
slang_storage_aggregate_construct (&agg);
if (!_slang_aggregate_variable (&agg, spec, array_size, space->funcs, space->structs))
{
slang_storage_aggregate_destruct (&agg);
return 0;
}
*size += _slang_sizeof_aggregate (&agg);
if (qual == slang_qual_out || qual == slang_qual_inout)
*size += 4;
slang_storage_aggregate_destruct (&agg);
return 1;
}
static int sizeof_variable2 (slang_variable *var, slang_assembly_name_space *space,
unsigned int *size)
{
var->address = *size;
if (var->type.qualifier == slang_qual_out || var->type.qualifier == slang_qual_inout)
var->address += 4;
return sizeof_variable (&var->type.specifier, var->type.qualifier, var->array_size, space,
size);
}
static int sizeof_variables (slang_variable_scope *vars, unsigned int start, unsigned int stop,
slang_assembly_name_space *space, unsigned int *size)
{
unsigned int i;
for (i = start; i < stop; i++)
if (!sizeof_variable2 (vars->variables + i, space, size))
return 0;
return 1;
}
static int collect_locals (slang_operation *op, slang_assembly_name_space *space,
unsigned int *size)
{
unsigned int i;
if (!sizeof_variables (op->locals, 0, op->locals->num_variables, space, size))
return 0;
for (i = 0; i < op->num_children; i++)
if (!collect_locals (op->children + i, space, size))
return 0;
return 1;
}
/* _slang_locate_function() */
slang_function *_slang_locate_function (const char *name, slang_operation *params,
unsigned int num_params, slang_assembly_name_space *space)
{
unsigned int i;
for (i = 0; i < space->funcs->num_functions; i++)
{
unsigned int j;
slang_function *f = space->funcs->functions + i;
if (slang_string_compare (name, f->header.name) != 0)
continue;
if (f->param_count != num_params)
continue;
for (j = 0; j < num_params; j++)
{
slang_assembly_typeinfo ti;
slang_assembly_typeinfo_construct (&ti);
if (!_slang_typeof_operation (params + j, space, &ti))
{
slang_assembly_typeinfo_destruct (&ti);
return 0;
}
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 (space->funcs->outer_scope != NULL)
{
slang_assembly_name_space my_space = *space;
my_space.funcs = space->funcs->outer_scope;
return _slang_locate_function (name, params, num_params, &my_space);
}
return NULL;
}
/* _slang_assemble_function() */
int _slang_assemble_function (slang_assembly_file *file, slang_function *fun,
slang_assembly_name_space *space)
{
unsigned int param_size, local_size;
unsigned int skip, cleanup;
slang_assembly_flow_control flow;
slang_assembly_local_info info;
slang_assembly_stack_info stk;
fun->address = file->count;
if (fun->body == NULL)
{
/* TODO: jump to the actual function body */
return 1;
}
/* calculate return value and parameters size */
param_size = 0;
if (fun->header.type.specifier.type != slang_spec_void)
if (!sizeof_variable (&fun->header.type.specifier, slang_qual_none, NULL, space,
¶m_size))
return 0;
info.ret_size = param_size;
if (!sizeof_variables (fun->parameters, 0, fun->param_count, space, ¶m_size))
return 0;
/* calculate local variables size, take into account the four-byte return address and
temporaries for various tasks */
info.addr_tmp = param_size + 4;
info.swizzle_tmp = param_size + 4 + 4;
local_size = param_size + 4 + 4 + 16;
if (!sizeof_variables (fun->parameters, fun->param_count, fun->parameters->num_variables, space,
&local_size))
return 0;
if (!collect_locals (fun->body, space, &local_size))
return 0;
/* allocate local variable storage */
if (!slang_assembly_file_push_label (file, slang_asm_local_alloc, local_size - param_size - 4))
return 0;
/* mark a new frame for function variable storage */
if (!slang_assembly_file_push_label (file, slang_asm_enter, local_size))
return 0;
/* skip the cleanup jump */
skip = file->count;
if (!slang_assembly_file_push_new (file))
return 0;
file->code[skip].type = slang_asm_jump;
/* all "return" statements will be directed here */
flow.function_end = file->count;
cleanup = file->count;
if (!slang_assembly_file_push_new (file))
return 0;
file->code[cleanup].type = slang_asm_jump;
/* execute the function body */
file->code[skip].param[0] = file->count;
if (!_slang_assemble_operation (file, fun->body, 0, &flow, space, &info, &stk))
return 0;
/* this is the end of the function - restore the old function frame */
file->code[cleanup].param[0] = file->count;
if (!slang_assembly_file_push (file, slang_asm_leave))
return 0;
/* free local variable storage */
if (!slang_assembly_file_push_label (file, slang_asm_local_free, local_size - param_size - 4))
return 0;
/* jump out of the function */
if (!slang_assembly_file_push (file, slang_asm_return))
return 0;
return 1;
}
int _slang_cleanup_stack (slang_assembly_file *file, slang_operation *op, int ref,
slang_assembly_name_space *space)
{
slang_assembly_typeinfo ti;
unsigned int size;
slang_assembly_typeinfo_construct (&ti);
if (!_slang_typeof_operation (op, space, &ti))
{
slang_assembly_typeinfo_destruct (&ti);
return 0;
}
if (ti.spec.type == slang_spec_void)
size = 0;
else if (ref)
size = 4;
else
{
size = 0;
if (!sizeof_variable (&ti.spec, slang_qual_none, NULL, space, &size))
{
slang_assembly_typeinfo_destruct (&ti);
return 0;
}
}
slang_assembly_typeinfo_destruct (&ti);
if (size != 0)
{
if (!slang_assembly_file_push_label (file, slang_asm_local_free, size))
return 0;
}
return 1;
}
/* _slang_assemble_operation() */
/* XXX: general swizzle! */
static int dereference_aggregate (slang_assembly_file *file, const slang_storage_aggregate *agg,
unsigned int index, unsigned int *size, slang_assembly_local_info *info)
{
unsigned int i;
for (i = agg->count; i > 0; i--)
{
const slang_storage_array *arr = agg->arrays + i - 1;
unsigned int j;
for (j = arr->length; j > 0; j--)
{
if (arr->type == slang_stor_aggregate)
{
if (!dereference_aggregate (file, arr->aggregate, index, size, info))
return 0;
}
else
{
*size -= 4;
if (!slang_assembly_file_push_label2 (file, slang_asm_local_addr, info->addr_tmp,
4))
return 0;
if (!slang_assembly_file_push (file, slang_asm_addr_deref))
return 0;
if (!slang_assembly_file_push_label (file, slang_asm_addr_push, *size))
return 0;
if (!slang_assembly_file_push (file, slang_asm_addr_add))
return 0;
switch (arr->type)
{
case slang_stor_bool:
if (!slang_assembly_file_push (file, slang_asm_bool_deref))
return 0;
break;
case slang_stor_int:
if (!slang_assembly_file_push (file, slang_asm_int_deref))
return 0;
break;
case slang_stor_float:
if (!slang_assembly_file_push (file, slang_asm_float_deref))
return 0;
break;
}
index += 4;
}
}
}
return 1;
}
/* XXX: general swizzle! */
int dereference (slang_assembly_file *file, slang_operation *op,
slang_assembly_name_space *space, slang_assembly_local_info *info)
{
slang_assembly_typeinfo ti;
int result;
slang_storage_aggregate agg;
unsigned int size;
slang_assembly_typeinfo_construct (&ti);
if (!_slang_typeof_operation (op, space, &ti))
{
slang_assembly_typeinfo_destruct (&ti);
return 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -