diff options
Diffstat (limited to 'src/mesa')
29 files changed, 5016 insertions, 339 deletions
diff --git a/src/mesa/shader/slang/slang_assemble.c b/src/mesa/shader/slang/slang_assemble.c index 0cba5d5d007..617249487f5 100644 --- a/src/mesa/shader/slang/slang_assemble.c +++ b/src/mesa/shader/slang/slang_assemble.c @@ -1,6 +1,6 @@ /* * Mesa 3-D graphics library - * Version: 6.5 + * Version: 6.5.2 * * Copyright (C) 2005-2006 Brian Paul All Rights Reserved. * @@ -32,6 +32,10 @@ #include "slang_assemble.h" #include "slang_compile.h" #include "slang_storage.h" +#include "slang_error.h" + +#include "slang_print.h" +/*#include "assemble2.c"*/ /* slang_assembly */ @@ -99,6 +103,9 @@ push_gen(slang_assembly_file * file, slang_assembly_type type, { slang_assembly *assem; +#if 0 + printf("Gen %s %f %d %d\n", slang_asm_string(type), literal, label, size); +#endif if (!push_new(file)) return GL_FALSE; assem = &file->code[file->count - 1]; @@ -169,7 +176,7 @@ slang_assembly_file_restore_point_load(slang_assembly_file * file, /* utility functions */ static GLboolean -sizeof_variable(slang_assemble_ctx * A, slang_type_specifier * spec, +sizeof_variable(const slang_assemble_ctx * A, slang_type_specifier * spec, slang_type_qualifier qual, GLuint array_len, GLuint * size) { slang_storage_aggregate agg; @@ -177,9 +184,9 @@ sizeof_variable(slang_assemble_ctx * A, slang_type_specifier * spec, /* 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)) { + 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; } @@ -231,33 +238,39 @@ collect_locals(slang_assemble_ctx * A, slang_operation * op, GLuint * size) /* _slang_locate_function() */ +/** + * Locate a function by comparing actual arguments against formal parameters. + */ slang_function * _slang_locate_function(const slang_function_scope * funcs, slang_atom a_name, - const slang_operation * params, GLuint num_params, + const slang_operation * args, GLuint num_args, const 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]; + const GLuint haveRetValue = _slang_function_has_return_value(f); + GLuint j; if (a_name != f->header.a_name) continue; - if (f->param_count != num_params) + if (f->param_count - haveRetValue != num_args) continue; - for (j = 0; j < num_params; j++) { + + /* compare parameter / argument types */ + for (j = 0; j < num_args; j++) { slang_assembly_typeinfo ti; if (!slang_assembly_typeinfo_construct(&ti)) return NULL; - if (!_slang_typeof_operation_(¶ms[j], space, &ti, atoms)) { + if (!_slang_typeof_operation_(&args[j], space, &ti, atoms)) { slang_assembly_typeinfo_destruct(&ti); return NULL; } - if (!slang_type_specifier_equal - (&ti.spec, &f->parameters->variables[j].type.specifier)) { + if (!slang_type_specifier_equal(&ti.spec, + &f->parameters->variables[j/* + haveRetValue*/].type.specifier)) { slang_assembly_typeinfo_destruct(&ti); break; } @@ -265,26 +278,30 @@ _slang_locate_function(const slang_function_scope * funcs, slang_atom a_name, /* "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)) + (f->parameters->variables[j/* + haveRetValue*/].type.qualifier == slang_qual_out || + f->parameters->variables[j/* + haveRetValue*/].type.qualifier == slang_qual_inout)) break; } - if (j == num_params) + if (j == num_args) return f; } if (funcs->outer_scope != NULL) - return _slang_locate_function(funcs->outer_scope, a_name, params, - num_params, space, atoms); + return _slang_locate_function(funcs->outer_scope, a_name, args, + num_args, space, atoms); return NULL; } -/* _slang_assemble_function() */ + +/** + * Generate assembly for a parsed function. + */ GLboolean _slang_assemble_function(slang_assemble_ctx * A, slang_function * fun) { GLuint param_size, local_size; GLuint skip, cleanup; + const GLuint haveRetValue = _slang_function_has_return_value(fun); fun->address = A->file->count; @@ -293,9 +310,9 @@ _slang_assemble_function(slang_assemble_ctx * A, slang_function * fun) * the instruction to fixup table */ if (!slang_fixup_save(&fun->fixups, fun->address)) - return GL_FALSE; + RETURN_NIL(); if (!PUSH(A->file, slang_asm_jump)) - return GL_FALSE; + RETURN_OUT_OF_MEMORY(); return GL_TRUE; } else { @@ -316,16 +333,18 @@ _slang_assemble_function(slang_assemble_ctx * A, slang_function * fun) /* 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; + if (fun->header.type.specifier.type != slang_spec_void) { + if (!sizeof_variable(A, &fun->header.type.specifier, + slang_qual_none, 0, ¶m_size)) + RETURN_NIL(); + } 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; + if (!sizeof_variables(A, fun->parameters, + 0, + fun->param_count - haveRetValue, ¶m_size)) + RETURN_NIL(); /* calculate local variables size - take into account the four-byte * return address and temporaries for various tasks (4 for addr and @@ -335,52 +354,52 @@ _slang_assemble_function(slang_assemble_ctx * A, slang_function * fun) 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 (!sizeof_variables(A, fun->parameters, fun->param_count, + fun->parameters->num_variables, &local_size)) { + RETURN_OUT_OF_MEMORY(); + } if (!collect_locals(A, fun->body, &local_size)) - return GL_FALSE; + RETURN_NIL(); /* allocate local variable storage */ if (!PLAB(A->file, slang_asm_local_alloc, local_size - param_size - 4)) - return GL_FALSE; + RETURN_OUT_OF_MEMORY(); /* mark a new frame for function variable storage */ if (!PLAB(A->file, slang_asm_enter, local_size)) - return GL_FALSE; + RETURN_OUT_OF_MEMORY(); /* jump directly to the actual code */ skip = A->file->count; if (!push_new(A->file)) - return GL_FALSE; + RETURN_OUT_OF_MEMORY(); 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; + RETURN_OUT_OF_MEMORY(); 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; + if (!_slang_assemble_operation(A, fun->body, + /*slang_ref_freelance */ slang_ref_forbid)) + RETURN_NIL(); /* 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; + RETURN_OUT_OF_MEMORY(); /* free local variable storage */ if (!PLAB(A->file, slang_asm_local_free, local_size - param_size - 4)) - return GL_FALSE; + RETURN_OUT_OF_MEMORY(); /* return from the function */ if (!PUSH(A->file, slang_asm_return)) - return GL_FALSE; + RETURN_OUT_OF_MEMORY(); return GL_TRUE; } @@ -488,23 +507,19 @@ dereference_aggregate(slang_assemble_ctx * A, for (j = arr->length; j > 0; j--) { if (arr->type == slang_stor_aggregate) { - if (!dereference_aggregate - (A, arr->aggregate, size, swz, is_swizzled)) + if (!dereference_aggregate(A, arr->aggregate, size, + swz, is_swizzled)) return GL_FALSE; } else { if (is_swizzled && arr->type == slang_stor_vec4) { - if (!dereference_basic - (A, slang_stor_float, size, swz, is_swizzled)) + if (!dereference_basic(A, slang_stor_float, size, swz, is_swizzled)) return GL_FALSE; - if (!dereference_basic - (A, slang_stor_float, size, swz, is_swizzled)) + if (!dereference_basic(A, slang_stor_float, size, swz, is_swizzled)) return GL_FALSE; - if (!dereference_basic - (A, slang_stor_float, size, swz, is_swizzled)) + if (!dereference_basic(A, slang_stor_float, size, swz, is_swizzled)) return GL_FALSE; - if (!dereference_basic - (A, slang_stor_float, size, swz, is_swizzled)) + if (!dereference_basic(A, slang_stor_float, size, swz, is_swizzled)) return GL_FALSE; } else { @@ -535,9 +550,9 @@ _slang_dereference(slang_assemble_ctx * A, slang_operation * op) /* 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)) + 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 */ @@ -551,6 +566,10 @@ _slang_dereference(slang_assemble_ctx * A, slang_operation * op) return result; } + +/** + * Assemble a function call, given a pointer to the actual function to call. + */ GLboolean _slang_assemble_function_call(slang_assemble_ctx * A, slang_function * fun, slang_operation * params, GLuint param_count, @@ -559,6 +578,9 @@ _slang_assemble_function_call(slang_assemble_ctx * A, slang_function * fun, GLuint i; slang_swizzle p_swz[64]; slang_ref_type p_ref[64]; + /* + const GLuint haveRetValue = _slang_function_has_return_value(fun); + */ /* TODO: fix this, allocate dynamically */ if (param_count > 64) @@ -568,8 +590,8 @@ _slang_assemble_function_call(slang_assemble_ctx * A, slang_function * fun, if (fun->header.type.specifier.type != slang_spec_void) { GLuint ret_size = 0; - if (!sizeof_variable - (A, &fun->header.type.specifier, slang_qual_none, 0, &ret_size)) + if (!sizeof_variable(A, &fun->header.type.specifier, + slang_qual_none, 0, &ret_size)) return GL_FALSE; if (!PLAB(A->file, slang_asm_local_alloc, ret_size)) return GL_FALSE; @@ -577,8 +599,8 @@ _slang_assemble_function_call(slang_assemble_ctx * A, slang_function * fun, /* push the actual parameters on the stack */ for (i = 0; i < param_count; i++) { - if (fun->parameters->variables[i].type.qualifier == slang_qual_inout || - fun->parameters->variables[i].type.qualifier == slang_qual_out) { + if (fun->parameters->variables[i /*+ haveRetValue*/].type.qualifier == slang_qual_inout || + fun->parameters->variables[i /*+ haveRetValue*/].type.qualifier == slang_qual_out) { if (!PLAB2(A->file, slang_asm_local_addr, A->local.addr_tmp, 4)) return GL_FALSE; /* TODO: optimize the "out" parameter case */ @@ -609,6 +631,10 @@ _slang_assemble_function_call(slang_assemble_ctx * A, slang_function * fun, } /* call the function */ +#if 0 + printf("CALL FUNCTION %s\n", (char*) fun->header.a_name); + slang_print_var_scope(fun->parameters, fun->param_count); +#endif if (!PLAB(A->file, slang_asm_call, fun->address)) return GL_FALSE; @@ -618,8 +644,8 @@ _slang_assemble_function_call(slang_assemble_ctx * A, slang_function * fun, A->swz = p_swz[j]; A->ref = p_ref[j]; - if (fun->parameters->variables[j].type.qualifier == slang_qual_inout || - fun->parameters->variables[j].type.qualifier == slang_qual_out) { + if (fun->parameters->variables[j /*+ haveRetValue*/].type.qualifier == slang_qual_inout || + fun->parameters->variables[j/* + haveRetValue*/].type.qualifier == slang_qual_out) { /* for output parameter copy the contents of the formal parameter * back to the original actual parameter */ @@ -639,6 +665,11 @@ _slang_assemble_function_call(slang_assemble_ctx * A, slang_function * fun, return GL_TRUE; } + +/** + * Assemble a function call, given the name of the function to call and a + * list of parameters. + */ GLboolean _slang_assemble_function_call_name(slang_assemble_ctx * A, const char *name, slang_operation * params, @@ -653,6 +684,12 @@ _slang_assemble_function_call_name(slang_assemble_ctx * A, const char *name, fun = _slang_locate_function(A->space.funcs, atom, params, param_count, &A->space, A->atoms); + { + char *s = (char *) name; + if (strcmp(name, "vec4") == 0) + printf("LLLLLLLLLLLLLLL locate %s %p\n", s, (void*) fun); + } + if (fun == NULL) return GL_FALSE; return _slang_assemble_function_call(A, fun, params, param_count, @@ -682,18 +719,25 @@ static const struct } inst[] = { /* core */ {"float_add", slang_asm_float_add, slang_asm_float_copy}, + {"float_subtract", slang_asm_float_subtract, 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_min", slang_asm_float_min, slang_asm_float_copy}, + {"float_max", slang_asm_float_max, slang_asm_float_copy}, {"float_less", slang_asm_float_less, slang_asm_bool_copy}, {"float_equal", slang_asm_float_equal_exp, slang_asm_bool_copy}, {"float_to_int", slang_asm_float_to_int, slang_asm_int_copy}, {"float_sine", slang_asm_float_sine, slang_asm_float_copy}, + {"float_cosine", slang_asm_float_cosine, slang_asm_float_copy}, {"float_arcsine", slang_asm_float_arcsine, slang_asm_float_copy}, {"float_arctan", slang_asm_float_arctan, slang_asm_float_copy}, {"float_power", slang_asm_float_power, slang_asm_float_copy}, + {"float_exp", slang_asm_float_exp, slang_asm_float_copy}, + {"float_exp2", slang_asm_float_exp2, slang_asm_float_copy}, + {"float_rsq", slang_asm_float_rsq, slang_asm_float_copy}, + {"float_rcp", slang_asm_float_rcp, slang_asm_float_copy}, {"float_log2", slang_asm_float_log2, slang_asm_float_copy}, - {"float_floor", slang_asm_float_floor, slang_asm_float_copy}, {"float_ceil", slang_asm_float_ceil, slang_asm_float_copy}, {"float_noise1", slang_asm_float_noise1, slang_asm_float_copy}, {"float_noise2", slang_asm_float_noise2, slang_asm_float_copy}, @@ -712,12 +756,24 @@ static const struct {"bool_print", slang_asm_bool_deref, slang_asm_bool_print}, /* vec4 */ {"float_to_vec4", slang_asm_float_to_vec4, slang_asm_none}, - {"vec4_add", slang_asm_vec4_add, slang_asm_none}, - {"vec4_subtract", slang_asm_vec4_subtract, slang_asm_none}, - {"vec4_multiply", slang_asm_vec4_multiply, slang_asm_none}, + {"vec4_add", slang_asm_vec4_add, slang_asm_float_copy}, + {"vec4_subtract", slang_asm_vec4_subtract, slang_asm_float_copy}, + {"vec4_multiply", slang_asm_vec4_multiply, slang_asm_float_copy}, + {"vec4_min", slang_asm_vec4_min, slang_asm_float_copy}, + {"vec4_max", slang_asm_vec4_max, slang_asm_float_copy}, + {"vec4_seq", slang_asm_vec4_seq, slang_asm_float_copy}, + {"vec4_sne", slang_asm_vec4_sne, slang_asm_float_copy}, + {"vec4_sge", slang_asm_vec4_sge, slang_asm_float_copy}, + {"vec4_sgt", slang_asm_vec4_sgt, slang_asm_float_copy}, + {"vec4_floor", slang_asm_vec4_floor, slang_asm_float_copy}, + {"vec4_frac", slang_asm_vec4_frac, slang_asm_float_copy}, + {"vec4_abs", slang_asm_vec4_abs, slang_asm_float_copy}, + {"vec4_divide", slang_asm_vec4_divide, slang_asm_none}, {"vec4_negate", slang_asm_vec4_negate, slang_asm_none}, - {"vec4_dot", slang_asm_vec4_dot, slang_asm_none}, + {"vec4_dot", slang_asm_vec4_dot, slang_asm_float_copy}, + {"vec3_dot", slang_asm_vec3_dot, slang_asm_float_copy}, + {"vec3_cross", slang_asm_vec3_cross, slang_asm_float_copy}, {NULL, slang_asm_none, slang_asm_none} }; @@ -767,15 +823,14 @@ equality_aggregate(slang_assemble_ctx * A, else { #if defined(USE_X86_ASM) || defined(SLANG_X86) if (arr->type == slang_stor_vec4) { - if (!PLAB2 - (A->file, slang_asm_vec4_equal_int, size + *index, *index)) + if (!PLAB2(A->file, slang_asm_vec4_equal_int, + size + *index, *index)) return GL_FALSE; } else #endif - if (!PLAB2 - (A->file, slang_asm_float_equal_int, size + *index, - *index)) + if (!PLAB2(A->file, slang_asm_float_equal_int, + size + *index, *index)) return GL_FALSE; *index += _slang_sizeof_type(arr->type); @@ -799,19 +854,21 @@ equality(slang_assemble_ctx * A, slang_operation * op, GLboolean equal) /* get type of operation */ if (!slang_assembly_typeinfo_construct(&ti)) - return GL_FALSE; + RETURN_OUT_OF_MEMORY(); if (!_slang_typeof_operation(A, op, &ti)) goto end1; /* convert it to an aggregate */ if (!slang_storage_aggregate_construct(&agg)) goto end1; - if (!_slang_aggregate_variable - (&agg, &ti.spec, 0, A->space.funcs, A->space.structs, A->space.vars, - A->mach, A->file, A->atoms)) + if (!_slang_aggregate_variable(&agg, &ti.spec, 0, A->space.funcs, + A->space.structs, A->space.vars, + A->mach, A->file, A->atoms)) goto end; - /* compute the size of the agregate - there are two such aggregates on the stack */ + /* 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 */ @@ -840,10 +897,12 @@ equality(slang_assemble_ctx * A, slang_operation * op, GLboolean equal) A->file->code[skip_jump].param[0] = A->file->count; - /* compare the data on stack, it will eventually jump either to true or false label */ + /* compare the data on stack, it will eventually jump either to + * true or false label + */ index = 0; - if (!equality_aggregate - (A, &agg, &index, size, equal ? false_label : true_label)) + if (!equality_aggregate(A, &agg, &index, size, + equal ? false_label : true_label)) goto end; if (!PLAB(A->file, slang_asm_jump, equal ? true_label : false_label)) goto end; @@ -869,8 +928,8 @@ handle_subscript(slang_assemble_ctx * A, slang_assembly_typeinfo * tie, /* get type info of the master expression (matrix, vector or an array */ if (!_slang_typeof_operation(A, &op->children[0], tia)) return GL_FALSE; - if (!sizeof_variable - (A, &tia->spec, slang_qual_none, tia->array_len, &asize)) + if (!sizeof_variable(A, &tia->spec, slang_qual_none, + tia->array_len, &asize)) return GL_FALSE; /* get type info of the result (matrix column, vector row or array element) */ @@ -944,8 +1003,8 @@ handle_subscript(slang_assemble_ctx * A, slang_assembly_typeinfo * tie, /* move the selected element to the beginning of the master expression */ for (i = 0; i < esize; i += 4) - if (!PLAB2 - (A->file, slang_asm_float_move, asize - esize + i + 4, i + 4)) + if (!PLAB2(A->file, slang_asm_float_move, + asize - esize + i + 4, i + 4)) return GL_FALSE; if (!PLAB(A->file, slang_asm_local_free, 4)) return GL_FALSE; @@ -965,20 +1024,20 @@ handle_field(slang_assemble_ctx * A, slang_assembly_typeinfo * tia, { /* get type info of the result (field or swizzle) */ if (!_slang_typeof_operation(A, op, tia)) - return GL_FALSE; + RETURN_NIL(); /* get type info of the master expression being accessed (struct or vector) */ if (!_slang_typeof_operation(A, &op->children[0], tib)) - return GL_FALSE; + RETURN_NIL(); /* if swizzling a vector in-place, the swizzle temporary is needed */ if (ref == slang_ref_forbid && tia->is_swizzled) if (!PLAB2(A->file, slang_asm_local_addr, A->local.swizzle_tmp, 16)) - return GL_FALSE; + RETURN_OUT_OF_MEMORY(); /* assemble the master expression */ if (!_slang_assemble_operation(A, &op->children[0], ref)) - return GL_FALSE; + RETURN_NIL(); /* assemble the field expression */ if (tia->is_swizzled) { @@ -989,9 +1048,9 @@ handle_field(slang_assemble_ctx * A, slang_assembly_typeinfo * tia, * the selected component */ if (!PLAB(file, slang_asm_addr_push, tia->swz.swizzle[0] * 4)) - return 0; + RETURN_OUT_OF_MEMORY(); if (!PUSH(file, slang_asm_addr_add)) - return 0; + RETURN_OUT_OF_MEMORY(); } else #endif @@ -1005,9 +1064,9 @@ handle_field(slang_assemble_ctx * A, slang_assembly_typeinfo * tia, } else { /* swizzle the vector in-place using the swizzle temporary */ - if (!_slang_assemble_constructor_from_swizzle - (A, &tia->swz, &tia->spec, &tib->spec)) - return GL_FALSE; + if (!_slang_assemble_constructor_from_swizzle(A, &tia->swz, + &tia->spec, &tib->spec)) + RETURN_NIL(); } } else { @@ -1023,12 +1082,13 @@ handle_field(slang_assemble_ctx * A, slang_assembly_typeinfo * tia, field = &tib->spec._struct->fields->variables[i]; if (!slang_storage_aggregate_construct(&agg)) - return GL_FALSE; - if (!_slang_aggregate_variable - (&agg, &field->type.specifier, field->array_len, A->space.funcs, - A->space.structs, A->space.vars, A->mach, A->file, A->atoms)) { + RETURN_NIL(); + if (!_slang_aggregate_variable(&agg, &field->type.specifier, + field->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; + RETURN_NIL(); } size = _slang_sizeof_aggregate(&agg); slang_storage_aggregate_destruct(&agg); @@ -1051,9 +1111,9 @@ handle_field(slang_assemble_ctx * A, slang_assembly_typeinfo * tia, if (shift) { if (!PLAB(A->file, slang_asm_addr_push, field_offset)) - return GL_FALSE; + RETURN_OUT_OF_MEMORY(); if (!PUSH(A->file, slang_asm_addr_add)) - return GL_FALSE; + RETURN_OUT_OF_MEMORY(); } } else { @@ -1079,12 +1139,11 @@ handle_field(slang_assemble_ctx * A, slang_assembly_typeinfo * tia, * Do it in reverse order to avoid overwriting itself. */ if (!PLAB(A->file, slang_asm_addr_push, field_offset)) - return GL_FALSE; + RETURN_OUT_OF_MEMORY(); for (i = field_size; i > 0; i -= 4) - if (!PLAB2 - (A->file, slang_asm_float_move, - struct_size - field_size + i, i)) - return GL_FALSE; + if (!PLAB2(A->file, slang_asm_float_move, + struct_size - field_size + i, i)) + RETURN_OUT_OF_MEMORY(); free_b += 4; } @@ -1095,7 +1154,7 @@ handle_field(slang_assemble_ctx * A, slang_assembly_typeinfo * tia, if (free_b) { if (!PLAB(A->file, slang_asm_local_free, free_b)) - return GL_FALSE; + RETURN_OUT_OF_MEMORY(); } } } @@ -1118,12 +1177,11 @@ _slang_assemble_operation(slang_assemble_ctx * A, slang_operation * op, GLuint i; for (i = 0; i < op->num_children; i++) { - if (!_slang_assemble_operation - (A, &op->children[i], - slang_ref_forbid /*slang_ref_freelance */ )) - return GL_FALSE; + if (!_slang_assemble_operation(A, &op->children[i], + slang_ref_forbid /*slang_ref_freelance */ )) + RETURN_NIL(); if (!_slang_cleanup_stack(A, &op->children[i])) - return GL_FALSE; + RETURN_NIL(); } } break; @@ -1135,21 +1193,19 @@ _slang_assemble_operation(slang_assemble_ctx * A, slang_operation * op, /* Construct assignment expression placeholder. */ if (!slang_operation_construct(&assign)) - return GL_FALSE; + RETURN_NIL(); assign.type = slang_oper_assign; - assign.children = - (slang_operation *) slang_alloc_malloc(2 * - sizeof(slang_operation)); + assign.children = slang_operation_new(2); if (assign.children == NULL) { slang_operation_destruct(&assign); - return GL_FALSE; + RETURN_NIL(); } for (assign.num_children = 0; assign.num_children < 2; assign.num_children++) - if (!slang_operation_construct - (&assign.children[assign.num_children])) { + if (!slang_operation_construct(&assign.children + [assign.num_children])) { slang_operation_destruct(&assign); - return GL_FALSE; + RETURN_OUT_OF_MEMORY(); } result = GL_TRUE; @@ -1177,99 +1233,98 @@ _slang_assemble_operation(slang_assemble_ctx * A, slang_operation * op, } slang_operation_destruct(&assign); if (!result) - return GL_FALSE; + RETURN_NIL(); } break; case slang_oper_asm: { GLuint i; if (!_slang_assemble_operation(A, &op->children[0], slang_ref_force)) - return GL_FALSE; + RETURN_NIL(); for (i = 1; i < op->num_children; i++) - if (!_slang_assemble_operation - (A, &op->children[i], slang_ref_forbid)) - return GL_FALSE; + if (!_slang_assemble_operation(A, &op->children[i], + slang_ref_forbid)) + RETURN_NIL(); if (!call_asm_instruction(A, op->a_id)) - return GL_FALSE; + RETURN_ERROR2("Unknown __asm call", (char*) op->a_id, 0); } break; case slang_oper_break: if (!PLAB(A->file, slang_asm_jump, A->flow.loop_end)) - return GL_FALSE; + RETURN_OUT_OF_MEMORY(); break; case slang_oper_continue: if (!PLAB(A->file, slang_asm_jump, A->flow.loop_start)) - return GL_FALSE; + RETURN_OUT_OF_MEMORY(); break; case slang_oper_discard: if (!PUSH(A->file, slang_asm_discard)) - return GL_FALSE; + RETURN_OUT_OF_MEMORY(); if (!PUSH(A->file, slang_asm_exit)) - return GL_FALSE; + RETURN_OUT_OF_MEMORY(); break; case slang_oper_return: if (A->local.ret_size != 0) { /* push the result's address */ if (!PLAB2(A->file, slang_asm_local_addr, 0, A->local.ret_size)) - return GL_FALSE; - if (!_slang_assemble_operation - (A, &op->children[0], slang_ref_forbid)) - return GL_FALSE; + RETURN_OUT_OF_MEMORY(); + if (!_slang_assemble_operation(A, &op->children[0], slang_ref_forbid)) + RETURN_NIL(); A->swz.num_components = 0; /* assign the operation to the function result (it was reserved on the stack) */ if (!_slang_assemble_assignment(A, op->children)) - return GL_FALSE; + RETURN_NIL(); if (!PLAB(A->file, slang_asm_local_free, 4)) - return GL_FALSE; + RETURN_OUT_OF_MEMORY(); } if (!PLAB(A->file, slang_asm_jump, A->flow.function_end)) - return GL_FALSE; + RETURN_OUT_OF_MEMORY(); break; case slang_oper_expression: if (ref == slang_ref_force) - return GL_FALSE; + RETURN_NIL(); if (!_slang_assemble_operation(A, &op->children[0], ref)) - return GL_FALSE; + RETURN_NIL(); break; case slang_oper_if: if (!_slang_assemble_if(A, op)) - return GL_FALSE; + RETURN_NIL(); break; case slang_oper_while: if (!_slang_assemble_while(A, op)) - return GL_FALSE; + RETURN_NIL(); break; case slang_oper_do: if (!_slang_assemble_do(A, op)) - return GL_FALSE; + RETURN_NIL(); break; case slang_oper_for: if (!_slang_assemble_for(A, op)) - return GL_FALSE; + RETURN_NIL(); break; case slang_oper_void: break; case slang_oper_literal_bool: if (ref == slang_ref_force) - return GL_FALSE; - if (!PLIT(A->file, slang_asm_bool_push, op->literal)) - return GL_FALSE; + RETURN_NIL(); + if (!PLIT(A->file, slang_asm_bool_push, op->literal[0])) + RETURN_OUT_OF_MEMORY(); A->ref = slang_ref_forbid; break; case slang_oper_literal_int: if (ref == slang_ref_force) - return GL_FALSE; - if (!PLIT(A->file, slang_asm_int_push, op->literal)) - return GL_FALSE; + RETURN_NIL(); + if (!PLIT(A->file, slang_asm_int_push, op->literal[0])) + RETURN_OUT_OF_MEMORY(); A->ref = slang_ref_forbid; break; case slang_oper_literal_float: if (ref == slang_ref_force) - return GL_FALSE; - if (!PLIT(A->file, slang_asm_float_push, op->literal)) - return GL_FALSE; + RETURN_NIL(); + if (!PLIT(A->file, slang_asm_float_push, op->literal[0])) + RETURN_OUT_OF_MEMORY(); A->ref = slang_ref_forbid; break; case slang_oper_identifier: @@ -1280,68 +1335,67 @@ _slang_assemble_operation(slang_assemble_ctx * A, slang_operation * op, /* find the variable and calculate its size */ var = _slang_locate_variable(op->locals, op->a_id, GL_TRUE); if (var == NULL) - return GL_FALSE; + RETURN_ERROR2("undefined variable", (char *) op->a_id, 0); size = 0; - if (!sizeof_variable - (A, &var->type.specifier, slang_qual_none, var->array_len, - &size)) - return GL_FALSE; + if (!sizeof_variable(A, &var->type.specifier, slang_qual_none, + var->array_len, &size)) + RETURN_OUT_OF_MEMORY(); /* prepare stack for dereferencing */ if (ref == slang_ref_forbid) if (!PLAB2(A->file, slang_asm_local_addr, A->local.addr_tmp, 4)) - return GL_FALSE; + RETURN_OUT_OF_MEMORY(); /* push the variable's address */ if (var->global) { if (!PLAB(A->file, slang_asm_global_addr, var->address)) - return GL_FALSE; + RETURN_OUT_OF_MEMORY(); } else { if (!PLAB2(A->file, slang_asm_local_addr, var->address, size)) - return GL_FALSE; + RETURN_OUT_OF_MEMORY(); } /* perform the dereference */ if (ref == slang_ref_forbid) { if (!PUSH(A->file, slang_asm_addr_copy)) - return GL_FALSE; + RETURN_OUT_OF_MEMORY(); if (!PLAB(A->file, slang_asm_local_free, 4)) - return GL_FALSE; + RETURN_OUT_OF_MEMORY(); if (!_slang_dereference(A, op)) - return GL_FALSE; + RETURN_NIL(); } } break; case slang_oper_sequence: if (ref == slang_ref_force) - return GL_FALSE; + RETURN_NIL(); if (!_slang_assemble_operation(A, &op->children[0], slang_ref_forbid /*slang_ref_freelance */ )) - return GL_FALSE; + RETURN_NIL(); if (!_slang_cleanup_stack(A, &op->children[0])) - return GL_FALSE; + RETURN_NIL(); if (!_slang_assemble_operation(A, &op->children[1], slang_ref_forbid)) - return GL_FALSE; + RETURN_NIL(); A->ref = slang_ref_forbid; break; case slang_oper_assign: if (!_slang_assemble_assign(A, op, "=", ref)) - return GL_FALSE; + RETURN_NIL(); break; case slang_oper_addassign: if (!_slang_assemble_assign(A, op, "+=", ref)) - return GL_FALSE; + RETURN_NIL(); A->ref = ref; break; case slang_oper_subassign: if (!_slang_assemble_assign(A, op, "-=", ref)) - return GL_FALSE; + RETURN_NIL(); A->ref = ref; break; case slang_oper_mulassign: if (!_slang_assemble_assign(A, op, "*=", ref)) - return GL_FALSE; + RETURN_NIL(); A->ref = ref; break; /*case slang_oper_modassign: */ @@ -1352,27 +1406,27 @@ _slang_assemble_operation(slang_assemble_ctx * A, slang_operation * op, /*case slang_oper_andassign: */ case slang_oper_divassign: if (!_slang_assemble_assign(A, op, "/=", ref)) - return GL_FALSE; + RETURN_NIL(); A->ref = ref; break; case slang_oper_select: if (!_slang_assemble_select(A, op)) - return GL_FALSE; + RETURN_NIL(); A->ref = slang_ref_forbid; break; case slang_oper_logicalor: if (!_slang_assemble_logicalor(A, op)) - return GL_FALSE; + RETURN_NIL(); A->ref = slang_ref_forbid; break; case slang_oper_logicaland: if (!_slang_assemble_logicaland(A, op)) - return GL_FALSE; + RETURN_NIL(); A->ref = slang_ref_forbid; break; case slang_oper_logicalxor: if (!_slang_assemble_function_call_name(A, "^^", op->children, 2, GL_FALSE)) - return GL_FALSE; + RETURN_NIL(); A->ref = slang_ref_forbid; break; /*case slang_oper_bitor: */ @@ -1380,91 +1434,89 @@ _slang_assemble_operation(slang_assemble_ctx * A, slang_operation * op, /*case slang_oper_bitand: */ case slang_oper_less: if (!_slang_assemble_function_call_name(A, "<", op->children, 2, GL_FALSE)) - return GL_FALSE; + RETURN_NIL(); A->ref = slang_ref_forbid; break; case slang_oper_greater: if (!_slang_assemble_function_call_name(A, ">", op->children, 2, GL_FALSE)) - return GL_FALSE; + RETURN_NIL(); A->ref = slang_ref_forbid; break; case slang_oper_lessequal: if (!_slang_assemble_function_call_name(A, "<=", op->children, 2, GL_FALSE)) - return GL_FALSE; + RETURN_NIL(); A->ref = slang_ref_forbid; break; case slang_oper_greaterequal: if (!_slang_assemble_function_call_name(A, ">=", op->children, 2, GL_FALSE)) - return GL_FALSE; + RETURN_NIL(); A->ref = slang_ref_forbid; break; /*case slang_oper_lshift: */ /*case slang_oper_rshift: */ case slang_oper_add: if (!_slang_assemble_function_call_name(A, "+", op->children, 2, GL_FALSE)) - return GL_FALSE; + RETURN_NIL(); A->ref = slang_ref_forbid; break; case slang_oper_subtract: if (!_slang_assemble_function_call_name(A, "-", op->children, 2, GL_FALSE)) - return GL_FALSE; + RETURN_NIL(); A->ref = slang_ref_forbid; break; case slang_oper_multiply: if (!_slang_assemble_function_call_name(A, "*", op->children, 2, GL_FALSE)) - return GL_FALSE; + RETURN_NIL(); A->ref = slang_ref_forbid; break; /*case slang_oper_modulus: */ case slang_oper_divide: if (!_slang_assemble_function_call_name(A, "/", op->children, 2, GL_FALSE)) - return GL_FALSE; + RETURN_NIL(); A->ref = slang_ref_forbid; break; case slang_oper_equal: if (!_slang_assemble_operation(A, &op->children[0], slang_ref_forbid)) - return GL_FALSE; + RETURN_NIL(); if (!_slang_assemble_operation(A, &op->children[1], slang_ref_forbid)) - return GL_FALSE; + RETURN_NIL(); if (!equality(A, op->children, GL_TRUE)) - return GL_FALSE; + RETURN_NIL(); A->ref = slang_ref_forbid; break; case slang_oper_notequal: if (!_slang_assemble_operation(A, &op->children[0], slang_ref_forbid)) - return GL_FALSE; + RETURN_NIL(); if (!_slang_assemble_operation(A, &op->children[1], slang_ref_forbid)) - return GL_FALSE; + RETURN_NIL(); if (!equality(A, op->children, GL_FALSE)) - return GL_FALSE; + RETURN_NIL(); A->ref = slang_ref_forbid; break; case slang_oper_preincrement: if (!_slang_assemble_assign(A, op, "++", ref)) - return GL_FALSE; + RETURN_NIL(); A->ref = ref; break; case slang_oper_predecrement: if (!_slang_assemble_assign(A, op, "--", ref)) - return GL_FALSE; + RETURN_NIL(); A->ref = ref; break; case slang_oper_plus: if (!_slang_dereference(A, op)) - return GL_FALSE; + RETURN_NIL(); A->ref = slang_ref_forbid; break; case slang_oper_minus: - if (!_slang_assemble_function_call_name - (A, "-", op->children, 1, GL_FALSE)) - return GL_FALSE; + if (!_slang_assemble_function_call_name(A, "-", op->children, 1, GL_FALSE)) + RETURN_NIL(); A->ref = slang_ref_forbid; break; /*case slang_oper_complement: */ case slang_oper_not: - if (!_slang_assemble_function_call_name - (A, "!", op->children, 1, GL_FALSE)) - return GL_FALSE; + if (!_slang_assemble_function_call_name(A, "!", op->children, 1, GL_FALSE)) + RETURN_NIL(); A->ref = slang_ref_forbid; break; case slang_oper_subscript: @@ -1472,15 +1524,15 @@ _slang_assemble_operation(slang_assemble_ctx * A, slang_operation * op, slang_assembly_typeinfo ti_arr, ti_elem; if (!slang_assembly_typeinfo_construct(&ti_arr)) - return GL_FALSE; + RETURN_OUT_OF_MEMORY(); if (!slang_assembly_typeinfo_construct(&ti_elem)) { slang_assembly_typeinfo_destruct(&ti_arr); - return GL_FALSE; + RETURN_OUT_OF_MEMORY(); } if (!handle_subscript(A, &ti_elem, &ti_arr, op, ref)) { slang_assembly_typeinfo_destruct(&ti_arr); slang_assembly_typeinfo_destruct(&ti_elem); - return GL_FALSE; + RETURN_NIL(); } slang_assembly_typeinfo_destruct(&ti_arr); slang_assembly_typeinfo_destruct(&ti_elem); @@ -1488,19 +1540,17 @@ _slang_assemble_operation(slang_assemble_ctx * A, slang_operation * op, break; case slang_oper_call: { - slang_function *fun; - - fun = - _slang_locate_function(A->space.funcs, op->a_id, op->children, - op->num_children, &A->space, A->atoms); + slang_function *fun + = _slang_locate_function(A->space.funcs, op->a_id, op->children, + op->num_children, &A->space, A->atoms); if (fun == NULL) { if (!_slang_assemble_constructor(A, op)) - return GL_FALSE; + RETURN_OUT_OF_MEMORY(); } else { - if (!_slang_assemble_function_call - (A, fun, op->children, op->num_children, GL_FALSE)) - return GL_FALSE; + if (!_slang_assemble_function_call(A, fun, op->children, + op->num_children, GL_FALSE)) + RETURN_NIL(); } A->ref = slang_ref_forbid; } @@ -1510,15 +1560,15 @@ _slang_assemble_operation(slang_assemble_ctx * A, slang_operation * op, slang_assembly_typeinfo ti_after, ti_before; if (!slang_assembly_typeinfo_construct(&ti_after)) - return GL_FALSE; + RETURN_OUT_OF_MEMORY(); if (!slang_assembly_typeinfo_construct(&ti_before)) { slang_assembly_typeinfo_destruct(&ti_after); - return GL_FALSE; + RETURN_OUT_OF_MEMORY(); } if (!handle_field(A, &ti_after, &ti_before, op, ref)) { slang_assembly_typeinfo_destruct(&ti_after); slang_assembly_typeinfo_destruct(&ti_before); - return GL_FALSE; + RETURN_NIL(); } slang_assembly_typeinfo_destruct(&ti_after); slang_assembly_typeinfo_destruct(&ti_before); @@ -1526,16 +1576,16 @@ _slang_assemble_operation(slang_assemble_ctx * A, slang_operation * op, break; case slang_oper_postincrement: if (!assemble_function_call_name_dummyint(A, "++", op->children)) - return GL_FALSE; + RETURN_NIL(); A->ref = slang_ref_forbid; break; case slang_oper_postdecrement: if (!assemble_function_call_name_dummyint(A, "--", op->children)) - return GL_FALSE; + RETURN_NIL(); A->ref = slang_ref_forbid; break; default: - return GL_FALSE; + RETURN_NIL(); } return GL_TRUE; diff --git a/src/mesa/shader/slang/slang_assemble.h b/src/mesa/shader/slang/slang_assemble.h index d004e665003..d507fc0161e 100644 --- a/src/mesa/shader/slang/slang_assemble.h +++ b/src/mesa/shader/slang/slang_assemble.h @@ -25,6 +25,8 @@ #ifndef SLANG_ASSEMBLE_H #define SLANG_ASSEMBLE_H +#include "imports.h" +#include "mtypes.h" #include "slang_utility.h" #if defined __cplusplus @@ -43,6 +45,7 @@ typedef enum slang_assembly_type_ slang_asm_float_push, slang_asm_float_deref, slang_asm_float_add, /* a = pop(); b = pop(); push(a + b); */ + slang_asm_float_subtract, slang_asm_float_multiply, slang_asm_float_divide, slang_asm_float_negate, /* push(-pop()) */ @@ -51,11 +54,17 @@ typedef enum slang_assembly_type_ slang_asm_float_equal_int, slang_asm_float_to_int, /* push(floatToInt(pop())) */ slang_asm_float_sine, /* push(sin(pop()) */ + slang_asm_float_cosine, slang_asm_float_arcsine, slang_asm_float_arctan, slang_asm_float_power, /* push(pow(pop(), pop())) */ + slang_asm_float_exp, + slang_asm_float_exp2, + slang_asm_float_rsq, + slang_asm_float_rcp, slang_asm_float_log2, - slang_asm_float_floor, + slang_asm_float_min, + slang_asm_float_max, slang_asm_float_ceil, slang_asm_float_noise1, /* push(noise1(pop()) */ slang_asm_float_noise2, /* push(noise2(pop(), pop())) */ @@ -114,7 +123,19 @@ typedef enum slang_assembly_type_ slang_asm_vec4_multiply, slang_asm_vec4_divide, slang_asm_vec4_negate, + slang_asm_vec4_min, + slang_asm_vec4_max, + slang_asm_vec4_seq, + slang_asm_vec4_sne, + slang_asm_vec4_sge, + slang_asm_vec4_sgt, slang_asm_vec4_dot, + slang_asm_vec3_dot, + slang_asm_vec3_cross, + slang_asm_vec4_floor, + slang_asm_vec4_frac, + slang_asm_vec4_abs, + slang_asm_vec4_copy, slang_asm_vec4_deref, slang_asm_vec4_equal_int, @@ -231,6 +252,7 @@ typedef struct slang_assemble_ctx_ slang_assembly_local_info local; slang_ref_type ref; slang_swizzle swz; + struct gl_program *program; } slang_assemble_ctx; extern struct slang_function_ * @@ -244,9 +266,6 @@ extern GLboolean _slang_assemble_function(slang_assemble_ctx *, struct slang_function_ *); extern GLboolean -_slang_assemble_function2(slang_assemble_ctx * , struct slang_function_ *); - -extern GLboolean _slang_cleanup_stack(slang_assemble_ctx *, struct slang_operation_ *); extern GLboolean diff --git a/src/mesa/shader/slang/slang_assemble_assignment.c b/src/mesa/shader/slang/slang_assemble_assignment.c index a1038671c41..dbcc4bcf9df 100644 --- a/src/mesa/shader/slang/slang_assemble_assignment.c +++ b/src/mesa/shader/slang/slang_assemble_assignment.c @@ -31,6 +31,7 @@ #include "imports.h" #include "slang_assemble.h" #include "slang_storage.h" +#include "slang_error.h" /* * _slang_assemble_assignment() @@ -95,9 +96,9 @@ assign_basic(slang_assemble_ctx * A, slang_storage_type type, GLuint * index, */ dst_addr_loc = size - *index; - if (!slang_assembly_file_push_label2 - (A->file, ty, dst_addr_loc, dst_offset)) - return GL_FALSE; + if (!slang_assembly_file_push_label2(A->file, ty, dst_addr_loc, dst_offset)) + RETURN_NIL(); + *index += _slang_sizeof_type(type); return GL_TRUE; @@ -155,7 +156,7 @@ _slang_assemble_assignment(slang_assemble_ctx * A, const slang_operation * op) GLuint index, size; if (!slang_assembly_typeinfo_construct(&ti)) - return GL_FALSE; + RETURN_OUT_OF_MEMORY(); if (!_slang_typeof_operation(A, op, &ti)) goto end1; @@ -174,6 +175,8 @@ _slang_assemble_assignment(slang_assemble_ctx * A, const slang_operation * op) slang_storage_aggregate_destruct(&agg); end: slang_assembly_typeinfo_destruct(&ti); + if (!result) + RETURN_NIL(); return result; } diff --git a/src/mesa/shader/slang/slang_assemble_constructor.c b/src/mesa/shader/slang/slang_assemble_constructor.c index 6cd320d4466..a4115971303 100644 --- a/src/mesa/shader/slang/slang_assemble_constructor.c +++ b/src/mesa/shader/slang/slang_assemble_constructor.c @@ -46,6 +46,10 @@ _slang_is_swizzle(const char *field, GLuint rows, slang_swizzle * swz) GLuint i; GLboolean xyzw = GL_FALSE, rgba = GL_FALSE, stpq = GL_FALSE; + /* init to default */ + for (i = 0; i < 4; i++) + swz->swizzle[i] = i; + /* the swizzle can be at most 4-component long */ swz->num_components = slang_string_length(field); if (swz->num_components > 4) @@ -109,6 +113,12 @@ _slang_is_swizzle(const char *field, GLuint rows, slang_swizzle * swz) if ((xyzw && rgba) || (xyzw && stpq) || (rgba && stpq)) return GL_FALSE; + if (swz->num_components == 1) { + /* smear */ + swz->swizzle[3] = + swz->swizzle[2] = + swz->swizzle[1] = swz->swizzle[0]; + } return GL_TRUE; } @@ -301,6 +311,18 @@ _slang_assemble_constructor(slang_assemble_ctx * A, const slang_operation * op) /* check if there are too few arguments */ if (arg_sums[1] < size) { /* TODO: info log: too few arguments in constructor list */ + /* DEBUG */ + { + if (!slang_storage_aggregate_construct(&agg)) + goto end1; + if (!_slang_aggregate_variable(&agg, &ti.spec, 0, A->space.funcs, + A->space.structs, A->space.vars, + A->mach, A->file, A->atoms)) + goto end2; + + /* calculate size of the constructor */ + size = _slang_sizeof_aggregate(&agg); + } goto end; } @@ -316,8 +338,7 @@ _slang_assemble_constructor(slang_assemble_ctx * A, const slang_operation * op) else garbage_size = 0; - if (!constructor_aggregate - (A, &flat, &op->children[i - 1], garbage_size)) + if (!constructor_aggregate(A, &flat, &op->children[i - 1], garbage_size)) goto end; } diff --git a/src/mesa/shader/slang/slang_assemble_typeinfo.c b/src/mesa/shader/slang/slang_assemble_typeinfo.c index 265e417dadd..21b31091ea7 100644 --- a/src/mesa/shader/slang/slang_assemble_typeinfo.c +++ b/src/mesa/shader/slang/slang_assemble_typeinfo.c @@ -31,10 +31,8 @@ #include "imports.h" #include "slang_assemble.h" #include "slang_compile.h" +#include "slang_error.h" -/* - * slang_type_specifier - */ GLvoid slang_type_specifier_ctr(slang_type_specifier * self) @@ -113,7 +111,6 @@ slang_type_specifier_equal(const slang_type_specifier * x, return 1; } -/* slang_assembly_typeinfo */ GLboolean slang_assembly_typeinfo_construct(slang_assembly_typeinfo * ti) @@ -129,7 +126,6 @@ slang_assembly_typeinfo_destruct(slang_assembly_typeinfo * ti) slang_type_specifier_dtr(&ti->spec); } -/* _slang_typeof_operation() */ /** * Determine the return type of a function. @@ -209,7 +205,7 @@ _slang_typeof_operation_(const slang_operation * op, case slang_oper_preincrement: case slang_oper_predecrement: if (!_slang_typeof_operation_(op->children, space, ti, atoms)) - return 0; + return GL_FALSE; break; case slang_oper_literal_bool: case slang_oper_logicalor: @@ -233,12 +229,11 @@ _slang_typeof_operation_(const slang_operation * op, case slang_oper_identifier: { slang_variable *var; - var = _slang_locate_variable(op->locals, op->a_id, GL_TRUE); if (var == NULL) - return GL_FALSE; + RETURN_ERROR2("undefined variable", (char *) op->a_id, 0); if (!slang_type_specifier_copy(&ti->spec, &var->type.specifier)) - return GL_FALSE; + RETURN_OUT_OF_MEMORY(); ti->can_be_referenced = GL_TRUE; ti->array_len = var->array_len; } @@ -246,7 +241,7 @@ _slang_typeof_operation_(const slang_operation * op, case slang_oper_sequence: /* TODO: check [0] and [1] if they match */ if (!_slang_typeof_operation_(&op->children[1], space, ti, atoms)) - return GL_FALSE; + RETURN_NIL(); ti->can_be_referenced = GL_FALSE; ti->is_swizzled = GL_FALSE; break; @@ -259,7 +254,7 @@ _slang_typeof_operation_(const slang_operation * op, case slang_oper_select: /* TODO: check [1] and [2] if they match */ if (!_slang_typeof_operation_(&op->children[1], space, ti, atoms)) - return GL_FALSE; + RETURN_NIL(); ti->can_be_referenced = GL_FALSE; ti->is_swizzled = GL_FALSE; break; @@ -271,34 +266,34 @@ _slang_typeof_operation_(const slang_operation * op, case slang_oper_add: if (!typeof_existing_function("+", op->children, 2, space, &ti->spec, atoms)) - return GL_FALSE; + RETURN_NIL(); break; case slang_oper_subtract: if (!typeof_existing_function("-", op->children, 2, space, &ti->spec, atoms)) - return GL_FALSE; + RETURN_NIL(); break; case slang_oper_multiply: if (!typeof_existing_function("*", op->children, 2, space, &ti->spec, atoms)) - return GL_FALSE; + RETURN_NIL(); break; case slang_oper_divide: if (!typeof_existing_function("/", op->children, 2, space, &ti->spec, atoms)) - return GL_FALSE; + RETURN_NIL(); break; /*case slang_oper_modulus: */ case slang_oper_plus: if (!_slang_typeof_operation_(op->children, space, ti, atoms)) - return GL_FALSE; + RETURN_NIL(); ti->can_be_referenced = GL_FALSE; ti->is_swizzled = GL_FALSE; break; case slang_oper_minus: - if (!typeof_existing_function - ("-", op->children, 1, space, &ti->spec, atoms)) - return GL_FALSE; + if (!typeof_existing_function("-", op->children, 1, space, + &ti->spec, atoms)) + RETURN_NIL(); break; /*case slang_oper_complement: */ case slang_oper_subscript: @@ -306,23 +301,23 @@ _slang_typeof_operation_(const slang_operation * op, slang_assembly_typeinfo _ti; if (!slang_assembly_typeinfo_construct(&_ti)) - return GL_FALSE; + RETURN_NIL(); if (!_slang_typeof_operation_(op->children, space, &_ti, atoms)) { slang_assembly_typeinfo_destruct(&_ti); - return GL_FALSE; + RETURN_NIL(); } ti->can_be_referenced = _ti.can_be_referenced; if (_ti.spec.type == slang_spec_array) { if (!slang_type_specifier_copy(&ti->spec, _ti.spec._array)) { slang_assembly_typeinfo_destruct(&_ti); - return GL_FALSE; + RETURN_NIL(); } } else { if (!_slang_type_is_vector(_ti.spec.type) && !_slang_type_is_matrix(_ti.spec.type)) { slang_assembly_typeinfo_destruct(&_ti); - return GL_FALSE; + RETURN_ERROR("cannot index a non-array type", 0); } ti->spec.type = _slang_type_base(_ti.spec.type); } @@ -335,7 +330,7 @@ _slang_typeof_operation_(const slang_operation * op, if (!_slang_typeof_function(op->a_id, op->children, op->num_children, space, &ti->spec, &exists, atoms)) - return GL_FALSE; + RETURN_NIL(); if (!exists) { slang_struct *s = slang_struct_scope_find(space->structs, op->a_id, GL_TRUE); @@ -344,14 +339,14 @@ _slang_typeof_operation_(const slang_operation * op, ti->spec._struct = (slang_struct *) slang_alloc_malloc(sizeof(slang_struct)); if (ti->spec._struct == NULL) - return GL_FALSE; + RETURN_NIL(); if (!slang_struct_construct(ti->spec._struct)) { slang_alloc_free(ti->spec._struct); ti->spec._struct = NULL; - return GL_FALSE; + RETURN_NIL(); } if (!slang_struct_copy(ti->spec._struct, s)) - return GL_FALSE; + RETURN_NIL(); } else { const char *name; @@ -360,7 +355,7 @@ _slang_typeof_operation_(const slang_operation * op, name = slang_atom_pool_id(atoms, op->a_id); type = slang_type_specifier_type_from_string(name); if (type == slang_spec_void) - return GL_FALSE; + RETURN_ERROR2("function not found", name, 0); ti->spec.type = type; } } @@ -371,24 +366,23 @@ _slang_typeof_operation_(const slang_operation * op, slang_assembly_typeinfo _ti; if (!slang_assembly_typeinfo_construct(&_ti)) - return GL_FALSE; + RETURN_NIL(); if (!_slang_typeof_operation_(op->children, space, &_ti, atoms)) { slang_assembly_typeinfo_destruct(&_ti); - return GL_FALSE; + RETURN_NIL(); } if (_ti.spec.type == slang_spec_struct) { slang_variable *field; - field = - _slang_locate_variable(_ti.spec._struct->fields, op->a_id, - GL_FALSE); + field = _slang_locate_variable(_ti.spec._struct->fields, op->a_id, + GL_FALSE); if (field == NULL) { slang_assembly_typeinfo_destruct(&_ti); - return GL_FALSE; + RETURN_NIL(); } if (!slang_type_specifier_copy(&ti->spec, &field->type.specifier)) { slang_assembly_typeinfo_destruct(&_ti); - return GL_FALSE; + RETURN_NIL(); } ti->can_be_referenced = _ti.can_be_referenced; } @@ -398,15 +392,17 @@ _slang_typeof_operation_(const slang_operation * op, slang_type_specifier_type base; /* determine the swizzle of the field expression */ +#if 000 if (!_slang_type_is_vector(_ti.spec.type)) { slang_assembly_typeinfo_destruct(&_ti); - return GL_FALSE; + RETURN_ERROR("Can't swizzle scalar expression", 0); } +#endif rows = _slang_type_dim(_ti.spec.type); swizzle = slang_atom_pool_id(atoms, op->a_id); if (!_slang_is_swizzle(swizzle, rows, &ti->swz)) { slang_assembly_typeinfo_destruct(&_ti); - return GL_FALSE; + RETURN_ERROR("Bad swizzle", 0); } ti->is_swizzled = GL_TRUE; ti->can_be_referenced = _ti.can_be_referenced @@ -478,12 +474,12 @@ _slang_typeof_operation_(const slang_operation * op, case slang_oper_postincrement: case slang_oper_postdecrement: if (!_slang_typeof_operation_(op->children, space, ti, atoms)) - return GL_FALSE; + RETURN_NIL(); ti->can_be_referenced = GL_FALSE; ti->is_swizzled = GL_FALSE; break; default: - return GL_FALSE; + RETURN_NIL(); } return GL_TRUE; diff --git a/src/mesa/shader/slang/slang_codegen.c b/src/mesa/shader/slang/slang_codegen.c new file mode 100644 index 00000000000..e428209ec4a --- /dev/null +++ b/src/mesa/shader/slang/slang_codegen.c @@ -0,0 +1,1272 @@ +/* + * Mesa 3-D graphics library + * Version: 6.5.3 + * + * Copyright (C) 2005-2007 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_codegen.c + * Mesa GLSL code generator. Convert AST to IR tree. + * \author Brian Paul + */ + +#include "imports.h" +#include "macros.h" +#include "slang_assemble.h" +#include "slang_codegen.h" +#include "slang_compile.h" +#include "slang_storage.h" +#include "slang_error.h" +#include "slang_simplify.h" +#include "slang_emit.h" +#include "slang_ir.h" +#include "mtypes.h" +#include "program.h" +#include "slang_print.h" + + +static slang_function *CurFunction = NULL; + + +static slang_ir_node * +slang_assemble_operation(slang_assemble_ctx * A, slang_operation *oper); + + + +/** + * Allocate storage for given variable, attach it to 'ir'. + */ +static GLboolean +slang_alloc_var_storage(slang_variable *variable, slang_ir_node *ir) +{ + slang_ir_storage *store; + + assert(variable); + + /*assert(!variable->aux);*/ + + if (variable->aux) { + store = (slang_ir_storage *) variable->aux; + ir->Store = store; + if (store) + store->Size = -12; + } + else { + /* alloc storage */ + store = (slang_ir_storage *) _mesa_calloc(sizeof(*store)); + store->File = PROGRAM_TEMPORARY; + store->Index = -1; + store->Size = -10; + variable->aux = store; + ir->Store = store; + } + return GL_TRUE; +} + + +static slang_ir_node * +new_node(slang_ir_opcode op, slang_ir_node *left, slang_ir_node *right) +{ + slang_ir_node *n = (slang_ir_node *) calloc(1, sizeof(slang_ir_node)); + if (n) { + n->Opcode = op; + n->Children[0] = left; + n->Children[1] = right; + n->Swizzle = SWIZZLE_NOOP; + n->Writemask = WRITEMASK_XYZW; + } + return n; +} + +static slang_ir_node * +new_seq(slang_ir_node *left, slang_ir_node *right) +{ + assert(left); + assert(right); + return new_node(IR_SEQ, left, right); +} + +static slang_ir_node * +new_label(const char *name) +{ + slang_ir_node *n = new_node(IR_LABEL, NULL, NULL); + n->Target = _mesa_strdup(name); + return n; +} + +static slang_ir_node * +new_float_literal(float x, float y, float z, float w) +{ + slang_ir_node *n = new_node(IR_FLOAT, NULL, NULL); + n->Value[0] = x; + n->Value[1] = y; + n->Value[2] = z; + n->Value[3] = w; + return n; +} + +static slang_ir_node * +new_cjump(slang_ir_node *cond, const char *target) +{ + slang_ir_node *n = new_node(IR_CJUMP, cond, NULL); + n->Target = _mesa_strdup(target); + return n; +} + +static slang_ir_node * +new_jump(const char *target) +{ + slang_ir_node *n = new_node(IR_JUMP, NULL, NULL); + if (n) { + n->Target = _mesa_strdup(target); + } + return n; +} + + +/** + * New IR_VAR_DECL node - allocate storage for a new variable. + */ +static slang_ir_node * +new_var_decl(slang_assemble_ctx *A, slang_variable *v) +{ + slang_ir_node *n = new_node(IR_VAR_DECL, NULL, NULL); + if (n) { + n->Var = v; + v->declared = GL_TRUE; + } + return n; +} + + +/** + * New IR_VAR node - a reference to a previously declared variable. + */ +static slang_ir_node * +new_var(slang_assemble_ctx *A, slang_operation *oper, + slang_atom name, GLuint swizzle) +{ + slang_variable *v = _slang_locate_variable(oper->locals, name, GL_TRUE); + slang_ir_node *n = new_node(IR_VAR, NULL, NULL); + if (!v) { + printf("VAR NOT FOUND %s\n", (char *) name); + assert(v); + } + /** + assert(v->declared); + **/ + assert(!oper->var || oper->var == v); + v->used = GL_TRUE; + oper->var = v; + n->Swizzle = swizzle; + n->Var = v; + slang_resolve_storage(NULL, n, A->program); + return n; +} + + +static GLboolean +slang_is_writemask(const char *field, GLuint *mask) +{ + const GLuint n = 4; + GLuint i, bit, c = 0; + + for (i = 0; i < n && field[i]; i++) { + switch (field[i]) { + case 'x': + case 'r': + bit = WRITEMASK_X; + break; + case 'y': + case 'g': + bit = WRITEMASK_Y; + break; + case 'z': + case 'b': + bit = WRITEMASK_Z; + break; + case 'w': + case 'a': + bit = WRITEMASK_W; + break; + default: + return GL_FALSE; + } + if (c & bit) + return GL_FALSE; + c |= bit; + } + *mask = c; + return GL_TRUE; +} + + +static slang_ir_node * +slang_assemble_return(slang_assemble_ctx * A, slang_operation *oper) +{ + if (oper->num_children == 0) { + /* Convert to: + * goto __endOfFunction; + */ + oper->type = slang_oper_goto; + oper->a_id = slang_atom_pool_atom(A->atoms, CurFunction->end_label); + } + else { + /* + * Convert from: + * return expr; + * To: + * __retVal = expr; + * goto __endOfFunction; + */ + slang_operation *block, *assign, *jump; + slang_atom a_retVal; + + a_retVal = slang_atom_pool_atom(A->atoms, "__retVal"); + assert(a_retVal); + +#if 1 + { + slang_variable *v + = _slang_locate_variable(oper->locals, a_retVal, GL_TRUE); + assert(v); + } +#endif + + block = slang_operation_new(1); + block->type = slang_oper_block_no_new_scope; + block->num_children = 2; + block->children = slang_operation_new(2); + assert(block->locals); + block->locals->outer_scope = oper->locals->outer_scope; + + /* child[0]: __retVal = expr; */ + assign = &block->children[0]; + assign->type = slang_oper_assign; + assign->locals->outer_scope = block->locals; + assign->num_children = 2; + assign->children = slang_operation_new(2); + /* lhs */ + assign->children[0].type = slang_oper_identifier; + assign->children[0].a_id = a_retVal; + assign->children[0].locals->outer_scope = assign->locals; + /* rhs */ +#if 0 + assign->children[1] = oper->children[0]; /* XXX copy */ +#else + slang_operation_copy(&assign->children[1], &oper->children[0]); +#endif + + + /* child[1]: goto __endOfFunction */ + jump = &block->children[1]; + jump->type = slang_oper_goto; + assert(CurFunction->end_label); + jump->a_id = slang_atom_pool_atom(A->atoms, CurFunction->end_label); + +#if 00 + printf("NEW RETURN:\n"); + slang_print_tree(block, 0); +#endif + + slang_operation_copy(oper, block); + /* XXX destruct block */ + } + + /* assemble the new code */ + return slang_assemble_operation(A, oper); +} + + + +/** + * Check if the given function is really just a wrapper for an + * basic assembly instruction. + */ +static GLboolean +slang_is_asm_function(const slang_function *fun) +{ + if (fun->body->type == slang_oper_block_no_new_scope && + fun->body->num_children == 1 && + fun->body->children[0].type == slang_oper_asm) { + return GL_TRUE; + } + return GL_FALSE; +} + + +/** + * Produce inline code for a call to an assembly instruction. + */ +static slang_operation * +slang_inline_asm_function(slang_assemble_ctx *A, + slang_function *fun, slang_operation *oper) +{ + const int numArgs = oper->num_children; + const slang_operation *args = oper->children; + GLuint i; + slang_operation *inlined = slang_operation_new(1); + + /*assert(oper->type == slang_oper_call); or vec4_add, etc */ + + inlined->type = fun->body->children[0].type; + inlined->a_id = fun->body->children[0].a_id; + inlined->num_children = numArgs; + inlined->children = slang_operation_new(numArgs); +#if 0 + inlined->locals = slang_variable_scope_copy(oper->locals); +#else + assert(inlined->locals); + inlined->locals->outer_scope = oper->locals->outer_scope; +#endif + + for (i = 0; i < numArgs; i++) { + slang_operation_copy(inlined->children + i, args + i); + } + + return inlined; +} + + +static void +slang_resolve_variable(slang_operation *oper) +{ + if (oper->type != slang_oper_identifier) + return; + if (!oper->var) { + oper->var = _slang_locate_variable(oper->locals, + (const slang_atom) oper->a_id, + GL_TRUE); + if (oper->var) + oper->var->used = GL_TRUE; + } +} + + +/** + * Replace particular variables (slang_oper_identifier) with new expressions. + */ +static void +slang_substitute(slang_assemble_ctx *A, slang_operation *oper, + GLuint substCount, slang_variable **substOld, + slang_operation **substNew, GLboolean isLHS) +{ + switch (oper->type) { + case slang_oper_variable_decl: + { + slang_variable *v = _slang_locate_variable(oper->locals, + oper->a_id, GL_TRUE); + assert(v); + if (v->initializer && oper->num_children == 0) { + /* set child of oper to copy of initializer */ + oper->num_children = 1; + oper->children = slang_operation_new(1); + slang_operation_copy(&oper->children[0], v->initializer); + } + if (oper->num_children == 1) { + /* the initializer */ + slang_substitute(A, &oper->children[0], substCount, substOld, substNew, GL_FALSE); + } + } + break; + case slang_oper_identifier: + assert(oper->num_children == 0); + if (1/**!isLHS XXX FIX */) { + slang_atom id = oper->a_id; + slang_variable *v; + GLuint i; + v = _slang_locate_variable(oper->locals, id, GL_TRUE); + if (!v) { + printf("var %s not found!\n", (char *) oper->a_id); + break; + } + + /* look for a substitution */ + for (i = 0; i < substCount; i++) { + if (v == substOld[i]) { + /* OK, replace this slang_oper_identifier with a new expr */ + assert(substNew[i]->type == slang_oper_identifier || + substNew[i]->type == slang_oper_literal_float); +#if 1 /* DEBUG only */ + if (substNew[i]->type == slang_oper_identifier) { + assert(substNew[i]->var); + assert(substNew[i]->var->a_name); + printf("Substitute %s with %s in id node %p\n", + (char*)v->a_name, (char*) substNew[i]->var->a_name, + (void*) oper); + } + else + printf("Substitute %s with %f in id node %p\n", + (char*)v->a_name, substNew[i]->literal[0], + (void*) oper); +#endif + slang_operation_copy(oper, substNew[i]); + break; + } + } + } + break; + case slang_oper_return: + /* do return replacement here too */ + slang_assemble_return(A, oper); + slang_substitute(A, oper, substCount, substOld, substNew, GL_FALSE); + break; + case slang_oper_assign: + case slang_oper_subscript: + /* special case: + * child[0] can't have substitutions but child[1] can. + */ + slang_substitute(A, &oper->children[0], substCount, substOld, substNew, GL_TRUE); + slang_substitute(A, &oper->children[1], substCount, substOld, substNew, GL_FALSE); + break; + case slang_oper_field: + /* XXX NEW - test */ + slang_substitute(A, &oper->children[0], substCount, substOld, substNew, GL_TRUE); + break; + default: + { + GLuint i; + for (i = 0; i < oper->num_children; i++) + slang_substitute(A, &oper->children[i], substCount, substOld, substNew, GL_FALSE); + } + } +} + + + +/** + * Inline the given function call operation. + * Return a new slang_operation that corresponds to the inlined code. + */ +static slang_operation * +slang_inline_function_call(slang_assemble_ctx * A, slang_function *fun, + slang_operation *oper, slang_operation *returnOper) +{ + typedef enum { + SUBST = 1, + COPY_IN, + COPY_OUT + } ParamMode; + ParamMode *paramMode; + const GLboolean haveRetValue = _slang_function_has_return_value(fun); + const GLuint numArgs = oper->num_children; + const GLuint totalArgs = numArgs + haveRetValue; + slang_operation *args = oper->children; + slang_operation *inlined, *top; + slang_variable **substOld; + slang_operation **substNew; + GLuint substCount, numCopyIn, i; + + /*assert(oper->type == slang_oper_call); (or (matrix) multiply, etc) */ + assert(fun->param_count == totalArgs); + + /* allocate temporary arrays */ + paramMode = (ParamMode *) + _mesa_calloc(totalArgs * sizeof(ParamMode)); + substOld = (slang_variable **) + _mesa_calloc(totalArgs * sizeof(slang_variable *)); + substNew = (slang_operation **) + _mesa_calloc(totalArgs * sizeof(slang_operation *)); + + printf("\nInline call to %s (total vars=%d nparams=%d)\n", + (char *) fun->header.a_name, + fun->parameters->num_variables, numArgs); + + + if (haveRetValue && !returnOper) { + /* Create comma sequence for inlined code, the left child will be the + * function body and the right child will be a variable (__retVal) + * that will get the return value. + */ + slang_operation *commaSeq; + slang_operation *declOper = NULL; + slang_variable *resultVar; + + commaSeq = slang_operation_new(1); + commaSeq->type = slang_oper_sequence; + assert(commaSeq->locals); + commaSeq->locals->outer_scope = oper->locals->outer_scope; + commaSeq->num_children = 3; + commaSeq->children = slang_operation_new(3); + /* allocate the return var */ + resultVar = slang_variable_scope_grow(commaSeq->locals); + /* + printf("ALLOC __retVal from scope %p\n", (void*) commaSeq->locals); + */ + printf("Alloc __resultTemp in scope %p for retval of calling %s\n", + (void*)commaSeq->locals, (char *) fun->header.a_name); + + resultVar->a_name = slang_atom_pool_atom(A->atoms, "__resultTmp"); + resultVar->type = fun->header.type; /* XXX copy? */ + /*resultVar->type.qualifier = slang_qual_out;*/ + + /* child[0] = __resultTmp declaration */ + declOper = &commaSeq->children[0]; + declOper->type = slang_oper_variable_decl; + declOper->a_id = resultVar->a_name; + declOper->locals->outer_scope = commaSeq->locals; /*** ??? **/ + + /* child[1] = function body */ + inlined = &commaSeq->children[1]; + /* XXXX this may be inappropriate!!!!: */ + inlined->locals->outer_scope = commaSeq->locals; + + /* child[2] = __resultTmp reference */ + returnOper = &commaSeq->children[2]; + returnOper->type = slang_oper_identifier; + returnOper->a_id = resultVar->a_name; + returnOper->locals->outer_scope = commaSeq->locals; + declOper->locals->outer_scope = commaSeq->locals; + + top = commaSeq; + } + else { + top = inlined = slang_operation_new(1); + /* XXXX this may be inappropriate!!!! */ + inlined->locals->outer_scope = oper->locals->outer_scope; + } + + + assert(inlined->locals); + + /* Examine the parameters, look for inout/out params, look for possible + * substitutions, etc: + * param type behaviour + * in copy actual to local + * const in substitute param with actual + * out copy out + */ + substCount = 0; + for (i = 0; i < totalArgs; i++) { + slang_variable *p = &fun->parameters->variables[i]; + printf("Param %d: %s %s \n", i, + slang_type_qual_string(p->type.qualifier), + (char *) p->a_name); + if (p->type.qualifier == slang_qual_inout || + p->type.qualifier == slang_qual_out) { + /* an output param */ + slang_operation *arg; + if (i < numArgs) + arg = &args[i]; + else + arg = returnOper; + paramMode[i] = SUBST; + assert(arg->type == slang_oper_identifier + /*||arg->type == slang_oper_variable_decl*/); + slang_resolve_variable(arg); + /* replace parameter 'p' with argument 'arg' */ + substOld[substCount] = p; + substNew[substCount] = arg; /* will get copied */ + substCount++; + } + else if (p->type.qualifier == slang_qual_const) { + /* a constant input param */ + if (args[i].type == slang_oper_identifier || + args[i].type == slang_oper_literal_float) { + /* replace all occurances of this parameter variable with the + * actual argument variable or a literal. + */ + paramMode[i] = SUBST; + slang_resolve_variable(&args[i]); + substOld[substCount] = p; + substNew[substCount] = &args[i]; /* will get copied */ + substCount++; + } + else { + paramMode[i] = COPY_IN; + } + } + else { + paramMode[i] = COPY_IN; + } + assert(paramMode[i]); + } + +#if 00 + printf("ABOUT to inline body %p with checksum %d\n", + (char *) fun->body, slang_checksum_tree(fun->body)); +#endif + + /* actual code inlining: */ + slang_operation_copy(inlined, fun->body); + +#if 000 + printf("======================= orig body code ======================\n"); + printf("=== params scope = %p\n", (void*) fun->parameters); + slang_print_tree(fun->body, 8); + printf("======================= copied code =========================\n"); + slang_print_tree(inlined, 8); +#endif + + /* do parameter substitution in inlined code: */ + slang_substitute(A, inlined, substCount, substOld, substNew, GL_FALSE); + +#if 000 + printf("======================= subst code ==========================\n"); + slang_print_tree(inlined, 8); + printf("=============================================================\n"); +#endif + + /* New prolog statements: (inserted before the inlined code) + * Copy the 'in' arguments. + */ + numCopyIn = 0; + for (i = 0; i < numArgs; i++) { + if (paramMode[i] == COPY_IN) { + slang_variable *p = &fun->parameters->variables[i]; + /* declare parameter 'p' */ + slang_operation *decl = slang_operation_insert(&inlined->num_children, + &inlined->children, + numCopyIn); + printf("COPY_IN %s from expr\n", (char*)p->a_name); + decl->type = slang_oper_variable_decl; + assert(decl->locals); + decl->locals = fun->parameters; + decl->a_id = p->a_name; + decl->num_children = 1; + decl->children = slang_operation_new(1); + + /* child[0] is the var's initializer */ + slang_operation_copy(&decl->children[0], args + i); + + numCopyIn++; + } + } + + /* New epilog statements: + * 1. Create end of function label to jump to from return statements. + * 2. Copy the 'out' parameter vars + */ + { + slang_operation *lab = slang_operation_insert(&inlined->num_children, + &inlined->children, + inlined->num_children); + lab->type = slang_oper_label; + lab->a_id = slang_atom_pool_atom(A->atoms, CurFunction->end_label); + } + + for (i = 0; i < totalArgs; i++) { + if (paramMode[i] == COPY_OUT) { + const slang_variable *p = &fun->parameters->variables[i]; + /* actualCallVar = outParam */ + /*if (i > 0 || !haveRetValue)*/ + slang_operation *ass = slang_operation_insert(&inlined->num_children, + &inlined->children, + inlined->num_children); + ass->type = slang_oper_assign; + ass->num_children = 2; + ass->locals = _slang_variable_scope_new(inlined->locals); + assert(ass->locals); + ass->children = slang_operation_new(2); + ass->children[0] = args[i]; /*XXX copy */ + ass->children[1].type = slang_oper_identifier; + ass->children[1].a_id = p->a_name; + ass->children[1].locals = _slang_variable_scope_new(ass->locals); + } + } + + _mesa_free(paramMode); + _mesa_free(substOld); + _mesa_free(substNew); + + printf("Done Inline call to %s (total vars=%d nparams=%d)\n", + (char *) fun->header.a_name, + fun->parameters->num_variables, numArgs); + + return top; +} + + +static slang_ir_node * +slang_assemble_function_call(slang_assemble_ctx *A, slang_function *fun, + slang_operation *oper, slang_operation *dest) +{ + slang_ir_node *n; + slang_operation *inlined; + slang_function *prevFunc; + + prevFunc = CurFunction; + CurFunction = fun; + + if (!CurFunction->end_label) { + char name[200]; + sprintf(name, "__endOfFunc_%s_", (char *) CurFunction->header.a_name); + CurFunction->end_label = slang_atom_pool_gen(A->atoms, name); + } + + if (slang_is_asm_function(fun) && !dest) { + /* assemble assembly function - tree style */ + inlined = slang_inline_asm_function(A, fun, oper); + } + else { + /* non-assembly function */ + inlined = slang_inline_function_call(A, fun, oper, dest); + } + + /* Replace the function call with the inlined block */ +#if 0 + slang_operation_construct(oper); + slang_operation_copy(oper, inlined); +#else + *oper = *inlined; +#endif + + +#if 1 + assert(inlined->locals); + printf("*** Inlined code for call to %s:\n", + (char*) fun->header.a_name); + + slang_print_tree(oper, 10); + printf("\n"); +#endif + + /* assemble what we just made XXX here??? */ + n = slang_assemble_operation(A, oper); + + CurFunction = prevFunc; + + return n; +} + + +/** + * Map "_asm foo" to IR_FOO, etc. + */ +typedef struct +{ + const char *Name; + slang_ir_opcode Opcode; + GLuint HaveRetValue, NumParams; +} slang_asm_info; + + +static slang_asm_info AsmInfo[] = { + /* vec4 binary op */ + { "vec4_add", IR_ADD, 1, 2 }, + { "vec4_multiply", IR_MUL, 1, 2 }, + { "vec4_dot", IR_DOT4, 1, 2 }, + { "vec3_dot", IR_DOT3, 1, 2 }, + { "vec3_cross", IR_CROSS, 1, 2 }, + { "vec4_min", IR_MIN, 1, 2 }, + { "vec4_max", IR_MAX, 1, 2 }, + { "vec4_seq", IR_SEQ, 1, 2 }, + { "vec4_sge", IR_SGE, 1, 2 }, + { "vec4_sgt", IR_SGT, 1, 2 }, + /* vec4 unary */ + { "vec4_floor", IR_FLOOR, 1, 1 }, + { "vec4_frac", IR_FRAC, 1, 1 }, + { "vec4_abs", IR_ABS, 1, 1 }, + /* float binary op */ + { "float_add", IR_ADD, 1, 2 }, + { "float_subtract", IR_SUB, 1, 2 }, + { "float_multiply", IR_MUL, 1, 2 }, + { "float_divide", IR_DIV, 1, 2 }, + { "float_power", IR_POW, 1, 2 }, + /* unary op */ + { "int_to_float", IR_I_TO_F, 1, 1 }, + { "float_exp", IR_EXP, 1, 1 }, + { "float_exp2", IR_EXP2, 1, 1 }, + { "float_log2", IR_LOG2, 1, 1 }, + { "float_rsq", IR_RSQ, 1, 1 }, + { "float_rcp", IR_RCP, 1, 1 }, + { "float_sine", IR_SIN, 1, 1 }, + { "float_cosine", IR_COS, 1, 1 }, + { NULL, IR_NOP, 0, 0 } +}; + + +static slang_asm_info * +slang_find_asm_info(const char *name) +{ + GLuint i; + for (i = 0; AsmInfo[i].Name; i++) { + if (_mesa_strcmp(AsmInfo[i].Name, name) == 0) { + return AsmInfo + i; + } + } + return NULL; +} + + +static GLuint +make_writemask(char *field) +{ + GLuint mask = 0x0; + while (*field) { + switch (*field) { + case 'x': + mask |= WRITEMASK_X; + break; + case 'y': + mask |= WRITEMASK_Y; + break; + case 'z': + mask |= WRITEMASK_Z; + break; + case 'w': + mask |= WRITEMASK_W; + break; + default: + abort(); + } + field++; + } + if (mask == 0x0) + return WRITEMASK_XYZW; + else + return mask; +} + + +/** + * Generate IR code for an instruction/operation such as: + * __asm vec4_dot __retVal.x, v1, v2; + */ +static slang_ir_node * +slang_assemble_asm(slang_assemble_ctx *A, slang_operation *oper, + slang_operation *dest) +{ + const slang_asm_info *info; + slang_ir_node *kids[2], *n; + GLuint j, firstOperand; + + assert(oper->type == slang_oper_asm); + + info = slang_find_asm_info((char *) oper->a_id); + assert(info); + assert(info->NumParams <= 2); + + if (info->NumParams == oper->num_children) { + /* storage for result not specified */ + firstOperand = 0; + } + else { + /* storage for result (child[0]) is specified */ + firstOperand = 1; + } + + /* assemble child(ren) */ + kids[0] = kids[1] = NULL; + for (j = 0; j < info->NumParams; j++) { + kids[j] = slang_assemble_operation(A, &oper->children[firstOperand + j]); + } + + n = new_node(info->Opcode, kids[0], kids[1]); + + if (firstOperand) { + /* Setup n->Store to be a particular location. Otherwise, storage + * for the result (a temporary) will be allocated later. + */ + GLuint writemask = WRITEMASK_XYZW; + slang_operation *dest_oper; + slang_ir_node *n0; + + dest_oper = &oper->children[0]; + if (dest_oper->type == slang_oper_field) { + /* writemask */ + writemask = make_writemask((char*) dest_oper->a_id); + dest_oper = &dest_oper->children[0]; + } + + assert(dest_oper->type == slang_oper_identifier); + n0 = slang_assemble_operation(A, dest_oper); + assert(n0->Var); + assert(n0->Store); + free(n0); + + n->Store = n0->Store; + n->Writemask = writemask; + } + + return n; +} + + + + + +/** + * Assemble a function call, given a particular function name. + * \param name the function's name (operators like '*' are possible). + */ +static slang_ir_node * +slang_assemble_function_call_name(slang_assemble_ctx *A, const char *name, + slang_operation *oper, slang_operation *dest) +{ + slang_operation *params = oper->children; + const GLuint param_count = oper->num_children; + slang_atom atom; + slang_function *fun; + + atom = slang_atom_pool_atom(A->atoms, name); + if (atom == SLANG_ATOM_NULL) + return NULL; + + fun = _slang_locate_function(A->space.funcs, atom, params, param_count, + &A->space, A->atoms); + if (!fun) { + RETURN_ERROR2("Undefined function", name, 0); + } + + return slang_assemble_function_call(A, fun, oper, dest); +} + + +static slang_ir_node * +slang_assemble_operation(slang_assemble_ctx * A, slang_operation *oper) +{ + switch (oper->type) { + case slang_oper_block_no_new_scope: + case slang_oper_block_new_scope: + /* list of operations */ + assert(oper->num_children > 0); + { + slang_ir_node *n, *first = NULL; + GLuint i; + for (i = 0; i < oper->num_children; i++) { + n = slang_assemble_operation(A, &oper->children[i]); + first = first ? new_seq(first, n) : n; + } + return first; + } + break; + case slang_oper_expression: + return slang_assemble_operation(A, &oper->children[0]); + break; + case slang_oper_while: + { + slang_ir_node *nStartLabel = new_label("while-start"); + slang_ir_node *nCond = slang_assemble_operation(A, &oper->children[0]); + slang_ir_node *nNotCond = new_node(IR_NOT, nCond, NULL); + slang_ir_node *nBody = slang_assemble_operation(A, &oper->children[1]); + slang_ir_node *nEndLabel = new_label("while-end"); + slang_ir_node *nCJump = new_cjump(nNotCond, "while-end"); + slang_ir_node *nJump = new_jump("while-start"); + + return new_seq(nStartLabel, + new_seq(nCJump, + new_seq(nBody, + new_seq(nJump, + nEndLabel) + ) + ) + ); + } + break; + case slang_oper_less: + return new_node(IR_LESS, + slang_assemble_operation(A, &oper->children[0]), + slang_assemble_operation(A, &oper->children[1])); + case slang_oper_add: + { + slang_ir_node *n; + assert(oper->num_children == 2); + n = slang_assemble_function_call_name(A, "+", oper, NULL); + return n; + } + case slang_oper_subtract: + { + slang_ir_node *n; + assert(oper->num_children == 2); + n = slang_assemble_function_call_name(A, "-", oper, NULL); + return n; + } + case slang_oper_multiply: + { + slang_ir_node *n; + assert(oper->num_children == 2); + n = slang_assemble_function_call_name(A, "*", oper, NULL); + return n; + } + case slang_oper_divide: + { + slang_ir_node *n; + assert(oper->num_children == 2); + n = slang_assemble_function_call_name(A, "/", oper, NULL); + return n; + } + + case slang_oper_variable_decl: + { + slang_ir_node *n; + slang_ir_node *varDecl; + slang_variable *v; + + assert(oper->num_children == 0 || oper->num_children == 1); + + v = _slang_locate_variable(oper->locals, + oper->a_id, GL_TRUE); + assert(v); + varDecl = new_var_decl(A, v); + slang_alloc_var_storage(v, varDecl); + + if (oper->num_children > 0) { + /* child is initializer */ + slang_ir_node *var, *init, *rhs; + assert(oper->num_children == 1); + var = new_var(A, oper, oper->a_id, SWIZZLE_NOOP); + /* XXX make copy of this initializer? */ + printf("\n*** ASSEMBLE INITIALIZER %p\n", (void*) v->initializer); + rhs = slang_assemble_operation(A, &oper->children[0]); + init = new_node(IR_MOVE, var, rhs); + n = new_seq(varDecl, init); + } + else if (v->initializer) { + slang_ir_node *var, *init, *rhs; + var = new_var(A, oper, oper->a_id, SWIZZLE_NOOP); + /* XXX make copy of this initializer? */ + printf("\n*** ASSEMBLE INITIALIZER %p\n", (void*) v->initializer); + rhs = slang_assemble_operation(A, v->initializer); + init = new_node(IR_MOVE, var, rhs); + n = new_seq(varDecl, init); + } + else { + n = varDecl; + } + return n; + } + break; + case slang_oper_assign: + /* assignment */ + /* XXX look for special case of: x = f(a, b) + * and replace with f(a, b, x) (where x == hidden __retVal out param) + */ + if (oper->children[0].type == slang_oper_identifier && + oper->children[1].type == slang_oper_call) { + /* special case */ + slang_ir_node *n; + printf(">>>>>>>>>>>>>> Assign function call\n"); + n = slang_assemble_function_call_name(A, + (const char *) oper->children[1].a_id, + &oper->children[1], &oper->children[0]); + return n; + } + else + { + slang_operation *lhs = &oper->children[0]; + slang_ir_node *n, *c0, *c1; + GLuint mask = WRITEMASK_XYZW; + if (lhs->type == slang_oper_field) { + /* writemask */ + if (!slang_is_writemask((char *) lhs->a_id, &mask)) + mask = WRITEMASK_XYZW; + lhs = &lhs->children[0]; + } + c0 = slang_assemble_operation(A, lhs); + c1 = slang_assemble_operation(A, &oper->children[1]); + + n = new_node(IR_MOVE, c0, c1); + n->Writemask = mask; + return n; + } + break; + case slang_oper_asm: + return slang_assemble_asm(A, oper, NULL); + case slang_oper_call: + return slang_assemble_function_call_name(A, (const char *) oper->a_id, + oper, NULL); + break; + case slang_oper_return: + return slang_assemble_return(A, oper); + case slang_oper_goto: + return new_jump((char*) oper->a_id); + case slang_oper_label: + return new_label((char*) oper->a_id); + case slang_oper_identifier: + { + /* If there's a variable associated with this oper (from inlining) + * use it. Otherwise, use the oper's var id. + */ + slang_atom aVar = oper->var ? oper->var->a_name : oper->a_id; + slang_ir_node *n = new_var(A, oper, aVar, SWIZZLE_NOOP); + assert(oper->var); + return n; + } + break; + case slang_oper_field: + { + slang_assembly_typeinfo ti; + slang_assembly_typeinfo_construct(&ti); + _slang_typeof_operation(A, &oper->children[0], &ti); + if (_slang_type_is_vector(ti.spec.type)) { + /* the field should be a swizzle */ + const GLuint rows = _slang_type_dim(ti.spec.type); + slang_swizzle swz; + slang_ir_node *n; + if (!_slang_is_swizzle((char *) oper->a_id, rows, &swz)) { + RETURN_ERROR("Bad swizzle", 0); + } + n = slang_assemble_operation(A, &oper->children[0]); + n->Swizzle = MAKE_SWIZZLE4(swz.swizzle[0], + swz.swizzle[1], + swz.swizzle[2], + swz.swizzle[3]); + return n; + } + else if (ti.spec.type == slang_spec_float) { + const GLuint rows = 1; + slang_swizzle swz; + slang_ir_node *n; + if (!_slang_is_swizzle((char *) oper->a_id, rows, &swz)) { + RETURN_ERROR("Bad swizzle", 0); + } + n = slang_assemble_operation(A, &oper->children[0]); + n->Swizzle = MAKE_SWIZZLE4(swz.swizzle[0], + swz.swizzle[1], + swz.swizzle[2], + swz.swizzle[3]); + return n; + } + else { + /* the field is a structure member */ + abort(); + } + } + break; + case slang_oper_subscript: + /* array dereference */ + if (oper->children[1].type == slang_oper_literal_int) { + /* compile-time constant index - OK */ + slang_assembly_typeinfo ti; + slang_ir_node *base; + slang_ir_storage *store2; + GLint index; + slang_assembly_typeinfo_construct(&ti); + _slang_typeof_operation(A, &oper->children[0], &ti); + + base = slang_assemble_operation(A, &oper->children[0]); + assert(base->Opcode == IR_VAR); + + index = (GLint) oper->children[1].literal[0]; + /* + printf("element[%d]\n", index); + */ +#if 1 + store2 = (slang_ir_storage *) _mesa_calloc(sizeof(*store2)); + *store2 = *base->Store; + base->Store = store2; + base->Store->Size = -15; +#endif + assert(base->Store); + base->Store->Index += index; + base->Store->Size = 1; + return base; + } + else { + /* run-time index - TBD */ + abort(); + } + return NULL; + case slang_oper_literal_float: + return new_float_literal(oper->literal[0], oper->literal[1], + oper->literal[2], oper->literal[3]); + case slang_oper_literal_int: + return new_float_literal(oper->literal[0], 0, 0, 0); + case slang_oper_literal_bool: + return new_float_literal(oper->literal[0], 0, 0, 0); + case slang_oper_postincrement: + /* XXX not 100% about this */ + { + slang_ir_node *var = slang_assemble_operation(A, &oper->children[0]); + slang_ir_node *one = new_float_literal(1.0, 1.0, 1.0, 1.0); + slang_ir_node *sum = new_node(IR_ADD, var, one); + slang_ir_node *assign = new_node(IR_MOVE, var, sum); + return assign; + } + break; + case slang_oper_sequence: + { + slang_ir_node *top = NULL; + GLuint i; + for (i = 0; i < oper->num_children; i++) { + slang_ir_node *n = slang_assemble_operation(A, &oper->children[i]); + top = top ? new_seq(top, n) : n; + } + return top; + } + break; + case slang_oper_none: + return NULL; + default: + printf("Unhandled node type %d\n", oper->type); + abort(); + return new_node(IR_NOP, NULL, NULL); + } + abort(); + return NULL; +} + + +/** + * Produce an IR tree from a function AST. + * Then call the code emitter to convert the IR tree into a gl_program. + */ +struct slang_ir_node_ * +_slang_codegen_function(slang_assemble_ctx * A, slang_function * fun) +{ + slang_ir_node *n, *endLabel; + + if (_mesa_strcmp((char *) fun->header.a_name, "main") != 0 && + _mesa_strcmp((char *) fun->header.a_name, "foo") != 0 && + _mesa_strcmp((char *) fun->header.a_name, "bar") != 0) + return 0; + + printf("\n*********** Assemble function2(%s)\n", (char*)fun->header.a_name); + + slang_print_function(fun, 1); + + A->program->Parameters = _mesa_new_parameter_list(); + A->program->Varying = _mesa_new_parameter_list(); + + /*printf("** Begin Simplify\n");*/ + slang_simplify(fun->body, &A->space, A->atoms); + /*printf("** End Simplify\n");*/ + + CurFunction = fun; + + n = slang_assemble_operation(A, fun->body); + + if (!CurFunction->end_label) + CurFunction->end_label = slang_atom_pool_gen(A->atoms, "__endOfFunction_Main"); + + endLabel = new_label(fun->end_label); + n = new_seq(n, endLabel); + + CurFunction = NULL; + + + printf("************* New body for %s *****\n", (char*)fun->header.a_name); + slang_print_function(fun, 1); + + printf("************* IR for %s *******\n", (char*)fun->header.a_name); + slang_print_ir(n, 0); + + if (_mesa_strcmp((char*) fun->header.a_name, "main") == 0) { + _slang_emit_code(n, A->program); + } + + printf("************* End assemble function2 ************\n\n"); + + return n; +} + + diff --git a/src/mesa/shader/slang/slang_codegen.h b/src/mesa/shader/slang/slang_codegen.h new file mode 100644 index 00000000000..042737b2b5c --- /dev/null +++ b/src/mesa/shader/slang/slang_codegen.h @@ -0,0 +1,39 @@ +/* + * Mesa 3-D graphics library + * Version: 6.5.3 + * + * Copyright (C) 2005-2007 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. + */ + + +#ifndef SLANG_CODEGEN_H +#define SLANG_CODEGEN_H + + +#include "imports.h" +#include "slang_compile.h" +#include "slang_ir.h" + + +extern struct slang_ir_node_ * +_slang_codegen_function(slang_assemble_ctx *A , struct slang_function_ *fun); + + +#endif /* SLANG_CODEGEN_H */ diff --git a/src/mesa/shader/slang/slang_compile.c b/src/mesa/shader/slang/slang_compile.c index c49ab4a68dc..a9c84abdce0 100644 --- a/src/mesa/shader/slang/slang_compile.c +++ b/src/mesa/shader/slang/slang_compile.c @@ -29,10 +29,16 @@ */ #include "imports.h" +#include "context.h" +#include "program.h" #include "grammar_mesa.h" +#include "slang_codegen.h" #include "slang_compile.h" #include "slang_preprocess.h" #include "slang_storage.h" +#include "slang_error.h" + +#include "slang_print.h" /* * This is a straightforward implementation of the slang front-end @@ -214,6 +220,7 @@ slang_info_log_memory(slang_info_log * log) log->dont_free_text = 1; log->text = out_of_memory; } + abort(); } /* slang_parse_ctx */ @@ -237,6 +244,7 @@ typedef struct slang_output_ctx_ slang_assembly_file *assembly; slang_var_pool *global_pool; slang_machine *machine; + struct gl_program *program; } slang_output_ctx; /* _slang_compile() */ @@ -782,16 +790,17 @@ parse_fully_specified_type(slang_parse_ctx * C, slang_output_ctx * O, * \param C the parsing context * \param O the output context * \param oper the operation we're parsing - * \param statment which child of the operation is being parsed + * \param statement indicates whether parsing a statement, or expression * \return 1 if success, 0 if error */ static int parse_child_operation(slang_parse_ctx * C, slang_output_ctx * O, - slang_operation * oper, unsigned int statement) + slang_operation * oper, GLboolean statement) { slang_operation *ch; /* grow child array */ +#if 000 oper->children = (slang_operation *) slang_alloc_realloc(oper->children, oper->num_children * sizeof(slang_operation), @@ -807,7 +816,9 @@ parse_child_operation(slang_parse_ctx * C, slang_output_ctx * O, return 0; } oper->num_children++; - /* XXX I guess the 0th "statement" is not really a statement? */ +#else + ch = slang_operation_grow(&oper->num_children, &oper->children); +#endif if (statement) return parse_statement(C, O, ch); return parse_expression(C, O, ch); @@ -846,6 +857,7 @@ parse_statement(slang_parse_ctx * C, slang_output_ctx * O, /* local variable declaration, individual declarators are stored as * children identifiers */ +#if 000 oper->type = slang_oper_variable_decl; { const unsigned int first_var = O->vars->num_variables; @@ -881,6 +893,38 @@ parse_statement(slang_parse_ctx * C, slang_output_ctx * O, } } } +#else + + oper->type = slang_oper_block_no_new_scope; + { + const unsigned int first_var = O->vars->num_variables; + + /* parse the declaration, note that there can be zero or more + * than one declarators + */ + if (!parse_declaration(C, O)) + return 0; + if (first_var < O->vars->num_variables) { + const unsigned int num_vars = O->vars->num_variables - first_var; + unsigned int i; + + oper->num_children = num_vars; + oper->children = slang_operation_new(num_vars); + if (oper->children == NULL) { + slang_info_log_memory(C->L); + return 0; + } + for (i = first_var; i < O->vars->num_variables; i++) { + slang_operation *o = &oper->children[i - first_var]; + o->type = slang_oper_variable_decl; + o->locals->outer_scope = O->vars; + o->a_id = O->vars->variables[i].a_name; + } + } + } + + +#endif break; case OP_ASM: /* the __asm statement, parse the mnemonic and all its arguments @@ -888,6 +932,9 @@ parse_statement(slang_parse_ctx * C, slang_output_ctx * O, */ oper->type = slang_oper_asm; oper->a_id = parse_identifier(C); + if (strcmp((char*)oper->a_id, "dot") == 0) { + printf("Assemble dot! **************************\n"); + } if (oper->a_id == SLANG_ATOM_NULL) return 0; while (*C->I != OP_END) { @@ -1042,18 +1089,27 @@ parse_expression(slang_parse_ctx * C, slang_output_ctx * O, op->type = slang_oper_literal_bool; if (!parse_number(C, &number)) return 0; - op->literal = (GLfloat) number; + op->literal[0] = + op->literal[1] = + op->literal[2] = + op->literal[3] = (GLfloat) number; break; case OP_PUSH_INT: op->type = slang_oper_literal_int; if (!parse_number(C, &number)) return 0; - op->literal = (GLfloat) number; + op->literal[0] = + op->literal[1] = + op->literal[2] = + op->literal[3] = (GLfloat) number; break; case OP_PUSH_FLOAT: op->type = slang_oper_literal_float; - if (!parse_float(C, &op->literal)) + if (!parse_float(C, &op->literal[0])) return 0; + op->literal[1] = + op->literal[2] = + op->literal[3] = op->literal[0]; break; case OP_PUSH_IDENTIFIER: op->type = slang_oper_identifier; @@ -1480,6 +1536,20 @@ parse_function_prototype(slang_parse_ctx * C, slang_output_ctx * O, return 0; } +#if 111 + /* if the function returns a value, append a hidden __retVal 'out' + * parameter that corresponds to the return value. + */ + if (_slang_function_has_return_value(func)) { + slang_variable *p = slang_variable_scope_grow(func->parameters); + slang_atom a_retVal = slang_atom_pool_atom(C->atoms, "__retVal"); + assert(a_retVal); + p->a_name = a_retVal; + p->type = func->header.type; + p->type.qualifier = slang_qual_out; + } +#endif + /* function formal parameters and local variables share the same * scope, so save the information about param count in a seperate * place also link the scope to the global variable scope so when a @@ -1488,6 +1558,7 @@ parse_function_prototype(slang_parse_ctx * C, slang_output_ctx * O, */ func->param_count = func->parameters->num_variables; func->parameters->outer_scope = O->vars; + return 1; } @@ -1770,9 +1841,9 @@ parse_init_declarator_list(slang_parse_ctx * C, slang_output_ctx * O) * \param O output context * \param definition if non-zero expect a definition, else a declaration * \param parsed_func_ret returns the parsed function - * \return 1 if success, 0 if failure + * \return GL_TRUE if success, GL_FALSE if failure */ -static int +static GLboolean parse_function(slang_parse_ctx * C, slang_output_ctx * O, int definition, slang_function ** parsed_func_ret) { @@ -1780,17 +1851,17 @@ parse_function(slang_parse_ctx * C, slang_output_ctx * O, int definition, /* parse function definition/declaration */ if (!slang_function_construct(&parsed_func)) - return 0; + return GL_FALSE; if (definition) { if (!parse_function_definition(C, O, &parsed_func)) { slang_function_destruct(&parsed_func); - return 0; + return GL_FALSE; } } else { if (!parse_function_prototype(C, O, &parsed_func)) { slang_function_destruct(&parsed_func); - return 0; + return GL_FALSE; } } @@ -1800,7 +1871,7 @@ parse_function(slang_parse_ctx * C, slang_output_ctx * O, int definition, */ found_func = slang_function_scope_find(O->funs, &parsed_func, 0); if (found_func == NULL) { - /* add the parsed function to the function list */ + /* New function, add it to the function list */ O->funs->functions = (slang_function *) slang_alloc_realloc(O->funs->functions, O->funs->num_functions * @@ -1810,7 +1881,7 @@ parse_function(slang_parse_ctx * C, slang_output_ctx * O, int definition, if (O->funs->functions == NULL) { slang_info_log_memory(C->L); slang_function_destruct(&parsed_func); - return 0; + return GL_FALSE; } O->funs->functions[O->funs->num_functions] = parsed_func; O->funs->num_functions++; @@ -1819,6 +1890,7 @@ parse_function(slang_parse_ctx * C, slang_output_ctx * O, int definition, *parsed_func_ret = &O->funs->functions[O->funs->num_functions - 1]; } else { + /* previously defined or declared */ /* TODO: check function return type qualifiers and specifiers */ if (definition) { if (found_func->body != NULL) { @@ -1827,7 +1899,7 @@ parse_function(slang_parse_ctx * C, slang_output_ctx * O, int definition, parsed_func.header. a_name)); slang_function_destruct(&parsed_func); - return 0; + return GL_FALSE; } /* destroy the existing function declaration and replace it @@ -1857,10 +1929,33 @@ parse_function(slang_parse_ctx * C, slang_output_ctx * O, int definition, A.space.funcs = O->funs; A.space.structs = O->structs; A.space.vars = O->vars; - if (!_slang_assemble_function(&A, *parsed_func_ret)) - return 0; + A.program = O->program; + + _slang_reset_error(); + +#if 0 + printf("*************** Assemble function %s ****\n", (char *) (*parsed_func_ret)->header.a_name); + slang_print_var_scope((*parsed_func_ret)->parameters, + (*parsed_func_ret)->param_count); +#endif + + + if (!_slang_assemble_function(&A, *parsed_func_ret)) { + /* propogate the error message back through the info log */ + C->L->text = _mesa_strdup(_slang_error_text()); + C->L->dont_free_text = GL_FALSE; + return GL_FALSE; + } + + +#if 0 + printf("**************************************\n"); +#endif +#if 1 + _slang_codegen_function(&A, *parsed_func_ret); +#endif } - return 1; + return GL_TRUE; } /* declaration */ @@ -1895,7 +1990,8 @@ parse_declaration(slang_parse_ctx * C, slang_output_ctx * O) #define EXTERNAL_DECLARATION 2 static GLboolean -parse_code_unit(slang_parse_ctx * C, slang_code_unit * unit) +parse_code_unit(slang_parse_ctx * C, slang_code_unit * unit, + struct gl_program *program) { slang_output_ctx o; @@ -1906,6 +2002,7 @@ parse_code_unit(slang_parse_ctx * C, slang_code_unit * unit) o.assembly = &unit->object->assembly; o.global_pool = &unit->object->varpool; o.machine = &unit->object->machine; + o.program = program; /* parse individual functions and declarations */ while (*C->I != EXTERNAL_NULL) { @@ -1915,25 +2012,26 @@ parse_code_unit(slang_parse_ctx * C, slang_code_unit * unit) slang_function *func; if (!parse_function(C, &o, 1, &func)) - return 0; + return GL_FALSE; } break; case EXTERNAL_DECLARATION: if (!parse_declaration(C, &o)) - return 0; + return GL_FALSE; break; default: - return 0; + return GL_FALSE; } } C->I++; - return 1; + return GL_TRUE; } static GLboolean compile_binary(const byte * prod, slang_code_unit * unit, slang_unit_type type, slang_info_log * infolog, - slang_code_unit * builtin, slang_code_unit * downlink) + slang_code_unit * builtin, slang_code_unit * downlink, + struct gl_program *program) { slang_parse_ctx C; @@ -1956,13 +2054,14 @@ compile_binary(const byte * prod, slang_code_unit * unit, } /* parse translation unit */ - return parse_code_unit(&C, unit); + return parse_code_unit(&C, unit, program); } static GLboolean compile_with_grammar(grammar id, const char *source, slang_code_unit * unit, slang_unit_type type, slang_info_log * infolog, - slang_code_unit * builtin) + slang_code_unit * builtin, + struct gl_program *program) { byte *prod; GLuint size, start, version; @@ -1987,8 +2086,9 @@ compile_with_grammar(grammar id, const char *source, slang_code_unit * unit, } /* Finally check the syntax and generate its binary representation. */ - if (!grammar_fast_check - (id, (const byte *) (slang_string_cstr(&preprocessed)), &prod, &size, + if (!grammar_fast_check(id, + (const byte *) (slang_string_cstr(&preprocessed)), + &prod, &size, 65536)) { char buf[1024]; GLint pos; @@ -1996,14 +2096,14 @@ compile_with_grammar(grammar id, const char *source, slang_code_unit * unit, slang_string_free(&preprocessed); grammar_get_last_error((byte *) (buf), sizeof(buf), &pos); slang_info_log_error(infolog, buf); - return GL_FALSE; + RETURN_ERROR("syntax error", 0); } slang_string_free(&preprocessed); /* Syntax is okay - translate it to internal representation. */ - if (!compile_binary - (prod, unit, type, infolog, builtin, - &builtin[SLANG_BUILTIN_TOTAL - 1])) { + if (!compile_binary(prod, unit, type, infolog, builtin, + &builtin[SLANG_BUILTIN_TOTAL - 1], + program)) { grammar_alloc_free(prod); return GL_FALSE; } @@ -2032,6 +2132,7 @@ static const byte slang_vertex_builtin_gc[] = { }; #if defined(USE_X86_ASM) || defined(SLANG_X86) +foo static const byte slang_builtin_vec4_gc[] = { #include "library/slang_builtin_vec4_gc.h" }; @@ -2039,7 +2140,8 @@ static const byte slang_builtin_vec4_gc[] = { static GLboolean compile_object(grammar * id, const char *source, slang_code_object * object, - slang_unit_type type, slang_info_log * infolog) + slang_unit_type type, slang_info_log * infolog, + struct gl_program *program) { slang_code_unit *builtins = NULL; @@ -2067,56 +2169,79 @@ compile_object(grammar * id, const char *source, slang_code_object * object, /* if parsing user-specified shader, load built-in library */ if (type == slang_unit_fragment_shader || type == slang_unit_vertex_shader) { /* compile core functionality first */ - if (!compile_binary(slang_core_gc, &object->builtin[SLANG_BUILTIN_CORE], - slang_unit_fragment_builtin, infolog, NULL, NULL)) + if (!compile_binary(slang_core_gc, + &object->builtin[SLANG_BUILTIN_CORE], + slang_unit_fragment_builtin, infolog, + NULL, NULL, NULL)) return GL_FALSE; /* compile common functions and variables, link to core */ - if (!compile_binary - (slang_common_builtin_gc, &object->builtin[SLANG_BUILTIN_COMMON], - slang_unit_fragment_builtin, infolog, NULL, - &object->builtin[SLANG_BUILTIN_CORE])) + if (!compile_binary(slang_common_builtin_gc, + &object->builtin[SLANG_BUILTIN_COMMON], + slang_unit_fragment_builtin, infolog, NULL, + &object->builtin[SLANG_BUILTIN_CORE], NULL)) return GL_FALSE; /* compile target-specific functions and variables, link to common */ if (type == slang_unit_fragment_shader) { - if (!compile_binary - (slang_fragment_builtin_gc, - &object->builtin[SLANG_BUILTIN_TARGET], - slang_unit_fragment_builtin, infolog, NULL, - &object->builtin[SLANG_BUILTIN_COMMON])) + if (!compile_binary(slang_fragment_builtin_gc, + &object->builtin[SLANG_BUILTIN_TARGET], + slang_unit_fragment_builtin, infolog, NULL, + &object->builtin[SLANG_BUILTIN_COMMON], NULL)) return GL_FALSE; } else if (type == slang_unit_vertex_shader) { - if (!compile_binary - (slang_vertex_builtin_gc, &object->builtin[SLANG_BUILTIN_TARGET], - slang_unit_vertex_builtin, infolog, NULL, - &object->builtin[SLANG_BUILTIN_COMMON])) + if (!compile_binary(slang_vertex_builtin_gc, + &object->builtin[SLANG_BUILTIN_TARGET], + slang_unit_vertex_builtin, infolog, NULL, + &object->builtin[SLANG_BUILTIN_COMMON], NULL)) return GL_FALSE; } #if defined(USE_X86_ASM) || defined(SLANG_X86) /* compile x86 4-component vector overrides, link to target */ - if (!compile_binary - (slang_builtin_vec4_gc, &object->builtin[SLANG_BUILTIN_VEC4], - slang_unit_fragment_builtin, infolog, NULL, - &object->builtin[SLANG_BUILTIN_TARGET])) + if (!compile_binary(slang_builtin_vec4_gc, + &object->builtin[SLANG_BUILTIN_VEC4], + slang_unit_fragment_builtin, infolog, NULL, + &object->builtin[SLANG_BUILTIN_TARGET])) return GL_FALSE; #endif /* disable language extensions */ +#if NEW_SLANG /* allow-built-ins */ + grammar_set_reg8(*id, (const byte *) "parsing_builtin", 1); +#else grammar_set_reg8(*id, (const byte *) "parsing_builtin", 0); +#endif builtins = object->builtin; } /* compile the actual shader - pass-in built-in library for external shader */ return compile_with_grammar(*id, source, &object->unit, type, infolog, - builtins); + builtins, program); +} + + +static void +slang_create_uniforms(const slang_export_data_table *exports, + struct gl_program *program) +{ + /* XXX only add uniforms that are actually going to get used */ + GLuint i; + for (i = 0; i < exports->count; i++) { + if (exports->entries[i].access == slang_exp_uniform) { + const char *name = (char *) exports->entries[i].quant.name; + GLint j = _mesa_add_uniform(program->Parameters, name, 4); + assert(j >= 0); + } + } } + GLboolean _slang_compile(const char *source, slang_code_object * object, - slang_unit_type type, slang_info_log * infolog) + slang_unit_type type, slang_info_log * infolog, + struct gl_program *program) { GLboolean success; grammar id = 0; @@ -2124,7 +2249,7 @@ _slang_compile(const char *source, slang_code_object * object, _slang_code_object_dtr(object); _slang_code_object_ctr(object); - success = compile_object(&id, source, object, type, infolog); + success = compile_object(&id, source, object, type, infolog, program); if (id != 0) grammar_destroy(id); if (!success) @@ -2132,10 +2257,20 @@ _slang_compile(const char *source, slang_code_object * object, if (!_slang_build_export_data_table(&object->expdata, &object->unit.vars)) return GL_FALSE; - if (!_slang_build_export_code_table - (&object->expcode, &object->unit.funs, &object->unit)) + if (!_slang_build_export_code_table(&object->expcode, &object->unit.funs, + &object->unit)) return GL_FALSE; +#if NEW_SLANG + { + GET_CURRENT_CONTEXT(ctx); + slang_create_uniforms(&object->expdata, program); + _mesa_print_program(program); + _mesa_print_program_parameters(ctx, program); + } +#endif + + #if defined(USE_X86_ASM) || defined(SLANG_X86) /* XXX: lookup the @main label */ if (!_slang_x86_codegen @@ -2146,3 +2281,4 @@ _slang_compile(const char *source, slang_code_object * object, return GL_TRUE; } + diff --git a/src/mesa/shader/slang/slang_compile.h b/src/mesa/shader/slang/slang_compile.h index 02987f4e1bc..a41c00a3f5e 100644 --- a/src/mesa/shader/slang/slang_compile.h +++ b/src/mesa/shader/slang/slang_compile.h @@ -25,6 +25,8 @@ #if !defined SLANG_COMPILE_H #define SLANG_COMPILE_H +#include "imports.h" +#include "mtypes.h" #include "slang_export.h" #include "slang_execute.h" #include "slang_compile_variable.h" @@ -107,7 +109,7 @@ int slang_info_log_warning (slang_info_log *, const char *, ...); void slang_info_log_memory (slang_info_log *); extern GLboolean -_slang_compile (const char *, slang_code_object *, slang_unit_type, slang_info_log *); +_slang_compile (const char *, slang_code_object *, slang_unit_type, slang_info_log *, struct gl_program *program); #ifdef __cplusplus } diff --git a/src/mesa/shader/slang/slang_compile_function.c b/src/mesa/shader/slang/slang_compile_function.c index e6e0d89ddb6..58a453d4c23 100644 --- a/src/mesa/shader/slang/slang_compile_function.c +++ b/src/mesa/shader/slang/slang_compile_function.c @@ -86,6 +86,7 @@ slang_function_construct(slang_function * func) func->param_count = 0; func->body = NULL; func->address = ~0; + func->end_label = 0; slang_fixup_table_init(&func->fixups); return 1; } @@ -127,6 +128,16 @@ slang_function_scope_destruct(slang_function_scope * scope) /** + * Does this function have a non-void return value? + */ +GLboolean +_slang_function_has_return_value(const slang_function *fun) +{ + return fun->header.type.specifier.type != slang_spec_void; +} + + +/** * Search a list of functions for a particular function by name. * \param funcs the list of functions to search * \param a_name the name to search for @@ -166,21 +177,39 @@ slang_function_scope_find(slang_function_scope * funcs, slang_function * fun, for (i = 0; i < funcs->num_functions; i++) { slang_function *f = &funcs->functions[i]; + const GLuint haveRetValue = 0; +#if 0 + = (f->header.type.specifier.type != slang_spec_void); +#endif unsigned int j; + /* + printf("Compare name %s to %s (ret %u, %d, %d)\n", + (char *) fun->header.a_name, (char *) f->header.a_name, + haveRetValue, + fun->param_count, f->param_count); + */ + if (fun->header.a_name != f->header.a_name) continue; if (fun->param_count != f->param_count) continue; - for (j = 0; j < fun->param_count; j++) { + for (j = haveRetValue; j < fun->param_count; j++) { if (!slang_type_specifier_equal (&fun->parameters->variables[j].type.specifier, &f->parameters->variables[j].type.specifier)) break; } - if (j == fun->param_count) + if (j == fun->param_count) { + /* + printf("Found match\n"); + */ return f; + } } + /* + printf("Not found\n"); + */ if (all_scopes && funcs->outer_scope != NULL) return slang_function_scope_find(funcs->outer_scope, fun, 1); return NULL; diff --git a/src/mesa/shader/slang/slang_compile_function.h b/src/mesa/shader/slang/slang_compile_function.h index c05c6f4d850..8f0e3b326d4 100644 --- a/src/mesa/shader/slang/slang_compile_function.h +++ b/src/mesa/shader/slang/slang_compile_function.h @@ -69,6 +69,7 @@ typedef struct slang_function_ slang_operation *body; /**< The instruction tree */ unsigned int address; /**< Address of this func in memory */ slang_fixup_table fixups; /**< Mem locations which need func's address */ + slang_atom end_label; /**< The end-of-function label */ } slang_function; extern int slang_function_construct(slang_function *); @@ -92,6 +93,9 @@ _slang_function_scope_ctr(slang_function_scope *); extern void slang_function_scope_destruct(slang_function_scope *); +extern GLboolean +_slang_function_has_return_value(const slang_function *fun); + extern int slang_function_scope_find_by_name(slang_function_scope *, slang_atom, int); diff --git a/src/mesa/shader/slang/slang_compile_operation.c b/src/mesa/shader/slang/slang_compile_operation.c index 73f57bfb123..192f2b086b6 100644 --- a/src/mesa/shader/slang/slang_compile_operation.c +++ b/src/mesa/shader/slang/slang_compile_operation.c @@ -41,14 +41,14 @@ slang_operation_construct(slang_operation * oper) oper->type = slang_oper_none; oper->children = NULL; oper->num_children = 0; - oper->literal = (float) 0; + oper->literal[0] = 0.0; oper->a_id = SLANG_ATOM_NULL; - oper->locals = - (slang_variable_scope *) - slang_alloc_malloc(sizeof(slang_variable_scope)); + oper->locals = _slang_variable_scope_new(NULL); if (oper->locals == NULL) return GL_FALSE; _slang_variable_scope_ctr(oper->locals); + oper->fun = NULL; + oper->var = NULL; return GL_TRUE; } @@ -62,6 +62,9 @@ slang_operation_destruct(slang_operation * oper) slang_alloc_free(oper->children); slang_variable_scope_destruct(oper->locals); slang_alloc_free(oper->locals); + oper->children = NULL; + oper->num_children = 0; + oper->locals = NULL; } /** @@ -96,12 +99,21 @@ slang_operation_copy(slang_operation * x, const slang_operation * y) return GL_FALSE; } } - z.literal = y->literal; + z.literal[0] = y->literal[0]; + z.literal[1] = y->literal[1]; + z.literal[2] = y->literal[2]; + z.literal[3] = y->literal[3]; z.a_id = y->a_id; - if (!slang_variable_scope_copy(z.locals, y->locals)) { - slang_operation_destruct(&z); - return GL_FALSE; + if (y->locals) { + if (!slang_variable_scope_copy(z.locals, y->locals)) { + slang_operation_destruct(&z); + return GL_FALSE; + } } +#if 0 + z.var = y->var; + z.fun = y->fun; +#endif slang_operation_destruct(x); *x = z; return GL_TRUE; @@ -111,5 +123,77 @@ slang_operation_copy(slang_operation * x, const slang_operation * y) slang_operation * slang_operation_new(GLuint count) { - return (slang_operation *) _mesa_calloc(count * sizeof(slang_operation)); + slang_operation *ops + = (slang_operation *) _mesa_malloc(count * sizeof(slang_operation)); + assert(count > 0); + if (ops) { + GLuint i; + for (i = 0; i < count; i++) + slang_operation_construct(ops + i); + } + return ops; +} + + +slang_operation * +slang_operation_grow(GLuint *numChildren, slang_operation **children) +{ + slang_operation *ops; + + ops = (slang_operation *) + slang_alloc_realloc(*children, + *numChildren * sizeof(slang_operation), + (*numChildren + 1) * sizeof(slang_operation)); + if (ops) { + slang_operation *newOp = ops + *numChildren; + if (!slang_operation_construct(newOp)) { + _mesa_free(ops); + *children = NULL; + return NULL; + } + *children = ops; + (*numChildren)++; + return newOp; + } + return NULL; +} + +/** + * Insert a new slang_operation into an array. + * \param numChildren pointer to current number of children (in/out) + * \param children address of array (in/out) + * \param pos position to insert + * \return pointer to the new operation + */ +slang_operation * +slang_operation_insert(GLuint *numChildren, slang_operation **children, + GLuint pos) +{ + slang_operation *ops; + + assert(pos <= *numChildren); + + ops = (slang_operation *) + _mesa_malloc((*numChildren + 1) * sizeof(slang_operation)); + if (ops) { + slang_operation *newOp; + newOp = ops + pos; + if (pos > 0) + _mesa_memcpy(ops, *children, pos * sizeof(slang_operation)); + if (pos < *numChildren) + _mesa_memcpy(newOp + 1, (*children) + pos, + (*numChildren - pos) * sizeof(slang_operation)); + + if (!slang_operation_construct(newOp)) { + _mesa_free(ops); + *numChildren = 0; + *children = NULL; + return NULL; + } + *children = ops; + (*numChildren)++; + return newOp; + } + return NULL; } + diff --git a/src/mesa/shader/slang/slang_compile_operation.h b/src/mesa/shader/slang/slang_compile_operation.h index a9376ec945f..f6d0ba85ba5 100644 --- a/src/mesa/shader/slang/slang_compile_operation.h +++ b/src/mesa/shader/slang/slang_compile_operation.h @@ -46,6 +46,8 @@ typedef enum slang_operation_type_ slang_oper_continue, /* "continue" statement */ slang_oper_discard, /* "discard" (kill fragment) statement */ slang_oper_return, /* "return" [expr] */ + slang_oper_goto, /* jump to label */ + slang_oper_label, /* a jump target */ slang_oper_expression, /* [expr] */ slang_oper_if, /* "if" [0] then [1] else [2] */ slang_oper_while, /* "while" [cond] [body] */ @@ -114,9 +116,13 @@ typedef struct slang_operation_ slang_operation_type type; struct slang_operation_ *children; GLuint num_children; - GLfloat literal; /**< Used for float, int and bool values */ - slang_atom a_id; /**< type: asm, identifier, call, field */ - slang_variable_scope *locals; /**< local vars for scope */ + GLfloat literal[4]; /**< Used for float, int and bool values */ + slang_atom a_id; /**< type: asm, identifier, call, field */ + slang_variable_scope *locals; /**< local vars for scope */ + struct slang_function_ *fun; /**< If type == slang_oper_call */ + struct slang_variable_ *var; /**< If type == slang_oper_identier */ + slang_fully_specified_type *datatype; /**< Type of this operation */ + slang_assembly_typeinfo ti; } slang_operation; @@ -132,6 +138,13 @@ slang_operation_copy(slang_operation *, const slang_operation *); extern slang_operation * slang_operation_new(GLuint count); +extern slang_operation * +slang_operation_grow(GLuint *numChildren, slang_operation **children); + +extern slang_operation * +slang_operation_insert(GLuint *numChildren, slang_operation **children, + GLuint pos); + #ifdef __cplusplus } diff --git a/src/mesa/shader/slang/slang_compile_variable.c b/src/mesa/shader/slang/slang_compile_variable.c index a8a2d6aa6a0..f9f02066a3a 100644 --- a/src/mesa/shader/slang/slang_compile_variable.c +++ b/src/mesa/shader/slang/slang_compile_variable.c @@ -127,6 +127,16 @@ slang_fully_specified_type_copy(slang_fully_specified_type * x, * slang_variable_scope */ +slang_variable_scope * +_slang_variable_scope_new(slang_variable_scope *parent) +{ + slang_variable_scope *s; + s = (slang_variable_scope *) _mesa_calloc(sizeof(slang_variable_scope)); + s->outer_scope = parent; + return s; +} + + GLvoid _slang_variable_scope_ctr(slang_variable_scope * self) { @@ -218,9 +228,11 @@ slang_variable_construct(slang_variable * var) var->array_len = 0; var->initializer = NULL; var->address = ~0; - var->address2 = 0; var->size = 0; var->global = GL_FALSE; + var->declared = GL_FALSE; + var->used = GL_FALSE; + var->aux = NULL; return 1; } @@ -248,8 +260,8 @@ slang_variable_copy(slang_variable * x, const slang_variable * y) z.a_name = y->a_name; z.array_len = y->array_len; if (y->initializer != NULL) { - z.initializer = - (slang_operation *) slang_alloc_malloc(sizeof(slang_operation)); + z.initializer + = (slang_operation *) slang_alloc_malloc(sizeof(slang_operation)); if (z.initializer == NULL) { slang_variable_destruct(&z); return 0; diff --git a/src/mesa/shader/slang/slang_compile_variable.h b/src/mesa/shader/slang/slang_compile_variable.h index b0910e855ea..d52e2660dc0 100644 --- a/src/mesa/shader/slang/slang_compile_variable.h +++ b/src/mesa/shader/slang/slang_compile_variable.h @@ -78,9 +78,10 @@ typedef struct slang_variable_ GLuint array_len; /**< only if type == slang_spec_array */ struct slang_operation_ *initializer; /**< Optional initializer code */ GLuint address; /**< Storage location */ - GLuint address2; /**< Storage location */ GLuint size; /**< Variable's size in bytes */ GLboolean global; /**< A global var? */ + GLboolean used; /**< Ever referenced by code? */ + GLboolean declared; /**< Declared by slang_variable_decl? */ void *aux; /**< Used during code gen */ } slang_variable; @@ -95,6 +96,10 @@ typedef struct slang_variable_scope_ struct slang_variable_scope_ *outer_scope; } slang_variable_scope; + +extern slang_variable_scope * +_slang_variable_scope_new(slang_variable_scope *parent); + extern GLvoid _slang_variable_scope_ctr(slang_variable_scope *); diff --git a/src/mesa/shader/slang/slang_emit.c b/src/mesa/shader/slang/slang_emit.c new file mode 100644 index 00000000000..0b4ef6dba10 --- /dev/null +++ b/src/mesa/shader/slang/slang_emit.c @@ -0,0 +1,1027 @@ +/* + * Mesa 3-D graphics library + * Version: 6.5.3 + * + * Copyright (C) 2005-2007 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_emit.c + * Emit program instructions (PI code) from IR trees. + * \author Brian Paul + */ + +#include "imports.h" +#include "context.h" +#include "get.h" +#include "macros.h" +#include "program.h" +#include "program_instruction.h" +#include "slang_emit.h" + + +/** + * Assembly and IR info + */ +typedef struct +{ + slang_ir_opcode IrOpcode; + const char *IrName; + gl_inst_opcode InstOpcode; + GLuint ResultSize, NumParams; +} slang_ir_info; + + + +static slang_ir_info IrInfo[] = { + /* binary ops */ + { IR_ADD, "IR_ADD", OPCODE_ADD, 4, 2 }, + { IR_SUB, "IR_SUB", OPCODE_SUB, 4, 2 }, + { IR_MUL, "IR_MUL", OPCODE_MUL, 4, 2 }, + { IR_DIV, "IR_DIV", OPCODE_NOP, 0, 2 }, /* XXX broke */ + { IR_DOT4, "IR_DOT_4", OPCODE_DP4, 1, 2 }, + { IR_DOT3, "IR_DOT_3", OPCODE_DP3, 1, 2 }, + { IR_CROSS, "IR_CROSS", OPCODE_XPD, 3, 2 }, + { IR_MIN, "IR_MIN", OPCODE_MIN, 4, 2 }, + { IR_MAX, "IR_MAX", OPCODE_MAX, 4, 2 }, + { IR_SEQUAL, "IR_SEQUAL", OPCODE_SEQ, 4, 2 }, + { IR_SNEQUAL, "IR_SNEQUAL", OPCODE_SNE, 4, 2 }, + { IR_SGE, "IR_SGE", OPCODE_SGE, 4, 2 }, + { IR_SGT, "IR_SGT", OPCODE_SGT, 4, 2 }, + { IR_POW, "IR_POW", OPCODE_POW, 1, 2 }, + /* unary ops */ + { IR_I_TO_F, "IR_I_TO_F", OPCODE_NOP, 1, 1 }, + { IR_EXP, "IR_EXP", OPCODE_EXP, 1, 1 }, + { IR_EXP2, "IR_EXP2", OPCODE_EX2, 1, 1 }, + { IR_LOG2, "IR_LOG2", OPCODE_LG2, 1, 1 }, + { IR_RSQ, "IR_RSQ", OPCODE_RSQ, 1, 1 }, + { IR_RCP, "IR_RCP", OPCODE_RCP, 1, 1 }, + { IR_FLOOR, "IR_FLOOR", OPCODE_FLR, 4, 1 }, + { IR_FRAC, "IR_FRAC", OPCODE_FRC, 4, 1 }, + { IR_ABS, "IR_ABS", OPCODE_ABS, 4, 1 }, + { IR_SIN, "IR_SIN", OPCODE_SIN, 1, 1 }, + { IR_COS, "IR_COS", OPCODE_COS, 1, 1 }, + /* other */ + { IR_SEQ, "IR_SEQ", 0, 0, 0 }, + { IR_LABEL, "IR_LABEL", 0, 0, 0 }, + { IR_JUMP, "IR_JUMP", 0, 0, 0 }, + { IR_CJUMP, "IR_CJUMP", 0, 0, 0 }, + { IR_CALL, "IR_CALL", 0, 0, 0 }, + { IR_MOVE, "IR_MOVE", 0, 0, 1 }, + { IR_LESS, "IR_LESS", 0, 1, 2 }, + { IR_NOT, "IR_NOT", 0, 1, 1 }, + { IR_VAR, "IR_VAR", 0, 0, 0 }, + { IR_VAR_DECL, "IR_VAR_DECL", 0, 0, 0 }, + { IR_FLOAT, "IR_FLOAT", 0, 0, 0 }, + { IR_FIELD, "IR_FIELD", 0, 0, 0 }, + { IR_NOP, NULL, OPCODE_NOP, 0, 0 } +}; + + +static slang_ir_info * +slang_find_ir_info(slang_ir_opcode opcode) +{ + GLuint i; + for (i = 0; IrInfo[i].IrName; i++) { + if (IrInfo[i].IrOpcode == opcode) { + return IrInfo + i; + } + } + return NULL; +} + +static const char * +slang_ir_name(slang_ir_opcode opcode) +{ + return slang_find_ir_info(opcode)->IrName; +} + + +slang_ir_storage * +_slang_new_ir_storage(enum register_file file, GLint index, GLint size) +{ + slang_ir_storage *st; + st = (slang_ir_storage *) _mesa_calloc(sizeof(slang_ir_storage)); + if (st) { + st->File = file; + st->Index = index; + st->Size = size; + } + return st; +} + + +static const char * +swizzle_string(GLuint swizzle) +{ + static char s[6]; + GLuint i; + s[0] = '.'; + for (i = 1; i < 5; i++) { + s[i] = "xyzw"[GET_SWZ(swizzle, i-1)]; + } + s[i] = 0; + return s; +} + +static const char * +writemask_string(GLuint writemask) +{ + static char s[6]; + GLuint i, j = 0; + s[j++] = '.'; + for (i = 0; i < 4; i++) { + if (writemask & (1 << i)) + s[j++] = "xyzw"[i]; + } + s[j] = 0; + return s; +} + +static const char * +storage_string(const slang_ir_storage *st) +{ + static const char *files[] = { + "TEMP", + "LOCAL_PARAM", + "ENV_PARAM", + "STATE", + "INPUT", + "OUTPUT", + "NAMED_PARAM", + "CONSTANT", + "UNIFORM", + "WRITE_ONLY", + "ADDRESS", + "UNDEFINED" + }; + static char s[100]; +#if 0 + if (st->Size == 1) + sprintf(s, "%s[%d]", files[st->File], st->Index); + else + sprintf(s, "%s[%d..%d]", files[st->File], st->Index, + st->Index + st->Size - 1); +#endif + sprintf(s, "%s", files[st->File]); + return s; +} + + +static GLuint +sizeof_struct(const slang_struct *s) +{ + return 0; +} + + +static GLuint +sizeof_type(const slang_fully_specified_type *t) +{ + switch (t->specifier.type) { + case slang_spec_void: + abort(); + return 0; + case slang_spec_bool: + return 1; + case slang_spec_bvec2: + return 2; + case slang_spec_bvec3: + return 3; + case slang_spec_bvec4: + return 4; + case slang_spec_int: + return 1; + case slang_spec_ivec2: + return 2; + case slang_spec_ivec3: + return 3; + case slang_spec_ivec4: + return 4; + case slang_spec_float: + return 1; + case slang_spec_vec2: + return 2; + case slang_spec_vec3: + return 3; + case slang_spec_vec4: + return 4; + case slang_spec_mat2: + return 2 * 2; + case slang_spec_mat3: + return 3 * 3; + case slang_spec_mat4: + return 4 * 4; + case slang_spec_sampler1D: + case slang_spec_sampler2D: + case slang_spec_sampler3D: + case slang_spec_samplerCube: + case slang_spec_sampler1DShadow: + case slang_spec_sampler2DShadow: + abort(); + return 0; + case slang_spec_struct: + return sizeof_struct(t->specifier._struct); + case slang_spec_array: + return 1; /* XXX */ + default: + abort(); + return 0; + } + return 0; +} + + +#define IND 0 +void +slang_print_ir(const slang_ir_node *n, int indent) +{ + int i; + if (!n) + return; +#if !IND + if (n->Opcode != IR_SEQ) +#else + printf("%3d:", indent); +#endif + for (i = 0; i < indent; i++) + printf(" "); + + switch (n->Opcode) { + case IR_SEQ: +#if IND + printf("SEQ store %p\n", (void*) n->Store); +#endif + assert(n->Children[0]); + assert(n->Children[1]); + slang_print_ir(n->Children[0], indent + IND); + slang_print_ir(n->Children[1], indent + IND); + break; + case IR_MOVE: + printf("MOVE (writemask = %s)\n", writemask_string(n->Writemask)); + slang_print_ir(n->Children[0], indent+3); + slang_print_ir(n->Children[1], indent+3); + break; + case IR_LABEL: + printf("LABEL: %s\n", n->Target); + break; + case IR_JUMP: + printf("JUMP %s\n", n->Target); + break; + case IR_CJUMP: + printf("CJUMP %s\n", n->Target); + slang_print_ir(n->Children[0], indent+3); + break; + case IR_VAR: + printf("VAR %s%s at %s store %p\n", + (char *) n->Var->a_name, swizzle_string(n->Swizzle), + storage_string(n->Store), (void*) n->Store); + break; + case IR_VAR_DECL: + printf("VAR_DECL %s (%p) at %s store %p\n", + (char *) n->Var->a_name, (void*) n->Var, storage_string(n->Store), + (void*) n->Store); + break; + case IR_FIELD: + printf("FIELD %s of\n", n->Target); + slang_print_ir(n->Children[0], indent+3); + break; + case IR_CALL: + printf("ASMCALL %s(%d args)\n", n->Target, n->Swizzle); + break; + case IR_FLOAT: + printf("FLOAT %f %f %f %f\n", + n->Value[0], n->Value[1], n->Value[2], n->Value[3]); + break; + case IR_I_TO_F: + printf("INT_TO_FLOAT %d\n", (int) n->Value[0]); + break; + default: + printf("%s (%p, %p)\n", slang_ir_name(n->Opcode), + (void*) n->Children[0], (void*) n->Children[1]); + slang_print_ir(n->Children[0], indent+3); + slang_print_ir(n->Children[1], indent+3); + } +} + + +static GLint +alloc_temporary(slang_gen_context *gc) +{ + GLuint i; + for (i = 0; i < MAX_PROGRAM_TEMPS; i++) { + if (!gc->TempUsed[i]) { + gc->TempUsed[i] = GL_TRUE; + return i; + } + } + return -1; +} + + +static GLboolean +is_temporary(const slang_gen_context *gc, const slang_ir_storage *st) +{ + if (st->File == PROGRAM_TEMPORARY && gc->TempUsed[st->Index]) + return gc->TempUsed[st->Index]; + else + return GL_FALSE; +} + + +static void +free_temporary(slang_gen_context *gc, GLuint r) +{ + if (gc->TempUsed[r]) + gc->TempUsed[r] = GL_FALSE; +} + + + +static GLint +slang_find_input(GLenum target, const char *name, GLint index) +{ + struct input_info { + const char *Name; + GLuint Attrib; + }; + static const struct input_info vertInputs[] = { + { "gl_Vertex", VERT_ATTRIB_POS }, + { "gl_Normal", VERT_ATTRIB_NORMAL }, + { "gl_Color", VERT_ATTRIB_COLOR0 }, + { "gl_SecondaryColor", VERT_ATTRIB_COLOR1 }, + { NULL, 0 } + }; + static const struct input_info fragInputs[] = { + { NULL, 0 } + }; + const struct input_info *inputs; + GLuint i; + + if (target == GL_VERTEX_PROGRAM_ARB) { + inputs = vertInputs; + } + else { + assert(target == GL_FRAGMENT_PROGRAM_ARB); + inputs = fragInputs; + } + + for (i = 0; inputs[i].Name; i++) { + if (strcmp(inputs[i].Name, name) == 0) { + /* found */ + return inputs[i].Attrib; + } + } + return -1; +} + + +static GLint +slang_find_output(GLenum target, const char *name, GLint index) +{ + struct output_info { + const char *Name; + GLuint Attrib; + }; + static const struct output_info vertOutputs[] = { + { "gl_Position", VERT_RESULT_HPOS }, + { "gl_FrontColor", VERT_RESULT_COL0 }, + { "gl_BackColor", VERT_RESULT_BFC0 }, + { "gl_FrontSecondaryColor", VERT_RESULT_COL1 }, + { "gl_BackSecondaryColor", VERT_RESULT_BFC1 }, + { "gl_TexCoord", VERT_RESULT_TEX0 }, /* XXX indexed */ + { "gl_FogFragCoord", VERT_RESULT_FOGC }, + { NULL, 0 } + }; + static const struct output_info fragOutputs[] = { + { "gl_FragColor", FRAG_RESULT_COLR }, + { NULL, 0 } + }; + const struct output_info *outputs; + GLuint i; + + if (target == GL_VERTEX_PROGRAM_ARB) { + outputs = vertOutputs; + } + else { + assert(target == GL_FRAGMENT_PROGRAM_ARB); + outputs = fragOutputs; + } + + for (i = 0; outputs[i].Name; i++) { + if (strcmp(outputs[i].Name, name) == 0) { + /* found */ + return outputs[i].Attrib; + } + } + return -1; +} + + +/** + * Lookup a named constant and allocate storage for the parameter in + * the given parameter list. + * \return position of the constant in the paramList. + */ +static GLint +slang_lookup_constant(const char *name, GLint index, + struct gl_program_parameter_list *paramList) +{ + struct constant_info { + const char *Name; + const GLenum Token; + }; + static const struct constant_info info[] = { + { "gl_MaxLights", GL_MAX_LIGHTS }, + { "gl_MaxClipPlanes", GL_MAX_CLIP_PLANES }, + { "gl_MaxTextureUnits", GL_MAX_TEXTURE_UNITS }, + { "gl_MaxTextureCoords", GL_MAX_TEXTURE_COORDS }, + { "gl_MaxVertexAttribs", GL_MAX_VERTEX_ATTRIBS }, + { "gl_MaxVertexUniformComponents", GL_MAX_VERTEX_UNIFORM_COMPONENTS }, + { "gl_MaxVaryingFloats", GL_MAX_VARYING_FLOATS }, + { "gl_MaxVertexTextureImageUnits", GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS }, + { "gl_MaxTextureImageUnits", GL_MAX_TEXTURE_IMAGE_UNITS }, + { "gl_MaxFragmentUniformComponents", GL_MAX_FRAGMENT_UNIFORM_COMPONENTS }, + { "gl_MaxCombinedTextureImageUnits", GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS }, + { NULL, 0 } + }; + GLuint i; + GLuint swizzle; /* XXX use this */ + + for (i = 0; info[i].Name; i++) { + if (strcmp(info[i].Name, name) == 0) { + /* found */ + GLfloat value = -1.0; + GLint pos; + _mesa_GetFloatv(info[i].Token, &value); + ASSERT(value >= 0.0); /* sanity check that glGetFloatv worked */ + pos = _mesa_add_unnamed_constant(paramList, &value, 1, &swizzle); + return pos; + } + } + return -1; +} + + +/** + * Determine if 'name' is a state variable. If so, create a new program + * parameter for it, and return the param's index. Else, return -1. + */ +static GLint +slang_lookup_statevar(const char *name, GLint index, + struct gl_program_parameter_list *paramList) +{ + struct state_info { + const char *Name; + const GLuint NumRows; /** for matrices */ + const GLuint Swizzle; + const GLint Indexes[6]; + }; + static const struct state_info state[] = { + { "gl_ModelViewMatrix", 4, SWIZZLE_NOOP, + { STATE_MATRIX, STATE_MODELVIEW, 0, 0, 0, STATE_MATRIX_TRANSPOSE } }, + { "gl_NormalMatrix", 3, SWIZZLE_NOOP, + { STATE_MATRIX, STATE_MODELVIEW, 0, 0, 0, STATE_MATRIX_INVTRANS } }, + { "gl_ProjectionMatrix", 4, SWIZZLE_NOOP, + { STATE_MATRIX, STATE_PROJECTION, 0, 0, 0, STATE_MATRIX_TRANSPOSE } }, + { "gl_ModelViewProjectionMatrix", 4, SWIZZLE_NOOP, + { STATE_MATRIX, STATE_MVP, 0, 0, 0, STATE_MATRIX_TRANSPOSE } }, + { "gl_TextureMatrix", 4, SWIZZLE_NOOP, + { STATE_MATRIX, STATE_TEXTURE, 0, 0, 0, STATE_MATRIX_TRANSPOSE } }, + { NULL, 0, 0, {0, 0, 0, 0, 0, 0} } + }; + GLuint i; + + for (i = 0; state[i].Name; i++) { + if (strcmp(state[i].Name, name) == 0) { + /* found */ + if (paramList) { + if (state[i].NumRows > 1) { + /* a matrix */ + GLuint j; + GLint pos[4], indexesCopy[6]; + /* make copy of state tokens */ + for (j = 0; j < 6; j++) + indexesCopy[j] = state[i].Indexes[j]; + /* load rows */ + for (j = 0; j < state[i].NumRows; j++) { + indexesCopy[3] = indexesCopy[4] = j; /* jth row of matrix */ + pos[j] = _mesa_add_state_reference(paramList, indexesCopy); + assert(pos[j] >= 0); + } + return pos[0]; + } + else { + /* non-matrix state */ + GLint pos + = _mesa_add_state_reference(paramList, state[i].Indexes); + assert(pos >= 0); + return pos; + } + } + } + } + return -1; +} + + +static GLint +slang_alloc_uniform(struct gl_program *prog, const char *name) +{ + GLint i = _mesa_add_uniform(prog->Parameters, name, 4); + return i; +} + + +static GLint +slang_alloc_varying(struct gl_program *prog, const char *name) +{ + GLint i = _mesa_add_varying(prog->Varying, name, 4); /* XXX fix size */ + if (prog->Target == GL_VERTEX_PROGRAM_ARB) { + i += VERT_RESULT_VAR0; + prog->OutputsWritten |= (1 << i); + } + else { + i += FRAG_ATTRIB_VAR0; + prog->InputsRead |= (1 << i); + } + return i; +} + + +/** + * Allocate temporary storage for an intermediate result (such as for + * a multiply or add, etc. + */ +static void +slang_alloc_temp_storage(slang_gen_context *gc, slang_ir_node *n, GLint size) +{ + GLint indx; + assert(!n->Var); + assert(!n->Store); + assert(size > 0); + indx = alloc_temporary(gc); + n->Store = _slang_new_ir_storage(PROGRAM_TEMPORARY, indx, size); +} + + +/** + * Allocate storage info for an IR node (n->Store). + * We may do any of the following: + * 1. Compute Store->File/Index for program inputs/outputs/uniforms/etc. + * 2. Allocate storage for user-declared variables. + * 3. Allocate intermediate/unnamed storage for complex expressions. + * 4. other? + * + * If gc or prog is NULL, we may only be able to determine the Store->File + * but not an Index (register). + */ +void +slang_resolve_storage(slang_gen_context *gc, slang_ir_node *n, + struct gl_program *prog) +{ + int k = 0; + if (!n->Store) { + /**assert(n->Var);**/ + if (n->Var && n->Var->aux) { + /* node storage info = var storage info */ + n->Store = (slang_ir_storage *) n->Var->aux; + } + else { + /* alloc new storage info */ + n->Store = _slang_new_ir_storage(PROGRAM_UNDEFINED, -1, -5); + k = 1; + /*XXX n->Store->Size = sizeof(var's type) */ + if (n->Var) + n->Var->aux = n->Store; + } + } + + if (n->Opcode == IR_VAR_DECL) { + /* allocate storage for a user's variable */ + assert(n->Var); + if (n->Store->Index < 0) { + assert(gc); + n->Store->File = PROGRAM_TEMPORARY; + n->Store->Index = alloc_temporary(gc); + n->Store->Size = sizeof_type(&n->Var->type); + printf("alloc var %s storage at %d (size %d)\n", + (char *) n->Var->a_name, + n->Store->Index, + n->Store->Size); + assert(n->Store->Size > 0); + n->Var->declared = GL_TRUE; + } + return; + } + + if (n->Opcode == IR_VAR && n->Store->File == PROGRAM_UNDEFINED) { + /* try to determine the storage for this variable */ + GLint i; + + assert(n->Var); + assert(prog); + +#if 0 + assert(n->Var->declared || + n->Var->type.qualifier == slang_qual_uniform || + n->Var->type.qualifier == slang_qual_varying || + n->Var->type.qualifier == slang_qual_fixedoutput || + n->Var->type.qualifier == slang_qual_attribute || + n->Var->type.qualifier == slang_qual_out || + n->Var->type.qualifier == slang_qual_const); +#endif + + i = slang_find_input(prog->Target, (char *) n->Var->a_name, 0); + if (i >= 0) { + n->Store->File = PROGRAM_INPUT; + n->Store->Index = i; + n->Store->Size = sizeof_type(&n->Var->type); + assert(n->Store->Size > 0); + prog->InputsRead |= (1 << i); + return; + } + + i = slang_find_output(prog->Target, (char *) n->Var->a_name, 0); + if (i >= 0) { + n->Store->File = PROGRAM_OUTPUT; + n->Store->Index = i; + n->Store->Size = sizeof_type(&n->Var->type); + prog->OutputsWritten |= (1 << i); + return; + } + + i = slang_lookup_statevar((char *) n->Var->a_name, 0, prog->Parameters); + if (i >= 0) { + n->Store->File = PROGRAM_STATE_VAR; + n->Store->Index = i; + n->Store->Size = sizeof_type(&n->Var->type); + return; + } + + i = slang_lookup_constant((char *) n->Var->a_name, 0, prog->Parameters); + if (i >= 0) { + n->Store->File = PROGRAM_CONSTANT; + n->Store->Index = i; + n->Store->Size = sizeof_type(&n->Var->type); + return; + } + + /* probably a uniform or varying */ + if (n->Var->type.qualifier == slang_qual_uniform) { + i = slang_alloc_uniform(prog, (char *) n->Var->a_name); + if (i >= 0) { + n->Store->File = PROGRAM_UNIFORM; + n->Store->Index = i; + n->Store->Size = sizeof_type(&n->Var->type); + return; + } + } + else if (n->Var->type.qualifier == slang_qual_varying) { + i = slang_alloc_varying(prog, (char *) n->Var->a_name); + if (i >= 0) { + if (prog->Target == GL_VERTEX_PROGRAM_ARB) + n->Store->File = PROGRAM_OUTPUT; + else + n->Store->File = PROGRAM_INPUT; + n->Store->Size = sizeof_type(&n->Var->type); + n->Store->Index = i; + return; + } + } + + /* what is this?!? */ + /* + abort(); + */ + } + + if (n->Store->File == PROGRAM_TEMPORARY && n->Store->Index < 0) { + /* unnamed intermediate temporary */ + if (gc) + n->Store->Index = alloc_temporary(gc); + return; + } + + if (gc && n->Store->File == PROGRAM_UNDEFINED && n->Store->Size < 0) { + abort(); + } +} + + +static slang_ir_storage * +alloc_constant(const GLfloat v[], GLuint size, struct gl_program *prog) +{ + GLuint swizzle; + GLint ind = _mesa_add_unnamed_constant(prog->Parameters, v, size, &swizzle); + slang_ir_storage *st = _slang_new_ir_storage(PROGRAM_CONSTANT, ind, size); + return st; +} + + +/** + * Swizzle a swizzle. + */ +static GLuint +swizzle_compose(GLuint swz1, GLuint swz2) +{ + GLuint i, swz, s[4]; + for (i = 0; i < 4; i++) { + GLuint c = GET_SWZ(swz1, i); + s[i] = GET_SWZ(swz2, c); + } + swz = MAKE_SWIZZLE4(s[0], s[1], s[2], s[3]); + return swz; +} + + +/** + * Convert IR storage to an instruction dst register. + */ +static void +storage_to_dst_reg(struct prog_dst_register *dst, const slang_ir_storage *st, + GLuint writemask) +{ + static const GLuint defaultWritemask[4] = { + WRITEMASK_X, + WRITEMASK_X | WRITEMASK_Y, + WRITEMASK_X | WRITEMASK_Y | WRITEMASK_Z, + WRITEMASK_X | WRITEMASK_Y | WRITEMASK_Z | WRITEMASK_W + }; + dst->File = st->File; + dst->Index = st->Index; + assert(st->Size >= 1); + assert(st->Size <= 4); + dst->WriteMask = defaultWritemask[st->Size - 1] & writemask; +} + + +/** + * Convert IR storage to an instruction src register. + */ +static void +storage_to_src_reg(struct prog_src_register *src, const slang_ir_storage *st, + GLuint swizzle) +{ + static const GLuint defaultSwizzle[4] = { + MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_X, SWIZZLE_X, SWIZZLE_X), + MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_W), + MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_W), + MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_W) + }; + + src->File = st->File; + src->Index = st->Index; + assert(st->Size >= 1); + assert(st->Size <= 4); + /* XXX swizzling logic here may need some work */ + /*src->Swizzle = swizzle_compose(swizzle, defaultSwizzle[st->Size - 1]);*/ + if (swizzle != SWIZZLE_NOOP) + src->Swizzle = swizzle; + else + src->Swizzle = defaultSwizzle[st->Size - 1]; +} + + + +/** + * Add new instruction at end of given program. + * \param prog the program to append instruction onto + * \param opcode opcode for the new instruction + * \return pointer to the new instruction + */ +static struct prog_instruction * +new_instruction(struct gl_program *prog, gl_inst_opcode opcode) +{ + struct prog_instruction *inst; + prog->Instructions = _mesa_realloc_instructions(prog->Instructions, + prog->NumInstructions, + prog->NumInstructions + 1); + inst = prog->Instructions + prog->NumInstructions; + prog->NumInstructions++; + _mesa_init_instructions(inst, 1); + inst->Opcode = opcode; + return inst; +} + + +static struct prog_instruction * +gen(slang_gen_context *gc, slang_ir_node *n, struct gl_program *prog); + + +/** + * Generate code for a simple binary-op instruction. + */ +static struct prog_instruction * +gen_binop(slang_gen_context *gc, slang_ir_node *n, struct gl_program *prog) +{ + struct prog_instruction *inst; + const slang_ir_info *info = slang_find_ir_info(n->Opcode); + assert(info); + + gen(gc, n->Children[0], prog); + gen(gc, n->Children[1], prog); + inst = new_instruction(prog, info->InstOpcode); + /* alloc temp storage for the result: */ + if (!n->Store || n->Store->File == PROGRAM_UNDEFINED) { +#if 1 + slang_alloc_temp_storage(gc, n, info->ResultSize); +#else + slang_resolve_storage(gc, n, prog); +#endif + } + storage_to_dst_reg(&inst->DstReg, n->Store, n->Writemask); + storage_to_src_reg(&inst->SrcReg[0], n->Children[0]->Store, + n->Children[0]->Swizzle); + storage_to_src_reg(&inst->SrcReg[1], n->Children[1]->Store, + n->Children[1]->Swizzle); + inst->Comment = n->Comment; + return inst; +} + + +static struct prog_instruction * +gen_unop(slang_gen_context *gc, slang_ir_node *n, struct gl_program *prog) +{ + struct prog_instruction *inst; + const slang_ir_info *info = slang_find_ir_info(n->Opcode); + assert(info); + + assert(info->NumParams == 1); + + gen(gc, n->Children[0], prog); + + inst = new_instruction(prog, info->InstOpcode); + /*slang_resolve_storage(gc, n, prog);*/ + + if (!n->Store) + slang_alloc_temp_storage(gc, n, info->ResultSize); + + storage_to_dst_reg(&inst->DstReg, n->Store, n->Writemask); + + storage_to_src_reg(&inst->SrcReg[0], n->Children[0]->Store, + n->Children[0]->Swizzle); + + inst->Comment = n->Comment; + + return inst; +} + + +static struct prog_instruction * +gen(slang_gen_context *gc, slang_ir_node *n, struct gl_program *prog) +{ + struct prog_instruction *inst; + if (!n) + return NULL; + + switch (n->Opcode) { + case IR_SEQ: + assert(n->Children[0]); + assert(n->Children[1]); + gen(gc, n->Children[0], prog); + inst = gen(gc, n->Children[1], prog); + n->Store = n->Children[1]->Store; + return inst; + break; + case IR_VAR_DECL: + slang_resolve_storage(gc, n, prog); + assert(n->Store->Index >= 0); + assert(n->Store->Size > 0); + break; + case IR_VAR: + /*printf("Gen: var ref\n");*/ + { + int b = !n->Store || n->Store->Index < 0; + if (b) + slang_resolve_storage(gc, n, prog); + /*assert(n->Store->Index >= 0);*/ + assert(n->Store->Size > 0); + } + break; + case IR_MOVE: + /* rhs */ + assert(n->Children[1]); + inst = gen(gc, n->Children[1], prog); + /* lhs */ + gen(gc, n->Children[0], prog); + +#if 1 + if (inst && is_temporary(gc, n->Children[1]->Store)) { + /* Peephole optimization: + * Just modify the RHS to put its result into the dest of this + * MOVE operation. Then, this MOVE is a no-op. + */ + free_temporary(gc, n->Children[1]->Store->Index); + *n->Children[1]->Store = *n->Children[0]->Store; + /* fixup the prev (RHS) instruction */ + storage_to_dst_reg(&inst->DstReg, n->Children[0]->Store, n->Writemask); + return inst; + } + else +#endif + { + inst = new_instruction(prog, OPCODE_MOV); + storage_to_dst_reg(&inst->DstReg, n->Children[0]->Store, n->Writemask); + storage_to_src_reg(&inst->SrcReg[0], n->Children[1]->Store, + n->Children[1]->Swizzle); + if (n->Children[1]->Store->File == PROGRAM_TEMPORARY) { + free_temporary(gc, n->Children[1]->Store->Index); + } + inst->Comment = n->Comment; + n->Store = n->Children[0]->Store; /*XXX new */ + return inst; + } + break; + case IR_ADD: + case IR_SUB: + case IR_MUL: + case IR_DOT4: + case IR_DOT3: + case IR_CROSS: + case IR_MIN: + case IR_MAX: + case IR_SEQUAL: + case IR_SNEQUAL: + case IR_SGE: + case IR_SGT: + case IR_POW: + case IR_EXP: + case IR_EXP2: + return gen_binop(gc, n, prog); + break; + case IR_RSQ: + case IR_RCP: + case IR_FLOOR: + case IR_FRAC: + case IR_ABS: + case IR_SIN: + case IR_COS: + return gen_unop(gc, n, prog); + break; + case IR_LABEL: + /*printf("LAB: %s\n", n->Target);*/ + break; + case IR_JUMP: +#if 0 + inst = new_instruction(prog, OPCODE_BRA); + inst->Comment = _mesa_strdup(n->Target); +#endif + break; + case IR_FLOAT: + n->Store = alloc_constant(n->Value, 4, prog); /*XXX fix size */ + break; + default: + printf("gen: ?\n"); + abort(); + } + return NULL; +} + + + +GLboolean +_slang_emit_code(slang_ir_node *n, struct gl_program *prog) +{ + slang_gen_context *gc; + /*GET_CURRENT_CONTEXT(ctx);*/ + + gc = (slang_gen_context *) _mesa_calloc(sizeof(*gc)); + + printf("************ Begin generate code\n"); + + gen(gc, n, prog); + + { + struct prog_instruction *inst; + inst = new_instruction(prog, OPCODE_END); + } + + printf("************ End generate code (%u inst):\n", prog->NumInstructions); + +#if 0 + _mesa_print_program(prog); + _mesa_print_program_parameters(ctx,prog); +#endif + + _mesa_free(gc); + + return GL_FALSE; +} diff --git a/src/mesa/shader/slang/slang_emit.h b/src/mesa/shader/slang/slang_emit.h new file mode 100644 index 00000000000..1683542b905 --- /dev/null +++ b/src/mesa/shader/slang/slang_emit.h @@ -0,0 +1,56 @@ +/* + * Mesa 3-D graphics library + * Version: 6.5.3 + * + * Copyright (C) 2005-2007 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. + */ + +#ifndef SLANG_EMIT_H +#define SLANG_EMIT_H + + +#include "imports.h" +#include "slang_compile.h" +#include "slang_ir.h" +#include "mtypes.h" + + +typedef struct { + GLboolean TempUsed[MAX_PROGRAM_TEMPS]; +} slang_gen_context; + + +extern void +slang_print_ir(const slang_ir_node *n, int indent); + + +extern slang_ir_storage * +_slang_new_ir_storage(enum register_file file, GLint index, GLint size); + + +extern void +slang_resolve_storage(slang_gen_context *gc, slang_ir_node *n, + struct gl_program *prog); + +extern GLboolean +_slang_emit_code(slang_ir_node *n, struct gl_program *prog); + + +#endif /* SLANG_EMIT_H */ diff --git a/src/mesa/shader/slang/slang_error.c b/src/mesa/shader/slang/slang_error.c new file mode 100644 index 00000000000..27671631784 --- /dev/null +++ b/src/mesa/shader/slang/slang_error.c @@ -0,0 +1,77 @@ +/* + * Mesa 3-D graphics library + * Version: 6.5.2 + * + * 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. + */ + +#include "imports.h" +#include "slang_error.h" + + +static char ErrorText[10000]; +static char FormattedErrorText[10000]; +static int ErrorPos; + + +void +_slang_reset_error(void) +{ + ErrorText[0] = 0; + ErrorPos = -1; +} + + +/** + * Record an error message, if one hasn't been recorded already. + */ +void +_slang_record_error(const char *msg1, const char *msg2, + GLint pos, const char *file, int line) +{ + /* don't overwrite a previously recorded error */ + if (!ErrorText[0]) { + _mesa_sprintf(ErrorText, "%s %s", msg1, msg2); + ErrorPos = -1; +#ifdef DEBUG + fprintf(stderr, "Mesa shader compile error: %s %s at %d (%s line %d)\n", + msg1, msg2, pos, file, line); +#endif + } +} + + +/** + * Return formatted error text. + */ +const char * +_slang_error_text(void) +{ + /* + * NVIDIA formats errors like this: + * (LINE_NUMBER) : error ERROR_CODE: ERROR_TEXT + * Example: + * (7) : error C1048: invalid character 'P' in swizzle "P" + */ + _mesa_sprintf(FormattedErrorText, + "(%d) : error: %s", ErrorPos, ErrorText); + return FormattedErrorText; +} + diff --git a/src/mesa/shader/slang/slang_error.h b/src/mesa/shader/slang/slang_error.h new file mode 100644 index 00000000000..d35ae83fba0 --- /dev/null +++ b/src/mesa/shader/slang/slang_error.h @@ -0,0 +1,85 @@ +/* + * Mesa 3-D graphics library + * Version: 6.5.2 + * + * 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. + */ + +#ifndef SLANG_ERROR_H +#define SLANG_ERROR_H + + +extern void +_slang_reset_error(void); + + +extern void +_slang_record_error(const char *msg1, const char *msg2, + GLint pos, const char *file, int line); + + +extern const char * +_slang_error_text(void); + + +/** + * Record a compilation error, single string message. + */ +#define RETURN_ERROR(MSG, POS) \ +do { \ + _slang_record_error(MSG, "", POS, __FILE__, __LINE__); \ + return GL_FALSE; \ +} while (0) + + +/** + * Record a compilation error, two-string message. + */ +#define RETURN_ERROR2(MSG1, MSG2, POS) \ +do { \ + _slang_record_error(MSG1, MSG2, POS, __FILE__, __LINE__); \ + return GL_FALSE; \ +} while (0) + + +/** + * Record a nil error. Either a real error message or out of memory should + * have already been recorded. + */ +#define RETURN_NIL() \ +do { \ + _slang_record_error("unknown", "", -1, __FILE__, __LINE__); \ + return GL_FALSE; \ +} while (0) + + +/** + * Used to report an out of memory condition. + */ +#define RETURN_OUT_OF_MEMORY() \ +do { \ + _slang_record_error("Out of memory", "", -1, __FILE__, __LINE__); \ + return GL_FALSE; \ +} while (0) + + + + +#endif /* SLANG_ERROR_H */ diff --git a/src/mesa/shader/slang/slang_execute.c b/src/mesa/shader/slang/slang_execute.c index e469de02075..09401b8910a 100644 --- a/src/mesa/shader/slang/slang_execute.c +++ b/src/mesa/shader/slang/slang_execute.c @@ -392,12 +392,16 @@ _slang_execute2(const slang_assembly_file * file, slang_machine * mach) case slang_asm_int_copy: case slang_asm_bool_copy: /* store top value on stack to memory */ +#if 0 { GLuint address = (stack[mach->sp + a->param[0] / 4]._addr + a->param[1]) / 4; GLfloat value = stack[mach->sp]._float; mach->mem[address]._float = value; } +#else + mach->mem[(stack[mach->sp + a->param[0] / 4]._addr +a->param[1]) / 4]._float = stack[mach->sp]._float; +#endif mach->sp++; break; case slang_asm_float_move: @@ -425,6 +429,10 @@ _slang_execute2(const slang_assembly_file * file, slang_machine * mach) stack[mach->sp + 1]._float += stack[mach->sp]._float; mach->sp++; break; + case slang_asm_float_subtract: + stack[mach->sp + 1]._float -= stack[mach->sp]._float; + mach->sp++; + break; case slang_asm_float_multiply: stack[mach->sp + 1]._float *= stack[mach->sp]._float; mach->sp++; @@ -476,12 +484,14 @@ _slang_execute2(const slang_assembly_file * file, slang_machine * mach) case slang_asm_float_log2: stack[mach->sp]._float = LOG2(stack[mach->sp]._float); break; +#if 0 case slang_asm_float_floor: stack[mach->sp]._float = FLOORF(stack[mach->sp]._float); break; case slang_asm_float_ceil: stack[mach->sp]._float = CEILF(stack[mach->sp]._float); break; +#endif case slang_asm_float_noise1: stack[mach->sp]._float = _slang_library_noise1(stack[mach->sp]._float); @@ -718,6 +728,7 @@ _slang_execute2(const slang_assembly_file * file, slang_machine * mach) -mach->mem[(da + 12) / 4]._float; } break; +#if 0 case slang_asm_vec4_dot: /* [vec4] | vec4 > [float] */ { @@ -730,6 +741,7 @@ _slang_execute2(const slang_assembly_file * file, slang_machine * mach) mach->sp += 4; } break; +#endif case slang_asm_vec4_copy: /* [vec4] | vec4 > [vec4] */ { @@ -768,6 +780,19 @@ _slang_execute2(const slang_assembly_file * file, slang_machine * mach) } } break; + case slang_asm_vec4_dot: + case slang_asm_vec3_dot: + { + /* XXX almost certainly wrong */ + GLuint da = stack[mach->sp + 4]._addr; + mach->mem[da / 4]._float = + mach->mem[da / 4]._float * stack[mach->sp]._float + + mach->mem[(da + 4) / 4]._float * stack[mach->sp + 1]._float + + mach->mem[(da + 8) / 4]._float * stack[mach->sp + 2]._float + + mach->mem[(da + 12) / 4]._float * stack[mach->sp + 3]._float; + mach->sp += 4; + } + break; default: _mesa_problem(NULL, "bad slang opcode 0x%x", a->type); return GL_FALSE; diff --git a/src/mesa/shader/slang/slang_ir.h b/src/mesa/shader/slang/slang_ir.h new file mode 100644 index 00000000000..3c583365d8d --- /dev/null +++ b/src/mesa/shader/slang/slang_ir.h @@ -0,0 +1,115 @@ +/* + * Mesa 3-D graphics library + * Version: 6.5.3 + * + * Copyright (C) 2005-2007 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_ir.h + * Mesa GLSL Itermediate Representation tree types and constants. + * \author Brian Paul + */ + + +#ifndef SLANG_IR_H +#define SLANG_IR_H + + +#include "imports.h" +#include "slang_compile.h" +#include "mtypes.h" + + +/** + * Intermediate Representation opcode + */ +typedef enum +{ + IR_NOP = 0, + IR_SEQ, + IR_LABEL, /* target of a jump or cjump */ + IR_JUMP, /* unconditional jump */ + IR_CJUMP, /* conditional jump */ + IR_CALL, + IR_MOVE, + IR_ADD, + IR_SUB, + IR_MUL, + IR_DIV, + IR_DOT4, + IR_DOT3, + IR_CROSS, + IR_MIN, + IR_MAX, + IR_SEQUAL, + IR_SNEQUAL, + IR_SGE, + IR_SGT, + IR_POW, + IR_EXP, + IR_EXP2, + IR_LOG2, + IR_RSQ, + IR_RCP, + IR_FLOOR, + IR_FRAC, + IR_ABS, + IR_SIN, + IR_COS, + IR_LESS, + IR_NOT, + IR_VAR, + IR_VAR_DECL, + IR_FLOAT, + IR_FIELD, + IR_I_TO_F +} slang_ir_opcode; + + +/** + * Describes where data storage is allocated. + */ +typedef struct +{ + enum register_file File; /**< PROGRAM_TEMPORARY, PROGRAM_INPUT, etc */ + GLint Index; /**< -1 means unallocated */ + GLint Size; /**< number of floats */ +} slang_ir_storage; + + +/** + * Intermediate Representation (IR) tree node + */ +typedef struct slang_ir_node_ +{ + slang_ir_opcode Opcode; + struct slang_ir_node_ *Children[2]; + const char *Comment; + const char *Target; + GLuint Swizzle; + GLuint Writemask; /**< If Op == IR_MOVE */ + GLfloat Value[4]; /**< If Op == IR_FLOAT */ + slang_variable *Var; + slang_ir_storage *Store; +} slang_ir_node; + + +#endif /* SLANG_IR_H */ diff --git a/src/mesa/shader/slang/slang_link.h b/src/mesa/shader/slang/slang_link.h index 433964223a5..af45c6657e4 100644 --- a/src/mesa/shader/slang/slang_link.h +++ b/src/mesa/shader/slang/slang_link.h @@ -316,6 +316,9 @@ enum SLANG_COMMON_CODE_MAX }; +/** + * XXX promote this to mtypes.h? + */ typedef struct { slang_active_variables active_uniforms; @@ -345,6 +348,11 @@ _slang_program_rst (slang_program *); extern GLboolean _slang_link (slang_program *, slang_code_object **, GLuint); + +extern void +_slang_link2(GLcontext *ctx, GLhandleARB h, + struct gl_linked_program *linked); + #ifdef __cplusplus } #endif diff --git a/src/mesa/shader/slang/slang_link2.c b/src/mesa/shader/slang/slang_link2.c new file mode 100644 index 00000000000..e62cc01b3e1 --- /dev/null +++ b/src/mesa/shader/slang/slang_link2.c @@ -0,0 +1,226 @@ +/* + * Mesa 3-D graphics library + * Version: 6.6 + * + * Copyright (C) 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_link.c + * slang linker + * \author Michal Krol + */ + +#include "imports.h" +#include "context.h" +#include "hash.h" +#include "macros.h" +#include "program.h" +#include "shaderobjects.h" +#include "slang_link.h" + + + + +#define RELEASE_GENERIC(x)\ + (**x)._unknown.Release ((struct gl2_unknown_intf **) (x)) + +#define RELEASE_CONTAINER(x)\ + (**x)._generic._unknown.Release ((struct gl2_unknown_intf **) (x)) + +#define RELEASE_PROGRAM(x)\ + (**x)._container._generic._unknown.Release ((struct gl2_unknown_intf **) (x)) + +#define RELEASE_SHADER(x)\ + (**x)._generic._unknown.Release ((struct gl2_unknown_intf **) (x)) + + + +static struct gl2_unknown_intf ** +lookup_handle(GLcontext * ctx, GLhandleARB handle, enum gl2_uiid uiid, + const char *function) +{ + struct gl2_unknown_intf **unk; + + /* + * Note: _mesa_HashLookup() requires non-zero input values, so the + * passed-in handle value must be checked beforehand. + */ + if (handle == 0) { + _mesa_error(ctx, GL_INVALID_VALUE, function); + return NULL; + } + _glthread_LOCK_MUTEX(ctx->Shared->Mutex); + unk = (struct gl2_unknown_intf **) _mesa_HashLookup(ctx->Shared->GL2Objects, + handle); + _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); + + if (unk == NULL) { + _mesa_error(ctx, GL_INVALID_VALUE, function); + } + else { + unk = (**unk).QueryInterface(unk, uiid); + if (unk == NULL) + _mesa_error(ctx, GL_INVALID_OPERATION, function); + } + return unk; +} + +#define GET_GENERIC(x, handle, function)\ + struct gl2_generic_intf **x = (struct gl2_generic_intf **)\ + lookup_handle (ctx, handle, UIID_GENERIC, function); + +#define GET_CONTAINER(x, handle, function)\ + struct gl2_container_intf **x = (struct gl2_container_intf **)\ + lookup_handle (ctx, handle, UIID_CONTAINER, function); + +#define GET_PROGRAM(x, handle, function)\ + struct gl2_program_intf **x = (struct gl2_program_intf **)\ + lookup_handle (ctx, handle, UIID_PROGRAM, function); + +#define GET_SHADER(x, handle, function)\ + struct gl2_shader_intf **x = (struct gl2_shader_intf **)\ + lookup_handle (ctx, handle, UIID_SHADER, function); + + +static void +prelink(GLhandleARB programObj, struct gl_linked_program *linked) +{ + GET_CURRENT_CONTEXT(ctx); + + linked->VertexProgram = NULL; + linked->FragmentProgram = NULL; + + if (programObj != 0) { + GET_PROGRAM(program, programObj, "glUseProgramObjectARB(program)"); + + if (program == NULL) + return; + + /* XXX terrible hack to find the real vertex/fragment programs */ + { + GLuint handle; + GLsizei cnt, i; + cnt = (**program)._container.GetAttachedCount((struct gl2_container_intf **) (program)); + + for (i = 0; i < cnt; i++) { + struct gl2_generic_intf **x + = (**program)._container.GetAttached((struct gl2_container_intf **) program, i); + handle = (**x).GetName(x); + { + struct gl_program *prog; + GET_SHADER(sha, handle, "foo"); + if (sha && (*sha)->Program) { + prog = (*sha)->Program; + if (prog->Target == GL_VERTEX_PROGRAM_ARB) + linked->VertexProgram = (struct gl_vertex_program *) prog; + else if (prog->Target == GL_FRAGMENT_PROGRAM_ARB) + linked->FragmentProgram = (struct gl_fragment_program *) prog; + } + } +#if 0 + if (linked->VertexProgram) + printf("Found vert prog %p %d\n", + linked->VertexProgram, + linked->VertexProgram->Base.NumInstructions); + if (linked->FragmentProgram) + printf("Found frag prog %p %d\n", + linked->FragmentProgram, + linked->FragmentProgram->Base.NumInstructions); +#endif + RELEASE_GENERIC(x); + } + } + + } +} + + + +void +_slang_link2(GLcontext *ctx, + GLhandleARB programObj, + struct gl_linked_program *linked) +{ + struct gl_vertex_program *vertProg; + struct gl_fragment_program *fragProg; + + prelink(programObj, linked); + + vertProg = linked->VertexProgram; + fragProg = linked->FragmentProgram; + + /* free old linked data, if any */ + if (linked->NumUniforms > 0) { + GLuint i; + for (i = 0; i < linked->NumUniforms; i++) { + _mesa_free((char *) linked->Uniforms[i].Name); + linked->Uniforms[i].Name = NULL; + linked->Uniforms[i].Value = NULL; + } + linked->NumUniforms = 0; + } + + /* + * Find uniforms. + * XXX what about dups? + */ + if (vertProg) { + GLuint i; + for (i = 0; i < vertProg->Base.Parameters->NumParameters; i++) { + struct gl_program_parameter *p + = vertProg->Base.Parameters->Parameters + i; + if (p->Name) { + struct gl_uniform *u = linked->Uniforms + linked->NumUniforms; + u->Name = _mesa_strdup(p->Name); + u->Value = &vertProg->Base.Parameters->ParameterValues[i][0]; + linked->NumUniforms++; + assert(linked->NumUniforms < MAX_UNIFORMS); + } + } + } + if (fragProg) { + GLuint i; + for (i = 0; i < fragProg->Base.Parameters->NumParameters; i++) { + struct gl_program_parameter *p + = fragProg->Base.Parameters->Parameters + i; + if (p->Name) { + struct gl_uniform *u = linked->Uniforms + linked->NumUniforms; + u->Name = _mesa_strdup(p->Name); + u->Value = &fragProg->Base.Parameters->ParameterValues[i][0]; + linked->NumUniforms++; + assert(linked->NumUniforms < MAX_UNIFORMS); + } + } + } + + /* For varying: + * scan both programs for varyings, rewrite programs so they agree + * on locations of varyings. + */ + + /** + * Linking should _copy_ the vertex and fragment shader code, + * rewriting varying references as we go along... + */ + + linked->LinkStatus = (vertProg && fragProg); +} + diff --git a/src/mesa/shader/slang/slang_print.c b/src/mesa/shader/slang/slang_print.c new file mode 100644 index 00000000000..2ac06291bc2 --- /dev/null +++ b/src/mesa/shader/slang/slang_print.c @@ -0,0 +1,1136 @@ + +/** + * Dump/print a slang_operation tree + */ + + +#include "imports.h" +#include "slang_compile.h" +#include "slang_print.h" + + +static void +spaces(int n) +{ + while (n--) + printf(" "); +} + + +static void +print_type(const slang_fully_specified_type *t) +{ + switch (t->qualifier) { + case slang_qual_none: + /*printf("");*/ + break; + case slang_qual_const: + printf("const "); + break; + case slang_qual_attribute: + printf("attrib "); + break; + case slang_qual_varying: + printf("varying "); + break; + case slang_qual_uniform: + printf("uniform "); + break; + case slang_qual_out: + printf("output "); + break; + case slang_qual_inout: + printf("inout "); + break; + case slang_qual_fixedoutput: + printf("fixedoutput"); + break; + case slang_qual_fixedinput: + printf("fixedinput"); + break; + default: + printf("unknown qualifer!"); + } + + switch (t->specifier.type) { + case slang_spec_void: + printf("void"); + break; + case slang_spec_bool: + printf("bool"); + break; + case slang_spec_bvec2: + printf("bvec2"); + break; + case slang_spec_bvec3: + printf("bvec3"); + break; + case slang_spec_bvec4: + printf("bvec4"); + break; + case slang_spec_int: + printf("int"); + break; + case slang_spec_ivec2: + printf("ivec2"); + break; + case slang_spec_ivec3: + printf("ivec3"); + break; + case slang_spec_ivec4: + printf("ivec4"); + break; + case slang_spec_float: + printf("float"); + break; + case slang_spec_vec2: + printf("vec2"); + break; + case slang_spec_vec3: + printf("vec3"); + break; + case slang_spec_vec4: + printf("vec4"); + break; + case slang_spec_mat2: + printf("mat2"); + break; + case slang_spec_mat3: + printf("mat3"); + break; + case slang_spec_mat4: + printf("mat4"); + break; + case slang_spec_sampler1D: + printf("sampler1D"); + break; + case slang_spec_sampler2D: + printf("sampler2D"); + break; + case slang_spec_sampler3D: + printf("sampler3D"); + break; + case slang_spec_samplerCube: + printf("samplerCube"); + break; + case slang_spec_sampler1DShadow: + printf("sampler1DShadow"); + break; + case slang_spec_sampler2DShadow: + printf("sampler2DShadow"); + break; + case slang_spec_struct: + printf("struct"); + break; + case slang_spec_array: + printf("array"); + break; + default: + printf("unknown type"); + } + /*printf("\n");*/ +} + + +static void +print_variable(const slang_variable *v, int indent) +{ + spaces(indent); + printf("VAR "); + print_type(&v->type); + printf(" %s", (char *) v->a_name); + if (v->initializer) { + printf(" :=\n"); + slang_print_tree(v->initializer, indent + 3); + } + else { + printf(";\n"); + } +} + + +static void +print_binary(const slang_operation *op, const char *oper, int indent) +{ + assert(op->num_children == 2); + slang_print_tree(&op->children[0], indent + 3); + spaces(indent); + printf("%s\n", oper); + slang_print_tree(&op->children[1], indent + 3); +} + + +static void +print_generic2(const slang_operation *op, const char *oper, + const char *s, int indent) +{ + int i; + if (oper) { + spaces(indent); + printf("[%p locals %p] %s %s\n", (void*) op, (void*) op->locals, oper, s); + } + for (i = 0; i < op->num_children; i++) { + spaces(indent); + printf("//child %d:\n", i); + slang_print_tree(&op->children[i], indent); + } +} + +static void +print_generic(const slang_operation *op, const char *oper, int indent) +{ + print_generic2(op, oper, "", indent); +} + + +static const slang_variable_scope * +find_scope(const slang_variable_scope *s, slang_atom name) +{ + GLuint i; + for (i = 0; i < s->num_variables; i++) { + if (s->variables[i].a_name == name) + return s; + } + if (s->outer_scope) + return find_scope(s->outer_scope, name); + else + return NULL; +} + +static const slang_variable * +find_var(const slang_variable_scope *s, slang_atom name) +{ + GLuint i; + for (i = 0; i < s->num_variables; i++) { + if (s->variables[i].a_name == name) + return &s->variables[i]; + } + if (s->outer_scope) + return find_var(s->outer_scope, name); + else + return NULL; +} + + +void +slang_print_tree(const slang_operation *op, int indent) +{ + int i; + + switch (op->type) { + + case slang_oper_none: + spaces(indent); + printf("slang_oper_none\n"); + break; + + case slang_oper_block_no_new_scope: + spaces(indent); + printf("{ locals %p\n", (void*)op->locals); + print_generic(op, NULL, indent+3); + spaces(indent); + printf("}\n"); + break; + + case slang_oper_block_new_scope: + spaces(indent); + printf("{{ // new scope locals %p\n", (void*)op->locals); + print_generic(op, NULL, indent+3); + spaces(indent); + printf("}}\n"); + break; + + case slang_oper_variable_decl: + assert(op->num_children == 0 || op->num_children == 1); + { + slang_variable *v; + v = _slang_locate_variable(op->locals, op->a_id, GL_TRUE); + if (v) { + spaces(indent); + printf("DECL (locals=%p outer=%p) ", (void*)op->locals, (void*) op->locals->outer_scope); + print_type(&v->type); + printf(" %s (%p)", (char *) op->a_id, + (void *) find_var(op->locals, op->a_id)); + + printf(" (in scope %p) ", + (void *) find_scope(op->locals, op->a_id)); + if (op->num_children == 1) { + printf(" :=\n"); + slang_print_tree(&op->children[0], indent + 3); + } + else if (v->initializer) { + printf(" := INITIALIZER\n"); + slang_print_tree(v->initializer, indent + 3); + } + else { + printf(";\n"); + } + /* + spaces(indent); + printf("TYPE: "); + print_type(&v->type); + spaces(indent); + printf("ADDR: %d size: %d\n", v->address, v->size); + */ + } + else { + abort(); + spaces(indent); + printf("DECL %s (anonymous variable!!!!)\n", (char *) op->a_id); + /*abort();*/ + } + } + break; + + case slang_oper_asm: + spaces(indent); + printf("ASM: %s\n", (char*) op->a_id); + print_generic(op, NULL, indent+3); + break; + + case slang_oper_break: + spaces(indent); + printf("BREAK\n"); + break; + + case slang_oper_continue: + spaces(indent); + printf("CONTINUE\n"); + break; + + case slang_oper_discard: + spaces(indent); + printf("DISCARD\n"); + break; + + case slang_oper_return: + spaces(indent); + printf("RETURN\n"); + if (op->num_children > 0) + slang_print_tree(&op->children[0], indent + 3); + break; + + case slang_oper_goto: + spaces(indent); + printf("GOTO %s\n", (char *) op->a_id); + break; + + case slang_oper_label: + spaces(indent); + printf("LABEL %s\n", (char *) op->a_id); + break; + + case slang_oper_expression: + spaces(indent); + printf("EXPR: locals %p\n", (void*) op->locals); + /*print_generic(op, "slang_oper_expression", indent);*/ + slang_print_tree(&op->children[0], indent + 3); + break; + + case slang_oper_if: + spaces(indent); + printf("IF\n"); + slang_print_tree(&op->children[0], indent + 3); + spaces(indent); + printf("THEN\n"); + slang_print_tree(&op->children[1], indent + 3); + spaces(indent); + printf("ELSE\n"); + slang_print_tree(&op->children[2], indent + 3); + spaces(indent); + printf("ENDIF\n"); + break; + + case slang_oper_while: + assert(op->num_children == 2); + spaces(indent); + printf("WHILE cond:\n"); + slang_print_tree(&op->children[0], indent + 3); + spaces(indent); + printf("WHILE body:\n"); + slang_print_tree(&op->children[1], indent + 3); + break; + + case slang_oper_do: + spaces(indent); + printf("DO body:\n"); + slang_print_tree(&op->children[0], indent + 3); + spaces(indent); + printf("DO cond:\n"); + slang_print_tree(&op->children[1], indent + 3); + break; + + case slang_oper_for: + spaces(indent); + printf("FOR init:\n"); + slang_print_tree(&op->children[0], indent + 3); + spaces(indent); + printf("FOR while:\n"); + slang_print_tree(&op->children[1], indent + 3); + spaces(indent); + printf("FOR step:\n"); + slang_print_tree(&op->children[2], indent + 3); + spaces(indent); + printf("FOR body:\n"); + slang_print_tree(&op->children[3], indent + 3); + spaces(indent); + printf("ENDFOR\n"); + /* + print_generic(op, "FOR", indent + 3); + */ + break; + + case slang_oper_void: + spaces(indent); + printf("(oper-void)\n"); + break; + + case slang_oper_literal_bool: + spaces(indent); + /*printf("slang_oper_literal_bool\n");*/ + printf("%s\n", op->literal[0] ? "TRUE" : "FALSE"); + break; + + case slang_oper_literal_int: + spaces(indent); + /*printf("slang_oper_literal_int\n");*/ + printf("(%d %d %d %d)\n", (int) op->literal[0], (int) op->literal[1], + (int) op->literal[2], (int) op->literal[3]); + break; + + case slang_oper_literal_float: + spaces(indent); + /*printf("slang_oper_literal_float\n");*/ + printf("(%f %f %f %f)\n", op->literal[0], op->literal[1], op->literal[2], + op->literal[3]); + break; + + case slang_oper_identifier: + spaces(indent); + if (op->var && op->var->a_name) + printf("VAR %s (in scope %p)\n", (char *) op->var->a_name, + (void *) find_scope(op->locals, op->a_id)); + else + printf("VAR' %s (in scope %p)\n", (char *) op->a_id, + (void *) find_scope(op->locals, op->a_id)); + break; + + case slang_oper_sequence: + print_generic(op, "COMMA-SEQ", indent+3); + break; + + case slang_oper_assign: + spaces(indent); + printf("ASSIGNMENT locals %p\n", (void*)op->locals); + print_binary(op, ":=", indent); + break; + + case slang_oper_addassign: + spaces(indent); + printf("ASSIGN\n"); + print_binary(op, "+=", indent); + break; + + case slang_oper_subassign: + spaces(indent); + printf("ASSIGN\n"); + print_binary(op, "-=", indent); + break; + + case slang_oper_mulassign: + spaces(indent); + printf("ASSIGN\n"); + print_binary(op, "*=", indent); + break; + + case slang_oper_divassign: + spaces(indent); + printf("ASSIGN\n"); + print_binary(op, "/=", indent); + break; + + /*slang_oper_modassign,*/ + /*slang_oper_lshassign,*/ + /*slang_oper_rshassign,*/ + /*slang_oper_orassign,*/ + /*slang_oper_xorassign,*/ + /*slang_oper_andassign,*/ + case slang_oper_select: + spaces(indent); + printf("slang_oper_select n=%d\n", op->num_children); + assert(op->num_children == 3); + slang_print_tree(&op->children[0], indent+3); + spaces(indent); + printf("?\n"); + slang_print_tree(&op->children[1], indent+3); + spaces(indent); + printf(":\n"); + slang_print_tree(&op->children[2], indent+3); + break; + + case slang_oper_logicalor: + print_binary(op, "||", indent); + break; + + case slang_oper_logicalxor: + print_binary(op, "^^", indent); + break; + + case slang_oper_logicaland: + print_binary(op, "&&", indent); + break; + + /*slang_oper_bitor*/ + /*slang_oper_bitxor*/ + /*slang_oper_bitand*/ + case slang_oper_equal: + print_binary(op, "==", indent); + break; + + case slang_oper_notequal: + print_binary(op, "!=", indent); + break; + + case slang_oper_less: + print_binary(op, "<", indent); + break; + + case slang_oper_greater: + print_binary(op, ">", indent); + break; + + case slang_oper_lessequal: + print_binary(op, "<=", indent); + break; + + case slang_oper_greaterequal: + print_binary(op, ">=", indent); + break; + + /*slang_oper_lshift*/ + /*slang_oper_rshift*/ + case slang_oper_add: + print_binary(op, "+", indent); + break; + + case slang_oper_subtract: + print_binary(op, "-", indent); + break; + + case slang_oper_multiply: + print_binary(op, "*", indent); + break; + + case slang_oper_divide: + print_binary(op, "/", indent); + break; + + /*slang_oper_modulus*/ + case slang_oper_preincrement: + spaces(indent); + printf("PRE++\n"); + slang_print_tree(&op->children[0], indent+3); + break; + + case slang_oper_predecrement: + spaces(indent); + printf("PRE--\n"); + slang_print_tree(&op->children[0], indent+3); + break; + + case slang_oper_plus: + spaces(indent); + printf("slang_oper_plus\n"); + break; + + case slang_oper_minus: + spaces(indent); + printf("slang_oper_minus\n"); + break; + + /*slang_oper_complement*/ + case slang_oper_not: + spaces(indent); + printf("NOT\n"); + slang_print_tree(&op->children[0], indent+3); + break; + + case slang_oper_subscript: + spaces(indent); + printf("slang_oper_subscript\n"); + print_generic(op, NULL, indent+3); + break; + + case slang_oper_call: +#if 0 + slang_function *fun + = _slang_locate_function(A->space.funcs, oper->a_id, + oper->children, + oper->num_children, &A->space, A->atoms); +#endif + spaces(indent); + printf("CALL %s(\n", (char *) op->a_id); + for (i = 0; i < op->num_children; i++) { + slang_print_tree(&op->children[i], indent+3); + if (i + 1 < op->num_children) { + spaces(indent + 3); + printf(",\n"); + } + } + spaces(indent); + printf(")\n"); + break; + + case slang_oper_field: + spaces(indent); + printf("FIELD %s of\n", (char*) op->a_id); + slang_print_tree(&op->children[0], indent+3); + break; + + case slang_oper_postincrement: + spaces(indent); + printf("POST++\n"); + slang_print_tree(&op->children[0], indent+3); + break; + + case slang_oper_postdecrement: + spaces(indent); + printf("POST--\n"); + slang_print_tree(&op->children[0], indent+3); + break; + + default: + printf("unknown op->type %d\n", (int) op->type); + } + +} + + + +void +slang_print_function(const slang_function *f, GLboolean body) +{ + int i; + +#if 0 + if (_mesa_strcmp((char *) f->header.a_name, "main") != 0) + return; +#endif + + printf("FUNCTION %s (\n", + (char *) f->header.a_name); + + for (i = 0; i < f->param_count; i++) { + print_variable(&f->parameters->variables[i], 3); + } + + printf(")\n"); + if (body && f->body) + slang_print_tree(f->body, 0); +} + + + + +/* operation */ +#define OP_END 0 +#define OP_BLOCK_BEGIN_NO_NEW_SCOPE 1 +#define OP_BLOCK_BEGIN_NEW_SCOPE 2 +#define OP_DECLARE 3 +#define OP_ASM 4 +#define OP_BREAK 5 +#define OP_CONTINUE 6 +#define OP_DISCARD 7 +#define OP_RETURN 8 +#define OP_EXPRESSION 9 +#define OP_IF 10 +#define OP_WHILE 11 +#define OP_DO 12 +#define OP_FOR 13 +#define OP_PUSH_VOID 14 +#define OP_PUSH_BOOL 15 +#define OP_PUSH_INT 16 +#define OP_PUSH_FLOAT 17 +#define OP_PUSH_IDENTIFIER 18 +#define OP_SEQUENCE 19 +#define OP_ASSIGN 20 +#define OP_ADDASSIGN 21 +#define OP_SUBASSIGN 22 +#define OP_MULASSIGN 23 +#define OP_DIVASSIGN 24 +/*#define OP_MODASSIGN 25*/ +/*#define OP_LSHASSIGN 26*/ +/*#define OP_RSHASSIGN 27*/ +/*#define OP_ORASSIGN 28*/ +/*#define OP_XORASSIGN 29*/ +/*#define OP_ANDASSIGN 30*/ +#define OP_SELECT 31 +#define OP_LOGICALOR 32 +#define OP_LOGICALXOR 33 +#define OP_LOGICALAND 34 +/*#define OP_BITOR 35*/ +/*#define OP_BITXOR 36*/ +/*#define OP_BITAND 37*/ +#define OP_EQUAL 38 +#define OP_NOTEQUAL 39 +#define OP_LESS 40 +#define OP_GREATER 41 +#define OP_LESSEQUAL 42 +#define OP_GREATEREQUAL 43 +/*#define OP_LSHIFT 44*/ +/*#define OP_RSHIFT 45*/ +#define OP_ADD 46 +#define OP_SUBTRACT 47 +#define OP_MULTIPLY 48 +#define OP_DIVIDE 49 +/*#define OP_MODULUS 50*/ +#define OP_PREINCREMENT 51 +#define OP_PREDECREMENT 52 +#define OP_PLUS 53 +#define OP_MINUS 54 +/*#define OP_COMPLEMENT 55*/ +#define OP_NOT 56 +#define OP_SUBSCRIPT 57 +#define OP_CALL 58 +#define OP_FIELD 59 +#define OP_POSTINCREMENT 60 +#define OP_POSTDECREMENT 61 + + +void +slang_print_opcode(unsigned int opcode) +{ + switch (opcode) { + case OP_PUSH_VOID: + printf("OP_PUSH_VOID\n"); + break; + case OP_PUSH_BOOL: + printf("OP_PUSH_BOOL\n"); + break; + case OP_PUSH_INT: + printf("OP_PUSH_INT\n"); + break; + case OP_PUSH_FLOAT: + printf("OP_PUSH_FLOAT\n"); + break; + case OP_PUSH_IDENTIFIER: + printf("OP_PUSH_IDENTIFIER\n"); + break; + case OP_SEQUENCE: + printf("OP_SEQUENCE\n"); + break; + case OP_ASSIGN: + printf("OP_ASSIGN\n"); + break; + case OP_ADDASSIGN: + printf("OP_ADDASSIGN\n"); + break; + case OP_SUBASSIGN: + printf("OP_SUBASSIGN\n"); + break; + case OP_MULASSIGN: + printf("OP_MULASSIGN\n"); + break; + case OP_DIVASSIGN: + printf("OP_DIVASSIGN\n"); + break; + /*case OP_MODASSIGN:*/ + /*case OP_LSHASSIGN:*/ + /*case OP_RSHASSIGN:*/ + /*case OP_ORASSIGN:*/ + /*case OP_XORASSIGN:*/ + /*case OP_ANDASSIGN:*/ + case OP_SELECT: + printf("OP_SELECT\n"); + break; + case OP_LOGICALOR: + printf("OP_LOGICALOR\n"); + break; + case OP_LOGICALXOR: + printf("OP_LOGICALXOR\n"); + break; + case OP_LOGICALAND: + printf("OP_LOGICALAND\n"); + break; + /*case OP_BITOR:*/ + /*case OP_BITXOR:*/ + /*case OP_BITAND:*/ + case OP_EQUAL: + printf("OP_EQUAL\n"); + break; + case OP_NOTEQUAL: + printf("OP_NOTEQUAL\n"); + break; + case OP_LESS: + printf("OP_LESS\n"); + break; + case OP_GREATER: + printf("OP_GREATER\n"); + break; + case OP_LESSEQUAL: + printf("OP_LESSEQUAL\n"); + break; + case OP_GREATEREQUAL: + printf("OP_GREATEREQUAL\n"); + break; + /*case OP_LSHIFT:*/ + /*case OP_RSHIFT:*/ + case OP_ADD: + printf("OP_ADD\n"); + break; + case OP_SUBTRACT: + printf("OP_SUBTRACT\n"); + break; + case OP_MULTIPLY: + printf("OP_MULTIPLY\n"); + break; + case OP_DIVIDE: + printf("OP_DIVIDE\n"); + break; + /*case OP_MODULUS:*/ + case OP_PREINCREMENT: + printf("OP_PREINCREMENT\n"); + break; + case OP_PREDECREMENT: + printf("OP_PREDECREMENT\n"); + break; + case OP_PLUS: + printf("OP_PLUS\n"); + break; + case OP_MINUS: + printf("OP_MINUS\n"); + break; + case OP_NOT: + printf("OP_NOT\n"); + break; + /*case OP_COMPLEMENT:*/ + case OP_SUBSCRIPT: + printf("OP_SUBSCRIPT\n"); + break; + case OP_CALL: + printf("OP_CALL\n"); + break; + case OP_FIELD: + printf("OP_FIELD\n"); + break; + case OP_POSTINCREMENT: + printf("OP_POSTINCREMENT\n"); + break; + case OP_POSTDECREMENT: + printf("OP_POSTDECREMENT\n"); + break; + default: + printf("UNKNOWN OP %d\n", opcode); + } +} + + + +const char * +slang_asm_string(slang_assembly_type t) +{ + switch (t) { + /* core */ + case slang_asm_none: + return "none"; + case slang_asm_float_copy: + return "float_copy"; + case slang_asm_float_move: + return "float_move"; + case slang_asm_float_push: + return "float_push"; + case slang_asm_float_deref: + return "float_deref"; + case slang_asm_float_add: + return "float_add"; + case slang_asm_float_multiply: + return "float_multiply"; + case slang_asm_float_divide: + return "float_divide"; + case slang_asm_float_negate: + return "float_negate"; + case slang_asm_float_less: + return "float_less"; + case slang_asm_float_equal_exp: + return "float_equal"; + case slang_asm_float_equal_int: + return "float_equal"; + case slang_asm_float_to_int: + return "float_to_int"; + case slang_asm_float_sine: + return "float_sine"; + case slang_asm_float_arcsine: + return "float_arcsine"; + case slang_asm_float_arctan: + return "float_arctan"; + case slang_asm_float_power: + return "float_power"; + case slang_asm_float_log2: + return "float_log2"; + case slang_asm_vec4_floor: + return "vec4_floor"; + case slang_asm_float_ceil: + return "float_ceil"; + case slang_asm_float_noise1: + return "float_noise1"; + case slang_asm_float_noise2: + return "float_noise2"; + case slang_asm_float_noise3: + return "float_noise3"; + case slang_asm_float_noise4: + return "float_noise4"; + case slang_asm_int_copy: + return "int_copy"; + case slang_asm_int_move: + return "int_move"; + case slang_asm_int_push: + return "int_push"; + case slang_asm_int_deref: + return "int_deref"; + case slang_asm_int_to_float: + return "int_to_float"; + case slang_asm_int_to_addr: + return "int_to_addr"; + case slang_asm_bool_copy: + return "bool_copy"; + case slang_asm_bool_move: + return "bool_move"; + case slang_asm_bool_push: + return "bool_push"; + case slang_asm_bool_deref: + return "bool_deref"; + case slang_asm_addr_copy: + return "addr_copy"; + case slang_asm_addr_push: + return "addr_push"; + case slang_asm_addr_deref: + return "addr_deref"; + case slang_asm_addr_add: + return "addr_add"; + case slang_asm_addr_multiply: + return "addr_multiply"; + case slang_asm_vec4_tex1d: + return "vec4_tex1d"; + case slang_asm_vec4_tex2d: + return "vec4_tex2d"; + case slang_asm_vec4_tex3d: + return "vec4_tex3d"; + case slang_asm_vec4_texcube: + return "vec4_texcube"; + case slang_asm_vec4_shad1d: + return "vec4_shad1d"; + case slang_asm_vec4_shad2d: + return "vec4_shad2d"; + case slang_asm_jump: + return "jump"; + case slang_asm_jump_if_zero: + return "jump_if_zero"; + case slang_asm_enter: + return "enter"; + case slang_asm_leave: + return "leave"; + case slang_asm_local_alloc: + return "local_alloc"; + case slang_asm_local_free: + return "local_free"; + case slang_asm_local_addr: + return "local_addr"; + case slang_asm_global_addr: + return "global_addr"; + case slang_asm_call: + return "call"; + case slang_asm_return: + return "return"; + case slang_asm_discard: + return "discard"; + case slang_asm_exit: + return "exit"; + /* GL_MESA_shader_debug */ + case slang_asm_float_print: + return "float_print"; + case slang_asm_int_print: + return "int_print"; + case slang_asm_bool_print: + return "bool_print"; + /* vec4 */ + case slang_asm_float_to_vec4: + return "float_to_vec4"; + case slang_asm_vec4_add: + return "vec4_add"; + case slang_asm_vec4_subtract: + return "vec4_subtract"; + case slang_asm_vec4_multiply: + return "vec4_multiply"; + case slang_asm_vec4_divide: + return "vec4_divide"; + case slang_asm_vec4_negate: + return "vec4_negate"; + case slang_asm_vec4_dot: + return "vec4_dot"; + case slang_asm_vec4_copy: + return "vec4_copy"; + case slang_asm_vec4_deref: + return "vec4_deref"; + case slang_asm_vec4_equal_int: + return "vec4_equal"; + default: + return "??asm??"; + } +} + + +const char * +slang_type_qual_string(slang_type_qualifier q) +{ + switch (q) { + case slang_qual_none: + return "none"; + case slang_qual_const: + return "const"; + case slang_qual_attribute: + return "attribute"; + case slang_qual_varying: + return "varying"; + case slang_qual_uniform: + return "uniform"; + case slang_qual_out: + return "out"; + case slang_qual_inout: + return "inout"; + case slang_qual_fixedoutput: + return "fixedoutput"; + case slang_qual_fixedinput: + return "fixedinputk"; + default: + return "qual?"; + } +} + + +static const char * +slang_type_string(slang_type_specifier_type t) +{ + switch (t) { + case slang_spec_void: + return "void"; + case slang_spec_bool: + return "bool"; + case slang_spec_bvec2: + return "bvec2"; + case slang_spec_bvec3: + return "bvec3"; + case slang_spec_bvec4: + return "bvec4"; + case slang_spec_int: + return "int"; + case slang_spec_ivec2: + return "ivec2"; + case slang_spec_ivec3: + return "ivec3"; + case slang_spec_ivec4: + return "ivec4"; + case slang_spec_float: + return "float"; + case slang_spec_vec2: + return "vec2"; + case slang_spec_vec3: + return "vec3"; + case slang_spec_vec4: + return "vec4"; + case slang_spec_mat2: + return "mat2"; + case slang_spec_mat3: + return "mat3"; + case slang_spec_mat4: + return "mat4"; + case slang_spec_sampler1D: + return "sampler1D"; + case slang_spec_sampler2D: + return "sampler2D"; + case slang_spec_sampler3D: + return "sampler3D"; + case slang_spec_samplerCube: + return "samplerCube"; + case slang_spec_sampler1DShadow: + return "sampler1DShadow"; + case slang_spec_sampler2DShadow: + return "sampler2DShadow"; + case slang_spec_struct: + return "struct"; + case slang_spec_array: + return "array"; + default: + return "type?"; + } +} + + +static const char * +slang_fq_type_string(const slang_fully_specified_type *t) +{ + static char str[1000]; + sprintf(str, "%s %s", slang_type_qual_string(t->qualifier), + slang_type_string(t->specifier.type)); + return str; +} + + +void +slang_print_type(const slang_fully_specified_type *t) +{ + printf("%s %s", slang_type_qual_string(t->qualifier), + slang_type_string(t->specifier.type)); +} + + +static char * +slang_var_string(const slang_variable *v) +{ + static char str[1000]; + sprintf(str, "%s : %s", + (char *) v->a_name, + slang_fq_type_string(&v->type)); + return str; +} + + +void +slang_print_variable(const slang_variable *v) +{ + printf("Name: %s\n", (char *) v->a_name); + printf("Type: %s\n", slang_fq_type_string(&v->type)); +} + + +void +_slang_print_var_scope(const slang_variable_scope *vars, int indent) +{ + GLuint i; + + spaces(indent); + printf("Var scope %p %d vars\n", (void *) vars, vars->num_variables); + for (i = 0; i < vars->num_variables; i++) { + spaces(indent + 3); + printf("%s\n", (char *) vars->variables[i].a_name); + } + + if (vars->outer_scope) { + spaces(indent + 3); + printf("outer_scope = %p\n", (void*) vars->outer_scope); + _slang_print_var_scope(vars->outer_scope, indent + 3); + } +} + + + +int +slang_checksum_tree(const slang_operation *op) +{ + int s = op->num_children; + int i; + + for (i = 0; i < op->num_children; i++) { + s += slang_checksum_tree(&op->children[i]); + } + return s; +} diff --git a/src/mesa/shader/slang/slang_print.h b/src/mesa/shader/slang/slang_print.h new file mode 100644 index 00000000000..a98607a540f --- /dev/null +++ b/src/mesa/shader/slang/slang_print.h @@ -0,0 +1,38 @@ + + +#ifndef SLANG_PRINT +#define SLANG_PRINT + +extern void +slang_print_function(const slang_function *f, GLboolean body); + +extern void +slang_print_tree(const slang_operation *op, int indent); + + +extern void +slang_print_opcode(unsigned int opcode); + + +extern const char * +slang_asm_string(slang_assembly_type t); + + +extern const char * +slang_type_qual_string(slang_type_qualifier q); + +extern void +slang_print_type(const slang_fully_specified_type *t); + +extern void +slang_print_variable(const slang_variable *v); + +extern void +_slang_print_var_scope(const slang_variable_scope *s, int indent); + + +extern int +slang_checksum_tree(const slang_operation *op); + +#endif /* SLANG_PRINT */ + diff --git a/src/mesa/shader/slang/slang_simplify.c b/src/mesa/shader/slang/slang_simplify.c new file mode 100644 index 00000000000..94e6e1ecc2d --- /dev/null +++ b/src/mesa/shader/slang/slang_simplify.c @@ -0,0 +1,170 @@ +/* + * Mesa 3-D graphics library + * Version: 6.5.2 + * + * 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_typeinfo.c + * slang type info + * \author Michal Krol + */ + +#include "imports.h" +#include "macros.h" +#include "slang_compile.h" +#include "slang_simplify.h" + + +/** + * Recursively traverse an AST tree, applying simplifications wherever + * possible. + * At the least, we do constant folding. We need to do that much so that + * compile-time expressions can be evaluated for things like array + * declarations. I.e.: float foo[3 + 5]; + */ +void +slang_simplify(slang_operation *oper, + const slang_assembly_name_space * space, + slang_atom_pool * atoms) +{ + GLboolean isFloat[4]; + GLboolean isBool[4]; + GLuint i, n; + + /* first, simplify children */ + for (i = 0; i < oper->num_children; i++) { + slang_simplify(&oper->children[i], space, atoms); + } + + /* examine children */ + n = MIN2(oper->num_children, 4); + for (i = 0; i < n; i++) { + isFloat[i] = (oper->children[i].type == slang_oper_literal_float || + oper->children[i].type == slang_oper_literal_int); + isBool[i] = (oper->children[i].type == slang_oper_literal_bool); + } + + if (n == 2 && isFloat[0] && isFloat[1]) { + /* probably simple arithmetic */ + switch (oper->type) { + case slang_oper_add: + for (i = 0; i < 4; i++) { + oper->literal[i] + = oper->children[0].literal[i] + oper->children[1].literal[i]; + } + slang_operation_destruct(oper); + oper->type = slang_oper_literal_float; + break; + case slang_oper_subtract: + for (i = 0; i < 4; i++) { + oper->literal[i] + = oper->children[0].literal[i] - oper->children[1].literal[i]; + } + slang_operation_destruct(oper); + oper->type = slang_oper_literal_float; + break; + case slang_oper_multiply: + for (i = 0; i < 4; i++) { + oper->literal[i] + = oper->children[0].literal[i] * oper->children[1].literal[i]; + } + slang_operation_destruct(oper); + oper->type = slang_oper_literal_float; + break; + case slang_oper_divide: + for (i = 0; i < 4; i++) { + oper->literal[i] + = oper->children[0].literal[i] / oper->children[1].literal[i]; + } + slang_operation_destruct(oper); + oper->type = slang_oper_literal_float; + break; + default: + ; /* nothing */ + } + } + else if (n == 1 && isFloat[0]) { + switch (oper->type) { + case slang_oper_minus: + for (i = 0; i < 4; i++) { + oper->literal[i] = -oper->children[0].literal[i]; + } + slang_operation_destruct(oper); + oper->type = slang_oper_literal_float; + break; + case slang_oper_plus: + COPY_4V(oper->literal, oper->children[0].literal); + slang_operation_destruct(oper); + oper->type = slang_oper_literal_float; + break; + default: + ; /* nothing */ + } + } + else if (n == 2 && isBool[0] && isBool[1]) { + /* simple boolean expression */ + switch (oper->type) { + case slang_oper_logicaland: + for (i = 0; i < 4; i++) { + const GLint a = oper->children[0].literal[i] ? 1 : 0; + const GLint b = oper->children[1].literal[i] ? 1 : 0; + oper->literal[i] = (GLfloat) (a && b); + } + slang_operation_destruct(oper); + oper->type = slang_oper_literal_bool; + break; + case slang_oper_logicalor: + for (i = 0; i < 4; i++) { + const GLint a = oper->children[0].literal[i] ? 1 : 0; + const GLint b = oper->children[1].literal[i] ? 1 : 0; + oper->literal[i] = (GLfloat) (a || b); + } + slang_operation_destruct(oper); + oper->type = slang_oper_literal_bool; + break; + case slang_oper_logicalxor: + for (i = 0; i < 4; i++) { + const GLint a = oper->children[0].literal[i] ? 1 : 0; + const GLint b = oper->children[1].literal[i] ? 1 : 0; + oper->literal[i] = (GLfloat) (a ^ b); + } + slang_operation_destruct(oper); + oper->type = slang_oper_literal_bool; + break; + default: + ; /* nothing */ + } + } + else if (n == 4 && isFloat[0] && isFloat[1] && isFloat[2] && isFloat[3]) { + if (oper->type == slang_oper_call) { + if (strcmp((char *) oper->a_id, "vec4") == 0) { + oper->literal[0] = oper->children[0].literal[0]; + oper->literal[1] = oper->children[1].literal[0]; + oper->literal[2] = oper->children[2].literal[0]; + oper->literal[3] = oper->children[3].literal[0]; + slang_operation_destruct(oper); + oper->type = slang_oper_literal_float; + } + } + } +} + diff --git a/src/mesa/shader/slang/slang_simplify.h b/src/mesa/shader/slang/slang_simplify.h new file mode 100644 index 00000000000..69be3092a58 --- /dev/null +++ b/src/mesa/shader/slang/slang_simplify.h @@ -0,0 +1,12 @@ + +#ifndef SLANG_SIMPLIFY_H +#define SLANG_SIMPLIFY_H + +extern void +slang_simplify(slang_operation *oper, + const slang_assembly_name_space * space, + slang_atom_pool * atoms); + + + +#endif /* SLANG_SIMPLIFY_H */ diff --git a/src/mesa/shader/slang/slang_utility.c b/src/mesa/shader/slang/slang_utility.c index 256d52455db..314ecc8d759 100644 --- a/src/mesa/shader/slang/slang_utility.c +++ b/src/mesa/shader/slang/slang_utility.c @@ -220,3 +220,16 @@ slang_atom_pool_id(slang_atom_pool * pool, slang_atom atom) return (const char *) (atom); } + +/** + * Generate a new, unique atom with given prefix. + */ +slang_atom +slang_atom_pool_gen(slang_atom_pool * pool, const char *prefix) +{ + char name[1000]; + static int nextFree = 100; + sprintf(name, "%s%d", prefix, nextFree); + nextFree++; + return slang_atom_pool_atom(pool, name); +} diff --git a/src/mesa/shader/slang/slang_utility.h b/src/mesa/shader/slang/slang_utility.h index 565de4e4b02..c969ffcd2af 100644 --- a/src/mesa/shader/slang/slang_utility.h +++ b/src/mesa/shader/slang/slang_utility.h @@ -102,6 +102,10 @@ GLvoid slang_atom_pool_destruct (slang_atom_pool *); slang_atom slang_atom_pool_atom (slang_atom_pool *, const char *); const char *slang_atom_pool_id (slang_atom_pool *, slang_atom); +slang_atom +slang_atom_pool_gen(slang_atom_pool * pool, const char *prefix); + + #ifdef __cplusplus } #endif |