📄 slang_assemble.c
字号:
}
slang_storage_aggregate_construct (&agg);
if (!_slang_aggregate_variable (&agg, &ti.spec, NULL, space->funcs, space->structs))
{
slang_storage_aggregate_destruct (&agg);
slang_assembly_typeinfo_destruct (&ti);
return 0;
}
size = _slang_sizeof_aggregate (&agg);
result = dereference_aggregate (file, &agg, 0, &size, info);
slang_storage_aggregate_destruct (&agg);
slang_assembly_typeinfo_destruct (&ti);
return result;
}
static int call_function (slang_assembly_file *file, slang_function *fun, slang_operation *params,
unsigned int param_count, int assignment, slang_assembly_name_space *space,
slang_assembly_local_info *info)
{
unsigned int i;
slang_assembly_stack_info stk;
/* make room for the return value, if any */
if (fun->header.type.specifier.type != slang_spec_void)
{
unsigned int ret_size = 0;
if (!sizeof_variable (&fun->header.type.specifier, slang_qual_none, NULL, space, &ret_size))
return 0;
if (!slang_assembly_file_push_label (file, slang_asm_local_alloc, ret_size))
return 0;
}
/* push the actual parameters on the stack */
for (i = 0; i < param_count; i++)
{
slang_assembly_flow_control flow;
if (fun->parameters->variables[i].type.qualifier == slang_qual_inout ||
fun->parameters->variables[i].type.qualifier == slang_qual_out)
{
if (!slang_assembly_file_push_label2 (file, slang_asm_local_addr, info->addr_tmp, 4))
return 0;
/* TODO: optimize the "out" parameter case */
/* TODO: inspect stk */
if (!_slang_assemble_operation (file, params + i, 1, &flow, space, info, &stk))
return 0;
if (!slang_assembly_file_push (file, slang_asm_addr_copy))
return 0;
if (!slang_assembly_file_push (file, slang_asm_addr_deref))
return 0;
if (i == 0 && assignment)
{
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 (!dereference (file, params, space, info))
return 0;
}
else
{
/* TODO: for "out" and "inout" parameters also push the address (first) */
/* TODO: optimize the "out" parameter case */
/* TODO: inspect stk */
if (!_slang_assemble_operation (file, params + i, 0, &flow, space, info, &stk))
return 0;
}
}
/* call the function */
if (!slang_assembly_file_push_label (file, slang_asm_call, fun->address))
return 0;
/* pop the parameters from the stack */
for (i = param_count; i > 0; i--)
{
unsigned int j = i - 1;
if (fun->parameters->variables[j].type.qualifier == slang_qual_inout ||
fun->parameters->variables[j].type.qualifier == slang_qual_out)
{
if (!_slang_assemble_assignment (file, params + j, space, info))
return 0;
if (!slang_assembly_file_push_label (file, slang_asm_local_free, 4))
return 0;
}
else
{
if (!_slang_cleanup_stack (file, params + j, 0, space))
return 0;
}
}
return 1;
}
int call_function_name (slang_assembly_file *file, const char *name, slang_operation *params,
unsigned int param_count, int assignment, slang_assembly_name_space *space,
slang_assembly_local_info *info)
{
slang_function *fun = _slang_locate_function (name, params, param_count, space);
if (fun == NULL)
return 0;
return call_function (file, fun, params, param_count, assignment, space, info);
}
static int call_function_name_dummyint (slang_assembly_file *file, const char *name,
slang_operation *params, slang_assembly_name_space *space, slang_assembly_local_info *info)
{
slang_operation p2[2];
int result;
p2[0] = *params;
if (!slang_operation_construct_a (p2 + 1))
return 0;
p2[1].type = slang_oper_literal_int;
result = call_function_name (file, name, p2, 2, 0, space, info);
slang_operation_destruct (p2 + 1);
return result;
}
static int call_asm_instruction (slang_assembly_file *file, const char *name)
{
const struct
{
const char *name;
slang_assembly_type code1, code2;
} inst[] = {
{ "float_to_int", slang_asm_float_to_int, slang_asm_int_copy },
{ "int_to_float", slang_asm_int_to_float, slang_asm_float_copy },
{ "float_copy", slang_asm_float_copy, slang_asm_none },
{ "int_copy", slang_asm_int_copy, slang_asm_none },
{ "bool_copy", slang_asm_bool_copy, slang_asm_none },
{ "float_add", slang_asm_float_add, slang_asm_float_copy },
{ "float_multiply", slang_asm_float_multiply, slang_asm_float_copy },
{ "float_divide", slang_asm_float_divide, slang_asm_float_copy },
{ "float_negate", slang_asm_float_negate, slang_asm_float_copy },
{ "float_less", slang_asm_float_less, slang_asm_bool_copy },
{ "float_equal", slang_asm_float_equal, slang_asm_bool_copy },
{ NULL, slang_asm_none, slang_asm_none }
};
unsigned int i;
for (i = 0; inst[i].name != NULL; i++)
if (slang_string_compare (name, inst[i].name) == 0)
break;
if (inst[i].name == NULL)
return 0;
if (!slang_assembly_file_push_label2 (file, inst[i].code1, 4, 0))
return 0;
if (inst[i].code2 != slang_asm_none)
if (!slang_assembly_file_push_label2 (file, inst[i].code2, 4, 0))
return 0;
/* clean-up the stack from the remaining dst address */
if (!slang_assembly_file_push_label (file, slang_asm_local_free, 4))
return 0;
return 1;
}
/* XXX: general swizzle! */
static int equality_aggregate (slang_assembly_file *file, const slang_storage_aggregate *agg,
unsigned int *index, unsigned int size, slang_assembly_local_info *info, unsigned int z_label)
{
unsigned int i;
for (i = 0; i < agg->count; i++)
{
const slang_storage_array *arr = agg->arrays + i;
unsigned int j;
for (j = 0; j < arr->length; j++)
{
if (arr->type == slang_stor_aggregate)
{
if (!equality_aggregate (file, arr->aggregate, index, size, info, z_label))
return 0;
}
else
{
if (!slang_assembly_file_push_label2 (file, slang_asm_float_equal, size + *index,
*index))
return 0;
*index += 4;
if (!slang_assembly_file_push_label (file, slang_asm_jump_if_zero, z_label))
return 0;
}
}
}
return 1;
}
/* XXX: general swizzle! */
static int equality (slang_assembly_file *file, slang_operation *op,
slang_assembly_name_space *space, slang_assembly_local_info *info, int equal)
{
slang_assembly_typeinfo ti;
int result;
slang_storage_aggregate agg;
unsigned int index, size;
unsigned int skip_jump, true_label, true_jump, false_label, false_jump;
/* get type of operation */
slang_assembly_typeinfo_construct (&ti);
if (!_slang_typeof_operation (op, space, &ti))
{
slang_assembly_typeinfo_destruct (&ti);
return 0;
}
/* convert it to an aggregate */
slang_storage_aggregate_construct (&agg);
if (!(result = _slang_aggregate_variable (&agg, &ti.spec, NULL, space->funcs, space->structs)))
goto end;
/* compute the size of the agregate - there are two such aggregates on the stack */
size = _slang_sizeof_aggregate (&agg);
/* jump to the actual data-comparison code */
skip_jump = file->count;
if (!(result = slang_assembly_file_push (file, slang_asm_jump)))
goto end;
/* pop off the stack the compared data and push 1 */
true_label = file->count;
if (!(result = slang_assembly_file_push_label (file, slang_asm_local_free, size * 2)))
goto end;
if (!(result = slang_assembly_file_push_literal (file, slang_asm_bool_push, 1.0f)))
goto end;
true_jump = file->count;
if (!(result = slang_assembly_file_push (file, slang_asm_jump)))
goto end;
false_label = file->count;
if (!(result = slang_assembly_file_push_label (file, slang_asm_local_free, size * 2)))
goto end;
if (!(result = slang_assembly_file_push_literal (file, slang_asm_bool_push, 0.0f)))
goto end;
false_jump = file->count;
if (!(result = slang_assembly_file_push (file, slang_asm_jump)))
goto end;
file->code[skip_jump].param[0] = file->count;
/* compare the data on stack, it will eventually jump either to true or false label */
index = 0;
if (!(result = equality_aggregate (file, &agg, &index, size, info,
equal ? false_label : true_label)))
goto end;
if (!(result = slang_assembly_file_push_label (file, slang_asm_jump,
equal ? true_label : false_label)))
goto end;
file->code[true_jump].param[0] = file->count;
file->code[false_jump].param[0] = file->count;
result = 1;
end:
slang_storage_aggregate_destruct (&agg);
slang_assembly_typeinfo_destruct (&ti);
return result;
}
int _slang_assemble_operation (slang_assembly_file *file, slang_operation *op, int reference,
slang_assembly_flow_control *flow, slang_assembly_name_space *space,
slang_assembly_local_info *info, slang_assembly_stack_info *stk)
{
unsigned int assem;
stk->swizzle_mask = 0;
assem = file->count;
if (!slang_assembly_file_push_new (file))
return 0;
switch (op->type)
{
case slang_oper_block_no_new_scope:
case slang_oper_block_new_scope:
{
unsigned int i;
for (i = 0; i < op->num_children; i++)
{
slang_assembly_stack_info stk;
if (!_slang_assemble_operation (file, op->children + i, 0, flow, space, info, &stk))
return 0;
/* TODO: pass-in stk to cleanup */
if (!_slang_cleanup_stack (file, op->children + i, 0, space))
return 0;
}
}
break;
case slang_oper_variable_decl:
{
unsigned int i;
for (i = 0; i < op->num_children; i++)
{
/* TODO: perform initialization of op->children[i] */
/* TODO: clean-up stack */
}
}
break;
case slang_oper_asm:
{
unsigned int i;
for (i = 0; i < op->num_children; i++)
{
slang_assembly_stack_info stk;
if (!_slang_assemble_operation (file, op->children + i, i == 0, flow, space, info,
&stk))
return 0;
/* TODO: inspect stk */
}
if (!call_asm_instruction (file, op->identifier))
return 0;
}
break;
case slang_oper_break:
file->code[assem].type = slang_asm_jump;
file->code[assem].param[0] = flow->loop_end;
break;
case slang_oper_continue:
file->code[assem].type = slang_asm_jump;
file->code[assem].param[0] = flow->loop_start;
break;
case slang_oper_discard:
file->code[assem].type = slang_asm_discard;
if (!slang_assembly_file_push (file, slang_asm_exit))
return 0;
break;
case slang_oper_return:
if (info->ret_size != 0)
{
slang_assembly_stack_info stk;
if (!slang_assembly_file_push_label2 (file, slang_asm_local_addr, 0, info->ret_size))
return 0;
if (!_slang_assemble_operation (file, op->children, 0, flow, space, info, &stk))
return 0;
/* TODO: inspect stk */
if (!_slang_assemble_assignment (file, op->children, space, info))
return 0;
if (!slang_assembly_file_push_label (file, slang_asm_local_free, 4))
return 0;
}
if (!slang_assembly_file_push_label (file, slang_asm_jump, flow->function_end))
return 0;
break;
case slang_oper_expression:
{
slang_assembly_stack_info stk;
if (!_slang_assemble_operation (file, op->children, reference, flow, space, info, &stk))
return 0;
/* TODO: inspect stk */
}
break;
case slang_oper_if:
if (!_slang_assemble_if (file, op, flow, space, info))
return 0;
break;
case slang_oper_while:
if (!_slang_assemble_while (file, op, flow, space, info))
return 0;
break;
case slang_oper_do:
if (!_slang_assemble_do (file, op, flow, space, info))
return 0;
break;
case slang_oper_for:
if (!_slang_assemble_for (file, op, flow, space, info))
return 0;
break;
case slang_oper_void:
break;
case slang_oper_literal_bool:
file->code[assem].type = slang_asm_bool_push;
file->code[assem].literal = op->literal;
break;
case slang_oper_literal_int:
file->code[assem].type = slang_asm_int_push;
file->code[assem].literal = op->literal;
break;
case slang_oper_literal_float:
file->code[assem].type = slang_asm_float_push;
file->code[assem].literal = op->literal;
break;
case slang_oper_identifier:
{
slang_variable *var;
unsigned int size;
var = _slang_locate_variable (op->locals, op->identifier, 1);
if (var == NULL)
return 0;
size = 0;
if (!sizeof_variable (&var->type.specifier, slang_qual_none, var->array_size, space,
&size))
return 0;
if (var->initializer != NULL)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -